Symbols Parsing

Symbol Introduction

A symbols represents the name of a constant value in the Cinema 4D SDK.

Symbol should always be used rather than the direct constant value, as value may change between two Cinema 4D releases.
As an example Ocube is a symbols representing the constant value 5159. This symbol represent the Plugin ID used to register the Cube Object.
Other built-in symbols are listed in the Types and Symbols List documents.

Internal Creation Process

During the compilation of Cinema 4D, symbols and their associated constants values are extracted from the Cinema 4D C++ SDK. They are saved to a file shipped with Cinema 4D.
During the first Cinema 4D startup, this file and all descriptions resource files are loaded by Python. Python will then parse theses files to expose symbols and their value to you, 3rd party plugin developers.
This parsing is cached within the “symbolcache” file to speedup next Cinema 4D startup and this file is updated only when a resource files is added, removed or modified.

The symbolcache file is located in :

(Mac) e.g: ‘/Users/UserName/Library/Preferences/MAXON/Maxon Cinema 4D R25_C333CB6C/prefs/symbolcache’

(Windows) e.g: ‘C:\Users\UserName\AppData\Roaming\Maxon\Maxon Cinema 4D R25_C333CB6C\prefs\symbolcache’

Symbols Parser Usage

The symbol_parser Python module was introduced with Cinema 4D R25 to extract symbols and their corresponding values from C++ files and description resource files.

symbol_parser.parse_and_export_in_caller(input_directory)
Parse all .h files recursively from input_directory to find define, enum and static const int (read Symbols Parser Features for more information).
They are then exported as a Python variable in the caller locals.
Parameters

input_directory (integer or None) – The directories

Given this c4d_symbols.h file

enum
{
    My_Symbol = 1000,
    My_Syml = 1001,
    _DUMMY_ELEMENT_
};

To automatically have My_Symbol and My_Syml symbol with their respective associated value in Python use the next code:

import os
import symbol_parser

# Parse recursively all header files and parse enums and define
c4d_symbol_dir = os.path.dirname("c4d_symbols.h")
symbol_parser.parse_and_export_in_caller(c4d_symbol_dir)

# Values are accessible directly
print(My_Symbol)
>>> 1000
print(My_Syml)
>>> 1001

Symbols Parser Features

Supported Values

For the moment Cinema 4D, can only ingest Int32 value when reading the cached symbolcache files. However, the parser, understand and parse correctly all POD including string.

Integer value

Integer value are parsed, all bit operations are supported, even simple arithmetic.

C++ Input

Python Output

#define LEGACY_DRAW_FLAGS_DEPTH_TEST_ALWAYS (1 << 10)

LEGACY_DRAW_FLAGS_DEPTH_TEST_ALWAYS == 1024

#define COLORMODE_MAXCOLOR ((1 << 6) - 1)

COLORMODE_MAXCOLOR == 63

#define HUDCONTROL_FLAG_KEYVALUE_CHANGED (1ULL << 32ULL)

Note

UL/LL/ULL are removed only if the previous char is a number, otherwise it’s kept to not break symbols like BASEDRAW_DISPLAYFILTER_NULL.

HUDCONTROL_FLAG_KEYVALUE_CHANGED == 4294967296

Hexadecimal value

Hexadecimal value are parsed.

C++ Input

Python Output

#define ZIP_FILE_FLAG_OWNER_R 0x01000000

ZIP_FILE_FLAG_OWNER_R == 16777216

Float value

Float32 value are parsed, supporting scientific notation.

C++ Input

Python Output

#define MAXRANGE 1.0e20

ZIP_FILE_FLAG_OWNER_R == 1e+20

#define MIN_EPSILON 0.001

MIN_EPSILON == 0.001

Single Quote string

Single quote string, are converted to their corresponding integer value if they have length of 3 or 4. Otherwise they are treated as regular string.

C++ Input

Python Output

#define QUICKTAB_BARTITLE ‘btit’

QUICKTAB_BARTITLE == 1651796340

