Bone Getters Part 2/3, plus fixed warnings for MSVC

* add getters for frame poses

* fix missing joint in GetJointPose

* clean up models_iqm.cpp

* clean up usage of I_GetTimeFrac, split out matrix calculation into its own function

* clean up SetModelBoneRotationInternal

* clean up a few float <-> double and unsigned <-> signed warnings

* fix more warnings

* further clean up warnings

* split mode ObjectToWorldMatrix stuff

* initial work on bone getters, matrix hell

(the matrix/vec3 multiplications are probably wrong af, just gotta add more stuff 'till i can test it)

* clean up matrix math

* GetBone/TransformByBone

* fix GetBoneFramePose

* fix ObjectToWorldMatrix

* fix missing array resize

* raw matrix getters (for use with gutamatics/etc)

* reverse matrix mult order

* replace GetBoneLength/GetBoneDir with GetBoneBaseTRS

* fix GetBonePosition, remove GetBoneWorldMatrix as it's useless

* GetBonePosition

* deduplicate code

* rename GetBonePosition to GetBoneBasePosition to avoid confusion

* GetBoneBaseRotation

* GetBonePosition helper function

* forgot include_offsets
This commit is contained in:
Ricardo Luís Vaz Silva 2025-05-09 17:06:16 -03:00 committed by Nash Muhandes
commit d5f5c71d67
33 changed files with 1065 additions and 220 deletions

View file

@ -307,7 +307,7 @@ bool Wiper_Crossfade::Run(int ticks)
bool Wiper_Crossfade::RunInterpolated(double ticks)
{
Clock += ticks;
Clock += float(ticks);
DrawTexture(twod, startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE);
DrawTexture(twod, endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE);
return Clock >= 32.;

View file

@ -157,6 +157,7 @@ public:
const char* GetHash() const { return Hash; }
int EntryCount() const { return NumLumps; }
uint32_t EntryCountU() const { return NumLumps; }
int FindEntry(const char* name);
size_t Length(uint32_t entry)

View file

@ -67,13 +67,13 @@ struct BoneOverrideComponent
void Modify(T &value, double tic) const
{
double lerp_amt = interplen > 0.0 ? std::clamp(((tic - switchtic) / interplen), 0.0, 1.0) : 1.0;
float lerp_amt = interplen > 0.0f ? std::clamp(float((tic - switchtic) / interplen), 0.0f, 1.0f) : 1.0f;
if(mode > 0 || (prev_mode > 0 && lerp_amt < 1.0))
{
T from = ModifyValue(value, prev, prev_mode);
T to = ModifyValue(value, cur, mode);
value = Lerp(from, to, lerp_amt, 1.0 - lerp_amt);
value = Lerp(from, to, lerp_amt, 1.0f - lerp_amt);
}
}
@ -126,9 +126,10 @@ struct BoneOverride
struct BoneInfo
{
TArray<TRS> bones_anim_only;
TArray<TRS> bones;
TArray<TRS> bones_with_override;
TArray<VSMatrix> positions;
TArray<VSMatrix> positions_with_override;
};
struct ModelAnim

View file

@ -17,7 +17,9 @@ class FGameTexture;
class IModelVertexBuffer;
class FModel;
class PClass;
class AActor;
struct FSpriteModelFrame;
struct FLevelLocals;
FTextureID LoadSkin(const char* path, const char* fn);
void FlushModels();
@ -59,6 +61,9 @@ public:
unsigned int getFlags(class DActorModelData * defs) const;
friend void InitModels();
friend void ParseModelDefLump(int Lump);
VSMatrix ObjectToWorldMatrix(AActor * actor, float x, float y, float z, double ticFrac);
VSMatrix ObjectToWorldMatrix(FLevelLocals *Level, DVector3 translation, DRotator rotation, DVector2 scaling, unsigned int flags, double tic);
};
@ -92,9 +97,12 @@ public:
virtual int FindJoint(FName name) { return -1; }
virtual int GetJointParent(int joint) { return -1; }
virtual double GetJointLength(int joint) { return 0.0; }
virtual FName GetJointName(int joint) { return NAME_None; }
virtual FVector3 GetJointDir(int joint) { return FVector3(0.0f,0.0f,0.0f); }
virtual FQuaternion GetJointRotation(int joint) { return FQuaternion(0.0f,0.0f,0.0f,1.0f); }
virtual FVector3 GetJointPosition(int joint) { return FVector3(0.0f,0.0f,0.0f); }
virtual TRS GetJointBaseTRS(int joint) { return {}; }
virtual TRS GetJointPose(int joint, int frame) { return {}; }
virtual int NumFrames() { return -1; }
virtual void GetJointChildren(int joint, TArray<int> &out) {}

View file

@ -73,6 +73,9 @@ struct IQMJoint
FVector3 Translate;
FQuaternion Quaternion;
FVector3 Scale;
FVector3 Position;
FQuaternion Rotation;
FVector3 Scaling;
};
struct IQMPose
@ -164,7 +167,7 @@ private:
TArray<VSMatrix> inversebaseframe;
TArray<TRS> TRSData;
public:
int NumJoints() override { return Joints.Size(); }
int NumJoints() override { return Joints.SSize(); }
int FindJoint(FName name) override
{
int *j = NamedJoints.CheckKey(name);
@ -174,12 +177,12 @@ public:
int GetJointParent(int joint) override
{
return (joint >= 0 && joint < Joints.Size()) ? Joints[joint].Parent : -1;
return (joint >= 0 && joint < Joints.SSize()) ? Joints[joint].Parent : -1;
}
FName GetJointName(int joint) override
{
return (joint >= 0 && joint < Joints.Size()) ? Joints[joint].Name : FName(NAME_None);
return (joint >= 0 && joint < Joints.SSize()) ? Joints[joint].Name : FName(NAME_None);
}
void GetRootJoints(TArray<int> &out) override
@ -189,20 +192,34 @@ public:
void GetJointChildren(int joint, TArray<int> &out) override
{
if(joint >= 0 && joint < Joints.Size())
if(joint >= 0 && joint < Joints.SSize())
{
out = Joints[joint].Children;
}
}
double GetJointLength(int joint) override
FQuaternion GetJointRotation(int joint) override
{
return (joint >= 0 && joint < Joints.Size()) ? Joints[joint].Translate.Length() : 0.0;
return (joint >= 0 && joint < Joints.SSize()) ? Joints[joint].Rotation : FQuaternion(0.0f,0.0f,0.0f,1.0f);
}
FVector3 GetJointDir(int joint) override
FVector3 GetJointPosition(int joint) override
{
return (joint >= 0 && joint < Joints.Size()) ? Joints[joint].Translate.Unit() : FVector3(0.0f,0.0f,0.0f);
return (joint >= 0 && joint < Joints.SSize()) ? Joints[joint].Position : FVector3(0.0f,0.0f,0.0f);
}
TRS GetJointBaseTRS(int joint) override
{
return (joint >= 0 && joint < Joints.SSize()) ? TRS{Joints[joint].Translate, Joints[joint].Quaternion, Joints[joint].Scale} : TRS{};
}
TRS GetJointPose(int joint, int frame) override
{
return (joint >= 0 && joint < Joints.SSize() && frame >= 0 && ((frame * Joints.SSize()) + joint) < TRSData.SSize()) ? TRSData[(frame * Joints.SSize()) + joint] : TRS{} ;
}
virtual int NumFrames()
{
return Joints.SSize() > 0 ? (TRSData.SSize() / Joints.SSize()) : 0;
}
};

View file

