00001 #include <ctype.h>
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004
00005 #include <fstream>
00006 #include <string>
00007
00008 #include "SDL.h"
00009
00010 #include <vrs/camera.h>
00011 #include <vrs/font.h>
00012 #include <vrs/opengl/lightmodelgl.h>
00013 #include <vrs/opengl/shapematerialgl.h>
00014 #include <vrs/opengl/transparencytechniquegl.h>
00015 #include <vrs/polygonset.h>
00016 #include <vrs/sg/behaviorcallback.h>
00017 #include <vrs/sg/canvas.h>
00018 #include <vrs/sg/key.h>
00019 #include <vrs/sg/keyevent.h>
00020 #include <vrs/sg/resizeevent.h>
00021 #include <vrs/text.h>
00022 #include <vrs/translation.h>
00023
00024 #include "ResourceManager.h"
00025
00026 #include "Console.h"
00027
00028 using namespace VRS;
00029
00030
00031 namespace random_racer
00032 {
00033
00034
00035 SO<Console> Console::s_instance = NULL;
00036 const float Console::c_marginX = 0.3;
00037 const float Console::c_marginY = 0.6;
00038 const float Console::c_pixelsPerChar = 11.0;
00039 const unsigned int Console::c_animationDuration = 230;
00040
00041
00042 Console::TextBuffer::TextBuffer(
00043 int p_maxLines, const Vector& p_startOffset, double p_lineHeight)
00044 : SceneThing()
00045 {
00046 m_maxLines = p_maxLines;
00047 m_startOffset = p_startOffset;
00048 m_lineHeight = p_lineHeight;
00049 }
00050
00051 void
00052 Console::TextBuffer::addLine(SO<Text> p_newLine)
00053 {
00054
00055 prepend( p_newLine );
00056
00057
00058 if(objects() > m_maxLines)
00059 remove(m_maxLines);
00060
00061 SO<Text> line;
00062 Vector offset = m_startOffset;
00063
00064
00065 for( int i = 0; i < objects(); i++ )
00066 {
00067 line = VRS_Cast(Text, object(i));
00068 line->setPosition(offset);
00069 offset[1] += m_lineHeight;
00070 }
00071 }
00072
00073 void
00074 Console::TextBuffer::addLine(const std::string& p_newLine)
00075 {
00076 addLine(new Text(Console::get()->font(), p_newLine));
00077 }
00078
00079 Console::Console()
00080 {
00081
00082
00083 const float maxConsoleSize = 2300000.42;
00084
00085
00086
00087 SO<NonPersistentArray<Vector> > points = new NonPersistentArray<Vector>();
00088 points->append(Vector(-c_marginX, -c_marginY, 0.0001));
00089 points->append(Vector(maxConsoleSize, -c_marginY, 0.0001));
00090 points->append(Vector(-c_marginX, maxConsoleSize, 0.0001));
00091 points->append(Vector(maxConsoleSize, maxConsoleSize, 0.0001));
00092
00093 m_sceneThing = new SceneThing();
00094
00095
00096
00097 m_cam = Camera::newNormalizedDeviceCoordsCamera();
00098 m_sceneThing->append(m_cam);
00099
00100
00101 m_sceneThing->append(new LightModelGL(false));
00102
00103
00104
00105
00106
00107 m_translation = new Translation();
00108 m_sceneThing->append(m_translation);
00109
00110
00111 m_sceneThing->append(new ShapeMaterialGL(
00112 Color(0.0, 0.25, 0.5, 0.54), Color(1.0)));
00113 m_sceneThing->append(new PolygonSet(
00114 PolygonSet::TriangleStrip, points->newIterator()));
00115
00116 m_sceneThing->append(new ShapeMaterialGL(Color(1.0), Color(1.0)));
00117
00118
00119 m_font = ResourceManager::get()->loadFont("DejaVuSansMono.ttf",
00120 Font::POLYGON);
00121
00122 m_currentLine = new Text(m_font);
00123 m_sceneThing->append(m_currentLine);
00124
00125 m_textBuffer = new TextBuffer(42, Vector(0, 1.4, 0), 1.4);
00126 m_sceneThing->append(m_textBuffer);
00127
00128
00129 m_history.push_front("");
00130 m_histIter = m_history.begin();
00131
00132
00133 m_canvas = NULL;
00134
00135 m_eventCallback = new BehaviorCallback;
00136 m_eventCallback->setCanvasCallback(
00137 new MethodCallback<Console>(this, &Console::handleEvents));
00138
00139 m_startNewTabCompletition = true;
00140
00141 m_animationInProgress = false;
00142 }
00143
00144 SO<Console>
00145 Console::get()
00146 {
00147 if(s_instance == NULL)
00148 s_instance = new Console();
00149
00150 return s_instance;
00151 }
00152
00153 void
00154 Console::handleKey(unsigned int p_key)
00155 {
00156 std::string text = m_currentLine->getText();
00157
00158
00159 if((p_key == BackSpaceKey || p_key == DeleteKey) && !text.empty())
00160 m_currentLine->setText(text.substr(0, text.size()-1));
00161
00162
00163 else if(p_key == DeleteLineKey)
00164 m_currentLine->setText("");
00165
00166
00167 else if(p_key == EnterKey || p_key == ReturnKey)
00168 {
00169 m_textBuffer->addLine(m_currentLine);
00170 m_sceneThing->remove(m_currentLine);
00171
00172 m_currentLine = new Text(m_font);
00173 m_sceneThing->append(m_currentLine);
00174
00175 dispatchCommand(text);
00176 }
00177
00178 else if(p_key == UpKey)
00179 historyUp();
00180
00181
00182 else if(p_key == DownKey)
00183 historyDown();
00184
00185
00186 else if(p_key == TabKey)
00187 tabCompleteForward();
00188
00189
00190 else if(p_key == ShiftTabKey)
00191 tabCompleteBackward();
00192
00193
00194 else if(isprint(p_key))
00195 {
00196 text += p_key;
00197 m_currentLine->setText(text);
00198 }
00199
00200
00201 m_startNewTabCompletition = (p_key == TabKey||p_key == ShiftTabKey) ?
00202 false : true;
00203 }
00204
00205 bool
00206 Console::dispatchCommand(const std::string& p_line, bool p_batchMode)
00207 {
00208 if(!p_batchMode && !p_line.empty())
00209 {
00210
00211 m_histIter = m_history.begin();
00212 m_history.insert(++m_histIter, p_line);
00213
00214
00215 m_histIter = m_history.begin();
00216 }
00217
00218 std::string cmd, args;
00219 unsigned int state = 0, r = 0;
00220
00221
00222
00223
00224 for(unsigned int i = 0; i < p_line.size(); i++)
00225 if(state == 0 && p_line[i] != ' ')
00226 {
00227 r = i;
00228 state = 1;
00229 }
00230 else if(state == 1 && p_line[i] == ' ')
00231 {
00232 cmd = p_line.substr(r, i-r);
00233 state = 2;
00234 }
00235 else if(state == 2 && p_line[i] != ' ')
00236 {
00237 r = i;
00238 state = 3;
00239 break;
00240 }
00241
00242
00243
00244 if(state < 2 && cmd.empty())
00245 cmd = p_line.substr(r, p_line.size()-r);
00246 else if(state == 3)
00247 args = p_line.substr(r, p_line.size()-r);
00248
00249
00250 if(!cmd.empty())
00251 {
00252
00253
00254
00255 if(!m_registry.contains(cmd))
00256 {
00257 unsigned int found = 0;
00258 std::string fullCmd;
00259 SO<Iterator<std::string> > it = m_registry.newKeyIterator();
00260
00261 for(unsigned int i = 0; i < it->size() && found <= 1; i++)
00262 if((it->get(i)).find(cmd) == 0)
00263 {
00264 fullCmd = it->get(i);
00265 found++;
00266 }
00267
00268 if(found != 1)
00269 {
00270 if(!p_batchMode)
00271 addLine("(command not found)");
00272
00273 return false;
00274 }
00275
00276 cmd = fullCmd;
00277 }
00278
00279
00280
00281
00282 CallbackBase* c = (CallbackBase*)m_registry[cmd];
00283
00284
00285 if(dynamic_cast<Callback2<const std::string&,const std::string&>*>(c) != NULL)
00286 ((Callback2<const std::string&,const std::string&>*)c)->callback(cmd, args);
00287
00288
00289 else if(dynamic_cast<Callback1<const std::string&>*>(c) != NULL)
00290 ((Callback1<const std::string&>*)c)->callback(args);
00291
00292
00293 else if(dynamic_cast<Callback*>(c) != NULL)
00294 ((Callback*)c)->callback();
00295
00296 else
00297 {
00298 if(!p_batchMode)
00299 addLine("(invalid callback)");
00300
00301 return false;
00302 }
00303 }
00304
00305
00306 else if(!p_batchMode &&
00307 ++m_histIter != m_history.end() &&
00308 !(*m_histIter).empty())
00309 return dispatchCommand(*(m_histIter--), true);
00310
00311 else
00312 {
00313 if(!p_batchMode)
00314 addLine("(empty line)");
00315
00316 return false;
00317 }
00318
00319 return true;
00320 }
00321
00322 void
00323 Console::historyUp(bool p_realyUp)
00324 {
00325
00326 if(m_histIter == m_history.end())
00327 return;
00328
00329
00330 if(p_realyUp)
00331 {
00332
00333 if(++m_histIter == m_history.end())
00334 m_histIter--;
00335 }
00336
00337 else if(m_histIter != m_history.begin())
00338 m_histIter--;
00339
00340 m_currentLine->setText(*m_histIter);
00341 }
00342
00343 void
00344 Console::setCanvas(SO<Canvas> p_canvas)
00345 {
00346 if(p_canvas == m_canvas)
00347 return;
00348
00349 if(m_canvas != NULL)
00350 {
00351 m_eventCallback->deactivate();
00352 m_canvas->remove(m_eventCallback);
00353 }
00354
00355 m_canvas = p_canvas;
00356
00357 if(p_canvas == NULL)
00358 return;
00359
00360 m_canvas->append(m_eventCallback);
00361 m_eventCallback->activate();
00362 }
00363
00364 void
00365 Console::handleEvents()
00366 {
00367 KeyEvent* event = VRS_Cast(KeyEvent, m_eventCallback->currentCanvasEvent());
00368
00369 if(event != NULL)
00370 keyEvent(event);
00371
00372 else
00373 {
00374 ResizeEvent* event = VRS_Cast(ResizeEvent,
00375 m_eventCallback->currentCanvasEvent());
00376 if(event != NULL)
00377 resizeEvent(event);
00378 }
00379
00380 m_canvas->postForRedisplay();
00381 }
00382
00383 void
00384 Console::resizeEvent(SO<ResizeEvent> p_event)
00385 {
00386 double x1, x2, y1, y2, ratio;
00387 ratio = double(p_event->width()) / double(p_event->height());
00388
00389 y2 = double(p_event->height())/2.0/c_pixelsPerChar;
00390 y1 = -y2;
00391 x1 = -c_marginX;
00392 x2 = (double(p_event->height())/c_pixelsPerChar)*ratio;
00393
00394 m_sceneThing->remove(m_cam);
00395 m_cam = Camera::newNormalizedDeviceCoordsCamera(x1, x2, y1, y2);
00396 m_sceneThing->prepend(m_cam);
00397 }
00398
00399 void
00400 Console::keyEvent(SO<KeyEvent> p_event)
00401 {
00402 if(p_event->pressed())
00403 {
00404 if(p_event->keyCode() == '<' || p_event->keyCode() == '^')
00405 toggleVisibility();
00406
00407 else if(isVisible())
00408 handleKey(p_event->keyCode());
00409 }
00410 }
00411
00412 void
00413 Console::attach(SO<Canvas> p_canvas)
00414 {
00415 if(! p_canvas->contains(sceneThing()))
00416 p_canvas->append(sceneThing());
00417
00418 setCanvas(p_canvas);
00419 }
00420
00421 void
00422 Console::detach()
00423 {
00424 if(m_canvas->contains(sceneThing()))
00425 m_canvas->remove(sceneThing());
00426
00427 setCanvas(NULL);
00428 }
00429
00430
00431
00432 #define iterateBackCyclic(BEGIN, END, ITERATOR) \
00433 { if(ITERATOR-- == BEGIN) { ITERATOR = END; ITERATOR--; } }
00434
00435 #define iterateForwardCyclic(BEGIN, END, ITERATOR) \
00436 { if(++ITERATOR == END) ITERATOR = BEGIN; }
00437
00438 void
00439 Console::tabCompleteForward(bool p_forward)
00440 {
00441 if(m_startNewTabCompletition)
00442 {
00443 m_currentTabWord = m_currentLine->getText();
00444
00445 m_tabList.clear();
00446
00447 SO<Iterator<std::string> > it = m_registry.newKeyIterator();
00448 int pos;
00449
00450
00451
00452 for(unsigned int i = 0; i < it->size(); i++)
00453 {
00454 pos = (it->get(i)).find(m_currentTabWord);
00455
00456 if(pos == 0)
00457 m_tabList.push_back(it->get(i));
00458 }
00459
00460 m_tabList.sort();
00461
00462 if(p_forward)
00463 {
00464 m_tabIter = m_tabList.begin();
00465 m_lastTabWasForward = true;
00466 }
00467 else
00468 {
00469 m_tabIter = m_tabList.end();
00470 m_lastTabWasForward = false;
00471
00472 if(m_tabIter != m_tabList.begin())
00473 m_tabIter--;
00474 }
00475 }
00476
00477
00478 if(m_tabIter == m_tabList.begin() && m_tabIter == m_tabList.end())
00479 return;
00480
00481
00482 if(p_forward)
00483 {
00484
00485
00486 if(!m_lastTabWasForward)
00487 {
00488 iterateForwardCyclic(m_tabList.begin(), m_tabList.end(), m_tabIter);
00489 iterateForwardCyclic(m_tabList.begin(), m_tabList.end(), m_tabIter);
00490 }
00491
00492 m_currentLine->setText(*m_tabIter + " ");
00493
00494 iterateForwardCyclic(m_tabList.begin(), m_tabList.end(), m_tabIter);
00495 m_lastTabWasForward = true;
00496 }
00497 else
00498 {
00499 if(m_lastTabWasForward)
00500 {
00501 iterateBackCyclic(m_tabList.begin(), m_tabList.end(), m_tabIter);
00502 iterateBackCyclic(m_tabList.begin(), m_tabList.end(), m_tabIter);
00503 }
00504
00505 m_currentLine->setText(*m_tabIter + " ");
00506
00507 iterateBackCyclic(m_tabList.begin(), m_tabList.end(), m_tabIter);
00508 m_lastTabWasForward = false;
00509 }
00510 }
00511
00512 #undef iterateBackCyclic
00513 #undef iterateForwardCyclic
00514
00515 void
00516 Console::autoexec()
00517 {
00518 std::fstream stream(ResourceManager::get()->getPathOfFile(
00519 "autoexec.txt").c_str(), std::ios_base::in);
00520
00521 if(!stream.is_open())
00522 return;
00523
00524 char lineBuf[255];
00525
00526 while(stream.good())
00527 {
00528 stream.getline(lineBuf, sizeof(lineBuf));
00529
00530
00531 if(lineBuf[0] != 0 && lineBuf[0] != '#')
00532 dispatchCommand(lineBuf, true);
00533 }
00534
00535 stream.close();
00536 }
00537
00538 bool
00539 Console::toggleVisibility()
00540 {
00541 if(isVisible())
00542 {
00543 hide();
00544 return false;
00545 }
00546 else
00547 {
00548 show();
00549 return true;
00550 }
00551 }
00552
00553 bool
00554 Console::isVisible()
00555 {
00556 return(!m_animationInProgress && m_sceneThing->getNodeState() != 0);
00557 }
00558
00559 void
00560 Console::startAnimation()
00561 {
00562 m_lastTick = SDL_GetTicks();
00563
00564 m_animationInProgress = true;
00565
00566 startTimer(23);
00567 }
00568
00569 void
00570 Console::hide()
00571 {
00572 if(m_animationInProgress || m_sceneThing->getNodeState() == 0)
00573 return;
00574
00575
00576 m_animationDistance = double(m_canvas->getHeight())/2.0/c_pixelsPerChar;
00577 m_distancePerTick = m_animationDistance / double(c_animationDuration);
00578
00579 startAnimation();
00580 }
00581
00582 void
00583 Console::show()
00584 {
00585 if(m_animationInProgress || m_sceneThing->getNodeState() != 0)
00586 return;
00587
00588
00589 m_sceneThing->setNodeState(
00590 SceneNode::EvaluationOn|SceneNode::TraversalOn);
00591
00592 m_animationDistance = double(m_canvas->getHeight())/2.0/c_pixelsPerChar;
00593 m_translation->setTranslate(Vector(0.0, m_animationDistance, 0.0));
00594 m_distancePerTick = -m_animationDistance / double(c_animationDuration);
00595
00596 startAnimation();
00597 }
00598
00599 void
00600 Console::timerTick()
00601 {
00602 unsigned int currentTick = SDL_GetTicks();
00603
00604
00605
00606
00607 if(currentTick == m_lastTick)
00608 return;
00609
00610 Vector tr = m_translation->getTranslate();
00611 tr[1] += (m_distancePerTick * (currentTick - m_lastTick));
00612
00613
00614
00615 if(tr[1] < 0 || tr[1] > m_animationDistance)
00616 {
00617
00618
00619 m_animationInProgress = false;
00620
00621
00622 if(m_distancePerTick < 0)
00623 m_translation->setTranslate(Vector(0,0,0));
00624
00625
00626 else
00627 m_sceneThing->setNodeState(0);
00628
00629
00630 stopTimer();
00631 }
00632 else
00633 {
00634 m_translation->setTranslate(tr);
00635 m_lastTick = currentTick;
00636 }
00637 }
00638
00639 }