/*************************************************************************** File: main1B.cpp Created: 02/08/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 1B ----------------------------------------------------------------------------. Copyright 2002 Maxim Garber UNC Collide Research Group *****************************************************************************/ #include "PBMSpringMass.h" #include "ODEEuler.h" #include "ODEMidpoint.h" #include #include #include #include #include "vec3fv.hpp" // viewer GLVU glvu; // springs PBMSpringMass *e_spring, // euler integrated spring *m_spring; // midpoint integrated spring // start and stop the simulation bool runSimulation = 0; // cannon model float parameterIncrement = 5; // projectile parameters PBMSpringMassParams params; // 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 spring *****************************************************************************/ void userDisplayFunc0() { glvu.BeginFrame(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw spring e_spring->Draw(); m_spring->Draw(); // draw a ruler int maxHeight = 20; int minHeight = -20; glColor3f(0.3f, 0.3f, 0.7f); glBegin(GL_LINES); for(int i=minHeight; i<=maxHeight;i++) { glVertex3f(-1.0f, (float) i, 0.0f); glVertex3f( 0.0f, (float) i, 0.0f); } glVertex3f(-1.0f, (float) minHeight, 0.0f); glVertex3f(-1.0f, (float) maxHeight, 0.0f); glEnd(); // draw frames per second counter glColor3f(1.0f, 1.0f, 1.0f); glvu.DrawFPS(); // print text parameters unsigned int textHeight = 200; Text(5, textHeight, "PARAMETERS:"); Text(5, textHeight-=15, "mass: %00.0f kg ", params.mass); Text(5, textHeight-=15, "spring constant: %00.0f ks/s^2 ", params.springConstant); Text(5, textHeight-=15, "friction: %00.0f kg/s ", params.friction); if(fixedFrameSimulation) Text(5, textHeight-=15, "time step: %f s", frameTime/1000.0f); else Text(5, textHeight-=15, "time step: 1 frame"); // label the two springs Text3D(0.0, 0.5, 0, "Euler"); Text3D(5.0, 0.5, 0, "Midpoint"); glvu.EndFrame(); } /***************************************************************************** FUNCTION : userIdleFunc0 DESCRIPTION: Update objects and post redisplay. Gets 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; e_spring->Update(timeElapsed); m_spring->Update(timeElapsed); } lastTimeInstant = timeInstant; glutPostRedisplay(); } /***************************************************************************** FUNCTION : userTimerFunc0 DESCRIPTION: Update objects and post redisplay Calls itself every frameTime seconds if simulation is runs on a fixed frame rate. *****************************************************************************/ void userTimerFunc0(int timeElapsed) { if(runSimulation) { e_spring->Update(frameTime / 1000.0f); m_spring->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) { // enable / disable simulation case 's': runSimulation = !runSimulation; break; // take simulation one frame at a time case ' ': // manual simulation time step if(fixedFrameSimulation) { e_spring->Update(frameTime / 1000.0f); m_spring->Update(frameTime / 1000.0f); } else { clock_t timeInstant = clock(); e_spring->Update((float) (timeInstant - lastTimeInstant) / CLOCKS_PER_SEC); m_spring->Update((float) (timeInstant - lastTimeInstant) / CLOCKS_PER_SEC); lastTimeInstant = timeInstant; glutPostRedisplay(); } 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; // decrease friction case 0x7f: params.friction -= parameterIncrement; e_spring->SetFriction(params.friction); m_spring->SetFriction(params.friction); 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) { // change mass case GLUT_KEY_PAGE_UP: params.mass += 1; e_spring->SetMass(params.mass); m_spring->SetMass(params.mass); break; case GLUT_KEY_PAGE_DOWN: params.mass -= 1; e_spring->SetMass(params.mass); m_spring->SetMass(params.mass); break; // change spring constant case GLUT_KEY_HOME: params.springConstant += parameterIncrement; e_spring->SetSpringConstant(params.springConstant); m_spring->SetSpringConstant(params.springConstant); break; case GLUT_KEY_END: params.springConstant -= parameterIncrement; e_spring->SetSpringConstant(params.springConstant); m_spring->SetSpringConstant(params.springConstant); break; // increase friction case GLUT_KEY_INSERT: params.friction += parameterIncrement; e_spring->SetFriction(params.friction); m_spring->SetFriction(params.friction); break; // change frame rate of 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 spring *****************************************************************************/ void Initialize() { // initialize spring parameters Set3fv(params.gravity , 0.0f, -9.8f, 0.0f); Set3fv(params.position, 0.0f, -1.0f, 0.0f); Set3fv(params.anchor, 0.0f, 0.0f, 0.0f); params.restLength = 1.0f; params.mass = 5.0f; params.springConstant = 15.0f; params.friction = 0.0f; // instantiate integrators // - midpoint already instantiates euler integrator MidpointSolver::Instantiate(); // set integrator to euler params.integrator = EulerSolver::InstancePtr(); e_spring = new PBMSpringMass(params); // set integrator to midpint Set3fv(params.position, 5.0f, -1.0f, 0.0f); Set3fv(params.anchor, 5.0f, 0.0f, 0.0f); params.integrator = MidpointSolver::InstancePtr(); m_spring = new PBMSpringMass(params); } /***************************************************************************** FUNCTION : main DESCRIPTION: Init viewer and start main loop *****************************************************************************/ void main() { // initialize the viewer glvu.Init("Physically Based Modeling: Homework 1B", GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA, // buffers 50,50,512,512); // screen position and size // remove inertia in camera model glvu.Keyboard('i',0,0); // initialize spring 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 ( 0, 0, 20), 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 springs delete(e_spring); delete(m_spring); }