@ -108,7 +108,7 @@ bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int lengt
}
reader.SeekTo(ofs_joints);
for (int i = 0; i < Joints.Size(); i++)
for (int i = 0; i < Joints.SSize(); i++)
{
IQMJoint& joint = Joints[i];
@ -126,8 +126,6 @@ bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int lengt
joint.Translate.Y = reader.ReadFloat();
joint.Translate.Z = reader.ReadFloat();
int len = joint.Translate.Length();
joint.Quaternion.X = reader.ReadFloat();
joint.Quaternion.Y = reader.ReadFloat();
joint.Quaternion.Z = reader.ReadFloat();
@ -139,14 +137,24 @@ bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int lengt
if(joint.Parent < 0)
{
joint.Rotation = joint.Quaternion;
joint.Scaling = joint.Scale;
joint.Position = joint.Translate.ScaleXYZ(joint.Scaling);
RootJoints.Push(i);
}
else if(joint.Parent >= Joints.Size())
else if(joint.Parent >= i)
{
I_FatalError("Joint child comes before parent in IQM Model");
}
else if(joint.Parent >= Joints.SSize())
{
I_FatalError("Joint parent index out of bounds in IQM Model");
}
else
{
joint.Rotation = (Joints[joint.Parent].Rotation * joint.Quaternion).Unit();
joint.Scaling = joint.Scale.ScaleXYZ(Joints[joint.Parent].Scaling);
joint.Position = (Joints[joint.Parent].Rotation * joint.Translate.ScaleXYZ(joint.Scaling)) + Joints[joint.Parent].Position;
Joints[joint.Parent].Children.Push(i);
}
}
@ -618,11 +626,6 @@ const TArray<VSMatrix>* IQMModel::CalculateBones(const ModelAnimFrame &from, con
}
}
inline void ModifyBone(const BoneOverride& mod, TRS &bone, double time)
{
mod.Modify(bone, time);
}
// explicitly don't pass modelBoneOverrides when precalculating animation for interpolation, as it's applied _after_ animation
ModelAnimFramePrecalculatedIQM IQMModel::CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData)
{
@ -682,15 +685,16 @@ const TArray<VSMatrix>* IQMModel::CalculateBonesIQM(int frame1, int frame2, floa
{
const TArray<TRS>& animationFrames = animationData ? *animationData : TRSData;
TArray<VSMatrix>* outMatrix = out ? &out->positions : &boneData;
TArray<VSMatrix>* outMatrix = out ? &out->positions_with_override : &boneData;
int numbones = Joints.SSize();
outMatrix->Resize(numbones);
if(out)
{
out->bones_anim_only.Resize(numbones);
out->bones.Resize(numbones);
out->bones_with_override.Resize(numbones);
out->positions.Resize(numbones);
}
if(in && in->size() != Joints.Size()) in = nullptr;
@ -701,11 +705,11 @@ const TArray<VSMatrix>* IQMModel::CalculateBonesIQM(int frame1, int frame2, floa
frame1 = clamp(frame1, 0, (animationFrames.SSize() - 1) / numbones);
frame2 = clamp(frame2, 0, (animationFrames.SSize() - 1) / numbones);
int offset1 = frame1 * numbones;
int offset2 = frame2 * numbones;
unsigned int offset1 = frame1 * numbones;
unsigned int offset2 = frame2 * numbones;
int offset1_1 = frame1_prev * numbones;
int offset2_1 = frame2_prev * numbones;
unsigned int offset1_1 = frame1_prev * numbones;
unsigned int offset2_1 = frame2_prev * numbones;
float invt = 1.0f - inter;
float invt1 = 1.0f - inter1_prev;
@ -751,7 +755,7 @@ const TArray<VSMatrix>* IQMModel::CalculateBonesIQM(int frame1, int frame2, floa
if(out)
{
out->bones_anim_only[i] = bone;
out->bones[i] = bone;
if(in)
{
@ -774,7 +778,6 @@ const TArray<VSMatrix>* IQMModel::CalculateBonesIQM(int frame1, int frame2, floa
VSMatrix& result = (*outMatrix)[i];
if (Joints[i].Parent >= 0)
{
assert(Joints[i].Parent < i);
result = (*outMatrix)[Joints[i].Parent];
result.multMatrix(swapYZ);
result.multMatrix(baseframe[Joints[i].Parent]);
@ -788,6 +791,32 @@ const TArray<VSMatrix>* IQMModel::CalculateBonesIQM(int frame1, int frame2, floa
result.multMatrix(inversebaseframe[i]);
}
result.multMatrix(swapYZ);
if(out)
{
VSMatrix m;
m.loadIdentity();
m.translate(out->bones[i].translation.X, out->bones[i].translation.Y, out->bones[i].translation.Z);
m.multQuaternion(out->bones[i].rotation);
m.scale(out->bones[i].scaling.X, out->bones[i].scaling.Y, out->bones[i].scaling.Z);
VSMatrix& result = out->positions[i];
if (Joints[i].Parent >= 0)
{
result = out->positions[Joints[i].Parent];
result.multMatrix(swapYZ);
result.multMatrix(baseframe[Joints[i].Parent]);
result.multMatrix(m);
result.multMatrix(inversebaseframe[i]);
}
else
{
result.loadMatrix(swapYZ);
result.multMatrix(m);
result.multMatrix(inversebaseframe[i]);
}
result.multMatrix(swapYZ);
}
}
return &boneData;

View file

@ -680,14 +680,14 @@ int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction
auto vproto = Virtuals[i]->Proto;
auto &vflags = Virtuals[i]->ArgFlags;
int n = flags.size();
int n = flags.SSize();
bool flagsOk = true;
for(int i = 0; i < n; i++)
{
int argA = i >= vflags.size() ? 0 : vflags[i];
int argB = i >= flags.size() ? 0 : flags[i];
int argA = i >= vflags.SSize() ? 0 : vflags[i];
int argB = i >= flags.SSize() ? 0 : flags[i];
bool AisRef = argA & (VARF_Out | VARF_Ref);
bool BisRef = argB & (VARF_Out | VARF_Ref);

View file

@ -102,14 +102,14 @@ namespace
float v_MinimumToFill2(uint32_t inwidth, uint32_t inheight)
{
// sx = screen x dimension, sy = same for y
float sx = (float)inwidth * 1.2, sy = (float)inheight;
float sx = (float)inwidth * 1.2f, sy = (float)inheight;
static float lastsx = 0., lastsy = 0., result = 0.;
if (lastsx != sx || lastsy != sy)
{
if (sx <= 0. || sy <= 0.)
return 1.; // prevent x/0 error
// set absolute minimum scale to fill the entire screen but get as close to 640x400 as possible
float ssx = (float)(VID_MIN_UI_WIDTH) / 1.2 / sx, ssy = (float)(VID_MIN_UI_HEIGHT) / sy;
float ssx = (float)(VID_MIN_UI_WIDTH) / 1.2f / sx, ssy = (float)(VID_MIN_UI_HEIGHT) / sy;
result = (ssx < ssy) ? ssy : ssx;
lastsx = sx;
lastsy = sy;
@ -165,7 +165,7 @@ namespace
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return 1280; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 800; }, 1.2f, false }, // 4 - 1280x800
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customheight; }, 1.0f, true }, // 5 - Custom
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return 320; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 200; }, 1.2f, false }, // 6 - 320x200
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX2(Width, Height) * 1.2; }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY2(Width, Height); }, 1.2f, false }, // 7 - Minimum Scale to Fill Entire Screen (1.2)
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return uint32_t(v_mfillX2(Width, Height) * 1.2); }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY2(Width, Height); }, 1.2f, false }, // 7 - Minimum Scale to Fill Entire Screen (1.2)
};
bool isOutOfBounds(int x)
{

View file

@ -49,6 +49,7 @@
#endif
#include "m_png.h"
#include "basics.h"
#include "printf.h"
// MACROS ------------------------------------------------------------------
@ -944,7 +945,13 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height
y = height;
stream.next_out = buffer.data();
stream.avail_out = buffer.size();
if(buffer.size() > UINT_MAX)
{
I_Error("save png buffer too large");
}
stream.avail_out = (unsigned int) buffer.size();
temprow[0][0] = 0;
#if USE_FILTER_HEURISTIC
@ -1006,12 +1013,24 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height
}
while (stream.avail_out == 0)
{
if (!WriteIDAT (file, buffer.data(), buffer.size()))
if(buffer.size() > INT_MAX)
{
I_Error("save png buffer too large");
}
int sz = (int) buffer.size();
if (!WriteIDAT (file, buffer.data(), sz))
{
return false;
}
stream.next_out = buffer.data();
stream.avail_out = buffer.size();
if(buffer.size() > UINT_MAX)
{
I_Error("save png buffer too large");
}
stream.avail_out = (unsigned int) buffer.size();
if (stream.avail_in != 0)
{
err = deflate (&stream, (y == 0) ? Z_FINISH : 0);
@ -1032,12 +1051,23 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height
}
if (stream.avail_out == 0)
{
if (!WriteIDAT (file, buffer.data(), buffer.size()))
if(buffer.size() > INT_MAX)
{
I_Error("save png buffer too large");
}
int sz = (int) buffer.size();
if (!WriteIDAT (file, buffer.data(), sz))
{
return false;
}
stream.next_out = buffer.data();
stream.avail_out = buffer.size();
if(buffer.size() > UINT_MAX)
{
I_Error("save png buffer too large");
}
stream.avail_out = (unsigned int) buffer.size();
}
}
@ -1047,7 +1077,15 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height
{
return false;
}
return WriteIDAT (file, buffer.data(), buffer.size() - stream.avail_out);
if((buffer.size() - stream.avail_out) > INT_MAX)
{
I_Error("save png buffer too large");
}
int sz = (int) (buffer.size() - stream.avail_out);
return WriteIDAT (file, buffer.data(), sz);
}
//==========================================================================

View file

@ -144,7 +144,7 @@ class VSMatrix {
static void multMatrix(FLOATTYPE *resMatrix, const FLOATTYPE *aMatrix);
static void setIdentityMatrix(FLOATTYPE *mat, int size = 4);
public:
/// The storage for matrices
FLOATTYPE mMatrix[16];

View file

@ -82,25 +82,15 @@ public:
}
// returns the XY fields as a 2D-vector.
const Vector2& XY() const
Vector2 XY() const
{
return *reinterpret_cast<const Vector2*>(this);
return Vector2(X, Y);
}
Vector2& XY()
// returns the XYZ fields as a 3D-vector.
Vector3 XYZ() const
{
return *reinterpret_cast<Vector2*>(this);
}
// returns the XY fields as a 2D-vector.
const Vector3& XYZ() const
{
return *reinterpret_cast<const Vector3*>(this);
}
Vector3& XYZ()
{
return *reinterpret_cast<Vector3*>(this);
return Vector3(X, Y, Z);
}
@ -320,7 +310,10 @@ public:
auto factor = sinTheta / g_sqrt(lengthSquared);
TQuaternion<vec_t> ret;
ret.W = cosTheta;
ret.XYZ() = factor * axis;
auto xyz = vec_t(factor) * axis;
ret.X = vec_t(xyz.X);
ret.Y = vec_t(xyz.Y);
ret.Z = vec_t(xyz.Z);
return ret;
}
static TQuaternion<vec_t> FromAngles(TAngle<vec_t> yaw, TAngle<vec_t> pitch, TAngle<vec_t> roll)

View file

