EvolutionSurface.cpp

Display a triangular surface as transparent object using depth-sorting.

#include <ocean/plankton/VCreator.hpp>

#include <ocean/GLvish/VGLRenderObject.hpp>
#include <ocean/GLvish/BoundingBox.hpp>
#include <ocean/GLvish/ArrayTypes.hpp>
#include <ocean/GLvish/colors.hpp>

#include <ocean/shrimp/VObjectStatus.hpp>

#include <ocean/eagle/PhysicalSpace.hpp>

#include <field/Cell.hpp>
#include <GL/fiberGL.hpp>

#include <baseop/ExpandBBox.hpp>
#include <eye/retina/VSkeletonRenderObject.hpp>
#include <grid/types/TriangularSurface.hpp>
#include <bundle/BundleProperty.hpp>
#include <bone/GridActor.hpp>

#include <GL/PartialElementRenderer.hpp>


using namespace Wizt;
using namespace Fiber;
using namespace Eagle;

namespace Fiber
{


        class   EvolutionSurface : public VSkeletonRenderObject
        {
        public:

                struct MyState : State, Fiber::TriangularSurface
                {
                        vector<Fiber::TriangularSurface> gridEvolution;
                };
                
                override RefPtr<State> newState() const
                {
                        return new MyState();
                }

                struct EvolutionSurfaceIterator: EvolutionIterator<Grid>
                {
                        
                        double startTime;
                        double pastTime;
                        double skip; //MR should better be a uint
                        vector<Fiber::TriangularSurface> *grid;
                        int counter;
                        
                        EvolutionSurfaceIterator(vector<Fiber::TriangularSurface> *surfaces, double time, double past_time,double skipSteps)
                        : startTime(time)
                        , grid(surfaces)
                        , skip(skipSteps)
                        , counter(0)
                        , pastTime(past_time)
                        {}
                        
                        override bool apply(double time, GridID&id, Grid&G)
                        {
                                if( startTime < 0 || startTime-time>pastTime ) 
                                {
                                        return false;
                                } 

                                // MR should be something like ( counter % skip == 0), such that only everth nth surface is drawn 
                                if( counter==skip ) 
                                {
                                        RefPtr<Grid> *newGrid = new RefPtr<Grid>(&G);
                                        grid->push_back(*newGrid);
                                }
                                counter ++;
                                if(counter > skip)
                                {
                                        counter = 0;
                                }
                                return true;
                        }
                };

                TypedSlot<rgba_float_t> SurfaceColor,
                SurfaceBackColor;

                TypedSlot<double>       Transparency;
                TypedSlot<double>       PastTime;
                TypedSlot<double>       SkipSteps;
                
                EvolutionSurface(const string&name, int, const RefPtr<VCreationPreferences>&VP)
                : VGLRenderObject(name, TRANSPARENT_OBJECT, VP)
                , Fish<VObject>(this)
                , VSkeletonRenderObject(name, TRANSPARENT_OBJECT, VP)
                , SurfaceColor(this, "color", makeColor(1.,.1,1., 1.0),0)
                , SurfaceBackColor(this, "backcolor", makeColor(.0, 1.,1.0, 1.0),0)
                , Transparency(this, "opacity", 0.5, 0)
                , PastTime(this, "pastTime", 1)
                , SkipSteps(this, "skipSteps", 1)
                {
                        PastTime.setProperty("max", 100.0);
                        SkipSteps.setProperty("max", 100.0);
                }

                override void render(VGLRenderContext&Context) const;
                override bool update(VRequest&R, double precision);

                static string createChildname(const string&parent_name)
                {
                        return "EvolutionSurface(" + parent_name + ")";
                }

        };


