Thanks! That worked for me!
Dan
Hi Ferdinand,
Thanks for the reply!
When you said to add volume.framework, did you mean like this? I'm working from the SDK examples for this test.
// Supported platforms - can be [Win64;OSX]
Platform=Win64;OSX
// Type of project - can be [Lib;DLL;App]
Type=DLL
// API dependencies
APIS=\
asset.framework;\
cinema.framework;\
cinema_hybrid.framework;\
crypt.framework;\
core.framework;\
command.framework;\
image.framework;\
math.framework;\
mesh_misc.framework;\
volume.framework;\
python.framework;
// C4D component
C4D=true
stylecheck.level=0 // must be set after c4d=true
stylecheck.enum-registration=false
stylecheck.enum-class=false
// Custom ID
ModuleId=net.maxonexample.cinema4dsdk
It doesn't seem to me working for me here, with maxon/volume.h not being found. I've tried a few others things but none of them seem to be working. Do I need to add the framework somewhere else as well?
Thanks again,
Dan
Hello! I was trying to get the Volume Object example working that's in the SDK here:
https://developers.maxon.net/docs/Cinema4DCPPSDK/html/page_manual_volumeobject.html
I'm having trouble having it successfully compile though.
The two headers I'm including:
#include "lib_volumeobject.h"
#include "lib_volumebuilder.h"
BaseObject* object = static_cast<BaseObject*>(node->GetDown());
// create VolumeObject
// This example checks if the given object is a volume builder.
// If so, it accesses the cache to get the VolumeObject.
if (object == nullptr)
return true;
// check if VolumeBuilder
if (object->IsInstanceOf(Ovolumebuilder) == false)
return true;
VolumeBuilder* const volumeBuilder = static_cast<VolumeBuilder*>(object);
// get cache
BaseObject* const cache = volumeBuilder->GetCache(nullptr);
if (cache == nullptr)
return true;
// check for volume object
if (cache->IsInstanceOf(Ovolume))
{
const VolumeObject* const volumeObject = static_cast<VolumeObject*>(cache);
const maxon::VolumeInterface* volInterface = volumeObject->GetVolume();
const maxon::String gridname2 = volInterface->GetGridName();
//Error:: Member access into incomplete type 'const maxon::VolumeInterface'
const maxon::Volume volume = volumeObject->GetVolume();
// Error:: No type named 'Volume' in namespace 'maxon'
const maxon::String gridName = volume.GetGridName();
DiagnosticOutput("Grid Name: @", gridName);
}
I'm having problems with these two bits:
const maxon::VolumeInterface* volInterface = volumeObject->GetVolume();
const maxon::String gridname2 = volInterface->GetGridName();
//Error:: Member access into incomplete type 'const maxon::VolumeInterface'
const maxon::Volume volume = volumeObject->GetVolume();
// Error:: No type named 'Volume' in namespace 'maxon'
Is there some sort of header that I need to include or is the example out of date?
Thanks for any help!
Dan
I checked it out and the issue is resolved!
Dan
Thanks Manuel,
I don't seem to have access to that level of the beta, but when I do I'll be sure to test it!
Dan
Hello, I'm experiencing a difference between 2023 and 2023. If I add a Constraint tag to a Cube in both versions they behave differently when made Editable.
In 2023 when there is a Constraint tag and the Cube is made Editable the Constraint Tag remains on the now Polygon Object.
In 2023.1 when there is a Constraint tag and the Cube is made Editable the Constraint Tag disappears on the now Polygon Object.
I'm seeing the same behavior on one of my plugins, where is now disappears, and I don't know if this is a bug or something I need to solve for. Any idea what the cause of this would be?
Dan
Hi Manuel,
I didn't think about CopyTo being called on undo. That might be all I need then, thanks. I did a couple tweaks and as of now everything is perfect.
Dan
Hello! I had a more general question about the proper way to do something within Cinema.
I want to have a 'Bake' button on my plugin that will do some of the heavy lifting as a single step, so that these calculations don't need to be done on a per update basis. I could create the needed data structures once and use those instead of constantly rebuilding them.
My question is what is the best way to implement this. My initial thought was to use a BaseArray of a custom Class to store the needed data. Something along the lines of one entry per child object to keep track of relationships and choices. Is this a valid way to go about it?
I was running into some problems with Read and Write, converting the Class to be read and written could be done though. One thing I was stumped on is that if I Free my BaseArray when the object is deleted then how would I bring it back if Undo was used?
Thanks for any help,
Dan
@m_adam Hi!
Thanks for looking into it!
Hi @ferdinand,
No worry on any delay. I did some addition checking with the description resource and I even completely removed the resource folder but I'm having the same thing happen, so that doesn't seem to be playing a part as far as I can tell.
Dan
Hello, I don't want to be pushy or bothersome. Just checking in to see if there is anything else I can provide or that I should look into. I know I initially responded late so I wouldn't blame anyone for this post being forgotten about.
Dan
@m_adam Hi Maxime, super sorry about the slow reply.
you can also upload GIF up to 4mb directly in the forum (just drag and drop it).
I'll keep this in mind in the future!
Do you override the Message method?
I was when I posted the test, but I removed it and nothing changed.
I saw that you use the flag DESCFLAGS_DESC::RECURSIONLOCK is there any reason for that? This prevent further evaluation and may cause the issue.
I shouldn't have been including this, but the issue still exists when I remedied the situation.
would it be possible to share you resource file?
My resource file is actually not doing anything in this case. I think there actually isn't one.
That all being said, it still works in R20 and doesn't in R24. Is there anything else I can test to help out?
Dan
Hello! I have a plugin that I compiled for R20 and R24 and I'm noticing a difference between the two of them.
Here is my plugin in R20:
And here is in R24:
In R20 the description is redrawn as the cube is dragged over. In R24 it isn't redrawn despite GetDDescription being called.
Here is my code, which is the same for each version, but they're behaving differently.
Bool ShortTest::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
{
if (!description->LoadDescription(node->GetType()))
{
}
BaseObject* op = static_cast<BaseObject*>(node);
if (op == nullptr)
{
return FALSE;
}
const DescID *singleid = description->GetSingleDescID();
DescID cid;
BaseContainer* datainstance = op->GetDataInstance();
DescID DescGroup = DescLevel(2000, DTYPE_GROUP, 0);
Int32 idShowNothing = 1;
Int32 idShowEverything = 2;
Int32 idMode = 10001;
if (!singleid || DescGroup.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_GROUP);
bc.SetString(DESC_NAME, "Object"_s);
bc.SetInt32(DESC_COLUMNS, 1);
bc.SetFloat(DESC_DEFAULT, 1);
bc.SetBool(DESC_SCALEH, TRUE);
bc.SetBool(DESC_DEFAULT, TRUE);
if (!description->SetParameter(DescGroup, bc, DescLevel(1057950)))
{
return TRUE;
}
}
cid = DescLevel(idMode, DTYPE_LONG, 0);
if (!singleid || cid.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_LONG);
bc.SetBool(DESC_FORBID_SCALING, TRUE);
bc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);
bc.SetBool(DESC_GUIOPEN, TRUE);
bc.SetString(DESC_NAME, "Test "_s);
BaseContainer MeasureDivisionNames;
// if (ModifiersNames == emptyBC) return TRUE;
MeasureDivisionNames.SetString(idShowNothing, "Show Nothing"_s);
MeasureDivisionNames.SetString(idShowEverything, "Show Parameters"_s);
bc.SetInt32(DESC_CUSTOMGUI, ID_QUICKTABSRADIO_GADGET);
bc.SetContainer(DESC_CYCLE, MeasureDivisionNames);
if (!description->SetParameter(cid, bc, DescGroup))
return TRUE;
}
if(datainstance->GetInt32(idMode) == idShowEverything)
{
cid = DescLevel(2002, DTYPE_REAL, 0);
if (!singleid || cid.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_REAL);
bc.SetInt32(DESC_UNIT,FORMAT_DEGREE);
bc.SetBool(DESC_FORBID_SCALING, TRUE);
bc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);
bc.SetString(DESC_NAME, "Test 1"_s);
BaseContainer MeasureDivisionNames;
if (!description->SetParameter(cid, bc, DescGroup))
return TRUE;
}
cid = DescLevel(2003, DTYPE_VECTOR, 0);
if (!singleid || cid.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_VECTOR);
bc.SetBool(DESC_FORBID_SCALING, TRUE);
bc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);
bc.SetString(DESC_NAME, "Test 2"_s);
BaseContainer MeasureDivisionNames;
if (!description->SetParameter(cid, bc, DescGroup))
return TRUE;
}
cid = DescLevel(2004, DTYPE_BOOL, 0);
if (!singleid || cid.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_BOOL);
bc.SetBool(DESC_FORBID_SCALING, TRUE);
bc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);
bc.SetString(DESC_NAME, "Test 3"_s);
BaseContainer MeasureDivisionNames;
if (!description->SetParameter(cid, bc, DescGroup))
return TRUE;
}
cid = DescLevel(2005, DTYPE_BOOL, 0);
if (!singleid || cid.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_BOOL);
bc.SetBool(DESC_FORBID_SCALING, TRUE);
bc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);
bc.SetString(DESC_NAME, "Test 4"_s);
BaseContainer MeasureDivisionNames;
if (!description->SetParameter(cid, bc, DescGroup))
return TRUE;
}
cid = DescLevel(2006, DTYPE_BOOL, 0);
if (!singleid || cid.IsPartOf(*singleid, NULL))
{
BaseContainer bc;
bc = GetCustomDataTypeDefault(DTYPE_BOOL);
bc.SetBool(DESC_FORBID_SCALING, TRUE);
bc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);
bc.SetString(DESC_NAME, "Test 5"_s);
BaseContainer MeasureDivisionNames;
if (!description->SetParameter(cid, bc, DescGroup))
return TRUE;
}
}
flags |= DESCFLAGS_DESC::LOADED| DESCFLAGS_DESC::RECURSIONLOCK;
return SUPER::GetDDescription(node, description, flags);
}
Any idea why there is the difference between versions of Cinema?
Thanks, Dan
Thanks, that was exactly what I needed!
Here's the code I wrote. From what I can tell it gets the job done but it seems to get slow fast when the caches get big. Is there a better way to do this?
CompleteDirtyCheck(BaseObject* checkobject, DIRTYFLAGS flags, maxon::BaseArray<Int32>* dirtyvalues)
{
if (checkobject == nullptr)
{
return ;
}
Int32 dvalue = checkobject->GetDirty(flags);
dirtyvalues->Append(dvalue);
BaseObject* cache = checkobject->GetCache();
if (cache == nullptr)
{
return;
}
maxon::BaseArray<BaseObject*> caches;
GetChildren(cache, &caches);
Int32 childcount = caches.GetCount();
for (Int32 x = 0; x<childcount; x++)
{
BaseObject* subcache = caches[x]->GetCache();
CompleteDirtyCheck(subcache,flags,dirtyvalues);
Int32 dirtyvalue = caches[x]->GetDirty(flags);
dirtyvalues->Append(dirtyvalue);
BaseObject* deformcache = caches[x]->GetDeformCache();
if (deformcache!=nullptr)
{
Int32 dirtyvalue2 = deformcache->GetDirty(flags);
dirtyvalues->Append(dirtyvalue2);
}
}
Hello! I'm having an issue with detecting whether and input object is dirty or not. For reference here is my scene file: Voronoi Fracture.c4d
My understanding is that the Random Effector is making changes to making changes to the Voronoi Fracture's Cache.
I don't understand why checking GetDirty(DIRTYFLAGS::CACHE) isn't returning dirty in this case. Is there something beyond that should be done?
The other test I was doing was browsing through the cache via GetCache(), GetDown and GetNext and checking each individual part of the Cache for it being dirty. This does correctly return whether it is dirty or not, but this really slow to me, especially for something that would be running so often.
What is the best way to reliably get if the Voronoi Fracture is dirty?
Dan
Hi Maxime,
I don't fully understand what you mean. Does my object being a child of the effector matter? If my object is a child of the effector how would I get the result from it?
Dan
Hello!
Is it possible to sample an Effector like it is a Field?
I've done some searching around, but I'm not super familiar with Effectors so I'm not sure if I 100% understand them. I'm looking to do something similar to the MoSpline, where I could feed in a vector and get an output to create something from.
Is there a manual or post to reference? I saw a few, but they don't seem to be exactly on this topic or I missed them.
Thanks,
Dan
Hi @ferdinand !
Thank you for all the help! I think that wraps up my question, not the answer I wanted, but it all makes sense and I know a bit more about what how Fields work.
I'll look into ModifyObjects more as well.
Dan
Hi @ferdinand , thank you for the impressive write up!
I'm not the most familiar with Deformers, so I have a couple of questions on that front. This does seem out of scope of the initial question, but I'm not sure if I should make a different thread or not.
With your cube example: This works because the Bulge deformer is looking at Cache of the Cube and then returning the Deform Cache of it, right? So there is no infinite loop because it isn't modify the Deform Cache.
Is a Deformer capable of doing what I need it to in this case? My understanding is that a Deformer generally moves points around and the like. What I want is to get a float value from the Field to then generator a different cache with that value in GetContour. This wouldn't be just moving points around, but creating completely new ones or utterly changes existing ones.
This seems like it would have the same problem, since my main plugin wouldn't be modified, but recalculating based on changes from the Deformer. So the Cache would rebuild which would trigger infinite rebuilds as a result.
Dan