@ -705,12 +705,16 @@ struct TVector3
return *this;
}
// returns a version with swapped Z/Y
constexpr const TVector3 ToXZY() const
{
return {X, Z, Y};
}
constexpr TVector3 ScaleXYZ (const TVector3 &scaling)
{
return TVector3(X * scaling.X, Y * scaling.Y, Z * scaling.Z);
}
};
template<class vec_t>

View file

@ -1844,12 +1844,15 @@ FExecList *D_MultiExec (FArgs *list, FExecList *exec)
static void GetCmdLineFiles(std::vector<std::string>& wadfiles)
{
FString *args;
int i, argc;
int i;
int argc;
argc = Args->CheckParmList("-file", &args);
assert(wadfiles.size() < INT_MAX);
// [RL0] Check for array size to only add new wads
for (i = wadfiles.size(); i < argc; ++i)
for (i = int(wadfiles.size()); i < argc; ++i)
{
D_AddWildFile(wadfiles, args[i].GetChars(), ".wad", GameConfig);
}

View file

@ -123,7 +123,12 @@ void DNetworkBuffer::AddDouble(double msg)
void DNetworkBuffer::AddString(const FString& msg)
{
_size += msg.Len() + 1u;
if(msg.Len() >= UINT_MAX)
{
I_Error("network buffer string too large");
}
_size += ((unsigned int)msg.Len()) + 1u;
_buffer.Push({ NET_STRING, msg });
}
@ -427,8 +432,14 @@ bool EventManager::SendNetworkCommand(const FName& cmd, VMVa_List& args)
{
++bytes; // Strings will always consume at least one byte.
const FString* str = ListGetString(args);
if(str->Len() >= UINT_MAX || (bytes + (unsigned int)str->Len()) >= UINT_MAX)
{
I_Error("network buffer string too large");
}
if (str != nullptr)
bytes += str->Len();
bytes += (unsigned int)str->Len();
break;
}
}

View file

@ -2024,7 +2024,7 @@ void G_ReadSnapshots(FResourceFile *resf)
G_ClearSnapshots();
for (unsigned j = 0; j < resf->EntryCount(); j++)
for (unsigned j = 0; j < resf->EntryCountU(); j++)
{
auto name = resf->getName(j);
auto ptr = strstr(name, ".map.json");

View file

@ -1063,7 +1063,7 @@ public:
void SetPlaneReflectivity(int pos, double val)
{
reflect[pos] = val;
reflect[pos] = float(val);
}
double GetPlaneReflectivity(int pos)

View file

@ -210,7 +210,7 @@ void FTextureAnimator::InitAnimated (void)
if (lumpnum != -1)
{
auto animatedlump = fileSystem.ReadFile (lumpnum);
int animatedlen = fileSystem.FileLength(lumpnum);
ptrdiff_t animatedlen = fileSystem.FileLength(lumpnum);
auto animdefs = animatedlump.bytes();
const uint8_t *anim_p;
FTextureID pic1, pic2;

View file

@ -283,7 +283,12 @@ void InitBuildTiles()
}
auto& artdata = TexMan.GetNewBuildTileData();
artdata.Resize(fileSystem.FileLength(lumpnum));
ptrdiff_t len = fileSystem.FileLength(lumpnum);
assert(len >= 0 && len < UINT_MAX);
artdata.Resize((unsigned int)len);
fileSystem.ReadFile(lumpnum, &artdata[0]);
if ((numtiles = CountTiles(&artdata[0])) > 0)

View file

@ -93,7 +93,7 @@ SettingsPage::SettingsPage(LauncherWindow* launcher, int* autoloadflags) : Widge
}
}
}
catch (const std::exception& ex)
catch (const std::exception&)
{
hideLanguage = true;
}

View file

