Navigation

    • Register
    • Login
        No matches found
    • Search
    1. Home
    2. fwilleke80
    fwilleke80

    Frank Willeke

    @fwilleke80

    Software Engineer

    32
    Reputation
    400
    Posts
    338
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online
    Website www.frankwilleke.de Location Berlin Age 42

    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups
    fwilleke80 Follow

    Best posts made by fwilleke80

    RE: Best way to update objects after preference change?

    Oh wait, I think I found a way. In case anybody else wants to know, here it is...

    In the PrefsDialogObject:

    Bool MyPrefsDialog::SetDParameter(GeListNode *node, const DescID &id,const GeData &t_data,DESCFLAGS_SET &flags)
    {
    	BaseContainer* bc = MyPlugin::GetPreferences();
    	if (!bc)
    		SUPER::SetDParameter(node, id, t_data, flags);
    	
    	switch (id[0].id)
    	{
    		// If PREFS_MYPLUGIN_SOMEVALUE was changed, store value and notify plugin objects in all open documents.
    		case PREFS_MYPLUGIN_SOMEVALUE:
    			bc->SetInt32(PREFS_MYPLUGIN_SOMEVALUE, t_data.GetInt32());
    			flags |= DESCFLAGS_SET::PARAM_SET;
    			
    			// Iterate open documents
    			for (BaseDocument *doc = GetFirstDocument(); doc; doc = doc->GetNext())
    			{
    				// Send broadcast message to each document, use unique ID
    				doc->MultiMessage(MULTIMSG_ROUTE::BROADCAST, MyPlugin::UNIQUE_ID_PREFS, nullptr);
    			}
    			
    			GeUpdateUI();
    			return true;
    	}
    	
    	return SUPER::SetDParameter(node, id, t_data, flags);
    }
    

    And then, in the plugin object:

    Bool MyPluginObject::Message(GeListNode *node, Int32 type, void *data)
    {
    	if (type == MyPlugin::UNIQUE_ID_PREFS)
    	{
    		GePrint("Aha! My prefs have changed!"_s);
    		return true;
    	}
    	return SUPER::Message(node, type, data);
    }
    
    posted in Cinema 4D SDK •
    RE: Python Source Protector: Can it be called via CLI?

    And in deed, having the option of executing the source protector using a command line argument for Cinema 4D, or using c4dpy would be great for integration in a plugin build pipeline.

    posted in Cinema 4D SDK •
    RE: Custom Tokens with Team Render Server

    Hi,
    I'll just chime in here, as I'm involved in that project, too.

    So the token hook needs to access certain elements of the scene to get their values, and the problem (thankfully) is easily reproducible.

    I wrote a sample plugin that recreates the behaviour by simply returning data from the first object in the scene. Download it from our dropbox: tokenhookbug.zip

    Here is the code:
    tokenhookbug_code.png

    This is the render setting in my example scene (which just contains a Cube):
    tokenhookbug_rendersetting.png

    Here is the render result in the Picture Viewer, notice the correct file name:
    tokenhookbug_result_pv.png

    Uploading and rendering the file on TeamRender produces this:
    tokenhookbug_result_tr.png

    The debugger clearly shows that doc->GetFirstObject() returns nullptr.

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: Shader that gets data from an object: Refresh

    It works like a charm!
    Thank you again!

    I was surprised at how little code was required.

    Sharing is caring. In case anyone needs it, here's the code:

    #include "ge_prepass.h"
    #include "c4d_general.h"
    #include "c4d_baselinkarray.h"
    #include "c4d_basedocument.h"
    
    ///
    /// \brief Registers observers and sends messages to them.
    ///
    class Observable
    {
    public:
    	///
    	/// \brief Subscribes a new observer.
    	///
    	/// \param[in] observer Pointer to an AtomGoal
    	/// \param[in] doc The document that owns the AtomGoal
    	///
    	/// \return A maxon error object if anything went wrong, otherwise maxon::OK
    	///
    	maxon::Result<void> Subscribe(C4DAtomGoal *observer, BaseDocument *doc);
    		
    	///
    	/// \brief Unsubscribes an observer
    	///
    	/// \param[in] observer Pointer to an AtomGoal that has previously been subscribed
    	/// \param[in] doc The document that owns the AtomGoal
    	///
    	void Unsubscribe(C4DAtomGoal *observer, BaseDocument *doc);
    		
    	///
    	/// \brief Sends a messages to all subscribed observers
    	///
    	/// \param[in] type Message type
    	/// \param[in] doc The document that owns the subscribed observers
    	/// \param[in] data Optional message data
    	///
    	void Message(Int32 type, BaseDocument *doc, void *data = nullptr) const;
    
    private:
    	BaseLinkArray _observers;
    };
    
    maxon::Result<void> Observable::Subscribe(C4DAtomGoal *observer, BaseDocument *doc)
    {
    	if (!observer)
    		return maxon::NullptrError(MAXON_SOURCE_LOCATION, "Observer must not be nullptr!"_s);
    
    	// Check if this observer is already registered
    	const Int32 observerIndex = _observers.Find(observer, doc);
    	if (observerIndex != NOTOK)
    		return maxon::OK;
    
    	// Register new observer
    	if (!_observers.Append(observer))
    	{
    		return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Failed to add observer to the list!"_s);
    	}
    
    	return maxon::OK;
    }
    
    void Observable::Unsubscribe(C4DAtomGoal *observer, BaseDocument *doc)
    {
    	if (observer && doc)
    	{
    		const Int32 observerIndex = _observers.Find(observer, doc);
    		if (observerIndex != NOTOK)
    		{
    			_observers.Remove(observerIndex);
    		}
    	}
    }
    
    void Observable::Message(Int32 type, BaseDocument *doc, void *data) const
    {
    	for (Int32 i = 0; i < _observers.GetCount(); ++i)
    	{
    		C4DAtomGoal *atom = _observers.GetIndex(i, doc);
    		if (atom)
    		{
    			atom->Message(type, data);
    		}
    	}
    }
    
    posted in Cinema 4D SDK •
    RE: Dynamic elements in a CYCLE, CYCLE empty after loading document?

    Hi Adam, happy new year to you, too!

    Since it works now, for some reason, I am pretty happy with what I have. However, since it might interest other plugin developers, I'll share more code. Maybe you have some tipps about improvements or potentially dangerous stuff, too.

    The idea is that the shader has a LINK field where the user can link an object (which is also part of my plugin). The object can (but doesn't have to) provide a list of "custom outputs" that will be added to the shader's CYCLE. In the screenshot below it's the "Difference Map".

    When a rendering is started, the shader will request the according data from the linked object during InitRender(). But that's not part of this thread 😉

    Screenshot 2021-01-26 at 11.42.45.png

    The shader's GetDDescription():

    Bool TerrainOperatorShader::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
    {
    	iferr_scope_handler
    	{
    		GePrint(err.GetMessage());
    		return false;
    	};
    
    	if (!description->LoadDescription(node->GetType()))
    		return false;
    	flags |= DESCFLAGS_DESC::LOADED;
    
    	BaseDocument* doc = node->GetDocument();
    	const BaseContainer& dataRef = static_cast<BaseShader*>(node)->GetDataInstanceRef();
    	
    	// Hide or show attributes, depending on shader mode
    	const Bool slopeMode = dataRef.GetInt32(XTERRAINOPERATORSHADER_DATA) == XTERRAINOPERATORSHADER_DATA_SLOPE;
    	TF4D::GUI::ShowDescription(node, description, XTERRAINOPERATORSHADER_SLOPE_DIRECTION_ENABLE, slopeMode);
    	TF4D::GUI::ShowDescription(node, description, XTERRAINOPERATORSHADER_SLOPE_DIRECTION, slopeMode);
    
    	// Get linked object
    	BaseObject *linkedObject = dataRef.GetObjectLink(XTERRAINOPERATORSHADER_OPERATORLINK, doc);
    	if (linkedObject)
    	{
    		// Get linked object's NodeData
    		TF4D::BaseTerrainOperatorData* linkedOperator = linkedObject->GetNodeData<TF4D::BaseTerrainOperatorData>();
    
    		// Get list of custom outputs (these are the elements to add to the CYCLE)
    		maxon::BaseArray<TF4D::GUI::CycleElementData> customOutputs;
    		if (linkedOperator->GetCustomOperatorOutputs(customOutputs))
    		{
    			if (!TF4D::GUI::AddCycleElements(node, description, XTERRAINOPERATORSHADER_DATA, customOutputs, true))
    				iferr_throw(maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not add LONG CYCLE elements!"_s));
    		}
    	}
    
    	return SUPER::GetDDescription(node, description, flags);
    }
    

    The linked object's NodeData's GetCustomOperatorOutputs():

    Bool ErosionOperator::GetCustomOperatorOutputs(maxon::BaseArray<TF4D::GUI::CycleElementData>& customOperatorOutputs) const
    {
    	iferr_scope_handler
    	{
    		GePrint(err.GetMessage());
    		return false;
    	};
    
    	customOperatorOutputs.Reset();
    
    	// GetCustomOutputName() simply returns a maxon::String
    	customOperatorOutputs.Append(TF4D::GUI::CycleElementData(TF4D_CUSTOMOUTPUT_EROSION_DIFFERENCE, GetCustomOutputName(TF4D_CUSTOMOUTPUT_EROSION_DIFFERENCE))) iferr_return;
    
    	return true;
    }
    

    Cheers,
    Frank

    Ah, damn. Now I've spoiled that I'm working on erosion for Terraform4D 😄

    posted in Cinema 4D SDK •
    RE: PySide2 Integration

    Why don't you avoid all those difficulties and simply implement that dialog using the C4D UI?

    posted in General Talk •
    RE: Save node data in Read and Write

    If you're storing data in the tag's BaseContainer, you don't need to override Write() and Read(). That's meant for private class member whose data would be lost otherwise.

    Also, you can remove the "return true" at the end of the functions. As you already return in the previous line, it will never be called.

    posted in Cinema 4D SDK •
    RE: Type Viewer not working in Visual Studio 2015

    I did today, including it in projectdefinition.txt worked smoothly, thank you!
    If I ever find out why copying it do the folders does not work, I'll post it here.

    posted in Cinema 4D SDK •
    RE: Threading & job questions

    Oh my god. the stupidest error.... 😵
    OK, question 1 solved already, thanks 😁

    posted in Cinema 4D SDK •
    RE: Creating and saving a 32bit grayscale bitmap

    Ah, great, thank for checking!
    Then I don't need to worry about my bmp code 🙂

    Cheers,
    Frank

    posted in Cinema 4D SDK •

    Latest posts made by fwilleke80

    RE: GeClipMap and init(BaseBitmap)

    Ah, learned something, too 🙂

    posted in Cinema 4D SDK •
    RE: Compiling for R20... linker error in maxon::String

    Hi Ferdinand,

    thanks for your reply!

    @ferdinand said in Compiling for R20... linker error in maxon::String:

    Are you sure there are no build fragments in your build directory, so that the linker/compiler cannot get confused? Visual Studio has sometimes the tendency to make a mess.
    I have made a full rebuild, and cleaned the build, the .vs, and the generated folder before. Is there anything else? Visual Studio does tend to make a mess 😆

    @ferdinand said in Compiling for R20... linker error in maxon::String:

    Regenerating/checking your solution could also solve the problem.
    What do you mean? Deleting the solution file, and making a new one?

    I wish I had tried R20 a bit more often. Last time is three months and hundreds of code changes ago 😢

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    Compiling for R20... linker error in maxon::String

    Hi,

    I know the support for R20 has ended, but maybe someone still has an idea about this:

    I'm building a project for R20 (I develop using mostly R25 for debugging), and it compiles without any warning or errors. However, linking fails with these errors:

    error LNK2019: unresolved external symbol "class maxon::String __cdecl ToString(class String const &,class maxon::FormatStatement const *,bool)" ([email protected]@[email protected]@@[email protected]@[email protected][email protected]) referenced in function "void __cdecl maxon::ToStrHlp<class String>(class maxon::String &,class String const *,class maxon::FormatStatement const *)" ([email protected]@@@[email protected]@[email protected]@[email protected]@[email protected]@Z)
    
    error LNK2019: unresolved external symbol "class maxon::String __cdecl ToString(class Filename const &,class maxon::FormatStatement const *,bool)" ([email protected]@[email protected]@@[email protected]@[email protected]@[email protected]) referenced in function "void __cdecl maxon::ToStrHlp<class Filename>(class maxon::String &,class Filename const *,class maxon::FormatStatement const *)" ([email protected]@@@[email protected]@[email protected]@[email protected]@[email protected]@@Z)
    

    Any idea where I should look to fix the error? Obviously, the problem has to do with some ToString() call. But I'm using these a lot throughout the code, and they when I last built for R20, there was no problem.

    Thanks in advance!

    Frank

    posted in Cinema 4D SDK •
    RE: GeClipMap and init(BaseBitmap)

    Hi,

    the SDK documentation says about GeClipMap::Init(BaseBitmap* bm):

    Loads the clip map bitmap from bm. Any previous data is lost.

    and about parameter bm:

    The bitmap to initialize the clip map with. The caller owns the pointed bitmap.

    Sounds like it's copying the bitmap. Casting probably won't work, as GeClipMap and BaseBitmap are not related by inheritance. To get to the clipmap's bitmap, you need to use GeClipMap::GetBitmap().

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: Sample a shader in 3D space

    Thanks, Paul! I'll try that out 🙂

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: older documentation links?

    You can download older SDK documentation versions here:
    https://developers.maxon.net/?page_id=1118

    posted in Cinema 4D SDK •
    RE: SendModelingCommand(MCOMMAND_SUBDIVIDE) broken in C4D 2023?

    Thank you, that fixed it.

    posted in Cinema 4D SDK •
    RE: SendModelingCommand(MCOMMAND_SUBDIVIDE) broken in C4D 2023?

    Interesting...

    If I put all code aside, simply start Cinema 4D 2023, and do the following:

    1. Create Cube
    2. Make Cube editable (with "c")
    3. Choose Mesh > Add > Subdivide (click the cogwheel icon)
    4. Set any settings, or don't change anything
    5. Click OK

    --> The cube does not change at all.

    Is MCOMMAND_SUBDIVIDE maybe completely broken?

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    SendModelingCommand(MCOMMAND_SUBDIVIDE) broken in C4D 2023?

    Hi,

    I have a function that looks like this:

    Bool SubdividePolygonObject(PolygonObject* const objectPtr, const maxon::Int32 subdivisions, const maxon::Bool sds)
    {
    	// Parameters for the modeling command
    	BaseContainer modelingCommandParameters;
    	modelingCommandParameters.SetBool(MDATA_SUBDIVIDE_HYPER, sds);
    	modelingCommandParameters.SetInt32(MDATA_SUBDIVIDE_SUB, subdivisions);
    
    	// Execute modeling command
    	ModelingCommandData modelingCommandData;
    	modelingCommandData.op = objectPtr;
    	modelingCommandData.bc = &modelingCommandParameters;
    	if (!SendModelingCommand(MCOMMAND_SUBDIVIDE, modelingCommandData))
    		return false;
    
    	return true;
    }
    

    Example usage:

    BaseContainer cubeData;
    basicObjectData.SetVector(PRIM_CUBE_LEN, maxon::Vector(100.0));
    cubeData.SetInt32(PRIM_CUBE_SUBX, 2);
    cubeData.SetInt32(PRIM_CUBE_SUBY, 2);
    cubeData.SetInt32(PRIM_CUBE_SUBZ, 2);
    
    PolygonObject* const objectPtr = static_cast<PolygonObject*>(GeneratePrimitive(nullptr, Ocube, cubeData, 1.0, false, hh->GetThread()));
    if (!SubdividePolygonObject(objectPtr, 5, true))
    	GePrint("Something went wrong."_s);
    

    This works fine in R20 - R25, but returns false in 2023.
    What could be the reason?

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: Linker error in new plugin project: DllMain already defined?

    Thanks, you just recieved it!

    posted in Cinema 4D SDK •