00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
00166 RCShdPtr<ResConfigRegistryR> reader =
00167 ResConfigRegistryR::create( "clothApp" );
00168 _config.load( *reader );
00169
00170 setupWindow();
00171
00172
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
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
00224
00225
00226
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
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
00510
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
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
00694 }
00695 else {
00696 _simulator->subStep();
00697 }
00698 }
00699
00700
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
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
00844
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
00858
00859
00860
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
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
01078 UInt32 N = 100;
01079
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
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
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
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
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
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
01281
01282
01283
01284 int main()
01285 {
01286 ClothApp app;
01287 app.runApp();
01288 return 0;
01289 }