@ -283,7 +283,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck)
map->MapLumps[0].Reader = map->resource->GetEntryReader(0, FileSys::READER_SHARED);
uppercopy(map->MapLumps[0].Name, map->resource->getName(0));
for(uint32_t i = 1; i < map->resource->EntryCount(); i++)
for(uint32_t i = 1; i < map->resource->EntryCountU(); i++)
{
const char* lumpname = map->resource->getName(i);

View file

@ -726,8 +726,19 @@ struct AnimModelOverride
enum EModelDataFlags
{
MODELDATA_HADMODEL = 1 << 0,
MODELDATA_OVERRIDE_FLAGS = 1 << 1,
MODELDATA_HADMODEL = 1 << 0,
MODELDATA_OVERRIDE_FLAGS = 1 << 1,
MODELDATA_GET_BONE_INFO = 1 << 2,
MODELDATA_GET_BONE_INFO_RECALC = 1 << 3, // RECALCULATE BONE INFO INSTANTLY WHEN STATE/ANIMATION CHANGES, MIGHT GET EXPENSIVE
MODELDATA_IQMFLAGS = MODELDATA_GET_BONE_INFO | MODELDATA_GET_BONE_INFO_RECALC,
};
class DActorModelData : public DObject
@ -740,6 +751,7 @@ public:
TArray<AnimModelOverride> animationIDs;
TArray<int> modelFrameGenerators;
TArray<TArray<BoneOverride>> modelBoneOverrides;
TArray<BoneInfo> modelBoneInfo;
int flags;
int overrideFlagsSet;
int overrideFlagsClear;
@ -801,6 +813,15 @@ public:
virtual void Tick() override;
void EnableNetworking(const bool enable) override;
void CalcBones(bool recalc);
TRS GetBoneTRS(int model_index, int bone_index, bool with_override);
//outmat must be double[16]
void GetBoneMatrix(int model_index, int bone_index, bool with_override, double *outMat);
void GetBonePosition(int model_index, int bone_index, bool with_override, DVector3 &pos, DVector3 &normal);
void GetObjectToWorldMatrix(double *outMat);
static AActor *StaticSpawn (FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
inline AActor *GetDefault () const

View file

@ -5125,15 +5125,6 @@ static void CleanupModelData(AActor * mobj)
FQuaternion InterpolateQuat(const FQuaternion &from, const FQuaternion &to, float t, float invt);
static void SetModelBoneRotationInternal(AActor * self, FModel * mdl, int model_index, int index, FQuaternion rotation, int mode, double interpolation_duration, double switchTic)
{
if(self->modelData->modelBoneOverrides.Size() <= model_index) self->modelData->modelBoneOverrides.Resize(model_index + 1);
self->modelData->modelBoneOverrides[model_index].Resize(mdl->NumJoints());
self->modelData->modelBoneOverrides[model_index][index].rotation.Set(rotation, switchTic, interpolation_duration, mode);
}
template<bool isSet, bool isOffset>
FModel * SetGetBoneShared(AActor * self, int model_index)
{
@ -5149,11 +5140,11 @@ FModel * SetGetBoneShared(AActor * self, int model_index)
EnsureModelData(self);
if(self->modelData->models.Size() > model_index && self->modelData->models[model_index].modelID >= 0 && self->modelData->models[model_index].modelID < Models.Size())
if(self->modelData->models.SSize() > model_index && self->modelData->models[model_index].modelID >= 0 && self->modelData->models[model_index].modelID < Models.SSize())
{
return Models[self->modelData->models[model_index].modelID];
}
else if(BaseSpriteModelFrames[self->GetClass()].modelIDs.Size() > model_index)
else if(BaseSpriteModelFrames[self->GetClass()].modelIDs.SSize() > model_index)
{
return Models[BaseSpriteModelFrames[self->GetClass()].modelIDs[model_index]];
}
@ -5182,7 +5173,7 @@ FModel * SetGetBoneSharedIndex(AActor * self, int model_index, int &bone_index,
ThrowAbortException(X_OTHER, "bone index out of range");
}
if(self->modelData->modelBoneOverrides.Size() <= model_index) self->modelData->modelBoneOverrides.Resize(model_index + 1);
if(self->modelData->modelBoneOverrides.SSize() <= model_index) self->modelData->modelBoneOverrides.Resize(model_index + 1);
self->modelData->modelBoneOverrides[model_index].Resize(mdl->NumJoints());
@ -5224,6 +5215,8 @@ static void SetModelBoneRotationNative(AActor * self, int model_index, int bone_
if(!mdl) return;
self->modelData->modelBoneOverrides[model_index][bone_index].rotation.Set(FQuaternion(rot_x, rot_y, rot_z, rot_w), self->Level->totaltime + ticFrac, interpolation_duration, mode);
self->CalcBones(true);
}
static void SetBoneRotationNative(AActor * self, int bone_index, double rot_x, double rot_y, double rot_z, double rot_w, int mode, double interpolation_duration, double ticFrac)
@ -5242,6 +5235,8 @@ static void SetModelNamedBoneRotationNative(AActor * self, int model_index, int
if(!mdl) return;
self->modelData->modelBoneOverrides[model_index][bone_index].rotation.Set(FQuaternion(rot_x, rot_y, rot_z, rot_w), self->Level->totaltime + ticFrac, interpolation_duration, mode);
self->CalcBones(true);
}
static void SetNamedBoneRotationNative(AActor * self, int boneName_i, double rot_x, double rot_y, double rot_z, double rot_w, int mode, double interpolation_duration, double ticFrac)
@ -5294,6 +5289,8 @@ static void SetModelBoneTranslationNative(AActor * self, int model_index, int bo
if(!mdl) return;
self->modelData->modelBoneOverrides[model_index][bone_index].translation.Set(FVector3(rot_x, rot_y, rot_z), self->Level->totaltime + ticFrac, interpolation_duration, mode);
self->CalcBones(true);
}
static void SetBoneTranslationNative(AActor * self, int bone_index, double rot_x, double rot_y, double rot_z, int mode, double interpolation_duration, double ticFrac)
@ -5312,6 +5309,8 @@ static void SetModelNamedBoneTranslationNative(AActor * self, int model_index, i
if(!mdl) return;
self->modelData->modelBoneOverrides[model_index][bone_index].translation.Set(FVector3(rot_x, rot_y, rot_z), self->Level->totaltime + ticFrac, interpolation_duration, mode);
self->CalcBones(true);
}
static void SetNamedBoneTranslationNative(AActor * self, int boneName_i, double rot_x, double rot_y, double rot_z, int mode, double interpolation_duration, double ticFrac)
@ -5362,6 +5361,8 @@ static void SetModelBoneScalingNative(AActor * self, int model_index, int bone_i
if(!mdl) return;
self->modelData->modelBoneOverrides[model_index][bone_index].scaling.Set(FVector3(rot_x, rot_y, rot_z), self->Level->totaltime + ticFrac, interpolation_duration, mode);
self->CalcBones(true);
}
static void SetBoneScalingNative(AActor * self, int bone_index, double rot_x, double rot_y, double rot_z, int mode, double interpolation_duration, double ticFrac)
@ -5380,6 +5381,8 @@ static void SetModelNamedBoneScalingNative(AActor * self, int model_index, int b
if(!mdl) return;
self->modelData->modelBoneOverrides[model_index][bone_index].scaling.Set(FVector3(rot_x, rot_y, rot_z), self->Level->totaltime + ticFrac, interpolation_duration, mode);
self->CalcBones(true);
}
static void SetNamedBoneScalingNative(AActor * self, int boneName_i, double rot_x, double rot_y, double rot_z, int mode, double interpolation_duration, double ticFrac)
@ -5665,51 +5668,46 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetNamedBoneChildren, GetNamedBoneChildren
return 0;
}
static double GetBoneLengthNative(AActor * self, int bone_index)
{
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
return mdl->GetJointLength(bone_index);
}
static double GetNamedBoneLengthNative(AActor * self, int boneName_i)
{
FName bone_name {ENamedName(boneName_i)};
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
return mdl->GetJointLength(bone_index);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetBoneLength, GetBoneLengthNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(boneindex);
ACTION_RETURN_FLOAT(GetBoneLengthNative(self, boneindex));
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetNamedBoneLength, GetNamedBoneLengthNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bonename);
ACTION_RETURN_FLOAT(GetNamedBoneLengthNative(self, bonename.GetIndex()));
}
DEFINE_ACTION_FUNCTION(AActor, GetBoneDir)
DEFINE_ACTION_FUNCTION(AActor, GetBoneBaseTRS)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
ACTION_RETURN_VEC3(DVector3(mdl->GetJointDir(bone_index)));
DVector3 translation(0,0,0);
DVector4 rotation(0,0,0,1);
DVector3 scaling(0,0,0);
if(mdl)
{
TRS pose = mdl->GetJointBaseTRS(bone_index);
translation = DVector3(pose.translation);
rotation = DVector4(pose.rotation);
scaling = DVector3(pose.scaling);
}
if(numret > 2)
{
ret[2].SetVector(scaling);
numret = 3;
}
if(numret > 1)
{
ret[1].SetVector(translation);
}
if(numret > 0)
{
ret[0].SetVector4(rotation);
}
return numret;
}
DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneDir)
DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneBaseTRS)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
@ -5718,7 +5716,36 @@ DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneDir)
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
ACTION_RETURN_VEC3(DVector3(mdl->GetJointDir(bone_index)));
DVector3 translation(0,0,0);
DVector4 rotation(0,0,0,1);
DVector3 scaling(0,0,0);
if(mdl)
{
TRS pose = mdl->GetJointBaseTRS(bone_index);
translation = DVector3(pose.translation);
rotation = DVector4(pose.rotation);
scaling = DVector3(pose.scaling);
}
if(numret > 2)
{
ret[2].SetVector(scaling);
numret = 3;
}
if(numret > 1)
{
ret[1].SetVector(translation);
}
if(numret > 0)
{
ret[0].SetVector4(rotation);
}
return numret;
}
static int GetBoneCountNative(AActor * self)
@ -5735,9 +5762,415 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetBoneCount, GetBoneCountNative)
ACTION_RETURN_INT(GetBoneCountNative(self));
}
//================================================
//
// Bone Pose Getters
//
//================================================
static int GetAnimStartFrameNative(AActor * self, int animName_i)
{
FName anim_name {ENamedName(animName_i)};
FModel * mdl = SetGetBoneShared<false, false>(self, 0);
return mdl->FindFirstFrame(anim_name);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetAnimStartFrame, GetAnimStartFrameNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(animName);
ACTION_RETURN_INT(GetAnimStartFrameNative(self, animName.GetIndex()));
}
static int GetAnimEndFrameNative(AActor * self, int animName_i)
{
FName anim_name {ENamedName(animName_i)};
FModel * mdl = SetGetBoneShared<false, false>(self, 0);
return mdl->FindLastFrame(anim_name);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetAnimEndFrame, GetAnimEndFrameNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(animName);
ACTION_RETURN_INT(GetAnimEndFrameNative(self, animName.GetIndex()));
}
static double GetAnimFramerateNative(AActor * self, int animName_i)
{
FName anim_name {ENamedName(animName_i)};
FModel * mdl = SetGetBoneShared<false, false>(self, 0);
return mdl->FindFramerate(anim_name);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetAnimFramerate, GetAnimFramerateNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(animName);
ACTION_RETURN_FLOAT(GetAnimFramerateNative(self, animName.GetIndex()));
}
DEFINE_ACTION_FUNCTION(AActor, GetBoneFramePose)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
PARAM_INT(frame_index);
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
DVector3 translation(0,0,0);
DVector4 rotation(0,0,0,1);
DVector3 scaling(0,0,0);
if(mdl && frame_index < mdl->NumFrames())
{
TRS pose = mdl->GetJointPose(bone_index, frame_index);
translation = DVector3(pose.translation);
rotation = DVector4(pose.rotation);
scaling = DVector3(pose.scaling);
}
if(numret > 2)
{
ret[2].SetVector(scaling);
numret = 3;
}
if(numret > 1)
{
ret[1].SetVector(translation);
}
if(numret > 0)
{
ret[0].SetVector4(rotation);
}
return numret;
}
DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneFramePose)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
PARAM_INT(frame_index);
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
DVector3 translation(0,0,0);
DVector4 rotation(0,0,0,1);
DVector3 scaling(0,0,0);
if(mdl && frame_index < mdl->NumFrames())
{
TRS pose = mdl->GetJointPose(bone_index, frame_index);
translation = DVector3(pose.translation);
rotation = DVector4(pose.rotation);
scaling = DVector3(pose.scaling);
}
if(numret > 2)
{
ret[2].SetVector(scaling);
numret = 3;
}
if(numret > 1)
{
ret[1].SetVector(translation);
}
if(numret > 0)
{
ret[0].SetVector4(rotation);
}
return numret;
}
DEFINE_ACTION_FUNCTION(AActor, GetBoneBasePosition)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
ACTION_RETURN_VEC3(DVector3(mdl->GetJointPosition(bone_index)));
}
DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneBasePosition)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
ACTION_RETURN_VEC3(DVector3(mdl->GetJointPosition(bone_index)));
}
DEFINE_ACTION_FUNCTION(AActor, GetBoneBaseRotation)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
ACTION_RETURN_VEC4(DVector4(mdl->GetJointRotation(bone_index)));
}
DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneBaseRotation)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
ACTION_RETURN_VEC4(DVector4(mdl->GetJointRotation(bone_index)));
}
//================================================
//
// Bone TRS Getters
//
//================================================
DEFINE_ACTION_FUNCTION(AActor, GetBone)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
PARAM_BOOL(with_override);
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
DVector3 translation(0,0,0);
DVector4 rotation(0,0,0,1);
DVector3 scaling(0,0,0);
if(mdl)
{
TRS trs = self->GetBoneTRS(0, bone_index, with_override);
translation = DVector3(trs.translation);
rotation = DVector4(trs.rotation);
scaling = DVector3(trs.scaling);
}
if(numret > 2)
{
ret[2].SetVector(scaling);
numret = 3;
}
if(numret > 1)
{
ret[1].SetVector(translation);
}
if(numret > 0)
{
ret[0].SetVector4(rotation);
}
return numret;
}
DEFINE_ACTION_FUNCTION(AActor, GetNamedBone)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
PARAM_BOOL(with_override);
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
DVector3 translation(0,0,0);
DVector4 rotation(0,0,0,1);
DVector3 scaling(0,0,0);
if(mdl)
{
TRS trs = self->GetBoneTRS(0, bone_index, with_override);
translation = DVector3(trs.translation);
rotation = DVector4(trs.rotation);
scaling = DVector3(trs.scaling);
}
if(numret > 2)
{
ret[2].SetVector(scaling);
numret = 3;
}
if(numret > 1)
{
ret[1].SetVector(translation);
}
if(numret > 0)
{
ret[0].SetVector4(rotation);
}
return numret;
}
DEFINE_ACTION_FUNCTION(AActor, TransformByBone)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
PARAM_FLOAT(pos_x);
PARAM_FLOAT(pos_y);
PARAM_FLOAT(pos_z);
PARAM_FLOAT(dir_x);
PARAM_FLOAT(dir_y);
PARAM_FLOAT(dir_z);
PARAM_BOOL(with_override);
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
DVector3 position(pos_x, pos_y, pos_z);
DVector3 direction(dir_x, dir_y, dir_z);
if(mdl)
{
self->GetBonePosition(0, bone_index, with_override, position, direction);
}
if(numret > 1)
{
ret[1].SetVector(direction);
}
if(numret > 0)
{
ret[0].SetVector(position);
}
return numret;
}
DEFINE_ACTION_FUNCTION(AActor, TransformByNamedBone)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
PARAM_FLOAT(pos_x);
PARAM_FLOAT(pos_y);
PARAM_FLOAT(pos_z);
PARAM_FLOAT(dir_x);
PARAM_FLOAT(dir_y);
PARAM_FLOAT(dir_z);
PARAM_BOOL(with_override);
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
DVector3 position(pos_x, pos_y, pos_z);
DVector3 direction(dir_x, dir_y, dir_z);
if(mdl)
{
self->GetBonePosition(0, bone_index, with_override, position, direction);
}
if(numret > 1)
{
ret[1].SetVector(direction);
}
if(numret > 0)
{
ret[0].SetVector(position);
}
return numret;
}
//================================================
//
// Bone Matrix Getters
//
//================================================
DEFINE_ACTION_FUNCTION(AActor, GetBoneMatrixRaw)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(bone_index);
PARAM_POINTER(outMatrix, TArray<double>);
PARAM_BOOL(with_override);
if(outMatrix)
{
FModel * mdl = GetBoneShared(self, 0, bone_index, nullptr);
outMatrix->Clear();
outMatrix->Resize(16);
if(mdl)
{
self->GetBoneMatrix(0, bone_index, with_override, outMatrix->Data());
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, GetNamedBoneMatrixRaw)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_NAME(bone_name);
PARAM_POINTER(outMatrix, TArray<double>);
PARAM_BOOL(with_override);
if(outMatrix)
{
int bone_index;
FModel * mdl = GetBoneShared(self, 0, bone_index, &bone_name);
outMatrix->Clear();
outMatrix->Resize(16);
if(mdl)
{
self->GetBoneMatrix(0, bone_index, with_override, outMatrix->Data());
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, GetObjectToWorldMatrixRaw)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_POINTER(outMatrix, TArray<double>);
if(outMatrix)
{
FModel * mdl = SetGetBoneShared<false, false>(self, 0);
outMatrix->Clear();
outMatrix->Resize(16);
if(mdl)
{
self->GetObjectToWorldMatrix(outMatrix->Data());
}
}
return 0;
}
//================================================
// SetAnimation
@ -5771,7 +6204,11 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
if(animName == NAME_None)
{
if(self->modelData->curAnim.flags & MODELANIM_NONE) return;
self->modelData->curAnim.flags = MODELANIM_NONE;
self->CalcBones(true);
return;
}
@ -5794,11 +6231,11 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
}
FModel * animation = nullptr;
if (animID >= 0 && animID < Models.Size())
if (animID >= 0 && animID < Models.SSize())
{
animation = Models[animID];
}
else if(self->modelData->models.Size() && self->modelData->models[0].modelID >= 0 && self->modelData->models[0].modelID < Models.Size())
else if(self->modelData->models.Size() > 0 && self->modelData->models[0].modelID >= 0 && self->modelData->models[0].modelID < Models.SSize())
{
animation = Models[self->modelData->models[0].modelID];
}
@ -5811,8 +6248,12 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
if(animStart == FErr_NotFound)
{
self->modelData->curAnim.flags = MODELANIM_NONE;
Printf("Could not find animation %s\n", animName.GetChars());
if(self->modelData->curAnim.flags & MODELANIM_NONE) return;
self->modelData->curAnim.flags = MODELANIM_NONE;
self->CalcBones(true);
return;
}
@ -5861,20 +6302,32 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
if(startFrame >= len)
{
self->modelData->curAnim.flags = MODELANIM_NONE;
Printf("frame %d (startFrame) is past the end of animation %s\n", startFrame, animName.GetChars());
if(self->modelData->curAnim.flags & MODELANIM_NONE) return;
self->modelData->curAnim.flags = MODELANIM_NONE;
self->CalcBones(true);
return;
}
else if(loopFrame >= len)
{
self->modelData->curAnim.flags = MODELANIM_NONE;
Printf("frame %d (loopFrame) is past the end of animation %s\n", startFrame, animName.GetChars());
if(self->modelData->curAnim.flags & MODELANIM_NONE) return;
self->modelData->curAnim.flags = MODELANIM_NONE;
self->CalcBones(true);
return;
}
else if(endFrame >= len)
{
self->modelData->curAnim.flags = MODELANIM_NONE;
Printf("frame %d (endFrame) is past the end of animation %s\n", endFrame, animName.GetChars());
if(self->modelData->curAnim.flags & MODELANIM_NONE) return;
self->modelData->curAnim.flags = MODELANIM_NONE;
self->CalcBones(true);
return;
}
@ -5896,6 +6349,8 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
self->modelData->curAnim.startTic = tic;
self->modelData->curAnim.switchOffset = 0;
}
self->CalcBones(true);
}
void SetAnimationNative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags)
@ -5957,29 +6412,60 @@ void SetAnimationFrameRateUINative(AActor * self, double framerate)
SetAnimationFrameRateInternal(self, framerate, I_GetTimeFrac());
}
void SetModelFlag(AActor * self, int flag)
void SetModelFlag(AActor * self, int flag, int iqmFlag)
{
EnsureModelData(self);
self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS;
self->modelData->overrideFlagsSet |= flag;
self->modelData->overrideFlagsClear &= ~flag;
iqmFlag &= MODELDATA_IQMFLAGS;
if(flag)
{
self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS;
self->modelData->overrideFlagsSet |= flag;
self->modelData->overrideFlagsClear &= ~flag;
}
if(iqmFlag)
{
self->modelData->flags |= iqmFlag;
}
}
void ClearModelFlag(AActor * self, int flag)
void ClearModelFlag(AActor * self, int flag, int iqmFlag)
{
EnsureModelData(self);
self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS;
self->modelData->overrideFlagsClear |= flag;
self->modelData->overrideFlagsSet &= ~flag;
iqmFlag &= MODELDATA_IQMFLAGS;
if(flag)
{
self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS;
self->modelData->overrideFlagsClear |= flag;
self->modelData->overrideFlagsSet &= ~flag;
}
if(iqmFlag)
{
self->modelData->flags &= ~iqmFlag;
}
}
void ResetModelFlags(AActor * self)
void ResetModelFlags(AActor * self, int resetModel, int resetIqm)
{
if(self->modelData)
{
self->modelData->overrideFlagsClear = 0;
self->modelData->overrideFlagsSet = 0;
self->modelData->flags &= ~MODELDATA_OVERRIDE_FLAGS;
if(resetModel)
{
self->modelData->overrideFlagsClear = 0;
self->modelData->overrideFlagsSet = 0;
self->modelData->flags &= ~MODELDATA_OVERRIDE_FLAGS;
}
if(resetIqm)
{
self->modelData->flags &= ~MODELDATA_IQMFLAGS;
}
}
}
@ -6148,6 +6634,11 @@ void ChangeModelNative(
CleanupModelData(mobj);
if(animation != NAME_None || modeldef != nullptr)
{
mobj->CalcBones(true);
}
return;
}
@ -6228,8 +6719,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetModelFlag, SetModelFlag)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(flag);
PARAM_INT(flagIqm);
SetModelFlag(self, flag);
SetModelFlag(self, flag, flagIqm);
return 0;
}
@ -6238,8 +6730,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(flag);
PARAM_INT(flagIqm);
ClearModelFlag(self, flag);
ClearModelFlag(self, flag, flagIqm);
return 0;
}
@ -6247,8 +6740,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag)
DEFINE_ACTION_FUNCTION_NATIVE(AActor, ResetModelFlags, ResetModelFlags)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_BOOL(resetModel);
PARAM_BOOL(resetIqm);
ResetModelFlags(self);
ResetModelFlags(self, resetModel, resetIqm);
return 0;
}

