Programming
Fundamentals
Setting Up Development Environment
Usage Examples
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
CIGI Client Plugin
Rendering-Related Classes

KeyLine System

Introduction

In many cases there is a need in changing some "in game" parameters dynamically, depending on time or something else (e.g. lighting conditions). For example, one needs to change some parameter depending on time: the parameter animation can be stored as a sequence of animation keys: values and their time. To calculate the parameter value at any given moment of time it's needed to find the previous and the next keys and make some kind of interpolation between their values.

KeyLine system handles key sequences and takes care of interpolation between key values, providing GUI for data manipulation as well. It is a somewhat data-driven system, meta-information is stored in the XML format.

KeyLine scripts are located in data/scripts/keyline directory of Unigine SDK.

Entities

Param

Param is a type of an atomic parameter, whose value needs to be changed dynamically (see ParamBase class). Param can be serialized to XML and deserialized from it by using meta-data (ParamDef). There are functions associated with the parameter, which specify how parameter's value is applied to some environment (setter) or retieved from it (getter).

There is a pre-defined set of "basic" parameter types available out-of-the box: ParamFloat, ParamInt, ParamVec4 classes.

ParamDef

ParamDef is a definition of a parameter (type, ParamEditor, min/max values, default value, setter/getter functions). ParamDef class is used to create parameter instances by its definition.

ParamEditor

ParamEditor is a definition of GUI editor type, which is used to edit parameter's value (see ParamEditorBase class).

Key

Key is a set of parameters grouped by some subject (see KeyBase class).

KeyDef

