From 6b53d759970aa157e7b669dca32bd51302a907ac Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Thu, 1 Apr 2010 23:00:05 +0200 Subject: [PATCH] Implement mesh serialization --- src/game/object/C4DefGraphics.h | 2 +- src/game/object/C4MeshAnimation.cpp | 224 ++++++++++++++++++-- src/game/object/C4MeshAnimation.h | 200 +++++++++++------- src/game/object/C4Object.cpp | 97 +++++++++ src/game/object/C4Object.h | 17 ++ src/game/script/C4Script.cpp | 4 +- src/platform/StdMesh.cpp | 315 +++++++++++++++++++++++++++- src/platform/StdMesh.h | 129 ++++++++++-- 8 files changed, 879 insertions(+), 109 deletions(-) diff --git a/src/game/object/C4DefGraphics.h b/src/game/object/C4DefGraphics.h index a782714f8..a120c97d8 100644 --- a/src/game/object/C4DefGraphics.h +++ b/src/game/object/C4DefGraphics.h @@ -197,7 +197,7 @@ protected: C4DefGraphics *pSourceGfx; // source graphics - used for savegame saving and comparisons in ReloadDef char Action[C4MaxName+1]; // action used as overlay in source gfx C4TargetFacet fctBlit; // current blit data for bitmap graphics - StdMeshInstance* pMeshInstance; // current blit data for mesh graphics + StdMeshInstance* pMeshInstance; // NoSave // - current blit data for mesh graphics uint32_t dwBlitMode; // extra parameters for additive blits, etc. uint32_t dwClrModulation; // colormod for this overlay C4ObjectPtr OverlayObj; // object to be drawn as overlay in MODE_Object diff --git a/src/game/object/C4MeshAnimation.cpp b/src/game/object/C4MeshAnimation.cpp index edc4c5b42..15aaa4c5e 100644 --- a/src/game/object/C4MeshAnimation.cpp +++ b/src/game/object/C4MeshAnimation.cpp @@ -22,6 +22,25 @@ #include "C4ValueList.h" #include "C4Game.h" +namespace +{ + // Register value providers for serialization + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderConstID("const"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderLinearID("linear"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderXID("x"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderYID("y"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderAbsXID("absx"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderAbsYID("absy"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderXDirID("xdir"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderYDirID("ydir"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderRDirID("rdir"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderCosRID("cosr"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderSinRID("sinr"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderCosVID("cosv"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderSinVID("sinv"); + const StdMeshInstance::SerializableValueProvider::ID C4ValueProviderActionID("action"); +} + StdMeshInstance::ValueProvider* CreateValueProviderFromArray(C4Object* pForObj, C4ValueArray& Data) { int32_t type = Data[0].getInt(); @@ -114,7 +133,31 @@ bool C4ValueProviderLinear::Execute() return true; } -C4ValueProviderX::C4ValueProviderX(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): +void C4ValueProviderLinear::CompileFunc(StdCompiler* pComp) +{ + const StdEnumEntry Endings[] = + { + { "Loop", ANIM_Loop }, + { "Hold", ANIM_Hold }, + { "Remove", ANIM_Remove }, + + { NULL, static_cast(0) } + }; + + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Length); + pComp->Seperator(); + pComp->Value(mkEnumAdapt(Ending, Endings)); + pComp->Seperator(); + pComp->Value(LastTick); +} + +C4ValueProviderX::C4ValueProviderX(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): Object(object), Begin(begin), End(end), Length(length), LastX(object->fix_x) { Value = pos; @@ -144,7 +187,22 @@ bool C4ValueProviderX::Execute() return true; } -C4ValueProviderY::C4ValueProviderY(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): +void C4ValueProviderX::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Length); + pComp->Seperator(); + pComp->Value(LastX); +} + +C4ValueProviderY::C4ValueProviderY(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): Object(object), Begin(begin), End(end), Length(length), LastY(object->fix_y) { Value = pos; @@ -174,7 +232,22 @@ bool C4ValueProviderY::Execute() return true; } -C4ValueProviderAbsX::C4ValueProviderAbsX(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): +void C4ValueProviderY::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Length); + pComp->Seperator(); + pComp->Value(LastY); +} + +C4ValueProviderAbsX::C4ValueProviderAbsX(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): Object(object), Begin(begin), End(end), Length(length), LastX(object->fix_x) { Value = pos; @@ -192,7 +265,22 @@ bool C4ValueProviderAbsX::Execute() return true; } -C4ValueProviderAbsY::C4ValueProviderAbsY(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): +void C4ValueProviderAbsX::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Length); + pComp->Seperator(); + pComp->Value(LastX); +} + +C4ValueProviderAbsY::C4ValueProviderAbsY(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length): Object(object), Begin(begin), End(end), Length(length), LastY(object->fix_y) { Value = pos; @@ -210,20 +298,47 @@ bool C4ValueProviderAbsY::Execute() return true; } -C4ValueProviderXDir::C4ValueProviderXDir(const C4Object* object, FIXED begin, FIXED end, FIXED max_xdir): +void C4ValueProviderAbsY::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Length); + pComp->Seperator(); + pComp->Value(LastY); +} + +C4ValueProviderXDir::C4ValueProviderXDir(C4Object* object, FIXED begin, FIXED end, FIXED max_xdir): Object(object), Begin(begin), End(end), MaxXDir(max_xdir) { Execute(); } - bool C4ValueProviderXDir::Execute() { Value = Begin + (End - Begin) * Min(Abs(Object->xdir/MaxXDir), itofix(1)); return true; } -C4ValueProviderYDir::C4ValueProviderYDir(const C4Object* object, FIXED begin, FIXED end, FIXED max_ydir): +void C4ValueProviderXDir::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(MaxXDir); +} + +C4ValueProviderYDir::C4ValueProviderYDir(C4Object* object, FIXED begin, FIXED end, FIXED max_ydir): Object(object), Begin(begin), End(end), MaxYDir(max_ydir) { Execute(); @@ -235,7 +350,20 @@ bool C4ValueProviderYDir::Execute() return true; } -C4ValueProviderRDir::C4ValueProviderRDir(const C4Object* object, FIXED begin, FIXED end, FIXED max_rdir): +void C4ValueProviderYDir::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(MaxYDir); +} + +C4ValueProviderRDir::C4ValueProviderRDir(C4Object* object, FIXED begin, FIXED end, FIXED max_rdir): Object(object), Begin(begin), End(end), MaxRDir(max_rdir) { Execute(); @@ -247,7 +375,20 @@ bool C4ValueProviderRDir::Execute() return true; } -C4ValueProviderCosR::C4ValueProviderCosR(const C4Object* object, FIXED begin, FIXED end, FIXED offset): +void C4ValueProviderRDir::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(MaxRDir); +} + +C4ValueProviderCosR::C4ValueProviderCosR(C4Object* object, FIXED begin, FIXED end, FIXED offset): Object(object), Begin(begin), End(end), Offset(offset) { Execute(); @@ -259,7 +400,20 @@ bool C4ValueProviderCosR::Execute() return true; } -C4ValueProviderSinR::C4ValueProviderSinR(const C4Object* object, FIXED begin, FIXED end, FIXED offset): +void C4ValueProviderCosR::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Offset); +} + +C4ValueProviderSinR::C4ValueProviderSinR(C4Object* object, FIXED begin, FIXED end, FIXED offset): Object(object), Begin(begin), End(end), Offset(offset) { Execute(); @@ -271,7 +425,20 @@ bool C4ValueProviderSinR::Execute() return true; } -C4ValueProviderCosV::C4ValueProviderCosV(const C4Object* object, FIXED begin, FIXED end, FIXED offset): +void C4ValueProviderSinR::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Offset); +} + +C4ValueProviderCosV::C4ValueProviderCosV(C4Object* object, FIXED begin, FIXED end, FIXED offset): Object(object), Begin(begin), End(end), Offset(offset) { Execute(); @@ -287,7 +454,20 @@ bool C4ValueProviderCosV::Execute() return true; } -C4ValueProviderSinV::C4ValueProviderSinV(const C4Object* object, FIXED begin, FIXED end, FIXED offset): +void C4ValueProviderCosV::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Offset); +} + +C4ValueProviderSinV::C4ValueProviderSinV(C4Object* object, FIXED begin, FIXED end, FIXED offset): Object(object), Begin(begin), End(end), Offset(offset) { Execute(); @@ -303,6 +483,19 @@ bool C4ValueProviderSinV::Execute() return true; } +void C4ValueProviderSinV::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); + pComp->Seperator(); + pComp->Value(Begin); + pComp->Seperator(); + pComp->Value(End); + pComp->Seperator(); + pComp->Value(Offset); +} + C4ValueProviderAction::C4ValueProviderAction(C4Object* object): Object(object) { @@ -325,3 +518,10 @@ bool C4ValueProviderAction::Execute() return true; } + +void C4ValueProviderAction::CompileFunc(StdCompiler* pComp) +{ + SerializableValueProvider::CompileFunc(pComp); + pComp->Seperator(); + pComp->Value(Object); +} diff --git a/src/game/object/C4MeshAnimation.h b/src/game/object/C4MeshAnimation.h index a9dd14cb0..353578ca9 100644 --- a/src/game/object/C4MeshAnimation.h +++ b/src/game/object/C4MeshAnimation.h @@ -22,6 +22,7 @@ #define INC_C4MeshAnimation #include "StdMesh.h" +#include "C4ObjectPtr.h" class C4Action; class C4Object; @@ -53,188 +54,239 @@ enum C4AnimationEnding }; // Keep a constant value -class C4ValueProviderConst: public StdMeshInstance::ValueProvider +class C4ValueProviderConst: public StdMeshInstance::SerializableValueProvider { public: + C4ValueProviderConst() {} C4ValueProviderConst(FIXED value); virtual bool Execute(); }; // Interpolate linearly in time between two values -class C4ValueProviderLinear: public StdMeshInstance::ValueProvider +class C4ValueProviderLinear: public StdMeshInstance::SerializableValueProvider { public: + C4ValueProviderLinear(): Begin(Fix0), End(Fix0), Length(0), Ending(ANIM_Loop), LastTick(0) {} C4ValueProviderLinear(FIXED pos, FIXED begin, FIXED end, int32_t length, C4AnimationEnding ending); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); private: - const FIXED Begin; - const FIXED End; - const int32_t Length; - const C4AnimationEnding Ending; + FIXED Begin; + FIXED End; + int32_t Length; + C4AnimationEnding Ending; int32_t LastTick; }; -class C4ValueProviderX: public StdMeshInstance::ValueProvider +class C4ValueProviderX: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderX(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); + C4ValueProviderX(): Object(NULL), Begin(Fix0), End(Fix0), Length(0), LastX(Fix0) {} + C4ValueProviderX(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const int32_t Length; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + int32_t Length; FIXED LastX; }; -class C4ValueProviderY: public StdMeshInstance::ValueProvider +class C4ValueProviderY: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderY(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); + C4ValueProviderY(): Object(NULL), Begin(Fix0), End(Fix0), Length(0), LastY(Fix0) {} + C4ValueProviderY(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const int32_t Length; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + int32_t Length; FIXED LastY; }; -class C4ValueProviderAbsX: public StdMeshInstance::ValueProvider +class C4ValueProviderAbsX: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderAbsX(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); + C4ValueProviderAbsX(): Object(NULL), Begin(Fix0), End(Fix0), Length(0), LastX(Fix0) {} + C4ValueProviderAbsX(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const int32_t Length; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + int32_t Length; FIXED LastX; }; -class C4ValueProviderAbsY: public StdMeshInstance::ValueProvider +class C4ValueProviderAbsY: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderAbsY(const C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); + C4ValueProviderAbsY(): Object(NULL), Begin(Fix0), End(Fix0), Length(0), LastY(Fix0) {} + C4ValueProviderAbsY(C4Object* object, FIXED pos, FIXED begin, FIXED end, int32_t length); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const int32_t Length; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + int32_t Length; FIXED LastY; }; -class C4ValueProviderXDir: public StdMeshInstance::ValueProvider +class C4ValueProviderXDir: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderXDir(const C4Object* object, FIXED begin, FIXED end, FIXED max_xdir); + C4ValueProviderXDir(): Object(NULL), Begin(Fix0), End(Fix0), MaxXDir(Fix0) {} + C4ValueProviderXDir(C4Object* object, FIXED begin, FIXED end, FIXED max_xdir); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED MaxXDir; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED MaxXDir; }; -class C4ValueProviderYDir: public StdMeshInstance::ValueProvider +class C4ValueProviderYDir: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderYDir(const C4Object* object, FIXED begin, FIXED end, FIXED max_ydir); + C4ValueProviderYDir(): Object(NULL), Begin(Fix0), End(Fix0), MaxYDir(Fix0) {} + C4ValueProviderYDir(C4Object* object, FIXED begin, FIXED end, FIXED max_ydir); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED MaxYDir; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED MaxYDir; }; -class C4ValueProviderRDir: public StdMeshInstance::ValueProvider +class C4ValueProviderRDir: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderRDir(const C4Object* object, FIXED begin, FIXED end, FIXED max_rdir); + C4ValueProviderRDir(): Object(NULL), Begin(Fix0), End(Fix0), MaxRDir(Fix0) {} + C4ValueProviderRDir(C4Object* object, FIXED begin, FIXED end, FIXED max_rdir); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED MaxRDir; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED MaxRDir; }; -class C4ValueProviderCosR: public StdMeshInstance::ValueProvider +class C4ValueProviderCosR: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderCosR(const C4Object* object, FIXED begin, FIXED end, FIXED offset); + C4ValueProviderCosR(): Object(NULL), Begin(Fix0), End(Fix0), Offset(Fix0) {} + C4ValueProviderCosR(C4Object* object, FIXED begin, FIXED end, FIXED offset); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED Offset; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED Offset; }; -class C4ValueProviderSinR: public StdMeshInstance::ValueProvider +class C4ValueProviderSinR: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderSinR(const C4Object* object, FIXED begin, FIXED end, FIXED offset); + C4ValueProviderSinR(): Object(NULL), Begin(Fix0), End(Fix0), Offset(Fix0) {} + C4ValueProviderSinR(C4Object* object, FIXED begin, FIXED end, FIXED offset); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED Offset; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED Offset; }; -class C4ValueProviderCosV: public StdMeshInstance::ValueProvider +class C4ValueProviderCosV: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderCosV(const C4Object* object, FIXED begin, FIXED end, FIXED offset); + C4ValueProviderCosV(): Object(NULL), Begin(Fix0), End(Fix0), Offset(Fix0) {} + C4ValueProviderCosV(C4Object* object, FIXED begin, FIXED end, FIXED offset); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED Offset; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED Offset; }; -class C4ValueProviderSinV: public StdMeshInstance::ValueProvider +class C4ValueProviderSinV: public StdMeshInstance::SerializableValueProvider { public: - C4ValueProviderSinV(const C4Object* object, FIXED begin, FIXED end, FIXED offset); + C4ValueProviderSinV(): Object(NULL), Begin(Fix0), End(Fix0), Offset(Fix0) {} + C4ValueProviderSinV(C4Object* object, FIXED begin, FIXED end, FIXED offset); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - const C4Object* const Object; - const FIXED Begin; - const FIXED End; - const FIXED Offset; + C4ObjectPtr Object; + FIXED Begin; + FIXED End; + FIXED Offset; }; -class C4ValueProviderAction: public StdMeshInstance::ValueProvider +class C4ValueProviderAction: public StdMeshInstance::SerializableValueProvider { public: + C4ValueProviderAction(): Object(NULL) {} C4ValueProviderAction(C4Object* object); virtual bool Execute(); + virtual void CompileFunc(StdCompiler* pComp); + virtual void DenumeratePointers() { Object.DenumeratePointers(); } + virtual void EnumeratePointers() { Object.EnumeratePointers(); } private: - C4Object* Object; + C4ObjectPtr Object; }; // Reference another value (which is convertible to FIXED), and optionally scale it diff --git a/src/game/object/C4Object.cpp b/src/game/object/C4Object.cpp index 991a3be41..190592efc 100644 --- a/src/game/object/C4Object.cpp +++ b/src/game/object/C4Object.cpp @@ -53,6 +53,75 @@ #include #include +namespace +{ + const StdMeshInstance::AttachedMesh::DenumeratorFactoryFunc C4MeshDenumeratorFactory = StdMeshInstance::AttachedMesh::DenumeratorFactory; +} + +void C4MeshDenumerator::CompileFunc(StdCompiler* pComp, StdMeshInstance::AttachedMesh* attach) +{ + if(pComp->isCompiler()) + { + int32_t def; + pComp->Value(mkNamingCountAdapt(def, "ChildInstance")); + + if(def) + { + C4DefGraphics* pGfx = NULL; + pComp->Value(mkNamingAdapt(C4DefGraphicsAdapt(pGfx), "ChildMesh")); + if(pGfx->Type != C4DefGraphics::TYPE_Mesh) + pComp->excCorrupt("ChildMesh points to non-mesh graphics"); + assert(!attach->Child); + pComp->Value(mkParAdapt(mkNamingContextPtrAdapt(attach->Child, *pGfx->Mesh, "ChildInstance"), C4MeshDenumeratorFactory)); + attach->OwnChild = true; // Delete the newly allocated child instance when the parent instance is gone + } + else + { + pComp->Value(mkNamingAdapt(Object, "ChildObject")); + attach->OwnChild = false; // Keep child instance when parent instance is gone since it belongs to a different object + } + } + else + { + int32_t def = 0; + if(Def) ++def; + pComp->Value(mkNamingCountAdapt(def, "ChildInstance")); + + if(Def) + { + assert(attach->OwnChild); + C4DefGraphics* pGfx = &Def->Graphics; + assert(pGfx->Type != C4DefGraphics::TYPE_Mesh); + pComp->Value(mkNamingAdapt(C4DefGraphicsAdapt(pGfx), "ChildMesh")); + pComp->Value(mkParAdapt(mkNamingContextPtrAdapt(attach->Child, *pGfx->Mesh, "ChildInstance"), C4MeshDenumeratorFactory)); + } + else + { + assert(!attach->OwnChild); + pComp->Value(mkNamingAdapt(Object, "ChildObject")); + } + } +} + +void C4MeshDenumerator::EnumeratePointers(StdMeshInstance::AttachedMesh* attach) +{ + Object.EnumeratePointers(); +} + +void C4MeshDenumerator::DenumeratePointers(StdMeshInstance::AttachedMesh* attach) +{ + Object.DenumeratePointers(); + + // Set child instance of attach after denumeration + if(Object) + { + assert(!attach->OwnChild); + assert(!attach->Child || attach->Child == Object->pMeshInstance); + if(!attach->Child) + attach->Child = Object->pMeshInstance; + } +} + void DrawVertex(C4Facet &cgo, int32_t tx, int32_t ty, int32_t col, int32_t contact) { if (Inside(tx,1,cgo.Wdt-2) && Inside(ty,1,cgo.Hgt-2)) @@ -2708,6 +2777,24 @@ void C4Object::CompileFunc(StdCompiler *pComp) pComp->Value(mkNamingPtrAdapt( pEffects, "Effects" )); pComp->Value(mkNamingAdapt( C4GraphicsOverlayListAdapt(pGfxOverlay),"GfxOverlay", (C4GraphicsOverlay *)NULL)); + // Serialize mesh instance if we have a mesh graphics + if(pGraphics->Type == C4DefGraphics::TYPE_Mesh) + { + if(pComp->isCompiler()) + { + assert(!pMeshInstance); + pMeshInstance = new StdMeshInstance(*pGraphics->Mesh); + } + + pComp->Value(mkNamingAdapt(mkParAdapt(*pMeshInstance, C4MeshDenumeratorFactory), "Mesh")); + + // Does not work because unanimated meshes without attached meshes + // do not even write a [Mesh] header so this does not create a mesh instance in that case +/* pComp->Value(mkNamingContextPtrAdapt( pMeshInstance, *pGraphics->Mesh, "Mesh")); + if(!pMeshInstance) + pComp->excCorrupt("Mesh graphics without mesh instance");*/ + } + if (PhysicalTemporary) { pComp->FollowName("Physical"); @@ -2766,7 +2853,11 @@ void C4Object::CompileFunc(StdCompiler *pComp) // Set Action animation by slot 0 if (pMeshInstance) + { Action.Animation = pMeshInstance->GetRootAnimationForSlot(0); + if ( ((ColorMod >> 24) & 0xff) != 0xff) // Sort faces if the object is transparent + pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest); + } // if on fire but no effect is present (old-style savegames), re-incinerate int32_t iFireNumber; @@ -2806,6 +2897,9 @@ void C4Object::EnumeratePointers() if (pGfxOverlay) for (C4GraphicsOverlay *pGfxOvrl = pGfxOverlay; pGfxOvrl; pGfxOvrl = pGfxOvrl->GetNext()) pGfxOvrl->EnumeratePointers(); + + // mesh instance + if (pMeshInstance) pMeshInstance->EnumeratePointers(); } void C4Object::DenumeratePointers() @@ -2831,6 +2925,9 @@ void C4Object::DenumeratePointers() if (pGfxOverlay) for (C4GraphicsOverlay *pGfxOvrl = pGfxOverlay; pGfxOvrl; pGfxOvrl = pGfxOvrl->GetNext()) pGfxOvrl->DenumeratePointers(); + + // mesh instance + if (pMeshInstance) pMeshInstance->DenumeratePointers(); } void C4Object::DrawPicture(C4Facet &cgo, bool fSelected, C4RegionList *pRegions) diff --git a/src/game/object/C4Object.h b/src/game/object/C4Object.h index c66d26484..51b8f605c 100644 --- a/src/game/object/C4Object.h +++ b/src/game/object/C4Object.h @@ -85,6 +85,23 @@ class C4Command; class C4MaterialList; class C4Player; +// Helper struct to serialize an object's mesh instance with other object's mesh instances attached +class C4MeshDenumerator: public StdMeshInstance::AttachedMesh::Denumerator +{ +private: + C4Def* Def; // Set if a definition mesh was attached + C4ObjectPtr Object; // Set if an instance mesh was attached + +public: + C4MeshDenumerator(): Def(NULL), Object(NULL) {} + C4MeshDenumerator(C4Def* def): Def(def), Object(NULL) {} + C4MeshDenumerator(C4Object* object): Def(NULL), Object(object) {} + + virtual void CompileFunc(StdCompiler* pComp, StdMeshInstance::AttachedMesh* attach); + virtual void EnumeratePointers(StdMeshInstance::AttachedMesh* attach); + virtual void DenumeratePointers(StdMeshInstance::AttachedMesh* attach); +}; + class C4Action { public: diff --git a/src/game/script/C4Script.cpp b/src/game/script/C4Script.cpp index 028695b7a..78ed2c353 100644 --- a/src/game/script/C4Script.cpp +++ b/src/game/script/C4Script.cpp @@ -5822,7 +5822,7 @@ static C4Value FnAttachMesh(C4AulContext *ctx, C4Value* pPars) if (pObj) { if (!pObj->pMeshInstance) return C4VNull; - attach = ctx->Obj->pMeshInstance->AttachMesh(*pObj->pMeshInstance, szParentBone->GetData(), szChildBone->GetData(), trans); + attach = ctx->Obj->pMeshInstance->AttachMesh(*pObj->pMeshInstance, new C4MeshDenumerator(pObj), szParentBone->GetData(), szChildBone->GetData(), trans); } else { @@ -5831,7 +5831,7 @@ static C4Value FnAttachMesh(C4AulContext *ctx, C4Value* pPars) C4Def* pDef = C4Id2Def(id); if (pDef->Graphics.Type != C4DefGraphics::TYPE_Mesh) return C4VNull; - attach = ctx->Obj->pMeshInstance->AttachMesh(*pDef->Graphics.Mesh, szParentBone->GetData(), szChildBone->GetData(), trans); + attach = ctx->Obj->pMeshInstance->AttachMesh(*pDef->Graphics.Mesh, new C4MeshDenumerator(pDef), szParentBone->GetData(), szChildBone->GetData(), trans); } if (!attach) return C4VNull; diff --git a/src/platform/StdMesh.cpp b/src/platform/StdMesh.cpp index d64e8aa14..f68f28772 100644 --- a/src/platform/StdMesh.cpp +++ b/src/platform/StdMesh.cpp @@ -26,6 +26,8 @@ #include +std::vector* StdMeshInstance::SerializableValueProvider::IDs = NULL; + namespace { // Helper to sort faces for FaceOrdering @@ -62,6 +64,86 @@ namespace } }; + // Seralize a ValueProvider with StdCompiler + struct ValueProviderAdapt + { + ValueProviderAdapt(StdMeshInstance::ValueProvider** Provider): + ValueProvider(Provider) {} + + StdMeshInstance::ValueProvider** ValueProvider; + + void CompileFunc(StdCompiler* pComp) + { + const StdMeshInstance::SerializableValueProvider::IDBase* id; + StdMeshInstance::SerializableValueProvider* svp = NULL; + + if(pComp->isCompiler()) + { + StdCopyStrBuf id_str; + pComp->Value(mkParAdapt(id_str, StdCompiler::RCT_Idtf)); + + id = StdMeshInstance::SerializableValueProvider::Lookup(id_str.getData()); + if(!id) pComp->excCorrupt("No value provider for ID \"%s\"", id_str.getData()); + } + else + { + svp = dynamic_cast(*ValueProvider); + if(!svp) pComp->excCorrupt("Value provider cannot be compiled"); + id = StdMeshInstance::SerializableValueProvider::Lookup(typeid(*svp)); + if(!id) pComp->excCorrupt("No ID for value provider registered"); + + StdCopyStrBuf id_str(id->name); + pComp->Value(mkParAdapt(id_str, StdCompiler::RCT_Idtf)); + } + + pComp->Seperator(StdCompiler::SEP_START); + pComp->Value(mkContextPtrAdapt(svp, *id, false)); + pComp->Seperator(StdCompiler::SEP_END); + + if(pComp->isCompiler()) + *ValueProvider = svp; + } + }; + + ValueProviderAdapt mkValueProviderAdapt(StdMeshInstance::ValueProvider** ValueProvider) { return ValueProviderAdapt(ValueProvider); } + + // Serialize a bone index by name with StdCompiler + struct TransformAdapt + { + StdMeshMatrix& Matrix; + TransformAdapt(StdMeshMatrix& matrix): Matrix(matrix) {} + + void CompileFunc(StdCompiler* pComp) + { + pComp->Seperator(StdCompiler::SEP_START); + for(unsigned int i = 0; i < 3; ++i) + { + for(unsigned int j = 0; j < 4; ++j) + { + if(i != 0 || j != 0) pComp->Seperator(); + // TODO: Teach StdCompiler how to handle float +// pComp->Value(Matrix(i, j)); + + if(pComp->isCompiler()) + { + FIXED f; + pComp->Value(f); + Matrix(i,j) = fixtof(f); + } + else + { + FIXED f = ftofix(Matrix(i,j)); + pComp->Value(f); + } + } + } + + pComp->Seperator(StdCompiler::SEP_END); + } + }; + + TransformAdapt mkTransformAdapt(StdMeshMatrix& Matrix) { return TransformAdapt(Matrix); } + // Reset all animation list entries corresponding to node or its children void ClearAnimationListRecursively(std::vector& list, StdMeshInstance::AnimationNode* node) { @@ -832,6 +914,18 @@ void StdSubMeshInstance::SetMaterial(const StdMeshMaterial& material) } } +void StdMeshInstance::SerializableValueProvider::CompileFunc(StdCompiler* pComp) +{ + pComp->Value(Value); +} + +StdMeshInstance::AnimationNode::AnimationNode(): + Type(LeafNode), Parent(NULL) +{ + Leaf.Animation = NULL; + Leaf.Position = NULL; +} + StdMeshInstance::AnimationNode::AnimationNode(const StdMeshAnimation* animation, ValueProvider* position): Type(LeafNode), Parent(NULL) { @@ -889,9 +983,97 @@ bool StdMeshInstance::AnimationNode::GetBoneTransform(unsigned int bone, StdMesh } } -StdMeshInstance::AttachedMesh::AttachedMesh(unsigned int number, StdMeshInstance* parent, StdMeshInstance* child, bool own_child, - unsigned int parent_bone, unsigned int child_bone, const StdMeshMatrix& transform): - Number(number), Parent(parent), Child(child), OwnChild(own_child), +void StdMeshInstance::AnimationNode::CompileFunc(StdCompiler* pComp, const StdMesh* Mesh) +{ + static const StdEnumEntry NodeTypes[] = + { + { "Leaf", LeafNode }, + { "LinearInterpolation", LinearInterpolationNode }, + + { NULL, static_cast(0) } + }; + + pComp->Value(mkNamingAdapt(Slot, "Slot")); + pComp->Value(mkNamingAdapt(Number, "Number")); + pComp->Value(mkNamingAdapt(mkEnumAdapt(Type, NodeTypes), "Type")); + + switch(Type) + { + case LeafNode: + if(pComp->isCompiler()) + { + StdCopyStrBuf anim_name; + pComp->Value(mkNamingAdapt(toC4CStrBuf(anim_name), "Animation")); + Leaf.Animation = Mesh->GetAnimationByName(anim_name); + if(!Leaf.Animation) pComp->excCorrupt("No such animation: \"%s\"", anim_name.getData()); + } + else + { + pComp->Value(mkNamingAdapt(mkParAdapt(mkDecompileAdapt(Leaf.Animation->Name), StdCompiler::RCT_All), "Animation")); + } + + pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&Leaf.Position), "Position")); + break; + case LinearInterpolationNode: + pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildLeft, "ChildLeft"), Mesh)); + pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildRight, "ChildRight"), Mesh)); + pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&LinearInterpolation.Weight), "Weight")); + if(pComp->isCompiler()) + { + if(LinearInterpolation.ChildLeft->Slot != Slot) + pComp->excCorrupt("Slot of left child does not match parent slot"); + if(LinearInterpolation.ChildRight->Slot != Slot) + pComp->excCorrupt("Slof of right child does not match parent slot"); + LinearInterpolation.ChildRight->Parent = this; + LinearInterpolation.ChildRight->Parent = this; + } + break; + default: + pComp->excCorrupt("Invalid animation node type"); + break; + } +} + +void StdMeshInstance::AnimationNode::EnumeratePointers() +{ + SerializableValueProvider* value_provider = NULL; + switch(Type) + { + case LeafNode: + value_provider = dynamic_cast(Leaf.Position); + break; + case LinearInterpolationNode: + value_provider = dynamic_cast(LinearInterpolation.Weight); + break; + } + + if(value_provider) value_provider->EnumeratePointers(); +} + +void StdMeshInstance::AnimationNode::DenumeratePointers() +{ + SerializableValueProvider* value_provider = NULL; + switch(Type) + { + case LeafNode: + value_provider = dynamic_cast(Leaf.Position); + break; + case LinearInterpolationNode: + value_provider = dynamic_cast(LinearInterpolation.Weight); + break; + } + + if(value_provider) value_provider->DenumeratePointers(); +} + +StdMeshInstance::AttachedMesh::AttachedMesh(): + Number(0), Parent(NULL), Child(NULL), OwnChild(true), ChildDenumerator(NULL), ParentBone(0), ChildBone(0), FinalTransformDirty(false) +{ +} + +StdMeshInstance::AttachedMesh::AttachedMesh(unsigned int number, StdMeshInstance* parent, StdMeshInstance* child, bool own_child, Denumerator* denumerator, + unsigned int parent_bone, unsigned int child_bone, const StdMeshMatrix& transform): + Number(number), Parent(parent), Child(child), OwnChild(own_child), ChildDenumerator(denumerator), ParentBone(parent_bone), ChildBone(child_bone), AttachTrans(transform), FinalTransformDirty(true) { @@ -901,6 +1083,7 @@ StdMeshInstance::AttachedMesh::~AttachedMesh() { if (OwnChild) delete Child; + delete ChildDenumerator; } bool StdMeshInstance::AttachedMesh::SetParentBone(const StdStrBuf& bone) @@ -929,6 +1112,32 @@ void StdMeshInstance::AttachedMesh::SetAttachTransformation(const StdMeshMatrix& FinalTransformDirty = true; } +void StdMeshInstance::AttachedMesh::CompileFunc(StdCompiler* pComp, DenumeratorFactoryFunc Factory) +{ + if(pComp->isCompiler()) + { + FinalTransformDirty = true; + ChildDenumerator = Factory(); + } + + pComp->Value(mkNamingAdapt(Number, "Number")); + pComp->Value(mkNamingAdapt(ParentBone, "ParentBone")); // TODO: Save as string + pComp->Value(mkNamingAdapt(ChildBone, "ChildBone")); // TODO: Save as string (note we can only resolve this in DenumeratePointers then!) + pComp->Value(mkNamingAdapt(mkTransformAdapt(AttachTrans), "AttachTransformation")); + + pComp->Value(mkParAdapt(*ChildDenumerator, this)); +} + +void StdMeshInstance::AttachedMesh::EnumeratePointers() +{ + ChildDenumerator->EnumeratePointers(this); +} + +void StdMeshInstance::AttachedMesh::DenumeratePointers() +{ + ChildDenumerator->DenumeratePointers(this); +} + StdMeshInstance::StdMeshInstance(const StdMesh& mesh): Mesh(mesh), CurrentFaceOrdering(FO_Fixed), BoneTransforms(Mesh.GetNumBones(), StdMeshMatrix::Identity()), @@ -1198,17 +1407,19 @@ void StdMeshInstance::ExecuteAnimation(float dt) (*iter)->Child->ExecuteAnimation(dt); } -StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(const StdMesh& mesh, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation) +StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(const StdMesh& mesh, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation) { StdMeshInstance* instance = new StdMeshInstance(mesh); instance->SetFaceOrdering(CurrentFaceOrdering); - AttachedMesh* attach = AttachMesh(*instance, parent_bone, child_bone, transformation, true); - if (!attach) { delete instance; return NULL; } + AttachedMesh* attach = AttachMesh(*instance, denumerator, parent_bone, child_bone, transformation, true); + if (!attach) { delete instance; delete denumerator; return NULL; } return attach; } -StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(StdMeshInstance& instance, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, bool own_child) +StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(StdMeshInstance& instance, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, bool own_child) { + std::auto_ptr auto_denumerator(denumerator); + // We don't allow an instance to be attached to multiple parent instances for now if (instance.AttachParent) return NULL; @@ -1230,7 +1441,7 @@ StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(StdMeshInstance& inst if (!parent_bone_obj || !child_bone_obj) return NULL; // TODO: Face Ordering is not lined up... can't do that properly here - attach = new AttachedMesh(number, this, &instance, own_child, parent_bone_obj->Index, child_bone_obj->Index, transformation); + attach = new AttachedMesh(number, this, &instance, own_child, auto_denumerator.release(), parent_bone_obj->Index, child_bone_obj->Index, transformation); instance.AttachParent = attach; AttachChildren.push_back(attach); @@ -1377,6 +1588,94 @@ void StdMeshInstance::UpdateBoneTransforms() BoneTransformsDirty = false; } +void StdMeshInstance::CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory) +{ + if(pComp->isCompiler()) + { + // Only initially created instances can be compiled + assert(!AttachParent); + assert(AttachChildren.empty()); + assert(AnimationStack.empty()); + BoneTransformsDirty = true; + + int32_t iAnimCnt = AnimationStack.size(); + pComp->Value(mkNamingCountAdapt(iAnimCnt, "AnimationNode")); + + for(int32_t i = 0; i < iAnimCnt; ++i) + { + AnimationNode* node = NULL; + pComp->Value(mkParAdapt(mkNamingPtrAdapt(node, "AnimationNode"), &Mesh)); + AnimationNodeList::iterator iter = GetStackIterForSlot(node->Slot, true); + if(*iter != NULL) { delete node; pComp->excCorrupt("Duplicate animation slot index"); } + *iter = node; + + // Add nodes into lookup table + std::vector nodes(1, node); + while(!nodes.empty()) + { + node = nodes.back(); + nodes.erase(nodes.end()-1); + + AnimationNodes.resize(node->Number+1); + if(AnimationNodes[node->Number] != NULL) pComp->excCorrupt("Duplicate animation node number"); + AnimationNodes[node->Number] = node; + + if(node->Type == AnimationNode::LinearInterpolationNode) + { + nodes.push_back(node->LinearInterpolation.ChildLeft); + nodes.push_back(node->LinearInterpolation.ChildRight); + } + } + } + + int32_t iAttachedCnt; + pComp->Value(mkNamingCountAdapt(iAttachedCnt, "Attached")); + + for(int32_t i = 0; i < iAttachedCnt; ++i) + { + AttachChildren.push_back(new AttachedMesh); + AttachedMesh* attach = AttachChildren.back(); + + attach->Parent = this; + pComp->Value(mkNamingAdapt(mkParAdapt(*attach, Factory), "Attached")); + } + } + else + { + int32_t iAnimCnt = AnimationStack.size(); + pComp->Value(mkNamingCountAdapt(iAnimCnt, "AnimationNode")); + + for(AnimationNodeList::iterator iter = AnimationStack.begin(); iter != AnimationStack.end(); ++iter) + pComp->Value(mkParAdapt(mkNamingPtrAdapt(*iter, "AnimationNode"), &Mesh)); + + int32_t iAttachedCnt = AttachChildren.size(); + pComp->Value(mkNamingCountAdapt(iAttachedCnt, "Attached")); + + for(unsigned int i = 0; i < AttachChildren.size(); ++i) + pComp->Value(mkNamingAdapt(mkParAdapt(*AttachChildren[i], Factory), "Attached")); + } +} + +void StdMeshInstance::EnumeratePointers() +{ + for(unsigned int i = 0; i < AnimationNodes.size(); ++i) + if(AnimationNodes[i]) + AnimationNodes[i]->EnumeratePointers(); + + for(unsigned int i = 0; i < AttachChildren.size(); ++i) + AttachChildren[i]->EnumeratePointers(); +} + +void StdMeshInstance::DenumeratePointers() +{ + for(unsigned int i = 0; i < AnimationNodes.size(); ++i) + if(AnimationNodes[i]) + AnimationNodes[i]->DenumeratePointers(); + + for(unsigned int i = 0; i < AttachChildren.size(); ++i) + AttachChildren[i]->DenumeratePointers(); +} + StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlot(int slot, bool create) { // TODO: bsearch diff --git a/src/platform/StdMesh.h b/src/platform/StdMesh.h index e735acf74..bcd1e5554 100644 --- a/src/platform/StdMesh.h +++ b/src/platform/StdMesh.h @@ -21,6 +21,8 @@ #include +class StdCompiler; + // OGRE mesh struct StdMeshVector @@ -370,6 +372,71 @@ public: FIXED Value; // Current provider value }; + // Serializable value providers need to be registered with SerializeableValueProvider::Register. + // They also need to implement a default constructor and a compile func + class SerializableValueProvider: public ValueProvider + { + public: + struct IDBase; + + private: + // Pointer for deterministic initialization + static std::vector* IDs; + + public: + struct IDBase + { + typedef SerializableValueProvider*(*NewFunc)(); + protected: + IDBase(const char* name, const std::type_info& type, NewFunc newfunc): + name(name), type(type), newfunc(newfunc) + { + if(!IDs) IDs = new std::vector; + IDs->push_back(this); + } + + public: + const char* name; + const std::type_info& type; + NewFunc newfunc; + }; + + + + template + struct ID: IDBase + { + private: + static SerializableValueProvider* CreateFunc() { return new T; } + + public: + ID(const char* name): + IDBase(name, typeid(T), CreateFunc) {} + }; + + static const IDBase* Lookup(const char* name) + { + if(!IDs) return NULL; + for(unsigned int i = 0; i < IDs->size(); ++i) + if(strcmp((*IDs)[i]->name, name) == 0) + return (*IDs)[i]; + return NULL; + } + + static const IDBase* Lookup(const std::type_info& type) + { + if(!IDs) return NULL; + for(unsigned int i = 0; i < IDs->size(); ++i) + if((*IDs)[i]->type == type) + return (*IDs)[i]; + return NULL; + } + + virtual void CompileFunc(StdCompiler* pComp); + virtual void EnumeratePointers() {} + virtual void DenumeratePointers() {} + }; + // A node in the animation tree // Can be either a leaf node, or interpolation between two other nodes class AnimationNode @@ -378,6 +445,7 @@ public: public: enum NodeType { LeafNode, LinearInterpolationNode }; + AnimationNode(); AnimationNode(const StdMeshAnimation* animation, ValueProvider* position); AnimationNode(AnimationNode* child_left, AnimationNode* child_right, ValueProvider* weight); ~AnimationNode(); @@ -398,11 +466,15 @@ public: ValueProvider* GetWeightProvider() { assert(Type == LinearInterpolationNode); return LinearInterpolation.Weight; } FIXED GetWeight() const { assert(Type == LinearInterpolationNode); return LinearInterpolation.Weight->Value; } + void CompileFunc(StdCompiler* pComp, const StdMesh* Mesh); + void EnumeratePointers(); + void DenumeratePointers(); + protected: int Slot; unsigned int Number; NodeType Type; - AnimationNode* Parent; + AnimationNode* Parent; // NoSave union { @@ -441,37 +513,59 @@ public: { friend class StdMeshInstance; public: - AttachedMesh(unsigned int number, StdMeshInstance* parent, StdMeshInstance* child, bool own_child, + // The job of this class is to help serialize the Child and OwnChild members of AttachedMesh + class Denumerator + { + public: + virtual ~Denumerator() {} + + virtual void CompileFunc(StdCompiler* pComp, AttachedMesh* attach) = 0; + virtual void EnumeratePointers(AttachedMesh* attach) {} + virtual void DenumeratePointers(AttachedMesh* attach) {} + }; + + typedef Denumerator*(*DenumeratorFactoryFunc)(); + + template + static Denumerator* DenumeratorFactory() { return new T; } + + AttachedMesh(); + AttachedMesh(unsigned int number, StdMeshInstance* parent, StdMeshInstance* child, bool own_child, Denumerator* denumerator, unsigned int parent_bone, unsigned int child_bone, const StdMeshMatrix& transform); ~AttachedMesh(); - const unsigned int Number; - StdMeshInstance* const Parent; - StdMeshInstance* const Child; - const bool OwnChild; // Whether to delete child on destruction + uint32_t Number; + StdMeshInstance* Parent; // NoSave (set by parent) + StdMeshInstance* Child; + bool OwnChild; // NoSave + Denumerator* ChildDenumerator; bool SetParentBone(const StdStrBuf& bone); bool SetChildBone(const StdStrBuf& bone); void SetAttachTransformation(const StdMeshMatrix& transformation); const StdMeshMatrix& GetFinalTransformation() const { return FinalTrans; } + void CompileFunc(StdCompiler* pComp, DenumeratorFactoryFunc Factory); + void EnumeratePointers(); + void DenumeratePointers(); + private: unsigned int ParentBone; unsigned int ChildBone; StdMeshMatrix AttachTrans; // Cache final attach transformation, updated in UpdateBoneTransform - StdMeshMatrix FinalTrans; - bool FinalTransformDirty; // Whether FinalTrans is up to date or not + StdMeshMatrix FinalTrans; // NoSave + bool FinalTransformDirty; // NoSave; Whether FinalTrans is up to date or not }; typedef std::vector AttachedMeshList; typedef AttachedMeshList::const_iterator AttachedMeshIter; - // Create a new instance and attach it to this mesh. - AttachedMesh* AttachMesh(const StdMesh& mesh, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation = StdMeshMatrix::Identity()); - // Attach an instance to this instance. If own_child is true then take ownership of instance, deleting it when the mesh is detached. - AttachedMesh* AttachMesh(StdMeshInstance& instance, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation = StdMeshMatrix::Identity(), bool own_child = false); + // Create a new instance and attach it to this mesh. Takes ownership of denumerator + AttachedMesh* AttachMesh(const StdMesh& mesh, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation = StdMeshMatrix::Identity()); + // Attach an instance to this instance. Takes ownership of denumerator. If own_child is true deletes instance on detach. + AttachedMesh* AttachMesh(StdMeshInstance& instance, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation = StdMeshMatrix::Identity(), bool own_child = false); // Removes attachment with given number bool DetachMesh(unsigned int number); // Returns attached mesh with given number @@ -493,6 +587,10 @@ public: // which would also not update its attach transformation. Call this once before rendering. void UpdateBoneTransforms(); + void CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory); + void EnumeratePointers(); + void DenumeratePointers(); + const StdMesh& Mesh; protected: @@ -521,4 +619,11 @@ private: StdMeshInstance& operator=(const StdMeshInstance& other); // noncopyable }; +inline void CompileNewFuncCtx(StdMeshInstance::SerializableValueProvider *&pStruct, StdCompiler *pComp, const StdMeshInstance::SerializableValueProvider::IDBase& rID) +{ + std::auto_ptr temp(rID.newfunc()); + pComp->Value(*temp); + pStruct = temp.release(); +} + #endif