View file

@ -1701,8 +1701,6 @@ int P_LookForTID (AActor *actor, INTBOOL allaround, FLookExParams *params)
AActor *LookForEnemiesInBlock (AActor *lookee, int index, void *extparam)
{
FBlockNode *block;
AActor *link;
AActor *other;
FLookExParams *params = (FLookExParams *)extparam;
for (block = lookee->Level->blockmap.blocklinks[index]; block != NULL; block = block->NextActor)

View file

@ -101,6 +101,7 @@
#include "fragglescript/t_fs.h"
#include "shadowinlines.h"
#include "model.h"
#include "models.h"
#include "d_net.h"
// MACROS ------------------------------------------------------------------
@ -3898,6 +3899,122 @@ DEFINE_ACTION_FUNCTION(AActor, CheckPortalTransition)
return 0;
}
void AActor::CalcBones(bool recalc)
{
if(modelData && (!recalc || (modelData->flags & MODELDATA_GET_BONE_INFO_RECALC)) && modelData->flags & MODELDATA_GET_BONE_INFO)
{
if(picnum.isValid()) return; // picnum overrides don't render models
FSpriteModelFrame *smf = FindModelFrame(this, sprite, frame, false); // dropped flag is for voxels
if(!smf) return;
bool is_decoupled = flags9 & MF9_DECOUPLEDANIMATIONS;
double tic = Level->totaltime + 1;
CalcModelFrameInfo frameinfo = CalcModelFrame(Level, smf, state, tics, modelData, this, is_decoupled, tic, 1.0);
ModelDrawInfo drawinfo;
int boneStartingPosition = -1;
bool evaluatedSingle = false;
modelData->modelBoneInfo.Resize(frameinfo.modelsamount);
for (unsigned i = 0; i < frameinfo.modelsamount; i++)
{
if (CalcModelOverrides(i, smf, modelData, frameinfo, drawinfo, is_decoupled))
{
if(!evaluatedSingle)
{ // [Jay] TODO per-model decoupled animations
FModel * mdl = Models[drawinfo.modelid];
bool nextFrame = frameinfo.smfNext && drawinfo.modelframe != drawinfo.modelframenext;
ProcessModelFrame(mdl, nextFrame, i, smf, modelData, frameinfo, drawinfo, is_decoupled, tic, &modelData->modelBoneInfo[i]);
if(frameinfo.smf_flags & MDL_MODELSAREATTACHMENTS || is_decoupled)
{
evaluatedSingle = true;
//if(!is_decoupled) break;
break; // TODO remove this break when per-model decoupled animations are in
}
}
}
}
}
}
TRS AActor::GetBoneTRS(int model_index, int bone_index, bool with_override)
{
if(modelData && (modelData->flags & MODELDATA_GET_BONE_INFO) && model_index > 0 && bone_index > 0 && modelData->modelBoneInfo.SSize() < model_index && modelData->modelBoneInfo[model_index].bones.SSize() < bone_index)
{
return with_override ? modelData->modelBoneInfo[model_index].bones_with_override[bone_index] : modelData->modelBoneInfo[model_index].bones[bone_index];
}
return {};
}
void AActor::GetBoneMatrix(int model_index, int bone_index, bool with_override, double *outMat)
{
VSMatrix boneMatrix = (with_override ? modelData->modelBoneInfo[model_index].positions_with_override : modelData->modelBoneInfo[model_index].positions)[bone_index];
for(int i = 0; i < 16; i++)
{
outMat[i] = boneMatrix.mMatrix[i];
}
}
void AActor::GetBonePosition(int model_index, int bone_index, bool with_override, DVector3 &pos, DVector3 &normal)
{
if(modelData && modelData->flags & MODELDATA_GET_BONE_INFO)
{
if(picnum.isValid()) return; // picnum overrides don't render models
FSpriteModelFrame *smf = FindModelFrame(this, sprite, frame, false); // dropped flag is for voxels
FVector3 objPos = FVector3(Pos() + WorldOffset);
VSMatrix boneMatrix = (with_override ? modelData->modelBoneInfo[model_index].positions_with_override : modelData->modelBoneInfo[model_index].positions)[bone_index];
VSMatrix worldMatrix = smf->ObjectToWorldMatrix(this, objPos.X, objPos.Y, objPos.Z, 1.0);
FVector4 oldPos(pos.X, pos.Z, pos.Y, 1.0);
FVector4 newPos;
FVector4 oldNormal(normal.X, normal.Z, normal.Y, 0.0);
FVector4 newNormal;
boneMatrix.multMatrixPoint(&oldPos.X, &newPos.X);
boneMatrix.multMatrixPoint(&oldNormal.X, &newNormal.X);
oldPos = FVector4(FVector3(newPos.X, newPos.Y, newPos.Z) / newPos.W, 1.0);
oldNormal = FVector4(FVector3(newNormal.X, newNormal.Y, newNormal.Z) / newNormal.W, 0.0);
worldMatrix.multMatrixPoint(&oldPos.X, &newPos.X);
worldMatrix.multMatrixPoint(&oldNormal.X, &newNormal.X);
pos = DVector3(newPos.X, newPos.Z, newPos.Y);
normal = DVector3(newNormal.X, newNormal.Z, newNormal.Y);
}
}
void AActor::GetObjectToWorldMatrix(double *outMat)
{
if(modelData && modelData->flags & MODELDATA_GET_BONE_INFO)
{
if(picnum.isValid()) return; // picnum overrides don't render models
FSpriteModelFrame *smf = FindModelFrame(this, sprite, frame, false); // dropped flag is for voxels
FVector3 pos = FVector3(Pos() + WorldOffset);
VSMatrix outMatrix = smf->ObjectToWorldMatrix(this, pos.X, pos.Y, pos.Z, 1.0);
for(int i = 0; i < 16; i++)
{
outMat[i] = outMatrix.mMatrix[i];
}
}
}
//
// P_MobjThinker
//
@ -3945,6 +4062,11 @@ void AActor::Tick ()
return;
}
if(flags9 & MF9_DECOUPLEDANIMATIONS)
{
CalcBones(false);
}
AActor *onmo;
//assert (state != NULL);
@ -4501,6 +4623,11 @@ void AActor::Tick ()
}
}
if(!(flags9 & MF9_DECOUPLEDANIMATIONS) && modelData && !(modelData->flags & MODELDATA_GET_BONE_INFO_RECALC))
{
CalcBones(false);
}
if (tics == -1 || state->GetCanRaise())
{
int respawn_monsters = G_SkillProperty(SKILLP_Respawn);

View file

@ -797,7 +797,7 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkin)
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkinCount)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
ACTION_RETURN_INT(Skins.size());
ACTION_RETURN_INT(Skins.SSize());
}
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetGender)

