diff --git a/src/common/models/models_iqm.cpp b/src/common/models/models_iqm.cpp index d2d70ae3e..521a545ab 100644 --- a/src/common/models/models_iqm.cpp +++ b/src/common/models/models_iqm.cpp @@ -543,15 +543,35 @@ const TArray IQMModel::CalculateBones(int frame1, int frame2, double i for (int i = 0; i < numbones; i++) { TRS bone; - bone.translation = animationFrames[offset1 + i].translation * invt + animationFrames[offset2 + i].translation * t; - bone.rotation = animationFrames[offset1 + i].rotation * invt; - if ((bone.rotation | animationFrames[offset2 + i].rotation * t) < 0) + TRS from = animationFrames[offset1 + i]; + TRS to = animationFrames[offset2 + i]; + + if (actor->boneManipulationData != nullptr) + { + if (i < actor->boneManipulationData->boneComponentsOld.Size()) + { + from.translation += actor->boneManipulationData->boneComponentsOld[i].translation; + from.rotation += actor->boneManipulationData->boneComponentsOld[i].rotation; + from.scaling += actor->boneManipulationData->boneComponentsOld[i].scaling; + } + + if (i < actor->boneManipulationData->boneComponentsNew.Size()) + { + to.translation += actor->boneManipulationData->boneComponentsNew[i].translation; + to.rotation += actor->boneManipulationData->boneComponentsNew[i].rotation; + to.scaling += actor->boneManipulationData->boneComponentsNew[i].scaling; + } + } + + bone.translation = from.translation * invt + to.translation * t; + bone.rotation = from.rotation * invt; + if ((bone.rotation | to.rotation * t) < 0) { bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1; } - bone.rotation += animationFrames[offset2 + i].rotation * t; + bone.rotation += to.rotation * t; bone.rotation.MakeUnit(); - bone.scaling = animationFrames[offset1 + i].scaling * invt + animationFrames[offset2 + i].scaling * t; + bone.scaling = from.scaling * invt + to.scaling * t; if (actor->boneComponentData->trscomponents[i].Equals(bone)) { diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 6bd8caf47..68ea64d4b 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -701,6 +701,16 @@ public: DBoneComponents() = default; }; +class DBoneManipulations : public DObject +{ + DECLARE_CLASS(DBoneComponents, DObject); +public: + TArray boneComponentsNew; + TArray boneComponentsOld; + + DBoneManipulations() = default; +}; + class DViewPosition : public DObject { DECLARE_CLASS(DViewPosition, DObject); @@ -1098,6 +1108,7 @@ public: double FloatSpeed; TObjPtr modelData; TObjPtr boneComponentData; + TObjPtr boneManipulationData; // interaction info FBlockNode *BlockNode; // links in blocks (if needed) diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 851b72b83..0e94ae5dd 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5195,3 +5195,86 @@ DEFINE_ACTION_FUNCTION(AActor, GetRenderStyle) } ACTION_RETURN_INT(-1); // no symbolic constant exists to handle this style. } + +//========================================================================== +// +// A_ManipulateBone(a bunch of crap) +// +// This function allows manipulating a bone +//========================================================================== + +enum ManipulateBoneFlags +{ + BM_USEEULER = 1 +}; + +DEFINE_ACTION_FUNCTION(AActor, A_ManipulateBone) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(modelindex); + PARAM_INT(boneindex); + PARAM_FLOAT(positionX); + PARAM_FLOAT(positionY); + PARAM_FLOAT(positionZ); + PARAM_FLOAT(rotationX); + PARAM_FLOAT(rotationY); + PARAM_FLOAT(rotationZ); + PARAM_FLOAT(rotationW); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_FLOAT(scaleZ); + PARAM_INT(flags); + + if (self == nullptr) + ACTION_RETURN_BOOL(false); + + AActor* mobj = ACTION_CALL_FROM_INVENTORY() ? self : stateowner; + + if (mobj->boneManipulationData == nullptr) + { + auto ptr = Create(); + ptr->boneComponentsNew = *new TArray(); + ptr->boneComponentsOld = *new TArray(); + mobj->boneManipulationData = ptr; + GC::WriteBarrier(mobj, ptr); + } + + while(boneindex >= mobj->boneManipulationData->boneComponentsNew.Size()) + mobj->boneManipulationData->boneComponentsNew.Push(TRS()); + while (boneindex >= mobj->boneManipulationData->boneComponentsOld.Size()) + mobj->boneManipulationData->boneComponentsOld.Push(TRS()); + + if (flags & BM_USEEULER) + { + double cr = cos(rotationZ * 0.5); + double sr = sin(rotationZ * 0.5); + double cp = cos(rotationY * 0.5); + double sp = sin(rotationY * 0.5); + double cy = cos(rotationX * 0.5); + double sy = sin(rotationX * 0.5); + + rotationW = cr * cp * cy + sr * sp * sy; + rotationX = sr * cp * cy - cr * sp * sy; + rotationY = cr * sp * cy + sr * cp * sy; + rotationZ = cr * cp * sy - sr * sp * cy; + + //Printf("Rotation X is: %f\n", rotationX); + //Printf("Rotation Y is: %f\n", rotationY); + //Printf("Rotation Z is: %f\n", rotationZ); + //Printf("Rotation W is: %f\n", rotationW); + } + + mobj->boneManipulationData->boneComponentsOld[boneindex] = mobj->boneManipulationData->boneComponentsNew[boneindex]; + mobj->boneManipulationData->boneComponentsNew[boneindex].translation.X = positionX; + mobj->boneManipulationData->boneComponentsNew[boneindex].translation.Y = positionZ; + mobj->boneManipulationData->boneComponentsNew[boneindex].translation.Z = positionY; + mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.X = rotationX; + mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.Y = rotationY; + mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.Z = rotationZ; + mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.W = rotationW; + mobj->boneManipulationData->boneComponentsNew[boneindex].scaling.X = scaleX; + mobj->boneManipulationData->boneComponentsNew[boneindex].scaling.Y = scaleZ; + mobj->boneManipulationData->boneComponentsNew[boneindex].scaling.Z = scaleY; + + return 0; +} diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 82287ddb4..13ec1da7e 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -160,6 +160,7 @@ CVAR (Int, cl_bloodtype, 0, CVAR_ARCHIVE); IMPLEMENT_CLASS(DActorModelData, false, false); IMPLEMENT_CLASS(DBoneComponents, false, false); +IMPLEMENT_CLASS(DBoneManipulations, false, false); IMPLEMENT_CLASS(AActor, false, true) IMPLEMENT_POINTERS_START(AActor) @@ -176,6 +177,7 @@ IMPLEMENT_POINTERS_START(AActor) IMPLEMENT_POINTER(ViewPos) IMPLEMENT_POINTER(modelData) IMPLEMENT_POINTER(boneComponentData) + IMPLEMENT_POINTER(boneManipulationData) IMPLEMENT_POINTERS_END AActor::~AActor () diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 68fc53dd6..b8514d792 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1134,6 +1134,7 @@ class Actor : Thinker native deprecated("2.3", "Use 'b = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); action native void A_ChangeModel(name modeldef, int modelindex = 0, string modelpath = "", name model = "", int skinindex = 0, string skinpath = "", name skin = "", int flags = 0, int generatorindex = -1, int animationindex = 0, string animationpath = "", name animation = ""); + action native void A_ManipulateBone(int modelindex, int boneindex, float positionX = 0, float positionY = 0, float positionZ = 0, float rotationX = 0, float rotationY = 0, float rotationZ = 0, float rotationW = 0, float scaleX = 0, float scaleY = 0, float scaleZ = 0, int flags = 0); void A_SetFriendly (bool set) { diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 9a32392f9..53dce4d78 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -373,6 +373,12 @@ enum ChangeModelFlags CMDL_USESURFACESKIN = 1 << 2, }; +// Manipulate Bone Flags +enum ManipulateBoneFlags +{ + BM_USEEULER = 1 +}; + // Activation flags enum EActivationFlags {