THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/12/2012 at 12:20, xxxxxxxx wrote:
Hello,
Can somebody please enlighten me about what exactly goes up when
GeListNode::InsertUnder() is called? Because, when I inserted the referenced
shader under my plugin shader, and clone the referenced shader internally
on ShaderData::InitRender() , but do not create any relationships with the clone
(i.e. I do not insert the cloned shader as child of my plugin shader), it works fine.
And it works fine, although the cloned shader, which is used for sampling, does,
or actually should not , know anything related to my plugin shader.
I could be satisfied with this, if it wouldn't scratch on Cinema's stability, but it
does. Almost always when the ShaderLink shader was used, closing Cinema 4D
will lead in undefined behavior and finally into a crash.
What I would like to do, is to find a way to build up the necessary relationships
without drowning Cinema's stability, by producing valid results. (I.e. inserting an
already inserted shader under my plugin shader, as I'm doing it, is not valid).
It seems like GeListNode::InsertUnder() does build up the relationships correctly,
but I am not able to reproduce it, since I do not know enough about the internals
or how the relationships must be built. The SDK documentation is leaking this
information.
In the following, you can find the code that results in satisfying results when
rendering (i.e. the referenced shader is always rendered and not just black,
the channel-preview is updated when the referenced shader is changed), but
involves easily crashing Cinema 4D.
// coding: utf-8
//
// Copyright (C) 2012, Niklas Rosenstein <[email protected]>
#include <c4d.h>
#include "ShaderLink.h"
#include "res/c4d_symbols.h"
class ShaderLinkData : public ShaderData {
private:
typedef ShaderData super;
BaseShader* iref;
public:
static NodeData* Alloc();
ShaderLinkData() : super(), iref(NULL) {
};
void AdjustShaderReference(BaseShader* shader);
// ShaderData
INITRENDERRESULT InitRender(BaseShader* shader, const InitRenderStruct& irs);
void FreeRender(BaseShader* shader);
Vector Output(BaseShader* shader, ChannelData* data);
// NodeData
Bool Init(GeListNode* node);
Bool Message(GeListNode* node, LONG type, void* data);
};
// ShaderLinkData
NodeData* ShaderLinkData::Alloc() {
return gNew ShaderLinkData;
}
void ShaderLinkData::AdjustShaderReference(BaseShader* shader) {
BaseDocument* doc = shader->GetDocument();
BaseContainer* container = shader->GetDataInstance();
if (!container || !doc) return;
BaseShader* reference = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc, Xbase);
if (!reference) return;
// Check if the referenced shader is already a child of the plugin shader.
BaseShader* child = shader->GetDown();
Bool reference_ischild = FALSE;
LONG childcount = 0;
while (child) {
if (child == reference) {
reference_ischild = TRUE;
break;
}
childcount++;
child = child->GetNext();
}
GePrint("The shader has " + LongToString(childcount) + " children.");
// Insert the referenced shader as child if it isn't already.
if (!reference_ischild) {
** reference->InsertUnder(shader);**
}
}
// ShaderLinkData - ShaderData
INITRENDERRESULT ShaderLinkData::InitRender(BaseShader* shader, const InitRenderStruct& irs) {
if (!shader) {
return INITRENDERRESULT_UNKNOWNERROR;
}
BaseDocument* doc = shader->GetDocument();
if (!doc) {
return INITRENDERRESULT_UNKNOWNERROR;
}
BaseContainer* container = shader->GetDataInstance();
if (!container) {
return INITRENDERRESULT_UNKNOWNERROR;
}
// Grab the reference from the container.
BaseShader* reference = (BaseShader* ) container->GetLink(SHADERLINK_REFERENCE, doc, Xbase);
** if (reference) {
this->iref = (BaseShader* ) reference->GetClone(COPYFLAGS_0, NULL);
if (!this->iref) {
return INITRENDERRESULT_OUTOFMEMORY;
}
return this->iref->InitRender(irs);
}**
else {
this->iref = NULL;
}
return INITRENDERRESULT_OK;
}
void ShaderLinkData::FreeRender(BaseShader* shader) {
// Free the internal reference when it was allocated.
if (this->iref) {
this->iref->FreeRender();
BaseShader::Free(this->iref);
this->iref = NULL;
}
}
Vector ShaderLinkData::Output(BaseShader* shader, ChannelData* data) {
// Redirect the ShaderData::Output() class to the reference shader or
// return black color.
if (this->iref) {
return this->iref->Sample(data);
}
else {
return Vector(0.0);
}
}
// ShaderLinkData - NodeData
Bool ShaderLinkData::Init(GeListNode* node) {
if (!node) return FALSE;
BaseShader* shader = (BaseShader* ) node;
BaseContainer* container = shader->GetDataInstance();
if (!container) return FALSE;
// Initialize the shaders parameters.
container->SetLink(SHADERLINK_REFERENCE, NULL);
return TRUE;
}
Bool ShaderLinkData::Message(GeListNode* node, LONG type, void* data) {
if (type == MSG_DESCRIPTION_POSTSETPARAMETER) {
this->AdjustShaderReference((BaseShader* )node);
}
return super::Message(node, type, data);
}
The complete source code, including res-files, is located here. It does
not contain a Visual Studio project or similar, as I'm building from the
command-line.
The zip-file located at the link above contains prebuilt binaries for
Windows x86 and x64, built with Cinema 4D R14.025.
I appreciate any help and information regarding this topic.
Thanks,
Niklas