/*************************************************************************** File: main.cpp Created: 04/01/2002 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 3 ----------------------------------------------------------------------------. Copyright 2002 Maxim Garber UNC Collide Research Group *****************************************************************************/ #include #include #include #include #include "vec3fv.hpp" #include "ODEMidpoint.h" #include "PBMCircleParticle.h" // viewer GLVU glvu; // constrained particle PBMCircleParticle* particle; bool runSimulation = false; enum IntegratorType{euler, midpoint, numIntergratorTypes}; IntegratorType integrator = euler; // directional added force attractor float attractorDir[2] = {0, 0}; bool attractorOn = false; float attractorMagnitude = 10; // 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 : AddAttractorForce DESCRIPTION: Adds the force of an attractor to the particle *****************************************************************************/ void AddAttractorForce() { if(attractorOn) { float force[2]; force[0] = attractorMagnitude * attractorDir[0]; force[1] = attractorMagnitude * attractorDir[1]; particle->AddForce(force); } } /***************************************************************************** FUNCTION : userDisplayFunc0 DESCRIPTION: Displays the hockey scene *****************************************************************************/ void userDisplayFunc0() { glvu.BeginFrame(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ///////////////////////////////////////////////////////////////////////// // draw the particle particle->Draw(); ///////////////////////////////////////////////////////////////////////// // draw forces float arrowWidth = 0.1, arrowLength = 0.5, arrowOffset = 0.25; glDisable(GL_LIGHTING); glBegin(GL_TRIANGLES); // draw gravity glColor3f(0.8f, 0.2f, 0.2f); glVertex3f(-arrowWidth, 0.0f, 0.0f); glVertex3f(0.0f, - arrowLength, 0.0f); glVertex3f( arrowWidth, 0.0f, 0.0f); // draw attractor force if(attractorOn) { glColor3f(0.2f, 0.2f, 0.8f); glVertex3f(arrowWidth*attractorDir[1], -arrowWidth*attractorDir[0], 0.0f); glVertex3f(arrowLength*(attractorMagnitude/9.8)*attractorDir[0], arrowLength*(attractorMagnitude/9.8)*attractorDir[1], 0.0f); glVertex3f(-arrowWidth*attractorDir[1], arrowWidth*attractorDir[0], 0.0f); } glEnd(); /////////////////////////////////////////////////////////////////////////// // draw a ruler float maxHeight = 3; float minHeight = -3; glColor3f(0.3f, 0.3f, 0.7f); glBegin(GL_LINES); for(float i=minHeight; i<=maxHeight;i+=0.5) { glVertex3f(-1.0f, i, 0.0f); glVertex3f( 0.0f, i, 0.0f); } glVertex3f(-1.0f, minHeight, 0.0f); glVertex3f(-1.0f, maxHeight, 0.0f); glEnd(); glEnable(GL_LIGHTING); /////////////////////////////////////////////////////////////////////////// // draw frames per second counter glColor3f(1.0f, 1.0f, 1.0f); glvu.DrawFPS(); ////////////////////////////////////////////////////////////////////////// // print text parameters unsigned int textHeight = 100; Text(5, textHeight , "STATE"); Text(5, textHeight-15, "====="); float x, y; particle->GetParticlePosition(x, y); Text(5, textHeight-=15, "particle postion: (%2.2f, %2.2f)", x, y); Text(5, textHeight-=15, "particle angle: %2.2f ", particle->GetTheta()); if(attractorOn) Text(5, textHeight-=15, "attractor magnitude: %2.2f ", attractorMagnitude); 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: %2.2 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; // update scene AddAttractorForce(); particle->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) { AddAttractorForce(); particle->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 force attractor case 'f': attractorOn = !attractorOn; break; // run simulation case 's': runSimulation = !runSimulation; break; case ' ': // manual simulation time step if(fixedFrameSimulation) { AddAttractorForce(); particle->Update(frameTime / 1000.0f); } else { clock_t timeInstant = clock(); AddAttractorForce(); particle->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) particle->SetSolver(EulerSolver::InstancePtr()); else if(integrator = midpoint) particle->SetSolver(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; }; // 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) { float forceIncrement = 2; float radiusIncrement = 0.5; switch(Key) { case GLUT_KEY_UP: attractorMagnitude += forceIncrement; break; case GLUT_KEY_DOWN: attractorMagnitude -= forceIncrement; break; case GLUT_KEY_PAGE_UP: particle->SetCircleRadius(particle->GetCircleRadius() + radiusIncrement); break; case GLUT_KEY_PAGE_DOWN: particle->SetCircleRadius(particle->GetCircleRadius() - radiusIncrement); if(particle->GetCircleRadius() <= 0) particle->SetCircleRadius(radiusIncrement); break; } } /***************************************************************************** FUNCTION : userSpecialFunc0 DESCRIPTION: my mouse motion ruitine *****************************************************************************/ void userPassiveMotionFunc0(int x, int y) { float width = glutGet(GLUT_WINDOW_WIDTH ); float height = glutGet(GLUT_WINDOW_HEIGHT); attractorDir[0] = (x - width /2.0)/width ; attractorDir[1] = -(y - height/2.0)/height; // normalize float length = sqrtf(attractorDir[0]*attractorDir[0] + attractorDir[1]*attractorDir[1]); attractorDir[0] /= length; attractorDir[1] /= length; } /***************************************************************************** FUNCTION : Initialize DESCRIPTION: Initialize all objects in the scene *****************************************************************************/ void Initialize() { // initialize integrator MidpointSolver::Instantiate(); // inialize particle float center[2] = {0.0, 0.0}; particle = new PBMCircleParticle(center, 1.0, 0.0, 1.0, 0.98, EulerSolver::InstancePtr()); } /*********************************************************** ****************** FUNCTION : main DESCRIPTION: Init viewer and start main loop *****************************************************************************/ void main() { // initialize the viewer glvu.Init("Physically Based Modeling: Homework 3", 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 ); glutPassiveMotionFunc(userPassiveMotionFunc0); 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(-10,-10,-10), ModelMax(10,10,10), Eye(0,0,10), 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(); }