Просмотр исходного кода

Building a better battle model extractor.

Iñigo Valentin 3 лет назад
Родитель
Сommit
44992ed742

+ 12 - 16
src/common/File.h

@@ -90,37 +90,33 @@ class File{
          * @param[in] start Offset to the data to load.
          * @param[in] length Length of the data to load.
          */
-        void GetFileBuffer(
-          u8* buffer, const u32 &start, const u32 &length
-        ) const;
+        void GetFileBuffer(u8* buffer, const u32 &start, const u32 &length) const;
 
         /**
-         * Retrieves a pointer to a byte address in the file.
+         * Retrieves a byte.
          *
-         * @param[in] offset The offset to the requested address.
+         * @param[in] offset The offset of the byte.
+         * @return The byte at the specified offset.
          */
         u8 GetU8(u32 offset) const;
 
         /**
-         * Retrieves a pointer to a two-byte address in the file.
+         * Retrieves two bytes (little endian) from the file.
          *
-         * The data must b considered to be in little endian.
-         *
-         * @param[in] offset The offset to the requested address.
+         * @param[in] offset The offset to the bytes.
+         * @return The bytes at the specified offset.
          */
         u16 GetU16LE(u32 offset) const;
 
         /**
-         * Retrieves a pointer to a four-byte address in the file.
-         *
-         * The data must b considered to be in little endian.
+         * Retrieves four bytes (little endian) from the file.
          *
-         * @param[in] offset The offset to the requested address.
+         * @return The bytes at the specified offset.
          */
         u32 GetU32LE(u32 offset) const;
 
         /**
-         * Reads a byte from the file.
+         * Reads a byte from the file at the current offset.
          *
          * Advances the current offset by one byte.
          *
@@ -129,7 +125,7 @@ class File{
         u8 readU8();
 
         /**
-         * Reads two bytes from the file (little endian).
+         * Reads two bytes from the file (little endian) at the current offset.
          *
          * Advances the current offset by two bytes.
          *
@@ -138,7 +134,7 @@ class File{
         u16 readU16LE();
 
         /**
-         * Reads four bytes from the file (little endian).
+         * Reads four bytes from the file (little endian) at the current offset.
          *
          * Advances the current offset by four byte.
          *

+ 40 - 19
src/installer/BattleDataInstaller.cpp

@@ -17,6 +17,7 @@
  */
 
 #include <iostream>
+#include <cstdint>
 #include <fstream>
 #include <zlib.h>
 #include <tinyxml.h>
@@ -27,6 +28,7 @@
 #include "data/VGearsHRCFileManager.h"
 #include "data/VGearsAFileManager.h"
 #include "common/VGearsStringUtil.h"
+#include "common/BinaryFile.h"
 #include "common/FinalFantasy7/FF7NameLookup.h"
 
 BattleDataInstaller::BattleDataInstaller(const std::string input_dir, const std::string output_dir):
@@ -770,7 +772,6 @@ void BattleDataInstaller::ExportMesh(const std::string outdir, const Ogre::MeshP
                 }
             }
             if (std::count(materials_.begin(), materials_.end(), sub_mesh->getMaterialName()) == 0){
-                 << sub_mesh->getMaterialName() << std::endl;
                 mat_ser.queueForExport(mat);
                 materials_.push_back(sub_mesh->getMaterialName());
             }
@@ -862,15 +863,18 @@ void BattleDataInstaller::DecompileHrc(File compiled, Model model, std::string p
     out.close();
 }
 
