Overview¶
Note
Prefer learning by example? Jump straight to the examples! Looking for a specific class or method? Check the class index
Object types and their relationships¶
The Logic Engine
consists of a network of Lua
scripts with a set of inputs and outputs with
links between them. A special type of object we call binding serves as a bridge to a Ramses scene.
The following graph shows an example of such script network:
The scripts have inputs and outputs which together define the script’s interface
(more info on scripts). Scripts
can be linked together directionally, so that the output of a script can provide its data to
the input of another script (more info on links).
Scripts can’t interact with Ramses objects directly. Instead, they
can link to Bindings
which are designed to “bind” Ramses
objects and modify
their properties’ values (node visibility, transformation values, material properties etc.) (more info on bindings).
The greyed-out slots in the image above represent input properties which are neither linked nor
have a statically configured value. In bindings, this denotes that the corresponding Ramses
property
is not being updated by the Logic Engine
(see also next section). In scripts, these
properties will receive a default value at runtime (0, 0.0f, “”, true etc.) unless explicitly set by the application
logic. Bindings’ input values are initialized with the values of the bound Ramses object, for all bindings except
rlogic::RamsesAppearanceBinding
.
Usually, script inputs without a configured value or a link to other output are considered the interface
of the logic network towards a runtime application, and their values are supposed to be explicitly set at runtime.
Note
One of the planned features of the Logic Engine
is to formalize interface inputs in a special
interface class in a future release.
Data flow¶
The cornerstone of the Logic Engine
is the rlogic::LogicEngine::update()
method which
“executes” the network of logic nodes and updates the values of the Ramses
scene bound to some of them. The nodes
are executed based on a topological graph sort, where the traversal direction is given by the link
pairs (A, B) where A is an output and B is an input property in the logic graph
(as shown here).
The update logic of each node depends on its type. Lua
scripts execute their run()
function
and modify some or all of their outputs based on the logic defined in run()
. Ramses bindings pass the values of their
input properties to the bound Ramses object.
Logic nodes are not executed on every rlogic::LogicEngine::update()
iteration in order to save performance.
However, it’s guaranteed that:
scripts which were just created will be executed on next update
scripts which inputs received a new value (either from calling
rlogic::Property::set()
or from a link) will be executed on next updatebinding properties which received a value (regardless of their current value or from the value stored in Ramses) will overwrite the value in Ramses on next update. This works both for direct
rlogic::Property::set()
calls and for values received over links
Additionally, bindings’ properties are applied selectively - e.g. setting the scaling
property of a rlogic::RamsesNodeBinding
will result in a call to ramses::Node::setScaling()
, but will not cause setting any other ramses::Node
properties.
This can be useful if you want to have your own logic e.g.
to control the visibility of all Ramses
nodes, and only use a Logic Engine
to control transformation properties. In that case
you should never set the visibility
property of a Binding object, instead set the visibility directly on the bound ramses::Node
.
Warning
We strongly discourage setting values to Ramses
objects and to Ramses Logic
bindings in the same update cycle
for the same property to avoid unexpected behavior. At any given time, use one or the other, not both mechanisms to set values!
The Logic Engine
can be also serialized and deserialized into binary files for fast loading.
The above data flow rules still apply as if all the scripts and binding objects were just created. The first call to
rlogic::LogicEngine::update()
after loading from file will execute all scripts. Binding values will only be passed further to Ramses
if their values were modified, e.g. by a link which produced a different value than before saving, or if the application
called rlogic::Property::set()
explicitly on any of the bindings’ input properties. For more details on saving and loading,
see the section further down.
Script creation¶
The entry point to RAMSES logic
is a factory-style class rlogic::LogicEngine
which can
create instances of all other types of objects supported by RAMSES Logic
:
You can create multiple instances of rlogic::LogicEngine
, but each copy owns the objects it
created, and must be used to destroy them, as befits a factory class.
You can create scripts using the rlogic::LogicEngine
class like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include "ramses-logic/LogicEngine.h"
using namespace ramses::logic;
std::string source = R"(
function interface()
IN.gear = INT
OUT.speed = FLOAT
end
function run()
OUT.speed = IN.gear * 15
end
)"
LogicEngine engine;
LuaScript* script = engine.createLuaScriptFromSource(source, "simple script");
script->getInputs()->getChild("gear")->set<int32_t>(4);
script->execute();
float speed = script->getOutputs()->getChild("speed")->get<float>();
std::cout << "OUT.speed == " << speed;
|
For details regarding the Lua
syntax and its specifics, check the dedicated section on Lua.
rlogic::LogicNode
(the base class of rlogic::LuaScript
) provides an interface to access the inputs and outputs declared by the interface()
function - see rlogic::LogicNode::getInputs()
and rlogic::LogicNode::getOutputs()
.
You can link scripts to form a more sophisticated logic execution graph.
You can bind to Ramses objects to control a 3D Ramses
scene.
Finally, the rlogic::LogicEngine
class and all its content can be also saved/loaded from a file. Refer to
the section on saving/loading from files for more details.
Object lifecycle¶
All objects besides the rlogic::LogicEngine
instance follow a strict factory pattern.
An object X
is created by a method of the shape X* LogicEngine::createX(...)
. The pointer
returned shall not be freed or deleted, instead objects must be destroyed by calling rlogic::LogicEngine::destroy()
.
Note
This may seem strange for a library which is based on C++17
, but there are good reasons
for this design choice. Smart pointers don’t work well together with Windows DLL’s, specifically
when combining different CRTs. In order to provide a stable API on Windows
we chose to use raw pointers and hide object creation/deletion behind a pimpl/factory pattern.
The rlogic::LogicEngine
doesn’t create or destroy objects on its own - all data is
explicitly created by calling create
and destroy
methods. There are two special cases worth mentioning:
if
rlogic::LogicEngine
is destroyed, all objects are destroyed as well and theirs pointers invalidatedrlogic::LogicEngine::loadFromFile()
destroys all objects previously created before the new content is loaded from the file
Note
Loading data from files will invalidate all previous pointers to objects in
the rlogic::LogicEngine
. To avoid that, we recommend generally avoiding using
a logicengine instance which already has content to load from files, and instead always
create a fresh instance.
Creating links between scripts¶
One of the complex problems of 3D graphics development is managing complexity, especially for larger projects.
For that purpose it is useful to split the application logic into multiple scripts, so that individual scripts
can remain small and easy to understand. To do that, Ramses Logic
provides a mechanism to link script
properties - either statically or during runtime, in order to pass data from 1
producer script to N
consumer scripts.
Here is a simple example how links are created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | LogicEngine logicEngine;
LuaScript* sourceScript = logicEngine.createLuaScriptFromSource(R"(
function interface()
OUT.source = STRING
end
function run()
OUT.source = "World!"
end
)");
LuaScript* destinationScript = logicEngine.createLuaScriptFromSource(R"(
function interface()
IN.destination = STRING
end
function run()
print("Hello, " .. IN.destination)
end
)");
logicEngine.link(
*sourceScript->getOutputs()->getChild("source"),
*destinationScript->getInputs()->getChild("destination"));
// This will print 'Hello, World!' to the console
logicEngine.update();
|
In this simple example, the ‘sourceScript’ provides string data to the ‘destinationScript’ every time the LogicEngine::update
method is called. The ‘destinationScript’ receives the data in its input property and can process it further. After
two scripts are linked in this way, the rlogic::LogicEngine
will execute them in a order which ensures data consistency, i.e.
scripts which provide data to other scripts’ inputs are executed first. In this example, the ‘sourceScript’ will be executed before
the ‘destionationScript’ because it provides data to it over the link.
Creating links as shown above enforces a so-called ‘directed acyclic graph’, or DAG
, to the rlogic::LogicNode
inside a given
rlogic::LogicEngine
. In order to ensure data consistency, this graph can not have cyclic dependencies, thus following operations
will cause an error:
Creating a link from any
rlogic::LogicNode
to itselfCreating a link from node A to node B if node B is linked to node A (links have a direction and this creates a two-node loop!)
Any set of
rlogic::LogicNode
instances whose links form a (directed) circle, e.g. A->B->C->A (this is caught at update time, not at link creation time)
A link can be removed in a similar fashion:
1 2 3 | logicEngine.unlink(
*sourceScript->getOutputs()->getChild("source"),
*destinationScript->getInputs()->getChild("destination"));
|
For more detailed information on the exact behavior of these methods, refer to the documentation of the rlogic::LogicEngine::link()
and rlogic::LogicEngine::unlink()
documentation. The data flow section explains in detail how data is passed throughout the
network of logic nodes when connected by links.
Linking scripts to Ramses scenes¶
Lua scripts would not make much sense on their own if they can’t interact with Ramses
scene objects. The way to
link script output properties to Ramses
scene objects is by creating rlogic::RamsesBinding
instances and linking their inputs to scripts’ outputs.
There are different binding types depending on the type of Ramses
object - refer to rlogic::RamsesBinding
for the full list of derived classes.
Bindings can be linked in the exact same way as scripts can. In fact, they derive from the
same base class - rlogic::LogicNode
. The only
difference is that the bindings have only input properties (the outputs are implicitly defined and statically linked to the Ramses
objects attached to them), whereas scripts have inputs and outputs explicitly defined in the script interface.
One might wonder, why not allow to directly link script outputs to Ramses
objects?
The reason for that is two-fold:
Separation of concerns between pure script logic and
Ramses
-related scene updatesThis allows to handle all inputs and outputs in a generic way using the
rlogic::LogicNode
class’ interface from which bothrlogic::LuaScript
andrlogic::RamsesNodeBinding
derive
The section on data flow describes how data is passed throughout the network of logic nodes and when bound Ramses objects are updated and when not.
Note
Binding input values are initialized with the same values as the Ramses objects they “bind”. The only exception to this are Appearance bindings - extracting all data from Ramses Appearances would incur performance costs not worth the convenience.
Error handling¶
Some of the RAMSES Logic
classes’ methods can issue errors when used incorrectly or when
a Lua
script encounters a compile-time or run-time error. Those errors are globally collected
by the rlogic::LogicEngine
class and can be obtained by calling rlogic::LogicEngine::getErrors()
.
The error information stored in rlogic::ErrorData
contains additional stack trace information for Lua runtime errors,
and a pointer to the originating rlogic::LogicNode
which caused the error for errors which occured during rlogic::LogicEngine::update()
and can’t be directly attributed to a specific API call.
Beware that any of the mutable methods of rlogic::LogicEngine
clear the previously generated errors
in the list, so that the list only ever contains the errors since the last method call!
For code samples which demonstrate how compile-time and runtime errors can be gracefully handled, have a look at the examples.
Print messages from within Lua¶
In common Lua
code you can print messages e.g. for debugging with the “print” function.
Because ramses-logic can be used in different environments which not always have a console
to print messages, the “print” function is overloaded. The default behavior is that your
message will be piped to std::cout together with the name of the calling script.
If you need more control of the print messages, you can overload the printing function with
you own one like this:
1 2 3 4 5 6 7 8 9 10 11 12 | LogicEngine logicEngine;
LuaScript* script = logicEngine.createLuaScriptFromSource(R"(
function interface()
end
function run()
print("message")
end
)");
script->overrideLuaPrint([](std::string_view scriptName, std::string_view message){
std::cout << scriptName << ": " << message << std::endl;
});
|
Iterating over object collections¶
Iterating over objects can be useful, for example when loading content from files
or when applying search or filter algorithms over all objects from a specific type.
The rlogic::LogicEngine
class provides iterator-style access to all of its objects:
1 2 3 4 5 6 7 | LogicEngine logicEngine;
Collection<LuaScript> allScripts = logicEngine.scripts();
for(const auto script : allScripts)
{
std::cout << "Script name: " << script->getName() << std::endl;
}
|
The rlogic::Collection
class and the iterators it returns are STL-compatible, meaning that you can use them with any
other STL algorithms or libraries which adhere to STL principles. The iterators implement forward
iterator semantics
(have a look at C++ docs).
Note
The rlogic::Iterator
and rlogic::Collection
classes are not following the pimpl
pattern as the rest of
the Ramses Logic
to performance ends. Be careful not to depend on any internals of the classes (mostly the Internally
wrapped STL containers) to avoid compatibility problems when updating the Ramses Logic
version!
Saving/Loading from file¶
The rlogic::LogicEngine
class and its content can be stored in a file and loaded from file again using the functions
rlogic::LogicEngine::saveToFile()
and rlogic::LogicEngine::loadFromFile()
. The latter has an optional argument
to provide a Ramses
scene which should be used to resolve references to Ramses objects in the Logic Engine file. Read
further for more details.
Note
Even though it would be technically possible to combine the storing and loading of Ramses scenes together with the Logic Engine and its scripts in a single file, we decided to not do this but instead keep the content in separate files and load/save it independently. This allows to have the same Ramses scene stored multiple times or with different settings, but using the same logic content, as well as the other way around - having different logic implementations based on the same Ramses scene. It also leaves more freedom to choose how to store the Ramses scene. This implies that at most a single Ramses scene can be referenced at the time of saving, having more than one scene will result in error.
Object lifecycle when saving and loading to files¶
After loading, the current state of the logic engine objects will be completely overwritten by the contents from the file. If you don’t want this behavior, use two different instances of the class - one dedicated for loading from files and nothing else.
Here is a simple example which demonstrates how saving/loading from file works in the simplest case (i.e. no references to Ramses objects):
1 2 3 4 5 6 7 8 9 10 | // Creates an empty LogicEngine instance, saves it to file and destroys the object
{
rlogic::LogicEngine engine;
engine.saveToFile("logicEngine.bin");
}
// Loads the file we saved above into a freshly created LogicEngine instance
{
rlogic::LogicEngine engine;
engine.loadFromFile("logicEngine.bin");
}
|
After the call to rlogic::LogicEngine::loadFromFile()
successfully returns (refer to the Error handling section
for info on handling errors), the state of the rlogic::LogicEngine
class will be overwritten with
the contents loaded from the file. This implies that all objects created prior loading will be deleted and pointers to them
will be pointing to invalid memory locations. We advise designing your object lifecycles around this and immediately dispose
such pointers after loading from file.
Warning
In case of error during loading the rlogic::LogicEngine
may be left in an inconsistent state. In the future we may implement
graceful handling of deserialization errors, but for now we suggest discarding a rlogic::LogicEngine
object which failed to load.
Saving and loading together with a Ramses scene¶
In a slightly less simple, but more realistic setup, the Logic Engine will contain objects of type Ramses<Object>Binding
which
contain references to Ramses objects. In that case, use the optional ramses::Scene*
argument to rlogic::LogicEngine::loadFromFile()
to specify the scene from which the references to Ramses objects should be resolved. Ramses Logic
uses the getSceneObjectId()
method of the
ramses::SceneObject
class to track references to scene objects. This implies that those IDs must be the same after loading, otherwise
rlogic::LogicEngine::loadFromFile()
will report error and fail. Ramses Logic
makes no assumptions on the origin of the scene, its name
or ID.
For a full-fledged example, have a look at the serialization example.
Warning
The LogicEngine
expects that immediately after loading, the state of the Ramses
scene is the same as it was right before saving, and will not
modify Ramses
objects which are attached to bindings in the LogicEngine
in its first update, unless they are linked to scripts or explicitly
overwritten by rlogic::Property::set()
calls after loading from the file. We strongly advice to always save and load
both the Ramses
scene and the LogicEngine
scene together to avoid data inconsistencies!
Using memory buffer instead of file¶
You can use rlogic::LogicEngine::loadFromBuffer()
to load the contents of the logic engine from your own memory. This can be useful
if you have your own file management logic, or the data comes from a different source than a file on disk. Be mindful that passing data buffers
over the boundaries of libraries can be unsafe with C++, and some errors/abuse can’t be reliably prevented. Make sure you check the size of
the buffer and don’t load from memory of untrusted origins.
Logging¶
Internally there are four log levels available.
Info
Debug
Warn
Error
By default all internal logging messages are sent to std::cout. You can toggle this with rlogic::Logger::SetDefaultLogging()
.
In addition, it is possible to have a custom log handler function which is called each time a log message is issued.
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <iostream>
Logger::SetLogHandler([](ElogMessageType msgType, std::string_view message){
switch(type)
{
case ELogMessageType::ERROR:
std::cout << "Error: " << message << std::endl;
break;
default:
std::cout << message << std::endl;
break;
}
});
|
Inside the log handler function, you get the type of the message and the message itself as a std::string_view. Keep in mind, that you can’t store the std::string_view. It will be invalid after the call to the log handler function. If you need the message for later usage, store it in a std::string.
The amount of logging can be configured with rlogic::Logger::SetLogVerbosity()
. This affects both the default
logging and the custom logger.
Security and memory safety¶
One of the biggest challenges of modern C++
is finding a balance between compatibility with older compilers
and platforms, while not sacrificing memory safety and code readibility. In the RAMSES
ecosystem we try to
find a good balance by testing with different compilers, employing automation techniques and making use of
modern compiler-based tools to perform static code analysis and introspection. The methods and tools we use are:
compiling on different compilers (MSVC, gcc, clang) with strict compiler settings
clang-tidy with fairly strict configuration
valgrind
treat warnings as errors
use various clang-based sanitizers (undefined behavior, thread sanitizer, address sanitizer)
Those tools cover a lot of the standard sources of problems with C++
revolving around memory. We also uphold
a strict code review, ensuring that each line of code is looked at by at least two pairs of eyes, for critical
parts of the code usually more than that. Still, no project is safe from bugs, thus we recommend following
some or all of the additional conventions and best practices from below subchapters to minimize the risk of
memory-related bugs and malicious attacks when using Ramses Logic
.
Additional memory safety measures¶
One of the biggest sources of bugs and security problems in C++
arise from memory management, both in terms of
allocation/deallocation and memory access and boundary checks. Ramses Logic
takes care of memory lifecycle
for all objects created by it, and provides raw pointer access to their memory. We suggest creating your own wrapper
objects for anything created or loaded by the rlogic::LogicEngine
class and ensure it is destroyed exactly once
and only after not used any more.
Furthermore, pay special attention when passing strings as std::string_view
to and from the Logic Engine
as those
may not be terminated by a 0 and may lead to out of bounds accesses when used by functions expecting 0-termination.
Additional security considerations¶
Lua
is a script language, and as such provides great flexibility and expresiveness at the cost of
more error potential and security risks compared to other techniques for describing logic. The Logic engine
and the
underlying sol
library do a lot of error checking and prevents undefined behavior by executing faulty script code,
but there are cases which can’t be checked.
To give one example, a script may overwrite the global variables IN
or OUT
from within script code because of the nature of Lua
scripts. This can’t be automatically checked by the runtime without
overloading the global Lua
metatable and injecting every single assignment operation, which is too high a cost to avoid
faulty scripts.
To avoid malicious or broken script, we suggest implementing an additional security mechanism on top
of Ramses Logic
which doesn’t allow execution of scripts of unknown origin. Also, build your code with errors in mind
and force scripts into an automated testing process. We also advise to use hashsums and whitelisting techniques to only
execute scripts which are tested and verified to be benign.
Sanitizing of files and buffers¶
Since the Logic Engine
can deserialize itself from files and memory buffers, it opens possibilities for data corruption and
truncation. To mitigate those risks, we use Flatbuffer’s “Verify” feature which checks the integrity of data,
detects possible index-out-of-range issues and prevents binary data abuse. What it doesn’t check is
whether the actual memory buffer size (passed in rlogic::LogicEngine::loadFromBuffer()
) is consistent with the size provided
by the user. The application must ensure that this size does not exceed the size of the actual memory!
Performance¶
The Logic Engine
is designed to be fast and efficient, as long as the performance improvements are
not made at cost of unreadable code. In order to be able to track and improve
the runtime of the Logic Engine
, we maintain a set of benchmarks based on the google-benchmark library.
These benchmarks can be used to measure the time it takes for specific operations under different loads.
We kindly ask our users and developers to report performance problems by creating a benchmark which describes
the specific use-case which needs optimizing. Refer to the
google-benchmark docs for hints how to
design good benchmarks, to set the time measurement units, derive O-complexity, etc.
List of all examples¶
Class Index¶
Top-level API classes:
Base classes:
rlogic::LogicNode
(base for almost everything)rlogic::RamsesBinding
(base for all bindings)
Iterators:
Free functions:
Type traits:
Error information:
-
template<typename
T
>
classrlogic
::
Collection
¶ - #include <Collection.h>
A Collection which allows STL-style algorithm with forward semantics to be executed (e.g. find_if, for_each etc.). A Collection should not be instantiated directly, instead use one of the rlogic::LogicEngine methods:
See also rlogic::Iterator for more info on the iterator objects returned by begin and end.
Template parameters:
T: the object type to iterate over, e.g. rlogic::LuaScript
Public Types
-
using
iterator
= Iterator<T, internal_container_type, false>¶
-
using
const_iterator
= Iterator<T, internal_container_type, true>¶
Public Functions
-
iterator
begin
()¶ Return an iterator to the start of the collection
- Return
iterator to the start of the collection
-
const_iterator
begin
() const¶ Return an const iterator to the start of the collection
- Return
const iterator to the start of the collection
-
iterator
end
()¶ Return an iterator to the end of the collection
- Return
iterator to the end of the collection
-
const_iterator
end
() const¶ Return a const iterator to the end of the collection
- Return
const iterator to the end of the collection
-
const_iterator
cbegin
() const¶ Return a const iterator to the start of the collection
- Return
const iterator to the of the collection
-
const_iterator
cend
() const¶ Return a const iterator to the end of the collection
- Return
const iterator to the end of the collection
-
Collection
() = delete¶ Default constructor is deleted because a collection is supposed to provide read-only access to internal data of the rlogic::LogicEngine class, therefore it has to be obtained by calling methods of the rlogic::LogicEngine which return such collections, e.g. rlogic::LogicEngine::scripts()
-
~Collection
() noexcept = default¶ Default destructor
-
Collection
(const Collection &other) noexcept = default¶ Default copy constructor
- Parameters
other
: collection to copy
-
Collection &
operator=
(const Collection &other) noexcept = default¶ Default assignment operator
- Parameters
other
: collection to assign from
-
Collection
(internal_container_type &container)¶ Internal constructor. Not supposed to be called from user code!
- Parameters
container
: internal container
Private Types
Private Members
-
std::reference_wrapper<internal_container_type>
m_container
¶ Internal reference to the container holding the actual data held by the collection.
-
struct
rlogic
::
ErrorData
¶ - #include <ErrorData.h>
Holds information about an error which occured during rlogic::LogicEngine API calls
Public Members
-
std::string
message
¶ Error description as human-readable text. For Lua errors, an extra stack trace is contained in the error string with new-line separators.
-
const LogicNode *
node
¶ The rlogic::LogicNode which caused the error. Can be nullptr if the error was not originating from a specific node.
-
std::string
-
template<typename
T
>
structrlogic
::
IsPrimitiveProperty
¶ - #include <EPropertyType.h>
Type trait which can be used to check if a type is primitive or not. “primitive” in this context means the type can be used as a template for rlogic::Property::set() and rlogic::Property::get(), i.e. it has a value which can be directly set/obtained, as opposed to non-primitive types like structs or arrays which don’t have a singular settable value.
Public Static Attributes
-
const bool
value
= false¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<bool>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<float>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<int>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<std::string>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<vec2f>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<vec2i>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<vec3f>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<vec3i>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<vec4f>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<>
structrlogic
::
IsPrimitiveProperty
<vec4i>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const bool
value
= true¶
-
const bool
-
template<typename
T
, typenameinternal_container
, boolisConst
>
classrlogic
::
Iterator
¶ - #include <Iterator.h>
An STL-style iterator for various object types (T) with forward-semantics. See also:
Template parameters:
T: the object type to iterate over, e.g. rlogic::LuaScript
internal_container: the internally wrapped container type. User code should NOT depend on this type to avoid API incompatibilities!
isConst: true for const-iterators, false for non-const iterators
Dereferencing the iterator yields a pointer of type T* or const T*, depending if the iterator is a const iterator. The class is STL-compatible, meaning that the public type declarations may safely be used.
Additional note: the Iterator class does not support swap() functionality as well as mutable assignments, because the internal data structures used to iterate over objects are not supposed to be changed by user code. The iterators are supposed to be used only in read-only scenarios. It is still possible to exercise write access on the pointers returned by the iterator, but it’s not possible to assign a new value to the pointer itself or to swap the pointers.
Public Types
-
using
difference_type
= typename internal_iterator::difference_type¶ Type traits as mandated by STL for custom iterators.
-
using
value_type
= typename internal_iterator::value_type¶ The iterator type after dereferencing
-
using
pointer
= typename internal_iterator::pointer¶ Iterator value pointer type
-
using
reference
= typename internal_iterator::reference¶ Iterator value reference type
Public Functions
-
maybe_const_T
operator*
() noexcept¶ Operator dereferencing. Returns const T* if template argument isConst == true, otherwise returns T*.
- Return
T* or const T* pointer to iterable object, depending on iterator constness
-
maybe_const_T
operator->
() noexcept¶ Member forwarding operator. Translates to ‘(const T*)->method’ if template argument isConst == true, otherwise to ‘(T*)->method’.
- Return
T* or const T* pointer to iterable object, depending on iterator constness
-
Iterator
operator++
(int) noexcept¶ Post-increment operator.
- Return
a copy of self before the increment was performed
-
template<bool
otherIsConst
>
booloperator==
(const Iterator<T, internal_container, otherIsConst> &other) const noexcept¶ Equality operator.
- Return
true if the iterators point to the same object internally
- Parameters
other
: the other iterator to compare to
-
template<bool
otherIsConst
>
booloperator!=
(const Iterator<T, internal_container, otherIsConst> &other) const noexcept¶ Inequality operator.
- Return
true if the iterators point to different objects internally
- Parameters
other
: the other iterator to compare to
-
Iterator
() noexcept = default¶ Default constructor.
-
template<bool
otherIsConst
, typename = std::enable_if_t<isConst && !otherIsConst>>Iterator
(const Iterator<T, internal_container, otherIsConst> &other) noexcept¶ Constructor which allows const-iterator to be constructed from a non-const iterator, but not the other way around
- Parameters
other
: iterator to construct from
-
template<bool
otherIsConst
, class = std::enable_if_t<isConst && !otherIsConst>>
Iterator &operator=
(const Iterator<T, internal_container, otherIsConst> &other) noexcept¶ Assignment operator which allows const-iterator to be assigned from a non-const iterator, but not the other way around
- Parameters
other
: iterator to be assign from
-
Iterator
(const Iterator&) noexcept = default¶ Default copy constructor. This is redundant to the template version above, but is considered good style.
-
Iterator &
operator=
(const Iterator&) noexcept = default¶ Default assignment operator. This is redundant to the template version above, but is considered good style.
-
~Iterator
() noexcept = default¶ Default destructor.
-
Iterator
(internal_iterator iter) noexcept¶ Internal constructor which should not be called by user code to avoid API dependencies. Use rlogic::Collection::begin() and rlogic::Collection::end() or their const-counterparts to obtain iterators to desired rlogic::LogicEngine objects.
- Parameters
iter
: internal iterator to be constructed from
Private Types
-
using
const_iter
= typename internal_container::const_iterator¶ Internal type trait (const iterator type)
-
using
non_const_iter
= typename internal_container::iterator¶ Internal type trait (non-const iterator type)
-
using
internal_iterator
= typename std::conditional<isConst, const_iter, non_const_iter>::type¶ Internal type trait (internally wrapped iterator type)
Private Members
-
internal_iterator
m_iterator
= {}¶ Internal iterator. This implementation is not following the pimpl pattern for efficiency reasons.
Friends
- friend class Iterator< T, internal_container, true >
- friend class Iterator< T, internal_container, false >
-
class
rlogic
::
LogicEngine
¶ - #include <LogicEngine.h>
Central object which creates and manages the lifecycle and execution of scripts, bindings, and all other objects supported by the Ramses Logic library. All objects created by this class’ methods must be destroyed with destroy!
Use the create[Type] methods to create various objects, use destroy() to delete them.
Use link and unlink to connect data properties between these objects
use update() to trigger the execution of all objects
Public Functions
-
LogicEngine
() noexcept¶ Constructor of LogicEngine.
-
~LogicEngine
() noexcept¶ Destructor of LogicEngine
-
Collection<LuaScript>
scripts
() const¶ Returns an iterable rlogic::Collection of all rlogic::LuaScript instances created by this LogicEngine.
- Return
an iterable rlogic::Collection with all rlogic::LuaScript instances created by this LogicEngine
-
Collection<RamsesNodeBinding>
ramsesNodeBindings
() const¶ Returns an iterable rlogic::Collection of all rlogic::RamsesNodeBinding instances created by this LogicEngine.
- Return
an iterable rlogic::Collection with all rlogic::RamsesNodeBinding instances created by this LogicEngine
-
Collection<RamsesAppearanceBinding>
ramsesAppearanceBindings
() const¶ Returns an iterable rlogic::Collection of all rlogic::RamsesAppearanceBinding instances created by this LogicEngine.
- Return
an iterable rlogic::Collection with all rlogic::RamsesAppearanceBinding created by this LogicEngine
-
Collection<RamsesCameraBinding>
ramsesCameraBindings
() const¶ Returns an iterable rlogic::Collection of all rlogic::RamsesCameraBinding instances created by this LogicEngine.
- Return
an iterable rlogic::Collection with all rlogic::RamsesCameraBinding created by this LogicEngine
-
LuaScript *
findScript
(std::string_view name) const¶ Returns a pointer to the first occurrence of a script with a given
name
if such exists, and nullptr otherwise.- Return
a pointer to the script, or nullptr if none was found
- Parameters
name
: the name of the script to search for
-
RamsesNodeBinding *
findNodeBinding
(std::string_view name) const¶ Returns a pointer to the first occurrence of a node binding with a given
name
if such exists, and nullptr otherwise.- Return
a pointer to the node binding, or nullptr if none was found
- Parameters
name
: the name of the node binding to search for
-
RamsesAppearanceBinding *
findAppearanceBinding
(std::string_view name) const¶ Returns a pointer to the first occurrence of an appearance binding with a given
name
if such exists, and nullptr otherwise.- Return
a pointer to the appearance binding, or nullptr if none was found
- Parameters
name
: the name of the appearance binding to search for
-
RamsesCameraBinding *
findCameraBinding
(std::string_view name) const¶ Returns a pointer to the first occurrence of a camera binding with a given
name
if such exists, and nullptr otherwise.- Return
a pointer to the camera binding, or nullptr if none was found
- Parameters
name
: the name of the camera binding to search for
-
LuaScript *
createLuaScriptFromFile
(std::string_view filename, std::string_view scriptName = "")¶ Creates a new rlogic::LuaScript from an existing Lua source file. Refer to the rlogic::LuaScript class documentation for requirements that Lua scripts must fulfill in order to be added to the LogicEngine.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
a pointer to the created object or nullptr if something went wrong during creation. In that case, use getErrors() to obtain errors. The script can be destroyed by calling the destroy method
- Parameters
filename
: path to file from which to load the script source codescriptName
: name to assign to the script once it’s created
-
LuaScript *
createLuaScriptFromSource
(std::string_view source, std::string_view scriptName = "")¶ Creates a new Lua script from a source string. Refer to the rlogic::LuaScript class for requirements which Lua scripts must fulfill in order to be added to the LogicEngine.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
a pointer to the created object or nullptr if something went wrong during creation. In that case, use getErrors() to obtain errors. The script can be destroyed by calling the destroy method
- Parameters
source
: the Lua source codescriptName
: name to assign to the script once it’s created
-
RamsesNodeBinding *
createRamsesNodeBinding
(ramses::Node &ramsesNode, std::string_view name = "")¶ Creates a new rlogic::RamsesNodeBinding which can be used to set the properties of a Ramses Node object.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
a pointer to the created object or nullptr if something went wrong during creation. In that case, use getErrors() to obtain errors. The binding can be destroyed by calling the destroy method
- Parameters
ramsesNode
: the ramses::Node object to control with the binding.name
: a name for the new rlogic::RamsesNodeBinding.
-
RamsesAppearanceBinding *
createRamsesAppearanceBinding
(ramses::Appearance &ramsesAppearance, std::string_view name = "")¶ Creates a new rlogic::RamsesAppearanceBinding which can be used to set the properties of a Ramses Appearance object.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
a pointer to the created object or nullptr if something went wrong during creation. In that case, use getErrors() to obtain errors. The binding can be destroyed by calling the destroy method
- Parameters
ramsesAppearance
: the ramses::Appearance object to control with the binding.name
: a name for the the new rlogic::RamsesAppearanceBinding.
-
RamsesCameraBinding *
createRamsesCameraBinding
(ramses::Camera &ramsesCamera, std::string_view name = "")¶ Creates a new rlogic::RamsesCameraBinding which can be used to set the properties of a Ramses Camera object.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
a pointer to the created object or nullptr if something went wrong during creation. In that case, use getErrors() to obtain errors. The binding can be destroyed by calling the destroy method
- Parameters
ramsesCamera
: the ramses::Camera object to control with the binding.name
: a name for the the new rlogic::RamsesCameraBinding.
-
bool
update
()¶ Updates all rlogic::LogicNode’s which were created by this LogicEngine instance. The order in which rlogic::LogicNode’s are executed is determined by the links created between them (see link and unlink). rlogic::LogicNode’s which don’t have any links between then are executed in arbitrary order, but the order is always the same between two invocations of update without any calls to link or unlink between them. As an optimization rlogic::LogicNode’s are only updated, if at least one input of a rlogic::LogicNode has changed since the last call to update. If the links between logic nodes create a loop, this method will fail with an error and will not execute any of the logic nodes.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
true if the update was successful, false otherwise In case of an error, use getErrors() to obtain errors.
-
bool
link
(const Property &sourceProperty, const Property &targetProperty)¶ Links a property of a rlogic::LogicNode to another rlogic::Property of another rlogic::LogicNode. After linking, calls to update will propagate the value of
sourceProperty
to thetargetProperty
. Creating links influences the order in which scripts are executed - if node A provides data to node B, then node A will be executed before node B. A single output property (sourceProperty
) can be linked to any number of input properties (targetProperty
), but any input property can have at most one link to an output property (links are directional and support a 1-to-N relationships).The link() method will fail when:
sourceProperty
andtargetProperty
belong to the same rlogic::LogicNodesourceProperty
is not an output (see rlogic::LogicNode::getOutputs())targetProperty
is not an input (see rlogic::LogicNode::getInputs())either
sourceProperty
ortargetProperty
is not a primitive property (you have to link sub-properties of structs and arrays individually)
Creating link loops will cause the next call to update() to fail with an error. Loops are directional, it is OK to have A->B, A->C and B->C, but is not OK to have A->B->C->A.
After calling link, the value of the
targetProperty
will not change until the next call to update. Creating and destroying links generally has no effect until update is called.Attention! This method clears all previous errors! See also docs of getErrors()
- Return
true if linking was successful, false otherwise. To get more detailed error information use getErrors()
- Parameters
sourceProperty
: the output property which will provide data fortargetProperty
targetProperty
: the target property which will receive its value fromsourceProperty
-
bool
unlink
(const Property &sourceProperty, const Property &targetProperty)¶ Unlinks two properties which were linked with link. After a link is destroyed, calls to update will no longer propagate the output value from the
sourceProperty
to the input value of thetargetProperty
. The value of thetargetProperty
will remain as it was after the last call to update - it will not be restored to a default value or to any value which was set manually with calls to rlogic::Property::set().Attention! This method clears all previous errors! See also docs of getErrors()
- Return
true if unlinking was successful, false otherwise. To get more detailed error information use getErrors().
- Parameters
sourceProperty
: the output property which is currently linked totargetProperty
targetProperty
: the property which will no longer receive the value fromsourceProperty
-
bool
isLinked
(const LogicNode &logicNode) const¶ Checks if an input or output of a given LogicNode is linked to another LogicNode
-
const std::vector<ErrorData> &
getErrors
() const¶ Returns the list of all errors which occurred during the last API call to a LogicEngine method or any other method of its subclasses (scripts, bindings etc). Note that errors get wiped by all mutable methods of the LogicEngine.
This method can be used in two different ways:
To debug the correct usage of the Logic Engine API (e.g. by wrapping all API calls with a check for their return value and using this method to find out the cause of the error)
To check for runtime errors of scripts which come from a dynamic source, e.g. by calling the method after an unsuccessful call to update() with a faulty script
- Return
a list of errors
-
bool
destroy
(LogicNode &logicNode)¶ Destroys a rlogic::LogicNode instance. If any links are connected to this rlogic::LogicNode, they will be destroyed too. Note that after this call, the execution order of rlogic::LogicNode may change! See the docs of link and unlink for more information.
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
true if logicNode destroyed, false otherwise. Call getErrors() for error details upon failure.
- Parameters
logicNode
: the logic node instance to destroy
-
bool
saveToFile
(std::string_view filename)¶ Writes the whole LogicEngine and all of its objects to a binary file with the given filename. The RAMSES scene potentially referenced by rlogic::RamsesBinding objects is not saved - that is left to the application. LogicEngine saves the references to those object, and restores them after loading. Thus, deleting Ramses objects which are being referenced from within the LogicEngine will result in errors if the Logic Engine is loaded from the file again. Note that it is not sufficient to have objects with the same name, they have to be the exact same objects as during saving! For more in-depth information regarding saving and loading, refer to the online documentation at https://ramses-logic.readthedocs.io/en/latest/api.html#save-load-to-file
Note: The method reports error and aborts if the rlogic::RamsesBinding objects reference more than one Ramses scene (this is acceptable during runtime, but not for saving to file).
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
true if saving was successful, false otherwise. To get more detailed error information use getErrors()
- Parameters
filename
: path to file to save the data (relative or absolute). The file will be created or overwritten if it exists!
-
bool
loadFromFile
(std::string_view filename, ramses::Scene *ramsesScene = nullptr, bool enableMemoryVerification = true)¶ Loads the whole LogicEngine data from the given file. See also saveToFile(). After loading, the previous state of the LogicEngine will be overwritten with the contents loaded from the file, i.e. all previously created objects (scripts, bindings, etc.) will be deleted and pointers to them will be invalid. The (optionally) provided ramsesScene will be used to resolve potential rlogic::RamsesBinding objects which point to Ramses objects. You can provide a nullptr if you know for sure that the LogicEngine loaded from the file has no rlogic::RamsesBinding objects which point to a Ramses scene object. Otherwise, the call to loadFromFile will fail with an error. In case of errors, the LogicEngine may be left in an inconsistent state. For more in-depth information regarding saving and loading, refer to the online documentation at https://ramses-logic.readthedocs.io/en/latest/api.html#saving-loading-from-file
Attention! This method clears all previous errors! See also docs of getErrors()
- Return
true if deserialization was successful, false otherwise. To get more detailed error information use getErrors()
- Parameters
filename
: path to file from which to load content (relative or absolute)ramsesScene
: pointer to the Ramses Scene which holds the objects referenced in the Ramses Logic fileenableMemoryVerification
: flag to enable memory verifier (a flatbuffers feature which checks bounds and ranges). Disable this only if the file comes from a trusted source and performance is paramount.
-
bool
loadFromBuffer
(const void *rawBuffer, size_t bufferSize, ramses::Scene *ramsesScene = nullptr, bool enableMemoryVerification = true)¶ Loads the whole LogicEngine data from the given memory buffer. This method is equivalent to loadFromFile but allows to have the file-opening logic done by the user and only pass the data as a buffer. The logic engine only reads the data, does not take ownership of it and does not modify it. The memory can be freed or modified after the call returns, the LogicEngine keeps no references to it.
- Return
true if deserialization was successful, false otherwise. To get more detailed error information use getErrors()
- Parameters
rawBuffer
: pointer to the raw data in memorybufferSize
: size of the data (bytes)ramsesScene
: pointer to the Ramses Scene which holds the objects referenced in the Ramses Logic fileenableMemoryVerification
: flag to enable memory verifier (a flatbuffers feature which checks bounds and ranges). Disable this only if the file comes from a trusted source and performance is paramount.
-
LogicEngine
(const LogicEngine &other) = delete¶ Copy Constructor of LogicEngine is deleted because logic engines hold named resources and are not supposed to be copied
- Parameters
other
: logic engine to copy from
-
LogicEngine
(LogicEngine &&other) = delete¶ Move Constructor of LogicEngine is deleted because because logic engine is not supposed to be moved
- Parameters
other
: logic engine to move from
-
LogicEngine &
operator=
(const LogicEngine &other) = delete¶ Assignment operator of LogicEngine is deleted because logic engines hold named resources and are not supposed to be copied
- Parameters
other
: logic engine to assign from
-
LogicEngine &
operator=
(LogicEngine &&other) = delete¶ Move assignment operator of LogicEngine is deleted because logic engine is not supposed to be moved
- Parameters
other
: logic engine to move from
Public Members
-
std::unique_ptr<internal::LogicEngineImpl>
m_impl
¶ Implementation detail of LogicEngine
-
class
rlogic
::
LogicNode
¶ - #include <LogicNode.h>
A base class for multiple logic classes which provides a unified interface to their inputs and outputs. Some subclasses don’t have inputs or outputs - in that case the getInputs or getOutputs methods respectively will return nullptr. Some subclasses, like the rlogic::RamsesAppearanceBinding, will have their inputs depending on their current state (in this example the GLSL uniforms of the shader to which the bound ramses Appearance belongs). In those cases, getInputs()/getOutputs() will return a rlogic::Property which represents an empty struct (type Struct, but no child properties).
Subclassed by rlogic::LuaScript, rlogic::RamsesBinding
Public Functions
-
Property *
getInputs
()¶ Returns a property of type Struct which holds the inputs of the LogicNode.
Returns the root Property of the LogicNode which contains potentially nested list of properties. The properties are different for the classes which derive from LogicNode. Look at the documentation of each derived class for more information on the properties. *
- Return
a tree like structure with the inputs of the LogicNode
-
const Property *
getInputs
() const¶ Returns a property of type Struct which holds the inputs of the LogicNode.
Returns the root Property of the LogicNode which contains potentially nested list of properties. The properties are different for the classes which derive from LogicNode. Look at the documentation of each derived class for more information on the properties. *
- Return
a tree like structure with the inputs of the LogicNode
-
const Property *
getOutputs
() const¶ Returns a property of type Struct which holds the outputs of the LogicNode
Returns the root Property of the LogicNode which contains potentially nested list of properties. The properties are different for the classes which derive from LogicNode. Look at the documentation of each derived class for more information on the properties. *
- Return
a tree like structure with the outputs of the LogicNode
-
std::string_view
getName
() const¶ Returns the name of this LogicNode.
- Return
the name of the LogicNode
-
void
setName
(std::string_view name)¶ Sets the name of this LogicNode.
- Parameters
name
: new name of the LogicNode
-
LogicNode
(const LogicNode &other) = delete¶ Copy Constructor of LogicNode is deleted because LogicNodes are not supposed to be copied
- Parameters
other
: LogicNode to copy from
-
LogicNode
(LogicNode &&other) = delete¶ Move Constructor of LogicNode is deleted because LogicNodes are not supposed to be moved
- Parameters
other
: LogicNode to move from
Public Members
-
Property *
-
class
rlogic
::
LuaScript
: public rlogic::LogicNode¶ - #include <LuaScript.h>
The LuaScript class is the cornerstone of RAMSES Logic as it encapsulates a Lua script and the associated with it Lua environment. LuaScript instances are created by the rlogic::LogicEngine class.
A LuaScript can be created from Lua source code which must fulfill following requirements:
valid Lua 5.1 syntax
contains two global functions - interface() and run() with no parameters and no return values
declares its inputs and outputs in the interface() function, and its logic in the run() function
the interface() function declares zero or more inputs and outputs to the IN and OUT global symbols
inputs and outputs are declared like this:
function interface() IN.input_name = TYPE OUT.output_name = TYPE end
TYPE is one of [INT|FLOAT|BOOL|STRING|VEC2F|VEC3F|VEC4F|VEC2I|VEC3I|VEC4I], or…
TYPE can be also a Lua table with nested properties, obeying the same rules as above, or…
TYPE can be an array declaration of the form ARRAY(n, T) where:
n is a positive integer
T obeys the same rules as TYPE, except T can not be an ARRAY itself
T can be a struct, i.e. arrays of structs are supported
Each property must have a name (string) - other types like number, bool etc. are not supported as keys
the run() function only accesses the IN and OUT global symbols and the properties defined by it
Violating any of these requirements will result in errors, which can be obtained by calling rlogic::LogicEngine::getErrors(). The LuaScript object encapsulates a Lua environment (see official Lua docs) which strips all global table entries after the script is loaded to the Lua state, and leaves only the run() function.
See also the full documentation at https://ramses-logic.readthedocs.io/en/latest/api.html for more details on Lua and its interaction with C++.
Public Functions
-
std::string_view
getFilename
() const¶ Returns the filename provided when the script was created
- Return
the filename of the script
-
void
overrideLuaPrint
(LuaPrintFunction luaPrintFunction)¶ Overrides the lua print function with a custom function. Each time “print” is used inside a lua script, the function will be called. Because the lua “print” function allows an arbitrary amount of parameters, the function is called for each provided parameter.
- Parameters
luaPrintFunction
: to use for printing
-
LuaScript
(std::unique_ptr<internal::LuaScriptImpl> impl) noexcept¶ Constructor of LuaScript. User is not supposed to call this - script are created by other factory classes
- Parameters
impl
: implementation details of the script
-
LuaScript
(const LuaScript &other) = delete¶ Copy Constructor of LuaScript is deleted because scripts are not supposed to be copied
- Parameters
other
: script to copy from
-
LuaScript
(LuaScript &&other) = delete¶ Move Constructor of LuaScript is deleted because scripts are not supposed to be moved
- Parameters
other
: script to move from
-
class
rlogic
::
Property
¶ - #include <Property.h>
Represents a generic property slot of the rlogic::LogicNode and its derived classes. Properties can have primitive types (string, integer, etc.) or complex types (structs, arrays). Complex types can have “children”, i.e. nested properties: named fields (structs), or indexed fields (arrays).
Public Functions
-
EPropertyType
getType
() const¶ Returns the type of this Property
- Return
the type of this Property
-
std::string_view
getName
() const¶ Returns the name of this Property. Note that not all properties have a name - for example an array element does not have a name. In that case the result will be an empty string view. Struct fields always have a non-empty name.
- Return
the name of this Property
-
size_t
getChildCount
() const¶ Returns the amount of available child (nested) properties. If the Property is of type rlogic::EPropertyType::Struct, the returned number will correspond to the number of named properties of the struct. If the Property is of type rlogic::EPropertyType::Array, the method will return the array size. For all other property types getChildCount returns zero.
- Return
the number of nested properties.
-
const Property *
getChild
(size_t index) const¶ Returns the child property with the given
index
.index
must be < getChildCount().This method can be used to get nested properties of structs and arrays. For primitive types this will always return nullptr.
Note that array indexing in getChild follows C++ conventions and not Lua conventions! Inside the Lua scripts, you can and must use Lua conventions when indexing arrays (start at 1, end at N) while in C++ you must use [0, N-1].
Struct properties can also be retrieved by index. The ordering is not guaranteed to match the order of declaration inside Lua scripts (Lua explicitly warns to not rely on ordering of named table entries!). However, once a script is created, the index will not change, i.e. it is permitted that user code caches the property index for faster future access.
- Return
the child with the given index, or nullptr if the property is primitive or the index is out of range
-
Property *
getChild
(size_t index)¶ Returns the child property with the given
index
.index
must be < getChildCount().This method can be used to get nested properties of structs and arrays. For primitive types this will always return nullptr.
Note that array indexing in getChild follows C++ conventions and not Lua conventions! Inside the Lua scripts, you can and must use Lua conventions when indexing arrays (start at 1, end at N) while in C++ you must use [0, N-1].
Struct properties can also be retrieved by index. The ordering is not guaranteed to match the order of declaration inside Lua scripts (Lua explicitly warns to not rely on ordering of named table entries!). However, once a script is created, the index will not change, i.e. it is permitted that user code caches the property index for faster future access.
- Return
the child with the given index, or nullptr if the property is primitive or the index is out of range
-
Property *
getChild
(std::string_view name)¶ Searches for a child with the given name. Only properties of type rlogic::EPropertyType::Struct can return a child by name. In case of a primitive property or array this method will return nullptr.
Note that this method may be slower than getChild(size_t index) as it must do a string-based search.
- Return
the child with the given name, or nullptr if property is not of type rlogic::EPropertyType::Struct
-
const Property *
getChild
(std::string_view name) const¶ Searches for a child with the given name. Only properties of type rlogic::EPropertyType::Struct can return a child by name. In case of a primitive property or array this method will return nullptr.
Note that this method may be slower than getChild(size_t index) as it must do a string-based search.
- Return
the child with the given name, or nullptr if property is not of type rlogic::EPropertyType::Struct
-
template<typename
T
>
std::optional<T>get
() const¶ Returns the value of this property. The supported template types are defined by rlogic::IsPrimitiveProperty where IsPrimitiveProperty<T>::value == true for a type T.
Attention! We recommend always specifying the template argument T explicitly, and don’t rely on the compiler’s type deduction! If T is not one of the supported types, a static_assert will be triggered!
Returns nullopt if the template type T does not match the internal type of the property.
- Return
the value of this Property as std::optional or std::nullopt if T does not match.
-
template<typename
T
>
boolset
(T value)¶ Sets the value of this Property. Same rules apply to template parameter T as in get()
Attention! We recommend always specifying the template argument T explicitly, and don’t rely on the compiler’s type deduction! If T is not one of the supported types, a static_assert will be triggered!
- Return
true if setting the
value
was successful, false otherwise.- Parameters
value
: the value to set for this Property
-
Property
(std::unique_ptr<internal::PropertyImpl> impl) noexcept¶ Constructor of Property. User is not supposed to call this - properties are created by other factory classes
- Parameters
impl
: implementation details of the property
-
~Property
() noexcept¶ Destructor of Property. User is not supposed to call this - properties are destroyed by other factory classes
-
Property
(const Property &other) = delete¶ Copy Constructor of Property is deleted because properties are not supposed to be copied
- Parameters
other
: property to copy from
-
Property
(Property &&other) = delete¶ Move Constructor of Property is deleted because properties are not supposed to be moved
- Parameters
other
: property to move from
Public Members
-
EPropertyType
-
template<typename
T
>
structPropertyTypeToEnum
¶ - #include <EPropertyType.h>
Type trait which converts C++ types to rlogic::EPropertyType enum for primitive types.
-
template<>
structrlogic
::
PropertyTypeToEnum
<bool>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Bool¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<float>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Float¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<int>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Int32¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<std::string>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::String¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<vec2f>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Vec2f¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<vec2i>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Vec2i¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<vec3f>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Vec3f¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<vec3i>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Vec3i¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<vec4f>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Vec4f¶
-
const EPropertyType
-
template<>
structrlogic
::
PropertyTypeToEnum
<vec4i>¶ - #include <EPropertyType.h>
Public Static Attributes
-
const EPropertyType
TYPE
= EPropertyType::Vec4i¶
-
const EPropertyType
-
class
rlogic
::
RamsesAppearanceBinding
: public rlogic::RamsesBinding¶ - #include <RamsesAppearanceBinding.h>
The RamsesAppearanceBinding is a type of rlogic::RamsesBinding which allows the rlogic::LogicEngine to control instances of ramses::Appearance. RamsesAppearanceBinding’s can be created with rlogic::LogicEngine::createRamsesAppearanceBinding.
The RamsesAppearanceBinding has a static link to a ramses::Appearance. After creation, rlogic::LogicNode::getInputs will return a struct property with children equivalent to the uniform inputs of the provided ramses Appearance.
Since the RamsesAppearanceBinding derives from rlogic::RamsesBinding, it also provides the rlogic::LogicNode::getInputs and rlogic::LogicNode::getOutputs method. For this particular implementation, the methods behave as follows:
rlogic::LogicNode::getInputs: returns the inputs corresponding to the available shader uniforms of the bound ramses::Appearance
rlogic::LogicNode::getOutputs: returns always nullptr, because a RamsesAppearanceBinding does not have outputs, it implicitly controls the ramses Appearance
The values of this binding’s inputs are initialized to default values (0, 0.0f, etc) and not loaded from the values in Ramses
All shader uniforms are supported, except the following:
texture samplers of any kind
matrix types (e.g. mat4, mat23 etc.)
any uniform with attached semantics (e.g. display resolution) - see ramses::EEffectUniformSemantic docs
Uniform types which are not supported are not available when queried over rlogic::LogicNode::getInputs.
Public Functions
-
ramses::Appearance &
getRamsesAppearance
() const¶ Returns the bound Ramses Appearance.
- Return
the bound ramses appearance
-
RamsesAppearanceBinding
(std::unique_ptr<internal::RamsesAppearanceBindingImpl> impl) noexcept¶ Constructor of RamsesAppearanceBinding. User is not supposed to call this - RamsesAppearanceBinding are created by other factory classes
- Parameters
impl
: implementation details of the RamsesAppearanceBinding
-
~RamsesAppearanceBinding
() noexcept override¶ Destructor of RamsesAppearanceBinding.
-
RamsesAppearanceBinding
(const RamsesAppearanceBinding &other) = delete¶ Copy Constructor of RamsesAppearanceBinding is deleted because RamsesAppearanceBinding are not supposed to be copied
- Parameters
other
: RamsesNodeBindings to copy from
-
RamsesAppearanceBinding
(RamsesAppearanceBinding &&other) = delete¶ Move Constructor of RamsesAppearanceBinding is deleted because RamsesAppearanceBinding are not supposed to be moved
- Parameters
other
: RamsesAppearanceBinding to move from
-
RamsesAppearanceBinding &
operator=
(const RamsesAppearanceBinding &other) = delete¶ Assignment operator of RamsesAppearanceBinding is deleted because RamsesAppearanceBinding are not supposed to be copied
- Parameters
other
: RamsesAppearanceBinding to assign from
-
RamsesAppearanceBinding &
operator=
(RamsesAppearanceBinding &&other) = delete¶ Move assignment operator of RamsesAppearanceBinding is deleted because RamsesAppearanceBinding are not supposed to be moved
- Parameters
other
: RamsesAppearanceBinding to assign from
Public Members
-
std::unique_ptr<internal::RamsesAppearanceBindingImpl>
m_appearanceBinding
¶ Implementation detail of RamsesAppearanceBinding
-
class
rlogic
::
RamsesBinding
: public rlogic::LogicNode¶ - #include <RamsesBinding.h>
The RamsesBinding is a shared base class for bindings to Ramses objects. For details on each type of binding, look at the derived classes.
Subclassed by rlogic::RamsesAppearanceBinding, rlogic::RamsesCameraBinding, rlogic::RamsesNodeBinding
Public Functions
-
RamsesBinding
(std::reference_wrapper<internal::RamsesBindingImpl> impl) noexcept¶ Constructor of RamsesBinding. User is not supposed to call this - RamsesBinding are created by other factory classes
- Parameters
impl
: implementation details of the RamsesBinding
-
~RamsesBinding
() noexcept override = default¶ Destructor of RamsesBinding.
-
RamsesBinding
(const RamsesBinding &other) = delete¶ Copy Constructor of RamsesBinding is deleted because RamsesBindings are not supposed to be copied
- Parameters
other
: RamsesBindings to copy from
-
RamsesBinding
(RamsesBinding &&other) = delete¶ Move Constructor of RamsesBinding is deleted because RamsesBindings are not supposed to be moved
- Parameters
other
: RamsesBindings to move from
-
RamsesBinding &
operator=
(const RamsesBinding &other) = delete¶ Assignment operator of RamsesBinding is deleted because RamsesBindings are not supposed to be copied
- Parameters
other
: RamsesBindings to assign from
-
RamsesBinding &
operator=
(RamsesBinding &&other) = delete¶ Move assignment operator of RamsesBinding is deleted because RamsesBindings are not supposed to be moved
- Parameters
other
: RamsesBindings to assign from
-
-
class
rlogic
::
RamsesCameraBinding
: public rlogic::RamsesBinding¶ - #include <RamsesCameraBinding.h>
The RamsesCameraBinding is a type of rlogic::RamsesBinding which allows the rlogic::LogicEngine to control instances of ramses::Camera. RamsesCameraBinding’s can be created with rlogic::LogicEngine::createRamsesCameraBinding.
The RamsesCameraBinding has a static link to a ramses::Camera. After creation, rlogic::LogicNode::getInputs will return a struct property with children equivalent to the camera settings of the provided ramses::Camera.
There are two types of ramses::Camera:
ramses::PerspectiveCamera
ramses::OrthographicCamera. Both camera types are defined through their viewport and their frustum properties. These are represented as two separate property structs in the RamsesCameraBinding. Be aware if you set one or more values to one of the structs on the binding and update the LogicEngine it will lead to all properties of this struct being set on the actual ramses::Camera. For example if you only set the Viewport/OffsetX of the Camera per linked script or directly on the binding it will set Viewport/OffsetX, Viewport/OffsetY, Viewport/Width and Viewport/Height to whatever the state of the properties is at that moment. The values of the RamsesCameraBinding inputs are initialized with the values of the provided ramses::Camera during creation. The frustum values of the ramses::Camera are not affected when setting viewport values, and vice-versa. Check the ramses::Camera API to see which values belong together. To avoid unexpected behavior, we highly recommend setting all viewport values together, and also setting all frustum planes together (either by link or by setting them directly). This way unwanted behavior can be avoided.
Since the RamsesCameraBinding derives from rlogic::RamsesBinding, it also provides the rlogic::LogicNode::getInputs and rlogic::LogicNode::getOutputs method. For this particular implementation, the methods behave as follows:
rlogic::LogicNode::getInputs: returns an empty struct with no child properties if no ramses::Camera is currently assigned
rlogic::LogicNode::getInputs: returns inputs struct with two child properties: viewport and frustum. Their child properties in turn vary for the two available camera types (ramses::PerspectiveCamera and ramses::OrthographicCamera)
Perspective Camera: viewport > offsetX, offsetY, width, height frustum > fieldOfView, aspectRatio, nearPlane, farPlane
Orthographic Camera: viewport > same as for Perspective Camera frustum > leftPlane, rightPlane, bottomPlane, topPlane, nearPlane, farPlane
rlogic::LogicNode::getOutputs: returns always nullptr, because a RamsesCameraBinding does not have outputs, it implicitly controls the ramses Camera
Public Functions
-
ramses::Camera &
getRamsesCamera
() const¶ Returns the bound ramses camera.
- Return
the bound ramses camera
-
RamsesCameraBinding
(std::unique_ptr<internal::RamsesCameraBindingImpl> impl) noexcept¶ Constructor of RamsesCameraBinding. User is not supposed to call this - RamsesCameraBindings are created by other factory classes
- Parameters
impl
: implementation details of the RamsesCameraBinding
-
~RamsesCameraBinding
() noexcept override¶ Destructor of RamsesCameraBinding.
-
RamsesCameraBinding
(const RamsesCameraBinding &other) = delete¶ Copy Constructor of RamsesCameraBinding is deleted because RamsesCameraBindings are not supposed to be copied
- Parameters
other
: RamsesNodeBindings to copy from
-
RamsesCameraBinding
(RamsesCameraBinding &&other) = delete¶ Move Constructor of RamsesCameraBinding is deleted because RamsesCameraBindings are not supposed to be moved
- Parameters
other
: RamsesCameraBinding to move from
-
RamsesCameraBinding &
operator=
(const RamsesCameraBinding &other) = delete¶ Assignment operator of RamsesCameraBinding is deleted because RamsesCameraBindings are not supposed to be copied
- Parameters
other
: RamsesCameraBinding to assign from
-
RamsesCameraBinding &
operator=
(RamsesCameraBinding &&other) = delete¶ Move assignment operator of RamsesCameraBinding is deleted because RamsesCameraBindings are not supposed to be moved
- Parameters
other
: RamsesCameraBinding to assign from
Public Members
-
std::unique_ptr<internal::RamsesCameraBindingImpl>
m_cameraBinding
¶ Implementation detail of RamsesCameraBinding
-
class
rlogic
::
RamsesNodeBinding
: public rlogic::RamsesBinding¶ - #include <RamsesNodeBinding.h>
The RamsesNodeBinding is a type of rlogic::RamsesBinding which allows manipulation of Ramses nodes. RamsesNodeBinding’s can be created with rlogic::LogicEngine::createRamsesNodeBinding.
The RamsesNodeBinding has a fixed set of inputs which correspond to properties of ramses::Node. They have a fixed type and name: ‘visibility’ (type bool) ‘rotation’ (type vec3f) ‘translation’ (type vec3f) ‘scaling’ (type vec3f)
The default values of the input properties are taken from the bound ramses::Node provided during construction. The rotation convention is also taken from Ramses (see rlogic::RamsesNodeBinding::setRotationConvention)..
The RamsesNodeBinding class has no output properties (thus getOutputs() will return nullptr) because the outputs are implicitly the properties of the bound Ramses node.
Note
In case no values were set (because the user neither set a value explicitly nor linked the input of rlogic::RamsesNodeBinding to another LogicNode output) the Ramses values are not touched. It is possible to set values directly to ramses::Node which will not be overwritten by rlogic::RamsesNodeBinding if you never explicitly assigned a value to the rlogic::RamsesNodeBinding inputs. You can also mix-and-match this behavior - assign some properties and others not.
The LogicEngine does not restrict which Scene the bound nodes belong to - it is possible to have nodes from different scenes bound to the same LogicEngine, and vice-versa. The effects on the ramses::Node property values which are bound to a rlogic::RamsesNodeBinding are immediately visible after rlogic::LogicEngine::update() returns, however the user has to call ramses::Scene::flush() explicitly based on their scene update logic and frame lifecycle.
Public Functions
-
bool
setRotationConvention
(ramses::ERotationConvention rotationConvention)¶ Sets the rotation convention used to set the rotation values to a potentially bound ramses::Node. Default is the same as the ramses default. Use this to change the setting.
- Return
true if successful, false otherwise
- Parameters
rotationConvention
: the rotation convention to use
-
ramses::ERotationConvention
getRotationConvention
() const¶ Returns the currently used rotation convention for the node rotation property.
- Return
the currently used rotation convention
-
RamsesNodeBinding
(std::unique_ptr<internal::RamsesNodeBindingImpl> impl) noexcept¶ Constructor of RamsesNodeBinding. User is not supposed to call this - RamsesNodeBindings are created by other factory classes
- Parameters
impl
: implementation details of the RamsesNodeBinding
-
~RamsesNodeBinding
() noexcept override¶ Destructor of RamsesNodeBinding.
-
RamsesNodeBinding
(const RamsesNodeBinding &other) = delete¶ Copy Constructor of RamsesNodeBinding is deleted because RamsesNodeBindings are not supposed to be copied
- Parameters
other
: RamsesNodeBindings to copy from
-
RamsesNodeBinding
(RamsesNodeBinding &&other) = delete¶ Move Constructor of RamsesNodeBinding is deleted because RamsesNodeBindings are not supposed to be moved
- Parameters
other
: RamsesNodeBindings to move from
-
RamsesNodeBinding &
operator=
(const RamsesNodeBinding &other) = delete¶ Assignment operator of RamsesNodeBinding is deleted because RamsesNodeBindings are not supposed to be copied
- Parameters
other
: RamsesNodeBindings to assign from
-
RamsesNodeBinding &
operator=
(RamsesNodeBinding &&other) = delete¶ Move assignment operator of RamsesNodeBinding is deleted because RamsesNodeBindings are not supposed to be moved
- Parameters
other
: RamsesNodeBindings to assign from
Public Members
-
std::unique_ptr<internal::RamsesNodeBindingImpl>
m_nodeBinding
¶ Implementation detail of RamsesNodeBinding
-
bool
-
namespace
ramses
¶
-
namespace
rlogic
¶ Typedefs
-
using
vec2f
= std::array<float, 2>¶
-
using
vec3f
= std::array<float, 3>¶
-
using
vec4f
= std::array<float, 4>¶
-
using
vec2i
= std::array<int, 2>¶
-
using
vec3i
= std::array<int, 3>¶
-
using
vec4i
= std::array<int, 4>¶
-
using
LuaPrintFunction
= std::function<void(std::string_view scriptName, std::string_view message)>¶
Enums
-
enum
ELogMessageType
¶ ELogMessageType lists the types of available log messages. The integer represents the priority of the log messages (lower means more important, thus higher priority).
Values:
-
enumerator
Off
= 0¶
-
enumerator
Fatal
= 1¶
-
enumerator
Error
= 2¶
-
enumerator
Warn
= 3¶
-
enumerator
Info
= 4¶
-
enumerator
Debug
= 5¶
-
enumerator
Trace
= 6¶
-
enumerator
-
enum
EPropertyType
¶ EPropertyType lists the types of properties created and managed by the rlogic::LogicNode class and its derivates.
Values:
-
enumerator
Float
¶
-
enumerator
Vec2f
¶
-
enumerator
Vec3f
¶
-
enumerator
Vec4f
¶
-
enumerator
Int32
¶
-
enumerator
Vec2i
¶
-
enumerator
Vec3i
¶
-
enumerator
Vec4i
¶
-
enumerator
Struct
¶
-
enumerator
String
¶
-
enumerator
Bool
¶
-
enumerator
Array
¶
-
enumerator
Functions
-
constexpr const char *
GetLuaPrimitiveTypeName
(EPropertyType type)¶ Returns the string representation of a property type. This string corresponds to the syntax that has to be used in the Lua source code used to create scripts with properties with the corresponding type.
-
RamsesLogicVersion
GetRamsesLogicVersion
()¶ Retrieve currently used Ramses Logic version information.
- Return
the Ramses Logic version of the currently used build
-
using
-
namespace
internal
¶
-
namespace
rlogic
::
Logger
¶ Interface to interact with the internal logger. If you want to handle log messages by yourself, you can register your own log handler function with rlogic::Logger::SetLogHandler, which is called each time a log message is logged. In addition you can silence the standard output of the log messages
Typedefs
-
using
LogHandlerFunc
= std::function<void(ELogMessageType, std::string_view)>¶ The LogHandlerFunc can be used to implement a custom log handler. The function is called for each log message separately. After the call to the function the string data behind std::string_view is deleted. If you want to keep it, you must copy it e.g. to a std::string. E.g.
rlogic::Logger::SetLogHandler([](ElogMessageType msgType, std::string_view message){ std::cout << message std::endl; });
Functions
-
void
SetLogVerbosityLimit
(ELogMessageType verbosityLimit)¶ Controls how verbose the logging is.
verbosityLimit
has the following semantics:if log message has message type with higher or equal priority as verbosityLimit, then it is logged
log priority is as documented by rlogic::ELogMessageType (Errors are more important than Warnings, etc)
the default value is rlogic::ELogMessageType::Info, meaning that log messages are processed if they have INFO priority or higher.
- Parameters
verbosityLimit
: least priority a log message must have in order to be processed
-
ELogMessageType
GetLogVerbosityLimit
()¶ Returns the current log verbosity limit of the logger. See rlogic::Logger::SetLogVerbosityLimit for more info on semantics.
- Return
current log verbosity limit
-
void
SetLogHandler
(const LogHandlerFunc &logHandlerFunc)¶ Sets a custom log handler function, which is called each time a log message occurs. Note: setting a custom logger incurs a slight performance cost because log messages will be assembled and reported, even if default logging is disabled (SetDefaultLogging).
@ param logHandlerFunc function which is called for each log message
-
void
SetDefaultLogging
(bool loggingEnabled)¶ Sets the default logging to std::out to enabled or disabled. Enabled by default.
- Parameters
loggingEnabled
: true if you want to enable logging to std::out, false otherwise
-
using
-
file
APIExport.h
Defines
-
RLOGIC_API
¶
-
-
file
Collection.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/Iterator.h”#include <functional>#include <memory>
-
file
ELogMessageType.h
- #include <cassert>
-
file
EPropertyType.h
- #include “ramses-logic/APIExport.h”#include <array>#include <string>
-
file
ErrorData.h
- #include <string>
-
file
Iterator.h
- #include “ramses-logic/APIExport.h”#include <type_traits>#include <iterator>
-
file
Logger.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/ELogMessageType.h”#include <functional>#include <string_view>
-
file
LogicEngine.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/LuaScript.h”#include “ramses-logic/Collection.h”#include “ramses-logic/ErrorData.h”#include <vector>#include <string_view>
-
file
LogicNode.h
- #include “ramses-logic/APIExport.h”#include <vector>#include <string>#include <functional>
-
file
LuaScript.h
- #include “ramses-logic/LogicNode.h”#include <string>#include <memory>
-
file
Property.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/EPropertyType.h”#include <cstddef>#include <optional>#include <memory>#include <string>
-
file
RamsesAppearanceBinding.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/RamsesBinding.h”#include <memory>
-
file
RamsesBinding.h
- #include “ramses-logic/LogicNode.h”
-
file
RamsesCameraBinding.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/RamsesBinding.h”#include <memory>
-
file
RamsesLogicVersion.h
- #include “ramses-logic/APIExport.h”#include <string_view>#include <cstdint>
-
file
RamsesNodeBinding.h
- #include “ramses-logic/APIExport.h”#include “ramses-logic/RamsesBinding.h”#include <memory>
-
dir
/home/docs/checkouts/readthedocs.org/user_builds/ramses-logic/checkouts/v0.7.0/include
-
dir
/home/docs/checkouts/readthedocs.org/user_builds/ramses-logic/checkouts/v0.7.0/include/ramses-logic