mirror of https://github.com/zeldaret/mm.git
Extract Keyframe Assets data (#1664)
* git subrepo pull --force tools/ZAPD subrepo: subdir: "tools/ZAPD" merged: "c31c5e9fe" upstream: origin: "https://github.com/zeldaret/ZAPD.git" branch: "master" commit: "c31c5e9fe" git-subrepo: version: "0.4.6" origin: "git@github.com:ingydotnet/git-subrepo.git" commit: "110b9eb" * extract keyframe data * initialize typo
This commit is contained in:
parent
6f5352e6c2
commit
bd776e6bf5
|
@ -970,15 +970,12 @@
|
|||
<Texture Name="gSwordBeam2Tex" OutName="sword_beam_2" Format="i8" Width="32" Height="64" Offset="0x271E0" />
|
||||
<DList Name="gSwordBeamDL" Offset="0x27CA0" />
|
||||
|
||||
<Blob Name="gameplay_keep_Blob_027DD0" Size="0x32C" Offset="0x27DD0" />
|
||||
<Blob Name="gameplay_keep_Blob_0281DC" Size="0x14" Offset="0x281DC" />
|
||||
|
||||
<KeyFrameAnimation Name="gameplay_keep_KFAnim_0281DC" Skel="0x2900C" Offset="0x281DC"/>
|
||||
<DList Name="gameplay_keep_DL_0282D0" Offset="0x282D0" />
|
||||
<Texture Name="gameplay_keep_Tex_0283B8" OutName="tex_0283B8" Format="i4" Width="64" Height="64" Offset="0x283B8" />
|
||||
<Texture Name="gameplay_keep_Tex_028BB8" OutName="tex_028BB8" Format="i8" Width="32" Height="32" Offset="0x28BB8" />
|
||||
<TextureAnimation Name="gameplay_keep_Matanimheader_028FEC" Offset="0x28FEC" />
|
||||
<Blob Name="gameplay_keep_Blob_028FFC" Size="0x10" Offset="0x28FFC" />
|
||||
<Blob Name="gameplay_keep_Blob_02900C" Size="0x14" Offset="0x2900C" />
|
||||
<KeyFrameSkel Name="gameplay_keep_KFSkel_02900C" LimbType="Flex" Offset="0x2900C"/>
|
||||
<Animation Name="gameplay_keep_Anim_029140" Offset="0x29140" />
|
||||
<Texture Name="gameplay_keep_Tex_029150" OutName="tex_029150" Format="i8" Width="32" Height="64" Offset="0x29150" />
|
||||
<DList Name="gameplay_keep_DL_029990" Offset="0x29990" />
|
||||
|
@ -1333,10 +1330,7 @@
|
|||
<Texture Name="gameplay_keep_Tex_06ABF8" OutName="tex_06ABF8" Format="rgba16" Width="36" Height="36" Offset="0x6ABF8" />
|
||||
<TextureAnimation Name="gameplay_keep_Matanimheader_06B6A0" Offset="0x6B6A0" />
|
||||
<TextureAnimation Name="gameplay_keep_Matanimheader_06B730" Offset="0x6B730" />
|
||||
|
||||
<Blob Name="gameplay_keep_Blob_06B750" Size="0x3BC" Offset="0x6B750" />
|
||||
<Blob Name="gameplay_keep_Blob_06BB0C" Size="0x14" Offset="0x6BB0C" />
|
||||
|
||||
<KeyFrameAnimation Name="gameplay_keep_KFAnim_06BB0C" Skel="0x6EB70" Offset="0x6BB0C"/>
|
||||
<DList Name="gameplay_keep_DL_06BFE0" Offset="0x6BFE0" />
|
||||
<DList Name="gameplay_keep_DL_06C098" Offset="0x6C098" />
|
||||
<DList Name="gameplay_keep_DL_06C1E8" Offset="0x6C1E8" />
|
||||
|
@ -1345,8 +1339,7 @@
|
|||
<Texture Name="gameplay_keep_Tex_06D350" OutName="tex_06D350" Format="i4" Width="64" Height="64" Offset="0x6D350" />
|
||||
<Texture Name="gameplay_keep_Tex_06DB50" OutName="tex_06DB50" Format="i4" Width="64" Height="64" Offset="0x6DB50" />
|
||||
<Texture Name="gameplay_keep_Tex_06E350" OutName="tex_06E350" Format="i4" Width="64" Height="64" Offset="0x6E350" />
|
||||
<Blob Name="gameplay_keep_Blob_06EB50" Size="0x20" Offset="0x6EB50" />
|
||||
<Blob Name="gameplay_keep_Blob_06EB70" Size="0x10" Offset="0x6EB70" />
|
||||
<KeyFrameSkel Name="gameplay_keep_KFSkel_06EB70" LimbType="Flex" Offset="0x6EB70"/>
|
||||
<Texture Name="gameplay_keep_Tex_06EB80" OutName="tex_06EB80" Format="i4" Width="64" Height="64" Offset="0x6EB80" />
|
||||
<DList Name="gameplay_keep_DL_06F380" Offset="0x6F380" />
|
||||
<DList Name="gameplay_keep_DL_06F9F0" Offset="0x6F9F0" />
|
||||
|
@ -1450,8 +1443,7 @@
|
|||
<DList Name="gSoaringWarpCsEmptyDL" Offset="0x81620" />
|
||||
<DList Name="gSoaringWarpCsFeatherDL" Offset="0x81628" />
|
||||
<Texture Name="gSoaringWarpCsFeatherTex" OutName="soaring_warp_cs_feather" Format="rgba16" Width="16" Height="32" Offset="0x816C0" />
|
||||
<Blob Name="gameplay_keep_Blob_081AC0" Size="0x1A74" Offset="0x81AC0" />
|
||||
<Blob Name="gameplay_keep_Blob_083534" Size="0x1C" Offset="0x83534" /> <!-- Is a `KeyFrameAnimation` struct -->
|
||||
<KeyFrameAnimation Name="gameplay_keep_KFAnim_083534" Skel="0x85640" Offset="0x83534"/>
|
||||
<DList Name="gameplay_keep_DL_084790" Offset="0x84790" />
|
||||
<DList Name="gameplay_keep_DL_0847E0" Offset="0x847E0" />
|
||||
<DList Name="gameplay_keep_DL_084850" Offset="0x84850" />
|
||||
|
@ -1482,8 +1474,7 @@
|
|||
<DList Name="gameplay_keep_DL_0853B0" Offset="0x853B0" />
|
||||
<DList Name="gameplay_keep_DL_085418" Offset="0x85418" />
|
||||
<DList Name="gameplay_keep_DL_085490" Offset="0x85490" />
|
||||
<Blob Name="gameplay_keep_Blob_085510" Size="0x130" Offset="0x85510" />
|
||||
<Blob Name="gameplay_keep_Blob_085640" Size="0x10" Offset="0x85640" /> <!-- Is a `KeyFrameSkeleton` struct -->
|
||||
<KeyFrameSkel Name="gameplay_keep_KFSkel_085640" LimbType="Flex" Offset="0x85640"/>
|
||||
|
||||
<!-- Zora Elegy of Emptiness Shell -->
|
||||
<DList Name="gElegyShellZoraDL" Offset="0x89070" /> <!-- Original name is "pzs_zo_model" -->
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
<Texture Name="gOpenMouthMoonFaceTex" OutName="open_mouth_moon_face" Format="ci4" Width="64" Height="64" Offset="0x44E8" />
|
||||
<Texture Name="gOpenMouthMoonTeethTex" OutName="open_mouth_moon_teeth" Format="rgba16" Width="64" Height="32" Offset="0x4CE8" />
|
||||
<TextureAnimation Name="object_fall2_Matanimheader_005CF0" Offset="0x5CF0" /> <!-- Empty TexAnim -->
|
||||
<!-- <Blob Name="object_fall2_Blob_005CF8" Size="0x11C" Offset="0x5CF8" /> -->
|
||||
<Blob Name="object_fall2_Blob_005EF4" Size="0x1C" Offset="0x5EF4" /> <!-- Original name might be "moon_start_anm"; needs c_keyframe docs to know if it's this one or the one below. -->
|
||||
<KeyFrameAnimation Name="object_fall2_KFAnim_005EF4" Skel="0x8898" Offset="0x5EF4"/> <!-- Original name is "moon_start_anm" -->
|
||||
<Array Name="object_fall2_Vtx_005F10" Count="239" Offset="0x5F10">
|
||||
<Vtx />
|
||||
</Array>
|
||||
|
@ -30,6 +29,6 @@
|
|||
<Texture Name="object_fall2_Tex_007838" OutName="tex_007838" Format="i4" Width="64" Height="64" Offset="0x7838" />
|
||||
<Texture Name="object_fall2_Tex_008038" OutName="tex_008038" Format="i4" Width="64" Height="64" Offset="0x8038" />
|
||||
<TextureAnimation Name="object_fall2_Matanimheader_008840" Offset="0x8840" />
|
||||
<Blob Name="object_fall2_Blob_008898" Size="0x8" Offset="0x8898" /> <!-- Original name might be "moon_start_anm"; needs c_keyframe docs to know if it's this one or the one above. -->
|
||||
<KeyFrameSkel Name="object_fall2_KFSkel_008898" LimbType="Flex" Offset="0x8898"/>
|
||||
</File>
|
||||
</Root>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<Root>
|
||||
<File Name="object_moonend" Segment="6">
|
||||
<Blob Name="object_moonend_Blob_000000" Size="0x1214" Offset="0x0" />
|
||||
<Blob Name="object_moonend_Blob_001214" Size="0x1C" Offset="0x1214" />
|
||||
|
||||
<KeyFrameAnimation Name="object_moonened_KFAnim_001214" Skel="0xB5A0" Offset="0x1214"/>
|
||||
<DList Name="object_moonend_DL_0055F0" Offset="0x55F0" />
|
||||
<DList Name="object_moonend_DL_0061F8" Offset="0x61F8" />
|
||||
<DList Name="object_moonend_DL_006460" Offset="0x6460" />
|
||||
|
@ -21,10 +19,8 @@
|
|||
<Texture Name="object_moonend_Tex_009530" OutName="tex_009530" Format="i8" Width="64" Height="64" Offset="0x9530" />
|
||||
<Texture Name="object_moonend_Tex_00A530" OutName="tex_00A530" Format="i8" Width="64" Height="64" Offset="0xA530" />
|
||||
<TextureAnimation Name="object_moonend_Matanimheader_00B540" Offset="0xB540" />
|
||||
|
||||
<Blob Name="object_moonend_Blob_00B550" Size="0x50" Offset="0xB550" />
|
||||
<Blob Name="object_moonend_Blob_00B5A0" Size="0x170" Offset="0xB5A0" />
|
||||
|
||||
<KeyFrameSkel Name="object_moonend_KFSkel_00B5A0" LimbType="Flex" Offset="0xB5A0"/>
|
||||
<KeyFrameAnimation Name="object_moonened_KFAnim_00B6F4" Skel="0xE690" Offset="0xB6F4"/>
|
||||
<DList Name="object_moonend_DL_00CCF0" Offset="0xCCF0" />
|
||||
<DList Name="object_moonend_DL_00CF58" Offset="0xCF58" />
|
||||
<DList Name="object_moonend_DL_00D080" Offset="0xD080" />
|
||||
|
@ -34,7 +30,7 @@
|
|||
<DList Name="object_moonend_DL_00D520" Offset="0xD520" />
|
||||
<Texture Name="object_moonend_Tex_00D648" OutName="tex_00D648" Format="i8" Width="64" Height="64" Offset="0xD648" />
|
||||
<TextureAnimation Name="object_moonend_Matanimheader_00E650" Offset="0xE650" />
|
||||
<!-- <Blob Name="object_moonend_Blob_00E658" Size="0x48" Offset="0xE658" /> -->
|
||||
<KeyFrameSkel Name="object_moonend_KFSkel_00E690" LimbType="Flex" Offset="0xE690"/>
|
||||
<DList Name="object_moonend_DL_00EB00" Offset="0xEB00" />
|
||||
<Texture Name="object_moonend_Tex_00EC58" OutName="tex_00EC58" Format="i8" Width="64" Height="64" Offset="0xEC58" />
|
||||
<DList Name="object_moonend_DL_010C40" Offset="0x10C40" /> <!-- Original name is "rainbow_model" -->
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<Root>
|
||||
<File Name="object_syoten" Segment="6">
|
||||
<Blob Name="object_syoten_Blob_000000" Size="0x23C" Offset="0x0" />
|
||||
<Blob Name="object_syoten_Blob_00023C" Size="0x14" Offset="0x23C" />
|
||||
|
||||
<KeyFrameAnimation Name="object_syoten_KFAnim_00023C" Skel="0x1328" Offset="0x23C"/>
|
||||
<DList Name="object_syoten_DL_000450" Offset="0x450" />
|
||||
<DList Name="object_syoten_DL_000518" Offset="0x518" />
|
||||
<DList Name="object_syoten_DL_0005E0" Offset="0x5E0" />
|
||||
|
@ -14,10 +12,7 @@
|
|||
<Texture Name="object_syoten_Tex_000A90" OutName="tex_000A90" Format="i8" Width="32" Height="32" Offset="0xA90" />
|
||||
<Texture Name="object_syoten_Tex_000E90" OutName="tex_000E90" Format="i8" Width="32" Height="32" Offset="0xE90" />
|
||||
<TextureAnimation Name="object_syoten_Matanimheader_001298" Offset="0x1298" />
|
||||
|
||||
<!-- <Blob Name="object_syoten_Blob_0012A0" Size="0x88" Offset="0x12A0" /> -->
|
||||
<Blob Name="object_syoten_Blob_001328" Size="0x8" Offset="0x1328" />
|
||||
|
||||
<KeyFrameSkel Name="object_syoten_KFSkel_001328" LimbType="Flex" Offset="0x1328"/>
|
||||
<DList Name="object_syoten_DL_001370" Offset="0x1370" />
|
||||
<TextureAnimation Name="object_syoten_Matanimheader_001448" Offset="0x1448" />
|
||||
<DList Name="object_syoten_DL_001730" Offset="0x1730" />
|
||||
|
|
|
@ -70,6 +70,8 @@ typedef struct {
|
|||
// Array of bitflags for each limb indicating whether to do keyframe interpolation
|
||||
// or pull from fixed values that do not change throughout the animation.
|
||||
union {
|
||||
// Used to initialize bitflags without warnings
|
||||
/* 0x00 */ void* data;
|
||||
// For standard the bit layout in each array element is:
|
||||
// [5] X Translation (root limb only)
|
||||
// [4] Y Translation (root limb only)
|
||||
|
|
|
@ -46,9 +46,9 @@ void DemoMoonend_Init(Actor* thisx, PlayState* play) {
|
|||
this->actionFunc = func_80C17B60;
|
||||
} else {
|
||||
Actor_SetScale(&this->actor, 0.095f);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, (KeyFrameFlexSkeleton*)&object_moonend_Blob_00B5A0,
|
||||
(KeyFrameAnimation*)&object_moonend_Blob_001214, this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, (KeyFrameAnimation*)&object_moonend_Blob_001214);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, &object_moonend_KFSkel_00B5A0, &object_moonened_KFAnim_001214,
|
||||
this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, &object_moonened_KFAnim_001214);
|
||||
this->cueType = CS_CMD_ACTOR_CUE_560;
|
||||
this->actionFunc = func_80C17C48;
|
||||
this->actor.home.rot.z = 0;
|
||||
|
@ -110,13 +110,13 @@ void func_80C17C48(DemoMoonend* this, PlayState* play) {
|
|||
switch (this->cueId) {
|
||||
case 1:
|
||||
this->actor.draw = DemoMoonend_Draw;
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, (KeyFrameAnimation*)&object_moonend_Blob_001214);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, &object_moonened_KFAnim_001214);
|
||||
this->kfSkelAnime.frameCtrl.speed = 0.0f;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this->actor.draw = DemoMoonend_Draw;
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, (KeyFrameAnimation*)&object_moonend_Blob_001214);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, &object_moonened_KFAnim_001214);
|
||||
this->kfSkelAnime.frameCtrl.speed = 2.0f / 3.0f;
|
||||
Actor_PlaySfx(&this->actor, NA_SE_EV_MOON_EXPLOSION);
|
||||
this->actor.home.rot.z = 1;
|
||||
|
|
|
@ -73,9 +73,9 @@ void DemoSyoten_Init(Actor* thisx, PlayState* play) {
|
|||
|
||||
switch (DEMOSYOTEN_GET_F(&this->actor)) {
|
||||
case DEMOSYOTEN_F_0:
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, (KeyFrameFlexSkeleton*)&object_syoten_Blob_001328,
|
||||
(KeyFrameAnimation*)&object_syoten_Blob_00023C, this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayLoop(&this->kfSkelAnime, (KeyFrameAnimation*)&object_syoten_Blob_00023C);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, &object_syoten_KFSkel_001328, &object_syoten_KFAnim_00023C,
|
||||
this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayLoop(&this->kfSkelAnime, &object_syoten_KFAnim_00023C);
|
||||
this->actor.draw = NULL;
|
||||
this->actionFunc = func_80C16A74;
|
||||
this->actor.child =
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* Description: Blue warp portal and crystal, and the Majora's Mask-shaped boss warp platform
|
||||
*/
|
||||
|
||||
#include "prevent_bss_reordering.h"
|
||||
#include "z_door_warp1.h"
|
||||
#include "objects/object_warp1/object_warp1.h"
|
||||
|
||||
|
|
|
@ -50,9 +50,9 @@ void EffChange_Init(Actor* thisx, PlayState* play) {
|
|||
EffChange_SetColors(this, EFFCHANGE_GET_COLORS(thisx));
|
||||
Actor_SetScale(&this->actor, 0.075f);
|
||||
this->primColors[3] = 0;
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, (KeyFrameFlexSkeleton*)&gameplay_keep_Blob_02900C,
|
||||
(KeyFrameAnimation*)&gameplay_keep_Blob_0281DC, this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, (KeyFrameAnimation*)&gameplay_keep_Blob_0281DC);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, &gameplay_keep_KFSkel_02900C, &gameplay_keep_KFAnim_0281DC, this->jointTable,
|
||||
this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, &gameplay_keep_KFAnim_0281DC);
|
||||
this->step = 0;
|
||||
this->actor.shape.rot.y = 0;
|
||||
this->kfSkelAnime.frameCtrl.speed = 2.0f / 3.0f;
|
||||
|
|
|
@ -35,9 +35,9 @@ void EnFall2_Init(Actor* thisx, PlayState* play) {
|
|||
|
||||
Actor_SetScale(&this->actor, 1.0f);
|
||||
this->actionFunc = EnFall2_DoNothing;
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, (KeyFrameFlexSkeleton*)&object_fall2_Blob_008898,
|
||||
(KeyFrameAnimation*)&object_fall2_Blob_005EF4, this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayLoop(&this->kfSkelAnime, (KeyFrameAnimation*)&object_fall2_Blob_005EF4);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, &object_fall2_KFSkel_008898, &object_fall2_KFAnim_005EF4, this->jointTable,
|
||||
this->morphTable, NULL);
|
||||
Keyframe_FlexPlayLoop(&this->kfSkelAnime, &object_fall2_KFAnim_005EF4);
|
||||
this->unk2DC = Lib_SegmentedToVirtual(object_fall2_Matanimheader_008840);
|
||||
Actor_SetScale(&this->actor, 0.02f);
|
||||
this->actionFunc = EnFall2_HandleCutscene;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* Description: Seahorse
|
||||
*/
|
||||
|
||||
#include "prevent_bss_reordering.h"
|
||||
#include "z_en_ot.h"
|
||||
#include "objects/gameplay_keep/gameplay_keep.h"
|
||||
|
||||
|
|
|
@ -186,9 +186,9 @@ void EnTest_Init(Actor* thisx, PlayState* play2) {
|
|||
this->surfaceMaterial = SurfaceType_GetMaterial(&play->colCtx, thisx->floorPoly, bgId);
|
||||
}
|
||||
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, (KeyFrameFlexSkeleton*)&gameplay_keep_Blob_06EB70,
|
||||
(KeyFrameAnimation*)&gameplay_keep_Blob_06BB0C, this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, (KeyFrameAnimation*)&gameplay_keep_Blob_06BB0C);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, &gameplay_keep_KFSkel_06EB70, &gameplay_keep_KFAnim_06BB0C, this->jointTable,
|
||||
this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, &gameplay_keep_KFAnim_06BB0C);
|
||||
this->kfSkelAnime.frameCtrl.curTime = 9.0f;
|
||||
func_80862B70(this->unk_20C);
|
||||
}
|
||||
|
|
|
@ -383,9 +383,9 @@ void EnTest7_Init(Actor* thisx, PlayState* play2) {
|
|||
this->playerScaleZ = player->actor.scale.z;
|
||||
|
||||
// Keyframe animations
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, (KeyFrameFlexSkeleton*)&gameplay_keep_Blob_085640,
|
||||
(KeyFrameAnimation*)&gameplay_keep_Blob_083534, this->jointTable, this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, (KeyFrameAnimation*)&gameplay_keep_Blob_083534);
|
||||
Keyframe_InitFlex(&this->kfSkelAnime, &gameplay_keep_KFSkel_085640, &gameplay_keep_KFAnim_083534, this->jointTable,
|
||||
this->morphTable, NULL);
|
||||
Keyframe_FlexPlayOnce(&this->kfSkelAnime, &gameplay_keep_KFAnim_083534);
|
||||
|
||||
EnTest7_InitFeathers(this->feathers);
|
||||
EnTest7_InitWindCapsule(&this->windCapsule);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
name: Build ZAPD
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: self-hosted-runner
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build ZAPD
|
||||
run: make -j WERROR=1
|
||||
|
||||
- name: Checkout Repos
|
||||
run: echo "Checkout Repos"
|
||||
|
||||
- name: Checkout oot
|
||||
run: |
|
||||
cd ../
|
||||
rm -rf oot/
|
||||
git clone https://github.com/zeldaret/oot.git
|
||||
cd oot
|
||||
echo $(pwd)
|
||||
git submodule update --init --recursive
|
||||
|
||||
- name: Checkout mm
|
||||
run: |
|
||||
cd ../
|
||||
rm -rf mm/
|
||||
git clone https://github.com/zeldaret/mm.git
|
||||
cd mm
|
||||
echo $(pwd)
|
||||
|
||||
- name: Set up repos
|
||||
run: echo "Set up repos"
|
||||
|
||||
- name: Setup OOT
|
||||
run: |
|
||||
cd ../
|
||||
cd oot
|
||||
echo $(pwd)
|
||||
mkdir -p baseroms/gc-eu-mq-dbg/segments
|
||||
cp ~/baserom_original.z64 ./baseroms/gc-eu-mq-dbg/baserom.z64
|
||||
cd tools
|
||||
rm -rf ZAPD/
|
||||
ln -s ../../ZAPD
|
||||
cd ../
|
||||
make -j $(nproc) setup
|
||||
|
||||
- name: Setup MM
|
||||
run: |
|
||||
cd ../
|
||||
cd mm
|
||||
echo $(pwd)
|
||||
python3 -m venv .mm-env
|
||||
source .mm-env/bin/activate
|
||||
python3 -m pip install -r requirements.txt
|
||||
cp ~/baserom.mm.us.rev1.z64 ./baserom.mm.us.rev1.z64
|
||||
cd tools
|
||||
rm -rf ZAPD/
|
||||
ln -s ../../ZAPD
|
||||
cd ../
|
||||
make -C tools -j
|
||||
python3 tools/fixbaserom.py
|
||||
python3 tools/extract_baserom.py
|
||||
python3 tools/decompress_yars.py
|
||||
python3 extract_assets.py -j $(nproc)
|
||||
|
||||
- name: Build Repos
|
||||
run: echo "Build Repos"
|
||||
|
||||
- name: Build oot
|
||||
run: |
|
||||
cd ../
|
||||
cd oot
|
||||
echo $(pwd)
|
||||
make venv
|
||||
make -j
|
||||
|
||||
- name: Build mm
|
||||
run: |
|
||||
cd ../
|
||||
cd mm
|
||||
echo $(pwd)
|
||||
python3 -m venv .mm-env
|
||||
source .mm-env/bin/activate
|
||||
python3 -m pip install -r requirements.txt
|
||||
make -j disasm
|
||||
make -j
|
||||
|
||||
- name: Clean workspace
|
||||
run: git clean -fdX
|
|
@ -6,7 +6,7 @@
|
|||
[subrepo]
|
||||
remote = https://github.com/zeldaret/ZAPD.git
|
||||
branch = master
|
||||
commit = 9601f2699c142bb8273d33763ef4d84e8a7d650f
|
||||
parent = 3e1207d5e7818ab6676422cda10f206b180126db
|
||||
commit = c31c5e9fec72863e38cdfef8c0b1915140234253
|
||||
parent = 1685597d9aded6ee06f4e191954940331e34f346
|
||||
method = merge
|
||||
cmdver = 0.4.6
|
||||
|
|
|
@ -117,6 +117,16 @@ ZAPD also accepts the following list of extra parameters:
|
|||
- `-us` / `--unaccounted-static` : Mark unaccounted data as `static`
|
||||
- `-s` / `--static` : Mark every asset as `static`.
|
||||
- This behaviour can be overridden per asset using `Static=` in the respective XML node.
|
||||
- `--cs-float` : How cutscene floats should be extracted.
|
||||
- Valid values:
|
||||
- `hex`: `0x42280000`
|
||||
- `float`: `42.0f`
|
||||
- `both`: `CS_FLOAT(0x42280000, 42.0f)`
|
||||
- `hex-commented-left`: `/* 42.0f */ 0x42280000`
|
||||
- `hex-commented-right`: `0x42280000 /* 42.0f */`
|
||||
- `--base-address ADDRESS`: Override base virtual address for input files.
|
||||
- `--start-offset OFFSET`: Override start offset for input files.
|
||||
- `--end-offset OFFSET`: Override end offset for input files.
|
||||
- `-W...`: warning flags, see below
|
||||
|
||||
Additionally, you can pass the flag `--version` to see the current ZAPD version. If that flag is passed, ZAPD will ignore any other parameter passed.
|
||||
|
|
|
@ -16,6 +16,15 @@ enum class VerbosityLevel
|
|||
VERBOSITY_DEBUG
|
||||
};
|
||||
|
||||
enum class CsFloatType
|
||||
{
|
||||
HexOnly,
|
||||
FloatOnly,
|
||||
HexAndFloat,
|
||||
HexAndCommentedFloatLeft,
|
||||
HexAndCommentedFloatRight,
|
||||
};
|
||||
|
||||
class Globals
|
||||
{
|
||||
public:
|
||||
|
@ -31,6 +40,10 @@ public:
|
|||
ZFileMode fileMode;
|
||||
fs::path baseRomPath, inputPath, outputPath, sourceOutputPath, cfgPath;
|
||||
TextureType texType;
|
||||
CsFloatType floatType = CsFloatType::FloatOnly;
|
||||
int64_t baseAddress = -1;
|
||||
int64_t startOffset = -1;
|
||||
int64_t endOffset = -1;
|
||||
ZGame game;
|
||||
GameConfig cfg;
|
||||
bool verboseUnaccounted = false;
|
||||
|
|
|
@ -36,11 +36,15 @@ void Arg_SetExporter(int& i, char* argv[]);
|
|||
void Arg_EnableGCCCompat(int& i, char* argv[]);
|
||||
void Arg_ForceStatic(int& i, char* argv[]);
|
||||
void Arg_ForceUnaccountedStatic(int& i, char* argv[]);
|
||||
void Arg_CsFloatMode(int& i, char* argv[]);
|
||||
void Arg_BaseAddress(int& i, char* argv[]);
|
||||
void Arg_StartOffset(int& i, char* argv[]);
|
||||
void Arg_EndOffset(int& i, char* argv[]);
|
||||
|
||||
int main(int argc, char* argv[]);
|
||||
|
||||
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
|
||||
ZFileMode fileMode);
|
||||
ZFileMode fileMode);
|
||||
|
||||
void ParseArgs(int& argc, char* argv[]);
|
||||
|
||||
|
@ -114,7 +118,7 @@ int main(int argc, char* argv[])
|
|||
returnCode = HandleExtract(fileMode, exporterSet);
|
||||
else if (fileMode == ZFileMode::BuildTexture)
|
||||
BuildAssetTexture(Globals::Instance->inputPath, Globals::Instance->texType,
|
||||
Globals::Instance->outputPath);
|
||||
Globals::Instance->outputPath);
|
||||
else if (fileMode == ZFileMode::BuildBackground)
|
||||
BuildAssetBackground(Globals::Instance->inputPath, Globals::Instance->outputPath);
|
||||
else if (fileMode == ZFileMode::BuildBlob)
|
||||
|
@ -125,7 +129,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
|
||||
ZFileMode fileMode)
|
||||
ZFileMode fileMode)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
tinyxml2::XMLError eResult = doc.LoadFile(xmlFilePath.string().c_str());
|
||||
|
@ -134,7 +138,7 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path
|
|||
{
|
||||
// TODO: use XMLDocument::ErrorIDToName to get more specific error messages here
|
||||
HANDLE_ERROR(WarningType::InvalidXML,
|
||||
StringHelper::Sprintf("invalid XML file: '%s'", xmlFilePath.c_str()), "");
|
||||
StringHelper::Sprintf("invalid XML file: '%s'", xmlFilePath.c_str()), "");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -149,7 +153,7 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path
|
|||
}
|
||||
|
||||
for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != NULL;
|
||||
child = child->NextSiblingElement())
|
||||
child = child->NextSiblingElement())
|
||||
{
|
||||
if (std::string_view(child->Name()) == "File")
|
||||
{
|
||||
|
@ -252,6 +256,10 @@ void ParseArgs(int& argc, char* argv[])
|
|||
{"--static", &Arg_ForceStatic},
|
||||
{"-us", &Arg_ForceUnaccountedStatic},
|
||||
{"--unaccounted-static", &Arg_ForceUnaccountedStatic},
|
||||
{"--cs-float", &Arg_CsFloatMode},
|
||||
{"--base-address", &Arg_BaseAddress},
|
||||
{"--start-offset", &Arg_StartOffset},
|
||||
{"--end-offset", &Arg_EndOffset},
|
||||
};
|
||||
|
||||
for (int32_t i = 2; i < argc; i++)
|
||||
|
@ -392,6 +400,62 @@ void Arg_ForceUnaccountedStatic([[maybe_unused]] int& i, [[maybe_unused]] char*
|
|||
Globals::Instance->forceUnaccountedStatic = true;
|
||||
}
|
||||
|
||||
void Arg_CsFloatMode([[maybe_unused]] int& i, [[maybe_unused]] char* argv[])
|
||||
{
|
||||
i++;
|
||||
if (std::strcmp(argv[i], "hex") == 0)
|
||||
{
|
||||
Globals::Instance->floatType = CsFloatType::HexOnly;
|
||||
}
|
||||
else if (std::strcmp(argv[i], "float") == 0)
|
||||
{
|
||||
Globals::Instance->floatType = CsFloatType::FloatOnly;
|
||||
}
|
||||
else if (std::strcmp(argv[i], "both") == 0)
|
||||
{
|
||||
Globals::Instance->floatType = CsFloatType::HexAndFloat;
|
||||
}
|
||||
else if (std::strcmp(argv[i], "hex-commented-left") == 0)
|
||||
{
|
||||
Globals::Instance->floatType = CsFloatType::HexAndCommentedFloatLeft;
|
||||
}
|
||||
else if (std::strcmp(argv[i], "hex-commented-right") == 0)
|
||||
{
|
||||
Globals::Instance->floatType = CsFloatType::HexAndCommentedFloatRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Globals::Instance->floatType = CsFloatType::FloatOnly;
|
||||
HANDLE_WARNING(
|
||||
WarningType::Always, "Invalid CS Float Type",
|
||||
StringHelper::Sprintf("Invalid CS float type entered. Expected \"hex\", \"float\", "
|
||||
"\"both\", \"hex-commented-left\" or \"hex-commented-right\". "
|
||||
"Got %s.\n Defaulting to \"float\".",
|
||||
argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ParseU32Hex(char* str)
|
||||
{
|
||||
static_assert(sizeof(uint32_t) <= sizeof(unsigned long));
|
||||
return (uint32_t)std::stoul(str, nullptr, 16);
|
||||
}
|
||||
|
||||
void Arg_BaseAddress(int& i, char* argv[])
|
||||
{
|
||||
Globals::Instance->baseAddress = ParseU32Hex(argv[++i]);
|
||||
}
|
||||
|
||||
void Arg_StartOffset(int& i, char* argv[])
|
||||
{
|
||||
Globals::Instance->startOffset = ParseU32Hex(argv[++i]);
|
||||
}
|
||||
|
||||
void Arg_EndOffset(int& i, char* argv[])
|
||||
{
|
||||
Globals::Instance->endOffset = ParseU32Hex(argv[++i]);
|
||||
}
|
||||
|
||||
int HandleExtract(ZFileMode fileMode, ExporterSet* exporterSet)
|
||||
{
|
||||
bool procFileModeSuccess = false;
|
||||
|
@ -412,14 +476,14 @@ int HandleExtract(ZFileMode fileMode, ExporterSet* exporterSet)
|
|||
printf("Parsing external file from config: '%s'\n", externalXmlFilePath.c_str());
|
||||
|
||||
parseSuccessful = Parse(externalXmlFilePath, Globals::Instance->baseRomPath,
|
||||
extFile.outPath, ZFileMode::ExternalFile);
|
||||
extFile.outPath, ZFileMode::ExternalFile);
|
||||
|
||||
if (!parseSuccessful)
|
||||
return 1;
|
||||
}
|
||||
|
||||
parseSuccessful = Parse(Globals::Instance->inputPath, Globals::Instance->baseRomPath,
|
||||
Globals::Instance->outputPath, fileMode);
|
||||
Globals::Instance->outputPath, fileMode);
|
||||
if (!parseSuccessful)
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "Utils/StringHelper.h"
|
||||
#include "WarningHandler.h"
|
||||
|
||||
#include "ZCutscene.h"
|
||||
|
||||
/**** GENERIC ****/
|
||||
|
||||
// Specific for command lists where each entry has size 8 bytes
|
||||
|
@ -127,8 +129,9 @@ std::string CutsceneMMCommand_GenericCmd::GetCommandMacro() const
|
|||
|
||||
/**** CAMERA ****/
|
||||
|
||||
CutsceneSubCommandEntry_SplineCamPoint::CutsceneSubCommandEntry_SplineCamPoint(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex): CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
CutsceneSubCommandEntry_SplineCamPoint::CutsceneSubCommandEntry_SplineCamPoint(
|
||||
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
|
||||
: CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
{
|
||||
interpType = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0);
|
||||
weight = BitConverter::ToUInt8BE(rawData, rawDataIndex + 1);
|
||||
|
@ -144,7 +147,9 @@ std::string CutsceneSubCommandEntry_SplineCamPoint::GetBodySourceCode() const
|
|||
const auto interpTypeMap = &Globals::Instance->cfg.enumData.interpType;
|
||||
const auto relToMap = &Globals::Instance->cfg.enumData.relTo;
|
||||
|
||||
return StringHelper::Sprintf("CS_CAM_POINT(%s, 0x%02X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, %s)", interpTypeMap->at(interpType).c_str(), weight, duration, posX, posY, posZ, relToMap->at(relTo).c_str());
|
||||
return StringHelper::Sprintf("CS_CAM_POINT(%s, 0x%02X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, %s)",
|
||||
interpTypeMap->at(interpType).c_str(), weight, duration, posX,
|
||||
posY, posZ, relToMap->at(relTo).c_str());
|
||||
}
|
||||
|
||||
size_t CutsceneSubCommandEntry_SplineCamPoint::GetRawSize() const
|
||||
|
@ -152,9 +157,9 @@ size_t CutsceneSubCommandEntry_SplineCamPoint::GetRawSize() const
|
|||
return 0x0C;
|
||||
}
|
||||
|
||||
|
||||
CutsceneSubCommandEntry_SplineMiscPoint::CutsceneSubCommandEntry_SplineMiscPoint(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex): CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
CutsceneSubCommandEntry_SplineMiscPoint::CutsceneSubCommandEntry_SplineMiscPoint(
|
||||
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
|
||||
: CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
{
|
||||
unused0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
|
||||
roll = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
|
||||
|
@ -164,7 +169,8 @@ CutsceneSubCommandEntry_SplineMiscPoint::CutsceneSubCommandEntry_SplineMiscPoint
|
|||
|
||||
std::string CutsceneSubCommandEntry_SplineMiscPoint::GetBodySourceCode() const
|
||||
{
|
||||
return StringHelper::Sprintf("CS_CAM_MISC(0x%04X, 0x%04X, 0x%04X, 0x%04X)", unused0, roll, fov, unused1);
|
||||
return StringHelper::Sprintf("CS_CAM_MISC(0x%04X, 0x%04X, 0x%04X, 0x%04X)", unused0, roll, fov,
|
||||
unused1);
|
||||
}
|
||||
|
||||
size_t CutsceneSubCommandEntry_SplineMiscPoint::GetRawSize() const
|
||||
|
@ -172,8 +178,9 @@ size_t CutsceneSubCommandEntry_SplineMiscPoint::GetRawSize() const
|
|||
return 0x08;
|
||||
}
|
||||
|
||||
CutsceneSubCommandEntry_SplineHeader::CutsceneSubCommandEntry_SplineHeader(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex): CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
CutsceneSubCommandEntry_SplineHeader::CutsceneSubCommandEntry_SplineHeader(
|
||||
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
|
||||
: CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
{
|
||||
numEntries = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0);
|
||||
unused0 = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
|
||||
|
@ -183,8 +190,8 @@ CutsceneSubCommandEntry_SplineHeader::CutsceneSubCommandEntry_SplineHeader(const
|
|||
|
||||
std::string CutsceneSubCommandEntry_SplineHeader::GetBodySourceCode() const
|
||||
{
|
||||
return StringHelper::Sprintf("CS_CAM_SPLINE(0x%04X, 0x%04X, 0x%04X, 0x%04X)", numEntries, unused0, unused1, duration);
|
||||
|
||||
return StringHelper::Sprintf("CS_CAM_SPLINE(0x%04X, 0x%04X, 0x%04X, 0x%04X)", numEntries,
|
||||
unused0, unused1, duration);
|
||||
}
|
||||
|
||||
size_t CutsceneSubCommandEntry_SplineHeader::GetRawSize() const
|
||||
|
@ -192,16 +199,19 @@ size_t CutsceneSubCommandEntry_SplineHeader::GetRawSize() const
|
|||
return 0x08;
|
||||
}
|
||||
|
||||
CutsceneSubCommandEntry_SplineFooter::CutsceneSubCommandEntry_SplineFooter(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex): CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
CutsceneSubCommandEntry_SplineFooter::CutsceneSubCommandEntry_SplineFooter(
|
||||
const std::vector<uint8_t>& rawData, offset_t rawDataIndex)
|
||||
: CutsceneSubCommandEntry(rawData, rawDataIndex)
|
||||
{
|
||||
uint16_t firstHalfWord = BitConverter::ToUInt16BE(rawData, rawDataIndex);
|
||||
uint16_t secondHalfWord = BitConverter::ToUInt16BE(rawData, rawDataIndex + 2);
|
||||
|
||||
if (firstHalfWord != 0xFFFF || secondHalfWord != 4) {
|
||||
if (firstHalfWord != 0xFFFF || secondHalfWord != 4)
|
||||
{
|
||||
HANDLE_ERROR(WarningType::InvalidExtractedData, "Invalid Spline Footer",
|
||||
StringHelper::Sprintf("Invalid Spline footer. Was expecting 0xFFFF, 0x0004. Got 0x%04X, 0x%04X",
|
||||
firstHalfWord, secondHalfWord));
|
||||
StringHelper::Sprintf(
|
||||
"Invalid Spline footer. Was expecting 0xFFFF, 0x0004. Got 0x%04X, 0x%04X",
|
||||
firstHalfWord, secondHalfWord));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,8 +233,10 @@ CutsceneMMCommand_Spline::CutsceneMMCommand_Spline(const std::vector<uint8_t>& r
|
|||
totalCommands = 0;
|
||||
rawDataIndex += 4;
|
||||
|
||||
while(1) {
|
||||
if (BitConverter::ToUInt16BE(rawData, rawDataIndex) == 0xFFFF) {
|
||||
while (1)
|
||||
{
|
||||
if (BitConverter::ToUInt16BE(rawData, rawDataIndex) == 0xFFFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
numHeaders++;
|
||||
|
@ -232,7 +244,7 @@ CutsceneMMCommand_Spline::CutsceneMMCommand_Spline(const std::vector<uint8_t>& r
|
|||
auto* header = new CutsceneSubCommandEntry_SplineHeader(rawData, rawDataIndex);
|
||||
rawDataIndex += header->GetRawSize();
|
||||
entries.push_back(header);
|
||||
|
||||
|
||||
totalCommands += header->numEntries;
|
||||
|
||||
for (uint32_t i = 0; i < header->numEntries; i++)
|
||||
|
@ -269,7 +281,8 @@ std::string CutsceneMMCommand_Spline::GetCommandMacro() const
|
|||
|
||||
size_t CutsceneMMCommand_Spline::GetCommandSize() const
|
||||
{
|
||||
// 8 Bytes once for the spline command, 8 Bytes per spline the header, two groups of size 12, 1 group of size 8, 4 bytes for the footer.
|
||||
// 8 Bytes once for the spline command, 8 Bytes per spline the header, two groups of size 12, 1
|
||||
// group of size 8, 4 bytes for the footer.
|
||||
return 8 + (8 * numHeaders) + ((totalCommands * 2) * 0xC) + (totalCommands * 8) + 4;
|
||||
}
|
||||
|
||||
|
@ -545,22 +558,29 @@ CutsceneMMSubCommandEntry_ActorCue::CutsceneMMSubCommandEntry_ActorCue(
|
|||
std::string CutsceneMMSubCommandEntry_ActorCue::GetBodySourceCode() const
|
||||
{
|
||||
EnumData* enumData = &Globals::Instance->cfg.enumData;
|
||||
std::string normalXStr =
|
||||
ZCutscene::GetCsEncodedFloat(normalX, Globals::Instance->floatType, true);
|
||||
std::string normalYStr =
|
||||
ZCutscene::GetCsEncodedFloat(normalY, Globals::Instance->floatType, true);
|
||||
std::string normalZStr =
|
||||
ZCutscene::GetCsEncodedFloat(normalZ, Globals::Instance->floatType, true);
|
||||
|
||||
if (static_cast<CutsceneMM_CommandType>(commandID) == CutsceneMM_CommandType::CS_CMD_PLAYER_CUE)
|
||||
{
|
||||
return StringHelper::Sprintf("CS_PLAYER_CUE(%s, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, "
|
||||
"%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)",
|
||||
"%i, %i, %i, %i, %s, %s, %s)",
|
||||
enumData->playerCueId[base].c_str(), startFrame, endFrame,
|
||||
rotX, rotY, rotZ, startPosX, startPosY, startPosZ, endPosX,
|
||||
endPosY, endPosZ, normalX, normalY, normalZ);
|
||||
endPosY, endPosZ, normalXStr.c_str(), normalYStr.c_str(),
|
||||
normalZStr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
return StringHelper::Sprintf("CS_ACTOR_CUE(%i, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, "
|
||||
"%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)",
|
||||
"%i, %i, %i, %i, %s, %s, %s)",
|
||||
base, startFrame, endFrame, rotX, rotY, rotZ, startPosX,
|
||||
startPosY, startPosZ, endPosX, endPosY, endPosZ, normalX,
|
||||
normalY, normalZ);
|
||||
startPosY, startPosZ, endPosX, endPosY, endPosZ,
|
||||
normalXStr.c_str(), normalYStr.c_str(), normalZStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -282,7 +282,8 @@ public:
|
|||
uint16_t posZ;
|
||||
uint16_t relTo;
|
||||
|
||||
CutsceneSubCommandEntry_SplineCamPoint(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
|
||||
CutsceneSubCommandEntry_SplineCamPoint(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex);
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
|
@ -296,8 +297,9 @@ public:
|
|||
uint16_t roll;
|
||||
uint16_t fov;
|
||||
uint16_t unused1;
|
||||
|
||||
CutsceneSubCommandEntry_SplineMiscPoint(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
|
||||
|
||||
CutsceneSubCommandEntry_SplineMiscPoint(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex);
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
|
@ -306,8 +308,9 @@ public:
|
|||
|
||||
class CutsceneSubCommandEntry_SplineFooter : public CutsceneSubCommandEntry
|
||||
{
|
||||
public:
|
||||
CutsceneSubCommandEntry_SplineFooter(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
|
||||
public:
|
||||
CutsceneSubCommandEntry_SplineFooter(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex);
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
|
@ -321,7 +324,8 @@ public:
|
|||
uint16_t unused0;
|
||||
uint16_t unused1;
|
||||
uint16_t duration;
|
||||
CutsceneSubCommandEntry_SplineHeader(const std::vector<uint8_t>& rawData, offset_t rawDataIndex);
|
||||
CutsceneSubCommandEntry_SplineHeader(const std::vector<uint8_t>& rawData,
|
||||
offset_t rawDataIndex);
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "Utils/BitConverter.h"
|
||||
#include "Utils/StringHelper.h"
|
||||
|
||||
#include "ZCutscene.h"
|
||||
|
||||
/**** GENERIC ****/
|
||||
|
||||
// Specific for command lists where each entry has size 0x30 bytes
|
||||
|
@ -13,7 +15,7 @@ const std::unordered_map<CutsceneOoT_CommandType, CsCommandListDescriptor> csCom
|
|||
{CutsceneOoT_CommandType::CS_CMD_MISC,
|
||||
{"CS_MISC", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
|
||||
{CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING,
|
||||
{"CS_LIGHT_SETTING", "(0x%02X, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
|
||||
{"CS_LIGHT_SETTING", "(0x%02X, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
|
||||
{CutsceneOoT_CommandType::CS_CMD_START_SEQ,
|
||||
{"CS_START_SEQ", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}},
|
||||
{CutsceneOoT_CommandType::CS_CMD_STOP_SEQ,
|
||||
|
@ -139,9 +141,11 @@ std::string CutsceneOoTCommand_CameraPoint::GetBodySourceCode() const
|
|||
if (continueFlag != 0)
|
||||
continueMacro = "CS_CAM_STOP";
|
||||
|
||||
return StringHelper::Sprintf("CS_CAM_POINT(%s, 0x%02X, %i, %ff, %i, %i, %i, 0x%04X)",
|
||||
continueMacro.c_str(), cameraRoll, nextPointFrame, viewAngle, posX,
|
||||
posY, posZ, unused);
|
||||
return StringHelper::Sprintf(
|
||||
"CS_CAM_POINT(%s, 0x%02X, %i, %s, %i, %i, %i, 0x%04X)", continueMacro.c_str(), cameraRoll,
|
||||
nextPointFrame,
|
||||
ZCutscene::GetCsEncodedFloat(viewAngle, Globals::Instance->floatType, false).c_str(), posX,
|
||||
posY, posZ, unused);
|
||||
}
|
||||
|
||||
size_t CutsceneOoTCommand_CameraPoint::GetRawSize() const
|
||||
|
@ -334,27 +338,34 @@ CutsceneOoTSubCommandEntry_ActorCue::CutsceneOoTSubCommandEntry_ActorCue(
|
|||
normalY = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x28);
|
||||
normalZ = BitConverter::ToFloatBE(rawData, rawDataIndex + 0x2C);
|
||||
}
|
||||
|
||||
std::string CutsceneOoTSubCommandEntry_ActorCue::GetBodySourceCode() const
|
||||
{
|
||||
EnumData* enumData = &Globals::Instance->cfg.enumData;
|
||||
|
||||
std::string normalXStr =
|
||||
ZCutscene::GetCsEncodedFloat(normalX, Globals::Instance->floatType, true);
|
||||
std::string normalYStr =
|
||||
ZCutscene::GetCsEncodedFloat(normalY, Globals::Instance->floatType, true);
|
||||
std::string normalZStr =
|
||||
ZCutscene::GetCsEncodedFloat(normalZ, Globals::Instance->floatType, true);
|
||||
|
||||
if (static_cast<CutsceneOoT_CommandType>(commandID) ==
|
||||
CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE)
|
||||
{
|
||||
return StringHelper::Sprintf("CS_PLAYER_CUE(%s, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, "
|
||||
"%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)",
|
||||
"%i, %i, %i, %i, %s, %s, %s)",
|
||||
enumData->playerCueId[base].c_str(), startFrame, endFrame,
|
||||
rotX, rotY, rotZ, startPosX, startPosY, startPosZ, endPosX,
|
||||
endPosY, endPosZ, normalX, normalY, normalZ);
|
||||
endPosY, endPosZ, normalXStr.c_str(), normalYStr.c_str(),
|
||||
normalZStr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
return StringHelper::Sprintf("CS_ACTOR_CUE(%i, %i, %i, 0x%04X, 0x%04X, 0x%04X, %i, %i, "
|
||||
"%i, %i, %i, %i, %.8ef, %.8ef, %.8ef)",
|
||||
"%i, %i, %i, %i, %s, %s, %s)",
|
||||
base, startFrame, endFrame, rotX, rotY, rotZ, startPosX,
|
||||
startPosY, startPosZ, endPosX, endPosY, endPosZ, normalX,
|
||||
normalY, normalZ);
|
||||
startPosY, startPosZ, endPosX, endPosY, endPosZ,
|
||||
normalXStr.c_str(), normalYStr.c_str(), normalZStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<EnableASAN>false</EnableASAN>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
|
@ -52,6 +53,7 @@
|
|||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<EnableASAN>false</EnableASAN>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -194,6 +196,8 @@ mkdir build\ZAPD
|
|||
<ClCompile Include="ZActorList.cpp" />
|
||||
<ClCompile Include="ZArray.cpp" />
|
||||
<ClCompile Include="ZBackground.cpp" />
|
||||
<ClCompile Include="ZCKeyFrame.cpp" />
|
||||
<ClCompile Include="ZCKeyFrameAnim.cpp" />
|
||||
<ClCompile Include="ZCollisionPoly.cpp" />
|
||||
<ClCompile Include="ZLimb.cpp" />
|
||||
<ClCompile Include="ZMtx.cpp" />
|
||||
|
@ -289,6 +293,8 @@ mkdir build\ZAPD
|
|||
<ClInclude Include="ZArray.h" />
|
||||
<ClInclude Include="ZBackground.h" />
|
||||
<ClInclude Include="ZBlob.h" />
|
||||
<ClInclude Include="ZCKeyFrame.h" />
|
||||
<ClInclude Include="ZCkeyFrameAnim.h" />
|
||||
<ClInclude Include="ZCollision.h" />
|
||||
<ClInclude Include="ZCollisionPoly.h" />
|
||||
<ClInclude Include="ZCutscene.h" />
|
||||
|
|
|
@ -300,6 +300,12 @@
|
|||
<ClCompile Include="ZRoom\Commands\SetCutsceneEntryList.cpp">
|
||||
<Filter>Source Files\Z64\ZRoom\Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZCKeyFrame.cpp">
|
||||
<Filter>Source Files\Z64</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZCKeyFrameAnim.cpp">
|
||||
<Filter>Source Files\Z64</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ZRoom\ZRoom.h">
|
||||
|
@ -575,6 +581,12 @@
|
|||
<ClInclude Include="ZRoom\Commands\SetCutsceneEntryList.h">
|
||||
<Filter>Header Files\Z64\ZRoom\Commands</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZCKeyFrame.h">
|
||||
<Filter>Header Files\Z64</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZCkeyFrameAnim.h">
|
||||
<Filter>Header Files\Z64</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\SymbolMap_OoTMqDbg.txt">
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
#include "ZCKeyFrame.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Utils/BitConverter.h"
|
||||
#include "Utils/StringHelper.h"
|
||||
#include "WarningHandler.h"
|
||||
|
||||
REGISTER_ZFILENODE(KeyFrameSkel, ZKeyFrameSkel);
|
||||
REGISTER_ZFILENODE(KeyFrameLimbList, ZKeyFrameLimbList);
|
||||
|
||||
ZKeyFrameSkel::ZKeyFrameSkel(ZFile* nParent) : ZResource(nParent)
|
||||
{
|
||||
RegisterRequiredAttribute("LimbType");
|
||||
}
|
||||
|
||||
ZKeyFrameSkel::~ZKeyFrameSkel()
|
||||
{
|
||||
}
|
||||
|
||||
ZKeyFrameLimb::ZKeyFrameLimb(ZFile* nParent) : ZResource(nParent)
|
||||
{
|
||||
}
|
||||
|
||||
ZKeyFrameStandardLimb::ZKeyFrameStandardLimb(ZFile* nParent) : ZKeyFrameLimb(nParent)
|
||||
{
|
||||
}
|
||||
|
||||
ZKeyFrameFlexLimb::ZKeyFrameFlexLimb(ZFile* nParent) : ZKeyFrameLimb(nParent)
|
||||
{
|
||||
}
|
||||
|
||||
ZKeyFrameLimbList::ZKeyFrameLimbList(ZFile* nParent) : ZResource(nParent)
|
||||
{
|
||||
RegisterRequiredAttribute("LimbType");
|
||||
RegisterRequiredAttribute("LimbCount");
|
||||
}
|
||||
|
||||
ZKeyFrameLimbList::ZKeyFrameLimbList(ZFile* nParent, uint32_t limbCount, ZKeyframeSkelType type)
|
||||
: ZResource(nParent)
|
||||
{
|
||||
numLimbs = limbCount;
|
||||
limbType = type;
|
||||
}
|
||||
|
||||
ZKeyFrameLimbList::~ZKeyFrameLimbList()
|
||||
{
|
||||
for (const auto l : limbs)
|
||||
delete l;
|
||||
}
|
||||
|
||||
void ZKeyFrameSkel::ParseXML(tinyxml2::XMLElement* reader)
|
||||
{
|
||||
ZResource::ParseXML(reader);
|
||||
|
||||
std::string limbTypeStr = registeredAttributes.at("LimbType").value;
|
||||
|
||||
limbType = ZKeyFrameLimbList::ParseLimbTypeStr(limbTypeStr);
|
||||
if (limbType == ZKeyframeSkelType::Error)
|
||||
HANDLE_ERROR_RESOURCE(
|
||||
WarningType::InvalidXML, parent, this, rawDataIndex, "Invalid limb type",
|
||||
StringHelper::Sprintf("Invalid limb type. Was expecting 'Flex' or 'Normal'. Got %s.",
|
||||
limbTypeStr.c_str()));
|
||||
}
|
||||
void ZKeyFrameLimbList::ParseXML(tinyxml2::XMLElement* reader)
|
||||
{
|
||||
ZResource::ParseXML(reader);
|
||||
|
||||
std::string limbTypeStr = registeredAttributes.at("LimbType").value;
|
||||
std::string numLimbStr = registeredAttributes.at("LimbCount").value;
|
||||
|
||||
limbType = ParseLimbTypeStr(limbTypeStr);
|
||||
|
||||
if (limbType == ZKeyframeSkelType::Error)
|
||||
HANDLE_ERROR_RESOURCE(
|
||||
WarningType::InvalidXML, parent, this, rawDataIndex, "Invalid limb type",
|
||||
StringHelper::Sprintf("Invalid limb type. Was expecting 'Flex' or 'Normal'. Got %s.",
|
||||
limbTypeStr.c_str()));
|
||||
|
||||
numLimbs = (uint8_t)StringHelper::StrToL(numLimbStr);
|
||||
}
|
||||
|
||||
void ZKeyFrameSkel::ParseRawData()
|
||||
{
|
||||
ZResource::ParseRawData();
|
||||
|
||||
const auto& rawData = parent->GetRawData();
|
||||
limbCount = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0);
|
||||
dListCount = BitConverter::ToUInt8BE(rawData, rawDataIndex + 1);
|
||||
limbsPtr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4);
|
||||
|
||||
limbList = std::make_unique<ZKeyFrameLimbList>(parent, limbCount, limbType);
|
||||
limbList->SetRawDataIndex(GETSEGOFFSET(limbsPtr));
|
||||
limbList->ParseRawData();
|
||||
}
|
||||
|
||||
void ZKeyFrameSkel::DeclareReferences(const std::string& prefix)
|
||||
{
|
||||
std::string defaultPrefix = name;
|
||||
std::string declaration;
|
||||
|
||||
if (defaultPrefix == "")
|
||||
defaultPrefix = prefix;
|
||||
|
||||
ZResource::DeclareReferences(defaultPrefix);
|
||||
declaration += limbList->GetBodySourceCode();
|
||||
parent->AddDeclarationArray(
|
||||
GETSEGOFFSET(limbsPtr), DeclarationAlignment::Align4, limbList->GetRawDataSize(),
|
||||
limbList->GetSourceTypeName(),
|
||||
StringHelper::Sprintf("%s_KeyFrameLimbs_%06X", prefix.c_str(), rawDataIndex),
|
||||
limbList->limbs.size(), declaration);
|
||||
}
|
||||
|
||||
std::string ZKeyFrameSkel::GetBodySourceCode() const
|
||||
{
|
||||
std::string limbStr;
|
||||
|
||||
if (limbType == ZKeyframeSkelType::Normal)
|
||||
Globals::Instance->GetSegmentedPtrName(limbsPtr, parent, "KeyFrameStandardLimb", limbStr);
|
||||
else
|
||||
Globals::Instance->GetSegmentedPtrName(limbsPtr, parent, "KeyFrameFlexLimb", limbStr);
|
||||
|
||||
return StringHelper::Sprintf("\n\t0x%02X, 0x%02X, %s\n", limbCount, dListCount,
|
||||
limbStr.c_str());
|
||||
}
|
||||
|
||||
size_t ZKeyFrameSkel::GetRawDataSize() const
|
||||
{
|
||||
return 0x8;
|
||||
}
|
||||
|
||||
std::string ZKeyFrameSkel::GetSourceTypeName() const
|
||||
{
|
||||
switch (limbType)
|
||||
{
|
||||
case ZKeyframeSkelType::Normal:
|
||||
return "KeyFrameSkeleton";
|
||||
|
||||
case ZKeyframeSkelType::Flex:
|
||||
return "KeyFrameFlexSkeleton";
|
||||
|
||||
default:
|
||||
return "KeyFrameSkeleton";
|
||||
}
|
||||
}
|
||||
|
||||
ZResourceType ZKeyFrameSkel::GetResourceType() const
|
||||
{
|
||||
return ZResourceType::KeyFrameSkel;
|
||||
}
|
||||
|
||||
size_t ZKeyFrameStandardLimb::GetRawDataSize() const
|
||||
{
|
||||
return 0xC;
|
||||
}
|
||||
|
||||
size_t ZKeyFrameFlexLimb::GetRawDataSize() const
|
||||
{
|
||||
return 0x8;
|
||||
}
|
||||
|
||||
size_t ZKeyFrameLimbList::GetRawDataSize() const
|
||||
{
|
||||
size_t limbSize;
|
||||
if (limbType == ZKeyframeSkelType::Flex)
|
||||
limbSize = 0x8;
|
||||
else
|
||||
limbSize = 0xC;
|
||||
|
||||
return limbSize * numLimbs;
|
||||
}
|
||||
|
||||
ZKeyframeSkelType ZKeyFrameLimbList::ParseLimbTypeStr(const std::string& typeStr)
|
||||
{
|
||||
if (typeStr == "Flex")
|
||||
return ZKeyframeSkelType::Flex;
|
||||
else if (typeStr == "Normal")
|
||||
return ZKeyframeSkelType::Normal;
|
||||
else
|
||||
return ZKeyframeSkelType::Error;
|
||||
}
|
||||
|
||||
void ZKeyFrameLimb::ParseRawData()
|
||||
{
|
||||
const auto& rawData = parent->GetRawData();
|
||||
|
||||
dlist = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0);
|
||||
numChildren = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x4);
|
||||
flags = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x5);
|
||||
}
|
||||
|
||||
void ZKeyFrameStandardLimb::ParseRawData()
|
||||
{
|
||||
const auto& rawData = parent->GetRawData();
|
||||
|
||||
ZKeyFrameLimb::ParseRawData();
|
||||
translation.x = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x6);
|
||||
translation.y = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0x8);
|
||||
translation.z = BitConverter::ToUInt16BE(rawData, rawDataIndex + 0xA);
|
||||
}
|
||||
|
||||
void ZKeyFrameFlexLimb::ParseRawData()
|
||||
{
|
||||
const auto& rawData = parent->GetRawData();
|
||||
|
||||
ZKeyFrameLimb::ParseRawData();
|
||||
callbackIndex = BitConverter::ToUInt8BE(rawData, rawDataIndex + 0x6);
|
||||
}
|
||||
|
||||
void ZKeyFrameLimbList::ParseRawData()
|
||||
{
|
||||
limbs.reserve(numLimbs);
|
||||
rawDataIndex = GetRawDataIndex();
|
||||
|
||||
for (uint32_t i = 0; i < numLimbs; i++)
|
||||
{
|
||||
ZKeyFrameLimb* limb;
|
||||
if (limbType == ZKeyframeSkelType::Flex)
|
||||
limb = new ZKeyFrameFlexLimb(parent);
|
||||
else
|
||||
limb = new ZKeyFrameStandardLimb(parent);
|
||||
|
||||
limb->SetRawDataIndex(rawDataIndex + (offset_t)(i * limb->GetRawDataSize()));
|
||||
limb->ParseRawData();
|
||||
limbs.push_back(limb);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ZKeyFrameLimbList::GetBodySourceCode() const
|
||||
{
|
||||
std::string declaration;
|
||||
|
||||
for (const auto l : limbs)
|
||||
declaration += StringHelper::Sprintf("\t{ %s },\n", l->GetBodySourceCode().c_str());
|
||||
// Remove last newline
|
||||
return declaration.substr(0, declaration.length() - 1);
|
||||
}
|
||||
|
||||
std::string ZKeyFrameStandardLimb::GetBodySourceCode() const
|
||||
{
|
||||
std::string declaration;
|
||||
std::string dlString;
|
||||
|
||||
Globals::Instance->GetSegmentedArrayIndexedName(dlist, 8, parent, "Gfx", dlString);
|
||||
|
||||
declaration +=
|
||||
StringHelper::Sprintf("%s, 0x%02X, 0x%02X, { 0x%04X, 0x%04X, 0x%04X},", dlString.c_str(),
|
||||
numChildren, flags, translation.x, translation.y, translation.z);
|
||||
return declaration;
|
||||
}
|
||||
|
||||
std::string ZKeyFrameFlexLimb::GetBodySourceCode() const
|
||||
{
|
||||
std::string declaration;
|
||||
|
||||
std::string dlString;
|
||||
|
||||
Globals::Instance->GetSegmentedArrayIndexedName(dlist, 8, parent, "Gfx", dlString);
|
||||
|
||||
declaration += StringHelper::Sprintf("%s, 0x%02X, 0x%02X, 0x%02X", dlString.c_str(),
|
||||
numChildren, flags, callbackIndex);
|
||||
return declaration;
|
||||
}
|
||||
|
||||
std::string ZKeyFrameStandardLimb::GetSourceTypeName() const
|
||||
{
|
||||
return "KeyFrameStandardLimb";
|
||||
}
|
||||
|
||||
std::string ZKeyFrameFlexLimb::GetSourceTypeName() const
|
||||
{
|
||||
return "KeyFrameFlexLimb";
|
||||
}
|
||||
|
||||
std::string ZKeyFrameLimbList::GetSourceTypeName() const
|
||||
{
|
||||
switch (limbType)
|
||||
{
|
||||
case ZKeyframeSkelType::Flex:
|
||||
return "KeyFrameFlexLimb";
|
||||
case ZKeyframeSkelType::Normal:
|
||||
return "KeyFrameStandardLimb";
|
||||
default:
|
||||
HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex,
|
||||
"Invalid limb type", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ZResourceType ZKeyFrameStandardLimb::GetResourceType() const
|
||||
{
|
||||
return ZResourceType::KeyFrameStandardLimb;
|
||||
}
|
||||
|
||||
ZResourceType ZKeyFrameFlexLimb::GetResourceType() const
|
||||
{
|
||||
return ZResourceType::KeyFrameFlexLimb;
|
||||
}
|
||||
|
||||
ZResourceType ZKeyFrameLimbList::GetResourceType() const
|
||||
{
|
||||
switch (limbType)
|
||||
{
|
||||
case ZKeyframeSkelType::Flex:
|
||||
return ZResourceType::KeyFrameFlexLimb;
|
||||
case ZKeyframeSkelType::Normal:
|
||||
return ZResourceType::KeyFrameStandardLimb;
|
||||
default:
|
||||
HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex,
|
||||
"Invalid limb type", "");
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "ZFile.h"
|
||||
|
||||
class ZKeyFrameLimb;
|
||||
|
||||
struct Vec3s
|
||||
{
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
};
|
||||
|
||||
enum class ZKeyframeSkelType
|
||||
{
|
||||
Normal,
|
||||
Flex,
|
||||
Error,
|
||||
};
|
||||
|
||||
class ZKeyFrameLimbList : public ZResource
|
||||
{
|
||||
public:
|
||||
ZKeyFrameLimbList();
|
||||
ZKeyFrameLimbList(ZFile* nParent);
|
||||
ZKeyFrameLimbList(ZFile* nParent, uint32_t limbCount, ZKeyframeSkelType type);
|
||||
|
||||
~ZKeyFrameLimbList();
|
||||
|
||||
void ParseRawData() override;
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
void ParseXML(tinyxml2::XMLElement* reader) override;
|
||||
|
||||
std::string GetSourceTypeName() const override;
|
||||
ZResourceType GetResourceType() const override;
|
||||
|
||||
size_t GetRawDataSize() const override;
|
||||
|
||||
static ZKeyframeSkelType ParseLimbTypeStr(const std::string& typeStr);
|
||||
|
||||
std::vector<ZKeyFrameLimb*> limbs;
|
||||
ZKeyframeSkelType limbType;
|
||||
uint8_t numLimbs;
|
||||
};
|
||||
|
||||
class ZKeyFrameLimb : public ZResource
|
||||
{
|
||||
public:
|
||||
segptr_t dlist;
|
||||
uint8_t numChildren;
|
||||
uint8_t flags;
|
||||
|
||||
ZKeyFrameLimb(ZFile* nParent);
|
||||
void ParseRawData() override;
|
||||
};
|
||||
|
||||
class ZKeyFrameStandardLimb : public ZKeyFrameLimb
|
||||
{
|
||||
public:
|
||||
Vec3s translation;
|
||||
|
||||
ZKeyFrameStandardLimb(ZFile* nParent);
|
||||
void ParseRawData() override;
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
|
||||
std::string GetSourceTypeName() const override;
|
||||
ZResourceType GetResourceType() const override;
|
||||
|
||||
size_t GetRawDataSize() const override;
|
||||
};
|
||||
|
||||
class ZKeyFrameFlexLimb : public ZKeyFrameLimb
|
||||
{
|
||||
public:
|
||||
uint8_t callbackIndex;
|
||||
|
||||
ZKeyFrameFlexLimb(ZFile* nParent);
|
||||
// void ParseXML(tinyxml2::XMLElement* reader) override;
|
||||
void ParseRawData() override;
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
// std::string GetSourceOutputHeader(const std::string& prefix) override;
|
||||
|
||||
std::string GetSourceTypeName() const override;
|
||||
ZResourceType GetResourceType() const override;
|
||||
|
||||
size_t GetRawDataSize() const override;
|
||||
};
|
||||
|
||||
class ZKeyFrameSkel : public ZResource
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<ZKeyFrameLimbList> limbList;
|
||||
segptr_t limbsPtr;
|
||||
ZKeyframeSkelType limbType;
|
||||
uint8_t limbCount;
|
||||
uint8_t dListCount;
|
||||
|
||||
ZKeyFrameSkel(ZFile* nParent);
|
||||
~ZKeyFrameSkel();
|
||||
|
||||
void ParseXML(tinyxml2::XMLElement* reader) override;
|
||||
void ParseRawData() override;
|
||||
void DeclareReferences(const std::string& prefix) override;
|
||||
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
std::string GetSourceTypeName() const override;
|
||||
ZResourceType GetResourceType() const override;
|
||||
|
||||
size_t GetRawDataSize() const override;
|
||||
};
|
|
@ -0,0 +1,219 @@
|
|||
#include "ZCkeyFrameAnim.h"
|
||||
#include "ZCKeyFrame.h"
|
||||
#include "Globals.h"
|
||||
|
||||
#include "Utils/BitConverter.h"
|
||||
|
||||
REGISTER_ZFILENODE(KeyFrameAnimation, ZKeyFrameAnim);
|
||||
|
||||
ZKeyFrameAnim::ZKeyFrameAnim(ZFile* nParent) : ZResource(nParent)
|
||||
{
|
||||
RegisterRequiredAttribute("Skel");
|
||||
}
|
||||
|
||||
ZKeyFrameAnim::~ZKeyFrameAnim()
|
||||
{
|
||||
}
|
||||
|
||||
void ZKeyFrameAnim::ParseXML(tinyxml2::XMLElement* reader)
|
||||
{
|
||||
ZResource::ParseXML(reader);
|
||||
|
||||
std::string skelAddrStr = registeredAttributes.at("Skel").value;
|
||||
skelOffset = (offset_t)StringHelper::StrToL(skelAddrStr, 16);
|
||||
}
|
||||
|
||||
void ZKeyFrameAnim::DeclareReferencesLate(const std::string& prefix)
|
||||
{
|
||||
std::string defaultPrefix = name;
|
||||
std::string declaration;
|
||||
|
||||
if (defaultPrefix == "")
|
||||
defaultPrefix = prefix;
|
||||
|
||||
ZResource::DeclareReferences(defaultPrefix);
|
||||
|
||||
declaration += "\t";
|
||||
|
||||
if (skel->limbType == ZKeyframeSkelType::Normal)
|
||||
{
|
||||
for (const auto b : bitFlags)
|
||||
{
|
||||
declaration += StringHelper::Sprintf("0x%02X, ", b);
|
||||
parent->AddDeclarationArray(
|
||||
GETSEGOFFSET(bitFlagsAddr), DeclarationAlignment::Align4, bitFlags.size(), "u8",
|
||||
StringHelper::Sprintf("%s_bitFlags_%06X", prefix.c_str(), rawDataIndex),
|
||||
bitFlags.size(), declaration);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto b : bitFlagsFlex)
|
||||
{
|
||||
declaration += StringHelper::Sprintf("0x%04X, ", b);
|
||||
parent->AddDeclarationArray(
|
||||
GETSEGOFFSET(bitFlagsAddr), DeclarationAlignment::Align4, bitFlagsFlex.size() * 2,
|
||||
"u16", StringHelper::Sprintf("%s_flexBitFlags_%06X", prefix.c_str(), rawDataIndex),
|
||||
bitFlagsFlex.size(), declaration);
|
||||
}
|
||||
}
|
||||
declaration.clear();
|
||||
|
||||
for (const auto kf : keyFrames)
|
||||
{
|
||||
declaration +=
|
||||
StringHelper::Sprintf(" \t { %i, %i, %i, },\n", kf.frame, kf.value, kf.velocity);
|
||||
}
|
||||
// Remove last new line to prevent an extra line after the last element
|
||||
declaration = declaration.substr(0, declaration.length() - 1);
|
||||
parent->AddDeclarationArray(
|
||||
GETSEGOFFSET(keyFramesAddr), DeclarationAlignment::Align4, keyFrames.size() * 6, "KeyFrame",
|
||||
StringHelper::Sprintf("%s_KeyFrame_%06X", prefix.c_str(), rawDataIndex), keyFrames.size(),
|
||||
declaration);
|
||||
|
||||
declaration.clear();
|
||||
|
||||
declaration += "\t";
|
||||
|
||||
for (const auto kfNum : kfNums)
|
||||
{
|
||||
declaration += StringHelper::Sprintf("0x%04X, ", kfNum);
|
||||
}
|
||||
|
||||
parent->AddDeclarationArray(
|
||||
GETSEGOFFSET(kfNumsAddr), DeclarationAlignment::Align4, kfNums.size() * 2, "s16",
|
||||
StringHelper::Sprintf("%s_kfNums_%06X", prefix.c_str(), rawDataIndex), kfNums.size(),
|
||||
declaration);
|
||||
declaration += "\n";
|
||||
|
||||
declaration.clear();
|
||||
|
||||
declaration += "\t";
|
||||
|
||||
for (const auto pv : presetValues)
|
||||
{
|
||||
declaration += StringHelper::Sprintf("0x%04X, ", pv);
|
||||
}
|
||||
declaration += "\n";
|
||||
parent->AddDeclarationArray(
|
||||
GETSEGOFFSET(presentValuesAddr), DeclarationAlignment::Align4, presetValues.size() * 2,
|
||||
"s16", StringHelper::Sprintf("%s_presetValues_%06X", prefix.c_str(), rawDataIndex),
|
||||
presetValues.size(), declaration);
|
||||
|
||||
}
|
||||
|
||||
// ParseRawDataLate is used because we need to make sure the flex skel has been processed first.
|
||||
void ZKeyFrameAnim::ParseRawDataLate()
|
||||
{
|
||||
const auto& rawData = parent->GetRawData();
|
||||
|
||||
skel = static_cast<ZKeyFrameSkel*>(parent->FindResource(skelOffset));
|
||||
size_t numLimbs = skel->limbCount;
|
||||
|
||||
bitFlagsAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0);
|
||||
keyFramesAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x4);
|
||||
kfNumsAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x8);
|
||||
presentValuesAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0xC);
|
||||
|
||||
uint32_t kfNumsSize = 0;
|
||||
uint32_t presetValuesSize = 0;
|
||||
uint32_t keyFramesCount = 0;
|
||||
if (skel->limbType == ZKeyframeSkelType::Normal)
|
||||
{
|
||||
bitFlags.reserve(numLimbs);
|
||||
for (size_t i = 0; i < numLimbs; i++)
|
||||
{
|
||||
uint8_t e = BitConverter::ToUInt8BE(rawData, GETSEGOFFSET(bitFlagsAddr) + i);
|
||||
bitFlags.push_back(e);
|
||||
kfNumsSize += GetSetBits((uint8_t)(e & 0b111111));
|
||||
presetValuesSize += GetSetBits((uint8_t)((e ^ 0xFF) & 0b111111));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bitFlagsFlex.reserve(numLimbs);
|
||||
for (size_t i = 0; i < numLimbs; i++)
|
||||
{
|
||||
uint16_t e = BitConverter::ToUInt16BE(rawData, GETSEGOFFSET(bitFlagsAddr) + (i * 2));
|
||||
bitFlagsFlex.push_back(e);
|
||||
kfNumsSize += GetSetBits((uint16_t)(e & 0b111111111));
|
||||
presetValuesSize += GetSetBits((uint16_t)((e ^ 0xFFFF) & 0b111111111));
|
||||
}
|
||||
}
|
||||
|
||||
kfNums.reserve(kfNumsSize);
|
||||
for (uint32_t i = 0; i < kfNumsSize; i++)
|
||||
{
|
||||
int16_t kfNum = BitConverter::ToUInt16BE(rawData, GETSEGOFFSET(kfNumsAddr) + (i * 2));
|
||||
keyFramesCount += kfNum;
|
||||
kfNums.push_back(kfNum);
|
||||
}
|
||||
|
||||
keyFrames.reserve(keyFramesCount);
|
||||
for (uint32_t i = 0; i < keyFramesCount; i++)
|
||||
{
|
||||
KeyFrame kf;
|
||||
kf.frame = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 0) + (i * 6));
|
||||
kf.value = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 2) + (i * 6));
|
||||
kf.velocity = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 4) + (i * 6));
|
||||
keyFrames.push_back(kf);
|
||||
}
|
||||
|
||||
presetValues.reserve(presetValuesSize);
|
||||
for (uint32_t i = 0; i < presetValuesSize; i++)
|
||||
{
|
||||
presetValues.push_back(
|
||||
BitConverter::ToInt16BE(rawData, GETSEGOFFSET(presentValuesAddr) + (i * 2)));
|
||||
}
|
||||
|
||||
unk_10 = BitConverter::ToInt16BE(rawData, GETSEGOFFSET(rawDataIndex) + 0x10);
|
||||
duration = BitConverter::ToInt16BE(rawData, GETSEGOFFSET(rawDataIndex) + 0x12);
|
||||
}
|
||||
|
||||
std::string ZKeyFrameAnim::GetBodySourceCode() const
|
||||
{
|
||||
std::string declaration;
|
||||
|
||||
std::string bitFlagsStr;
|
||||
std::string keyFrameStr;
|
||||
std::string kfNumsStr;
|
||||
std::string presetValuesStr;
|
||||
|
||||
Globals::Instance->GetSegmentedPtrName(bitFlagsAddr, parent, "", bitFlagsStr);
|
||||
Globals::Instance->GetSegmentedPtrName(keyFramesAddr, parent, "", keyFrameStr);
|
||||
Globals::Instance->GetSegmentedPtrName(kfNumsAddr, parent, "", kfNumsStr);
|
||||
Globals::Instance->GetSegmentedPtrName(presentValuesAddr, parent, "", presetValuesStr);
|
||||
|
||||
return StringHelper::Sprintf("\n\t%s, %s, %s, %s, 0x%04X, 0x%04X\n", bitFlagsStr.c_str(),
|
||||
keyFrameStr.c_str(), kfNumsStr.c_str(), presetValuesStr.c_str(),
|
||||
unk_10, duration);
|
||||
}
|
||||
|
||||
std::string ZKeyFrameAnim::GetSourceTypeName() const
|
||||
{
|
||||
return "KeyFrameAnimation";
|
||||
}
|
||||
|
||||
ZResourceType ZKeyFrameAnim::GetResourceType() const
|
||||
{
|
||||
return ZResourceType::KeyFrameAnimation;
|
||||
}
|
||||
|
||||
size_t ZKeyFrameAnim::GetRawDataSize() const
|
||||
{
|
||||
return 0x14;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t ZKeyFrameAnim::GetSetBits(T data) const
|
||||
{
|
||||
uint32_t num = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(T) * 8; i++)
|
||||
{
|
||||
if ((data >> i) & 1)
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "ZFile.h"
|
||||
|
||||
class ZKeyFrameSkel;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t frame;
|
||||
int16_t value;
|
||||
int16_t velocity;
|
||||
} KeyFrame;
|
||||
|
||||
class ZKeyFrameAnim : public ZResource
|
||||
{
|
||||
public:
|
||||
ZKeyFrameSkel* skel;
|
||||
std::vector<uint8_t> bitFlags; // Standard only
|
||||
std::vector<uint16_t> bitFlagsFlex; // Flex only
|
||||
|
||||
std::vector<KeyFrame> keyFrames;
|
||||
std::vector<int16_t> kfNums;
|
||||
std::vector<int16_t> presetValues;
|
||||
|
||||
uint16_t unk_10;
|
||||
int16_t duration;
|
||||
|
||||
ZKeyFrameAnim(ZFile* nParent);
|
||||
~ZKeyFrameAnim();
|
||||
void ParseXML(tinyxml2::XMLElement* reader) override;
|
||||
void DeclareReferencesLate(const std::string& prefix) override;
|
||||
void ParseRawDataLate() override;
|
||||
std::string GetBodySourceCode() const override;
|
||||
|
||||
std::string GetSourceTypeName() const override;
|
||||
ZResourceType GetResourceType() const override;
|
||||
|
||||
size_t GetRawDataSize() const override;
|
||||
|
||||
private:
|
||||
offset_t skelOffset;
|
||||
segptr_t bitFlagsAddr;
|
||||
segptr_t keyFramesAddr;
|
||||
segptr_t kfNumsAddr;
|
||||
segptr_t presentValuesAddr;
|
||||
template <typename T>
|
||||
uint32_t GetSetBits(T data) const;
|
||||
};
|
|
@ -24,7 +24,7 @@ std::string ZCutscene::GetBodySourceCode() const
|
|||
{
|
||||
std::string output = "";
|
||||
|
||||
output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),\n", commands.size(), endFrame);
|
||||
output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),\n", numCommands, endFrame);
|
||||
|
||||
for (size_t i = 0; i < commands.size(); i++)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ std::string ZCutscene::GetBodySourceCode() const
|
|||
output += " " + cmd->GenerateSourceCode();
|
||||
}
|
||||
|
||||
output += StringHelper::Sprintf(" CS_END(),", commands.size(), endFrame);
|
||||
output += StringHelper::Sprintf(" CS_END(),");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -372,3 +372,25 @@ ZResourceType ZCutscene::GetResourceType() const
|
|||
{
|
||||
return ZResourceType::Cutscene;
|
||||
}
|
||||
|
||||
std::string ZCutscene::GetCsEncodedFloat(float f, CsFloatType type, bool useSciNotation)
|
||||
{
|
||||
uint32_t i;
|
||||
std::memcpy(&i, &f, sizeof(i));
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
// This default case will NEVER be reached, but GCC still gives a warning.
|
||||
case CsFloatType::HexOnly:
|
||||
return StringHelper::Sprintf("0x%08X", i);
|
||||
case CsFloatType::FloatOnly:
|
||||
return StringHelper::Sprintf(useSciNotation ? "%.8ef" : "%ff", f);
|
||||
case CsFloatType::HexAndFloat:
|
||||
return StringHelper::Sprintf(useSciNotation ? "CS_FLOAT(0x%08X, %.8ef)" : "CS_FLOAT(0x%08X, %ff)", i, f);
|
||||
case CsFloatType::HexAndCommentedFloatLeft:
|
||||
return StringHelper::Sprintf(useSciNotation ? "/* %.8ef */ 0x%08X" : "/* %ff */ 0x%08X", f, i);
|
||||
case CsFloatType::HexAndCommentedFloatRight:
|
||||
return StringHelper::Sprintf(useSciNotation ? "0x%08X /* %.8ef */" : "0x%08X /* %ff */", i, f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "ZFile.h"
|
||||
#include "ZResource.h"
|
||||
|
||||
enum class CsFloatType;
|
||||
|
||||
class ZCutscene : public ZResource
|
||||
{
|
||||
public:
|
||||
|
@ -27,6 +29,8 @@ public:
|
|||
std::string GetSourceTypeName() const override;
|
||||
ZResourceType GetResourceType() const override;
|
||||
|
||||
static std::string GetCsEncodedFloat(float f, CsFloatType type, bool useSciNotation);
|
||||
|
||||
int32_t numCommands;
|
||||
int32_t endFrame;
|
||||
std::vector<CutsceneCommand*> commands;
|
||||
|
|
|
@ -120,6 +120,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename)
|
|||
if (reader->Attribute("BaseAddress") != nullptr)
|
||||
baseAddress = StringHelper::StrToL(reader->Attribute("BaseAddress"), 16);
|
||||
|
||||
if (mode == ZFileMode::Extract && Globals::Instance->baseAddress != -1)
|
||||
baseAddress = Globals::Instance->baseAddress;
|
||||
|
||||
if (reader->Attribute("RangeStart") != nullptr)
|
||||
rangeStart = StringHelper::StrToL(reader->Attribute("RangeStart"), 16);
|
||||
|
||||
|
@ -197,6 +200,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename)
|
|||
}
|
||||
|
||||
rawData = File::ReadAllBytes((basePath / name).string());
|
||||
if (mode == ZFileMode::Extract && Globals::Instance->startOffset != -1 && Globals::Instance->endOffset != -1)
|
||||
rawData = std::vector<uint8_t>(rawData.begin() + Globals::Instance->startOffset,
|
||||
rawData.begin() + Globals::Instance->endOffset);
|
||||
|
||||
if (reader->Attribute("RangeEnd") == nullptr)
|
||||
rangeEnd = rawData.size();
|
||||
|
@ -585,6 +591,12 @@ Declaration* ZFile::AddDeclarationIncludeArray(offset_t address, std::string& in
|
|||
includePath = "assets/" + StringHelper::Split(includePath, "assets/extracted/")[1];
|
||||
if (StringHelper::StartsWith(includePath, "assets/custom/"))
|
||||
includePath = "assets/" + StringHelper::Split(includePath, "assets/custom/")[1];
|
||||
// Hack for OOT: don't prefix include paths with extracted/VERSION/
|
||||
if (StringHelper::StartsWith(includePath, "extracted/")) {
|
||||
std::vector<std::string> parts = StringHelper::Split(includePath, "/");
|
||||
parts.erase(parts.begin(), parts.begin() + 2);
|
||||
includePath = StringHelper::Join(parts, "/");
|
||||
}
|
||||
|
||||
Declaration* decl = GetDeclaration(address);
|
||||
if (decl == nullptr)
|
||||
|
@ -621,6 +633,12 @@ Declaration* ZFile::AddDeclarationIncludeArray(offset_t address, std::string& in
|
|||
includePath = "assets/" + StringHelper::Split(includePath, "assets/extracted/")[1];
|
||||
if (StringHelper::StartsWith(includePath, "assets/custom/"))
|
||||
includePath = "assets/" + StringHelper::Split(includePath, "assets/custom/")[1];
|
||||
// Hack for OOT: don't prefix include paths with extracted/VERSION/
|
||||
if (StringHelper::StartsWith(includePath, "extracted/")) {
|
||||
std::vector<std::string> parts = StringHelper::Split(includePath, "/");
|
||||
parts.erase(parts.begin(), parts.begin() + 2);
|
||||
includePath = StringHelper::Join(parts, "/");
|
||||
}
|
||||
|
||||
Declaration* decl = GetDeclaration(address);
|
||||
if (decl == nullptr)
|
||||
|
|
|
@ -55,6 +55,10 @@ enum class ZResourceType
|
|||
Vector,
|
||||
Vertex,
|
||||
Waterbox,
|
||||
KeyFrameFlexLimb,
|
||||
KeyFrameStandardLimb,
|
||||
KeyFrameSkel,
|
||||
KeyFrameAnimation,
|
||||
};
|
||||
|
||||
class ResourceAttribute
|
||||
|
|
|
@ -30,6 +30,21 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
static std::string Join(const std::vector<std::string> parts, const std::string& delimiter)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for (size_t i = 0; i < parts.size(); i++)
|
||||
{
|
||||
result += parts[i];
|
||||
|
||||
if (i != parts.size() - 1)
|
||||
result += delimiter;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string Strip(std::string s, const std::string& delimiter)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
|
Loading…
Reference in New Issue