VR-Vantage 2.7 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleDriver

Table of Contents

Overview

This example creates a new driver. On start, this driver will load the Makland terrain database if it is not already loaded; create and initialize an example sim engine; and attach the main observer to the entity created by the sim engine. On tick, the driver will tick the sim engine. On stop, it will destroy the sim engine.

Expected Result

exampleDriver2.png
Example Driver Result

Example details

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

The Driver

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
myAgentManager.de().scene().terrain().addOceanLayer("Ocean");
// set the sea level above to 10 m since this database has water polygons instead
// of bathymetry
DtOceanLayer* layer = myAgentManager.de().scene().terrain().findOceanLayer( "Ocean" );
layer->setSeaLevel( 10. );
// ---- set the sea state
// Put sea state in manual mode ( otherwise, its driven by the wind speed / direction
DtEnvironment& env = myAgentManager.de().scene().environment();
env.setWindDrivenSeaState(false);
// 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
}

It then creates the example sim engine and initializes it.

if ( ! myExampleSimEngine )
{
myExampleSimEngine = new DtExampleSimEngine( myAgentManager.de() );
myExampleSimEngine->init();
}

Finally, it attaches the current observer to the entity that the sim engine will create by calling attachObserverToEntity.

attachObserverToEntity( "Entity From Facade" );

attachObserverToEntity fills out a DtObserverStateRecord by getting the current state of the current observer, changing the attached state, and then calling DtObserver::setFromRecord on the same observer. setFromRecord has the special property that if an attachment is specified and the entity indicated is not yet available to attach to, the observer listen for signals that elements have been added, until the desired element is created.

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

The example driver's onTick() method calls the sim engine's tick function, providing the current simulation time from the display engine.

myExampleSimEngine->tick( myAgentManager.de().simulationTime() );

The example driver's onStop() method call's the sim engine's uninit method and then deletes the sim engine if the sim engine exists (it may not, since onStop() may be called multiple times).

if ( myExampleSimEngine )
{
myExampleSimEngine->uninit();
delete myExampleSimEngine;
myExampleSimEngine = 0;
}

The Sim Engine

The example sim engine creates and updates an entity that includes an entity indicator and a height-above-terrain (HAT) line. The sim engine is constructed with a reference to the display engine (DtDe) which provides access to the agent manager for creating distributed objects; a coordinate system object for converting locations and orientations to the current coordinate system is use; the databank, so that the engine can report element creation and attribute changes; and the main event queue, to listen for mouse over signals for the entity indicator.

The init() method is responsible for creating and initializing the entity, entity indicator, entity information widget, and HAT line.

First, the sim engine creates a new entity facade and tells it to use the F16 Visual Definition.

// Create the entity
DtElementID parentElementId = 0;
myEntityDisplayName = "Entity From Facade";
DtElementID elementId = mySimulationConnection.sceneInterface().createNewUniqueId();
myEntityFacade = new DtEntity3dFacade( mySimulationConnection.sceneInterface(),
mySimulationConnection.settingsManager(), elementId, true );
// Load the model
myEntityFacade->setArticulatedModelDefinition("FixedWingRQ-1Predator");

It creates the entity indicator, and adds the new model agent to the existing entity facade's scene object (so that it will be positioned in the same place).

