Introduction to Project 4C
Project 4C in the Distributed Simulation tutorial takes a look at how to add an entity to the scene using a custom VR-Vantage agent. For this project we will create a custom class which will contain all the functionality that we want the scene entity to have. In order to add this entity to the scene, we will introduce the VT MAK dcgen tool, which is used to generate the agent and supporting classes that we will use.
Examining the files that make up the project
For this project, all files from Project 2A will be reused. We will add one more class called ExampleSimulationObject and we will use the dcgen tool (both discussed below) to generate the classes needed for creating an agent. The resulting agent class is what we will use to place an entity into the scene.
Adding an Entity to the Scene
To add an entity to the scene, we will change the driver class so that it has a member pointer to an example simulation object agent, along with a double for use in image rotation.
ExampleSimulationObjectAgent* myAgent;
double myRotationDegree;
In the driver definition file, we will need to add an include for the example simulation object agent class header.
The new onStart() function looks as follows:
bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
DtExerciseConnInitializer
init;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
init.setReceiveBufferSize(0x100000);
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);
if (!myAgent)
{
myAgent = ExampleSimulationObjectAgent::create(myAgentManager);
myAgent->loadModel("../data/Lifeforms/Animals/cow.osg");
}
return myConnectionState;
}
The difference here is that we create an instance of an ExampleSimulationObjectAgent object if it doesn't already exist, and then call that object to load the necessary model from file, as was done with Project 4A. This is different to Project 4B where we had to use a string to reference a VR-Vantage pre-registered model.
if (!myAgent)
{
myAgent = ExampleSimulationObjectAgent::create(myAgentManager);
myAgent->loadModel("../data/Lifeforms/Animals/cow.osg");
}
The new onStop() function removes the added model from the agent object if it exists, and then deletes the object.
bool DistributedSimulationDriver::onStop()
{
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
delete myConnection;
myConnection = 0;
if (myAgent)
{
myAgent->removeModel();
delete myAgent;
}
myAgent = 0;
return true;
}
As with Project 4B, the onTick() function is responsible for animating the cow image by rotating it to the left.
bool DistributedSimulationDriver::onTick()
{
if (myConnectionState)
{
int numread = myConnection->drainInput();
std::cout << "." << numread;
}
else
std::cout << "x";
myAgent->setRotationAngle(myRotationDegree);
myRotationDegree += 0.15;
if(myRotationDegree > 360.0)
{
myRotationDegree = 0.0;
}
return myConnectionState;
}
We then need to create the example simulation object class, which will be used to generate the agent class and all other classes needed to support the agent. We will give this class the ability to load a model to the scene root node, remove a model from the scene root node, and set the rotation angle on a loaded node. The files defining this class can be seen at the following links:
Generating an agent class using dcgen
The VR-Vantage Distributed Code Generator can be started as follows:
- Windows: Go to the start menu, and select: All Programs > MAK Technologies > VR-Vantage 1.4 > Tools > VR-Vantage Distributed Code Generator.
- Linux: Run <VRVInstallDir>/bin/dcgen, where VRVInstallDir is the directory where you have installed VR-Vantage into.
When the dcgen window opens, choose File > New. Do the following:
- Go to the Object Class area:
- In the Name box, type the name of the object class that we are generating an agent for. In our case, that would be ExampleSimulationObject.
- In the Namespace box, type the namespace if used (in our case, makVrv).
- In the Header File box, type the full name of the header file for this class (in our case, ExampleSimulationObject.h).
- Go to the Functions area:
- Click New to add the names of all functions in the API for this class.
- For each of the added functions, highlight the function in the Functions list and go to the Function Arguments area:
- Click New to add each of the type/name pairs for the function's parameter list. Add these in the order they appear in the function signature.
- Finally, choose Files > Save, navigate to the project directory, give an output filename for the .ocdx file, and click Save.
The resulting .ocdx file is an XML definition file that will be used to generate the agent class that we will use to add entities to the scene. We can now run dcgen against this .ocdx file to generate the agent files either by GUI or the command line:
-
Generating from the GUI:
After creating the .ocdx file, before closing the GUI window, do the following:
-
Select Build > Set Output Directory to specify where the new class files will be generated.
-
Select Build > Generate Files to generate the new agent class files and the files for supporting classes.
-
Generating from the command line:
Type:
dcgend.exe input_file [{-i | -a | -p} -A root_dir -H header_dir -S source_dir -o output_dir -- -v -h]
Where:
-
-i specifies to generate all implementation classes.
-
-a specifies to generate all classes.
-
-p specifies to generate only the abstract driver class.
-
-A specifies the root directory that generated include statements are relative to.
-
-H specifies the directory to write header files to.
-
-S specifies the directory to write source files to.
-
-o specifies the directory to write all files to.
-
-v displays version information.
-
-h displays usage information.
-
Generating using Microsoft Visual Studio:
-
The VS project file (.vsproj) for this project already includes the pre-created .ocdx file for the ExampleSimulationObject class. When you open the project in Visual Studio, right-click on the .ocdx file and choose Properties. You should see the following:
$(InputDir)$(InputName)Agent.hpp;$(InputDir)$(InputName)Agent.cpp
$(InputDir)$(InputName)Classes.hpp;$(InputDir)$(InputName)Classes.cpp
Additional Dependencies: ..\..\bin\sceneObjectCompilerd.exe
Command Line: ..\..\bin\sceneObjectCompilerd.exe "$(InputPath)" -a -S
"$(InputDir)/" -H "$(InputDir)/" -A "../../include"
-
Right-click the .ocdx file and choose Compile. This will generate the same class files as would be generated above from the dcgen GUI or by using dcgen on the command line.
Having generated the class files to support the use of an agent, we now need to add these four new files to our project and then build: DtExampleObjectClasses.cpp/.hpp and DtExampleObjectAgent.cpp/.hpp.
Testing the plugin
Invoke either the tutorialDistributedSimulation4Cd.bat or tutorialDistributedSimulation4C.sh script file to start the VR-Vantage Stealth application. Follow these instructions to test the plugin:
-
Choose File > View > Drivers Panel.
-
Select the driver named "DistributedSimulationDriver4C".
-
Click on the Start button.
-
In the Stealth window, you will see that a cow image has been added in the center of the scene, and is rotating to the left. You may need to dismiss the "Choose a Terrain" dialog in order to see this, but make sure to do so by clicking on the X at the top right, rather than on the OK, or just choose "Do not load any terrain" and then click OK.
-
In Stealth, make sure the same driver is selected in the Drivers Panel, and click the Stop button.
-
You will notice that the image of the cow is no longer present in the center of the Stealth window.
-
Continually clicking the Start and Stop button will keep starting and stopping the driver, giving these same results in the console window.
[<< Add an Entity Using an Existing VR-Vantage Agent] [Conclusion >>]
Project Files
DistributedSimulationDriver4C.h
#pragma once
class DtExerciseConn;
namespace makVrv
{
class ExampleSimulationObjectAgent;
namespace tutorialDistributedSimulation4C
{
class DistributedSimulationDriver : public DtDriver
{
public:
virtual const std::string&
className()
const;
protected:
protected:
ExampleSimulationObjectAgent*
myAgent;
};
}
}
DistributedSimulationDriver4C.cxx
#define DtDIS 1
#include <vl/exConnInit.h>
#include <vl/exerciseConn.h>
#include <iostream>
namespace makVrv
{
namespace tutorialDistributedSimulation4C
{
const std::string& instanceName)
: DtDriver(agentManager, instanceName)
, myConnection(0)
, myAgent(0)
, myConnectionState(0)
, myRotationDegree(0.0)
{
}
DistributedSimulationDriver::~DistributedSimulationDriver(void)
{
onStop();
}
const std::string& DistributedSimulationDriver::className() const
{
static std::string name("DistributedSimulationDriver");
return name;
}
bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
DtExerciseConnInitializer
init;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
init.setReceiveBufferSize(0x100000);
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);
if (!myAgent)
{
myAgent = ExampleSimulationObjectAgent::create(myAgentManager);
myAgent->loadModel("../data/Lifeforms/Animals/cow.osg");
}
return myConnectionState;
}
bool DistributedSimulationDriver::onStop()
{
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
delete myConnection;
myConnection = 0;
if (myAgent)
{
myAgent->removeModel();
delete myAgent;
}
myAgent = 0;
return true;
}
bool DistributedSimulationDriver::onTick()
{
if (myConnectionState)
{
int numread = myConnection->drainInput();
std::cout << "." << numread;
}
else
std::cout << "x";
myAgent->setRotationAngle(myRotationDegree);
myRotationDegree += 0.15;
if(myRotationDegree > 360.0)
{
myRotationDegree = 0.0;
}
return myConnectionState;
}
}
}
DistributedSimulationPlugin4C.h
#pragma once
#ifdef WIN32
#define DT_DE_PLUGIN_EXPORT_MACRO __declspec ( dllexport )
#else
#define DT_DE_PLUGIN_EXPORT_MACRO
#endif
namespace makVrv { class DtDe; }
DistributedSimulationPlugin4C.cxx
#include <boost/bind.hpp>
using namespace makVrv;
using namespace makVrv::tutorialDistributedSimulation4C;
{
DistributedSimulationDriver* driver = new DistributedSimulationDriver(
}
{
{
}
}
{
return true;
}
ExampleSimulationObject.h
#pragma once
#include <osg/PositionAttitudeTransform>
#include <string>
namespace makVrv
{
class ExampleSimulationObject
{
public:
protected:
osg::ref_ptr<osg::PositionAttitudeTransform>
myPat;
};
}
ExampleSimulationObject.cxx
#include <osg/Group>
#include <osg/Node>
#include <osgDB/ReadFile>
#include <osg/ShapeDrawable>
#include <osg/Geode>
namespace makVrv
{
: myDe(de)
, myPat(0)
{
}
ExampleSimulationObject::~ExampleSimulationObject()
{
}
void ExampleSimulationObject::loadModel( const std::string& filename )
{
if (!myPat)
{
osg::ref_ptr<osg::Node> modelNode = osgDB::readNodeFile(filename);
myPat = new osg::PositionAttitudeTransform();
myPat->addChild(modelNode.get());
myPat->setPosition(osg::Vec3(0,100,0));
}
((DtOsgRenderer&)myDe.renderer()).addNodeToRoot(myPat.get(),
DtOsgRenderer::visualizerTypeRoot( 0, 0 ) );
}
void ExampleSimulationObject::removeModel()
{
((DtOsgRenderer&)myDe.renderer()).removeNodeFromRoot(myPat.get(),
DtOsgRenderer::visualizerTypeRoot(0, 0));
}
void ExampleSimulationObject::setRotationAngle( double rotationAngleInDegrees )
{
myPat->setAttitude(osg::Quat(
osg::DegreesToRadians(0.0), osg::Vec3d(1.0, 0.0, 0.0),
osg::DegreesToRadians(0.0), osg::Vec3d(0.0, 1.0, 0.0),
osg::DegreesToRadians(rotationAngleInDegrees), osg::Vec3d(0.0, 0.0, 1.0)));
}
}