View file

@ -61,32 +61,42 @@ float pauseTimeOffset = .0f;
extern TDeletingArray<FVoxel *> Voxels;
extern TDeletingArray<FVoxelDef *> VoxelDefs;
void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame *smf, const FState* curState, const int curTics, FTranslationID translation, AActor* actor);
void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame *smf, const FState* curState, int curTics, double tic, FTranslationID translation, AActor* actor);
void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac)
{
// Setup transformation.
int smf_flags = smf->getFlags(actor->modelData);
FTranslationID translation = NO_TRANSLATION;
if (!(smf_flags & MDL_IGNORETRANSLATION))
translation = actor->Translation;
// y scale for a sprite means height, i.e. z in the world!
VSMatrix objectToWorldMatrix = smf->ObjectToWorldMatrix(actor, x, y, z, ticFrac);
float scaleFactorX = actor->Scale.X * smf->xscale;
float scaleFactorY = actor->Scale.X * smf->yscale;
float scaleFactorZ = actor->Scale.Y * smf->zscale;
float pitch = 0;
float roll = 0;
double rotateOffset = 0;
float orientation = scaleFactorX * scaleFactorY * scaleFactorZ;
renderer->BeginDrawModel(actor->RenderStyle, smf_flags, objectToWorldMatrix, orientation < 0);
RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, ticFrac, translation, actor);
renderer->EndDrawModel(actor->RenderStyle, smf_flags);
}
VSMatrix FSpriteModelFrame::ObjectToWorldMatrix(AActor * actor, float x, float y, float z, double ticFrac)
{
int smf_flags = getFlags(actor->modelData);
// Setup transformation.
DRotator angles;
if (actor->renderflags & RF_INTERPOLATEANGLES) // [Nash] use interpolated angles
angles = actor->InterpolatedAngles(ticFrac);
else
angles = actor->Angles;
float angle = angles.Yaw.Degrees();
float pitch = 0;
float roll = 0;
// [BB] Workaround for the missing pitch information.
if ((smf_flags & MDL_PITCHFROMMOMENTUM))
@ -109,34 +119,6 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod
}
}
if (smf_flags & MDL_ROTATING)
{
bool isPaused = paused || P_CheckTickerPaused();
float timeFloat;
if (isPaused)
{
if (pauseTimeOffset == .0f)
pauseTimeOffset = (I_GetTime() + I_GetTimeFrac());
timeFloat = pauseTimeOffset;
}
else
{
pauseTimeOffset = .0f;
timeFloat = (I_GetTime() + I_GetTimeFrac());
}
if (smf->rotationSpeed > 0.0000000001 || smf->rotationSpeed < -0.0000000001)
{
double turns = timeFloat / (200.0 / smf->rotationSpeed);
turns -= floor(turns);
rotateOffset = turns * 360.0;
}
else
{
rotateOffset = 0.0;
}
}
// Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing.
// If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch.
if (smf_flags & MDL_USEACTORPITCH)
@ -147,75 +129,130 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod
}
if (smf_flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees();
// [Nash] take SpriteRotation into account
angle += actor->SpriteRotation.Degrees();
double tic = actor->Level->totaltime;
if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !actor->isFrozen())
{
tic += ticFrac;
}
return ObjectToWorldMatrix(actor->Level, DVector3(x, y, z), DRotator(DAngle::fromDeg(pitch), DAngle::fromDeg(angle), DAngle::fromDeg(roll)), actor->Scale, smf_flags, tic);
}
VSMatrix FSpriteModelFrame::ObjectToWorldMatrix(FLevelLocals *Level, DVector3 translation, DRotator rotation, DVector2 scaling, unsigned int flags, double tic)
{
double rotateOffset = 0;
if (flags & MDL_ROTATING)
{
bool isPaused = paused || P_CheckTickerPaused();
float timeFloat;
if (isPaused)
{
if (pauseTimeOffset == .0f)
pauseTimeOffset = tic;
timeFloat = pauseTimeOffset;
}
else
{
pauseTimeOffset = .0f;
timeFloat = tic;
}
if (rotationSpeed > 0.0000000001 || rotationSpeed < -0.0000000001)
{
double turns = (timeFloat) / (200.0 / rotationSpeed);
turns -= floor(turns);
rotateOffset = turns * 360.0;
}
else
{
rotateOffset = 0.0;
}
}
// y scale for a sprite means height, i.e. z in the world!
float scaleFactorX = scaling.X * xscale;
float scaleFactorY = scaling.X * yscale;
float scaleFactorZ = scaling.Y * zscale;
VSMatrix objectToWorldMatrix;
objectToWorldMatrix.loadIdentity();
// Model space => World space
objectToWorldMatrix.translate(x, z, y);
// [Nash] take SpriteRotation into account
angle += actor->SpriteRotation.Degrees();
objectToWorldMatrix.translate(translation.X, translation.Z, translation.Y);
// consider the pixel stretching. For non-voxels this must be factored out here
float stretch = 1.f;
// [MK] distortions might happen depending on when the pixel stretch is compensated for
// so we make the "undistorted" behavior opt-in
if (smf_flags & MDL_CORRECTPIXELSTRETCH)
if ((flags & MDL_CORRECTPIXELSTRETCH) && modelIDs.Size() > 0)
{
stretch = (smf->modelIDs[0] >= 0 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch;
stretch = (modelIDs[0] >= 0 ? Models[modelIDs[0]]->getAspectFactor(Level->info->pixelstretch) : 1.f) / Level->info->pixelstretch;
objectToWorldMatrix.scale(1, stretch, 1);
}
// Applying model transformations:
// 1) Applying actor angle, pitch and roll to the model
if (smf_flags & MDL_USEROTATIONCENTER)
if (flags & MDL_USEROTATIONCENTER)
{
objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterZ/stretch, smf->rotationCenterY);
}
objectToWorldMatrix.rotate(-angle, 0, 1, 0);
objectToWorldMatrix.rotate(pitch, 0, 0, 1);
objectToWorldMatrix.rotate(-roll, 1, 0, 0);
if (smf_flags & MDL_USEROTATIONCENTER)
{
objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterZ/stretch, -smf->rotationCenterY);
}
objectToWorldMatrix.translate(rotationCenterX, rotationCenterY/stretch, rotationCenterZ);
// 2) Applying Doomsday like rotation of the weapon pickup models
// The rotation angle is based on the elapsed time.
objectToWorldMatrix.rotate(-rotation.Yaw.Degrees(), 0, 1, 0);
objectToWorldMatrix.rotate(rotation.Pitch.Degrees(), 0, 0, 1);
objectToWorldMatrix.rotate(-rotation.Roll.Degrees(), 1, 0, 0);
if (smf_flags & MDL_ROTATING)
// 2) Applying Doomsday like rotation of the weapon pickup models
// The rotation angle is based on the elapsed time.
if(flags & MDL_ROTATING)
{
objectToWorldMatrix.rotate(rotateOffset, xrotate, yrotate, zrotate);
}
objectToWorldMatrix.translate(-rotationCenterX, -rotationCenterY/stretch, -rotationCenterZ);
}
else
{
objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterY/stretch, smf->rotationCenterZ);
objectToWorldMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate);
objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY/stretch, -smf->rotationCenterZ);
objectToWorldMatrix.rotate(-rotation.Yaw.Degrees(), 0, 1, 0);
objectToWorldMatrix.rotate(rotation.Pitch.Degrees(), 0, 0, 1);
objectToWorldMatrix.rotate(-rotation.Roll.Degrees(), 1, 0, 0);
// 2) Applying Doomsday like rotation of the weapon pickup models
// The rotation angle is based on the elapsed time.
if(flags & MDL_ROTATING)
{
objectToWorldMatrix.translate(rotationCenterX, rotationCenterY/stretch, rotationCenterZ);
objectToWorldMatrix.rotate(rotateOffset, xrotate, yrotate, zrotate);
objectToWorldMatrix.translate(-rotationCenterX, -rotationCenterY/stretch, -rotationCenterZ);
}
}
// 3) Scaling model.
objectToWorldMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY);
// 4) Aplying model offsets (model offsets do not depend on model scalings).
objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / (smf->zscale*stretch), smf->yoffset / smf->yscale);
objectToWorldMatrix.translate(xoffset / xscale, zoffset / (zscale*stretch), yoffset / yscale);
// 5) Applying model rotations.
objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0);
objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1);
objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0);
objectToWorldMatrix.rotate(-angleoffset, 0, 1, 0);
objectToWorldMatrix.rotate(pitchoffset, 0, 0, 1);
objectToWorldMatrix.rotate(-rolloffset, 1, 0, 0);
if (!(smf_flags & MDL_CORRECTPIXELSTRETCH) && smf->modelIDs.Size() > 0)
if (!(flags & MDL_CORRECTPIXELSTRETCH) && modelIDs.Size() > 0)
{
stretch = (smf->modelIDs[0] >= 0 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch;
stretch = (modelIDs[0] >= 0 ? Models[modelIDs[0]]->getAspectFactor(Level->info->pixelstretch) : 1.f) / Level->info->pixelstretch;
objectToWorldMatrix.scale(1, stretch, 1);
}
float orientation = scaleFactorX * scaleFactorY * scaleFactorZ;
renderer->BeginDrawModel(actor->RenderStyle, smf_flags, objectToWorldMatrix, orientation < 0);
RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, translation, actor);
renderer->EndDrawModel(actor->RenderStyle, smf_flags);
return objectToWorldMatrix;
}
void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf)
void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf, double ticFrac)
{
AActor * playermo = players[consoleplayer].camera;
@ -272,7 +309,7 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio
auto trans = psp->GetTranslation();
if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation;
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), trans, psp->Caller);
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), ticFrac, trans, psp->Caller);
renderer->EndDrawHUDModel(playermo->RenderStyle, smf_flags);
}
@ -329,7 +366,7 @@ void calcFrames(const ModelAnim &curAnim, double tic, ModelAnimFrameInterp &to,
}
}
CalcModelFrameInfo CalcModelFrame(FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, DActorModelData* data, AActor* actor, bool is_decoupled, double tic)
CalcModelFrameInfo CalcModelFrame(FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, DActorModelData* data, AActor* actor, bool is_decoupled, double tic, double ticFrac)
{
// [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation
// and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame.
@ -364,8 +401,9 @@ CalcModelFrameInfo CalcModelFrame(FLevelLocals *Level, const FSpriteModelFrame *
// [BB] In case the tic counter is frozen we have to leave ticFraction at zero.
if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !Level->isFrozen())
{
ticFraction = I_GetTimeFrac();
ticFraction = ticFrac;
}
inter = static_cast<double>(curState->Tics - curTics + ticFraction) / static_cast<double>(curState->Tics);
// [BB] For some actors (e.g. ZPoisonShroom) spr->actor->tics can be bigger than curState->Tics.
@ -429,11 +467,11 @@ bool CalcModelOverrides(int i, const FSpriteModelFrame *smf, DActorModelData* da
if (data)
{
//modelID
if (data->models.Size() > i && data->models[i].modelID >= 0)
if (data->models.SSize() > i && data->models[i].modelID >= 0)
{
out.modelid = data->models[i].modelID;
}
else if(data->models.Size() > i && data->models[i].modelID == -2)
else if(data->models.SSize() > i && data->models[i].modelID == -2)
{
return false;
}
@ -443,7 +481,7 @@ bool CalcModelOverrides(int i, const FSpriteModelFrame *smf, DActorModelData* da
}
//animationID
if (data->animationIDs.Size() > i && data->animationIDs[i] >= 0)
if (data->animationIDs.SSize() > i && data->animationIDs[i] >= 0)
{
out.animationid = data->animationIDs[i];
}
@ -454,7 +492,7 @@ bool CalcModelOverrides(int i, const FSpriteModelFrame *smf, DActorModelData* da
if(!is_decoupled)
{
//modelFrame
if (data->modelFrameGenerators.Size() > i
if (data->modelFrameGenerators.SSize() > i
&& (unsigned)data->modelFrameGenerators[i] < info.modelsamount
&& smf->modelframes[data->modelFrameGenerators[i]] >= 0
) {
@ -480,7 +518,7 @@ bool CalcModelOverrides(int i, const FSpriteModelFrame *smf, DActorModelData* da
}
//skinID
if (data->skinIDs.Size() > i && data->skinIDs[i].isValid())
if (data->skinIDs.SSize() > i && data->skinIDs[i].isValid())
{
out.skinid = data->skinIDs[i];
}
@ -490,7 +528,7 @@ bool CalcModelOverrides(int i, const FSpriteModelFrame *smf, DActorModelData* da
}
//surfaceSkinIDs
if(data->models.Size() > i && data->models[i].surfaceSkinIDs.Size() > 0)
if(data->models.SSize() > i && data->models[i].surfaceSkinIDs.SSize() > 0)
{
unsigned sz1 = smf->surfaceskinIDs.Size();
unsigned sz2 = data->models[i].surfaceSkinIDs.Size();
@ -550,7 +588,7 @@ const TArray<VSMatrix> * ProcessModelFrame(FModel * animation, bool nextFrame, i
frameinfo.decoupled_frame,
frameinfo.inter,
animationData,
modelData->modelBoneOverrides.Size() > i
modelData->modelBoneOverrides.SSize() > i
? &modelData->modelBoneOverrides[i]
: nullptr,
out,
@ -568,7 +606,7 @@ const TArray<VSMatrix> * ProcessModelFrame(FModel * animation, bool nextFrame, i
},
-1.0f,
animationData,
(modelData && modelData->modelBoneOverrides.Size() > i)
(modelData && modelData->modelBoneOverrides.SSize() > i)
? &modelData->modelBoneOverrides[i]
: nullptr,
out,
@ -586,7 +624,7 @@ static inline void RenderModelFrame(FModelRenderer *renderer, int i, const FSpri
auto ssidp = drawinfo.surfaceskinids.Size() > 0
? drawinfo.surfaceskinids.Data()
: (((i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.Size()) ? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr);
: (((i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.SSize()) ? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr);
bool nextFrame = frameinfo.smfNext && drawinfo.modelframe != drawinfo.modelframenext;
@ -605,19 +643,19 @@ static inline void RenderModelFrame(FModelRenderer *renderer, int i, const FSpri
mdl->RenderFrame(renderer, tex, drawinfo.modelframe, nextFrame ? drawinfo.modelframenext : drawinfo.modelframe, nextFrame ? frameinfo.inter : -1.f, translation, ssidp, boneStartingPosition, actor);
}
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor)
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, int curTics, double ticFrac, FTranslationID translation, AActor* actor)
{
double tic = actor->Level->totaltime;
if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !actor->isFrozen())
{
tic += I_GetTimeFrac();
tic += ticFrac;
}
bool is_decoupled = (actor->flags9 & MF9_DECOUPLEDANIMATIONS);
DActorModelData* modelData = actor ? actor->modelData.ForceGet() : nullptr;
CalcModelFrameInfo frameinfo = CalcModelFrame(Level, smf, curState, curTics, modelData, actor, is_decoupled, tic);
CalcModelFrameInfo frameinfo = CalcModelFrame(Level, smf, curState, curTics, modelData, actor, is_decoupled, tic, ticFrac);
ModelDrawInfo drawinfo;
int boneStartingPosition = -1;

View file

@ -115,7 +115,7 @@ void BSPWalkCircle(FLevelLocals *Level, float x, float y, float radiusSquared, c
}
void RenderModel(FModelRenderer* renderer, float x, float y, float z, FSpriteModelFrame* smf, AActor* actor, double ticFrac);
void RenderHUDModel(FModelRenderer* renderer, DPSprite* psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf);
void RenderHUDModel(FModelRenderer* renderer, DPSprite* psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf, double ticFrac);
struct CalcModelFrameInfo
{
@ -140,7 +140,7 @@ struct ModelDrawInfo
class DActorModelData;
CalcModelFrameInfo CalcModelFrame(FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, DActorModelData* modelData, AActor* actor, bool is_decoupled, double tic);
CalcModelFrameInfo CalcModelFrame(FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, int curTics, DActorModelData* modelData, AActor* actor, bool is_decoupled, double tic, double ticFrac);
// returns true if the model isn't removed
bool CalcModelOverrides(int modelindex, const FSpriteModelFrame *smf, DActorModelData* modelData, const CalcModelFrameInfo &frameinfo, ModelDrawInfo &drawinfo, bool is_decoupled);

View file

@ -93,7 +93,7 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state)
state.AlphaFunc(Alpha_GEqual, 0);
FHWModelRenderer renderer(this, state, huds->lightindex);
RenderHUDModel(&renderer, huds->weapon, huds->translation, huds->rotation + FVector3(huds->mx / 4., (huds->my - WEAPONTOP) / -4., 0), huds->pivot, huds->mframe);
RenderHUDModel(&renderer, huds->weapon, huds->translation, huds->rotation + FVector3(huds->mx / 4., (huds->my - WEAPONTOP) / -4., 0), huds->pivot, huds->mframe, Viewpoint.TicFrac);
state.SetFlatVertexBuffer();
state.SetShadeVertex(false);
}

View file

@ -68,7 +68,7 @@
#include "i_interface.h"
#include "d_main.h"
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
const float MY_SQRT2 = float(1.41421356237309504880); // sqrt(2)
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern bool DrawFSHUD; // [RH] Defined in d_main.cpp

View file

@ -339,7 +339,7 @@ TArray<FString> I_GetSteamPath()
}
}
}
catch (const CRecoverableError& err)
catch (const CRecoverableError&)
{
// don't abort on errors in here. Just return an empty path.
}

View file

@ -416,7 +416,7 @@ static int actioncmp(void *_ap1,void *_ap2)
rc = ap1->x.rp->index - ap2->x.rp->index;
}
if( rc==0 ){
rc = ap2 - ap1;
rc = (int)(ap2 - ap1);
}
return rc;
}
@ -1957,7 +1957,7 @@ static int handleswitch(int i, FILE *err)
if( err ){
fprintf(err,
"%sillegal character in floating-point argument.\n",emsg);
errline(i,((size_t)end)-(size_t)argv[i],err);
errline(i,(int)(((size_t)end)-(size_t)argv[i]),err);
}
errcnt++;
}
@ -1968,7 +1968,7 @@ static int handleswitch(int i, FILE *err)
if( *end ){
if( err ){
fprintf(err,"%sillegal character in integer argument.\n",emsg);
errline(i,((size_t)end)-(size_t)argv[i],err);
errline(i,(int)(((size_t)end)-(size_t)argv[i]),err);
}
errcnt++;
}

View file

@ -1408,17 +1408,67 @@ class Actor : Thinker native
native version("4.15.1") void GetBoneChildren(int boneIndex, out Array<int> children);
native version("4.15.1") void GetNamedBoneChildren(Name boneName, out Array<int> children);
// this is the length in model units, not in world units, and does not take model scale in MODELDEF, world, etc, or current animation or offset into account at all
native version("4.15.1") double GetBoneLength(int boneIndex);
native version("4.15.1") double GetNamedBoneLength(Name boneName);
// this is the direction of the bone in the armature, does not take the current animation or offset into account at all
native version("4.15.1") Vector3 GetBoneDir(int boneIndex);
native version("4.15.1") Vector3 GetNamedBoneDir(Name boneName);
/* rotation, translation, scaling */
native version("4.15.1") Quat, Vector3, Vector3 GetBoneBaseTRS(int boneIndex);
native version("4.15.1") Quat, Vector3, Vector3 GetNamedBoneBaseTRS(Name boneName);
native version("4.15.1") Vector3 GetBoneBasePosition(int boneIndex);
native version("4.15.1") Vector3 GetNamedBoneBasePosition(Name boneName);
native version("4.15.1") Quat GetBoneBaseRotation(int boneIndex);
native version("4.15.1") Quat GetNamedBoneBaseRotation(Name boneName);
native version("4.15.1") int GetBoneCount();
//================================================
//
// Bone Pose Getters
//
//================================================
native version("4.15.1") int GetAnimStartFrame(Name animName);
native version("4.15.1") int GetAnimEndFrame(Name animName);
native version("4.15.1") double GetAnimFramerate(Name animName);
/* rotation, translation, scaling */
native version("4.15.1") Quat, Vector3, Vector3 GetBoneFramePose(int boneIndex, int frame);
native version("4.15.1") Quat, Vector3, Vector3 GetNamedBoneFramePose(Name boneName, int frame);
//================================================
//
// Bone TRS Getters
//
//================================================
/* rotation, translation, scaling */
native version("4.15.1") Quat, Vector3, Vector3 GetBone(int boneIndex, bool include_offsets = true);
native version("4.15.1") Quat, Vector3, Vector3 GetNamedBone(Name boneName, bool include_offsets = true);
native version("4.15.1") Vector3, Vector3 TransformByBone(int boneIndex, Vector3 position, Vector3 direction = (0,0,0), bool include_offsets = true);
native version("4.15.1") Vector3, Vector3 TransformByNamedBone(Name boneName, Vector3 position, Vector3 direction = (0,0,0), bool include_offsets = true);
version("4.15.1") Vector3 GetBonePosition(int boneIndex, bool include_offsets = true)
{
return TransformByBone(boneIndex, GetBoneBasePosition(boneIndex), include_offsets:include_offsets);
}
version("4.15.1") Vector3 GetNamedBonePosition(name boneName, bool include_offsets = true)
{
return GetBonePosition(GetBoneIndex(boneName), include_offsets);
}
//================================================
//
// Bone Matrix Getters
//
//================================================
//outMatrix will be a 16-length array containing the raw matrix data
native version("4.15.1") void GetBoneMatrixRaw(int boneIndex, out Array<double> outMatrix, bool include_offsets = true);
native version("4.15.1") void GetNamedBoneMatrixRaw(Name boneName, out Array<double> outMatrix, bool include_offsets = true);
native version("4.15.1") void GetObjectToWorldMatrixRaw(out Array<double> outMatrix);
//================================================
//
@ -1426,16 +1476,15 @@ class Actor : Thinker native
//
//================================================
native version("4.12") void SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") ui void SetAnimationUI(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") void SetAnimationFrameRate(double framerate);
native version("4.12") ui void SetAnimationFrameRateUI(double framerate);
native version("4.12") void SetModelFlag(int flag);
native version("4.12") void ClearModelFlag(int flag);
native version("4.12") void ResetModelFlags();
native version("4.12") void SetModelFlag(int flag, int iqmFlags = 0);
native version("4.12") void ClearModelFlag(int flag, int iqmFlags = 0);
native version("4.12") void ResetModelFlags(bool resetModel = true, bool resetIqm = false);
action version("4.12") void A_SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0)

View file

@ -1554,3 +1554,10 @@ enum ESetBoneMode
SB_ADD = 1,
SB_REPLACE = 2,
};
enum EIQMFlags
{
IQM_GET_BONE_INFO = 1 << 2,
IQM_GET_BONE_INFO_RECALC = 1 << 3, // RECALCULATE BONE INFO INSTANTLY WHEN STATE/ANIMATION CHANGES, MIGHT GET EXPENSIVE
};