|
VR-Engage
2.2
|
Purpose: This example demonstrates how to extend VR-Engage's CIGI (Common Image Generator Interface) host capabilities by implementing a custom CIGI publisher that transmits simulation date and time to visual image generators. It shows the pattern for creating versioned CIGI packet publishers that integrate with the VR-Engage CIGI framework.
Observable Behavior: When running this example, you will see:
Prerequisites:
This example demonstrates:
DtCigiPublisherTemplate for type-safe publisher creationDtCigiTimePublisher)DtCigiTimePublisherV4)CigiBaseEnvCtrl (version-agnostic interface)CigiCelestialCtrlV4 (CIGI 4 specific)DtEnvironmentalStateManagerThe CIGI publisher uses a template-based inheritance pattern:
This pattern uses DtCigiPublisherTemplate to compose the common publisher functionality. The template parameters identify the CIGI packet type, the concrete publisher class, the base publisher in the hierarchy, and an optional creator. CigiBaseEnvCtrl provides a version-agnostic base class from the CIGI SDK, so the base publisher can implement all of the time-publishing logic while derived classes supply the version-specific packet type.
Concrete CIGI 4 publisher:
CigiCelestialCtrlV4 derives from CigiBaseEnvCtrl, so the concrete publisher can reuse the same logic as the base class while binding to the CIGI 4 celestial control packet. The fourth template parameter, DtCigiDataCreator, enables the framework to instantiate the publisher; you omit this creator parameter for abstract base publishers. The derived class itself remains minimal because the base class already provides all of the behavior.
Initialize retrieves configuration and validates environment:
The initialization path first validates that the physical world and environmental state manager are available before enabling the publisher. If either dependency is missing, the code logs a fatal message and disables the publisher with setEnabled(false) instead of allowing it to run in a partially initialized state. The time deviation tolerance is read from the per-role Lua configuration, and the call to Super::init() delegates to the base publisher’s initialization.
Initialize non-changing packet fields once:
The cigi() accessor returns a typed pointer to the underlying CIGI packet so that the publisher can initialize constant fields in one place. This method is called once when the publisher is created, and the values it sets persist across subsequent updates rather than being reinitialized every frame. The base class has already populated the packet header and ID fields before these example-specific fields are set.
Tick monitors simulation time and triggers updates when threshold exceeded:
The tick implementation detects time jumps caused by scenario resets or explicit time manipulation by comparing accumulated time with the current value from the environmental state manager. When the deviation exceeds the configured tolerance, it calls markDirty() to schedule a packet update and resynchronizes the tracked time. This tolerance prevents unnecessary network traffic from minor floating-point drift; the base publisher’s tick then handles transmission when the packet is marked dirty.
Update packet fields that change each transmission:
The updateCigi() method uses updateValue() to change the ephemeris flag based on whether the simulation is paused, automatically marking the packet dirty when the value changes. When the packet is dirty—either because of a time deviation or a play/pause transition—it converts the Unix time to a calendar date using gmtime() and updates the date and time fields. This design ensures that the CIGI packet is only updated and transmitted when necessary rather than on every tick.
Plugin registers publisher version and session callback:
The plugin entry point registers the concrete time publisher for CIGI version 4 with registerCreatorVersion<>(), so the framework can choose the correct implementation at runtime based on the image generator’s capabilities. It also sets up a session-start callback so that new CIGI sessions automatically receive a time publisher instance without requiring changes to core host initialization. Using DtPostInitializeVrfPlugin ensures that this registration runs after the standard plugins have finished loading.
Session callback instantiates and initializes publisher:
The addToSession() helper attaches the time publisher as a child of the session’s root publisher, which keeps all publishers organized in a simple tree. The call to addNewChild<>() relies on the previously registered creator to perform version-based dispatch. The human-readable name "Date and Time" appears in logs to aid troubleshooting, and the immediate call to init() validates the environment and loads configuration before any ticks occur.
Build the example (see Environment Setup & Build Guide):
Install the plugin to the VR-Engage installation:
This copies the plugin to <VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleCigiHostExtension.dll
Verify installation:
Configure VR-Forces to load the plugin:
The plugin configuration file is automatically installed to <VR-Engage-Install-Dir>\appData\plugins\exampleCigiHostExtension.xml when you select the toolkit documentation component during installation.
Verify the plugin configuration:
The file should reference the plugin DLL:
Configure CIGI host settings (optional tolerance adjustment):
Edit appData/settings/vrfSim/cigiHost/toVantageIg.lua:
Enable CIGI in player station configuration:
Ensure role configuration includes CIGI host setup (typically pre-configured for visual station roles).
Standalone Test (without image generator):
Image Generator Test (with IG connected):
Expected Behavior:
EphemerisEn = false)Verification:
Plugin not loading:
plugins64/vrForces/release/, ensure CIGI SDK DLLs availableTime publisher not initialized:
DtPostInitializeVrfPlugin (not DtInitializeVrfPlugin)Time not updating:
timeDeviationTolerance in config, or verify simulation time actually changingIG not receiving packets:
Date/time incorrect:
dateAndTimeOfDay() returns Unix epoch time in seconds, ensure using UTC (not local time)| Class | Template Arguments | Purpose |
|---|---|---|
DtCigiTimePublisher | <CigiBaseEnvCtrl, DtCigiTimePublisher, DtCigiPublisherBase> | Base unversioned publisher with core logic |
DtCigiTimePublisherV4 | <CigiCelestialCtrlV4, DtCigiTimePublisherV4, DtCigiTimePublisher, DtCigiDataCreator> | CIGI 4 concrete publisher |
| Position | Name | Description |
|---|---|---|
| 1 | PacketType | CIGI packet class (from CIGI SDK) |
| 2 | ThisClass | The publisher class being defined (CRTP pattern) |
| 3 | SuperClass | Parent publisher class in hierarchy |
| 4 | Creator | Optional: DtCigiDataCreator enables instantiation (omit for abstract) |
CIGI Publisher APIs:
DtCigiPublisherTemplate<...> - Template base class for publisherssession() - Access owning CIGI sessioncigi() - Get typed pointer to CIGI packet datamarkDirty() - Schedule packet transmissionisDirty() - Check if transmission scheduledsetEnabled() - Enable/disable publisherupdateValue() - Update field and auto-mark dirty on changeaddNewChild<>() - Create child publisher (version-dispatched)CIGI SDK APIs:
CigiBaseEnvCtrl - Base environmental control packet (version-agnostic)CigiCelestialCtrlV4 - CIGI 4 celestial sphere control packetSunEn, MoonEn, StarEn, StarInt, DateVld, EphemerisEn, Year, Month, Day, Hour, Minute, SecondsVR-Forces Environment APIs:
DtCgf::physicalWorld() - Access simulation physical environmentDtPhysicalWorld::environmentalStateManager() - Access environment stateDtEnvironmentalStateManager::dateAndTimeOfDay() - Get simulation time (Unix epoch seconds)DtCgf::simulationServices() - Access simulation control servicesDtSimulationServices::isPaused() - Check if simulation pausedCIGI Host APIs:
DtCigiHost::instance() - Get CIGI host singletonDtCigiHost::addSessionStartedCallback() - Register session creation callbackDtCigiHost::removeSessionStartedCallback() - Unregister callbackDtCigiSession::rootPublisher() - Get root of publisher hierarchyDtCigiPublisher::registerCreatorVersion<>() - Associate version with concrete class| Field | Type | Description | Set By |
|---|---|---|---|
SunEn | bool | Enable sun rendering | initCigi() |
MoonEn | bool | Enable moon rendering | initCigi() |
StarEn | bool | Enable star field | initCigi() |
StarInt | float | Star intensity (0.0-1.0) | initCigi() |
DateVld | bool | Date/time data valid | initCigi() |
EphemerisEn | bool | IG advances time | updateCigi() (dynamic) |
Year | int | Years since 1900 | updateCigi() (on dirty) |
Month | int | Month (0-11) | updateCigi() (on dirty) |
Day | int | Day of month (1-31) | updateCigi() (on dirty) |
Hour | int | Hour (0-23 UTC) | updateCigi() (on dirty) |
Minute | int | Minute (0-59) | updateCigi() (on dirty) |
Seconds | int | Second (0-59) | updateCigi() (on dirty) |
CIGI Host Configuration (appData/settings/vrfSim/cigiHost/toVantageIg.lua):
| Parameter | Type | Default | Description |
|---|---|---|---|
timeDeviationTolerance | double | 1.0 | Time deviation threshold (seconds) before triggering update |
cigiHostExtension → exampleCigiHostExtension.dllplugins64/vrForces/release/ccl_dll.dll), VR-Forces simulation librariesRelated Documentation: