Add functions to python via C++ SDK [R20]
-
In the past we added Coffee functions to allow the users to make some scripts using our plugins, with the deprecation of Coffee we cannot longer support them as we did with
*Coffee cof = GetCoffeeMaster();
cof->AddGlobalFunction("blablabla", (V_CODE)blablabla);Is there any chance to add custom functions to Python in C4d?
Thank you in advance for any help.
-
Hi,
You can add new functions with the C++ API using the Python library defined in frameworks/cinema.frameworksource/c4d_libs/lib_py.h
This header is not documented but it allows to extend and embed Python.I already posted some code snippets and information in this topic.
The posted code mostly compiles in R20 except the enumerations.
Here's the code and corresponding files to add c4d.extendpyapi.HelloPython() Python function adapted for R20:
extendpyapi.h
#ifndef EXTENDPYAPI_H__ #define EXTENDPYAPI_H__ namespace extendpyapi { void InitExtendPython(); void FreeExtendPython(); } #endif
extendpyapi.cpp
#include "extendpyapi.h" #include "lib_py.h" namespace extendpyapi { // Global table of c4d.extendpyapi functions for PythonLibrary::InitModule() static maxon::BaseArray<PythonMethodData>* g_extendpyapi_functions = nullptr; // Prints "Hello from Python!" to the console static _PyObject *ExtendPyAPI_HelloPython(_PyObject *self) { PythonLibrary pylib; ApplicationOutput("Hello from Python!"); return pylib.ReturnPyNone(); } // Initializes c4d.extendpyapi module void InitExtendPyAPI() { PythonLibrary pylib; // Allocates c4d.extendpyapi module functions g_extendpyapi_functions = NewObjClear(maxon::BaseArray<PythonMethodData>); if (g_extendpyapi_functions == nullptr) return; // Initializes c4d.extendpyapi module functions g_extendpyapi_functions->Resize(2); PythonMethodData* moduleFunctions = g_extendpyapi_functions->GetFirst(); moduleFunctions[0].Init("HelloPython", (PyFn)ExtendPyAPI_HelloPython, PYFN_FLAGS::NOARGS, "HelloPython() - Extend Python API"); moduleFunctions[1].Init(String(), nullptr, PYFN_FLAGS::NONE, String()); // Last dummy element! // Initializes c4d.extendpyapi module if (pylib.InitModule("c4d.extendpyapi", moduleFunctions, "Extend Python API")) ApplicationOutput("\'c4d.extendpyapi\' module successfully initialized"); } // Frees the module global function table void FreeExtendPyAPI() { DeleteObj(g_extendpyapi_functions); } }
main.cpp
#include "lib_py.h" #include "extendpyapi.h" ::Bool PluginStart() { return true; } void PluginEnd() { } ::Bool PluginMessage(::Int32 id, void* data) { switch (id) { case C4DPL_PYINITTYPES: { extendpyapi::InitExtendPyAPI(); return true; } case C4DPL_PYFINALIZE: { extendpyapi::FreeExtendPyAPI(); return true; } default: break; } return false; }
Note
ApplicationOutput()
writes to the Default logger in the console and not the Python one.The use of the Python library defined in lib_py.h is not straightforward so do not hesitate to ask any question you may have.
-
How could I add a string parameter to that function? I mean to ExtendPyAPI_HelloPython,
Regards, Víctor
-
Hi Víctor,
To retrieve parameters a function must be initialized with
PYFN_FLAGS::KEYWORDS
. Then usepylib.ParseTupleAndKeywords()
to get the value for each parameter.
The following code shows the implementation of a function which expects a string, an integer and a float:static _PyObject *extendpyapi_PassParameters(_PyObject *self, _PyObject *args, _PyObject *keywords) { PythonLibrary pylib; String str; Int32 integer = 0; Float real = 0.0f; const Char *kwlist[] = {"str", "integer", "real", nullptr}; if (!pylib.ParseTupleAndKeywords(args, keywords, "$if", kwlist, &str, &integer, &real)) return nullptr; if (str.Content()) GePrint("Parameter str: " + str); GePrint("Parameter integer: " + String::IntToString(integer)); GePrint("Parameter real: " + String::FloatToString(real)); return pylib.ReturnPyNone(); } ... moduleFunctions[1].Init("PassParameters", (PyFn)extendpyapi_PassParameters, PYFN_FLAGS::KEYWORDS, "PassParameters() - Extend Python API");