• UI, Resource Descripion and all those .h, .str, .res

    11
    4
    0 Votes
    11 Posts
    2k Views
    intenditoreI
    Brah... Third time spent fighting with stupid typos! : @PluginStudent @zipit @r_gigante many thanks! I didn't assume you are using the same system inside the program and had no thought to take a look there! Seems adding the "," helped it. And, as I see, you must enumerate all the elements in your .h file, but though you can leave id blank. Thank you! %\
  • Custom Errors

    r20 c++
    13
    0 Votes
    13 Posts
    2k Views
    r_giganteR
    Hi @tdapper thanks for reaching out us. With regard to your comment, although I confirm that you don't have to put them in a separate framework but it's actually recommended to grant good design and straightforward reusability. For the sake of clarity, find below the files used to create a project which includes both the declaration and the implementation of the custom error together with the code using it. The example is derived from the code presented on GitHub. project/projectdefinition.txt // Supported platforms - can be [Win64;OSX] Platform=Win64;OSX // Type of project - can be [Lib;DLL;App] Type=DLL // API dependencies APIS=cinema.framework;mesh_misc.framework;math.framework;crypt.framework;python.framework;core.framework; // C4D component C4D=true stylecheck.level=3 // must be set after c4d=true stylecheck.enum-registration=false stylecheck.enum-class=false ModuleId=net.maxonexample.support.single_plugins.PC12316 source/PC12316_CustomErrorImpl.cpp #include "PC12316_CustomErrorInterface.h" // This example shows the implementation of a custom error type. class PC12316_CustomErrorImpl : public maxon::Component<PC12316_CustomErrorImpl, PC12316_CustomErrorInterface> { // use ErrorObjectClass to implement basic error functionality MAXON_COMPONENT(NORMAL, maxon::ErrorObjectClass); public: maxon::Result<void> CopyFrom(const PC12316_CustomErrorImpl& src) { _errorCode = src._errorCode; return maxon::OK; } public: MAXON_METHOD maxon::String GetMessage() const { return FormatString("Custom error code is @", _errorCode); } // custom methods MAXON_METHOD void SetCustomErrorCode(maxon::Int errorCode) { _errorCode = errorCode; } MAXON_METHOD maxon::Int GetCustomErrorCode() const { return _errorCode; } private: maxon::Int _errorCode; ///< error code value }; // register all the non-static methods in the implementation MAXON_COMPONENT_OBJECT_REGISTER(PC12316_CustomErrorImpl, PC12316_CustomErrorObject); source/PC12316_CustomErrorInterface.h #ifndef PC12316_CUSTOMERRORINTERFACE_H__ #define PC12316_CUSTOMERRORINTERFACE_H__ #include "maxon/object.h" // This example shows the declaration of a custom error type. // The custom error is able to store a custom error code. // --------------------------------------------------------------------- // Custom error class that stores an error code. // --------------------------------------------------------------------- class PC12316_CustomErrorInterface : MAXON_INTERFACE_BASES(maxon::ErrorInterface) { MAXON_INTERFACE(PC12316_CustomErrorInterface, MAXON_REFERENCE_COPY_ON_WRITE, "net.maxonexample.example.errors.PC12316_customerror"); public: MAXON_ADD_TO_COPY_ON_WRITE_REFERENCE_CLASS( void Create(MAXON_SOURCE_LOCATION_DECLARATION, maxon::Int errorCode) { #if API_VERSION >= 20000 && API_VERSION < 21000 * static_cast<typename S::DirectlyReferencedType::ReferenceClassHelper::type*>(this) = S::DirectlyReferencedType::ReferenceClassHelper::object::GetInstance() (); #elif API_VERSION >= 21000 *static_cast<typename S::DirectlyReferencedType::Hxx1::ReferenceClass*>(this) = S::DirectlyReferencedType::Hxx1::ErrObj::GetInstance()(); #endif typename S::DirectlyReferencedType::Ptr e = this->MakeWritable(false).GetPointer(); e.SetLocation(MAXON_SOURCE_LOCATION_FORWARD); e.SetCustomErrorCode(errorCode); } ); // custom methods // --------------------------------------------------------------------- // Stores an custom error code. // --------------------------------------------------------------------- MAXON_METHOD void SetCustomErrorCode(maxon::Int errorCode); // --------------------------------------------------------------------- // Returns the stored custom error code. // --------------------------------------------------------------------- MAXON_METHOD maxon::Int GetCustomErrorCode() const; }; #include "PC12316_CustomErrorInterface1.hxx" #include "PC12316_CustomErrorInterface2.hxx" #endif /* PC12316_CUSTOMERRORINTERFACE_H__ */ source/PC12316.cpp #include "c4d.h" static const Int32 PluginID = 99912316; #include "PC12316_CustomErrorInterface.h" // Dummy test function maxon::Result<void> TestFunction(maxon::Int * val); maxon::Result<void> TestFunction(maxon::Int * val) { iferr_scope; if (!val) return PC12316_CustomError(MAXON_SOURCE_LOCATION, 4242); ApplicationOutput("Value is @", *val); return maxon::OK; } // Command to test the custom error class CustomErrorExample : public CommandData { public: #if API_VERSION >= 20000 && API_VERSION < 21000 Bool Execute(BaseDocument* doc) #elif API_VERSION >= 21000 Bool Execute(BaseDocument* doc, GeDialog* parentManager) #endif { iferr_scope_handler { return false; }; if (!doc) return false; iferr (TestFunction(nullptr)) ApplicationOutput("Error: @", err); maxon::Int a = 100; iferr (TestFunction(&a)) ApplicationOutput("Error: @", err); return true; } static CommandData* Alloc() { return NewObj(CustomErrorExample) iferr_ignore("Unexpected failure on allocating CustomErrorExample plugin."_s); } }; Bool RegisterCustomErrorExample(); Bool RegisterCustomErrorExample() { return RegisterCommandPlugin(PluginID, "PC12316_CustomErrorExample"_s, PLUGINFLAG_COMMAND_OPTION_DIALOG, nullptr, ""_s, CustomErrorExample::Alloc()); } Bool PluginStart() { if (!RegisterCustomErrorExample()) return false; return true; } void PluginEnd() { } Bool PluginMessage(Int32 id, void* data) { return true; } A final minor note on register=true: since R21 it's not needed anymore because in former releases it was needed to specify when a module was supposed to run in pure legacy-mode but nowadays modules can be either hybrid (classic + maxon API) or maxon API-only. Hoping this makes using our Error Handling system more clear and easy to integrate in your products, give best and don't hesitate to ask for more. Best, R
  • Description String field without label

    c++
    4
    1
    0 Votes
    4 Posts
    398 Views
    ferdinandF
    @C4DS Hi, no need to be sorry. Actually I am sorry for the (sort of) misinformation. But I have had the same problem and this was my conclusion for other node types (I just quickly reconfirmed it with a user data static text). Maybe DescriptionTooldata behave differently? Anyways, good luck Cheers, zipit
  • Custom exporting animation data into aec file crashes Cinema

    r19 python
    9
    0 Votes
    9 Posts
    1k Views
    A
    @m_magalhaes Hi Manuel, Thank you for giving me some time to check this out. So after a bit of testing and changing the code to work with Cinema I cannot replicate the issue. As you mention it seems to be related to Pyblish. I did find interesting that when running the code in Cinema without Pyblish you can't see the active frame running through the timeline, while you do see it when running through Pyblish. Perhaps that's the correlation with the crash. I will close this as solve, for the fact that it does not crash in the Cinema context. Thanks again! Andre
  • Check User Data Link Field

    Moved
    3
    0 Votes
    3 Posts
    617 Views
    SwinnS
    @Swinn is None did the trick. Thanks.
  • c4d.utils.RangeMap clampval funkyness

    r20 python
    2
    0 Votes
    2 Posts
    274 Views
    ManuelM
    Hi, thanks a lot. I've opened a bug entry for that one. It will be fixed in a futur release. Cheers, Manuel
  • 0 Votes
    11 Posts
    2k Views
    Tasos MagkafasT
    @m_adam Dear Maxime thanks for everything! But, unfortunally now that I almost finished this part I realized that all this scripting doen't give me the desired procedural result. It just changes the values once but if i change the values of the PARENT object the OBJECT_A (child) is not updated... Anyway I have to approach it in a different way. I think I should tag this thread as "SOLVED" and in case I need again help i create a new one. Please advise me Maxime. And for one more time THANK YOU both , Maxime and Zipit
  • Render to Picture Viewer with fields problem.

    Moved
    7
    0 Votes
    7 Posts
    1k Views
    Danchyg1337D
    @m_adam Thank you for reply. I would probably send my code to your email to try to figure it out better. What i see so far is that in renderer, fields returns 0 for each point they sample. I have a function which samples fields and accepting a result to each vertex. For example imagine extrude with fields. In viewport i see extruded points, but in renderer everything is flat, like there is no field or it is so far to make any extrusion and returns 0. for each point. Second is more likely due to my tests.
  • Undo for a TagData?

    5
    0 Votes
    5 Posts
    869 Views
    M
    As said previously this is not possible in the execute method to add an undo event because this execute method is called during the execute. But if I understood correctly you have an UserData attached then this UD drive children parameters. If that's the case you can react to this parameter change (coming from the GUI which is a Main Thread thing) and then apply the undo. You can find an example in https://developers.maxon.net/forum/topic/12479/update-button/3 Cheers, Maxime.
  • Texture renaming

    Moved python
    16
    0 Votes
    16 Posts
    2k Views
    M
    @zipit hm yes this sounds too complicated overall, particularly point 3 there could so much happen on the os side. A gui with more options like renaming the hole texturename or a replace option of certain words could be the way forward. Instead of undo it would be easy then to rename the texture with he old name etc. for now im happy how this works and let this solved. Much Thanks! Cheers, moko
  • Python NODES - Shouldn't really they can change the scene?

    Moved
    19
    0 Votes
    19 Posts
    4k Views
    ferdinandF
    @SolarPH said in Python NODES - Shouldn't really they can change the scene?: Edit: One thing though, this code kinda has it's own holes, because I encountered a problem ... I never said that it is perfect, I just implemented, what I thought you were after. If you want to find all file paths where the file name matches the file name part of a given preset URL, you could use os.walk. Something like this: def find_preset_url_candidates(url): """Find all OS file paths for which the file name matches the file name of a given MAXON preset url. Args: url (str): The url in the MAXON 'preset' scheme to resolve. Returns: list[str]: The resolved preset paths. Raises: ValueError: When the argument preset_url is not a valid preset url. """ # Half-heartedly sort out some malformed preset urls. url = str(url) if (not url.startswith("preset://") or not url.endswith(".lib4d")): msg = r"Not a preset url: {}." raise ValueError(msg.format(url)) # Split the url into the scheme-path and filename-extension parts _, preset_file = os.path.split(url) candidates = [] # For each preset path walk that path and test if any file matches the # file name of our preset file name. for preset_path in PRESET_PATHS: for root, folders, files in os.walk(preset_path): if preset_file in files: candidates.append((os.path.join(root, preset_file))) return candidates My example does not deal with any fuzzy path searches / does not sort its output by the edit-distance (you would have to do that yourself). To test successfully against something like testrig0.lib4d you would have to implement a Hamming distance or Levenshtein distance to sort out what is close enough. For your example you would need the latter. Or you could just use a regular expression if you do not care about the edit distance. Cheers, zipit
  • Custom GUI button via resource description

    c++ r20 r21
    3
    0 Votes
    3 Posts
    589 Views
    C4DSC
    @PluginStudent You mentioning the BITMAPBUTTON and with the help of ExampleSculptGrabBrush::GetDDescription from the cinemasdk I was able to make it work. Thanks.
  • User Area and ScrollArea()

    r20 python
    4
    0 Votes
    4 Posts
    534 Views
    P
    Yes, I use the auto way. I thought that using ScrollArea() it would only display that part (no need to draw the other parts). So, fill the virtual UA once and then display parts of it using ScrollArea(). But if "you still need to draw completely the GeUserArea with all the DrawBitmap", there will be no speed benefit. I will try it under R21 and will read "Profiling Python Plugins". Thank you, Pim [image: 1586507628642-24fbc034-a80c-42f0-acb3-77deffeadaec-image.png]
  • Cannot write specific values to UVWTag

    r20 r21 c++ python
    6
    0 Votes
    6 Posts
    643 Views
    r_giganteR
    It's actually due to a lower number of bits used to store the floating value.
  • Custom FIELDLAYER_CHANNELFLAG

    r20 c++ classic api maxon api r21
    7
    1
    1 Votes
    7 Posts
    1k Views
    mikeudinM
    @m_adam @zipit @PluginStudent OK, thank you guys!
  • Set Track Data Method?

    r21 python
    4
    0 Votes
    4 Posts
    371 Views
    B
    @zipit @m_adam Apologies for the late response. Thank you for the confirmation both. I will close this for now.
  • 0 Votes
    15 Posts
    1k Views
    M
    Looking at the doc in R19: [image: 1586334998271-5fdf5fb0-1327-4589-b6b6-d68af8869c11-image.png] [image: 1586334983049-821d97fa-e103-4cca-84b1-85f0f50304f0-image.png] So I'm afraid there is no simple solution that will work on each version maxon::String being introduced in R20, you will need to adapt your code. Cheers, Maxime.
  • Need Help Debugging EXC_BAD_ACCESS error during render

    r21 macos c++
    8
    1
    0 Votes
    8 Posts
    904 Views
    r_giganteR
    Hi @JuicyJuggles , I apologize for coming late here but luckly you've been already provided in the meanwhile of some good guidance from @PluginStudent and @zipit . Rest assured that the API documentation is, by far, the best place where to look for answers although I can see that, due to huge number of covered topics, it could take time to get used to browse it effectively. Last but not least, if the issue is addressed, don't forget to mark the right post as correct answer or if it's not possible to identify a specific one, to set the whole topic as Solved Cheers, Riccardo
  • Avoid: IsActive()

    python classic api
    10
    0 Votes
    10 Posts
    1k Views
    lasselauchL
    Thanks @m_adam for the insights! Works like a charm!! Cheers, Lasse
  • Python Generator - Linking ports to xpresso node

    14
    0 Votes
    14 Posts
    2k Views
    M
    Hi sorry to jump on this topic so late, and I agree that if you could do what you want in a Python Scripting tag its preferred, the mains issue with xpresso is that its a whole system that assumes certain things and was really not designed to be embedded within a generator. So the issue about the AddNode, not working is because user data things, as an object xpresso node, is something dynamic (they will change according to the linked object) and I found no way except via the UI (by asking a UI Redraw or a whole scene execution) to refresh these data so the GvPort can be created. But since you are in a Generator you don't have access to the GUI since all GUI operation should be done in the Main thread see Threading Information. Cheers, Maxime.