VR-Forces 4.10 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleDriverPlugin

Table of Contents

Overview

This driver will load the Makland terrain database and create an F-16 entity on start, attach the main observer to it, and then move the F16 a small amount each time that it's ticked. This example adds a driver via a plugin.

Expected Result

exampleDriver2.png
Example Driver Plugin Result

Example details

The example driver's onStart() method loads the database first.

It then creates a new entity facade and tells it to use the f-16_Falcon Visual Definition.

Using the coordinate system information provided by the loaded terrain database, the driver provides an initial position and orientation in the coordinate system of the database.

The current observer is then attached to the newly created entity, and reset to provide a perspective view.

The driver manager ticks the example driver by calling its onTick() method. The onTick() method updates the driver's local kinematic member variables and then passes them on to the entity facade.

The driver is stopped by the driver manager callings its onStop() method. This cleans up the entity facade allocated on the heap.

The example driver is created, added to the driver manager, and started in the main program.

void installDriver(DtDe& de)
{
// Create DtExampleDriver.
DtExampleDriver* driver = new DtExampleDriver( 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);

The plugin registers the install function to be called after the DtDe has been initialized.

if (de.isInMasterMode())
{
// The accessory must be created after the DE's initialization is
// finished, to make sure all the objects it uses exist.
de.signal_postInitialize.connect(boost::bind(
&installDriver, boost::ref(de) ));

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/exampleDriverPlugin_stealth.bat (on Windows) or ./bin64/exampleDriverPlugin_stealth.sh (on Linux). Press the "s" key to get away from the entity and see the HAT line. For more information about running examples, please see Running Applications and Examples.

Example Source Files


exampleDriver.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <string>
// This driver creates and owns the example driver.
{
public:
virtual ~DtExampleDriver();
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
virtual void attachObserverToEntity(const std::string& entityName);
virtual void slot_displayEngineAdded(const makVrv::DtDeRecord& igRecord);
protected:
};

exampleDriver.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include "exampleDriver.h"
#include <vrvCore/DtDe.h>
#ifdef SIM_IS_SHIP
#endif
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
: makVrv::DtDriver(am, "DtExampleDriver")
, myExampleSimEngine(0)
{
}
{
}
const std::string& DtExampleDriver::className() const
{
static std::string name = "DtExampleDriver";
return name;
}
{
// Load Makland programatically.
DtScene& sceneDriver = myAgentManager.de().scene();
std::string maklandPath = myAgentManager.de().dePathConfiguration().userPath();
maklandPath += "/terrains/Makland.mtf";
if (sceneDriver.terrainFileName() != maklandPath)
{
sceneDriver.loadTerrain(maklandPath);
#ifdef SIM_IS_SHIP
// add an ocean layer - this can be saved with the database in an mtf file
// set the sea level above to 10 m since this database has water polygons instead
// of bathymetry
layer->setSeaLevel(10.);
// ---- set the sea state
// Put sea state in manual mode ( otherwise, its driven by the wind speed / direction
// Now we can manually set sea state and direction
env.setSeaState((int)DtDouglasSeaState::Slight);
env.setSeaStateDirection(1.57); // roughly east
env.setSeaChoppiness(0.8); // 0.-1.
#endif
}
{
}
// Attach to entity.
#ifdef SIM_IS_SHIP
#else
#endif
return true;
}
{
{
}
return true;
}
{
{
}
return true;
}
void DtExampleDriver::attachObserverToEntity(const std::string& entityName)
{
DtObserver* currentObserver = myAgentManager.de().
driverManager().inputDriver().currentObserver();
currentObserver->getRecord(observerStart);
std::set<std::string> displayNames;
displayNames.insert(entityName);
observerStart.setAttachedToDisplayNames(displayNames);
observerStart.setObserverOffsetVector(150., 0., 20.);
currentObserver->setFromRecord(observerStart);
}
{
stop();
start();
}

exampleSimEngine.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <matrix/vlTaitBryan.h>
#include <matrix/vlVector.h>
#include <string>
//#define SIM_IS_SHIP
namespace makVrv
{
class DtEntity3dFacade;
class DtEntityHATLineFacade;
class DtDe;
}
{
public:
bool init();
bool uninit();
bool tick(double simTime);
protected:
virtual void setHoverSignalsActive(bool active);
virtual void setEntityInfoWidgetActive(bool active);
virtual void updatePosition(double simTime);
#ifdef SIM_IS_SHIP
// For the ship, need to pass dT so we can determine velocity
virtual void repositionShip(DtVector position, DtTaitBryan ori, double dT);
#else
virtual void repositionAircraft(DtVector position, DtTaitBryan ori);
#endif
protected:
std::string myEntityDisplayName;
DtTaitBryan myOrientation;
#ifdef SIM_IS_SHIP
// For the ship, need our last (local) position to determine our velocity
DtVector myLastPosition;
#endif
double myHeading;
double myClockAngle;
double myRadius;
double myRoll;
};

exampleSimEngine.cxx

/*****************************************************************************
* Copyright (c) 2021 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include <vrvCore/DtWakeModelAgent.hpp>
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <matrix/LibMatrix.h>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
: myDe(de)
, myEntityFacade(0)
, myEntityIndicator(0)
, myEntityInfoWidget(0)
, myEntityDisplayName("")
, myEntityInfoWidgetPinnedFlag(false)
, myPosition()
, myOrientation()
, myLastUpdateTime(0.0)
, myEntityHATLineFacade(0)
, myHeading(0.0)
, myLastCommLineTime(0.0)
#ifdef SIM_IS_SHIP
, myOrbitCenter(-9500.0, 17200.0, 10.0)
, myAngularVelocity(0.006)
, myClockAngle(0.0)
, myRadius(5000.0)
, myRoll(0.0)
, myLastPosition(-9500.0, 22200.0, 10.)
#else
, myOrbitCenter(2000.0, 1400.0, 350.0)
, myAngularVelocity(0.1)
, myClockAngle(0.0)
, myRadius(1000.0)
, myRoll(0.6)
#endif
{
}
{
// Create the entity
DtElementID parentElementId = 0;
#ifdef SIM_IS_SHIP
myEntityDisplayName = "Ship 1";
#else
#endif
DtSharedSettingsManager::instance(myDe), elementId, true);
#ifdef SIM_IS_SHIP
// Load the model
myEntityFacade->setArticulatedModelDefinition("SurfaceWatercraftDDG151Arleigh-BurkeNavy");
// Need to 'dead reckon' position because wakes use the velocity from the dead
// reckoner
// Enable watercraft-specific elements
DtWakeModelAgent* wakeModelAgent = myEntityFacade->wake();
wakeModelAgent->setSprayEnabled(true);
wakeModelAgent->setBowSprayOffset(58.);
wakeModelAgent->setSpraySizeScale(3.);
wakeModelAgent->setNumHullSprays(5);
wakeModelAgent->setHullSprayStart(-155.);
wakeModelAgent->setHullSprayEnd(30.);
wakeModelAgent->setPropWashEnabled(true);
wakeModelAgent->setShipLength(300.);
wakeModelAgent->setBeamWidth(16.);
wakeModelAgent->setDraft(10.);
wakeModelAgent->setSprayVelocityScale(0.65);
wakeModelAgent->setBowWaveScale(1.);
wakeModelAgent->setBowSize(2.);
wakeModelAgent->setBowWaveOffset(70.);
wakeModelAgent->setSternWaveOffset(-60.);
wakeModelAgent->setWakeOffset(0.);
wakeModelAgent->setPropWashOffset(-75.);
wakeModelAgent->setPropWashFadeTime(30.);
wakeModelAgent->setMaxBowWaveAmplitude(5.);
wakeModelAgent->setHullSpraySizeScale(1.);
wakeModelAgent->setHullSprayVelocityScale(0.4);
wakeModelAgent->setHullSprayVerticalOffset(1.);
myEntityFacade->setWakeLODDistance(10000.0); //set the wake lod distance to 10000.0 meters
#else
// Load the model
myEntityFacade->setArticulatedModelDefinition("FixedWingRQ-1Predator");
#endif
// Let the DataBank know about this new element
changes.myElementsAdded.push_back(new DtElementEntry(elementId, parentElementId, DtElementEntry::Entity));
changes.myAttributesChanged[elementId].push_back(new DtElementAttributeVisibility(true));
changes.myAttributesChanged[elementId].push_back(new DtElementAttributeElementSubtype(DtElementAttributes::Friendly));
changes.myAttributesChanged[elementId].push_back(new DtElementAttributeDriverType("Example Driver"));
// the below change makes it so the entity we're creating respects the 'Fixed Wing' display unit collection
changes.myAttributesChanged[elementId].push_back(new DtElementAttributeDisplayUnitCollectionName("Fixed Wing"));
// Create the entity indicator
// Attach the entity indicator to the entity
DtStateVisualizer::EntityVisualizerType);
#ifndef SIM_IS_SHIP
// Create a HAT line
// The element ID is used to look up the display unit collection element
// attribute set above
#endif
// Listen for a signal toggling the entity info widget's pinned state
DtSelectionManager& selectMgr(DtSelectionManager::instance(myDe));
mySignalConnections += selectMgr.signal_entityInfoToggled.connect(boost::bind(
return true;
}
{
{
{
}
{
}
}
return true;
}
DtSceneObject* findSceneObjectFromElement(DtDe& myDe, const DtElementID& id)
{
myDe.dataBank().elementData().getSceneObjectIds(id, idList, 0);
if (idList.size() == 0)
{
return 0;
}
DtAgentUpdateResolverInterface* updater = myDe.agentManager().findUpdater(idList.front());
if (updater)
{
return updater->castObjectTypeFromUpdater<DtSceneObject>("DtSceneObject");
}
return 0;
}
bool DtExampleSimEngine::tick(double simTime)
{
updatePosition(simTime);
{
}
return true;
}
{
// Get the event signals for the entity indicator from the widget signaler.
DtWidgetSignaler& widgetSignaler =
DtWidgetSignaler::instance(myDe.mainEventQueue());
widgetSignaler);
// Connect to or disconnect from the signals.
if (active)
{
signals.signal_mouseEnter.connect(boost::bind(
signals.signal_mouseLeave.connect(boost::bind(
}
else
{
signals.signal_mouseEnter.disconnect(boost::bind(
signals.signal_mouseLeave.disconnect(boost::bind(
}
}
{
// If mouse is hovering and there's no info widget...
if (active && !myEntityInfoWidget)
{
// Create the entity info widget and set the color.
myDe.agentManager(),
myEntityFacade->modelSet(), "entityInfo");
// Set group id in the entityInfoHoverGroup.
DtOverlayGroupManager& groupManager =
DtOverlayGroupManager::instance(myDe);
myEntityInfoWidget->setGroup(groupManager.nextGroupId("hoverGroupSet"));
// Add it to the entity,
DtStateVisualizer::EntityVisualizerType);
// And update its display text.
DtUnicode infoString = generateInfoString();
}
// If mouse isn't hovering, and there is an info widget...
else if (!active && myEntityInfoWidget)
{
// Remove it from the model and destroy it.
}
}
{
DtReferenceEllipsoid refEllip(DtWGS84);
DtGeodeticCoord geod(&refEllip);
geod.setGeocentric(myPosition);
DtVector localp;
DtTaitBryan hpr;
const DtCoordinateSystem& coordSys =
coordSys.netToLocalPos(myPosition, localp);
coordSys.netToLocalHpr(localp, myOrientation, hpr);
const char* entityFormatString =
"Marking :%s\n" // Marking Text
"Heading :%.2f Deg\n" // Heading
"Lat|Lon :%.2fN %.fE\n" // Location
"Alt. :%.1f m above sea level";
std::string buffer;
buffer.resize(1024, '0');
{
int charsWritten = sprintf(
const_cast<char*>(buffer.c_str()), entityFormatString,
myEntityDisplayName.c_str(), // Marking Text
DtRad2Deg(myHeading), // Heading
DtRad2Deg(geod.lat()), // Location (Lat)
DtRad2Deg(geod.lon()), // Location (Lon)
myPosition[2] // Altitude
);
buffer.resize(charsWritten, '0');
}
return DtUnicode::fromUtf8(buffer);
}
{
// Compute time since last update.
double now = simTime;
double dt = now - myLastUpdateTime;
// Update clock angle. The clock angle represents the bearing
// to the aircraft from the center point of its orbit.
// Compute the offset to the aircraft using the radius and clock angle.
// Compute heading and net orientation. Since the entity is
// orbiting in a perfect circle, the heading is always 90 degrees
// (pi/2) more than the bearing to the aircraft.
myHeading = DtModPerLo(myClockAngle + M_PI_2, 0., 2.*M_PI);
DtTaitBryan ori(myHeading, 0, myRoll);
#ifdef SIM_IS_SHIP
// Update the ship's position/orientation with the new parameters.
repositionShip(myOrbitCenter + offset, ori, dt);
#else
// Update the aircraft's position/orientation with the new parameters.
#endif
// Store as last update time.
myLastUpdateTime = now;
}
#ifdef SIM_IS_SHIP
void DtExampleSimEngine::repositionShip(DtVector position, DtTaitBryan ori, double dt)
#else
void DtExampleSimEngine::repositionAircraft(DtVector position, DtTaitBryan ori)
#endif
{
// Get the coordinate converter and initialize.
DtCoordinateConverter* coordConverter;
coordConverter = myDe.sharedState().coordinateSystem().converter();
if (coordConverter->type() == DtCoordinateConverter::Geocentric)
{
// => Use this for MaklandGeocentric - not exact but close enough
DtGeodeticCoord geod(DtDeg2Rad(10.0), DtDeg2Rad(60.0), 0.0);
coordConverter->setupTopoFrame(geod.geocentric());
}
else
{
// Or this for Makland (UTM)
coordConverter->setupTopoFrame(position);
}
// Convert the position (from ENU) to local database (CIG) coords.
coordConverter->enuToCig_coordTrans(position, myPosition);
// Convert the orientation (from NED) to local database (CIG) ori.
myOrientation = coordConverter->nedToCig_EulerTrans(ori);
// Set the Position and Orientation on the aircraft.
myEntityFacade->setOrientation(myOrientation);
myEntityFacade->setPosition(myPosition);
#ifdef SIM_IS_SHIP
// need a velocity for wakes
DtVector vecDiff;
DtVector localVel;
DtVector velocity;
DtVecSub(position, myLastPosition, vecDiff);
DtVecScale(vecDiff, 1.0 / dt, localVel);
coordConverter->enuToCig_vecTrans(localVel, velocity);
myEntityFacade->setVelocity(DtVector64To32(velocity));
myLastPosition = position;
#endif
}
{
// Iterate over selected entities...
DtSelectionManager::IdSet::const_iterator i = sel.begin();
DtSelectionManager::IdSet::const_iterator e = sel.end();
for (; i != e; ++i)
{
// If the entity facade is selected...
if ((*i) == myEntityFacade->elementId())
{
// Pin/unpin the label and stop/start listening for mouse hovers.
}
}
}

exampleDriverPlugin.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#ifdef _WIN32
#ifdef EXAMPLEDRIVERPLUGIN_EXPORTS
#define DT_DLL_EXAMPLEDRIVERPLUGIN __declspec ( dllexport )
#else
#define DT_DLL_EXAMPLEDRIVERPLUGIN __declspec ( dllimport )
#endif
#else
#define DT_DLL_EXAMPLEDRIVERPLUGIN
#endif
// Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLEDRIVERPLUGIN
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))

exampleDriverPlugin.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include "exampleDriver.h"
// Use the VR-Vantage namespace. All classes in VR-Vantage are in this namespace.
using namespace makVrv;
{
// Create DtExampleDriver.
// 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 Tue Sep 21 17:42:52 EDT 2021 from SVN revision 234861
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)