Main Page   Class Hierarchy   Compound List   File List   Compound Members  

clothApp.cpp

00001 //////////////////////////////////////////////////////////////////////
00002 // Copyright (c) 2002-2003 David Pritchard <drpritch@alumni.uwaterloo.ca>
00003 // 
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either
00007 // version 2 of the License, or (at your option) any later
00008 // version.
00009 // 
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019 #include <freecloth/clothApp/clothApp.h>
00020 #include <freecloth/colour/colColourRGB.h>
00021 #include <freecloth/geom/geMatrix4.h>
00022 #include <freecloth/geom/geMesh.h>
00023 #include <freecloth/geom/geMeshBuilder.h>
00024 #include <freecloth/gfx/gfxGL.h>
00025 #include <freecloth/gfx/gfxGLWindowGLUI.h>
00026 #include <freecloth/gfx/gfxGLTexture.h>
00027 #include <freecloth/gfx/gfxImage.h>
00028 #include <freecloth/gfx/gfxImageReaderPNM.h>
00029 #include <freecloth/gfx/gfxImageWriterPNM.h>
00030 #include <freecloth/resmgt/resConfigRegistry.h>
00031 #include <freecloth/base/GL_gl.h>
00032 #include <freecloth/base/GL_glu.h>
00033 #include <freecloth/base/stdio.h>
00034 
00035 namespace {
00036     const Float DEFAULT_H = .01f;
00037     const Float DEFAULT_RHO = .1f;
00038     const Float DEFAULT_PCG_TOLERANCE = 1e-3f;
00039 
00040     const Float FPS = 25.f;
00041 
00042 //------------------------------------------------------------------------------
00043 
00044 // Create mesh with double the resolution of the input mesh.
00045 RCShdPtr<GeMesh> refineMesh(
00046     const GeMesh& mesh,
00047     UInt32 nbRows,
00048     UInt32 nbCols
00049 ) {
00050     UInt32 oldRows = nbRows;
00051     UInt32 oldCols = nbCols;
00052     DGFX_ASSERT( (nbRows + 1) * (nbCols + 1) == mesh.getNbVertices() );
00053     nbRows *= 2;
00054     nbCols *= 2;
00055 
00056     GeMeshBuilder builder;
00057     UInt32 r, c;
00058     builder.preallocVertices( (nbRows + 1) * (nbCols + 1 ) );
00059     builder.preallocTextureVertices( (nbRows + 1) * (nbCols + 1 ) );
00060     builder.preallocFaces( nbRows * nbCols );
00061     for ( r = 0; r <= nbRows; ++r ) {
00062         for ( c = 0; c <= nbCols; ++c ) {
00063             if ( r % 2 == 0 ) {
00064                 if ( c % 2 == 0 ) {
00065                     builder.addVertex(
00066                         mesh.getVertex( (r/2)*(oldCols+1) + c/2 )
00067                     );
00068                     builder.addTextureVertex(
00069                         mesh.getTextureVertex( (r/2)*(oldCols+1) + c/2 )
00070                     );
00071                 }
00072                 else {
00073                     builder.addVertex(
00074                         GePoint(
00075                             mesh.getVertex( (r/2)*(oldCols+1) + c/2 ),
00076                             mesh.getVertex( (r/2)*(oldCols+1) + c/2+1 ),
00077                             .5
00078                         )
00079                     );
00080                     builder.addTextureVertex(
00081                         GePoint(
00082                             mesh.getTextureVertex( (r/2)*(oldCols+1) + c/2 ),
00083                             mesh.getTextureVertex( (r/2)*(oldCols+1) + c/2+1 ),
00084                             .5
00085                         )
00086                     );
00087                 }
00088             } else {
00089                 if ( c % 2 == 0 ) {
00090                     builder.addVertex(
00091                         GePoint(
00092                             mesh.getVertex( (r/2)*(oldCols+1) + c/2 ),
00093                             mesh.getVertex( (r/2+1)*(oldCols+1) + c/2 ),
00094                             .5
00095                         )
00096                     );
00097                     builder.addTextureVertex(
00098                         GePoint(
00099                             mesh.getTextureVertex( (r/2)*(oldCols+1) + c/2 ),
00100                             mesh.getTextureVertex( (r/2+1)*(oldCols+1) + c/2 ),
00101                             .5
00102                         )
00103                     );
00104                 }
00105                 else {
00106                     builder.addVertex(
00107                         GePoint(
00108                             mesh.getVertex( (r/2)*(oldCols+1) + c/2+1 ),
00109                             mesh.getVertex( (r/2+1)*(oldCols+1) + c/2 ),
00110                             .5
00111                         )
00112                     );
00113                     builder.addTextureVertex(
00114                         GePoint(
00115                             mesh.getTextureVertex( (r/2)*(oldCols+1) + c/2+1 ),
00116                             mesh.getTextureVertex( (r/2+1)*(oldCols+1) + c/2 ),
00117                             .5
00118                         )
00119                     );
00120                 }
00121             }
00122         }
00123     }
00124     const UInt32 rstride=nbCols+1;
00125     for( r = 0; r < nbRows; ++r ) {
00126         for ( c = 0; c < nbCols; ++c ) {
00127             GeMesh::FaceId fid = builder.addFace(
00128                 r*rstride + c, r*rstride + c+1, (r+1)*rstride + c,
00129                 r*rstride + c, r*rstride + c+1, (r+1)*rstride + c
00130             );
00131             fid = builder.addFace(
00132                 (r+1)*rstride + c, r*rstride + c+1, (r+1)*rstride + c+1,
00133                 (r+1)*rstride + c, r*rstride + c+1, (r+1)*rstride + c+1
00134             );
00135         }
00136     }
00137     return builder.createMesh();
00138 }
00139 
00140 }
00141 
00142 ////////////////////////////////////////////////////////////////////////////////
00143 // CLASS ClothApp
00144 
00145 //------------------------------------------------------------------------------
00146 
00147 ClothApp::ClothApp()
00148   : _nbPatches( 11 ),
00149     _clothSize( 1 ),
00150     _h( DEFAULT_H ),
00151     _rho( DEFAULT_RHO ),
00152     _pcgTolerance( DEFAULT_PCG_TOLERANCE ),
00153     _constraints( CON_CORNERS3b ),
00154     _quitFlag( false ),
00155     _rewindFlag( false ),
00156     _freeRunFlag( false ),
00157     _stopFlag( false ),
00158     _stepFlag( false ),
00159     _snapFlag( false ),
00160     _snapCount( 0 ),
00161     _subStepFlag( false )
00162 {
00163     setupMesh();
00164 
00165     // Setup config
00166     RCShdPtr<ResConfigRegistryR> reader =
00167         ResConfigRegistryR::create( "clothApp" );
00168     _config.load( *reader );
00169 
00170     setupWindow();
00171 
00172     // Read textures
00173     RCShdPtr<GfxImage> texImage;
00174 
00175     texImage = GfxImageReaderPNM( "marble.ppm" ).readImage();
00176     if ( ! texImage.isNull() ) {
00177         _floorTexture = RCShdPtr<GfxGLTexture>(
00178             new GfxGLTexture( texImage, GL_RGB )
00179         );
00180         _floorTexture->generateMipmaps();
00181     }
00182 
00183     texImage = GfxImageReaderPNM( "checker3.ppm" ).readImage();
00184     if ( ! texImage.isNull() ) {
00185         _clothTexture = RCShdPtr<GfxGLTexture>(
00186             new GfxGLTexture( texImage, GL_RGB )
00187         );
00188         _clothTexture->generateMipmaps();
00189     }
00190 
00191     setupSimulator();
00192 }
00193 
00194 //------------------------------------------------------------------------------
00195 
00196 void ClothApp::runApp()
00197 {
00198     _glWindow->eventLoop();
00199 }
00200 
00201 //------------------------------------------------------------------------------
00202 
00203 void ClothApp::setupMesh()
00204 {
00205     _initialMesh = createRectMesh( _clothSize, _nbPatches, _nbPatches );
00206     DGFX_TRACE( ! _initialMesh.isNull() );
00207     // Centre mesh
00208     _meshPos = GePoint( _clothSize/-2.f, _clothSize/-2.f, 0 );
00209 
00210     _meshWE = RCShdPtr<GeMeshWingedEdge>(
00211         new GeMeshWingedEdge( _initialMesh )
00212     );
00213     _meshNormals.resize( _initialMesh->getNbVertices() );
00214     initMeshIndices( *_initialMesh, _meshIndices );
00215 
00216     _meshTextureVertices.clear();
00217     _meshTextureVertices.reserve( _initialMesh->getNbVertices() );
00218 
00219     UInt32 r,c;
00220     Float NB_REPS = 16.5f;
00221     for ( r = 0; r <= _nbPatches; ++r ) {
00222         for ( c = 0; c <= _nbPatches; ++c ) {
00223             // Old approach: one square per mesh rect
00224                 //GePoint( c * .5, r * .5, 0 )
00225             // New approach: always NB_REPS repetitions of texture across
00226             // cloth.
00227             _meshTextureVertices.push_back(
00228                 GePoint( c * NB_REPS / _nbPatches, r * NB_REPS / _nbPatches, 0 )
00229             );
00230         }
00231     }
00232 }
00233 
00234 //------------------------------------------------------------------------------
00235 
00236 void ClothApp::setupSimulator()
00237 {
00238     _simulator = RCShdPtr<SimSimulator>(
00239         new SimSimulator( *_initialMesh )
00240     );
00241     _simulator->setTimestep( _h );
00242     _simulator->setDensity( _rho );
00243     _simulator->setParams( _params );
00244     _simulator->setPCGTolerance( _pcgTolerance );
00245     setConstraints();
00246     _nextMovieFrame = 0;
00247 }
00248 
00249 //------------------------------------------------------------------------------
00250 
00251 void ClothApp::setConstraints()
00252 {
00253     const UInt32 N = _nbPatches;
00254     _simulator->removeAllConstraints();
00255     switch ( _constraints ) {
00256         case CON_NONE: {
00257         } break;
00258 
00259         case CON_CENTRE: {
00260             _simulator->setPosConstraintFull( (N+1)*(N/2) + N/2 );
00261         } break;
00262 
00263         case CON_CORNERS4: {
00264             _simulator->setPosConstraintFull( 0 );
00265             _simulator->setPosConstraintFull( N );
00266             _simulator->setPosConstraintFull( N*(N+1) );
00267             _simulator->setPosConstraintFull( (N+1)*(N+1)-1 );
00268         } break;
00269 
00270         case CON_CORNERS3a: {
00271             _simulator->setPosConstraintFull( N );
00272             _simulator->setPosConstraintFull( N*(N+1) );
00273             _simulator->setPosConstraintFull( (N+1)*(N+1)-1 );
00274         } break;
00275 
00276         case CON_CORNERS3b: {
00277             _simulator->setPosConstraintFull( 0 );
00278             _simulator->setPosConstraintFull( N*(N+1) );
00279             _simulator->setPosConstraintFull( (N+1)*(N+1)-1 );
00280         } break;
00281 
00282         case CON_CORNERS1c: {
00283             _simulator->setPosConstraintFull( N*(N+1) );
00284         } break;
00285 
00286         case CON_CORNERS1d: {
00287             _simulator->setPosConstraintFull( (N+1)*(N+1)-1 );
00288         } break;
00289 
00290         case CON_CORNERYANK: {
00291             _simulator->setPosConstraintFull( (N+1)*(N+1)-1 );
00292             _simulator->setVelConstraint( (N+1)*(N+1)-1, -.1f * GeVector::X );
00293         } break;
00294 
00295         case CON_TABLE_SQUARE: {
00296             const UInt32 C = BaMath::roundUInt32( std::max( 1.f, N*5/11.f ) );
00297             const UInt32 x = (N-C)/2;
00298             for (UInt32 i = 0; i <= C; ++i ) for ( UInt32 j = 0; j <= C; ++j ) {
00299                 _simulator->setPosConstraintFull( (x + i)*(N+1) + x + j );
00300             }
00301         } break;
00302 
00303         case CON_TABLE_CIRCLE: {
00304             const Float r = 7/11.f;
00305             for (UInt32 i = 0; i <= N; ++i ) for ( UInt32 j = 0; j <= N; ++j ) {
00306                 Float x = 2*i/static_cast<Float>( N ) - 1;
00307                 Float y = 2*j/static_cast<Float>( N ) - 1;
00308                 if ( x*x + y*y < r*r ) {
00309                     _simulator->setPosConstraintFull( i*(N+1) + j );
00310                 }
00311             }
00312         } break;
00313     }
00314 }
00315 
00316 //------------------------------------------------------------------------------
00317 
00318 void ClothApp::setupWindow()
00319 {
00320     // Create GL window, monitor for events
00321     _glWindow = RCShdPtr<GfxGLWindowGLUI>( new GfxGLWindowGLUI(
00322         _config, "Cloth test app"
00323     ) );
00324     _glWindow->addObserver( *this );
00325     _glWindow->enableIdleEvents( true );
00326 
00327     enum {
00328         PANEL_CAMERA,
00329         PANEL_SCENE, PANEL_SCENE2,
00330         PANEL_EXEC,
00331         PANEL_PARAMS,
00332         PANEL_CON,
00333         PANEL_SNAPS, PANEL_SNAPS2,
00334         PANEL_DEBUG,
00335         PANEL_ENERGY,
00336         PANEL_TRI,
00337         PANEL_VERT
00338     };
00339     _glWindow->addGroup( GfxGLWindowGLUI::BORDER_RAISED, PANEL_CAMERA );
00340     _glWindow->addRotate( "Camera", ID_CAMERA_ROTATE, PANEL_CAMERA );
00341     _glWindow->setRotate(
00342         ID_CAMERA_ROTATE, GeMatrix4::rotation( GeVector::X, -M_PI / 3 )
00343     );
00344     _glWindow->addColumn( false, PANEL_CAMERA );
00345     _glWindow->addTranslate(
00346         "Zoom", GfxGLWindowGLUI::TR_Z, ID_ZOOM, PANEL_CAMERA
00347     );
00348     _glWindow->setTranslateZ( ID_ZOOM, -20 );
00349 
00350     _glWindow->addRollout( "Scene", PANEL_SCENE, false );
00351     _glWindow->addGroup(
00352         GfxGLWindowGLUI::BORDER_NONE, PANEL_SCENE2, PANEL_SCENE
00353     );
00354         _glWindow->addRotate( "Light", ID_LIGHT, PANEL_SCENE2 );
00355         _glWindow->addColumn( false, PANEL_SCENE2 );
00356     _glWindow->addCheckbox( "Axes", ID_AXES, PANEL_SCENE );
00357     _glWindow->setCheckbox( ID_AXES, false );
00358     _glWindow->addCheckbox( "Wireframe", ID_WIREFRAME, PANEL_SCENE );
00359     _glWindow->setCheckbox( ID_WIREFRAME, false );
00360     _glWindow->addEditFloat( "Cloth size: ", ID_CLOTH_SIZE, PANEL_SCENE );
00361     _glWindow->setEditFloat( ID_CLOTH_SIZE, _clothSize );
00362 
00363     _glWindow->addPanel( "Simulation", PANEL_EXEC );
00364     _glWindow->addButton( "Run", ID_RUN, PANEL_EXEC );
00365     _glWindow->addButton( "Stop", ID_STOP, PANEL_EXEC );
00366     _glWindow->addButton( "Step", ID_STEP, PANEL_EXEC );
00367     _glWindow->addButton( "Rewind", ID_REWIND, PANEL_EXEC );
00368     _glWindow->addText( "Time: ", ID_TIME, PANEL_EXEC );
00369     _glWindow->addEditInt( "Cloth patches: ", ID_PATCHES, PANEL_EXEC );
00370     _glWindow->setEditInt( ID_PATCHES, _nbPatches );
00371     _glWindow->setEditIntLimits( ID_PATCHES, 1, 200 );
00372     _glWindow->addEditFloat( "Time step: ", ID_TIMESTEP, PANEL_EXEC );
00373     _glWindow->setEditFloat( ID_TIMESTEP, _h );
00374     _glWindow->addEditFloat( "Tolerance: ", ID_PCG_TOLERANCE, PANEL_EXEC );
00375     _glWindow->setEditFloat( ID_PCG_TOLERANCE, _pcgTolerance );
00376 
00377     _glWindow->addRollout( "Parameters", PANEL_PARAMS, false );
00378     _glWindow->addEditFloat( "k_stretch (k)", ID_PAR_K_STRETCH, PANEL_PARAMS );
00379     _glWindow->addEditFloat( "k_shear (k)", ID_PAR_K_SHEAR, PANEL_PARAMS );
00380     _glWindow->addEditFloat( "k_bend_u (m)", ID_PAR_K_BEND_U, PANEL_PARAMS );
00381     _glWindow->addEditFloat( "k_bend_v (m)", ID_PAR_K_BEND_V, PANEL_PARAMS );
00382     _glWindow->addEditFloat( "k_damp", ID_PAR_K_DAMP, PANEL_PARAMS );
00383     _glWindow->addEditFloat( "k_drag", ID_PAR_K_DRAG, PANEL_PARAMS );
00384     _glWindow->addEditFloat( "b_u", ID_PAR_B_U, PANEL_PARAMS );
00385     _glWindow->addEditFloat( "b_v", ID_PAR_B_V, PANEL_PARAMS );
00386     _glWindow->addEditFloat( "density", ID_PAR_RHO, PANEL_PARAMS );
00387     _glWindow->addEditFloat( "gravity", ID_PAR_G, PANEL_PARAMS );
00388     _glWindow->addButton( "Reset", ID_PAR_RESET, PANEL_PARAMS );
00389     updateParamsUI();
00390 
00391     _glWindow->addRollout( "Constraints", PANEL_CON, false );
00392     _glWindow->addRadioGroup( ID_CONSTRAINTS, PANEL_CON );
00393     _glWindow->addRadioButton( ID_CONSTRAINTS, "None" );
00394     _glWindow->addRadioButton( ID_CONSTRAINTS, "Centre" );
00395     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (4)" );
00396     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (3a)" );
00397     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (3b)" );
00398     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (1c)" );
00399     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (1d)" );
00400     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (1d, moving)" );
00401     _glWindow->addRadioButton( ID_CONSTRAINTS, "Square table" );
00402     _glWindow->addRadioButton( ID_CONSTRAINTS, "Circular table" );
00403     _glWindow->setRadioGroup( ID_CONSTRAINTS, _constraints );
00404 
00405     _glWindow->addRollout( "Snapshots", PANEL_SNAPS, false );
00406     _glWindow->addButton( "Snapshot", ID_SNAPSHOT, PANEL_SNAPS );
00407     _glWindow->addCheckbox( "Movie", ID_MOVIE, PANEL_SNAPS );
00408     _glWindow->setCheckbox( ID_MOVIE, false );
00409     _glWindow->addGroup(
00410         GfxGLWindowGLUI::BORDER_NONE, PANEL_SNAPS2, PANEL_SNAPS
00411     );
00412         _glWindow->addTranslate(
00413             "Fog start", GfxGLWindowGLUI::TR_Z, ID_FOG_START, PANEL_SNAPS2
00414         );
00415         _glWindow->setTranslateZ( ID_FOG_START, 20 );
00416         _glWindow->addColumn( false, PANEL_SNAPS2 );
00417         _glWindow->addTranslate(
00418             "Fog end", GfxGLWindowGLUI::TR_Z, ID_FOG_END, PANEL_SNAPS2
00419         );
00420         _glWindow->setTranslateZ( ID_FOG_END, 60 );
00421 
00422     _glWindow->addRollout( "Debug", PANEL_DEBUG, false );
00423     _glWindow->addPanel( "Energy", PANEL_ENERGY, PANEL_DEBUG );
00424     _glWindow->addText( "Stretch: ", ID_EN_STRETCH, PANEL_ENERGY );
00425     _glWindow->addText( "Shear: ", ID_EN_SHEAR, PANEL_ENERGY );
00426     _glWindow->addText( "Bend: ", ID_EN_BEND, PANEL_ENERGY );
00427 
00428     _glWindow->addRollout( "Triangles", PANEL_TRI, false, PANEL_DEBUG );
00429     _glWindow->addCheckbox( "Stretch energy", ID_TRI_STRETCH, PANEL_TRI );
00430     _glWindow->setCheckbox( ID_TRI_STRETCH, false );
00431     _glWindow->addCheckbox( "Shear energy", ID_TRI_SHEAR, PANEL_TRI );
00432     _glWindow->setCheckbox( ID_TRI_SHEAR, false );
00433     _glWindow->addCheckbox( "Bend energy", ID_TRI_BEND, PANEL_TRI );
00434     _glWindow->setCheckbox( ID_TRI_BEND, false );
00435 
00436     _glWindow->addRollout( "Vertices", PANEL_VERT, false, PANEL_DEBUG );
00437     _glWindow->addCheckbox( "Velocity", ID_VERT_VEL, PANEL_VERT );
00438     _glWindow->setCheckbox( ID_VERT_VEL, false );
00439     _glWindow->addCheckbox( "Total force", ID_VERT_FORCE, PANEL_VERT );
00440     _glWindow->setCheckbox( ID_VERT_FORCE, false );
00441 #if !defined( NDEBUG )
00442     _glWindow->addCheckbox( "Damping forces", ID_VERT_FORCE_DAMP, PANEL_VERT );
00443     _glWindow->setCheckbox( ID_VERT_FORCE_DAMP, false );
00444     _glWindow->addCheckbox( "Stretch force", ID_VERT_FORCE_STRETCH, PANEL_VERT);
00445     _glWindow->setCheckbox( ID_VERT_FORCE_STRETCH, false );
00446     _glWindow->addCheckbox( "Shear force", ID_VERT_FORCE_SHEAR, PANEL_VERT );
00447     _glWindow->setCheckbox( ID_VERT_FORCE_SHEAR, false );
00448     _glWindow->addCheckbox( "Bend force", ID_VERT_FORCE_BEND, PANEL_VERT );
00449     _glWindow->setCheckbox( ID_VERT_FORCE_BEND, false );
00450     _glWindow->addCheckbox( "Gravity force", ID_VERT_FORCE_GRAVITY, PANEL_VERT );
00451     _glWindow->setCheckbox( ID_VERT_FORCE_GRAVITY, false );
00452     _glWindow->addCheckbox( "Drag force", ID_VERT_FORCE_DRAG, PANEL_VERT );
00453     _glWindow->setCheckbox( ID_VERT_FORCE_DRAG, false );
00454 #endif
00455 
00456     _glWindow->addButton( "Quit", ID_QUIT );
00457 
00458     initGL();
00459 }
00460 
00461 //------------------------------------------------------------------------------
00462 
00463 void ClothApp::updateParamsUI()
00464 {
00465     _glWindow->setEditFloat( ID_PAR_K_STRETCH, _params._k_stretch / 1000.f );
00466     _glWindow->setEditFloat( ID_PAR_K_SHEAR, _params._k_shear / 1000.f );
00467     _glWindow->setEditFloat( ID_PAR_K_BEND_U, _params._k_bend_u * 1000.f );
00468     _glWindow->setEditFloat( ID_PAR_K_BEND_V, _params._k_bend_v * 1000.f );
00469     _glWindow->setEditFloat( ID_PAR_K_DAMP, _params._k_damp );
00470     _glWindow->setEditFloat( ID_PAR_K_DRAG, _params._k_drag );
00471     _glWindow->setEditFloat( ID_PAR_B_U, _params._b_u );
00472     _glWindow->setEditFloat( ID_PAR_B_V, _params._b_v );
00473     _glWindow->setEditFloat( ID_PAR_RHO, _rho );
00474     _glWindow->setEditFloat( ID_PAR_G, _params._g );
00475 }
00476 
00477 //------------------------------------------------------------------------------
00478 
00479 void ClothApp::closeReceived( GfxWindow& )
00480 {
00481     _glWindow->removeObserver( *this );
00482     ::exit( 0 );
00483 }
00484 
00485 //------------------------------------------------------------------------------
00486 
00487 void ClothApp::uiReceived( GfxWindow&, UInt32 uid )
00488 {
00489     switch ( uid ) {
00490         case ID_CAMERA_ROTATE:
00491         case ID_ZOOM:
00492         case ID_LIGHT:
00493         case ID_FOG_START:
00494         case ID_FOG_END:
00495         case ID_AXES:
00496         case ID_WIREFRAME: {
00497             _glWindow->postRedisplay();
00498         } break;
00499         case ID_PATCHES:
00500         case ID_CLOTH_SIZE: {
00501             UInt32 oldNbPatches = _nbPatches;
00502             if ( uid == ID_PATCHES ) {
00503                 _nbPatches = _glWindow->getEditInt( ID_PATCHES );
00504             }
00505             else {
00506                 _clothSize = _glWindow->getEditFloat( ID_CLOTH_SIZE );
00507             }
00508             
00509             // Special case: if the user doubles the number of patches,
00510             // then we can refine and keep the current state.
00511             RCShdPtr<GeMesh> refinedMesh;
00512             Float ratio( static_cast<Float>( _nbPatches ) / oldNbPatches );
00513             if (
00514                 _nbPatches > oldNbPatches &&
00515                 BaMath::isInteger( ratio ) &&
00516                 BaMath::isPow2( BaMath::roundUInt32( ratio ) )
00517             ) {
00518                 refinedMesh = _simulator->getMeshPtr();
00519                 for ( ; oldNbPatches < _nbPatches; oldNbPatches *= 2 ) {
00520                     refinedMesh = refineMesh(
00521                         *refinedMesh,
00522                         oldNbPatches,
00523                         oldNbPatches
00524                     );
00525                 }
00526             }
00527 
00528             setupMesh();
00529             setupSimulator();
00530             if ( ! refinedMesh.isNull() ) {
00531                 _simulator->setMesh( *refinedMesh );
00532             }
00533             _glWindow->postRedisplay();
00534         } break;
00535 
00536         case ID_RUN: {
00537             _freeRunFlag = true;
00538         } break;
00539         case ID_STOP: {
00540             _stopFlag = true;
00541         } break;
00542         case ID_STEP: {
00543             _stepFlag = true;
00544         } break;
00545         case ID_REWIND: {
00546             _rewindFlag = true;
00547             _glWindow->postRedisplay();
00548         } break;
00549         case ID_TIMESTEP: {
00550             _h = _glWindow->getEditFloat( uid );
00551             _simulator->setTimestep( _h );
00552         } break;
00553         case ID_PCG_TOLERANCE: {
00554             _pcgTolerance = _glWindow->getEditFloat( uid );
00555             _simulator->setPCGTolerance( _pcgTolerance );
00556         } break;
00557 
00558         case ID_PAR_K_STRETCH: {
00559             _params._k_stretch = _glWindow->getEditFloat( uid ) * 1000.f;
00560             _simulator->setParams( _params );
00561         } break;
00562 
00563         case ID_PAR_K_SHEAR: {
00564             _params._k_shear = _glWindow->getEditFloat( uid ) * 1000.f;
00565             _simulator->setParams( _params );
00566         } break;
00567 
00568         case ID_PAR_K_BEND_U: {
00569             _params._k_bend_u = _glWindow->getEditFloat( uid ) / 1000.f;
00570             _simulator->setParams( _params );
00571         } break;
00572 
00573         case ID_PAR_K_BEND_V: {
00574             _params._k_bend_v = _glWindow->getEditFloat( uid ) / 1000.f;
00575             _simulator->setParams( _params );
00576         } break;
00577 
00578         case ID_PAR_K_DAMP: {
00579             _params._k_damp = _glWindow->getEditFloat( uid );
00580             _simulator->setParams( _params );
00581         } break;
00582         case ID_PAR_K_DRAG: {
00583             _params._k_drag = _glWindow->getEditFloat( uid );
00584             _simulator->setParams( _params );
00585         } break;
00586 
00587         case ID_PAR_B_U: {
00588             _params._b_u = _glWindow->getEditFloat( uid );
00589             _simulator->setParams( _params );
00590         } break;
00591 
00592         case ID_PAR_B_V: {
00593             _params._b_v = _glWindow->getEditFloat( uid );
00594             _simulator->setParams( _params );
00595         } break;
00596 
00597         case ID_PAR_RHO: {
00598             _simulator->setDensity( _glWindow->getEditFloat( uid ) );
00599             // Must readd constraints after call to setDensity
00600             setConstraints();
00601         } break;
00602 
00603         case ID_PAR_G: {
00604             _params._g = _glWindow->getEditFloat( uid );
00605             _simulator->setParams( _params );
00606         } break;
00607 
00608         case ID_PAR_RESET: {
00609             _params = SimSimulator::Params();
00610             _rho = DEFAULT_RHO;
00611             _simulator->setParams( _params );
00612             _simulator->setDensity( _rho );
00613             updateParamsUI();
00614         } break;
00615 
00616         case ID_CONSTRAINTS: {
00617             _constraints = static_cast<ConstraintType>(
00618                 _glWindow->getRadioGroup( ID_CONSTRAINTS )
00619             );
00620             setConstraints();
00621         }
00622 
00623         case ID_TRI_STRETCH:
00624         case ID_TRI_SHEAR:
00625         case ID_TRI_BEND: {
00626             _glWindow->postRedisplay();
00627         } break;
00628 
00629         case ID_VERT_VEL:
00630         case ID_VERT_FORCE:
00631         case ID_VERT_FORCE_DAMP:
00632         case ID_VERT_FORCE_STRETCH:
00633         case ID_VERT_FORCE_SHEAR:
00634         case ID_VERT_FORCE_BEND:
00635         case ID_VERT_FORCE_GRAVITY:
00636         case ID_VERT_FORCE_DRAG: {
00637             _glWindow->postRedisplay();
00638         } break;
00639 
00640         case ID_SNAPSHOT: {
00641             _snapFlag = true;
00642         } break;
00643         case ID_QUIT: {
00644             _quitFlag = true;
00645         } break;
00646     }
00647 }
00648 
00649 //------------------------------------------------------------------------------
00650 
00651 void ClothApp::idleReceived()
00652 {
00653     if ( _quitFlag ) {
00654         if ( ! _glWindow.isNull() ) {
00655             _glWindow->close();
00656         }
00657         return;
00658     }
00659 
00660     bool redisplay = false;
00661 
00662     if ( _rewindFlag ) {
00663         setupSimulator();
00664 
00665         _rewindFlag = false;
00666         _freeRunFlag = false;
00667         _stopFlag = false;
00668         _subStepFlag = false;
00669         redisplay = true;
00670     }
00671 
00672     if ( _stopFlag ) {
00673         _subStepFlag = false;
00674         _freeRunFlag = false;
00675         _stopFlag = false;
00676     }
00677     if ( _stepFlag ) {
00678         _simulator->preSubSteps();
00679         _subStepFlag = true;
00680         _stepFlag = false;
00681     }
00682     if ( _freeRunFlag ) {
00683         if ( ! _subStepFlag ) {
00684             _simulator->preSubSteps();
00685             _subStepFlag = true;
00686         }
00687     }
00688     if ( _subStepFlag ) {
00689         if ( _simulator->subStepsDone() ) {
00690             _simulator->postSubSteps();
00691             _subStepFlag = false;
00692             redisplay = true;
00693             // If free run is on, the substeps will restart with next idle.
00694         }
00695         else {
00696             _simulator->subStep();
00697         }
00698     }
00699 
00700     // FIXME: this is pretty naive...
00701     if (
00702         _glWindow->getCheckbox( ID_MOVIE ) &&
00703         BaMath::isLess(
00704             _nextMovieFrame / FPS,
00705             BaTime::instantAsSeconds( _simulator->getTime() )
00706         )
00707     ) {
00708         _snapFlag = true;
00709         ++_nextMovieFrame; 
00710     }
00711 
00712     if ( redisplay ) {
00713         _glWindow->postRedisplay();
00714     }
00715 }
00716 
00717 //------------------------------------------------------------------------------
00718 
00719 RCShdPtr<GeMesh> ClothApp::createRectMesh(
00720     Float size,
00721     UInt32 nbRows,
00722     UInt32 nbCols
00723 ) {
00724     GeMeshBuilder builder;
00725     UInt32 r, c;
00726     builder.preallocVertices( (nbRows + 1) * (nbCols + 1 ) );
00727     builder.preallocTextureVertices( (nbRows + 1) * (nbCols + 1 ) );
00728     builder.preallocFaces( nbRows * nbCols );
00729     for ( r = 0; r <= nbRows; ++r ) {
00730         for ( c = 0; c <= nbCols; ++c ) {
00731             builder.addVertex(
00732                 GePoint( c * size / nbCols, r * size / nbRows, 0 )
00733             );
00734             builder.addTextureVertex(
00735                 GePoint( c * size / nbCols, r * size / nbRows, 0 )
00736             );
00737         }
00738     }
00739     const UInt32 rstride=nbCols+1;
00740     for( r = 0; r < nbRows; ++r ) {
00741         for ( c = 0; c < nbCols; ++c ) {
00742             GeMesh::FaceId fid = builder.addFace(
00743                 r*rstride + c, r*rstride + c+1, (r+1)*rstride + c,
00744                 r*rstride + c, r*rstride + c+1, (r+1)*rstride + c
00745             );
00746             fid = builder.addFace(
00747                 (r+1)*rstride + c, r*rstride + c+1, (r+1)*rstride + c+1,
00748                 (r+1)*rstride + c, r*rstride + c+1, (r+1)*rstride + c+1
00749             );
00750         }
00751     }
00752     return builder.createMesh();
00753 }
00754 
00755 //------------------------------------------------------------------------------
00756 
00757 void ClothApp::initMeshIndices(
00758     const GeMesh& mesh,
00759     std::vector<UInt32>& indices
00760 ) {
00761     GeMesh::FaceConstIterator fi;
00762     indices.clear();
00763     indices.reserve( mesh.getNbFaces() * GeMesh::FaceType::NB_VERTICES );
00764     for ( fi = mesh.beginFace(); fi != mesh.endFace(); ++fi ) {
00765         for ( UInt32 i = 0; i < fi->getNbVertices(); ++i ) {
00766             indices.push_back( fi->getVertexId( i ) );
00767         }
00768     }
00769 }
00770 
00771 //------------------------------------------------------------------------------
00772 
00773 void ClothApp::initGL()
00774 {
00775     ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
00776     ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00777     ::glShadeModel( GL_SMOOTH );
00778 
00779     GL::fog( ColColourRGB::BLACK, 1.f );
00780     ::glFogi( GL_FOG_MODE, GL_LINEAR );
00781     ::glFogf( GL_FOG_DENSITY, .03f );
00782 
00783     ::glDisable( GL_TEXTURE_2D );
00784     ::glEnable( GL_LIGHTING );
00785     ::glEnable( GL_DEPTH_TEST );
00786     ::glDisable( GL_FOG );
00787 
00788     ::glMatrixMode( GL_MODELVIEW );
00789     ::glLoadIdentity();
00790 
00791     ::glEnable( GL_LIGHT0 );
00792 
00793     ::glEnable( GL_COLOR_MATERIAL );
00794     ::glColorMaterial( GL_FRONT, GL_DIFFUSE );
00795 
00796     ::glDisable( GL_BLEND );
00797 }
00798 
00799 //------------------------------------------------------------------------------
00800 
00801 void ClothApp::calcNormals()
00802 {
00803     const RCShdPtr<GeMesh>& mesh = _simulator->getMeshPtr();
00804     std::vector<GeVector> faceNormals( mesh->getNbFaces() );
00805     GeMesh::FaceConstIterator fi;
00806     for ( fi = mesh->beginFace(); fi != mesh->endFace(); ++fi ) {
00807         faceNormals[ fi->getFaceId() ] = fi->calcNormal();
00808     }
00809     // FIXME: meshWE should be a member of clothApp.
00810     GeMeshWingedEdge meshWE( mesh );
00811     for ( GeMesh::VertexId vid = 0; vid < mesh->getNbVertices(); ++vid ) {
00812         GeMeshWingedEdge::VertexFaceIterator vfi;
00813         GeVector normal ( GeVector::ZERO );
00814         UInt32 nbFaces = 0;
00815         for (
00816             vfi = meshWE.beginVertexFace( vid );
00817             vfi != meshWE.endVertexFace( vid );
00818             ++vfi
00819         ) {
00820             normal += faceNormals[ vfi->getFaceId() ];
00821             ++nbFaces;
00822         }
00823         if ( nbFaces > 0 ) {
00824             _meshNormals[ vid ] = normal / nbFaces;
00825         }
00826         else {
00827             _meshNormals[ vid ] = normal;
00828         }
00829     }
00830 }
00831 
00832 //------------------------------------------------------------------------------
00833 
00834 void ClothApp::renderCloth()
00835 {
00836     GL::material( GL_FRONT, GL_SPECULAR, ColColourRGB::WHITE * .2f );
00837     ::glMaterialf( GL_FRONT, GL_SHININESS, 128 );
00838 
00839     const GeMesh& mesh = _simulator->getMesh();
00840     if ( ! _clothTexture.isNull() ) {
00841         ::glBindTexture( GL_TEXTURE_2D, _clothTexture->getTextureId() );
00842         ::glEnable( GL_TEXTURE_2D );
00843         // We seem to have to do this after each glEnable( GL_TEXTURE_2D ),
00844         // at least with Linux GeForce3 drivers. 2003/04/22
00845         ::glTexParameteri(
00846             GL_TEXTURE_2D,
00847             GL_TEXTURE_MIN_FILTER,
00848             GL_LINEAR_MIPMAP_LINEAR
00849         );
00850         ::glTexParameteri(
00851             GL_TEXTURE_2D,
00852             GL_TEXTURE_MAG_FILTER,
00853             GL_LINEAR
00854         );
00855     }
00856 
00857     // Note: polygon smoothing can't possibly smooth our edges nicely.
00858     // Instead, as a post-processing step, we draw the outline of the
00859     // cloth rectangle with a smoothed line. This at least looks a little
00860     // nicer.
00861     ::glEnable( GL_BLEND );
00862     ::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00863     ::glEnable( GL_LINE_SMOOTH );
00864 
00865     ::glEnableClientState( GL_VERTEX_ARRAY );
00866     ::glEnableClientState( GL_NORMAL_ARRAY );
00867     ::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00868     if ( sizeof (Float) == sizeof(GLfloat) ) {
00869         ::glVertexPointer( 3, GL_FLOAT, 0, mesh.getVertexArray() );
00870         ::glNormalPointer( GL_FLOAT, 0, &_meshNormals.front() );
00871         ::glTexCoordPointer( 3, GL_FLOAT, 0, &_meshTextureVertices.front() );
00872     }
00873     else {
00874         ::glVertexPointer( 3, GL_DOUBLE, 0, mesh.getVertexArray() );
00875         ::glNormalPointer( GL_DOUBLE, 0, &_meshNormals.front() );
00876         ::glTexCoordPointer( 3, GL_DOUBLE, 0, &_meshTextureVertices.front() );
00877     }
00878     ::glPushMatrix();
00879         GL::translate( _meshPos );
00880         ::glDrawElements(
00881             GL_TRIANGLES,
00882             _meshIndices.size(),
00883             GL_UNSIGNED_INT,
00884             &_meshIndices.front()
00885         );
00886     ::glPopMatrix();
00887 
00888     ::glDisable( GL_TEXTURE_2D );
00889 
00890     ::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
00891     ::glDisableClientState( GL_NORMAL_ARRAY );
00892     ::glDisableClientState( GL_VERTEX_ARRAY );
00893 
00894     ::glDisable( GL_BLEND );
00895     ::glDisable( GL_LINE_SMOOTH );
00896 }
00897 
00898 //------------------------------------------------------------------------------
00899 
00900 void ClothApp::renderClothOutline()
00901 {
00902     ::glEnable( GL_BLEND );
00903     ::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00904     ::glEnable( GL_LINE_SMOOTH );
00905     ::glPushAttrib( GL_ENABLE_BIT );
00906     ::glDisable( GL_LIGHTING );
00907     GL::colour( ColColourRGB::BLACK );
00908     ::glPushMatrix();
00909         GL::translate( _meshPos );
00910         ::glBegin( GL_LINE_STRIP );
00911             const GeMesh& mesh = _simulator->getMesh();
00912             const UInt32 N( _nbPatches );
00913             UInt32 vid;
00914             for ( vid = 0; vid <= N; ++vid ) {
00915                 GL::vertex( mesh.getVertex( vid ) );
00916             }
00917             for ( vid = 0; vid <= N; ++vid ) {
00918                 GL::vertex( mesh.getVertex( vid * (N+1) + N ) );
00919             }
00920             for ( vid = 0; vid <= N; ++vid ) {
00921                 GL::vertex( mesh.getVertex( N*(N+1) + (N-vid) ) );
00922             }
00923             for ( vid = 0; vid <= N; ++vid ) {
00924                 GL::vertex( mesh.getVertex( (N-vid) * (N+1) ) );
00925             }
00926         ::glEnd();
00927     ::glPopMatrix();
00928     ::glPopAttrib();
00929     ::glDisable( GL_BLEND );
00930     ::glDisable( GL_LINE_SMOOTH );
00931 }
00932 
00933 //------------------------------------------------------------------------------
00934 
00935 void ClothApp::renderClothTriDebug(
00936     bool showStretch,
00937     bool showShear,
00938     bool showBend
00939 ) {
00940     const GeMesh& mesh = _simulator->getMesh();
00941     const Float MAX_EN[ 3 ] = { 10e-3f, 10e-3f, 10e-3f };
00942     const bool show[3] = { showStretch, showShear, showBend };
00943     const SimSimulator::ForceType f[3] = {
00944         SimSimulator::F_STRETCH,
00945         SimSimulator::F_SHEAR,
00946         SimSimulator::F_BEND
00947     };
00948     ::glPushAttrib( GL_ENABLE_BIT );
00949     ::glDisable( GL_LIGHTING );
00950     ::glPushMatrix();
00951         GL::translate( _meshPos );
00952         GeMesh::FaceConstIterator fi;
00953         for ( fi = mesh.beginFace(); fi != mesh.endFace(); ++fi ) {
00954             Float en[3];
00955             Float area = fi->calcArea();
00956             for ( UInt32 i = 0; i < 3; ++i ) {
00957                 en[ i ] = show[ i ] ?
00958                     _simulator->getTriEnergy( f[ i ], fi->getFaceId() ) : 0;
00959                 en[ i ] = std::min( MAX_EN[ i ], en[ i ] ) / MAX_EN[ i ];
00960             }
00961 
00962             ::glColor3f( en[0] / area, en[1] / area, en[2] / area );
00963             ::glBegin( GL_TRIANGLES );
00964                 GL::vertex( fi->getVertex( 0 ) );
00965                 GL::vertex( fi->getVertex( 1 ) );
00966                 GL::vertex( fi->getVertex( 2 ) );
00967             ::glEnd();
00968         }
00969     ::glPopMatrix();
00970     ::glPopAttrib();
00971 }
00972 
00973 //------------------------------------------------------------------------------
00974 
00975 void ClothApp::renderClothVertDebug()
00976 {
00977     bool showvel = _glWindow->getCheckbox( ID_VERT_VEL );
00978     bool showf = _glWindow->getCheckbox( ID_VERT_FORCE );
00979     const UInt32 NB_FS = 5;
00980 #ifdef NDEBUG
00981     bool showfs[ NB_FS ] = { false, false, false, false, false };
00982     bool showdamp = false;
00983 #else
00984     bool showfs[ NB_FS ] = {
00985         _glWindow->getCheckbox( ID_VERT_FORCE_STRETCH ),
00986         _glWindow->getCheckbox( ID_VERT_FORCE_SHEAR ),
00987         _glWindow->getCheckbox( ID_VERT_FORCE_BEND ),
00988         _glWindow->getCheckbox( ID_VERT_FORCE_GRAVITY ),
00989         _glWindow->getCheckbox( ID_VERT_FORCE_DRAG ),
00990     };
00991     bool showdamp = _glWindow->getCheckbox( ID_VERT_FORCE_DAMP );
00992 #endif
00993     if ( !showvel && !showf && !showfs[0] && !showfs[1] && !showfs[2] &&
00994          !showfs[3] && !showfs[4] ) {
00995         return;
00996     }
00997 
00998     const GeMesh& mesh = _simulator->getMesh();
00999     const SimSimulator::ForceType f[ NB_FS ] = {
01000         SimSimulator::F_STRETCH, SimSimulator::F_SHEAR, SimSimulator::F_BEND,
01001         SimSimulator::F_GRAVITY, SimSimulator::F_DRAG
01002     };
01003     const ColColourRGB c[ NB_FS ] = {
01004         ColColourRGB::RED,
01005         ColColourRGB::GREEN,
01006         ColColourRGB::BLUE,
01007         ColColourRGB( .8f, .6f, .2f ),
01008         ColColourRGB( .7f, .2f, .7f )
01009     };
01010 
01011     // Scale factors
01012     const Float SF = 4.f, SV = .2f;
01013     GeMesh::VertexConstIterator vi;
01014     GeMesh::VertexId vid = 0;
01015 
01016     ::glPushAttrib( GL_ENABLE_BIT );
01017     ::glDisable( GL_LIGHTING );
01018     ::glDisable( GL_COLOR_MATERIAL );
01019     ::glPushMatrix();
01020     GL::translate( _meshPos );
01021     ::glBegin( GL_LINES );
01022     for ( vi = mesh.beginVertex(); vi != mesh.endVertex(); ++vi, ++vid ) {
01023         if ( showvel ) {
01024             GL::colour( ColColourRGB::WHITE );
01025             GL::vertex( *vi );
01026             GL::vertex( *vi + SV * _simulator->getVelocity( vid ) );
01027         }
01028         if ( showf ) {
01029             GL::colour( ColColourRGB::YELLOW );
01030             GL::vertex( *vi );
01031             GL::vertex( *vi + SF * _simulator->getForce( vid ) );
01032         }
01033         for ( UInt32 i = 0; i < NB_FS; ++i ) {
01034             if (showfs[ i ] ) {
01035                 GL::colour( c[ i ] );
01036                 GL::vertex( *vi );
01037                 GL::vertex( *vi + SF * _simulator->getForce( f[i], vid ) );
01038                 if ( showdamp ) {
01039                     GL::colour( c[ i ] * .5f );
01040                     GL::vertex( *vi );
01041                     GL::vertex(
01042                         *vi + SF * _simulator->getDampingForce( f[i], vid )
01043                     );
01044                 }
01045             }
01046         }
01047     }
01048     ::glEnd();
01049     ::glPopMatrix();
01050     ::glPopAttrib();
01051 }
01052 
01053 //------------------------------------------------------------------------------
01054 
01055 void ClothApp::renderAxes()
01056 {
01057     ::glPushAttrib( GL_ENABLE_BIT );
01058     ::glDisable( GL_LIGHTING );
01059     ::glBegin( GL_LINES );
01060         GL::colour( ColColourRGB::RED );
01061         ::glVertex3f( 0, 0, 0 );
01062         ::glVertex3f( .1f, 0, 0 );
01063         GL::colour( ColColourRGB::GREEN );
01064         ::glVertex3f( 0, 0, 0 );
01065         ::glVertex3f( 0, .1f, 0 );
01066         GL::colour( ColColourRGB::BLUE );
01067         ::glVertex3f( 0, 0, 0 );
01068         ::glVertex3f( 0, 0, .1f );
01069     ::glEnd();
01070     ::glPopAttrib();
01071 }
01072 
01073 //------------------------------------------------------------------------------
01074 
01075 void ClothApp::renderFloor()
01076 {
01077     // Number of times to repeat texture
01078     UInt32 N = 100;
01079     // Size of floor, in metres
01080     Float size = 100;
01081     if ( !_floorTexture.isNull() ) {
01082         ::glBindTexture( GL_TEXTURE_2D, _floorTexture->getTextureId() );
01083         ::glEnable( GL_TEXTURE_2D );
01084         ::glColor3f( 1, 1, 1 );
01085     }
01086     else {
01087         ::glColor3f( .8f, .7f, .7f );
01088     }
01089     ::glPushMatrix();
01090     ::glTranslatef( 0, 0, -5 );
01091     ::glScalef( size, size, 1 );
01092     ::glBegin( GL_QUADS );
01093         ::glNormal3f( 0.f, 0.f, 1.f );
01094         ::glVertex3f( -size/2, -size/2, 0 );
01095         ::glTexCoord2f( 0, 0 );
01096         ::glVertex3f( size/2, -size/2, 0 );
01097         ::glTexCoord2f( N, 0 );
01098         ::glVertex3f( size/2, size/2, 0 );
01099         ::glTexCoord2f( N, N );
01100         ::glVertex3f( -size/2, size/2, 0 );
01101         ::glTexCoord2f( 0, N );
01102     ::glEnd();
01103     ::glDisable( GL_TEXTURE_2D );
01104     ::glPopMatrix();
01105 }
01106 
01107 //------------------------------------------------------------------------------
01108 
01109 void ClothApp::displayReceived( GfxWindow& )
01110 {
01111     calcNormals();
01112 
01113     char buf[ 256 ];
01114     ::sprintf( buf, "Time: %.3f",
01115         BaTime::instantAsSeconds( _simulator->getTime() )
01116     );
01117     _glWindow->setText( ID_TIME, buf );
01118     ::sprintf( buf, "Stretch: %.3f",
01119         _simulator->getEnergy( SimSimulator::F_STRETCH )
01120     );
01121     _glWindow->setText( ID_EN_STRETCH, buf );
01122     ::sprintf( buf, "Shear: %.3f",
01123         _simulator->getEnergy( SimSimulator::F_SHEAR )
01124     );
01125     _glWindow->setText( ID_EN_SHEAR, buf );
01126     ::sprintf( buf, "Bend: %.3f",
01127         _simulator->getEnergy( SimSimulator::F_BEND )
01128     );
01129     _glWindow->setText( ID_EN_BEND, buf );
01130 
01131     if ( _snapFlag ) {
01132         _snapFlag = false;
01133         ++_snapCount;
01134 
01135         // Snap both with and without debug stuff
01136         snap( false );
01137         snap( true );
01138     }
01139 
01140     render(
01141         _glWindow->getCheckbox( ID_TRI_STRETCH ),
01142         _glWindow->getCheckbox( ID_TRI_SHEAR ),
01143         _glWindow->getCheckbox( ID_TRI_BEND )
01144     );
01145 
01146     _glWindow->swapBuffers();
01147 }
01148 
01149 //------------------------------------------------------------------------------
01150 
01151 void ClothApp::snap( bool debug )
01152 {
01153     char buf[ 256 ];
01154     const char* pre = "snap";
01155     const char* pred = "snapf";
01156     render( debug, debug, debug );
01157 
01158     ::sprintf( buf, "%s%03d.ppm", debug ? pred : pre, _snapCount );
01159     GLint params[4];
01160     ::glGetIntegerv( GL_VIEWPORT, params );
01161     GfxImage image( params[2], params[3], GfxImage::RGB24 );
01162     ::glPixelStorei( GL_PACK_ALIGNMENT, 1 );
01163     ::glReadPixels(
01164         params[0], params[1], params[2], params[3],
01165         GL_RGB,
01166         GL_UNSIGNED_BYTE,
01167         image.getRawData()
01168     );
01169     // Flip image vertically
01170     for ( UInt32 y = 0; y < static_cast<UInt32>( params[ 3 ] ) / 2; ++y ) {
01171         for ( UInt32 x = 0; x < static_cast<UInt32>( params[ 2 ] ); ++x ) {
01172             for ( UInt32 c = 0; c < 3; ++c ) {
01173                 std::swap(
01174                     image.getData( x, y, c ),
01175                     image.getData( x, params[ 3 ] - y - 1, c )
01176                 );
01177             }
01178         }
01179     }
01180     GfxImageWriterPNM writer( GfxImageWriterPNM::BINARY );
01181     writer.writeImage( buf, image );
01182 }
01183 
01184 //------------------------------------------------------------------------------
01185 
01186 void ClothApp::render( bool debug_stretch, bool debug_shear, bool debug_bend )
01187 {
01188     ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
01189 
01190     ::glLoadIdentity();
01191 
01192     ::glTranslatef( 0, 0, _glWindow->getTranslateZ( ID_ZOOM ) / 10 );
01193     GL::multMatrix( _glWindow->getRotate( ID_CAMERA_ROTATE ) );
01194 
01195     ::glPushMatrix();
01196         GL::multMatrix( _glWindow->getRotate( ID_LIGHT ) );
01197         GL::lightPosition( GL_LIGHT0, GeVector::Z );
01198         GL::light( GL_LIGHT0, GL_DIFFUSE, ColColourRGB::WHITE );
01199         GL::light( GL_LIGHT0, GL_SPECULAR, ColColourRGB::WHITE );
01200     ::glPopMatrix();
01201 
01202     if ( _glWindow->getCheckbox( ID_AXES ) ) {
01203         renderAxes();
01204     }
01205     //::glFogf( GL_FOG_DENSITY, _glWindow->getTranslateZ( ID_FOG_START ) / 10 );
01206     ::glFogf( GL_FOG_START, _glWindow->getTranslateZ( ID_FOG_START ) / 10 );
01207     ::glFogf( GL_FOG_END, _glWindow->getTranslateZ( ID_FOG_END ) / 10 );
01208 
01209     ::glEnable( GL_FOG );
01210     //renderFloor();
01211     ::glDisable( GL_FOG );
01212 
01213     ::glEnable( GL_POLYGON_OFFSET_FILL );
01214     ::glPolygonOffset( 1, 1 );
01215     if ( debug_stretch || debug_shear || debug_bend ) {
01216         renderClothTriDebug( debug_stretch, debug_shear, debug_bend );
01217         ::glDisable( GL_POLYGON_OFFSET_FILL );
01218     }
01219     else {
01220         //::glColor3f( .6f, .1f, .3f );
01221         ::glColor3f( 1, 1, 1 );
01222         ::glEnable( GL_FOG );
01223         renderCloth();
01224         ::glDisable( GL_FOG );
01225         ::glDisable( GL_POLYGON_OFFSET_FILL );
01226         renderClothOutline();
01227     }
01228 
01229     if ( _glWindow->getCheckbox( ID_WIREFRAME ) ) {
01230         ::glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
01231         ::glPushAttrib( GL_ENABLE_BIT );
01232         ::glDisable( GL_LIGHTING );
01233         ::glColor3f( .1f, .1f, .4f );
01234         renderCloth();
01235         ::glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
01236         ::glPopAttrib();
01237     }
01238 
01239     renderClothVertDebug();
01240 }
01241 
01242 //------------------------------------------------------------------------------
01243 
01244 void ClothApp::keyPressed(
01245     GfxWindow&,
01246     GfxWindow::KeyID keyId,
01247     GfxWindow::ModBitfield modifiers
01248 ) {
01249     switch( keyId ) {
01250         case GfxWindow::KB_ESCAPE: {
01251             _quitFlag = true;
01252         } break;
01253 
01254         case GfxWindow::KB_SPACE: {
01255             _stepFlag = true;
01256         } break;
01257 
01258         default: {
01259         } break;
01260     }
01261 }
01262 
01263 //------------------------------------------------------------------------------
01264 
01265 void ClothApp::windowResized(
01266     GfxWindow&, UInt32 x, UInt32 y, UInt32 width, UInt32 height
01267 ) {
01268     ::glMatrixMode( GL_PROJECTION );
01269     ::glLoadIdentity();
01270     ::glViewport( x, y, width, height );
01271     ::gluPerspective( 45.0f, static_cast<Float>( width )/height, 0.1f, 1000.f );
01272     ::gluLookAt( 0, 0, 1, 0, 0, 0, 0, 1, 0 );
01273 
01274     ::glMatrixMode( GL_MODELVIEW );
01275     ::glLoadIdentity();
01276 }
01277 
01278 
01279 ////////////////////////////////////////////////////////////////////////////////
01280 // GLOBALS
01281 
01282 //------------------------------------------------------------------------------
01283 
01284 int main()
01285 {
01286     ClothApp app;
01287     app.runApp();
01288     return 0;
01289 }

Generated on Fri May 2 16:51:12 2003 for Freecloth by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002