VR-Vantage 3.0 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleLogo

Table of Contents

Overview

This example shows how to add a 2D Overlay to a channel. We will add a logo to the bottom left hand corner of the channel.

Expected Result

exampleLogo.png
MAK Logo Result

Example details

It is important to understand the concept of overlays in VR-Vantage. An overlay is a 2D scene that is drawn on top of a 3D scene. The 2D scene can contain any number of the 2D primitives which include: DtLineSegment, DtQuad, DtFilledPolygon and DtOutlinedPolygon. To draw an overlay we need to add something to the scene graph. In this case we add a DtOverlayDrawable to the scene graph. The DtOverlayDrawable is responsible for telling overlays to render themselves at the appropriate time. The class that implements the overlay concept is the DtOverlayRenderer. The DtOverlayRenderer does the actual drawing of the graphical primitives. The DtOverlayDrawable is told which DtOverlayRenderer it should draw. During the render phase, the DtOverlayDrawable tells the DtOverlayRenderer to render itself and the graphics primitives are then rendered.

So to draw our logo we create a DtOverlayDrawable, give it a DtOverlayRenderer to render, then add a DtQuad to the DtOverlayRenderer. However, since we would like to add a texture to the DtQuad, we will create a new class MyTexturedQuad, which has an osg::ref_ptr that will hold our texture reference.

Create a New Class (MyTexturedQuad)

Overlays can be created that are drawn on a specific channel, on all channels currently rendering a specific model set, or on all channels with the keyword "RemoteGraphics". For our example we will create a channel-specific overlay, in the function createUserOverlay.

Create the DtOverlayDrawable

Creating the DtOverlayDrawable requires a DtOsgOverlayManager and a DtChannel. Additionally, drawables need to be added to osg::Geodes and somehow added to the scene. Here we add the geode to the scene as a child of the channel's overlay camera. The overlay camera uses an orthographic projection matrix. This has the effect of drawing the graphical primitives in 2D on channel.

Create the DtOverlayRenderer

DtOverlayRenderers (commonly referred to as the overlay) can be "lazily created" by asking for one that doesn't yet exist. Here we also tell the DtOverlayDrawable to render that specific overlay via the setOverlayToRender call.

The Main Routine

Our main routine, addQuad, will look up the first channel, create our user overlay (calling createUserOverlay), create the textured quad on the overlay, assign a texture to it, then position and size it.

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/exampleLogo_stealth.bat (on Windows from cmd.exe) or ./bin64/exampleLogo_stealth.sh (on Linux). The MAK logo is displayed on top of the scene. For more information about running examples, please see Running Applications and Examples.

Example Source Files


exampleLogo.h

