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 = 10.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_CORNERS ),
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_CORNERS: {
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_CORNERS2: {
00271             _simulator->setPosConstraintFull( 0 );
00272             _simulator->setPosConstraintPlane( N, GeVector::Z );
00273             _simulator->setPosConstraintFull( N*(N+1) );
00274             _simulator->setPosConstraintFull( (N+1)*(N+1)-1 );
00275         } break;
00276 
00277         case CON_CORNERYANK: {
00278             _simulator->setPosConstraintFull( 0 );
00279             _simulator->setVelConstraint( 0, -.1f * GeVector::X );
00280         } break;
00281 
00282         case CON_TABLE_SQUARE: {
00283             const UInt32 C = BaMath::roundUInt32( std::max( 1.f, N*5/11.f ) );
00284             const UInt32 x = (N-C)/2;
00285             for (UInt32 i = 0; i <= C; ++i ) for ( UInt32 j = 0; j <= C; ++j ) {
00286                 _simulator->setPosConstraintFull( (x + i)*(N+1) + x + j );
00287             }
00288         } break;
00289 
00290         case CON_TABLE_CIRCLE: {
00291             const Float r = 7/11.f;
00292             for (UInt32 i = 0; i <= N; ++i ) for ( UInt32 j = 0; j <= N; ++j ) {
00293                 Float x = 2*i/static_cast<Float>( N ) - 1;
00294                 Float y = 2*j/static_cast<Float>( N ) - 1;
00295                 if ( x*x + y*y < r*r ) {
00296                     _simulator->setPosConstraintFull( i*(N+1) + j );
00297                 }
00298             }
00299         } break;
00300     }
00301 }
00302 
00303 //------------------------------------------------------------------------------
00304 
00305 void ClothApp::setupWindow()
00306 {
00307     // Create GL window, monitor for events
00308     _glWindow = RCShdPtr<GfxGLWindowGLUI>( new GfxGLWindowGLUI(
00309         _config, "Cloth test app"
00310     ) );
00311     _glWindow->addObserver( *this );
00312     _glWindow->enableIdleEvents( true );
00313 
00314     enum {
00315         PANEL_CAMERA,
00316         PANEL_SCENE, PANEL_SCENE2,
00317         PANEL_EXEC,
00318         PANEL_PARAMS,
00319         PANEL_CON,
00320         PANEL_SNAPS, PANEL_SNAPS2,
00321         PANEL_DEBUG,
00322         PANEL_ENERGY,
00323         PANEL_TRI,
00324         PANEL_VERT
00325     };
00326     _glWindow->addGroup( GfxGLWindowGLUI::BORDER_RAISED, PANEL_CAMERA );
00327     _glWindow->addRotate( "Camera", ID_CAMERA_ROTATE, PANEL_CAMERA );
00328     _glWindow->addColumn( false, PANEL_CAMERA );
00329     _glWindow->addTranslate(
00330         "Zoom", GfxGLWindowGLUI::TR_Z, ID_ZOOM, PANEL_CAMERA
00331     );
00332     _glWindow->setTranslateZ( ID_ZOOM, -5 );
00333 
00334     _glWindow->addRollout( "Scene", PANEL_SCENE, false );
00335     _glWindow->addGroup(
00336         GfxGLWindowGLUI::BORDER_NONE, PANEL_SCENE2, PANEL_SCENE
00337     );
00338         _glWindow->addRotate( "Light", ID_LIGHT, PANEL_SCENE2 );
00339         _glWindow->addColumn( false, PANEL_SCENE2 );
00340     _glWindow->addCheckbox( "Axes", ID_AXES, PANEL_SCENE );
00341     _glWindow->setCheckbox( ID_AXES, false );
00342     _glWindow->addCheckbox( "Wireframe", ID_WIREFRAME, PANEL_SCENE );
00343     _glWindow->setCheckbox( ID_WIREFRAME, false );
00344     _glWindow->addEditFloat( "Cloth size: ", ID_CLOTH_SIZE, PANEL_SCENE );
00345     _glWindow->setEditFloat( ID_CLOTH_SIZE, _clothSize );
00346 
00347     _glWindow->addPanel( "Simulation", PANEL_EXEC );
00348     _glWindow->addButton( "Run", ID_RUN, PANEL_EXEC );
00349     _glWindow->addButton( "Stop", ID_STOP, PANEL_EXEC );
00350     _glWindow->addButton( "Step", ID_STEP, PANEL_EXEC );
00351     _glWindow->addButton( "Rewind", ID_REWIND, PANEL_EXEC );
00352     _glWindow->addText( "Time: ", ID_TIME, PANEL_EXEC );
00353     _glWindow->addEditInt( "Cloth patches: ", ID_PATCHES, PANEL_EXEC );
00354     _glWindow->setEditInt( ID_PATCHES, _nbPatches );
00355     _glWindow->setEditIntLimits( ID_PATCHES, 1, 200 );
00356     _glWindow->addEditFloat( "Time step: ", ID_TIMESTEP, PANEL_EXEC );
00357     _glWindow->setEditFloat( ID_TIMESTEP, _h );
00358     _glWindow->addEditFloat( "Tolerance: ", ID_PCG_TOLERANCE, PANEL_EXEC );
00359     _glWindow->setEditFloat( ID_PCG_TOLERANCE, _pcgTolerance );
00360 
00361     _glWindow->addRollout( "Parameters", PANEL_PARAMS, false );
00362     _glWindow->addEditFloat( "k_stretch (k)", ID_PAR_K_STRETCH, PANEL_PARAMS );
00363     _glWindow->addEditFloat( "k_shear (k)", ID_PAR_K_SHEAR, PANEL_PARAMS );
00364     _glWindow->addEditFloat( "k_bend_u (m)", ID_PAR_K_BEND_U, PANEL_PARAMS );
00365     _glWindow->addEditFloat( "k_bend_v (m)", ID_PAR_K_BEND_V, PANEL_PARAMS );
00366     _glWindow->addEditFloat( "k_damp", ID_PAR_K_DAMP, PANEL_PARAMS );
00367     _glWindow->addEditFloat( "k_drag", ID_PAR_K_DRAG, PANEL_PARAMS );
00368     _glWindow->addEditFloat( "b_u", ID_PAR_B_U, PANEL_PARAMS );
00369     _glWindow->addEditFloat( "b_v", ID_PAR_B_V, PANEL_PARAMS );
00370     _glWindow->addEditFloat( "density", ID_PAR_RHO, PANEL_PARAMS );
00371     _glWindow->addEditFloat( "gravity", ID_PAR_G, PANEL_PARAMS );
00372     _glWindow->addButton( "Reset", ID_PAR_RESET, PANEL_PARAMS );
00373     updateParamsUI();
00374 
00375     _glWindow->addRollout( "Constraints", PANEL_CON, false );
00376     _glWindow->addRadioGroup( ID_CONSTRAINTS, PANEL_CON );
00377     _glWindow->addRadioButton( ID_CONSTRAINTS, "None" );
00378     _glWindow->addRadioButton( ID_CONSTRAINTS, "Centre" );
00379     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners" );
00380     _glWindow->addRadioButton( ID_CONSTRAINTS, "Corners (3.5)" );
00381     _glWindow->addRadioButton( ID_CONSTRAINTS, "Yank corner" );
00382     _glWindow->addRadioButton( ID_CONSTRAINTS, "Square table" );
00383     _glWindow->addRadioButton( ID_CONSTRAINTS, "Circular table" );
00384     _glWindow->setRadioGroup( ID_CONSTRAINTS, _constraints );
00385 
00386     _glWindow->addRollout( "Snapshots", PANEL_SNAPS, false );
00387     _glWindow->addButton( "Snapshot", ID_SNAPSHOT, PANEL_SNAPS );
00388     _glWindow->addCheckbox( "Movie", ID_MOVIE, PANEL_SNAPS );
00389     _glWindow->setCheckbox( ID_MOVIE, false );
00390     _glWindow->addGroup(
00391         GfxGLWindowGLUI::BORDER_NONE, PANEL_SNAPS2, PANEL_SNAPS
00392     );
00393         _glWindow->addTranslate(
00394             "Fog start", GfxGLWindowGLUI::TR_Z, ID_FOG_START, PANEL_SNAPS2
00395         );
00396         _glWindow->setTranslateZ( ID_FOG_START, 10 );
00397         _glWindow->addColumn( false, PANEL_SNAPS2 );
00398         _glWindow->addTranslate(
00399             "Fog end", GfxGLWindowGLUI::TR_Z, ID_FOG_END, PANEL_SNAPS2
00400         );
00401         _glWindow->setTranslateZ( ID_FOG_END, 100 );
00402 
00403     _glWindow->addRollout( "Debug", PANEL_DEBUG, false );
00404     _glWindow->addPanel( "Energy", PANEL_ENERGY, PANEL_DEBUG );
00405     _glWindow->addText( "Stretch: ", ID_EN_STRETCH, PANEL_ENERGY );
00406     _glWindow->addText( "Shear: ", ID_EN_SHEAR, PANEL_ENERGY );
00407     _glWindow->addText( "Bend: ", ID_EN_BEND, PANEL_ENERGY );
00408 
00409     _glWindow->addRollout( "Triangles", PANEL_TRI, false, PANEL_DEBUG );
00410     _glWindow->addCheckbox( "Stretch energy", ID_TRI_STRETCH, PANEL_TRI );
00411     _glWindow->setCheckbox( ID_TRI_STRETCH, false );
00412     _glWindow->addCheckbox( "Shear energy", ID_TRI_SHEAR, PANEL_TRI );
00413     _glWindow->setCheckbox( ID_TRI_SHEAR, false );
00414     _glWindow->addCheckbox( "Bend energy", ID_TRI_BEND, PANEL_TRI );
00415     _glWindow->setCheckbox( ID_TRI_BEND, false );
00416 
00417     _glWindow->addRollout( "Vertices", PANEL_VERT, false, PANEL_DEBUG );
00418     _glWindow->addCheckbox( "Velocity", ID_VERT_VEL, PANEL_VERT );
00419     _glWindow->setCheckbox( ID_VERT_VEL, false );
00420     _glWindow->addCheckbox( "Total force", ID_VERT_FORCE, PANEL_VERT );
00421     _glWindow->setCheckbox( ID_VERT_FORCE, false );
00422 #if !defined( NDEBUG )
00423     _glWindow->addCheckbox( "Damping forces", ID_VERT_FORCE_DAMP, PANEL_VERT );
00424     _glWindow->setCheckbox( ID_VERT_FORCE_DAMP, false );
00425     _glWindow->addCheckbox( "Stretch force", ID_VERT_FORCE_STRETCH, PANEL_VERT);
00426     _glWindow->setCheckbox( ID_VERT_FORCE_STRETCH, false );
00427     _glWindow->addCheckbox( "Shear force", ID_VERT_FORCE_SHEAR, PANEL_VERT );
00428     _glWindow->setCheckbox( ID_VERT_FORCE_SHEAR, false );
00429     _glWindow->addCheckbox( "Bend force", ID_VERT_FORCE_BEND, PANEL_VERT );
00430     _glWindow->setCheckbox( ID_VERT_FORCE_BEND, false );
00431     _glWindow->addCheckbox( "Gravity force", ID_VERT_FORCE_GRAVITY, PANEL_VERT );
00432     _glWindow->setCheckbox( ID_VERT_FORCE_GRAVITY, false );
00433     _glWindow->addCheckbox( "Drag force", ID_VERT_FORCE_DRAG, PANEL_VERT );
00434     _glWindow->setCheckbox( ID_VERT_FORCE_DRAG, false );
00435 #endif
00436 
00437     _glWindow->addButton( "Quit", ID_QUIT );
00438 
00439     initGL();
00440 }
00441 
00442 //------------------------------------------------------------------------------
00443 
00444 void ClothApp::updateParamsUI()
00445 {
00446     _glWindow->setEditFloat( ID_PAR_K_STRETCH, _params._k_stretch / 1000.f );
00447     _glWindow->setEditFloat( ID_PAR_K_SHEAR, _params._k_shear / 1000.f );
00448     _glWindow->setEditFloat( ID_PAR_K_BEND_U, _params._k_bend_u * 1000.f );
00449     _glWindow->setEditFloat( ID_PAR_K_BEND_V, _params._k_bend_v * 1000.f );
00450     _glWindow->setEditFloat( ID_PAR_K_DAMP, _params._k_damp );
00451     _glWindow->setEditFloat( ID_PAR_K_DRAG, _params._k_drag );
00452     _glWindow->setEditFloat( ID_PAR_B_U, _params._b_u );
00453     _glWindow->setEditFloat( ID_PAR_B_V, _params._b_v );
00454     _glWindow->setEditFloat( ID_PAR_RHO, _rho );
00455     _glWindow->setEditFloat( ID_PAR_G, _params._g );
00456 }
00457 
00458 //------------------------------------------------------------------------------
00459 
00460 void ClothApp::closeReceived( GfxWindow& )
00461 {
00462     _glWindow->removeObserver( *this );
00463     ::exit( 0 );
00464 }
00465 
00466 //------------------------------------------------------------------------------
00467 
00468 void ClothApp::uiReceived( GfxWindow&, UInt32 uid )
00469 {
00470     switch ( uid ) {
00471         case ID_CAMERA_ROTATE:
00472         case ID_ZOOM:
00473         case ID_LIGHT:
00474         case ID_FOG_START:
00475         case ID_FOG_END:
00476         case ID_AXES:
00477         case ID_WIREFRAME: {
00478             _glWindow->postRedisplay();
00479         } break;
00480         case ID_PATCHES:
00481         case ID_CLOTH_SIZE: {
00482             UInt32 oldNbPatches = _nbPatches;
00483             if ( uid == ID_PATCHES ) {
00484                 _nbPatches = _glWindow->getEditInt( ID_PATCHES );
00485             }
00486             else {
00487                 _clothSize = _glWindow->getEditFloat( ID_CLOTH_SIZE );
00488             }
00489             
00490             // Special case: if the user doubles the number of patches,
00491             // then we can refine and keep the current state.
00492             RCShdPtr<GeMesh> refinedMesh;
00493             Float ratio( static_cast<Float>( _nbPatches ) / oldNbPatches );
00494             if (
00495                 _nbPatches > oldNbPatches &&
00496                 BaMath::isInteger( ratio ) &&
00497                 BaMath::isPow2( BaMath::roundUInt32( ratio ) )
00498             ) {
00499                 refinedMesh = _simulator->getMeshPtr();
00500                 for ( ; oldNbPatches < _nbPatches; oldNbPatches *= 2 ) {
00501                     refinedMesh = refineMesh(
00502                         *refinedMesh,
00503                         oldNbPatches,
00504                         oldNbPatches
00505                     );
00506                 }
00507             }
00508 
00509             setupMesh();
00510             setupSimulator();
00511             if ( ! refinedMesh.isNull() ) {
00512                 _simulator->setMesh( *refinedMesh );
00513             }
00514             _glWindow->postRedisplay();
00515         } break;
00516 
00517         case ID_RUN: {
00518             _freeRunFlag = true;
00519         } break;
00520         case ID_STOP: {
00521             _stopFlag = true;
00522         } break;
00523         case ID_STEP: {
00524             _stepFlag = true;
00525         } break;
00526         case ID_REWIND: {
00527             _rewindFlag = true;
00528             _glWindow->postRedisplay();
00529         } break;
00530         case ID_TIMESTEP: {
00531             _h = _glWindow->getEditFloat( uid );
00532             _simulator->setTimestep( _h );
00533         } break;
00534         case ID_PCG_TOLERANCE: {
00535             _pcgTolerance = _glWindow->getEditFloat( uid );
00536             _simulator->setPCGTolerance( _pcgTolerance );
00537         } break;
00538 
00539         case ID_PAR_K_STRETCH: {
00540             _params._k_stretch = _glWindow->getEditFloat( uid ) * 1000.f;
00541             _simulator->setParams( _params );
00542         } break;
00543 
00544         case ID_PAR_K_SHEAR: {
00545             _params._k_shear = _glWindow->getEditFloat( uid ) * 1000.f;
00546             _simulator->setParams( _params );
00547         } break;
00548 
00549         case ID_PAR_K_BEND_U: {
00550             _params._k_bend_u = _glWindow->getEditFloat( uid ) / 1000.f;
00551             _simulator->setParams( _params );
00552         } break;
00553 
00554         case ID_PAR_K_BEND_V: {
00555             _params._k_bend_v = _glWindow->getEditFloat( uid ) / 1000.f;
00556             _simulator->setParams( _params );
00557         } break;
00558 
00559         case ID_PAR_K_DAMP: {
00560             _params._k_damp = _glWindow->getEditFloat( uid );
00561             _simulator->setParams( _params );
00562         } break;
00563         case ID_PAR_K_DRAG: {
00564             _params._k_drag = _glWindow->getEditFloat( uid );
00565             _simulator->setParams( _params );
00566         } break;
00567 
00568         case ID_PAR_B_U: {
00569             _params._b_u = _glWindow->getEditFloat( uid );
00570             _simulator->setParams( _params );
00571         } break;
00572 
00573         case ID_PAR_B_V: {
00574             _params._b_v = _glWindow->getEditFloat( uid );
00575             _simulator->setParams( _params );
00576         } break;
00577 
00578         case ID_PAR_RHO: {
00579             _simulator->setDensity( _glWindow->getEditFloat( uid ) );
00580             // Must readd constraints after call to setDensity
00581             setConstraints();
00582         } break;
00583 
00584         case ID_PAR_G: {
00585             _params._g = _glWindow->getEditFloat( uid );
00586             _simulator->setParams( _params );
00587         } break;
00588 
00589         case ID_PAR_RESET: {
00590             _params = SimSimulator::Params();
00591             _rho = DEFAULT_RHO;
00592             _simulator->setParams( _params );
00593             _simulator->setDensity( _rho );
00594             updateParamsUI();
00595         } break;
00596 
00597         case ID_CONSTRAINTS: {
00598             _constraints = static_cast<ConstraintType>(
00599                 _glWindow->getRadioGroup( ID_CONSTRAINTS )
00600             );
00601             setConstraints();
00602         }
00603 
00604         case ID_TRI_STRETCH:
00605         case ID_TRI_SHEAR:
00606         case ID_TRI_BEND: {
00607             _glWindow->postRedisplay();
00608         } break;
00609 
00610         case ID_VERT_VEL:
00611         case ID_VERT_FORCE:
00612         case ID_VERT_FORCE_DAMP:
00613         case ID_VERT_FORCE_STRETCH:
00614         case ID_VERT_FORCE_SHEAR:
00615         case ID_VERT_FORCE_BEND:
00616         case ID_VERT_FORCE_GRAVITY:
00617         case ID_VERT_FORCE_DRAG: {
00618             _glWindow->postRedisplay();
00619         } break;
00620 
00621         case ID_SNAPSHOT: {
00622             _snapFlag = true;
00623         } break;
00624         case ID_QUIT: {
00625             _quitFlag = true;
00626         } break;
00627     }
00628 }
00629 
00630 //------------------------------------------------------------------------------
00631 
00632 void ClothApp::idleReceived()
00633 {
00634     if ( _quitFlag ) {
00635         if ( ! _glWindow.isNull() ) {
00636             _glWindow->close();
00637         }
00638         return;
00639     }
00640 
00641     bool redisplay = false;
00642 
00643     if ( _rewindFlag ) {
00644         setupSimulator();
00645 
00646         _rewindFlag = false;
00647         _freeRunFlag = false;
00648         _stopFlag = false;
00649         _subStepFlag = false;
00650         redisplay = true;
00651     }
00652 
00653     if ( _stopFlag ) {
00654         _subStepFlag = false;
00655         _freeRunFlag = false;
00656         _stopFlag = false;
00657     }
00658     if ( _stepFlag ) {
00659         _simulator->preSubSteps();
00660         _subStepFlag = true;
00661         _stepFlag = false;
00662     }
00663     if ( _freeRunFlag ) {
00664         if ( ! _subStepFlag ) {
00665             _simulator->preSubSteps();
00666             _subStepFlag = true;
00667         }
00668     }
00669     if ( _subStepFlag ) {
00670         if ( _simulator->subStepsDone() ) {
00671             _simulator->postSubSteps();
00672             _subStepFlag = false;
00673             redisplay = true;
00674             // If free run is on, the substeps will restart with next idle.
00675         }
00676         else {
00677             _simulator->subStep();
00678         }
00679     }
00680 
00681     // FIXME: this is pretty naive...
00682     if (
00683         _glWindow->getCheckbox( ID_MOVIE ) &&
00684         BaMath::isLess(
00685             _nextMovieFrame / FPS,
00686             BaTime::instantAsSeconds( _simulator->getTime() )
00687         )
00688     ) {
00689         _snapFlag = true;
00690         ++_nextMovieFrame; 
00691     }
00692 
00693     if ( redisplay ) {
00694         _glWindow->postRedisplay();
00695     }
00696 }
00697 
00698 //------------------------------------------------------------------------------
00699 
00700 RCShdPtr<GeMesh> ClothApp::createRectMesh(
00701     Float size,
00702     UInt32 nbRows,
00703     UInt32 nbCols
00704 ) {
00705     GeMeshBuilder builder;
00706     UInt32 r, c;
00707     builder.preallocVertices( (nbRows + 1) * (nbCols + 1 ) );
00708     builder.preallocTextureVertices( (nbRows + 1) * (nbCols + 1 ) );
00709     builder.preallocFaces( nbRows * nbCols );
00710     for ( r = 0; r <= nbRows; ++r ) {
00711         for ( c = 0; c <= nbCols; ++c ) {
00712             builder.addVertex(
00713                 GePoint( c * size / nbCols, r * size / nbRows, 0 )
00714             );
00715             builder.addTextureVertex(
00716                 GePoint( c * size / nbCols, r * size / nbRows, 0 )
00717             );
00718         }
00719     }
00720     const UInt32 rstride=nbCols+1;
00721     for( r = 0; r < nbRows; ++r ) {
00722         for ( c = 0; c < nbCols; ++c ) {
00723             GeMesh::FaceId fid = builder.addFace(
00724                 r*rstride + c, r*rstride + c+1, (r+1)*rstride + c,
00725                 r*rstride + c, r*rstride + c+1, (r+1)*rstride + c
00726             );
00727             fid = builder.addFace(
00728                 (r+1)*rstride + c, r*rstride + c+1, (r+1)*rstride + c+1,
00729                 (r+1)*rstride + c, r*rstride + c+1, (r+1)*rstride + c+1
00730             );
00731         }
00732     }
00733     return builder.createMesh();
00734 }
00735 
00736 //------------------------------------------------------------------------------
00737 
00738 void ClothApp::initMeshIndices(
00739     const GeMesh& mesh,
00740     std::vector<UInt32>& indices
00741 ) {
00742     GeMesh::FaceConstIterator fi;
00743     indices.clear();
00744     indices.reserve( mesh.getNbFaces() * GeMesh::FaceType::NB_VERTICES );
00745     for ( fi = mesh.beginFace(); fi != mesh.endFace(); ++fi ) {
00746         for ( UInt32 i = 0; i < fi->getNbVertices(); ++i ) {
00747             indices.push_back( fi->getVertexId( i ) );
00748         }
00749     }
00750 }
00751 
00752 //------------------------------------------------------------------------------
00753 
00754 void ClothApp::initGL()
00755 {
00756     ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
00757     ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00758     ::glShadeModel( GL_SMOOTH );
00759 
00760     GL::fog( ColColourRGB::BLACK, 1.f );
00761     ::glFogi( GL_FOG_MODE, GL_LINEAR );
00762     ::glFogf( GL_FOG_DENSITY, .03f );
00763 
00764     ::glDisable( GL_TEXTURE_2D );
00765     ::glEnable( GL_LIGHTING );
00766     ::glEnable( GL_DEPTH_TEST );
00767     ::glDisable( GL_FOG );
00768     //::glEnable( GL_CULL_FACE );
00769 
00770     ::glMatrixMode( GL_MODELVIEW );
00771     ::glLoadIdentity();
00772 
00773     ::glEnable( GL_LIGHT0 );
00774 
00775     ::glEnable( GL_COLOR_MATERIAL );
00776     ::glColorMaterial( GL_FRONT, GL_DIFFUSE );
00777 
00778     ::glDisable( GL_BLEND );
00779 #if 0
00780     ::glEnable( GL_BLEND );
00781     ::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00782     ::glEnable( GL_LINE_SMOOTH );
00783     ::glEnable( GL_POLYGON_SMOOTH );
00784 #endif
00785 }
00786 
00787 //------------------------------------------------------------------------------
00788 
00789 void ClothApp::calcNormals()
00790 {
00791     const RCShdPtr<GeMesh>& mesh = _simulator->getMeshPtr();
00792     std::vector<GeVector> faceNormals( mesh->getNbFaces() );
00793     GeMesh::FaceConstIterator fi;
00794     for ( fi = mesh->beginFace(); fi != mesh->endFace(); ++fi ) {
00795         faceNormals[ fi->getFaceId() ] = fi->calcNormal();
00796     }
00797     // FIXME: meshWE should be a member of clothApp.
00798     GeMeshWingedEdge meshWE( mesh );
00799     for ( GeMesh::VertexId vid = 0; vid < mesh->getNbVertices(); ++vid ) {
00800         GeMeshWingedEdge::VertexFaceIterator vfi;
00801         GeVector normal ( GeVector::ZERO );
00802         UInt32 nbFaces = 0;
00803         for (
00804             vfi = meshWE.beginVertexFace( vid );
00805             vfi != meshWE.endVertexFace( vid );
00806             ++vfi
00807         ) {
00808             normal += faceNormals[ vfi->getFaceId() ];
00809             ++nbFaces;
00810         }
00811         if ( nbFaces > 0 ) {
00812             _meshNormals[ vid ] = normal / nbFaces;
00813         }
00814         else {
00815             _meshNormals[ vid ] = normal;
00816         }
00817     }
00818 }
00819 
00820 //------------------------------------------------------------------------------
00821 
00822 void ClothApp::renderCloth()
00823 {
00824     GL::material( GL_FRONT, GL_SPECULAR, ColColourRGB::WHITE * .2f );
00825     ::glMaterialf( GL_FRONT, GL_SHININESS, 128 );
00826 
00827     const GeMesh& mesh = _simulator->getMesh();
00828     if ( ! _clothTexture.isNull() ) {
00829         ::glBindTexture( GL_TEXTURE_2D, _clothTexture->getTextureId() );
00830         ::glEnable( GL_TEXTURE_2D );
00831         // We seem to have to do this after each glEnable( GL_TEXTURE_2D ),
00832         // at least with Linux GeForce3 drivers. 2003/04/22
00833         ::glTexParameteri(
00834             GL_TEXTURE_2D,
00835             GL_TEXTURE_MIN_FILTER,
00836             GL_LINEAR_MIPMAP_LINEAR
00837         );
00838         ::glTexParameteri(
00839             GL_TEXTURE_2D,
00840             GL_TEXTURE_MAG_FILTER,
00841             GL_LINEAR
00842         );
00843     }
00844 
00845     // Note: polygon smoothing can't possibly smooth our edges nicely.
00846     // Instead, as a post-processing step, we draw the outline of the
00847     // cloth rectangle with a smoothed line. This at least looks a little
00848     // nicer.
00849     ::glEnable( GL_BLEND );
00850     ::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00851     ::glEnable( GL_LINE_SMOOTH );
00852 
00853     ::glEnableClientState( GL_VERTEX_ARRAY );
00854     ::glEnableClientState( GL_NORMAL_ARRAY );
00855     ::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00856     if ( sizeof (Float) == sizeof(GLfloat) ) {
00857         ::glVertexPointer( 3, GL_FLOAT, 0, mesh.getVertexArray() );
00858         ::glNormalPointer( GL_FLOAT, 0, &_meshNormals.front() );
00859         ::glTexCoordPointer( 3, GL_FLOAT, 0, &_meshTextureVertices.front() );
00860     }
00861     else {
00862         ::glVertexPointer( 3, GL_DOUBLE, 0, mesh.getVertexArray() );
00863         ::glNormalPointer( GL_DOUBLE, 0, &_meshNormals.front() );
00864         ::glTexCoordPointer( 3, GL_DOUBLE, 0, &_meshTextureVertices.front() );
00865     }
00866     ::glPushMatrix();
00867         GL::translate( _meshPos );
00868         ::glDrawElements(
00869             GL_TRIANGLES,
00870             _meshIndices.size(),
00871             GL_UNSIGNED_INT,
00872             &_meshIndices.front()
00873         );
00874     ::glPopMatrix();
00875 
00876     ::glDisable( GL_TEXTURE_2D );
00877 
00878     ::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
00879     ::glDisableClientState( GL_NORMAL_ARRAY );
00880     ::glDisableClientState( GL_VERTEX_ARRAY );
00881 
00882     ::glDisable( GL_BLEND );
00883     ::glDisable( GL_LINE_SMOOTH );
00884 }
00885 
00886 //------------------------------------------------------------------------------
00887 
00888 void ClothApp::renderClothOutline()
00889 {
00890     ::glEnable( GL_BLEND );
00891     ::glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00892     ::glEnable( GL_LINE_SMOOTH );
00893     ::glPushAttrib( GL_ENABLE_BIT );
00894     ::glDisable( GL_LIGHTING );
00895     GL::colour( ColColourRGB::BLACK );
00896     ::glPushMatrix();
00897         GL::translate( _meshPos );
00898         ::glBegin( GL_LINE_STRIP );
00899             const GeMesh& mesh = _simulator->getMesh();
00900             const UInt32 N( _nbPatches );
00901             UInt32 vid;
00902             for ( vid = 0; vid <= N; ++vid ) {
00903                 GL::vertex( mesh.getVertex( vid ) );
00904             }
00905             for ( vid = 0; vid <= N; ++vid ) {
00906                 GL::vertex( mesh.getVertex( vid * (N+1) + N ) );
00907             }
00908             for ( vid = 0; vid <= N; ++vid ) {
00909                 GL::vertex( mesh.getVertex( N*(N+1) + (N-vid) ) );
00910             }
00911             for ( vid = 0; vid <= N; ++vid ) {
00912                 GL::vertex( mesh.getVertex( (N-vid) * (N+1) ) );
00913             }
00914         ::glEnd();
00915     ::glPopMatrix();
00916     ::glPopAttrib();
00917     ::glDisable( GL_BLEND );
00918     ::glDisable( GL_LINE_SMOOTH );
00919 }
00920 
00921 //------------------------------------------------------------------------------
00922 
00923 void ClothApp::renderClothTriDebug(
00924     bool showStretch,
00925     bool showShear,
00926     bool showBend
00927 ) {
00928     const GeMesh& mesh = _simulator->getMesh();
00929     const Float MAX_EN[ 3 ] = { 10e-3f, 10e-3f, 10e-3f };
00930     const bool show[3] = { showStretch, showShear, showBend };
00931     const SimSimulator::ForceType f[3] = {
00932         SimSimulator::F_STRETCH,
00933         SimSimulator::F_SHEAR,
00934         SimSimulator::F_BEND
00935     };
00936     ::glPushAttrib( GL_ENABLE_BIT );
00937     ::glDisable( GL_LIGHTING );
00938     ::glPushMatrix();
00939         ::glTranslatef( _meshPos._x, _meshPos._y, _meshPos._z );
00940         GeMesh::FaceConstIterator fi;
00941         for ( fi = mesh.beginFace(); fi != mesh.endFace(); ++fi ) {
00942             Float en[3];
00943             for ( UInt32 i = 0; i < 3; ++i ) {
00944                 en[ i ] = show[ i ] ?
00945                     _simulator->getTriEnergy( f[ i ], fi->getFaceId() ) : 0;
00946                 en[ i ] = std::min( MAX_EN[ i ], en[ i ] ) / MAX_EN[ i ];
00947             }
00948 
00949             ::glColor3f( en[0], en[1], en[2] );
00950             ::glBegin( GL_TRIANGLES );
00951                 GL::vertex( fi->getVertex( 0 ) );
00952                 GL::vertex( fi->getVertex( 1 ) );
00953                 GL::vertex( fi->getVertex( 2 ) );
00954             ::glEnd();
00955         }
00956     ::glPopMatrix();
00957     ::glPopAttrib();
00958 }
00959 
00960 //------------------------------------------------------------------------------
00961 
00962 void ClothApp::renderClothVertDebug()
00963 {
00964     bool showvel = _glWindow->getCheckbox( ID_VERT_VEL );
00965     bool showf = _glWindow->getCheckbox( ID_VERT_FORCE );
00966     const UInt32 NB_FS = 5;
00967 #ifdef NDEBUG
00968     bool showfs[ NB_FS ] = { false, false, false, false, false };
00969     bool showdamp = false;
00970 #else
00971     bool showfs[ NB_FS ] = {
00972         _glWindow->getCheckbox( ID_VERT_FORCE_STRETCH ),
00973         _glWindow->getCheckbox( ID_VERT_FORCE_SHEAR ),
00974         _glWindow->getCheckbox( ID_VERT_FORCE_BEND ),
00975         _glWindow->getCheckbox( ID_VERT_FORCE_GRAVITY ),
00976         _glWindow->getCheckbox( ID_VERT_FORCE_DRAG ),
00977     };
00978     bool showdamp = _glWindow->getCheckbox( ID_VERT_FORCE_DAMP );
00979 #endif
00980     if ( !showvel && !showf && !showfs[0] && !showfs[1] && !showfs[2] &&
00981          !showfs[3] && !showfs[4] ) {
00982         return;
00983     }
00984 
00985     const GeMesh& mesh = _simulator->getMesh();
00986     const SimSimulator::ForceType f[ NB_FS ] = {
00987         SimSimulator::F_STRETCH, SimSimulator::F_SHEAR, SimSimulator::F_BEND,
00988         SimSimulator::F_GRAVITY, SimSimulator::F_DRAG
00989     };
00990     const ColColourRGB c[ NB_FS ] = {
00991         ColColourRGB::RED,
00992         ColColourRGB::GREEN,
00993         ColColourRGB::BLUE,
00994         ColColourRGB( .8f, .6f, .2f ),
00995         ColColourRGB( .7f, .2f, .7f )
00996     };
00997 
00998     // Scale factors
00999     const Float SF = 4.f, SV = .2f;
01000     GeMesh::VertexConstIterator vi;
01001     GeMesh::VertexId vid = 0;
01002 
01003     ::glPushAttrib( GL_ENABLE_BIT );
01004     ::glDisable( GL_LIGHTING );
01005     ::glDisable( GL_COLOR_MATERIAL );
01006     ::glPushMatrix();
01007     ::glTranslatef( _meshPos._x, _meshPos._y, _meshPos._z );
01008     ::glBegin( GL_LINES );
01009     for ( vi = mesh.beginVertex(); vi != mesh.endVertex(); ++vi, ++vid ) {
01010         if ( showvel ) {
01011             GL::colour( ColColourRGB::WHITE );
01012             GL::vertex( *vi );
01013             GL::vertex( *vi + SV * _simulator->getVelocity( vid ) );
01014         }
01015         if ( showf ) {
01016             GL::colour( ColColourRGB::YELLOW );
01017             GL::vertex( *vi );
01018             GL::vertex( *vi + SF * _simulator->getForce( vid ) );
01019         }
01020         for ( UInt32 i = 0; i < NB_FS; ++i ) {
01021             if (showfs[ i ] ) {
01022                 GL::colour( c[ i ] );
01023                 GL::vertex( *vi );
01024                 GL::vertex( *vi + SF * _simulator->getForce( f[i], vid ) );
01025                 if ( showdamp ) {
01026                     GL::colour( c[ i ] * .5f );
01027                     GL::vertex( *vi );
01028                     GL::vertex(
01029                         *vi + SF * _simulator->getDampingForce( f[i], vid )
01030                     );
01031                 }
01032             }
01033         }
01034     }
01035     ::glEnd();
01036     ::glPopMatrix();
01037     ::glPopAttrib();
01038 }
01039 
01040 //------------------------------------------------------------------------------
01041 
01042 void ClothApp::renderAxes()
01043 {
01044     ::glPushAttrib( GL_ENABLE_BIT );
01045     ::glDisable( GL_LIGHTING );
01046     ::glBegin( GL_LINES );
01047         GL::colour( ColColourRGB::RED );
01048         ::glVertex3f( 0, 0, 0 );
01049         ::glVertex3f( .1f, 0, 0 );
01050         GL::colour( ColColourRGB::GREEN );
01051         ::glVertex3f( 0, 0, 0 );
01052         ::glVertex3f( 0, .1f, 0 );
01053         GL::colour( ColColourRGB::BLUE );
01054         ::glVertex3f( 0, 0, 0 );
01055         ::glVertex3f( 0, 0, .1f );
01056     ::glEnd();
01057     ::glPopAttrib();
01058 }
01059 
01060 //------------------------------------------------------------------------------
01061 
01062 void ClothApp::renderFloor()
01063 {
01064     // Number of times to repeat texture
01065     UInt32 N = 100;
01066     // Size of floor, in metres
01067     Float size = 100;
01068     if ( !_floorTexture.isNull() ) {
01069         ::glBindTexture( GL_TEXTURE_2D, _floorTexture->getTextureId() );
01070         ::glEnable( GL_TEXTURE_2D );
01071         ::glColor3f( 1, 1, 1 );
01072     }
01073     else {
01074         ::glColor3f( .8f, .7f, .7f );
01075     }
01076     ::glPushMatrix();
01077     ::glTranslatef( 0, 0, -5 );
01078     ::glScalef( size, size, 1 );
01079     ::glBegin( GL_QUADS );
01080         ::glNormal3f( 0.f, 0.f, 1.f );
01081         ::glVertex3f( -size/2, -size/2, 0 );
01082         ::glTexCoord2f( 0, 0 );
01083         ::glVertex3f( size/2, -size/2, 0 );
01084         ::glTexCoord2f( N, 0 );
01085         ::glVertex3f( size/2, size/2, 0 );
01086         ::glTexCoord2f( N, N );
01087         ::glVertex3f( -size/2, size/2, 0 );
01088         ::glTexCoord2f( 0, N );
01089     ::glEnd();
01090     ::glDisable( GL_TEXTURE_2D );
01091     ::glPopMatrix();
01092 }
01093 
01094 //------------------------------------------------------------------------------
01095 
01096 void ClothApp::displayReceived( GfxWindow& )
01097 {
01098     calcNormals();
01099 
01100     char buf[ 256 ];
01101     ::sprintf( buf, "Time: %.3f",
01102         BaTime::instantAsSeconds( _simulator->getTime() )
01103     );
01104     _glWindow->setText( ID_TIME, buf );
01105     ::sprintf( buf, "Stretch: %.3f",
01106         _simulator->getEnergy( SimSimulator::F_STRETCH )
01107     );
01108     _glWindow->setText( ID_EN_STRETCH, buf );
01109     ::sprintf( buf, "Shear: %.3f",
01110         _simulator->getEnergy( SimSimulator::F_SHEAR )
01111     );
01112     _glWindow->setText( ID_EN_SHEAR, buf );
01113     ::sprintf( buf, "Bend: %.3f",
01114         _simulator->getEnergy( SimSimulator::F_BEND )
01115     );
01116     _glWindow->setText( ID_EN_BEND, buf );
01117 
01118     if ( _snapFlag ) {
01119         _snapFlag = false;
01120         ++_snapCount;
01121 
01122         // Snap both with and without debug stuff
01123         snap( false );
01124         snap( true );
01125     }
01126 
01127     render(
01128         _glWindow->getCheckbox( ID_TRI_STRETCH ),
01129         _glWindow->getCheckbox( ID_TRI_SHEAR ),
01130         _glWindow->getCheckbox( ID_TRI_BEND )
01131     );
01132 
01133     _glWindow->swapBuffers();
01134 }
01135 
01136 //------------------------------------------------------------------------------
01137 
01138 void ClothApp::snap( bool debug )
01139 {
01140     char buf[ 256 ];
01141     const char* pre = "snap";
01142     const char* pred = "snapf";
01143     render( debug, debug, debug );
01144 
01145     ::sprintf( buf, "%s%03d.ppm", debug ? pred : pre, _snapCount );
01146     GLint params[4];
01147     ::glGetIntegerv( GL_VIEWPORT, params );
01148     GfxImage image( params[2], params[3], GfxImage::RGB24 );
01149     ::glPixelStorei( GL_PACK_ALIGNMENT, 1 );
01150     ::glReadPixels(
01151         params[0], params[1], params[2], params[3],
01152         GL_RGB,
01153         GL_UNSIGNED_BYTE,
01154         image.getRawData()
01155     );
01156     // Flip image vertically
01157     for ( UInt32 y = 0; y < static_cast<UInt32>( params[ 3 ] ) / 2; ++y ) {
01158         for ( UInt32 x = 0; x < static_cast<UInt32>( params[ 2 ] ); ++x ) {
01159             for ( UInt32 c = 0; c < 3; ++c ) {
01160                 std::swap(
01161                     image.getData( x, y, c ),
01162                     image.getData( x, params[ 3 ] - y - 1, c )
01163                 );
01164             }
01165         }
01166     }
01167     GfxImageWriterPNM writer( GfxImageWriterPNM::BINARY );
01168     writer.writeImage( buf, image );
01169 }
01170 
01171 //------------------------------------------------------------------------------
01172 
01173 void ClothApp::render( bool debug_stretch, bool debug_shear, bool debug_bend )
01174 {
01175     ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
01176 
01177     ::glLoadIdentity();
01178 
01179     ::glTranslatef( 0, 0, _glWindow->getTranslateZ( ID_ZOOM ) );
01180     GL::multMatrix( _glWindow->getRotate( ID_CAMERA_ROTATE ) );
01181 
01182     ::glPushMatrix();
01183         GL::multMatrix( _glWindow->getRotate( ID_LIGHT ) );
01184         GL::lightPosition( GL_LIGHT0, GeVector::Z );
01185         GL::light( GL_LIGHT0, GL_DIFFUSE, ColColourRGB::WHITE );
01186         GL::light( GL_LIGHT0, GL_SPECULAR, ColColourRGB::WHITE );
01187     ::glPopMatrix();
01188 
01189     if ( _glWindow->getCheckbox( ID_AXES ) ) {
01190         renderAxes();
01191     }
01192     ::glEnable( GL_FOG );
01193     renderFloor();
01194     ::glDisable( GL_FOG );
01195 
01196     ::glFogf( GL_FOG_DENSITY, _glWindow->getTranslateZ( ID_FOG_START ) );
01197     ::glFogf( GL_FOG_START, _glWindow->getTranslateZ( ID_FOG_START ) );
01198     ::glFogf( GL_FOG_END, _glWindow->getTranslateZ( ID_FOG_END ) );
01199 
01200     ::glEnable( GL_POLYGON_OFFSET_FILL );
01201     ::glPolygonOffset( 1, 1 );
01202     if ( debug_stretch || debug_shear || debug_bend ) {
01203         renderClothTriDebug( debug_stretch, debug_shear, debug_bend );
01204     }
01205     else {
01206         //::glColor3f( .6f, .1f, .3f );
01207         ::glColor3f( 1, 1, 1 );
01208         ::glEnable( GL_FOG );
01209         renderCloth();
01210         ::glDisable( GL_FOG );
01211     }
01212     ::glDisable( GL_POLYGON_OFFSET_FILL );
01213     renderClothOutline();
01214 
01215     if ( _glWindow->getCheckbox( ID_WIREFRAME ) ) {
01216         ::glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
01217         ::glPushAttrib( GL_ENABLE_BIT );
01218         ::glDisable( GL_LIGHTING );
01219         ::glColor3f( .1f, .1f, .4f );
01220         renderCloth();
01221         ::glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
01222         ::glPopAttrib();
01223     }
01224 
01225     renderClothVertDebug();
01226 }
01227 
01228 //------------------------------------------------------------------------------
01229 
01230 void ClothApp::keyPressed(
01231     GfxWindow&,
01232     GfxWindow::KeyID keyId,
01233     GfxWindow::ModBitfield modifiers
01234 ) {
01235     switch( keyId ) {
01236         case GfxWindow::KB_ESCAPE: {
01237             _quitFlag = true;
01238         } break;
01239 
01240         case GfxWindow::KB_SPACE: {
01241             _stepFlag = true;
01242         } break;
01243 
01244         default: {
01245         } break;
01246     }
01247 }
01248 
01249 //------------------------------------------------------------------------------
01250 
01251 void ClothApp::windowResized(
01252     GfxWindow&, UInt32 x, UInt32 y, UInt32 width, UInt32 height
01253 ) {
01254     ::glMatrixMode( GL_PROJECTION );
01255     ::glLoadIdentity();
01256     ::glViewport( x, y, width, height );
01257     ::gluPerspective( 45.0f, static_cast<Float>( width )/height, 0.1f, 1000.f );
01258     ::gluLookAt( 0, 0, 1, 0, 0, 0, 0, 1, 0 );
01259 
01260     ::glMatrixMode( GL_MODELVIEW );
01261     ::glLoadIdentity();
01262 }
01263 
01264 
01265 ////////////////////////////////////////////////////////////////////////////////
01266 // GLOBALS
01267 
01268 //------------------------------------------------------------------------------
01269 
01270 int main()
01271 {
01272     ClothApp app;
01273     app.runApp();
01274     return 0;
01275 }

Generated on Wed Apr 23 15:58:50 2003 for Freecloth by doxygen1.3-rc3