VISH  0.2
SeagrassBoundingVolume.cpp

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

}