Display a triangular surface with a color field. Builds on MonochromeSurface.cpp .
Colors need to be specified as an array of rgb_float_t data for each vertex. If no such field is defined, then this surface module creates something artificial, which maps each vertex into its own specific color.
#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 <bone/FishField.hpp> using namespace Wizt; using namespace Fiber; using namespace Eagle; namespace { /* Render a triangular surface transparently. */ class PolychromeSurface : public VSkeletonRenderObject { public: struct MyState : State, TriangularSurface { string ColorFieldName; using TriangularSurface::operator=; }; override RefPtr<State> newState() const { return new MyState(); } TypedSlot<Field> SurfaceColorField; TypedSlot<rgba_float_t> SurfaceColor; TypedSlot<double> ScaleFactor; PolychromeSurface(const string&name, int p, const RefPtr<VCreationPreferences>&VP) : VGLRenderObject(name, p, VP) , Fish<VObject>(this) , VSkeletonRenderObject(name, p, VP) , SurfaceColorField(this, "colorfield" ) , SurfaceColor(this, "color", makeColor(.8,.5,.1, 1.0),0) , ScaleFactor(this, "colorization", 0.0, 1) {} override void render(VGLRenderContext&Context) const; override bool update(VRequest&R, double precision); static string createChildname(const string&parent_name) { return "PolychromeSurface(" + parent_name + ")"; } }; bool PolychromeSurface::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."); } /* Assign grid pointer to TriangularSurface, which investigates the Grid for properties conforming to a TriangularSurface. If the Grid is not a TriangularSurface, then the following status check witll return false. */ *S = G; if (!*S) return setStatusError(Context, "No surface available."); FieldSelector FS; SurfaceColorField << Context >> FS; S->ColorFieldName = FS(); setBoundingBall(Context, getBoundingBox( S->CoordField ) ); return setStatusInfo(Context, "Surface ready to render."); } struct TriangleRenderer : VBO::Renderer { RefPtr<TriangularSurface::CellArray_t> Cells; TriangleRenderer(const RefPtr<TriangularSurface::CellArray_t>&TriangleCells) : Cells(TriangleCells) {} override void prefix() { glEnable(GL_NORMALIZE); glDisable( GL_BLEND ); } override bool draw() { MultiArray<1, TriangleCell> Triangles = *Cells; GL::DrawElements( Triangles ); return true; } }; void PolychromeSurface::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 cells :( %s\n", Typename( Surface.CellField->getFieldStorageType() ).c_str() ); return; } /* if (Surface.CellField->getData()->nElements() < 1) { puts("PolychromeSurface: No triangles."); 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; // glEnable( GL_DEPTH_TEST ); // glEnable( GL_MULTISAMPLE_ARB ); // glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB ); glColor( SurfColor ); // glColor4f( SurfColor[0],SurfColor[1],SurfColor[2],SurfColor[3]); // printf(">>>>> PolychromeSurface: RENDER cells for t=%ld, %lu Triangles\n", // myState->CellField->time_value(), Cells->nElements() ); double colorscale = 1.0; ScaleFactor << Context >> colorscale; // // Vertex Buffer Object (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 = ""; // This is an additional parameter for the OpenGL Cache. // It can be an arbitrary string, and this would be the // right place to use the name of a field fragment when // support for fragmented surfaces is added. For now, // such is not supported, and we can keep this key empty. RefPtr<ValueSet> V; // This is a set of values for each of which there should // be one OpenGL cache entry generated. This means that if // a parameter is changed to a value that it already had // in the past, then the VBO that is associated with this // value will be re-used instead of newly generated. // Be *very* cautious about what values to use here, // since every cache entry eats up valueable memory at // the GPU. See documentation for class ValueSet on // how to assign values here. // // Check for a named color field. If none is found, then we // use a field called "Colors". // RefPtr<Field> Colors = (*Surface.CartesianVertices)( myState->ColorFieldName ); if (Colors) VBOKey += myState->ColorFieldName ; else Colors = (*Surface.CartesianVertices)( "Colors" ); RefPtr<VBO> myVBO; try { // n-dimensional readonly cache indexing (see VizCascade paper) 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) && (Colors && !myVBO->isOlderThan( *Colors) ) ) { if (RefPtr<TriangleRenderer> TR = myVBO->getRenderer() ) { if (myVBO->call() ) { return; } } } // Cellfield is newer than surface view VBO, need to re-load VBO } catch(const GLCacheError&Err) {} // // Create new VBO if it doesn't exist yet. // 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. // // Vertex arrays are loaded by appending objects that have been // derived from class BufferArray. // using namespace Eagle::PhysicalSpace; // Note: this approach does not support fragmented surfaces. myVBO->append( new TypedVertexArray<point3>( myState->getCoords()->myChunk() ) ); if (RefPtr<TriangularSurface::NormalVectorArray_t> VertexNormals = Surface.getNormals() ) { myVBO->append( new TypedNormalArray<bivector3>( VertexNormals->myChunk() )); } if (Colors) { if (RefPtr<TypedArray<rgba_float_t> > colordata = Colors->getData() ) { myVBO->append( ColorArray::newArray( colordata->myChunk() )); } } else // no color field found, set something artifical here { index_t nVertices = Surface.CartesianVertices->getPositions()->getData()->nElements(); MemVector<rgba_float_t> 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[i] = 1-fi, 1-fi, fi, 1.0; } RefPtr<TypedChunk<rgba_float_t> > colordata = SurfaceColors; myVBO->append( ColorArray::newArray( colordata ) ); } myVBO->setRenderer( new TriangleRenderer(myState->CellField->getData() ) ); myVBO->call(); } // // Object Creation // struct GridInspector { static SkeletonExistence InspectionProperty() { return SkeletonExistence( TriangularSurface::ID() ); } }; static Ref<GridActor<GridInspector, PolychromeSurface> > MyPolychromeSurfaceCreator("Display/PolychromeSurface", ObjectQuality::DEMO); } // anon namespace