diff --git a/.gitignore b/.gitignore index e4205e4e..17756527 100644 --- a/.gitignore +++ b/.gitignore @@ -374,6 +374,7 @@ liberty/*.iso liberty/dca-liberty.elf liberty/dca-liberty.elf.bin liberty/dca-liberty-sim.elf +liberty/animtool* liberty/texconv* liberty/imgtool* liberty/extract-sfx* @@ -391,6 +392,7 @@ miami/*.iso miami/dca-miami.elf miami/dca-miami.elf.bin miami/dca-miami-sim.elf +miami/animtool* miami/texconv* miami/imgtool* miami/extract-sfx* diff --git a/liberty/Makefile b/liberty/Makefile index 9244516d..73138881 100644 --- a/liberty/Makefile +++ b/liberty/Makefile @@ -18,6 +18,7 @@ MOD_NAME?= GTA_DIR?=../../gta3 GTA_MOD_DIR?=../../gta3_mod$(MOD_NAME) GTA_MOD_IMG_DIR?=$(GTA_MOD_DIR)/img +GTA_MOD_CUTS_DIR=$(GTA_MOD_DIR)/cuts GTA_MOD_SFX_DIR?=$(GTA_MOD_DIR)/sfx GTA_MOD_LOOSE_DIR?=$(GTA_MOD_DIR)/loose @@ -28,6 +29,8 @@ REPACK_IMG_DC_DIR?=$(REPACK_DIR)/img-dc REPACK_SFX_ORIG_DIR?=$(REPACK_DIR)/sfx-orig REPACK_SFX_DC_DIR?=$(REPACK_DIR)/sfx-dc REPACK_STREAM_DECODED_DIR?=$(REPACK_DIR)/stream-decoded +REPACK_CUTS_ORIG_DIR?=$(REPACK_DIR)/cuts-orig +REPACK_CUTS_DC_DIR?=$(REPACK_DIR)/cuts-dc LIBS := TEXCONV_FLAGS := @@ -287,6 +290,9 @@ texconv: $(OBJS_TEXCONV) | pvrtex # You'll have to rebuild pvrtex manually if yo %.texconv.o: %.cpp $(CXX) -std=c++2a -c -O3 -g -MMD -MP -o $@ -I../vendor/koshle -I../vendor/librw/src $(INCLUDE) -I../vendor/emu -I../vendor/crypto -I../vendor/TriStripper/include $(DEFINES) -DDC_TEXCONV -DDC_SIM -D_INC_WINDOWS $(TEXCONV_FLAGS) $< +animtool: ../src/tools/animtool.cpp + $(CXX) -std=c++17 -o $@ -g -O0 $< + -include $(DEPS) #### Repacking #### @@ -355,10 +361,16 @@ TEXTURE_DOWNSAMPLE_IMG ?= HALF -include sfxlooplist.mk -include wavlist.mk -include mp3list.mk +-include cuts.mk IMG_TEXTURES_DC = $(addprefix $(REPACK_IMG_DC_DIR)/, $(IMG_TEXTURES)) IMG_MODELS_DC = $(addprefix $(REPACK_IMG_DC_DIR)/, $(IMG_MODELS)) + +CUTS_IFP_DC = $(addprefix $(REPACK_CUTS_DC_DIR)/, $(CUTS_IFP)) +CUTS_MISC_DC = $(addprefix $(REPACK_CUTS_DC_DIR)/, $(CUTS_MISC)) + LOOSE_FILES_DC = $(addprefix $(REPACK_GTA_DIR)/, $(MISC_FILES)) + SFX_DC_DIR = $(REPACK_GTA_DIR)/sfx SFX_DC_RAW = $(SFX_DC_DIR)/sfx_all.raw SFX_DC_DSC = $(SFX_DC_DIR)/sfx_all.dsc @@ -368,6 +380,9 @@ STREAM_ADPCM_DC = $(addprefix $(REPACK_GTA_DIR)/stream/, $(STREAM_WAV:.wav=.APM) IMG_TEXTURES_ORIG = $(addprefix $(REPACK_IMG_ORIG_DIR)/, $(IMG_TEXTURES)) IMG_MODELS_ORIG = $(addprefix $(REPACK_IMG_ORIG_DIR)/, $(IMG_MODELS)) +CUTS_IFP_ORIG = $(addprefix $(REPACK_CUTS_ORIG_DIR)/, $(CUTS_IFP)) +CUTS_MISC_ORIG = $(addprefix $(REPACK_CUTS_ORIG_DIR)/, $(CUTS_MISC)) + SFX_ORIG = $(addprefix $(REPACK_SFX_ORIG_DIR)/, $(SFX_WAV)) SFX_ORIG_LOOP = $(addprefix $(REPACK_SFX_ORIG_DIR)/, $(SFX_LOOP_WAV)) SFX_REPACK_DC_WAV = $(addprefix $(REPACK_SFX_DC_DIR)/, $(SFX_WAV) $(SFX_LOOP_WAV)) @@ -391,6 +406,15 @@ $(REPACK_DIR)/unpacked: imgtool $(GTA_DIR)/models/gta3.img $(GTA_DIR)/models/gta $(IMG_TEXTURES_ORIG) $(IMG_MODELS_ORIG): $(REPACK_DIR)/unpacked @touch $@ +$(REPACK_DIR)/unpacked-cuts: imgtool $(GTA_DIR)/anim/cuts.img $(GTA_DIR)/anim/cuts.dir + mkdir -p $(@D) + ./imgtool unpack "$(GTA_DIR)/anim/cuts" "$(REPACK_CUTS_ORIG_DIR)" + @touch $@ + +$(CUTS_IFP_ORIG) $(CUTS_MISC_ORIG): $(REPACK_DIR)/unpacked-cuts + @test -f $@ + @touch $@ + # First try the mods img directory $(REPACK_IMG_DC_DIR)/%.dff: $(GTA_MOD_IMG_DIR)/%.dff texconv @mkdir -p $(@D) @@ -423,6 +447,30 @@ $(REPACK_IMG_DC_DIR)/%.TXD: $(REPACK_IMG_ORIG_DIR)/%.TXD texconv @mkdir -p $(@D) ./texconv $< $@ $(DEFAULT_RES) $(DEFAULT_RES) -e $(PVR_ENCODER) -d $(TEXTURE_DOWNSAMPLE_IMG) + +### cuts +# First try the mods img directory +$(REPACK_CUTS_DC_DIR)/%.dat: $(GTA_MOD_CUTS_DIR)/%.dat + @mkdir -p $(@D) + cp $< $@ +$(REPACK_CUTS_DC_DIR)/%.anm: $(GTA_MOD_CUTS_DIR)/%.anm + @mkdir -p $(@D) + cp $< $@ +$(REPACK_CUTS_DC_DIR)/%.ifp: $(GTA_MOD_CUTS_DIR)/%.ifp animtool + @mkdir -p $(@D) + ./animtool $< $@ + +# if not, the extracted img directory +$(REPACK_CUTS_DC_DIR)/%.dat: $(REPACK_CUTS_ORIG_DIR)/%.dat + @mkdir -p $(@D) + cp $< $@ +$(REPACK_CUTS_DC_DIR)/%.anm: $(REPACK_CUTS_ORIG_DIR)/%.anm + @mkdir -p $(@D) + cp $< $@ +$(REPACK_CUTS_DC_DIR)/%.ifp: $(REPACK_CUTS_ORIG_DIR)/%.ifp animtool + @mkdir -p $(@D) + ./animtool $< $@ + # first try the mods loose directory $(REPACK_GTA_DIR)/%.dff: $(GTA_MOD_LOOSE_DIR)/%.dff texconv @mkdir -p $(@D) @@ -456,6 +504,22 @@ $(REPACK_GTA_DIR)/%.TXD: $(GTA_DIR)/%.TXD texconv @mkdir -p $(@D) ./texconv $< $@ $(TXD_OPTS_$(notdir $*)) -e $(PVR_ENCODER) -d $(TEXTURE_DOWNSAMPLE_TXD) +# first try the mods loose directory +$(REPACK_GTA_DIR)/%.ifp: $(GTA_MOD_LOOSE_DIR)/%.ifp animtool + @mkdir -p $(@D) + ./animtool $< $@ +$(REPACK_GTA_DIR)/%.IFP: $(GTA_MOD_LOOSE_DIR)/%.IFP animtool + @mkdir -p $(@D) + ./animtool $< $@ + +#if not, the original files +$(REPACK_GTA_DIR)/%.ifp: $(GTA_DIR)/%.ifp animtool + @mkdir -p $(@D) + ./animtool $< $@ +$(REPACK_GTA_DIR)/%.IFP: $(GTA_DIR)/%.IFP animtool + @mkdir -p $(@D) + ./animtool $< $@ + $(REPACK_DIR)/packed: $(IMG_TEXTURES_DC) $(IMG_MODELS_DC) mkdir -p $(@D) mkdir -p "$(REPACK_GTA_DIR)/models/gta3" @@ -465,6 +529,15 @@ $(REPACK_DIR)/packed: $(IMG_TEXTURES_DC) $(IMG_MODELS_DC) $(REPACK_GTA_DIR)/models/gta3.img $(REPACK_GTA_DIR)/models/gta3.dir: $(REPACK_DIR)/packed @touch $@ +$(REPACK_DIR)/packed-cuts: $(CUTS_IFP_DC) $(CUTS_MISC_DC) + mkdir -p $(@D) + mkdir -p "$(REPACK_GTA_DIR)/anim/cuts" + ./imgtool pack "$(REPACK_GTA_DIR)/anim/cuts" "$(REPACK_CUTS_DC_DIR)" + @touch $@ + +$(REPACK_GTA_DIR)/anim/cuts.img $(REPACK_GTA_DIR)/anim/cuts.dir: $(REPACK_DIR)/packed-cuts + @touch $@ + # sfx processing $(REPACK_DIR)/unpacked-sfx: extract-sfx $(GTA_DIR)/audio/sfx.SDT $(GTA_DIR)/audio/sfx.RAW mkdir -p $(@D) diff --git a/liberty/cuts.mk b/liberty/cuts.mk new file mode 100644 index 00000000..178e17b1 --- /dev/null +++ b/liberty/cuts.mk @@ -0,0 +1,286 @@ +CUTS_IFP = \ + A1_ss0.ifp \ + A2_pp.ifp \ + A3_ss.ifp \ + A4_pdr.ifp \ + A5_k2ft.ifp \ + A6_BAIT.ifp \ + A7_ETG.ifp \ + A8_PS.ifp \ + A9_ASD.ifp \ + BET.ifp \ + C1_TEX.ifp \ + D1_STOG.ifp \ + D2_KK.ifp \ + D3_ADO.ifp \ + D4_GTA2.ifp \ + D4_GTA.ifp \ + D5_ES.ifp \ + D6_STS.ifp \ + D7_MLD.ifp \ + el_ph1.ifp \ + el_ph2.ifp \ + el_ph3.ifp \ + el_ph4.ifp \ + END.ifp \ + hd_ph1.ifp \ + hd_ph2.ifp \ + hd_ph3.ifp \ + hd_ph4.ifp \ + hd_ph5.ifp \ + J0_dm2.ifp \ + J1_lfl.ifp \ + J2_kcl.ifp \ + J3_vh.ifp \ + J4_ETH.ifp \ + J5_dst.ifp \ + J6_tbj.ifp \ + JB.ifp \ + k1_kbo.ifp \ + k2_gis.ifp \ + k3_ds.ifp \ + k4_shi2.ifp \ + k4_shi.ifp \ + k5_sd.ifp \ + l1_lg.ifp \ + l2_dsb.ifp \ + l3_dm.ifp \ + l4_pap.ifp \ + l5_tfb.ifp \ + mt_ph1.ifp \ + mt_ph2.ifp \ + mt_ph3.ifp \ + mt_ph4.ifp \ + R0_PDR2.ifp \ + R1_SW.ifp \ + R2_AP.ifp \ + R3_ED.ifp \ + R4_GF.ifp \ + R5_PB.ifp \ + R6_MM.ifp \ + S0_MAS.ifp \ + S1_PF.ifp \ + S2_CTG2.ifp \ + S2_CTG.ifp \ + S3_RTC.ifp \ + S4_BDBA.ifp \ + S4_BDBB.ifp \ + S4_BDBD.ifp \ + S5_LRQb.ifp \ + S5_LRQc.ifp \ + S5_LRQ.ifp \ + t1_tol.ifp \ + t2_tpu.ifp \ + t3_mas.ifp \ + t4_tat.ifp \ + t5_bf.ifp \ + yd_ph1.ifp \ + yd_ph2.ifp \ + yd_ph3.ifp \ + yd_ph4.ifp + +CUTS_MISC = \ + a1_ss0_asuka.anm \ + a1_ss0.dat \ + a1_ss0_maria.anm \ + a1_ss0_player.anm \ + a2_pp.dat \ + a2_pp_player.anm \ + a3_ss_asuka.anm \ + a3_ss.dat \ + a3_ss_kenji.anm \ + a3_ss_player.anm \ + a4_pdr_asuka.anm \ + a4_pdr.dat \ + a4_pdr_player.anm \ + a5_k2ft.dat \ + a5_k2ft_player.anm \ + a6_bait_asuka.anm \ + a6_bait.dat \ + a6_bait_player.anm \ + a7_etg_asuka.anm \ + a7_etg.dat \ + a7_etg_player.anm \ + a8_ps_asuka.anm \ + A8_PS.dat \ + a8_ps_maria.anm \ + a8_ps_player.anm \ + a9_asd.dat \ + a9_asd_player.anm \ + bet_cat.anm \ + bet.dat \ + c1_tex_cat.anm \ + c1_tex.dat \ + d1_stog.dat \ + d1_stog_love.anm \ + d1_stog_player.anm \ + D2_KK.dat \ + d2_kk_love.anm \ + d2_kk_player.anm \ + d3_ado.dat \ + d3_ado_love.anm \ + d3_ado_player.anm \ + d4_gta2_asuka.anm \ + d4_gta2_cat.anm \ + d4_gta2.dat \ + d4_gta2_miguel.anm \ + D4_GTA.dat \ + d4_gta_love.anm \ + d4_gta_player.anm \ + d5_es.dat \ + d5_es_love.anm \ + d5_es_player.anm \ + d6_sts.dat \ + d6_sts_love.anm \ + d6_sts_player.anm \ + d7_mld.dat \ + el_ph1.dat \ + el_ph2.dat \ + el_ph3.dat \ + el_ph4.dat \ + end.dat \ + hd_ph1.dat \ + hd_ph2.dat \ + hd_ph3.dat \ + hd_ph4.dat \ + hd_ph5.dat \ + intro.dat \ + J0_dm2.dat \ + j0_dm2_joey.anm \ + j0_dm2_misty.anm \ + j0_dm2_player.anm \ + J1_lfl.dat \ + j1_lfl_joey.anm \ + j1_lfl_misty.anm \ + j1_lfl_player.anm \ + J2_KCL.dat \ + j2_kcl_joey.anm \ + j2_kcl_player.anm \ + j3_vh.dat \ + j3_vh_joey.anm \ + j3_vh_player.anm \ + J4_ETH.dat \ + j4_eth_joey.anm \ + j4_eth_player.anm \ + j4_eth_tony.anm \ + J5_dst.dat \ + j5_dst_joey.anm \ + j5_dst_player.anm \ + j6_tbj.dat \ + j6_tbj_joey.anm \ + j6_tbj_player.anm \ + jb_col1.anm \ + jb.dat \ + K1_KBO.dat \ + k1_kbo_kenji.anm \ + k1_kbo_player.anm \ + K2_GIS.dat \ + k2_gis_kenji.anm \ + k2_gis_player.anm \ + k3_ds.dat \ + k3_ds_kenji.anm \ + k3_ds_player.anm \ + k4_shi2.dat \ + k4_shi2_keeper.anm \ + k4_shi2_player.anm \ + k4_shi.dat \ + k4_shi_kenji.anm \ + k4_shi_player.anm \ + K5_SD.dat \ + k5_sd_kenji.anm \ + k5_sd_player.anm \ + L1_LG.dat \ + l1_lg_eight.anm \ + l1_lg_luigi.anm \ + l1_lg_micky.anm \ + l1_lg_player.anm \ + l2_dsb.dat \ + l2_DSB_micky.anm \ + l2_dsb_player.anm \ + L3_DM.dat \ + l3_dm_luigi.anm \ + l3_dm_micky.anm \ + l3_dm_player.anm \ + l4_pap.dat \ + l4_pap_luigi.anm \ + l4_pap_player.anm \ + L5_TFB.dat \ + l5_tfb_luigi.anm \ + l5_tfb_micky.anm \ + l5_tfb_player.anm \ + mt_ph1.dat \ + mt_ph2.dat \ + mt_ph3.dat \ + mt_ph4.dat \ + R0_PDR2.dat \ + R0_pdr2_player.anm \ + R0_pdr2_ray.anm \ + R1_SW.dat \ + R1_sw_player.anm \ + R1_sw_ray.anm \ + R2_AP.dat \ + R2_ap_player.anm \ + R2_ap_ray.anm \ + r3_ed.dat \ + R3_ed_player.anm \ + R3_ed_ray.anm \ + R4_GF.dat \ + R4_gf_player.anm \ + R4_gf_ray.anm \ + R5_PB.dat \ + R5_pb_player.anm \ + R5_pb_ray.anm \ + R6_MM.dat \ + R6_mm_player.anm \ + R6_mm_ray.anm \ + S0_MAS.dat \ + S0_mas_frank.anm \ + s0_mas_joey.anm \ + s0_mas_luigi.anm \ + s0_mas_player.anm \ + S0_mas_tony.anm \ + S1_PF.dat \ + S1_pf_frank.anm \ + S1_pf_maria.anm \ + S1_pf_player.anm \ + S2_ctg2_cat.anm \ + S2_ctg2_curly.anm \ + s2_ctg2.dat \ + S2_ctg2_miguel.anm \ + S2_CTG.dat \ + s2_ctg_frank.anm \ + S3_rtc.dat \ + S3_rtc_frank.anm \ + S4_BDBA.dat \ + S4_BDBA_eight.anm \ + S4_BDBA_player.anm \ + S4_BDBB.dat \ + S4_BDBB_eight.anm \ + S4_BDBB_player.anm \ + S4_BDBD.dat \ + S5_lrqb_asuka.anm \ + s5_lrqb.dat \ + S5_lrqb_maria.anm \ + S5_lrqc_asuka.anm \ + S5_LRQC.dat \ + S5_lrqc_maria.anm \ + S5_lrqc_player.anm \ + S5_LRQ.dat \ + S5_lrq_frank.anm \ + S5_lrq_player.anm \ + T1_TOL.dat \ + t1_tol_player.anm \ + t1_tol_tony.anm \ + T2_TPU.dat \ + t2_tpu_player.anm \ + T3_MAS.dat \ + t3_mas_player.anm \ + T4_TAT.dat \ + t4_tat_player.anm \ + T5_BF.dat \ + t5_bf_player.anm \ + t5_bf_tony.anm \ + yd_ph1.dat \ + yd_ph2.dat \ + yd_ph3.dat \ + yd_ph4.dat \ No newline at end of file diff --git a/src/liberty/animation/AnimBlendAssociation.cpp b/src/liberty/animation/AnimBlendAssociation.cpp index fcaa84fa..f1b5face 100644 --- a/src/liberty/animation/AnimBlendAssociation.cpp +++ b/src/liberty/animation/AnimBlendAssociation.cpp @@ -55,6 +55,8 @@ void CAnimBlendAssociation::FreeAnimBlendNodeArray(void) { assert(nodes != nil); + for(unsigned i = 0; i < numNodes; i++) + nodes[i].Destroy(); RwFreeAlign(nodes); } diff --git a/src/liberty/animation/AnimBlendHierarchy.cpp b/src/liberty/animation/AnimBlendHierarchy.cpp index e87de493..462c387a 100644 --- a/src/liberty/animation/AnimBlendHierarchy.cpp +++ b/src/liberty/animation/AnimBlendHierarchy.cpp @@ -29,22 +29,15 @@ CAnimBlendHierarchy::CalcTotalTime(void) totalLength = 0.0f; for(i = 0; i < numSequences; i++){ - float seqTime = 0.0f; - for(j = 0; j < sequences[i].numFrames; j++) - seqTime += sequences[i].GetDeltaTime(j); +#ifdef FIX_BUGS + if(sequences[i].numFrames == 0) + continue; +#endif + float seqTime = sequences[i].GetEndTime(); totalLength = Max(totalLength, seqTime); } } -void -CAnimBlendHierarchy::RemoveQuaternionFlips(void) -{ - int i; - - for(i = 0; i < numSequences; i++) - sequences[i].RemoveQuaternionFlips(); -} - void CAnimBlendHierarchy::RemoveAnimSequences(void) { diff --git a/src/liberty/animation/AnimBlendNode.cpp b/src/liberty/animation/AnimBlendNode.cpp index 1392bed4..d52a954a 100644 --- a/src/liberty/animation/AnimBlendNode.cpp +++ b/src/liberty/animation/AnimBlendNode.cpp @@ -11,11 +11,21 @@ CAnimBlendNode::Init(void) remainingTime = 0.0f; sequence = nil; association = nil; + player = nil; +} + +void CAnimBlendNode::Destroy(void) { + if (player) { + delete player; + player = nil; + } } bool CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight) { + assert (player && player->keyFrames == sequence->keyFrames); + bool looped = false; trans = CVector(0.0f, 0.0f, 0.0f); @@ -29,17 +39,17 @@ CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight) float blend = association->GetBlendAmount(weight); if(blend > 0.0f){ - float kfAdt = sequence->GetDeltaTime(frameA); + float kfAdt = player->GetDeltaTime(frameA); float t = kfAdt == 0.0f ? 0.0f : (kfAdt - remainingTime)/kfAdt; - if(sequence->type & CAnimBlendSequence::KF_TRANS){ - auto kfAt = sequence->GetTranslation(frameA); - auto kfBt = sequence->GetTranslation(frameB); + if(player->type & CAnimBlendSequence::KF_TRANS){ + auto kfAt = player->GetTranslation(frameA); + auto kfBt = player->GetTranslation(frameB); trans = kfBt + t*(kfAt - kfBt); trans *= blend; } - if(sequence->type & CAnimBlendSequence::KF_ROT){ - auto kfAr = sequence->GetRotation(frameA); - auto kfBr = sequence->GetRotation(frameB); + if(player->type & CAnimBlendSequence::KF_ROT){ + auto kfAr = player->GetRotation(frameA); + auto kfBr = player->GetRotation(frameB); rot.Slerp(kfBr, kfAr, theta, invSin, t); rot *= blend; } @@ -48,12 +58,14 @@ CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight) return looped; } +// TODO: Check this bool CAnimBlendNode::NextKeyFrame(void) { + assert(player != nil); bool looped; - if(sequence->numFrames <= 1) + if(player->numFrames <= 1) return false; looped = false; @@ -63,23 +75,33 @@ CAnimBlendNode::NextKeyFrame(void) while(remainingTime <= 0.0f){ frameA++; - if(frameA >= sequence->numFrames){ + if(frameA >= player->numFrames){ // reached end of animation if(!association->IsRepeating()){ frameA--; + frameB = frameA - 1; + if(frameB < 0) + frameB += player->numFrames; remainingTime = 0.0f; + // // range chekcs + // auto kfAt = player->GetTranslation(frameA); + // auto kfBt = player->GetTranslation(frameB); return false; } looped = true; frameA = 0; } - - remainingTime += sequence->GetDeltaTime(frameA); + player->AdvanceFrame(); + remainingTime += player->GetDeltaTime(frameA); } frameB = frameA - 1; if(frameB < 0) - frameB += sequence->numFrames; + frameB += player->numFrames; + + // // range chekcs + // auto kfAt = player->GetTranslation(frameA); + // auto kfBt = player->GetTranslation(frameB); CalcDeltas(); return looped; @@ -89,31 +111,51 @@ CAnimBlendNode::NextKeyFrame(void) bool CAnimBlendNode::FindKeyFrame(float t) { - if(sequence->numFrames < 1) + if (player == nil) { + player = new CAnimBlendPlayer(); + player->Init(sequence->keyFrames, sequence->type, sequence->numFrames); + } + if(player->numFrames < 1) return false; frameA = 0; frameB = frameA; + player->SeekToStart(); - if(sequence->numFrames >= 2){ - frameA++; + assert (player->keyFrames == sequence->keyFrames); + if(player->numFrames == 1){ + remainingTime = 0.0f; + }else{ // advance until t is between frameB and frameA - while(t > sequence->GetDeltaTime(frameA)){ - t -= sequence->GetDeltaTime(frameA); - frameB = frameA++; - if(frameA >= sequence->numFrames){ + frameA++; + player->AdvanceFrame(); + while (t > player->GetDeltaTime(frameA)) { + t -= player->GetDeltaTime(frameA); + if (frameA + 1 >= player->numFrames) { // reached end of animation - if(!association->IsRepeating()) + if (!association->IsRepeating()) { + // // range chekcs + // auto kfAt = player->GetTranslation(frameA); + // auto kfBt = player->GetTranslation(frameB); + CalcDeltas(); + remainingTime = 0.0f; return false; + } frameA = 0; - frameB = 0; } + frameB = frameA; + frameA++; + player->AdvanceFrame(); } - remainingTime = sequence->GetDeltaTime(frameA) - t; + remainingTime = player->GetDeltaTime(frameA) - t; } + // // range chekcs + // auto kfAt = player->GetTranslation(frameA); + // auto kfBt = player->GetTranslation(frameB); + CalcDeltas(); return true; } @@ -121,10 +163,10 @@ CAnimBlendNode::FindKeyFrame(float t) void CAnimBlendNode::CalcDeltas(void) { - if((sequence->type & CAnimBlendSequence::KF_ROT) == 0) + if((player->type & CAnimBlendSequence::KF_ROT) == 0) return; - auto kfAr = sequence->GetRotation(frameA); - auto kfBr = sequence->GetRotation(frameB); + auto kfAr = player->GetRotation(frameA); + auto kfBr = player->GetRotation(frameB); float cos = DotProduct(kfAr, kfBr); if(cos > 1.0f) cos = 1.0f; @@ -139,11 +181,11 @@ CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight) float blend = association->GetBlendAmount(weight); if(blend > 0.0f){ - auto kfAdt = sequence->GetDeltaTime(frameA); + auto kfAdt = player->GetDeltaTime(frameA); float t = kfAdt == 0.0f ? 0.0f : (kfAdt - remainingTime)/kfAdt; - if(sequence->type & CAnimBlendSequence::KF_TRANS){ - auto kfAt = sequence->GetTranslation(frameA); - auto kfBt = sequence->GetTranslation(frameB); + if(player->type & CAnimBlendSequence::KF_TRANS){ + auto kfAt = player->GetTranslation(frameA); + auto kfBt = player->GetTranslation(frameB); trans = kfBt + t*(kfAt - kfBt); trans *= blend; } @@ -157,7 +199,9 @@ CAnimBlendNode::GetEndTranslation(CVector &trans, float weight) float blend = association->GetBlendAmount(weight); if(blend > 0.0f){ - if(sequence->type & CAnimBlendSequence::KF_TRANS) - trans = sequence->GetTranslation(sequence->numFrames-1) * blend; + if(player->type & CAnimBlendSequence::KF_TRANS){ + CVector pos = sequence->GetEndTranslation(); + trans = pos * blend; + } } } diff --git a/src/liberty/animation/AnimBlendNode.h b/src/liberty/animation/AnimBlendNode.h index 89924d6a..78db24c7 100644 --- a/src/liberty/animation/AnimBlendNode.h +++ b/src/liberty/animation/AnimBlendNode.h @@ -15,10 +15,12 @@ public: int32 frameA; // next key frame int32 frameB; // previous key frame float remainingTime; // time until frames have to advance + CAnimBlendPlayer* player; CAnimBlendSequence *sequence; CAnimBlendAssociation *association; void Init(void); + void Destroy(void); bool Update(CVector &trans, CQuaternion &rot, float weight); bool NextKeyFrame(void); bool FindKeyFrame(float t); diff --git a/src/liberty/animation/AnimBlendSequence.cpp b/src/liberty/animation/AnimBlendSequence.cpp index 0718f37c..200f7c77 100644 --- a/src/liberty/animation/AnimBlendSequence.cpp +++ b/src/liberty/animation/AnimBlendSequence.cpp @@ -25,45 +25,6 @@ CAnimBlendSequence::SetName(char *name) strncpy(this->name, name, 24); } -void -CAnimBlendSequence::SetNumFrames(int numFrames, bool translation, bool compress) -{ - int sz; - - if(translation){ - type |= KF_ROT | KF_TRANS; - if (compress) { - type |= KF_COMPRESSED; - sz = sizeof(KeyFrameTransCompressed); - } else { - sz = sizeof(KeyFrameTransUncompressed); - } - }else{ - sz = sizeof(KeyFrame); - type |= KF_ROT; - } - keyFrames = RwMalloc(sz * numFrames); - this->numFrames = numFrames; -} - -void -CAnimBlendSequence::RemoveQuaternionFlips(void) -{ - int i; - CQuaternion last; - - if(numFrames < 2) - return; - - last = GetRotation(0); - for(i = 1; i < numFrames; i++){ - auto KFr = GetRotation(i); - if(DotProduct(last, KFr) < 0.0f) - SetRotation(i, -KFr); - last = GetRotation(i); - } -} - #ifdef USE_CUSTOM_ALLOCATOR bool CAnimBlendSequence::MoveMemory(void) diff --git a/src/liberty/animation/AnimBlendSequence.h b/src/liberty/animation/AnimBlendSequence.h index bedc85ee..89f2455f 100644 --- a/src/liberty/animation/AnimBlendSequence.h +++ b/src/liberty/animation/AnimBlendSequence.h @@ -5,67 +5,338 @@ #ifdef MoveMemory #undef MoveMemory // windows shit #endif +struct CAnimBlendPlayer { + enum { + KF_ROT = 1, + KF_TRANS = 2, + + FLAGS_HAS_ROT_Y = 1 << 8, + FLAGS_HAS_ROT_P = 1 << 9, + FLAGS_HAS_ROT_R = 1 << 10, -// TODO: put them somewhere else? -static int16 checked_f2i16(float f) { - assert(f >= -32768 && f <= 32767); - return f; -} + FLAGS_HAS_TRANS_X = 1 << 11, + FLAGS_HAS_TRANS_Y = 1 << 12, + FLAGS_HAS_TRANS_Z = 1 << 13, + FLAGS_HAS_TRANS_ANY = 7 << 11, + FLAGS_HAS_TRANS_LARGE = 1 << 14, + FLAGS_QUAT0_NEG = 1 << 15 + }; -static uint16 checked_f2u16(float f) { - assert(f >= 0 && f <= 65535); - return f; -} + int32 type; + void* keyFrames; + int32 curFrame; + int32 numFrames; + CQuaternion currentRotation; + CQuaternion nextRotation; + CVector currentTranslation; + CVector nextTranslation; -#define KF_MINDELTA (1/256.f) + unsigned readOffset; + unsigned readOffset_initial; -struct KeyFrame { - int16 rot[4]; // 4096 - uint16 dltTime; // 256 + uint16_t predicted_y, predicted_p, predicted_r; + float predicted_tx = 0, predicted_ty = 0, predicted_tz = 0; + float nextDeltaTime; - CQuaternion rotation_() { - return { rot[0] * (1/4096.f), rot[1] * (1/4096.f), rot[2] * (1/4096.f), rot[3] * (1/4096.f) }; + #if !defined(DC_TEXCONV) + // static unsigned count; + + // CAnimBlendPlayer() { + // count++; + // fprintf(stderr, "CAnimBlendPlayer count %d\n", count); + // } + // ~CAnimBlendPlayer() { + // count--; + // } + #endif + + template + T read_unaligned(uint32_t ro) { + T rv; + for (unsigned i = 0; i < sizeof(T); i++) { + ((uint8_t*)&rv)[i] = ((uint8_t*)keyFrames)[ro]; + ro++; + } + readOffset = ro; + return rv; + } + template + __always_inline T read() { + if (!(readOffset & (sizeof(T) -1))) { + return read_aligned(); + } else { + return read_unaligned(readOffset); + } } - void rotation_(const CQuaternion& q) { - rot[0] = checked_f2i16(q.x * 4096.0f); - rot[1] = checked_f2i16(q.y * 4096.0f); - rot[2] = checked_f2i16(q.z * 4096.0f); - rot[3] = checked_f2i16(q.w * 4096.0f); + template + __always_inline T read_aligned() { + T rv; + rv = *(T*)((uint8_t*)keyFrames + readOffset); + readOffset += sizeof(T); + return rv; } - float deltaTime_() { - return dltTime * (1/256.0f); + __always_inline CQuaternion fromSphericalFixed(uint16_t y, uint16_t p, uint16_t r) { + CQuaternion q; + #if !defined(DC_SH4) + q.w = cos((y / 65536.0f) * 2 * M_PI) * cos((p / 65536.0f) * 2 * M_PI); + q.x = cos((y / 65536.0f) * 2 * M_PI) * sin((p / 65536.0f) * 2 * M_PI); + q.y = sin((y / 65536.0f) * 2 * M_PI) * cos((r / 65536.0f) * 2 * M_PI); + q.z = sin((y / 65536.0f) * 2 * M_PI) * sin((r / 65536.0f) * 2 * M_PI); + #else + register float __ys __asm__("fr0"); + register float __yc __asm__("fr1"); + register float __ps __asm__("fr2"); + register float __pc __asm__("fr3"); + register float __rs __asm__("fr4"); + register float __rc __asm__("fr5"); + + __asm__ __volatile__( + R"( + lds %[y],fpul + fsca fpul, dr0 + lds %[p],fpul + fsca fpul, dr2 + lds %[r],fpul + fsca fpul, dr4 + )" + : "=f" (__ys), "=f" (__yc), "=f" (__ps), "=f" (__pc), "=f" (__rs), "=f" (__rc) + : "0" (__ys), "1" (__yc), "2" (__ps), "3" (__pc), "4" (__rs), "5" (__rc), [y]"r"(y), [p]"r"(p), [r]"r"(r)); + + q.w = __yc * __pc; + q.x = __yc * __ps; + q.y = __ys * __rc; + q.z = __ys * __rs; + #endif + return q; } - void deltaTime_(float t) { - dltTime = checked_f2u16(t * 256); // always round down - } -}; + void AdvanceFrame() { + if (++curFrame == numFrames){ + currentRotation = nextRotation; + currentTranslation = nextTranslation; + SeekToStart(); + return; + } -struct KeyFrameTransUncompressed : KeyFrame { - // Some animations use bigger range, eg during the intro - CVector trans; - CVector translation_() { - return trans; + // rotation + { + currentRotation = nextRotation; + + // For rotation Y: + if (type & FLAGS_HAS_ROT_Y) { + uint8_t byteVal = read(); + if (byteVal == 128) { + predicted_y = read(); + } else { + int8_t diff = static_cast(byteVal); + predicted_y += diff * 8; + } + } + // For rotation P: + if (type & FLAGS_HAS_ROT_P) { + uint8_t byteVal = read(); + if (byteVal == 128) { + predicted_p = read(); + } else { + int8_t diff = static_cast(byteVal); + predicted_p += diff * 8; + } + } + // For rotation R: + if (type & FLAGS_HAS_ROT_R) { + uint8_t byteVal = read(); + if (byteVal == 128) { + predicted_r = read(); + } else { + int8_t diff = static_cast(byteVal); + predicted_r += diff * 8; + } + } + + nextRotation = fromSphericalFixed(predicted_y, predicted_p, predicted_r); + } + + // translation + if (type & KF_TRANS) { + currentTranslation = nextTranslation; + if (type & FLAGS_HAS_TRANS_X) { + uint8_t byteVal = read(); + if (byteVal == 128) { + uint16_t diff = read(); + if (diff != 32768) { + predicted_tx += static_cast(diff) / 128.f; + } else { + predicted_tx = read(); + } + } else { + int8_t diff = static_cast(byteVal); + predicted_tx += diff / 127.f; + } + } + // Translation Y: + if (type & FLAGS_HAS_TRANS_Y) { + uint8_t byteVal = read(); + if (byteVal == 128) { + uint16_t diff = read(); + if (diff != 32768) { + predicted_ty += static_cast(diff) / 128.f; + } else { + predicted_ty = read(); + } + } else { + int8_t diff = static_cast(byteVal); + predicted_ty += diff / 127.f; + } + } + // Translation Z: + if (type & FLAGS_HAS_TRANS_Z) { + uint8_t byteVal = read(); + if (byteVal == 128) { + uint16_t diff = read(); + if (diff != 32768) { + predicted_tz += static_cast(diff) / 128.f; + } else { + predicted_tz = read(); + } + } else { + int8_t diff = static_cast(byteVal); + predicted_tz += diff / 127.f; + } + } + + nextTranslation = { predicted_tx, predicted_ty, predicted_tz }; + } + + // time delta + quaternion flips + { + uint8_t byteValPacked = read(); + uint8_t byteVal = byteValPacked & 127; + float diff; + if (byteVal == 127) { + uint16_t fixed_diff = read(); + diff = fixed_diff / 256.f; + } else { + diff = byteVal / 256.f; + } + nextDeltaTime = diff; + + if (byteValPacked & 128) { + nextRotation = -nextRotation; + } + } } - void translation_(const CVector &v) { - trans = v; + CQuaternion GetRotation(unsigned frame) { + auto lastFrame = curFrame == 0 ? numFrames - 1 : curFrame - 1; + if (frame == lastFrame) { + return currentRotation; + } else if (frame == curFrame) { + return nextRotation; + } else { + assert(false); + } } -}; - -struct KeyFrameTransCompressed : KeyFrame { - int16 trans[3]; // 128 - - CVector translation_() { - return { trans[0] * (1/128.f), trans[1] * (1/128.f), trans[2] * (1/128.f)}; + CVector GetTranslation(unsigned frame) { + auto lastFrame = curFrame == 0 ? numFrames - 1 : curFrame - 1; + if (frame == lastFrame) { + return currentTranslation; + } else if (frame == curFrame) { + return nextTranslation; + } else { + assert(false); + } + } + float GetDeltaTime(unsigned frame) { + if (frame == curFrame) { + return nextDeltaTime; + } else { + assert(false); + } + return 1/30.f; } - void translation_(const CVector &v) { - trans[0] = checked_f2i16(v.x * 128.f); - trans[1] = checked_f2i16(v.y * 128.f); - trans[2] = checked_f2i16(v.z * 128.f); + // CQuaternion GetCurrentRotation() { + // return currentRotation; + // } + // CQuaternion GetNextRotation() { + // return nextRotation; + // } + // float GetNextTimeDelta() { + // return nextDeltaTime; + // } + + // CVector GetCurrentTranslation() { + // return currentTranslation; + // } + // CVector GetNextTranslationDelta() { + // return nextTranslation - currentTranslation; + // } + + void Init(void* kf, int32 tp, int nF) { + keyFrames = kf; + type = tp; + numFrames = nF; + + SeekToStart(); + currentTranslation = nextTranslation; + currentRotation = nextRotation; + } + + void SeekToStart() { + readOffset = 0; + float startTime = read_aligned(); + float endTime = read_aligned(); + + if (type & KF_TRANS) { + CVector startTranslation; + if (type & FLAGS_HAS_TRANS_LARGE) { + startTranslation.x = read_aligned(); + startTranslation.y = read_aligned(); + startTranslation.z = read_aligned(); + predicted_tx = startTranslation.x; + predicted_ty = startTranslation.y; + predicted_tz = startTranslation.z; + + CVector endTranslation; + // Read final translation (may be used for verification or ignored) + endTranslation.x = read_aligned(); + endTranslation.y = read_aligned(); + endTranslation.z = read_aligned(); + } else { + startTranslation.x = read_aligned() / 128.f; + startTranslation.y = read_aligned() / 128.f; + startTranslation.z = read_aligned() / 128.f; + predicted_tx = startTranslation.x; + predicted_ty = startTranslation.y; + predicted_tz = startTranslation.z; + + CVector endTranslation; + // Read final translation (for completeness) + endTranslation.x = read_aligned() / 128.f; + endTranslation.y = read_aligned() / 128.f; + endTranslation.z = read_aligned() / 128.f; + } + + nextTranslation = startTranslation; + } else { + CVector startTranslation = { 0, 0, 0 }; + CVector endTranslation = { 0, 0, 0 }; + nextTranslation = startTranslation; + } + + predicted_y = read_aligned(); + predicted_p = read_aligned(); + predicted_r = read_aligned(); + nextRotation = fromSphericalFixed(predicted_y, predicted_p, predicted_r); + + if (type & FLAGS_QUAT0_NEG) { + nextRotation = -nextRotation; + } + + nextDeltaTime = startTime; + curFrame = 0; } }; @@ -73,11 +344,28 @@ struct KeyFrameTransCompressed : KeyFrame { // The sequence of key frames of one animated node class CAnimBlendSequence { + template + __always_inline T read_aligned(uint32_t &readOffset) { + T rv; + rv = *(T*)((uint8_t*)keyFrames + readOffset); + readOffset += sizeof(T); + return rv; + } public: enum { KF_ROT = 1, KF_TRANS = 2, - KF_COMPRESSED = 4, // only applicable for KF_TRANS + + FLAGS_HAS_ROT_Y = 1 << 8, + FLAGS_HAS_ROT_P = 1 << 9, + FLAGS_HAS_ROT_R = 1 << 10, + + FLAGS_HAS_TRANS_X = 1 << 11, + FLAGS_HAS_TRANS_Y = 1 << 12, + FLAGS_HAS_TRANS_Z = 1 << 13, + FLAGS_HAS_TRANS_ANY = 7 << 11, + FLAGS_HAS_TRANS_LARGE = 1 << 14, + FLAGS_QUAT0_NEG = 1 << 15 }; int32 type; char name[24]; @@ -87,72 +375,61 @@ public: #endif void *keyFrames; + + struct InitData { + CVector startTranslation, endTranslation; + float endTime; + }; + + __always_inline InitData GetInitData() { + InitData rv; + uint32_t readOffset = 0; + + float startTime = read_aligned(readOffset); + rv.endTime = read_aligned(readOffset); + + if (type & KF_TRANS) { + if (type & FLAGS_HAS_TRANS_LARGE) { + rv.startTranslation.x = read_aligned(readOffset); + rv.startTranslation.y = read_aligned(readOffset); + rv.startTranslation.z = read_aligned(readOffset); + + // Read final translation (may be used for verification or ignored) + rv.endTranslation.x = read_aligned(readOffset); + rv.endTranslation.y = read_aligned(readOffset); + rv.endTranslation.z = read_aligned(readOffset); + } else { + rv.startTranslation.x = read_aligned(readOffset) / 128.f; + rv.startTranslation.y = read_aligned(readOffset) / 128.f; + rv.startTranslation.z = read_aligned(readOffset) / 128.f; + + // Read final translation (for completeness) + rv.endTranslation.x = read_aligned(readOffset) / 128.f; + rv.endTranslation.y = read_aligned(readOffset) / 128.f; + rv.endTranslation.z = read_aligned(readOffset) / 128.f; + } + } else { + rv.startTranslation = { 0, 0, 0 }; + rv.endTranslation = { 0, 0, 0 }; + } + + return rv; + } + + + CVector GetStartTranslation() { + return GetInitData().startTranslation; + } + float GetEndTime() { + return GetInitData().endTime; + } + CVector GetEndTranslation() { + return GetInitData().endTranslation; + } + CAnimBlendSequence(void); virtual ~CAnimBlendSequence(void); void SetName(char *name); - void SetNumFrames(int numFrames, bool translation, bool compress); - void RemoveQuaternionFlips(void); - - - void SetTranslation(int n, const CVector &v) { - if (type & KF_COMPRESSED) { - ((KeyFrameTransCompressed*)keyFrames)[n].translation_(v); - } else if (type & KF_TRANS) { - ((KeyFrameTransUncompressed*)keyFrames)[n].translation_(v); - } else { - assert(false && "SetTranslation called on sequence without translation"); - } - } - - CVector GetTranslation(int n) { - if (type & KF_COMPRESSED) { - return ((KeyFrameTransCompressed*)keyFrames)[n].translation_(); - } else if (type & KF_TRANS) { - return ((KeyFrameTransUncompressed*)keyFrames)[n].translation_(); - } else { - assert(false && "GetTranslation called on sequence without translation"); - } - } - - void SetRotation(int n, const CQuaternion &q) { - if (type & KF_COMPRESSED) { - ((KeyFrameTransCompressed*)keyFrames)[n].rotation_(q); - } else if (type & KF_TRANS) { - ((KeyFrameTransUncompressed*)keyFrames)[n].rotation_(q); - } else { - ((KeyFrame*)keyFrames)[n].rotation_(q); - } - } - - CQuaternion GetRotation(int n) { - if (type & KF_COMPRESSED) { - return ((KeyFrameTransCompressed*)keyFrames)[n].rotation_(); - } else if (type & KF_TRANS) { - return ((KeyFrameTransUncompressed*)keyFrames)[n].rotation_(); - } else { - return ((KeyFrame*)keyFrames)[n].rotation_(); - } - } - - void SetDeltaTime(int n, float t) { - if (type & KF_COMPRESSED) { - ((KeyFrameTransCompressed*)keyFrames)[n].deltaTime_(t); - } else if (type & KF_TRANS) { - ((KeyFrameTransUncompressed*)keyFrames)[n].deltaTime_(t); - } else { - ((KeyFrame*)keyFrames)[n].deltaTime_(t); - } - } - - float GetDeltaTime(int n) { - if (type & KF_COMPRESSED) { - return ((KeyFrameTransCompressed*)keyFrames)[n].deltaTime_(); - } else if (type & KF_TRANS) { - return ((KeyFrameTransUncompressed*)keyFrames)[n].deltaTime_(); - } else { - return ((KeyFrame*)keyFrames)[n].deltaTime_(); - } - } bool HasTranslation(void) { return !!(type & KF_TRANS); } bool MoveMemory(void); diff --git a/src/liberty/animation/AnimManager.cpp b/src/liberty/animation/AnimManager.cpp index b3889328..ec146853 100644 --- a/src/liberty/animation/AnimManager.cpp +++ b/src/liberty/animation/AnimManager.cpp @@ -780,134 +780,70 @@ CAnimManager::LoadAnimFile(int fd, bool compress) char ident[4]; uint32 size; }; - IfpHeader anpk, info, name, dgan, cpan, anim; - int numANPK; + IfpHeader anpv; char buf[256]; - int i, j, k, l; + int j, k, l; float *fbuf = (float*)buf; - CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader)); - if(!CGeneral::faststrncmp(anpk.ident, "ANLF", 4)) { - ROUNDSIZE(anpk.size); - CFileMgr::Read(fd, buf, anpk.size); - numANPK = *(int*)buf; - } else if(!CGeneral::faststrncmp(anpk.ident, "ANPK", 4)) { - CFileMgr::Seek(fd, -8, 1); - numANPK = 1; - } + CFileMgr::Read(fd, (char*)&anpv, sizeof(IfpHeader)); + assert(memcmp(anpv.ident, "ANPV", 4) == 0); + + // block name + CFileMgr::Read(fd, buf, anpv.size); + CAnimBlock *animBlock = &ms_aAnimBlocks[ms_numAnimBlocks++]; + strncpy(animBlock->name, buf, 24); + int32_t numAnims; + CFileMgr::Read(fd, (char*)&numAnims, sizeof(numAnims)); + animBlock->numAnims = numAnims; - for(i = 0; i < numANPK; i++){ - // block name - CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader)); - ROUNDSIZE(anpk.size); - CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader)); - ROUNDSIZE(info.size); - CFileMgr::Read(fd, buf, info.size); - CAnimBlock *animBlock = &ms_aAnimBlocks[ms_numAnimBlocks++]; - strncpy(animBlock->name, buf+4, 24); - animBlock->numAnims = *(int*)buf; + animBlock->firstIndex = ms_numAnimations; - animBlock->firstIndex = ms_numAnimations; + for(j = 0; j < animBlock->numAnims; j++){ + CAnimBlendHierarchy *hier = &ms_aAnimations[ms_numAnimations++]; - for(j = 0; j < animBlock->numAnims; j++){ - CAnimBlendHierarchy *hier = &ms_aAnimations[ms_numAnimations++]; + // animation name + int32_t animNameLength; + CFileMgr::Read(fd, (char*)&animNameLength, sizeof(animNameLength)); + CFileMgr::Read(fd, buf, animNameLength); + hier->SetName(buf); - // animation name - CFileMgr::Read(fd, (char*)&name, sizeof(IfpHeader)); - ROUNDSIZE(name.size); - CFileMgr::Read(fd, buf, name.size); - hier->SetName(buf); + int32_t numSeqs; + CFileMgr::Read(fd, (char*)&numSeqs, sizeof(animNameLength)); + hier->numSequences = numSeqs; + hier->sequences = new CAnimBlendSequence[hier->numSequences]; - // DG info has number of nodes/sequences - CFileMgr::Read(fd, (char*)&dgan, sizeof(IfpHeader)); - ROUNDSIZE(dgan.size); - CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader)); - ROUNDSIZE(info.size); - CFileMgr::Read(fd, buf, info.size); - hier->numSequences = *(int*)buf; - hier->sequences = new CAnimBlendSequence[hier->numSequences]; + CAnimBlendSequence *seq = hier->sequences; + for(k = 0; k < hier->numSequences; k++, seq++){ + // Each node has a name and key frames + int32_t seqNameLength; + CFileMgr::Read(fd, (char*)&seqNameLength, sizeof(seqNameLength)); + CFileMgr::Read(fd, buf, seqNameLength); + seq->SetName(buf); - CAnimBlendSequence *seq = hier->sequences; - for(k = 0; k < hier->numSequences; k++, seq++){ - // Each node has a name and key frames - CFileMgr::Read(fd, (char*)&cpan, sizeof(IfpHeader)); - ROUNDSIZE(dgan.size); - CFileMgr::Read(fd, (char*)&anim, sizeof(IfpHeader)); - ROUNDSIZE(anim.size); - CFileMgr::Read(fd, buf, anim.size); - int numFrames = *(int*)(buf+28); - seq->SetName(buf); + int32_t numFrames; + CFileMgr::Read(fd, (char*)&numFrames, sizeof(numFrames)); + seq->numFrames = numFrames; + int32_t boneTag; + CFileMgr::Read(fd, (char*)&boneTag, sizeof(boneTag)); + #ifdef PED_SKIN - if(anim.size == 44) - seq->SetBoneTag(*(int*)(buf+40)); + seq->SetBoneTag(boneTag); #endif - if(numFrames == 0) - continue; + if(numFrames == 0) + continue; - bool hasScale = false; - bool hasTranslation = false; - CFileMgr::Read(fd, (char*)&info, sizeof(info)); - if(!CGeneral::faststrncmp(info.ident, "KRTS", 4)) { - hasScale = true; - seq->SetNumFrames(numFrames, true, compress); - }else if(!CGeneral::faststrncmp(info.ident, "KRT0", 4)) { - hasTranslation = true; - seq->SetNumFrames(numFrames, true, compress); - }else if(!CGeneral::faststrncmp(info.ident, "KR00", 4)){ - seq->SetNumFrames(numFrames, false, compress); - } + uint32_t dataSize; + CFileMgr::Read(fd, (char*)&dataSize, sizeof(dataSize)); + uint16_t flags; + CFileMgr::Read(fd, (char*)&flags, sizeof(flags)); - float *frameTimes = (float*)RwMalloc(sizeof(float) * numFrames); - - for(l = 0; l < numFrames; l++){ - if(hasScale){ - CFileMgr::Read(fd, buf, 0x2C); - CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]); - rot.Invert(); - CVector trans(fbuf[4], fbuf[5], fbuf[6]); - - seq->SetRotation(l, rot); - seq->SetTranslation(l, trans); - // scaling ignored - frameTimes[l] = fbuf[10]; // absolute time here - }else if(hasTranslation){ - CFileMgr::Read(fd, buf, 0x20); - CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]); - rot.Invert(); - CVector trans(fbuf[4], fbuf[5], fbuf[6]); - - seq->SetRotation(l, rot); - seq->SetTranslation(l, trans); - frameTimes[l] = fbuf[7]; // absolute time here - }else{ - CFileMgr::Read(fd, buf, 0x14); - CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]); - rot.Invert(); - - seq->SetRotation(l, rot); - frameTimes[l] = fbuf[4]; // absolute time here - } - } - - // convert absolute time to deltas - float running_sum = 0.0f; - for (l = 0; l < numFrames; l++) { - auto dt = frameTimes[l] - running_sum; - seq->SetDeltaTime(l, dt); - assert(seq->GetDeltaTime(l) <= dt); - running_sum += seq->GetDeltaTime(l); - // if (seq->GetDeltaTime(l) == 0.0f && dt != 0.0f) { - // seq->SetDeltaTime(l, KF_MINDELTA); - // } - - // assert(seq->GetDeltaTime(l) != 0.0f || dt == 0.0f); - } - RwFree(frameTimes); - } - - hier->RemoveQuaternionFlips(); - hier->CalcTotalTime(); + seq->keyFrames = RwMalloc(dataSize); + assert(seq->keyFrames); + CFileMgr::Read(fd, (char*)seq->keyFrames, dataSize - sizeof(flags)); + seq->type = flags; } + + hier->CalcTotalTime(); } } diff --git a/src/liberty/animation/CutsceneMgr.cpp b/src/liberty/animation/CutsceneMgr.cpp index ade0bba9..98823224 100644 --- a/src/liberty/animation/CutsceneMgr.cpp +++ b/src/liberty/animation/CutsceneMgr.cpp @@ -267,7 +267,7 @@ CCutsceneMgr::SetupCutsceneToStart(void) assert(RwObjectGetType(ms_pCutsceneObjects[i]->m_rwObject) == rpCLUMP); if (CAnimBlendAssociation *pAnimBlendAssoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)ms_pCutsceneObjects[i]->m_rwObject)) { assert(pAnimBlendAssoc->hierarchy->sequences[0].HasTranslation()); - ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + pAnimBlendAssoc->hierarchy->sequences[0].GetTranslation(0)); + ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + pAnimBlendAssoc->hierarchy->sequences[0].GetStartTranslation()); CWorld::Add(ms_pCutsceneObjects[i]); pAnimBlendAssoc->SetRun(); } else { diff --git a/src/liberty/peds/PedAI.cpp b/src/liberty/peds/PedAI.cpp index b6e575c9..0fe9542f 100644 --- a/src/liberty/peds/PedAI.cpp +++ b/src/liberty/peds/PedAI.cpp @@ -4249,7 +4249,7 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) if (!seq->HasTranslation()) vecPedDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); else { - vecPedDraggedOutCarAnimOffset = seq->GetTranslation(seq->numFrames - 1); + vecPedDraggedOutCarAnimOffset = seq->GetEndTranslation(); } } @@ -4260,7 +4260,7 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) if (!seq->HasTranslation()) vecPedCarDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); else { - vecPedCarDoorAnimOffset = seq->GetTranslation(seq->numFrames - 1); + vecPedCarDoorAnimOffset = seq->GetEndTranslation(); } } @@ -4271,7 +4271,7 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) if (!seq->HasTranslation()) vecPedCarDoorLoAnimOffset = CVector(0.0f, 0.0f, 0.0f); else { - vecPedCarDoorLoAnimOffset = seq->GetTranslation(seq->numFrames - 1); + vecPedCarDoorLoAnimOffset = seq->GetEndTranslation(); } } @@ -4282,7 +4282,7 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) if (!seq->HasTranslation()) vecPedQuickDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); else { - vecPedQuickDraggedOutCarAnimOffset = seq->GetTranslation(seq->numFrames - 1); + vecPedQuickDraggedOutCarAnimOffset = seq->GetEndTranslation(); } } @@ -4293,7 +4293,7 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) if (!seq->HasTranslation()) vecPedVanRearDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); else { - vecPedVanRearDoorAnimOffset = seq->GetTranslation(seq->numFrames - 1); + vecPedVanRearDoorAnimOffset = seq->GetEndTranslation(); } } @@ -4304,7 +4304,7 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) if (!seq->HasTranslation()) vecPedTrainDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); else { - vecPedTrainDoorAnimOffset = seq->GetTranslation(seq->numFrames - 1); + vecPedTrainDoorAnimOffset = seq->GetEndTranslation(); } } } diff --git a/src/miami/animation/AnimBlendAssociation.cpp b/src/miami/animation/AnimBlendAssociation.cpp index ea7a37f4..72839bf4 100644 --- a/src/miami/animation/AnimBlendAssociation.cpp +++ b/src/miami/animation/AnimBlendAssociation.cpp @@ -41,14 +41,11 @@ CAnimBlendAssociation::~CAnimBlendAssociation(void) link.Remove(); } -// static unsigned ndcount = 0; void CAnimBlendAssociation::AllocateAnimBlendNodeArray(int n) { int i; - // ndcount += numNodes; - // fprintf(stderr, "ndcount = %d, %lu, %lu\n", ndcount, sizeof(CAnimBlendNode), sizeof(CAnimBlendPlayer)); nodes = (CAnimBlendNode*)RwMallocAlign(n*sizeof(CAnimBlendNode), 64); for(i = 0; i < n; i++) nodes[i].Init(); @@ -58,7 +55,6 @@ void CAnimBlendAssociation::FreeAnimBlendNodeArray(void) { if(nodes) { - // ndcount -= numNodes; for(unsigned i = 0; i < numNodes; i++) nodes[i].Destroy(); RwFreeAlign(nodes); diff --git a/src/miami/animation/AnimBlendHierarchy.cpp b/src/miami/animation/AnimBlendHierarchy.cpp index 7b0b9f1c..ee7413fc 100644 --- a/src/miami/animation/AnimBlendHierarchy.cpp +++ b/src/miami/animation/AnimBlendHierarchy.cpp @@ -40,15 +40,6 @@ CAnimBlendHierarchy::CalcTotalTime(void) } } -// void -// CAnimBlendHierarchy::RemoveQuaternionFlips(void) -// { -// int i; - -// for(i = 0; i < numSequences; i++) -// sequences[i].RemoveQuaternionFlips(); -// } - void CAnimBlendHierarchy::RemoveAnimSequences(void) { diff --git a/src/miami/animation/AnimBlendHierarchy.h b/src/miami/animation/AnimBlendHierarchy.h index 9780b62f..d363122e 100644 --- a/src/miami/animation/AnimBlendHierarchy.h +++ b/src/miami/animation/AnimBlendHierarchy.h @@ -21,7 +21,6 @@ public: void Shutdown(void); void SetName(char *name); void CalcTotalTime(void); - // void RemoveQuaternionFlips(void); void RemoveAnimSequences(void); void Uncompress(void); void RemoveUncompressedData(void); diff --git a/src/miami/animation/AnimBlendNode.cpp b/src/miami/animation/AnimBlendNode.cpp index 6f35e9ca..84bf8874 100644 --- a/src/miami/animation/AnimBlendNode.cpp +++ b/src/miami/animation/AnimBlendNode.cpp @@ -14,11 +14,7 @@ CAnimBlendNode::Init(void) player = nil; } -void CAnimBlendNode::Setup() { - player = nil; - // player->Init(sequence->keyFrames, sequence->type, sequence->numFrames); -} -void CAnimBlendNode::Destroy() { +void CAnimBlendNode::Destroy(void) { if (player) { delete player; player = nil; @@ -28,7 +24,7 @@ void CAnimBlendNode::Destroy() { bool CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight) { - assert (player->keyFrames == sequence->keyFrames); + assert (player && player->keyFrames == sequence->keyFrames); bool looped = false; diff --git a/src/miami/animation/AnimBlendNode.h b/src/miami/animation/AnimBlendNode.h index e9a2cd8d..78db24c7 100644 --- a/src/miami/animation/AnimBlendNode.h +++ b/src/miami/animation/AnimBlendNode.h @@ -20,15 +20,13 @@ public: CAnimBlendAssociation *association; void Init(void); + void Destroy(void); bool Update(CVector &trans, CQuaternion &rot, float weight); bool NextKeyFrame(void); bool FindKeyFrame(float t); void CalcDeltas(void); void GetCurrentTranslation(CVector &trans, float weight); void GetEndTranslation(CVector &trans, float weight); - - void Setup(); - void Destroy(); }; diff --git a/src/miami/animation/AnimBlendSequence.cpp b/src/miami/animation/AnimBlendSequence.cpp index ff6084e6..8262252d 100644 --- a/src/miami/animation/AnimBlendSequence.cpp +++ b/src/miami/animation/AnimBlendSequence.cpp @@ -23,26 +23,6 @@ CAnimBlendSequence::SetName(char *name) strncpy(this->name, name, 24); } -// void -// CAnimBlendSequence::RemoveQuaternionFlips(void) -// { -// int i; -// CQuaternion last; - -// if(numFrames < 2) -// return; - -// last = GetRotation(0); -// for(i = 1; i < numFrames; i++){ -// auto KFr = GetRotation(i); -// if(DotProduct(last, KFr) < 0.0f) -// SetRotation(i, -KFr); -// last = GetRotation(i); -// } -// } - -// unsigned CAnimBlendPlayer::count = 0; - #ifdef USE_CUSTOM_ALLOCATOR bool CAnimBlendSequence::MoveMemory(void) diff --git a/src/miami/animation/AnimBlendSequence.h b/src/miami/animation/AnimBlendSequence.h index 34e6a5cb..0de7098d 100644 --- a/src/miami/animation/AnimBlendSequence.h +++ b/src/miami/animation/AnimBlendSequence.h @@ -41,18 +41,6 @@ struct CAnimBlendPlayer { float predicted_tx = 0, predicted_ty = 0, predicted_tz = 0; float nextDeltaTime; - #if !defined(DC_TEXCONV) - // static unsigned count; - - // CAnimBlendPlayer() { - // count++; - // fprintf(stderr, "CAnimBlendPlayer count %d\n", count); - // } - // ~CAnimBlendPlayer() { - // count--; - // } - #endif - template T read_unaligned(uint32_t ro) { T rv; diff --git a/src/miami/animation/AnimManager.cpp b/src/miami/animation/AnimManager.cpp index 06cfcb48..73388016 100644 --- a/src/miami/animation/AnimManager.cpp +++ b/src/miami/animation/AnimManager.cpp @@ -1249,9 +1249,10 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedA int j, k, l; float *fbuf = (float*)buf; - // block name RwStreamRead(stream, &anpv, sizeof(IfpHeader)); assert(memcmp(anpv.ident, "ANPV", 4) == 0); + + // block name RwStreamRead(stream, buf, anpv.size); int32_t numAnims; RwStreamRead(stream, &numAnims, sizeof(numAnims)); diff --git a/src/tools/animtool.cpp b/src/tools/animtool.cpp index 49bcbc9b..78372f0c 100644 --- a/src/tools/animtool.cpp +++ b/src/tools/animtool.cpp @@ -497,7 +497,11 @@ struct sequence_t { } if (trans.size() > 0) { - if (fabs(trans[0].x) > 127 || fabs(trans[0].y) > 127 || fabs(trans[1].z) > 127) { + if (fabs(trans.front().x) > 127 || fabs(trans.front().y) > 127 || fabs(trans.front().z) > 127) { + flags |= FLAGS_HAS_TRANS_LARGE; + } + + if (fabs(trans.back().x) > 127 || fabs(trans.back().y) > 127 || fabs(trans.back().z) > 127) { flags |= FLAGS_HAS_TRANS_LARGE; } }