GlossyLines.cpp

Display a set of lines as specified by the Edge skeleton of a grid. Refinement levels and fragmented fields not implemented.

#include <bone/FishGrid.hpp>

#include <ocean/plankton/VCreator.hpp>
#include <ocean/GLvish/VGLRenderObject.hpp>
#include <ocean/GLvish/BoundingBox.hpp>
#include <ocean/GLvish/GlossyTexture.hpp>
#include <ocean/eagle/PhysicalSpace.hpp>

#include <ocean/shrimp/TimeDependent.hpp>

#include <GL/fieldGL.hpp>
#include <GL/FieldBuffer.hpp>

#include <baseop/ExpandBBox.hpp>

#include <ocean/shrimp/VObjectStatus.hpp>

#include <grid/types/LineSet.hpp>
#include <bundle/BundleProperty.hpp>

#include <GL/LineSetRenderer.hpp>
#include <bone/GridActor.hpp>

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

namespace
{

class   GlossyLines : public VGLRenderObject, public TimeDependent
{
public:
        GlossyTexture::Parameters  GlossyParameters;

        struct  FieldState : State
        {
                WeakPtr<Grid>   theGridOfInterest;
        };

        override RefPtr<State> newState() const
        {
                return new FieldState();
        }

        TypedSlot<Grid>         LineGrid;
        TypedSlot<double>       Thickness;

        TypedSlot<int>          WhichLine,
                                nLines;

        GlossyLines(const string&name, int p, const RefPtr<VCreationPreferences>&VP)
        : VGLRenderObject(name, DEFAULT_OBJECT, VP)
        , TimeDependent(this)
        , GlossyParameters(this)
        , LineGrid(this, "grid")
        , Thickness(this, "thickness", 1.0)
        , WhichLine(this, "lineid", -1, 1)
        , nLines(this, "nlines", 1, 2)
        {
                Thickness.setProperty( "max", 10.0);
                WhichLine.setProperty( "min", -1);
        }

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


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

//
// Update function, is called whenever some input is changed
// It extracts the fields required for rendering and deposits them
// in the context-relative state object. This state object is
// available then during rendering.
//
bool GlossyLines::update(VRequest&Context, double precision)
{
//      puts("\n\n************************************GlossyLines::update() enter\n");fflush(stdout); 


GridSelector    GS; 
        LineGrid << Context >> GS;

Info<Skeleton> SI = GS.getRefinementLevel( getTime(Context), 0, 0 );

double time = SI.getTime();
        if (!SI.getGrid())
                return setStatusError(Context,"No grid object found at T=" + String(time) ); 

        setBoundingBall( Context, getBoundingBox( *SI.getGrid() ) );

RefPtr<FieldState> S = myState(Context); 

LineSet LS = SI.getGrid(); 
        if (!LS)
        {
                return setStatusError(Context,"No line grid found at T=" + String(time) ); 
        }

        S->theGridOfInterest = SI.getGrid();

        return setStatusInfo(Context, "Lines ready.");
}


/*
  The render routine. Takes care of vertex buffer objects
  and calls its render routines.
 */
void GlossyLines::render(VGLRenderContext&Context) const
{
RefPtr<FieldState> S = getState(Context);
        if (!S) return;

        if (!S->theGridOfInterest)
                return; 

RefPtr<ValueSet> GlossyValues = new ValueSet();

RefPtr<GlossyTexture> LineTexture; 

        // try to get a LineTexture object cached at the Status
        try
        {
                LineTexture = Context( *S )( this ) ( GlossyValues ) ( TEXTURE() );
        }
        catch(const GLError&)
        {}

        // if none is there, then create one
        if (!LineTexture)
        {
                LineTexture = new GlossyTexture(0);
                LineTexture->enlighten();
                LineTexture->enlighten(GlossyParameters, Context);
                GLCHECK( LineTexture->enlighten );

                Context[ *S ][ this ][ GlossyValues ] ( TEXTURE() ) = LineTexture;
        }

double  width = 1.0;
        Thickness << Context >> width;
        if (width<=0.0) width=0.01;

        glEnable(GL_LINE_SMOOTH);
        glEnable(GL_POINT_SMOOTH);
        glDisable(GL_LIGHTING);
        glColor3f(.9,.4,.9);
        glEnable( GL_DEPTH_TEST );
        glLineWidth(width); 
//      GLCHECK( glLineWidth(width) ); 

//      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
//      glBlendFunc(GL_ONE, GL_ONE); 
//      glEnable( GL_BLEND );
        glDisable( GL_BLEND );

        glEnable ( GL_COLOR_MATERIAL );

        {
        // Enable the glossy texture for all subsequent OpenGL operations
        GlossyTexture::Render LINERENDER( *LineTexture, Context.CameraSettings );

        RefPtr<ValueSet> myCacheableValues = new ValueSet();
        string  VBOKey = ""; // fragment ID here in future extension 
        RefPtr<VBO> myVBO; 

        Intercube&CacheObject = *S->theGridOfInterest;

                // try to get a VBO
                try
                {
                        myVBO = Context( CacheObject )( typeid(*this) )( myCacheableValues )( VERTEXBUFFER(), VBOKey ); 
                } 
                catch(...){}

        LineSet LS(S->theGridOfInterest);

                // if none, need to create one 
                if (!myVBO || !myVBO->getRenderer() || 
                    (LS.Coords && myVBO->isOlderThan( *LS.Coords) ) || 
                    (LS.LineIndices && myVBO->isOlderThan( *LS.LineIndices) ) )
                {

                RefPtr<MemBase> Pts = LS.Coords->getData();
                        assert(Pts);
                RefPtr<VertexArray> VA = GL::FieldBuffer<VertexArray>::create( Pts, true );

                        myVBO = Context[ CacheObject ][ typeid(*this) ][ myCacheableValues ] ( VERTEXBUFFER(), VBOKey ); 
                        myVBO->clear(); 

//                      printf("GlossyLines: VBO %p is %d yet, add %d vertices (%d points)\n", 
//                             &*myVBO, myVBO->NumberOfElements(), VA->NumberOfElements(), Pts->nElements() );
                        
                        myVBO->append(VA );

#if 1
                        if (RefPtr<LineSet::TangentialVector_t> TV = LS.getTangentialVectors() )
                        {
//                              printf("GlossyLines: %d vertices, add %d tangential vectors\n",
//                                     Pts->nElements(), TV->nElements() );

                                assert( TV->nElements() == Pts->nElements() );

                        const   int TextureUnit = 0;
                        RefPtr<TexCoordArray> TCA =
                                GL::FieldBuffer<TypedTexCoordArray<Eagle::tvector3> >::createParam( TextureUnit, TV, false, NullPtr());
                                myVBO->append( TCA );
//                              puts("appended tangential arrays");fflush(stdout);
                        }
//                      else puts("GlossyLines: NO Tangential Vectors Available :(");
#endif 

                        myVBO->setRenderer( new GL::LineSetRenderer( S->theGridOfInterest ) );
                } 
//              if (myVBO->isOlderThan( *S->theGridOfInterest ) ) {puts("GlossyLines: RENDERER is outdated!");} 

        RefPtr<GL::LineSetRenderer> R = myVBO->getRenderer();
                if (!R)
                {
                        puts("GlossyLines: Renderer Problem");
                        return;
                }

                WhichLine << Context >> R->WhichOneOnly; 
                nLines    << Context >> R->nLines;

                // finally just call the VBO
                myVBO->call();
        }
}


//
// Object Creation
//

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

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

} // anon namespace