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 "glut.h"
00036
00037 #include "common/wave_ex.h"
00038 #include "perf/perf.h"
00039 #include "threadsafe/threadsafe_map.h"
00040
00041
00042 namespace glut {
00043
00044
00045
00046 Host::~Host(void) throw() { }
00047 Task::~Task(void) throw() { }
00048
00049
00050 struct task_record_t {
00051
00052 task_record_t(void) throw() { this->clear(); }
00053 void clear(void) throw() {
00054 task = NULL;
00055 exception = "";
00056 needThrow = false;
00057 }
00058
00059
00060 Task * task;
00061 std::string exception;
00062 bool needThrow;
00063 };
00064
00065
00066
00067
00068 typedef threadsafe_map<pthread_t, smart_ptr<task_record_t> > task_map_t;
00069
00070 static task_map_t s_pendingTasks;
00071 static task_map_t s_completedTasks;
00072
00073 static smart_ptr<Host> s_host;
00074 static bool s_fullscreen = false;
00075 static pthread_t s_glutThreadId = 0;
00076
00077
00078 static int s_width = 0;
00079 static int s_height = 0;
00080
00081
00082
00083
00084
00085
00086
00087
00088 void
00089 processTasks
00090 (
00091 void
00092 )
00093 {
00094
00095 task_map_t::iterator_t i;
00096 s_pendingTasks.getIterator(i);
00097 pthread_t t_id;
00098 smart_ptr<task_record_t> trec;
00099 while (s_pendingTasks.getNextElement(i, t_id, trec)) {
00100 ASSERT(trec, "null task record in map");
00101 ASSERT(trec->task, "null task in record");
00102
00103 try {
00104 trec->task->doTask();
00105 } catch (std::exception& e) {
00106 trec->needThrow = true;
00107 trec->exception = e.what();
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117 s_pendingTasks.remove(t_id);
00118 s_completedTasks.insert(t_id, trec);
00119 }
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 static void
00130 onExit
00131 (
00132 void
00133 )
00134 {
00135
00136 if (s_fullscreen) {
00137 perf::Timer timer("glutLeaveGameMode");
00138 glutLeaveGameMode();
00139 }
00140
00141
00142 ASSERT(s_host, "null");
00143 int retval = 1;
00144 try {
00145 retval = s_host->shutdown();
00146 } catch (std::exception& e) {
00147 DPRINTF("Exception during shutdown!");
00148 DPRINTF("%s", e.what());
00149 }
00150 s_host = NULL;
00151
00152 exit(retval);
00153 }
00154
00155
00156
00157 static void
00158 onDisplay
00159 (
00160 void
00161 )
00162 {
00163 perf::Timer timer("glut::onDisplay");
00164 ASSERT(s_host, "null");
00165
00166
00167 glViewport(0, 0, s_width, s_height);
00168
00169
00170 try {
00171 s_host->display(s_width, s_height);
00172 } catch (std::exception& e) {
00173 DPRINTF("Exception while rendering!");
00174 DPRINTF("%s", e.what());
00175 }
00176
00177
00178 glutSwapBuffers();
00179 }
00180
00181
00182
00183 static void
00184 onIdle
00185 (
00186 void
00187 )
00188 {
00189 perf::Timer timer("glut::onIdle");
00190 ASSERT(s_host, "null");
00191
00192
00193 glut::processTasks();
00194
00195 Host::eBehavior behave = Host::eContinue;
00196 try {
00197 behave = s_host->tick();
00198 } catch (std::exception& e) {
00199 behave = Host::eExit;
00200 DPRINTF("Exception during tick!");
00201 DPRINTF("%s", e.what());
00202 }
00203
00204 if (Host::eContinue != behave)
00205 onExit();
00206
00207
00208 glutPostRedisplay();
00209 }
00210
00211
00212
00213 static void
00214 onMouseButton
00215 (
00216 IN int button,
00217 IN int state,
00218 IN int x,
00219 IN int y
00220 )
00221 {
00222 ASSERT(s_host, "null");
00223
00224 Host::eBehavior behave = Host::eContinue;
00225 try {
00226 behave = s_host->mouseButton(button, state, x, y);
00227 } catch (std::exception& e) {
00228 DPRINTF("Exception procesing mouse button event");
00229 DPRINTF("%s", e.what());
00230 }
00231
00232 if (Host::eContinue != behave) {
00233 onExit();
00234 }
00235 }
00236
00237
00238
00239 static void
00240 onMouseMove
00241 (
00242 IN int x,
00243 IN int y
00244 )
00245 {
00246 ASSERT(s_host, "null");
00247
00248 Host::eBehavior behave = Host::eContinue;
00249 try {
00250 behave = s_host->mouseMove(x, y);
00251 } catch (std::exception& e) {
00252 DPRINTF("Exception procesing mouse button event");
00253 DPRINTF("%s", e.what());
00254 }
00255
00256 if (Host::eContinue != behave) {
00257 onExit();
00258 }
00259 }
00260
00261
00262
00263 static void
00264 onKeyboard
00265 (
00266 IN byte_t key,
00267 IN int x,
00268 IN int y
00269 )
00270 {
00271 ASSERT(s_host, "null");
00272
00273 int mods = glutGetModifiers();
00274
00275 Host::eBehavior behave = Host::eContinue;
00276 try {
00277 behave = s_host->keyboard(key, mods);
00278 } catch (std::exception& e) {
00279 DPRINTF("Exception processing keyboard event!");
00280 DPRINTF("%s", e.what());
00281 }
00282
00283 if (Host::eContinue != behave)
00284 onExit();
00285 }
00286
00287
00288
00289 static void
00290 onSpecialKeys
00291 (
00292 IN int key,
00293 IN int x,
00294 IN int y
00295 )
00296 {
00297 ASSERT(s_host, "null");
00298
00299 int mods = glutGetModifiers();
00300
00301 Host::eBehavior behave = Host::eContinue;
00302 try {
00303 behave = s_host->specialKey(key, mods);
00304 } catch (std::exception& e) {
00305 DPRINTF("Exception processing special key!");
00306 DPRINTF("%s", e.what());
00307 }
00308
00309 if (Host::eContinue != behave)
00310 onExit();
00311 }
00312
00313
00314
00315 static void
00316 onReshape
00317 (
00318 IN int w,
00319 IN int h
00320 )
00321 {
00322 DPRINTF("Window size: %d x %d", w, h);
00323
00324 s_width = w;
00325 s_height = h;
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 void
00337 start
00338 (
00339 IN int argc,
00340 IN const char * argv[],
00341 IN int width,
00342 IN int height,
00343 IN const char * title,
00344 IN const char * gameModeString,
00345 IN smart_ptr<Host>& host
00346 )
00347 {
00348 ASSERT(width > 0, "Bad width: %d", width);
00349 ASSERT(height > 0, "Bad height: %d", height);
00350 ASSERT(title, "null");
00351
00352 ASSERT(host, "null");
00353
00354
00355 ASSERT(sizeof(float) == sizeof(GLfloat),
00356 "Big problems: we don't agree with OpenGL on sizeof(float)!");
00357 ASSERT(sizeof(double) == sizeof(GLdouble),
00358 "Big problems: we don't agree with OpenGL on sizeof(double)!");
00359 ASSERT(sizeof(byte_t) == sizeof(GLbyte),
00360 "Big problems: we don't agree with OpenGL on sizeof(byte)!");
00361 ASSERT(sizeof(int) == sizeof(GLuint),
00362 "Big problems: we don't agree with OpenGL on sizeof(int)!");
00363
00364
00365 ASSERT(!s_host, "Already have a host");
00366 s_host = host;
00367
00368
00369 s_glutThreadId = pthread_self();
00370
00371
00372 glutInit(&argc, (char **) argv);
00373 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
00374
00375
00376 ASSERT(!s_fullscreen, "already in fullscreen mode?");
00377 if (0 && gameModeString) {
00378 DPRINTF("game mode string: '%s'", gameModeString);
00379 {
00380 perf::Timer timer("glutEnterGameMode");
00381 glutGameModeString(gameModeString);
00382 s_fullscreen = glutEnterGameMode();
00383 }
00384 if (!s_fullscreen) {
00385 DPRINTF("Failed to enter game mode!");
00386 DPRINTF(" Falling back to windowed mode...");
00387 }
00388 }
00389 if (!s_fullscreen) {
00390 s_width = width;
00391 s_height = height;
00392 glutInitWindowSize(width, height);
00393 int win_id = glutCreateWindow(title);
00394 ASSERT(win_id > 0, "Bad window id: %d", win_id);
00395 }
00396
00397
00398 GLenum err = glewInit();
00399 if (GLEW_OK != err) {
00400 WAVE_EX(wex);
00401 wex << "Failed to initialize glew: ";
00402 wex << glewGetErrorString(err);
00403 }
00404
00405
00406 glutDisplayFunc(onDisplay);
00407 glutIdleFunc(onIdle);
00408 glutKeyboardFunc(onKeyboard);
00409 glutSpecialFunc(onSpecialKeys);
00410 glutReshapeFunc(onReshape);
00411 glutMouseFunc(onMouseButton);
00412 glutMotionFunc(onMouseMove);
00413
00414 glutCloseFunc(onExit);
00415
00416
00417 glXSwapIntervalSGI(1);
00418
00419
00420 s_host->init();
00421
00422
00423 glutMainLoop();
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 void
00435 requestTask
00436 (
00437 IO Task * task
00438 )
00439 {
00440 ASSERT(task, "null task passed to requestTask()");
00441
00442 pthread_t t_id = pthread_self();
00443 if (t_id == s_glutThreadId) {
00444
00445 task->doTask();
00446 return;
00447 }
00448
00449
00450
00451 smart_ptr<task_record_t> trec;
00452 ASSERT(!s_pendingTasks.lookup(t_id, trec),
00453 "Thread already has a pending task?");
00454 ASSERT(!s_completedTasks.lookup(t_id, trec),
00455 "Thread already has a completed task?");
00456
00457
00458 trec = new task_record_t;
00459 ASSERT(trec, "out of memory");
00460 trec->task = task;
00461 s_pendingTasks.insert(t_id, trec);
00462
00463
00464 while (!s_completedTasks.lookup(t_id, trec)) {
00465 sleep(0);
00466 }
00467 ASSERT(trec, "received null record from completed task map");
00468 s_completedTasks.remove(t_id);
00469
00470
00471 if (trec->needThrow) {
00472 WAVE_EX(wex);
00473 wex << trec->exception;
00474 }
00475 }
00476
00477
00478
00479 void
00480 drawRectLines
00481 (
00482 IN const rect3d_t& r,
00483 IN const glut_color_t& c
00484 )
00485 throw()
00486 {
00487 glColor4bv((GLbyte *) &c);
00488 glBegin(GL_LINES);
00489 point3d_t p0, p1;
00490 for (int i = 0; i < rect3d_t::eMaxEdges; ++i) {
00491 r.getEdge(i, p0, p1);
00492 glVertex3fv((GLfloat *) &p0.x);
00493 glVertex3fv((GLfloat *) &p1.x);
00494 }
00495 glEnd();
00496 }
00497
00498
00499
00500 void
00501 getModelViewMatrix
00502 (
00503 OUT matrix4_t& T
00504 )
00505 throw()
00506 {
00507 glGetFloatv(GL_MODELVIEW_MATRIX, T.m);
00508 T.transpose();
00509 }
00510
00511
00512
00513 };
00514