00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "common/math/real.h"
00024 #include "common/math/vector3.h"
00025 #include "iframeworkapp.h"
00026 #include "sceneorbiter.h"
00027
00028 #include <cassert>
00029 #include <cstdlib>
00030 #include <GL/glut.h>
00031 #include <IL/il.h>
00032 #include <IL/ilu.h>
00033 #include <IL/ilut.h>
00034
00035 using namespace sheep;
00036 using namespace std;
00037
00038 const Real TUMBLING_SPEED = 3.0;
00039 const Real TRACKING_SPEED = 10.0;
00040 const Real DOLLYING_SPEED = 8.0;
00041
00042 IFrameworkApp *g_app;
00043
00044 int g_argc;
00045 char **g_argv;
00046
00047 GLuint g_grid_list;
00048
00049 int g_width, g_height;
00050 int g_old_width, g_old_height;
00051
00052 bool g_is_fullscreen = false;
00053 bool g_display_grid = true;
00054 bool g_use_freelook = false;
00055 bool g_in_step_mode = true;
00056 bool g_take_step = false;
00057
00058 void reset();
00059 void print_help();
00060
00061 void reshape(int width, int height) {
00062 g_width = width;
00063 g_height = height;
00064
00065 g_app->Reshape(width, height);
00066 }
00067
00068 void keyboard(unsigned char key, int x, int y) {
00069 switch(key) {
00070
00071 case 'f':
00072 if(g_is_fullscreen) {
00073 glutReshapeWindow(g_old_width, g_old_height);
00074 glutPositionWindow(50, 50);
00075 g_is_fullscreen = false;
00076 } else {
00077 g_old_width = g_width;
00078 g_old_height = g_height;
00079 glutFullScreen();
00080 g_is_fullscreen = true;
00081 }
00082 break;
00083
00084
00085 case 'g':
00086 g_display_grid ^= true;
00087 break;
00088
00089
00090 case 'h':
00091 print_help();
00092 break;
00093
00094
00095 case 'l':
00096 g_use_freelook ^= true;
00097 break;
00098
00099
00100 case 'q':
00101 exit(0);
00102 break;
00103
00104
00105 case 'r':
00106 reset();
00107 break;
00108
00109
00110 case 's':
00111 g_in_step_mode ^= true;
00112 if(g_in_step_mode)
00113 g_take_step = false;
00114 break;
00115
00116
00117 case 'v':
00118 if(!g_app->m_orbiter.IsDragging()) {
00119 g_app->m_orbiter.Configure(
00120 Vector3(0.0),
00121 DEFAULT_AZIMUTH,
00122 DEFAULT_ELEVATION,
00123 DEFAULT_DISTANCE);
00124 }
00125 break;
00126
00127
00128 case ' ':
00129 if(g_in_step_mode)
00130 g_take_step = true;
00131 break;
00132
00133
00134 case 27:
00135 if(g_app->m_orbiter.IsDragging())
00136 g_app->m_orbiter.CancelDrag();
00137 break;
00138
00139
00140 default:
00141 g_app->KeyPressed(key);
00142 }
00143 }
00144
00145 void special(int key, int x, int y) {
00146 switch(key) {
00147 case GLUT_KEY_UP:
00148 if(g_use_freelook) {
00149 g_app->m_orbiter.SetCenter(g_app->m_orbiter.GetCenter()
00150 + (g_app->m_orbiter.GetCenter() - g_app->m_orbiter.GetEyePosition()).Normalized());
00151 }
00152 break;
00153 case GLUT_KEY_DOWN:
00154 if(g_use_freelook) {
00155 g_app->m_orbiter.SetCenter(g_app->m_orbiter.GetCenter()
00156 - (g_app->m_orbiter.GetCenter() - g_app->m_orbiter.GetEyePosition()).Normalized());
00157 }
00158 break;
00159 }
00160 }
00161
00162 Vector2 convert_mouse_to_ndc(int x, int y) {
00163 Vector2 ndc;
00164
00165
00166 ndc.m_x = 2.0 * static_cast<Real>(x) / (g_width - 1) - 1.0;
00167 ndc.m_y = 1.0 - 2.0 * static_cast<Real>(y) / (g_height - 1);
00168
00169 ndc.m_y *= static_cast<Real>(g_height) / g_width;
00170
00171 return ndc;
00172 }
00173
00174 void mouse(int button, int state, int x, int y) {
00175 if(state == GLUT_UP) {
00176 if(g_app->m_orbiter.IsDragging())
00177 g_app->m_orbiter.EndDrag();
00178 return;
00179 }
00180
00181 assert(state == GLUT_DOWN);
00182
00183
00184 if(g_app->m_orbiter.IsDragging())
00185 return;
00186
00187 if(g_use_freelook) {
00188 if(button == GLUT_LEFT_BUTTON) {
00189 g_app->m_orbiter.BeginDrag(
00190 SceneOrbiter::Movement::TUMBLE,
00191 convert_mouse_to_ndc(x, y) * TUMBLING_SPEED);
00192 }
00193 } else {
00194 const int modifiers = glutGetModifiers();
00195 const Vector2 mp = convert_mouse_to_ndc(x, y);
00196
00197 switch(button) {
00198
00199
00200
00201 case GLUT_LEFT_BUTTON:
00202 if(modifiers == GLUT_ACTIVE_CTRL)
00203 g_app->m_orbiter.BeginDrag(SceneOrbiter::Movement::TUMBLE, mp * TUMBLING_SPEED);
00204 else if(modifiers == GLUT_ACTIVE_ALT)
00205 g_app->m_orbiter.BeginDrag(SceneOrbiter::Movement::TRACK, mp * TRACKING_SPEED);
00206 break;
00207
00208
00209 case GLUT_MIDDLE_BUTTON:
00210 if(modifiers == GLUT_ACTIVE_CTRL)
00211 g_app->m_orbiter.BeginDrag(SceneOrbiter::Movement::TRACK, mp * TRACKING_SPEED);
00212 break;
00213
00214
00215 case GLUT_RIGHT_BUTTON:
00216 if(modifiers == GLUT_ACTIVE_CTRL)
00217 g_app->m_orbiter.BeginDrag(SceneOrbiter::Movement::DOLLY, mp * DOLLYING_SPEED);
00218 break;
00219
00220 }
00221 }
00222 }
00223
00224 void motion(int x, int y) {
00225 if(g_app->m_orbiter.IsDragging()) {
00226 Vector2 mp = convert_mouse_to_ndc(x, y);
00227
00228 if(g_app->m_orbiter.IsTumbling())
00229 mp *= TUMBLING_SPEED;
00230 else if(g_app->m_orbiter.IsTracking())
00231 mp *= TRACKING_SPEED;
00232 else if(g_app->m_orbiter.IsDollying())
00233 mp *= DOLLYING_SPEED;
00234
00235 g_app->m_orbiter.UpdateDrag(mp);
00236 }
00237 }
00238
00239 void think(int ) {
00240 glutTimerFunc((unsigned int)(1000.0 / THINK_RATE), think, 0);
00241
00242 if(g_in_step_mode) {
00243 if(g_take_step) {
00244 g_app->Think();
00245 g_take_step = false;
00246 }
00247 } else g_app->Think();
00248 }
00249
00250 void update_screen(int ) {
00251 glutTimerFunc((unsigned int)(1000.0 / FRAME_RATE), update_screen, 0);
00252
00253
00254 glutPostRedisplay();
00255 }
00256
00257 void draw_grid() {
00258 const int GRID_HALF_SIZE = 12;
00259 const Real GRID_SPACING = 1.0;
00260
00261 glEnable(GL_DEPTH_TEST);
00262
00263 glLineWidth(1.0f);
00264 glColor3f(0.5f, 0.5f, 0.5f);
00265
00266 glBegin(GL_LINES);
00267
00268 for(int i = 0; i < GRID_HALF_SIZE; ++i) {
00269 Real k = (i + 1) * GRID_SPACING;
00270
00271 glVertex3f(-GRID_HALF_SIZE * GRID_SPACING, 0.0f, k);
00272 glVertex3f(GRID_HALF_SIZE * GRID_SPACING, 0.0f, k);
00273
00274 glVertex3f(-GRID_HALF_SIZE * GRID_SPACING, 0.0f, -k);
00275 glVertex3f(GRID_HALF_SIZE * GRID_SPACING, 0.0f, -k);
00276
00277 glVertex3f(k, 0.0f, -GRID_HALF_SIZE * GRID_SPACING);
00278 glVertex3f(k, 0.0f, GRID_HALF_SIZE * GRID_SPACING);
00279
00280 glVertex3f(-k, 0.0f, -GRID_HALF_SIZE * GRID_SPACING);
00281 glVertex3f(-k, 0.0f, GRID_HALF_SIZE * GRID_SPACING);
00282 }
00283
00284 glEnd();
00285
00286
00287
00288 glLineWidth(2.0f);
00289 glColor3f(0.0f, 0.0f, 0.0f);
00290
00291 glBegin(GL_LINES);
00292 glVertex3f(-GRID_HALF_SIZE * GRID_SPACING, 0.0f, 0.0f);
00293 glVertex3f(GRID_HALF_SIZE * GRID_SPACING, 0.0f, 0.0f);
00294
00295 glVertex3f(0.0f, 0.0f, -GRID_HALF_SIZE * GRID_SPACING);
00296 glVertex3f(0.0f, 0.0f, GRID_HALF_SIZE * GRID_SPACING);
00297 glEnd();
00298 }
00299
00300 void draw_axis() {
00301 const GLfloat TOLERANCE = g_app->m_orbiter.GetDistance() / 1000.0f;
00302 const GLfloat LENGTH = g_app->m_orbiter.GetDistance() / 20.0f;
00303
00304 glLineWidth(2.0f);
00305
00306 glBegin(GL_LINES);
00307
00308 glColor3f(1.0f, 0.0f, 0.0f);
00309 glVertex3f(0.0f, TOLERANCE, TOLERANCE);
00310 glVertex3f(LENGTH, TOLERANCE, TOLERANCE);
00311
00312
00313 glColor3f(0.0f, 1.0f, 0.0f);
00314 glVertex3f(TOLERANCE, 0.0f, TOLERANCE);
00315 glVertex3f(TOLERANCE, LENGTH, TOLERANCE);
00316
00317
00318 glColor3f(0.0f, 0.0f, 1.0f);
00319 glVertex3f(TOLERANCE, TOLERANCE, 0.0f);
00320 glVertex3f(TOLERANCE, TOLERANCE, LENGTH);
00321 glEnd();
00322 }
00323
00324 void draw_dragging_axis() {
00325 const GLfloat LENGTH = g_app->m_orbiter.GetDistance() / 30.0f;
00326
00327 glLineWidth(2.0f);
00328 glColor3f(0.3f, 0.3f, 0.3f);
00329
00330 glBegin(GL_LINES);
00331 glVertex3f(0.0f, 0.0f, 0.0f);
00332 glVertex3f(LENGTH, 0.0f, 0.0f);
00333
00334 glVertex3f(0.0f, 0.0f, 0.0f);
00335 glVertex3f(0.0f, LENGTH, 0.0f);
00336
00337 glVertex3f(0.0f, 0.0f, 0.0f);
00338 glVertex3f(0.0f, 0.0f, LENGTH);
00339 glEnd();
00340 }
00341
00342 void display() {
00343 glClearColor(0.63f, 0.63f, 0.63f, 0.0f);
00344 glClearDepth(1.0);
00345
00346 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00347
00348 glMatrixMode(GL_MODELVIEW);
00349 glLoadIdentity();
00350
00351 glTranslatef(0.0f, 0.0f, -g_app->m_orbiter.GetDistance());
00352 glRotatef(rtod(g_app->m_orbiter.GetElevation()), 1.0f, 0.0f, 0.0f);
00353 glRotatef(rtod(g_app->m_orbiter.GetAzimuth() - PI / 2.0), 0.0f, 1.0f, 0.0f);
00354
00355 glPushMatrix();
00356
00357 const Point3 center = g_app->m_orbiter.GetCenter();
00358 glTranslatef(-center.m_x, -center.m_y, -center.m_z);
00359
00360 glDisable(GL_LIGHTING);
00361 glDisable(GL_TEXTURE_2D);
00362 glEnable(GL_DEPTH_TEST);
00363
00364
00365 if(g_display_grid)
00366 glCallList(g_grid_list);
00367
00368
00369 draw_axis();
00370
00371
00372 g_app->Render();
00373
00374 glPopMatrix();
00375
00376
00377 if(g_app->m_orbiter.IsDragging()) {
00378 glDisable(GL_LIGHTING);
00379 glDisable(GL_TEXTURE_2D);
00380 glDisable(GL_DEPTH_TEST);
00381 draw_dragging_axis();
00382 }
00383
00384 glutSwapBuffers();
00385 }
00386
00387 void shutdown() {
00388 delete g_app;
00389 }
00390
00391 void reset() {
00392 delete g_app;
00393
00394 g_app = new_frameworkapp(g_argc, g_argv);
00395
00396 assert(g_app);
00397 }
00398
00399 void print_disclaimer() {
00400 cout << "Sheep - A Rigid Body Dynamics Engine" << endl;
00401 cout << "Copyright (C) 2001-2004 Francois Beaune" << endl << endl;
00402 cout << "Visit http://sheepengine.sourceforge.net/ for more information." << endl;
00403 cout << endl;
00404 }
00405
00406 void print_help() {
00407 cout << endl;
00408 cout << "Hold the CTRL key and use your mouse to manipulate the scene:" << endl;
00409 cout << " CTRL + left button: tumble" << endl;
00410 cout << " CTRL + middle button: track" << endl;
00411 cout << " CTRL + right button: dolly" << endl;
00412 cout << endl;
00413
00414 cout << "You can also use the ALT + left button combination to tumble." << endl;
00415 cout << endl;
00416
00417 cout << "Available keys:" << endl;
00418 cout << " f: toggle full screen mode" << endl;
00419 cout << " g: toggle grid display" << endl;
00420 cout << " h: display this help" << endl;
00421 cout << " l: toggle free look mode" << endl;
00422 cout << " q: quit" << endl;
00423 cout << " r: reset" << endl;
00424 cout << " s: toogle 'step by step' mode" << endl;
00425 cout << " v: reset the view" << endl;
00426 cout << " SPACE: take a step (only in 'step by step' mode)" << endl;
00427 cout << " ESCAPE: cancel drag movement" << endl;
00428 cout << endl;
00429
00430 cout << "Application-specific keys:" << endl;
00431
00432 g_app->PrintHelp();
00433
00434 cout << endl;
00435 }
00436
00437 int main(int argc, char **argv) {
00438 print_disclaimer();
00439
00440 g_argc = argc;
00441 g_argv = argv;
00442
00443
00444 glutInit(&argc, argv);
00445 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
00446
00447
00448 glutInitWindowPosition(50, 50);
00449 glutInitWindowSize(640, 480);
00450 glutCreateWindow(argv[0]);
00451 glutDisplayFunc(display);
00452 glutReshapeFunc(reshape);
00453 glutKeyboardFunc(keyboard);
00454 glutSpecialFunc(special);
00455 glutMouseFunc(mouse);
00456 glutMotionFunc(motion);
00457
00458
00459 ilInit();
00460 iluInit();
00461 ilutRenderer(ILUT_OPENGL);
00462
00463
00464 g_grid_list = glGenLists(1);
00465 glNewList(g_grid_list, GL_COMPILE);
00466 draw_grid();
00467 glEndList();
00468
00469
00470 g_app = 0;
00471 reset();
00472 print_help();
00473
00474
00475 atexit(shutdown);
00476
00477
00478 glutTimerFunc((unsigned int)(1000.0 / FRAME_RATE), update_screen, 0);
00479 glutTimerFunc((unsigned int)(1000.0 / THINK_RATE), think, 0);
00480
00481 glutMainLoop();
00482
00483 return 0;
00484 }