On 15/07/2016 at 07:13, xxxxxxxx wrote:
Hi!
Sorry for the late reply. It's possible to define new Python functions using the library defined in c4d_libs/lib_py.h
This library definitions are not documented currenly and many are meant for internal use only.
To expose a Python function a new module has to be initialized with PythonLibrary::InitModule().
Here is some code:
// 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;
GePrint("Hello from Python!");
return pylib.ReturnPyNone();
}
// Initializes c4d.extendpyapi module
void InitExtendPython()
{
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_0, String()); // Last dummy element!
// Initializes c4d.extendpyapi module
if (pylib.InitModule("c4d.extendpyapi", moduleFunctions, "Extend Python API"))
GePrint("\'c4d.extendpyapi\' module successfully initialized");
}
// Frees the module global function table
void FreeExtendPython()
{
DeleteObj(g_extendpyapi_functions);
}
InitExtendPython()/FreeExtendPython() have to called from within PluginMessage() C4DPL_PYINITTYPES/C4DPL_PYFINALIZE:
Bool PluginMessage(Int32 id, void* data)
{
case C4DPL_PYINITTYPES:
{
InitExtendPython();
return true;
}
case C4DPL_PYFINALIZE:
{
FreeExtendPython();
return true;
}
return false;
}
To pass basic parameters like string, integer or float use PythonLibrary::ParseTupleAndKeywords() like shown in the following code snippet:
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();
}
If a function accepts parameters pass PYFN_FLAGS_KEYWORDS instead of PYFN_FLAGS_NOARGS for the Init() call.
Finally, to parse a GeData/baselist object use 'G' format:
static _PyObject *extendpyapi_PassBaseList(_PyObject *self, _PyObject *args, _PyObject *keywords)
{
PythonLibrary pylib;
GeData data;
const Char *kwlist[] = {"baselist", nullptr};
if (!pylib.ParseTupleAndKeywords(args, keywords, "G", kwlist, &data))
return nullptr;
if (data.GetType() == DA_ALIASLINK)
{
BaseLink* link = data.GetBaseLink();
if (link == nullptr)
return pylib.ReturnPyNone();
BaseList2D* baseList = link->GetLink(nullptr);
if (baseList == nullptr)
return pylib.ReturnPyNone();
GePrint("Passed baselist: " + baseList->GetName());
}
return pylib.ReturnPyNone();
}