/*************************************************************************** File: main.cpp Created: 01/04/2002 Author: Maxim Garber Computer Science Department University of North Carolina - Chapel Hill garber@cs.unc.edu Description: Scene viewer. ----------------------------------------------------------------------------. Copyright 2002 Maxim Garber *****************************************************************************/ #include "SimScene.h" #include "ProjectileLaunchParams.h" #include "x_trimodel.hpp" #include "SnapShot.hpp" #include "stopwatch.hpp" #include #include #include #include // viewer GLVU glvu; // scene SimScene* scene; bool runSimulation = 0; // cannon model X_TriModel *cannon, *base, *stick; // projectile parameters ProjectileLaunchParams params; // parameter increments float radToDeg = 57.29577951308; // conversion factor from rads to degrees float angleIncrement = 0.08726646259; float parameterIncrement = 5; // ground plane int groundSize = 50; int gridSpacing = 5; // screen capture bool snapShots = false; // timing bool fixedFrameSimulation = 0; clock_t lastTimeInstant; // used for idle function simulation int frameTime = 25; // in ms, used for fixed frame time simulation Stopwatch simulationTimer; // times simulation without screen capture for accurate MPEGS // lighting float lightPosition[4] = {10, 10, 10,1}; /***************************************************************************** FUNCTION : userDisplayFunc0 DESCRIPTION: Displays the hockey scene *****************************************************************************/ void userDisplayFunc0() { glvu.BeginFrame(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw ground plane glNormal3f(0 ,1, 0); for(int i=-50; i<50; i++) { glColor3f(0.3f,0.6f,0.3f); glBegin(GL_TRIANGLE_STRIP); for(int j=-50; j<50; j++) { glVertex3f((float)i, -0.03, (float)j); glVertex3f((float)i+1,-0.03, (float)j); } glEnd(); if(i%gridSpacing == 0) { glColor3f(0.1f,1.0f,0.1f); glBegin(GL_LINES); for(j=-50; j<50; j+= gridSpacing) { glVertex3f((float)i, 0.0, (float)j ); glVertex3f((float)i+gridSpacing,0.0, (float)j ); glVertex3f((float)i, 0.0, (float)j ); glVertex3f((float)i, 0.0, (float)j+gridSpacing); } glEnd(); } } // draw scene scene->Draw(); // draw cannon and base glEnable(GL_NORMALIZE); glPushMatrix(); glTranslatef(0, 1.8, 0); glPushMatrix(); glRotatef(-90, 1, 0, 0); glColor3f(0.9f,0.6f,0.6f); stick->Render(); glPopMatrix(); glRotatef(90-params.azimuth*radToDeg, 0, 1, 0); glRotatef(-90, 1, 0, 0); glColor3f(0.7f,0.4f,0.4f); base->Render(); glRotatef(-params.elevation*radToDeg, 1, 0, 0); glColor3f(0.3f,0.3f,0.3f); cannon->Render(); glPopMatrix(); // print text parameters glColor3f(1.0f,1.0f,1.0f); unsigned int textHeight = 130; Text(5, textHeight, "PARAMETERS:"); Text(5, textHeight-=15, "azimuth: %00.0f deg [left/right arrows]", params.azimuth*radToDeg); Text(5, textHeight-=15, "elevation: %00.0f deg [up/down arrows]", params.elevation*radToDeg); Text(5, textHeight-=15, "powder mass: %00.0f kg [PageUp / PageDown]", params.powderMass); Text(5, textHeight-=25, "[s] to begin simulation"); Text(5, textHeight-=15, "[f] to fire cannon"); //Text(5, 5, "FPS: %00.0f", 1/simulationTimer.GetTime()); //simulationTimer.Reset(); glvu.DrawFPS(); glvu.EndFrame(); // take screen capture if(snapShots) { simulationTimer.Stop(); SnapShot(); simulationTimer.Start(); } } /***************************************************************************** FUNCTION : userKeyboardFunc0 DESCRIPTION: my keyboard handling ruitine *****************************************************************************/ void userKeyboardFunc0(unsigned char Key, int x, int y) { switch(Key) { // capture the screen case 'c': { snapShots = !snapShots; break; } // launch a projectile case 'f': { SimSphere* projectile = new SimSphere("ball.txt"); projectile->Launch(params); scene->AddSphere(projectile); break; } case 's': runSimulation = !runSimulation; break; case ' ': // manual simulation time step if(fixedFrameSimulation) { scene->Update(frameTime / 1000.0f); } else { clock_t timeInstant = clock(); scene->Update((float) (timeInstant - lastTimeInstant) / CLOCKS_PER_SEC); lastTimeInstant = timeInstant; glutPostRedisplay(); } break; }; // OPTIONAL: CALL THE DEFAULT GLVU KEYBOARD HANDLER glvu.Keyboard(Key,x,y); glutPostRedisplay(); } /***************************************************************************** FUNCTION : userSpecialFunc0 DESCRIPTION: my special keyhandling ruitine *****************************************************************************/ void userSpecialFunc0(int Key, int x, int y) { switch(Key) { // cannon direction case GLUT_KEY_LEFT: params.azimuth -= angleIncrement; break; case GLUT_KEY_RIGHT: params.azimuth += angleIncrement; break; case GLUT_KEY_UP: params.elevation += angleIncrement; break; case GLUT_KEY_DOWN: params.elevation -= angleIncrement; break; // cannon powder mass case GLUT_KEY_PAGE_UP: params.powderMass += 1; break; case GLUT_KEY_PAGE_DOWN: params.powderMass -= 1; break; } } /***************************************************************************** FUNCTION : userIdleFunc0 DESCRIPTION: update objects and post redisplay *****************************************************************************/ void userIdleFunc0() { clock_t timeInstant = clock(); if(runSimulation) { float timeElapsed = (float) (timeInstant - lastTimeInstant) / CLOCKS_PER_SEC; if(timeElapsed > 0.03) timeElapsed = 0.03; scene->Update(timeElapsed); } lastTimeInstant = timeInstant; glutPostRedisplay(); } /***************************************************************************** FUNCTION : userTimerFunc0 DESCRIPTION: update objects and post redisplay *****************************************************************************/ void userTimerFunc0(int timeElapsed) { if(runSimulation) { scene->Update(frameTime / 1000.0f); } glutPostRedisplay(); glutTimerFunc(frameTime,userTimerFunc0, timeElapsed+frameTime); } /***************************************************************************** FUNCTION : Initialize DESCRIPTION: Initialize all objects in the scene *****************************************************************************/ void Initialize() { scene = new SimScene("scene.txt"); // initialize launch parameters Set3fv(params.position, 0.0f, 1.8f, 0.0f); params.azimuth = 0.0f; params.elevation = 0.0f; params.powderMass = 10.0; // load models for cannon and base cannon = new X_TriModel("cannon.x"); base = new X_TriModel("base.x"); stick = new X_TriModel("stick.x"); } /***************************************************************************** FUNCTION : main DESCRIPTION: Init viewer and start main loop *****************************************************************************/ void main() { // initialize the viewer glvu.Init("Cloth Scene Demo App", GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA, // buffers 50,50,512,512); // screen position and size // remove inertia from camera model glvu.Keyboard('i',0,0); // initialize objects in scene Initialize(); // set openGL material and lighting state glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glClearColor(0,0,0,0); // register callbacks glutDisplayFunc(userDisplayFunc0); glutKeyboardFunc(userKeyboardFunc0); glutSpecialFunc(userSpecialFunc0); if(fixedFrameSimulation) // for fixed simulation spped at 60fps. glutTimerFunc(frameTime,userTimerFunc0, frameTime); else // for fastest simulation speed glutIdleFunc(userIdleFunc0); // initailize timer simulationTimer.Start(); // set camera position and projection parameters Vec3f ModelMin(-10,-10,-10), ModelMax(10,10,10), Eye(-20,10,0), LookAtCntr(0,0,0), Up(0,1,0); float Yfov = 45; float Aspect = 1; // width over height float Near = 0.1f; // near plane distance relative to model diagonal length float Far = 10.0f; // far plane distance (also relative) glvu.SetAllCams(ModelMin,ModelMax, Eye,LookAtCntr,Up, Yfov,Aspect, Near,Far); // frame per second clock glvu.StartFPSClock(); lastTimeInstant = 0; // start event loop glutMainLoop(); // delete collision sphere delete(scene); }