|
World of Rigid Bodies (WoRB)
|
00001 #ifndef _WORB_UTILITIES_H_INCLUDED 00002 #define _WORB_UTILITIES_H_INCLUDED 00003 00004 /** 00005 * @file Utilities.h 00006 * @brief Declarations for various GLUT utilites for a rigid body application. 00007 * @author Mikica B Kocic 00008 * @version 0.2 00009 * @date 2012-05-10 00010 * @copyright GNU Public License. 00011 */ 00012 00013 #include "WoRB.h" 00014 00015 ///////////////////////////////////////////////////////////////////////////////////////// 00016 // Include Freeglut 00017 00018 /** Disable GLUT ataxit workaround on windows. 00019 * 00020 * Win32 has an annoying issue where there are multiple C run-time 00021 * libraries (CRTs). If the executable is linked with a different CRT 00022 * from the GLUT DLL, the GLUT DLL will not share the same CRT static 00023 * data seen by the executable. In particular, atexit callbacks registered 00024 * in the executable will not be called if GLUT calls its (different) 00025 * exit routine). GLUT is typically built with the 00026 * "/MD" option (the CRT with multithreading DLL support), but the Visual 00027 * C++ linker default is "/ML" (the single threaded CRT). 00028 * 00029 * One workaround to this issue is requiring users to always link with 00030 * the same CRT as GLUT is compiled with. That requires users supply a 00031 * non-standard option. GLUT 3.7 has its own built-in workaround where 00032 * the executable's "exit" function pointer is covertly passed to GLUT. 00033 * GLUT then calls the executable's exit function pointer to ensure that 00034 * any "atexit" calls registered by the application are called if GLUT 00035 * needs to exit. 00036 * 00037 * To avoid the atexit workaround, define GLUT_DISABLE_ATEXIT_HACK. 00038 */ 00039 #define GLUT_DISABLE_ATEXIT_HACK 00040 00041 #include <GL/freeglut.h> 00042 00043 ///////////////////////////////////////////////////////////////////////////////////////// 00044 00045 namespace WoRB 00046 { 00047 ///////////////////////////////////////////////////////////////////////////////////// 00048 // Global Utilities functions 00049 00050 /** Gets a uniform real number in range [0,1). 00051 */ 00052 extern double RandomReal (); 00053 00054 /** Gets a quaternion of the given length having a random orientation. 00055 */ 00056 extern Quaternion RandomQuaternion( double length = 1.0 ); 00057 00058 /** Gets a random quaternion uniformly distributed in a 4D box 00059 */ 00060 extern Quaternion RandomQuaternion( const Quaternion& min, const Quaternion& max ); 00061 00062 /** Renders the given text to the given location in body-fixed space. 00063 */ 00064 extern void RenderText( double x, double y, double z, const char* text ); 00065 00066 /** Renders the given text to the given location in screen space on the window. 00067 * @return The next y location bellow the text. 00068 */ 00069 extern int RenderPrintf( int x, int y, const char* format, ... ); 00070 00071 /** Draws the geometry axes, angular velocity and angular momentum 00072 */ 00073 extern void RenderStateVariables( const RigidBody& body, const Quaternion& extent ); 00074 00075 /** Draws the world axes 00076 */ 00077 extern void RenderAxes( double length ); 00078 00079 /** Pauses execution for the given amount of milliseconds. 00080 */ 00081 extern void Pause( unsigned long ms ); 00082 00083 /** Brings the current GLUT window to the foreground. 00084 */ 00085 extern void glutForegroundWindow (); 00086 00087 ///////////////////////////////////////////////////////////////////////////////////// 00088 // FreeGLUT v2.8.0 specifics 00089 00090 #ifdef GLUT_HAS_MULTI // Appears first time in freeglut v2.8.0 00091 00092 /** Handles glut errors. 00093 */ 00094 extern void OnGlutError( const char* format, va_list args ); 00095 00096 /** Handles glut warnings. 00097 */ 00098 extern void OnGlutWarning( const char* format, va_list args ); 00099 00100 #endif 00101 00102 ///////////////////////////////////////////////////////////////////////////////////// 00103 00104 /** Interface for a GLUT-rendered rigid body. 00105 */ 00106 class GLUT_Renderer 00107 { 00108 public: 00109 ///////////////////////////////////////////////////////////////////////////////// 00110 00111 enum RenderType 00112 { 00113 BodyShape, //!< Render the body itself 00114 BodyAxes, //!< Render the body axes 00115 BodyShadow, //!< Render the body shadow (flattened body) 00116 FloorMirror //!< Render floor mirror image of the body 00117 }; 00118 00119 ///////////////////////////////////////////////////////////////////////////////// 00120 00121 /** Represents a color defined red, green, blue and alpha channels. 00122 */ 00123 struct Colorf 00124 { 00125 float R; //!< Holds red color component. 00126 float G; //!< Holds green color component. 00127 float B; //!< Holds blue color component. 00128 float A; //!< Holds aplpha (transparency) channel. 00129 00130 /** Default constructor; black opaque color. 00131 */ 00132 Colorf () 00133 : R( 0.0f ), G( 0.0f ), B( 0.0f ), A( 1.0f ) 00134 { 00135 } 00136 00137 /** Constructs color from the given components. 00138 */ 00139 Colorf( float red, float green, float blue, float alpha = 1.0f ) 00140 : R( red ), G( green ), B( blue ), A( alpha ) 00141 { 00142 } 00143 00144 /** Conctructs color from the elements of quaternion. 00145 */ 00146 Colorf( const Quaternion& q ) 00147 : R( float(q.x) ), G( float(q.y) ), B( float(q.z) ), A( float(q.w) ) 00148 { 00149 } 00150 }; 00151 00152 ///////////////////////////////////////////////////////////////////////////////// 00153 00154 /** Indicates whether to track objects trajectory. 00155 */ 00156 bool ShowTrajectory; 00157 00158 /** Holds the shape color, used when body is active (moving). 00159 */ 00160 Colorf ActiveColor; 00161 00162 /** Holds the shape color, used when body is inactive (not-moving). 00163 */ 00164 Colorf InactiveColor; 00165 00166 ///////////////////////////////////////////////////////////////////////////////// 00167 00168 /** Default construtor; enables tracking objects trajectory by default. 00169 */ 00170 GLUT_Renderer () 00171 : ShowTrajectory( true ) 00172 { 00173 } 00174 00175 /** Gets underlying rigid body. 00176 */ 00177 virtual RigidBody& GetBody () = 0; 00178 00179 /** Gets underlying geometry. 00180 */ 00181 virtual Geometry& GetGeometry () = 0; 00182 00183 /** Draws the required geometry (specified by RenderType) of the rigid body. 00184 */ 00185 virtual void Render( RenderType type ) = 0; 00186 00187 /** Draws the wireframe of the rigid body. 00188 */ 00189 virtual void RenderWireframe( double* transform ) = 0; 00190 00191 /** Virtual destructor (must have; even if not needed). 00192 */ 00193 virtual ~GLUT_Renderer () {} 00194 }; 00195 00196 ///////////////////////////////////////////////////////////////////////////////////// 00197 00198 /** Establishes temporarily a GL transform from body-fixed into world frame. 00199 * 00200 * Usage: usually in a statement-block, like: <code> 00201 00202 { 00203 GLTransform _( body ); 00204 00205 // ...code-here... 00206 } 00207 00208 </code> 00209 */ 00210 class GLTransform 00211 { 00212 public: 00213 /** Constructor; saves the current and establishes a new transformation. 00214 */ 00215 GLTransform( const RigidBody& body, bool flattenHeight = false ) 00216 { 00217 // Get the OpenGL transformation for the rigid body 00218 // 00219 GLdouble mat[ 16 ]; 00220 body.ToWorld.GetGLTransform( mat ); 00221 00222 glPushMatrix (); // Save the current transformation 00223 00224 if ( flattenHeight ) { 00225 glScaled( 1.0, 0, 1.0 ); 00226 } 00227 00228 glMultMatrixd( mat ); // Transform from body-fixed into world frame 00229 } 00230 00231 /** Constructor; saves the current and establishes a new transformation. 00232 */ 00233 GLTransform( const double* matrix ) 00234 { 00235 glPushMatrix (); // Save the current transformation 00236 glMultMatrixd( matrix ); // Transform from body-fixed into world frame 00237 } 00238 00239 /** Destructor; restores the earlier transformation. 00240 */ 00241 ~GLTransform () 00242 { 00243 glPopMatrix (); 00244 } 00245 }; 00246 00247 ///////////////////////////////////////////////////////////////////////////////////// 00248 00249 /** Establishes temporarily orthogonal projection in screen coordinates. 00250 */ 00251 class GLOrthoScreen 00252 { 00253 public: 00254 /** Constructor; saves the current and establishes a new transformation. 00255 */ 00256 GLOrthoScreen () 00257 { 00258 glDisable( GL_DEPTH_TEST ); 00259 00260 // Temporarily set up the view in orthographic projection. 00261 // 00262 glMatrixMode( GL_PROJECTION ); 00263 00264 glPushMatrix (); 00265 glLoadIdentity (); 00266 glOrtho( /* left */ 0.0, /* right */ glutGet( GLUT_WINDOW_WIDTH ), 00267 /* bottom */ 0.0, /* top */ glutGet( GLUT_WINDOW_HEIGHT ), 00268 /* zNear */ -1.0, /* zFar */ 1.0 00269 ); 00270 00271 glMatrixMode( GL_MODELVIEW ); 00272 00273 glPushMatrix (); 00274 glLoadIdentity (); 00275 } 00276 00277 /** Destructor; restores the earlier transformation. 00278 */ 00279 ~GLOrthoScreen () 00280 { 00281 // Go back to projection mode 00282 // 00283 glPopMatrix (); 00284 glMatrixMode( GL_PROJECTION ); 00285 00286 glPopMatrix (); 00287 glMatrixMode( GL_MODELVIEW ); 00288 00289 glEnable( GL_DEPTH_TEST ); 00290 } 00291 }; 00292 00293 ///////////////////////////////////////////////////////////////////////////////////// 00294 00295 /** Encapsulates a rigid body with geometry of a sphere. 00296 */ 00297 class Ball : public Sphere, public RigidBody, public GLUT_Renderer 00298 { 00299 const static int slices = 20; //!< Number of slices for glutSolidSphere() 00300 const static int stacks = 20; //!< Number of stacks for glutSolidSphere() 00301 00302 public: 00303 00304 ///////////////////////////////////////////////////////////////////////////////// 00305 00306 /** Creates a ball at the given location. 00307 */ 00308 Ball( 00309 Quaternion position, Quaternion orientation, 00310 Quaternion velocity, Quaternion angularVelocity, 00311 double radius, double mass 00312 ) 00313 { 00314 Body = this; 00315 00316 Radius = radius; 00317 00318 ActiveColor = Colorf( 0.9f, 0.7f, 0.7f, 0.8f ); 00319 InactiveColor = Colorf( 0.7f, 0.7f, 0.9f, 0.8f ); 00320 00321 SetMass( mass ); 00322 00323 Body->Set_XQVW( position, orientation, velocity, angularVelocity ); 00324 Body->Activate (); 00325 } 00326 00327 ///////////////////////////////////////////////////////////////////////////////// 00328 00329 /** Gets underlying rigid body. 00330 */ 00331 virtual RigidBody& GetBody () 00332 { 00333 return *this; 00334 } 00335 00336 /** Gets underlying geometry. 00337 */ 00338 virtual Geometry& GetGeometry () 00339 { 00340 return *this; 00341 } 00342 00343 /** Draws the geometry. 00344 */ 00345 virtual void Render( RenderType type ) 00346 { 00347 if ( type == BodyAxes ) 00348 { 00349 RenderStateVariables( *Body, Quaternion(0,1,1,1) * Radius * 2.0 ); 00350 return; 00351 } 00352 00353 GLTransform bodySpace( *Body, /* flattenHeight if */ type == BodyShadow ); 00354 00355 if ( type != BodyShadow ) 00356 { 00357 if ( Body->IsActive ) { 00358 glColor4f( ActiveColor.R, ActiveColor.G, ActiveColor.B, 00359 type == BodyShape ? ActiveColor.A : ActiveColor.A/2 ); 00360 } 00361 else { 00362 glColor4f( InactiveColor.R, InactiveColor.G, InactiveColor.B, 00363 type == BodyShape ? ActiveColor.A : ActiveColor.A/2 ); 00364 } 00365 } 00366 00367 glutSolidSphere( Radius, slices, stacks ); 00368 } 00369 00370 /** Draws the wireframe of the rigid body. 00371 */ 00372 virtual void RenderWireframe( double* transform ) 00373 { 00374 GLTransform bodySpace( transform ); 00375 glColor4f( 0.0f, 0.0f, 0.0f, 0.1f ); 00376 glutWireSphere( Radius, slices, stacks ); 00377 } 00378 }; 00379 00380 ///////////////////////////////////////////////////////////////////////////////////// 00381 00382 /** Encapsulates a rigid body with geometry of a rectangular parallelepiped. 00383 */ 00384 class Box : public Cuboid, public RigidBody, public GLUT_Renderer 00385 { 00386 public: 00387 00388 ///////////////////////////////////////////////////////////////////////////////// 00389 00390 /** Creates the box at the specific location. 00391 */ 00392 Box( const Quaternion& position, const Quaternion& orientation, 00393 const Quaternion& velocity, const Quaternion& angularVelocity, 00394 const Quaternion& halfExtent, double mass 00395 ) 00396 { 00397 Body = this; 00398 00399 HalfExtent = halfExtent; 00400 00401 double minsz = HalfExtent.x; 00402 minsz = HalfExtent.y < minsz ? HalfExtent.y : minsz; 00403 minsz = HalfExtent.z < minsz ? HalfExtent.z : minsz; 00404 00405 ActiveColor = minsz < 0.1 ? Colorf( 0.0f, 0.0f, 0.1f, 0.7f ) 00406 : Colorf( 0.7f, 0.9f, 0.7f, 0.8f ); 00407 00408 InactiveColor = Colorf( 0.9f, 0.5f, 0.5f, 0.8f ); 00409 00410 SetMass( mass ); 00411 00412 Body->Set_XQVW( position, orientation, velocity, angularVelocity ); 00413 Body->Activate (); 00414 } 00415 00416 ///////////////////////////////////////////////////////////////////////////////// 00417 00418 /** Gets underlying rigid body. 00419 */ 00420 virtual RigidBody& GetBody () 00421 { 00422 return *this; 00423 } 00424 00425 /** Gets underlying geometry. 00426 */ 00427 virtual Geometry& GetGeometry () 00428 { 00429 return *this; 00430 } 00431 00432 /** Draws the geometry 00433 */ 00434 virtual void Render( RenderType type ) 00435 { 00436 if ( type == BodyAxes ) 00437 { 00438 RenderStateVariables( *Body, HalfExtent * 1.2 ); 00439 return; 00440 } 00441 00442 GLTransform bodySpace( *Body, /* flattenHeight if */ type == BodyShadow ); 00443 00444 if ( type != BodyShadow ) 00445 { 00446 if ( Body->IsActive ) { 00447 glColor4f( ActiveColor.R, ActiveColor.G, ActiveColor.B, 00448 type == BodyShape ? ActiveColor.A : ActiveColor.A/2 ); 00449 } 00450 else { 00451 glColor4f( InactiveColor.R, InactiveColor.G, InactiveColor.B, 00452 type == BodyShape ? InactiveColor.A : InactiveColor.A/2 ); 00453 } 00454 } 00455 00456 glScaled( HalfExtent.x * 2, HalfExtent.y * 2, HalfExtent.z * 2 ); 00457 glutSolidCube( 1.0 ); 00458 } 00459 00460 /** Draws the wireframe of the rigid body. 00461 */ 00462 virtual void RenderWireframe( double* transform ) 00463 { 00464 GLTransform bodySpace( transform ); 00465 glColor4f( 0.0f, 0.0f, 0.0f, 0.1f ); 00466 glScaled( HalfExtent.x * 2, HalfExtent.y * 2, HalfExtent.z * 2 ); 00467 glutWireCube( 1.0 ); 00468 } 00469 }; 00470 00471 ///////////////////////////////////////////////////////////////////////////////////// 00472 00473 /** GLUT wrapper around a single instance of a GlutApplication template class. 00474 * GlutApplication should implement event handlers that respond to GLUT callbacks. 00475 */ 00476 template<class GlutApplication> 00477 class GLUT_Framework 00478 { 00479 /** Indicates whether glut has been initialized. 00480 */ 00481 bool Initialized; 00482 00483 /** Holds an instance of the GlutApplication 00484 */ 00485 static GlutApplication* Application; 00486 00487 /** Called when glut closes the application window. 00488 */ 00489 static void CloseFunc () 00490 { 00491 if ( Application && Application->IsValid () ) { 00492 Application->CloseEventHandler (); 00493 } 00494 } 00495 00496 /** Called each frame to display the scene. 00497 */ 00498 static void DisplayFunc () 00499 { 00500 if ( Application && Application->IsValid () ) { 00501 Application->DisplayEventHandler (); 00502 } 00503 } 00504 00505 /** Called when a mouse button is pressed. 00506 */ 00507 static void MouseFunc( int button, int state, int x, int y ) 00508 { 00509 if ( Application && Application->IsValid () ) { 00510 Application->MouseEventHandler( button, state, x, y ); 00511 } 00512 } 00513 00514 /** Called when the display window changes size. 00515 */ 00516 static void ReshapeFunc( int width, int height ) 00517 { 00518 if ( Application && Application->IsValid () ) { 00519 Application->ReshapeEventHandler( width, height ); 00520 } 00521 } 00522 00523 /** Called when a key is pressed. 00524 */ 00525 static void KeyboardFunc( unsigned char key, int /*x*/, int /*y*/ ) 00526 { 00527 if ( Application && Application->IsValid () ) { 00528 Application->KeyboardEventHandler( key ); 00529 } 00530 } 00531 00532 /** Called when a special key is pressed. 00533 */ 00534 static void SpecialFunc( int key, int /*x*/, int /*y*/ ) 00535 { 00536 if ( Application && Application->IsValid () ) { 00537 Application->SpecialKeyEventHandler( key ); 00538 } 00539 } 00540 00541 /** Called when the mouse is dragged. 00542 */ 00543 static void MotionFunc( int x, int y ) 00544 { 00545 if ( Application && Application->IsValid () ) { 00546 Application->MotionEventHandler( x, y ); 00547 } 00548 } 00549 00550 /** Called when the mouse wheel is spun. 00551 */ 00552 static void MouseWheelFunc( int wheel, int direction, int x, int y ) 00553 { 00554 if ( Application && Application->IsValid () ) { 00555 Application->MouseWheelEventHandler( wheel, direction, x, y ); 00556 } 00557 } 00558 00559 public: 00560 00561 GLUT_Framework () 00562 : Initialized( false ) 00563 { 00564 Printf( "WoRB: GLUT_Framework: Constructed\n" ); 00565 } 00566 00567 ~GLUT_Framework () 00568 { 00569 Initialized = false; 00570 Printf( "WoRB: GLUT_Framework: Destructed\n" ); 00571 } 00572 00573 bool Initialize () 00574 { 00575 // We must have proper dummy argument for glutInit() not to crash. 00576 int argc = 1; 00577 char arg0[] = "WoRB"; 00578 char* argv[] = { arg0 }; 00579 00580 return Initialize( &argc, argv ); 00581 } 00582 00583 bool Initialize( int* argc, char* argv[] ) 00584 { 00585 if ( Initialized ) { 00586 return true; 00587 } 00588 00589 Printf( "WoRB: GLUT_Framework: Calling glutInit...\n" ); 00590 00591 // In case of glut >= v2.8.0 00592 #ifdef GLUT_HAS_MULTI 00593 glutInitWarningFunc( OnGlutWarning ); 00594 glutInitErrorFunc( OnGlutError ); 00595 #endif 00596 00597 glutInit( argc, argv ); 00598 00599 Initialized = glutGet( GLUT_INIT_STATE ) != 0; 00600 00601 return Initialized; 00602 } 00603 00604 void Terminate () 00605 { 00606 Disconnect (); 00607 00608 Printf( "WoRB: GLUT_Framework: glutExit...\n" ); 00609 // glutExit (); 00610 00611 Initialized = false; 00612 } 00613 00614 /** Connects GLUT event handlers to GlutApplication instance. 00615 */ 00616 void Connect( GlutApplication& application ) 00617 { 00618 Printf( "WoRB: GLUT_Framework: Connecting event handlers\n" ); 00619 00620 GLUT_Framework::Application = &application; 00621 00622 glutCloseFunc( CloseFunc ); 00623 glutDisplayFunc( DisplayFunc ); 00624 glutReshapeFunc( ReshapeFunc ); 00625 glutKeyboardFunc( KeyboardFunc ); 00626 glutSpecialFunc( SpecialFunc ); 00627 glutMouseFunc( MouseFunc ); 00628 glutMotionFunc( MotionFunc ); 00629 glutMouseWheelFunc( MouseWheelFunc ); 00630 } 00631 00632 /** Disconect event handlers from the GlutApplication instance. 00633 */ 00634 void Disconnect () 00635 { 00636 Printf( "WoRB: GLUT_Framework: Disconnecting event handlers\n" ); 00637 00638 GLUT_Framework::Application = 0; 00639 } 00640 }; 00641 00642 ///////////////////////////////////////////////////////////////////////////////////// 00643 00644 } // namespace WoRB 00645 00646 #endif // _WORB_UTILITIES_H_INCLUDED