CHAR_CONST32

CHAR_CONST32 are converted to their corresponding integer value.

C++ Input

Python Output

#define FLAT_SETTINGS_MAGIC CHAR_CONST32(‘fflt’)

FLAT_SETTINGS_MAGIC == 1717988468

C4D_FOUR_BYTE

C4D_FOUR_BYTE are converted to their corresponding integer value.

C++ Input

Python Output

#define QUICKTAB_BAR C4D_FOUR_BYTE(0,’b’,’a’,’r’)

QUICKTAB_BAR == 6447474

Double Quote string

Double quote string, are parsed.

C++ Input

Python Output

#define MENUCOMMAND “CMD”

MENUCOMMAND == “CMD”

Value referencing other value

Value referencing other value are resolved.

C++ Input

Python Output

#define POLY_TRIANG_NGON 32
#define POLY_TRIANG_FORCE_NGON (128 | POLY_TRIANG_NGON)

POLY_TRIANG_NGON == 32 POLY_TRIANG_FORCE_NGON == 160

Note

The system is able to resolve any numbers of references.

enum class HDIRTY_ID {RENDERSETTINGS = 7}
enum class HDIRTYFLAGS {RENDERSETTINGS = (1 << (UInt32)HDIRTY_ID::RENDERSETTINGS)}

HDIRTY_ID_RENDERSETTINGS == 7 HDIRTYFLAGS_RENDERSETTINGS == 128

Supported types

Define

Define expressing a value are parsed. Define expressing an expression/macro are not parsed.

C++ Input

Python Output

#define CUSTOMGUI_TEXTURENAME 1000484

CUSTOMGUI_TEXTURENAME == 1000484

#define COLORBYTES_GRAYw (COLORBYTES_GRAY * sizeof(PIX_W)) // COLORBYTES_GRAY == 1, sizeof(PIX_W) == 2

COLORBYTES_GRAYw == 2

static const Int32

static const Int32 and only Int32 value are parsed and outputs using the current namespace/class.

C++ Input

Python Output

static const Int32 ID_CUSTOMDATA_TAG_LIB = 431000187;

ID_CUSTOMDATA_TAG_LIB == 431000187

Enums

Enums value are incremented, starting from 0 if no value is defined otherwise, it take the previous enum value.

Unnamed Enums

Enums without name are expressed in Python with the current C++ namespace or class.

C++ Input

Python Output

enum {Mcamera, Xyz, Mdrag}

Mcamera == 0 Xyz == 1 Mdrag = 2

enum {Mcamera = 5, Xyz, Mdrag = 1000}

Mcamera == 5 Xyz == 6 Mdrag = 1000

Named Enums

Enums with name are expressed in Python with the current C++ namespace or class, so their names are not took into consideration.

C++ Input

Python Output

enum DA {DA_NIL= 0, DA_VOID = 14};

DA_NIL == 0 DA_VOID == 14

Note

DA.DA_NIL does not exist

Enums Struct/Class and MAXON_ENUM_LIST/MAXON_ENUM_FLAGS

Enums struct, class, MAXON_ENUM_LIST and MAXON_ENUM_FLAGS are expressed in Python with their scope name. Given a enum class XYZ with the value ABC will output XYZ_ABC.

C++ Input

Python Output

enum class MDDIRTY
{
    NONE = 0,
    ARRAYCOUNT = (1 << 0)
} MAXON_ENUM_FLAGS(MDDIRTY);

MDDIRTY_NONE MDDIRTY_0 == 0 MDDIRTY_ARRAYCOUNT == 1

Note

The MDDIRTY_0 value is added to Python, each time there is a NONE entry to not break API compatibility as older version of the API may still use it.

enum class MD_TYPE
{
    MD_NONE = DA_NIL,
    MD_CHAR = 40000000,
} MAXON_ENUM_LIST(MD_TYPE);

MD_TYPE_MD_NONE = 0 MD_TYPE_MD_CHAR = 40000000