• How to use String::Split

    c++
    2
    0 Votes
    2 Posts
    381 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
  • GeUserArea use DrawBitmap() to overlay multiple images(has alpha)

    2024 python
    3
    0 Votes
    3 Posts
    669 Views
    i_mazlovI
    Hi @chuanzhen, Glad you've solved the issue! We're grateful to you for sharing your solution with the community (moreover in such a visual way), this is highly appreciated! Cheers, Ilia
  • MoGraph data index and Multi-Instances

    c++
    5
    0 Votes
    5 Posts
    1k Views
    P
    Hi Ferdinand, Thank you, I will consider different approaches based on your reply and might file a feature request as you suggested if I can't find any solution. Thanks, Peter
  • GraphModelInterface.GetNode not worked

    python windows 2025
    3
    0 Votes
    3 Posts
    557 Views
    DunhouD
    Hi @m_adam , Thanks for your reply, it worked well. But I still have some doubts about the usage of Node Path, such as how to calculate the port through NodePath instead of concatenating strings (which can easily lead to misoperation). There are few examples and answers for NodePath on the forum, and it seems that people rarely use it. Do you have any insights on this, or in other words, what usage scenarios do you think NodePath is more suitable for. Cheers~ DunHou
  • Realtime Slider Update

    python
    3
    0 Votes
    3 Posts
    533 Views
    i_mazlovI
    Hi @shurkan, Welcome to the Maxon developers forum and its community, it is great to have you with us! Getting Started Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules. Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment. Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support. Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads. It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions. About your First Question Great that you've managed to find the solution yourself! Thank you in advance for sharing it with the community! Just a short note about your solution is to be careful with threading, namely, in your case it's expected to execute DrawViewes in the following way: c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_STATICBREAK) Something similar to this topic here: Troubleshooting Safe Frame Calculations Across Different Takes in Cinema 4D Cheers, Ilia
  • Transparency Issue with MultipassBitmap in GeUserArea

    c++ 2024 windows
    7
    0 Votes
    7 Posts
    1k Views
    ferdinandF
    Hey @T1001, find below an example for a user area which draws multiple semi-transparent bitmaps on top of each other. I will likely add this code example to the SDK at some point, as this is a common task. Please provide feedback when you think things are missing. The example focuses on the core problem of having an 'alien' app which places bitmap data in memory and the Image API wrapping around that data with transparencies. What I have not yet done here, is that I avoided all copying altogether and directly operate on the raw memory managed and owned by the alien app. Which is possible to do in the public API I think, but one would have to write a component for ImageBaseInterface so that one can modify the Get/SetPixelHandler's. This would have been out of scope for this example. But I have it on my backlog, as I can see how this would be a desirable feature for render engine vendors and similar plugin types. Cheers, Ferdinand Result image_layers.mp4 Code /* Demonstrates how to implement a dialog that wraps around image buffers provided by an alien application. The buffers are of type RGBA-32 but could also follow any other pixel format the Image API supports. The buffers are drawn with their transparencies on top of each other in a user area and automatically scaled to the size of the user area. The example contains the following sections: * namespace alien: Contains code that generates image data in memory, mocking an alien app. * namespace cinema: Contains the code to wrap that alien image data in Cinema 4D with: * class ImageLayersArea: The UI element which wraps the buffers concretely. * class ImageLayersAreaDialog: The dialog implementation which uses an #ImageLayersArea. * class ImageLayersAreaCommand: The command which wraps the dialog as a menu/palette item which can be invoked by the user to open the dialog. */ // std is here only used to simulate an alien app, do not use std in your regular Cinema projects. #include <vector> #include <algorithm> #include "c4d_basedocument.h" #include "c4d_colors.h" #include "c4d_commandplugin.h" #include "c4d_general.h" #include "c4d_gui.h" #include "maxon/gfx_image.h" #include "maxon/gfx_image_colorprofile.h" #include "maxon/gfx_image_colorspaces.h" #include "maxon/gfx_image_pixelformats.h" #include "maxon/gfx_image_storage.h" #include "maxon/mediasession_image_export.h" // Must be included before the specialization. #include "maxon/mediasession_image_export_psd.h" #include "maxon/lib_math.h" // The plugin ID of the #ImageLayersAreaCommand. You must register unique plugin IDs for your plugins // via https://developers.maxon.net/. static const cinema::Int32 g_image_layers_command = 1064549; // The definition of bitmap buffers generated by the alien application. static const cinema::Int32 g_buffer_height = 2048; static const cinema::Int32 g_buffer_width = 2048; static const cinema::Int32 g_buffer_channel_count = 4; static const cinema::Int32 g_buffer_line_size = g_buffer_width * g_buffer_channel_count; static const cinema::Int32 g_buffer_size = g_buffer_line_size * g_buffer_height; // Title used by the dialog and command, and the IDs of the dialog gadgets. #define CMD_TITLE "C++ SDK: Image Layers Area"_s #define ID_GRP_BUTTONS 1000 #define ID_UA_IMAGE_LAYERS 2000 #define ID_BTN_ADD 2001 #define ID_BTN_REMOVE 2002 #define ID_BTN_SAVE 2003 /// We need this because IMAGEINTERPOLATIONMODE is currently not exposed in the public API, I /// will fix this in a future release. namespace maxon { enum class IMAGEINTERPOLATIONMODE { NEARESTNEIGHBOR, ///< worst quality, no interpolation at all LINEAR, ///< linear interpolation between pixels BICUBIC, ///< best quality using bicubic interpolation } MAXON_ENUM_LIST(IMAGEINTERPOLATIONMODE); } // end of namespace maxon // --- Alien Application Code /// This namespace is meant to simulate some alien application which places bitmap data in memory /// which we are going to wrap with the Image API. The example is using here the std library for /// the sole purpose of simulating an alien application. PLEASE NOTE THAT THE USE OF STD IN CINEMA /// PROJECTS IS STRONGLY DISCOURAGED. namespace alien { // A list of alien bitmap buffers held and managed by an alien application. Each float* in the // vector is a head to a buffer as defined by the g_buffer_ constants. std::vector<float*> g_alien_buffers; // A random number generator used by the alien application. maxon::LinearCongruentialRandom<maxon::Float32> g_random; /// Places an RGBA buffer in memory which holds a horizontal gradient in an otherwise largely /// transparent bitmap. This could for example be a buffer of an render engine which stores /// its data as #float. /// /// We are going to draw something like this, a horizontal gradient that only covers a portion /// of the height of the bitmap buffer, leaving the rest of the buffer entirely transparent. /// /// ---------------------------------------- /// /// /// @@@@@%%%%#####****+++++====-----::::.... /// /// /// ---------------------------------------- float* AddAlienBuffer() { iferr_scope; // The starting position and height of the horizontal gradient bar. const int32_t gradientHeight = std::max( 3, int32_t (g_random.Get01() * float(g_buffer_height) * 0.333)); const int32_t gradientStart = std::min( g_buffer_height - gradientHeight, int32_t (g_random.Get01() * float(g_buffer_height))); const int32_t gradientEnd = gradientStart + gradientHeight - 1; // The knots of the gradient. We either interpolate from opaque to transparent or vice versa. We // dip here our toes a bit into the Maxon API with ColorA32 so that we later use its color // interpolation function. const float alphaA = g_random.Get01() > .5 ? 0.0 : 1.0; const float alphaB = alphaA > 0.5 ? 0.0 : 1.0; const maxon::ColorA32 gradientColorA( g_random.Get01(), g_random.Get01(), g_random.Get01(), alphaA); const maxon::ColorA32 gradientColorB( g_random.Get01(), g_random.Get01(), g_random.Get01(), alphaB); // Allocate a new buffer. float* buffer = new float[g_buffer_size]; // Now we write a gradient into an otherwise fully transparent image. We write RGBA float data // in an at this point undefined color profile. We will then on the Cinema 4D side interpret // this data as PixelFormats::RGBA::F32() with an sRGB-2.1 profile. for (int32_t y = 0; y < g_buffer_height; ++y) { // We are outside of the gradient strip, we fill the line with fully transparent pure black. if (MAXON_LIKELY((y < gradientStart) || (y > gradientEnd))) { for (int32_t x = 0; x < g_buffer_width; x++) { const int32_t i = (y * g_buffer_line_size) + (x * g_buffer_channel_count); buffer[i + 0] = 0.0; // R buffer[i + 1] = 0.0; // G buffer[i + 2] = 0.0; // B buffer[i + 3] = 0.0; // A } } // We are inside the gradient strip, we write a gradient into the buffer. else { for (int32_t x = 0; x < g_buffer_width; x++) { const int32_t i = (y * g_buffer_line_size) + (x * g_buffer_channel_count); const maxon::ColorA32 color = maxon::BlendColor( gradientColorA, gradientColorB, float(x) / float(g_buffer_width)); buffer[i + 0] = color.r; buffer[i + 1] = color.g; buffer[i + 2] = color.b; buffer[i + 3] = color.a; } } } // Append the buffer to the global buffers and return the buffer. g_alien_buffers.push_back(buffer); return buffer; } /// Removes the last element from the alien buffer list and frees its memory. void PopAlienBuffer() { if (g_alien_buffers.empty()) return; float* last = g_alien_buffers.back(); delete[] last; g_alien_buffers.pop_back(); } } // end of alien // --- Cinema 4D Application Code namespace cinema { using namespace maxon; // --- UserArea Implementation -------------------------------------------------------------------- /// Implements a custom GUI that wraps around the bitmap buffers of an alien application. class ImageLayersArea : public GeUserArea { private: // Holds the images wrapping the alien buffers. Since we later want save out these buffers as // multi layer PSD files, we right away pick ImageLayerRef and not ImageRef as our image class. BaseArray<ImageLayerRef> _layers; public: // --- Custom Methods // Adds an image layer to the user area from the given #buffer. We rely here on the globally defined // buffer metadata, otherwise we would have to describe the layout of #buffer with more arguments. Result<void> AddLayer(float* buffer) { iferr_scope; // Allocate a new maxon Image API (layer) bitmap that uses the default non-linear RGB profile // (sRGB 2.1) and an RGBA four bytes per channel float pixel format, i.e., 16 bytes per pixel. // We could also import here an ICC profile from disk to match an exotic color profile used // by alien app. But when that is the case, we would have to convert colors here to sRGB 2.1 as // shown in the example_color_management examples. const ImageLayerRef layer = ImageLayerClasses::RASTER().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 could be a planar layout. layer.Init(g_buffer_width, g_buffer_height, ImagePixelStorageClasses::Normal(), format) iferr_return; // Set some metadata on the image layer. Setting a name is irrelevant, the rest is not. layer.Set(IMAGEPROPERTIES::NAME, FormatString("layer_@", _layers.GetCount() + 1)) iferr_return; layer.Set(IMAGEPROPERTIES::IMAGE::COLORPROFILE, profile) iferr_return; layer.Set(IMAGEPROPERTIES::TYPE, IMAGEPROPERTIES::ITYPE::LAYER) iferr_return; // Get the pixel handler to write data into the image. const maxon::SetPixelHandlerStruct handler = layer.SetPixelHandler( format, format.GetChannelOffsets(), profile, maxon::SETPIXELHANDLERFLAGS::NONE) iferr_return; // Copy the data line by line. for (Int32 y = 0; y < g_buffer_height; ++y) { // Construct a Pix, i.e., UChar , line buffer pointer for our current buffer pointer. The // Image API handles all data at its lowest level as UChar. E.g., a line with 10 RGBA::F32 // pixels, i.e, 10 * 4, elements will be actually stored as, 10 * 4 * 4 elements, as an F32 // is decomposed into four UChar bytes. Pix* head = reinterpret_cast<Pix*>(buffer); // Write the line buffer into the image. Despite its name, an ImagePos can express up to // a line in an image. handler.SetPixel( ImagePos(0, y, g_buffer_width), PixelMutableBuffer(head, format.GetBitsPerPixel()), SETPIXELFLAGS::NONE) iferr_return; // Advance the buffer to the next line. buffer += g_buffer_line_size; } // Append our layer to list of layers. _layers.Append(layer) iferr_return; return OK; } /// Pops the last layer from the list of layers. Bool PopImage() { return _layers.Pop(); } /// Saves the whole layer list as a PSD to disk. Result<void> Save() { iferr_scope; // Check that we are on the main thread and then ask the user for a save location. if (!GeIsMainThreadAndNoDrawThread()) return IllegalStateError( MAXON_SOURCE_LOCATION, "This function cannot be run off main-thread"_s); Filename file; if (!file.FileSelect( FILESELECTTYPE::IMAGES, FILESELECT::SAVE, "Select file path:"_s, "psd"_s)) return OK; // Insatiate an ImageTextureRef, the root level bitmap type required to save images. // A texture can only hold entries of type IMAGEHIERARCHY::IMAGE, adding multiple images // to a ImageTextureRef will not result in layers, but all data being put into the "background" // layer of the image. const ImageTextureRef texture = ImageTextureClasses::TEXTURE().Create() iferr_return; const ImageRef base = ImageClasses::IMAGE().Create() iferr_return; base.Init(g_buffer_width, g_buffer_height, ImagePixelStorageClasses::Normal(), PixelFormats::RGBA::F32()) iferr_return; base.Set(IMAGEPROPERTIES::IMAGE::COLORPROFILE, maxon::ColorProfile()) iferr_return; texture.AddChildren(IMAGEHIERARCHY::IMAGE, base, ImageBaseRef()) iferr_return; // Now iterate over our layers with transparencies and add them one by one to the image. for (const ImageLayerRef layer : _layers) { // It is really importan that #layer has IMAGEPROPERTIES::TYPE set to LAYER. base.AddChildren(IMAGEHIERARCHY::LAYER, layer, ImageBaseRef()) iferr_return; } // Save #texture as a PSD. const MediaOutputUrlRef psd = ImageSaverClasses::Psd().Create() iferr_return; texture.Save(MaxonConvert( file, MAXONCONVERTMODE::NONE), psd, MEDIASESSIONFLAGS::NONE) iferr_return; return OK; } // --- GeUserArea Methods /// Called by Cinema 4D to request the minium #width and #height for the area. Bool GetMinSize(Int32& w, Int32& h) { w = h = 256; return true; } /// Called by Cinema 4D to let the area draw its content. void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg) { // Enable some drawing optimizations. OffScreenOn(); SetClippingRegion(x1, y1, x2, y2); // Draw the background with the default background color. DrawSetPen(COLOR_BG); DrawRectangle(x1, y1, x2, y2); Float32 wx = Float32(x1); Float32 wy = Float32(y1); Float32 ww = Float32(x2 - x1); Float32 wh = Float32(y2 - y1); // Draw our layers on top of each other with bicubic interpolation. for (ImageBaseRef image : _layers) DrawImageRef(image, wx, wy, ww, wh, 1.0, IMAGEINTERPOLATIONMODE::BICUBIC); } }; // --- Dialog Implementation ---------------------------------------------------------------------- /// Realizes a dialog that displays a bitmap with multiple layers with transparencies. class ImageLayersAreaDialog : public GeDialog { private: // The custom user area and the default number of layers which are being added. ImageLayersArea _layers; const Int32 _defaultLayerCount = 3; public: // --- Custom Methods /// Adds an alien buffer and wraps it with an image in the #ImageLayersArea in tandem. Result<void> AddBuffer() { iferr_scope; float* buffer = alien::AddAlienBuffer(); _layers.AddLayer(buffer) iferr_return; return OK; } /// Pops an alien buffer and its wrapping image in the #ImageLayersArea in tandem. Result<void> PopBuffer() { _layers.PopImage(); alien::PopAlienBuffer(); return OK; } // --- GeDialog Methods /// Called by Cinema 4D to let the dialog populate itself with gadgets. Bool CreateLayout() { Bool result = true; static const Int32 margin = 5; // Set the title and the margin between the group and the border and between items in the // group. We are defining here the implicitly existing outmost group. SetTitle(CMD_TITLE); result &= GroupBorderSpace(margin, margin, margin, margin); result &= GroupSpace(margin, margin); // Add the image layers user area. result &= AddUserArea(ID_UA_IMAGE_LAYERS, BFH_SCALEFIT | BFV_SCALEFIT, 0, 200) != nullptr; result &= AttachUserArea(_layers, ID_UA_IMAGE_LAYERS); // Add a group with holds three elements pre row (opposed to the one element by row of the // default group and add the three buttons. result &= GroupBegin(ID_GRP_BUTTONS, BFH_SCALEFIT, 3, 0, ""_s, 0); { result &= GroupSpace(margin, margin); result &= AddButton(ID_BTN_ADD, BFH_SCALE, 0, 0, "Add"_s) != nullptr; result &= AddButton(ID_BTN_REMOVE, BFH_SCALE, 0, 0, "Remove"_s) != nullptr; result &= AddButton(ID_BTN_SAVE, BFH_SCALE, 0, 0, "Save"_s) != nullptr; } result &= GroupEnd(); return result; } /// Called by Cinema 4D to let the dialog init its values once its UI has been built. Bool InitValues() { // We implemented many methods here as Result<T>, the error system of the Maxon API. This method // is not of type Result<T> and we must therefore terimate the error handling in this function. // When an error is bubbling up through the 'iferr_return' of the #AddBuffer call, the function // will exit through this scope handler with #err being the error which is raised. iferr_scope_handler { // This is for demo purposes only, please avoid console spam in production code, use loggers // like DiagnosticsOutput instead. ApplicationOutput("@ failed with error: @", MAXON_FUNCTIONNAME, err); return false; }; // Add a few layers by default. for (Int32 i = 0; i < _defaultLayerCount; i++) { AddBuffer() iferr_return; } return true; } /// Called by Cinema 4D when the user clicks elements in the UI. /// /// Propagated are here only true click events, to realize things like scrubbing, mouse-over, /// etc, one has to implement GeDialog::Message (where one can also handle clicks). Bool Command(Int32 cid, const BaseContainer& msg) { iferr_scope_handler { // This is for demo purposes only, please avoid console spam in production code, use loggers // like DiagnosticsOutput instead. #err is the error exposed to the scope handler. ApplicationOutput("@ failed with error: @", MAXON_FUNCTIONNAME, err); return false; }; // We handle the buttons, when we add or pop layers, we force the user area to redraw. if (cid == ID_BTN_ADD) { AddBuffer() iferr_return; _layers.Redraw(); } else if (cid == ID_BTN_REMOVE) { PopBuffer() iferr_return; _layers.Redraw(); } else if (cid == ID_BTN_SAVE) { _layers.Save() iferr_return; } return true; } }; // --- Command Implementation --------------------------------------------------------------------- /// Realizes the command with which the user can open and close an the #ImageLayersAreaDialog. class ImageLayersAreaCommand : public CommandData { private: // The dialog of the command, we keep using the same instance over the life time of Cinema 4D. ImageLayersAreaDialog _dialog; public: /// Returns an instance of the #ImageLayersCommand. static ImageLayersAreaCommand* Alloc() { return NewObjClear(ImageLayersAreaCommand); } /// Called by Cinema 4D when the user invokes the command. Bool Execute(BaseDocument* doc, GeDialog* parentManager) { // Fold the dialog when open and unfolded, otherwise unfold it (Open both opens a never opened // dialog and unfolds a folded dialog). if (_dialog.IsOpen() && !_dialog.GetFolding()) _dialog.SetFolding(true); else _dialog.Open(DLG_TYPE::ASYNC, g_image_layers_command); return true; } /// Called by Cinema 4D to restore the UI associated with a command on layout switches. Bool RestoreLayout(void* secret) { return _dialog.RestoreLayout(g_image_layers_command, 0, secret); } }; } // namespace cinema /// Registers the #ImageLayersAreaCommand as a CommandData plugin. /// /// Must be called in the main.cpp of this module when #PluginStart() is emitted. cinema::Bool RegisterImageLayersAreaExample() { return cinema::RegisterCommandPlugin( g_image_layers_command, CMD_TITLE, 0, nullptr, "Opens a dialog holding a custom UI element that stacks multiple bitmaps with transparencies."_s, cinema::ImageLayersAreaCommand::Alloc()); }
  • Get and Set DTYPE_COLORA/DTYPE_VECTOR4D on basecontainer or gedata

    c++
    7
    0 Votes
    7 Posts
    880 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
  • Data, DataTypes, Python and GUI

    c++ python
    7
    0 Votes
    7 Posts
    1k Views
    E
    Ok thanks for the help Ferdinand. I will take the road of least resistance and just build on top of float64 vectors
  • 0 Votes
    2 Posts
    572 Views
    i_mazlovI
    Hi @heytraile, Please have a look at our Support Procedures: How to Ask Question section. Usually it is very helpful if one provides a relevant code snippet, demonstrating the issue. This helps to reduce the room for any misinterpretations of your original question. Regarding the issue you're describing, the "null" being logged to the console is often a symptom of an implementation issue within a function that overrides the base implementation. Specifically, if a function (such as Message() or RestoreLayout()) is expected to return a particular type (e.g., bool), but instead returns None or a mismatched type, it can result in unexpected behavior and the "null" log. Cheers, Ilia
  • Issue Retrieving Alpha Layer from a Layer in MultipassBitmap

    windows c++ 2024
    2
    0 Votes
    2 Posts
    439 Views
    ferdinandF
    Hello @T1001, Thank your for reaching out to us and for splitting your questions into multiple topics. But let's put this topic on hold here until we have asked your other question (which I set as the main question). Cheers, Ferdinand
  • Python - How to insert knots in c4d.Gradient

    python
    3
    0 Votes
    3 Posts
    527 Views
    V
    Thank you very much, @i_mazlov! This is what I needed!
  • Syntax highlight in VS Code under MacOS

    python macos
    4
    0 Votes
    4 Posts
    972 Views
    ferdinandF
    I would heavily recommend using the extension, as it will automatically curate the paths for you. I.e., when you use the extension and connect to a Cinema 4D instance, it will make sure that the dummy modules of that Cinema 4D version are on the search paths. But when you really do not want to use it, you can also just edit your config so that the dummy module paths are discoverable for auto complete and the linter. [image: 1731583351292-2a76cd6c-35aa-451f-82db-02b03694e72d-image.png] What you will need in any case, is the Python and Pylance extension for VS Code, as they are the extensions which make use of these settings. When you install the connector, they will be installed automatically as a dependency. [image: 1731583415824-0b5d77af-5f23-4203-9a0a-276b8eafc62e-image.png] Cheers, Ferdinand
  • C++ Import Custom Extension With Modal

    windows c++ 2024
    2
    0 Votes
    2 Posts
    388 Views
    i_mazlovI
    Hi @RyanTheDev, Welcome to the Maxon developers forum and its community, it is great to have you with us! Getting Started Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules. Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment. Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support. Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads. It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions. About your First Question Please elaborate on your question, there's no good reference or solution you can get without providing the context. What is a "custom file type"? do you mean you've implemented BaseSceneLoader plugin? When you try to open dialog? Is it happening on main thread? What's the code that does this? What does it mean "keeps failing" - does it give you error instead? You can also have a look at SCENEFILTER::DIALOGSALLOWED flag, if it's applicable in your case. Cheers, Ilia
  • Python - Set Take render state

    python
    4
    1
    0 Votes
    4 Posts
    708 Views
    J
    @ferdinand Okay I will do it in the future. Thanks for the code snippet, always helps to learn!
  • OpenUSD (pxr) library in c4d python

    python 2024
    17
    0 Votes
    17 Posts
    6k Views
    i_mazlovI
    Hi @llealloo, please excuse the delayed answers. To the best of my knowledge in the near future there're no plans for integrating usd python bindings into c4d python system. By the way, with the 2025.0 release internal usd library was properly updated to OpenUSD 24.08, so we expect the double loading usd issue to be solved under OSX. Cheers, Ilia
  • UserArea drag and drop example?

    windows 2024 python
    6
    0 Votes
    6 Posts
    2k Views
    K
    I tried using a timer to solve this problem, but I still want to know if there is a more direct way import c4d import threading from c4d.gui import GeUserArea, GeDialog GADGET_ID_GEUSERAREA = 10000 class DropArea(GeUserArea): def __init__(self): # Used to store all objects involved in the drag-and-drop operation self.currentDragObjects = [] # Flag to indicate whether a drag operation is in progress self.isDragging = False # Define a timer to delay the handling of the drag completion self.dragTimer = None def Message(self, msg, result): # Handle drag-and-drop messages if msg.GetId() == c4d.BFM_DRAGRECEIVE: # Check if the drag was lost or canceled if msg.GetInt32(c4d.BFM_DRAG_LOST) or msg.GetInt32(c4d.BFM_DRAG_ESC): self.isDragging = False return self.SetDragDestination(c4d.MOUSE_FORBIDDEN) # If the drag just started, clear the previous object list if not self.isDragging: self.currentDragObjects = [] # Initialize the storage list self.isDragging = True # Mark the beginning of the drag # Verify if it is a valid drop area if not self.CheckDropArea(msg, True, True): return self.SetDragDestination(c4d.MOUSE_FORBIDDEN) # Get the dragged file object dragInfo = self.GetDragObject(msg) if dragInfo is not None: dragObject = dragInfo['object'] # Check if the object already exists in the list to avoid duplicates if dragObject not in self.currentDragObjects: self.currentDragObjects.append(dragObject) # Reset the timer to delay the handling of drag completion if self.dragTimer is not None: self.dragTimer.cancel() # Set a short timer (e.g., 0.2 seconds) to determine if the drag operation is complete self.dragTimer = threading.Timer(0.2, self._finalize_drag) self.dragTimer.start() # Set the mouse cursor to a valid state return self.SetDragDestination(c4d.MOUSE_MOVE) # Call the base class Message() method to handle other messages return c4d.gui.GeUserArea.Message(self, msg, result) def _finalize_drag(self): # Delayed execution to ensure all dragged objects have been received self.isDragging = False if self.currentDragObjects: # Print all dropped files print(f"Dropped files: {self.currentDragObjects}") # Additional logic can be executed here, e.g., handling file paths or other content # Clear the object list for the next drag-and-drop operation self.currentDragObjects = [] # Redraw the user area (if UI update is needed) self.Redraw() class ExampleDialog(GeDialog): geUserArea = DropArea() def CreateLayout(self): self.SetTitle("Drag Area") if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=1, rows=0, title="", groupflags=0, initw=100, inith=100): self.GroupBorderSpace(8, 8, 8, 8) self.GroupSpace(2, 2) # Add the user area gadget self.AddUserArea(GADGET_ID_GEUSERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 200, 200) # Attach the user area to the gadget self.AttachUserArea(self.geUserArea, GADGET_ID_GEUSERAREA) self.GroupEnd() return True if __name__ == "__main__": global dlg dlg = ExampleDialog() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=200, defaulth=200)
  • How to set the active documents preview image

    windows python
    2
    0 Votes
    2 Posts
    446 Views
    ferdinandF
    Hey @MMayrh, Thank you for reaching out to us. This is not how this parameter works. The parameter DOCUMENT_PREVIEW_IMAGE is of data type BitmapButtonStruct, not of BaseBitmap. [image: 1731082043337-54c636b2-05c8-4e3a-af41-9edf7e80bd24-image.png] The documentation is a bit misleading here. This is not the document preview bitmap, but sort of the preview bitmap delegate. I.e., an entity that is used to retrieve a preview bitmap (for a document in this case). A BitmapButtonStruct wraps a node, an ID, and a dirty flag. [image: 1731082143508-3e4681a7-7db6-45b7-a1da-5279cc028cf2-image.png] This parameter does not make too much sense in the Python API, here is what the C++ API does when the parameter is access for a document: [image: 1731082401202-459e7ff6-a8fe-4abf-ae35-adc803c17170-image.png] I.e., it returns itself (the doc), the ID of the parameter (DOCUMENT_PREVIEW_IMAGE) and the dirty state of its internal current preview bitmap as the BitmapButtonStruct bbs. What you could technically try, is implement a node, e.g., an object, and then set that object as the preview provider for a document. Your node would for that have to implement MSG_DESCRIPTION_GETBITMAP, because that is what effectively will be called. But that is all very theoretical, DOCUMENT_PREVIEW_IMAGE is largely unused in our code base, and I do not see any implemnation for the SetParameter part. So, the document will likely just ignore you trying to overwrite its preview provider. There could be some base implemenation kicking in, but I doubt it. But what you definitely cannot do, is just set there a bitmap to overwrite the preview image of the document (assuming that was what you wanted to do). That would also not make too much sense since a document is constantly recalculating its preview image. So, on the next update that image would be gone (if it would work like that). Cheers, Ferdinand
  • How to Swap location in Object Manager

    c++ s26 windows
    3
    2
    0 Votes
    3 Posts
    798 Views
    P
    @ferdinand Thank you very much for your reply
  • TempUVHandle always None! Why?

    r21 python windows
    3
    0 Votes
    3 Posts
    790 Views
    ThomasBT
    @i_mazlov Thank you very much for the hint with the texture view and for the helpful links. The second thread I have already read, but was not able to find the solution so far. I study these examples. Thank you.
  • Finding duplicate materials - Octane Render

    python r19
    17
    0 Votes
    17 Posts
    3k Views
    John_DoJ
    Hi, sorry for bringing back up this topic but the Compare() method still gives weird results in 2024.5.1. [image: 1730828935913-cinema_4d_d5fwj9o4rq.gif] Comparing a material duplicated with Ctrl-Drag returns sometimes True, sometimes False Comparing a material against a copy-pasted version (in the same scene) always returns False Comparing two identical materials both copy-pasted together in one-go in another scene always returns False, even if True was returned in the original scene. Please note that I'm using Corona Materials here but results are the same with the Standard Material.