Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

main.cpp

Go to the documentation of this file.
00001 /*
00002     Sheep - A Rigid Body Dynamics Engine
00003     Copyright (C) 2001-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of Sheep.
00007 
00008     Sheep is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     Sheep is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with Sheep; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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     // f: toggle full screen mode.
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     // g: toggle grid display.
00085     case 'g':
00086         g_display_grid ^= true;
00087         break;
00088 
00089     // h: help.
00090     case 'h':
00091         print_help();
00092         break;
00093 
00094     // l: toggle free look mode.
00095     case 'l':
00096         g_use_freelook ^= true;
00097         break;
00098 
00099     // q: quit.
00100     case 'q':
00101         exit(0);    // GLUT programs should use exit() routine to quit
00102         break;
00103 
00104     // r: reset.
00105     case 'r':
00106         reset();
00107         break;
00108 
00109     // s: toggle 'step by step' mode.
00110     case 's':
00111         g_in_step_mode ^= true;
00112         if(g_in_step_mode)
00113             g_take_step = false;
00114         break;
00115 
00116     // v: reset the view.
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     // SPACE: take a step (only available in 'step by step' mode).
00128     case ' ':
00129         if(g_in_step_mode)
00130             g_take_step = true;
00131         break;
00132 
00133     // ESCAPE: cancel drag movement.
00134     case 27:
00135         if(g_app->m_orbiter.IsDragging())
00136             g_app->m_orbiter.CancelDrag();
00137         break;
00138 
00139     // Let the application handle any other key.
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     // Mouse coordinates are upside down.
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     // Already dragging.
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         // Left button with CTRL only: tumble.
00200         // Left button with ALT only: track.
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         // Middle button with CTRL only: track.
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         // Right button with CTRL only: dolly.
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 /*value*/) {
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 /*value*/) {
00251     glutTimerFunc((unsigned int)(1000.0 / FRAME_RATE), update_screen, 0);
00252 
00253     // Force screen update.
00254     glutPostRedisplay();
00255 }
00256 
00257 void draw_grid() {
00258     const int GRID_HALF_SIZE = 12;  // half the number of cells in each direction
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     // Main axes.
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         // X axis in red.
00308         glColor3f(1.0f, 0.0f, 0.0f);
00309         glVertex3f(0.0f, TOLERANCE, TOLERANCE);
00310         glVertex3f(LENGTH, TOLERANCE, TOLERANCE);
00311 
00312         // Y axis in green.
00313         glColor3f(0.0f, 1.0f, 0.0f);
00314         glVertex3f(TOLERANCE, 0.0f, TOLERANCE);
00315         glVertex3f(TOLERANCE, LENGTH, TOLERANCE);
00316 
00317         // Z axis in blue.
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     // Draw the grid.
00365     if(g_display_grid)
00366         glCallList(g_grid_list);
00367 
00368     // Draw the X, Y and Z axis.
00369     draw_axis();
00370 
00371     // Let the application do some rendering.
00372     g_app->Render();
00373 
00374     glPopMatrix();
00375 
00376     // Draw the dragging axis if dragging.
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     // Initialize GLUT.
00444     glutInit(&argc, argv);
00445     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
00446 
00447     // Create and configure the display window.
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     // Initialize DevIL.
00459     ilInit();
00460     iluInit();
00461     ilutRenderer(ILUT_OPENGL);
00462 
00463     // Create the grid display list.
00464     g_grid_list = glGenLists(1);
00465     glNewList(g_grid_list, GL_COMPILE);
00466     draw_grid();
00467     glEndList();
00468 
00469     // Create the client application.
00470     g_app = 0;
00471     reset();
00472     print_help();
00473 
00474     // Register an exit callback.
00475     atexit(shutdown);
00476 
00477     // Start the timers.
00478     glutTimerFunc((unsigned int)(1000.0 / FRAME_RATE), update_screen, 0);
00479     glutTimerFunc((unsigned int)(1000.0 / THINK_RATE), think, 0);
00480 
00481     glutMainLoop(); // never returns
00482 
00483     return 0;
00484 }

Generated on Tue May 11 01:31:50 2004 for toxic by doxygen 1.3.6