TransparentColoredSurface.cpp

TransparentColoredSurface.jpg

Spherical surface displayed via TransparentColoredSurface module.

Display a triangular surface as transparent object with a pretty shader using conventional depth-sorting (NOT depth-peeling).

The most simple version of a surface rendered is demonstrated by MonochromeSurface .

#include <ocean/plankton/VPipeline.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/shrimp/VEnum.hpp>

#include <ocean/eagle/PhysicalSpace.hpp>

#include <field/Cell.hpp>
#include <GL/fiberGL.hpp>
#include <GL/FieldBuffer.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>
#include <GLvish/Programmable.hpp>

#include <bone/FishField.hpp>
#include <ocean/GLvish/Colormap.hpp>

#include <baseop/GridField.hpp>

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

namespace
{


#define FSHADER_COLORMAP_NAME "ColormapTexture"


class   TransparentColoredSurface : public VSkeletonRenderObject, public Programmable
{
public:

        override string vertex_shader(VRenderContext&Context) const
        {
                return
#include        "TransparentColoredSurface.vcpp"
                        ;
        }

        override string fragment_shader(VRenderContext&Context) const
        {
                return
#include        "TransparentColoredSurface.fcpp"
                        ;
        }


        struct MyState : State, TriangularSurface
        {
                RefPtr<Field> ColorField;

                string  ColorFieldName,
                        ErrorMessage;

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

        TypedSlot<double>       Transparency,
                                Shininess,
                                Alpha,
                                Speculartransparency;

        TypedSlot<Range>        InputRange;
        TypedSlot<VColormap>    Colormap;

        TypedSlot<Field>        SurfaceColorField;

        enum    { NumberOfInputFields = 1 };
//      typedef LIST<double, LIST<float> > InputTypes;
        typedef LIST<double>            InputTypes;


        TransparentColoredSurface(const string&name, int, const RefPtr<VCreationPreferences>&VP)
        : VGLRenderObject(name, DEFAULT_OBJECT, VP)
        , Fish<VObject>(this)
        , VSkeletonRenderObject(name, DEFAULT_OBJECT, VP)
        , Transparency(this, "transparency", 0.0, 0)
        , Shininess(this, "shininess", 0.5, 0)
        , Alpha(this, "alpha", 1.0, 2)
        , Speculartransparency(this, "speculartransparency", 0.0,3)
        , InputRange(this, "range", Range(0,1), 0 )
        , Colormap(this, "colormap", NullPtr() )
        , SurfaceColorField(this, "field" )
        {}

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

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

};


bool TransparentColoredSurface::update(VRequest&Context, double precision)
{
FieldSelector FS; 
        SurfaceColorField << Context >> FS;

GridSelector GS;
        MyGrid << Context >> GS; 

GridField GF(GS, FS, getTime(Context) ); 

/*
Fiber::Bundle::GridInfo_t GI = findMostRecentGrid( Context ); 

RefPtr<Grid>  G = GI;
        if (!G)
        {
                G = FS.getGrid(); 
                if (!G)
                {
                        removeState(Context);
                        return setStatusError(Context, "No Grid found.");
                }
        }
*/

RefPtr<MyState> S = myState(Context);
        *S = GF;
        if (!*S)
                return setStatusError(Context, "No surface available."); 

        if (!S->CartesianVertices)
                return setStatusError(Context, "No vertices on the surface available."); 

        S->ColorFieldName = FS(); 
        S->ColorField = GF;

        if (S->ColorField)
        {
                puts("YAYYYYYYYY HAVE COLORFIELD"); 
                printf("And it should have a name: %s\n", S->ColorFieldName.c_str() );
        } 
        else
                puts("NOPE. NO COLORFIELD");


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

        if (S->ErrorMessage.length()>0)
                return setStatusError(Context, S->ErrorMessage );

        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;
        }

        // TODO: Add modus with alpha clamping and depth buffer writing
        override void prefix()
        {
                glEnable(GL_DEPTH_TEST); // see depth buffer 
//              glDepthMask(GL_FALSE);   // but don't write to it
                glDepthMask(GL_TRUE);    // and write to it
                glEnable(GL_NORMALIZE);
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                glEnable( GL_BLEND );
        }

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

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

        myState->ErrorMessage = "";

TriangularSurface&Surface = *myState;
        if (!Surface)
        {
                myState->ErrorMessage = "Grid is not a surface";
                return;
        }

        if (!Surface.CoordField)
        {
                printf("Did not find coordinates :( \n"); 
                myState->ErrorMessage = "Did not find surface coordinates.";
                return;
        }

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

        if (!myState->CellField->getData() )
        {
                printf("Did not find triangles indices :( \n"); 
                myState->ErrorMessage = "Did not find triangle indices (no data in triangle field)";
                return;
        }

//
// Check for a named color field.
//
RefPtr<Field> Colors = myState->ColorField;
        if (!Colors)
        {
                myState->ErrorMessage = "No such field: \"" + myState->ColorFieldName + "\"";
                return;
        }

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

double  Shine = 0.5;
        Shininess << Context >> Shine;
        glMaterialf( GL_FRONT, GL_SHININESS, Shine );
        glMaterialf( GL_BACK , GL_SHININESS, Shine ); 

        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 );


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

RefPtr<Field> Tmp = Surface.getTriangleBaryCenters();
RefPtr<CreativeArrayBase> BaryCenters = Tmp->getCreator(); 


