1 #ifndef STAGES_H 2 #define STAGES_H 3 4 #include "resources.h" 5 #include "povs_generator.h" 6 #include "simple_renderer.h" 7 8 #include <common/meshmodel.h> 9 10 #include <vcg/simplex/vertex/component_ocf.h> 11 12 namespace vs 13 { 14 /* stages base class */ 15 class Stage 16 { 17 18 public: Stage(Resources * resources)19 Stage( Resources* resources ) 20 { 21 this->resources = resources; 22 } 23 24 virtual void go( void ) = 0; 25 26 protected: 27 Resources* resources; 28 std::vector< PixelData* > tmpData; 29 std::vector< PixelData* > samplers; 30 Program* prog; 31 32 // data facilities collectAttributesData(QString prefix)33 void collectAttributesData( QString prefix ) 34 { 35 QString tmpAttribute; 36 PixelData* pData = 0; 37 38 for( unsigned int i=0; i<resources->attributes.size(); i++ ) 39 { 40 tmpAttribute = resources->attributes[ i ]; 41 pData = resources->buffers[ prefix + tmpAttribute ]; 42 assert( pData ); 43 tmpData.push_back( pData ); 44 } 45 } 46 collectData(QString dataName)47 void collectData( QString dataName ) 48 { 49 PixelData* pData = resources->buffers[ dataName ]; 50 assert( pData ); 51 tmpData.push_back( pData ); 52 } 53 getAttributesDataName(QString prefix,std::vector<QString> & target)54 void getAttributesDataName( QString prefix, std::vector< QString >& target ) 55 { 56 target.clear(); 57 for( unsigned int i=0; i<resources->attributes.size(); i++ ) 58 { 59 target.push_back( prefix + resources->attributes[i] ); 60 } 61 } 62 63 // drawing facilities drawFullscreenQuad(void)64 void drawFullscreenQuad( void ) 65 { 66 glBegin (GL_QUADS); 67 glVertex3i( -1, -1, -1); 68 glVertex3i( 1, -1, -1); 69 glVertex3i( 1, 1, -1); 70 glVertex3i( -1, 1, -1); 71 glEnd (); 72 } 73 feedCoords(GLint side,GLint count)74 void feedCoords( GLint side, GLint count ) 75 { 76 GLint x = 0, y = 0; 77 glBegin( GL_POINTS ); 78 for( GLint i=0; i<count; i++ ) 79 { 80 glVertex2i( x, y ); 81 x++; 82 if( x == side ) 83 { 84 x = 0; 85 y++; 86 } 87 } 88 glEnd(); 89 } 90 91 // shader facilities bindSampler(QString samplerName,PixelData * pData)92 void bindSampler( QString samplerName, PixelData* pData ) 93 { 94 const string str = samplerName.toStdString(); 95 const GLchar* c = (const GLchar*)( str.c_str() ); 96 GLint loc = glGetUniformLocation( prog->programId, c ); 97 GLint textureUnit = (GLint)samplers.size(); 98 pData->bind( textureUnit ); 99 glUniform1i( loc, textureUnit ); 100 samplers.push_back( pData ); 101 } 102 bindSampler(QString dataName,QString samplerName)103 void bindSampler( QString dataName, QString samplerName ) 104 { 105 PixelData* pData = resources->buffers[ dataName ]; 106 assert( pData && prog ); 107 bindSampler( samplerName, pData ); 108 } 109 bindAttributeSamplers(QString prefix)110 void bindAttributeSamplers( QString prefix ) 111 { 112 QString samplerName; 113 114 for( unsigned int i=0; i<resources->attributes.size(); i++ ) 115 { 116 samplerName = prefix + resources->attributes[i]; 117 bindSampler( samplerName, samplerName ); 118 } 119 } 120 unbindSamplers(void)121 void unbindSamplers( void ) 122 { 123 for( unsigned int i=0; i<samplers.size(); i++ ) 124 { 125 samplers[i]->unbind(); 126 } 127 samplers.clear(); 128 } 129 uploadFloat(QString uniformName,GLfloat value)130 void uploadFloat( QString uniformName, GLfloat value ) 131 { 132 const string str = uniformName.toStdString(); 133 const GLchar* c = (const GLchar*)( str.c_str() ); 134 GLint loc = glGetUniformLocation( prog->programId, c ); 135 glUniform1f( loc, value ); 136 } 137 uploadInt(QString uniformName,GLint value)138 void uploadInt( QString uniformName, GLint value ) 139 { 140 const string str = uniformName.toStdString(); 141 const GLchar* c = (const GLchar*)( str.c_str() ); 142 GLint loc = glGetUniformLocation( prog->programId, c ); 143 glUniform1i( loc, value ); 144 } 145 146 // dumping utils 147 void dumpAttributes( QString prefix, QString suffix = "" ) 148 { 149 std::vector< QString > names; 150 getAttributesDataName( prefix, names ); 151 for( unsigned int i=0; i<names.size(); i++ ) 152 { 153 PixelData* pData = resources->buffers[ names[i] ]; 154 assert( pData ); 155 pData->dumpToFile( names[i] + suffix + ".txt", 0 ); 156 } 157 } 158 159 void dump( QString dataName, QString prefix = "", int lod = 0 ) 160 { 161 PixelData* pData = resources->buffers[ dataName ]; 162 assert( pData ); 163 pData->dumpToFile( prefix + dataName + ".txt", lod ); 164 } 165 }; 166 167 /* attribute extraction stage */ 168 class AttributesExtractor: public Stage 169 { 170 171 public: 172 typedef CMeshO::ScalarType ScalarType; 173 typedef vcg::Point3< ScalarType > MyPoint; 174 typedef vcg::Shot< ScalarType > ShotType; 175 AttributesExtractor(MeshModel * inputMeshModel,Resources * res)176 AttributesExtractor( MeshModel* inputMeshModel, Resources* res ) 177 :Stage( res ), renderer( &(inputMeshModel->cm) ) 178 { 179 this->inputMeshModel = inputMeshModel; 180 this->inputMesh = &(inputMeshModel->cm); 181 currentPov = 0; 182 meshCenter = inputMesh->bbox.Center(); 183 184 if( resources->params->useCustomPovs ) 185 { 186 assert( resources->params->customPovs.size() > 0 ); 187 } 188 else 189 { 190 // generate povs 191 MyPoint coneAxis( res->params->coneAxis[0], 192 res->params->coneAxis[1], 193 res->params->coneAxis[2] ); 194 // NB: the cone axis must be inverted due to the ortographic projection, 195 // that sets a negative near plane 196 coneAxis = -coneAxis; 197 coneAxis.Normalize(); 198 ScalarType coneGap = ( res->params->coneGap / 180.0f ) * PI; 199 orthoRadius = ( inputMesh->bbox.Diag() / 2 ) * 1.2; 200 PovsGenerator< ScalarType >::generatePovs( res->params->povs, orthoRadius, meshCenter, coneAxis, coneGap, povs ); 201 generateUpVectors( povs, meshCenter, upVectors ); 202 } 203 } 204 go(void)205 virtual void go( void ) 206 { 207 if( resources->params->useCustomPovs ) 208 { 209 Pov& newPov = resources->params->customPovs[ currentPov ]; 210 ScalarType nearPlane, farPlane; 211 GlShot< ShotType >::GetNearFarPlanes( newPov.first, inputMesh->bbox, nearPlane, farPlane ); 212 GlShot< ShotType >::SetView( newPov.first, nearPlane, farPlane ); 213 214 glEnable( GL_SCISSOR_TEST ); 215 Box2i& scissorBox = newPov.second; 216 Point2i min = scissorBox.min; 217 int width = scissorBox.DimX(); 218 int height = scissorBox.DimY(); 219 glScissor( (GLint)min.X(), (GLint)min.Y(), (GLsizei)width, (GLsizei)height ); 220 } 221 else 222 { 223 glMatrixMode( GL_PROJECTION ); 224 glLoadIdentity(); 225 glOrtho( -orthoRadius, orthoRadius, -orthoRadius, orthoRadius, -orthoRadius, orthoRadius ); 226 227 MyPoint& p = povs[ currentPov ]; 228 MyPoint& up = upVectors[ currentPov ]; 229 glMatrixMode( GL_MODELVIEW ); 230 glLoadIdentity(); 231 gluLookAt( meshCenter.X(), meshCenter.Y(), meshCenter.Z(), 232 p.X(), p.Y(), p.Z(), 233 up.X(), up.Y(), up.Z() ); 234 } 235 236 // filling all attribute-maps except color 237 tmpData.clear(); 238 collectAttributesData( "input_" ); 239 collectData( "start_mask" ); 240 resources->fbo->load( tmpData ); 241 PixelData* depthBuffer = resources->buffers[ "depth_buffer" ]; 242 resources->fbo->loadDepth( depthBuffer->textureId ); 243 244 Program* startShader = resources->shaders[ "start" ]; 245 startShader->load(); 246 247 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 248 renderer.render( ); 249 //resources->fbo->screenshots( "start" ); 250 251 startShader->unload(); 252 resources->fbo->unload(); 253 254 // generate color-map with the vcg renderer 255 tmpData.clear(); 256 collectData( "input_color" ); 257 resources->fbo->load( tmpData ); 258 resources->fbo->loadDepth( depthBuffer->textureId ); 259 260 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 261 inputMeshModel->Render 262 ( resources->params->cmDrawMode, 263 resources->params->cmColorMode, 264 resources->params->cmTextureMode ); 265 /* 266 static int k = 0; 267 resources->fbo->screenshots( QString::number(k++).toStdString() ); 268 */ 269 270 resources->fbo->unload(); 271 272 if( resources->params->useCustomPovs ) 273 { 274 glDisable( GL_SCISSOR_TEST ); 275 } 276 277 // save and then reset modelview and projection matrix 278 glGetFloatv( GL_MODELVIEW_MATRIX, resources->mvMatrix ); 279 glGetFloatv( GL_PROJECTION_MATRIX, resources->projMatrix ); 280 281 if( resources->params->useCustomPovs ) 282 GlShot< ShotType >::UnsetView(); 283 284 glMatrixMode( GL_PROJECTION ); 285 glLoadIdentity(); 286 glMatrixMode( GL_MODELVIEW ); 287 glLoadIdentity(); 288 } 289 nextPov(void)290 bool nextPov( void ) 291 { 292 currentPov++; 293 int si = (resources->params->useCustomPovs)?resources->params->customPovs.size():(int)povs.size(); 294 return ( currentPov < si ); 295 } 296 297 int currentPov; 298 299 private: 300 MeshModel* inputMeshModel; 301 CMeshO* inputMesh; 302 SimpleRenderer< CMeshO > renderer; 303 std::vector< MyPoint > povs; 304 std::vector< MyPoint > upVectors; 305 MyPoint meshCenter; 306 ScalarType orthoRadius; 307 int dummyPov; 308 generateUpVectors(std::vector<MyPoint> & povs,MyPoint center,std::vector<MyPoint> & target)309 void generateUpVectors 310 ( std::vector< MyPoint >& povs, 311 MyPoint center, 312 std::vector< MyPoint >& target ) 313 { 314 srand( 12345 ); 315 target.clear(); 316 MyPoint dir; 317 MyPoint up; 318 bool ok = false; 319 320 for( unsigned int i=0; i<povs.size(); i++ ) 321 { 322 dir = (povs[i] - center).Normalize(); 323 324 ok = false; 325 while( !ok ) 326 { 327 up.X() = rand() % 1000; 328 up.Y() = rand() % 1000; 329 up.Z() = rand() % 1000; 330 up.Normalize(); 331 ok = ( vcg::math::Abs(up.dot( dir )) < 0.8 ); 332 } 333 334 target.push_back( up ); 335 } 336 } 337 }; 338 339 // a general compactor stage that uses hystogram pyramids 340 class Compactor: public Stage 341 { 342 343 public: 344 Compactor( Resources* res, QString pyramid, QString inputPrefix, QString outputPrefix, bool oneInput = false ) Stage(res)345 : Stage( res ) 346 { 347 this->pyramidName = pyramid; 348 this->inputPrefix = inputPrefix; 349 this->outputPrefix = outputPrefix; 350 this->oneInput = oneInput; 351 compactorShader = generateCompactionShader(); 352 } 353 go(void)354 virtual void go( void ) 355 { 356 buildPyramid(); 357 compact(); 358 } 359 360 private: 361 QString pyramidName; 362 QString inputPrefix; 363 QString outputPrefix; 364 PixelData* pyramid; 365 Program* compactorShader; 366 bool oneInput; 367 buildPyramid(void)368 void buildPyramid( void ) 369 { 370 pyramid = resources->buffers[ pyramidName ]; 371 assert( pyramid ); 372 pyramid->generateMipmaps(); 373 int levels = pyramid->getMipmapLevels(); 374 tmpData.clear(); 375 tmpData.push_back( pyramid ); 376 prog = resources->shaders[ "level_builder" ]; 377 prog->load(); 378 bindSampler( pyramidName, "pyramid" ); 379 380 for( int i=1; i<levels; i++ ) 381 { 382 resources->fbo->load( tmpData, i ); 383 uploadInt( "level", (GLint)i ); 384 drawFullscreenQuad(); 385 resources->fbo->unload(); 386 } 387 388 unbindSamplers(); 389 prog->unload(); 390 391 /* 392 for( int i=0; i<5; i++ ) 393 { 394 pyramid->dumpToFile( QString("pyramid") + QString::number(i) + ".txt", i ); 395 } 396 */ 397 } 398 compact(void)399 void compact( void ) 400 { 401 // prepare output buffers 402 GLint elements = getPyramidElements(); 403 tmpData.clear(); 404 405 if( oneInput ) 406 { 407 collectData( outputPrefix ); 408 } 409 else 410 { 411 collectAttributesData( outputPrefix ); 412 } 413 414 for( unsigned int i=0; i<tmpData.size(); i++ ) 415 { 416 tmpData[i]->resizeToFit( elements ); 417 } 418 resources->fbo->load( tmpData ); 419 420 // load shader and set uniforms 421 prog = compactorShader; 422 prog->load(); 423 samplers.clear(); 424 425 if( oneInput ) 426 { 427 bindSampler( inputPrefix, inputPrefix ); 428 } 429 else 430 { 431 bindAttributeSamplers( inputPrefix ); 432 } 433 bindSampler( "pyramid", pyramid ); 434 uploadInt( "samples", elements ); 435 uploadInt( "max_lod", (GLint)(pyramid->getMipmapLevels() - 1) ); 436 QString tmpName = oneInput? outputPrefix : (outputPrefix + resources->attributes[0]); 437 PixelData* outputPrototype = resources->buffers[ tmpName ]; 438 assert( outputPrototype ); 439 uploadInt( "tex_side", outputPrototype->side ); 440 441 glClear( GL_COLOR_BUFFER_BIT ); 442 drawFullscreenQuad(); 443 444 // free resources 445 unbindSamplers(); 446 pyramid->unbind(); 447 prog->unload(); 448 resources->fbo->unload(); 449 450 // update elements 451 std::vector< QString > outputNames; 452 453 if( oneInput ) 454 { 455 outputNames.push_back( outputPrefix ); 456 } 457 else 458 { 459 getAttributesDataName( outputPrefix, outputNames ); 460 } 461 462 for( unsigned int i=0; i<outputNames.size(); i++ ) 463 { 464 resources->buffers[ outputNames[i] ]->elements = elements; 465 //resources->buffers[ outputNames[i] ]->dumpToFile( outputNames[i] + ".txt" ); 466 } 467 } 468 generateCompactionShader(void)469 Program* generateCompactionShader( void ) 470 { 471 string simpleVertexProgram = "void main(){ gl_Position = ftransform(); }"; 472 std::vector< QString > inputs; 473 if( oneInput ) 474 { 475 inputs.push_back( inputPrefix ); 476 } 477 else 478 { 479 getAttributesDataName( inputPrefix, inputs ); 480 } 481 482 string offsets = "const ivec2 offset[4]={ivec2(0, 0), ivec2(1, 0), ivec2(0, 1), ivec2(1, 1)};"; 483 string shaderTemplate = getCompactionTemplate(); 484 string samplersDeclarations = "", outputString = ""; 485 486 string outputTemplate = string("val = texelFetch( %s, org_map_coords, 0 );\n") + 487 "gl_FragData[%d] = val;\n\n"; 488 const char* cc = outputTemplate.c_str(); 489 char buf[250]; 490 491 for( unsigned int i=0; i<inputs.size(); i++ ) 492 { 493 sprintf( buf, "uniform sampler2D %s;\n", inputs[i].toStdString().c_str() ); 494 samplersDeclarations += buf; 495 sprintf( buf, cc, inputs[i].toStdString().c_str(), i ); 496 outputString += buf; 497 } 498 499 string fragmentProgram = offsets + samplersDeclarations 500 + shaderTemplate + outputString + "}"; 501 502 return new Program( simpleVertexProgram, fragmentProgram ); 503 } 504 505 /* this is the template used to istantiate the compaction shader. A compaction 506 shader is composed of the offsets string, the samplers declarations, this 507 template and the output string. 508 */ getCompactionTemplate(void)509 string getCompactionTemplate( void ) 510 { 511 const static string templateStr = STRINGFY( 512 513 uniform sampler2D pyramid; 514 uniform int samples; 515 uniform int tex_side; 516 uniform int max_lod; 517 518 void main() 519 { 520 ivec2 coords = ivec2( gl_FragCoord.xy ); 521 int key_index = coords.y * tex_side + coords.x; 522 523 if( key_index >= samples ) discard; 524 525 ivec2 org_map_coords = ivec2( 0, 0 ); 526 ivec2 map_coords = ivec2( 0, 0 ); 527 float pyramid_val = 0.0; 528 float lower_bound = 0.0; 529 float upper_bound = 0.0; 530 bool found = false; 531 int offset_index = 0; 532 float descent_value = 0.0; 533 534 vec4 val = vec4( 0.0, 0.0, 0.0, 0.0 ); 535 for( int i=max_lod; i>=0; i-- ) 536 { 537 org_map_coords *= 2; 538 offset_index = 0; 539 lower_bound = descent_value; 540 found = false; 541 while( !found && offset_index < 4 ) 542 { 543 map_coords = org_map_coords + offset[ offset_index ]; 544 if ( i > 0 ) 545 { 546 pyramid_val = texelFetch( pyramid, map_coords, i ).x; 547 } 548 else 549 { 550 pyramid_val = 1.0f - (texelFetch( pyramid, map_coords, i ).x); 551 } 552 upper_bound = lower_bound + pyramid_val; 553 found = ( key_index >= lower_bound && key_index < upper_bound ); 554 offset_index++; 555 descent_value = lower_bound; 556 lower_bound = upper_bound; 557 } 558 559 org_map_coords = map_coords; 560 } 561 }); 562 563 return templateStr.substr( 0, templateStr.length() - 1 ); 564 } 565 getPyramidElements(void)566 GLint getPyramidElements( void ) 567 { 568 GLint maxLevel = pyramid->getMipmapLevels() - 1; 569 GLfloat* top = pyramid->download( maxLevel ); 570 GLint elements = 0; 571 572 if( top[1] < (GLfloat)0.5f ) 573 { 574 elements = (GLint)(top[0]); 575 } 576 else 577 { 578 elements = (GLint)0; 579 } 580 581 delete top; 582 return elements; 583 } 584 }; 585 586 class ConeFilter: public Stage 587 { 588 589 public: ConeFilter(Resources * res)590 ConeFilter( Resources* res ): Stage( res ) 591 { 592 float coneAngle = res->params->frontFacingConeU; 593 float rads = ( (coneAngle/2) * PI ) / 180.0f; 594 thresholdCosine = (GLfloat)(cos( rads )); 595 } 596 go()597 virtual void go() 598 { 599 tmpData.clear(); 600 collectData( "out_mask" ); 601 resources->fbo->load( tmpData ); 602 prog = resources->shaders[ "cone_filter" ]; 603 prog->load(); 604 samplers.clear(); 605 bindSampler( "start_mask", "start_mask" ); 606 bindSampler( "input_eye_normal", "input_eye_normal" ); 607 uploadFloat( "thresholdCosine", thresholdCosine ); 608 609 drawFullscreenQuad(); 610 611 unbindSamplers(); 612 prog->unload(); 613 resources->fbo->unload(); 614 } 615 616 private: 617 GLfloat thresholdCosine; 618 619 }; 620 621 class Killer: public Stage 622 { 623 624 public: Killer(Resources * res)625 Killer( Resources* res ) : Stage( res ) 626 { 627 628 } 629 go()630 virtual void go() 631 { 632 PixelData* bestPosition = resources->buffers[ "best_position" ]; 633 GLint samplesSoFar = bestPosition->elements; 634 635 // prepare output 636 tmpData.clear(); 637 collectData( "killer_map" ); 638 collectData( "dead_map" ); 639 resources->fbo->load( tmpData ); 640 641 // reloads the depth buffer and the modelview and projection matrices 642 PixelData* depthBuffer = resources->buffers[ "depth_buffer" ]; 643 resources->fbo->loadDepth( depthBuffer->textureId ); 644 645 glMatrixMode( GL_PROJECTION ); 646 glLoadMatrixf( resources->projMatrix ); 647 glMatrixMode( GL_MODELVIEW ); 648 glLoadMatrixf( resources->mvMatrix ); 649 650 // prepare shader 651 prog = resources->shaders[ "killer" ]; 652 prog->load(); 653 bindSampler( "best_position", "bestPosition" ); 654 bindSampler( "best_normal", "bestNormal" ); 655 bindSampler( "out_mask", "outMask" ); 656 bindSampler( "input_eye_normal", "inputEyeNormal" ); 657 bindSampler( "input_depth", "inputDepth" ); 658 659 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // depth buffer is not cleared, otherwise 660 // we cannot do shadow mapping 661 feedCoords( bestPosition->side, samplesSoFar ); 662 663 unbindSamplers(); 664 prog->unload(); 665 resources->fbo->unload(); 666 667 // reset matrices 668 glMatrixMode( GL_PROJECTION ); 669 glLoadIdentity(); 670 glMatrixMode( GL_MODELVIEW ); 671 glLoadIdentity(); 672 } 673 }; 674 675 class MaskUpdater: public Stage 676 { 677 678 public: MaskUpdater(Resources * res)679 MaskUpdater( Resources* res ) : Stage( res ) 680 { 681 ; 682 } 683 go(void)684 virtual void go( void ) 685 { 686 tmpData.clear(); 687 collectData( "pov_alive_mask" ); 688 resources->fbo->load( tmpData ); 689 690 prog = resources->shaders[ "mask_updater" ]; 691 prog->load(); 692 bindSampler( "out_mask", "out_mask" ); 693 bindSampler( "killer_map", "killer_map" ); 694 695 drawFullscreenQuad(); 696 697 unbindSamplers(); 698 prog->unload(); 699 resources->fbo->unload(); 700 } 701 702 }; 703 704 class DeadMasker: public Stage 705 { 706 707 public: DeadMasker(Resources * res)708 DeadMasker( Resources* res ): Stage( res ) 709 { 710 ; 711 } 712 go(void)713 virtual void go( void ) 714 { 715 PixelData* bestPosition = resources->buffers[ "best_position" ]; 716 PixelData* deadMask = resources->buffers[ "dead_mask" ]; 717 deadMask->resize( bestPosition->side ); 718 719 PixelData* compactedDeads = resources->buffers[ "compacted_deads" ]; 720 GLint deadsCount = compactedDeads->elements; 721 722 tmpData.clear(); 723 tmpData.push_back( deadMask ); 724 resources->fbo->load( tmpData ); 725 726 // adjust matrices to make the scattering work 727 glMatrixMode( GL_MODELVIEW ); 728 glLoadIdentity(); 729 GLfloat scaleFactor = 2.0f / bestPosition->side; 730 glTranslatef( -1.0f, -1.0f, 0.0f ); 731 glScalef( scaleFactor, scaleFactor, 1.0f ); 732 733 prog = resources->shaders[ "dead_masker" ]; 734 prog->load(); 735 bindSampler( "compacted_deads", "compactedDeadMap" ); 736 737 glClear( GL_COLOR_BUFFER_BIT ); 738 feedCoords( compactedDeads->side, deadsCount ); 739 740 unbindSamplers(); 741 prog->unload(); 742 resources->fbo->unload(); 743 744 glMatrixMode( GL_MODELVIEW ); 745 glLoadIdentity(); 746 } 747 748 }; 749 750 class AliveMasker: public Stage 751 { 752 753 public: AliveMasker(Resources * res)754 AliveMasker( Resources* res ): Stage( res ) 755 { 756 ; 757 } 758 go(void)759 virtual void go( void ) 760 { 761 PixelData* bestPosition = resources->buffers[ "best_position" ]; 762 PixelData* aliveMask = resources->buffers[ "alive_mask" ]; 763 aliveMask->resize( bestPosition->side ); 764 765 tmpData.clear(); 766 tmpData.push_back( aliveMask ); 767 resources->fbo->load( tmpData ); 768 769 prog = resources->shaders[ "alive_masker" ]; 770 prog->load(); 771 bindSampler( "dead_mask", "deadMask" ); 772 uploadInt( "elements", bestPosition->elements ); 773 uploadInt( "texSide", bestPosition->side ); 774 775 drawFullscreenQuad(); 776 777 unbindSamplers(); 778 prog->unload(); 779 resources->fbo->unload(); 780 } 781 782 }; 783 784 class FinalCompactor: public Stage 785 { 786 787 public: FinalCompactor(Resources * res)788 FinalCompactor( Resources* res ): Stage( res ) 789 { 790 ; 791 } 792 go(void)793 virtual void go( void ) 794 { 795 PixelData* currentBestPosition = resources->buffers[ "current_best_position" ]; 796 PixelData* alivePosition = resources->buffers[ "alive_position" ]; 797 GLint samplesCount = currentBestPosition->elements + alivePosition->elements; 798 799 tmpData.clear(); 800 collectAttributesData( "best_" ); 801 for( unsigned int i=0; i<tmpData.size(); i++ ) 802 { 803 tmpData[i]->resizeToFit( samplesCount ); 804 tmpData[i]->elements = samplesCount; 805 } 806 807 resources->fbo->load( tmpData ); 808 prog = resources->shaders[ "final_compactor" ]; 809 prog->load(); 810 bindAttributeSamplers( "current_best_" ); 811 bindAttributeSamplers( "alive_" ); 812 uploadInt( "totalElements", samplesCount ); 813 uploadInt( "survivors", alivePosition->elements ); 814 uploadInt( "currentBests", currentBestPosition->elements ); 815 uploadInt( "targetSide", tmpData[0]->side ); 816 uploadInt( "survivorsSide", alivePosition->side ); 817 uploadInt( "currentBestsSide", currentBestPosition->side ); 818 819 glClear( GL_COLOR_BUFFER_BIT ); 820 drawFullscreenQuad(); 821 822 unbindSamplers(); 823 prog->unload(); 824 resources->fbo->unload(); 825 } 826 827 }; 828 829 class FeatureDetector: public Stage 830 { 831 832 public: FeatureDetector(Resources * res)833 FeatureDetector( Resources* res ): Stage( res ) 834 { 835 ; 836 } 837 go(void)838 virtual void go( void ) 839 { 840 // retrieves the depth range 841 tmpData.clear(); 842 collectData( "input_depth" ); 843 tmpData[0]->generateMipmaps(); 844 prog = resources->shaders[ "depth_range_detector" ]; 845 prog->load(); 846 bindSampler( "input_depth", "input_depth" ); 847 848 for( int i=1; i<tmpData[0]->getMipmapLevels(); i++ ) 849 { 850 resources->fbo->load( tmpData, i ); 851 uploadInt( "level", i ); 852 drawFullscreenQuad(); 853 resources->fbo->unload(); 854 } 855 856 unbindSamplers(); 857 prog->unload(); 858 859 GLfloat* top = tmpData[0]->download( tmpData[0]->getMipmapLevels() - 1 ); 860 GLfloat depthRange = top[1] - top[0]; 861 delete top; 862 863 // performs feature detection 864 GLfloat smallJump = depthRange * resources->params->smallDepthJump; 865 GLfloat bigJump = depthRange * resources->params->bigDepthJump; 866 float rads = ( resources->params->angleThreshold * PI ) / 180.0f; 867 GLfloat thrCos = (GLfloat)( cos( rads ) ); 868 rads = ((resources->params->frontFacingConeF / 2.0f) * PI) / 180.0f; 869 GLfloat ffCos = (GLfloat)( cos( rads ) ); 870 871 tmpData.clear(); 872 collectData( "out_mask" ); 873 874 resources->fbo->load( tmpData ); 875 prog = resources->shaders[ "feature_detector" ]; 876 prog->load(); 877 bindSampler( "start_mask", "startMask" ); 878 bindSampler( "input_depth", "inputDepth" ); 879 bindSampler( "input_normal", "inputNormal" ); 880 bindSampler( "input_eye_normal", "inputEyeNormal" ); 881 uploadFloat( "smallDepthJump", smallJump ); 882 uploadFloat( "bigDepthJump", bigJump ); 883 uploadFloat( "thresholdCosine", thrCos ); 884 uploadFloat( "frontFacingCosine", ffCos ); 885 886 drawFullscreenQuad(); 887 888 unbindSamplers(); 889 prog->unload(); 890 resources->fbo->unload(); 891 } 892 893 }; 894 895 } 896 897 #endif // STAGES_H 898