KeyDef is a definition of a key (set of its parameters' definitions). KeyDef class is used to create Key instances by its definition.

KeyLine

KeyLine is a sequence of keys (of the same type), each of which is identified by a position. KeyLine is responsible for smooth interpolation between keys. When KeyLine cursor position (current position) is behind the last key, KeyLine makes interpolation between the last and the first keys (see KeyLine class).

KeyLineManager

KeyLineManager handles set of KeyLines (see KeyLineManager). It is also responsible for global settings of min/max positions.

File Formats

keyman

*.keyman file contains settings of KeyLineManager in XML format.

The keyline_manager node must be a root of the node hierarchy. This node has the following mandatory integer attributes: min (minimal position for all KeyLines in the KeyLineManager) and max (maximal position for all KeyLines). Besides that, integer attribute duration specifies the time period during which the KeyLineManager will pass from the minimal to the maximal position.

keyline_manager node can contain zero or more children keyline nodes, each of them must contain file attribute, which points to *.keyline file. For example:

Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<keyline_manager min="0" max="86399" duration="1440">
	<keyline file="demos/tropics/tropics_sky.keyline"/>
	<keyline file="demos/tropics/tropics_render.keyline"/>
</keyline_manager>
According to this code, the day in the game consists of 86399  in-game seconds and lasts for 1440  real seconds. This means that the keyline will pass through 60  positions during 1  second in the real time (86399  s / 1440  s = 60) and the in-game day will correspond to 24  real-world minutes (1440  s / 60  s).
Notice
KeyLineManager class allows to programmatically define duration and floating-point multiplier that controls the speed of time change. For that purpose it has member functions setDuration() and getDuration() as well as setMultiplier() and getMultiplier().

keyline

*.keyline file contains keyline data in XML format. Only one keyLine can be stored in a file.

keyline node must be a root of the node hierarchy, it has mandatory name attribute. min and max attributes has the same meaning as keyline_manager ones, but their values will be ignored, because they are overriden by KeyLineManager. keyline node must have key_def node as a child.

key_def node can be defined in two different ways:

Source code (XML)
<!--
key_def (key definition) node: reference format.
file (required) - Used to specify file, which contains key definition in the format described below.
-->
<key_def file="demos/tropics/tropics_timeline.keydef"/>
or
Source code (XML)
<!--
key_def node - full format.
attributes:
keyline (required, if key_def is placed into separate file and is optional, if key_def is placed into keyline node).
Used to identify key_def.
-->
<key_def keyline="scattering">
	<!--
	place parameter definitions here
	-->
	<!--
	param_def (parameter definition) node.
	attributes:
	type (required) - String identificator of a parameter type. Used to create a parameter instances by name.
	name (required) - Unique parameter name. Used to identify the parameter in a key.
	editor (required) String identificator of a parameter editor type. Used to generate GUI for editing keys.
	-->
	<param_def type="float" name="energy" editor="float_slider">
		<!--
		getter function name for parameter (optional)
		-->
		<getter>engine.render.getScatteringEnergy</getter>
		<!--
		setter function name for parameter (optional)
		-->
		<setter>engine.render.setScatteringEnergy</setter>
		<!--
		min value for parameter (optional)
		-->
		<min name="energy">0</min>
		<!--
		max value for parameter (optional)
		-->
		<max name="energy">40</max>
		<!--
		default value for parameter (optional)
		-->
		<default_value name="energy">15</default_value>
	</param_def>
</key_def>

keyline node has children key nodes, which contain keys' data. If there are no keys in the keyline, one key will be created automatically. This key will be filled using parameters retrieved by getter functions from the environment (this may be usefull when starting from previously tuned non-sequenced parameters).

key node has the following format:

Source code (XML)
<!--
key node. Contains set of parameter values.
attributes:
pos (required, unique) - key position on keyline.
-->
<key pos="43200">
	<!--
	param node. Contains parameter data.
	attributes:
	name (required, uniquie) - parameter name, which is also used by the system as a parameter identificator
	-->
	<param name="areal">30</param>
	<param name="greenstein">0.9</param>
	<param name="mie_color">1 0.972549 0.858824 1</param>
</key>

keydef

*.keydef file contains definition for key types in XML format.

definition node must be a root of a node hierarchy. version attribute is reserved for future implementations. definition node contains set of key_def nodes in the full format, which is described in keyline files definition.

Example:

Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<definitions version="1.0">
	<key_def keyline="scattering">
	<!-- ... -->
	</key_def>
	<key_def keyline="sky">
	<!-- ... -->
	</key_def>
	<key_def keyline="render">
	<!-- ... -->
	</key_def>
</definitions>

How to Use

Getting started

Step 1. Prepare getter and setters for parameters

Source code (UnigineScript)
namespace Foo {
	
	void setterFunc(DataType v) {
		// some work to set the parameter
	}
	
	DataType getterFunc() {
		// retrieve the parameter value
	}
}

Step 2. Prepare keyline manager files

Create keyline manager file (test.keyman, for example). Define keylines:

Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<keyline_manager min="0" max="86399" duration="2160">
	<keyline file="test.keyline"/>
</keyline_manager>

Create keyline file (test.keyline, for example):

Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<keyline name="test keyline">
	<key_def>
		<param_def type="float" name="param 1" editor="float_editline">
			<getter>Foo::getterFunc</getter>
			<setter>Foo::setterFunc</setter>
		</param_def>
	</key_def>
</keyline>

Step 3. Include keyline manager headers to your script

Source code (UnigineScript)
// include all required keyline manager headers:
#include <keyline.h>
// include basic parameters (optional), if you want to use float, vec4 or int paramter types and their editors:
#include <params_basic.h>

Step 4. Initialize keyline manager

Source code (UnigineScript)
KeyLineManager manager;

void init() {
	// register basic parameters to allow their creation by name (needed for loading from file)
	KeyLine::registerBasicParams();
	
	// create and load keyline
	manager = new KeyLine::KeyLineManager();
	manager.load("test.keyman");
}

Step 5. Update position and call apply, when needed

Source code (UnigineScript)
int update() {
	if(play_mode) { 
		manager.play();     // update position       
	}
	manager.apply();        // commit params (call setter function for each param in manager)
}

Using GUI for editing

KeyLine provides GUI editors, which allows user to manipulate keys and change parameter values. Refer to the following to use GUI editor in your project.

Step 1. Include headers

Source code (UnigineScript)
#include <keyline/keyline_window.h>

Step 2. Write initialization, shutdown and update code

Source code (UnigineScript)
void init() {
	Gui gui = engine.getGui();
	KeylineWindow::init(gui);
	KeyEditorWindow::init(gui);
}

void shutdown() {
	KeylineWindow::shutdown();
	KeyEditorWindow::shutdown();
}

void update() {
	KeylineWindow::update();
	KeyEditorWindow::update();
}

Step 3. Showing the window

Source code (UnigineScript)
void show_window() {
	// set callbacks (optional)
	KeylineWindow::setOnSaveCallback("on_save_manager");
	KeylineWindow::setOnResetCallback("on_reset_manager");
	KeylineWindow::setOnHideCallback("on_editor_closed");
	KeylineWindow::setOnSetCaptionCallback("gen_pos_caption");
	
	// show window
	KeylineWindow::show(manager);
}

/* callbacks (optional)
*/
void on_save_manager() {
	/* Hits when user want to save keyline manager to file  */
}
void on_reset_manager() {
	/* Hits when user want to discard changes and reload keyline manager */
}
void on_editor_closed(int is_changed) {
	/* Hits when editor window is closed. is_changed == 1, when there are unsaved changes in keyline manager */
}
string gen_pos_caption(float pos) {
	/* generate position caption for keyline window GUI. Returns a formatted string */
}

Using custom parameters

If basic parameters don't cover all of your needs, you can write your own parameter types.

To do this you must inherit your class from KeyLine::ParamBase and override at least load, save and clone methods. To create your own parameter editors inherit from KeyLine::ParamEditorBase class. Then you must write functions for creation your parameters:

Source code (UnigineScript)
/* creation function for custom parameter
*/
ParamBase createCustomParam() {
	// add here some extra initialization, if needed
	return new CustomParam("foo");
}

/* creation function for custom param editor
*/
ParamEditorBase createCustomParamEditor(ParamDef def,Gui gui) {
	// add here some extra initialization, if needed
	return new CustomParamEditor(gui);
}
and register them in the system:
Source code (UnigineScript)
addParamType("foo","createCustomParam");
addEditorType("foo_editor","createCustomParamEditor");

GUI

KeyLine system automatically generates GUI for editing keys.

Main KeyLine window

KeyLine Settings

Key editor window
Last update: 2017-12-21