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

Table of Contents

Overview

This example demonstrates how to add a new kind of visualizer to VR-Vantage. To demonstrate, we'll add the ability to draw bullet detonations as bullet hole decals on the terrain.

Expected Result

exampleBulletHole.png
Bullet Hole Result

Example details

To draw the bullet hole decals we can use a distributed polygon model. Since the simulation often doesn't correlate perfectly with the terrain loaded in VR-Vantage, we'll also need a scene object updater to set the position of the model so that it lines up perfectly with the terrain. The visualizer itself will read the simulated detonation's state and construct the decal and updater to visualize it.

In the plugin's initialization function, we can register the new visualizer and:

// Register a new visualizer. This visualizer will display the new mass
// attribute as a text label.
DtStateVisualizerFactory::instance(de).addStateVisualizerCreator(de,
// Register the creator for our enhanced polygon model; this will
// override the default polygon model implementation provided by
// the vrvOsg library
DtAgentFactory::instance(de).registerAgentCreator(
"DtPolygonModel", new DtMovablePolygonModelClassesCreator);
// Every visualizer has a visual type, identified by a unique integer
// key and a unique string name. Visualizers can be controlled by type.
// In this example, we create a new visual type for the bullet holes
// and use it to add a toolbar button that toggles them on and off.
// This integer will be the unique key for the bullet hole visual type.
// VR-Vantage's default visual types are declared in
// DtObserverSettingsManager::ObserverSetting. It's important when creating
// a new visual type to pick an integer id that is unlikely to collide with
// an existing type.
const int bulletHoleVisualTypeId = 976;
// Register a new observer setting item to toggle the bullet hole
// decals on and off. Registering it here allows it to be added to
// GUI configurations later on.
DtQtMenuAssembler::instance(de).registerMenu(new DtObserverSettingItem(
de, "BulletHoleItem", bulletHoleVisualTypeId));
// Register the new visual type to control the bullet holes
DtVisualTypeManager::instance(de).registerVisualType(
DtVisualTypeManager::VisualType("bullet_holes", bulletHoleVisualTypeId,
"../examples/exampleBulletHole/BulletHole.png",
DtVisualTypeManager::ModelSetAll));
// Add example menu and example toolbar item.
if(app)
{
DtMenuPath::menu("DtObserverMenu").item("BulletHoleItem"));
DtToolbarPath::toolbar("DtObserverSettingsToolbar").item("BulletHoleItem"));
}

In the GUI, we can create a new visual definition and map bullet detonations to the bullet hole visualizer. For more information see the comment in DtBulletHoleVisualizer.h. Once this is done, the visualizer will be created whenever the simulation reports a bullet detonation interaction. In turn, the visualizer will create its model and updater according to its visual definition:

DtBulletHoleVisualizer::DtBulletHoleVisualizer( DtBaseConnection& simulation,
DtStateListener& listener, DtSceneObjectAgent* sceneObject, DtModelSetId modelSet )
: DtStateVisualizer( simulation, listener, sceneObject, modelSet )
, myPolygonAgent( 0 )
, myDetonationSceneObjectAgent( nullptr )
, myRadius( 1 )
{
}
DtBulletHoleVisualizer::~DtBulletHoleVisualizer()
{
destroyModelAgents();
}
void DtBulletHoleVisualizer::createModelAgents()
{
// Only create the bullet hole if the detonation impacted terrain
if (((DtVrlinkDetonationInteractionStateListener*)&myListener)->detonationResult()
== DtDetResGroundImpact)
{
createBulletHole();
}
}
void DtBulletHoleVisualizer::destroyModelAgents()
{
if ( myDetonationSceneObjectAgent )
{
mySimulation.temporaryEffects().takeAgent( myDetonationSceneObjectAgent, 60, 0);
myDetonationSceneObjectAgent = nullptr;
}
if (myPolygonAgent)
{
mySimulation.temporaryEffects().takeAgent(myPolygonAgent, 60, 0);
myPolygonAgent = nullptr;
}
}
void DtBulletHoleVisualizer::setInitialValuesFromVisualizerDefinition()
{
if( myVisualizerDefinition )
{
const DtVisualizerAttributeFilename* texFile = dynamic_cast<const DtVisualizerAttributeFilename*>(
myVisualizerDefinition->findAttribute( "texture" ));
if( texFile )
{
myTexture = texFile->value().toAscii();
}
const DtVisualizerAttributeFloat* radius = dynamic_cast<const DtVisualizerAttributeFloat*>(
myVisualizerDefinition->findAttribute( "radius" ));
if( radius )
{
myRadius = radius->value();
}
else
{
myRadius = 1;
}
}
DtStateVisualizer::setInitialValuesFromVisualizerDefinition();
}
void DtBulletHoleVisualizer::setModelDefinitionForAgents()
{
}
void DtBulletHoleVisualizer::setParent(DtStateVisualizer*)
{
}
void DtBulletHoleVisualizer::createBulletHole()
{
DtVrlinkDetonationInteractionStateListener* detStateListener =
(DtVrlinkDetonationInteractionStateListener*)&myListener;
// Create a scene object if necessary
if(!myDetonationSceneObjectAgent)
{
myDetonationSceneObjectAgent = DtSceneObjectAgent::create(mySimulation.sceneInterface(), myDistributeFlag);
myDetonationSceneObjectAgent->setModelSet(myModelSet);
}
// Create the bullet hole polygon and add it to the scene object
// This will create a DtMovablePolygonModelAgent, since the DtPolygonModelAgent's
// creator was overridden in this plugin's initialization function
myPolygonAgent = DtPolygonModelAgent::create(mySimulation.sceneInterface(), myDistributeFlag);
myDetonationSceneObjectAgent->addModel(myPolygonAgent, myVisualizerType);
// Set vertices of the polygon
// The movable polygon uses it's 0th vertex to position the center of the polygon,
// and vertices 1...n as the actual polygon vertices.
// The scene object will set vertex 0 for us when the updater gives it a position
// specify points anti-clockwise like how OpenGL would need them specified for
// drawing them with back face culling on
myDetonationSceneObjectAgent->setPosition(1, DtVector(-myRadius, -myRadius, 0.1));
myDetonationSceneObjectAgent->setPosition(2, DtVector(myRadius , -myRadius, 0.1));
myDetonationSceneObjectAgent->setPosition(3, DtVector(myRadius , myRadius, 0.1));
myDetonationSceneObjectAgent->setPosition(4, DtVector(-myRadius , myRadius, 0.1));
// Create a bullet hole updater to find the intersection of the bullet and the terrain,
// and update the scene object's position and orientation accordingly
DtBulletHoleUpdaterAgent* updater = DtBulletHoleUpdaterAgent::create(mySimulation.sceneInterface(), myDistributeFlag);
updater->setSceneObject( myDetonationSceneObjectAgent );
updater->setBulletSource(detStateListener->sourceId());
updater->setBulletEnd(detStateListener->location());
// Give the polygon a texture
myPolygonAgent->setNumTextureTiles(1);
myPolygonAgent->setTexturePath(myTexture);
}
const DtStateVisualizer::TypeInfo& DtBulletHoleVisualizer::typeInfo() const
{
return theTypeInfo();
}
const DtStateVisualizer::TypeInfo& DtBulletHoleVisualizer::theTypeInfo()
{
static DtVisualizerSchema* schema = 0;
if (!schema)
{
schema = new DtVisualizerSchema("DtBulletHoleVisualizer",
DtUnicode::tr("Detonation Bullet Holes"));
DtVisualizerSchema::Parameter param;
param.myName = "texture";
param.myScreenName = DtUnicode::tr("Texture");
param.myDescription = DtUnicode::tr("Texture file for the bullet hole decals");
param.myRequired = true; // Force visualizers to specify a texture
param.myVisualizerAttributeTypeInfoName = DtVisualizerAttributeFilename::theTypeInfo().className;
schema->addParameter(param);
param.myName = "radius";
param.myScreenName = DtUnicode::tr("Radius");
param.myDescription = DtUnicode::tr("Radius in meters of the bullet hole decals");
param.myRequired = false; // defaults to 1m if not specified
param.myVisualizerAttributeTypeInfoName = DtVisualizerAttributeFloat::theTypeInfo().className;
schema->addParameter(param);
}
static DtStateVisualizer::TypeInfo thisTypeInfo(
"DtBulletHoleVisualizer",
DtUnicode::tr("Bullet Hole Visualizer"),
InteractionVisualizerType,
*schema);
return thisTypeInfo;
}
// end source

