World of Rigid Bodies (WoRB)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Utilities.h
Go to the documentation of this file.
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