From f03b4eec4c37eab75a5bd639279cfcc615105b01 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 23 Apr 2020 22:25:18 +0200 Subject: implemented skinned peds, no cutscene hands yet --- librw | 2 +- premake5.lua | 2 +- src/animation/AnimBlendClumpData.h | 4 +- src/animation/Bones.cpp | 52 +++++ src/animation/Bones.h | 24 +++ src/animation/FrameUpdate.cpp | 243 ++++++++++++++++++--- src/animation/RpAnimBlend.cpp | 114 ++++++++-- src/animation/RpAnimBlend.h | 5 +- src/control/Script.cpp | 8 +- src/core/AnimViewer.cpp | 7 +- src/core/Cam.cpp | 13 +- src/core/Debug.cpp | 37 +++- src/core/Debug.h | 11 + src/core/World.cpp | 5 + src/core/common.h | 11 + src/core/config.h | 1 + src/core/main.cpp | 1 + src/entities/Entity.cpp | 70 +++++- src/entities/Entity.h | 4 + src/fakerw/fake.cpp | 46 +++- src/fakerw/rphanim.h | 36 ++++ src/fakerw/rpskin.h | 18 ++ src/fakerw/rtcharse.h | 14 ++ src/fakerw/rtquat.h | 10 + src/math/Quaternion.h | 12 ++ src/modelinfo/ClumpModelInfo.cpp | 72 ++++++- src/modelinfo/PedModelInfo.cpp | 164 +++++++++++++- src/modelinfo/PedModelInfo.h | 17 +- src/objects/CutsceneHead.cpp | 95 +++++++- src/objects/CutsceneHead.h | 9 + src/objects/CutsceneObject.cpp | 65 +++++- src/objects/CutsceneObject.h | 16 ++ src/peds/CivilianPed.h | 2 + src/peds/CopPed.cpp | 3 +- src/peds/CopPed.h | 2 + src/peds/EmergencyPed.h | 2 + src/peds/Ped.cpp | 242 +++++++++++++++------ src/peds/Ped.h | 57 ++++- src/peds/PedIK.cpp | 431 ++++++++++++++++++++++++++----------- src/peds/PedIK.h | 2 + src/peds/PlayerPed.cpp | 6 + src/peds/PlayerPed.h | 2 + src/render/SpecialFX.cpp | 10 +- src/rw/RwHelper.cpp | 179 ++++++++++++++- src/rw/RwHelper.h | 9 + src/rw/VisibilityPlugins.cpp | 15 ++ src/rw/VisibilityPlugins.h | 3 + src/skel/win/win.cpp | 8 + src/weapons/Weapon.cpp | 3 +- 49 files changed, 1866 insertions(+), 298 deletions(-) create mode 100644 src/animation/Bones.cpp create mode 100644 src/animation/Bones.h create mode 100644 src/fakerw/rtcharse.h create mode 100644 src/fakerw/rtquat.h diff --git a/librw b/librw index 752fceb1..374f951d 160000 --- a/librw +++ b/librw @@ -1 +1 @@ -Subproject commit 752fceb1e3c4ce06b6f20b9c4471927821469bf2 +Subproject commit 374f951d7cee353914059d8ddf9c5aff7d764984 diff --git a/premake5.lua b/premake5.lua index 6037b01c..14aab9d8 100644 --- a/premake5.lua +++ b/premake5.lua @@ -62,7 +62,7 @@ workspace "re3" filter "configurations:DebugRW or ReleaseRW" includedirs { "rwsdk/include/d3d8" } libdirs { "rwsdk/lib/d3d8/release" } - links { "rwcore", "rpworld", "rpmatfx", "rpskin", "rphanim", "rtbmp" } + links { "rwcore", "rpworld", "rpmatfx", "rpskin", "rphanim", "rtbmp", "rtquat", "rtcharse" } filter {} diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h index 1c8c391d..a537425a 100644 --- a/src/animation/AnimBlendClumpData.h +++ b/src/animation/AnimBlendClumpData.h @@ -18,7 +18,7 @@ struct AnimBlendFrameData #ifdef PED_SKIN union { RwFrame *frame; - RpHAnimStdKeyFrame *hanimframe; + RpHAnimStdKeyFrame *hanimFrame; }; int32 nodeID; #else @@ -50,4 +50,6 @@ public: #endif void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg); }; +#ifndef PED_SKIN static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error"); +#endif diff --git a/src/animation/Bones.cpp b/src/animation/Bones.cpp new file mode 100644 index 00000000..1608449d --- /dev/null +++ b/src/animation/Bones.cpp @@ -0,0 +1,52 @@ +#include "common.h" +#include "PedModelInfo.h" +#include "Bones.h" + +#ifdef PED_SKIN + +int +ConvertPedNode2BoneTag(int node) +{ + switch(node){ + case PED_TORSO: return BONE_waist; + case PED_MID: return BONE_torso; // this is what Xbox/Mobile use + // return BONE_mid; // this is what PS2/PC use + case PED_HEAD: return BONE_head; + case PED_UPPERARML: return BONE_upperarml; + case PED_UPPERARMR: return BONE_upperarmr; + case PED_HANDL: return BONE_Lhand; + case PED_HANDR: return BONE_Rhand; + case PED_UPPERLEGL: return BONE_upperlegl; + case PED_UPPERLEGR: return BONE_upperlegr; + case PED_FOOTL: return BONE_footl; + case PED_FOOTR: return BONE_footr; + case PED_LOWERLEGR: return BONE_lowerlegl; + } + return -1; +} + +const char* +ConvertBoneTag2BoneName(int tag) +{ + switch(tag){ + case BONE_waist: return "Swaist"; + case BONE_upperlegr: return "Supperlegr"; + case BONE_lowerlegr: return "Slowerlegr"; + case BONE_footr: return "Sfootr"; + case BONE_upperlegl: return "Supperlegl"; + case BONE_lowerlegl: return "Slowerlegl"; + case BONE_footl: return "Sfootl"; + case BONE_mid: return "Smid"; + case BONE_torso: return "Storso"; + case BONE_head: return "Shead"; + case BONE_upperarmr: return "Supperarmr"; + case BONE_lowerarmr: return "Slowerarmr"; + case BONE_Rhand: return "SRhand"; + case BONE_upperarml: return "Supperarml"; + case BONE_lowerarml: return "Slowerarml"; + case BONE_Lhand: return "SLhand"; + } + return nil; +} + +#endif diff --git a/src/animation/Bones.h b/src/animation/Bones.h new file mode 100644 index 00000000..38d91ba3 --- /dev/null +++ b/src/animation/Bones.h @@ -0,0 +1,24 @@ +#pragma once + +enum BoneTag +{ + BONE_waist, + BONE_upperlegr, + BONE_lowerlegr, + BONE_footr, + BONE_upperlegl, + BONE_lowerlegl, + BONE_footl, + BONE_mid, + BONE_torso, + BONE_head, + BONE_upperarmr, + BONE_lowerarmr, + BONE_Rhand, + BONE_upperarml, + BONE_lowerarml, + BONE_Lhand, +}; + +int ConvertPedNode2BoneTag(int node); +const char *ConvertBoneTag2BoneName(int tag); diff --git a/src/animation/FrameUpdate.cpp b/src/animation/FrameUpdate.cpp index df45bfb5..a38ebc74 100644 --- a/src/animation/FrameUpdate.cpp +++ b/src/animation/FrameUpdate.cpp @@ -8,12 +8,18 @@ CAnimBlendClumpData *gpAnimBlendClump; -void FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg); -void FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg); -void FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg); +// PS2 names without "NonSkinned" +void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg); + +void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg); + void -FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) +FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg) { CVector vec, pos(0.0f, 0.0f, 0.0f); CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); @@ -25,9 +31,9 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && gpAnimBlendClump->velocity){ if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D) - FrameUpdateCallBackWith3dVelocityExtraction(frame, arg); + FrameUpdateCallBackNonSkinnedWith3dVelocityExtraction(frame, arg); else - FrameUpdateCallBackWithVelocityExtraction(frame, arg); + FrameUpdateCallBackNonSkinnedWithVelocityExtraction(frame, arg); return; } @@ -48,12 +54,7 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ RwMatrixSetIdentity(mat); - - float norm = rot.MagnitudeSqr(); - if(norm == 0.0f) - rot.w = 1.0f; - else - rot *= 1.0f/Sqrt(norm); + rot.Normalise(); rot.Get(mat); } @@ -69,7 +70,7 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) } void -FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) +FrameUpdateCallBackNonSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) { CVector vec, pos(0.0f, 0.0f, 0.0f); CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); @@ -122,12 +123,7 @@ FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ RwMatrixSetIdentity(mat); - - float norm = rot.MagnitudeSqr(); - if(norm == 0.0f) - rot.w = 1.0f; - else - rot *= 1.0f/Sqrt(norm); + rot.Normalise(); rot.Get(mat); } @@ -154,7 +150,7 @@ FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) // original code uses do loops? void -FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg) +FrameUpdateCallBackNonSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg) { CVector vec, pos(0.0f, 0.0f, 0.0f); CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); @@ -201,12 +197,7 @@ FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ RwMatrixSetIdentity(mat); - - float norm = rot.MagnitudeSqr(); - if(norm == 0.0f) - rot.w = 1.0f; - else - rot *= 1.0f/Sqrt(norm); + rot.Normalise(); rot.Get(mat); } @@ -220,3 +211,203 @@ FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg } RwMatrixUpdate(mat); } + +#ifdef PED_SKIN + +void +FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + RpHAnimStdKeyFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && + gpAnimBlendClump->velocity){ + if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D) + FrameUpdateCallBackSkinnedWith3dVelocityExtraction(frame, arg); + else + FrameUpdateCallBackSkinnedWithVelocityExtraction(frame, arg); + return; + } + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + (*node)->Update(vec, q, 1.0f-totalBlendAmount); + if((*node)->sequence->HasTranslation()) + pos += vec; + rot += q; + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + xform->t.x = pos.x; + xform->t.y = pos.y; + xform->t.z = pos.z; + xform->t.x += frame->resetPos.x; + xform->t.y += frame->resetPos.y; + xform->t.z += frame->resetPos.z; + } +} + +void +FrameUpdateCallBackSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + float transx = 0.0f, transy = 0.0f; + float curx = 0.0f, cury = 0.0f; + float endx = 0.0f, endy = 0.0f; + bool looped = false; + RpHAnimStdKeyFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->sequence->HasTranslation()){ + if((*node)->association->HasTranslation()){ + (*node)->GetCurrentTranslation(vec, 1.0f-totalBlendAmount); + cury += vec.y; + if((*node)->association->HasXTranslation()) + curx += vec.x; + } + } + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + bool nodelooped = (*node)->Update(vec, q, 1.0f-totalBlendAmount); + rot += q; + if((*node)->sequence->HasTranslation()){ + pos += vec; + if((*node)->association->HasTranslation()){ + transy += vec.y; + if((*node)->association->HasXTranslation()) + transx += vec.x; + looped |= nodelooped; + if(nodelooped){ + (*node)->GetEndTranslation(vec, 1.0f-totalBlendAmount); + endy += vec.y; + if((*node)->association->HasXTranslation()) + endx += vec.x; + } + } + } + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + gpAnimBlendClump->velocity->x = transx - curx; + gpAnimBlendClump->velocity->y = transy - cury; + if(looped){ + gpAnimBlendClump->velocity->x += endx; + gpAnimBlendClump->velocity->y += endy; + } + xform->t.x = pos.x - transx; + xform->t.y = pos.y - transy; + xform->t.z = pos.z; + if(xform->t.z >= -0.8f) + if(xform->t.z < -0.4f) + xform->t.z += (2.5f * xform->t.z + 2.0f) * frame->resetPos.z; + else + xform->t.z += frame->resetPos.z; + xform->t.x += frame->resetPos.x; + xform->t.y += frame->resetPos.y; + } +} + +void +FrameUpdateCallBackSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + CVector trans(0.0f, 0.0f, 0.0f); + CVector cur(0.0f, 0.0f, 0.0f); + CVector end(0.0f, 0.0f, 0.0f); + bool looped = false; + RpHAnimStdKeyFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->sequence->HasTranslation()){ + if((*node)->association->HasTranslation()){ + (*node)->GetCurrentTranslation(vec, 1.0f-totalBlendAmount); + cur += vec; + } + } + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + bool nodelooped = (*node)->Update(vec, q, 1.0f-totalBlendAmount); + rot += q; + if((*node)->sequence->HasTranslation()){ + pos += vec; + if((*node)->association->HasTranslation()){ + trans += vec; + looped |= nodelooped; + if(nodelooped){ + (*node)->GetEndTranslation(vec, 1.0f-totalBlendAmount); + end += vec; + } + } + } + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + *gpAnimBlendClump->velocity = trans - cur; + if(looped) + *gpAnimBlendClump->velocity += end; + xform->t.x = (pos - trans).x + frame->resetPos.x; + xform->t.y = (pos - trans).y + frame->resetPos.y; + xform->t.z = (pos - trans).z + frame->resetPos.z; + } +} + +#endif diff --git a/src/animation/RpAnimBlend.cpp b/src/animation/RpAnimBlend.cpp index 20290666..d3e10889 100644 --- a/src/animation/RpAnimBlend.cpp +++ b/src/animation/RpAnimBlend.cpp @@ -1,12 +1,17 @@ #include "common.h" +#include "RwHelper.h" #include "General.h" #include "NodeName.h" #include "VisibilityPlugins.h" +#include "Bones.h" #include "AnimBlendClumpData.h" #include "AnimBlendHierarchy.h" #include "AnimBlendAssociation.h" #include "RpAnimBlend.h" +#ifdef PED_SKIN +#include "PedModelInfo.h" +#endif RwInt32 ClumpOffset; @@ -122,19 +127,59 @@ FrameForAllChildrenFillFrameArrayCallBack(RwFrame *frame, void *data) return frame; } +// FrameInitCallBack on PS2 void -FrameInitCallBack(AnimBlendFrameData *frameData, void*) +FrameInitCBnonskin(AnimBlendFrameData *frameData, void*) { frameData->flag = 0; frameData->resetPos = *RwMatrixGetPos(RwFrameGetMatrix(frameData->frame)); } void -RpAnimBlendClumpInit(RpClump *clump) +FrameInitCBskin(AnimBlendFrameData *frameData, void*) { + frameData->flag = 0; +} + #ifdef PED_SKIN - TODO -#else +void +RpAnimBlendClumpInitSkinned(RpClump *clump) +{ + int i; + RwV3d boneTab[64]; + CAnimBlendClumpData *clumpData; + RpAtomic *atomic; + RpSkin *skin; + RpHAnimHierarchy *hier; + int numBones; + + RpAnimBlendAllocateData(clump); + clumpData = *RPANIMBLENDCLUMPDATA(clump); + atomic = IsClumpSkinned(clump); + assert(atomic); + skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)); + assert(skin); + numBones = RpSkinGetNumBones(skin); + clumpData->SetNumberOfBones(numBones); + hier = GetAnimHierarchyFromSkinClump(clump); + assert(hier); + memset(boneTab, 0, sizeof(boneTab)); + SkinGetBonePositionsToTable(clump, boneTab); + + AnimBlendFrameData *frames = clumpData->frames; + for(i = 0; i < numBones; i++){ + frames[i].nodeID = HIERNODEID(hier, i); + frames[i].resetPos = boneTab[i]; + frames[i].hanimFrame = (RpHAnimStdKeyFrame*)rpHANIMHIERARCHYGETINTERPFRAME(hier, i); + } + clumpData->ForAllFrames(FrameInitCBskin, nil); + clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION; +} +#endif + +void +RpAnimBlendClumpInitNotSkinned(RpClump *clump) +{ int numFrames = 0; CAnimBlendClumpData *clumpData; RwFrame *root; @@ -147,9 +192,19 @@ RpAnimBlendClumpInit(RpClump *clump) clumpData->SetNumberOfFrames(numFrames); frames = clumpData->frames; RwFrameForAllChildren(root, FrameForAllChildrenFillFrameArrayCallBack, &frames); - clumpData->ForAllFrames(FrameInitCallBack, nil); + clumpData->ForAllFrames(FrameInitCBnonskin, nil); clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION; +} + +void +RpAnimBlendClumpInit(RpClump *clump) +{ +#ifdef PED_SKIN + if(IsClumpSkinned(clump)) + RpAnimBlendClumpInitSkinned(clump); + else #endif + RpAnimBlendClumpInitNotSkinned(clump); } bool @@ -298,42 +353,68 @@ RpAnimBlendClumpGetFirstAssociation(RpClump *clump) return CAnimBlendAssociation::FromLink(clumpData->link.next); } +// FillFrameArrayCallBack on PS2 void -FillFrameArrayCallBack(AnimBlendFrameData *frame, void *arg) +FillFrameArrayCBnonskin(AnimBlendFrameData *frame, void *arg) { AnimBlendFrameData **frames = (AnimBlendFrameData**)arg; frames[CVisibilityPlugins::GetFrameHierarchyId(frame->frame)] = frame; } +#ifdef PED_SKIN +void +RpAnimBlendClumpFillFrameArraySkin(RpClump *clump, AnimBlendFrameData **frames) +{ + int i; + CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump); + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump); + for(i = PED_MID; i < PED_NODE_MAX; i++) + frames[i] = &clumpData->frames[RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(i))]; +} +#endif + void RpAnimBlendClumpFillFrameArray(RpClump *clump, AnimBlendFrameData **frames) { #ifdef PED_SKIN - TODO -#else - (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FillFrameArrayCallBack, frames); + if(IsClumpSkinned(clump)) + RpAnimBlendClumpFillFrameArraySkin(clump, frames); + else #endif + (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FillFrameArrayCBnonskin, frames); } AnimBlendFrameData *pFrameDataFound; +// FrameFindCallBack on PS2 void -FrameFindCallBack(AnimBlendFrameData *frame, void *arg) +FrameFindByNameCBnonskin(AnimBlendFrameData *frame, void *arg) { char *nodename = GetFrameNodeName(frame->frame); if(!CGeneral::faststricmp(nodename, (char*)arg)) pFrameDataFound = frame; } +#ifdef PED_SKIN +void +FrameFindByNameCBskin(AnimBlendFrameData *frame, void *arg) +{ + const char *name = ConvertBoneTag2BoneName(frame->nodeID); + if(name && CGeneral::faststricmp(name, (char*)arg) == 0) + pFrameDataFound = frame; +} +#endif + AnimBlendFrameData* RpAnimBlendClumpFindFrame(RpClump *clump, const char *name) { pFrameDataFound = nil; #ifdef PED_SKIN - TODO -#else - (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindCallBack, (void*)name); + if(IsClumpSkinned(clump)) + (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBskin, (void*)name); + else #endif + (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBnonskin, (void*)name); return pFrameDataFound; } @@ -369,7 +450,12 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta) } updateData.nodes[i] = nil; - clumpData->ForAllFrames(FrameUpdateCallBack, &updateData); +#ifdef PED_SKIN + if(IsClumpSkinned(clump)) + clumpData->ForAllFrames(FrameUpdateCallBackSkinned, &updateData); + else +#endif + clumpData->ForAllFrames(FrameUpdateCallBackNonSkinned, &updateData); for(link = clumpData->link.next; link; link = link->next){ CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link); diff --git a/src/animation/RpAnimBlend.h b/src/animation/RpAnimBlend.h index ccfa5872..838c8816 100644 --- a/src/animation/RpAnimBlend.h +++ b/src/animation/RpAnimBlend.h @@ -7,7 +7,7 @@ struct AnimBlendFrameData; struct AnimBlendFrameUpdateData { - int foobar; + int foobar; // TODO: figure out what this actually means CAnimBlendNode *nodes[16]; }; @@ -38,4 +38,5 @@ void RpAnimBlendClumpUpdateAnimations(RpClump* clump, float timeDelta); extern CAnimBlendClumpData *gpAnimBlendClump; -void FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 073cb661..7ab40847 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -6435,9 +6435,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) pPed->FlagToDestroyWhenNextProcessed(); } else if (CGame::nastyGame && pPed->IsPedInControl()) { - RwMatrix tmp_rw; - CPedIK::GetWorldMatrix(pPed->m_pFrames[PED_HEAD]->frame, &tmp_rw); - pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, tmp_rw.pos, true); + pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, pPed->GetNodePosition(PED_HEAD), true); } else { pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); @@ -6450,9 +6448,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; assert(pPed); if (CGame::nastyGame) { - RwMatrix tmp_rw; - CPedIK::GetWorldMatrix(pPed->m_pFrames[PED_HEAD]->frame, &tmp_rw); - pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, tmp_rw.pos, true); + pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, pPed->GetNodePosition(PED_HEAD), true); } else { pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); diff --git a/src/core/AnimViewer.cpp b/src/core/AnimViewer.cpp index 20e94bf4..cf3ec5bf 100644 --- a/src/core/AnimViewer.cpp +++ b/src/core/AnimViewer.cpp @@ -367,7 +367,12 @@ CAnimViewer::Update(void) } else { // Originally it was GetPad(1)->LeftShoulder2 if (pad->NewState.Triangle) { - CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(pTarget->m_modelIndex))->GetHitColModel(), RpClumpGetFrame(pTarget->GetClump())); +#ifdef PED_SKIN + if(IsClumpSkinned(pTarget->GetClump())) + ((CPedModelInfo*)CModelInfo::GetModelInfo(pTarget->m_modelIndex))->AnimatePedColModelSkinned(pTarget->GetClump()); + else +#endif + CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(pTarget->m_modelIndex))->GetHitColModel(), RpClumpGetFrame(pTarget->GetClump())); AsciiToUnicode("Ped Col model will be animated as long as you hold the button", gUString); CMessages::AddMessage(gUString, 100, 0); } diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index f0a60093..5cf1c8f3 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -2776,17 +2776,20 @@ CCam::Process_1rstPersonPedOnPC(const CVector&, float TargetOrientation, float, if(CamTargetEntity->IsPed()){ // static bool FailedTestTwelveFramesAgo = false; // unused - RwV3d HeadPos = vecHeadCamOffset; + CVector HeadPos = vecHeadCamOffset; CVector TargetCoors; - // needs fix for SKINNING - RwFrame *frm = ((CPed*)CamTargetEntity)->GetNodeFrame(PED_HEAD); + ((CPed*)CamTargetEntity)->TransformToNode(HeadPos, PED_HEAD); + // This is done on PC, but checking for the clump frame is not necessary apparently +/* + RwFrame *frm = ((CPed*)CamTargetEntity)->m_pFrames[PED_HEAD]->frame; while(frm){ RwV3dTransformPoints(&HeadPos, &HeadPos, 1, RwFrameGetMatrix(frm)); frm = RwFrameGetParent(frm); if(frm == RpClumpGetFrame(CamTargetEntity->GetClump())) frm = nil; } +*/ if(ResetStatics){ Beta = TargetOrientation; @@ -2813,13 +2816,13 @@ CCam::Process_1rstPersonPedOnPC(const CVector&, float TargetOrientation, float, m_vecBufferedPlayerBodyOffset.z = TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.z + (1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.z; - HeadPos = (CamTargetEntity->GetMatrix() * m_vecBufferedPlayerBodyOffset).toRwV3d(); + HeadPos = (CamTargetEntity->GetMatrix() * m_vecBufferedPlayerBodyOffset); }else{ float HeadDelta = (HeadPos - InitialHeadPos).Magnitude2D(); CVector Fwd = CamTargetEntity->GetForward(); Fwd.z = 0.0f; Fwd.Normalise(); - HeadPos = (HeadDelta*1.23f*Fwd + CamTargetEntity->GetPosition()).toRwV3d(); + HeadPos = (HeadDelta*1.23f*Fwd + CamTargetEntity->GetPosition()); HeadPos.z += 0.59f; } Source = HeadPos; diff --git a/src/core/Debug.cpp b/src/core/Debug.cpp index 917c99ab..e794dcaf 100644 --- a/src/core/Debug.cpp +++ b/src/core/Debug.cpp @@ -1,5 +1,7 @@ #include "common.h" +#include "RwHelper.h" #include "Debug.h" +#include "Lines.h" #include "Font.h" #include "main.h" #include "Text.h" @@ -114,11 +116,14 @@ CDebug::DisplayScreenStrings() CFont::SetFontStyle(FONT_BANK); for(i = 0; i < ms_nScreenStrs; i++){ +/* AsciiToUnicode(ms_aScreenStrs[i].str, gUString); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::PrintString(ms_aScreenStrs[i].x, ms_aScreenStrs[i].y, gUString); CFont::SetColor(CRGBA(255, 255, 255, 255)); CFont::PrintString(ms_aScreenStrs[i].x+1, ms_aScreenStrs[i].y+1, gUString); +*/ + ObrsPrintfString(ms_aScreenStrs[i].str, ms_aScreenStrs[i].x, ms_aScreenStrs[i].y); } CFont::DrawFonts(); @@ -131,7 +136,35 @@ CDebug::PrintAt(const char *str, int x, int y) if(ms_nScreenStrs >= MAX_SCREEN_STRS) return; strncpy(ms_aScreenStrs[ms_nScreenStrs].str, str, 256); - ms_aScreenStrs[ms_nScreenStrs].x = x*12; - ms_aScreenStrs[ms_nScreenStrs].y = y*22; + ms_aScreenStrs[ms_nScreenStrs].x = x;//*12; + ms_aScreenStrs[ms_nScreenStrs].y = y;//*22; ms_nScreenStrs++; } + +CDebug::Line CDebug::ms_aLines[MAX_DEBUG_LINES]; +int CDebug::ms_nLines; + +void +CDebug::AddLine(CVector p1, CVector p2, uint32 c1, uint32 c2) +{ + if(ms_nLines >= MAX_DEBUG_LINES) + return; + ms_aLines[ms_nLines].p1 = p1; + ms_aLines[ms_nLines].p2 = p2; + ms_aLines[ms_nLines].c1 = c1; + ms_aLines[ms_nLines].c2 = c2; + ms_nLines++; +} + +void +CDebug::DrawLines(void) +{ + int i; + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + for(i = 0; i < ms_nLines; i++){ + Line *l = &ms_aLines[i]; + CLines::RenderLineWithClipping(l->p1.x, l->p1.y, l->p1.z, l->p2.x, l->p2.y, l->p2.z, l->c1, l->c2); + } + ms_nLines = 0; +} diff --git a/src/core/Debug.h b/src/core/Debug.h index d169a0b4..4a25bf41 100644 --- a/src/core/Debug.h +++ b/src/core/Debug.h @@ -8,6 +8,7 @@ class CDebug MAX_STR_LEN = 80, MAX_SCREEN_STRS = 100, + MAX_DEBUG_LINES = 100, }; static int16 ms_nCurrentTextLine; @@ -21,6 +22,13 @@ class CDebug static ScreenStr ms_aScreenStrs[MAX_SCREEN_STRS]; static int ms_nScreenStrs; + struct Line { + CVector p1, p2; + uint32 c1, c2; + }; + static Line ms_aLines[MAX_DEBUG_LINES]; + static int ms_nLines; + public: static void DebugInitTextBuffer(); static void DebugDisplayTextBuffer(); @@ -29,6 +37,9 @@ public: // custom static void PrintAt(const char *str, int x, int y); static void DisplayScreenStrings(); + + static void AddLine(CVector p1, CVector p2, uint32 c1, uint32 c2); + static void DrawLines(void); }; extern bool gbDebugStuffInRelease; diff --git a/src/core/World.cpp b/src/core/World.cpp index 404b92c0..b2a01b80 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -339,6 +339,11 @@ CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColP if(e->IsPed()) { if(e->bUsesCollision || deadPeds && ((CPed *)e)->m_nPedState == PED_DEAD) { +#ifdef PED_SKIN + if(IsClumpSkinned(e->GetClump())) + colmodel = ((CPedModelInfo *)CModelInfo::GetModelInfo(e->GetModelIndex()))->AnimatePedColModelSkinned(e->GetClump()); + else +#endif if(((CPed *)e)->UseGroundColModel()) colmodel = &CTempColModels::ms_colModelPedGroundHit; else diff --git a/src/core/common.h b/src/core/common.h index 46b4d03a..8b057efa 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -27,9 +27,15 @@ #ifdef LIBRW #define STREAMPOS(str) ((str)->tell()) #define STREAMFILE(str) (((rw::StreamFile*)(str))->file) +#define HIERNODEINFO(hier) ((hier)->nodeInfo) +#define HIERNODEID(hier, i) ((hier)->nodeInfo[i].id) +#define HANIMFRAMES(anim) ((anim)->keyframes) #else #define STREAMPOS(str) ((str)->Type.memory.position) #define STREAMFILE(str) ((str)->Type.file.fpFile) +#define HIERNODEINFO(hier) ((hier)->pNodeInfo) +#define HIERNODEID(hier, i) ((hier)->pNodeInfo[i].nodeID) +#define HANIMFRAMES(anim) ((anim)->pFrames) #endif #define rwVENDORID_ROCKSTAR 0x0253F2 @@ -63,6 +69,11 @@ typedef uint16_t wchar; #include "config.h" +#ifdef PED_SKIN +#include +#include +#endif + #define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1)) // PDP-10 like byte functions diff --git a/src/core/config.h b/src/core/config.h index c52a708d..84712af3 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -234,6 +234,7 @@ enum Config { #define CAMERA_PICKUP // Peds +#define PED_SKIN // support for skinned geometry on peds #define ANIMATE_PED_COL_MODEL #define VC_PED_PORTS // various ports from VC's CPed, mostly subtle // #define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward diff --git a/src/core/main.cpp b/src/core/main.cpp index 77daaa01..7013b10f 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -794,6 +794,7 @@ RenderDebugShit(void) if(gbShowCollisionLines) CRenderer::RenderCollisionLines(); ThePaths.DisplayPathData(); + CDebug::DrawLines(); #endif } diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 3dce53da..756e1232 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "General.h" +#include "RwHelper.h" #include "ModelIndices.h" #include "Timer.h" #include "Placeable.h" @@ -24,6 +25,8 @@ #include "References.h" #include "TxdStore.h" #include "Zones.h" +#include "Bones.h" +#include "Debug.h" int gBuildings; @@ -282,6 +285,28 @@ CEntity::CreateRwObject(void) } } +#ifdef PED_SKIN +RpAtomic* +AtomicRemoveAnimFromSkinCB(RpAtomic *atomic, void *data) +{ + if(RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic))){ + RpHAnimHierarchy *hier = RpSkinAtomicGetHAnimHierarchy(atomic); +#ifdef LIBRW + if(hier && hier->interpolator->currentAnim){ + RpHAnimAnimationDestroy(hier->interpolator->currentAnim); + hier->interpolator->currentAnim = nil; + } +#else + if(hier && hier->pCurrentAnim){ + RpHAnimAnimationDestroy(hier->pCurrentAnim); + hier->pCurrentAnim = nil; + } +#endif + } + return atomic; +} +#endif + void CEntity::DeleteRwObject(void) { @@ -293,8 +318,13 @@ CEntity::DeleteRwObject(void) f = RpAtomicGetFrame((RpAtomic*)m_rwObject); RpAtomicDestroy((RpAtomic*)m_rwObject); RwFrameDestroy(f); - }else if(RwObjectGetType(m_rwObject) == rpCLUMP) + }else if(RwObjectGetType(m_rwObject) == rpCLUMP){ +#ifdef PED_SKIN + if(IsClumpSkinned((RpClump*)m_rwObject)) + RpClumpForAllAtomics((RpClump*)m_rwObject, AtomicRemoveAnimFromSkinCB, nil); +#endif RpClumpDestroy((RpClump*)m_rwObject); + } m_rwObject = nil; CModelInfo::GetModelInfo(m_modelIndex)->RemoveRef(); if(IsBuilding()) @@ -558,6 +588,44 @@ CEntity::PruneReferences(void) } } +#ifdef PED_SKIN +void +CEntity::UpdateRpHAnim(void) +{ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + RpHAnimHierarchyUpdateMatrices(hier); + +#if 0 + int i; + char buf[256]; + if(this == (CEntity*)FindPlayerPed()) + for(i = 0; i < hier->numNodes; i++){ + RpHAnimStdKeyFrame *kf = (RpHAnimStdKeyFrame*)rpHANIMHIERARCHYGETINTERPFRAME(hier, i); + sprintf(buf, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %d %s", + kf->q.imag.x, kf->q.imag.y, kf->q.imag.z, kf->q.real, + kf->t.x, kf->t.y, kf->t.z, + HIERNODEID(hier, i), + ConvertBoneTag2BoneName(HIERNODEID(hier, i))); + CDebug::PrintAt(buf, 10, 1+i*3); + + RwMatrix *m = &RpHAnimHierarchyGetMatrixArray(hier)[i]; + sprintf(buf, "%6.3f %6.3f %6.3f %6.3f", + m->right.x, m->up.x, m->at.x, m->pos.x); + CDebug::PrintAt(buf, 80, 1+i*3+0); + sprintf(buf, "%6.3f %6.3f %6.3f %6.3f", + m->right.y, m->up.y, m->at.y, m->pos.y); + CDebug::PrintAt(buf, 80, 1+i*3+1); + sprintf(buf, "%6.3f %6.3f %6.3f %6.3f", + m->right.z, m->up.z, m->at.z, m->pos.z); + CDebug::PrintAt(buf, 80, 1+i*3+2); + } + + void RenderSkeleton(RpHAnimHierarchy *hier); + RenderSkeleton(hier); +#endif +} +#endif + void CEntity::AddSteamsFromGround(CVector *unused) { diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 8c2634f3..ee9e6490 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -148,6 +148,10 @@ public: void ResolveReferences(void); void PruneReferences(void); +#ifdef PED_SKIN + void UpdateRpHAnim(void); +#endif + void PreRenderForGlassWindow(void); void AddSteamsFromGround(CVector *unused); void ModifyMatrixForTreeInWind(void); diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 3977007f..59c01c91 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -4,14 +4,10 @@ #include #include #include +#include #include #include -// TODO: split image<->raster functions in two -// implement raster context -// BMP reader -// geometry locking - using namespace rw; RwUInt8 RwObjectGetType(const RwObject *obj) { return obj->type; } @@ -55,7 +51,7 @@ RwMatrix *RwMatrixMultiply(RwMatrix * matrixOut, const RwMatrix * MatrixIn1, con RwMatrix *RwMatrixTransform(RwMatrix * matrix, const RwMatrix * transform, RwOpCombineType combineOp) { matrix->transform(transform, (rw::CombineOp)combineOp); return matrix; } //RwMatrix *RwMatrixOrthoNormalize(RwMatrix * matrixOut, const RwMatrix * matrixIn); -//RwMatrix *RwMatrixInvert(RwMatrix * matrixOut, const RwMatrix * matrixIn); +RwMatrix *RwMatrixInvert(RwMatrix * matrixOut, const RwMatrix * matrixIn) { Matrix::invert(matrixOut, matrixIn); return matrixOut; } RwMatrix *RwMatrixScale(RwMatrix * matrix, const RwV3d * scale, RwOpCombineType combineOp) { matrix->scale(scale, (rw::CombineOp)combineOp); return matrix; } RwMatrix *RwMatrixTranslate(RwMatrix * matrix, const RwV3d * translation, RwOpCombineType combineOp) @@ -742,14 +738,24 @@ RwBool RpHAnimPluginAttach(void) { return true; } +RwInt32 RpHAnimFrameGetID(RwFrame *frame) { return HAnimData::get(frame)->id; } + +RwInt32 RpHAnimIDGetIndex(RpHAnimHierarchy *hierarchy, RwInt32 ID) { return hierarchy->getIndex(ID); } + RwBool RpHAnimFrameSetHierarchy(RwFrame *frame, RpHAnimHierarchy *hierarchy) { HAnimData::get(frame)->hierarchy = hierarchy; return true; } RpHAnimHierarchy *RpHAnimFrameGetHierarchy(RwFrame *frame) { return HAnimHierarchy::get(frame); } -RwBool RpHAnimHierarchySetCurrentAnim(RpHAnimHierarchy *hierarchy, RpHAnimAnimation *anim) { hierarchy->currentAnim->setCurrentAnim(anim); return true; } -RwBool RpHAnimHierarchyAddAnimTime(RpHAnimHierarchy *hierarchy, RwReal time) { hierarchy->currentAnim->addTime(time); return true; } +RpHAnimHierarchy *RpHAnimHierarchySetFlags(RpHAnimHierarchy *hierarchy, RpHAnimHierarchyFlag flags) { hierarchy->flags = flags; return hierarchy; } +RwBool RpHAnimHierarchySetCurrentAnim(RpHAnimHierarchy *hierarchy, RpHAnimAnimation *anim) { hierarchy->interpolator->setCurrentAnim(anim); return true; } +RwBool RpHAnimHierarchyAddAnimTime(RpHAnimHierarchy *hierarchy, RwReal time) { hierarchy->interpolator->addTime(time); return true; } + +RwMatrix *RpHAnimHierarchyGetMatrixArray(RpHAnimHierarchy *hierarchy) { return hierarchy->matrices; } RwBool RpHAnimHierarchyUpdateMatrices(RpHAnimHierarchy *hierarchy) { hierarchy->updateMatrices(); return true; } +RpHAnimAnimation *RpHAnimAnimationCreate(RwInt32 typeID, RwInt32 numFrames, RwInt32 flags, RwReal duration) + { return Animation::create(AnimInterpolatorInfo::find(typeID), numFrames, flags, duration); } +RpHAnimAnimation *RpHAnimAnimationDestroy(RpHAnimAnimation *animation) { animation->destroy(); return animation; } RpHAnimAnimation *RpHAnimAnimationStreamRead(RwStream *stream) { return Animation::streamRead(stream); } @@ -762,6 +768,13 @@ RwBool RpSkinPluginAttach(void) { return true; } +RwUInt32 RpSkinGetNumBones( RpSkin *skin ) { return skin->numBones; } +const RwMatrixWeights *RpSkinGetVertexBoneWeights( RpSkin *skin ) { return (RwMatrixWeights*)skin->weights; } +const RwUInt32 *RpSkinGetVertexBoneIndices( RpSkin *skin ) { return (RwUInt32*)skin->indices; } +const RwMatrix *RpSkinGetSkinToBoneMatrices( RpSkin *skin ) { return (const RwMatrix*)skin->inverseMatrices; } + +RpSkin *RpSkinGeometryGetSkin( RpGeometry *geometry ) { return Skin::get(geometry); } + RpAtomic *RpSkinAtomicSetHAnimHierarchy( RpAtomic *atomic, RpHAnimHierarchy *hierarchy ) { Skin::setHierarchy(atomic, hierarchy); return atomic; } RpHAnimHierarchy *RpSkinAtomicGetHAnimHierarchy( const RpAtomic *atomic ) { return Skin::getHierarchy(atomic); } @@ -772,6 +785,23 @@ RpHAnimHierarchy *RpSkinAtomicGetHAnimHierarchy( const RpAtomic *atomic ) { retu RwImage *RtBMPImageWrite(RwImage * image, const RwChar * imageName) { rw::writeBMP(image, imageName); return image; } RwImage *RtBMPImageRead(const RwChar * imageName) { return rw::readBMP(imageName); } +#include "rtquat.h" + +RtQuat *RtQuatRotate(RtQuat * quat, const RwV3d * axis, RwReal angle, RwOpCombineType combineOp) { return quat->rotate(axis, angle/180.0f*3.14159f, (CombineOp)combineOp); } +void RtQuatConvertToMatrix(const RtQuat * const qpQuat, RwMatrix * const mpMatrix) { mpMatrix->rotate(*qpQuat, COMBINEREPLACE); } + + +#include "rtcharse.h" + +RwBool RtCharsetOpen(void) { return Charset::open(); } +void RtCharsetClose(void) { return Charset::close(); } +RtCharset *RtCharsetPrint(RtCharset * charSet, const RwChar * string, RwInt32 x, RwInt32 y) { charSet->print(string, x, y, true); return charSet; } +RtCharset *RtCharsetPrintBuffered(RtCharset * charSet, const RwChar * string, RwInt32 x, RwInt32 y, RwBool hideSpaces) { charSet->printBuffered(string, x, y, hideSpaces); return charSet; } +RwBool RtCharsetBufferFlush(void) { Charset::flushBuffer(); return true; } +RtCharset *RtCharsetSetColors(RtCharset * charSet, const RwRGBA * foreGround, const RwRGBA * backGround) { return charSet->setColors(foreGround, backGround); } +RtCharset *RtCharsetGetDesc(RtCharset * charset, RtCharsetDesc * desc) { *desc = charset->desc; return charset; } +RtCharset *RtCharsetCreate(const RwRGBA * foreGround, const RwRGBA * backGround) { return Charset::create(foreGround, backGround); } +RwBool RtCharsetDestroy(RtCharset * charSet) { charSet->destroy(); return true; } diff --git a/src/fakerw/rphanim.h b/src/fakerw/rphanim.h index 665e03f8..34dfeb09 100644 --- a/src/fakerw/rphanim.h +++ b/src/fakerw/rphanim.h @@ -1,20 +1,56 @@ #pragma once +#include "rtquat.h" + //struct RpHAnimHierarchy; typedef rw::HAnimHierarchy RpHAnimHierarchy; //struct RpHAnimAnimation; typedef rw::Animation RpHAnimAnimation; +#define rpHANIMSTDKEYFRAMETYPEID 0x1 + +typedef rw::HAnimKeyFrame RpHAnimStdKeyFrame; + +enum RpHAnimHierarchyFlag +{ + rpHANIMHIERARCHYSUBHIERARCHY = rw::HAnimHierarchy::SUBHIERARCHY, + rpHANIMHIERARCHYNOMATRICES = rw::HAnimHierarchy::NOMATRICES, + + rpHANIMHIERARCHYUPDATEMODELLINGMATRICES = rw::HAnimHierarchy::UPDATEMODELLINGMATRICES, + rpHANIMHIERARCHYUPDATELTMS = rw::HAnimHierarchy::UPDATELTMS, + rpHANIMHIERARCHYLOCALSPACEMATRICES = rw::HAnimHierarchy::LOCALSPACEMATRICES +}; + +#define rpHANIMPOPPARENTMATRIX rw::HAnimHierarchy::POP +#define rpHANIMPUSHPARENTMATRIX rw::HAnimHierarchy::PUSH + RwBool RpHAnimPluginAttach(void); +RwBool RpHAnimFrameSetID(RwFrame *frame, RwInt32 id); +RwInt32 RpHAnimFrameGetID(RwFrame *frame); + +RwInt32 RpHAnimIDGetIndex(RpHAnimHierarchy *hierarchy, RwInt32 ID); + RwBool RpHAnimFrameSetHierarchy(RwFrame *frame, RpHAnimHierarchy *hierarchy); RpHAnimHierarchy *RpHAnimFrameGetHierarchy(RwFrame *frame); +RpHAnimHierarchy *RpHAnimHierarchySetFlags(RpHAnimHierarchy *hierarchy, RpHAnimHierarchyFlag flags); +RpHAnimHierarchyFlag RpHAnimHierarchyGetFlags(RpHAnimHierarchy *hierarchy); + RwBool RpHAnimHierarchySetCurrentAnim(RpHAnimHierarchy *hierarchy, RpHAnimAnimation *anim); RwBool RpHAnimHierarchySetCurrentAnimTime(RpHAnimHierarchy *hierarchy, RwReal time); RwBool RpHAnimHierarchySubAnimTime(RpHAnimHierarchy *hierarchy, RwReal time); RwBool RpHAnimHierarchyAddAnimTime(RpHAnimHierarchy *hierarchy, RwReal time); +RwMatrix *RpHAnimHierarchyGetMatrixArray(RpHAnimHierarchy *hierarchy); RwBool RpHAnimHierarchyUpdateMatrices(RpHAnimHierarchy *hierarchy); +#define rpHANIMHIERARCHYGETINTERPFRAME( hierarchy, nodeIndex ) \ + ( (void *)( ( (RwUInt8 *)&(hierarchy->interpolator[1]) + \ + ((nodeIndex) * \ + hierarchy->interpolator->currentAnimKeyFrameSize) ) ) ) + + +RpHAnimAnimation *RpHAnimAnimationCreate(RwInt32 typeID, RwInt32 numFrames, RwInt32 flags, RwReal duration); +RpHAnimAnimation *RpHAnimAnimationDestroy(RpHAnimAnimation *animation); RpHAnimAnimation *RpHAnimAnimationStreamRead(RwStream *stream); diff --git a/src/fakerw/rpskin.h b/src/fakerw/rpskin.h index dd8551ae..1ffc9f27 100644 --- a/src/fakerw/rpskin.h +++ b/src/fakerw/rpskin.h @@ -2,7 +2,25 @@ #include +//struct RpSkin; +typedef rw::Skin RpSkin; + +struct RwMatrixWeights +{ + RwReal w0; + RwReal w1; + RwReal w2; + RwReal w3; +}; + RwBool RpSkinPluginAttach(void); +RwUInt32 RpSkinGetNumBones( RpSkin *skin ); +const RwMatrixWeights *RpSkinGetVertexBoneWeights( RpSkin *skin ); +const RwUInt32 *RpSkinGetVertexBoneIndices( RpSkin *skin ); +const RwMatrix *RpSkinGetSkinToBoneMatrices( RpSkin *skin ); + +RpSkin *RpSkinGeometryGetSkin( RpGeometry *geometry ); + RpAtomic *RpSkinAtomicSetHAnimHierarchy( RpAtomic *atomic, RpHAnimHierarchy *hierarchy ); RpHAnimHierarchy *RpSkinAtomicGetHAnimHierarchy( const RpAtomic *atomic ); diff --git a/src/fakerw/rtcharse.h b/src/fakerw/rtcharse.h new file mode 100644 index 00000000..10eb1f32 --- /dev/null +++ b/src/fakerw/rtcharse.h @@ -0,0 +1,14 @@ +#pragma once + +typedef rw::Charset RtCharset; +typedef rw::Charset::Desc RtCharsetDesc; + +RwBool RtCharsetOpen(void); +void RtCharsetClose(void); +RtCharset *RtCharsetPrint(RtCharset * charSet, const RwChar * string, RwInt32 x, RwInt32 y); +RtCharset *RtCharsetPrintBuffered(RtCharset * charSet, const RwChar * string, RwInt32 x, RwInt32 y, RwBool hideSpaces); +RwBool RtCharsetBufferFlush(void); +RtCharset *RtCharsetSetColors(RtCharset * charSet, const RwRGBA * foreGround, const RwRGBA * backGround); +RtCharset *RtCharsetGetDesc(RtCharset * charset, RtCharsetDesc * desc); +RtCharset *RtCharsetCreate(const RwRGBA * foreGround, const RwRGBA * backGround); +RwBool RtCharsetDestroy(RtCharset * charSet); diff --git a/src/fakerw/rtquat.h b/src/fakerw/rtquat.h new file mode 100644 index 00000000..3cf15f5a --- /dev/null +++ b/src/fakerw/rtquat.h @@ -0,0 +1,10 @@ +#pragma once + +typedef rw::Quat RtQuat; + +RwBool RtQuatConvertFromMatrix(RtQuat * const qpQuat, const RwMatrix * const mpMatrix); +RtQuat *RtQuatRotate(RtQuat * quat, const RwV3d * axis, RwReal angle, RwOpCombineType combineOp); +const RtQuat *RtQuatQueryRotate(const RtQuat *quat, RwV3d * unitAxis, RwReal * angle); +RwV3d *RtQuatTransformVectors(RwV3d * vectorsOut, const RwV3d * vectorsIn, const RwInt32 numPoints, const RtQuat *quat); + +void RtQuatConvertToMatrix(const RtQuat * const qpQuat, RwMatrix * const mpMatrix); diff --git a/src/math/Quaternion.h b/src/math/Quaternion.h index fb37dc10..1d04bdff 100644 --- a/src/math/Quaternion.h +++ b/src/math/Quaternion.h @@ -10,6 +10,18 @@ public: float Magnitude(void) const { return Sqrt(x*x + y*y + z*z + w*w); } float MagnitudeSqr(void) const { return x*x + y*y + z*z + w*w; } + void Normalise(void) { + float sq = MagnitudeSqr(); + if(sq == 0.0f) + w = 1.0f; + else{ + float invsqrt = RecipSqrt(sq); + x *= invsqrt; + y *= invsqrt; + z *= invsqrt; + w *= invsqrt; + } + } const CQuaternion &operator+=(CQuaternion const &right) { x += right.x; diff --git a/src/modelinfo/ClumpModelInfo.cpp b/src/modelinfo/ClumpModelInfo.cpp index 464bda61..44faf3c5 100644 --- a/src/modelinfo/ClumpModelInfo.cpp +++ b/src/modelinfo/ClumpModelInfo.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "RwHelper.h" #include "General.h" #include "NodeName.h" #include "VisibilityPlugins.h" @@ -15,12 +16,40 @@ CClumpModelInfo::DeleteRwObject(void) } } +#ifdef PED_SKIN +static RpAtomic* +SetHierarchyForSkinAtomic(RpAtomic *atomic, void *data) +{ + RpSkinAtomicSetHAnimHierarchy(atomic, (RpHAnimHierarchy*)data); + return nil; +} +#endif + RwObject* CClumpModelInfo::CreateInstance(void) { - if(m_clump) - return (RwObject*)RpClumpClone(m_clump); - return nil; + if(m_clump == nil) + return nil; + RpClump *clone = RpClumpClone(m_clump); +#ifdef PED_SKIN + if(IsClumpSkinned(clone)){ + RpHAnimHierarchy *hier; + RpHAnimAnimation *anim; + + hier = GetAnimHierarchyFromClump(clone); + assert(hier); + // This seems dangerous as only the first atomic will get a hierarchy + // can we guarantee this if hands and head are also in the clump? + RpClumpForAllAtomics(clone, SetHierarchyForSkinAtomic, hier); + anim = HAnimAnimationCreateForHierarchy(hier); + RpHAnimHierarchySetCurrentAnim(hier, anim); +// RpHAnimHierarchySetFlags(hier, (RpHAnimHierarchyFlag)(rpHANIMHIERARCHYUPDATEMODELLINGMATRICES|rpHANIMHIERARCHYUPDATELTMS)); + // the rest is xbox only: + // RpSkinGetNumBones(RpSkinGeometryGetSkin(RpAtomicGetGeometry(IsClumpSkinned(clone)))); + RpHAnimHierarchyUpdateMatrices(hier); + } +#endif + return (RwObject*)clone; } RwObject* @@ -48,8 +77,45 @@ CClumpModelInfo::SetClump(RpClump *clump) CVisibilityPlugins::SetClumpModelInfo(m_clump, this); AddTexDictionaryRef(); RpClumpForAllAtomics(clump, SetAtomicRendererCB, nil); + + // TODO: also set for player? if(strncmp(GetName(), "playerh", 8) == 0) RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); + +#ifdef PED_SKIN + if(IsClumpSkinned(clump)){ + int i; + RpHAnimHierarchy *hier; + RpAtomic *skinAtomic; + RpSkin *skin; + + // mobile: +// hier = nil; +// RwFrameForAllChildren(RpClumpGetFrame(clump), GetHierarchyFromChildNodesCB, &hier); +// assert(hier); +// RpClumpForAllAtomics(clump, SetHierarchyForSkinAtomic, hier); +// skinAtomic = GetFirstAtomic(clump); + + // xbox: + hier = GetAnimHierarchyFromClump(clump); + assert(hier); + RpSkinAtomicSetHAnimHierarchy(IsClumpSkinned(clump), hier); + skinAtomic = IsClumpSkinned(clump); + + assert(skinAtomic); + skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(skinAtomic)); + // ignore const + for(i = 0; i < RpGeometryGetNumVertices(RpAtomicGetGeometry(skinAtomic)); i++){ + RwMatrixWeights *weights = (RwMatrixWeights*)&RpSkinGetVertexBoneWeights(skin)[i]; + float sum = weights->w0 + weights->w1 + weights->w2 + weights->w3; + weights->w0 /= sum; + weights->w1 /= sum; + weights->w2 /= sum; + weights->w3 /= sum; + } +// RpHAnimHierarchySetFlags(hier, (RpHAnimHierarchyFlag)(rpHANIMHIERARCHYUPDATEMODELLINGMATRICES|rpHANIMHIERARCHYUPDATELTMS)); + } +#endif } void diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp index 5c801a2b..47080e23 100644 --- a/src/modelinfo/PedModelInfo.cpp +++ b/src/modelinfo/PedModelInfo.cpp @@ -1,6 +1,9 @@ #include "common.h" +#include "RwHelper.h" #include "General.h" +#include "Bones.h" +#include "SurfaceTable.h" #include "Ped.h" #include "NodeName.h" #include "VisibilityPlugins.h" @@ -9,13 +12,31 @@ void CPedModelInfo::DeleteRwObject(void) { - CClumpModelInfo::DeleteRwObject(); if(m_hitColModel) delete m_hitColModel; m_hitColModel = nil; +#ifdef PED_SKIN + RwFrame *frame; + if(m_head){ + frame = RpAtomicGetFrame(m_head); + RpAtomicDestroy(m_head); + RwFrameDestroy(frame); + } + if(m_lhand){ + frame = RpAtomicGetFrame(m_lhand); + RpAtomicDestroy(m_lhand); + RwFrameDestroy(frame); + } + if(m_rhand){ + frame = RpAtomicGetFrame(m_rhand); + RpAtomicDestroy(m_rhand); + RwFrameDestroy(frame); + } +#endif + CClumpModelInfo::DeleteRwObject(); // PC calls this first } -RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = { +RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[PED_NODE_MAX] = { { "Smid", PED_MID, 0, }, // that is strange... { "Shead", PED_HEAD, 0, }, { "Supperarml", PED_UPPERARML, 0, }, @@ -30,15 +51,70 @@ RwObjectNameIdAssocation CPedModelInfo::m_pPedIds[12] = { { nil, 0, 0, }, }; +#ifdef PED_SKIN +struct LimbCBarg +{ + CPedModelInfo *mi; + RpClump *clump; + int32 frameIDs[3]; +}; + +RpAtomic* +CPedModelInfo::findLimbsCb(RpAtomic *atomic, void *data) +{ + LimbCBarg *limbs = (LimbCBarg*)data; + RwFrame *frame = RpAtomicGetFrame(atomic); + const char *name = GetFrameNodeName(frame); + if(CGeneral::faststricmp(name, "Shead01") == 0){ + limbs->frameIDs[0] = RpHAnimFrameGetID(frame); + limbs->mi->m_head = atomic; + RpClumpRemoveAtomic(limbs->clump, atomic); + RwFrameRemoveChild(frame); + }else if(CGeneral::faststricmp(name, "SLhand01") == 0){ + limbs->frameIDs[1] = RpHAnimFrameGetID(frame); + limbs->mi->m_lhand = atomic; + RpClumpRemoveAtomic(limbs->clump, atomic); + RwFrameRemoveChild(frame); + }else if(CGeneral::faststricmp(name, "SRhand01") == 0){ + limbs->frameIDs[2] = RpHAnimFrameGetID(frame); + limbs->mi->m_rhand = atomic; + RpClumpRemoveAtomic(limbs->clump, atomic); + RwFrameRemoveChild(frame); + } + return atomic; +} +#endif + void CPedModelInfo::SetClump(RpClump *clump) { +#ifdef PED_SKIN + + // CB has to be set here before atomics are detached from clump + if(strncmp(GetName(), "player", 7) == 0) + RpClumpForAllAtomics(clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); + if(IsClumpSkinned(clump)){ + LimbCBarg limbs = { this, clump, { 0, 0, 0 } }; + RpClumpForAllAtomics(clump, findLimbsCb, &limbs); + } + CClumpModelInfo::SetClump(clump); + SetFrameIds(m_pPedIds); + if(m_hitColModel == nil && !IsClumpSkinned(clump)) + CreateHitColModel(); + // And again because CClumpModelInfo resets it + if(strncmp(GetName(), "player", 7) == 0) + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); + else if(IsClumpSkinned(clump)) + // skinned peds have no low detail version, so they don't have the right render Cb + RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPedCB); +#else CClumpModelInfo::SetClump(clump); SetFrameIds(m_pPedIds); if(m_hitColModel == nil) CreateHitColModel(); if(strncmp(GetName(), "player", 7) == 0) RpClumpForAllAtomics(m_clump, SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB); +#endif } RpAtomic* @@ -157,7 +233,7 @@ CPedModelInfo::CreateHitColModel(void) } if(nodeFrame){ float radius = m_pColNodeInfos[i].radius; - if(m_pColNodeInfos[i].pieceType == 6) + if(m_pColNodeInfos[i].pieceType == PEDPIECE_HEAD) RwFrameForAllObjects(nodeFrame, FindHeadRadiusCB, &radius); RwMatrixTransform(mat, RwFrameGetMatrix(nodeFrame), rwCOMBINEREPLACE); const char *name = GetFrameNodeName(nodeFrame); @@ -172,7 +248,7 @@ CPedModelInfo::CreateHitColModel(void) center.x = mat->pos.x + m_pColNodeInfos[i].x; center.y = mat->pos.y + 0.0f; center.z = mat->pos.z + m_pColNodeInfos[i].z; - spheres[i].Set(radius, center, 17, m_pColNodeInfos[i].pieceType); + spheres[i].Set(radius, center, SURFACE_FLESH, m_pColNodeInfos[i].pieceType); } } RwMatrixDestroy(mat); @@ -186,7 +262,7 @@ CPedModelInfo::CreateHitColModel(void) max.x = max.y = 0.5f; max.z = 1.2f; colmodel->boundingBox.Set(min, max, 0, 0); - colmodel->level = 0; + colmodel->level = LEVEL_NONE; m_hitColModel = colmodel; } @@ -229,3 +305,81 @@ CPedModelInfo::AnimatePedColModel(CColModel* colmodel, RwFrame* frame) return colmodel; } + +#ifdef PED_SKIN +void +CPedModelInfo::CreateHitColModelSkinned(RpClump *clump) +{ + CVector center; + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump); + CColModel *colmodel = new CColModel; + CColSphere *spheres = (CColSphere*)RwMalloc(NUMPEDINFONODES*sizeof(CColSphere)); + RwFrame *root = RpClumpGetFrame(m_clump); + RwMatrix *invmat = RwMatrixCreate(); + RwMatrix *mat = RwMatrixCreate(); + RwMatrixInvert(invmat, RwFrameGetMatrix(RpClumpGetFrame(clump))); + + for(int i = 0; i < NUMPEDINFONODES; i++){ + *mat = *invmat; + int id = ConvertPedNode2BoneTag(m_pColNodeInfos[i].pedNode); // this is wrong, wtf R* ??? + int idx = RpHAnimIDGetIndex(hier, id); + + // This doesn't really work as the positions are not initialized yet + RwMatrixTransform(mat, &RpHAnimHierarchyGetMatrixArray(hier)[idx], rwCOMBINEPRECONCAT); + RwV3d pos = { 0.0f, 0.0f, 0.0f }; + RwV3dTransformPoints(&pos, &pos, 1, mat); + + center.x = pos.x + m_pColNodeInfos[i].x; + center.y = pos.y + 0.0f; + center.z = pos.z + m_pColNodeInfos[i].z; + spheres[i].Set(m_pColNodeInfos[i].radius, center, SURFACE_FLESH, m_pColNodeInfos[i].pieceType); + } + RwMatrixDestroy(invmat); + RwMatrixDestroy(mat); + colmodel->spheres = spheres; + colmodel->numSpheres = NUMPEDINFONODES; + center.x = center.y = center.z = 0.0f; + colmodel->boundingSphere.Set(2.0f, center, 0, 0); + CVector min, max; + min.x = min.y = -0.5f; + min.z = -1.2f; + max.x = max.y = 0.5f; + max.z = 1.2f; + colmodel->boundingBox.Set(min, max, 0, 0); + colmodel->level = LEVEL_NONE; + m_hitColModel = colmodel; +} + +CColModel* +CPedModelInfo::AnimatePedColModelSkinned(RpClump *clump) +{ + if(m_hitColModel == nil){ + CreateHitColModelSkinned(clump); + return m_hitColModel; + } + RwMatrix *invmat, *mat; + CColSphere *spheres = m_hitColModel->spheres; + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump); + invmat = RwMatrixCreate(); + mat = RwMatrixCreate(); + RwMatrixInvert(invmat, RwFrameGetMatrix(RpClumpGetFrame(clump))); + + for(int i = 0; i < NUMPEDINFONODES; i++){ + *mat = *invmat; + int id = ConvertPedNode2BoneTag(m_pColNodeInfos[i].pedNode); + int idx = RpHAnimIDGetIndex(hier, id); + + RwMatrixTransform(mat, &RpHAnimHierarchyGetMatrixArray(hier)[idx], rwCOMBINEPRECONCAT); + RwV3d pos = { 0.0f, 0.0f, 0.0f }; + RwV3dTransformPoints(&pos, &pos, 1, mat); + + spheres[i].center.x = pos.x + m_pColNodeInfos[i].x; + spheres[i].center.y = pos.y + 0.0f; + spheres[i].center.z = pos.z + m_pColNodeInfos[i].z; + } + RwMatrixDestroy(invmat); + RwMatrixDestroy(mat); + return m_hitColModel; +} + +#endif diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index 0336fa9b..a2bfd122 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -28,11 +28,13 @@ public: ePedStats m_pedStatType; uint32 m_carsCanDrive; CColModel *m_hitColModel; +#ifdef PED_SKIN RpAtomic *m_head; RpAtomic *m_lhand; RpAtomic *m_rhand; +#endif - static RwObjectNameIdAssocation m_pPedIds[12]; + static RwObjectNameIdAssocation m_pPedIds[PED_NODE_MAX]; CPedModelInfo(void) : CClumpModelInfo(MITYPE_PED) { } void DeleteRwObject(void); @@ -40,7 +42,18 @@ public: void SetLowDetailClump(RpClump*); void CreateHitColModel(void); + void CreateHitColModelSkinned(RpClump *clump); CColModel *GetHitColModel(void) { return m_hitColModel; } static CColModel *AnimatePedColModel(CColModel* colmodel, RwFrame* frame); + CColModel *AnimatePedColModelSkinned(RpClump *clump); + +#ifdef PED_SKIN + static RpAtomic *findLimbsCb(RpAtomic *atomic, void *data); + RpAtomic *getHead(void) { return m_head; } + RpAtomic *getLeftHand(void) { return m_lhand; } + RpAtomic *getRightHand(void) { return m_rhand; } +#endif }; -static_assert(sizeof(CPedModelInfo) == 0x54, "CPedModelInfo: error"); +#ifndef PED_SKIN +static_assert(sizeof(CPedModelInfo) == 0x48, "CPedModelInfo: error"); +#endif \ No newline at end of file diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp index b716e17e..3ef257d2 100644 --- a/src/objects/CutsceneHead.cpp +++ b/src/objects/CutsceneHead.cpp @@ -5,6 +5,7 @@ #include "RwHelper.h" #include "RpAnimBlend.h" #include "AnimBlendClumpData.h" +#include "Bones.h" #include "Directory.h" #include "CutsceneMgr.h" #include "Streaming.h" @@ -17,11 +18,23 @@ CCutsceneHead::CCutsceneHead(CObject *obj) RpAtomic *atm; assert(RwObjectGetType(obj->m_rwObject) == rpCLUMP); - m_pHeadNode = RpAnimBlendClumpFindFrame((RpClump*)obj->m_rwObject, "Shead")->frame; - atm = (RpAtomic*)GetFirstObject(m_pHeadNode); - if(atm){ - assert(RwObjectGetType((RwObject*)atm) == rpATOMIC); - RpAtomicSetFlags(atm, RpAtomicGetFlags(atm) & ~rpATOMICRENDER); +#ifdef PED_SKIN + unk1 = 0; + bIsSkinned = false; + m_parentObject = (CCutsceneObject*)obj; + // Hide original head + if(IsClumpSkinned(obj->GetClump())){ + m_parentObject->SetRenderHead(false); + bIsSkinned = true; + }else +#endif + { + m_pHeadNode = RpAnimBlendClumpFindFrame((RpClump*)obj->m_rwObject, "Shead")->frame; + atm = (RpAtomic*)GetFirstObject(m_pHeadNode); + if(atm){ + assert(RwObjectGetType((RwObject*)atm) == rpATOMIC); + RpAtomicSetFlags(atm, RpAtomicGetFlags(atm) & ~rpATOMICRENDER); + } } } @@ -48,11 +61,28 @@ CCutsceneHead::ProcessControl(void) RpAtomic *atm; RpHAnimHierarchy *hier; + // android/xbox calls is at the end CPhysical::ProcessControl(); - m_matrix.SetRotateY(PI/2); - m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; - UpdateRwFrame(); +#ifdef PED_SKIN + if(bIsSkinned){ + UpdateRpHAnim(); + UpdateRwFrame(); + + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(m_parentObject->GetClump()); + int idx = RpHAnimIDGetIndex(hier, BONE_head); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + if(RwV3dLength(&mat->pos) > 100.0f){ + m_matrix.SetRotateY(PI/2); + m_matrix = CMatrix(mat) * m_matrix; + } + }else +#endif + { + m_matrix.SetRotateY(PI/2); + m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; + UpdateRwFrame(); // android/xbox don't call this + } assert(RwObjectGetType(m_rwObject) == rpCLUMP); atm = GetFirstAtomic((RpClump*)m_rwObject); @@ -65,8 +95,25 @@ CCutsceneHead::Render(void) { RpAtomic *atm; - m_matrix.SetRotateY(PI/2); - m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; +#ifdef PED_SKIN + if(bIsSkinned){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(m_parentObject->GetClump()); + RpHAnimHierarchyUpdateMatrices(hier); + int idx = RpHAnimIDGetIndex(hier, BONE_head); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + if(RwV3dLength(&mat->pos) > 100.0f){ + m_matrix.SetRotateY(PI/2); + m_matrix = CMatrix(mat) * m_matrix; + } + RenderLimb(BONE_Lhand); + RenderLimb(BONE_Rhand); + }else +#endif + { + m_matrix.SetRotateY(PI/2); + m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; + } + UpdateRwFrame(); assert(RwObjectGetType(m_rwObject) == rpCLUMP); @@ -76,6 +123,34 @@ CCutsceneHead::Render(void) CObject::Render(); } +#ifdef PED_SKIN +void +CCutsceneHead::RenderLimb(int32 bone) +{ + RpAtomic *atomic; + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(m_parentObject->GetClump()); + int idx = RpHAnimIDGetIndex(hier, bone); + RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier); + CPedModelInfo *mi = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); + switch(bone){ + case BONE_Lhand: + atomic = mi->getLeftHand(); + break; + case BONE_Rhand: + atomic = mi->getRightHand(); + break; + default: + return; + } + if(atomic){ + RwFrame *frame = RpAtomicGetFrame(atomic); + RwMatrixTransform(RwFrameGetMatrix(frame), &mats[idx], rwCOMBINEREPLACE); + RwFrameUpdateObjects(frame); + RpAtomicRender(atomic); + } +} +#endif + void CCutsceneHead::PlayAnimation(const char *animName) { diff --git a/src/objects/CutsceneHead.h b/src/objects/CutsceneHead.h index 52b66ede..0a70353d 100644 --- a/src/objects/CutsceneHead.h +++ b/src/objects/CutsceneHead.h @@ -6,6 +6,12 @@ class CCutsceneHead : public CCutsceneObject { public: RwFrame *m_pHeadNode; +#ifdef PED_SKIN + int32 unk1; + CCutsceneObject *m_parentObject; + int32 unk2; + int32 bIsSkinned; +#endif CCutsceneHead(CObject *obj); @@ -13,7 +19,10 @@ public: void DeleteRwObject(void); void ProcessControl(void); void Render(void); + void RenderLimb(int32 bone); void PlayAnimation(const char *animName); }; +#ifndef PED_SKIN static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error"); +#endif diff --git a/src/objects/CutsceneObject.cpp b/src/objects/CutsceneObject.cpp index cee83848..7b4ae02b 100644 --- a/src/objects/CutsceneObject.cpp +++ b/src/objects/CutsceneObject.cpp @@ -1,10 +1,12 @@ #include "common.h" #include "main.h" +#include "RwHelper.h" #include "Lights.h" #include "PointLights.h" #include "RpAnimBlend.h" #include "AnimBlendClumpData.h" +#include "Bones.h" #include "Renderer.h" #include "ModelIndices.h" #include "Shadows.h" @@ -19,6 +21,12 @@ CCutsceneObject::CCutsceneObject(void) ObjectCreatedBy = CUTSCENE_OBJECT; m_fMass = 1.0f; m_fTurnMass = 1.0f; + +#ifdef PED_SKIN + bRenderHead = true; + bRenderRightHand = true; + bRenderLeftHand = true; +#endif } void @@ -42,12 +50,24 @@ CCutsceneObject::ProcessControl(void) m_vecMoveSpeed *= 1.0f/CTimer::GetTimeStep(); ApplyMoveSpeed(); + +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())) + UpdateRpHAnim(); +#endif +} + +static RpMaterial* +MaterialSetAlpha(RpMaterial *material, void *data) +{ + ((RwRGBA*)RpMaterialGetColor(material))->alpha = (uint8)(uintptr)data; + return material; } void CCutsceneObject::PreRender(void) { - if(IsPedModel(GetModelIndex())) + if(IsPedModel(GetModelIndex())){ CShadows::StoreShadowForPedObject(this, CTimeCycle::m_fShadowDisplacementX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowDisplacementY[CTimeCycle::m_CurrentStoredValue], @@ -55,14 +75,57 @@ CCutsceneObject::PreRender(void) CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]); + // For some reason xbox/android limbs are transparent here... + RpGeometry *geometry = RpAtomicGetGeometry(GetFirstAtomic(GetClump())); + RpGeometrySetFlags(geometry, RpGeometryGetFlags(geometry) | rpGEOMETRYMODULATEMATERIALCOLOR); + RpGeometryForAllMaterials(geometry, MaterialSetAlpha, (void*)255); + } } void CCutsceneObject::Render(void) { +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + if(bRenderLeftHand) RenderLimb(BONE_Lhand); + if(bRenderRightHand) RenderLimb(BONE_Rhand); + if(bRenderHead) RenderLimb(BONE_head); + } +#endif CObject::Render(); } +#ifdef PED_SKIN +void +CCutsceneObject::RenderLimb(int32 bone) +{ + RpAtomic *atomic; + CPedModelInfo *mi = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); + switch(bone){ + case BONE_head: + atomic = mi->getHead(); + break; + case BONE_Lhand: + atomic = mi->getLeftHand(); + break; + case BONE_Rhand: + atomic = mi->getRightHand(); + break; + default: + return; + } + if(atomic){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, bone); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwFrame *frame = RpAtomicGetFrame(atomic); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + RpAtomicRender(atomic); + } +} +#endif + bool CCutsceneObject::SetupLighting(void) { diff --git a/src/objects/CutsceneObject.h b/src/objects/CutsceneObject.h index 31c3a528..9c4036bf 100644 --- a/src/objects/CutsceneObject.h +++ b/src/objects/CutsceneObject.h @@ -5,13 +5,29 @@ class CCutsceneObject : public CObject { public: +#ifdef PED_SKIN + bool bRenderHead; + bool bRenderRightHand; + bool bRenderLeftHand; + + bool GetRenderHead(void) { return bRenderHead; } + bool GetRenderRightHand(void) { return bRenderRightHand; } + bool GetRenderLeftHand(void) { return bRenderLeftHand; } + void SetRenderHead(bool render) { bRenderHead = render; } + void SetRenderRightHand(bool render) { bRenderRightHand = render; } + void SetRenderLeftHand(bool render) { bRenderLeftHand = render; } +#endif + CCutsceneObject(void); void SetModelIndex(uint32 id); void ProcessControl(void); void PreRender(void); void Render(void); + void RenderLimb(int32 bone); bool SetupLighting(void); void RemoveLighting(bool reset); }; +#ifndef PED_SKIN static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error"); +#endif diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index 6082c6ab..88d034c8 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -11,4 +11,6 @@ public: void CivilianAI(void); void ProcessControl(void); }; +#ifndef PED_SKIN static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); +#endif diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index 98a07316..3fc8b8ca 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -465,8 +465,7 @@ CCopPed::CopAI(void) if (m_fDistanceToTarget < weaponRange) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); CVector gunPos = weaponInfo->m_vecFireOffset; - for (RwFrame *i = GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i)) - RwV3dTransformPoints((RwV3d*)&gunPos, (RwV3d*)&gunPos, 1, RwFrameGetMatrix(i)); + TransformToNode(gunPos, PED_HANDR); CColPoint foundCol; CEntity *foundEnt; diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h index e3454875..e9780035 100644 --- a/src/peds/CopPed.h +++ b/src/peds/CopPed.h @@ -36,4 +36,6 @@ public: void CopAI(void); }; +#ifndef PED_SKIN static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error"); +#endif diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h index 6546e902..6d3dac79 100644 --- a/src/peds/EmergencyPed.h +++ b/src/peds/EmergencyPed.h @@ -36,4 +36,6 @@ public: void FiremanAI(void); void MedicAI(void); }; +#ifndef PED_SKIN static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); +#endif diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index f4cdff70..dcb167f0 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -6,6 +6,7 @@ #include "Stats.h" #include "World.h" #include "RpAnimBlend.h" +#include "Bones.h" #include "Ped.h" #include "Wanted.h" #include "PlayerPed.h" @@ -642,6 +643,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_collPoly.valid = false; m_fCollisionSpeed = 0.0f; m_wepModelID = -1; +#ifdef PED_SKIN + m_pWeaponModel = nil; +#endif CPopulation::UpdatePedCount((ePedType)m_nPedType, false); } @@ -818,10 +822,17 @@ CPed::AddWeaponModel(int id) RpAtomic *atm; if (id != -1) { - atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); - RwFrameDestroy(RpAtomicGetFrame(atm)); - RpAtomicSetFrame(atm, GetNodeFrame(PED_HANDR)); - RpClumpAddAtomic(GetClump(), atm); +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())) + m_pWeaponModel = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + else +#endif + { + atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atm)); + RpAtomicSetFrame(atm, m_pFrames[PED_HANDR]->frame); + RpClumpAddAtomic(GetClump(), atm); + } m_wepModelID = id; } } @@ -915,25 +926,28 @@ void CPed::RemoveBodyPart(PedNode nodeId, int8 direction) { RwFrame *frame; - RwV3d pos; + CVector pos; - frame = GetNodeFrame(nodeId); + frame = m_pFrames[nodeId]->frame; if (frame) { if (CGame::nastyGame) { +#ifdef PED_SKIN + if(!IsClumpSkinned(GetClump())) +#endif + { #ifdef TOGGLEABLE_BETA_FEATURES - if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) + if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) #else - if (nodeId != PED_HEAD) + if (nodeId != PED_HEAD) #endif - SpawnFlyingComponent(nodeId, direction); + SpawnFlyingComponent(nodeId, direction); - RecurseFrameChildrenVisibilityCB(frame, nil); + RecurseFrameChildrenVisibilityCB(frame, nil); + } pos.x = 0.0f; pos.y = 0.0f; pos.z = 0.0f; - - for (; frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints(&pos, &pos, 1, RwFrameGetMatrix(frame)); + TransformToNode(pos, PED_HEAD); if (CEntity::GetIsOnScreen()) { CParticle::AddParticle(PARTICLE_TEST, pos, @@ -1102,10 +1116,7 @@ CPed::ClearLookFlag(void) { bool CPed::IsPedHeadAbovePos(float zOffset) { - RwMatrix mat; - - CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &mat); - return zOffset + GetPosition().z < RwMatrixGetPos(&mat)->z; + return zOffset + GetPosition().z < GetNodePosition(PED_HEAD).z; } void @@ -1158,7 +1169,6 @@ CPed::Attack(void) CAnimBlendAssociation *weaponAnimAssoc; int32 weaponAnim; float animStart; - RwFrame *frame; eWeaponType ourWeaponType; float weaponAnimTime; eWeaponFire ourWeaponFire; @@ -1260,13 +1270,7 @@ CPed::Attack(void) firePos = GetMatrix() * firePos; } else if (ourWeaponType != WEAPONTYPE_UNARMED) { - if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR) - frame = GetNodeFrame(PED_FOOTR); - else - frame = GetNodeFrame(PED_HANDR); - - for (; frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); + TransformToNode(firePos, weaponAnimAssoc->animId == ANIM_KICK_FLOOR ? PED_FOOTR : PED_HANDR); } else { firePos = GetMatrix() * firePos; } @@ -1314,8 +1318,7 @@ CPed::Attack(void) firePos = ourWeapon->m_vecFireOffset; if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { - for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); + TransformToNode(firePos, PED_HANDR); CVector gunshellPos( firePos.x - 0.6f * GetForward().x, @@ -1415,7 +1418,17 @@ void CPed::RemoveWeaponModel(int modelId) { // modelId is not used!! This function just removes the current weapon. - RwFrameForAllObjects(GetNodeFrame(PED_HANDR),RemoveAllModelCB,nil); +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + if(m_pWeaponModel){ + RwFrame *frm = RpAtomicGetFrame(m_pWeaponModel); + RpAtomicDestroy(m_pWeaponModel); + RwFrameDestroy(frm); + m_pWeaponModel = nil; + } + }else +#endif + RwFrameForAllObjects(m_pFrames[PED_HANDR]->frame,RemoveAllModelCB,nil); m_wepModelID = -1; } @@ -2106,12 +2119,7 @@ CPed::PlayFootSteps(void) { { CVector pos(0.0f, 0.0f, 0.0f); - RwFrame *parent = m_pFrames[PED_FOOTL]->frame; - while( parent ) - { - RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(parent)); - parent = RwFrameGetParent(parent); - } + TransformToNode(pos, PED_FOOTL); pos.z -= 0.1f; pos += GetForward()*0.2f; @@ -2120,12 +2128,7 @@ CPed::PlayFootSteps(void) { CVector pos(0.0f, 0.0f, 0.0f); - RwFrame *parent = m_pFrames[PED_FOOTR]->frame; - while( parent ) - { - RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(parent)); - parent = RwFrameGetParent(parent); - } + TransformToNode(pos, PED_FOOTR); pos.z -= 0.1f; pos += GetForward()*0.2f; @@ -2149,9 +2152,7 @@ CPed::PlayFootSteps(void) if (stepPart != 0) { DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); CVector footPos(0.0f, 0.0f, 0.0f); - - for (RwFrame *frame = GetNodeFrame(stepPart == 1 ? PED_FOOTL : PED_FOOTR); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints(footPos, footPos, 1, RwFrameGetMatrix(frame)); + TransformToNode(footPos, stepPart == 1 ? PED_FOOTL : PED_FOOTR); CVector forward = GetForward(); @@ -2358,6 +2359,11 @@ CPed::SetModelIndex(uint32 mi) // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; + +#ifdef PED_SKIN + if(modelInfo->GetHitColModel() == nil) + modelInfo->CreateHitColModelSkinned(GetClump()); +#endif } void @@ -2517,9 +2523,31 @@ CPed::CalculateNewVelocity(void) } if (newUpperLegs.phi > -DEGTORAD(50.0f) && newUpperLegs.phi < DEGTORAD(50.0f)) { - newUpperLegs.theta = 0.0f; - m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); - m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ +/* + // this looks shit + newUpperLegs.theta = 0.0f; + RwV3d axis = { -1.0f, 0.0f, 0.0f }; + RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &axis, RADTODEG(newUpperLegs.phi), rwCOMBINEPRECONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &axis, RADTODEG(newUpperLegs.phi), rwCOMBINEPRECONCAT); +*/ + newUpperLegs.theta = 0.1f; + RwV3d Xaxis = { 1.0f, 0.0f, 0.0f }; + RwV3d Zaxis = { 0.0f, 0.0f, 1.0f }; + RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &Zaxis, RADTODEG(newUpperLegs.theta), rwCOMBINEPOSTCONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &Xaxis, RADTODEG(newUpperLegs.phi), rwCOMBINEPOSTCONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &Zaxis, RADTODEG(newUpperLegs.theta), rwCOMBINEPOSTCONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &Xaxis, RADTODEG(newUpperLegs.phi), rwCOMBINEPOSTCONCAT); + + bDontAcceptIKLookAts = true; + }else +#endif + { + newUpperLegs.theta = 0.0f; + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); + } } } } @@ -5118,6 +5146,12 @@ CPed::FightStrike(CVector &touchedNodePos) // He can beat us if (sq(maxDistanceToBeBeaten) > potentialAttackDistance.MagnitudeSqr()) { +#ifdef PED_SKIN + // Have to animate a skinned clump because the initial col model is useless + if(IsClumpSkinned(GetClump())) + ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->AnimatePedColModelSkinned(GetClump()); + else +#endif if (nearPed->m_nPedState == PED_FALL || nearPed->m_nPedState == PED_DEAD || nearPed->m_nPedState == PED_DIE || !nearPed->IsPedHeadAbovePos(-0.3f)) { @@ -6153,11 +6187,9 @@ CPed::Die(void) uint8 CPed::DoesLOSBulletHitPed(CColPoint &colPoint) { - RwMatrix mat; uint8 retVal = 2; - CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &mat); - float headZ = RwMatrixGetPos(&mat)->z; + float headZ = GetNodePosition(PED_HEAD).z; if (m_nPedState == PED_FALL) retVal = 1; @@ -6579,37 +6611,32 @@ CPed::Fight(void) if (curMove.hitLevel != HITLEVEL_NULL && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightState >= FIGHTSTATE_NO_MOVE) { CVector touchingNodePos(0.0f, 0.0f, 0.0f); - RwFrame *touchingFrame = nil; switch (m_lastFightMove) { case FIGHTMOVE_STDPUNCH: case FIGHTMOVE_PUNCHHOOK: case FIGHTMOVE_BODYBLOW: - touchingFrame = GetNodeFrame(PED_HANDR); + TransformToNode(touchingNodePos, PED_HANDR); break; case FIGHTMOVE_IDLE: case FIGHTMOVE_SHUFFLE_F: break; case FIGHTMOVE_KNEE: - touchingFrame = GetNodeFrame(PED_LOWERLEGR); + TransformToNode(touchingNodePos, PED_LOWERLEGR); break; case FIGHTMOVE_HEADBUTT: - touchingFrame = GetNodeFrame(PED_HEAD); + TransformToNode(touchingNodePos, PED_HEAD); break; case FIGHTMOVE_PUNCHJAB: - touchingFrame = GetNodeFrame(PED_HANDL); + TransformToNode(touchingNodePos, PED_HANDL); break; case FIGHTMOVE_KICK: case FIGHTMOVE_LONGKICK: case FIGHTMOVE_ROUNDHOUSE: case FIGHTMOVE_GROUNDKICK: - touchingFrame = GetNodeFrame(PED_FOOTR); + TransformToNode(touchingNodePos, PED_FOOTR); break; } - while (touchingFrame) { - RwV3dTransformPoints(touchingNodePos, touchingNodePos, 1, RwFrameGetMatrix(touchingFrame)); - touchingFrame = RwFrameGetParent(touchingFrame); - } if (m_lastFightMove == FIGHTMOVE_PUNCHJAB) { touchingNodePos += 0.1f * GetForward(); @@ -7091,8 +7118,7 @@ CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) if (ped->bDoBloodyFootprints) { CVector bloodPos(0.0f, 0.0f, 0.0f); - for (RwFrame *i = ped->GetNodeFrame(PED_FOOTL); i; i = RwFrameGetParent(i)) - RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(i)); + ped->TransformToNode(bloodPos, PED_FOOTL); bloodPos.z -= 0.1f; bloodPos += 0.2f * ped->GetForward(); @@ -7105,8 +7131,7 @@ CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) 255, 255, 0, 0, 4.0f, 3000, 1.0f); bloodPos = CVector(0.0f, 0.0f, 0.0f); - for (RwFrame *j = ped->GetNodeFrame(PED_FOOTR); j; j = RwFrameGetParent(j)) - RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(j)); + ped->TransformToNode(bloodPos, PED_FOOTR); bloodPos.z -= 0.1f; bloodPos += 0.2f * ped->GetForward(); @@ -12647,8 +12672,66 @@ CPed::Render(void) if (!bInVehicle || m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR || bRenderPedInCar && sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { CEntity::Render(); + +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + renderLimb(PED_HEAD); + renderLimb(PED_HANDL); + renderLimb(PED_HANDR); + } + if(m_pWeaponModel && IsClumpSkinned(GetClump())){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + RpAtomicRender(m_pWeaponModel); + } +#endif + } +} + +#ifdef PED_SKIN +static RpMaterial* +SetLimbAlphaCB(RpMaterial *material, void *data) +{ + ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; + return material; +} + +void +CPed::renderLimb(int node) +{ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + CPedModelInfo *mi = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); + RpAtomic *atomic; + switch(node){ + case PED_HEAD: + atomic = mi->getHead(); + break; + case PED_HANDL: + atomic = mi->getLeftHand(); + break; + case PED_HANDR: + atomic = mi->getRightHand(); + break; + default: + return; } + if(atomic == nil) + return; + + RwFrame *frame = RpAtomicGetFrame(atomic); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetLimbAlphaCB, &alpha); + RpAtomicRender(atomic); } +#endif void CPed::ProcessObjective(void) @@ -15065,12 +15148,26 @@ CPed::PreRender(void) CTimeCycle::m_fShadowFrontX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]); +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + UpdateRpHAnim(); + + if(bBodyPartJustCameOff && m_bodyPartBleeding == PED_HEAD){ + // scale head to 0 if shot off + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int32 idx = RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(PED_HEAD)); + RwMatrix *head = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwV3d zero = { 0.0f, 0.0f, 0.0f }; + RwMatrixScale(head, &zero, rwCOMBINEPRECONCAT); + } + } +#endif + if (bBodyPartJustCameOff && bIsPedDieAnimPlaying && m_bodyPartBleeding != -1 && (CTimer::GetFrameCounter() & 7) > 3) { CVector bloodDir(0.0f, 0.0f, 0.0f); CVector bloodPos(0.0f, 0.0f, 0.0f); - for (RwFrame *frame = GetNodeFrame(m_bodyPartBleeding); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(frame)); + TransformToNode(bloodPos, m_bodyPartBleeding); switch (m_bodyPartBleeding) { case PED_HEAD: @@ -16216,11 +16313,10 @@ CPed::StartFightDefend(uint8 direction, uint8 hitLevel, uint8 unk) } } if (CGame::nastyGame) { - RwMatrix headMat; - CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &headMat); + CVector headPos = GetNodePosition(PED_HEAD); for(int i = 0; i < 4; ++i) { CVector bloodDir(0.0f, 0.0f, 0.1f); - CVector bloodPos = headMat.pos - 0.2f * GetForward(); + CVector bloodPos = headPos - 0.2f * GetForward(); CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); } } @@ -16792,6 +16888,10 @@ CPed::SpawnFlyingComponent(int pedNode, int8 direction) if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) return nil; +#ifdef PED_SKIN + assert(!IsClumpSkinned(GetClump())); +#endif + CObject *obj = new CObject(); if (!obj) return nil; @@ -16799,12 +16899,12 @@ CPed::SpawnFlyingComponent(int pedNode, int8 direction) RwFrame *frame = RwFrameCreate(); RpClump *clump = RpClumpCreate(); RpClumpSetFrame(clump, frame); - RwMatrix *matrix = RwFrameGetLTM(GetNodeFrame(pedNode)); + RwMatrix *matrix = RwFrameGetLTM(m_pFrames[pedNode]->frame); *RwFrameGetMatrix(frame) = *matrix; flyingClumpTemp = clump; - RwFrameForAllObjects(GetNodeFrame(pedNode), CloneAtomicToFrameCB, frame); - RwFrameForAllChildren(GetNodeFrame(pedNode), RecurseFrameChildrenToCloneCB, frame); + RwFrameForAllObjects(m_pFrames[pedNode]->frame, CloneAtomicToFrameCB, frame); + RwFrameForAllChildren(m_pFrames[pedNode]->frame, RecurseFrameChildrenToCloneCB, frame); flyingClumpTemp = nil; switch (pedNode) { case PED_HEAD: diff --git a/src/peds/Ped.h b/src/peds/Ped.h index fd454528..f4caafd8 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -1,5 +1,6 @@ #pragma once +#include "RwHelper.h" #include "AnimManager.h" #include "Crime.h" #include "EventList.h" @@ -380,9 +381,11 @@ public: uint32 bFallenDown : 1; #ifdef VC_PED_PORTS uint32 bSomeVCflag1 : 1; -#else - uint32 m_ped_flagI20 : 1; #endif +#ifdef PED_SKIN + uint32 bDontAcceptIKLookAts : 1; // TODO: find uses of this +#endif + // our own flags uint32 m_ped_flagI40 : 1; // bMakePedsRunToPhonesToReportCrimes makes use of this as runover by car indicator uint32 m_ped_flagI80 : 1; // KANGAROO_CHEAT define makes use of this as cheat toggle @@ -401,6 +404,10 @@ public: CEntity* m_pEventEntity; float m_fAngleToEvent; AnimBlendFrameData *m_pFrames[PED_NODE_MAX]; +#ifdef PED_SKIN + // stored inside the clump with non-skin ped + RpAtomic *m_pWeaponModel; +#endif AssocGroupId m_animGroup; CAnimBlendAssociation *m_pVehicleAnim; CVector2D m_vecAnimMoveDelta; @@ -730,7 +737,6 @@ public: static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); - // functions that I see unnecessary to hook bool IsPlayer(void); bool UseGroundColModel(void); bool CanSetPedState(void); @@ -780,7 +786,6 @@ public: bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; } CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; } CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; } - RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; } PedState GetPedState(void) { return m_nPedState; } void SetPedState(PedState state) { m_nPedState = state; } @@ -815,6 +820,44 @@ public: SetMoveState(PEDMOVE_WALK); } + // Using this to abstract nodes of skinned and non-skinned meshes + CVector GetNodePosition(int32 node) + { +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + RwV3d pos = { 0.0f, 0.0f, 0.0f }; + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int32 idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); + RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier); + // this is just stupid + //RwV3dTransformPoints(&pos, &pos, 1, &mats[idx]); + pos = mats[idx].pos; + return pos; + }else +#endif + { + RwMatrix mat; + CPedIK::GetWorldMatrix(m_pFrames[node]->frame, &mat); + return mat.pos; + } + } + void TransformToNode(CVector &pos, int32 node) + { +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int32 idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); + RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier); + RwV3dTransformPoints((RwV3d*)&pos, (RwV3d*)&pos, 1, &mats[idx]); + }else +#endif + { + RwFrame *frame; + for (frame = m_pFrames[node]->frame; frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints((RwV3d*)&pos, (RwV3d*)&pos, 1, RwFrameGetMatrix(frame)); + } + } + // set by 0482:set_threat_reaction_range_multiplier opcode static uint16 nThreatReactionRangeMultiplier; @@ -836,6 +879,10 @@ public: static void SwitchDebugDisplay(void); void DebugRenderOnePedText(void); #endif + +#ifdef PED_SKIN + void renderLimb(int node); +#endif }; class cPedParams @@ -849,6 +896,7 @@ public: void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg); +#ifndef PED_SKIN static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error"); static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error"); static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error"); @@ -861,3 +909,4 @@ static_assert(offsetof(CPed, m_bodyPartBleeding) == 0x4F2, "CPed: error"); static_assert(offsetof(CPed, m_pedInObjective) == 0x16C, "CPed: error"); static_assert(offsetof(CPed, m_pEventEntity) == 0x19C, "CPed: error"); static_assert(sizeof(CPed) == 0x53C, "CPed: error"); +#endif diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp index 1464c4e8..3db3dc0f 100644 --- a/src/peds/PedIK.cpp +++ b/src/peds/PedIK.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "Bones.h" #include "Camera.h" #include "PedIK.h" #include "Ped.h" @@ -12,6 +13,10 @@ LimbMovementInfo CPedIK::ms_headRestoreInfo = { DEGTORAD(90.0f), DEGTORAD(-90.0f LimbMovementInfo CPedIK::ms_upperArmInfo = { DEGTORAD(20.0f), DEGTORAD(-100.0f), DEGTORAD(20.0f), DEGTORAD(70.0f), DEGTORAD(-70.0f), DEGTORAD(10.0f) }; LimbMovementInfo CPedIK::ms_lowerArmInfo = { DEGTORAD(80.0f), DEGTORAD(0.0f), DEGTORAD(20.0f), DEGTORAD(90.0f), DEGTORAD(-90.0f), DEGTORAD(5.0f) }; +const RwV3d XaxisIK = { 1.0f, 0.0f, 0.0f}; +const RwV3d YaxisIK = { 0.0f, 1.0f, 0.0f}; +const RwV3d ZaxisIK = { 0.0f, 0.0f, 1.0f}; + CPedIK::CPedIK(CPed *ped) { m_ped = ped; @@ -26,57 +31,104 @@ CPedIK::CPedIK(CPed *ped) m_lowerArmOrient.theta = 0.0f; } +#ifdef PED_SKIN +inline RwMatrix* +GetComponentMatrix(CPed *ped, int32 node) +{ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(ped->GetClump()); + int idx = RpHAnimIDGetIndex(hier, ped->m_pFrames[node]->nodeID); + RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier); + return &mats[idx]; +} +#endif + void -CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool changeRoll) +CPedIK::RotateTorso(AnimBlendFrameData *node, LimbOrientation *limb, bool changeRoll) { - RwFrame *f = animBlend->frame; - RwMatrix *mat = CPedIK::GetWorldMatrix(RwFrameGetParent(f), RwMatrixCreate()); - - RwV3d upVector = { mat->right.z, mat->up.z, mat->at.z }; - RwV3d rightVector; - RwV3d pos = RwFrameGetMatrix(f)->pos; - - // rotation == 0 -> looking in y direction - // left? vector - float c = Cos(m_ped->m_fRotationCur); - float s = Sin(m_ped->m_fRotationCur); - rightVector.x = -(c*mat->right.x + s*mat->right.y); - rightVector.y = -(c*mat->up.x + s*mat->up.y); - rightVector.z = -(c*mat->at.x + s*mat->at.y); - - if(changeRoll){ - // Used when aiming only involves over the legs.(canAimWithArm) - // Automatically changes roll(forward rotation) axis of the parts above upper legs while moving, based on position of upper legs. - // Not noticeable in normal conditions... - - RwV3d forwardVector; - CVector inversedForward = CrossProduct(CVector(0.0f, 0.0f, 1.0f), mat->up); - inversedForward.Normalise(); - float dotProduct = DotProduct(mat->at, inversedForward); - if(dotProduct > 1.0f) dotProduct = 1.0f; - if(dotProduct < -1.0f) dotProduct = -1.0f; - float alpha = Acos(dotProduct); - - if(mat->at.z < 0.0f) - alpha = -alpha; - - forwardVector.x = s * mat->right.x - c * mat->right.y; - forwardVector.y = s * mat->up.x - c * mat->up.y; - forwardVector.z = s * mat->at.x - c * mat->at.y; - - float curYaw, curPitch; - CPedIK::ExtractYawAndPitchWorld(mat, &curYaw, &curPitch); - RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); - RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi - (curYaw - m_ped->m_fRotationCur)), rwCOMBINEPOSTCONCAT); - RwMatrixRotate(RwFrameGetMatrix(f), &forwardVector, RADTODEG(alpha), rwCOMBINEPOSTCONCAT); - }else{ - // pitch - RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); - // yaw - RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi), rwCOMBINEPOSTCONCAT); +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + RtQuat *q = &node->hanimFrame->q; +#ifndef FIX_BUGS + // this is what the game does (also VC), but it does not look great + RtQuatRotate(q, &XaxisIK, RADTODEG(limb->phi), rwCOMBINEPRECONCAT); + RtQuatRotate(q, &ZaxisIK, RADTODEG(limb->theta), rwCOMBINEPRECONCAT); // pitch +#else + // copied the code from the non-skinned case + // this seems to work ok + + // We can't get the parent matrix of an hanim frame but + // this function is always called with PED_MID, so we know the parent frame. + // Trouble is that PED_MID is "Smid" on PS2/PC but BONE_torso on mobile/xbox... + // so this doesn't exactly do what we'd like anyway + RwMatrix *mat = GetComponentMatrix(m_ped, PED_MID); + + RwV3d vec1, vec2; + vec1.x = mat->right.z; + vec1.y = mat->up.z; + vec1.z = mat->at.z; + float c = Cos(m_ped->m_fRotationCur); + float s = Sin(m_ped->m_fRotationCur); + vec2.x = -(c*mat->right.x + s*mat->right.y); + vec2.y = -(c*mat->up.x + s*mat->up.y); + vec2.z = -(c*mat->at.x + s*mat->at.y); + + // Not sure what exactly to do here + RtQuatRotate(q, &vec1, RADTODEG(limb->phi), rwCOMBINEPRECONCAT); + RtQuatRotate(q, &vec2, RADTODEG(limb->theta), rwCOMBINEPRECONCAT); +#endif + m_ped->bDontAcceptIKLookAts = true; + }else +#endif + { + RwFrame *f = node->frame; + RwMatrix *mat = GetWorldMatrix(RwFrameGetParent(f), RwMatrixCreate()); + + RwV3d upVector = { mat->right.z, mat->up.z, mat->at.z }; + RwV3d rightVector; + RwV3d pos = RwFrameGetMatrix(f)->pos; + + // rotation == 0 -> looking in y direction + // left? vector + float c = Cos(m_ped->m_fRotationCur); + float s = Sin(m_ped->m_fRotationCur); + rightVector.x = -(c*mat->right.x + s*mat->right.y); + rightVector.y = -(c*mat->up.x + s*mat->up.y); + rightVector.z = -(c*mat->at.x + s*mat->at.y); + + if(changeRoll){ + // Used when aiming only involves over the legs.(canAimWithArm) + // Automatically changes roll(forward rotation) axis of the parts above upper legs while moving, based on position of upper legs. + // Not noticeable in normal conditions... + + RwV3d forwardVector; + CVector inversedForward = CrossProduct(CVector(0.0f, 0.0f, 1.0f), mat->up); + inversedForward.Normalise(); + float dotProduct = DotProduct(mat->at, inversedForward); + if(dotProduct > 1.0f) dotProduct = 1.0f; + if(dotProduct < -1.0f) dotProduct = -1.0f; + float alpha = Acos(dotProduct); + + if(mat->at.z < 0.0f) + alpha = -alpha; + + forwardVector.x = s * mat->right.x - c * mat->right.y; + forwardVector.y = s * mat->up.x - c * mat->up.y; + forwardVector.z = s * mat->at.x - c * mat->at.y; + + float curYaw, curPitch; + ExtractYawAndPitchWorld(mat, &curYaw, &curPitch); + RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi - (curYaw - m_ped->m_fRotationCur)), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(f), &forwardVector, RADTODEG(alpha), rwCOMBINEPOSTCONCAT); + }else{ + // pitch + RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); + // yaw + RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi), rwCOMBINEPOSTCONCAT); + } + RwFrameGetMatrix(f)->pos = pos; + RwMatrixDestroy(mat); } - RwFrameGetMatrix(f)->pos = pos; - RwMatrixDestroy(mat); } void @@ -85,12 +137,24 @@ CPedIK::GetComponentPosition(RwV3d *pos, uint32 node) RwFrame *f; RwMatrix *mat; - f = m_ped->GetNodeFrame(node); - mat = RwFrameGetMatrix(f); - *pos = mat->pos; - - for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) - RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(f)); +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + pos->x = 0.0f; + pos->y = 0.0f; + pos->z = 0.0f; + mat = GetComponentMatrix(m_ped, node); + // could just copy the position out of the matrix... + RwV3dTransformPoints(pos, pos, 1, mat); + }else +#endif + { + f = m_ped->m_pFrames[node]->frame; + mat = RwFrameGetMatrix(f); + *pos = mat->pos; + + for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) + RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(f)); + } } RwMatrix* @@ -157,50 +221,94 @@ CPedIK::RestoreGunPosn(void) return limbStatus == ANGLES_SET_EXACTLY; } +#ifdef PED_SKIN +void +CPedIK::RotateHead(void) +{ + RtQuat *q = &m_ped->m_pFrames[PED_HEAD]->hanimFrame->q; + RtQuatRotate(q, &XaxisIK, RADTODEG(m_headOrient.phi), rwCOMBINEREPLACE); + RtQuatRotate(q, &ZaxisIK, RADTODEG(m_headOrient.theta), rwCOMBINEPOSTCONCAT); + m_ped->bDontAcceptIKLookAts = true; +} +#endif + bool CPedIK::LookInDirection(float phi, float theta) { bool success = true; - RwFrame *frame = m_ped->GetNodeFrame(PED_HEAD); - RwMatrix *frameMat = RwFrameGetMatrix(frame); + float yaw, pitch; +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + if (!(m_ped->m_pFrames[PED_HEAD]->flag & AnimBlendFrameData::IGNORE_ROTATION)) { + m_ped->m_pFrames[PED_HEAD]->flag |= AnimBlendFrameData::IGNORE_ROTATION; + ExtractYawAndPitchLocalSkinned(m_ped->m_pFrames[PED_HEAD], &m_headOrient.phi, &m_headOrient.theta); + } - if (!(m_ped->m_pFrames[PED_HEAD]->flag & AnimBlendFrameData::IGNORE_ROTATION)) { - m_ped->m_pFrames[PED_HEAD]->flag |= AnimBlendFrameData::IGNORE_ROTATION; - CPedIK::ExtractYawAndPitchLocal(frameMat, &m_headOrient.phi, &m_headOrient.theta); - } + // parent of head is torso + RwMatrix worldMat = *GetComponentMatrix(m_ped, BONE_torso); + ExtractYawAndPitchWorld(&worldMat, &yaw, &pitch); + + LimbMoveStatus headStatus = MoveLimb(m_headOrient, CGeneral::LimitRadianAngle(phi - yaw), + CGeneral::LimitRadianAngle(DEGTORAD(10.0f)), ms_headInfo); + if (headStatus == ANGLES_SET_TO_MAX) + success = false; + + if (headStatus != ANGLES_SET_EXACTLY){ + if (!(m_flags & LOOKAROUND_HEAD_ONLY)){ + if (MoveLimb(m_torsoOrient, CGeneral::LimitRadianAngle(phi), theta, ms_torsoInfo)) + success = true; + }else{ + RotateHead(); + return success; + } + } - RwMatrix *worldMat = RwMatrixCreate(); - worldMat = CPedIK::GetWorldMatrix(RwFrameGetParent(frame), worldMat); + if (!(m_flags & LOOKAROUND_HEAD_ONLY)) + RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + RotateHead(); + }else +#endif + { + RwFrame *frame = m_ped->m_pFrames[PED_HEAD]->frame; + RwMatrix *frameMat = RwFrameGetMatrix(frame); + + if (!(m_ped->m_pFrames[PED_HEAD]->flag & AnimBlendFrameData::IGNORE_ROTATION)) { + m_ped->m_pFrames[PED_HEAD]->flag |= AnimBlendFrameData::IGNORE_ROTATION; + ExtractYawAndPitchLocal(frameMat, &m_headOrient.phi, &m_headOrient.theta); + } - float alpha, beta; - CPedIK::ExtractYawAndPitchWorld(worldMat, &alpha, &beta); - RwMatrixDestroy(worldMat); + RwMatrix *worldMat = RwMatrixCreate(); + worldMat = GetWorldMatrix(RwFrameGetParent(frame), worldMat); - alpha += m_torsoOrient.phi; - float neededPhiTurn = CGeneral::LimitRadianAngle(phi - alpha); - beta *= cos(neededPhiTurn); + ExtractYawAndPitchWorld(worldMat, &yaw, &pitch); + RwMatrixDestroy(worldMat); - float neededThetaTurn = CGeneral::LimitRadianAngle(theta - beta); - LimbMoveStatus headStatus = CPedIK::MoveLimb(m_headOrient, neededPhiTurn, neededThetaTurn, ms_headInfo); - if (headStatus == ANGLES_SET_TO_MAX) - success = false; + yaw += m_torsoOrient.phi; + float neededPhiTurn = CGeneral::LimitRadianAngle(phi - yaw); + pitch *= Cos(neededPhiTurn); - if (headStatus != ANGLES_SET_EXACTLY && !(m_flags & LOOKAROUND_HEAD_ONLY)) { - float remainingTurn = CGeneral::LimitRadianAngle(phi - m_ped->m_fRotationCur); - if (CPedIK::MoveLimb(m_torsoOrient, remainingTurn, theta, ms_torsoInfo)) - success = true; - } - CMatrix nextFrame = CMatrix(frameMat); - CVector framePos = nextFrame.GetPosition(); + float neededThetaTurn = CGeneral::LimitRadianAngle(theta - pitch); + LimbMoveStatus headStatus = MoveLimb(m_headOrient, neededPhiTurn, neededThetaTurn, ms_headInfo); + if (headStatus == ANGLES_SET_TO_MAX) + success = false; - nextFrame.SetRotateZ(m_headOrient.theta); - nextFrame.RotateX(m_headOrient.phi); - nextFrame.GetPosition() += framePos; - nextFrame.UpdateRW(); + if (headStatus != ANGLES_SET_EXACTLY && !(m_flags & LOOKAROUND_HEAD_ONLY)) { + float remainingTurn = CGeneral::LimitRadianAngle(phi - m_ped->m_fRotationCur); + if (MoveLimb(m_torsoOrient, remainingTurn, theta, ms_torsoInfo)) + success = true; + } + CMatrix nextFrame = CMatrix(frameMat); + CVector framePos = nextFrame.GetPosition(); - if (!(m_flags & LOOKAROUND_HEAD_ONLY)) - RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + nextFrame.SetRotateZ(m_headOrient.theta); + nextFrame.RotateX(m_headOrient.phi); + nextFrame.GetPosition() += framePos; + nextFrame.UpdateRW(); + + if (!(m_flags & LOOKAROUND_HEAD_ONLY)) + RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + } return success; } @@ -234,10 +342,24 @@ CPedIK::PointGunInDirection(float phi, float theta) if (m_flags & AIMS_WITH_ARM && m_torsoOrient.phi * m_upperArmOrient.phi < 0.0f) MoveLimb(m_torsoOrient, 0.0f, m_torsoOrient.theta, ms_torsoInfo); } else { - RwMatrix *matrix = GetWorldMatrix(RwFrameGetParent(m_ped->GetNodeFrame(PED_UPPERARMR)), RwMatrixCreate()); + // Unused code + RwMatrix *matrix; float yaw, pitch; - ExtractYawAndPitchWorld(matrix, &yaw, &pitch); - RwMatrixDestroy(matrix); +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + matrix = RwMatrixCreate(); + *matrix = *GetComponentMatrix(m_ped, PED_UPPERARMR); + ExtractYawAndPitchWorld(matrix, &yaw, &pitch); + RwMatrixDestroy(matrix); + }else +#endif + { + matrix = GetWorldMatrix(RwFrameGetParent(m_ped->m_pFrames[PED_UPPERARMR]->frame), RwMatrixCreate()); + ExtractYawAndPitchWorld(matrix, &yaw, &pitch); + RwMatrixDestroy(matrix); + } + // + LimbMoveStatus status = MoveLimb(m_torsoOrient, angle, theta, ms_torsoInfo); if (status == ANGLES_SET_TO_MAX) result = false; @@ -255,24 +377,56 @@ bool CPedIK::PointGunInDirectionUsingArm(float phi, float theta) { bool result = false; - RwFrame *frame = m_ped->GetNodeFrame(PED_UPPERARMR); - RwMatrix *matrix = GetWorldMatrix(RwFrameGetParent(frame), RwMatrixCreate()); - - RwV3d upVector = { matrix->right.z, matrix->up.z, matrix->at.z }; + RwV3d upVector; // only for non-skinned + RwMatrix *matrix; float yaw, pitch; - ExtractYawAndPitchWorld(matrix, &yaw, &pitch); - RwMatrixDestroy(matrix); +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + matrix = RwMatrixCreate(); + *matrix = *GetComponentMatrix(m_ped, PED_UPPERARMR); + ExtractYawAndPitchWorld(matrix, &yaw, &pitch); + RwMatrixDestroy(matrix); + }else +#endif + { + RwFrame *frame = m_ped->m_pFrames[PED_UPPERARMR]->frame; + matrix = GetWorldMatrix(RwFrameGetParent(frame), RwMatrixCreate()); + + // with PED_SKIN this is actually done below (with a memory leak) + upVector.x = matrix->right.z; + upVector.y = matrix->up.z; + upVector.z = matrix->at.z; + + ExtractYawAndPitchWorld(matrix, &yaw, &pitch); + RwMatrixDestroy(matrix); + } RwV3d rightVector = { 0.0f, 0.0f, 1.0f }; RwV3d forwardVector = { 1.0f, 0.0f, 0.0f }; - float uaPhi = phi - m_torsoOrient.phi - DEGTORAD(15.0f); - LimbMoveStatus uaStatus = MoveLimb(m_upperArmOrient, uaPhi, CGeneral::LimitRadianAngle(theta - pitch), ms_upperArmInfo); + float uaPhi, uaTheta; +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + uaPhi = phi; + uaTheta = theta + DEGTORAD(10.0f); + }else +#endif + { + uaPhi = phi - m_torsoOrient.phi - DEGTORAD(15.0f); + uaTheta = CGeneral::LimitRadianAngle(theta - pitch); + } + LimbMoveStatus uaStatus = MoveLimb(m_upperArmOrient, uaPhi, uaTheta, ms_upperArmInfo); if (uaStatus == ANGLES_SET_EXACTLY) { m_flags |= GUN_POINTED_SUCCESSFULLY; result = true; } + +#ifdef PED_SKIN + // this code is completely missing on xbox & android, but we can keep it with the check + // TODO? implement it for skinned geometry? + if(!IsClumpSkinned(m_ped->GetClump())) +#endif if (uaStatus == ANGLES_SET_TO_MAX) { float laPhi = uaPhi - m_upperArmOrient.phi; @@ -286,17 +440,29 @@ CPedIK::PointGunInDirectionUsingArm(float phi, float theta) m_flags |= GUN_POINTED_SUCCESSFULLY; result = true; } - RwFrame *child = GetFirstChild(frame); + RwFrame *child = GetFirstChild(m_ped->m_pFrames[PED_UPPERARMR]->frame); RwV3d pos = RwFrameGetMatrix(child)->pos; RwMatrixRotate(RwFrameGetMatrix(child), &forwardVector, RADTODEG(m_lowerArmOrient.theta), rwCOMBINEPOSTCONCAT); RwMatrixRotate(RwFrameGetMatrix(child), &rightVector, RADTODEG(-m_lowerArmOrient.phi), rwCOMBINEPOSTCONCAT); RwFrameGetMatrix(child)->pos = pos; } - RwV3d pos = RwFrameGetMatrix(frame)->pos; - RwMatrixRotate(RwFrameGetMatrix(frame), &rightVector, RADTODEG(m_upperArmOrient.theta), rwCOMBINEPOSTCONCAT); - RwMatrixRotate(RwFrameGetMatrix(frame), &upVector, RADTODEG(m_upperArmOrient.phi), rwCOMBINEPOSTCONCAT); - RwFrameGetMatrix(frame)->pos = pos; +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + RtQuat *q = &m_ped->m_pFrames[PED_UPPERARMR]->hanimFrame->q; + RtQuatRotate(q, &XaxisIK, RADTODEG(m_upperArmOrient.phi), rwCOMBINEPOSTCONCAT); + RtQuatRotate(q, &ZaxisIK, RADTODEG(m_upperArmOrient.theta), rwCOMBINEPOSTCONCAT); + m_ped->bDontAcceptIKLookAts = true; + }else +#endif + { + RwFrame *frame = m_ped->m_pFrames[PED_UPPERARMR]->frame; + // with PED_SKIN we're also getting upVector here + RwV3d pos = RwFrameGetMatrix(frame)->pos; + RwMatrixRotate(RwFrameGetMatrix(frame), &rightVector, RADTODEG(m_upperArmOrient.theta), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(frame), &upVector, RADTODEG(m_upperArmOrient.phi), rwCOMBINEPOSTCONCAT); + RwFrameGetMatrix(frame)->pos = pos; + } return result; } @@ -314,28 +480,42 @@ bool CPedIK::RestoreLookAt(void) { bool result = false; - RwMatrix *mat = RwFrameGetMatrix(m_ped->GetNodeFrame(PED_HEAD)); - if (m_ped->m_pFrames[PED_HEAD]->flag & AnimBlendFrameData::IGNORE_ROTATION) { - m_ped->m_pFrames[PED_HEAD]->flag &= (~AnimBlendFrameData::IGNORE_ROTATION); - } else { - float yaw, pitch; - ExtractYawAndPitchLocal(mat, &yaw, &pitch); - if (MoveLimb(m_headOrient, yaw, pitch, ms_headRestoreInfo) == ANGLES_SET_EXACTLY) - result = true; - } + float yaw, pitch; - CMatrix matrix(mat); - CVector pos = matrix.GetPosition(); - matrix.SetRotateZ(m_headOrient.theta); - matrix.RotateX(m_headOrient.phi); - matrix.Translate(pos); - matrix.UpdateRW(); +#ifdef PED_SKIN + if(IsClumpSkinned(m_ped->GetClump())){ + if (m_ped->m_pFrames[PED_HEAD]->flag & AnimBlendFrameData::IGNORE_ROTATION) { + m_ped->m_pFrames[PED_HEAD]->flag &= (~AnimBlendFrameData::IGNORE_ROTATION); + } else { + ExtractYawAndPitchLocalSkinned(m_ped->m_pFrames[PED_HEAD], &yaw, &pitch); + if (MoveLimb(m_headOrient, yaw, pitch, ms_headRestoreInfo) == ANGLES_SET_EXACTLY) + result = true; + } + RotateHead(); + }else +#endif + { + RwMatrix *mat = RwFrameGetMatrix(m_ped->m_pFrames[PED_HEAD]->frame); + if (m_ped->m_pFrames[PED_HEAD]->flag & AnimBlendFrameData::IGNORE_ROTATION) { + m_ped->m_pFrames[PED_HEAD]->flag &= (~AnimBlendFrameData::IGNORE_ROTATION); + } else { + ExtractYawAndPitchLocal(mat, &yaw, &pitch); + if (MoveLimb(m_headOrient, yaw, pitch, ms_headRestoreInfo) == ANGLES_SET_EXACTLY) + result = true; + } - if (!(m_flags & LOOKAROUND_HEAD_ONLY)) + CMatrix matrix(mat); + CVector pos = matrix.GetPosition(); + matrix.SetRotateZ(m_headOrient.theta); + matrix.RotateX(m_headOrient.phi); + matrix.Translate(pos); + matrix.UpdateRW(); + } + if (!(m_flags & LOOKAROUND_HEAD_ONLY)){ MoveLimb(m_torsoOrient, 0.0f, 0.0f, ms_torsoInfo); - if (!(m_flags & LOOKAROUND_HEAD_ONLY)) - RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); - + if (!(m_flags & LOOKAROUND_HEAD_ONLY)) + RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + } return result; } @@ -362,3 +542,14 @@ CPedIK::ExtractYawAndPitchLocal(RwMatrix *mat, float *yaw, float *pitch) *pitch = Acos(f); if (mat->up.x > 0.0f) *pitch = -*pitch; } + +#ifdef PED_SKIN +void +CPedIK::ExtractYawAndPitchLocalSkinned(AnimBlendFrameData *node, float *yaw, float *pitch) +{ + RwMatrix *mat = RwMatrixCreate(); + RtQuatConvertToMatrix(&node->hanimFrame->q, mat); + ExtractYawAndPitchLocal(mat, yaw, pitch); + RwMatrixDestroy(mat); +} +#endif diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h index 7b82d1ac..fd9e4702 100644 --- a/src/peds/PedIK.h +++ b/src/peds/PedIK.h @@ -55,9 +55,11 @@ public: static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination); void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); void ExtractYawAndPitchLocal(RwMatrix *mat, float *yaw, float *pitch); + void ExtractYawAndPitchLocalSkinned(AnimBlendFrameData *node, float *yaw, float *pitch); void ExtractYawAndPitchWorld(RwMatrix *mat, float *yaw, float *pitch); LimbMoveStatus MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo); bool RestoreGunPosn(void); + void RotateHead(void); bool LookInDirection(float phi, float theta); bool LookAtPosition(CVector const& pos); bool RestoreLookAt(void); diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 0163c12c..664fff18 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "RwHelper.h" #include "PlayerPed.h" #include "Wanted.h" #include "Fire.h" @@ -1497,4 +1498,9 @@ CPlayerPed::ProcessControl(void) m_nSpeedTimer = 0; m_bSpeedTimerFlag = false; } + +#ifdef PED_SKIN + if (!bIsVisible && IsClumpSkinned(GetClump())) + UpdateRpHAnim(); +#endif } diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h index 81f8e4d7..b8bd57e4 100644 --- a/src/peds/PlayerPed.h +++ b/src/peds/PlayerPed.h @@ -77,4 +77,6 @@ public: static void ReactivatePlayerPed(int32); }; +#ifndef PED_SKIN static_assert(sizeof(CPlayerPed) == 0x5F0, "CPlayerPed: error"); +#endif diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 16057420..fc081fa3 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -117,8 +117,14 @@ CSpecialFX::Update(void) if(FindPlayerPed() && FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && - FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING) - RwFrameForAllObjects(FindPlayerPed()->GetNodeFrame(PED_HANDR), LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT)); + FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING){ +#ifdef PED_SKIN + if(IsClumpSkinned(FindPlayerPed()->GetClump())){ + LookForBatCB((RwObject*)FindPlayerPed()->m_pWeaponModel, CModelInfo::GetModelInfo(MI_BASEBALL_BAT)); + }else +#endif + RwFrameForAllObjects(FindPlayerPed()->m_pFrames[PED_HANDR]->frame, LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT)); + } } void diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index acf811ad..5aa4475f 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -3,16 +3,15 @@ #include "Timecycle.h" #include "skeleton.h" -#if defined(RWLIBS) && !defined(FINAL) +#include "Debug.h" +#ifndef FINAL #include "rtcharse.h" -#pragma comment( lib, "rtcharse.lib" ) - RtCharset *debugCharset; #endif void CreateDebugFont() { -#if defined(RWLIBS) && !defined(FINAL) +#ifndef FINAL RwRGBA color = { 255, 255, 128, 255 }; RwRGBA colorbg = { 0, 0, 0, 0 }; RtCharsetOpen(); @@ -22,7 +21,7 @@ void CreateDebugFont() void DestroyDebugFont() { -#if defined(RWLIBS) && !defined(FINAL) +#ifndef FINAL RtCharsetDestroy(debugCharset); RtCharsetClose(); #endif @@ -30,14 +29,14 @@ void DestroyDebugFont() void ObrsPrintfString(const char *str, short x, short y) { -#if defined(RWLIBS) && !defined(FINAL) - RtCharsetPrintBuffered(debugCharset, str, x, y, true); +#ifndef FINAL + RtCharsetPrintBuffered(debugCharset, str, x*8, y*16, true); #endif } void FlushObrsPrintfs() { -#if defined(RWLIBS) && !defined(FINAL) +#ifndef FINAL RtCharsetBufferFlush(); #endif } @@ -168,6 +167,170 @@ GetFirstTexture(RwTexDictionary *txd) return tex; } +#ifdef PED_SKIN +static RpAtomic* +isSkinnedCb(RpAtomic *atomic, void *data) +{ + RpAtomic **pAtomic = (RpAtomic**)data; + if(*pAtomic) + return nil; // already found one + if(RpSkinGeometryGetSkin(atomic->geometry)) + *pAtomic = atomic; // we could just return nil here directly... + return atomic; +} + +RpAtomic* +IsClumpSkinned(RpClump *clump) +{ + RpAtomic *atomic = nil; + RpClumpForAllAtomics(clump, isSkinnedCb, &atomic); + return atomic; +} + +static RpAtomic* +GetAnimHierarchyCallback(RpAtomic *atomic, void *data) +{ + *(RpHAnimHierarchy**)data = RpSkinAtomicGetHAnimHierarchy(atomic); + return nil; +} + +RpHAnimHierarchy* +GetAnimHierarchyFromSkinClump(RpClump *clump) +{ + RpHAnimHierarchy *hier = nil; + RpClumpForAllAtomics(clump, GetAnimHierarchyCallback, &hier); + return hier; +} + +static RwFrame* +GetAnimHierarchyFromClumpCB(RwFrame *frame, void *data) +{ + RpHAnimHierarchy *hier = RpHAnimFrameGetHierarchy(frame); + if(hier){ + *(RpHAnimHierarchy**)data = hier; + return nil; + } + RwFrameForAllChildren(frame, GetAnimHierarchyFromClumpCB, data); + return frame; +} + +RpHAnimHierarchy* +GetAnimHierarchyFromClump(RpClump *clump) +{ + RpHAnimHierarchy *hier = nil; + RwFrameForAllChildren(RpClumpGetFrame(clump), GetAnimHierarchyFromClumpCB, &hier); + return hier; +} + +RwFrame* +GetHierarchyFromChildNodesCB(RwFrame *frame, void *data) +{ + RpHAnimHierarchy **pHier = (RpHAnimHierarchy**)data; + RpHAnimHierarchy *hier = RpHAnimFrameGetHierarchy(frame); + if(hier == nil) + RwFrameForAllChildren(frame, GetHierarchyFromChildNodesCB, &hier); + *pHier = hier; + return nil; +} + +void +SkinGetBonePositionsToTable(RpClump *clump, RwV3d *boneTable) +{ + int i, parent; + RpAtomic *atomic; + RpSkin *skin; + RpHAnimHierarchy *hier; + int numBones; + RwMatrix m, invmat; + int stack[32]; + int sp; + + if(boneTable == nil) + return; + +// atomic = GetFirstAtomic(clump); // mobile, also VC + atomic = IsClumpSkinned(clump); // xbox, seems safer + assert(atomic); + skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)); + assert(skin); + hier = GetAnimHierarchyFromSkinClump(clump); + assert(hier); + boneTable[0].x = 0.0f; + boneTable[0].y = 0.0f; + boneTable[0].z = 0.0f; + numBones = RpSkinGetNumBones(skin); + parent = 0; + sp = 0; +#ifdef FIX_BUGS + stack[0] = 0; // i think this is ok +#endif + for(i = 1; i < numBones; i++){ + RwMatrixCopy(&m, &RpSkinGetSkinToBoneMatrices(skin)[i]); + RwMatrixInvert(&invmat, &m); + const RwMatrix *x = RpSkinGetSkinToBoneMatrices(skin); + RwV3dTransformPoints(&boneTable[i], &invmat.pos, 1, &x[parent]); + if(HIERNODEINFO(hier)[i].flags & rpHANIMPUSHPARENTMATRIX) + stack[++sp] = parent; + if(HIERNODEINFO(hier)[i].flags & rpHANIMPOPPARENTMATRIX) + parent = stack[sp--]; + else + parent = i; + assert(parent >= 0 && parent < numBones); + } +} + +RpHAnimAnimation* +HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier) +{ + int i; +#ifdef FIX_BUGS + int numNodes = hier->numNodes*2; // you're supposed to have at least two KFs per node +#else + int numNodes = hier->numNodes; +#endif + RpHAnimAnimation *anim = RpHAnimAnimationCreate(rpHANIMSTDKEYFRAMETYPEID, numNodes, 0, 0.0f); + if(anim == nil) + return nil; + RpHAnimStdKeyFrame *frame = (RpHAnimStdKeyFrame*)HANIMFRAMES(anim); + for(i = 0; i < numNodes; i++){ + frame->q.real = 1.0f; + frame->q.imag.x = frame->q.imag.y = frame->q.imag.z = 0.0f; + frame->t.x = frame->t.y = frame->t.z = 0.0f; + frame->time = 0.0f; + frame->prevFrame = nil; + frame++; + } + return anim; +} + +void +RenderSkeleton(RpHAnimHierarchy *hier) +{ + int i; + int sp; + int stack[32]; + int par; + CVector p1, p2; + int numNodes = hier->numNodes; + RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier); + p1 = mats[0].pos; + + par = 0; + sp = 0; + stack[sp++] = par; + for(i = 1; i < numNodes; i++){ + p1 = mats[par].pos; + p2 = mats[i].pos; + CDebug::AddLine(p1, p2, 0xFFFFFFFF, 0xFFFFFFFF); + if(HIERNODEINFO(hier)[i].flags & rpHANIMPUSHPARENTMATRIX) + stack[sp++] = par; + par = i; + if(HIERNODEINFO(hier)[i].flags & rpHANIMPOPPARENTMATRIX) + par = stack[--sp]; + } +} +#endif + void CameraSize(RwCamera * camera, RwRect * rect, RwReal viewWindow, RwReal aspectRatio) diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h index 5b47cb6f..9f178ec2 100644 --- a/src/rw/RwHelper.h +++ b/src/rw/RwHelper.h @@ -13,6 +13,15 @@ RwObject *GetFirstObject(RwFrame *frame); RpAtomic *GetFirstAtomic(RpClump *clump); RwTexture *GetFirstTexture(RwTexDictionary *txd); +#ifdef PED_SKIN +RpAtomic *IsClumpSkinned(RpClump *clump); +RpHAnimHierarchy *GetAnimHierarchyFromSkinClump(RpClump *clump); // get from atomic +RpHAnimHierarchy *GetAnimHierarchyFromClump(RpClump *clump); // get from frame +RwFrame *GetHierarchyFromChildNodesCB(RwFrame *frame, void *data); +void SkinGetBonePositionsToTable(RpClump *clump, RwV3d *boneTable); +RpHAnimAnimation *HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier); +#endif + RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream); RwTexDictionary *RwTexDictionaryGtaStreamRead1(RwStream *stream); RwTexDictionary *RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict); diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 89bd13a6..7dc27f48 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -543,6 +543,21 @@ CVisibilityPlugins::RenderPedHiDetailCB(RpAtomic *atomic) return atomic; } +// This is needed for peds with only one clump, i.e. skinned models +// strangely even the xbox version has no such thing +RpAtomic* +CVisibilityPlugins::RenderPedCB(RpAtomic *atomic) +{ + int32 alpha; + + alpha = GetClumpAlpha(RpAtomicGetClump(atomic)); + if(alpha == 255) + AtomicDefaultRenderCallBack(atomic); + else + RenderAlphaAtomic(atomic, alpha); + return atomic; +} + float CVisibilityPlugins::GetDistanceSquaredFromCamera(RwFrame *frame) { diff --git a/src/rw/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h index 63bc95e4..b367d7ee 100644 --- a/src/rw/VisibilityPlugins.h +++ b/src/rw/VisibilityPlugins.h @@ -63,6 +63,7 @@ public: static RpAtomic *RenderPlayerCB(RpAtomic *atomic); static RpAtomic *RenderPedLowDetailCB(RpAtomic *atomic); static RpAtomic *RenderPedHiDetailCB(RpAtomic *atomic); + static RpAtomic *RenderPedCB(RpAtomic *atomic); // for skinned models with only one clump static void RenderAlphaAtomics(void); static void RenderFadingEntities(void); @@ -131,3 +132,5 @@ public: static bool PluginAttach(void); }; + +RpMaterial *SetAlphaCB(RpMaterial *material, void *data); diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index d13d3c52..cde9f9e5 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -1766,6 +1766,14 @@ WinMain(HINSTANCE instance, StaticPatcher::Apply(); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE); +/* + // TODO: make this an option somewhere + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); +*/ + /* * Initialize the platform independent data. * This will in turn initialize the platform specific data... diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index b7ccb455..54e73a41 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -566,8 +566,7 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) target.y = 0.0f; target.z = 0.0f; - for (RwFrame *i = shooterPed->GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i)) - RwV3dTransformPoints(target, target, 1, RwFrameGetMatrix(i)); + shooterPed->TransformToNode(target, PED_HANDR); ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); } -- cgit v1.2.3