Expose cpp-registered datatype to python
-
hi there so i made a custom gui and custom datatype in cpp and i want to use them in a python tag plugin, so i added it in the tag's ".res" file and it's working (i copied the "Dots CustomDataType & CustomGui Example" and tweaked it to my needs) , but i want to access the data type in python source code of the tag plugin so i can initialize some values on the CustomDataType (that will be vizualized in the GeUserArea of the custom gui) when i initialize the python tag, i read in the documentation that maybe i should use "MAXON_DATATYPE_REGISTER_STRUCT" to expose datatype to python but i didn't find examples implementing it, so basically i want a datatype like the BaseContainer that has (SplineData, Gradient, Float) in it .
-
Hello @aghiad322,
Thank you for reaching out to us. Please read our Support Procedures page, especially the section Asking Questions. Your question is very ambiguous, please share code in the future and sufficiently explain what you are doing.
About your Question
In short, it looks like you are not actually implementing the Python bindings for your data type, this cannot work. There is no magic conversion/macro (for classic API types¹) in place which would automatically expose a C++ type and its fields and functions to Python. You will have to implement your data type from the ground up as a C++ binding type using the Python module in our C++ API. How to wrap types in the classic API never has been something we really documented, and we rely there mostly on people "just knowing" how Python/C bindings work in general. We also have a simplification of the usual Python/C bindings code but going into that would go too far here as you have never showed us any code.
In general, it also seems overkill to expose the whole data type to Python. Again, an actual example of what you are doing would have helped here, but when your data type is just a husk for some structured data, you can use component access to expose the components of your structured data, decomposing it into atomic types such as
real
,long
,string
, andbool
; and quasi-atomic types which are decomposable themselves such asVector
,Matrix
, orBaseContainer
. So that you can then do something like this in Python:# We have here a three desc level access. We reach into a custom data type (which could be unexposed to Python) # to get its internal "Up Vector" field. Since this field is of type vector, it is decomposable itself into three floats. myNode[ID_MY_DATATYPE_PARAM, ID_UP_VECTOR, c4d.VECTOR_X] = 42
To do this, you would have to implement CustomDataTypeClass::Get/SetDParameter for your data type. Redshift for example exposes non of its data types to the Python API and instead provides component access for them. Here is an example for how the
Vector
data type does it for its x, y, and z components/channels:Bool GetParameter(const CustomDataType *data, const DescID &id, GeData &t_data, DESCFLAGS_GET &flags) override { Vector *d = (Vector*)data; switch (id[0].id) { case 0: t_data = GeData(*d); flags |= DESCFLAGS_GET::PARAM_GET; break; case VECTOR_X: t_data = GeData(d->x); flags |= DESCFLAGS_GET::PARAM_GET; break; case VECTOR_Y: t_data = GeData(d->y); flags |= DESCFLAGS_GET::PARAM_GET; break; case VECTOR_Z: t_data = GeData(d->z); flags |= DESCFLAGS_GET::PARAM_GET; break; } return true; } Bool SetDParameter(CustomDataType *data, const DescID &id, const GeData &t_data, DESCFLAGS_SET &flags) override { Vector *d = (Vector*)data; switch (id[0].id) { case 0: *d = t_data.GetVector(); flags |= DESCFLAGS_SET::PARAM_SET; break; case VECTOR_X: d->x = t_data.GetFloat(); flags |= DESCFLAGS_SET::PARAM_SET; break; case VECTOR_Y: d->y = t_data.GetFloat(); flags |= DESCFLAGS_SET::PARAM_SET; break; case VECTOR_Z: d->z = t_data.GetFloat(); flags |= DESCFLAGS_SET::PARAM_SET; break; } return true; }
There is a little bit more to this than I showed here, because you have to also handle the description, but that would be subject for a more concrete thread where you share your code.
The disadvantage of the component access is that you cannot wrap any functions on your data type this way, e.g., a
MyType::MakeFancy() -> void
function which is neither a getter or setter but somehow operates on the data of the instance. When you decide to go the full on Python binding way, you should als be aware that:You cannot get-access a custom data type implemented in C++ via the Python bindings because data types are hard-coded in the Python wrapper for
C4DAtom::GetParameter
. When you attempt to do this, Python will complain about an unknown data type. This is exactly what happens for the Redshift data types. The way out of this is providing component access.Cheers,
Ferdinand1 - When you implement a function or type in the maxon API, i.e., as published objects in a registry, you usually do not have to write C++ code to expose them in Python. But you must write Python code. Which is less work, but there is no magic automatism here either.
-
@ferdinand thanks for the reply, all that i'm trying to do is just to link a SplineData parameter "ANIMATION_CLONER_SPLINE" from the python tag to the customGUI that has a datatype "SPLINEVIS" to visualize the spline in the GeUserArea, here is snippet from ".res" file of the python tag
GROUP{ COLUMNS 1; SPLINE ANIMATION_CLONER_SPLINE { ANIM OFF; SHOWGRID_H; SHOWGRID_V; MINSIZE_H 300; MINSIZE_V 180; EDIT_H; EDIT_V; X_MIN 0; X_MAX 1; Y_MIN -1; Y_MAX 1; X_STEPS 0.01; Y_STEPS 0.01; }; SPLINEVIS ANIMATION_CLONER_SPLVIS { ANIM OFF; }; }
and here is the source code of the custom dataType/Gui
splinevis.zip
i want to change the splinedata of "iSplineVisDataType::_spline" , in the code i provided i just initialized it to demonstrate how im using it, but i want this splineData to be initialized from the python tag.
Or if i can have access to the node "BaseTag" that's hosting the customGui so that i can link it's splineData to the customGui ,that would work. -
Hey @aghiad322,
please re-read my answer I have given above. You implement a custom data type in C++, your
SplineVisDataType
insplinevis.h
. Then you reference that data type in a resource of a Python plugin (SPLINEVIS ANIMATION_CLONER_SPLVIS { ANIM OFF; };
). You will not be able to interact with this parameter/data type in Python until you have ported it or use the other approach I have lined out above - decomposition/channels.As also lined out above, you will be never able to get-access a parameter with a custom data type you have implemented yourself in Python because
C4DAtom.GetParameter
hardcodes the casting/unpacking of data types to Python.Cheers,
FerdinandPS: And if you only want another way to display
SplineData
, you can also just write a custom GUI targeting that data type. There is no necessity to always write your own custom data type for a custom GUI, you can also target existing ones. You would then have to set the custom GUI to yours when you define aSPLINE
element in a dialog or description resource