diff --git a/src/clump.cpp b/src/clump.cpp
index 7ec69ca..05e26d9 100644
--- a/src/clump.cpp
+++ b/src/clump.cpp
@@ -40,9 +40,47 @@ Frame::create(void)
return f;
}
+Frame*
+Frame::cloneHierarchy(void)
+{
+ Frame *frame = this->cloneAndLink(NULL);
+ frame->purgeClone();
+ return frame;
+}
+
void
Frame::destroy(void)
{
+ this->destructPlugins();
+ Frame *parent = this->getParent();
+ Frame *child;
+ if(parent){
+ // remove from child list
+ child = parent->child;
+ if(child == this)
+ parent->child = this->next;
+ else{
+ for(child = child->next; child != this; child = child->next)
+ ;
+ child->next = this->next;
+ }
+ this->object.parent = NULL;
+ // Doesn't seem to make much sense, blame criterion.
+ this->setHierarchyRoot(this);
+ }
+ for(Frame *f = this->child; f; f = f->next)
+ f->object.parent = NULL;
+ free(this);
+}
+
+void
+Frame::destroyHierarchy(void)
+{
+ Frame *next;
+ for(Frame *child = this->child; child; child = next){
+ next = child->next;
+ child->destroyHierarchy();
+ }
this->destructPlugins();
free(this);
}
@@ -138,6 +176,43 @@ Frame::setDirty(void)
this->forAllChildren(dirtyCB, NULL);
}
+void
+Frame::setHierarchyRoot(Frame *root)
+{
+ this->root = root;
+ for(Frame *child = this->child; child; child = child->next)
+ child->setHierarchyRoot(root);
+}
+
+// Clone a frame hierarchy. Link cloned frames into Frame::root of the originals.
+Frame*
+Frame::cloneAndLink(Frame *clonedroot)
+{
+ Frame *frame = Frame::create();
+ if(clonedroot == NULL)
+ clonedroot = frame;
+ frame->object.copy(&this->object);
+ memcpy(frame->matrix, this->matrix, sizeof(this->matrix));
+ frame->root = clonedroot;
+ this->root = frame; // Remember cloned frame
+ for(Frame *child = this->child; child; child = child->next){
+ Frame *clonedchild = child->cloneAndLink(clonedroot);
+ clonedchild->next = frame->child;
+ frame->child = clonedchild;
+ clonedchild->object.parent = frame;
+ }
+ frame->copyPlugins(this);
+ return frame;
+}
+
+// Remove links to cloned frames from hierarchy.
+void
+Frame::purgeClone(void)
+{
+ Frame *parent = this->getParent();
+ this->setHierarchyRoot(parent ? parent->root : this);
+}
+
static Frame*
sizeCB(Frame *f, void *size)
{
@@ -176,7 +251,15 @@ Clump*
Clump::clone(void)
{
Clump *clump = Clump::create();
- // TODO actually clone
+ Frame *root = this->getFrame()->cloneHierarchy();
+ clump->setFrame(root);
+ FORLIST(lnk, this->atomics){
+ Atomic *a = Atomic::fromClump(lnk);
+ Atomic *atomic = a->clone();
+ atomic->setFrame(a->getFrame()->root);
+ clump->addAtomic(atomic);
+ }
+ root->purgeClone();
clump->copyPlugins(this);
return clump;
}
@@ -184,7 +267,14 @@ Clump::clone(void)
void
Clump::destroy(void)
{
+ Frame *f;
this->destructPlugins();
+ FORLIST(lnk, this->atomics)
+ Atomic::fromClump(lnk)->destroy();
+ FORLIST(lnk, this->lights)
+ Light::fromClump(lnk)->destroy();
+ if(f = this->getFrame())
+ f->destroyHierarchy();
free(this);
}
@@ -445,13 +535,19 @@ Atomic::create(void)
atomic->pipeline = NULL;
atomic->constructPlugins();
return atomic;
-}
+}
Atomic*
Atomic::clone()
{
Atomic *atomic = Atomic::create();
- //TODO
+ atomic->object.copy(&this->object);
+ atomic->object.privateFlags |= 1;
+ if(this->geometry){
+ atomic->geometry = this->geometry;
+ atomic->geometry->refCount++;
+ }
+ atomic->pipeline = this->pipeline;
atomic->copyPlugins(this);
return atomic;
}
@@ -459,8 +555,10 @@ Atomic::clone()
void
Atomic::destroy(void)
{
- //TODO
this->destructPlugins();
+ if(this->geometry)
+ this->geometry->destroy();
+ this->setFrame(NULL);
free(this);
}
diff --git a/src/rwobjects.h b/src/rwobjects.h
index b6a7d69..29125f7 100644
--- a/src/rwobjects.h
+++ b/src/rwobjects.h
@@ -64,6 +64,13 @@ struct Object
this->privateFlags = 0;
this->parent = NULL;
}
+ void copy(Object *o){
+ this->type = o->type;
+ this->subType = o->subType;
+ this->flags = o->flags;
+ this->privateFlags = o->privateFlags;
+ this->parent = NULL;
+ }
};
struct Frame : PluginBase
@@ -85,14 +92,22 @@ struct Frame : PluginBase
// MEM create, clonehiearchy, destroy, destroy hierarchy
static Frame *create(void);
+ Frame *cloneHierarchy(void);
void destroy(void);
-
+ void destroyHierarchy(void);
Frame *addChild(Frame *f);
Frame *removeChild(void);
Frame *forAllChildren(Callback cb, void *data);
+ Frame *getParent(void){
+ return (Frame*)this->object.parent;
+ }
int32 count(void);
void updateLTM(void);
void setDirty(void);
+
+ void setHierarchyRoot(Frame *root);
+ Frame *cloneAndLink(Frame *clonedroot);
+ void purgeClone(void);
};
Frame **makeFrameList(Frame *frame, Frame **flist);
@@ -515,6 +530,7 @@ struct Atomic : PluginBase
Atomic *clone(void);
void destroy(void);
void setFrame(Frame *f) { this->object.setFrame(f); }
+ Frame *getFrame(void) { return (Frame*)this->object.parent; }
static Atomic *fromClump(LLLink *lnk){
return LLLinkGetData(lnk, Atomic, inClump);
}
@@ -553,6 +569,12 @@ struct Clump : PluginBase
l->clump = this;
this->lights.append(&l->inClump);
}
+ void setFrame(Frame *f){
+ this->object.parent = f;
+ }
+ Frame *getFrame(void){
+ return (Frame*)this->object.parent;
+ }
static Clump *streamRead(Stream *stream);
bool streamWrite(Stream *stream);
uint32 streamGetSize(void);