myEntityIndicator =
new DtEntityIndicatorWidget( mySimulationConnection.sceneInterface(), myEntityFacade->modelSet() );
myEntityIndicator->setEventsEnabled( true );
myEntityIndicator->setColor( 0, 0, 1, 1 );
setHoverSignalsActive( true );
// Attach the entity indicator to the entity
myEntityFacade->sceneObjectAgent().addModel( myEntityIndicator->model(),

It creates a HAT line using the DtEntityHATLineFacade, which will create the necessary models and attach to the entity's scene object.

myEntityHATLineFacade = new DtEntityHATLineFacade( mySimulationConnection.sceneInterface(), myEntityFacade->modelSet(),
myEntityFacade->sceneObjectAgent().uniqueId() );

init() then connects to the selection manager's signal_entityInfoToggled.

As labels are pinned or unpinned, this will cause slot_toggleLabelPinnedState to be called. This method updates the visibility of both the indicator and the info label, and also tells the sim to listen or stop listening to the mouse hover signals (detailed below).

The example driver updates the sim engine by calling its tick() method. The sim engine's tick() method updates the F16's position using updatePosition(), and updates the text displayed on the F16's entity info label.

The driver's generateInfoString() method essentially performs some formatting and unit conversion on the information it has about the aircraft's position and orientation in the scene. The value returned from this method is then simply set on the entity info widget (if there is one present - if the mouse isn't hovering, there won't be an info widget).

The driver's updatePosition() method first determines how long it's been since the last update, and updates the aircraft's clock angle based on its angular velocity. The clock angle is the bearing to the aircraft from the point at the center of the aircraft's orbit (0 for north, and increasing in the clockwise direction). It then determines the aircraft's offset from the center of its orbit.

The aircraft's orbit is circular, so computing the heading is as easy as adding 90 degrees (Pi/2) to the clock angle. Once this has been done, the heading and roll can be used to determine the net orientation of the F16.

Now that the F16's position and orientation have been computed, the aircraft can be repositioned in the scene.

Finally, the current time is set as the last update time in preparation for the next update.

Positioning the aircraft takes place in the repositionAircraft(..) method. This method first determines the type of coordinate system using the DtCoordinateConverter, then converts the position and orientation to local database (CIG) coordinates. Finally, the CIG coordinates are set on the entity facade, performing the actual reposition.

// Get the coordinate converter and initialize.
DtCoordinateConverter* coordConverter;
coordConverter = mySimulationConnection.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 );

The sim engine is unitialized by calling its uninit() method. This cleans up the entity facade, indicator, info widget, and HAT line allocated on the heap. It also tells the DataBank that the element has been destroyed.

if ( myEntityFacade )
{
if ( myEntityInfoWidget )
{
myEntityFacade->sceneObjectAgent().removeModel(
myEntityInfoWidget->model() );
delete myEntityInfoWidget;
myEntityInfoWidget = 0;
}
if ( myEntityIndicator )
{
setHoverSignalsActive( false );
myEntityFacade->sceneObjectAgent().removeModel(
myEntityIndicator->model() );
delete myEntityIndicator;
myEntityIndicator = 0;
}
mySimulationConnection.reportElementDestroyed(
myEntityFacade->elementId() );
delete myEntityFacade;
myEntityFacade = 0;
}
return true;

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

Building the Example

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

Running the Example

This example is an application. You can run it by running ./bin64/exampleDistributedObject.exe (on Windows) or ./bin64/exampleDistributedObject (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.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)
{
}
{
}
{
static std::string name = "DtExampleDriver";
return name;
}
{
// Load Makland programatically.
DtScene& sceneDriver = myAgentManager.de().scene();
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;
}
{
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();
}

DtExampleDriver.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:
};

DtExampleDriver.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include "DtExampleSimEngine.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 )
{
}
{
}
{
static std::string name = "DtExampleDriver";
return name;
}
{
// Load Makland programatically.
DtScene& sceneDriver = myAgentManager.de().scene();
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.
attachObserverToEntity( "Entity From Facade" );
return true;
}
{
{
}
return true;
}
{
{
}
return true;
}
{
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();
}

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

Overview

This example creates a new driver. 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.

Expected Result

exampleThreadedDriver.png
Threaded Driver Result

Example details

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

DtScene& sceneDriver = myAgentManager.de().scene();

It then creates a new entity facade and tells it to use the F16 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.

As labels are pinned or unpinned, the togglePinnedLabel slot is called. This slot updates the visibility of both the indicator and the info label, and also tells the driver to listen or stop listening to the mouse hover signals (detailed below).

The driver manager updates the example driver by calling its onTick() method. The driver's onTick() method updates the F16's position using updatePosition(), and updates the text displayed on the F16's entity info label.

The driver's generateInfoString() method essentially performs some formatting and unit conversion on the information it has about the aircraft's position and orientation in the scene. The value returned from this method is then simply set on the entity info widget (if there is one present - if the mouse isn't hovering, there won't be an info widget).

The driver's updatePosition() method first determines how long it's been since the last update, and updates the aircraft's clock angle based on its angular velocity. The clock angle is the bearing to the aircraft from the point at the center of the aircraft's orbit (0 for north, and increasing in the clockwise direction). It then determines the aircraft's offset from the center of its orbit.

