Tuesday, May 23, 2017

Unblender CPP14

Blender contains a specialized logic brick editor which is used to drive game logic in Blender's internal game engine (BGE). The Unblender fork removes the old BGE, and replaces it with a generic logic editor, for better export to external game engines like Unreal.

new Unblender generic logic nodes

Unblender supports material and texture groups

The logic brick editor is written in C and not yet exposed to the Python UI scripting layer. The C source code of Blender is split into two layers: DNA and RNA. DNA contains the core data types (structs), and the RNA wraps the data types with a public API. These layers are bound by C code generated by makesdna and makesrna. Rebuilding Blender from source only takes a couple minutes, which makes it even easier modify.


Below is an example of a custom logic brick, The struct bForEachCont abstracts a for each loop over a group of objects. It contains a pointer to a Group struct, the items to loop over.
typedef struct bForEachCont {
 struct Group *group;
 char body1[128];
 char body2[128];
} bForEachCont;

Inside Unblender's logic brick editor this controller UI will show a selector for any groups the user has defined. This allows the user to abstract away the name of a Group in the scene from the code that operates on it. Variables and other special key names, used in hand written code for runtime game logic, no longer need to be kept in sync with object and material names in the 3D scene by the artist and level designer.

Blender is not C++ (yet)

The core of Blender is written in C, with some use of C99 features (non-trival struct initialization). A C++ wrapper over the C API is generated by the build process, RNA_blender_cpp.h (55K lines). While this provides a clean interface for C++ code to use the Blender API, it is not a solution to make deep changes to blender.

Unblender removes this restriction, by making Blender's core fully C++. This makes it easy for the user to fork Unblender, and directly integrate C++ at any level: from compiled plugins to, changing the core data types like Object from a struct to a class with custom methods and data.

Blender Forward and Backwards Compatible

Unblender is a hard fork of Blender, and there is no expectation that these changes will ever be merged back into the BF main repo. As a fully independent fork that will continue for years to come, the long term plan is to:

  • blender core c++14
  • stay compatible with Blender2.7
  • merge new code from Blender2.8
  • merge code from the FractureModifier fork
  • stay C compatible as much as possible
  • custom pipeline to Unreal Engine
  • custom pipeline to Unity Engine
  • all new c++ modules are licensed MIT (not GPL)
  • rapid dev cycle bypassing the Blender Foundation

Porting Blender to C++14

Most of Blender's core is written in plain C, and very easy to port to C++, as these commits show, its mostly a matter of removing non-trivial struct initialization (a C99 feature) and some changes to the CMake build: [1] [2] [3] [4]

The C code generated by makesrna is harder to port to be C and C++ compatible, because it uses static structs that are initialized globally, and C allows you to forward declare a struct reference and use it in the initialization of another struct - while C++ only allows you to forward declare a pointer to a struct and use that in the initialization of another struct. These commits begin the work of fixing this problem. [5] [6]

PointerPropertyRNA rna_GroupLogicNode_group = {
 {(PropertyRNA *)&rna_GroupLogicNode_filter_startswith, NULL,
 -1, "group", 8388609, 0, 0, "group pointer",
 0, "*",
 NULL, 318767104, NULL, NULL,
 0, -1, NULL},
 GroupLogicNode_group_get, GroupLogicNode_group_set, NULL, NULL,&RNA_Group

StringPropertyRNA rna_GroupLogicNode_filter_startswith = {
 {NULL, (PropertyRNA *)&rna_GroupLogicNode_group,
 -1, "filter_startswith", 262145, 0, 0, "if starts with",
 "filters group results",
 0, "*",
 NULL, 318767104, NULL, NULL,
 0, -1, NULL},
 GroupLogicNode_filter_startswith_get, GroupLogicNode_filter_startswith_length, GroupLogicNode_filter_startswith_set, NULL, NULL, NULL, 64, ""

Above is an example of C code generated by makesrna, you will notice that the initialization of rna_GroupLogicNode_group begins with taking the address of rna_GroupLogicNode_filter_startswith, and casting it to a pointer of type PropertyRNA, but the definition of rna_GroupLogicNode_filter_startswith comes after. This is valid C code, but not valid C++. The workaround in C++ is to use a forward declared pointer to the struct.

Current Status

In the top level CMakeLists.txt file change set(WITH_CPP_CORE OFF) to set(WITH_CPP_CORE ON). At the moment all the libraries will compile but will fail at the final linker stage, with missing symbol errors from depsgraph and RNA.

No comments:

Post a Comment