Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. ECHekman
    3. Topics
    E
    • Profile
    • Following 0
    • Followers 0
    • Topics 19
    • Posts 41
    • Best 3
    • Controversial 0
    • Groups 0

    Topics created by ECHekman

    • E

      Getting an effective value of an enum from a GraphNode

      Cinema 4D SDK
      • c++ 2025 • • ECHekman
      6
      0
      Votes
      6
      Posts
      145
      Views

      ferdinandF

      Hey @ECHekman,

      I sense there is some frustration, but I am not sure telling us how bad our API is will get us anywhere. Yes, the Nodes API ist not trivial, but you are only on the using part (which is not that hard to understand) not the implementation part (which is the trickly one). There are multiple render engine vendors who took that hurdle. I already answered your questions, and as always you will not see source code from us, unless you give us executable code in the first place upon which we can build, or we deem a subject new.

      I often bend these rules a bit where it makes sense to meet our customers and third parties halfway. But you cannot just throw a snippet at us and then expect us to invent everything around it and then fix that for you. Executable code makes a difference as lined out in our support procedures. My hunch would be that your getConnectedNode does not work because you do not check if your nodes are valid.

      You can get the value of a port with GetPortValue or GetEffectivePortValue. What you are doing with GetValue and EffectivePortValue is the old way but will still work.

      // Redshift expresses a lot of its enums as strings and not as ints (did not check if that is here the case). const String value = myPort.GetEffectivePortValue<String>().GetOrDefault() iferr_return;

      And as lined out before, what your function is trying to do, can likely be done via GraphModelHelper too, e.g., with GraphModelHelper::GetDirectPredecessors. An alternative and more manual approach would be using GraphNode.GetInnerNodes and GraphNode.GetConnections.

      And as always, I am not really looking for a discussion about what you or I would consider a good API. I am telling you that you will be in a world of hurt when you terminate your errors everywhere as you did in your code. Your code will then just silently fail without you knowing why. So, I gave you an example on how to use our error handling.

      Cheers,
      Ferdinand

    • E

      Userarea keyboard focus issues in 2025.3

      Bugs
      • 2025 c++ • • ECHekman
      5
      0
      Votes
      5
      Posts
      213
      Views

      ferdinandF

      Hey @ECHekman,

      you can find our general answer here.

      This is unfortunately an unintended regression caused by an intentional bugfix, not taking API stability into account. The flag USERAREAFLAGS::HANDLEFOCUS is meant to signal if a user area is focusable or not. But before user areas were always focusable, as this flag was erroneously being ignored.

      We then 'fixed' this, causing the chain of events. The in detail logic is then that some types of events are not possible for non-focusable gadgets, as for example keyboard events. I will touch up the docs a bit in that area, as things are indeed a bit thin there. But the doc changes will probably not make it into the next release, given how close it is, unless I patch them in there manually.

      So, long story short, compiling with USERAREAFLAGS::HANDLEFOCUS against the 2025.0.0 SDK will result in a binary that will be compatible with all versions of 2025, you did the right thing.

      Cheers,
      Ferdinand

    • E

      Getting debugbreak in atom.cpp

      Cinema 4D SDK
      • c++ 2025 • • ECHekman
      2
      0
      Votes
      2
      Posts
      234
      Views

      ferdinandF

      Hey @ECHekman,

      Thank you for reaching out to us.

      @ECHekman said in Getting debugbreak in atom.cpp:

      Here is how i create the UI

      // in MyData::GetDDescription() BaseContainer bc = GetCustomDataTypeDefault(DA_CONTAINER); bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_OCIOCYCLE); bc.SetString(DESC_NAME, String(pinInfo->mStaticLabel)); bc.SetBool(DESC_SCALEH, TRUE); description->SetParameter(IDCopy, bc, groupID);

      That, the GetCustomDataTypeDefault(DA_CONTAINER) call, is illegal code. Check our documentation for the function. It could probably be put a bit more verbosely into the docstring, but:

      cb400f4a-9cf9-43eb-83b2-0bd37b7127f8-image.png

      DA_CONTAINER is not a resource data type. Which is a fancy way of saying that a C4DAtom parameter cannot be of data type DA_CONTAINER. On line 439 in atom.cpp is no crit stop (at least in the version of atom.cpp for 2025.2.x.yyyyyy I looked at), but on line 476 there is. This is inside C4DAtom::SetParameter, and it gets there the ID of the parameter container of the description element which shall be written, then switches through all the atomic DTYPE_ and when none matches, calls at the end FindResourceDataTypePlugin() on the ID of the parameter container, i.e., what you initialized as DA_CONTAINER. When it cannot find anything there, it raises the crit stop.

      When you want to have there some OCIO data bundle, you probably should also implement a data type for it. Otherwise you should try DTYPE_SUBCONTAINER. But I am not sure how nicely DTYPE_SUBCONTAINER will play with custom GUIs. In general I would lean towards that writing a container as a singular parameter with a GUI like this is not intended, but you can try your luck. What will work in any case, is implementing your own data type.

      And to be verbose, a resource data type is a data type that can be used in resources, i.e., res files.

      Cheers,
      Ferdinand

    • E

      GeDialog ColorChooser Color + Alpha

      Cinema 4D SDK
      • c++ • • ECHekman
      4
      0
      Votes
      4
      Posts
      589
      Views

      ferdinandF

      Hey @ECHekman,

      well, I was talking about User Data, as they can be a nice way to inspect what data types and their custom GUIs can do.

      c72e5dab-e512-48cb-8333-95ccee722325-image.png

      For what you want to do, this will however not help, as there are only the description settings listed, which necessarily do not have to be all settings there are. To start with an expanded GUI, you must set LAYOUTMODE_MAXIMIZED. I think the little toggle arrows are not supported in dialogs, but I might be wrong. When you want to know more about the little toggle arrow, I would suggest to write us a mail, so that I can forward it to a GUI specialist, as I do not know if and how you could make the arrow work.

      This is one of the cases how we internally setup such GUI in a dialog, maybe this already helps (but there are many, and they are not all the same). The a bit odd looking SetInt32('abcd', value)` thing, where we express an Int32 ID as four chars is something we sometimes do internally. Some people find it apparently easier to read/handle than symbols. It often also means that there is no proper integer value and symbol for that ID.

      void MyDialog::AddColorAlphaChooser(Int32 id, Int32 flags, Int32 layoutFlags) { BaseContainer colorUISettings = GetCustomDataTypeDefault(DTYPE_COLORA); colorUISettings.SetInt32(CUSTOMGUI_LAYOUTMODE, LAYOUTMODE_MAXIMIZED); colorUISettings.SetInt32('iccc', layoutFlags & (DR_COLORFIELD_ICC_BPTEX | DR_COLORFIELD_ICC_BASEDOC)); colorUISettings.SetInt32('cfld', layoutFlags); AddCustomGui(id, CUSTOMGUI_COLOR, String(), flags, 0, 0, colorUISettings); }

      Cheers,
      Ferdinand

    • E

      How to expose C++ symbols to Python users as a third party?

      General Talk
      • • • ECHekman
      5
      0
      Votes
      5
      Posts
      925
      Views

      M

      Hi @ECHekman sorry it took me more time than I expected. From my meory octane already have a Python module registered in C++. So I assume you want to add symbols to this python module.

      One important aspect is that the Symbol Parser by itself is completly agnostic of the c4d module therefor you can call it with any Python interpreter. This point is really important because this let you parse your C++ header files whenever you want within your build pipeline.

      With that's said the Symbol Parser is bundled within the mxutils package which needs the c4d and maxon module.
      So in order to have it running with any python intepreter you will need to do the following:

      import sys CI_PROJECT_DIR = r"C:\Users\m_adam.INTERN\Documents\MAXON\gitlab\c4d" # Build path to import the parser_symbol maxon_python_path = os.path.join(CI_PROJECT_DIR, "resource", "modules", "python", "libs") if not os.path.exists(maxon_python_path): raise RuntimeError(f"DEBUG: update_python_symbols - Unable to find {maxon_python_path}") # Get python311 folder where the symbol parser is located mxutils_path, symbol_parser_path = None, None for folder in os.listdir(maxon_python_path): full_path_folder = os.path.join(maxon_python_path, folder) if not os.path.isdir(full_path_folder): continue # We found the mxutils module containing the symbol parser. if os.path.exists(os.path.join(full_path_folder, "mxutils", "symbol_parser")): mxutils_path = os.path.join(full_path_folder, "mxutils") symbol_parser_path = os.path.join(mxutils_path, "symbol_parser") if None in (mxutils_path, symbol_parser_path): raise ImportError(f"Could not find 'symbol_parser' module path in {maxon_python_path}.") sys.path.append(mxutils_path) print(f"DEBUG: Added {mxutils_path} to sys.path.") # Import the symbol parser and do your stuff. import symbol_parser # Do something with it sys.path.remove(mxutils_path)

      Then the Symbol Parser paradigm is that you first parse your data and then the parser contain Scope that contains member (a name and a value).
      Therefor once you have parsed your data you can freely output to multiple format if needed. You can also write your own format if you want to.
      In this case because you are using mostly the Cinema API and not the Maxon API I re-use the same output as the one we use for the c4d Python package.
      This output is implemented in c4d\resource\modules\python\libs\python311\mxutils\symbol_parser\output_classic_api.py. Everything in the Symbol Parser is open source so feel free to look at it.

      So to get back to your question find bellow the next code that will parse all the resources files from the Redshift folder and insert them within the "redshift" Python Package. (You usually do not have to do that because Python is parsing automatically the c4d_symbols.h and include such symbols within the c4d Python package this is for the example). With that's said there is basically two ways, one hardcoding the parsed value in your C++ plugin when you register your Python module, the second one using a Python file that will get loaded at the startup of Cinema 4D once your Python module is already loaded and therefor inject symbol into your module.

      import os import c4d # Only used to retrieve various C4D paths used in this example, but not really necessary otherwise # These imports bellow are not bound to the c4d module therefor they can be used with a standard Python3 interpreter # But this code is written to be executed in the Script Manager, so you may need to adapt the import statement according to how you run this script. from mxutils.symbol_parser.extractor import SymbolParser from mxutils.symbol_parser.output_classic_api import _get_symbol_dict_from_parser def ParseRedshiftResources() -> SymbolParser: # Parse all Redshift ressource files and resolve their values rsDir = os.path.join(os.path.dirname(c4d.storage.GeGetStartupApplication()), "Redshift", "res", "description") parser = SymbolParser(rsDir, parse_mx_attribute=False, parse_define=True, parse_enum=True, parse_static_const=True) # Parse and resolve. Resolve means: # - Transfrom values that depends to others to their actual integer or float values. # - Transform complex values (such as bit mask, arithmetic, etc) into their actual integer or float values. # For more information about what is supported take a look at # https://developers.maxon.net/docs/py/2025_2_0/manuals/manual_py_symbols.html?highlight=symbol%20parser#symbols-parser-features parser.parse_all_files(resolve=True) return parser def OutputPythonFile(parser: SymbolParser): def GeneratePythonFileToBeInjected(parser: SymbolParser) -> str: """Generate a Python file that will inject all parsed symbols into the 'redshift' Python package when this file get imported. This function needs to be called once, most likely during your build pipeline. Once you have generated this Python file you should bundle it with your installer and then install it in the targeted Cinema 4D installation. See PatchCurrentC4DToInjectParsedSymbol for an example of such deployment """ import tempfile tempPath = None # Retrieve a sorted dict containing the symbol name as key and it's value as values # This will flatten all scopes so an enums called SOMETHING with a value FOO in it will result in a symbol named SOMETHING_FOO # If you do not want this behavior feel free to create your own solution, this function is public and declared in # c4d\resource\modules\Python\libs\python311\mxutils\symbol_parser\output_classic_api.py symbolTable = _get_symbol_dict_from_parser(parser) with tempfile.NamedTemporaryFile('w', delete=False) as tmpFile: tempPath = tmpFile.name tmpFile.write("import redshift\n") for name, value in symbolTable.items(): tmpFile.write(f"redshift.{name} = {value}\n") if not os.path.exists(tempPath): raise RunTimeError('Failed to create the Python File to Inject Symbols in "redshift" Python Package') return tempPath def PatchCurrentC4DToInjectParsedSymbol(fileToBeLoaded: str): """This function is going to create a Python file that is going to be called at each startup of Cinema 4D to inject symbols into the "redshift" Python package. This is done by placing the previous file in a place where it can be imported by the C4D Python VM. And by importing this file by editing the python_init.py file located in the preferences. For more information about it please read https://developers.maxon.net/docs/py/2025_2_0/manuals/manual_py_libraries.html?highlight=librarie#executing-code-with-Python-init-py """ import sys import shutil # Pref folder that contains a python_init.py that is laoded once c4d and maxon package is loaded and a libs folder that is part of the sys.path of the c4d Python VM. pyTempDirPath = os.path.join(c4d.storage.GeGetStartupWritePath(), f"Python{sys.version_info.major}{sys.version_info.minor}") # Path to our module that will inject the parsed symbols in the "redshift" Python package pyTempRsDirPath = os.path.join(pyTempDirPath, "libs", "rs_symbols") # Path to the __init__ file of our module that will be called when we import our module # we need to place the file we generated previously in this location. pyTempRsFilePath = os.path.join(pyTempDirPath, "libs", "rs_symbols", "__init__.py") if not os.path.exists(pyTempRsDirPath): os.mkdir(pyTempRsDirPath) if os.path.exists(pyTempRsFilePath): os.remove(pyTempRsFilePath) shutil.copy2(fileToBeLoaded, pyTempRsFilePath) # Now that we have our module that will inject symbols within the "redshift" Python package. We need to get this "rs_symbols" module be called at each startup. # So we use the python_init.py file to get loaded once all plugins are loaded. Therefor the Redshift plugin is already loaded and have already setup its "redshift" Python package. # We will inject a line in this file to load our "rs_symbols" module pyTempInitFilePath = os.path.join(pyTempDirPath, "python_init.py") isImportRsSymbolPresent = False initFileExist = os.path.exists(pyTempInitFilePath) # Because this file me be already present and already patched or contain other content # We should first check if we need to add our import or not if initFileExist: with open(pyTempInitFilePath, 'r') as f: isImportRsSymbolPresent = "import rs_symbols" in f.read() # prepend our import statement to the file if not isImportRsSymbolPresent: with open(pyTempInitFilePath, "w+") as f: content = f.read() f.seek(0, 0) f.write('import rs_symbols\n' + content) pythonFileGeneratedPath = GeneratePythonFileToBeInjected(parser) PatchCurrentC4DToInjectParsedSymbol(pythonFileGeneratedPath) def OutputCppFile(parser): # Retrieve a sorted dict containing the symbol name as key and it's value as values # This will flatten all scope so an enums called SOMETHING with a value FOO in it will result in a symbol named SOMETHING_FOO # If you do not want this behavior feel free to create your own solution, this function is public and declared in # c4d\resource\modules\Python\libs\python311\mxutils\symbol_parser\output_classic_api.py symbolTable = _get_symbol_dict_from_parser(parser) contentToPaste = 'auto mod_rs = lib.CPyImport_ImportModule("redshift");\n' contentToPaste += 'auto modDict = lib.CPyModule_GetDict(mod_rs);\n' for name, value in symbolTable.items(): contentToPaste += f'\nauto name = lib.CPyUnicode_FromString("{name}");\n' contentToPaste += 'if (!name)\n' contentToPaste += ' CPyErr_Print();\n' contentToPaste += f'maxon::py::CPyRef value = lib.CPyLong_FromInt32({value});\n' contentToPaste += 'if (!value)\n' contentToPaste += ' CPyErr_Print();\n' contentToPaste += 'if (!lib.CPyDict_SetItem(modDict, name, value))\n' contentToPaste += ' CPyErr_Print();\n' return contentToPaste def main() -> None: # Parse the Redshift resources and return the parser that hold the parsed values parser = ParseRedshiftResources() # First way: Generate a file that patch the current C4D with a Python file that you need to deploy on the installer. You may prefer this option since you can update this file without having to recompile your plugin. OutputPythonFile(parser) # Second way: Output pseudo C++ code that can be pasted within your C++ plugin after you initialize your custom Python module. You may want to call this whole script before you compile in your build pipeline and put the "cppContent" within a file that will get compiled automatically cppContent = OutputCppFile(parser) if __name__ == '__main__': main()

      So the system is really modular and being able to run on a regular Python interpreter let you integrate it within your build pipeline to suits your needs.
      If you have any questions, please let me know.
      Cheers,
      Maxime.

    • E

      Links on Tag are not animated when in Extrude Object cache

      Cinema 4D SDK
      • c++ • • ECHekman
      3
      0
      Votes
      3
      Posts
      414
      Views

      E

      Thanks Ferdinand, that was kind of what I expected the awnser to be. I'll use a creative solution that doesnt trigger an unnessesary recreation of the Extrude cache

    • E

      GUI shows M (meters) instead of CM (centimeters) in CUSTOMGUI_VECTOR

      Cinema 4D SDK
      • c++ • • ECHekman
      4
      0
      Votes
      4
      Posts
      532
      Views

      ferdinandF

      Hey,

      it seems I was a bit too tightlipped here. So in more verbose: You cannot customize the chosen unit of a parameter. This is impossible as this is a globally set value (which is also just smoke and mirrors as explained in the link above). There is a UnitScale custom GUI but it does not what you want, it is the field used in the document settings and is not really meant to store a value and unit but just a unit.

      image.png

      When you really-really-really want this, you can implement you own custom GUI, either targeting your own custom data types or existing data types. There you could then do whatever you want. But that might not mesh so well with the rest of Cinema 4D, given that Cinema 4D does not operate like that.

      Cheers,
      Ferdinand

    • E

      Start CUSTOMGUI_LINKBOX expanded

      Cinema 4D SDK
      • c++ • • ECHekman
      2
      0
      Votes
      2
      Posts
      387
      Views

      ferdinandF

      Hey @ECHekman,

      thank you for reaching out to us. This GUI does not support any of these flags (DESC_DEFAULT, i.e., DEFAULT is also not for gadgets but groups).

      This means that you cannot toggle the collapsed state of a link box (be it a normal one or a texture one) by setting a description flag either in a resource file or programmatically. Which makes sense, because other than for example a color field or a group, a link box is not guaranteed to have content which could be unfolded.

      Cheers,
      Ferdinand

    • E

      GeListNode from ShaderData::Read function does not have a document?

      Cinema 4D SDK
      • c++ • • ECHekman
      3
      0
      Votes
      3
      Posts
      451
      Views

      M

      Hi,
      yes, this is expected, and documented in NodeData::Read() / NodeData::Write() Manual. With that's said Read/Write is supposed to serialize data of your object (most of the time member variable) to the c4d file (the HyperFile), so accessing the BaseDocument is a sign of a bad design.

      May I ask why do you really want to access the BaseDocument in the Read function?

      Cheers,
      Maxime

      edit (@ferdinand): Just to be clear here, as we briefly talked about this in our morning meeting, what the docs write there is in a certain sense legacy information. When a branch, e.g., the Xbase (shader) branch of a material is being deserialized, the to be deserialized node is inserted into the branch and with that will have access to a document.

      But what @m_adam wrote is of course true, the document in this context is the fruit from the forbidden tree, as the node is not yet fully deserialized and certain parts of the GeListHead::Read, GeListNode::Read, BaseList2D::Read, ..., YourPluginLayer::Read deserialization chain might pull all sorts of tricks to carry out the deserialization, including temporarily removing the node from the scene graph.

      The documentation is therefore effectively still correct, as deserializing a node should never rely on the document context and accessing the document is forbidden in that context.

    • E

      Strange string addition crash

      Cinema 4D SDK
      • r21 c++ windows • • ECHekman
      3
      0
      Votes
      3
      Posts
      355
      Views

      E

      Thanks for your response. We found the issue. Turns out we had to delay load our dlls for earlier versions of the plugin R21 etc

    • E

      SubContainers and Symbol ranges

      Cinema 4D SDK
      • c++ • • ECHekman
      5
      0
      Votes
      5
      Posts
      406
      Views

      ferdinandF

      Hey @ECHekman,

      I assume you are looking here for some kind of approval from my side? That looks fine, but it is hard to give a concrete assessment with mock code. But as lined out above, there is little which can go wrong here. Splitting up your data into sub-containers could help with access times when you plan to add lots of 'attributes' and 'pins'. So, it is good that you do that. And shifting your application IDs into lower ranges for Cinema 4D is probably not technically necessary but will lead to more 'natural' IDs. I cannot really see much going wrong here.

      The only thing which is not so nice, is the unsafe C-style cast in BaseContainer *data = ((BaseShader*)node)->GetDataInstance();. We recommend using static_cast for safe casts and reinterpret_cast for casts which are explicitly meant to be unsafe.

      Cheers,
      Ferdinand

    • E

      How to use String::Split

      Cinema 4D SDK
      • c++ • • ECHekman
      2
      0
      Votes
      2
      Posts
      266
      Views

      ferdinandF

      Hello @ECHekman,

      Thank you for reaching out to us. When you run into compiler errors, you should always include them, because how should we otherwise help you? Sure, I could throw your code into our code base, guess some things, and then try to compile it, but the guessing and compiling is unnecessary and makes our answers more imprecise.

      But this should work:

      iferr_scope; maxon::String myString = "Hello/World"_s; maxon::BaseArray<maxon::String> parts; // could also be const myString.Split("/"_s, true, parts) iferr_return; if (MAXON_UNLIKELY(parts.GetCount() < 1)) return maxon::IllegalStateError(MAXON_SOURCE_LOCATION, "Splitting path failed."_s);

      FYI: There is also UrlInterface::GetComponents.

      Cheers,
      Ferdinand

    • E

      Get and Set DTYPE_COLORA/DTYPE_VECTOR4D on basecontainer or gedata

      Cinema 4D SDK
      • c++ • • ECHekman
      7
      0
      Votes
      7
      Posts
      655
      Views

      ferdinandF

      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

    • E

      Data, DataTypes, Python and GUI

      Cinema 4D SDK
      • c++ python • • ECHekman
      7
      0
      Votes
      7
      Posts
      788
      Views

      E

      Ok thanks for the help Ferdinand. I will take the road of least resistance and just build on top of float64 vectors

    • E

      Natvis settings not working?

      Cinema 4D SDK
      • windows c++ • • ECHekman
      5
      0
      Votes
      5
      Posts
      732
      Views

      ferdinandF

      Hey @bojidar,

      well, we do not write these object views (the natvis for MSVC and the Python scripts for Xcode) for public usage but for internal usage. That we hand them out to third parties is just a courtesy. When we are looking at maxon::GraphNode,

      <Type Name="maxon::GraphNode"> <DisplayString Condition="_mem[0] != 0">{((maxon::NodePath*)&amp;_mem[0]),na}</DisplayString> <!-- Root will have empty path and valid graph --> <DisplayString Condition="_mem[0] == 0 &amp;&amp; _graph._object != 0">Root</DisplayString> <DisplayString Condition="_mem[0] == 0">nullptr</DisplayString> <Expand> <Item Name="Path">(((maxon::NodePath*)&amp;_mem[0])),na</Item> <Item Name="Kind" Condition="_mem[0] != 0 &amp;&amp; _graph._object != 0">(maxon::NODE_KIND)((((nodes.module.xdl64!maxon::nodes::NodePathImpl::CountAndKind*) &amp; (*(nodes.module.xdl64!maxon::nodes::NodePathImpl**) &amp; _mem[0])->_path))->kind &amp; 0xFF)</Item> <Item Name="Kind" Condition="_mem[0] == 0 &amp;&amp; _graph._object != 0">maxon::NODE_KIND::NONE</Item> <Item Name="Info">((nodes.module.xdl64!maxon::nodes::NodesGraphModelImpl::Info*)this->_mem),na</Item> <Item Name="Graph">(this->_graph)</Item> <Item Name="Graph Storage">(this->_mem)</Item> </Expand> </Type>

      then there are indeed quite a few references to the implementation (which means that this cannot work in the public API). You could rip these out to make it work, but would then be left with only a small subset of the debug attributes. But that would be up to you.

      In general, you can expect the Cinema API to be more conservative and almost all object views working there, while the Maxon API is generally more internal in nature.

      Cheers,
      Ferdinand

    • E

      Global static classes?

      Cinema 4D SDK
      • c++ • • ECHekman
      4
      0
      Votes
      4
      Posts
      495
      Views

      ferdinandF

      As I said, you will run into access violations when you instantiate your fields on the class instead of the Init function. And as I also said, in your concrete case it would probably even be fine if you would directly do it in the class scope. But I would advise against breaking this rule. There is nothing to optimize here, either return a new instance when this is only called once in a blue moon and you do not want to bother with initializing a field. Or define a field and initialize it up in NodeData::Init. And no, scene elements (NodeData) should not share data on their class. We have types in the Maxon API to deal with this when you really want some heavy data structure which shall be initialized exactly once, but that is total overkill in this case.

      Cheers,
      Ferdinand

    • E

      Compiling material nodegraph to shaders

      Cinema 4D SDK
      • r23 sdk maxon api c++ • • ECHekman
      4
      0
      Votes
      4
      Posts
      607
      Views

      r_giganteR

      @ECHekman said in Compiling material nodegraph to shaders:

      I take it this also means its not possible to manually convert node ourselves?

      Right.

    • E

      BaseLink crash and tracking PolygonObjects/InstanceObjects in cache

      Cinema 4D SDK
      • • • ECHekman
      3
      0
      Votes
      3
      Posts
      553
      Views

      ferdinandF

      Hi,

      without further feedback, we will consider this thread as solved by Monday and flag it accordingly.

      Cheers,
      Ferdinand

    • E

      Tracking object lifetime in a scene

      Cinema 4D SDK
      • • • ECHekman
      4
      0
      Votes
      4
      Posts
      564
      Views

      ferdinandF

      Hi,

      without further feedback, we will consider this thread as solved by tomorrow and flag it accordingly.

      Cheers,
      Ferdinand