The aircraft's orbit is circular, so computing the heading is as easy as adding 90 degrees (Pi/2) to the clock angle. Once this has been done, the heading and roll can be used to determine the net orientation of the F16.

Now that the F16's position and orientation have been computed, the aircraft can be repositioned in the scene. Finally, the current time is set as the last update time in preparation for the next update.

Positioning the aircraft takes place in the repositionAircraft(..) method. This method first determines the type of coordinate system using the DtCoordinateConverter, then converts the position and orientation to local database (CIG) coordinates. Finally, the CIG coordinates are set on the entity facade, performing the actual reposition.

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.

Building the Example

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

Running the Example

This example is an application. You can run it by running ./bin64/exampleThreadedDriver.exe (on Windows) or ./bin64/exampleThreadedDriver (on Linux). For more information about running examples, please see Running Applications and Examples.

Example Source Files


DtExampleSimEngine.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <DtExampleSimEngine.h>
#include <vrvCore/DtDe.h>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
: mySimulationConnection( connection )
, myEntityFacade( 0 )
, myEntityIndicator( 0 )
, myEntityInfoWidget( 0 )
, myEntityHATLineFacade( 0 )
, myEntityDisplayName( "" )
, myEntityInfoWidgetPinnedFlag( false )
, myPosition()
, myOrientation()
, myOrbitCenter( 2000.0, 1400.0, 350.0 )
, myAngularVelocity( 0.2 )
, myLastCommLineTime( 0.0 )
, myLastUpdateTime( 0.0 )
, myClockAngle( 0.0 )
, myHeading( 0.0 )
, myRadius( 1000.0 )
, myRoll( 0.5 )
{
}
{
// Create the entity
DtElementID parentElementId = 0;
myEntityDisplayName = "Entity From Facade";
// Load the model
myEntityFacade->setArticulatedModelDefinition("FixedWingRQ-1Predator");
// Let the DataBank know about this new element
mySimulationConnection.reportElementCreated( elementId, parentElementId, DtElementEntry::Entity );
mySimulationConnection.reportElementAttribute(elementId, new DtElementAttributeElementSubtype(DtElementAttributes::Friendly));
// Create the entity indicator
myEntityIndicator->setColor( 0, 0, 1, 1 );
// Attach the entity indicator to the entity
DtStateVisualizer::EntityVisualizerType );
// Create a HAT line
// Listen for a signal toggling the entity info widget's pinned state
DtSharedSimulationSettingsSignaler& simSettingsSignaler =
DtSharedSimulationSettingsSignaler::instance( mySimulationConnection.settingsManager() );
mySignalConnections += simSettingsSignaler.signal_entityLabelPinnedToggled.connect(
return true;
}
{
{
{
}
{
}
}
return true;
}
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( mySimulationConnection.settingsManager() );
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.
myEntityFacade->modelSet(), "entityInfo" );
myEntityInfoWidget->setColor( 0, 0, 1, 1 );
// Set group id in the entityInfoHoverGroup.
DtOverlayGroupManager& groupManager =
DtOverlayGroupManager::instance( mySimulationConnection );
myEntityInfoWidget->setGroup( groupManager.nextGroupId("hoverGroupSet") );
// Add it to the entity,
DtStateVisualizer::EntityVisualizerType );
// And update its display text.
DtUnicode infoString = generateInfoString();
myEntityInfoWidget->setText( infoString );
}
// 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";
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);
}
void DtExampleSimEngine::updatePosition( double simTime )
{
// Get current time and 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.
DtVector offset( myRadius*sin(myClockAngle), myRadius*cos(myClockAngle), 0 );
// Compute heading and net orientation. Since the aircraft is
// orbiting in a perfect circle, the heading is always 90 degrees
// (pi/2) more than the bearing to the aircraft.
myHeading = myClockAngle + M_PI_2;
DtTaitBryan ori( myHeading, 0, myRoll );
// Update the aircraft's position/orientation with the new parameters.
// Store as last update time.
myLastUpdateTime = now;
}
void DtExampleSimEngine::repositionAircraft( DtVector position, DtTaitBryan ori )
{
// Get the coordinate converter and initialize.
DtCoordinateConverter* coordConverter;
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.
}
{
// 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.
}
}
}