        bool EvolutionSurface::update(VRequest&Context, double precision)
        {
                RefPtr<MyState> S = myState(Context);
                GridSelector    GS = getGridSelector(Context);
                RefPtr<Grid>  G = findMostRecentGrid( Context );
                string  SelectedGridName = GS.getGridname(); 
                if (!G)
                {
                        removeState(Context);
                        return setStatusError(Context, "No Grid found.");
                }

                S->TriangularSurface::operator=(G);

                if (!*S)
                return setStatusError(Context, "No surface available."); 

                setBoundingBall(Context, getBoundingBox( S->CoordField ) ); 

                if (BundlePtr B = GS.getBundle() )
                {
                        S->gridEvolution.clear();
                        double pastTime = 0.0;
                        PastTime << Context >> pastTime;
                        double skipSteps = 0.0;
                        SkipSteps << Context >> skipSteps;
                        double t = getTime(Context, B);
                        
                        EvolutionSurfaceIterator iterator(&(S->gridEvolution), t, pastTime, skipSteps);
                        B->iterateBackward(t,  SelectedGridName, iterator, false); 
                        S->gridEvolution.push_back(G);
                }
                return setStatusInfo(Context, "Surface ready to render.");
        }


        struct  TriangleRenderer : GL::PartialElementRenderer
        {
                RefPtr<TriangularSurface::CellArray_t>  Cells;

                TriangleRenderer(const MemCore::RefPtr<Fiber::MemBase>&FieldCoordinates,
                const RefPtr<TriangularSurface::CellArray_t>&TriangleCells)
                : GL::PartialElementRenderer( FieldCoordinates, NullPtr() )
                , Cells(TriangleCells)
                {
                        assert( TriangleCells );
                        assert( Cells->getTypedStorage() ); 

                        const std::vector<TriangleCell>&Cls = Cells->getTypedStorage()->get_vector();
                        this->CurrentIBO = new IndexBuffer<TriangleCell>( Cls ); 
                        draw_mode = GL_TRIANGLES;
                }

                override void prefix()
                {
                        glEnable(GL_DEPTH_TEST); // see depth buffer 
                        glDepthMask(GL_FALSE);   // but don't write to it
                        glEnable(GL_NORMALIZE);
                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                        glEnable( GL_BLEND );
                }

                void    postfix()
                {
                        glDepthMask(GL_TRUE);
                }
        };

        void EvolutionSurface::render(VGLRenderContext&Context) const
        {
                RefPtr<MyState> myState = getState(Context); 
                if (!myState)
                return;

                Fiber::TriangularSurface&Surface = *myState; 
                if (!Surface)
                return;

                if (!Surface.CoordField)
                {
                        printf("Did not find coordinates :( \n");
                        return;
                } 

                if (!Surface.CellField)
                {
                        printf("Did not find triangles :( \n");
                        return;
                } 

                // 
                // Generic OpenGL section, these settings affect all VBO's rendered later 
                //
                glEnable(GL_LIGHTING);

                glMaterialf( GL_FRONT, GL_SHININESS,  3 );
                glMaterialf( GL_BACK , GL_SHININESS, 50 ); 

                glMaterial( GL::FRONT_AND_BACK, GL::AMBIENT , makeColor( 0,0,.01,0) );
                glMaterial( GL::FRONT_AND_BACK, GL::SPECULAR, makeColor( 0.5,0.5,.53, 0) );
                glMaterial( GL::FRONT_AND_BACK, GL::EMISSION, makeColor( 0., 0.,0., 0) );
                glColor4f(1,0,0, 0.5); 

                glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); 
                //      glColorMaterial( GL_FRONT_AND_BACK, GL_DIFFUSE); 
                //      glEnable( GL_COLOR_MATERIAL );

                rgba_float_t    SurfColor( makeColor(1,0,0,0.5 ) );
                SurfaceColor << Context >> SurfColor; 

                rgba_float_t    SurfBackColor( makeColor(1,0,0,0.5 ) );
                SurfaceBackColor << Context >> SurfBackColor; 

                double  Alpha = 0.5; 
                Transparency << Context >> Alpha;

                SurfColor[3] = Alpha; 
                SurfBackColor[3] = Alpha;

                //      glEnable( GL_DEPTH_TEST ); 
                //       glEnable( GL_MULTISAMPLE_ARB ); 
                // glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB ); 