To place the bullet hole decal, we will make a vector from the shooter to the detonation and intersect it with the terrain. The bullet hole decal will be placed at the location of that intersection and rotated to have the same normal vector. Since intersections require access to the current scene graph, we use an updater to do the calculation:

void DtBulletHoleUpdater::update( double simTime )
{
if (myDirty)
{
// find the location of the scene object with id = bullet source id
DtVector bulletSource;
DtAgentUpdateResolverInterface* resolver =
myDe.agentManager().findUpdater( mySource );
if( resolver )
{
DtSceneObject* sceneObject = resolver->
castObjectTypeFromUpdater<DtSceneObject>( "DtSceneObject" );
if ( sceneObject )
{
sceneObject->getPosition(0, bulletSource);
}
}
DtSceneObject* bulletSceneObject = findActiveSceneObject();
if( !bulletSceneObject )
{
return;
}
if ( myIntersector == nullptr )
{
myIntersector = DtIntersectorCreator::instance(myDe).create(myDe, bulletSceneObject->modelSet());
}
// Intersect the bullet with the terrain
DtVector trajectory = myEnd - bulletSource;
// use half-way point along trajectory as start
DtVector segStart = bulletSource + DtVector(trajectory.x()*0.5, trajectory.y()*0.5, trajectory.z()*0.5);
// end point is full lenght of trajectory (an estimate)
DtVector segmentEnd = segStart + trajectory;
DtIntersectorResult isectResult;
bool hit = myIntersector->findFirstIntersectWithLineSegment(
segStart.x(), segStart.y(), segStart.z(),
segmentEnd.x(), segmentEnd.y(), segmentEnd.z(),
isectResult, DtIntersector::SupportNodes);
if (hit)
{
//std::cout<<"bullet: HIT!!"<<std::endl;
bulletSceneObject->setVisible(true);
bulletSceneObject->setPosition(0, DtVector(isectResult.x, isectResult.y, isectResult.z));
// make a taitbryan to rotate from (0, 0, 1) up to intersection normal up
// so that the bullet hole is parallel to the surface that it hit
DtTaitBryan orientation;
DtVector localDown;
DtVecNeg( DtVector(isectResult.normalX, isectResult.normalY, isectResult.normalZ), localDown );
// convert Euler to Orientation
DtDcm localOriDcm( orientation );
DtVector frontVec;
// Get front vector
frontVec[0] = localOriDcm[1][0];
frontVec[1] = localOriDcm[0][0];
frontVec[2] = -localOriDcm[2][0];
// current front X down gives us a right vector
DtVector rightVec = localDown.crossProduct( frontVec );
DtVecNormalize( rightVec, rightVec );
// and then new right cross down gives us a new front vector
frontVec = rightVec.crossProduct( localDown );
DtVecNormalize( frontVec, frontVec );
// Go from vectors back to DCM
DtDcm resultDcm;
register double* resDcmPtr = &resultDcm[0][0];
*resDcmPtr++ = frontVec[1];
*resDcmPtr++ = rightVec[1];
*resDcmPtr++ = localDown[1];
*resDcmPtr++ = frontVec[0];
*resDcmPtr++ = rightVec[0];
*resDcmPtr++ = localDown[0];
*resDcmPtr++ = -frontVec[2];
*resDcmPtr++ = -rightVec[2];
*resDcmPtr = -localDown[2];
// turn Dcm back to euler
DtTaitBryan result;
DtBodyToRef_to_Euler( resultDcm, &result );
bulletSceneObject->setOrientation(0, result);
}
else
{
//std::cout<<"bullet: *****MISS*****"<<std::endl;
bulletSceneObject->setVisible(false);
}
myDirty = false;
}
} // end source

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/exampleBulletHole_stealth.bat (on Windows) or ./bin64/exampleBulletHole_stealth.sh (on Linux). In Vantage go to menu "Settings->Visual Model Editors..", in "Interaction Definition Editor" select "BulletDetonation". With the "+" sign on the right panel, add a new "Detonation Bullet Holes" for the "Model Sets=3D Models" visualizer. After that, add the following "Visualizer Definition Attributes"; "type=DtBulletHoleVisualizer", "texture=(path to your VRV installation)/examples/exampleBulletHole/BulletHole.png", "radius=0.4". Load ground_DB II Terrain in Vantage. Connect Vantage with DIS. Open VRForce with a empty scenario (connect with DIS), load ground_DB II. Add a "Chilian M16" Character near a building in VRForce. Hit play, select the "Chilian M16" right click on him and select "Task->Engagement->Provide Suppresive Fire at Location...", Click on the building and click the ok button on the popup menu. You should then see the bullet detonation in Vantage on the building. For more information about running examples, please see Running Applications and Examples.