DtExampleSimEngine.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <matrix/vlTaitBryan.h>
#include <matrix/vlVector.h>
#include <string>
namespace makVrv
{
class DtEntity3dFacade;
class DtEntityHATLineFacade;
}
{
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 );
virtual void repositionAircraft( DtVector position, DtTaitBryan ori );
protected:
DtTaitBryan myOrientation;
DtVector myPosition;
DtVector myOrbitCenter;
double myClockAngle;
double myHeading;
double myRadius;
double myRoll;
};

DtExampleSimulationConnection.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include "DtExampleSimEngine.h"
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
const makVrv::DtCoordinateSystem& coordSystem,
: DtBaseConnection(settingsManager, aSceneInterface)
, myCoordinateSystem(coordSystem.clone())
, myExampleSimEngine( 0 )
, mySimTime( 0.0 )
{
}
{
}
{
return connected();
}
{
return myExampleSimEngine != 0;
}
{
return connected();
}
{
{
}
}
{
}
{
return mySimTime;
}
{
}

DtExampleSimulationConnection.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
namespace makVrv
{
class DtCoordinateSystem;
class DtAgentManagerInterface;
class DtSharedSettingsManager;
}
{
public:
const makVrv::DtCoordinateSystem& coordSystem,
virtual bool connect();
virtual bool connected() const;
virtual bool disconnect();
virtual void tick();
double simTime() const;
void setSimTime( double simTime );
protected:
//The local coordinate system the simulation will use.
double mySimTime;
};

DtExampleThreadedDriver.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include <vlutil/vlRunnable.h>
#include <vlutil/vlProcessControl.h>
#include <vlutil/vlPerformanceStats.h>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
: DtDriver( am, "DtExampleThreadedDriver" )
, myClassName("DtExampleThreadedDriver")
, myUseThreadFlag(true)
, myThread(0)
, myConnectionThreadFunctions()
, mySimulationConnection(0)
, myAsynchronousEventQueue(0)
, mySimulationConnectionState(false)
, myAsynchronousInterface(NULL)
{
if ( myUseThreadFlag )
{
myAsynchronousInterface =
myAgentManager.createAsynchronousManager(instanceName());
}
}
{
}
{
return myClassName;
}
{
}
{
// Load Makland programatically.
DtScene& sceneDriver = myAgentManager.de().scene();
maklandPath += "/terrains/Makland.mtf";
if ( sceneDriver.terrainFileName() != maklandPath )
{
sceneDriver.loadTerrain( maklandPath );
}
attachObserverToEntity( "Entity From Facade" );
// The simulation object must be created by a subclass.
{
return false;
}
{
}
else
{
}
return true;
}
{
{
}
else
{
}
{
//Add all queued messages.
}
return true;
}
{
double simTime = myAgentManager.de().simulationTime();
{
}
else
{
{
}
}
}
{
// Listen for requests to pin/unpin the info label
DtSelectionManager& selMgr = DtSelectionManager::instance( myAgentManager.de() );
}
{
myDynamicSignals.disconnectSignals();
}
// Execute a function queue. This is called from the main thread (with the queue of
// Driver functions) and from the connection queue (with the queue of connection functions)
void DtExampleThreadedDriver::runFunctionQueue(FunctionCallQueue& queue)
{
FunctionCallList* functions = 0;
queue.getForReading(functions);
if(functions->size() > 0)
{
FunctionCallList::iterator curIter = functions->begin();
FunctionCallList::iterator endIter = functions->end();
for(;curIter != endIter;++curIter)
{
(*curIter)();
}
}
}
//
// Start the thread the sim engine will run in
//
{
if ( ! myUseThreadFlag )
{
return;
}
if ( myThread )
{
}
// Hold on to point since VR-Link doesn't delete it.
myStart = DtThreadStartSP(new DtThreadStart( this ));
myThread = new DtThread( myStart );
if ( myThread->start() != DtThreadSuccess )
{
DtTHROW_NEW( DtCorruptedState, "Unable to start Connection thread." );
}
}
//
// Run the thread. This is the thread's main loop
//
{
//Register in thread.
bool connected = mySimulationConnection->connect();
if(!connected)
{
return;
}
//Start timing.
DtTimedSection ts;
// Don't let the thread tick flat out, or rendering performance will suffer
double desiredFrameTime = .01667; // 60Hz
// The thread's main loop
while(!timeToStop())
{
ts.start();
// If the driver has requested any functions to be run in the connection thread,
// run them now. In the current example, that will include the connection's
// setSimTime() method
//Process any asynchronous events.
//Tick the simulation.
try
{
}
catch(...)
{
break;
}
//Tick the interface aka send messages to main thread.
// Manage element creations, changes, and deletions. This updates the
// DtDataBank's element data
{
}
ts.stop();
//If duration is less than the desired frame time, sleep the remaining
//of the frame.
if(ts.duration() < desiredFrameTime )
{
DtSleep(desiredFrameTime - ts.duration());
}
}
// Shut down the simulation
// Process element data changes one more time; shutting down the simulation
// may have resulted in elements being destroyed.
{
}
// tell the driver to set our connection state back to false
}
//
// Stop the thread the sim engine runs in
//
{
if ( myThread )
{
myThread->stop(false);
DtYield();
//Problem the thread might be attempting to lock the IG.
//Solution until the thread stops, service lock attempts.
while(myThread->isRunning())
{
DtYield();
}
delete myThread;
myThread = 0;
myStart.reset();
}
}
{
DtAgentManagerInterface* simSceneInterface = &myAgentManager;
{
simSceneInterface = myAsynchronousInterface;
}
DtDe& de = agentManager().de();
*simSceneInterface,
DtSharedSettingsManager::instance(de));
return connection;
}
void DtExampleThreadedDriver::queueConnectionFunction(const boost::function<void ()>& function)
{
}
void DtExampleThreadedDriver::queueDriverFunction(const boost::function<void ()>& function)
{
}
{
}
{
}
{
DtObserver* currentObserver = myAgentManager.de().
driverManager().inputDriver().currentObserver();
currentObserver->getRecord( observerStart );
std::set<std::string> displayNames;
displayNames.insert( entityName );
observerStart.setAttachedToDisplayNames( displayNames );
observerStart.setObserverOffsetVector( 30., 0., 0. );
currentObserver->setFromRecord( observerStart );
}
{
{
}
}
{
DtSharedSimulationSettingsSignaler::instance(myAgentManager.de().mainEventQueue()).signal_entityLabelPinnedToggled(sel);
}