                glMaterial( GL::FRONT, GL::DIFFUSE, SurfColor ); 
                glMaterial( GL::BACK , GL::DIFFUSE, SurfBackColor );

                //      glColor4f( 1,0,0,.8); 
                //      glMaterial( GL::FRONT, GL::DIFFUSE, makeColor( 1., 0.,0., 0.3) ); 
                //      glMaterial( GL::BACK , GL::DIFFUSE, makeColor( .3, 1.,0., 0.3) );


                //      printf(">>>>>   EvolutionSurface: RENDER cells for t=%ld, %lu Triangles\n", 
                //             myState->CellField->time_value(), Cells->nElements() );

                RefPtr<Field> Tmp = Surface.getTriangleBaryCenters();

                RefPtr<CreativeArrayBase>
                BaryCenters = Tmp->getCreator(); 

                std::ostringstream stream;
                for(int i=0; i<myState->gridEvolution.size(); i++) 
                {
                        stream<<i;
                // 
                        // VBO Access via GLCache, retrieve and re-use or generate new VBO 
                        //
                        //const string VBOKey = ""; 
                        RefPtr<ValueSet> V;// = ScaleFactor(Context); 


                        RefPtr<VBO> myVBO; 
                        //              RefPtr<TriangleRenderer> MyTriangleRenderer; 

                        unsigned ViewCacheSize = 1;

                        try
                        {
                                myVBO = Context( *Surface )( typeid(*this) )( V )(VERTEXBUFFER(), stream.str());

                                // Call the VBO if it's there and all ready to go.
                                if (myVBO
                                                && !myVBO->isOlderThan( *Surface.CellField)
                                                && !myVBO->isOlderThan( *Surface.CoordField) )
                                {
                                        for(int j=i; j<myState->gridEvolution.size()&&myVBO; j++) 
                                        {
                                                if ( RefPtr<TriangleRenderer> TR = myVBO->getRenderer() )
                                                {
                                                        assert( TR->MyElementSorter );

                                                        TR->CurrentIBO = TR->sortByDepth(Context, BaryCenters, ViewCacheSize );

                                                        myVBO->call();
                                                        
                                                }
                                                stream<<j+1;
                                                myVBO = Context( *Surface )( typeid(*this) )( V )(VERTEXBUFFER(),       stream.str());
                                        }
                                        return;
                                }
                        }
                        catch(const GLCacheError&Err)
                        {} 
                        if (!myVBO)
                        myVBO = Context[*Surface][ typeid(*this) ][ V ]( VERTEXBUFFER(), stream.str()); 

                        assert( myVBO );
                        myVBO->clear(); 

                        // 
                        // Loading fields as vertex arrays and append them to the VBO. 
                        //
                        using namespace Eagle::PhysicalSpace; 

                        myVBO->append( new TypedVertexArray<point3>( myState->gridEvolution[i].getCoords()->myChunk() ) ); 

                        if (RefPtr<TriangularSurface::NormalVectorArray_t> VertexNormals = Surface.getNormals() )
                        {
                                myVBO->append( new TypedNormalArray<bivector3>( VertexNormals->myChunk() )); 
                        } 

                        RefPtr<TriangleRenderer> TR = new TriangleRenderer(myState->gridEvolution[i].getCoords(), myState->gridEvolution[i].CellField->getData() ); 
                        TR->MyElementSorter = new GL::TypedElementSorter<TriangleCell>(myState->gridEvolution[i].CellField->getCreator() );
                        TR->CurrentIBO = TR->sortByDepth(Context, BaryCenters, ViewCacheSize );

                        myVBO->setRenderer( TR );

                        myVBO->call(); 

                }
        }


        //
        // Object Creation
        //

        struct  GridInspector
        {
                static  SkeletonExistence InspectionProperty()
                {
                        return SkeletonExistence( Fiber::TriangularSurface::ID() );
                }
        };



        static  Ref<GridActor<GridInspector, EvolutionSurface> > 
        MyEvolutionSurfaceCreator("Display/EvolutionSurface",  ObjectQuality::EXPERIMENTAL);

} // anon namespace