Example Source Files


DtBulletHoleUpdater.cxx

/******************************************************************************
** Copyright (c) 2022 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/lexical_cast.hpp>
#include <matrix/vlMath.h>
namespace makVrv
{
: DtSceneObjectUpdater(de, id)
, mySource(0)
, myEnd(0, 0, 0)
, myDirty(false)
{
}
DtBulletHoleUpdater::~DtBulletHoleUpdater()
{
}
void DtBulletHoleUpdater::setEnabled( bool enabled )
{
}
void DtBulletHoleUpdater::update( double simTime )
{
if (myDirty)
{
// find the location of the scene object with id = bullet source id
DtVector bulletSource;
DtAgentUpdateResolverInterface* resolver =
myDe.agentManager().findUpdater( mySource );
if( resolver )
{
DtSceneObject* sceneObject = resolver->
castObjectTypeFromUpdater<DtSceneObject>( "DtSceneObject" );
if ( sceneObject )
{
sceneObject->getPosition(0, bulletSource);
}
}
DtSceneObject* bulletSceneObject = findActiveSceneObject();
if( !bulletSceneObject )
{
return;
}
if ( myIntersector == nullptr )
{
myIntersector = DtIntersectorCreator::instance(myDe).create(myDe, bulletSceneObject->modelSet());
}
// Intersect the bullet with the terrain
DtVector trajectory = myEnd - bulletSource;
// use half-way point along trajectory as start
DtVector segStart = bulletSource + DtVector(trajectory.x()*0.5, trajectory.y()*0.5, trajectory.z()*0.5);
// end point is full lenght of trajectory (an estimate)
DtVector segmentEnd = segStart + trajectory;
DtIntersectorResult isectResult;
bool hit = myIntersector->findFirstIntersectWithLineSegment(
segStart.x(), segStart.y(), segStart.z(),
segmentEnd.x(), segmentEnd.y(), segmentEnd.z(),
isectResult, DtIntersector::SupportNodes);
if (hit)
{
//std::cout<<"bullet: HIT!!"<<std::endl;
bulletSceneObject->setVisible(true);
bulletSceneObject->setPosition(0, DtVector(isectResult.x, isectResult.y, isectResult.z));
// make a taitbryan to rotate from (0, 0, 1) up to intersection normal up
// so that the bullet hole is parallel to the surface that it hit
DtTaitBryan orientation;
DtVector localDown;
DtVecNeg( DtVector(isectResult.normalX, isectResult.normalY, isectResult.normalZ), localDown );
// convert Euler to Orientation
DtDcm localOriDcm( orientation );
DtVector frontVec;
// Get front vector
frontVec[0] = localOriDcm[1][0];
frontVec[1] = localOriDcm[0][0];
frontVec[2] = -localOriDcm[2][0];
// current front X down gives us a right vector
DtVector rightVec = localDown.crossProduct( frontVec );
DtVecNormalize( rightVec, rightVec );
// and then new right cross down gives us a new front vector
frontVec = rightVec.crossProduct( localDown );
DtVecNormalize( frontVec, frontVec );
// Go from vectors back to DCM
DtDcm resultDcm;
register double* resDcmPtr = &resultDcm[0][0];
*resDcmPtr++ = frontVec[1];
*resDcmPtr++ = rightVec[1];
*resDcmPtr++ = localDown[1];
*resDcmPtr++ = frontVec[0];
*resDcmPtr++ = rightVec[0];
*resDcmPtr++ = localDown[0];
*resDcmPtr++ = -frontVec[2];
*resDcmPtr++ = -rightVec[2];
*resDcmPtr = -localDown[2];
// turn Dcm back to euler
DtTaitBryan result;
DtBodyToRef_to_Euler( resultDcm, &result );
bulletSceneObject->setOrientation(0, result);
}
else
{
//std::cout<<"bullet: *****MISS*****"<<std::endl;
bulletSceneObject->setVisible(false);
}
myDirty = false;
}
} // end source
void DtBulletHoleUpdater::setBulletEnd( const DtVector& end)
{
myEnd = end;
myDirty = true;
}
void DtBulletHoleUpdater::setBulletSource( DtUniqueID sourceId )
{
mySource = sourceId;
myDirty = true;
}
}

DtBulletHoleUpdater.h

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include <vrvCore/DtDe.h>
#include <string>
#include <matrix/vlVector.h>
#include <matrix/vlTaitBryan.h>
namespace makVrv
{
class DtIntersector;
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdater : public DtSceneObjectUpdater
{
public:
DtBulletHoleUpdater(DtDe& de, DtUniqueID id);
virtual ~DtBulletHoleUpdater();
virtual void update( double simTime );
virtual void setEnabled(bool enabled);
virtual void setBulletEnd(const DtVector& end);
virtual void setBulletSource(DtUniqueID sourceId);
protected:
DtUniqueID mySource;
DtVector myEnd;
bool myDirty;
DtIntersector* myIntersector = nullptr;
};
}

DtBulletHoleUpdaterAgent.cpp

// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <../examples/exampleBulletHole/DtBulletHoleUpdaterAgent.hpp>
namespace makVrv
{
{
}
DtBulletHoleUpdaterAgent* DtBulletHoleUpdaterAgent::create(makVrv::DtAgentManagerInterface& sceneInterface, bool bDistribute)
{
makVrv::DtAgent* agent = sceneInterface.createNewObject("DtBulletHoleUpdater", bDistribute);
DtBulletHoleUpdaterAgent* castedAgent = dynamic_cast<DtBulletHoleUpdaterAgent*>(agent);
if(!castedAgent)
{
delete agent;
}
return castedAgent;
}
{
}
{
}
const DtBulletHoleUpdater* DtBulletHoleUpdaterAgent::findObject() const
{
}
}

DtBulletHoleUpdaterAgent.hpp

/******************************************************************************
** Copyright (c) 2019 VT MAK
** All rights reserved.
******************************************************************************/
#pragma once
class DtTaitBryan;
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DtBulletHoleUpdater;
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterAgent : public virtual DtSceneObjectUpdaterAgent
{
public:
DtBulletHoleUpdaterAgent();
static DtBulletHoleUpdaterAgent* create(makVrv::DtAgentManagerInterface& sceneInterface, bool bDistribute = true);
virtual ~DtBulletHoleUpdaterAgent();
DtBulletHoleUpdater* findObject();
const DtBulletHoleUpdater* findObject() const;
virtual void setBulletSource(DtUniqueID sourceId) = 0;
virtual void setBulletEnd(const DtVector64& end) = 0;
protected:
virtual DtBulletHoleUpdater* findObjectAsDtBulletHoleUpdater() = 0;
};
}

