UnigineEditor
Interface Overview
Assets Workflow
Settings and Preferences
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Landscape Tool
Using Editor Tools for Specific Tasks
FAQ
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

Preprocessor Directives

Preprocessor directives are special language constructs, which control the script interpreter behavior. All UnigineScript directives begin with the # sign, and each of them should be on its own line. Note that there are no semicolons at the end of strings that start with directives.

Preprocessor Macros#

A macro is a fragment of code which has been given a name. Whenever the name is used, it is replaced by the contents of the macro.

There is a pre-defined set of macros:

  • __VERSION__ - the UnigineScript interpreter version, for example, "1.82".
  • NDEBUG - the binary does not contain debugging information (release build).
  • _WIN32 - target operating system is Windows.
  • _LINUX - target operating system is Linux.
  • _ARCH_X86 - target operating system version is 32-bit.
  • _ARCH_X64 - target operating system version is 64-bit.
  • HAS_BLOB - Blob class is available in the Core Library.
  • HAS_BOUNDS - Bounds-related classes are available in the Core Library.
  • HAS_DIRECT3D11 - the binary is built with Direct3D 11 rendering system.
  • HAS_JOYSTICK - the binary is built with support of a joystick.
  • HAS_IMAGE - Image class is available in the Core Library.
  • HAS_MESH - Mesh class is available in the Core Library.
  • HAS_MEMORY - the binary is built with Unigine memory management system.
  • HAS_OPENAL - the binary is built with OpenAL sound system.
  • HAS_OPENGL - the binary is built with OpenGL rendering system.
  • HAS_OPENEXR - the binary is built with support for the OpenEXR format.
  • HAS_PATH - Path class is available in the Core Library.
  • HAS_REGEXP - Regexp Class is available in the Core Library.
  • HAS_SIXAXIS - the binary is built with support for a sixaxis controller.
  • HAS_SOCKET - Socket Class is available in the Core Library.
  • HAS_XAUDIO2 - the binary is built with XAudio2 sound system.
  • HAS_XML - Xml Class is available in the Core Library.
  • HAS_XPAD360 - the binary is built with support for Xbox 360 gamepad.
  • HAS_ELLIPSOID - the binary is built including the ellipsoid functionality.
  • USE_DOUBLE - the binary is built with support for double precision of coordinates.
  • USE_GEODETICS - the binary is built with support for geodetics.
  • USE_MICROPROFILE - the binary is built with support of microprofile.

These macros can be used as conditions and combined with logical operators: () for grouping, || for "or", && for "and".

#include#

Loads the content of a given file.

Syntax: #include "someFile"

Here someFile is a target file name.

Source code (UnigineScript)
#include "foo.h"
foo(); // ok if foo.h contains declaration of foo()

To avoid conflicts it's recommended to include files this way:

Source code (UnigineScript)
#ifndef __MYLIB_H__
#define __MYLIB_H__

#include "myLib.h"

#endif /* __MYLIB_H__ */
In this case, even being included several times from different places, "myLib.h" will not cause re-definition collisions, since it will be compiled only once.

Notice
If a base path to the file is not mentioned in the #include pragma, the file will be searched among all files located in the data directory of the project.

#define#

Sets an identifier and a character sequence, by which the identifier will be replaced in the text of the program.

Syntax: #define macro_name character_sequence

Here macro_name will be replaced with character_sequence everywhere in the code. Note that character_sequence shouldn't contain spaces (except for strings, which must be enclosed in double quotes) and can be omitted.

Source code (UnigineScript)
#define LEFT 1
#define RIGHT 0

log.message("%d %d\n",LEFT,RIGHT);
// Output: 1 0

#define FRUIT "an apple"

log.message("%s\n", "today we will eat "FRUIT);
// Output: today we will eat an apple

// arguments are also supported:
#define saturate(v) clamp(v,0.0,1.0)

Inside the #define directive, the literal # operator can be used. It turns a macro argument into a string constant. This operator can also be used inside templates.

Syntax: #macro_arg

Here macro_arg is an argument to a macro.

Source code (UnigineScript)
#define assert(EXP) { if(EXP) { } else { throw("Assertion: '%s'",#EXP); } }

See also Templates.

#undef#

Removes a previously defined identifier.

Syntax: #undef macro_name

Source code (UnigineScript)
#define LOCK
#undef LOCK

#ifndef LOCK
log.message("unlocked\n"); // this fragment will be executed
#endif

#ifdef#

Allows executing some fragment of code conditionally, if a given identifier is defined with #define.

Syntax: #ifdef macro_name
some_code #endif

If macro_name is defined, then some_code will be executed.

Source code (UnigineScript)
#define LOCK1
#define LOCK2

#ifdef (LOCK1 && LOCK2) || LOCK3
log.message("locked\n"); // this fragment will be executed
#endif

#ifndef#

Allows executing some fragment of code conditionally, if a given identifier is not defined with #define or is undefined with #undef.

Syntax: #ifndef macro_name
some_code #endif

If macro_name is not defined, then some_code will be executed.

Source code (UnigineScript)
#define LOCK

#ifndef LOCK
log.message("unlocked\n"); // this fragment will NOT be executed
#endif

#else#

Creates an alternative to #ifdef and #ifndef pragmas.

Syntax: #ifdef macro_name some_code
#else some_more_code
#endif

Here #ifndef can be used instead of #ifdef (however, the meaning of the condition will be reversed). If the first condition is false, then everything from the first #else up to the first #endif will be executed.

Source code (UnigineScript)
#define SOUND_ENABLE

#ifdef SOUND_ENABLE
log.message("sound enabled\n");
#else
log.message("sound disabled\n"); // this fragment will be executed
#endif

#elif#

Create a conditional alternative to #ifdef and #ifndef pragmas.

Syntax: #ifdef macro_name1 some_code1
#elif macro_name2 some_code2
#endif

Here #ifndef can be used instead of #ifdef (however, the meaning of the condition will be reversed). If macro_name1 is false, then macro_name2 is tested, and if it's true, everything from this #elif up to the first #elif, #else or #endif will be executed.

Source code (UnigineScript)
#define VAL2

#ifdef VAL1
log.message("it is 1\n");
#elif VAL2
log.message("it is 2\n"); // this fragment will be executed
#elif VAL3
log.message("it is 3\n");
#endif

#endif#

Marks an end of conditional compilation.

#error#

Terminates execution of the script and logs the message into the console and a system log file.

Syntax: #error message_text

Source code (UnigineScript)
#error I don't want to execute it any longer

#warning#

Logs the message into the console and a system log file, the script continues execution.

Syntax: #warning message_text

Source code (UnigineScript)
#warning There is somethings wrong in here

#warn_long#

Terminates compilation if a variable of a long type is used in the script, and logs the error message into the console and a system log file.

#warn_double#

Terminates compilation if a variable of a double type is used in the script, and logs the error message into the console and a system log file.

#no_long#

Replaces all variables of a long type in the script with an int type.

#no_double#

Replaces all variables of a double type in the script with a float type.

Last update: 2017-12-21