VISH
0.2
|
Draw the bounding box of some VObject, if that one provides the respective information as an interface. This example demonstrates uses Render Anemone objects to perform the actual rendering. A Render Anemone is an Vish object to encapsulate rendering operations, see Wizt::Anemone for detailed documentation and the AnemoneBoundingVolume.cpp example, which demonstrates use of Render Anemones on a more basic level.
Associated with the Anemone is the Seagrass class, which provides cache management for Anemone objects. This example demonstrates how to make use of this Seagrass management, whereby the associated AnemoneCreator objects are stored in the object's local state object.
Storing AnemoneCreator with an object's local state object is the safest way to store them, as those AnemoneCreator will vanish automatically if the object dies. However, this is not the only possible scenario. AnemoneCreator may also be stored at some data objects to allow them to be shared across visualization modules: Two visualization modules will then use exactly the same rendering Anemones if they are based on the same data. This is however advanced usage and needs to be done very cautiously. The example given here is thus a very simple, but frequently applicable version which already provides all of the require efficient and safe cache management.
#include <ocean/plankton/VPipeline.hpp> #include <ocean/GLvish/VGLRenderObject.hpp> #include <ocean/eagle/PhysicalSpace.hpp> #include <ocean/eagle/GL/EagleGL.hpp> #include <ocean/GLvish/BoundingBox.hpp> #include <ocean/GLvish/GLFonts.hpp> #include <ocean/Anemonia/Seagrass.hpp> using namespace Wizt; using namespace Eagle; namespace { class BoundingBoxRenderer : public VGLRenderObject { public: TypedSlot<VBoundingBox> myData; TypedSlot<double> Thickness, FontSize; TypedSlot<GLFontManager> MyFonts; struct MyState : State { RefPtr<AnemoneCreator<> > FontAnemoneCreator, BoxAnemoneCreator, CornerAnemoneCreator; }; override RefPtr<State> newState() const { return new MyState(); } BoundingBoxRenderer(const string&name, int p, const RefPtr<VCreationPreferences>&VP) : VGLRenderObject(name, p, VP) , myData( this, "source", VBoundingBox() ) , Thickness(this, "thickness", 1.5, NullPtr(), 5) , FontSize(this, "fontsize", 1.0, NullPtr(), 0) , MyFonts(this, "fonts", Empty(), 10 ) { FontSize.setProperty("max",10.0); Thickness.setProperty("max",10.0); } override bool update(VRequest&Context, double precision); override void render(VGLRenderContext&Context) const; static string createChildname(const string&parent_name) { return "BoundingVolumeOf" + parent_name; } }; bool BoundingBoxRenderer::update(VRequest&Context, double precision) { VBoundingBox BBox; myData << Context >> BBox; if (!BBox) { resetBBox( Context ); return true; } setBoundingBall(Context, BBox); return true; } class FontTentacle : public Anemone::SpecializedTentacle<Anemone::DisplayLists> { public: string text; Eagle::PhysicalSpace::point Position; double FontScale; RefPtr<GLFontManager::Font> myFont; FontTentacle(const string&txt, const Eagle::PhysicalSpace::point&thePosition, double theFontScale, const RefPtr<GLFontManager::Font>&theFont) : text(txt) , Position( thePosition ) , FontScale ( theFontScale ) , myFont( theFont ) { myFont->setSize(2); } override bool activate(const Anemone&) { float llx, lly, llz, urx, ury, urz; glPushMatrix(); glTranslate( Position ); myFont->getBBox( text.c_str(), llx, lly, llz, urx, ury, urz); glTranslatef( -FontScale*(urx-llx)/2, -(ury-lly), 0); glScalef(FontScale, FontScale, FontScale ); myFont->render(text.c_str() ); glPopMatrix(); return true; } override bool deactivate(const Anemone&) { return true; } }; void BoundingBoxRenderer::render(VGLRenderContext&Context) const { VBoundingBox IB; myData << Context >> IB; if (!IB) return; using namespace Eagle::PhysicalSpace; point P0 = IB->center(), P1 = IB->center(); RefPtr<BoundingBox> BB = IB; if (BB) { P0 = BB->mincoord(); P1 = BB->maxcoord(); } else { for(int i=0; i<P0.SIZE; i++) { P0[i] -= IB->radius(); P1[i] += IB->radius(); } } /* Get the local state object */ RefPtr<MyState> S = myState(Context); /* If there are no Anemone Creators yet, create them. Note that we cannot do that in the constructor of the state object because AnemoneCreators require a Seagrass object, which is only provided in the render() function. Optionally we could create and set MyState object explicitly here and add it to the object state. */ if (!S->FontAnemoneCreator) S->FontAnemoneCreator = new AnemoneCreator<>( Context.getSeagrass() ); assert(S->FontAnemoneCreator); if (!S->BoxAnemoneCreator) S->BoxAnemoneCreator = new AnemoneCreator<>( Context.getSeagrass() ); assert(S->BoxAnemoneCreator); if (!S->CornerAnemoneCreator) S->CornerAnemoneCreator = new AnemoneCreator<>( Context.getSeagrass() ); assert(S->CornerAnemoneCreator); /* Taking care of the text display. */ double FontScale = 1.0; FontSize << Context >> FontScale; if (FontScale>0.0) { RefPtr<Anemone> FontAnemone = S->FontAnemoneCreator->create(); { float front_emission[4] = { 0.3, 0.2, 0.1, 0.0 }; float front_ambient[4] = { 0.2, 0.2, 0.2, 0.0 }; float front_diffuse[4] = { 0.95, 0.95, 0.8, 0.0 }; float front_specular[4] = { 0.6, 0.6, 0.6, 0.0 }; glMaterialfv(GL_FRONT, GL_EMISSION, front_emission); glMaterialfv(GL_FRONT, GL_AMBIENT, front_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, front_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, front_specular); glMaterialf(GL_FRONT, GL_SHININESS, 16.0); glColor4fv(front_diffuse); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); glColorMaterial(GL_FRONT, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glDisable( GL_TEXTURE_2D); glEnable( GL_DEPTH_TEST); glDisable( GL_BLEND); } glEnable( GL_NORMALIZE ); if (FontAnemone->empty() ) { FontAnemone->CacheInfoString = "FontAnemone"; if (GLFontManager*V = GLFontManagerCreator::getFontManager() ) { RefPtr<GLFontManager::Font> MyFont = V->newFont("arial.ttf;Vera.ttf",';'); if (MyFont) { MyFont->setSize(2); { char coords0[2048]; sprintf(coords0,"(%lg,%lg,%lg)", P0[0], P0[1], P0[2] ); Ref<FontTentacle> TextAtP0( coords0, P0, FontScale, MyFont); FontAnemone->insert( TextAtP0 ); } { char coords1[2048]; sprintf(coords1,"(%lg,%lg,%lg)", P1[0], P1[1], P1[2] ); Ref<FontTentacle> TextAtP1( coords1, P1, FontScale, MyFont); FontAnemone->insert( TextAtP1 ); } } else puts("font not found"); } else puts("no font manager"); } FontAnemone->wave(); } /* Drawing the bounding box with round corners. */ // printf("BBOX: %lg,%lg,%lg <-> %lg,%lg,%lg\n", // P0[0], P0[1], P0[2], // P1[0], P1[1], P1[2] ); point P000 ( P0.x(), P0.y(), P0.z() ), P001 ( P0.x(), P0.y(), P1.z() ), P010 ( P0.x(), P1.y(), P0.z() ), P011 ( P0.x(), P1.y(), P1.z() ), P100 ( P1.x(), P0.y(), P0.z() ), P101 ( P1.x(), P0.y(), P1.z() ), P110 ( P1.x(), P1.y(), P0.z() ), P111 ( P1.x(), P1.y(), P1.z() ); /* This code is inspired by http://www.bluevoid.com/opengl/sig00/advanced00/notes/node290.html */ /* Same as mentioned above, this OpenGL code should go into an existing Tentacle as provided by the RenderContext instead. */ double width = 20; Thickness << Context >> width; if (width<0.01) width=0.01; glLineWidth(width); glEnable(GL_LINE_SMOOTH); glDisable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glColor3f( 0.5, 0.7, 0.6); RefPtr<Anemone> BBoxAnemone = S->BoxAnemoneCreator->create(); if (BBoxAnemone->empty() ) { BBoxAnemone->CacheInfoString = "BBoxAnemone"; { MemVector<point> BoxVertices(24); BoxVertices[ 0] = P000; BoxVertices[ 1] = P010; BoxVertices[ 2] = P010; BoxVertices[ 3] = P011; BoxVertices[ 4] = P011; BoxVertices[ 5] = P001; BoxVertices[ 6] = P001; BoxVertices[ 7] = P000; BoxVertices[ 8] = P100; BoxVertices[ 9] = P110; BoxVertices[10] = P110; BoxVertices[11] = P111; BoxVertices[12] = P111; BoxVertices[13] = P101; BoxVertices[14] = P101; BoxVertices[15] = P100; BoxVertices[16] = P000; BoxVertices[17] = P100; BoxVertices[18] = P010; BoxVertices[19] = P110; BoxVertices[20] = P011; BoxVertices[21] = P111; BoxVertices[22] = P001; BoxVertices[23] = P101; BBoxAnemone->insert( Context.createCoordinates( BoxVertices ) ); } BBoxAnemone->insert( Context.drawPrimitives( RenderBasin::LINES ) ); } // actual rendering BBoxAnemone->wave(); glEnable(GL_POINT_SMOOTH); glPointSize(width); RefPtr<Anemone> BBoxCornerAnemone = S->CornerAnemoneCreator->create(); if (BBoxCornerAnemone->empty() ) { BBoxCornerAnemone->CacheInfoString = "BBoxCornerAnemone"; { MemVector<point> BoxVertices(8, true); // reserve space for 8 points BoxVertices.push_back( P000 ); BoxVertices.push_back( P010 ); BoxVertices.push_back( P011 ); BoxVertices.push_back( P001 ); BoxVertices.push_back( P100 ); BoxVertices.push_back( P110 ); BoxVertices.push_back( P111 ); BoxVertices.push_back( P101 ); BBoxCornerAnemone->insert( Context.createCoordinates( BoxVertices ) ); } BBoxCornerAnemone->insert( Context.drawPrimitives( RenderBasin::POINTS ) ); } // actual rendering BBoxCornerAnemone->wave(); } static VSink< AcceptList<VBoundingBox>, BoundingBoxRenderer> ThisIsMyGreatCreator("Display/SeagrassBoundingVolume", ObjectQuality::DEMO); }