Code Structure
Libraries
Here is an incomplete list of libraries that are involved to build the OpenSpace executable.
Ghoul is a helper library that contains classes and functions that are useful beyond just OpenSpace
SGCT is a library that helps with cluster synchronization and window creation
openspace-core
contains the core elements of the “game engine” part of OpenSpace, such as the handling of the scene graph, scripting, rendering, interaction methods, navigation, and othersFunctionality is divided into Modules that can that implement abstract classes defined in the
openspace-core
. Modules can depend on other modules and even other third-party librariesModules are collected in the
openspace-module-collection
which in itself does not contain any additional codeThe OpenSpace application consists of SGCT,
openspace-core
, and theopenspace-module-collection
Classes
The openspace-core
project contains all of the fundamental classes that are needed for the engine part of OpenSpace. These include a SceneGraphNode
which is collected into a Scene
. The Scene
has one special SceneGraphNode
called the Root
, which is the only scene graph node without a parent. A few of these are abstract base classes which are then derived from in other modules and thus filled with functionality.
Examples of these abstract classes are:
Renderable
: A class that represents anything that is rendered within the 3D scene and shows up on screenTranslation
: A class that describes some form of translation relative to the scene graph node’s parentRotation
: A class that describes some form of rotation relative to the scene graph node’s parentScale
: A class that describes some form of scaling relative to the scene graph node’s parentScreenSpaceRenderable
: A class that renders something on the screen but is not affected by the camera movement
Assets
All content is controlled through the inclusion of assets. Assets are fundamentally Lua scripts that have access to a special variable asset
which is injected by OpenSpace. This variable has a few functions that allow the asset to affect OpenSpace. A selection of these functions are:
asset.require
: Causes this asset to load another asset file, the path of which is provided either as a relative or absolute path. This function returns a table that contains all of the symbols that wereasset.export
ed by the required asset (see below)asset.onInitialize
: This function takes a function as an argument which is executed when the asset is asked to initialize itself. A common use case for this is for the asset to add a scene graph node to the scene in OpenSpaceasset.onDeinitialize
: Analogously to theonInitialize
, the function passed as an argument into this function is called when the asset is to be unloadedasset.export
: Export a single element to anyone thatasset.require
s this asset.
Through the user of the asset.require
function, assets form a tree where a Parent require
s their Children.
Simple Example
In this example, the child asset simply defines a variable that is then read by the parent asset and printed to the console.
-- Define a local table variable
local Green = { 0.0, 1.0, 0.0 }
-- Export the table under the name "Color", making it available to everyone requiring it
asset.export("Color", Green)
-- Include the child asset and store the resulting table in a local variable
local child = asset.require("./example1_child")
-- Register a function that is called when the asset should be initialized
asset.onInitialize(function()
-- openspace.printInfo is a function defined that will print the passed parameter
-- Here, we access the 'Color' variable out of the child's table
openspace.printInfo(child.Color)
end)
Advanced Example
In this example, the child asset is defining, adding, and exporting a scene graph node that is used in the parent asset to specify the parent of a scene graph node.
local Node = {
-- Every scene graph node needs an identifier
Identifier = "ExampleNode",
-- Moving the scene graph node relative to its parent
Transform = {
Translation = {
Type = "StaticTranslation",
-- Moving the node by 10 meters along the x axis
Position = { 10, 0, 0 }
},
Rotation = {
Type = "StaticRotation",
-- Use a rotation by 180 degrees around the y axis
Rotation = { 0, math.pi / 4, 0 }
},
Scale = {
Type = "StaticScale",
-- Scale the node up by a factor of 2
Scale = 2.0
}
},
Renderable = {
-- Just render three lines, one for each axis
Type = "RenderableCartesianAxes"
}
}
asset.onInitialize(function()
-- We initializing the asset, we want to add the node to the scene graph
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
-- When deinitializing, we remove the node from the scene graph
openspace.removeSceneGraphNode(Node)
end)
-- Making the node available to others
asset.export("Node", Node)
-- We want to load the child asset first and store its result
local example = asset.require("./example2_child")
local Node = {
Identifier = "Grid",
-- To define the parent of this node, we access the 'Node' table exported by the child
-- asset and access its 'Identifier' key
Parent = example.Node.Identifier,
Transform = {
Rotation = {
Type = "StaticRotation",
-- Use a rotation by 90 degrees around the z axis
Rotation = { 0, 0, math.pi / 8 }
}
},
Renderable = {
-- We want to render a grid
Type = "RenderableGrid"
}
}
asset.onInitialize(function()
-- We initializing the asset, we want to add the node to the scene graph
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
-- When deinitializing, we remove the node from the scene graph
openspace.removeSceneGraphNode(Node)
end)