DtExampleThreadedDriver.h

/*****************************************************************************
* Copyright (c) 2020 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <vlutil/vlRunnable.h>
#include <boost/function.hpp>
#include <vlutil/vlThread.h>
#include <string>
namespace makVrv
{
class DtAsynchronousAgentManager;
class DtAsynchronousEventQueue;
}
class DtThread;
class DtThreadStart;
// This driver creates and owns the example driver.
{
public:
virtual const std::string& className() const;
virtual void queueDriverFunction(const boost::function<void ()>& function);
virtual void queueConnectionFunction(const boost::function<void ()>& function);
bool useThreadFlag() const;
boost::signalslib::signal<void (DtExampleSimulationConnection*)> signal_simulationCreated;
boost::signalslib::signal<void (DtExampleSimulationConnection*)> signal_simulationAboutToBeDestroyed;
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 );
virtual void run();
void startThread();
void stopThread();
void setSimulationConnectionState( bool state );
virtual void connectToDynamicSignals();
virtual void slot_togglePinnedLabel(
typedef std::vector<boost::function<void ()> > FunctionCallList;
virtual void runFunctionQueue(FunctionCallQueue& queue);
protected:
//Main thread variables.
DtThreadStartSP myStart;
DtThread* myThread;
};

exampleThreadedDriver.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
int main( int argc, char* argv[] )
{
// Create the Application.
makVrv::DtVrvApplication application( stealthConfig );
application.installCommandLineProcessor( &stealthParser );
// This causes the plug-in manager to load plug-ins, cause a Display Configuration
// to be realized, creates the default environment, etc.
application.initialize( argc, argv );
// Create DtExampleThreadedDriver.
DtExampleThreadedDriver* driver = new DtExampleThreadedDriver( application.de().agentManager() );
// The driver is now owned by the display engine. Do not delete it.
application.de().driverManager().addDriver( driver );
// Start the driver, creating the agent.
application.de().driverManager().startDriver( driver );
// Creates an event loop and begins running it, causing the creation of frames.
application.run();
return 0;
}

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



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