DtBulletHoleUpdaterClasses.cpp

/******************************************************************************
** Copyright (c) 2019 VT MAK
** All rights reserved.
******************************************************************************/
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <../examples/exampleBulletHole/DtBulletHoleUpdaterAgent.hpp>
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterAgentImplementation : public virtual DtBulletHoleUpdaterAgent , public DtSceneObjectUpdaterAgentImplementation
{
public:
DtBulletHoleUpdaterAgentImplementation();
virtual ~DtBulletHoleUpdaterAgentImplementation();
virtual void setBulletSource(DtUniqueID sourceId);
virtual void setBulletEnd(const DtVector64& end);
protected:
virtual DtSceneObjectUpdater* findObjectAsDtSceneObjectUpdater();
virtual DtBulletHoleUpdater* findObjectAsDtBulletHoleUpdater();
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterClassDefinition : public makVrv::DtInheritedAgentDefinition<DtSceneObjectUpdaterClassDefinition,DtBulletHoleUpdater>
{
public:
DtBulletHoleUpdaterClassDefinition(const std::string& className = "DtBulletHoleUpdater");
virtual ~DtBulletHoleUpdaterClassDefinition();
enum FunctionIds
{
function_setBulletEnd,
end_FunctionIds
};
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DtBulletHoleUpdaterClassDefinition;
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterClassesCreator : public makVrv::DtAgentCreator
{
public:
DtBulletHoleUpdaterClassesCreator();
virtual ~DtBulletHoleUpdaterClassesCreator();
static makVrv::DtAgentCreator* create();
virtual makVrv::DtAgent* createAgent(makVrv::DtAgentManagerInterface& sceneInterface);
protected:
DtBulletHoleUpdaterClassDefinition* myDefinition;
static bool theRegisteredFlag;
static makVrv::DtAgentFactory::DtAutoUnregistrar theAutoUnregistrar;
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <matrix/vlVector.h>
#include <matrix/vlTaitBryan.h>
namespace makVrv
{
{
myClassName = "DtBulletHoleUpdater";
}
{
}
{
}
{
if(agentManager)
{
if(actualUpdater)
{
return actualUpdater->object();
}
}
return 0;
}
{
}
{
}
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
: makVrv::DtInheritedAgentDefinition<DtSceneObjectUpdaterClassDefinition,DtBulletHoleUpdater>(className)
{
myClassName = "DtBulletHoleUpdater";
bindFunction(function_setBulletSource,makVrv::bindMember((void (DtBulletHoleUpdater::*)(DtUniqueID))&DtBulletHoleUpdater::setBulletSource));
bindFunction(function_setBulletEnd,makVrv::bindMember((void (DtBulletHoleUpdater::*)(const DtVector64&))&DtBulletHoleUpdater::setBulletEnd));
}
DtBulletHoleUpdaterClassDefinition::~DtBulletHoleUpdaterClassDefinition()
{
}
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <exception>
namespace makVrv
{
: myDefinition(new DtBulletHoleUpdaterClassDefinition)
{
}
DtBulletHoleUpdaterClassesCreator::~DtBulletHoleUpdaterClassesCreator()
{
delete myDefinition;
}
makVrv::DtAgentCreator* DtBulletHoleUpdaterClassesCreator::create()
{
return new DtBulletHoleUpdaterClassesCreator();
}
makVrv::DtAgent* DtBulletHoleUpdaterClassesCreator::createAgent(makVrv::DtAgentManagerInterface& sceneInterface)
{
return new DtBulletHoleUpdaterAgentImplementation();
}
makVrv::DtAgentUpdateResolverInterface* DtBulletHoleUpdaterClassesCreator::createResolver(makVrv::DtDe& de, makVrv::DtUniqueID id)
{
return new makVrv::DtAgentUpdateResolver<DtBulletHoleUpdater>(de,new DtBulletHoleUpdater(de,id),myDefinition);
}
}

DtBulletHoleUpdaterClasses.hpp

/******************************************************************************
** Copyright (c) 2019 VT MAK
** All rights reserved.
******************************************************************************/
#pragma once
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <../examples/exampleBulletHole/DtBulletHoleUpdaterAgent.hpp>
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterAgentImplementation : public virtual DtBulletHoleUpdaterAgent , public DtSceneObjectUpdaterAgentImplementation
{
public:
DtBulletHoleUpdaterAgentImplementation();
virtual ~DtBulletHoleUpdaterAgentImplementation();
virtual void setBulletSource(DtUniqueID sourceId);
virtual void setBulletEnd(const DtVector64& end);
protected:
virtual DtSceneObjectUpdater* findObjectAsDtSceneObjectUpdater();
virtual DtBulletHoleUpdater* findObjectAsDtBulletHoleUpdater();
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterClassDefinition : public makVrv::DtInheritedAgentDefinition<DtSceneObjectUpdaterClassDefinition,DtBulletHoleUpdater>
{
public:
DtBulletHoleUpdaterClassDefinition(const std::string& className = "DtBulletHoleUpdater");
virtual ~DtBulletHoleUpdaterClassDefinition();
enum FunctionIds
{
function_setBulletEnd,
end_FunctionIds
};
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DtBulletHoleUpdaterClassDefinition;
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleUpdaterClassesCreator : public makVrv::DtAgentCreator
{
public:
DtBulletHoleUpdaterClassesCreator();
virtual ~DtBulletHoleUpdaterClassesCreator();
static makVrv::DtAgentCreator* create();
virtual makVrv::DtAgent* createAgent(makVrv::DtAgentManagerInterface& sceneInterface);
protected:
DtBulletHoleUpdaterClassDefinition* myDefinition;
static bool theRegisteredFlag;
static makVrv::DtAgentFactory::DtAutoUnregistrar theAutoUnregistrar;
};
}

DtBulletHoleVisualizer.inl

/******************************************************************************
** Copyright (c) 2021 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#ifndef DtBulletHoleVisualizer_INL_
#error This file may only be included by DtBulletHoleVisualizer.h
#endif
namespace makVrv
{
{
DtBulletHoleVisualizer::DtBulletHoleVisualizer( DtBaseConnection& simulation,
DtStateListener& listener, DtSceneObjectAgent* sceneObject, DtModelSetId modelSet )
: DtStateVisualizer( simulation, listener, sceneObject, modelSet )
, myPolygonAgent( 0 )
, myDetonationSceneObjectAgent( nullptr )
, myRadius( 1 )
{
}
DtBulletHoleVisualizer::~DtBulletHoleVisualizer()
{
destroyModelAgents();
}
void DtBulletHoleVisualizer::createModelAgents()
{
// Only create the bullet hole if the detonation impacted terrain
if (((DtVrlinkDetonationInteractionStateListener*)&myListener)->detonationResult()
== DtDetResGroundImpact)
{
createBulletHole();
}
}
void DtBulletHoleVisualizer::destroyModelAgents()
{
if ( myDetonationSceneObjectAgent )
{
mySimulation.temporaryEffects().takeAgent( myDetonationSceneObjectAgent, 60, 0);
myDetonationSceneObjectAgent = nullptr;
}
if (myPolygonAgent)
{
mySimulation.temporaryEffects().takeAgent(myPolygonAgent, 60, 0);
myPolygonAgent = nullptr;
}
}
void DtBulletHoleVisualizer::setInitialValuesFromVisualizerDefinition()
{
if( myVisualizerDefinition )
{
const DtVisualizerAttributeFilename* texFile = dynamic_cast<const DtVisualizerAttributeFilename*>(
myVisualizerDefinition->findAttribute( "texture" ));
if( texFile )
{
myTexture = texFile->value().toAscii();
}
const DtVisualizerAttributeFloat* radius = dynamic_cast<const DtVisualizerAttributeFloat*>(
myVisualizerDefinition->findAttribute( "radius" ));
if( radius )
{
myRadius = radius->value();
}
else
{
myRadius = 1;
}
}
DtStateVisualizer::setInitialValuesFromVisualizerDefinition();
}
void DtBulletHoleVisualizer::setModelDefinitionForAgents()
{
}
void DtBulletHoleVisualizer::setParent(DtStateVisualizer*)
{
}
void DtBulletHoleVisualizer::createBulletHole()
{
DtVrlinkDetonationInteractionStateListener* detStateListener =
(DtVrlinkDetonationInteractionStateListener*)&myListener;
// Create a scene object if necessary
if(!myDetonationSceneObjectAgent)
{
myDetonationSceneObjectAgent = DtSceneObjectAgent::create(mySimulation.sceneInterface(), myDistributeFlag);
myDetonationSceneObjectAgent->setModelSet(myModelSet);
}
// Create the bullet hole polygon and add it to the scene object
// This will create a DtMovablePolygonModelAgent, since the DtPolygonModelAgent's
// creator was overridden in this plugin's initialization function
myPolygonAgent = DtPolygonModelAgent::create(mySimulation.sceneInterface(), myDistributeFlag);
myDetonationSceneObjectAgent->addModel(myPolygonAgent, myVisualizerType);
// Set vertices of the polygon
// The movable polygon uses it's 0th vertex to position the center of the polygon,
// and vertices 1...n as the actual polygon vertices.
// The scene object will set vertex 0 for us when the updater gives it a position
// specify points anti-clockwise like how OpenGL would need them specified for
// drawing them with back face culling on
myDetonationSceneObjectAgent->setPosition(1, DtVector(-myRadius, -myRadius, 0.1));
myDetonationSceneObjectAgent->setPosition(2, DtVector(myRadius , -myRadius, 0.1));
myDetonationSceneObjectAgent->setPosition(3, DtVector(myRadius , myRadius, 0.1));
myDetonationSceneObjectAgent->setPosition(4, DtVector(-myRadius , myRadius, 0.1));
// Create a bullet hole updater to find the intersection of the bullet and the terrain,
// and update the scene object's position and orientation accordingly
DtBulletHoleUpdaterAgent* updater = DtBulletHoleUpdaterAgent::create(mySimulation.sceneInterface(), myDistributeFlag);
updater->setSceneObject( myDetonationSceneObjectAgent );
updater->setBulletSource(detStateListener->sourceId());
updater->setBulletEnd(detStateListener->location());
// Give the polygon a texture
myPolygonAgent->setNumTextureTiles(1);
myPolygonAgent->setTexturePath(myTexture);
}
const DtStateVisualizer::TypeInfo& DtBulletHoleVisualizer::typeInfo() const
{
return theTypeInfo();
}
const DtStateVisualizer::TypeInfo& DtBulletHoleVisualizer::theTypeInfo()
{
static DtVisualizerSchema* schema = 0;
if (!schema)
{
schema = new DtVisualizerSchema("DtBulletHoleVisualizer",
DtUnicode::tr("Detonation Bullet Holes"));
DtVisualizerSchema::Parameter param;
param.myName = "texture";
param.myScreenName = DtUnicode::tr("Texture");
param.myDescription = DtUnicode::tr("Texture file for the bullet hole decals");
param.myRequired = true; // Force visualizers to specify a texture
param.myVisualizerAttributeTypeInfoName = DtVisualizerAttributeFilename::theTypeInfo().className;
schema->addParameter(param);
param.myName = "radius";
param.myScreenName = DtUnicode::tr("Radius");
param.myDescription = DtUnicode::tr("Radius in meters of the bullet hole decals");
param.myRequired = false; // defaults to 1m if not specified
param.myVisualizerAttributeTypeInfoName = DtVisualizerAttributeFloat::theTypeInfo().className;
schema->addParameter(param);
}
static DtStateVisualizer::TypeInfo thisTypeInfo(
"DtBulletHoleVisualizer",
DtUnicode::tr("Bullet Hole Visualizer"),
InteractionVisualizerType,
*schema);
return thisTypeInfo;
}
// end source
}
}

DtBulletHoleVisualizer.h

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
namespace makVrv
{
class DtPolygonModelAgent;
class DtSceneObjectAgent;
{
class DT_DLL_EXAMPLEBULLETHOLE DtBulletHoleVisualizer :
public DtStateVisualizer
{
public:
DtBulletHoleVisualizer( DtBaseConnection& simulation,
DtStateListener& listener, DtSceneObjectAgent* sceneObject, DtModelSetId modelSet );
virtual ~DtBulletHoleVisualizer();
virtual void setParent(DtStateVisualizer*);
virtual void createModelAgents();
virtual void destroyModelAgents();
virtual void setInitialValuesFromVisualizerDefinition() override;
virtual void setModelDefinitionForAgents();
virtual const DtStateVisualizer::TypeInfo& typeInfo() const;
static const DtStateVisualizer::TypeInfo& theTypeInfo();
protected:
virtual void createBulletHole();
protected:
std::string myTexture;
float myRadius;
DtPolygonModelAgent* myPolygonAgent;
DtSceneObjectAgent* myDetonationSceneObjectAgent;
};
typedef DtStateVisualizerCreatorTemplate<DtBulletHoleVisualizer>
}
}
#define DtBulletHoleVisualizer_INL_
#undef DtBulletHoleVisualizer_INL_

DtMovablePolygonModel.cxx

/******************************************************************************
** Copyright (c) 2020 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <osg/Geometry>
#include <osgDB/ReadFile>
#include <osg/AlphaFunc>
namespace makVrv
{
: DtOsgPolygonModel(de, id)
{
// create a model instance
DtModelInstance* mi =
new DtMovablePolygonModelInstance(myDe);
setModelInstance(0);
setModelInstance(mi);
// must be called AFTER setModelInstance
signal_modelInstanceCreated( mi, this );
// we need this so that the decals dont mess with alpha of transparent objects
osg::StateSet* ss = static_cast<DtOsgModelInstance*>(mi)->rootNode()->getOrCreateStateSet();
ss->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
ss->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.3), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
//Enable color blending so the alpha in the decal works correctly.
mi->enableColorBlending(true);
}
DtMovablePolygonModel::~DtMovablePolygonModel()
{
}
void DtMovablePolygonModel::setVisible(bool isVisible)
{
DtModel::setVisible(isVisible);
mySceneConnector->setVisible(isVisible);
}
void DtMovablePolygonModel::setPosition( int vtx, const DtVector& position )
{
if (vtx == 0)
{
mySceneConnector->setPosition(position);
}
else
{
DtPolygonModelInstance* mi =
dynamic_cast<DtPolygonModelInstance*>(modelInstance());
if (mi)
{
mi->setPosition(vtx - 1, position);
}
}
}
void DtMovablePolygonModel::setOrientation( int vtx, const DtTaitBryan& orientation )
{
if (vtx == 0)
{
mySceneConnector->setOrientation(orientation);
}
else
{
DtPolygonModelInstance* mi =
dynamic_cast<DtPolygonModelInstance*>(modelInstance());
if (mi)
{
mi->setOrientation(vtx - 1, orientation);
}
}
}
void DtMovablePolygonModel::DtMovablePolygonModelInstance::addToConnector( DtOsgSceneConnector* connector )
{
// the base DtPolygonModel is unpositioned, and so adds itself to the scene connector's
// untransformed root. This function overrides that behavior to use the scene connector's
// transform.
osg::Group* parent = connector->getOrCreateTransformRoot();
if (!parent->containsNode(myGeode.get()))
{
parent->addChild(myGeode.get());
}
}
void DtMovablePolygonModel::update()
{
bool localMyNeedsUpdate = myNeedsUpdate;
DtOsgPolygonModel::update();
if (localMyNeedsUpdate)
{
DtPolygonModelInstance* mi =
dynamic_cast<DtPolygonModelInstance*>(modelInstance());
osg::Geode* geode = static_cast<osg::Geode*>(mi->rootNode());
if (geode->getNumDrawables()>0)
{
osg::BoundingBox bb;
bb._min = osg::Vec3f(-1,-1,-1);
bb._max = osg::Vec3f(1,1,1);
geode->getDrawable(0)->setInitialBound(bb);
geode->getDrawable(0)->getBound();
}
}
}
}

DtMovablePolygonModel.h

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
namespace makVrv
{
class DtDe;
class DtOsgSceneConnector;
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModel
: public DtOsgPolygonModel
{
public:
class DtMovablePolygonModelInstance : public DtPolygonModelInstance
{
public:
DtMovablePolygonModelInstance( DtDe& de )
: DtPolygonModelInstance(de)
{
}
virtual ~DtMovablePolygonModelInstance()
{
}
virtual void addToConnector( DtOsgSceneConnector* connector );
};
DtMovablePolygonModel(DtDe& de, DtUniqueID& id);
virtual ~DtMovablePolygonModel();
virtual void setVisible(bool isVisible);
virtual void setPosition( int vtx, const DtVector& position );
virtual void setOrientation( int vtx, const DtTaitBryan& orientation );
protected:
virtual void update();
};
}

DtMovablePolygonModelAgent.cpp

// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <../examples/exampleBulletHole/DtMovablePolygonModelAgent.hpp>
namespace makVrv
{
{
}
DtMovablePolygonModelAgent* DtMovablePolygonModelAgent::create(makVrv::DtAgentManagerInterface& sceneInterface, bool bDistribute)
{
makVrv::DtAgent* agent = sceneInterface.createNewObject("DtMovablePolygonModel", bDistribute);
DtMovablePolygonModelAgent* castedAgent = dynamic_cast<DtMovablePolygonModelAgent*>(agent);
if(!castedAgent)
{
delete agent;
}
return castedAgent;
}
{
}
{
}
const DtMovablePolygonModel* DtMovablePolygonModelAgent::findObject() const
{
}
}

DtMovablePolygonModelAgent.hpp

/******************************************************************************
** Copyright (c) 2019 VT MAK
** All rights reserved.
******************************************************************************/
#pragma once
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DtMovablePolygonModel;
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelAgent : public virtual DtOsgPolygonModelAgent
{
public:
DtMovablePolygonModelAgent();
static DtMovablePolygonModelAgent* create(makVrv::DtAgentManagerInterface& sceneInterface, bool bDistribute = true);
virtual ~DtMovablePolygonModelAgent();
DtMovablePolygonModel* findObject();
const DtMovablePolygonModel* findObject() const;
protected:
virtual DtMovablePolygonModel* findObjectAsDtMovablePolygonModel() = 0;
};
}

DtMovablePolygonModelClasses.cpp

/******************************************************************************
** Copyright (c) 2019 VT MAK
** All rights reserved.
******************************************************************************/
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <../examples/exampleBulletHole/DtMovablePolygonModelAgent.hpp>
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelAgentImplementation : public virtual DtMovablePolygonModelAgent , public DtOsgPolygonModelAgentImplementation
{
public:
DtMovablePolygonModelAgentImplementation();
virtual ~DtMovablePolygonModelAgentImplementation();
protected:
virtual DtOsgPolygonModel* findObjectAsDtOsgPolygonModel();
virtual DtMovablePolygonModel* findObjectAsDtMovablePolygonModel();
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelClassDefinition : public makVrv::DtInheritedAgentDefinition<DtOsgPolygonModelClassDefinition,DtMovablePolygonModel>
{
public:
DtMovablePolygonModelClassDefinition(const std::string& className = "DtMovablePolygonModel");
virtual ~DtMovablePolygonModelClassDefinition();
enum FunctionIds
{
};
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DtMovablePolygonModelClassDefinition;
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelClassesCreator : public makVrv::DtAgentCreator
{
public:
DtMovablePolygonModelClassesCreator();
virtual ~DtMovablePolygonModelClassesCreator();
static makVrv::DtAgentCreator* create();
virtual makVrv::DtAgent* createAgent(makVrv::DtAgentManagerInterface& sceneInterface);
protected:
DtMovablePolygonModelClassDefinition* myDefinition;
static bool theRegisteredFlag;
static makVrv::DtAgentFactory::DtAutoUnregistrar theAutoUnregistrar;
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
{
myClassName = "DtMovablePolygonModel";
}
{
}
{
}
{
if(agentManager)
{
if(actualUpdater)
{
return actualUpdater->object();
}
}
return 0;
}
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
: makVrv::DtInheritedAgentDefinition<DtOsgPolygonModelClassDefinition,DtMovablePolygonModel>(className)
{
myClassName = "DtMovablePolygonModel";
}
DtMovablePolygonModelClassDefinition::~DtMovablePolygonModelClassDefinition()
{
}
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <exception>
namespace makVrv
{
: myDefinition(new DtMovablePolygonModelClassDefinition)
{
}
DtMovablePolygonModelClassesCreator::~DtMovablePolygonModelClassesCreator()
{
delete myDefinition;
}
makVrv::DtAgentCreator* DtMovablePolygonModelClassesCreator::create()
{
return new DtMovablePolygonModelClassesCreator();
}
makVrv::DtAgent* DtMovablePolygonModelClassesCreator::createAgent(makVrv::DtAgentManagerInterface& sceneInterface)
{
return new DtMovablePolygonModelAgentImplementation();
}
makVrv::DtAgentUpdateResolverInterface* DtMovablePolygonModelClassesCreator::createResolver(makVrv::DtDe& de, makVrv::DtUniqueID id)
{
return new makVrv::DtAgentUpdateResolver<DtMovablePolygonModel>(de,new DtMovablePolygonModel(de,id),myDefinition);
}
}

DtMovablePolygonModelClasses.hpp

/******************************************************************************
** Copyright (c) 2019 VT MAK
** All rights reserved.
******************************************************************************/
#pragma once
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
#include <../examples/exampleBulletHole/DtMovablePolygonModelAgent.hpp>
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelAgentImplementation : public virtual DtMovablePolygonModelAgent , public DtOsgPolygonModelAgentImplementation
{
public:
DtMovablePolygonModelAgentImplementation();
virtual ~DtMovablePolygonModelAgentImplementation();
protected:
virtual DtOsgPolygonModel* findObjectAsDtOsgPolygonModel();
virtual DtMovablePolygonModel* findObjectAsDtMovablePolygonModel();
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelClassDefinition : public makVrv::DtInheritedAgentDefinition<DtOsgPolygonModelClassDefinition,DtMovablePolygonModel>
{
public:
DtMovablePolygonModelClassDefinition(const std::string& className = "DtMovablePolygonModel");
virtual ~DtMovablePolygonModelClassDefinition();
enum FunctionIds
{
};
};
}
// *** Generated Code - Do Not Edit! ***
// *** Created by dcgen ***
namespace makVrv
{
class DtMovablePolygonModelClassDefinition;
class DT_DLL_EXAMPLEBULLETHOLE DtMovablePolygonModelClassesCreator : public makVrv::DtAgentCreator
{
public:
DtMovablePolygonModelClassesCreator();
virtual ~DtMovablePolygonModelClassesCreator();
static makVrv::DtAgentCreator* create();
virtual makVrv::DtAgent* createAgent(makVrv::DtAgentManagerInterface& sceneInterface);
protected:
DtMovablePolygonModelClassDefinition* myDefinition;
static bool theRegisteredFlag;
static makVrv::DtAgentFactory::DtAutoUnregistrar theAutoUnregistrar;
};
}

exampleBulletHolePlugin.cxx

/******************************************************************************
** Copyright (c) 2024 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/bind/bind.hpp>
#include <iostream>
// Define export macro for vrvVrl includes
#define DL_DLL_IGCONVRLINK DT_DLL_EXAMPLEBULLETHOLE
// Define the protocol specific macros to compile for DIS
#define DT_PROTOCOL_NAMESPACE vrvDis
#define DtDIS 1
using namespace makVrv;
#undef DT_PROTOCOL_NAMESPACE
#undef DtDIS
void initializeBulletHoleMenuItem(DtDe& de, int bulletHoleVisualTypeId)
{
QString qTemp = QObject::tr("Bullet Holes");
nameProvider.setDisplayName(bulletHoleVisualTypeId, DtUnicode::fromQString<QString>(qTemp));
qTemp = QObject::tr("Show/Hide Bullet Holes");
nameProvider.setToolTip(bulletHoleVisualTypeId, DtUnicode::fromQString<QString>(qTemp));
}
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// Initialize the osg and qt plugins since we'll be overriding creators
// registered in them
std::cout << "Loading bullet hole plugin" << std::endl;
if (de.isInMasterMode())
{
// Register a new visualizer. This visualizer will display the new mass
// attribute as a text label.
// Register the creator for our enhanced polygon model; this will
// override the default polygon model implementation provided by
// the vrvOsg library
"DtPolygonModel", new DtMovablePolygonModelClassesCreator);
// Every visualizer has a visual type, identified by a unique integer
// key and a unique string name. Visualizers can be controlled by type.
// In this example, we create a new visual type for the bullet holes
// and use it to add a toolbar button that toggles them on and off.
// This integer will be the unique key for the bullet hole visual type.
// VR-Vantage's default visual types are declared in
// DtObserverSettingsManager::ObserverSetting. It's important when creating
// a new visual type to pick an integer id that is unlikely to collide with
// an existing type.
const int bulletHoleVisualTypeId = 976;
// Register a new observer setting item to toggle the bullet hole
// decals on and off. Registering it here allows it to be added to
// GUI configurations later on.
de, "BulletHoleItem", bulletHoleVisualTypeId));
// Register the new visual type to control the bullet holes
DtVisualTypeManager::VisualType("bullet_holes", bulletHoleVisualTypeId,
"../examples/exampleBulletHole/BulletHole.png",
// Add example menu and example toolbar item.
if(app)
{
DtMenuPath::menu("DtObserverMenu").item("BulletHoleItem"));
DtToolbarPath::toolbar("DtObserverSettingsToolbar").item("BulletHoleItem"));
}
//initialize default state is when tooltips and display names can be set
de.signal_initializeDefaultState.connect(boost::bind(&initializeBulletHoleMenuItem, std::ref(de), bulletHoleVisualTypeId));
}
}
{
// Setup the plug-in. Normally, the init function and functionality
// should be in its own library.
{
init(*de);
return true;
}
return false;
}

exampleBulletHolePlugin.h

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#ifndef exampleBulletHolePlugin_h_
#define exampleBulletHolePlugin_h_
// Get proper local export symbol
// Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLEBULLETHOLE
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
namespace makVrv { class DtDe; }
// Work function for the plugin initialization
#endif

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



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