-void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::string path){
+void BattleDataInstaller::ExtractAFilesFromDAFile(File da_file, Model* model, std::string path){
+
+    BinaryFile da(&da_file);
 
     struct Bone{
-        int raw[3]; // Z, Y, X.
+        u16 raw[3]; // Z, Y, X.
         float angle[3]; // Z, Y, X.
     };
 
     da.SetOffset(0);
-    int num_animations = da.readU32LE();
+    int num_animations = da.ReadU32LE();
+    std::cout << "TOTAL ANIMATIONS " << num_animations << "\n";
     for (int anim = 0; anim < num_animations; anim ++){
         std::string file_index_name = std::to_string(anim);
         while (file_index_name.size() < 2) file_index_name = "0" + file_index_name;
@@ -881,8 +885,8 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
         u32 zero = 0x00000000;
         u32 version = 0x00000001;
         u32 rotation_order = 0x00020001;
-        u32 bone_count = da.readU32LE() - 1;
-        u32 frames = da.readU32LE();
+        u32 bone_count = da.ReadU32LE() - 1;
+        u32 frames = da.ReadU32LE();
         Bone bones[frames][bone_count];
         a.write(reinterpret_cast<const char*>(&version), 4);
         a.write(reinterpret_cast<const char*>(&frames), 4);
@@ -893,13 +897,13 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
         a.write(reinterpret_cast<const char*>(&zero), 4);
         a.write(reinterpret_cast<const char*>(&zero), 4);
         a.write(reinterpret_cast<const char*>(&zero), 4);
-        int next_offset = da.GetCurrentOffset() + da.readU32LE() + 4;
-        da.readU16LE(); // Frames, again.
-        da.readU16LE(); // Size, again.
-        int key = da.readU8(); // Scale decoding key.
-        da.readU8(); // ???
-        da.readU32LE(); // ???
-        da.readU32LE(); // ???
+        int next_offset = da.GetCurrentOffset() / 8 + da.ReadU32LE() + 4;
+        da.ReadU16LE(); // Frames, again.
+        da.ReadU16LE(); // Size, again.
+        int key = da.ReadU8(); // Scale decoding key.
+        da.ReadU8(); // ???
+        da.ReadU32LE(); // ???
+        da.ReadU32LE(); // ???
         int frame = 0;
         while (frame < frames){
             a.write(reinterpret_cast<const char*>(&zero), 4);
@@ -913,7 +917,7 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
                 if (bone == 0){
                     // Uncompressed, 3 bytes per bone rotations. Read one bone.
                     for (int d = 0; d < 3; d ++){ // Read Z, Y, X.
-                        int delta = da.readU16LE();
+                        int delta = da.ReadU16LE();
                         delta = delta << key;
                         bones[frame][bone].raw[d] = delta;
                         bones[frame][bone].angle[d] = delta;
@@ -926,8 +930,8 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
                 }
                 else if (key == 0){
                     // 12 bits per bone rotation, 36 bits per bone. Read two bones (9 bytes).
-                    u8 data[9];
-                    for (int d = 0; d < 9; d ++) data[d] = da.readU8();
+                    /*u8 data[9];
+                    for (int d = 0; d < 9; d ++) data[d] = da.ReadU8();
                     // Read two bones.
                     float rot[6]; // Z, Y, X, Z, Y, X
                     bones[frame][bone].raw[0] = data[0] * 16 + (data[1] >> 4);
@@ -954,7 +958,24 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
                             a.write(reinterpret_cast<const char*>(&bones[frame][b].angle[r]), 4);
                         }
                     }
-                    bone += 2;
+                    bone += 2;*/
+
+
+                    // 12 bits per bone rotations.
+                    for (int r = 0; r < 3; r ++){
+                        bones[frame][bone].raw[r] = da.ReadBits(12);
+                        if (frames > 0){ // Frames 1 and up, sum to the previous frame.
+                            bones[frame][bone].raw[r] += bones[frame - 1][bone].raw[r];
+                        }
+                        bones[frame][bone].angle[r] = bones[frame][bone].raw[r];
+                        std::cout << "ROTATION: " << bones[frame][bone].raw[r] << " -> " << bones[frame][bone].angle[r];
+                        if (bones[frame][bone].angle[r] < 0) bones[frame][bone].angle[r] += 0x1000;
+                        std::cout << " -> " << bones[frame][bone].angle[r];
+                        bones[frame][bone].angle[r] = bones[frame][bone].angle[r] / 4096.0f * 360.0f;
+                        std::cout << " -> " << bones[frame][bone].angle[r] << "\n";
+                        a.write(reinterpret_cast<const char*>(&bones[frame][bone].angle[r]), 4);
+                    }
+                    bone ++;
 
                 }
                 else if (key == 2){
@@ -969,7 +990,7 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
                     // TODO: Fix this and do the same as key 0.
                     u8 data[3];
                     for (int d = 0; d < 3; d ++){
-                        if (bone + d < bone_count) data[d] = da.readU8();
+                        if (bone + d < bone_count) data[d] = da.ReadU8();
                         else data[d] = 0;
                     }
                     // Read two bones.
@@ -995,6 +1016,6 @@ void BattleDataInstaller::ExtractAFilesFromDAFile(File da, Model* model, std::st
             frame ++;
         }
         a.close();
-        da.SetOffset(next_offset);
+        da.SetOffset(next_offset * 8); // In bits
     }
 }

+ 1 - 0
src/installer/CMakeLists.txt

@@ -19,6 +19,7 @@ set(INSTALLER_SOURCE_FILES
     TexFile.cpp
     VGearsUtility.cpp
     WorldInstaller.cpp
+    common/BinaryFile.cpp
     common/BinGZipFile.cpp
     common/DrawSkeleton.cpp
     common/FontFile.cpp

+ 2 - 1
src/installer/FieldDataInstaller.cpp

@@ -17,8 +17,9 @@
 #include <boost/filesystem.hpp>
 #include <QtCore/QDir>
 #include "FieldDataInstaller.h"
+
+#include "common/BinaryFile.h"
 #include "TexFile.h"
-#include "common/File.h"
 #include "data/VGearsMapListFile.h"
 #include "data/VGearsLZSFLevelFileManager.h"
 #include "data/VGearsHRCFileManager.h"

+ 128 - 0
src/installer/common/BinaryFile.cpp

@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022 The V-Gears Team
+ *
+ * This file is part of V-Gears
+ *
+ * V-Gears is free software: you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.0 (GPLv3) of the License.
+ *
+ * V-Gears is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "BinaryFile.h"
+
+#include <iostream>
+#include <cassert>
+#include <math.h>
+#include <string.h>
+#include "common/FileSystem.h"
+#include "core/Logger.h"
+
+BinaryFile::BinaryFile(const File* file){
+    assert(file != nullptr);
+    buffer_size_bytes_ = file->GetFileSize();
+    buffer_size_bits_ = buffer_size_bytes_ * 8;
+    file_name_   = file->GetFileName();
+    buffer_bytes_ = static_cast<u8*>(malloc(sizeof(u8) * buffer_size_bytes_));
+    buffer_bits_ = static_cast<u8*>(malloc(sizeof(u8) * buffer_size_bits_));
+    file->GetFileBuffer(buffer_bytes_, 0, buffer_size_bytes_);
+    for (int b = 0; b < file->GetFileSize(); b ++){
+        u8 byte = file->GetU8(b);
+        for (int i = 0; i < 8; i ++){
+            buffer_bits_[8 * b + i] = (byte >> 7 - i) & 1;
+            if (b < 9){
+                std::cout << "BYTE " << b << ": " << (int) byte << " " << i << ": " << (int)buffer_bits_[8 * b + i] << "\n";
+            }
+
+        }
+    }
+}
+
+BinaryFile::~BinaryFile(){}
+
+const Ogre::String& BinaryFile::GetFileName() const{return file_name_;}
+
+u32 BinaryFile::GetFileSize() const{return buffer_size_bytes_;}
+
+int BinaryFile::GetBits(u32 offset_bytes, u8 offset_bits, u8 bits) const{
+    int value = 0;
+    for (int b = 0; b < bits; b ++){
+        std::cout << (int)buffer_bits_[offset_bytes * 8 + offset_bits + b];
+        if (buffer_bits_[offset_bytes * 8 + offset_bits + b] == 1){
+            std::cout << "(" << (int)pow(2, (bits - 1 - b)) << ") ";
+            value += pow(2, (bits - 1 - b));
+        }
+
+    }
+    std::cout << "\n";
+    return value;
+}
+
+int BinaryFile::ReadBits(u8 bits){
+    int data(GetBits(offset_.bytes, offset_.bits, bits));
+    //std::cout << "READING BITS: " << (int)bits << " FROM " << offset_.bytes << "." << (int)offset_.bits << ": " << data << "\n";
+    offset_.bits += bits;
+    while (offset_.bits > 6){
+        offset_.bytes += 1;
+        offset_.bits -= 7;
+    }
+    return data;
+}
+
+u8 BinaryFile::GetU8(u32 offset) const{return *(buffer_bytes_ + offset);}
+
+u16 BinaryFile::GetU16LE(u32 offset) const{
+    return (buffer_bytes_ + offset)[0] | ((buffer_bytes_ + offset)[1] << 8);
+}
+
+u32 BinaryFile::GetU32LE(u32 offset) const{
+    return
+      (buffer_bytes_ + offset)[0]
+      | ((buffer_bytes_ + offset)[1] << 8)
+      | ((buffer_bytes_ + offset)[2] << 16)
+      | ((buffer_bytes_ + offset)[3] << 24);
+}
+
+u8 BinaryFile::ReadU8(){
+    Align();
+    u8 data(GetU8(offset_.bytes));
+    offset_.bytes += 1;
+    return data;
+}
+
+u16 BinaryFile::ReadU16LE(){
+    Align();
+    u16 data(GetU16LE(offset_.bytes));
+    offset_.bytes += 2;
+    return data;
+}
+
+u32 BinaryFile::ReadU32LE(){
+    Align();
+    u32 data(GetU32LE(offset_.bytes));
+    offset_.bytes += 4;
+    return data;
+}
+
+void BinaryFile::Align(){
+    if (offset_.bits == 0) return;
+    offset_.bits = 0;
+    offset_.bytes += 1;
+}
+
+u32 BinaryFile::GetCurrentOffset(){return offset_.bytes * 8 + offset_.bits;}
+
+void BinaryFile::SetOffset(u32 offset){
+    if (offset < buffer_size_bits_){
+        offset_.bytes = offset / 8;
+        offset_.bits = offset % 8;
+    }
+    else{
+        offset_.bytes = buffer_size_bits_ / 8 - 1;
+        offset_.bits = 7;
+    }
+}

+ 226 - 0
src/installer/common/BinaryFile.h

@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2022 The V-Gears Team
+ *
+ * This file is part of V-Gears
+ *
+ * V-Gears is free software: you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.0 (GPLv3) of the License.
+ *
+ * V-Gears is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#pragma once
+
+#include <OgreString.h>
+#include "common/TypeDefine.h"
+#include "common/File.h"
+
+/**
+ * Represents a file.
+ *
+ * This class is for files that need a lot of bit-reading for parsing. It's slower than it's
+ * counterpart {@see File}, which is better used in the rest of cases.
+ */
+class BinaryFile{
+
+    public:
+
+        /**
+         * Opens a file.
+         *
+         * @param[in] file Pointer to the file.
+         */
+        BinaryFile(const File* file);
+
+        /**
+         * Destructor.
+         */
+        virtual ~BinaryFile();
+
+        /**
+         * Retrieves the file name.
+         *
+         * @return The file name, without path.
+         */
+        const Ogre::String& GetFileName() const;
+
+        /**
+         * Retrieves the file size.
+         *
+         * @return File size, in bytes.
+         */
+        u32 GetFileSize() const;
+
+        /**
+         * Loads a buffer with the file data.
+         *
+         * @param[out] buffer Pointer to the buffer to load.
+         * @param[in] start Offset to the data to load.
+         * @param[in] length Length of the data to load.
+         */
+        void GetFileBuffer(u8* buffer, const u32 &start, const u32 &length) const;
+
+        /**
+         * Retrieves bits from the file.
+         *
+         * @param[in] offset_bits The offset, in bytes, to the bits to read.
+         * @param[in] offset_bits The offset, in bits, of the byte at {@see offset_byte} to read
+         * from.
+         * @param[in] bits Number of bits to read.
+         * @return Decimal valud of the read bits.
+         */
+        int GetBits(u32 offset_bytes, u8 offset_bits, u8 bits) const;
+
+        /**
+         * Retrieves bits from the file at the current offset.
+         *
+         * @param[in] bits Number of bits to read.
+         * @return Decimal valud of the read bits.
+         */
+        int ReadBits(u8 bits);
+
+        /**
+         * Retrieves a byte.
+         *
+         * @param[in] offset The offset of the byte.
+         * @return The byte at the specified offset.
+         */
+        u8 GetU8(u32 offset) const;
+
+        /**
+         * Retrieves two bytes (little endian) from the file.
+         *
+         * @param[in] offset The offset to the bytes.
+         * @return The bytes at the specified offset.
+         */
+        u16 GetU16LE(u32 offset) const;
+
+        /**
+         * Retrieves four bytes (little endian) from the file.
+         *
+         * @return The bytes at the specified offset.
+         */
+        u32 GetU32LE(u32 offset) const;
+
+        /**
+         * Reads a byte from the file at the current offset.
+         *
+         * Before reading, it aligns the current offset to the next byte.Advances the current
+         * offset by one byte when done.
+         *
+         * @return The data in the byte in the current offset of the file.
+         */
+        u8 ReadU8();
+
+        /**
+         * Reads two bytes from the file (little endian) at the current offset.
+         *
+         * Before reading, it aligns the current offset to the next byte.Advances the current
+         * offset by two bytes when done.
+         *
+         * @return Two bytes of data from the current offset of the file.
+         */
+        u16 ReadU16LE();
+
+        /**
+         * Reads four bytes from the file (little endian) at the current offset.
+         *
+         * Before reading, it aligns the current offset to the next byte.Advances the current
+         * offset by four bytes when done.
+         *
+         * @return Four bytes of data from the current offset of the file.
+         */
+        u32 ReadU32LE();
+
+
+        /**
+         * Checks the current offset, in bits, of the file.
+         *
+         * Default is 0. Can be set on instantiation with {@see
+         * BinaryFile(const File* file, u32 offset, u32 length)} or {@see
+         * BinaryFile(const u8* buffer, u32 offset, u32 length)} and advanced with
+         * {@see GeadBitsLE}, or {@see ReadBitsLE}
+         */
+        unsigned int GetCurrentOffset();
+
+        /**
+         * Sets the file offset for reading.
+         *
+         * If the offset is larger than the file size, the offset will be set to the end of the
+         * file
+         *
+         * @param[in] offset The new offset, in bits.
+         */
+        void SetOffset(unsigned int offset);
+
+        /**
+         * Aligns the current offset to the next byte.
+         */
+        void Align();
+
+    private:
+
+        /**
+         * Offset, to the bit.
+         */
+        struct Offset{
+
+            /**
+             * File offset, in bytes.
+             */
+            u32 bytes;
+
+            /**
+             * Ofset of the current byte, in bits
+             */
+            u8 bits;
+
+            /**
+             * Constructor, initializes to 0.
+             */
+            Offset(): bytes(0), bits(0){};
+        };
+
+        /**
+         * The file name.
+         */
+        Ogre::String file_name_;
+
+        /**
+         * Current offset of the file.
+         *
+         * Default is 0. Can be set on instantiation with {@see
+         * File(const File* file, u32 offset, u32 length)} or {@see
+         * File(const u8* buffer, u32 offset, u32 length)} and advanced with
+         * {@see readU8}, {@see readU16LE} or {@see readU32LE}
+         */
+        Offset offset_;
+
+        /**
+         * The file buffer, in bytes.
+         *
+         * It contains the file data, in bytes.
+         */
+        u8* buffer_bytes_;
+
+        /**
+         * The allocated size of {@see buffer_bytes_}, in bytes.
+         */
+        u32 buffer_size_bytes_;
+
+        /**
+         * The file buffer, bit by bit.
+         *
+         * It contains the file data, in bits.
+         */
+        u8* buffer_bits_;
+
+        /**
+         * The allocated size of {@see buffer_bits_}, in bits.
+         */
+        u32 buffer_size_bits_;
+};