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