TransparentSurface.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
{


class   TransparentSurface : public VSkeletonRenderObject
{
public:

        struct MyState : State, TriangularSurface
        {
                using TriangularSurface::operator=;
        };
        
        override RefPtr<State> newState() const
        {
                return new MyState();
        }

        TypedSlot<rgba_float_t> SurfaceColor,
                                SurfaceBackColor;

        TypedSlot<double>       Transparency;

        TransparentSurface(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)
        {}

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

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

};


bool TransparentSurface::update(VRequest&Context, double precision)
{
RefPtr<MyState> S = myState(Context);

RefPtr<Grid>  G = findMostRecentGrid( Context );
        if (!G)
        {
                removeState(Context);
                return setStatusError(Context, "No Grid found.");
        }

        *S = G;

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

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

        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 TransparentSurface::render(VGLRenderContext&Context) const
{
RefPtr<MyState> myState = getState(Context); 
        if (!myState)
                return;

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(">>>>>   TransparentSurface: RENDER cells for t=%ld, %lu Triangles\n", 
//             myState->CellField->time_value(), Cells->nElements() );

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

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

// 
// 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(), VBOKey);

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

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

                                if (myVBO->call() )
                                {
                                        return;
                                }
                        }
                }
        }
        catch(const GLCacheError&Err)
        {} 
        if (!myVBO)
                myVBO = Context[*Surface][ typeid(*this) ][ V ]( VERTEXBUFFER(), VBOKey); 

        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->getCoords()->myChunk() ) ); 

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

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

        myVBO->setRenderer( TR );

        myVBO->call();
}


//
// Object Creation
//

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

static  Ref<GridActor<GridInspector, TransparentSurface> > 
        MyTransparentSurfaceCreator("Display/TransparentSurface",  ObjectQuality::MATURE);

} // anon namespace