Hey @Gemini,
as I just said, there aren't any, even in the non-public C++ API. When you want to provide a layout, you must save it as a layout file and then load it via LoadFile
.
Cheers,
Ferdinand
Forum wide moderators
Hey @Gemini,
as I just said, there aren't any, even in the non-public C++ API. When you want to provide a layout, you must save it as a layout file and then load it via LoadFile
.
Cheers,
Ferdinand
Hey @ECHekman,
COLORA and VECTOR4D are both Maxon datatypes. For how to deal with custom data types, you can have a look at this. But since this is a maxon data type and not a cinema data type, you cannot use a static_cast. When you do not want to store your maxon data wrapped as data, the only thing which remains is unsafely casting the data (but our style guide recommends using reinterpret_cast
to make the unsafe nature obvious).
const maxon::ColorA* myColor = reinterpret_cast<const maxon::ColorA*>(geData.GetCustomDataTypeI(DTYPE_COLORA));
I had a look and we do this in some UI related places too, so this might be a side effect of the 2024 changes to data types in relation to that specific custom gui.
Cheers,
Ferdinand
Hey,
I appreciate you separating questions But there is code for this exact question in the old thread:
https://developers.maxon.net/forum/topic/15823/data-datatypes-python-and-gui/2.
You must wrap the Data
as GeData
. One can of course play pointer games, as with pretty much everything, Cinema API types are usually just Maxon API types in disguise, but I would not recommend that. GeData
, i.e., a BaseContainer
, cannot store Data
directly.
Cheers,
Ferdinand
Hey @Gemini,
Thank you for reaching out to us. Please have a look at Programmatically create a palette?. The TLDR is: There is no API for interacting with palettes, even internally we do not dynamically inject things into palettes (except for a few special cases) and instead rely on layout files.
Cheers,
Ferdinand
Hey @ECHekman,
you are right, IntVector32
has been wrapped by Maxime, my bad. Regarding being a new specialization or not, I guess that depends a bit on the perspective. IntVector32
is an alias for a specialization of Vec3
.
And what I was hinting at, is that when you define your own specialization, as I did above for my bool vector example BoolVec3
, the Python API won't automatically know how to deal with it (although it knows what a Vec3
is). But you can wrap a data type relatively easily with pure Python code yourself (check out {C4D}\resource\modules\python\libs\python311\maxon
and the files vec
, vec4
, and vector
). To then use that type you would have to either put that binding into each script, import the binding from a module in each script, or make it so that your plugin puts it into \python311\_maxon_init
so that it is automatically exposed in the maxon package (please be careful with patching a users __init__.py
, as it could be customized, so you cannot blindly overwrite that file).
Regarding the rest, I already lined out your options above. Maybe I am still misunderstanding you, but you cannot use a Maxon datatype as a parameter, nor can you implement your own Cinema datatype and have the Python API understand it (1). As lined out above, the best option for you is likely writing a custom GUI which emulates 2, 3, or 4 component integer vector type and sits on top of the existing data type Vector4D.
Regarding your concerns about precsion: The error in a Float64
(the underlying component type of Vector
/DYTPE_VECTOR
) becomes larger than 1 when the value exceeds 2^53
. That is outside of the interval [-2^31, 2^31 - 1]
of Int32
.
Regarding the 'UI working for maxon::IntVector32': I can only speculate what you are doing there, my assumption would be that you probably have some form of dynamic description and shove that IntVector32
into the data container of the node. Feel free to expore this route, but that is not supported. (Cinema API) Descriptions must be composed out of Cinema API datatypes. The interpolation issues you encounter are like tied to how CKey::Set/GetValue
and CKey::Set/GetData
work and the API then getting confused about the datatype in the data container of the scene element which does not conform to a registered DTYPE_
(or on point, it likely treats your values as data although they are values).
To stress it gain, a custom GUI which wraps arround Vector4D
is porbably what you want to do here. If this is not a fit, please share concrete code and a concrete usage scneario, as we won't get anywhere otherwise.
Cheers,
Ferdinand
(1) With the exception of data types which are decomposable into channels, e.g., what DTYPE_VECTOR
does and many datatypes in Redshift do. So, you would then end up with a custom datatype DTYPE_FOO
and the Python API would still have no clue what to with it when the user calls myNode[c4d.FOO_PARAMETER]
and then raise an error. But when your data type is decomposable into known types (three DTYPE_LONG
in your case), the user could call myNode[c4d.FOO_PARAMETER, c4d.VECTOR_X]
to directly access the x-component of it.
Hello @Gregor-M,
when you have a problem with bit depths, please open a new thread. This is now a bug thread and we should keep it clean.
What I forgot to mention here is that there is one way to sort of fix this right now for you. There is an undocumented flag named RDATA_BAKE_OCIO_VIEW_TRANSFORM_RENDER
on the render data (not the same as RDATA_BAKE_OCIO_VIEW_TRANSFORM
which is exposed in the UI tto the user). With that you can bake the full transform chain into the bitmap. Such bitmap will then be displayed correctly in the PV. But when you save it to disk, it will be "incorrect", as it got the view and display transform baked into it (which is usually not what you want).
But it could be an option if you only volatiely render documents for displaying purposes only or are okay with rendering things twice (once with the flag for displaying, and once without it for saving). But that is of course very much a hack why we will fix this.
Cheers,
Ferdinand
Hey @Mats,
Thank you for reaching out to us. Is it intentional that you posted in General Talk? Because this strikes me more as an API question; although very broad in scope, which might be why you posted here.
What to use depends a bit on your goals. Graph descriptions are currently most geared towards creating new graphs from scratch. But with graph queries you can also modify existing graphs. Graph descriptions are still actively being developed, for 2025.0.0, when the docs only contained the change note about having fixed varidaic port handling I actually implemented much more, but that is currently all undocumented.
Documenting this is in my backlog, and planned for the upcoming release. Generally speaking graph descriptions are also not a new way, and the Nodes API an old way. Graph descriptions are just a more streamlined way to interact with nodes graphs (something like handling variadic ports or the undocumented node commands can either be quite complicated or outright impossible in the Python Nodes API).
But generally remains the fact that the Nodes API is the 'true' API which always will be more powerful (at least to the extent it has been wrapped for Python). My suggestion would be either to ask a concrete question what you want to do, or wait for the 2025.1 docs which are not far away. I will then have hopfeully found the time to document the new features and add some examples.
Cheers,
Ferdinand
Hey @T1001,
yes, you are on the right track there, to initialize an image as RGBA F32, you would do something like this:
static const Int32 size = 1024;
const ImageRef image = ImageClasses::IMAGE().Create() iferr_return;
const maxon::ColorProfile profile = ColorSpaces::RGBspace().GetDefaultNonlinearColorProfile();
const PixelFormat format = PixelFormats::RGBA::F32();
const Int32 channelCount = format.GetChannelCount();
// Init the bitmap with its size, storage convention, and pixel format. Whe choose here the
// "normal", i.e., consecutive layout. An alternative would be a planar layout.
image.Init(size, size, ImagePixelStorageClasses::Normal(), format) iferr_return;
image.Set(IMAGEPROPERTIES::IMAGE::COLORPROFILE, profile) iferr_return;
Regarding the rest, I roughly cover this in my example. A little GeUserArea which wraps around some render buffer data. I rather not yet share it here, as it "misbehaves" still in one aspect, and I am not sure if that is my or the API's fault (will have to catch one of the Image API devs for that).
You can also have a look at the Color Management and OCIO manual as I covered there quite a bit of pixel format and buffer handling subjects. Last but not least regarding hardware acceleration: The Image API does not have much drawing functions, that is primarily done in the semi-public Drawport API. It depends a bit on what you want to accelerate, filling a buffer cannot be accelerated, you either fill things row by row, or just wrap around some existing memory.
When you need hardware accelerated drawing functions like drawing a circle, etc., then you indeed must use the Drawport API. To get access to it as an external, you would have to apply for Maxon Registered Developer membership, as this would also grant access to the semi-public Drawport API. As its name implies, the Drawport API is the API with wich viewports are drawn in Cinema 4D. You might be familar with BaseDraw
, the Cinema API type which is used to draw into view ports. Similar to how you can get an ImageRef
from a BaseBitmap
, you can get a DrawPortRef
from a BaseDraw
. Under the hood, draw ports are also used to draw into bitmaps, and there is also a mechanism with which one can attach a draw port to a dialog (a draw port user area).
But not all parts of the Drawport API are semi-public, some are fully private. I would first have to check, if the bitmap drawing part is semi-public and I know for a fact that the user area is not semi-public (but we wanted to expose it at some point but I think it never happend).
So, long story short, when you think you need all that, I would recommend reaching out via our contact form or directly apply for registered developer membership.
Cheers,
Ferdinand
Hello @ECHekman,
please read my answer I have given above.
- You can store pretty much anything in a
BaseContainer
since you can store there raw memory. Because you can storemaxon::Data
, this also means you can store a wide range of Maxon API data types without getting hacky with raw memory.- The Python API understands
maxon::Data
and knows things likemaxon::Vec3
, but you when you define a new template specialization, it obviously won't know what to do with that. Stuff likeIntVector32
is not wrapped for Python.- You usually only need a custom data type and GUI when you want to use that data type as a parameter in a node. E.g., have a shader which has a parameter Enabled which is of type
BoolVector3
. When you implement a new custom data type, you must always implement a custom GUI (but a new custom GUI can sit on top of an existing data type).- Python won't know what to do with that data type. When you try call
MyNode.GetParameter()
on that parameter, Python will throw an error.Bottom line is here, you cannot implement a new data type and have the Python API magically understand it. You could:
- Ship you own Python bindings for that data type.
- Just implement a custom GUI which makes a Vector4d act like an integer 2, 3, or 4 vector. (That is in fact what the Vector2D custom gui is doing with Vector).
You neither can just have magically a GUI manifest for some data type, nor can you use maxon::Data
as a parameter type directly. As I stated in my previous answer, when you want to use your new data type(s) as parameter(s) types - opposed to just storing them in the data container of the node - you will have to implement a custom data type and GUI for them. But the Python API will then not be able to deal with such data types (unless you make them decomposable into existing data types - which would be possible in your case).
Cheers,
Ferdinand