/*************************************************************************** File: main1A.cpp Created: 02/06/2001 Author: Maxim Garber Computer Science Department University of North Carolina - Chapel Hill garber@cs.unc.edu Description: Viewer and test app. for physically based modeling homework 1 ----------------------------------------------------------------------------. Copyright 2002 Maxim Garber UNC Collide Research Group *****************************************************************************/ #include "PBMSimScene.h" #include "PBMProjectile.h" #include "ODEEuler.h" #include "ODEMidpoint.h" #include #include #include #include #include "vec3fv.hpp" #include "x_trimodel.hpp" // viewer GLVU glvu; // simulation scene PBMSimScene* scene; bool runSimulation = 0; // cannon model X_TriModel *cannon, *base, *stick; // parameter increments float radToDeg = 57.29577951308; // conversion factor from rads to degrees float angleIncrement = 0.08726646259; float parameterIncrement = 5; // projectile parameters PBMProjectileLaunchParams params; enum IntegratorType{euler, midpoint, numIntergratorTypes}; IntegratorType integrator = euler; // timing bool fixedFrameSimulation = 0; clock_t lastTimeInstant; // used for idle function simulation int frameTime = 30; // in ms, used for fixed frame time simulation // 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 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(); // draw ground plane glColor3f(0.6,3,0.6); glBegin(GL_QUADS); glNormal3f(0 ,1, 0); glVertex3f( 1000,-0.01, 1000); glVertex3f( 1000,-0.01,-1000); glVertex3f(-1000,-0.01,-1000); glVertex3f(-1000,-0.01, 1000); glEnd(); glvu.DrawFPS(); // print text parameters unsigned int textHeight = 200; Text(5, textHeight, "PARAMETERS:"); Text(5, textHeight-=15, "azimuth: %00.0f deg ", params.azimuth*radToDeg); Text(5, textHeight-=15, "elevation: %00.0f deg ", params.elevation*radToDeg); Text(5, textHeight-=15, "powder mass: %00.0f kg ", params.powderMass); Text(5, textHeight-=15, "ball mass: %00.0f kg ", params.projectileMass); Text(5, textHeight-=15, "friction: %00.0f kg/s", params.friction); if(integrator == euler) Text(5, textHeight-=15, "integrator: euler"); else if(integrator == midpoint) Text(5, textHeight-=15, "integrator: midpoint"); if(fixedFrameSimulation) Text(5, textHeight-=15, "time step: %f s", frameTime/1000.0f); else Text(5, textHeight-=15, "time step: 1 frame"); glvu.EndFrame(); } /***************************************************************************** FUNCTION : userIdleFunc0 DESCRIPTION: Update objects and post redisplay Called as often as possible *****************************************************************************/ 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 Called every frameTime milliseconds for fixed frame simulation *****************************************************************************/ void userTimerFunc0(int timeElapsed) { if(runSimulation) { scene->Update(frameTime / 1000.0f); } glutPostRedisplay(); if(fixedFrameSimulation) glutTimerFunc(frameTime,userTimerFunc0, timeElapsed+frameTime); } /***************************************************************************** FUNCTION : userKeyboardFunc0 DESCRIPTION: my keyboard handling ruitine *****************************************************************************/ void userKeyboardFunc0(unsigned char Key, int x, int y) { switch(Key) { // launch a projectile case 'f': { PBMProjectile* projectile = new PBMProjectile(params); scene->AddObject(projectile); break; } // run simulation 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; // change integrator case 'i': integrator = (IntegratorType) ((((int)integrator)+1)% (int) numIntergratorTypes); if(integrator == euler) params.integrator = EulerSolver::InstancePtr(); else if(integrator = midpoint) params.integrator = MidpointSolver::InstancePtr(); break; // change fixed frame to variable rate simulation case 't': fixedFrameSimulation = !fixedFrameSimulation; if(fixedFrameSimulation) { // for fixed simulation speed glutTimerFunc(frameTime,userTimerFunc0, frameTime); glutIdleFunc(0); } else { // for fastest simulation speed glutIdleFunc(userIdleFunc0); } break; // decrement friction case 0x7f: params.friction -= parameterIncrement; break; }; // CALL THE DEFAULT GLVU KEYBOARD HANDLER // as long as it doesn't add inertia if(Key != 'i') 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 += parameterIncrement; break; case GLUT_KEY_PAGE_DOWN: params.powderMass -= parameterIncrement; break; // cannon projectile mass case GLUT_KEY_HOME: params.projectileMass += parameterIncrement; break; case GLUT_KEY_END: params.projectileMass -= parameterIncrement; break; // friction case GLUT_KEY_INSERT: params.friction += parameterIncrement; break; // frame time for fixed frame simulation case GLUT_KEY_F1: frameTime -= parameterIncrement; break; case GLUT_KEY_F2: frameTime += parameterIncrement; break; } } /***************************************************************************** FUNCTION : Initialize DESCRIPTION: Initialize all objects in the scene *****************************************************************************/ void Initialize() { scene = new PBMSimScene(); // initialize launch parameters Set3fv(params.gravity , 0.0f, -9.8f, 0.0f); Set3fv(params.position, 0.0f, 1.8f, 0.0f); params.azimuth = 0.0f; params.elevation = 0.0f; params.powderMass = 10.0; params.projectileMass = 50.0; params.friction = 50.0; // instantiate 2 integrators MidpointSolver::Instantiate(); // set integrator to euler params.integrator = EulerSolver::InstancePtr(); // 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("Physically Based Modeling: Homework 1", 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.5,0.6,0.8,0); // register callbacks glutDisplayFunc(userDisplayFunc0); glutKeyboardFunc(userKeyboardFunc0); glutSpecialFunc(userSpecialFunc0); if(fixedFrameSimulation) // for fixed simulation speed glutTimerFunc(frameTime,userTimerFunc0, frameTime); else // for fastest simulation speed glutIdleFunc(userIdleFunc0); // set camera position and projection parameters Vec3f ModelMin(-100,-100,-100), ModelMax(100,100,100), Eye(-10,5,0), LookAtCntr(0,0,0), Up(0,1,0); float Yfov = 45; float Aspect = 1; // width over height float Near = 0.001f; // near plane distance relative to model diagonal length float Far = 10000.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); }