Navigation

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

    Frank Willeke

    @fwilleke80

    Senior Software Developer

    29
    Reputation
    379
    Posts
    314
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online
    Website www.frankwilleke.de Location Berlin Age 41

    • 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: Xcode 13.3 throws framework build errors with R25

    Okay, thanks!

    posted in Cinema 4D SDK •
    RE: Ray Tracing In One Weekend

    Cool! Thanks for your community work, Kent!

    posted in Cinema 4D SDK •
    RE: StringToNumber to BaseTime

    Oh, ok. I assumed he just wanted to set the document min time and didn't know a better way to get a BaseTime than using StringToNumber.

    posted in Cinema 4D SDK •
    RE: Base Object - Attributes : Enabled parameter

    Since this question is tagged as C++, I'll add the docs link to the dedicated functions that return and set this attribute:
    BaseObject::GetDeformMode() and BaseObject::SetDeformMode()

    posted in Cinema 4D SDK •
    RE: StringToNumber to BaseTime

    If you simply want to set the document's min time, why not just do this:

    doc[c4d.DOCUMENT_MINTIME] = c4d.BaseTime(11)
    
    posted in Cinema 4D SDK •
    RE: macOS Monterey - Can't run source processor anymore?

    @m_adam said in macOS Monterey - Can't run source processor anymore?:

    So you have to link for example from /usr/local/bin to a python installation, I personally have Python 3.8.9.
    Xcode itself ships with a python version you could link to (its in Contents/Developer/usr/bin of the application package).
    So with that path you can call call sudo ln -s PATH_TO_PYTHON /usr/local/bin/python in terminal.

    Hi Adam!

    That is in deed what I tried, creating a symlink that points to Python 3. I didn't use the paths, though, but just linked the word "python" to "python3". I guess that was my mistake.

    Wouldn't it be easier for Maxon and everybody else, if you just changed the preprocessor call in the projects' PreBuild events to "python3", instead of having to go the symlink way and change things on users' computers (which, I guess, will have side effects when users later decide to install Python 2.7 for some reason)?

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: macOS Monterey - Can't run source processor anymore?

    Hi Ferdinand,

    Thanks! And no problem about delayed reply, I remember how it is with company meetings 😉 the problem is resolved now, that’s what counts.

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: macOS Monterey - Can't run source processor anymore?

    Ok, just for a test I reinstalled Python 2.7.18 today, and voilà! everything works again.
    I must say, I find it weird that the Maxon source processor relies on a Python version that has been discontinued since 1st Jan. 2020. It's probably about time to update it.

    Cheers,
    Frank

    posted in Cinema 4D SDK •
    RE: macOS Monterey - Can't run source processor anymore?

    I‘m indeed on macOS 12.3.1.

    Can’t really say when exactly the problem started, as this is normally not my development machine.

    posted in Cinema 4D SDK •
    RE: macOS Monterey - Can't run source processor anymore?

    Hi Kent,

    Thanks for your reply! I did not change anything on that machine. Project Tool has long been working, and so were the builds. I have no idea why it doesn’t work anymore, my only suspicion is that something got auto-updated. Strange…

    Cheers,
    Frank

    posted in Cinema 4D SDK •