        glEnable( GL_VERTEX_PROGRAM_TWO_SIDE );

RefPtr<GLProgram> MyProgram = CompileShader( Context, "TransparentColoredSurface" ); 
        assert( MyProgram );
        MyProgram->use();

        Transparency << Context > MyProgram; 
        Alpha        << Context > MyProgram; 
        Speculartransparency << Context > MyProgram; 

// 
// VBO Access via GLCache,
// retrieve and re-use or generate new VBO.
// 
// The caching mechanism is part of the "Visualization Cascade" and 
// described in the article: 
//
// http://sciviz.cct.lsu.edu/papers/2009/VizCascade.pdf
// 
string VBOKey = myState->ColorFieldName ; 
RefPtr<ValueSet> V;// = ScaleFactor(Context); 

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

// 
// Colormap handling 
//
VColormap Cmap;
        Colormap << Context >> Cmap;

RefPtr<GLTexture1D> CMapTexture = new GLTexture1D(1);
        
RefPtr<ValueSet> CmapValues = new ValueSet(Colormap(Context) );
TextureCreator&TC = Context[ *myState ][ this ][ CmapValues ]( TEXTURE() ); 
        if (Cmap)
        {
                // true: clamp values, not repeating
        RefPtr<GLTexture1D> CmapTexture = Cmap->Enable(TC, 1, true); 
                MyProgram->setUniformTexture(  FSHADER_COLORMAP_NAME , *CmapTexture); 
        }


Range ColorMapRange(0,1);
        InputRange << Context >> ColorMapRange;
        // Set the data mapping as the INVERSE of the color map
Range   DataRange = ~ColorMapRange; 

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)
                    && !myVBO->isOlderThan( InputRange->age(Context) )
                    && (Colors && !myVBO->isOlderThan( *Colors) ) )
                {
                        if (RefPtr<TriangleRenderer> TR = myVBO->getRenderer() )
                        {
                                assert( TR->MyElementSorter );

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

                                if (myVBO->call() )
                                {
                                        myState->ErrorMessage = "";
                                        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() )); 
        }

#if     0
         // no color field found, set something artifical here
        if (!Colors)
        {
        index_t nVertices = Surface.CartesianVertices->getPositions()->getData()->nElements(); 

        Ref<MemArray<1,double> > SurfaceColors(nVertices);

                for(index_t i=0; i<nVertices; i++)
                {
                // a floating point index, which ranges from 0.0 to 1.0
                double  fi = i/(nVertices-1.0); 

                // some simple and stupid, but colorful formula 
                // to map an index to colors.
                        (*SurfaceColors)[ MIndex(i) ] = fi;
                }

                Colors = new Field(SurfaceColors);
        } 
#endif

        assert(Colors);

        if (RefPtr<TypedArray<rgba_float_t> > colordata = Colors->getData() )
        {
                myVBO->append( ColorArray::newArray( colordata->myChunk() ));
        } 
        else if (RefPtr<TypedArray<double> > colordata = Colors->getData() )
        {
        RefPtr<MemBase> FieldData = Colors->getData();

                if (!DataRange.isIdentity() )
                {
                        FieldData = colordata->applyOperator(DataRange, NullPtr() );
                } 
                else
                        FieldData = colordata; 

        RefPtr<TexCoordArray> TCA =
                GL::FieldBuffer<TypedTexCoordArray<double> >::createParam( 1, FieldData, false, NullPtr() );
                myVBO->append( TCA );
        } 
        else if( RefPtr<TypedArray<float> > colordata = Colors->getData()  )
        {
                puts("TransparentColoredSurface::render() Apparently this is not called!?!?");

                RefPtr<MemBase> FieldData = Colors->getData();

                if (!DataRange.isIdentity() )
                {
                        FieldData = colordata->applyOperator(DataRange, NullPtr() );
                } 
                else
                        FieldData = colordata; 

                RefPtr<TexCoordArray> TCA =
                        GL::FieldBuffer<TypedTexCoordArray<float> >::createParam( 1, FieldData, false, NullPtr() );
                myVBO->append( TCA );   
        }
        else
        {
                puts("TransparentColoredSurface::render() Apparently this IS called!?!?");
                myState->ErrorMessage = "Color field has unsupported type " 
                                        + Typename(Colors->getElementType())
                                        + ", only RGB or double supported"; 
                return;
        }

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, TransparentColoredSurface> >
        MyTransparentColoredSurfaceCreator("Display/TransparentColoredSurface",  ObjectQuality::MATURE);

//static  VSink<Field, TransparentColoredSurface>

static  Ref<TypedFieldInputCreator<TransparentColoredSurface> >
        MmmmyTransparentColoredSurfaceCreator("Display/ColoredSurface",  ObjectQuality::MATURE);

} // anon namespace