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 = 10.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_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
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_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
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
00491
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
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
00675 }
00676 else {
00677 _simulator->subStep();
00678 }
00679 }
00680
00681
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
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
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
00832
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
00846
00847
00848
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
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
01065 UInt32 N = 100;
01066
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
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
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
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
01267
01268
01269
01270 int main()
01271 {
01272 ClothApp app;
01273 app.runApp();
01274 return 0;
01275 }