diff --git a/datadump/main.cpp b/datadump/main.cpp index 9155f7a5..fdf1902d 100644 --- a/datadump/main.cpp +++ b/datadump/main.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../framework/rwbinarystream.h" using RW::BSSectionHeader; @@ -442,6 +443,27 @@ void dumpGenericTree(char* data) dumpBinaryStreamSection(root, 0); } +void dumpAnimationFile(char* data) +{ + LoaderIFP loader; + + if(loader.loadFromMemory(data)) { + std::cout << loader.animations.size() << " animations" << std::endl; + + for( auto it = loader.animations.begin(); + it != loader.animations.end(); ++it ) { + Animation* a = *it; + std::cout << a->name << std::endl; + std::cout << " " << a->bones.size() << " bones" << std::endl; + for( auto bit = a->bones.begin(); + bit != a->bones.end(); ++bit ) { + std::cout << " " << bit->first << " (" << bit->second->frames.size() << " frames)" << std::endl; + } + } + + } +} + int main(int argc, char** argv) { bool raw = false; @@ -485,6 +507,11 @@ int main(int argc, char** argv) std::cout << "Dumping Collsion file" << std::endl; dumpCollisionModel(data, size); } + else if(ext == "ifp") + { + std::cout << "Dumping animation file" << std::endl; + dumpAnimationFile(data); + } else { std::cout << "I'm not sure what that is" << std::endl; diff --git a/framework2/CMakeLists.txt b/framework2/CMakeLists.txt index bdbb0f11..a11e0f8c 100644 --- a/framework2/CMakeLists.txt +++ b/framework2/CMakeLists.txt @@ -2,7 +2,6 @@ SET(RENDERWARE_SOURCES # RenderWare related BinaryStream.cpp TextureArchive.cpp - LoaderDFF.cpp TextureLoader.cpp WeatherLoader.cpp @@ -11,6 +10,8 @@ SET(RENDERWARE_SOURCES LoaderIMG.cpp LoaderIPL.cpp LoaderIDE.cpp + LoaderDFF.cpp + LoaderIFP.cpp GTAData.cpp GTAEngine.cpp @@ -31,6 +32,7 @@ SET(RENDERWARE_HEADERS include/renderwure/loaders/LoaderIMG.hpp include/renderwure/loaders/LoaderIPL.hpp include/renderwure/loaders/LoaderIDE.hpp + include/renderwure/loaders/LoaderIFP.hpp include/renderwure/engine/GTAData.hpp include/renderwure/engine/GTAEngine.hpp diff --git a/framework2/LoaderIFP.cpp b/framework2/LoaderIFP.cpp new file mode 100644 index 00000000..0c74dcc2 --- /dev/null +++ b/framework2/LoaderIFP.cpp @@ -0,0 +1,93 @@ +#include + +bool LoaderIFP::loadFromMemory(char *data) +{ + size_t data_offs = 0; + size_t* dataI = &data_offs; + + ANPK* fileRoot = read(data, dataI); + std::string listname = readString(data, dataI); + + for( size_t a = 0; a < fileRoot->info.entries; ++a ) { + // something about a name? + NAME* n = read(data, dataI); + std::string animname = readString(data, dataI); + + Animation* animation = new Animation; + animation->name = animname; + + size_t animstart = data_offs + 8; + DGAN* animroot = read(data, dataI); + std::string infoname = readString(data, dataI); + + for( size_t c = 0; c < animroot->info.entries; ++c ) { + size_t start = data_offs; + CPAN* cpan = read(data, dataI); + ANIM* frames = read(data, dataI); + + AnimationBone* bonedata = new AnimationBone; + bonedata->name = frames->name; + bonedata->frames.reserve(frames->frames); + + data_offs += ((8+frames->base.size) - sizeof(ANIM)); + + KFRM* frame = read(data, dataI); + std::string type(frame->base.magic, 4); + bonedata->time = frame->time; + + if(type == "KR00") { + for( size_t d = 0; d < frames->frames; ++d ) { + bonedata->frames.push_back({ + *read(data, dataI), + glm::vec3(0.f, 0.f, 0.f), + glm::vec3(1.f, 1.f, 1.f) + }); + } + } + else if(type == "KRT0") { + for( size_t d = 0; d < frames->frames; ++d ) { + bonedata->frames.push_back({ + *read(data, dataI), + *read(data, dataI), + glm::vec3(1.f, 1.f, 1.f) + }); + } + } + else if(type == "KRTS") { + for( size_t d = 0; d < frames->frames; ++d ) { + bonedata->frames.push_back({ + *read(data, dataI), + *read(data, dataI), + *read(data, dataI) + }); + } + } + + data_offs = start + sizeof(CPAN) + cpan->base.size; + + animation->bones.insert({ + std::string(frames->name), + bonedata + }); + } + + data_offs = animstart + animroot->base.size; + + animations.push_back(animation); + } + + return true; +} + +std::string LoaderIFP::readString(char *data, size_t *ofs) +{ + size_t b = *ofs; + for(size_t o = *ofs; o = *ofs;) { + *ofs += 4; + if(data[o+0] == 0) break; + if(data[o+1] == 0) break; + if(data[o+2] == 0) break; + if(data[o+3] == 0) break; + } + return std::string(data+b); +} diff --git a/framework2/include/renderwure/loaders/LoaderIFP.hpp b/framework2/include/renderwure/loaders/LoaderIFP.hpp new file mode 100644 index 00000000..1df45878 --- /dev/null +++ b/framework2/include/renderwure/loaders/LoaderIFP.hpp @@ -0,0 +1,101 @@ +#pragma once +#ifndef _LOADERDFF_IFP_ +#define _LOADERDFF_IFP_ + +#include +#include +#include +#include +#include + +struct AnimationKeyframe +{ + glm::quat rotation; + glm::vec3 position; + glm::vec3 scale; +}; + +struct AnimationBone +{ + std::string name; + int32_t previous; + int32_t next; + float time; + std::vector frames; +}; + +struct Animation +{ + std::string name; + std::map bones; +}; + +class LoaderIFP +{ + template T* read(char* data, size_t* ofs) { + size_t b = *ofs; *ofs += sizeof(T); + return reinterpret_cast(data + b); + } + template T* peek(char* data, size_t* ofs) { + return reinterpret_cast(data + *ofs); + } + + std::string readString(char* data, size_t* ofs); + +public: + + struct BASE { + char magic[4]; + uint32_t size; + }; + + struct INFO { + BASE base; + int32_t entries; + // null terminated string + // entry data + }; + + struct ANPK { + BASE base; + INFO info; + }; + + struct NAME { + BASE base; + }; + + struct DGAN { + BASE base; + INFO info; + }; + + struct CPAN { + BASE base; + }; + + struct ANIM { + BASE base; + char name[28]; + int32_t frames; + int32_t unk; + int32_t next; + int32_t prev; + }; + + struct KFRM { + BASE base; + float time; + }; + + struct Anim { + std::string name; + + }; + + std::vector animations; + + bool loadFromMemory(char *data); +}; + +#endif