/******************************************************************************
** Copyright (c) 2020 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#ifndef EXAMPLELOGO_H_
#define EXAMPLELOGO_H_
#ifdef _WIN32
#ifdef EXAMPLELOGO_EXPORTS
#define DT_DLL_EXAMPLELOGO __declspec ( dllexport )
#else
#define DT_DLL_EXAMPLELOGO __declspec ( dllimport )
#endif
#else
#define DT_DLL_EXAMPLELOGO
#endif
#endif

exampleLogoPlugin.h

/******************************************************************************
** Copyright (c) 2020 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
// Get proper local export symbol
#include "exampleLogo.h"
// Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLELOGO
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
namespace makVrv
{
class DtDe;
}
// Work function for the plugin initialization

exampleLogoPlugin.cxx

/******************************************************************************
** Copyright (c) 2022 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <boost/bind.hpp>
using namespace makVrv;
// We need a DtQuad with a ref_ptr to the texture, or the file cache
// will think it's no longer being used and delete it
class MyTexturedQuad : public DtQuad
{
public:
MyTexturedQuad( DtOverlayRenderer& overlay )
: DtQuad( overlay )
{
}
void setTexture( DtDe& de, const std::string& texFilename )
{
// Create the texture and assign it to the quad.
DtOsgFileCache* osgFileCache = dynamic_cast<DtOsgFileCache*>(de.fileCache());
if(osgFileCache)
{
myTexture = osgFileCache->getTextureInstance(texFilename,
osg::Texture::NEAREST,osg::Texture::LINEAR,osg::Texture::REPEAT,
osg::Texture::REPEAT,
setTextureParameter(myTexture.get());
}
}
private:
osg::ref_ptr<osg::Texture> myTexture;
};
DtOverlayRenderer& createUserOverlay( DtDe& de, DtOsgChannel* osgChannel )
{
// Get the DtOsgOverlayManager from the DtDe.
DtOsgOverlayManager* osgOverlayManager =
// A DtOverlayDrawable is the thing added to the scene graph that tells a
// DtOverlayRenderer when to render.
osg::ref_ptr<DtOverlayDrawable> overlayDrawable = new DtOverlayDrawable(de, *osgOverlayManager, *osgChannel);
// Create a geode to add the drawable to.
osg::ref_ptr<osg::Geode> geod = new osg::Geode;
geod->addDrawable(overlayDrawable);
// Add the geod to the scenegraph under the 2D Overlay camera.
osgChannel->overlayCamera()->addChild( geod.get() );
// Set the coordinate system of the drawable to be whatever the camera's
// system is in this case the overlay camera's system is 2D pixel space. To
// get screen coordinate projection (0-1, 0-1) use
// osgChannel->normalizedOverlayCamera(), and call
// overlayRenderer.setProjectCameraIsNormalized(true).
//
// To get a camera that takes 3D (database) coordinates and projects them
// onto the screen, use osgChannel->sceneCamera(), and call
// overlayRenderer.setProjectCameraIs3D(true).
overlayDrawable->setProjectionCamera(osgChannel->overlayCamera());
// Lazily create a new overlay for the drawable to render.
DtOverlayRenderer& overlayRenderer = osgOverlayManager->overlayRenderer(DtOverlayManager::UserStart);
// Set this drawable to draw this overlay.
overlayDrawable->setOverlayToRender(&overlayRenderer);
return overlayRenderer;
}
MyTexturedQuad* addQuad( DtDe& de )
{
if ( ! de.display() )
{
return 0;
}
// First get the DtChannel we wish to draw the logo on. For this, just get the first window,
// and the first channel.
DtChannel* channel = 0;
if ( windows.size() > 0 )
{
DtWindow* window = windows.front();
if ( window )
{
const DtChannelManager::ChannelMap& channels = window->channelManager().channels();
DtChannelManager::ChannelMap::const_iterator curIter = channels.begin();
channel = curIter->second;
if ( ! channel )
{
return 0;
}
}
}
DtOsgChannel* osgChannel = dynamic_cast<DtOsgChannel*>(channel);
if(!osgChannel)
{
return 0;
}
// Create the user overlay.
DtOverlayRenderer& overlay = createUserOverlay( de, osgChannel );
// Create a textured quad
float lowerLeftX = 50.0;
float lowerLeftY = 50.0;
float imageWidth = 184.0;
float imageHeight = 60.0;
float points[8];
DtBoundingBox box(0., 0., imageWidth, imageHeight);
box.toPoints(points);
MyTexturedQuad* logoQuad = new MyTexturedQuad(overlay);
logoQuad->setFillType(DtQuad::Fill_Texture);
logoQuad->setPoints(points);
logoQuad->setPosition(lowerLeftX, lowerLeftY, 0.0, 0.0);
const std::string file = de.dePathConfiguration().resolvePath("$(SHARED_DATA_DIR)/Overlays/VtMakLogo.png");
logoQuad->setTexture( de, file );
return logoQuad;
}
void addQuadCallback(DtDe* de)
{
de->signal_postTick.disconnect(boost::bind(&addQuadCallback, de));
addQuad(*de);
}
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 accessory if we're running in master mode:
if (de.isInMasterMode())
{
de.signal_postTick.connect(boost::bind(&addQuadCallback, &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]



Copyright © 2005-2022 MAK Technologies. All Rights Reserved (www.mak.com)