Story of an added controller (how to add a new controller to blender)

Here we are,

and today we are “learning” (better say reverse engineering) how to add a new controller.

I do this small guide to help someone else in case s/he would like to add a new controller, to put on written words what i’ve learned, and because this little project helped me understand a lot of parts of blender code.

Well, let’s start!! (i assume you already set up your environment)

1)As a first step, we want to add the new controller’s sources.
Logically they would need to be inside

blender\source\gameengine\GameLogic

with the name starting with SCA_, but in my case, i needed to use ketsji parts, so i added my controller source into

blender\source\gameengine\Ketsji

and i named them KX_SCA_CLibraryController.

2)After adding the controller source, we need to notify to the game engine that this controller exists! Then open

gameengine/Ketsji/KX_PythonInitTypes.cpp

and add in the include part

#include "KX_SCA_CLibraryController.h"

and near the bottom

PyType_Ready_Attr(dict, KX_SCA_CLibraryController, init_getset);
  1. Ok, now the engine knows that this new controller exists, but we also want this controller to remain saved into the file when we save it and close blender. For this, we need to pass to a more blender specific part: dna.
    Open
blender/makesdna/DNA_controller_types.h

and add

typedef struct bCLibCont {
    char libpath[64];
    char funcname[32];
   int    flag;/* only used for degub now*/
} bCLibCont;

under the python typedef, and

#define CONT_CLIBRARY    8

at the end.

Another think we’ll need to add is

case CONT_CLIBRARY:
        cont->data= MEM_callocN(sizeof(bCLibCont), "clibcont");

at line 281
in

blender/blenkernel/intern/sca.c

to be sure we’ll allocate the memory for out controller

4)We just defined how to save it, but not how it will be saved.
For this we modify

blender/blenloader/intern/writefile.c

adding

        case CONT_CLIBRARY:
            writestruct(wd, DATA, "bCLibCont", 1, cont->data);
            break;

around line 1000.

5)Now the controller can be saved, but how will it be added to the engine? For this, there is

gameengine/Converter/KX_ConvertControllers.cpp

as usual include our new source

#include "KX_SCA_CLibraryController.h"

and add

            case CONT_CLIBRARY:
            {
                bCLibCont* clibcont = (bCLibCont*) bcontr->data;
                KX_SCA_CLibraryController* clctrl = new KX_SCA_CLibraryController(gameobj);
                gamecontroller = clctrl;
                if (clibcont->flag){
                    clctrl->SetDebug(true); /*false by default*/
                    printf("
Debuging \"%s\", module for object %s
	expect worse performance.
", clctrl->GetModulePath().Ptr(), blenderobject->id.name+2);
                }
                clctrl->SetModulePath(STR_String(clibcont->libpath));
                clctrl->SetFunctiontName(STR_String(clibcont->funcname));
                break;
            }

before the Python case.

6)We also need to define all the rna for the controller.
Open

blender/makesrna/intern/rna_controller.c

and add

{CONT_CLIBRARY, "CLIBRARY", 0, "C Library", "C Library"},

@line 45,

case CONT_CLIBRARY:
       return &RNA_CLibraryController;

@line 72,

srna = RNA_def_struct(brna, "CLibraryController", "Controller");
    RNA_def_struct_sdna_from(srna, "bCLibCont", "data");
    RNA_def_struct_ui_text(srna, "C Library Controller", "Controller executing C/C++ extern module function");

    prop= RNA_def_property(srna, "libpath", PROP_STRING, PROP_NONE);
    RNA_def_property_ui_text(prop, "Library Path", "Path to the library. It may be both relative or absolute. You can omit the extension of the file, it will automatically loaded according to the OS");
    RNA_def_property_update(prop, NC_LOGIC, NULL);

    prop= RNA_def_property(srna, "funcname", PROP_STRING, PROP_NONE);
    RNA_def_property_ui_text(prop, "Function Name", "The name of the function to call");
    RNA_def_property_update(prop, NC_LOGIC, NULL);

    prop= RNA_def_property(srna, "use_debug", PROP_BOOLEAN, PROP_NONE);
    RNA_def_property_boolean_sdna(prop, NULL, "flag", CONT_PY_DEBUG);
    RNA_def_property_ui_text(prop, "D", "Continuously reload the module and function from disk for editing external modules without restarting");
    RNA_def_property_update(prop, NC_LOGIC, NULL);

@line 255

7)Everything is ready to go, except for a thing: we don’t have an UI for this controller!!
Open

blender/editors/space_logic/logic_window.c

and add

