VR-Forces 5.0.3 Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleGLDrawingPlugin

Table of Contents

Overview

This example plugin creates a new driver that demonstrates how to use OpenGL draw calls from a subclass of osg::Drawable that gets added to the normalized 2D camera of all DtOsgChannels.

Expected Result

exampleGLDrawingPlugin.png
GL Drawing Plugin Result

Example details

Make a DtReticleDrawable which is subclassed from osg::Drawable:

// This subclass of osg::Drawable has a drawImplementation that can draw a
// green reticle overlay
class DtReticleDrawable : public osg::Drawable

Override drawImplementation to make some OpenGL calls:

virtual void drawImplementation(osg::RenderInfo& state) const
{
// Access the viewport to determine the dimensions and aspect ratio of the
// current channel
osg::Viewport* viewport = state.getCurrentCamera()->getViewport();
if (!viewport)
{
return;
}
int width = viewport->width();
int height = viewport->height();
float aspect = viewport->width() / viewport->height();
// Push the current OpenGL state for the things that will be modified
glPushMatrix();
glPushAttrib(GL_LINE_BIT);
// Update the projection matrix for the current aspect ratio and to base
// the coordinates on OpenGL (which uses -1,-1 .. 1, 1) instead of the
// normalized overlay coordinates in DtOsgChannel (which uses 0,0 .. 1,1)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (width >= height)
{
gluOrtho2D(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
}
else
{
gluOrtho2D(-1.0, 1.0, -1.0 / aspect, 1.0 / aspect);
}
// Default thicker lines to 10 but if the window is smaller (like with
// an inset view) use 1% of the screen width as the line width so they
// don't get drawn so fat as to hide the proper shape of the reticle.
int lineWidth = 10;
if ((width * .01) < lineWidth)
{
lineWidth = width * .01;
}
glLineWidth(lineWidth);
// Draw the circle
glBegin(GL_LINE_LOOP);
glColor3f(0.0f, 1.0f, 0.0f);
float radius = 0.5;
float centerX = 0.0;
float centerY = 0.0;
for (int i=0; i < 360; i++)
{
float radians = i * M_DEG2RAD;
glVertex2f(centerX + cos(radians)*radius,
centerY + sin(radians)*radius);
}
glEnd();

Instantiate a DtReticleDrawable when the driver starts up and put it into an osg::Geode so it can be added to cameras:

virtual bool onStart()
{
// Create myReticle and add it to myReticleGeode
myReticle = new DtReticleDrawable();
myReticleGeode = new osg::Geode();
myReticleGeode->setName("Reticle Geode");
myReticleGeode->addDrawable(myReticle);

Next make sure it's added to all the current channels:

// Add myReticleGeode to all the current channels
DtWindowManager::WindowList wins =
myAgentManager.de().display()->windowManager().windows();
DtWindowManager::WindowList::iterator winIter = wins.begin();
for(winIter; winIter != wins.end(); ++winIter)
{
DtChannelManager::ChannelMap channels =
(*winIter)->channelManager().channels();
DtChannelManager::ChannelMap::iterator chanIter=channels.begin();
for(chanIter; chanIter!=channels.end(); ++chanIter)
{
DtOsgChannel* osgChannel =
dynamic_cast<DtOsgChannel*>(chanIter->second);
if (osgChannel)
{
//osgChannel->overlayCamera()->addChild(myReticleGeode);
osgChannel->normalizedOverlayCamera()->addChild(myReticleGeode);
}
}
}
// onStart() complete

To get the reticle geode added to any new channels, hook up signal_channelCreated from the drivers constructor:

mySignalConnections += DtChannelManagerSignaler::instance(
myAgentManager.de()).signal_channelCreated.connect(
boost::bind(&DtExampleGLDrawingDriver::slot_channelCreated, this,
_1, _2));

And then add it from the callback:

void slot_channelCreated(DtChannelManager* mgr, DtChannel* channel)
{
DtOsgChannel* osgChannel = dynamic_cast<DtOsgChannel*>(channel);
if (!osgChannel || !myReticleGeode)
{
return;
}
// Add myReticleGeode to the new channel
osgChannel->normalizedOverlayCamera()->addChild(myReticleGeode);

Building the Example

VR-Vantage includes pre-built versions of the example plug-in. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

This example is a plug-in. You can run it by running ./bin64/exampleGLDrawingPlugin_stealth.bat (on Windows) or ./bin64/exampleGLDrawingPlugin_stealth.sh (on Linux). For more information about running examples, please see Running Applications and Examples.

Example Source Files


exampleGLDrawingPlugin.cxx

/******************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
******************************************************************************/
#ifdef _WIN32
#ifdef EXAMPLEGLDRAWINGPLUGIN_EXPORTS
#define DT_DLL_EXAMPLEGLDRAWINGPLUGIN __declspec ( dllexport )
#else
#define DT_DLL_EXAMPLEGLDRAWINGPLUGIN __declspec ( dllimport )
#endif
#else
#define DT_DLL_EXAMPLEGLDRAWINGPLUGIN
#endif
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLEGLDRAWINGPLUGIN
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
#include <vrvCore/DtDe.h>
#include <matrix/vlMath.h>
#include <osg/Drawable>
#include <osg/Geode>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <boost/bind.hpp>
// Use the VR-Vantage namespace. All classes in VR-Vantage are in this namespace.
using namespace makVrv;
// NOTE: For this example to work in Virtual Reality, the normalizedOverlayCamera should be switched to just overlayCamera
// This subclass of osg::Drawable has a drawImplementation that can draw a
// green reticle overlay
class DtReticleDrawable : public osg::Drawable
{
public:
DtReticleDrawable()
{
// set to false to make sure drawImplementation is called every frame
setSupportsDisplayList(false);
setUseDisplayList(false);
};
DtReticleDrawable(const DtReticleDrawable& reticle,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
osg::Drawable(reticle,copyop)
{
// set to false to make sure drawImplementation is called every frame
setSupportsDisplayList(false);
setUseDisplayList(false);
}
virtual ~DtReticleDrawable()
{
};
META_Object(test, DtReticleDrawable)
virtual void drawImplementation(osg::RenderInfo& state) const
{
// Access the viewport to determine the dimensions and aspect ratio of the
// current channel
osg::Viewport* viewport = state.getCurrentCamera()->getViewport();
if (!viewport)
{
return;
}
int width = viewport->width();
int height = viewport->height();
float aspect = viewport->width() / viewport->height();
// Push the current OpenGL state for the things that will be modified
glPushMatrix();
glPushAttrib(GL_LINE_BIT);
// Update the projection matrix for the current aspect ratio and to base
// the coordinates on OpenGL (which uses -1,-1 .. 1, 1) instead of the
// normalized overlay coordinates in DtOsgChannel (which uses 0,0 .. 1,1)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (width >= height)
{
gluOrtho2D(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
}
else
{
gluOrtho2D(-1.0, 1.0, -1.0 / aspect, 1.0 / aspect);
}
// Default thicker lines to 10 but if the window is smaller (like with
// an inset view) use 1% of the screen width as the line width so they
// don't get drawn so fat as to hide the proper shape of the reticle.
int lineWidth = 10;
if ((width * .01) < lineWidth)
{
lineWidth = width * .01;
}
glLineWidth(lineWidth);
// Draw the circle
glBegin(GL_LINE_LOOP);
glColor3f(0.0f, 1.0f, 0.0f);
float radius = 0.5;
float centerX = 0.0;
float centerY = 0.0;
for (int i=0; i < 360; i++)
{
float radians = i * M_DEG2RAD;
glVertex2f(centerX + cos(radians)*radius,
centerY + sin(radians)*radius);
}
glEnd();
// Draw the thick lines
glBegin(GL_LINES);
glColor3f(0.0f, 1.0f, 0.0f);
float extra = 0.06;
glVertex2f(centerX - (radius + extra), centerY);
glVertex2f(centerX - radius/2, centerY);
glVertex2f(centerX + (radius + extra), centerY);
glVertex2f(centerX + radius/2, centerY);
glVertex2f(centerX, centerY - (radius + extra));
glVertex2f(centerX, centerY - radius/2);
glVertex2f(centerX, centerY + (radius + extra));
glVertex2f(centerX, centerY + radius/2);
glEnd();
// Draw the thin lined inner crosshair
glLineWidth(2.0);
glBegin(GL_LINES);
glVertex2f(centerX - radius/2, centerY);
glVertex2f(centerX + radius/2, centerY);
glVertex2f(centerX, centerY - radius/2);
glVertex2f(centerX, centerY + radius/2);
glEnd();
// Clean up the OpenGL state
glPopAttrib();
glPopMatrix();
}
};
// This driver creates and owns the example driver.
class DtExampleGLDrawingDriver : public makVrv::DtDriver
{
public:
DtExampleGLDrawingDriver( DtAgentManager& am )
: makVrv::DtDriver( am, "DtExampleGLDrawingDriver" )
{
// Hook up slot_channelCreated so it gets calls whenever a new channel is
// created.
mySignalConnections += DtChannelManagerSignaler::instance(
myAgentManager.de()).signal_channelCreated.connect(
boost::bind(&DtExampleGLDrawingDriver::slot_channelCreated, this,
_1, _2));
}
virtual ~DtExampleGLDrawingDriver()
{
}
virtual const std::string& className() const
{
static std::string name = "DtExampleGLDrawingDriver";
return name;
}
void slot_channelCreated(DtChannelManager* mgr, DtChannel* channel)
{
DtOsgChannel* osgChannel = dynamic_cast<DtOsgChannel*>(channel);
if (!osgChannel || !myReticleGeode)
{
return;
}
// Add myReticleGeode to the new channel
osgChannel->normalizedOverlayCamera()->addChild(myReticleGeode);
}
virtual bool onStart()
{
// Create myReticle and add it to myReticleGeode
myReticle = new DtReticleDrawable();
myReticleGeode = new osg::Geode();
myReticleGeode->setName("Reticle Geode");
myReticleGeode->addDrawable(myReticle);
// Set up a known scenegraph state set used for drawing.
osg::StateSet* ss = myReticleGeode->getOrCreateStateSet();
ss->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OFF);
ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OFF);
ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
ss->setTextureMode(0, GL_TEXTURE_3D, osg::StateAttribute::OFF);
ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
ss->setMode(GL_BLEND, osg::StateAttribute::OFF);
ss->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
// Add myReticleGeode to all the current channels
myAgentManager.de().display()->windowManager().windows();
DtWindowManager::WindowList::iterator winIter = wins.begin();
for(winIter; winIter != wins.end(); ++winIter)
{
(*winIter)->channelManager().channels();
DtChannelManager::ChannelMap::iterator chanIter=channels.begin();
for(chanIter; chanIter!=channels.end(); ++chanIter)
{
DtOsgChannel* osgChannel =
dynamic_cast<DtOsgChannel*>(chanIter->second);
if (osgChannel)
{
//osgChannel->overlayCamera()->addChild(myReticleGeode);
osgChannel->normalizedOverlayCamera()->addChild(myReticleGeode);
}
}
}
// onStart() complete
return true;
}
virtual bool onStop()
{
return true;
}
virtual bool onTick()
{
return true;
}
protected:
osg::ref_ptr<osg::Geode> myReticleGeode;
makVrv::DtSignalConnectionManager mySignalConnections;
};
{
// Create DtExampleDriver.
DtExampleGLDrawingDriver* driver =
new DtExampleGLDrawingDriver(de.agentManager());
// The driver is now owned by the display engine. Do not delete it.
de.driverManager().addDriver(driver);
// Start the driver, creating the agent.
de.driverManager().startDriver(driver);
}
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// We only want to create the driver if we are running in master mode.
if (de.isInMasterMode())
{
// The accessory must be created after the DE's initialization is
// finished, to make sure all the objects it uses exist.
&installDriver, boost::ref(de) ));
}
}
{
// Setup the plug-in. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}

[<< Examples] [Home] [Top of Page]


Document ID: Generated on Thu Jun 1 17:58:13 EDT 2023 from SVN revision 255404
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)