How to expose an object function done in C++
-
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(); }
-
On 15/07/2016 at 10:15, xxxxxxxx wrote:
Howdy,
Wow, thanks Yannick!
I've been working on making aspects of my plugins scriptable through cofffee and wanted to included python scriptability, too. This gives me a place to start.
Adios,
Cactus Dan -
On 28/07/2016 at 16:15, xxxxxxxx wrote:
Howdy,
OK, I got the passing a BaseList as a prameter with the "G" format, but suppose I want to pass both a BaseList and an interger or real in the same function? How would that be formatted?
Adios,
Cactus Dan -
On 29/07/2016 at 02:37, xxxxxxxx wrote:
Originally posted by xxxxxxxx
OK, I got the passing a BaseList as a prameter with the "G" format, but suppose I want to pass both a BaseList and an interger or real in the same function? How would that be formatted?
Like the argument parsing in the function example extendpyapi_PassParameters() I posted above, concatenate the characters for each parameter.
For instance:GeData data; Int32 integer = 0; Float real = 0.0f; const Char *kwlist[] = {"baselist", "integer", "real", nullptr}; if (!pylib.ParseTupleAndKeywords(args, keywords, "Gif", kwlist, &data, &integer, &real)) return nullptr;
-
On 29/07/2016 at 04:53, xxxxxxxx wrote:
Howdy,
DOH! It's the strings that always throw me off when they're used for anything other than printing.
But I get it now:
"$" = string format
"i" = integer format
"f" = float format
"G" = GeData formatPossibly if the example had the float first like "$fi" then I might have been able to figure that out. But, with it the other way around, no matter how many times I looked at it, I still saw the word "if", and got confused.
Thanks for the clarification.
Adios,
Cactus Dan -
On 29/07/2016 at 05:53, xxxxxxxx wrote:
You're welcome
"C" can also be used to parse BaseContainer* too (note only pointer to BaseContainer, initialize with nullptr before calling ParseTupleAndKeywords()).
-
On 29/07/2016 at 06:07, xxxxxxxx wrote:
Howdy,
Thanks. Is there a complete list of formatting letters that you could post?
Also, is there a way to add global symbols in python like in coffee, and if so, can you post an example?
Adios,
Cactus Dan -
On 26/04/2017 at 00:05, xxxxxxxx wrote:
Hello,
I know this is a bit older topic but the last question from Cactus Dan was not answered and I also need it. Especially I need to transfer BaseObject to and from python script.
So again, we just need a table of all formatting letters and types that Cinema python binding API uses.
Just for completeness, python build-in formatting letters seems to work and are available here: https://docs.python.org/2.7/c-api/arg.html?highlight=parsetupleandkeywords#c.PyArg_ParseTupleAndKeywords
-
On 26/04/2017 at 02:38, xxxxxxxx wrote:
Hi Miro,
Originally posted by xxxxxxxx
I know this is a bit older topic but the last question from Cactus Dan was not answered and I also need it. Especially I need to transfer BaseObject to and from python script.
To parse a BaseList based object, use 'G' format character as show in my above code snippet's function extendpyapi_PassBaseList(). The object can be casted to the most interesting type after retrieving it.
Originally posted by xxxxxxxx
So again, we just need a table of all formatting letters and types that Cinema python binding API uses.
PythonLibrary::ParseTupleAndKeywords() accepts the following format characters for Cinema 4D C++ API classes:
- $: String
- %: Filename
- M: Matrix
- V: Vector
- Q: Quaternion
- BaseContainer*
- G: GeData (versatile: can parse a BaseList, a custom data, a time, etc.)
- T: BaseTime
- X: BaseThreadOriginally posted by xxxxxxxx
Just for completeness, python build-in formatting letters seems to work and are available here: https://docs.python.org/2.7/c-api/arg.html?highlight=parsetupleandkeywords#c.PyArg_ParseTupleAndKeywords
PythonLibrary::ParseTupleAndKeywords()also accepts the following standard format characters: b, B, j, h, i, I, v, l, L, r, f, d, c
-
On 27/04/2017 at 23:34, xxxxxxxx wrote:
That's perfect! Thank you.
-
On 24/09/2017 at 13:07, xxxxxxxx wrote:
Hello all,
It seems to be that i's only possible to make a python extension library as a plugin. Which plugin then is best suited? A command plugin, I would guess, or is there another plugin that loads completely automatic at startup?
I need something that is always available, so that I don't have to think about loading the library. Much like the c++ example here: page_creating_libraries.html
Regards,
Hermen
-
On 25/09/2017 at 01:29, xxxxxxxx wrote:
Hello,
a "_ plugin_" is just a custom module loaded by Cinema. So a "plugin" does not need to include anything e.g. a command data extension. You only have to implement PluginStart()/PluginMessage()/PluginEnd(), see Plugin Functions Manual. In such a PluginMessage () function you have to register your Python extension as shown above.
best wishes,
Sebastian -
On 25/09/2017 at 02:53, xxxxxxxx wrote:
Aha!
Now I understand, thanks for clearing that up!regards,
Hermen