case CONT_CLIBRARY:
       return "C Library";

@line 664 and

return "Controllers   %t|AND %x0|OR %x1|XOR %x6|NAND %x4|NOR %x5|XNOR %x7|Expression %x2|Python %x3|C Library %x8";
bCLibCont *cc;

@line 1669 under

bPythonCont *pc;

and then add

case CONT_CLIBRARY:
        ysize= 28;
         
        if(cont->data==NULL) init_controller(cont);
        cc= cont->data;
        
        UI_ThemeColor(TH_PANEL);
        glRects(xco, yco-ysize, xco+width, yco);
        uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);

    
        uiBlockBeginAlign(block);

        uiDefBut(block, TEX, 1, "", xco+70,yco-23,(width-70)-25, 19, cc->libpath, 0, 63, 0, 0, "Path to the library. It may be both relative or absolute. You can omit the extension of the file, it will automatically loaded according to the OS");
        uiDefBut(block, TEX, 1, "", xco+70,yco-23,(width-70)-25, 19, cc->funcname, 0, 31, 0, 0, "The name of the function to call");
        uiDefButBitI(block, TOG, CONT_PY_DEBUG, B_REDR, "D", (xco+width)-25, yco-23, 19, 19, &cc->flag, 0, 0, 0, 0, "Continuously reload the module and function from disk for editing external modules without restarting");
        
        uiBlockEndAlign(block);
        
        yco-= ysize;
        break;

at line 1711
As i said, i reverse engineered what to add and what to do not add, simply by searching all the instances of CONT_PYTHON in the source. So, if i understood correctly by moguri, is the old ui code, but since i saw it in the source, i added the modifications too.
This should be the new ui code

static void draw_controller_clibrary(uiLayout *layout, PointerRNA *ptr)
{
    uiLayout *split;
    split = uiLayoutSplit(layout,0.8, 0);
    uiItemR(split, ptr, "libpath", 0, "Library Path", ICON_NONE);
    uiItemR(split, ptr, "use_debug", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
    uiItemR(layout, ptr, "funcname", 0, "Function Name", ICON_NONE);
}

at line 3604 and

        case CONT_CLIBRARY:
            draw_controller_clibrary(box, ptr);
            break;

@ 3631

8)Last of all: compile!
Open

gameengine/Ketsji/CMakeLists.txt

and add KX_SCA_CLibraryController.cpp and KX_SCA_CLibraryController.h with the other sources.

Now generate the new project and compile: it all should go fine!!

Final hints and tips:
1)If you use files written in c in c++, remeber always to include them within extern “C”{ }
2)If you need general informations, like the main path to the actual executable, you can use G(sometimes name maggie). This is in BKE_global.h and BKE_main.h. For example the current file path is in G.main->name

Hope it was useful to you! You can find the the full diff here
http://pastebin.com/CcQJKEBi

For managing to add this i must thank moguri, i really bothered him with my questions! Also kupoman and naz-gul were of help to me! Thanks guys!

I just want to say thank you for your time, writing this down here. It helped me a lot to understand blender source code a bit better.

Some questions to this controller:

  • You can load functions from dynamic liked libraries (dll/so) written in C?
  • this works platform independent?

greetings, moerdn

I’m working right now on a patch that will add the directory for C modules(like the examples in gamekit), so when you compile blender you’ll also compile the bundled modules.
The modules are not cross platform, you’ll need to provide the win and unix module.
This will also make easy to share modules, since you just have to share the patch and who wants to use it just apply it and compile blender.(if you don’t share it like a patch for blender, you would need to share all the sources of blender that need to be linked to… It would be a pain).
The new controller automatically load the right library, so if you put “my_module.dll” and in the directory you put my_module.dll and my_module.so, if you are in win it will load my_module.dll, if you are on unix it will load my_module.so.
Since quite all games are shared different for the win and the unix platform, i don’t think it will be a problem.
Here the patch for the example module.
Right now it raise a linking problem linking the jpeg library.
Here the patch if you want to try
[http://pastebin.com/JhNzaY0X

http://www.mediafire.com/?9265dhr1ucszvt0](http://pastebin.com/JhNzaY0X)
here you can find a module(win32) to try. It just have a bge_func exposed function, that prints “I did it” and return as an error message a simple message.


extern "C" BGE_MODULE_API void bge_func(KX_KetsjiEngine* engine, KX_Scene* scene, KX_GameObject* object, SCA_IController* cont, char *msg)
{
    cout<<"I did it!
";
    strcpy(msg,"Everything gone fine");
}

Makers_F thanks for this, it’s just what was needed.