00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "terminal.h"
00036
00037 #include <sstream>
00038
00039 #include "datahash/datahash_text.h"
00040 #include "dialog-draw/dialog-draw.h"
00041 #include "gamepad-vgfx-element/gamepad-vgfx-element.h"
00042 #include "geometry/geometry_2d.h"
00043 #include "glut/glut.h"
00044 #include "glut/glut_2d.h"
00045 #include "glut/renderable.h"
00046 #include "glut-font/glut-font.h"
00047 #include "map-kdtree/map-kdtree.h"
00048 #include "model-loader/model-loader.h"
00049 #include "perf/perf.h"
00050 #include "vgfx-opengl-draw/vgfx-opengl-draw.h"
00051
00052
00053 namespace aesop {
00054
00056
00059
00060 TerminalHost::~TerminalHost(void) throw() { }
00061 Terminal::~Terminal(void) throw() { }
00062
00063
00070 enum eInputMode {
00071 eMode_Normal = 1,
00072 eMode_Cursor = 2,
00073
00074
00075 eMode_Invalid = 0
00076 };
00077
00078
00079 typedef point2d_t<int> pointi_t;
00080 typedef point2d_t<float> pointf_t;
00081
00082
00083 static const float s_turnSpeed = 2.0;
00084
00085
00087
00088
00089
00091
00092 static float
00093 tweakMouseMotion
00094 (
00095 IN float dx
00096 )
00097 throw()
00098 {
00099 int ix = +1;
00100 if (dx < 0) {
00101 dx = -dx;
00102 ix = -1;
00103 }
00104 return 16.0 * ix * dx * dx;
00105 }
00106
00107
00108
00109 static void
00110 clipCoord
00111 (
00112 IN float& x,
00113 IN int maxX
00114 )
00115 throw()
00116 {
00117 if (x < 0.0) {
00118 x = 0.0;
00119 } else if (x > maxX) {
00120 x = maxX;
00121 }
00122 }
00123
00124
00125
00126 static float
00127 getRandomX
00128 (
00129 void
00130 )
00131 throw()
00132 {
00133 return rand() / (1.0 * RAND_MAX);
00134 }
00135
00136
00137
00138 static float
00139 getPotRatio
00140 (
00141 IN const gamepad::pot_value_t& pv
00142 )
00143 throw()
00144 {
00145 int delta = pv.maxSeen - pv.minSeen;
00146 if (delta < 1)
00147 return 0.5;
00148
00149 return ((float) pv.value - pv.minSeen) / delta;
00150 }
00151
00152
00153
00154 static float
00155 getJoyAxis
00156 (
00157 IN const gamepad::pot_value_t& rawValue
00158 )
00159 throw()
00160 {
00161 float dx = 2.0 * (getPotRatio(rawValue) - 0.5);
00162
00163
00164 int iSign = +1;
00165 if (dx < 0) {
00166 dx = -dx;
00167 iSign = -1;
00168 }
00169
00170 const float cutoff = 0.2;
00171 dx -= cutoff;
00172 if (dx < 0) {
00173 return 0;
00174 }
00175 const float inverted = 1.0 / (1.0 - cutoff);
00176 return iSign * dx * inverted;
00177 }
00178
00179
00181
00182
00183
00185
00186 class TermImpl : public Terminal {
00187 public:
00188 TermImpl(void) throw();
00189 ~TermImpl(void) throw() { DPRINTF("Destroying terminal"); }
00190
00191
00192 void initialize(IN TerminalHost * host,
00193 IN int playerId,
00194 IN smart_ptr<glut::RenderQueue>& rq);
00195
00196
00197 void setKeys(IN smart_ptr<crypto::DESKey>& desKey,
00198 IN smart_ptr<gamepad::Manager>& mgr);
00199 void input(IN gamepad::Gamepad * gp, IN float dt);
00200 void mouseMove(IN int x, IN int y);
00201 void mouseButton(IN int button, IN int state,
00202 IN int x, IN int y);
00203 void keyboard(IN int key, IN int mods);
00204 void showDialog(IN const char * id,
00205 IN const Datahash * dialog,
00206 IN dialog::Host * host);
00207 void destroyDialog(IN const char * id);
00208 void notifyMap(IN MapKdTree * mapKdTree);
00209 void notifyInstance(IN smart_ptr<Instance>& instance);
00210
00211
00212 void render3D(IN int id, IN const view::render_info_t& ri);
00213 void render2D(IN int id, IN const view::render_info_t& ri);
00214
00215 private:
00216
00217 smart_ptr<dialog::Manager> m_dialogManager;
00218 smart_ptr<glut::RenderQueue> m_rQueue;
00219 smart_ptr<vgfx::Drawer> m_vgfxDrawer;
00220 smart_ptr<glut::Renderable> m_model;
00221 smart_ptr<Instance> m_instance;
00222 eInputMode m_mode;
00223 int m_playerId;
00224 TerminalHost * m_host;
00225
00226 pointf_t m_cursor;
00227 float m_back[3];
00228 int m_maxX;
00229 int m_maxY;
00230 int m_lastX;
00231 int m_lastY;
00232 bool m_newMap;
00233 map_draw_stats_t m_stats;
00234 MapKdTree * m_mapKdTree;
00235 glut::Viewer m_viewer;
00236 glut::fps_t m_fps;
00237 };
00238
00239
00240
00241 TermImpl::TermImpl(void)
00242 throw()
00243 {
00244 DPRINTF("New terminal!");
00245
00246
00247 m_mode = eMode_Normal;
00248 m_maxX = m_maxY = 1;
00249 m_mapKdTree = NULL;
00250 m_newMap = false;
00251
00252 m_lastX = 64;
00253 m_lastY = 64;
00254
00255
00256 srand(time(NULL));
00257 m_back[0] = 0.2 + 0.4 * getRandomX();
00258 m_back[1] = 0.2 + 0.4 * getRandomX();
00259 m_back[2] = 0.2 + 0.4 * getRandomX();
00260 }
00261
00262
00263
00264 void
00265 TermImpl::initialize
00266 (
00267 IN TerminalHost * host,
00268 IN int playerId,
00269 IN smart_ptr<glut::RenderQueue>& rq
00270 )
00271 {
00272 ASSERT(host, "null");
00273 ASSERT(playerId > 0, "bad player id: %d", playerId);
00274 ASSERT(rq, "null");
00275
00276 m_host = host;
00277 m_playerId = playerId;
00278 m_rQueue = rq;
00279
00280 m_vgfxDrawer = vgfx::createOpenGLDrawer();
00281 ASSERT(m_vgfxDrawer, "null");
00282
00283 smart_ptr<crypto::DESKey> key = NULL;
00284 smart_ptr<gamepad::Manager> mgr = NULL;
00285 this->setKeys(key, mgr);
00286
00287 m_fps.init(perf::getNow());
00288 }
00289
00290
00291
00293
00294
00295
00297
00298 void
00299 TermImpl::setKeys
00300 (
00301 IN smart_ptr<crypto::DESKey>& desKey,
00302 IN smart_ptr<gamepad::Manager>& gamepadMgr
00303 )
00304 {
00305
00306
00307 ASSERT(m_vgfxDrawer, "null");
00308
00309 smart_ptr<dialog::Drawer> drawer = dialog::createOpenGLDrawer();
00310 ASSERT(drawer, "null");
00311
00312 m_dialogManager = dialog::Manager::create(desKey, drawer);
00313 ASSERT(m_dialogManager, "failed to create dialog manager");
00314
00315
00316 if (gamepadMgr) {
00317 gamepad::registerVgfxTestFactory(gamepadMgr, m_dialogManager,
00318 m_vgfxDrawer);
00319 gamepad::registerVgfxSimpleFactory(gamepadMgr, m_dialogManager,
00320 m_vgfxDrawer);
00321 }
00322 }
00323
00324
00325
00326 void
00327 TermImpl::input
00328 (
00329 IN gamepad::Gamepad * gp,
00330 IN float dt
00331 )
00332 {
00333
00334 ASSERT(dt > 0.0, "Bad time increment: %f", dt);
00335
00336
00337 gamepad::Type * type = (gp) ? gp->getType() : NULL;
00338 ASSERT(!gp || type, "gamepad but no type?");
00339
00340
00341 int iLeftJoy = -1;
00342 int iRightJoy = -1;
00343 int iAction1 = -1;
00344 int iTrigger = -1;
00345 int iLeftJoyPush = -1;
00346 if (gp) {
00347 int iStart2 = type->getLogicalIndex("start2",
00348 gamepad::eInput_Button);
00349 iLeftJoy = type->getLogicalIndex("leftJoy",
00350 gamepad::eInput_Joystick);
00351 iRightJoy = type->getLogicalIndex("rightJoy",
00352 gamepad::eInput_Joystick);
00353 iAction1 = type->getLogicalIndex("action1",
00354 gamepad::eInput_Button);
00355 iTrigger = type->getLogicalIndex("rightTrigger",
00356 gamepad::eInput_Button);
00357 iLeftJoyPush = type->getLogicalIndex("leftJoyPush",
00358 gamepad::eInput_Button);
00359 if (iTrigger < 0) {
00360 DPRINTF("Failed to retrieve trigger as button, trying pot...");
00361
00362
00363
00364 DPRINTF("Nope!");
00365
00366 }
00367 if (iStart2 >= 0) {
00368 if (gamepad::eButtonWasReleased & gp->getButton(iStart2)) {
00369 m_mode = (eMode_Normal == m_mode) ? eMode_Cursor : eMode_Normal;
00370 DPRINTF("Mode = %d", m_mode);
00371 }
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381 if (m_newMap) {
00382
00383 m_newMap = false;
00384 point3d_t newPos;
00385 point3d_t delta;
00386 delta.clear();
00387 point3d_t euler;
00388 euler.clear();
00389 m_host->requestMove(m_playerId, delta, euler, newPos);
00390 m_viewer.setPosition(newPos);
00391 }
00392
00393
00394 point3d_t delta;
00395 delta.clear();
00396
00397
00398 gamepad::joystick_t joyR, joyL;
00399 if (gp && eMode_Cursor == m_mode) {
00400 gp->getJoystick(iRightJoy, joyR);
00401
00402 float dx = getJoyAxis(joyR.x);
00403 float dy = getJoyAxis(joyR.y);
00404
00405 dx = tweakMouseMotion(dx);
00406 dy = tweakMouseMotion(dy);
00407
00408 m_cursor.x += dx;
00409 m_cursor.y += dy;
00410
00411
00412 clipCoord(m_cursor.x, m_maxX);
00413 clipCoord(m_cursor.y, m_maxY);
00414
00415 int x = (int) m_cursor.x;
00416 int y = (int) m_cursor.y;
00417
00418 gamepad::eButton button = gp->getButton(iAction1);
00419
00420 if (gamepad::eButtonWasPushed & button) {
00421 m_dialogManager->button(0, 0, x, y);
00422 } else if (gamepad::eButtonWasReleased & button) {
00423 m_dialogManager->button(0, 1, x, y);
00424 } else if (gamepad::eButtonDown & button) {
00425 m_dialogManager->cursor(x, y);
00426 }
00427 } else if (gp) {
00428
00429
00430 const char * verb = "idle";
00431
00432 gp->getJoystick(iRightJoy, joyR);
00433 gp->getJoystick(iLeftJoy, joyL);
00434
00435
00436 float dx = getJoyAxis(joyR.x);
00437 float dy = getJoyAxis(joyR.y);
00438
00439 float rotY = -dx * dt * s_turnSpeed;
00440 float rotUp = dy * dt * s_turnSpeed;
00441
00442 m_viewer.rotateY(rotY);
00443 m_viewer.rotateUp(rotUp);
00444
00445
00446 dx = getJoyAxis(joyL.x);
00447 float dz = getJoyAxis(joyL.y);
00448 dy = 0.0;
00449
00450 ASSERT(dx > -1.01 && dx < 1.01, "bad dx: %f", dx);
00451 ASSERT(dz > -1.01 && dz < 1.01, "bad dz: %f", dz);
00452
00453
00454 float mult = 1.0;
00455 if (iLeftJoyPush >= 0 &&
00456 gamepad::eButtonDown & gp->getButton(iLeftJoyPush)) {
00457 mult = 4.0;
00458 verb = "run";
00459 } else {
00460 float r = (dx * dx) + (dz * dz);
00461 if (r > 0.1) {
00462 verb = "walk";
00463 }
00464 }
00465
00466
00467 const float maxSpeed = 4.5;
00468
00469 dx *= dt * mult * maxSpeed;
00470 dz *= dt * mult * maxSpeed;
00471
00472
00473 if (m_model) {
00474 m_model->setAnimation(verb);
00475 }
00476
00477
00478
00479 point3d_t oldPos = m_viewer.getPosition();
00480 m_viewer.move(dz, dx, 0);
00481 point3d_t newPos = m_viewer.getPosition();
00482 delta = newPos - oldPos;
00483
00484
00485 if (iTrigger >= 0 &&
00486 gamepad::eButtonWasReleased & gp->getButton(iTrigger)) {
00487
00488 event_t event;
00489 event.device = eDevice_Gamepad;
00490 event.event = eEvent_Press;
00491 event.item = iTrigger;
00492
00493 m_host->notifyInput(m_playerId, event);
00494 }
00495 }
00496
00497
00498
00499 point3d_t euler(-m_viewer.getUpRotation(),
00500 m_viewer.getYRotation(),
00501 0.0);
00502
00503
00504 point3d_t newPos;
00505 m_host->requestMove(m_playerId, delta, euler, newPos);
00506 m_viewer.setPosition(newPos);
00507
00508
00509
00510 }
00511
00512
00513
00514 void
00515 TermImpl::mouseMove
00516 (
00517 IN int x,
00518 IN int y
00519 )
00520 {
00521 m_dialogManager->cursor(x, y);
00522 }
00523
00524
00525
00526 void
00527 TermImpl::mouseButton
00528 (
00529 IN int button,
00530 IN int state,
00531 IN int x,
00532 IN int y
00533 )
00534 {
00535 if (state) {
00536 m_lastX = x;
00537 m_lastY = y;
00538 }
00539 m_dialogManager->button(button, state, x, y);
00540 }
00541
00542
00543
00544 void
00545 TermImpl::keyboard
00546 (
00547 IN int key,
00548 IN int mods
00549 )
00550 {
00551 if (eMode_Cursor == m_mode) {
00552 m_dialogManager->keyboard(key, mods);
00553 } else {
00554
00555 }
00556 }
00557
00558
00559
00560 void
00561 TermImpl::showDialog
00562 (
00563 IN const char * id,
00564 IN const Datahash * dialog,
00565 IN dialog::Host * host
00566 )
00567 {
00568 ASSERT(id, "null");
00569 ASSERT(dialog, "null");
00570 ASSERT(host, "null");
00571
00572 m_dialogManager->createDialog(id, m_lastX, m_lastY, dialog, host);
00573 }
00574
00575
00576
00577 void
00578 TermImpl::destroyDialog
00579 (
00580 IN const char * id
00581 )
00582 {
00583 ASSERT(id, "null");
00584
00585 m_dialogManager->destroyDialog(id);
00586 }
00587
00588
00589
00590 void
00591 TermImpl::notifyMap
00592 (
00593 IN MapKdTree * mapKdTree
00594 )
00595 {
00596
00597
00598 if (m_mapKdTree && !mapKdTree) {
00599 DPRINTF("LOSING MAP!");
00600 } else if (!m_mapKdTree && mapKdTree) {
00601 DPRINTF("Gaining map!");
00602 m_newMap = true;
00603 }
00604
00605 m_mapKdTree = mapKdTree;
00606 }
00607
00608
00609
00610 void
00611 TermImpl::notifyInstance
00612 (
00613 IN smart_ptr<Instance>& instance
00614 )
00615 {
00616
00617
00618 m_instance = instance;
00619 if (m_instance) {
00620 m_model = getModel(instance);
00621 } else {
00622 m_model = NULL;
00623 }
00624 }
00625
00626
00627
00629
00630
00631
00633
00634 void
00635 TermImpl::render3D
00636 (
00637 IN int id,
00638 IN const view::render_info_t& ri
00639 )
00640 {
00641 perf::Timer timer("Terminal::render3D");
00642 ASSERT(id > 0, "Bad id: %d", id);
00643 ASSERT(ri.isValid(), "invalid render info?");
00644 ASSERT(m_rQueue, "null");
00645
00646
00647
00648
00649
00650 glut::render_context_t rc;
00651 rc.camera.setAspect(ri.width, ri.height);
00652
00653
00654
00655 rc.viewer = m_viewer;
00656 point3d_t pos = rc.viewer.getPosition();
00657 pos.y += 0.5;
00658 rc.viewer.setPosition(pos);
00659
00660
00661 if (m_mapKdTree) {
00662 drawMap(m_mapKdTree, rc, m_rQueue, m_stats);
00663 }
00664 }
00665
00666
00667
00668 void
00669 TermImpl::render2D
00670 (
00671 IN int id,
00672 IN const view::render_info_t& ri
00673 )
00674 {
00675 perf::Timer timer("Terminal::render2D");
00676 ASSERT(id > 0, "Bad id: %d", id);
00677
00678
00679 m_fps.tick(perf::getNow());
00680
00681
00682 m_maxX = ri.width;
00683 m_maxY = ri.height;
00684
00685 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00686
00687
00688 if (!m_mapKdTree) {
00689 glColor3f(m_back[0], m_back[1], m_back[2]);
00690 glRecti(0, 0, m_maxX, m_maxY);
00691 }
00692
00693
00694
00695 glColor3f(1.0, 1.0, 1.0);
00696 m_dialogManager->display(m_maxX, m_maxY);
00697
00698
00699 if (eMode_Cursor == m_mode) {
00700 glut::drawCursor((int) m_cursor.x, (int) m_cursor.y);
00701 }
00702
00703
00704 glColor3f(1.0, 1.0, 1.0);
00705 char buffer[128];
00706 sprintf(buffer, "%d fps", (int) (m_fps.getFPS() + 0.5));
00707 displayString(eGlutFont_Bitmap_9_by_15, 1, m_maxY - 5, -1, buffer);
00708
00709
00710 sprintf(buffer, "drawing %d objects", m_stats.nObjects);
00711 displayString(eGlutFont_Bitmap_9_by_15, 1, m_maxY - 18, -1, buffer);
00712
00713
00714 sprintf(buffer, "%d x %d", m_maxX, m_maxY);
00715 displayString(eGlutFont_Bitmap_9_by_15, m_maxX - 192, m_maxY - 5, -1,
00716 buffer);
00717
00718 sprintf(buffer, "player id: %d", id);
00719 displayString(eGlutFont_Bitmap_9_by_15, m_maxX - 192, m_maxY - 21, -1,
00720 buffer);
00721
00722
00723 if (m_mapKdTree) {
00724 point3d_t pos = m_viewer.getPosition();
00725 sprintf(buffer, "position: (%3.1f, %3.1f, %3.1f)",
00726 pos.x, pos.y, pos.z);
00727 displayString(eGlutFont_Bitmap_9_by_15, 1, 12, -1, buffer);
00728
00729 pos = m_viewer.getFacing();
00730 sprintf(buffer, " facing: (%3.1f, %3.1f, %3.1f)",
00731 pos.x, pos.y, pos.z);
00732 displayString(eGlutFont_Bitmap_9_by_15, 1, 24, -1, buffer);
00733 }
00734 }
00735
00736
00737
00738
00740
00741
00742
00744
00745 smart_ptr<Terminal>
00746 Terminal::create
00747 (
00748 IN TerminalHost * host,
00749 IN int playerId,
00750 IN smart_ptr<glut::RenderQueue>& rq
00751 )
00752 {
00753 ASSERT(host, "null");
00754 ASSERT(playerId > 0, "bad player id: %d", playerId);
00755 ASSERT(rq, "null");
00756
00757 smart_ptr<TermImpl> local = new TermImpl;
00758 ASSERT(local, "out of memory");
00759
00760 local->initialize(host, playerId, rq);
00761
00762 return local;
00763 }
00764
00765
00766
00767 };
00768