From 1dba055926e16d6d35744541e504171589fb56a3 Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Thu, 16 Jan 2025 22:40:36 +0200 Subject: [PATCH 01/13] Init Game Model Converter --- CMakeLists.txt | 3 + src/tools/CMakeLists.txt | 1 + src/tools/gamemodelconverter/CMakeLists.txt | 17 + src/tools/gamemodelconverter/src/commands.cpp | 139 ++++ src/tools/gamemodelconverter/src/commands.h | 227 +++++++ src/tools/gamemodelconverter/src/log.cpp | 27 + src/tools/gamemodelconverter/src/log.h | 17 + src/tools/gamemodelconverter/src/main.cpp | 254 +++++++ .../gamemodelconverter/src/processor.cpp | 618 ++++++++++++++++++ src/tools/gamemodelconverter/src/processor.h | 155 +++++ src/tools/gamemodelconverter/src/readme.md | 24 + 11 files changed, 1482 insertions(+) create mode 100644 src/tools/gamemodelconverter/CMakeLists.txt create mode 100644 src/tools/gamemodelconverter/src/commands.cpp create mode 100644 src/tools/gamemodelconverter/src/commands.h create mode 100644 src/tools/gamemodelconverter/src/log.cpp create mode 100644 src/tools/gamemodelconverter/src/log.h create mode 100644 src/tools/gamemodelconverter/src/main.cpp create mode 100644 src/tools/gamemodelconverter/src/processor.cpp create mode 100644 src/tools/gamemodelconverter/src/processor.h create mode 100644 src/tools/gamemodelconverter/src/readme.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 633d57455..2b4093cdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -314,6 +314,9 @@ endif() # Build Thyme add_subdirectory(src) +# Build Game Model Converter +add_subdirectory(src/tools/gamemodelconverter) + if(STANDALONE) list(APPEND INSTALL_TARGETS thyme) endif() diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 9e1531eab..a33a2c89f 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -12,3 +12,4 @@ if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") endif() add_subdirectory(gametextcompiler) +add_subdirectory(gamemodelconverter) diff --git a/src/tools/gamemodelconverter/CMakeLists.txt b/src/tools/gamemodelconverter/CMakeLists.txt new file mode 100644 index 000000000..79a72059d --- /dev/null +++ b/src/tools/gamemodelconverter/CMakeLists.txt @@ -0,0 +1,17 @@ +set(CMAKE_CXX_STANDARD 17) + +set(GAMEMODELCONVERTER_SOURCES + src/commands.cpp + src/commands.h + src/log.cpp + src/log.h + src/main.cpp + src/processor.cpp + src/processor.h +) + +set(GAMEMODELCONVERTER_INCLUDES src) + +add_executable(gamemodelconverter ${GAMEMODELCONVERTER_SOURCES}) +target_include_directories(gamemodelconverter PRIVATE ${GAMEMODELCONVERTER_INCLUDES}) +target_link_libraries(gamemodelconverter PRIVATE thyme_lib) diff --git a/src/tools/gamemodelconverter/src/commands.cpp b/src/tools/gamemodelconverter/src/commands.cpp new file mode 100644 index 000000000..606be5f82 --- /dev/null +++ b/src/tools/gamemodelconverter/src/commands.cpp @@ -0,0 +1,139 @@ +/** + * @file + * + * @author xezon, DevGeniusCode + * + * @brief Model Converter Commands. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "commands.h" + +namespace Thyme +{ +namespace +{ +const char *const s_command_action_names[] = { + "LOAD_W3D", + "LOAD_W3X", + "LOAD_BLEND", + "LOAD_MAX", + "SAVE_W3D", + "SAVE_W3X", + "SAVE_BLEND", + "SAVE_MAX", + "RESET", + "SET_OPTIONS", +}; + +const char *const s_command_argument_names[] = { + "FILE_ID", + "FILE_PATH", + "OPTION", +}; + +const char *const s_simple_action_names[] = { + "OPTIONS", + "LOAD_W3D", + "LOAD_W3X", + "LOAD_BLEND", + "LOAD_MAX", + "SAVE_W3D", + "SAVE_W3X", + "SAVE_BLEND", + "SAVE_MAX", + +}; + +static_assert(ARRAY_SIZE(s_command_action_names) == g_commandActionCount); +static_assert(ARRAY_SIZE(s_command_argument_names) == g_commandArgumentCount); +static_assert(ARRAY_SIZE(s_simple_action_names) == g_simpleActionCount); + +template +bool String_To_Enum_Id(const char *str, EnumType &id, const char *const (&search_names)[Size]) +{ + for (size_t index = 0; index < ARRAY_SIZE(search_names); ++index) { + if (strcasecmp(str, search_names[index]) == 0) { + id = static_cast(index); + return true; + } + } + return false; +} +} // namespace + +bool String_To_Command_Action_Id(const char *str, CommandActionId &action_id) +{ + return String_To_Enum_Id(str, action_id, s_command_action_names); +} + +bool String_To_Command_Argument_Id(const char *str, CommandArgumentId &argument_id) +{ + return String_To_Enum_Id(str, argument_id, s_command_argument_names); +} + +bool String_To_Simple_Action_Id(const char *str, SimpleActionId &action_id) +{ + return String_To_Enum_Id(str, action_id, s_simple_action_names); +} + +CommandId Command::s_id = 1000000000; + +bool LoadW3DCommand::Execute() const +{ + return m_filePtr->Load_CSF(m_filePath.c_str()); +} + +bool LoadW3XCommand::Execute() const +{ + return m_filePtr->Load_W3X(m_filePath.c_str()); +} + +bool LoadBlendCommand::Execute() const +{ + return m_filePtr->Load_BLEND(m_filePath.c_str()); +} + +bool LoadMaxCommand::Execute() const +{ + return m_filePtr->Load_MAX(m_filePath.c_str()); +} + +bool SaveW3DCommand::Execute() const +{ + return m_filePtr->Save_W3D(m_filePath.c_str()); +} + +bool SaveW3XCommand::Execute() const +{ + return m_filePtr->Save_W3X(m_filePath.c_str()); +} + +bool SaveBlendCommand::Execute() const +{ + return m_filePtr->Save_BLEND(m_filePath.c_str()); +} + +bool SaveMaxCommand::Execute() const +{ + return m_filePtr->Save_MAX(m_filePath.c_str()); +} + +bool ResetCommand::Execute() const +{ + m_filePtr->Reset(); + return true; +} + +bool SetOptionsCommand::Execute() const +{ + m_filePtr->Set_Options(m_options); + return true; +} + +} // namespace Thyme diff --git a/src/tools/gamemodelconverter/src/commands.h b/src/tools/gamemodelconverter/src/commands.h new file mode 100644 index 000000000..708932914 --- /dev/null +++ b/src/tools/gamemodelconverter/src/commands.h @@ -0,0 +1,227 @@ +/** + * @file + * + * @author xezon, DevGeniusCode + * + * @brief GameModel Converter Commands. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once + +// TODO gameGameModelfile.h +#include +#include +#include + +namespace Thyme +{ +using CommandId = size_t; +using GameModelOption = GameModelOption; +using GameModelOptions = GameModelFile::Options; +using GameModelFile = GameModelFile; +using GameModelFilePtr = std::shared_ptr; + +enum class CommandActionId + +{ + INVALID = -1, + LOAD_W3D, + LOAD_W3X, + LOAD_BLEND, + LOAD_MAX, + SAVE_W3D, + SAVE_W3X, + SAVE_BLEND, + SAVE_MAX, + RESET, + SET_OPTIONS, + + COUNT +}; + +enum class CommandArgumentId +{ + INVALID = -1, + FILE_ID, + FILE_PATH, + OPTIONS, + + COUNT +}; + +enum class SimpleActionId +{ + OPTIONS, + LOAD_W3D_FILE, + LOAD_W3X_FILE, + LOAD_BLEND_FILE, + LOAD_MAX_FILE, + SAVE_W3D, + SAVE_W3X, + SAVE_BLEND, + SAVE_MAX, + + COUNT +}; + +constexpr size_t g_commandActionCount = size_t(CommandActionId::COUNT); +constexpr size_t g_commandArgumentCount = size_t(CommandArgumentId::COUNT); +constexpr size_t g_simpleActionCount = size_t(SimpleActionId::COUNT); + +bool String_To_Command_Action_Id(const char *str, CommandActionId &action_id); +bool String_To_Command_Argument_Id(const char *str, CommandArgumentId &argument_id); +bool String_To_Simple_Action_Id(const char *str, SimpleActionId &action_id); + +class Command +{ +public: + Command() : m_id(s_id++) {} + virtual ~Command() {} + + CommandId Id() const { return m_id; } + void Set_Id(CommandId id) { m_id = id; } + + virtual CommandActionId Type() const = 0; + virtual bool Execute() const = 0; + +private: + CommandId m_id; + static CommandId s_id; +}; + +class LoadW3DCommand : public Command +{ +public: + LoadW3DCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::LOAD_W3D; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class LoadW3XCommand : public Command +{ +public: + LoadW3XCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::LOAD_W3X; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class LoadBlendCommand : public Command +{ +public: + LoadBlendCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::LOAD_BLEND; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class LoadMaxCommand : public Command +{ +public: + LoadMaxCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::LOAD_MAX; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class SaveW3DCommand : public Command +{ +public: + SaveW3DCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::SAVE_W3D; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class SaveW3XCommand : public Command +{ +public: + SaveW3XCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::SAVE_W3X; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class SaveBlendCommand : public Command +{ +public: + SaveBlendCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::SAVE_BLEND; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class SaveMaxCommand : public Command +{ +public: + SaveMaxCommand(const GameModelFilePtr &file_ptr, const char *path) : m_filePtr(file_ptr), m_filePath(path) {} + + virtual CommandActionId Type() const override { return CommandActionId::SAVE_MAX; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + std::string m_filePath; +}; + +class ResetCommand : public Command +{ +public: + ResetCommand(const GameModelFilePtr &file_ptr) : m_filePtr(file_ptr) {} + + virtual CommandActionId Type() const override { return CommandActionId::RESET; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; +}; + +class SetOptionsCommand : public Command +{ +public: + SetOptionsCommand(const GameModelFilePtr &file_ptr, GameModelOptions options) : m_filePtr(file_ptr), m_options(options) {} + + virtual CommandActionId Type() const override { return CommandActionId::SET_OPTIONS; } + virtual bool Execute() const override; + +private: + GameModelFilePtr m_filePtr; + GameModelOptions m_options; +}; + +} // namespace Thyme diff --git a/src/tools/gamemodelconverter/src/log.cpp b/src/tools/gamemodelconverter/src/log.cpp new file mode 100644 index 000000000..bde4e3400 --- /dev/null +++ b/src/tools/gamemodelconverter/src/log.cpp @@ -0,0 +1,27 @@ +/** + * @file + * + * @author xezon + * + * @brief Game Text Compiler Log. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "log.h" +#include +#include + +void Print_Line(const char *message, ...) +{ + va_list args; + va_start(args, message); + vfprintf(stderr, message, args); + fprintf(stderr, "\n"); + va_end(args); + fflush(stderr); +} diff --git a/src/tools/gamemodelconverter/src/log.h b/src/tools/gamemodelconverter/src/log.h new file mode 100644 index 000000000..55b52f169 --- /dev/null +++ b/src/tools/gamemodelconverter/src/log.h @@ -0,0 +1,17 @@ +/** + * @file + * + * @author xezon + * + * @brief Game Text Compiler Log. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once + +void Print_Line(const char *message, ...); diff --git a/src/tools/gamemodelconverter/src/main.cpp b/src/tools/gamemodelconverter/src/main.cpp new file mode 100644 index 000000000..e29182e52 --- /dev/null +++ b/src/tools/gamemodelconverter/src/main.cpp @@ -0,0 +1,254 @@ +/** + * @file + * + * @author xezon, DevGeniusCode + * + * @brief Model Converter. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "log.h" +#include "processor.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined PLATFORM_WINDOWS +HWND g_applicationHWnd; +#endif + +using namespace Thyme; + +// clang-format off +void Print_Help() +{ +// 1 2 3 4 5 6 7 8 9 10 11 12 +//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 +Print_Line( +R"#(Function Command List ... + +Syntax: COMMAND_NAME(ARGUMENT_NAME_A:value,ARGUMENT_NAME_B:value) +All capital words are interpreted keywords and must not be omitted. +All symbols of ( : , ) are part of the syntax and must not be omitted. +'mandatory' and 'optional' words show whether or not argument is mandatory. +[1] and [n] words show that argument takes one or multiple values. +Commands and command arguments are not case sensitive. +Space character will end current Command and begin new Command in command line. +Commands are executed in the order they are written in the command line. + +LOAD_W3D(FILE_ID:optional, FILE_PATH:mandatory) + > Loads a W3D file from FILE_PATH into the FILE_ID slot. + The W3D file is considered the authoritative format. + +LOAD_W3X(FILE_ID:optional, FILE_PATH:mandatory) + > Loads a W3X file from FILE_PATH into the FILE_ID slot. + W3X is an XML format representation of W3D. + +LOAD_BLEND(FILE_ID:optional, FILE_PATH:mandatory) + > Loads a Blender (.blend) file from FILE_PATH into the FILE_ID slot. + Used for non-destructive editing of W3D data. + +LOAD_MAX(FILE_ID:optional, FILE_PATH:mandatory) + > Loads a 3ds Max (.max) file from FILE_PATH into the FILE_ID slot. + Used for non-destructive editing of W3D data. + +SAVE_W3D(FILE_ID:optional, FILE_PATH:mandatory) + > Saves the W3D file from FILE_ID slot to FILE_PATH. + +SAVE_W3X(FILE_ID:optional, FILE_PATH:mandatory) + > Saves the W3X file from FILE_ID slot to FILE_PATH. + +SAVE_BLEND(FILE_ID:optional, FILE_PATH:mandatory) + > Saves the Blender (.blend) file from FILE_ID slot to FILE_PATH. + +SAVE_MAX(FILE_ID:optional, FILE_PATH:mandatory) + > Saves the 3ds Max (.max) file from FILE_ID slot to FILE_PATH. + +RESET(FILE_ID:optional) + > Resets all loaded data in the specified FILE_ID slot. + +SET_OPTIONS(FILE_ID:optional,OPTION:[n]optional) + > Sets options of OPTION in FILE_ID. +)#"); +// 1 2 3 4 5 6 7 8 9 10 11 12 +//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 +Print_Line( +R"#(Command Argument List ... + +FILE_ID:number +FILE_ID takes number and allows to manage multiple files in compiler. Default is 0. + +FILE_PATH:path +FILE_PATH takes any relative or absolute path. + +OPTION:enum +OPTION takes one [1] or multiple [n] options, separated by pipe: +None +)#"); +// 1 2 3 4 5 6 7 8 9 10 11 12 +//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 +Print_Line( +R"#(Simplified Command List ... + +Commands are executed in the order they are listed here. +All capital words are NOT interpreted keywords and are substituted by the command argument(s) of choice. +[1] and [n] words show that argument takes one or multiple values. +Commands and command arguments are not case sensitive. + +WARNING: Commands that save files will overwrite existing files without confirmation. + +-load_w3d filepath.w3d + > Loads a W3D file from the specified file path. + +-load_w3x filepath.w3x + > Loads a W3X file from the specified file path. + +-load_blend filepath.blend + > Loads a Blender file from the specified file path. + +-load_max filepath.max + > Loads a 3ds Max file from the specified file path. + +-save_w3d filepath.w3d + > Saves the loaded data as a W3D file to the given file path. + +-save_w3x filepath.w3x + > Saves the loaded data as a W3X file to the given file path. + +-save_blend filepath.blend + > Saves the loaded data as a Blender file to the given file path. + +-save_max filepath.max + > Saves the loaded data as a 3ds Max file to the given file path. + +Example 1: Convert a W3D file to W3X format + > w3d2w3xcompiler.exe -load_w3d D:\models\model.w3d -convert_w3d_to_w3x D:\models\model.w3x + +Example 2: Convert a W3X file to W3D format + > w3d2w3xcompiler.exe -load_w3x D:\models\model.w3x -convert_w3x_to_w3d D:\models\model.w3d + +Example 3: Load a Blender file and save as W3D + > w3d2w3xcompiler.exe -load_blend D:\models\model.blend -save_w3d D:\models\model.w3d + +Example 4: Load a W3D file and save as Max format + > w3d2w3xcompiler.exe -load_w3d D:\models\model.w3d -save_max D:\models\model.max +)#"); +} +// clang-format on + +void Print_Error(const Processor::Result &result, const Processor::CommandTexts &command_texts) +{ + const size_t command_index = result.error_command_index; + const char *result_name = Processor::Get_Result_Name(result.id); + const char *command_name = (command_index < command_texts.size()) ? command_texts[command_index] : ""; + const std::string error_str(result.error_text.begin(), result.error_text.end()); + + Print_Line("Execution stopped with error '%s' at command '%s' (%zu) and error string '%s'", + result_name, + command_name, + command_index, + error_str.c_str()); +} + + +namespace +{ +constexpr int NoError = 0; +constexpr int MissingArgumentsError = 1; +constexpr int ProcessorParseError = 2; +constexpr int ProcessorExecuteError = 3; +} // namespace + +LocalFileSystem *Create_Local_File_System() +{ + return new Win32LocalFileSystem; +} + +ArchiveFileSystem *Create_Archive_File_System() +{ + return new Win32BIGFileSystem; +} + +struct CaptainsLogCreator +{ + CaptainsLogCreator() + { + captains_settings_t captains_settings = { 0 }; + captains_settings.level = LOGLEVEL_DEBUG; + captains_settings.console = true; + captains_settings.print_file = true; + captainslog_init(&captains_settings); + }; + ~CaptainsLogCreator() { captainslog_deinit(); } +}; + +struct EngineSystemsCreator +{ + EngineSystemsCreator() + { + g_theSubsystemList = new SubsystemInterfaceList; + g_theFileSystem = new FileSystem; + Init_Subsystem(g_theLocalFileSystem, "TheLocalFileSystem", Create_Local_File_System()); + g_theLocalFileSystem->Init(); +#if 0 + Init_Subsystem(g_theArchiveFileSystem, "TheArchiveFileSystem", Create_Archive_File_System()); + g_theArchiveFileSystem->Init(); +#endif + } + ~EngineSystemsCreator() + { + delete g_theArchiveFileSystem; + delete g_theLocalFileSystem; + delete g_theFileSystem; + delete g_theSubsystemList; + g_theArchiveFileSystem = nullptr; + g_theLocalFileSystem = nullptr; + g_theFileSystem = nullptr; + g_theSubsystemList = nullptr; + } +}; + +int main(int argc, const char *argv[]) +{ + Print_Line("W3D W3X Compiler v1.0 By The Assembly Armada"); + + if (argc < 2) { + Print_Help(); + return MissingArgumentsError; + } + // TODO: W3DFILE + GameModelFILE::Set_Log_File(stderr); + CaptainsLogCreator captains_log_creator; + EngineSystemsCreator engine_systems_creator; + + const auto command_texts = rts::Make_Array_View(argv + 1, argc - 1); + Processor processor; + Processor::Result result = processor.Parse_Commands(command_texts); + + if (result.id != Processor::ResultId::SUCCESS) { + Print_Line("ERROR : Model Converter failed to parse commands"); + Print_Error(result, command_texts); + return ProcessorParseError; + } + + result = processor.Execute_Commands(); + + if (result.id != Processor::ResultId::SUCCESS) { + Print_Line("ERROR : Model Converter failed to execute commands"); + Print_Error(result, command_texts); + return ProcessorExecuteError; + } + + Print_Line("Model Converter completed successfully"); + return NoError; +} diff --git a/src/tools/gamemodelconverter/src/processor.cpp b/src/tools/gamemodelconverter/src/processor.cpp new file mode 100644 index 000000000..cdf37d404 --- /dev/null +++ b/src/tools/gamemodelconverter/src/processor.cpp @@ -0,0 +1,618 @@ +/** + * @file + * + * @author xezon, DevGeniusCode + * + * @brief Model Converter Processor. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "processor.h" +#include "commands.h" +#include +#include + +namespace Thyme +{ +namespace +{ +constexpr const char *const s_result_names[] = { + "SUCCESS", + "INVALID_COMMAND_ACTION", + "INVALID_COMMAND_ARGUMENT", + "INVALID_OPTION_VALUE", + "INVALID_FILE_ID_ARGUMENT", + "MISSING_FILE_PATH_ARGUMENT", + "EXECUTION_ERROR", +}; + +static_assert(ARRAY_SIZE(s_result_names) == size_t(Processor::ResultId::COUNT)); +} // namespace + +const char *Processor::Get_Result_Name(ResultId id) +{ + return s_result_names[size_t(id)]; +} + +const Processor::FileId Processor::s_defaultFileId = { 0 }; + +Processor::Processor() : m_fileMap(), m_commands() {} + +Processor::Result Processor::Parse_Commands(const CommandTexts &command_texts) +{ + if (Has_Simple_Command(command_texts)) { + return Parse_Simple_Commands(command_texts); + } else { + return Parse_Function_Commands(command_texts); + } +} + +Processor::Result Processor::Execute_Commands() const +{ + Result result(ResultId::SUCCESS); + + for (const CommandPtr &command : m_commands) { + if (!command->Execute()) { + result.id = ResultId::EXECUTION_ERROR; + result.error_command_index = command->Id(); + break; + } + } + return result; +} + +Processor::Result Processor::Parse_Function_Commands(const CommandTexts &command_texts) +{ + Result result(ResultId::SUCCESS); + CommandPtrs commands; + + for (size_t index = 0; index < command_texts.size(); ++index) { + + CommandAction action; + result = Parse_Function_Command(action, command_texts[index], index); + + if (result.id != ResultId::SUCCESS) { + result.error_command_index = index; + break; + } + + result = Add_New_Command(commands, m_fileMap, action); + + if (result.id != ResultId::SUCCESS) { + result.error_command_index = index; + break; + } + } + + if (result.id == ResultId::SUCCESS) { + m_commands.swap(commands); + } + + return result; +} + +Processor::Result Processor::Parse_Simple_Commands(const CommandTexts &command_texts) +{ + Result result(ResultId::SUCCESS); + CommandActionSequence actions; + CommandPtrs commands; + + if (!command_texts.empty()) { + + const size_t size = command_texts.size(); + + for (size_t index = 0; index < size - 1; ++index) { + + if (!Is_Simple_Command(command_texts[index])) { + continue; + } + + const char *command_name = command_texts[index] + 1; + const char *command_value = command_texts[index + 1]; + + result = Parse_Simple_Command(actions, command_name, command_value, index); + + if (result.id != ResultId::SUCCESS) { + result.error_command_index = index; + break; + } + + ++index; + } + } + + if (result.id == ResultId::SUCCESS) { + + for (const CommandAction &action : actions) { + if (action.action_id != CommandActionId::INVALID) { + result = Add_New_Command(commands, m_fileMap, action); + + if (result.id != ResultId::SUCCESS) { + result.error_command_index = action.command_index; + break; + } + } + } + } + + if (result.id == ResultId::SUCCESS) { + m_commands.swap(commands); + } + + return result; +} + +bool Processor::Has_Simple_Command(const CommandTexts &command_texts) +{ + for (const char *command_text : command_texts) { + if (Is_Simple_Command(command_text)) { + return true; + } + } + return false; +} + +bool Processor::Is_Simple_Command(const char *command_text) +{ + return command_text != nullptr && *command_text == '-'; +} + +template bool Processor::Parse_Next_Word(std::string &word, const char *&str, const char (&separators)[Size]) +{ + const char *reader = str; + + do { + for (const char separator : separators) { + if (*reader == separator && reader > str) { + word.assign(str, reader); + str = reader; + if (*str != '\0') { + str += 1; + } + return true; + } + } + } while (*reader++ != '\0'); + + return false; +} + +Processor::Result Processor::Parse_Function_Command(CommandAction &action, const char *command_text, size_t command_index) +{ + Result result(ResultId::SUCCESS); + CommandActionId action_id = CommandActionId::INVALID; + CommandArgumentId argument_id = CommandArgumentId::INVALID; + CommandArguments arguments; + const char *reader = command_text; + std::string word; + + while (true) { + const char *word_begin = reader; + + if (reader == command_text && Parse_Next_Word(word, reader, { '(' })) { + if (!String_To_Command_Action_Id(word.c_str(), action_id)) { + result.id = ResultId::INVALID_COMMAND_ACTION; + result.error_text = ErrorText(word_begin, reader); + break; + } + + } else if (argument_id == CommandArgumentId::INVALID && Parse_Next_Word(word, reader, { ':' })) { + if (!String_To_Command_Argument_Id(word.c_str(), argument_id)) { + result.id = ResultId::INVALID_COMMAND_ARGUMENT; + result.error_text = ErrorText(word_begin, reader); + break; + } + arguments.emplace_back(); + + } else if (argument_id != CommandArgumentId::INVALID && Parse_Next_Word(word, reader, { ',', '|', ')' })) { + result = Parse_Command_Argument(arguments.back(), word, argument_id); + if (result.id != ResultId::SUCCESS) { + result.error_text = ErrorText(word_begin, reader); + break; + } + if (*(reader - 1) == ',') { + argument_id = CommandArgumentId::INVALID; + } + + } else { + break; + } + } + + if (action_id == CommandActionId::INVALID) { + result.id = ResultId::INVALID_COMMAND_ACTION; + } + + if (result.id == ResultId::SUCCESS) { + action.action_id = action_id; + action.arguments.swap(arguments); + action.command_index = command_index; + } + + return result; +} + +Processor::Result Processor::Parse_Simple_Command( + CommandActionSequence &actions, const char *command_name, const char *command_value, size_t command_index) +{ + Result result(ResultId::SUCCESS); + SimpleActionId simple_action_id; + + if (!String_To_Simple_Action_Id(command_name, simple_action_id)) { + result.id = ResultId::INVALID_COMMAND_ACTION; + result.error_text = ErrorText(command_name, command_name + strlen(command_name)); + return result; + } + + bool overwrite_action_id = false; + SequenceId sequence_id = SequenceId::INVALID; + CommandActionId action_id = CommandActionId::INVALID; + CommandArgumentId argument_id = CommandArgumentId::INVALID; + + switch (simple_action_id) { + case SimpleActionId::OPTIONS: + sequence_id = SequenceId::SET_OPTIONS; + action_id = CommandActionId::SET_OPTIONS; + argument_id = CommandArgumentId::OPTIONS; + break; + case SimpleActionId::LOAD_W3D_FILE: + sequence_id = SequenceId::LOAD; + action_id = CommandActionId::LOAD_W3D; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::LOAD_W3X_FILE: + sequence_id = SequenceId::LOAD; + action_id = CommandActionId::LOAD_W3X; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::LOAD_BLEND_FILE: + sequence_id = SequenceId::LOAD; + action_id = CommandActionId::LOAD_BLEND; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::LOAD_MAX_FILE: + sequence_id = SequenceId::LOAD; + action_id = CommandActionId::LOAD_MAX; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::SAVE_W3D: + sequence_id = SequenceId::SAVE; + action_id = CommandActionId::SAVE_W3D; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::SAVE_W3X: + sequence_id = SequenceId::SAVE; + action_id = CommandActionId::SAVE_W3X; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::SAVE_BLEND: + sequence_id = SequenceId::SAVE; + action_id = CommandActionId::SAVE_BLEND; + argument_id = CommandArgumentId::FILE_PATH; + break; + case SimpleActionId::SAVE_MAX: + sequence_id = SequenceId::SAVE; + action_id = CommandActionId::SAVE_MAX; + argument_id = CommandArgumentId::FILE_PATH; + break; + } + + static_assert(g_simpleActionCount == 9, "SimpleAction is missing"); + + captainslog_assert(sequence_id != SequenceId::INVALID); + + if (sequence_id != SequenceId::INVALID) { + CommandArgument argument; + + { + const char *reader = command_value; + const char *word_begin = reader; + std::string word; + + while (Parse_Next_Word(word, reader, { '|', '\0' })) { + result = Parse_Command_Argument(argument, word, argument_id); + if (result.id != ResultId::SUCCESS) { + result.error_text = ErrorText(word_begin, reader); + break; + } + word_begin = reader; + } + } + + if (result.id == ResultId::SUCCESS) { + CommandAction &action = actions[size_t(sequence_id)]; + + if (action.action_id == CommandActionId::INVALID || overwrite_action_id) { + action.action_id = action_id; + action.command_index = command_index; + } + action.arguments.emplace_back(std::move(argument)); + } + } + + return result; +} + +Processor::Result Processor::Parse_Command_Argument( + CommandArgument &argument, std::string &str, CommandArgumentId argument_id) +{ + Result result(ResultId::SUCCESS); + + switch (argument_id) { + case CommandArgumentId::FILE_ID: { + FileId file_id; + file_id.value = std::stoi(str); + argument.value.emplace(std::move(file_id)); + break; + } + case CommandArgumentId::FILE_PATH: { + FilePath file_path; + file_path.value = str.c_str(); + argument.value.emplace(std::move(file_path)); + break; + } + case CommandArgumentId::OPTIONS: { + GameModelOption option; + + if (Name_To_Game_Text_Option(str.c_str(), option)) { + GameModelOptions options; + const GameModelOptions *options_ptr = std::get_if(&argument.value); + if (options_ptr != nullptr) { + options = *options_ptr; + } + options |= option; + argument.value.emplace(std::move(options)); + + } else { + result.id = ResultId::INVALID_OPTION_VALUE; + } + break; + } + } + + static_assert(g_commandArgumentCount == 3, "CommandArgument is missing"); + + return result; +} + +Processor::Result Processor::Add_New_Command(CommandPtrs &commands, FileMap &file_map, const CommandAction &action) +{ + Result result(ResultId::SUCCESS); + + Populate_File_Map(file_map, action); + + switch (action.action_id) { + case CommandActionId::LOAD_W3D: + result = Add_Load_W3D_Command(commands, file_map, action); + break; + case CommandActionId::LOAD_W3X: + result = Add_Load_W3X_Command(commands, file_map, action); + break; + case CommandActionId::LOAD_BLEND: + result = Add_Load_BLEND_Command(commands, file_map, action); + break; + case CommandActionId::LOAD_MAX: + result = Add_Load_MAX_Command(commands, file_map, action); + break; + case CommandActionId::SAVE_W3D: + result = Add_Save_W3D_Command(commands, file_map, action); + break; + case CommandActionId::SAVE_W3X: + result = Add_Save_W3X_Command(commands, file_map, action); + break; + case CommandActionId::SAVE_BLEND: + result = Add_Save_BLEND_Command(commands, file_map, action); + break; + case CommandActionId::SAVE_MAX: + result = Add_Save_MAX_Command(commands, file_map, action); + break; + case CommandActionId::RESET: + result = Add_Reset_Command(commands, file_map, action); + break; + case CommandActionId::SET_OPTIONS: + result = Add_Set_Options_Command(commands, file_map, action); + break; + } + + static_assert(g_commandActionCount == 10, "CommandAction is missing"); + + if (result.id == ResultId::SUCCESS) { + commands.back()->Set_Id(action.command_index); + } + + return result; +} + +Processor::Result Processor::Add_Load_W3D_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new LoadW3DCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Load_W3X_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new LoadW3XCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Load_BLEND_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new LoadBlendCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Load_MAX_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new LoadMaxCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Save_W3D_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new SaveW3DCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Save_W3X_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new SaveW3XCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Save_BLEND_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new SaveBlendCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Save_MAX_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto file_path = Get_File_Path(action.arguments); + + if (file_path == nullptr) { + return Result(ResultId::MISSING_FILE_PATH_ARGUMENT); + } + + commands.emplace_back(new SaveMaxCommand(file_ptr, file_path)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Reset_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + + commands.emplace_back(new ResetCommand(file_ptr)); + return Result(ResultId::SUCCESS); +} + +Processor::Result Processor::Add_Set_Options_Command( + CommandPtrs &commands, const FileMap &file_map, const CommandAction &action) +{ + const auto file_ptr = Get_File_Ptr(action.arguments, file_map); + const auto options = Get_Options(action.arguments); + + commands.emplace_back(new SetOptionsCommand(file_ptr, options)); + return Result(ResultId::SUCCESS); +} + +void Processor::Populate_File_Map(FileMap &file_map, const CommandAction &action) +{ + const FileId *file_id_ptr = Find_Ptr(action.arguments); + const FileId file_id = (file_id_ptr == nullptr) ? s_defaultFileId : *file_id_ptr; + Populate_File_Map(file_map, file_id); +} + +void Processor::Populate_File_Map(FileMap &file_map, FileId file_id) +{ + const FileMap::iterator it = file_map.find(file_id); + if (it == file_map.end()) { + auto *file = new GameModelFile(); + file->Set_Options(GameModelOptions::Value::NONE); + file_map.emplace(file_id, file); + } +} + +GameModelFilePtr Processor::Get_File_Ptr(const FileMap &file_map, FileId file_id) +{ + const FileMap::const_iterator it = file_map.find(file_id); + captainslog_assert(it != file_map.end()); + return it->second; +} + +template const Type *Processor::Find_Ptr(const CommandArguments &arguments, size_t occurence) +{ + size_t num = 0; + for (const CommandArgument &argument : arguments) { + const Type *type_ptr = std::get_if(&argument.value); + if (type_ptr != nullptr) { + if (occurence == num++) { + return type_ptr; + } + } + } + return nullptr; +} + +GameModelFilePtr Processor::Get_File_Ptr(const CommandArguments &arguments, const FileMap &file_map, size_t occurence) +{ + const FileId *ptr = Find_Ptr(arguments, occurence); + const FileId file_id = (ptr == nullptr) ? s_defaultFileId : *ptr; + return Get_File_Ptr(file_map, file_id); +} + +const char *Processor::Get_File_Path(const CommandArguments &arguments, size_t occurence) +{ + const FilePath *ptr = Find_Ptr(arguments, occurence); + return (ptr == nullptr) ? nullptr : ptr->value.c_str(); +} + +GameModelOptions Processor::Get_Options(const CommandArguments &arguments, size_t occurence) +{ + const GameModelOptions *ptr = Find_Ptr(arguments, occurence); + return (ptr == nullptr) ? GameModelOptions() : *ptr; +} + +} // namespace Thyme diff --git a/src/tools/gamemodelconverter/src/processor.h b/src/tools/gamemodelconverter/src/processor.h new file mode 100644 index 000000000..60722a30d --- /dev/null +++ b/src/tools/gamemodelconverter/src/processor.h @@ -0,0 +1,155 @@ +/** + * @file + * + * @author xezon, DevGeniusCode + * + * @brief Model Converter Processor. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once + +#include "commands.h" +#include +#include +#include +#include +#include + +namespace Thyme +{ +class Processor +{ +public: + enum class ResultId + { + SUCCESS, + INVALID_COMMAND_ACTION, + INVALID_COMMAND_ARGUMENT, + INVALID_OPTION_VALUE, + INVALID_FILE_ID_ARGUMENT, + MISSING_FILE_PATH_ARGUMENT, + EXECUTION_ERROR, + + // #TODO Add more detailed execution errors once GameModelFile supports it + + COUNT + }; + + static const char *Get_Result_Name(ResultId id); + + using ErrorText = rts::array_view; + using CommandTexts = rts::array_view; + + struct Result + { + explicit Result(ResultId id) : id(id), error_command_index(0), error_text() {} + + ResultId id; + size_t error_command_index; + ErrorText error_text; + }; + +public: + Processor(); + + Result Parse_Commands(const CommandTexts &command_texts); + Result Execute_Commands() const; + +private: + using CommandPtr = std::shared_ptr; + using CommandPtrs = std::vector; + + struct FileId + { + bool operator==(const FileId &other) const { return value == other.value; } + int value; + }; + + struct FileIdHash + { + std::size_t operator()(const FileId &key) const { return std::hash{}(key.value); } + }; + // TODO GameModelFilePtr change + using FileMap = std::unordered_map; + + struct FilePath + { + std::string value; + }; + + struct CommandArgument + { + // TODO GameModelOptions change + std::variant value; + }; + + using CommandArguments = std::vector; + + struct CommandAction + { + CommandActionId action_id = CommandActionId::INVALID; + CommandArguments arguments; + size_t command_index = 0; + }; + + enum class SequenceId + { + INVALID = -1, + SET_OPTIONS, + LOAD, + SAVE, + + COUNT + }; + + using CommandActionSequence = std::array; + +private: + Result Parse_Function_Commands(const CommandTexts &command_texts); + Result Parse_Simple_Commands(const CommandTexts &command_texts); + + static bool Has_Simple_Command(const CommandTexts &command_texts); + static bool Is_Simple_Command(const char *command_text); + + template bool static Parse_Next_Word(std::string &word, const char *&str, const char (&separators)[Size]); + + static Result Parse_Function_Command(CommandAction &action, const char *command_text, size_t command_index); + static Result Parse_Simple_Command( + CommandActionSequence &actions, const char *command_name, const char *command_value, size_t command_index); + static Result Parse_Command_Argument(CommandArgument &argument, std::string &str, CommandArgumentId argument_id); + + static Result Add_New_Command(CommandPtrs &commands, FileMap &file_map, const CommandAction &action); + static Result Add_Load_W3D_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Load_W3X_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Load_BLEND_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Load_MAX_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Save_W3D_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Save_W3X_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Save_BLEND_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Save_MAX_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Reset_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + static Result Add_Set_Options_Command(CommandPtrs &commands, const FileMap &file_map, const CommandAction &action); + + static void Populate_File_Map(FileMap &file_map, const CommandAction &action); + static void Populate_File_Map(FileMap &file_map, FileId file_id); + static GameModelFilePtr Get_File_Ptr(const FileMap &file_map, FileId file_id); + + template static const Type *Find_Ptr(const CommandArguments &arguments, size_t occurence = 0); + static GameModelFilePtr Get_File_Ptr(const CommandArguments &arguments, const FileMap &file_map, size_t occurence = 0); + static const char *Get_File_Path(const CommandArguments &arguments, size_t occurence = 0); + static GameModelOptions Get_Options(const CommandArguments &arguments, size_t occurence = 0); + +private: + FileMap m_fileMap; + CommandPtrs m_commands; + + static const FileId s_defaultFileId; +}; + +} // namespace Thyme diff --git a/src/tools/gamemodelconverter/src/readme.md b/src/tools/gamemodelconverter/src/readme.md new file mode 100644 index 000000000..c78a4503a --- /dev/null +++ b/src/tools/gamemodelconverter/src/readme.md @@ -0,0 +1,24 @@ +The main goal of the project is to create a set of tools that allow the conversion between different file formats used +in 3D modeling for game development. Specifically, the tools will focus on converting **W3D** files (binary format) into +**W3X** (XML format), and also facilitate conversion between W3D and other formats like **Blend** (Blender files) and * +*Max** (3ds Max files). Here's a breakdown of the key points: + +1. **W3D to W3X Conversion**: The first task is to convert binary W3D files into a text-based W3X format. This would + allow better compatibility and transparency because W3X is an XML format, which is easier to parse and edit compared + to the binary W3D format. + +2. **Thyme as the Starting Point**: The development of the **W3D to W3X** conversion tool will begin by using **existing + code in Thyme**, which will help maintain consistency and compatibility across tools and workflows. + +3. **Maintaining Consistency with Mod Builder**: Once W3X files are created, the Mod Builder tool will allow conversion + between W3D, Blend, and Max files. The goal is to ensure that these conversions are **non-destructive**, meaning that + converting a Blend or Max file back to W3D should not introduce any errors or issues. The **Blend to W3D** conversion + is already supported by Mod Builder, but there are concerns about potential issues with the Blender plugin causing + data loss on import. + +4. **W3D as the "File of Truth"**: Throughout this process, the W3D file is considered the authoritative format. W3X is + a **faithful representation** of the W3D file, while Blend and Max files are **non-destructive** representations, + meaning they can be used for editing and modeling without corrupting or altering the original W3D file. + +In summary, the project involves creating a reliable pipeline that can convert between W3D, W3X, Blend, and Max files, +using W3D as the reference format and leveraging existing tools like Thyme and Mod Builder. \ No newline at end of file From c3791344738d48c184ce1aef694227f9334c4878 Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Sat, 18 Jan 2025 23:05:04 +0200 Subject: [PATCH 02/13] Added gamemodelfile.h and gamemodelcommon.h --- src/tools/gamemodelconverter/CMakeLists.txt | 9 +- src/tools/gamemodelconverter/src/commands.cpp | 2 +- src/tools/gamemodelconverter/src/commands.h | 3 +- .../gamemodelconverter/src/gamemodelcommon.h | 69 +++ .../gamemodelconverter/src/gamemodelfile.cpp | 425 ++++++++++++++++++ .../gamemodelconverter/src/gamemodelfile.h | 197 ++++++++ src/tools/gamemodelconverter/src/main.cpp | 11 +- .../gamemodelconverter/src/processor.cpp | 2 +- 8 files changed, 705 insertions(+), 13 deletions(-) create mode 100644 src/tools/gamemodelconverter/src/gamemodelcommon.h create mode 100644 src/tools/gamemodelconverter/src/gamemodelfile.cpp create mode 100644 src/tools/gamemodelconverter/src/gamemodelfile.h diff --git a/src/tools/gamemodelconverter/CMakeLists.txt b/src/tools/gamemodelconverter/CMakeLists.txt index 79a72059d..8f0188f64 100644 --- a/src/tools/gamemodelconverter/CMakeLists.txt +++ b/src/tools/gamemodelconverter/CMakeLists.txt @@ -1,6 +1,9 @@ set(CMAKE_CXX_STANDARD 17) set(GAMEMODELCONVERTER_SOURCES + src/gamemodelcommon.h + src/gamemodelfile.cpp + src/gamemodelfile.h src/commands.cpp src/commands.h src/log.cpp @@ -12,6 +15,6 @@ set(GAMEMODELCONVERTER_SOURCES set(GAMEMODELCONVERTER_INCLUDES src) -add_executable(gamemodelconverter ${GAMEMODELCONVERTER_SOURCES}) -target_include_directories(gamemodelconverter PRIVATE ${GAMEMODELCONVERTER_INCLUDES}) -target_link_libraries(gamemodelconverter PRIVATE thyme_lib) +add_executable(GameModelConverter ${GAMEMODELCONVERTER_SOURCES}) +target_include_directories(GameModelConverter PRIVATE ${GAMEMODELCONVERTER_INCLUDES}) +target_link_libraries(GameModelConverter PRIVATE thyme_lib) diff --git a/src/tools/gamemodelconverter/src/commands.cpp b/src/tools/gamemodelconverter/src/commands.cpp index 606be5f82..e0530c653 100644 --- a/src/tools/gamemodelconverter/src/commands.cpp +++ b/src/tools/gamemodelconverter/src/commands.cpp @@ -86,7 +86,7 @@ CommandId Command::s_id = 1000000000; bool LoadW3DCommand::Execute() const { - return m_filePtr->Load_CSF(m_filePath.c_str()); + return m_filePtr->Load_W3D(m_filePath.c_str()); } bool LoadW3XCommand::Execute() const diff --git a/src/tools/gamemodelconverter/src/commands.h b/src/tools/gamemodelconverter/src/commands.h index 708932914..6ad86f2d5 100644 --- a/src/tools/gamemodelconverter/src/commands.h +++ b/src/tools/gamemodelconverter/src/commands.h @@ -14,8 +14,7 @@ */ #pragma once -// TODO gameGameModelfile.h -#include +#include #include #include diff --git a/src/tools/gamemodelconverter/src/gamemodelcommon.h b/src/tools/gamemodelconverter/src/gamemodelcommon.h new file mode 100644 index 000000000..bedb1b580 --- /dev/null +++ b/src/tools/gamemodelconverter/src/gamemodelcommon.h @@ -0,0 +1,69 @@ +/** + * @file gamemodelcommon.h + * + * @author DevGeniusCode + * + * @brief Common structures for Game Model Files. + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once + +#include "asciistring.h" +#include "bittype.h" +#include "unicodestring.h" +#include "utility/array.h" +#include "w3d_file.h" +#include +#include +#include + +namespace Thyme +{ + +struct ChunkInfo +{ + uint32_t id; + size_t size; + std::vector data; + + //Helper function to read data from the chunk + template + T* GetData() { + if (data.size() < sizeof(T)) return nullptr; //Check for size before cast. + return reinterpret_cast(data.data()); + } + + //Helper function to read a string from the chunk. Assumes null termination + std::string GetString() { + auto cstr = reinterpret_cast(data.data()); + return std::string(cstr); + } +}; + +struct ChunkInfos +{ + std::vector chunks; + + //Helper to find a chunk by ID + ChunkInfo* FindChunk(uint32_t id) { + for (auto& chunk : chunks) { + if (chunk.id == id) return &chunk; + } + return nullptr; + } + + const ChunkInfo* FindChunk(uint32_t id) const { + for (const auto& chunk : chunks) { + if (chunk.id == id) return &chunk; + } + return nullptr; + } +}; + +} // namespace Thyme \ No newline at end of file diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp new file mode 100644 index 000000000..9d59ce6f4 --- /dev/null +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -0,0 +1,425 @@ +/** + * @file gamemodelfile.cpp + * + * @author DevGeniusCode + * + * @brief Game Model File. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "always.h" +#include "gamemodelfile.h" +#include "filesystem.h" +#include "rtsutils.h" +#include "utility/arrayutil.h" +#include "utility/fileutil.h" +#include "utility/stlutil.h" +#include "utility/stringutil.h" +#include "w3dfilesystem.h" + +#define GAMEMODELLOG_TRACE(fmt, ...) \ + captainslog_trace(fmt, ##__VA_ARGS__); \ + GameModelFile::Log_Line("TRACE : ", fmt, ##__VA_ARGS__) + +#define GAMEMODELLOG_DEBUG(fmt, ...) \ + captainslog_debug(fmt, ##__VA_ARGS__); \ + GameModelFile::Log_Line("DEBUG : ", fmt, ##__VA_ARGS__) + +#define GAMEMODELLOG_INFO(fmt, ...) \ + captainslog_info(fmt, ##__VA_ARGS__); \ + GameModelFile::Log_Line("", fmt, ##__VA_ARGS__) + +#define GAMEMODELLOG_WARN(fmt, ...) \ + captainslog_warn(fmt, ##__VA_ARGS__); \ + GameModelFile::Log_Line("WARNING : ", fmt, ##__VA_ARGS__) + +#define GAMEMODELLOG_ERROR(fmt, ...) \ + captainslog_error(fmt, ##__VA_ARGS__); \ + GameModelFile::Log_Line("ERROR : ", fmt, ##__VA_ARGS__) + +#define GAMEMODELLOG_FATAL(fmt, ...) \ + captainslog_fatal(fmt, ##__VA_ARGS__); \ + GameModelFile::Log_Line("FATAL : ", fmt, ##__VA_ARGS__) + +namespace Thyme +{ + +namespace +{ +template constexpr size_t Bit_To_Index(IntegerType integer) +{ + using UnsignedInt = UnsignedIntegerT; + size_t n = 0; + for (; n < sizeof(IntegerType) * 8; ++n) { + if (UnsignedInt(integer) & (UnsignedInt(1) << n)) { + return n; + } + } + return n; +} + +constexpr const char *const s_option_0 = "None"; + +constexpr const char *const s_options[] = { + s_option_0, +}; + +static_assert(s_option_0 == s_options[size_t(GameModelOption::NONE)]); +} // namespace + +bool Name_To_Game_Model_Option(const char *name, GameModelOption &option) +{ + size_t index = 0; + for (const char *option_name : s_options) { + if (strcasecmp(option_name, name) == 0) { + option = (index == 0) ? GameModelOption::NONE : static_cast(1 << (index - 1)); + return true; + } + ++index; + } + return false; +} + +FILE *GameModelFile::s_logfile = nullptr; +GameModelFile::GameModelFile() : // Initialize with default options + m_options(GameModelOption::NONE), m_chunkInfosArray() {}; + +bool GameModelFile::Is_Loaded() const +{ + return !Get_Chunk_Infos().empty(); +} + +bool GameModelFile::Load(const char *filename) +{ + const FileType filetype = Get_File_Type(filename, FileType::AUTO); + + return Load(filename, filetype); +} + +bool GameModelFile::Load_W3D(const char *filename) +{ + return Load(filename, FileType::W3D); +} + +bool GameModelFile::Load_W3X(const char *filename) +{ + return Load(filename, FileType::W3X); +} + +bool GameModelFile::Load_BLEND(const char *filename) +{ + return Load(filename, FileType::BLEND); +} + +bool GameModelFile::Load_MAX(const char *filename) +{ + return Load(filename, FileType::MAX); +} + +bool GameModelFile::Save(const char *filename) +{ + FileType filetype = Get_File_Type(filename, FileType::AUTO); + + return Save(filename, filetype); +} + +bool GameModelFile::Save_W3D(const char *filename) +{ + return Save(filename, FileType::W3D); +} + +bool GameModelFile::Save_W3X(const char *filename) +{ + return Save(filename, FileType::W3X); +} + +bool GameModelFile::Save_BLEND(const char *filename) +{ + return Save(filename, FileType::BLEND); +} + +bool GameModelFile::Save_MAX(const char *filename) +{ + return Save(filename, FileType::MAX); +} + +const ChunkInfos &GameModelFile::Get_Chunk_Infos() const +{ + // TODO size/vector of chunks + return m_chunkInfosArray[size_t(CHUNK_SIZE)]; +} + +void GameModelFile::Set_Options(Options options) +{ + m_options = options; +} + +GameModelFile::Options GameModelFile::Get_Options() const +{ + return m_options; +} + +void GameModelFile::Set_Log_File(FILE *log) +{ + s_logfile = log; +} + +// Private Methods + +bool GameModelFile::Load(const char *filename, FileType filetype) +{ + captainslog_assert(filetype != FileType::AUTO); + + if (!filename || !filename[0]) { + GAMEMODELLOG_ERROR("File without name cannot be loaded"); + return false; + } + + const int filemode = Encode_Buffered_File_Mode(File::READ | File::BINARY, 1024 * 32); + // TODO: Check if this is the correct way to open a file, there is g_theW3DFileSystem + FileRef file = g_theFileSystem->Open_File(filename, filemode); + + if (!file.Is_Open()) { + GAMEMODELLOG_ERROR("File '%s' cannot be opened for read", filename); + return false; + } + + bool success = false; + + ChunkInfosArray chunk_infos_array; + // TODO size of chunks + ChunkInfos &chunk_infos = chunk_infos_array[size_t(CHUNK_SIZE)]; + + switch (filetype) { + + case FileType::W3D: { + success = Read_W3D_File(file, chunk_infos, m_options); + // TODO size of chunks + // chunk_infos_array[size_t(CHUNK_SIZE)].swap(chunk_infos); + break; + } + case FileType::W3X: { + // TODO: W3X + // success = Read_W3X_File(file, chunk_infos, m_options); + break; + } + } + + if (success) { + GAMEMODELLOG_INFO("File '%s' loaded successfully", filename); + } else { + GAMEMODELLOG_ERROR("File '%s' failed to load", filename); + } + + return success; +} + +bool GameModelFile::Save(const char *filename, FileType filetype) +{ + captainslog_assert(filetype != FileType::AUTO); + + if (!filename || !filename[0]) { + GAMEMODELLOG_ERROR("File without name cannot be saved"); + return false; + } + + // TODO Is_Any_Loaded for chunks + // if (!Is_Any_Loaded()) { + // GAMEMODELLOG_ERROR("File without chunk data cannot be saved"); + // return false; + // } + + const int filemode = Encode_Buffered_File_Mode(File::WRITE | File::CREATE | File::BINARY, 1024 * 32); + FileRef file = g_theFileSystem->Open_File(filename, filemode); + + if (!file.Is_Open()) { + GAMEMODELLOG_ERROR("File '%s' cannot be opened for write", filename); + return false; + } + + bool success = false; + + switch (filetype) { + + case FileType::W3D: { + success = Write_W3D_File(file, Get_Chunk_Infos(), m_options); + break; + } + case FileType::W3X: { + // TODO: W3X + // success = Write_W3X_File(file, Get_Chunk_Infos(), m_options); + break; + } + } + + if (success) { + GAMEMODELLOG_INFO("File '%s' saved successfully", filename); + + } else { + GAMEMODELLOG_ERROR("File '%s' failed to save", filename); + } + + return success; +} + +void GameModelFile::Reset() +{ + for (ChunkInfos &chunk_infos : m_chunkInfosArray) { + // TODO size/vector of chunks + rts::Free_Container(chunk_infos); + } + m_options = Options::Value::NONE; +} + +void GameModelFile::Check_Buffer_Lengths() +{ + // TODO: Implement +} + +ChunkInfos &GameModelFile::Mutable_Chunk_Infos() +{ + // TODO size/vector of chunks + return m_chunkInfosArray[size_t(CHUNK_SIZE)]; +} + +ChunkInfosPtrArray GameModelFile::Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) +{ + // TODO: Implement + return {}; +} + +ConstChunkInfosPtrArray GameModelFile::Build_Const_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) +{ + // TODO: Implement + return {}; +} + +size_t GameModelFile::Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs) +{ + // TODO: Implement + return 0; +} + +FileType GameModelFile::Get_File_Type(const char *filename, FileType filetype) +{ + // TODO: Implement + return FileType::AUTO; +} + +void GameModelFile::Collect_Length_Info(LengthInfo &len_info, const ChunkInfos &chunks) +{ + // TODO: Implement +} + +void GameModelFile::Log_Length_Info(const LengthInfo &len_info) +{ + // TODO: Implement +} + +void GameModelFile::Assert_Length_Info(const LengthInfo &len_info) +{ + // TODO: Implement +} + +ChunkInfos &GameModelFile::Get_Specific_Chunk(ChunkInfo &chunk_info) +{ + // TODO: Implement + return m_chunkInfos; +} + +bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options) +{ + // TODO: Implement + return false; +} + +template +void GameModelFile::Read_W3D_File_T(FileRef &file, ChunkInfosType &chunk_infos, Options options) +{ + // TODO: Implement +} + +ModelParseResult GameModelFile::Parse_W3D_Specific_Step(Utf8Array &buf, ChunkInfo &chunk, Options options) +{ + // TODO: Implement + return ModelParseResult::IS_NOTHING; +} + +bool GameModelFile::Is_W3D_Pre_Specific(Utf8View buf) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Is_W3D_Comment(const char *cchunk) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Is_W3D_End(const char *cchunk) +{ + // TODO: Implement + return false; +} + +void GameModelFile::Change_Step(ModelReadStep &step, ModelReadStep new_step, const char *&eol_chars) +{ + // TODO: Implement +} + +bool GameModelFile::Read_W3D_Header(FileRef &file, ChunkInfos &chunk_infos) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Read_W3D_Entry(FileRef &file, ChunkInfo &chunk_info, Options options, Utf16Array &buf) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Write_W3D_Entry( + FileRef &file, const ChunkInfo &chunk_info, Options options, Utf8Array &buf, ChunkInfo &str) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Write_W3D_Chunk(FileRef &file, const ChunkInfo &chunk) +{ + // TODO: Implement + return false; +} + +bool GameModelFile::Write_W3D_End(FileRef &file) +{ + // TODO: Implement + return false; +} + +void GameModelFile::Log_Line(const char *prefix, const char *format, ...) +{ + // TODO: Implement +} + +} // namespace Thyme + +#undef GAMEMODELLOG_TRACE +#undef GAMEMODELLOG_DEBUG +#undef GAMEMODELLOG_INFO +#undef GAMEMODELLOG_WARN +#undef GAMEMODELLOG_ERROR +#undef GAMEMODELLOG_FATAL diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.h b/src/tools/gamemodelconverter/src/gamemodelfile.h new file mode 100644 index 000000000..85e7a6cd0 --- /dev/null +++ b/src/tools/gamemodelconverter/src/gamemodelfile.h @@ -0,0 +1,197 @@ +/** + * @file gamemodelfile.h + * + * @author DevGeniusCode + * + * @brief Game Model File. (Thyme Feature) + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once + +#include "fileref.h" +#include "gamemodelcommon.h" +#include "utility/array.h" +#include "utility/arrayview.h" +#include "utility/ebitflags.h" +#include "utility/enumerator.h" +#include "utility/enumflags.h" + +namespace Thyme +{ + +enum class GameModelOption : uint32_t +{ + NONE = 0, +}; + +bool Name_To_Game_Model_Option(const char *name, GameModelOption &option); + +} // namespace Thyme + +DEFINE_RTS_UNDERLYING_TYPE(Thyme::GameModelOption, uint32_t); + +namespace Thyme +{ + +// #TODO Return error codes for load and save? + +class GameModelFile +{ +public: + using Options = rts::ebitflags; + +public: + GameModelFile(); + + // Checks whether model is loaded. + bool Is_Loaded() const; + + // Loads models file from disk. Does not unload previous data on failure. + bool Load(const char *filename); + bool Load_W3D(const char *filename); + bool Load_W3X(const char *filename); + bool Load_BLEND(const char *filename); + bool Load_MAX(const char *filename); + + // Saves models file to disk. Will write over any existing file. + bool Save(const char *filename); + bool Save_W3D(const char *filename); + bool Save_W3X(const char *filename); + bool Save_BLEND(const char *filename); + bool Save_MAX(const char *filename); + + // Unloads all data and resets all settings. + void Reset(); + + // Retrieves all Chunk data. + const ChunkInfos &Get_Chunk_Infos() const; + + // Sets options for loading and saving files. + void Set_Options(Options options); + Options Get_Options() const; + + // Optional logging stream. Works besides captains log. + static void Set_Log_File(FILE *log); + +private: + enum class FileType + { + AUTO, + W3D, + W3X, + BLEND, + MAX, + + COUNT, + }; + + enum class ModelReadStep + { + // TODO ModelReadStep + INITIAL, + HEADER, + CHUNK, + COMPLETE, + }; + + enum class ModelParseResult + { + // TODO ModelParseResult + IS_HEADER, + IS_CHUNK, + IS_NOTHING, + IS_END, + }; + + struct LengthInfo + { + // TODO LengthInfo of chunks + size_t totalLength; + size_t chunkCount; + + LengthInfo() : totalLength(0), chunkCount(0) {} + + void AddChunk(size_t length) { + totalLength += length; + chunkCount++; + } + + void Reset() { + totalLength = 0; + chunkCount = 0; + } + }; + + // TODO chunk size + enum : size_t + { + CHUNK_SIZE = 1024 + }; + + using ChunkInfosPtrArray = std::vector>; + using ConstChunkInfosPtrArray = rts::array; + using ChunkInfosArray = rts::array; + using Utf8Array = rts::array; + using Utf16Array = rts::array; + using Utf8View = rts::array_view; + using Utf16View = rts::array_view; + +private: + bool Load(const char *filename, FileType filetype); + bool Save(const char *filename, FileType filetype); + + void Check_Buffer_Lengths(); + + ChunkInfos &Mutable_Chunk_Infos(); + + static ChunkInfosPtrArray Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array); + static ConstChunkInfosPtrArray Build_Const_Chunk_Infos_Ptrs_Array( + ChunkInfosArray &chunk_infos_array); + + static size_t Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs); + + static FileType Get_File_Type(const char *filename, FileType filetype); + + static void Collect_Length_Info(LengthInfo &len_info, const ChunkInfos &chunks); + static void Log_Length_Info(const LengthInfo &len_info); + static void Assert_Length_Info(const LengthInfo &len_info); + + // TODO Get_Specific_Chunk + static ChunkInfos &Get_Specific_Chunk(ChunkInfo &chunk_info); + + static bool Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options); + template + static void Read_W3D_File_T(FileRef &file, ChunkInfosType &chunk_infos, Options options); + // TODO Parse_W3D_Specific_Step + static ModelParseResult Parse_W3D_Specific_Step(Utf8Array &buf, ChunkInfo &chunk, Options options); + static bool Is_W3D_Pre_Specific(Utf8View buf); + static bool Is_W3D_Comment(const char *cchunk); + static bool Is_W3D_End(const char *cchunk); + static void Change_Step(ModelReadStep &step, ModelReadStep new_step, const char *&eol_chars); + + // TODO read specific chunk + static bool Read_W3D_Header(FileRef &file, ChunkInfos &chunk_infos); + static bool Read_W3D_Entry(FileRef &file, ChunkInfo &chunk_info, Options options, Utf16Array &buf); + + static bool Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options); + static bool Write_W3D_Entry( + FileRef &file, const ChunkInfo &chunk_info, Options options, Utf8Array &buf, ChunkInfo &str); + static bool Write_W3D_Chunk(FileRef &file, const ChunkInfo &chunk); + static bool Write_W3D_End(FileRef &file); + + static void Log_Line(const char *prefix, const char *format, ...); + +private: + Options m_options; + ChunkInfosArray m_chunkInfosArray; + ChunkInfos m_chunkInfos; + static FILE *s_logfile; +}; + +} // namespace Thyme diff --git a/src/tools/gamemodelconverter/src/main.cpp b/src/tools/gamemodelconverter/src/main.cpp index e29182e52..ae9c2445c 100644 --- a/src/tools/gamemodelconverter/src/main.cpp +++ b/src/tools/gamemodelconverter/src/main.cpp @@ -132,16 +132,16 @@ WARNING: Commands that save files will overwrite existing files without confirma > Saves the loaded data as a 3ds Max file to the given file path. Example 1: Convert a W3D file to W3X format - > w3d2w3xcompiler.exe -load_w3d D:\models\model.w3d -convert_w3d_to_w3x D:\models\model.w3x + > GameModelConverter.exe -load_w3d D:\models\model.w3d -convert_w3d_to_w3x D:\models\model.w3x Example 2: Convert a W3X file to W3D format - > w3d2w3xcompiler.exe -load_w3x D:\models\model.w3x -convert_w3x_to_w3d D:\models\model.w3d + > GameModelConverter.exe -load_w3x D:\models\model.w3x -convert_w3x_to_w3d D:\models\model.w3d Example 3: Load a Blender file and save as W3D - > w3d2w3xcompiler.exe -load_blend D:\models\model.blend -save_w3d D:\models\model.w3d + > GameModelConverter.exe -load_blend D:\models\model.blend -save_w3d D:\models\model.w3d Example 4: Load a W3D file and save as Max format - > w3d2w3xcompiler.exe -load_w3d D:\models\model.w3d -save_max D:\models\model.max + > GameModelConverter.exe -load_w3d D:\models\model.w3d -save_max D:\models\model.max )#"); } // clang-format on @@ -226,8 +226,7 @@ int main(int argc, const char *argv[]) Print_Help(); return MissingArgumentsError; } - // TODO: W3DFILE - GameModelFILE::Set_Log_File(stderr); + GameModelFile::Set_Log_File(stderr); CaptainsLogCreator captains_log_creator; EngineSystemsCreator engine_systems_creator; diff --git a/src/tools/gamemodelconverter/src/processor.cpp b/src/tools/gamemodelconverter/src/processor.cpp index cdf37d404..9debd4144 100644 --- a/src/tools/gamemodelconverter/src/processor.cpp +++ b/src/tools/gamemodelconverter/src/processor.cpp @@ -359,7 +359,7 @@ Processor::Result Processor::Parse_Command_Argument( case CommandArgumentId::OPTIONS: { GameModelOption option; - if (Name_To_Game_Text_Option(str.c_str(), option)) { + if (Name_To_Game_Model_Option(str.c_str(), option)) { GameModelOptions options; const GameModelOptions *options_ptr = std::get_if(&argument.value); if (options_ptr != nullptr) { From 7c7f533ab1f92f6d1acc23f6f354a47a50feef1a Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Sun, 19 Jan 2025 21:46:03 +0200 Subject: [PATCH 03/13] Add gamemodelfile.cpp and fix filesystem --- .../gamemodelconverter/src/gamemodelcommon.h | 53 ++-- .../gamemodelconverter/src/gamemodelfile.cpp | 289 ++++++++++-------- .../gamemodelconverter/src/gamemodelfile.h | 77 ++--- src/tools/gamemodelconverter/src/main.cpp | 11 +- 4 files changed, 200 insertions(+), 230 deletions(-) diff --git a/src/tools/gamemodelconverter/src/gamemodelcommon.h b/src/tools/gamemodelconverter/src/gamemodelcommon.h index bedb1b580..467b08275 100644 --- a/src/tools/gamemodelconverter/src/gamemodelcommon.h +++ b/src/tools/gamemodelconverter/src/gamemodelcommon.h @@ -18,52 +18,37 @@ #include "bittype.h" #include "unicodestring.h" #include "utility/array.h" +#include "utility/arrayview.h" #include "w3d_file.h" #include #include #include +// TODO size/count of chunks +constexpr size_t g_chunkCount = 77; + namespace Thyme { struct ChunkInfo { - uint32_t id; - size_t size; + uint32_t chunkType; + uint32_t chunkSize; // Note: MSB indicates presence of subchunks. std::vector data; - - //Helper function to read data from the chunk - template - T* GetData() { - if (data.size() < sizeof(T)) return nullptr; //Check for size before cast. - return reinterpret_cast(data.data()); - } - - //Helper function to read a string from the chunk. Assumes null termination - std::string GetString() { - auto cstr = reinterpret_cast(data.data()); - return std::string(cstr); - } + std::vector subChunks; // To handle nested chunks }; -struct ChunkInfos -{ - std::vector chunks; - - //Helper to find a chunk by ID - ChunkInfo* FindChunk(uint32_t id) { - for (auto& chunk : chunks) { - if (chunk.id == id) return &chunk; - } - return nullptr; - } - - const ChunkInfo* FindChunk(uint32_t id) const { - for (const auto& chunk : chunks) { - if (chunk.id == id) return &chunk; - } - return nullptr; - } -}; +using ChunkInfos = std::vector; +using ChunkInfosArray = rts::array; +using ConstChunkInfosPtrArray = rts::array; +using ChunkInfosPtrArray = rts::array; +using Utf8Array = std::vector; +using utf8view = rts::array_view; + +// Helper function to read a string from a ChunkInfo's data +inline std::string readStringFromChunk(const ChunkInfo& chunk) { + if (chunk.data.empty()) return ""; + return std::string((char*)chunk.data.data(), chunk.data.size()); +} } // namespace Thyme \ No newline at end of file diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index 9d59ce6f4..d808f49a8 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -20,7 +20,6 @@ #include "utility/fileutil.h" #include "utility/stlutil.h" #include "utility/stringutil.h" -#include "w3dfilesystem.h" #define GAMEMODELLOG_TRACE(fmt, ...) \ captainslog_trace(fmt, ##__VA_ARGS__); \ @@ -32,7 +31,7 @@ #define GAMEMODELLOG_INFO(fmt, ...) \ captainslog_info(fmt, ##__VA_ARGS__); \ - GameModelFile::Log_Line("", fmt, ##__VA_ARGS__) + GameModelFile::Log_Line("INFO : ", fmt, ##__VA_ARGS__) #define GAMEMODELLOG_WARN(fmt, ...) \ captainslog_warn(fmt, ##__VA_ARGS__); \ @@ -87,7 +86,8 @@ bool Name_To_Game_Model_Option(const char *name, GameModelOption &option) FILE *GameModelFile::s_logfile = nullptr; GameModelFile::GameModelFile() : // Initialize with default options - m_options(GameModelOption::NONE), m_chunkInfosArray() {}; + // TODO chunks array + m_options(GameModelOption::NONE), m_chunkInfos() {}; bool GameModelFile::Is_Loaded() const { @@ -124,7 +124,6 @@ bool GameModelFile::Load_MAX(const char *filename) bool GameModelFile::Save(const char *filename) { FileType filetype = Get_File_Type(filename, FileType::AUTO); - return Save(filename, filetype); } @@ -151,7 +150,7 @@ bool GameModelFile::Save_MAX(const char *filename) const ChunkInfos &GameModelFile::Get_Chunk_Infos() const { // TODO size/vector of chunks - return m_chunkInfosArray[size_t(CHUNK_SIZE)]; + return m_chunkInfos; } void GameModelFile::Set_Options(Options options) @@ -173,6 +172,8 @@ void GameModelFile::Set_Log_File(FILE *log) bool GameModelFile::Load(const char *filename, FileType filetype) { + Reset(); + captainslog_assert(filetype != FileType::AUTO); if (!filename || !filename[0]) { @@ -180,10 +181,10 @@ bool GameModelFile::Load(const char *filename, FileType filetype) return false; } + + // TODO: Check if this is the correct way to open a file, there is g_theW3DFileSystem, but he use game path, not the file path const int filemode = Encode_Buffered_File_Mode(File::READ | File::BINARY, 1024 * 32); - // TODO: Check if this is the correct way to open a file, there is g_theW3DFileSystem FileRef file = g_theFileSystem->Open_File(filename, filemode); - if (!file.Is_Open()) { GAMEMODELLOG_ERROR("File '%s' cannot be opened for read", filename); return false; @@ -191,23 +192,30 @@ bool GameModelFile::Load(const char *filename, FileType filetype) bool success = false; - ChunkInfosArray chunk_infos_array; - // TODO size of chunks - ChunkInfos &chunk_infos = chunk_infos_array[size_t(CHUNK_SIZE)]; + // TODO size/len of chunks + // ChunkInfos chunk_infos; + // ChunkInfos &chunk_infos = chunk_infos_array[size_t(CHUNK_SIZE)]; switch (filetype) { case FileType::W3D: { - success = Read_W3D_File(file, chunk_infos, m_options); + success = Read_W3D_File(file, m_chunkInfos, m_options); // TODO size of chunks - // chunk_infos_array[size_t(CHUNK_SIZE)].swap(chunk_infos); + // chunk_infos_array[size_t(CHUNK_SIZE)].swap(chunk_infos); break; } - case FileType::W3X: { + case FileType::W3X: // TODO: W3X - // success = Read_W3X_File(file, chunk_infos, m_options); + // success = Read_W3X_File(file, chunk_infos, m_options); + case FileType::BLEND: + case FileType::MAX: { + // TODO: Implement loading for other file types + GAMEMODELLOG_WARN("Loading for file type '%s' not yet implemented.", filetype); break; } + default: + GAMEMODELLOG_ERROR("Unknown file type: %d", filetype); + break; } if (success) { @@ -236,7 +244,6 @@ bool GameModelFile::Save(const char *filename, FileType filetype) const int filemode = Encode_Buffered_File_Mode(File::WRITE | File::CREATE | File::BINARY, 1024 * 32); FileRef file = g_theFileSystem->Open_File(filename, filemode); - if (!file.Is_Open()) { GAMEMODELLOG_ERROR("File '%s' cannot be opened for write", filename); return false; @@ -250,16 +257,25 @@ bool GameModelFile::Save(const char *filename, FileType filetype) success = Write_W3D_File(file, Get_Chunk_Infos(), m_options); break; } - case FileType::W3X: { + case FileType::W3X: + case FileType::BLEND: + case FileType::MAX: { + // const int filemode = Encode_Buffered_File_Mode(File::WRITE | File::CREATE | File::BINARY, 1024 * 32); + // FileRef file = g_theFileSystem->Open_File(filename, filemode); // TODO: W3X - // success = Write_W3X_File(file, Get_Chunk_Infos(), m_options); + // success = Write_W3X_File(file, Get_Chunk_Infos(), m_options); + GAMEMODELLOG_WARN("Saving for file type '%s' not yet implemented.", filetype); + success = false; break; } + default: + GAMEMODELLOG_ERROR("Unknown file type: %d", filetype); + success = false; + break; } if (success) { GAMEMODELLOG_INFO("File '%s' saved successfully", filename); - } else { GAMEMODELLOG_ERROR("File '%s' failed to save", filename); } @@ -268,151 +284,164 @@ bool GameModelFile::Save(const char *filename, FileType filetype) } void GameModelFile::Reset() -{ - for (ChunkInfos &chunk_infos : m_chunkInfosArray) { - // TODO size/vector of chunks - rts::Free_Container(chunk_infos); - } - m_options = Options::Value::NONE; -} - -void GameModelFile::Check_Buffer_Lengths() -{ - // TODO: Implement -} - -ChunkInfos &GameModelFile::Mutable_Chunk_Infos() { // TODO size/vector of chunks - return m_chunkInfosArray[size_t(CHUNK_SIZE)]; -} - -ChunkInfosPtrArray GameModelFile::Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) -{ - // TODO: Implement - return {}; -} - -ConstChunkInfosPtrArray GameModelFile::Build_Const_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) -{ - // TODO: Implement - return {}; -} - -size_t GameModelFile::Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs) -{ - // TODO: Implement - return 0; -} - -FileType GameModelFile::Get_File_Type(const char *filename, FileType filetype) -{ - // TODO: Implement - return FileType::AUTO; -} - -void GameModelFile::Collect_Length_Info(LengthInfo &len_info, const ChunkInfos &chunks) -{ - // TODO: Implement -} - -void GameModelFile::Log_Length_Info(const LengthInfo &len_info) -{ - // TODO: Implement + // for (ChunkInfos &chunk_infos : m_chunkInfosArray) { + // rts::Free_Container(chunk_infos); + // } + m_chunkInfos.clear(); + m_options = Options::Value::NONE; } -void GameModelFile::Assert_Length_Info(const LengthInfo &len_info) -{ - // TODO: Implement +// void GameModelFile::Check_Buffer_Lengths() +//{ +// // TODO: Implement +// } +// +// ChunkInfos &GameModelFile::Mutable_Chunk_Infos() +//{ +// // TODO size/vector of chunks +// return m_chunkInfosArray[size_t(CHUNK_SIZE)]; +// } +// +// ChunkInfosPtrArray GameModelFile::Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) +//{ +// // TODO: Implement +// return {}; +// } +// +// ConstChunkInfosPtrArray GameModelFile::Build_Const_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) +//{ +// // TODO: Implement +// return {}; +// } +// +// size_t GameModelFile::Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs) +//{ +// // TODO size/vector of chunks +// return 0; +// } + +GameModelFile::FileType GameModelFile::Get_File_Type(const char *filename, FileType filetype) +{ + // TODO Implement file type detection logic here based on filename extension. + if (filetype == FileType::AUTO) { + std::string fn(filename); + if (fn.find(".w3d") != std::string::npos) + return FileType::W3D; + // Add checks for .w3x, .blend, .max here + } + return filetype; } -ChunkInfos &GameModelFile::Get_Specific_Chunk(ChunkInfo &chunk_info) +Utf8Array &GameModelFile::Get_Chunk_Data(ChunkInfo &chunk_info) { - // TODO: Implement - return m_chunkInfos; + return chunk_info.data; } bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options) { - // TODO: Implement - return false; -} + GAMEMODELLOG_INFO("Reading model file '%s' in W3D format", file.Get_File_Name().Str()); -template -void GameModelFile::Read_W3D_File_T(FileRef &file, ChunkInfosType &chunk_infos, Options options) -{ - // TODO: Implement -} + bool success = true; + if (!file.Is_Open()) { + GAMEMODELLOG_ERROR("Could not open file: %s\n", file.Get_File_Name().Str()); + return false; + } + // TODO Utf8Array buf = {}; -ModelParseResult GameModelFile::Parse_W3D_Specific_Step(Utf8Array &buf, ChunkInfo &chunk, Options options) -{ - // TODO: Implement - return ModelParseResult::IS_NOTHING; + if (!Read_W3D_Chunks(file, chunk_infos)) { + GAMEMODELLOG_ERROR("Failed to read W3D chunks from: %s\n", file.Get_File_Name().Str()); + return false; + } + return true; } -bool GameModelFile::Is_W3D_Pre_Specific(Utf8View buf) +bool GameModelFile::Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options) { - // TODO: Implement - return false; -} + GAMEMODELLOG_INFO("Writing model file '%s' in W3D format", file.Get_File_Name().Str()); -bool GameModelFile::Is_W3D_Comment(const char *cchunk) -{ - // TODO: Implement - return false; -} + bool success = true; + if (!file.Is_Open()) { // Use FM_WRITE for saving + GAMEMODELLOG_ERROR("File '%s' cannot be opened for write", file.Get_File_Name().Str()); + success = false; + } + if (!Write_W3D_Chunks(file, chunk_infos)) { + GAMEMODELLOG_ERROR("Failed to write W3D chunks to: %s\n", file.Get_File_Name().Str()); + success = false; + } -bool GameModelFile::Is_W3D_End(const char *cchunk) -{ - // TODO: Implement - return false; + return success; } -void GameModelFile::Change_Step(ModelReadStep &step, ModelReadStep new_step, const char *&eol_chars) +bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) { - // TODO: Implement -} + // Implementation largely the same as before, but using FileRef instead of FileRef + // and adding error checking with W3D error codes. + while (true) { + ChunkInfo chunk; + uint32_t chunkType; + uint32_t chunkSize; -bool GameModelFile::Read_W3D_Header(FileRef &file, ChunkInfos &chunk_infos) -{ - // TODO: Implement - return false; -} + if (file.Read(&chunkType, sizeof(uint32_t)) != sizeof(uint32_t)) + break; + if (file.Read(&chunkSize, sizeof(uint32_t)) != sizeof(uint32_t)) + break; -bool GameModelFile::Read_W3D_Entry(FileRef &file, ChunkInfo &chunk_info, Options options, Utf16Array &buf) -{ - // TODO: Implement - return false; -} + chunk.chunkType = chunkType; + chunk.chunkSize = chunkSize; + size_t dataSize = chunkSize & 0x7FFFFFFF; // Mask out MSB -bool GameModelFile::Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options) -{ - // TODO: Implement - return false; -} + chunk.data.resize(dataSize); + // TODO rts::Read_Any(file.Get_File(), parentChunks); + if (file.Read(chunk.data.data(), dataSize) != dataSize) { + GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data.\n", file.Get_File_Name().Str()); + return false; // TODO return a specific W3D error code + } -bool GameModelFile::Write_W3D_Entry( - FileRef &file, const ChunkInfo &chunk_info, Options options, Utf8Array &buf, ChunkInfo &str) -{ - // TODO: Implement - return false; + if (chunkSize & 0x80000000) { + if (!Read_W3D_Chunks(file, chunk.subChunks)) + return false; + } + parentChunks.push_back(chunk); + } + return true; } -bool GameModelFile::Write_W3D_Chunk(FileRef &file, const ChunkInfo &chunk) +bool GameModelFile::Write_W3D_Chunks(FileRef &file, const ChunkInfos &parentChunks) { - // TODO: Implement - return false; -} + for (const auto &chunk : parentChunks) { + uint32_t chunkSize = (uint32_t)chunk.data.size(); + if (!chunk.subChunks.empty()) + chunkSize |= 0x80000000; -bool GameModelFile::Write_W3D_End(FileRef &file) -{ - // TODO: Implement - return false; + if (file.Write(&chunk.chunkType, sizeof(chunk.chunkType)) != sizeof(chunk.chunkType) + || file.Write(&chunkSize, sizeof(chunkSize)) != sizeof(chunkSize) + || file.Write(chunk.data.data(), chunk.data.size()) != chunk.data.size()) { + GAMEMODELLOG_ERROR("File '%s': Failed to wrtie chunk data.\n", file.Get_File_Name().Str()); + return false; + } + if (!chunk.subChunks.empty()) { + if (!Write_W3D_Chunks(file, chunk.subChunks)) + return false; + } + } + return true; } void GameModelFile::Log_Line(const char *prefix, const char *format, ...) { - // TODO: Implement + FILE *file = s_logfile; + + if (file != nullptr) { + va_list args; + va_start(args, format); + fputs(prefix, file); + vfprintf(file, format, args); + fputs("\n", file); + va_end(args); + fflush(file); + } } } // namespace Thyme diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.h b/src/tools/gamemodelconverter/src/gamemodelfile.h index 85e7a6cd0..cdff50d79 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.h +++ b/src/tools/gamemodelconverter/src/gamemodelfile.h @@ -112,84 +112,49 @@ class GameModelFile struct LengthInfo { // TODO LengthInfo of chunks - size_t totalLength; - size_t chunkCount; - - LengthInfo() : totalLength(0), chunkCount(0) {} - - void AddChunk(size_t length) { - totalLength += length; - chunkCount++; - } - - void Reset() { - totalLength = 0; - chunkCount = 0; - } - }; - - // TODO chunk size - enum : size_t - { - CHUNK_SIZE = 1024 + int max_chunk_len; }; - using ChunkInfosPtrArray = std::vector>; - using ConstChunkInfosPtrArray = rts::array; - using ChunkInfosArray = rts::array; - using Utf8Array = rts::array; - using Utf16Array = rts::array; - using Utf8View = rts::array_view; - using Utf16View = rts::array_view; private: bool Load(const char *filename, FileType filetype); bool Save(const char *filename, FileType filetype); - void Check_Buffer_Lengths(); - - ChunkInfos &Mutable_Chunk_Infos(); - - static ChunkInfosPtrArray Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array); - static ConstChunkInfosPtrArray Build_Const_Chunk_Infos_Ptrs_Array( - ChunkInfosArray &chunk_infos_array); +// void Check_Buffer_Lengths(); +// +// ChunkInfos &Mutable_Chunk_Infos(); +// +// static ChunkInfosPtrArray Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array); +// static ConstChunkInfosPtrArray Build_Const_Chunk_Infos_Ptrs_Array( +// ChunkInfosArray &chunk_infos_array); static size_t Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs); static FileType Get_File_Type(const char *filename, FileType filetype); - static void Collect_Length_Info(LengthInfo &len_info, const ChunkInfos &chunks); - static void Log_Length_Info(const LengthInfo &len_info); - static void Assert_Length_Info(const LengthInfo &len_info); +// static void Collect_Length_Info(LengthInfo &len_info, const ChunkInfos &chunks); +// static void Log_Length_Info(const LengthInfo &len_info); +// static void Assert_Length_Info(const LengthInfo &len_info); - // TODO Get_Specific_Chunk - static ChunkInfos &Get_Specific_Chunk(ChunkInfo &chunk_info); + // TODO need a significant rewrite based on the chunk structure + static Utf8Array &Get_Chunk_Data(ChunkInfo &chunk_info); static bool Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options); - template - static void Read_W3D_File_T(FileRef &file, ChunkInfosType &chunk_infos, Options options); - // TODO Parse_W3D_Specific_Step - static ModelParseResult Parse_W3D_Specific_Step(Utf8Array &buf, ChunkInfo &chunk, Options options); - static bool Is_W3D_Pre_Specific(Utf8View buf); - static bool Is_W3D_Comment(const char *cchunk); - static bool Is_W3D_End(const char *cchunk); - static void Change_Step(ModelReadStep &step, ModelReadStep new_step, const char *&eol_chars); - - // TODO read specific chunk - static bool Read_W3D_Header(FileRef &file, ChunkInfos &chunk_infos); - static bool Read_W3D_Entry(FileRef &file, ChunkInfo &chunk_info, Options options, Utf16Array &buf); + + // TODO need substantial changes based on the chunk structure + // Recursive function to read/write chunks and subchunks + static bool Read_W3D_Chunks(FileRef &file, ChunkInfos& parentChunks); + static bool Write_W3D_Chunks(FileRef &file, const ChunkInfos& parentChunks); + + //Helper function to write a single chunk to the file + static bool Write_W3D_Chunk(FileRef &file, const ChunkInfo& chunk); static bool Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options); - static bool Write_W3D_Entry( - FileRef &file, const ChunkInfo &chunk_info, Options options, Utf8Array &buf, ChunkInfo &str); - static bool Write_W3D_Chunk(FileRef &file, const ChunkInfo &chunk); - static bool Write_W3D_End(FileRef &file); static void Log_Line(const char *prefix, const char *format, ...); private: Options m_options; - ChunkInfosArray m_chunkInfosArray; ChunkInfos m_chunkInfos; static FILE *s_logfile; }; diff --git a/src/tools/gamemodelconverter/src/main.cpp b/src/tools/gamemodelconverter/src/main.cpp index ae9c2445c..3eb8b7fb3 100644 --- a/src/tools/gamemodelconverter/src/main.cpp +++ b/src/tools/gamemodelconverter/src/main.cpp @@ -174,11 +174,6 @@ LocalFileSystem *Create_Local_File_System() return new Win32LocalFileSystem; } -ArchiveFileSystem *Create_Archive_File_System() -{ - return new Win32BIGFileSystem; -} - struct CaptainsLogCreator { CaptainsLogCreator() @@ -200,10 +195,6 @@ struct EngineSystemsCreator g_theFileSystem = new FileSystem; Init_Subsystem(g_theLocalFileSystem, "TheLocalFileSystem", Create_Local_File_System()); g_theLocalFileSystem->Init(); -#if 0 - Init_Subsystem(g_theArchiveFileSystem, "TheArchiveFileSystem", Create_Archive_File_System()); - g_theArchiveFileSystem->Init(); -#endif } ~EngineSystemsCreator() { @@ -220,7 +211,7 @@ struct EngineSystemsCreator int main(int argc, const char *argv[]) { - Print_Line("W3D W3X Compiler v1.0 By The Assembly Armada"); + Print_Line("Game Model Converter v1.0 By The Assembly Armada"); if (argc < 2) { Print_Help(); From 9cd6504f46056eeb9096ba4e90ee84a9b38c5807 Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Sun, 19 Jan 2025 22:01:54 +0200 Subject: [PATCH 04/13] basic clean code --- src/tools/gamemodelconverter/src/gamemodelfile.cpp | 14 ++++++++------ src/tools/gamemodelconverter/src/gamemodelfile.h | 1 + src/tools/gamemodelconverter/src/processor.h | 2 -- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index d808f49a8..82c9c7f0f 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -86,7 +86,7 @@ bool Name_To_Game_Model_Option(const char *name, GameModelOption &option) FILE *GameModelFile::s_logfile = nullptr; GameModelFile::GameModelFile() : // Initialize with default options - // TODO chunks array + // TODO chunks array/buffer m_options(GameModelOption::NONE), m_chunkInfos() {}; bool GameModelFile::Is_Loaded() const @@ -209,7 +209,6 @@ bool GameModelFile::Load(const char *filename, FileType filetype) // success = Read_W3X_File(file, chunk_infos, m_options); case FileType::BLEND: case FileType::MAX: { - // TODO: Implement loading for other file types GAMEMODELLOG_WARN("Loading for file type '%s' not yet implemented.", filetype); break; } @@ -260,8 +259,6 @@ bool GameModelFile::Save(const char *filename, FileType filetype) case FileType::W3X: case FileType::BLEND: case FileType::MAX: { - // const int filemode = Encode_Buffered_File_Mode(File::WRITE | File::CREATE | File::BINARY, 1024 * 32); - // FileRef file = g_theFileSystem->Open_File(filename, filemode); // TODO: W3X // success = Write_W3X_File(file, Get_Chunk_Infos(), m_options); GAMEMODELLOG_WARN("Saving for file type '%s' not yet implemented.", filetype); @@ -324,12 +321,17 @@ void GameModelFile::Reset() GameModelFile::FileType GameModelFile::Get_File_Type(const char *filename, FileType filetype) { - // TODO Implement file type detection logic here based on filename extension. if (filetype == FileType::AUTO) { std::string fn(filename); if (fn.find(".w3d") != std::string::npos) return FileType::W3D; // Add checks for .w3x, .blend, .max here + if (fn.find(".w3x") != std::string::npos) + return FileType::W3X; + if (fn.find(".blend") != std::string::npos) + return FileType::BLEND; + if (fn.find(".max") != std::string::npos) + return FileType::MAX; } return filetype; } @@ -396,7 +398,7 @@ bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) // TODO rts::Read_Any(file.Get_File(), parentChunks); if (file.Read(chunk.data.data(), dataSize) != dataSize) { GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data.\n", file.Get_File_Name().Str()); - return false; // TODO return a specific W3D error code + return false; // TODO return a specific W3D error code ? } if (chunkSize & 0x80000000) { diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.h b/src/tools/gamemodelconverter/src/gamemodelfile.h index cdff50d79..77586691a 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.h +++ b/src/tools/gamemodelconverter/src/gamemodelfile.h @@ -156,6 +156,7 @@ class GameModelFile private: Options m_options; ChunkInfos m_chunkInfos; + // TODO chunks array/buffer static FILE *s_logfile; }; diff --git a/src/tools/gamemodelconverter/src/processor.h b/src/tools/gamemodelconverter/src/processor.h index 60722a30d..2ab4f62f0 100644 --- a/src/tools/gamemodelconverter/src/processor.h +++ b/src/tools/gamemodelconverter/src/processor.h @@ -75,7 +75,6 @@ class Processor { std::size_t operator()(const FileId &key) const { return std::hash{}(key.value); } }; - // TODO GameModelFilePtr change using FileMap = std::unordered_map; struct FilePath @@ -85,7 +84,6 @@ class Processor struct CommandArgument { - // TODO GameModelOptions change std::variant value; }; From 0bad6520523a0230c0ad3c8c08e85769f1d2875d Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:21:02 +0200 Subject: [PATCH 05/13] basic R/W chunks --- .../gamemodelconverter/src/gamemodelcommon.h | 94 ++++++++++-- .../gamemodelconverter/src/gamemodelfile.cpp | 139 +++++++++++++++--- .../gamemodelconverter/src/gamemodelfile.h | 19 ++- 3 files changed, 219 insertions(+), 33 deletions(-) diff --git a/src/tools/gamemodelconverter/src/gamemodelcommon.h b/src/tools/gamemodelconverter/src/gamemodelcommon.h index 467b08275..350b6513a 100644 --- a/src/tools/gamemodelconverter/src/gamemodelcommon.h +++ b/src/tools/gamemodelconverter/src/gamemodelcommon.h @@ -30,14 +30,39 @@ constexpr size_t g_chunkCount = 77; namespace Thyme { -struct ChunkInfo -{ - uint32_t chunkType; - uint32_t chunkSize; // Note: MSB indicates presence of subchunks. - std::vector data; - std::vector subChunks; // To handle nested chunks +/* +// Type aliases to avoid duplication +using W3dVector = W3dVectorStruct; +using W3dQuaternion = W3dQuaternionStruct; +using W3dRGB = W3dRGBStruct; +using W3dRGBA = W3dRGBAStruct; +using W3dMaterial3 = W3dMaterial3Struct; +using W3dVertexMaterial = W3dVertexMaterialStruct; +using W3dTri = W3dTriStruct; +using W3dVertInf = W3dVertInfStruct; +using W3dTexCoord = W3dTexCoordStruct; +using W3dMaterialInfo = W3dMaterialInfoStruct; +using W3dShader = W3dShaderStruct; +using W3dTextureInfo = W3dTextureInfoStruct; +using W3dMeshHeader3 = W3dMeshHeader3Struct; +using W3dMeshAABTreeHeader = W3dMeshAABTreeHeader; +using W3dMeshAABTreeNode = W3dMeshAABTreeNode; +using W3dEmitterHeader = W3dEmitterHeaderStruct; +using W3dEmitterInfo = W3dEmitterInfoStruct; +using W3dEmitterInfoV2 = W3dEmitterInfoStructV2; +using W3dEmitterProperty = W3dEmitterPropertyStruct; +// ...add other type aliases as needed... + + */ + +struct ChunkInfo { + uint32_t chunkType; // Chunk ID (from w3d_file.h) + uint32_t chunkSize; // Size of chunk data (including subchunk flag) Note: MSB indicates presence of subchunks. + std::vector data; // Raw chunk data + std::vector subChunks; // Vector to store sub-chunks }; + using ChunkInfos = std::vector; using ChunkInfosArray = rts::array; using ConstChunkInfosPtrArray = rts::array; @@ -45,10 +70,57 @@ using ChunkInfosPtrArray = rts::array; using Utf8Array = std::vector; using utf8view = rts::array_view; -// Helper function to read a string from a ChunkInfo's data -inline std::string readStringFromChunk(const ChunkInfo& chunk) { - if (chunk.data.empty()) return ""; - return std::string((char*)chunk.data.data(), chunk.data.size()); +struct ParsedMeshData { + std::vector vertices; + std::vector normals; + std::vector triangles; + // ... other mesh data ... + W3dMeshHeader3Struct header; +}; + +struct ParsedEmitterData { + W3dEmitterHeaderStruct header; + W3dEmitterInfoStruct info; + W3dEmitterInfoStructV2 infoV2; + std::vector properties; +}; + +//Helper functions for reading data from chunk +template +T ReadFromChunk(const Thyme::ChunkInfo& chunk, size_t offset) { + if (offset + sizeof(T) > chunk.data.size()) { +// std::cerr << "Error: Trying to read past the end of the chunk data!" << std::endl; + T temp{}; + return temp; + } + return *reinterpret_cast(&chunk.data[offset]); +} + +template +std::vector ReadArrayFromChunk(const Thyme::ChunkInfo& chunk) { + size_t numElements = chunk.data.size() / sizeof(T); + std::vector array(numElements); + if (chunk.data.size() % sizeof(T) != 0) { +// std::cerr << "Error: Chunk data size is not a multiple of element size!" << std::endl; + return {}; //Return empty vector in case of error + } + memcpy(array.data(), chunk.data.data(), chunk.data.size()); + return array; } -} // namespace Thyme \ No newline at end of file +std::string ReadStringFromChunk(const Thyme::ChunkInfo& chunk); //Defined below + + +} // namespace Thyme + +inline std::string Thyme::ReadStringFromChunk(const Thyme::ChunkInfo& chunk) { + if (chunk.data.empty()) return ""; + size_t nullTerminatorPos = chunk.data.size(); + for (size_t i = 0; i < chunk.data.size(); i++) { + if (chunk.data[i] == 0) { + nullTerminatorPos = i; + break; + } + } + return std::string((char*)chunk.data.data(), nullTerminatorPos); +} \ No newline at end of file diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index 82c9c7f0f..5f5acd368 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -20,6 +20,9 @@ #include "utility/fileutil.h" #include "utility/stlutil.h" #include "utility/stringutil.h" +#include "gamemodelcommon.h" +#include "w3d_file.h" + #define GAMEMODELLOG_TRACE(fmt, ...) \ captainslog_trace(fmt, ##__VA_ARGS__); \ @@ -345,7 +348,6 @@ bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Option { GAMEMODELLOG_INFO("Reading model file '%s' in W3D format", file.Get_File_Name().Str()); - bool success = true; if (!file.Is_Open()) { GAMEMODELLOG_ERROR("Could not open file: %s\n", file.Get_File_Name().Str()); return false; @@ -356,6 +358,9 @@ bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Option GAMEMODELLOG_ERROR("Failed to read W3D chunks from: %s\n", file.Get_File_Name().Str()); return false; } + + //Parse the loaded chunks here (example for mesh data) + Parse_W3D_Data(chunk_infos); return true; } @@ -378,34 +383,60 @@ bool GameModelFile::Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) { - // Implementation largely the same as before, but using FileRef instead of FileRef - // and adding error checking with W3D error codes. while (true) { - ChunkInfo chunk; uint32_t chunkType; - uint32_t chunkSize; + uint32_t chunkSizeRaw; - if (file.Read(&chunkType, sizeof(uint32_t)) != sizeof(uint32_t)) - break; - if (file.Read(&chunkSize, sizeof(uint32_t)) != sizeof(uint32_t)) - break; + if (file.Read(&chunkType, sizeof(chunkType)) != sizeof(chunkType)) break; + if (file.Read(&chunkSizeRaw, sizeof(chunkSizeRaw)) != sizeof(chunkSizeRaw)) break; + ChunkInfo chunk; chunk.chunkType = chunkType; - chunk.chunkSize = chunkSize; - size_t dataSize = chunkSize & 0x7FFFFFFF; // Mask out MSB + chunk.chunkSize = chunkSizeRaw; + size_t dataSize = chunkSizeRaw & 0x7FFFFFFF; // Mask out MSB for subChunk flag chunk.data.resize(dataSize); // TODO rts::Read_Any(file.Get_File(), parentChunks); if (file.Read(chunk.data.data(), dataSize) != dataSize) { GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data.\n", file.Get_File_Name().Str()); + // TODO GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunkType); return false; // TODO return a specific W3D error code ? } - if (chunkSize & 0x80000000) { - if (!Read_W3D_Chunks(file, chunk.subChunks)) + // Recursive call for subchunks + // Check for subchunks AFTER reading the main chunk data + bool hasSubchunks = (chunkSizeRaw >> 31) & 1; //Check MSB for subchunks (chunkSizeRaw & 0x80000000) + if (hasSubchunks) { + if (!Read_W3D_Chunks(file, chunk.subChunks)) { + GAMEMODELLOG_ERROR("File '%s': Failed to read subchunks of chunk type 0x%X\n", file.Get_File_Name().Str(), chunkType); return false; + } } parentChunks.push_back(chunk); + + + // Example of handling specific chunk types (Expand this significantly) + switch (chunkType) { + case W3D_CHUNK_MESH: + // Parse W3dMeshStruct from chunk.data + GAMEMODELLOG_DEBUG("Found W3D_CHUNK_MESH"); + break; + case W3D_CHUNK_MESH_HEADER3: + // Parse W3dMeshHeader3Struct from chunk.data + GAMEMODELLOG_DEBUG("Found W3D_CHUNK_MESH_HEADER3"); + break; + case W3D_CHUNK_VERTICES: + //Parse W3dVectorStruct array from chunk.data + GAMEMODELLOG_DEBUG("Found W3D_CHUNK_VERTICES"); + break; + case W3D_CHUNK_TRIANGLES: + GAMEMODELLOG_DEBUG("Found W3D_CHUNK_TRIANGLES"); + break; + // Add cases for other chunk types as needed... + default: + GAMEMODELLOG_DEBUG("Unknown chunk type: 0x%X", chunkType); + break; + } } return true; } @@ -417,10 +448,11 @@ bool GameModelFile::Write_W3D_Chunks(FileRef &file, const ChunkInfos &parentChun if (!chunk.subChunks.empty()) chunkSize |= 0x80000000; - if (file.Write(&chunk.chunkType, sizeof(chunk.chunkType)) != sizeof(chunk.chunkType) - || file.Write(&chunkSize, sizeof(chunkSize)) != sizeof(chunkSize) - || file.Write(chunk.data.data(), chunk.data.size()) != chunk.data.size()) { - GAMEMODELLOG_ERROR("File '%s': Failed to wrtie chunk data.\n", file.Get_File_Name().Str()); + if (file.Write(&chunk.chunkType, sizeof(chunk.chunkType)) != sizeof(chunk.chunkType) || + file.Write(&chunkSize, sizeof(chunkSize)) != sizeof(chunkSize) || + file.Write(chunk.data.data(), chunk.data.size()) != chunk.data.size()) { + GAMEMODELLOG_ERROR("File '%s': Failed to write chunk data.\n", file.Get_File_Name().Str()); + // TODO GAMEMODELLOG_ERROR("File '%s': Failed to write chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunk.chunkType); return false; } if (!chunk.subChunks.empty()) { @@ -431,6 +463,79 @@ bool GameModelFile::Write_W3D_Chunks(FileRef &file, const ChunkInfos &parentChun return true; } +void GameModelFile::Parse_W3D_Data(const ChunkInfos& chunks) { + for (const auto& chunk : chunks) { + switch (chunk.chunkType) { + case W3D_CHUNK_MESH: + Parse_Mesh_Chunk(chunk); + break; + case W3D_CHUNK_EMITTER: + Parse_Emitter_Chunk(chunk); + break; + // Add cases for other top-level chunk types... + default: + GAMEMODELLOG_DEBUG("Ignoring unknown top-level chunk type: 0x%X", chunk.chunkType); + break; + } + } +} + +void GameModelFile::Parse_Mesh_Chunk(const ChunkInfo& meshChunk) { + // Example: Parse Mesh Header + for (const auto& subChunk : meshChunk.subChunks) { + if (subChunk.chunkType == W3D_CHUNK_MESH_HEADER3) { + //Use the helper functions from gamemodelcommon.h + m_meshData.header = ReadFromChunk(subChunk, 0); + break; + } + } + // Parse other mesh subchunks (vertices, normals, triangles, etc.) using similar logic, + // referencing the struct definitions in w3d_file.h and using the helper functions from gamemodelcommon.h + + for (const auto& subChunk : meshChunk.subChunks) { + switch (subChunk.chunkType) { + case W3D_CHUNK_VERTICES: + m_meshData.vertices = Thyme::ReadArrayFromChunk(subChunk); + break; + case W3D_CHUNK_VERTEX_NORMALS: + m_meshData.normals = Thyme::ReadArrayFromChunk(subChunk); + break; + case W3D_CHUNK_TRIANGLES: + m_meshData.triangles = Thyme::ReadArrayFromChunk(subChunk); + break; + case W3D_CHUNK_MESH_HEADER3: +// m_meshData.header = Thyme::ReadFromChunk(subChunk,0); + break; + // ... parse other mesh subchunks ... + default: + break; + } + } +} + +void GameModelFile::Parse_Emitter_Chunk(const ChunkInfo& emitterChunk) { + //Similar logic as ParseMeshChunk, but for emitter chunks and subchunks + for (const auto& subChunk : emitterChunk.subChunks) { + if (subChunk.chunkType == W3D_CHUNK_EMITTER_HEADER) { + m_emitterData.header = ReadFromChunk(subChunk, 0); + } else if (subChunk.chunkType == W3D_CHUNK_EMITTER_INFO) { + m_emitterData.info = ReadFromChunk(subChunk, 0); + } else if (subChunk.chunkType == W3D_CHUNK_EMITTER_INFOV2){ + m_emitterData.infoV2 = ReadFromChunk(subChunk, 0); + } + // ... parse other emitter subchunks ... + } +} + +const ParsedMeshData& GameModelFile::GetMeshData() const { + return m_meshData; +} + +const ParsedEmitterData& GameModelFile::GetEmitterData() const { + return m_emitterData; +} + + void GameModelFile::Log_Line(const char *prefix, const char *format, ...) { FILE *file = s_logfile; diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.h b/src/tools/gamemodelconverter/src/gamemodelfile.h index 77586691a..fff9d27ea 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.h +++ b/src/tools/gamemodelconverter/src/gamemodelfile.h @@ -139,17 +139,23 @@ class GameModelFile // TODO need a significant rewrite based on the chunk structure static Utf8Array &Get_Chunk_Data(ChunkInfo &chunk_info); - static bool Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options); + bool Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options); // TODO need substantial changes based on the chunk structure // Recursive function to read/write chunks and subchunks - static bool Read_W3D_Chunks(FileRef &file, ChunkInfos& parentChunks); - static bool Write_W3D_Chunks(FileRef &file, const ChunkInfos& parentChunks); + bool Read_W3D_Chunks(FileRef &file, ChunkInfos& parentChunks); + bool Write_W3D_Chunks(FileRef &file, const ChunkInfos& parentChunks); //Helper function to write a single chunk to the file - static bool Write_W3D_Chunk(FileRef &file, const ChunkInfo& chunk); + bool Write_W3D_Chunk(FileRef &file, const ChunkInfo& chunk); - static bool Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options); + bool Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options); + + void Parse_W3D_Data(const ChunkInfos& chunks); + void Parse_Mesh_Chunk(const ChunkInfo& meshChunk); + void Parse_Emitter_Chunk(const ChunkInfo& emitterChunk); + const ParsedMeshData &GetMeshData() const; + const ParsedEmitterData &GetEmitterData() const; static void Log_Line(const char *prefix, const char *format, ...); @@ -158,6 +164,9 @@ class GameModelFile ChunkInfos m_chunkInfos; // TODO chunks array/buffer static FILE *s_logfile; + ParsedMeshData m_meshData; + ParsedEmitterData m_emitterData; + }; } // namespace Thyme From 9f09f51f8d95333013c4560bb26ca7878dd28aea Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Tue, 21 Jan 2025 02:46:35 +0200 Subject: [PATCH 06/13] Handle subChunks --- .../gamemodelconverter/src/gamemodelfile.cpp | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index 5f5acd368..44cfd27cd 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -387,33 +387,47 @@ bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) uint32_t chunkType; uint32_t chunkSizeRaw; + // Read chunk type and size if (file.Read(&chunkType, sizeof(chunkType)) != sizeof(chunkType)) break; if (file.Read(&chunkSizeRaw, sizeof(chunkSizeRaw)) != sizeof(chunkSizeRaw)) break; ChunkInfo chunk; chunk.chunkType = chunkType; chunk.chunkSize = chunkSizeRaw; + size_t dataSize = chunkSizeRaw & 0x7FFFFFFF; // Mask out MSB for subChunk flag + bool hasSubchunks = (chunkSizeRaw >> 31) & 1; // Check MSB for subchunks (chunkSizeRaw & 0x80000000) - chunk.data.resize(dataSize); - // TODO rts::Read_Any(file.Get_File(), parentChunks); - if (file.Read(chunk.data.data(), dataSize) != dataSize) { - GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data.\n", file.Get_File_Name().Str()); - // TODO GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunkType); - return false; // TODO return a specific W3D error code ? - } + int currentPosition = file.Position(); // Save current file position - // Recursive call for subchunks - // Check for subchunks AFTER reading the main chunk data - bool hasSubchunks = (chunkSizeRaw >> 31) & 1; //Check MSB for subchunks (chunkSizeRaw & 0x80000000) if (hasSubchunks) { - if (!Read_W3D_Chunks(file, chunk.subChunks)) { - GAMEMODELLOG_ERROR("File '%s': Failed to read subchunks of chunk type 0x%X\n", file.Get_File_Name().Str(), chunkType); + // Read subchunks recursively + while (file.Position() < currentPosition + dataSize) { + if (!Read_W3D_Chunks(file, chunk.subChunks)) { + GAMEMODELLOG_ERROR("Failed to read subchunks for chunk type 0x%X\n", chunkType); + return false; + } + } + } else { + // Read the current chunk data + chunk.data.resize(dataSize); + if (file.Read(chunk.data.data(), dataSize) != dataSize) { + GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunkType); return false; } } + + // Move the file pointer if necessary to ensure alignment + int endPosition = currentPosition + chunkSizeRaw; + int offset = endPosition - file.Position(); + if (file.Position() < endPosition) { + file.Seek(offset, File::SeekMode::CURRENT); + } + + // Add chunk to the parent chunk list parentChunks.push_back(chunk); + GAMEMODELLOG_DEBUG("Read chunk: type=0x%X, size=%zu, subchunks=%s", chunkType, dataSize, hasSubchunks ? "yes" : "no"); // Example of handling specific chunk types (Expand this significantly) switch (chunkType) { @@ -437,6 +451,9 @@ bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) GAMEMODELLOG_DEBUG("Unknown chunk type: 0x%X", chunkType); break; } + + // If we've read the entire chunk, exit loop (we are done with the current chunk) + if (file.Position() == currentPosition + chunkSizeRaw) break; // endPosition == dataSize } return true; } From 8d15c2826792d2677194367f883570d6a3197ebd Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:54:07 +0200 Subject: [PATCH 07/13] Fix bugs and override Position --- src/platform/standardfile.cpp | 5 + src/platform/standardfile.h | 1 + .../gamemodelconverter/src/gamemodelcommon.h | 17 +-- .../gamemodelconverter/src/gamemodelfile.cpp | 105 +++++++----------- .../gamemodelconverter/src/gamemodelfile.h | 15 +-- src/tools/gamemodelconverter/src/main.cpp | 4 +- 6 files changed, 53 insertions(+), 94 deletions(-) diff --git a/src/platform/standardfile.cpp b/src/platform/standardfile.cpp index 07523eb47..f425fa079 100644 --- a/src/platform/standardfile.cpp +++ b/src/platform/standardfile.cpp @@ -152,6 +152,11 @@ int StandardFile::Seek(int offset, File::SeekMode mode) return fseek(m_file, (long)offset, fmode); } +int StandardFile::Position() +{ + return ftell(m_file); +} + void StandardFile::Next_Line(char *dst, int bytes) { captainslog_trace("Seeking getting next line from StandardFile %s.", m_name.Str()); diff --git a/src/platform/standardfile.h b/src/platform/standardfile.h index ccf36cd0f..67ff7398f 100644 --- a/src/platform/standardfile.h +++ b/src/platform/standardfile.h @@ -42,6 +42,7 @@ class StandardFile : public LocalFile virtual int Read(void *dst, int bytes) override; virtual int Write(void const *src, int bytes) override; virtual int Seek(int offset, File::SeekMode mode) override; + virtual int Position() override; virtual void Next_Line(char *dst, int bytes) override; virtual bool Scan_Int(int &integer) override; virtual bool Scan_Real(float &real) override; diff --git a/src/tools/gamemodelconverter/src/gamemodelcommon.h b/src/tools/gamemodelconverter/src/gamemodelcommon.h index 350b6513a..2442387d8 100644 --- a/src/tools/gamemodelconverter/src/gamemodelcommon.h +++ b/src/tools/gamemodelconverter/src/gamemodelcommon.h @@ -108,19 +108,4 @@ std::vector ReadArrayFromChunk(const Thyme::ChunkInfo& chunk) { return array; } -std::string ReadStringFromChunk(const Thyme::ChunkInfo& chunk); //Defined below - - -} // namespace Thyme - -inline std::string Thyme::ReadStringFromChunk(const Thyme::ChunkInfo& chunk) { - if (chunk.data.empty()) return ""; - size_t nullTerminatorPos = chunk.data.size(); - for (size_t i = 0; i < chunk.data.size(); i++) { - if (chunk.data[i] == 0) { - nullTerminatorPos = i; - break; - } - } - return std::string((char*)chunk.data.data(), nullTerminatorPos); -} \ No newline at end of file +} // namespace Thyme \ No newline at end of file diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index 44cfd27cd..f990293b5 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -89,7 +89,6 @@ bool Name_To_Game_Model_Option(const char *name, GameModelOption &option) FILE *GameModelFile::s_logfile = nullptr; GameModelFile::GameModelFile() : // Initialize with default options - // TODO chunks array/buffer m_options(GameModelOption::NONE), m_chunkInfos() {}; bool GameModelFile::Is_Loaded() const @@ -152,7 +151,6 @@ bool GameModelFile::Save_MAX(const char *filename) const ChunkInfos &GameModelFile::Get_Chunk_Infos() const { - // TODO size/vector of chunks return m_chunkInfos; } @@ -195,20 +193,13 @@ bool GameModelFile::Load(const char *filename, FileType filetype) bool success = false; - // TODO size/len of chunks - // ChunkInfos chunk_infos; - // ChunkInfos &chunk_infos = chunk_infos_array[size_t(CHUNK_SIZE)]; - switch (filetype) { case FileType::W3D: { success = Read_W3D_File(file, m_chunkInfos, m_options); - // TODO size of chunks - // chunk_infos_array[size_t(CHUNK_SIZE)].swap(chunk_infos); break; } case FileType::W3X: - // TODO: W3X // success = Read_W3X_File(file, chunk_infos, m_options); case FileType::BLEND: case FileType::MAX: { @@ -262,7 +253,6 @@ bool GameModelFile::Save(const char *filename, FileType filetype) case FileType::W3X: case FileType::BLEND: case FileType::MAX: { - // TODO: W3X // success = Write_W3X_File(file, Get_Chunk_Infos(), m_options); GAMEMODELLOG_WARN("Saving for file type '%s' not yet implemented.", filetype); success = false; @@ -295,7 +285,7 @@ void GameModelFile::Reset() // void GameModelFile::Check_Buffer_Lengths() //{ -// // TODO: Implement +// // TODO: Implement buffer management // } // // ChunkInfos &GameModelFile::Mutable_Chunk_Infos() @@ -339,11 +329,6 @@ GameModelFile::FileType GameModelFile::Get_File_Type(const char *filename, FileT return filetype; } -Utf8Array &GameModelFile::Get_Chunk_Data(ChunkInfo &chunk_info) -{ - return chunk_info.data; -} - bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options) { GAMEMODELLOG_INFO("Reading model file '%s' in W3D format", file.Get_File_Name().Str()); @@ -352,7 +337,6 @@ bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Option GAMEMODELLOG_ERROR("Could not open file: %s\n", file.Get_File_Name().Str()); return false; } - // TODO Utf8Array buf = {}; if (!Read_W3D_Chunks(file, chunk_infos)) { GAMEMODELLOG_ERROR("Failed to read W3D chunks from: %s\n", file.Get_File_Name().Str()); @@ -360,7 +344,7 @@ bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Option } //Parse the loaded chunks here (example for mesh data) - Parse_W3D_Data(chunk_infos); + Parse_Model_Data(chunk_infos); return true; } @@ -387,15 +371,17 @@ bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) uint32_t chunkType; uint32_t chunkSizeRaw; - // Read chunk type and size - if (file.Read(&chunkType, sizeof(chunkType)) != sizeof(chunkType)) break; - if (file.Read(&chunkSizeRaw, sizeof(chunkSizeRaw)) != sizeof(chunkSizeRaw)) break; + // Read chunk header (type + size) together + if (file.Read(&chunkType, sizeof(chunkType)) != sizeof(chunkType) || + file.Read(&chunkSizeRaw, sizeof(chunkSizeRaw)) != sizeof(chunkSizeRaw)) { + break; // End of file or error + } + // Prepare the chunk information ChunkInfo chunk; chunk.chunkType = chunkType; - chunk.chunkSize = chunkSizeRaw; - size_t dataSize = chunkSizeRaw & 0x7FFFFFFF; // Mask out MSB for subChunk flag + chunk.chunkSize = dataSize; bool hasSubchunks = (chunkSizeRaw >> 31) & 1; // Check MSB for subchunks (chunkSizeRaw & 0x80000000) int currentPosition = file.Position(); // Save current file position @@ -417,43 +403,23 @@ bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) } } - // Move the file pointer if necessary to ensure alignment - int endPosition = currentPosition + chunkSizeRaw; - int offset = endPosition - file.Position(); - if (file.Position() < endPosition) { - file.Seek(offset, File::SeekMode::CURRENT); + // Check if we are at the correct position after reading chunk data + if (file.Position() != currentPosition + dataSize) { + GAMEMODELLOG_ERROR("Incorrect position after reading chunk data (type: 0x%X).\n", chunkType); } // Add chunk to the parent chunk list parentChunks.push_back(chunk); - GAMEMODELLOG_DEBUG("Read chunk: type=0x%X, size=%zu, subchunks=%s", chunkType, dataSize, hasSubchunks ? "yes" : "no"); + GAMEMODELLOG_DEBUG("Read chunk: type=0x%X, size=%zu, subchunks=%d", chunkType, dataSize, hasSubchunks); - // Example of handling specific chunk types (Expand this significantly) - switch (chunkType) { - case W3D_CHUNK_MESH: - // Parse W3dMeshStruct from chunk.data - GAMEMODELLOG_DEBUG("Found W3D_CHUNK_MESH"); - break; - case W3D_CHUNK_MESH_HEADER3: - // Parse W3dMeshHeader3Struct from chunk.data - GAMEMODELLOG_DEBUG("Found W3D_CHUNK_MESH_HEADER3"); - break; - case W3D_CHUNK_VERTICES: - //Parse W3dVectorStruct array from chunk.data - GAMEMODELLOG_DEBUG("Found W3D_CHUNK_VERTICES"); - break; - case W3D_CHUNK_TRIANGLES: - GAMEMODELLOG_DEBUG("Found W3D_CHUNK_TRIANGLES"); - break; - // Add cases for other chunk types as needed... - default: - GAMEMODELLOG_DEBUG("Unknown chunk type: 0x%X", chunkType); - break; + if (file.Position() == dataSize + sizeof(chunkType) + sizeof(chunkSizeRaw)) { + GAMEMODELLOG_DEBUG("File '%s': Read past end of chunk data (type: 0x%X).", file.Get_File_Name().Str(), chunkType); + return true; } // If we've read the entire chunk, exit loop (we are done with the current chunk) - if (file.Position() == currentPosition + chunkSizeRaw) break; // endPosition == dataSize + if (file.Position() == currentPosition + dataSize) break; // endPosition == dataSize } return true; } @@ -461,26 +427,41 @@ bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) bool GameModelFile::Write_W3D_Chunks(FileRef &file, const ChunkInfos &parentChunks) { for (const auto &chunk : parentChunks) { - uint32_t chunkSize = (uint32_t)chunk.data.size(); - if (!chunk.subChunks.empty()) - chunkSize |= 0x80000000; + uint32_t chunkSize = (uint32_t)chunk.chunkSize; + bool hasSubchunks = !chunk.subChunks.empty(); + + if (hasSubchunks) { + chunkSize |= 0x80000000; // Set MSB to indicate subChunks + } + // Write ChunkType and ChunkSize if (file.Write(&chunk.chunkType, sizeof(chunk.chunkType)) != sizeof(chunk.chunkType) || - file.Write(&chunkSize, sizeof(chunkSize)) != sizeof(chunkSize) || - file.Write(chunk.data.data(), chunk.data.size()) != chunk.data.size()) { - GAMEMODELLOG_ERROR("File '%s': Failed to write chunk data.\n", file.Get_File_Name().Str()); - // TODO GAMEMODELLOG_ERROR("File '%s': Failed to write chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunk.chunkType); + file.Write(&chunkSize, sizeof(chunkSize)) != sizeof(chunkSize)) { + GAMEMODELLOG_ERROR("File '%s': Failed to write chunk header (type: 0x%X).\n", file.Get_File_Name().Str(), chunk.chunkType); return false; } - if (!chunk.subChunks.empty()) { - if (!Write_W3D_Chunks(file, chunk.subChunks)) + + // Write chunk data (only if there's data to write) + if (chunk.data.size() > 0) { + if (file.Write(chunk.data.data(), chunk.data.size()) != chunk.data.size()) { + GAMEMODELLOG_ERROR("File '%s': Failed to write chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunk.chunkType); return false; + } + } + + // If there are subChunks, write them recursively + if (hasSubchunks) { + if (!Write_W3D_Chunks(file, chunk.subChunks)) { + return false; + } } } + return true; } -void GameModelFile::Parse_W3D_Data(const ChunkInfos& chunks) { + +void GameModelFile::Parse_Model_Data(const ChunkInfos& chunks) { for (const auto& chunk : chunks) { switch (chunk.chunkType) { case W3D_CHUNK_MESH: @@ -489,7 +470,7 @@ void GameModelFile::Parse_W3D_Data(const ChunkInfos& chunks) { case W3D_CHUNK_EMITTER: Parse_Emitter_Chunk(chunk); break; - // Add cases for other top-level chunk types... + // Add additional cases for other chunk types default: GAMEMODELLOG_DEBUG("Ignoring unknown top-level chunk type: 0x%X", chunk.chunkType); break; diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.h b/src/tools/gamemodelconverter/src/gamemodelfile.h index fff9d27ea..cb875ba02 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.h +++ b/src/tools/gamemodelconverter/src/gamemodelfile.h @@ -121,9 +121,7 @@ class GameModelFile bool Save(const char *filename, FileType filetype); // void Check_Buffer_Lengths(); -// // ChunkInfos &Mutable_Chunk_Infos(); -// // static ChunkInfosPtrArray Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array); // static ConstChunkInfosPtrArray Build_Const_Chunk_Infos_Ptrs_Array( // ChunkInfosArray &chunk_infos_array); @@ -136,22 +134,12 @@ class GameModelFile // static void Log_Length_Info(const LengthInfo &len_info); // static void Assert_Length_Info(const LengthInfo &len_info); - // TODO need a significant rewrite based on the chunk structure - static Utf8Array &Get_Chunk_Data(ChunkInfo &chunk_info); - bool Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options); - - // TODO need substantial changes based on the chunk structure - // Recursive function to read/write chunks and subchunks bool Read_W3D_Chunks(FileRef &file, ChunkInfos& parentChunks); bool Write_W3D_Chunks(FileRef &file, const ChunkInfos& parentChunks); - - //Helper function to write a single chunk to the file - bool Write_W3D_Chunk(FileRef &file, const ChunkInfo& chunk); - bool Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options); - void Parse_W3D_Data(const ChunkInfos& chunks); + void Parse_Model_Data(const ChunkInfos& chunks); void Parse_Mesh_Chunk(const ChunkInfo& meshChunk); void Parse_Emitter_Chunk(const ChunkInfo& emitterChunk); const ParsedMeshData &GetMeshData() const; @@ -162,7 +150,6 @@ class GameModelFile private: Options m_options; ChunkInfos m_chunkInfos; - // TODO chunks array/buffer static FILE *s_logfile; ParsedMeshData m_meshData; ParsedEmitterData m_emitterData; diff --git a/src/tools/gamemodelconverter/src/main.cpp b/src/tools/gamemodelconverter/src/main.cpp index 3eb8b7fb3..d132b3a81 100644 --- a/src/tools/gamemodelconverter/src/main.cpp +++ b/src/tools/gamemodelconverter/src/main.cpp @@ -132,10 +132,10 @@ WARNING: Commands that save files will overwrite existing files without confirma > Saves the loaded data as a 3ds Max file to the given file path. Example 1: Convert a W3D file to W3X format - > GameModelConverter.exe -load_w3d D:\models\model.w3d -convert_w3d_to_w3x D:\models\model.w3x + > GameModelConverter.exe -load_w3d D:\models\model.w3d -save_w3x D:\models\model.w3x Example 2: Convert a W3X file to W3D format - > GameModelConverter.exe -load_w3x D:\models\model.w3x -convert_w3x_to_w3d D:\models\model.w3d + > GameModelConverter.exe -load_w3x D:\models\model.w3x -save_w3d D:\models\model.w3d Example 3: Load a Blender file and save as W3D > GameModelConverter.exe -load_blend D:\models\model.blend -save_w3d D:\models\model.w3d From 08ff13bd16d488f507dcbac2819bb0855fc575dc Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Fri, 24 Jan 2025 05:22:40 +0200 Subject: [PATCH 08/13] new class chunksmanager --- src/tools/gamemodelconverter/CMakeLists.txt | 3 +- .../gamemodelconverter/src/chunksmanager.cpp | 491 ++++++++++++++++++ .../gamemodelconverter/src/chunksmanager.h | 109 ++++ .../gamemodelconverter/src/gamemodelfile.cpp | 326 ++---------- .../gamemodelconverter/src/gamemodelfile.h | 73 +-- 5 files changed, 666 insertions(+), 336 deletions(-) create mode 100644 src/tools/gamemodelconverter/src/chunksmanager.cpp create mode 100644 src/tools/gamemodelconverter/src/chunksmanager.h diff --git a/src/tools/gamemodelconverter/CMakeLists.txt b/src/tools/gamemodelconverter/CMakeLists.txt index 8f0188f64..61d2fe9a4 100644 --- a/src/tools/gamemodelconverter/CMakeLists.txt +++ b/src/tools/gamemodelconverter/CMakeLists.txt @@ -1,6 +1,8 @@ set(CMAKE_CXX_STANDARD 17) set(GAMEMODELCONVERTER_SOURCES + src/chunksmanager.cpp + src/chunksmanager.h src/gamemodelcommon.h src/gamemodelfile.cpp src/gamemodelfile.h @@ -14,7 +16,6 @@ set(GAMEMODELCONVERTER_SOURCES ) set(GAMEMODELCONVERTER_INCLUDES src) - add_executable(GameModelConverter ${GAMEMODELCONVERTER_SOURCES}) target_include_directories(GameModelConverter PRIVATE ${GAMEMODELCONVERTER_INCLUDES}) target_link_libraries(GameModelConverter PRIVATE thyme_lib) diff --git a/src/tools/gamemodelconverter/src/chunksmanager.cpp b/src/tools/gamemodelconverter/src/chunksmanager.cpp new file mode 100644 index 000000000..a5ec6e2d0 --- /dev/null +++ b/src/tools/gamemodelconverter/src/chunksmanager.cpp @@ -0,0 +1,491 @@ +#include "chunksmanager.h" + +ChunkManager::ChunkManager(const char *filePath, int flag) +{ + m_rootChunk = std::make_unique(); + +// if (flag == LOAD) { +// // Open the file for reading +// m_file = auto_file_ptr(g_theFileFactory, filePath); // Assuming auto_file_ptr is a smart pointer +// if (!m_file->Open(FileOpenType::FM_READ)) { +// captainslog_error("Could not open file for reading: %s", filePath); +// } +// } else if (flag == SAVE) { +// // Open the file for writing +// m_file = auto_file_ptr(g_theFileFactory, filePath); // Assuming auto_file_ptr is a smart pointer +// if (!m_file->Open(FileOpenType::FM_WRITE)) { +// captainslog_error("Could not open file for writing: %s", filePath); +// } +// } else { +// captainslog_error("Invalid flag in ChunkManager constructor"); +// } +} + +ChunkManager::~ChunkManager() +{ + if (m_file) { + m_file->Close(); + } +} + +void ChunkManager::ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) +{ + if (parentChunk == nullptr) { + captainslog_error("Parent chunk is null"); + return; + } + while (chunkLoader.Open_Chunk()) { + ChunkPtr chunk = std::make_unique(); + ReadChunkInfo(chunkLoader, chunk); + parentChunk->data = std::move(chunk); + if (chunkLoader.Contains_Chunks()) { + while (chunkLoader.Open_Chunk()) { + ChunkPtr subchunk = std::make_unique(); + ReadChunkInfo(chunkLoader, subchunk); + parentChunk->subchunks.push_back(std::move(subchunk)); + chunkLoader.Close_Chunk(); + } + } + chunkLoader.Close_Chunk(); + } +} + +std::map typeToIOFuncMap; + +void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkPtr &chunk) +{ + if (chunk == nullptr) { + captainslog_error("Chunk is null"); + return; + } + chunk->chunkType = chunkLoader.Cur_Chunk_ID(); + chunk->chunkSize = chunkLoader.Cur_Chunk_Length(); + auto it = typeToIOFuncMap.find(chunk->chunkType); + if (it != typeToIOFuncMap.end()) { + chunk->info = createChunkInfo(); + it->second.ReadFunc(chunkLoader, chunk->info); + } else { + StringClass str; + str.Format("Unknown Chunk 0x%X", chunk->chunkType); + captainslog_warn((const char *)str); + chunk->info = nullptr; + } +} + +void ChunkManager::WriteSubchunks(ChunkSaveClass &chunkSaver, const ChunkTreePtr &parentChunk) +{ + if (parentChunk->data) { + if (!chunkSaver.Begin_Chunk(parentChunk->data->chunkType)) { + captainslog_error("Failed to begin chunk"); + return; + } + WriteChunkInfo(chunkSaver, parentChunk->data); + if (!chunkSaver.End_Chunk()) { + captainslog_error("Failed to end chunk"); + return; + } + + } + + for (const auto& subchunk : parentChunk->subchunks) { + WriteChunkInfo(chunkSaver, subchunk); + } +} + +void ChunkManager::WriteChunkInfo(ChunkSaveClass &chunkSaver, const ChunkPtr &chunk) +{ + auto it = typeToIOFuncMap.find(chunk->chunkType); + if (it != typeToIOFuncMap.end()) { + it->second.WriteFunc(chunkSaver, chunk->info); + } else { + StringClass str; + str.Format("Unknown Chunk 0x%X", chunk->chunkType); + captainslog_warn((const char*)str); + } +} + +void ChunkManager::AddData( + ChunkInfoPtr &data, const char *name, const StringClass &type, const StringClass &formattedValue, void *value) +{ + if (data == nullptr) { + data = std::move(createChunkInfo(name, type, formattedValue, value)); + } else { + captainslog_error("ChunkInfo %s already exists, cannot set %s", (const char*)data->name, name); + } + data = std::move(createChunkInfo(name, type, formattedValue, value)); +} + +void ChunkManager::AddString(ChunkInfoPtr &data, const char *name, const StringClass &value, const StringClass &type) +{ + AddData(data, name, type, value, nullptr); +} + +void ChunkManager::AddVersion(ChunkInfoPtr &data, uint32_t value) +{ + char c[64]; + sprintf(c, "%u.%hu", value >> 16, (uint16_t)value); + AddData(data, "Version", "uint32_t", c, (void *)&value); +} + +void ChunkManager::AddInt32(ChunkInfoPtr &data, const char *name, uint32_t value) +{ + char c[256]; + sprintf(c, "%u", value); + AddData(data, name, "uint32_t", c, (void *)&value); +} + +void ChunkManager::AddInt16(ChunkInfoPtr &data, const char *name, uint16_t value) +{ + char c[256]; + sprintf(c, "%hu", value); + AddData(data, name, "uint16_t", c, (void *)&value); +} + +void ChunkManager::AddInt8(ChunkInfoPtr &data, const char *name, uint8_t value) +{ + char c[256]; + sprintf(c, "%hhu", value); + AddData(data, name, "uint8_t", c, (void *)&value); +} + +void ChunkManager::AddInt8Array(ChunkInfoPtr &data, const char *name, const uint8_t *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("%hhu ", values[i]); + str += str2; + } + char c[256]; + sprintf(c, "int8[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void ChunkManager::AddFloat(ChunkInfoPtr &data, const char *name, float value) +{ + char c[256]; + sprintf(c, "%f", value); + AddData(data, name, "float", c, (void *)&value); +} + +void ChunkManager::AddInt32Array(ChunkInfoPtr &data, const char *name, const uint32_t *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("%u ", values[i]); + str += str2; + } + char c[256]; + sprintf(c, "int32[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void ChunkManager::AddFloatArray(ChunkInfoPtr &data, const char *name, const float *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("%f ", values[i]); + str += str2; + } + char c[256]; + sprintf(c, "float[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void ChunkManager::AddVector(ChunkInfoPtr &data, const char *name, const W3dVectorStruct *value) +{ + char c[256]; + sprintf(c, "%f %f %f", value->x, value->y, value->z); + AddData(data, name, "W3dVectorStruct", c, (void *)value); +} + +void ChunkManager::AddQuaternion(ChunkInfoPtr &data, const char *name, const W3dQuaternionStruct *value) +{ + char c[256]; + sprintf(c, "%f %f %f %f", value->q[0], value->q[1], value->q[2], value->q[3]); + AddData(data, name, "W3dQuaternionStruct", c, (void *)value); +} + +void ChunkManager::AddRGB(ChunkInfoPtr &data, const char *name, const W3dRGBStruct *value) +{ + StringClass str; + str.Format("(%hhu %hhu %hhu) ", value->r, value->g, value->b); + AddData(data, name, "W3dRGBStruct", str, (void *)value); +} + +void ChunkManager::AddRGBArray(ChunkInfoPtr &data, const char *name, const W3dRGBStruct *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("(%hhu %hhu %hhu) ", values[i].r, values[i].g, values[i].b); + str += str2; + } + char c[256]; + sprintf(c, "float[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void ChunkManager::AddRGBA(ChunkInfoPtr &data, const char *name, const W3dRGBAStruct *value) +{ + StringClass str; + str.Format("(%hhu %hhu %hhu %hhu) ", value->R, value->G, value->B, value->A); + AddData(data, name, "W3dRGBAStruct", str, (void *)value); +} + +void ChunkManager::AddTexCoord(ChunkInfoPtr &data, const char *name, const W3dTexCoordStruct *value) +{ + char c[256]; + sprintf(c, "%f %f", value->U, value->V); + AddData(data, name, "W3dTexCoordStruct", c, (void *)value); +} + +void ChunkManager::AddTexCoordArray(ChunkInfoPtr &data, const char *name, const W3dTexCoordStruct *values, int count) +{ + StringClass str; + for (int i = 0; i < count; i++) { + char c[256]; + sprintf(c, "%s.TexCoord[%d]", name, i); + AddTexCoord(data, c, &values[i]); + } +} + +const char *DepthCompareValues[] = { "Pass Never", + "Pass Less", + "Pass Equal", + "Pass Less or Equal", + "Pass Greater", + "Pass Not Equal", + "Pass Greater or Equal", + "Pass Always" }; + +const char *DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; + +const char *DestBlendValues[] = { "Zero", + "One", + "Src Color", + "One Minus Src Color", + "Src Alpha", + "One Minus Src Alpha", + "Src Color Prefog", + "Disable", + "Enable", + "Scale Fragment", + "Replace Fragment" }; + +const char *PriGradientValues[] = { + "Disable", "Modulate", "Add", "Bump-Environment", "Bump-Environment Luminance", "Modulate 2x" +}; + +const char *SecGradientValues[] = { "Disable", "Enable" }; + +const char *SrcBlendValues[] = { "Zero", "One", "Src Alpha", "One Minus Src Alpha" }; + +const char *TexturingValues[] = { "Disable", "Enable" }; + +const char *DetailColorValues[] = { "Disable", + "Detail", + "Scale", + "InvScale", + "Add", + "Sub", + "SubR", + "Blend", + "DetailBlend", + "Add Signed", + "Add Signed 2x", + "Scale 2x", + "Mod Alpha Add Color" }; + +const char *DetailAlphaValues[] = { "Disable", "Detail", "Scale", "InvScale", "Disable", "Enable", "Smooth", "Flat" }; + +const char *AlphaTestValues[] = { "Alpha Test Disable", "Alpha Test Enable" }; + +void ChunkManager::AddShader(ChunkInfoPtr &data, const char *name, const W3dShaderStruct *value) +{ + // main shader + AddData(data, name, "W3dShaderStruct", "Main Shader", (void *)value); + char c[256]; + sprintf(c, "%s.DepthCompare", name); + + if (value->DepthCompare < W3DSHADER_DEPTHCOMPARE_PASS_MAX) { + AddString(data, c, DepthCompareValues[value->DepthCompare], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Depth Compare type %x", c, value->DepthCompare); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthCompare); + } + + sprintf(c, "%s.DepthMask", name); + + if (value->DepthMask < W3DSHADER_DEPTHMASK_WRITE_MAX) { + AddString(data, c, DepthMaskValues[value->DepthMask], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Depth Mask type %x", c, value->DepthMask); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthMask); + } + + sprintf(c, "%s.DestBlend", name); + + if (value->DestBlend < W3DSHADER_DESTBLENDFUNC_MAX) { + AddString(data, c, DestBlendValues[value->DestBlend], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Dest Blend type %x", c, value->DestBlend); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DestBlend); + } + + sprintf(c, "%s.PriGradient", name); + + if (value->PriGradient < W3DSHADER_PRIGRADIENT_MAX) { + AddString(data, c, PriGradientValues[value->PriGradient], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Primary Gradient type %x", c, value->PriGradient); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->PriGradient); + } + + sprintf(c, "%s.SecGradient", name); + + if (value->SecGradient < W3DSHADER_SECGRADIENT_MAX) { + AddString(data, c, SecGradientValues[value->SecGradient], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Secondary Gradient type %x", c, value->SecGradient); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->SecGradient); + } + + sprintf(c, "%s.SrcBlend", name); + + if (value->SrcBlend < W3DSHADER_SRCBLENDFUNC_MAX) { + AddString(data, c, SrcBlendValues[value->SrcBlend], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Src Blend type %x", c, value->SrcBlend); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->SrcBlend); + } + + sprintf(c, "%s.Texturing", name); + + if (value->Texturing < W3DSHADER_TEXTURING_MAX) { + AddString(data, c, TexturingValues[value->Texturing], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Texturing type %x", c, value->Texturing); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->Texturing); + } + + sprintf(c, "%s.DetailColor", name); + + if (value->DetailColorFunc < W3DSHADER_DETAILCOLORFUNC_MAX) { + AddString(data, c, DetailColorValues[value->DetailColorFunc], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Detail Color Func type %x", c, value->DetailColorFunc); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailColorFunc); + } + + sprintf(c, "%s.DetailAlpha", name); + + if (value->DetailAlphaFunc < W3DSHADER_DETAILALPHAFUNC_MAX) { + AddString(data, c, DetailAlphaValues[value->DetailAlphaFunc], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Detail Alpha Func type %x", c, value->DetailAlphaFunc); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailAlphaFunc); + } + + sprintf(c, "%s.AlphaTest", name); + + if (value->AlphaTest < W3DSHADER_ALPHATEST_MAX) { + AddString(data, c, AlphaTestValues[value->AlphaTest], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Alpha Test type %x", c, value->AlphaTest); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->AlphaTest); + } +} + +const char *PS2DepthCompareValues[] = { "Pass Never", "Pass Less", "Pass Always", "Pass Less or Equal" }; + +const char *PS2DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; + +const char *PS2ABDParamValues[] = { "Src Color", "Dest Color", "Zero" }; + +const char *PS2CParamValues[] = { + "Src Alpha", "Dest Alpha", "One", "Disable", "Enable", "Scale Fragment", "Replace Fragment" +}; + +const char *PS2PriGradientValues[] = { "Disable", "Modulate", "Highlight", "Highlight2", "Disable", "Enable" }; + +const char *PS2TexturingValues[] = { "Disable", + "Enable", + "Disable", + "Detail", + "Scale", + "InvScale", + "Add", + "Sub", + "SubR", + "Blend", + "DetailBlend", + "Disable", + "Detail", + "Scale", + "InvScale", + "Disable", + "Enable", + "Smooth", + "Flat" }; + +void ChunkManager::AddPS2Shader(ChunkInfoPtr &data, const char *name, const W3dPS2ShaderStruct *value) +{ + // main shader + // TODO check if this is correct and works + AddData(data, name, "W3dPS2ShaderStruct", "Main Shader", (void *)value); + char c[256]; + sprintf(c, "%s.DepthCompare", name); + AddData(data, c, "uint8_t", PS2DepthCompareValues[value->DepthCompare], (void *)&value->DepthCompare); + AddString(data, c, PS2DepthCompareValues[value->DepthCompare], "uint8_t"); + sprintf(c, "%s.DepthMask", name); + AddString(data, c, PS2DepthMaskValues[value->DepthMask], "uint8_t"); + sprintf(c, "%s.PriGradient", name); + AddString(data, c, PS2PriGradientValues[value->PriGradient], "uint8_t"); + sprintf(c, "%s.Texturing", name); + AddString(data, c, PS2TexturingValues[value->Texturing], "uint8_t"); + sprintf(c, "%s.AParam", name); + AddString(data, c, PS2ABDParamValues[value->AParam], "uint8_t"); + sprintf(c, "%s.BParam", name); + AddString(data, c, PS2ABDParamValues[value->BParam], "uint8_t"); + sprintf(c, "%s.CParam", name); + AddString(data, c, PS2CParamValues[value->CParam], "uint8_t"); + sprintf(c, "%s.DParam", name); + AddString(data, c, PS2ABDParamValues[value->DParam], "uint8_t"); +} + +void ChunkManager::AddIJK(ChunkInfoPtr &data, const char *name, const Vector3i *value) +{ + char c[256]; + sprintf(c, "%d %d %d", value->I, value->J, value->K); + AddData(data, name, "Vector3i", c, (void *)value); +} + +void ChunkManager::AddIJK16(ChunkInfoPtr &data, const char *name, const Vector3i16 *value) +{ + char c[256]; + sprintf(c, "%d %d %d", value->I, value->J, value->K); + AddData(data, name, "Vector3i16", c, (void *)value); +} diff --git a/src/tools/gamemodelconverter/src/chunksmanager.h b/src/tools/gamemodelconverter/src/chunksmanager.h new file mode 100644 index 000000000..eab022818 --- /dev/null +++ b/src/tools/gamemodelconverter/src/chunksmanager.h @@ -0,0 +1,109 @@ +#pragma once + +#include "chunkio.h" +#include "ffactory.h" +#include "vector3i.h" +#include "w3d_file.h" +#include "w3d_obsolete.h" +#include +#include +#include + +struct ChunkInfo +{ + StringClass name; // The chunk name (e.g. "W3D_CHUNK_VERTEX_MATERIALS") + StringClass type; // The chunk type (e.g., "W3dVectorStruct," "W3dColorStruct") + StringClass data; // Formatted data (e.g. "Version 4.2", "X: 1, Y: 3, Z: 8"), will W3X support. + void *value; // The Raw type data (e.g. address of W3dVectorStruct content) + + ChunkInfo(const char *name, const StringClass &type, const StringClass &data, void *value) : + name(name), type(type), data(data), value(value) {} +}; + + +using ChunkInfoPtr = std::unique_ptr; + +struct Chunk +{ + uint32_t chunkType; + uint32_t chunkSize; + ChunkInfoPtr info; +}; + +using ChunkPtr = std::unique_ptr; +using ChunkList = std::vector; + +struct ChunkTree +{ + ChunkPtr data; + ChunkList subchunks; + ~ChunkTree() = default; +}; + +using ChunkTreePtr = std::unique_ptr; + +struct ChunkIOFuncs +{ + const char *name; + void (*ReadFunc)(ChunkLoadClass &chunkLoader, ChunkInfoPtr &data); + void (*WriteFunc)(ChunkSaveClass &chunkSaver, ChunkInfoPtr &data); +}; + +class ChunkManager +{ +public: + // flags for the chunk manager + enum ChunkManagerType + { + LOAD = 0, + SAVE = 1, + }; + + ChunkManager(const char *filePath, int flag); + ~ChunkManager(); + + // Utility functions + static ChunkInfoPtr createChunkInfo( + const char *name = "Unknown", + const StringClass &type = "Unknown", + const StringClass &data = "Unknown", + void *value = nullptr) + { + return std::make_unique(name, type, data, value); + } + static void AddData( + ChunkInfoPtr &chunk, const char *name, const StringClass &type, const StringClass &formattedValue, void *value); + + + static void ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); + static void ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkPtr &chunk); + void WriteSubchunks(ChunkSaveClass &chunkSaver, const ChunkTreePtr &parentChunk); + void WriteChunkInfo(ChunkSaveClass &chunkSaver, const ChunkPtr &chunk); + + ChunkTreePtr & GetRootChunk() { return m_rootChunk; } + +private: + static void AddString(ChunkInfoPtr &chunk, const char *name, const StringClass &value, const StringClass &type); + static void AddVersion(ChunkInfoPtr &chunk, uint32_t value); + static void AddInt32(ChunkInfoPtr &chunk, const char *name, uint32_t value); + static void AddInt16(ChunkInfoPtr &chunk, const char *name, uint16_t value); + static void AddInt8(ChunkInfoPtr &chunk, const char *name, uint8_t value); + static void AddInt8Array(ChunkInfoPtr &chunk, const char *name, const uint8_t *values, int count); + static void AddFloat(ChunkInfoPtr &chunk, const char *name, float value); + static void AddInt32Array(ChunkInfoPtr &chunk, const char *name, const uint32_t *values, int count); + static void AddFloatArray(ChunkInfoPtr &chunk, const char *name, const float *values, int count); + static void AddVector(ChunkInfoPtr &chunk, const char *name, const W3dVectorStruct *value); + static void AddQuaternion(ChunkInfoPtr &chunk, const char *name, const W3dQuaternionStruct *value); + static void AddRGB(ChunkInfoPtr &chunk, const char *name, const W3dRGBStruct *value); + static void AddRGBArray(ChunkInfoPtr &chunk, const char *name, const W3dRGBStruct *values, int count); + static void AddRGBA(ChunkInfoPtr &chunk, const char *name, const W3dRGBAStruct *value); + static void AddTexCoord(ChunkInfoPtr &chunk, const char *name, const W3dTexCoordStruct *value); + static void AddTexCoordArray(ChunkInfoPtr &chunk, const char *name, const W3dTexCoordStruct *values, int count); + static void AddShader(ChunkInfoPtr &chunk, const char *name, const W3dShaderStruct *value); + static void AddPS2Shader(ChunkInfoPtr &chunk, const char *name, const W3dPS2ShaderStruct *value); + static void AddIJK(ChunkInfoPtr &chunk, const char *name, const Vector3i *value); + static void AddIJK16(ChunkInfoPtr &chunk, const char *name, const Vector3i16 *value); + + ChunkTreePtr m_rootChunk; + FileClass *m_file; +}; diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index f990293b5..b5b3678b3 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -12,16 +12,7 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ -#include "always.h" #include "gamemodelfile.h" -#include "filesystem.h" -#include "rtsutils.h" -#include "utility/arrayutil.h" -#include "utility/fileutil.h" -#include "utility/stlutil.h" -#include "utility/stringutil.h" -#include "gamemodelcommon.h" -#include "w3d_file.h" #define GAMEMODELLOG_TRACE(fmt, ...) \ @@ -53,6 +44,7 @@ namespace Thyme namespace { +// TODO delete this function template constexpr size_t Bit_To_Index(IntegerType integer) { using UnsignedInt = UnsignedIntegerT; @@ -89,13 +81,31 @@ bool Name_To_Game_Model_Option(const char *name, GameModelOption &option) FILE *GameModelFile::s_logfile = nullptr; GameModelFile::GameModelFile() : // Initialize with default options - m_options(GameModelOption::NONE), m_chunkInfos() {}; + m_options(GameModelOption::NONE), m_rootChunk(nullptr), m_chunkLoader(nullptr) {}; bool GameModelFile::Is_Loaded() const { - return !Get_Chunk_Infos().empty(); + return false; +} + +GameModelFile::FileType GameModelFile::Get_File_Type(const char *filename, FileType filetype) +{ + if (filetype == FileType::AUTO) { + std::string fn(filename); + if (fn.find(".w3d") != std::string::npos) + return FileType::W3D; + // Add checks for .w3x, .blend, .max here + if (fn.find(".w3x") != std::string::npos) + return FileType::W3X; + if (fn.find(".blend") != std::string::npos) + return FileType::BLEND; + if (fn.find(".max") != std::string::npos) + return FileType::MAX; + } + return filetype; } + bool GameModelFile::Load(const char *filename) { const FileType filetype = Get_File_Type(filename, FileType::AUTO); @@ -149,11 +159,6 @@ bool GameModelFile::Save_MAX(const char *filename) return Save(filename, FileType::MAX); } -const ChunkInfos &GameModelFile::Get_Chunk_Infos() const -{ - return m_chunkInfos; -} - void GameModelFile::Set_Options(Options options) { m_options = options; @@ -182,25 +187,15 @@ bool GameModelFile::Load(const char *filename, FileType filetype) return false; } - - // TODO: Check if this is the correct way to open a file, there is g_theW3DFileSystem, but he use game path, not the file path - const int filemode = Encode_Buffered_File_Mode(File::READ | File::BINARY, 1024 * 32); - FileRef file = g_theFileSystem->Open_File(filename, filemode); - if (!file.Is_Open()) { - GAMEMODELLOG_ERROR("File '%s' cannot be opened for read", filename); - return false; - } - bool success = false; switch (filetype) { case FileType::W3D: { - success = Read_W3D_File(file, m_chunkInfos, m_options); + success = Read_W3D_File(filename, m_options); break; } case FileType::W3X: - // success = Read_W3X_File(file, chunk_infos, m_options); case FileType::BLEND: case FileType::MAX: { GAMEMODELLOG_WARN("Loading for file type '%s' not yet implemented.", filetype); @@ -235,25 +230,18 @@ bool GameModelFile::Save(const char *filename, FileType filetype) // return false; // } - const int filemode = Encode_Buffered_File_Mode(File::WRITE | File::CREATE | File::BINARY, 1024 * 32); - FileRef file = g_theFileSystem->Open_File(filename, filemode); - if (!file.Is_Open()) { - GAMEMODELLOG_ERROR("File '%s' cannot be opened for write", filename); - return false; - } bool success = false; switch (filetype) { case FileType::W3D: { - success = Write_W3D_File(file, Get_Chunk_Infos(), m_options); + success = Write_W3D_File(filename, m_options); break; } case FileType::W3X: case FileType::BLEND: case FileType::MAX: { - // success = Write_W3X_File(file, Get_Chunk_Infos(), m_options); GAMEMODELLOG_WARN("Saving for file type '%s' not yet implemented.", filetype); success = false; break; @@ -275,265 +263,53 @@ bool GameModelFile::Save(const char *filename, FileType filetype) void GameModelFile::Reset() { - // TODO size/vector of chunks - // for (ChunkInfos &chunk_infos : m_chunkInfosArray) { - // rts::Free_Container(chunk_infos); - // } - m_chunkInfos.clear(); m_options = Options::Value::NONE; + // TODO good free memory? +// if (m_chunkManager) { +// delete m_chunkManager; +// m_chunkManager = nullptr; +// } } -// void GameModelFile::Check_Buffer_Lengths() -//{ -// // TODO: Implement buffer management -// } -// -// ChunkInfos &GameModelFile::Mutable_Chunk_Infos() -//{ -// // TODO size/vector of chunks -// return m_chunkInfosArray[size_t(CHUNK_SIZE)]; -// } -// -// ChunkInfosPtrArray GameModelFile::Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) -//{ -// // TODO: Implement -// return {}; -// } -// -// ConstChunkInfosPtrArray GameModelFile::Build_Const_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array) -//{ -// // TODO: Implement -// return {}; -// } -// -// size_t GameModelFile::Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs) -//{ -// // TODO size/vector of chunks -// return 0; -// } - -GameModelFile::FileType GameModelFile::Get_File_Type(const char *filename, FileType filetype) +bool GameModelFile::Read_W3D_File(const char *filename, const Options& options) { - if (filetype == FileType::AUTO) { - std::string fn(filename); - if (fn.find(".w3d") != std::string::npos) - return FileType::W3D; - // Add checks for .w3x, .blend, .max here - if (fn.find(".w3x") != std::string::npos) - return FileType::W3X; - if (fn.find(".blend") != std::string::npos) - return FileType::BLEND; - if (fn.find(".max") != std::string::npos) - return FileType::MAX; - } - return filetype; -} + GAMEMODELLOG_INFO("Reading model file '%s' in W3D format", filename); -bool GameModelFile::Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options) -{ - GAMEMODELLOG_INFO("Reading model file '%s' in W3D format", file.Get_File_Name().Str()); - if (!file.Is_Open()) { - GAMEMODELLOG_ERROR("Could not open file: %s\n", file.Get_File_Name().Str()); - return false; - } - if (!Read_W3D_Chunks(file, chunk_infos)) { - GAMEMODELLOG_ERROR("Failed to read W3D chunks from: %s\n", file.Get_File_Name().Str()); + auto_file_ptr file(g_theFileFactory, filename); + if (!file->Open(FileOpenType::FM_READ)) { + GAMEMODELLOG_ERROR("Could not open file: %s", filename); return false; } + m_chunkManager = new ChunkManager(filename, ChunkManager::ChunkManagerType::LOAD); + m_chunkLoader = ChunkLoadClass(file); + m_chunkManager->ParseSubchunks(m_chunkLoader, m_chunkManager->GetRootChunk()); +// if (!Log_Unknown_Chunks(m_rootChunk)) { +// GAMEMODELLOG_ERROR("Unknown chunks found in file: %s", filename); +// GAMEMODELLOG_ERROR("Failed to load chunks correctly"); +// return false; +// } +// else { + GAMEMODELLOG_INFO("Successfully parsed W3D file: %s", filename); - //Parse the loaded chunks here (example for mesh data) - Parse_Model_Data(chunk_infos); - return true; -} - -bool GameModelFile::Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options) -{ - GAMEMODELLOG_INFO("Writing model file '%s' in W3D format", file.Get_File_Name().Str()); - - bool success = true; - if (!file.Is_Open()) { // Use FM_WRITE for saving - GAMEMODELLOG_ERROR("File '%s' cannot be opened for write", file.Get_File_Name().Str()); - success = false; - } - if (!Write_W3D_Chunks(file, chunk_infos)) { - GAMEMODELLOG_ERROR("Failed to write W3D chunks to: %s\n", file.Get_File_Name().Str()); - success = false; - } - - return success; -} - -bool GameModelFile::Read_W3D_Chunks(FileRef &file, ChunkInfos &parentChunks) -{ - while (true) { - uint32_t chunkType; - uint32_t chunkSizeRaw; - - // Read chunk header (type + size) together - if (file.Read(&chunkType, sizeof(chunkType)) != sizeof(chunkType) || - file.Read(&chunkSizeRaw, sizeof(chunkSizeRaw)) != sizeof(chunkSizeRaw)) { - break; // End of file or error - } - - // Prepare the chunk information - ChunkInfo chunk; - chunk.chunkType = chunkType; - size_t dataSize = chunkSizeRaw & 0x7FFFFFFF; // Mask out MSB for subChunk flag - chunk.chunkSize = dataSize; - bool hasSubchunks = (chunkSizeRaw >> 31) & 1; // Check MSB for subchunks (chunkSizeRaw & 0x80000000) - - int currentPosition = file.Position(); // Save current file position - - if (hasSubchunks) { - // Read subchunks recursively - while (file.Position() < currentPosition + dataSize) { - if (!Read_W3D_Chunks(file, chunk.subChunks)) { - GAMEMODELLOG_ERROR("Failed to read subchunks for chunk type 0x%X\n", chunkType); - return false; - } - } - } else { - // Read the current chunk data - chunk.data.resize(dataSize); - if (file.Read(chunk.data.data(), dataSize) != dataSize) { - GAMEMODELLOG_ERROR("File '%s': Failed to read chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunkType); - return false; - } - } - - // Check if we are at the correct position after reading chunk data - if (file.Position() != currentPosition + dataSize) { - GAMEMODELLOG_ERROR("Incorrect position after reading chunk data (type: 0x%X).\n", chunkType); - } - - // Add chunk to the parent chunk list - parentChunks.push_back(chunk); - - GAMEMODELLOG_DEBUG("Read chunk: type=0x%X, size=%zu, subchunks=%d", chunkType, dataSize, hasSubchunks); - - if (file.Position() == dataSize + sizeof(chunkType) + sizeof(chunkSizeRaw)) { - GAMEMODELLOG_DEBUG("File '%s': Read past end of chunk data (type: 0x%X).", file.Get_File_Name().Str(), chunkType); - return true; - } - - // If we've read the entire chunk, exit loop (we are done with the current chunk) - if (file.Position() == currentPosition + dataSize) break; // endPosition == dataSize - } return true; } -bool GameModelFile::Write_W3D_Chunks(FileRef &file, const ChunkInfos &parentChunks) +bool GameModelFile::Write_W3D_File(const char *filename, const Options& options) { - for (const auto &chunk : parentChunks) { - uint32_t chunkSize = (uint32_t)chunk.chunkSize; - bool hasSubchunks = !chunk.subChunks.empty(); - - if (hasSubchunks) { - chunkSize |= 0x80000000; // Set MSB to indicate subChunks - } + GAMEMODELLOG_INFO("Writing model file '%s' in W3D format", filename); - // Write ChunkType and ChunkSize - if (file.Write(&chunk.chunkType, sizeof(chunk.chunkType)) != sizeof(chunk.chunkType) || - file.Write(&chunkSize, sizeof(chunkSize)) != sizeof(chunkSize)) { - GAMEMODELLOG_ERROR("File '%s': Failed to write chunk header (type: 0x%X).\n", file.Get_File_Name().Str(), chunk.chunkType); - return false; - } - - // Write chunk data (only if there's data to write) - if (chunk.data.size() > 0) { - if (file.Write(chunk.data.data(), chunk.data.size()) != chunk.data.size()) { - GAMEMODELLOG_ERROR("File '%s': Failed to write chunk data (type: 0x%X).\n", file.Get_File_Name().Str(), chunk.chunkType); - return false; - } - } - - // If there are subChunks, write them recursively - if (hasSubchunks) { - if (!Write_W3D_Chunks(file, chunk.subChunks)) { - return false; - } - } + auto_file_ptr file(g_theFileFactory, filename); + if (!file->Open(FileOpenType::FM_WRITE)) { + GAMEMODELLOG_ERROR("Could not open file: %s", filename); + return false; } - + ChunkSaveClass chunkSaver(file); + m_chunkManager->WriteSubchunks(chunkSaver, m_chunkManager->GetRootChunk()); return true; } - -void GameModelFile::Parse_Model_Data(const ChunkInfos& chunks) { - for (const auto& chunk : chunks) { - switch (chunk.chunkType) { - case W3D_CHUNK_MESH: - Parse_Mesh_Chunk(chunk); - break; - case W3D_CHUNK_EMITTER: - Parse_Emitter_Chunk(chunk); - break; - // Add additional cases for other chunk types - default: - GAMEMODELLOG_DEBUG("Ignoring unknown top-level chunk type: 0x%X", chunk.chunkType); - break; - } - } -} - -void GameModelFile::Parse_Mesh_Chunk(const ChunkInfo& meshChunk) { - // Example: Parse Mesh Header - for (const auto& subChunk : meshChunk.subChunks) { - if (subChunk.chunkType == W3D_CHUNK_MESH_HEADER3) { - //Use the helper functions from gamemodelcommon.h - m_meshData.header = ReadFromChunk(subChunk, 0); - break; - } - } - // Parse other mesh subchunks (vertices, normals, triangles, etc.) using similar logic, - // referencing the struct definitions in w3d_file.h and using the helper functions from gamemodelcommon.h - - for (const auto& subChunk : meshChunk.subChunks) { - switch (subChunk.chunkType) { - case W3D_CHUNK_VERTICES: - m_meshData.vertices = Thyme::ReadArrayFromChunk(subChunk); - break; - case W3D_CHUNK_VERTEX_NORMALS: - m_meshData.normals = Thyme::ReadArrayFromChunk(subChunk); - break; - case W3D_CHUNK_TRIANGLES: - m_meshData.triangles = Thyme::ReadArrayFromChunk(subChunk); - break; - case W3D_CHUNK_MESH_HEADER3: -// m_meshData.header = Thyme::ReadFromChunk(subChunk,0); - break; - // ... parse other mesh subchunks ... - default: - break; - } - } -} - -void GameModelFile::Parse_Emitter_Chunk(const ChunkInfo& emitterChunk) { - //Similar logic as ParseMeshChunk, but for emitter chunks and subchunks - for (const auto& subChunk : emitterChunk.subChunks) { - if (subChunk.chunkType == W3D_CHUNK_EMITTER_HEADER) { - m_emitterData.header = ReadFromChunk(subChunk, 0); - } else if (subChunk.chunkType == W3D_CHUNK_EMITTER_INFO) { - m_emitterData.info = ReadFromChunk(subChunk, 0); - } else if (subChunk.chunkType == W3D_CHUNK_EMITTER_INFOV2){ - m_emitterData.infoV2 = ReadFromChunk(subChunk, 0); - } - // ... parse other emitter subchunks ... - } -} - -const ParsedMeshData& GameModelFile::GetMeshData() const { - return m_meshData; -} - -const ParsedEmitterData& GameModelFile::GetEmitterData() const { - return m_emitterData; -} - - void GameModelFile::Log_Line(const char *prefix, const char *format, ...) { FILE *file = s_logfile; diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.h b/src/tools/gamemodelconverter/src/gamemodelfile.h index cb875ba02..ae7dfc748 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.h +++ b/src/tools/gamemodelconverter/src/gamemodelfile.h @@ -14,13 +14,11 @@ */ #pragma once -#include "fileref.h" -#include "gamemodelcommon.h" -#include "utility/array.h" -#include "utility/arrayview.h" #include "utility/ebitflags.h" -#include "utility/enumerator.h" -#include "utility/enumflags.h" +#include "chunksmanager.h" +#include "filesystem.h" +#include + namespace Thyme { @@ -48,8 +46,11 @@ class GameModelFile public: GameModelFile(); + ~GameModelFile(){ + Reset(); + } - // Checks whether model is loaded. + // TODO Checks whether chunks is loaded. bool Is_Loaded() const; // Loads models file from disk. Does not unload previous data on failure. @@ -69,9 +70,6 @@ class GameModelFile // Unloads all data and resets all settings. void Reset(); - // Retrieves all Chunk data. - const ChunkInfos &Get_Chunk_Infos() const; - // Sets options for loading and saving files. void Set_Options(Options options); Options Get_Options() const; @@ -91,69 +89,24 @@ class GameModelFile COUNT, }; - enum class ModelReadStep - { - // TODO ModelReadStep - INITIAL, - HEADER, - CHUNK, - COMPLETE, - }; - - enum class ModelParseResult - { - // TODO ModelParseResult - IS_HEADER, - IS_CHUNK, - IS_NOTHING, - IS_END, - }; - - struct LengthInfo - { - // TODO LengthInfo of chunks - int max_chunk_len; - }; - private: bool Load(const char *filename, FileType filetype); bool Save(const char *filename, FileType filetype); -// void Check_Buffer_Lengths(); -// ChunkInfos &Mutable_Chunk_Infos(); -// static ChunkInfosPtrArray Build_Chunk_Infos_Ptrs_Array(ChunkInfosArray &chunk_infos_array); -// static ConstChunkInfosPtrArray Build_Const_Chunk_Infos_Ptrs_Array( -// ChunkInfosArray &chunk_infos_array); - - static size_t Get_Max_Size(const ConstChunkInfosPtrArray &chunk_infos_ptrs); - static FileType Get_File_Type(const char *filename, FileType filetype); -// static void Collect_Length_Info(LengthInfo &len_info, const ChunkInfos &chunks); -// static void Log_Length_Info(const LengthInfo &len_info); -// static void Assert_Length_Info(const LengthInfo &len_info); - - bool Read_W3D_File(FileRef &file, ChunkInfos &chunk_infos, Options options); - bool Read_W3D_Chunks(FileRef &file, ChunkInfos& parentChunks); - bool Write_W3D_Chunks(FileRef &file, const ChunkInfos& parentChunks); - bool Write_W3D_File(FileRef &file, const ChunkInfos &chunk_infos, Options options); - - void Parse_Model_Data(const ChunkInfos& chunks); - void Parse_Mesh_Chunk(const ChunkInfo& meshChunk); - void Parse_Emitter_Chunk(const ChunkInfo& emitterChunk); - const ParsedMeshData &GetMeshData() const; - const ParsedEmitterData &GetEmitterData() const; + bool Read_W3D_File(const char *filename, const Options& options); + bool Write_W3D_File(const char *filename, const Options& options); static void Log_Line(const char *prefix, const char *format, ...); private: Options m_options; - ChunkInfos m_chunkInfos; static FILE *s_logfile; - ParsedMeshData m_meshData; - ParsedEmitterData m_emitterData; - + ChunkTreePtr m_rootChunk; + ChunkManager * m_chunkManager; + ChunkLoadClass m_chunkLoader; }; } // namespace Thyme From 4abecf6acacd31a7add6bbe22913349ba1ec715c Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Sat, 25 Jan 2025 04:06:42 +0200 Subject: [PATCH 09/13] add chunkfactory and func map --- src/tools/gamemodelconverter/CMakeLists.txt | 1 + .../gamemodelconverter/src/chunkfactory.cpp | 2186 +++++++++++++++++ .../gamemodelconverter/src/chunksmanager.cpp | 445 +--- .../gamemodelconverter/src/chunksmanager.h | 43 +- 4 files changed, 2220 insertions(+), 455 deletions(-) create mode 100644 src/tools/gamemodelconverter/src/chunkfactory.cpp diff --git a/src/tools/gamemodelconverter/CMakeLists.txt b/src/tools/gamemodelconverter/CMakeLists.txt index 61d2fe9a4..8b148099f 100644 --- a/src/tools/gamemodelconverter/CMakeLists.txt +++ b/src/tools/gamemodelconverter/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_CXX_STANDARD 17) set(GAMEMODELCONVERTER_SOURCES src/chunksmanager.cpp src/chunksmanager.h + src/chunkfactory.cpp src/gamemodelcommon.h src/gamemodelfile.cpp src/gamemodelfile.h diff --git a/src/tools/gamemodelconverter/src/chunkfactory.cpp b/src/tools/gamemodelconverter/src/chunkfactory.cpp new file mode 100644 index 000000000..acdea4c66 --- /dev/null +++ b/src/tools/gamemodelconverter/src/chunkfactory.cpp @@ -0,0 +1,2186 @@ +#include "chunksmanager.h" +#include +#include + +// Helper Functions + +char *ReadChunkData(ChunkLoadClass &cload) +{ + if (!cload.Cur_Chunk_Length()) { + char *c = new char[1]; + c[0] = 0; + return c; + } + char *c = new char[cload.Cur_Chunk_Length()]; + cload.Read(c, cload.Cur_Chunk_Length()); + return c; +} + +void AddData(ChunkTreePtr &data, const char *name, const StringClass &type, const StringClass &formattedValue, void *value) +{ + if (data->data->info == nullptr) { + data->data->info = std::move(ChunkManager::createChunkInfo(name, type, formattedValue, value)); + } else { + captainslog_error("ChunkInfo %s already exists, cannot set %s", (const char *)data->data->info->name, name); + } +} + +void AddString(ChunkTreePtr &data, const char *name, const StringClass &value, const StringClass &type) +{ + AddData(data, name, type, value, nullptr); +} + +void AddVersion(ChunkTreePtr &data, uint32_t value) +{ + char c[64]; + sprintf(c, "%u.%hu", value >> 16, (uint16_t)value); + AddData(data, "Version", "uint32_t", c, (void *)&value); +} + +void AddInt32(ChunkTreePtr &data, const char *name, uint32_t value) +{ + char c[256]; + sprintf(c, "%u", value); + AddData(data, name, "uint32_t", c, (void *)&value); +} + +void AddInt16(ChunkTreePtr &data, const char *name, uint16_t value) +{ + char c[256]; + sprintf(c, "%hu", value); + AddData(data, name, "uint16_t", c, (void *)&value); +} + +void AddInt8(ChunkTreePtr &data, const char *name, uint8_t value) +{ + char c[256]; + sprintf(c, "%hhu", value); + AddData(data, name, "uint8_t", c, (void *)&value); +} + +void AddInt8Array(ChunkTreePtr &data, const char *name, const uint8_t *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("%hhu ", values[i]); + str += str2; + } + char c[256]; + sprintf(c, "int8[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void AddFloat(ChunkTreePtr &data, const char *name, float value) +{ + char c[256]; + sprintf(c, "%f", value); + AddData(data, name, "float", c, (void *)&value); +} + +void AddInt32Array(ChunkTreePtr &data, const char *name, const uint32_t *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("%u ", values[i]); + str += str2; + } + char c[256]; + sprintf(c, "int32[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void AddFloatArray(ChunkTreePtr &data, const char *name, const float *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("%f ", values[i]); + str += str2; + } + char c[256]; + sprintf(c, "float[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void AddVector(ChunkTreePtr &data, const char *name, const W3dVectorStruct *value) +{ + char c[256]; + sprintf(c, "%f %f %f", value->x, value->y, value->z); + AddData(data, name, "W3dVectorStruct", c, (void *)value); +} + +void AddQuaternion(ChunkTreePtr &data, const char *name, const W3dQuaternionStruct *value) +{ + char c[256]; + sprintf(c, "%f %f %f %f", value->q[0], value->q[1], value->q[2], value->q[3]); + AddData(data, name, "W3dQuaternionStruct", c, (void *)value); +} + +void AddRGB(ChunkTreePtr &data, const char *name, const W3dRGBStruct *value) +{ + StringClass str; + str.Format("(%hhu %hhu %hhu) ", value->r, value->g, value->b); + AddData(data, name, "W3dRGBStruct", str, (void *)value); +} + +void AddRGBArray(ChunkTreePtr &data, const char *name, const W3dRGBStruct *values, int count) +{ + StringClass str; + StringClass str2; + for (int i = 0; i < count; i++) { + str2.Format("(%hhu %hhu %hhu) ", values[i].r, values[i].g, values[i].b); + str += str2; + } + char c[256]; + sprintf(c, "float[%d]", count); + AddData(data, name, c, str, (void *)values); +} + +void AddRGBA(ChunkTreePtr &data, const char *name, const W3dRGBAStruct *value) +{ + StringClass str; + str.Format("(%hhu %hhu %hhu %hhu) ", value->R, value->G, value->B, value->A); + AddData(data, name, "W3dRGBAStruct", str, (void *)value); +} + +void AddTexCoord(ChunkTreePtr &data, const char *name, const W3dTexCoordStruct *value) +{ + char c[256]; + sprintf(c, "%f %f", value->U, value->V); + AddData(data, name, "W3dTexCoordStruct", c, (void *)value); +} + +void AddTexCoordArray(ChunkTreePtr &data, const char *name, const W3dTexCoordStruct *values, int count) +{ + StringClass str; + for (int i = 0; i < count; i++) { + char c[256]; + sprintf(c, "%s.TexCoord[%d]", name, i); + AddTexCoord(data, c, &values[i]); + } +} + +const char *DepthCompareValues[] = { "Pass Never", + "Pass Less", + "Pass Equal", + "Pass Less or Equal", + "Pass Greater", + "Pass Not Equal", + "Pass Greater or Equal", + "Pass Always" }; + +const char *DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; + +const char *DestBlendValues[] = { "Zero", + "One", + "Src Color", + "One Minus Src Color", + "Src Alpha", + "One Minus Src Alpha", + "Src Color Prefog", + "Disable", + "Enable", + "Scale Fragment", + "Replace Fragment" }; + +const char *PriGradientValues[] = { + "Disable", "Modulate", "Add", "Bump-Environment", "Bump-Environment Luminance", "Modulate 2x" +}; + +const char *SecGradientValues[] = { "Disable", "Enable" }; + +const char *SrcBlendValues[] = { "Zero", "One", "Src Alpha", "One Minus Src Alpha" }; + +const char *TexturingValues[] = { "Disable", "Enable" }; + +const char *DetailColorValues[] = { "Disable", + "Detail", + "Scale", + "InvScale", + "Add", + "Sub", + "SubR", + "Blend", + "DetailBlend", + "Add Signed", + "Add Signed 2x", + "Scale 2x", + "Mod Alpha Add Color" }; + +const char *DetailAlphaValues[] = { "Disable", "Detail", "Scale", "InvScale", "Disable", "Enable", "Smooth", "Flat" }; + +const char *AlphaTestValues[] = { "Alpha Test Disable", "Alpha Test Enable" }; + +void AddShader(ChunkTreePtr &data, const char *name, const W3dShaderStruct *value) +{ + // main shader + AddData(data, name, "W3dShaderStruct", "Main Shader", (void *)value); + char c[256]; + sprintf(c, "%s.DepthCompare", name); + + if (value->DepthCompare < W3DSHADER_DEPTHCOMPARE_PASS_MAX) { + AddString(data, c, DepthCompareValues[value->DepthCompare], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Depth Compare type %x", c, value->DepthCompare); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthCompare); + } + + sprintf(c, "%s.DepthMask", name); + + if (value->DepthMask < W3DSHADER_DEPTHMASK_WRITE_MAX) { + AddString(data, c, DepthMaskValues[value->DepthMask], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Depth Mask type %x", c, value->DepthMask); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthMask); + } + + sprintf(c, "%s.DestBlend", name); + + if (value->DestBlend < W3DSHADER_DESTBLENDFUNC_MAX) { + AddString(data, c, DestBlendValues[value->DestBlend], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Dest Blend type %x", c, value->DestBlend); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DestBlend); + } + + sprintf(c, "%s.PriGradient", name); + + if (value->PriGradient < W3DSHADER_PRIGRADIENT_MAX) { + AddString(data, c, PriGradientValues[value->PriGradient], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Primary Gradient type %x", c, value->PriGradient); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->PriGradient); + } + + sprintf(c, "%s.SecGradient", name); + + if (value->SecGradient < W3DSHADER_SECGRADIENT_MAX) { + AddString(data, c, SecGradientValues[value->SecGradient], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Secondary Gradient type %x", c, value->SecGradient); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->SecGradient); + } + + sprintf(c, "%s.SrcBlend", name); + + if (value->SrcBlend < W3DSHADER_SRCBLENDFUNC_MAX) { + AddString(data, c, SrcBlendValues[value->SrcBlend], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Src Blend type %x", c, value->SrcBlend); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->SrcBlend); + } + + sprintf(c, "%s.Texturing", name); + + if (value->Texturing < W3DSHADER_TEXTURING_MAX) { + AddString(data, c, TexturingValues[value->Texturing], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Texturing type %x", c, value->Texturing); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->Texturing); + } + + sprintf(c, "%s.DetailColor", name); + + if (value->DetailColorFunc < W3DSHADER_DETAILCOLORFUNC_MAX) { + AddString(data, c, DetailColorValues[value->DetailColorFunc], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Detail Color Func type %x", c, value->DetailColorFunc); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailColorFunc); + } + + sprintf(c, "%s.DetailAlpha", name); + + if (value->DetailAlphaFunc < W3DSHADER_DETAILALPHAFUNC_MAX) { + AddString(data, c, DetailAlphaValues[value->DetailAlphaFunc], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Detail Alpha Func type %x", c, value->DetailAlphaFunc); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailAlphaFunc); + } + + sprintf(c, "%s.AlphaTest", name); + + if (value->AlphaTest < W3DSHADER_ALPHATEST_MAX) { + AddString(data, c, AlphaTestValues[value->AlphaTest], "uint8_t"); + } else { + StringClass str; + str.Format("%s Shader unknown Alpha Test type %x", c, value->AlphaTest); + captainslog_warn("Unknown chunk: %s", (const char *)str); + AddData(data, c, "Unknown", "uint8_t", (void *)&value->AlphaTest); + } +} + +const char *PS2DepthCompareValues[] = { "Pass Never", "Pass Less", "Pass Always", "Pass Less or Equal" }; + +const char *PS2DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; + +const char *PS2ABDParamValues[] = { "Src Color", "Dest Color", "Zero" }; + +const char *PS2CParamValues[] = { + "Src Alpha", "Dest Alpha", "One", "Disable", "Enable", "Scale Fragment", "Replace Fragment" +}; + +const char *PS2PriGradientValues[] = { "Disable", "Modulate", "Highlight", "Highlight2", "Disable", "Enable" }; + +const char *PS2TexturingValues[] = { "Disable", + "Enable", + "Disable", + "Detail", + "Scale", + "InvScale", + "Add", + "Sub", + "SubR", + "Blend", + "DetailBlend", + "Disable", + "Detail", + "Scale", + "InvScale", + "Disable", + "Enable", + "Smooth", + "Flat" }; + +void AddPS2Shader(ChunkTreePtr &data, const char *name, const W3dPS2ShaderStruct *value) +{ + // main shader + // TODO check if this is correct and works + AddData(data, name, "W3dPS2ShaderStruct", "Main Shader", (void *)value); + char c[256]; + sprintf(c, "%s.DepthCompare", name); + AddData(data, c, "uint8_t", PS2DepthCompareValues[value->DepthCompare], (void *)&value->DepthCompare); + AddString(data, c, PS2DepthCompareValues[value->DepthCompare], "uint8_t"); + sprintf(c, "%s.DepthMask", name); + AddString(data, c, PS2DepthMaskValues[value->DepthMask], "uint8_t"); + sprintf(c, "%s.PriGradient", name); + AddString(data, c, PS2PriGradientValues[value->PriGradient], "uint8_t"); + sprintf(c, "%s.Texturing", name); + AddString(data, c, PS2TexturingValues[value->Texturing], "uint8_t"); + sprintf(c, "%s.AParam", name); + AddString(data, c, PS2ABDParamValues[value->AParam], "uint8_t"); + sprintf(c, "%s.BParam", name); + AddString(data, c, PS2ABDParamValues[value->BParam], "uint8_t"); + sprintf(c, "%s.CParam", name); + AddString(data, c, PS2CParamValues[value->CParam], "uint8_t"); + sprintf(c, "%s.DParam", name); + AddString(data, c, PS2ABDParamValues[value->DParam], "uint8_t"); +} + +void AddIJK(ChunkTreePtr &data, const char *name, const Vector3i *value) +{ + char c[256]; + sprintf(c, "%d %d %d", value->I, value->J, value->K); + AddData(data, name, "Vector3i", c, (void *)value); +} + +void AddIJK16(ChunkTreePtr &data, const char *name, const Vector3i16 *value) +{ + char c[256]; + sprintf(c, "%d %d %d", value->I, value->J, value->K); + AddData(data, name, "Vector3i16", c, (void *)value); +} + +// Macro for Defining Functions + +#define DUMP_CHUNK(name, type) \ + void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ + { \ + char *chunkdata = ReadChunkData(cload); \ + type *chunkData = (type *)chunkdata; \ + AddData(data, #name, #type, "", (void *)chunkData); \ + delete[] chunkdata; \ + } + +#define DUMP_CHUNK_ARRAY(name, type) \ + void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ + { \ + char *chunkdata = ReadChunkData(cload); \ + type *arrayData = (type *)chunkdata; \ + AddData(data, #name, #type "[]", "", (void *)arrayData); \ + delete[] chunkdata; \ + } + +#define DUMP_CHUNK_PARSER(name) \ + void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ + { \ + AddString(data, #name, "", "string"); \ + ChunkManager::ParseSubchunks(cload, data->subchunks.back()); \ + } + +#define SERIALIZE_CHUNK(name, type) \ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) {} + +#define SERIALIZE_CHUNK_ARRAY(name, type) \ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) {} + +#define SERIALIZE_CHUNK_PARSER(name) \ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) {} + +#define DUMP_SERIALIZE_CHUNK(name, type) \ + DUMP_CHUNK(name, type) \ + SERIALIZE_CHUNK(name, type) + +#define DUMP_SERIALIZE_CHUNK_ARRAY(name, type) \ + DUMP_CHUNK_ARRAY(name, type) \ + SERIALIZE_CHUNK_ARRAY(name, type) + +#define DUMP_SERIALIZE_PARSER(name) \ + DUMP_CHUNK_PARSER(name) \ + SERIALIZE_CHUNK_PARSER(name) + +/* +Replacement: +void Dump_O_W3D_CHUNK_MATERIALS(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dMaterialStruct *arrayData = (W3dMaterialStruct *)chunkdata; + AddData(data, + "O_W3D_CHUNK_MATERIALS", "W3dMaterialStruct" "[]", (void *)arrayData); + delete[] chunkdata; +} +*/ +DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS, W3dMaterialStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS2, W3dMaterial2Struct) +void Dump_O_W3D_C(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + // spilt name from Dump___func__ + const char *name = strstr(__func__, "Dump_") + 5; + AddString(data, name, "", "string"); + data->subchunks = std::vector(1); + ChunkManager::ParseSubchunks(cload, data->subchunks.back()); +} + +void Dump_O_W3D_CHUNK_POV_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + AddString(data, "O_W3D_CHUNK_POV_QUADRANGLES", "unsupported", "string"); +} + +void Serialize_O_W3D_CHUNK_POV_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_O_W3D_CHUNK_POV_QUADRANGLES +} + +void Dump_O_W3D_CHUNK_POV_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + AddString(data, "O_W3D_CHUNK_POV_TRIANGLES", "unsupported", "string"); +} + +void Serialize_O_W3D_CHUNK_POV_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_O_W3D_CHUNK_POV_QUADRANGLES +} + +void Dump_O_W3D_CHUNK_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + AddString(data, "O_W3D_CHUNK_QUADRANGLES", "Outdated", "string"); +} + +void Serialize_O_W3D_CHUNK_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_O_W3D_CHUNK_POV_QUADRANGLES +} + +DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_SURRENDER_TRIANGLES, W3dSurrenderTriangleStruct) + +void Dump_O_W3D_CHUNK_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + AddString(data, "O_W3D_CHUNK_TRIANGLES", "Obsolete", "string"); +} + +void Serialize_O_W3D_CHUNK_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_O_W3D_CHUNK_TRIANGLES +} + +DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_COLOR_KEYFRAME, W3dEmitterColorKeyframeStruct) + +DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_OPACITY_KEYFRAME, W3dEmitterOpacityKeyframeStruct) + +DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_SIZE_KEYFRAME, W3dEmitterSizeKeyframeStruct) + +DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_SHADOW_NODE, W3dHModelNodeStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_AABTREE) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AABTREE_HEADER, W3dMeshAABTreeHeader) + +void Dump_W3D_CHUNK_AABTREE_NODES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dMeshAABTreeNode *nodes = (W3dMeshAABTreeNode *)chunkdata; + // TODO: valid + for (unsigned int i = 0; i < cload.Cur_Chunk_Length() / sizeof(W3dMeshAABTreeNode); i++) { + char c[256]; + sprintf(c, "Node[%d].Min", i); + AddVector(data, c, &nodes[i].Min); + sprintf(c, "Node[%d].Max", i); + AddVector(data, c, &nodes[i].Max); + + if ((nodes[i].FrontOrPoly0 & 0x80000000) == 0) { + sprintf(c, "Node[%d].Front", i); + AddInt32(data, c, nodes[i].FrontOrPoly0); + sprintf(c, "Node[%d].Back", i); + } else { + sprintf(c, "Node[%d].Poly0", i); + AddInt32(data, c, nodes[i].FrontOrPoly0 & 0x7FFFFFFF); + sprintf(c, "Node[%d].PolyCount", i); + } + + AddInt32(data, c, nodes[i].BackOrPolyCount); + } + + AddData(data, "W3D_CHUNK_AABTREE_NODES", "W3dMeshAABTreeNode[]", "", (void *)nodes); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_AABTREE_NODES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_AABTREE_NODES +} + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_POLYINDICES, uint32_t) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_AGGREGATE) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AGGREGATE_CLASS_INFO, W3dAggregateMiscInfo) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AGGREGATE_HEADER, W3dAggregateHeaderStruct) + +void Dump_W3D_CHUNK_AGGREGATE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dAggregateInfoStruct *info = (W3dAggregateInfoStruct *)chunkdata; + AddString(data, "BaseModelName", info->BaseModelName, "string"); + AddInt32(data, "SubobjectCount", info->SubobjectCount); + W3dAggregateSubobjectStruct *subobj = (W3dAggregateSubobjectStruct *)(chunkdata + sizeof(W3dAggregateInfoStruct)); + + for (unsigned int i = 0; i < info->SubobjectCount; i++) { + char c[256]; + sprintf(c, "SubObject[%u].SubobjectName", i); + AddString(data, c, subobj[i].SubobjectName, "string"); + sprintf(c, "SubObject[%u].BoneName", i); + AddString(data, c, subobj[i].BoneName, "string"); + } + // TODO: valid? + AddData(data, "W3D_CHUNK_AGGREGATE_INFO", "W3dAggregateInfoStruct", "", (void *)info); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_AGGREGATE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_AGGREGATE_INFO +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_ANIMATION) + +void Dump_W3D_CHUNK_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)chunkdata; + + AddData(data, "W3D_CHUNK_ANIMATION_CHANNEL", "W3dAnimChannelStruct", "", (void *)channel); + if (channel->Flags <= ANIM_CHANNEL_VIS) { + + StringClass str; + str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_ANIMATION_CHANNEL +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_ANIMATION_HEADER, W3dAnimHeaderStruct) + +void Dump_W3D_CHUNK_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dBitChannelStruct *channel = (W3dBitChannelStruct *)chunkdata; + AddData(data, "W3D_CHUNK_BIT_CHANNEL", "W3dBitChannelStruct", "", (void *)channel); + if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { + StringClass str; + str.Format("W3D_CHUNK_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + delete[] chunkdata; +} +void Serialize_W3D_CHUNK_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_BIT_CHANNEL +} + +void Dump_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dBoxStruct *box = (W3dBoxStruct *)chunkdata; + AddData(data, "W3D_CHUNK_BOX", "W3dBoxStruct", "", (void *)box); + + if (box->Attributes & 4) { + StringClass str; + str.Format("W3D_CHUNK_BOX Unknown Attribute 0x00000004"); + captainslog_warn((const char *)str); + } + + if (box->Attributes & 8) { + StringClass str; + str.Format("W3D_CHUNK_BOX Unknown Attribute 0x00000008"); + captainslog_warn((const char *)str); + } + + if (box->Attributes & 0xFFFFFE00) { + StringClass str; + str.Format("W3D_CHUNK_BOX Unknown Attributes %x", box->Attributes & 0xFFFFFE00); + captainslog_warn((const char *)str); + } + + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_BOX(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_BOX +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_COLLECTION) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_COLLECTION_HEADER, W3dCollectionHeaderStruct) + +void Dump_W3D_CHUNK_COLLECTION_OBJ_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_COLLECTION_OBJ_NAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_COLLECTION_OBJ_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_COLLECTION_OBJ_NAME +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_COLLISION_NODE, W3dHModelNodeStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_DAMAGE) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_COLORS, W3dDamageColorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_HEADER, W3dDamageStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_VERTICES, W3dDamageVertexStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_DAZZLE) + +void Dump_W3D_CHUNK_DAZZLE_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_DAZZLE_NAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_DAZZLE_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_DAZZLE_NAME +} + +void Dump_W3D_CHUNK_DAZZLE_TYPENAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_DAZZLE_TYPENAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_DAZZLE_TYPENAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_DAZZLE_TYPENAME +} + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DCG, W3dRGBAStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DIG, W3dRGBStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_EMITTER) + +void Dump_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dEmitterBlurTimeHeaderStruct *header = (W3dEmitterBlurTimeHeaderStruct *)chunkdata; + AddInt32(data, "KeyframeCount", header->KeyframeCount); + AddFloat(data, "Random", header->Random); + W3dEmitterBlurTimeKeyframeStruct *blurtime = + (W3dEmitterBlurTimeKeyframeStruct *)(chunkdata + sizeof(W3dEmitterBlurTimeHeaderStruct)); + + for (unsigned int i = 0; i < header->KeyframeCount + 1; i++) { + char c[256]; + sprintf(c, "Time[%u]", i); + AddFloat(data, c, blurtime[i].Time); + sprintf(c, "BlurTime[%u]", i); + AddFloat(data, c, blurtime[i].BlurTime); + } + // TODO valid + AddData(data, "W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES", "W3dEmitterBlurTimeKeyframeStruct[]", "", (void *)chunkdata); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES +} + +void Dump_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dEmitterFrameHeaderStruct *header = (W3dEmitterFrameHeaderStruct *)chunkdata; + AddInt32(data, "KeyframeCount", header->KeyframeCount); + AddFloat(data, "Random", header->Random); + W3dEmitterFrameKeyframeStruct *frame = + (W3dEmitterFrameKeyframeStruct *)(chunkdata + sizeof(W3dEmitterFrameHeaderStruct)); + + for (unsigned int i = 0; i < header->KeyframeCount + 1; i++) { + char c[256]; + sprintf(c, "Time[%u]", i); + AddFloat(data, c, frame[i].Time); + sprintf(c, "Frame[%u]", i); + AddFloat(data, c, frame[i].Frame); + } + // TODO valid + AddData(data, "W3D_CHUNK_EMITTER_FRAME_KEYFRAMES", "W3dEmitterFrameKeyframeStruct[]", "", (void *)chunkdata); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_HEADER, W3dEmitterHeaderStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_INFO, W3dEmitterInfoStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_INFOV2, W3dEmitterInfoStructV2) + +void Dump_W3D_CHUNK_EMITTER_PROPS(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dEmitterPropertyStruct *props = (W3dEmitterPropertyStruct *)chunkdata; + AddInt32(data, "ColorKeyframes", props->ColorKeyframes); + AddInt32(data, "OpacityKeyframes", props->OpacityKeyframes); + AddInt32(data, "SizeKeyframes", props->SizeKeyframes); + AddRGBA(data, "ColorRandom", &props->ColorRandom); + AddFloat(data, "OpacityRandom", props->OpacityRandom); + AddFloat(data, "SizeRandom", props->SizeRandom); + W3dEmitterColorKeyframeStruct *color = (W3dEmitterColorKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct)); + + for (unsigned int i = 0; i < props->ColorKeyframes; i++) { + char c[256]; + sprintf(c, "Time[%u]", i); + AddFloat(data, c, color[i].Time); + sprintf(c, "Color[%u]", i); + AddRGBA(data, c, &color[i].Color); + } + + W3dEmitterOpacityKeyframeStruct *opacity = (W3dEmitterOpacityKeyframeStruct *)(chunkdata + + sizeof(W3dEmitterPropertyStruct) + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct))); + + for (unsigned int i = 0; i < props->OpacityKeyframes; i++) { + char c[256]; + sprintf(c, "Time[%u]", i); + AddFloat(data, c, opacity[i].Time); + sprintf(c, "Opacity[%u]", i); + AddFloat(data, c, opacity[i].Opacity); + } + + W3dEmitterSizeKeyframeStruct *size = (W3dEmitterSizeKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct) + + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct)) + + (props->OpacityKeyframes * sizeof(W3dEmitterOpacityKeyframeStruct))); + + for (unsigned int i = 0; i < props->OpacityKeyframes; i++) { + char c[256]; + sprintf(c, "Time[%u]", i); + AddFloat(data, c, size[i].Time); + sprintf(c, "Size[%u]", i); + AddFloat(data, c, size[i].Size); + } + // TODO valid + AddData(data, "W3D_CHUNK_EMITTER_PROPS", "W3dEmitterPropertyStruct", "", (void *)chunkdata); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_EMITTER_PROPS(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_EMITTER_PROPS +} + +void Dump_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dEmitterRotationHeaderStruct *header = (W3dEmitterRotationHeaderStruct *)chunkdata; + AddInt32(data, "KeyframeCount", header->KeyframeCount); + AddFloat(data, "Random", header->Random); + AddFloat(data, "OrientationRandom", header->OrientationRandom); + W3dEmitterRotationKeyframeStruct *frame = + (W3dEmitterRotationKeyframeStruct *)(chunkdata + sizeof(W3dEmitterRotationHeaderStruct)); + + for (unsigned int i = 0; i < header->KeyframeCount + 1; i++) { + char c[256]; + sprintf(c, "Time[%u]", i); + AddFloat(data, c, frame[i].Time); + sprintf(c, "Rotation[%u]", i); + AddFloat(data, c, frame[i].Rotation); + } + // TODO valid + AddData(data, "W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES", "W3dEmitterRotationKeyframeStruct[]", "", (void *)chunkdata); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES +} + +void Dump_W3D_CHUNK_EMITTER_USER_DATA(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_EMITTER_USER_DATA", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_EMITTER_USER_DATA(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_EMITTER_USER_DATA +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_FAR_ATTENUATION, W3dLightAttenuationStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_HIERARCHY) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HIERARCHY_HEADER, W3dHierarchyStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD_AGGREGATE_ARRAY) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HLOD_HEADER, W3dHLodHeaderStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD_LOD_ARRAY) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER, W3dHLodArrayHeaderStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD_PROXY_ARRAY) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT, W3dHLodSubObjectStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_HMODEL) + +DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_HMODEL_AUX_DATA, W3dHModelAuxDataStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HMODEL_HEADER, W3dHModelHeaderStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_LIGHT) + +void Dump_W3D_CHUNK_LIGHT_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dLightStruct *light = (W3dLightStruct *)chunkdata; + int type = light->Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK; + if (type == W3D_LIGHT_ATTRIBUTE_POINT) { + } else if (type == W3D_LIGHT_ATTRIBUTE_SPOT) { + } else if (type == W3D_LIGHT_ATTRIBUTE_DIRECTIONAL) { + } else { + StringClass str; + str.Format("W3D_CHUNK_LIGHT_INFO Unknown Light Type %x", type); + captainslog_warn((const char *)str); + } + + if (light->Attributes & 0xFFFFFE00) { + StringClass str; + str.Format("W3D_CHUNK_LIGHT_INFO Unknown Light Flags %x", light->Attributes & 0xFFFFFE00); + captainslog_warn((const char *)str); + } + AddData(data, "W3D_CHUNK_LIGHT_INFO", "W3dLightStruct", "", (void *)chunkdata); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_LIGHT_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_LIGHT_INFO +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LIGHT_TRANSFORM, W3dLightTransformStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_LIGHTSCAPE) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_LIGHTSCAPE_LIGHT) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LOD, W3dLODStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_LODMODEL) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LODMODEL_HEADER, W3dLODModelHeaderStruct) + +void Dump_W3D_CHUNK_MAP3_FILENAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_MAP3_FILENAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_MAP3_FILENAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_MAP3_FILENAME +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MAP3_INFO, W3dMap3Struct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MATERIAL_INFO, W3dMaterialInfoStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL_PASS) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_DC_MAP) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_DI_MAP) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MATERIAL3_INFO, W3dMaterial3Struct) + +void Dump_W3D_CHUNK_MATERIAL3_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_MATERIAL3_NAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_MATERIAL3_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_MATERIAL3_NAME +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_SC_MAP) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_SI_MAP) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIALS3) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MESH) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MESH_HEADER, W3dMeshHeaderStruct) + +void Dump_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dMeshHeader3Struct *header = (W3dMeshHeader3Struct *)chunkdata; + int type = header->Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK; + switch (type) { + case W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL: + break; + case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED: + break; + case W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN: + break; + case OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW: + break; + case W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX: + break; + case W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX: + break; + case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED: + break; + case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_Z_ORIENTED: + break; + default: { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Mesh Type %x", type); + captainslog_warn((const char *)str); + break; + } + } + + if (header->Attributes & 0x00000800) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Attribute 0x00000800"); + captainslog_warn((const char *)str); + } + + char c[64]; + + if (header->Attributes & W3D_MESH_FLAG_PRELIT_MASK) { + if (header->PrelitVersion) { + } else { + sprintf(c, "UNKNOWN"); + } + } else { + sprintf(c, "N/A"); + } + // AddString(data, "PrelitVersion", c, "string"); + // TODO valid + captainslog_warn((const char *)"str"); + + if (header->VertexChannels & 0xFFFFFF00) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Vertex Channels %x", header->VertexChannels); + captainslog_warn((const char *)str); + } + + if (header->FaceChannels & 0xFFFFFFFE) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Face Channels %x", header->FaceChannels); + captainslog_warn((const char *)str); + } + AddData(data, "W3D_CHUNK_MESH_HEADER3", "W3dMeshHeader3Struct", "", (void *)header); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_MESH_HEADER3 +} + +void Dump_W3D_CHUNK_MESH_USER_TEXT(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_MESH_USER_TEXT", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_MESH_USER_TEXT(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_MESH_USER_TEXT +} + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NEAR_ATTENUATION, W3dLightAttenuationStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NODE, W3dHModelNodeStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NULL_OBJECT, W3dNullObjectStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PER_FACE_TEXCOORD_IDS, Vector3i) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PER_TRI_MATERIALS, uint16_t) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PIVOT_FIXUPS, W3dPivotFixupStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PIVOTS, W3dPivotStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_PLACEHOLDER, W3dPlaceholderStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_POINTS, W3dVectorStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_UNLIT) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_VERTEX) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PS2_SHADERS, W3dPS2ShaderStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SCG, W3dRGBStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHADER_IDS, uint32_t) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHADERS, W3dShaderStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SKIN_NODE, W3dHModelNodeStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO, W3dSpotLightStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO_5_0, W3dSpotLightStruct_v5_0) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_STAGE_TEXCOORDS, W3dTexCoordStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SURRENDER_NORMALS, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXCOORDS, W3dTexCoordStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURE) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXTURE_IDS, uint32_t) + +void Dump_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dTextureInfoStruct *info = (W3dTextureInfoStruct *)chunkdata; + + int hint = info->Attributes & 0xF00; + + if (hint == W3DTEXTURE_HINT_BASE) { + } else if (hint == W3DTEXTURE_HINT_EMISSIVE) { + } else if (hint == W3DTEXTURE_HINT_ENVIRONMENT) { + } else if (hint == W3DTEXTURE_HINT_SHINY_MASK) { + } else { + StringClass str; + str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Hints %x", hint); + captainslog_warn((const char *)str); + } + + if (info->Attributes & 0xE000) { + StringClass str; + str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Flags %x", info->Attributes & 0xE000); + captainslog_warn((const char *)str); + } + + if (info->AnimType == W3DTEXTURE_ANIM_LOOP) { + } else if (info->AnimType == W3DTEXTURE_ANIM_PINGPONG) { + } else if (info->AnimType == W3DTEXTURE_ANIM_ONCE) { + } else if (info->AnimType == W3DTEXTURE_ANIM_MANUAL) { + } else { + StringClass str; + str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Anim Type %x", info->AnimType); + captainslog_warn((const char *)str); + } + + AddData(data, "W3D_CHUNK_TEXTURE_INFO", "W3dTextureInfoStruct", "", (void *)info); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_TEXTURE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_TEXTURE_INFO +} + +void Dump_W3D_CHUNK_TEXTURE_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_TEXTURE_NAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_TEXTURE_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_TEXTURE_NAME +} + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXTURE_REPLACER_INFO, W3dTextureReplacerStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURE_STAGE) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURES) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_TRANSFORM_NODE, W3dPlaceholderStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TRIANGLES, W3dTriStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_COLORS, W3dRGBStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_INFLUENCES, W3dVertInfStruct) + +void Dump_W3D_CHUNK_VERTEX_MAPPER_ARGS0(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_VERTEX_MAPPER_ARGS0", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS0(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS0 +} + +void Dump_W3D_CHUNK_VERTEX_MAPPER_ARGS1(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_VERTEX_MAPPER_ARGS1", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS1(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS1 +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_VERTEX_MATERIAL) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_MATERIAL_IDS, uint32_t) + +void Dump_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dVertexMaterialStruct *material = (W3dVertexMaterialStruct *)chunkdata; + + if (material->Attributes & 0x00000010) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000010"); + captainslog_warn((const char *)str); + } + + if (material->Attributes & 0x00000020) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000020"); + captainslog_warn((const char *)str); + } + + if (material->Attributes & 0x00000040) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000040"); + captainslog_warn((const char *)str); + } + + if (material->Attributes & 0x00000080) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000080"); + captainslog_warn((const char *)str); + } + + if ((material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK) == W3DVERTMAT_STAGE0_MAPPING_UV) { + AddString(data, "Material.Attributes", "W3DVERTMAT_STAGE0_MAPPING_UV", "flag"); + } + + if ((material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK) > W3DVERTMAT_STAGE0_MAPPING_GRID_WS_ENVIRONMENT) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Stage 0 Mapper %x", + material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK); + captainslog_warn((const char *)str); + } + + if ((material->Attributes & W3DVERTMAT_STAGE1_MAPPING_MASK) > W3DVERTMAT_STAGE1_MAPPING_GRID_WS_ENVIRONMENT) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Stage 1 Mapper %x", + material->Attributes & W3DVERTMAT_STAGE1_MAPPING_MASK); + captainslog_warn((const char *)str); + } + + if (material->Attributes & W3DVERTMAT_PSX_MASK) { + if (material->Attributes & 0xF0000000) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown PSX material flag %x", material->Attributes & 0xF0000000); + captainslog_warn((const char *)str); + } + } + AddData(data, "W3D_CHUNK_VERTEX_MATERIAL_INFO", "W3dVertexMaterialStruct", "", (void *)material); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MATERIAL_INFO +} + +void Dump_W3D_CHUNK_VERTEX_MATERIAL_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_VERTEX_MATERIAL_NAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_VERTEX_MATERIAL_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MATERIAL_NAME +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_VERTEX_MATERIALS) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_NORMALS, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_SHADE_INDICES, uint32_t) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTICES, W3dVectorStruct) + +void Dump_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dEmitterLinePropertiesStruct *props = (W3dEmitterLinePropertiesStruct *)chunkdata; + + if (props->Flags & 0x00FFFFF0) { + StringClass str; + str.Format("W3D_CHUNK_EMITTER_LINE_PROPERTIES Unknown Emitter Line Properties flags %x", props->Flags & 0x00FFFFF0); + captainslog_warn((const char *)str); + } + + int mapmode = props->Flags >> W3D_ELINE_TEXTURE_MAP_MODE_OFFSET; + + switch (mapmode) { + case W3D_ELINE_UNIFORM_WIDTH_TEXTURE_MAP: + break; + case W3D_ELINE_UNIFORM_LENGTH_TEXTURE_MAP: + break; + case W3D_ELINE_TILED_TEXTURE_MAP: + break; + default: { + StringClass str; + str.Format("W3D_CHUNK_EMITTER_LINE_PROPERTIES Unknown Emitter Mapping Mode %x", mapmode); + captainslog_warn((const char *)str); + break; + } + } + AddData(data, "W3D_CHUNK_EMITTER_LINE_PROPERTIES", "W3dEmitterLinePropertiesStruct", "", (void *)props); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_EMITTER_LINE_PROPERTIES +} + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTICES, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTEX_NORMALS, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TANGENTS, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_BINORMALS, W3dVectorStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_COMPRESSED_ANIMATION) + +int flavor = ANIM_FLAVOR_TIMECODED; +const char *FlavorTypes[] = { "Timecoded", "Adaptive Delta" }; + +void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dCompressedAnimHeaderStruct *header = (W3dCompressedAnimHeaderStruct *)chunkdata; + if (header->Flavor < ANIM_FLAVOR_VALID) { + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_HEADER Unknown Flavor Type %x", header->Flavor); + captainslog_warn((const char *)str); + } + + flavor = header->Flavor; + AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_HEADER", "W3dCompressedAnimHeaderStruct", "", (void *)header); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER +} + +void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + + if (flavor == ANIM_FLAVOR_TIMECODED) { + W3dTimeCodedAnimChannelStruct *channel = (W3dTimeCodedAnimChannelStruct *)chunkdata; + + if (channel->Flags <= ANIM_CHANNEL_VIS) { + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + + delete[] chunkdata; + } else { + W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)chunkdata; + + if (channel->Flags <= ANIM_CHANNEL_VIS) { + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + + delete[] chunkdata; + } + // TODO valid + // AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL", "char*", "", (void *)channel); +} + +void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL +} + +void Dump_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)chunkdata; + + if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + AddData(data, "W3D_CHUNK_COMPRESSED_BIT_CHANNEL", "W3dTimeCodedBitChannelStruct", "", (void *)channel); + + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_BIT_CHANNEL +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MORPH_ANIMATION) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MORPHANIM_HEADER, W3dMorphAnimHeaderStruct) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_MORPHANIM_CHANNEL) + +void Dump_W3D_CHUNK_MORPHANIM_POSENAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_MORPHANIM_POSENAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_MORPHANIM_POSENAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_MORPHANIM_POSENAME +} + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_KEYDATA, W3dMorphAnimKeyStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA, uint32_t) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_SOUNDROBJ) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SOUNDROBJ_HEADER, W3dSoundRObjHeaderStruct) + +#define READ_FLOAT(id, name) \ + case id: { \ + float f; \ + cload.Read(&f, sizeof(f)); \ + AddFloat(data, #name, f); \ + break; \ + } + +#define READ_INT(id, name) \ + case id: { \ + int i; \ + cload.Read(&i, sizeof(i)); \ + AddInt32(data, #name, i); \ + break; \ + } + +#define READ_BOOL(id, name) \ + case id: { \ + bool b; \ + cload.Read(&b, sizeof(b)); \ + AddInt8(data, #name, b); \ + break; \ + } + +#define READ_VECTOR(id, name) \ + case id: { \ + Vector3 v; \ + cload.Read(&v, sizeof(v)); \ + W3dVectorStruct v2; \ + v2.x = v.X; \ + v2.y = v.Y; \ + v2.z = v.Z; \ + AddVector(data, #name, &v2); \ + break; \ + } + +#define READ_STRING(id, name) \ + case id: { \ + StringClass str; \ + cload.Read(str.Get_Buffer(cload.Cur_Micro_Chunk_Length()), cload.Cur_Micro_Chunk_Length()); \ + AddString(data, #name, str, "String"); \ + break; \ + } + +void Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + while (cload.Open_Chunk()) { + switch (cload.Cur_Chunk_ID()) { + case 0x100: + while (cload.Open_Micro_Chunk()) { + switch (cload.Cur_Micro_Chunk_ID()) { + READ_FLOAT(3, m_Priority); + READ_FLOAT(4, m_Volume); + READ_FLOAT(5, m_Pan); + READ_INT(6, m_LoopCount); + READ_FLOAT(7, m_DropoffRadius); + READ_FLOAT(8, m_MaxVolRadius); + READ_INT(9, m_Type); + READ_BOOL(10, m_Is3DSound); + READ_STRING(11, m_Filename); + READ_STRING(12, m_DisplayText); + READ_FLOAT(18, m_StartOffset); + READ_FLOAT(19, m_PitchFactor); + READ_FLOAT(20, m_PitchFactorRandomizer); + READ_FLOAT(21, m_VolumeRandomizer); + READ_INT(22, m_VirtualChannel); + READ_INT(13, m_LogicalType); + READ_FLOAT(14, m_LogicalNotifDelay); + READ_BOOL(15, m_CreateLogicalSound); + READ_FLOAT(16, m_LogicalDropoffRadius); + READ_VECTOR(17, m_SphereColor); + } + cload.Close_Micro_Chunk(); + } + break; + case 0x200: + while (cload.Open_Chunk()) { + if (cload.Cur_Chunk_ID() == 0x100) { + while (cload.Open_Micro_Chunk()) { + switch (cload.Cur_Micro_Chunk_ID()) { + READ_INT(1, m_ID); + READ_STRING(3, m_Name); + } + cload.Close_Micro_Chunk(); + } + } + cload.Close_Chunk(); + } + break; + } + cload.Close_Chunk(); + } +} + +void Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION +} + +void DoVector3Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) +{ + int i = 0; + + for (; cload.Open_Chunk(); cload.Close_Chunk()) { + if (cload.Cur_Chunk_ID() == 51709961) { // PrimitiveAnimationChannelClass + for (; cload.Open_Micro_Chunk(); cload.Close_Micro_Chunk()) { + if (cload.Cur_Micro_Chunk_ID() == 1) { + Vector3 value; + float time; + cload.Read(&value, sizeof(value)); + cload.Read(&time, sizeof(time)); + StringClass str; + str.Format("%s[%d].Value.X", name, i); + AddFloat(data, str, value.X); + str.Format("%s[%d].Value.Y", name, i); + AddFloat(data, str, value.Y); + str.Format("%s[%d].Value.Z", name, i); + AddFloat(data, str, value.Z); + str.Format("%s[%d].time", name, i); + AddFloat(data, str, time); + i++; + } + } + } + } +} + +void Serialize_DoVector3Channel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) +{ + // TODO: Implement Serialize_DoVector3Channel +} + +void DoVector2Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) +{ + int i = 0; + + for (; cload.Open_Chunk(); cload.Close_Chunk()) { + if (cload.Cur_Chunk_ID() == 51709961) { // PrimitiveAnimationChannelClass + for (; cload.Open_Micro_Chunk(); cload.Close_Micro_Chunk()) { + if (cload.Cur_Micro_Chunk_ID() == 1) { + Vector2 value; + float time; + cload.Read(&value, sizeof(value)); + cload.Read(&time, sizeof(time)); + StringClass str; + str.Format("%s[%d].Value.X", name, i); + AddFloat(data, str, value.X); + str.Format("%s[%d].Value.Y", name, i); + AddFloat(data, str, value.Y); + str.Format("%s[%d].time", name, i); + AddFloat(data, str, time); + i++; + } + } + } + } +} + +void Serialize_DoVector2Channel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) +{ + // TODO: Implement Serialize_DoVector2Channel +} + +void DofloatChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) +{ + int i = 0; + + for (; cload.Open_Chunk(); cload.Close_Chunk()) { + if (cload.Cur_Chunk_ID() == 51709961) { // PrimitiveAnimationChannelClass + for (; cload.Open_Micro_Chunk(); cload.Close_Micro_Chunk()) { + if (cload.Cur_Micro_Chunk_ID() == 1) { + float value; + float time; + cload.Read(&value, sizeof(value)); + cload.Read(&time, sizeof(time)); + StringClass str; + str.Format("%s[%d].Value", name, i); + AddFloat(data, str, value); + str.Format("%s[%d].time", name, i); + AddFloat(data, str, time); + i++; + } + } + } + } +} + +void Serialize_DofloatChannel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) +{ + // TODO: Implement Serialize_DofloatChannel +} + +void DoAlphaVectorStructChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) +{ + int i = 0; + + for (; cload.Open_Chunk(); cload.Close_Chunk()) { + if (cload.Cur_Chunk_ID() == 51709961) { // PrimitiveAnimationChannelClass + for (; cload.Open_Micro_Chunk(); cload.Close_Micro_Chunk()) { + if (cload.Cur_Micro_Chunk_ID() == 1) { + AlphaVectorStruct value; + float time; + cload.Read(&value, sizeof(value)); + cload.Read(&time, sizeof(time)); + StringClass str; + str.Format("%s[%d].Value.Quat.X", name, i); + AddFloat(data, str, value.Quat.X); + str.Format("%s[%d].Value.Quat.Y", name, i); + AddFloat(data, str, value.Quat.Y); + str.Format("%s[%d].Value.Quat.Z", name, i); + AddFloat(data, str, value.Quat.Z); + str.Format("%s[%d].Value.Quat.W", name, i); + AddFloat(data, str, value.Quat.W); + str.Format("%s[%d].Value.Magnitude", name, i); + AddFloat(data, str, value.Magnitude); + str.Format("%s[%d].time", name, i); + AddFloat(data, str, time); + i++; + } + } + } + } +} + +void Serialize_DoAlphaVectorStructChannel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) +{ + // TODO: Implement Serialize_DoAlphaVectorStructChannel +} + +void Dump_W3D_CHUNK_RING(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + while (cload.Open_Chunk()) { + switch (cload.Cur_Chunk_ID()) { + case 1: { + W3dRingStruct RingStruct; + cload.Read(&RingStruct, sizeof(RingStruct)); + AddInt32(data, "unk0", RingStruct.unk0); + AddInt32(data, "Flags", RingStruct.Flags); + + if (RingStruct.Flags & RING_CAMERA_ALIGNED) { + AddString(data, "Flags", "RING_CAMERA_ALIGNED", "flag"); + } + + if (RingStruct.Flags & RING_LOOPING) { + AddString(data, "Flags", "RING_LOOPING", "flag"); + } + + if (RingStruct.Flags & 0xFFFFFFFC) { + StringClass str; + str.Format("W3D_CHUNK_RING Unknown Ring Flags %x", RingStruct.Flags & 0xFFFFFFFC); + captainslog_warn((const char *)str); + } + + AddString(data, "Name", RingStruct.Name, "string"); + AddVector(data, "Center", &RingStruct.Center); + AddVector(data, "Extent", &RingStruct.Extent); + AddFloat(data, "AnimationDuration", RingStruct.AnimationDuration); + AddVector(data, "Color", &RingStruct.Color); + AddFloat(data, "Alpha", RingStruct.Alpha); + AddFloat(data, "InnerScale.X", RingStruct.InnerScale.x); + AddFloat(data, "InnerScale.Y", RingStruct.InnerScale.y); + AddFloat(data, "OuterScale.X", RingStruct.OuterScale.x); + AddFloat(data, "OuterScale.Y", RingStruct.OuterScale.y); + AddFloat(data, "InnerExtent.X", RingStruct.InnerExtent.x); + AddFloat(data, "InnerExtent.Y", RingStruct.InnerExtent.y); + AddFloat(data, "OuterExtent.X", RingStruct.OuterExtent.x); + AddFloat(data, "OuterExtent.Y", RingStruct.OuterExtent.y); + AddString(data, "TextureName", RingStruct.TextureName, "string"); + AddShader(data, "Shader", &RingStruct.Shader); + AddInt32(data, "TextureTiling", RingStruct.TextureTiling); + break; + } + case 2: + DoVector3Channel(cload, data, "ColorChannel"); + break; + case 3: + DofloatChannel(cload, data, "AlphaChannel"); + break; + case 4: + DoVector2Channel(cload, data, "InnerScaleChannel"); + break; + case 5: + DoVector2Channel(cload, data, "OuterScaleChannel"); + break; + } + cload.Close_Chunk(); + } +} + +void Serialize_W3D_CHUNK_RING(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_RING +} + +void Dump_W3D_CHUNK_SPHERE(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + while (cload.Open_Chunk()) { + switch (cload.Cur_Chunk_ID()) { + case 1: { + W3dSphereStruct SphereStruct; + cload.Read(&SphereStruct, sizeof(SphereStruct)); + AddInt32(data, "unk0", SphereStruct.unk0); + AddInt32(data, "Flags", SphereStruct.Flags); + if (SphereStruct.Flags & SPHERE_ALPHA_VECTOR) { + AddString(data, "Flags", "SPHERE_ALPHA_VECTOR", "flag"); + } + if (SphereStruct.Flags & SPHERE_CAMERA_ALIGNED) { + AddString(data, "Flags", "SPHERE_CAMERA_ALIGNED", "flag"); + } + if (SphereStruct.Flags & SPHERE_INVERT_EFFECT) { + AddString(data, "Flags", "SPHERE_INVERT_EFFECT", "flag"); + } + if (SphereStruct.Flags & SPHERE_LOOPING) { + AddString(data, "Flags", "SPHERE_LOOPING", "flag"); + } + if (SphereStruct.Flags & 0xFFFFFFF0) { + StringClass str; + str.Format("W3D_CHUNK_SPHERE Unknown Sphere Flags %x", SphereStruct.Flags & 0xFFFFFFFC); + captainslog_warn((const char *)str); + } + AddString(data, "Name", SphereStruct.Name, "string"); + AddVector(data, "Center", &SphereStruct.Center); + AddVector(data, "Extent", &SphereStruct.Extent); + AddFloat(data, "AnimationDuration", SphereStruct.AnimationDuration); + AddVector(data, "Color", &SphereStruct.Color); + AddFloat(data, "Alpha", SphereStruct.Alpha); + AddVector(data, "Scale", &SphereStruct.Scale); + AddFloat(data, "Vector.Quat.X", SphereStruct.Vector.Quat.X); + AddFloat(data, "Vector.Quat.Y", SphereStruct.Vector.Quat.Y); + AddFloat(data, "Vector.Quat.Z", SphereStruct.Vector.Quat.Z); + AddFloat(data, "Vector.Quat.W", SphereStruct.Vector.Quat.W); + AddFloat(data, "Vector.Magnutide", SphereStruct.Vector.Magnitude); + AddString(data, "TextureName", SphereStruct.TextureName, "string"); + AddShader(data, "Shader", &SphereStruct.Shader); + } break; + case 2: + DoVector3Channel(cload, data, "ColorChannel"); + break; + case 3: + DofloatChannel(cload, data, "AlphaChannel"); + break; + case 4: + DoVector3Channel(cload, data, "ScaleChannel"); + break; + case 5: + DoAlphaVectorStructChannel(cload, data, "VectorChannel"); + break; + } + cload.Close_Chunk(); + } +} + +void Serialize_W3D_CHUNK_SPHERE(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_SPHERE +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDMESH) + +void Dump_W3D_CHUNK_SHDMESH_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_SHDMESH_NAME", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_SHDMESH_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_SHDMESH_NAME +} + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDSUBMESH) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDSUBMESH_SHADER) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SHDSUBMESH_SHADER_TYPE, uint32_t) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTICES, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTEX_NORMALS, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TRIANGLES, Vector3i16) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTEX_SHADE_INDICES, uint32_t) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_UV0, W3dTexCoordStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_UV1, W3dTexCoordStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_S, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_T, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_SXT, W3dVectorStruct) + +DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_EXTRA_INFO, W3dEmitterExtraInfoStruct) + +void Dump_W3D_CHUNK_SHDMESH_USER_TEXT(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + AddString(data, "W3D_CHUNK_SHDMESH_USER_TEXT", chunkdata, "string"); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_SHDMESH_USER_TEXT(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_SHDMESH_USER_TEXT +} + +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_FXSHADER_IDS, uint32_t) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_FX_SHADERS) + +DUMP_SERIALIZE_PARSER(W3D_CHUNK_FX_SHADER) + +void Dump_W3D_CHUNK_FX_SHADER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + uint8_t *version = (uint8_t *)chunkdata; + AddInt8(data, "Version", *version); + W3dFXShaderStruct *shader = (W3dFXShaderStruct *)(chunkdata + 1); + AddString(data, "ShaderName", shader->shadername, "string"); + AddInt8(data, "Technique", shader->technique); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_FX_SHADER_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_FX_SHADER_INFO +} + +const char *Types[] = { "Texture", "Float", "Vector2", "Vector3", "Vector4", "Int", "Bool" }; + +void Dump_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + uint32_t type = *(uint32_t *)chunkdata; + uint32_t length = *(uint32_t *)(chunkdata + 4); + char *constantname = (char *)(chunkdata + 4 + 4); + AddString(data, "Type", Types[type - 1], "String"); + AddString(data, "Constant Name", constantname, "String"); + + if (type == CONSTANT_TYPE_TEXTURE) { + char *texture = (char *)(chunkdata + 4 + 4 + length + 4); + AddString(data, "Texture", texture, "String"); + } else if (type >= CONSTANT_TYPE_FLOAT1 && type <= CONSTANT_TYPE_FLOAT4) { + int count = type - 1; + float *floats = (float *)(chunkdata + 4 + 4 + length); + AddFloatArray(data, "Floats", floats, count); + } else if (type == CONSTANT_TYPE_INT) { + uint32_t u = *(uint32_t *)(chunkdata + 4 + 4 + length); + AddInt32(data, "Int", u); + } else if (type == CONSTANT_TYPE_BOOL) { + uint8_t u = *(uint8_t *)(chunkdata + 4 + 4 + length); + AddInt32(data, "Bool", u); + } else { + StringClass str; + str.Format("W3D_CHUNK_FX_SHADER_CONSTANT Unknown Constant Type %x", type); + captainslog_warn((const char *)str); + } + + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_FX_SHADER_CONSTANT +} +const char *NewFlavorTypes[] = { "Timecoded", "Adaptive Delta 4", "Adaptive Delta 8" }; + +void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dCompressedMotionChannelStruct *channel = (W3dCompressedMotionChannelStruct *)chunkdata; + + if (channel->Flavor < ANIM_FLAVOR_NEW_VALID) { + AddString(data, "Flavor", NewFlavorTypes[channel->Flavor], "string"); + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Flavor Type %x", channel->Flavor); + captainslog_warn((const char *)str); + } + + AddInt8(data, "VectorLen", channel->VectorLen); + + if (channel->Flags <= ANIM_CHANNEL_VIS) { + // AddString(data, "ChannelType", ChannelTypes[channel->Flags], "string"); + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + + AddInt32(data, "NumTimeCodes", channel->NumTimeCodes); + AddInt16(data, "Pivot", channel->Pivot); + + if (channel->Flavor == ANIM_FLAVOR_NEW_TIMECODED) { + uint16_t *keyframes = (uint16_t *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct)); + + for (int i = 0; i < channel->NumTimeCodes; i++) { + StringClass str; + str.Format("KeyFrames[%d]", i); + AddInt32(data, str, keyframes[i]); + } + + int datalen = channel->VectorLen * channel->NumTimeCodes; + int pos = sizeof(W3dCompressedMotionChannelStruct); + pos += channel->NumTimeCodes * 2; + + if (channel->NumTimeCodes & 1) { + pos += 2; + } + + uint32_t *values = (uint32_t *)(chunkdata + pos); + + for (int i = 0; i < datalen; i++) { + StringClass str; + str.Format("Data[%d]", i); + AddInt32(data, str, values[i]); + } + } else { + float *scale = (float *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct)); + AddFloat(data, "Scale", *scale); + float *initial = (float *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct) + 4); + + for (int i = 0; i < channel->VectorLen; i++) { + StringClass str; + str.Format("Initial[%d]", i); + AddFloat(data, str, initial[i]); + } + + int count = (cload.Cur_Chunk_Length() - sizeof(W3dCompressedMotionChannelStruct) - 4 - 4 * channel->VectorLen) / 4; + uint32_t *values = (uint32_t *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct) + 4 + 4 * channel->VectorLen); + + for (int i = 0; i < count; i++) { + StringClass str; + str.Format("Data[%d]", i); + AddInt32(data, str, values[i]); + } + } + + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL +} + +std::map chunkFuncMap; + +#define CHUNK(id) \ + { \ + ChunkIOFuncs c; \ + c.name = #id; \ + c.ReadFunc = Dump_##id; \ + c.WriteFunc = Serialize_##id; \ + chunkFuncMap[id] = c; \ + } + +void ChunkManager::InitiateChunkFuncMap() +{ + CHUNK(O_W3D_CHUNK_MATERIALS) + CHUNK(O_W3D_CHUNK_MATERIALS2) + CHUNK(O_W3D_CHUNK_POV_QUADRANGLES) + CHUNK(O_W3D_CHUNK_POV_TRIANGLES) + CHUNK(O_W3D_CHUNK_QUADRANGLES) + CHUNK(O_W3D_CHUNK_SURRENDER_TRIANGLES) + CHUNK(O_W3D_CHUNK_TRIANGLES) + CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_COLOR_KEYFRAME) + CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_OPACITY_KEYFRAME) + CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_SIZE_KEYFRAME) + CHUNK(OBSOLETE_W3D_CHUNK_SHADOW_NODE) + CHUNK(W3D_CHUNK_AABTREE) + CHUNK(W3D_CHUNK_AABTREE_HEADER) + CHUNK(W3D_CHUNK_AABTREE_NODES) + CHUNK(W3D_CHUNK_AABTREE_POLYINDICES) + CHUNK(W3D_CHUNK_AGGREGATE) + CHUNK(W3D_CHUNK_AGGREGATE_CLASS_INFO) + CHUNK(W3D_CHUNK_AGGREGATE_HEADER) + CHUNK(W3D_CHUNK_AGGREGATE_INFO) + CHUNK(W3D_CHUNK_ANIMATION) + CHUNK(W3D_CHUNK_ANIMATION_CHANNEL) + CHUNK(W3D_CHUNK_ANIMATION_HEADER) + CHUNK(W3D_CHUNK_BIT_CHANNEL) + CHUNK(W3D_CHUNK_BOX) + CHUNK(W3D_CHUNK_COLLECTION) + CHUNK(W3D_CHUNK_COLLECTION_HEADER) + CHUNK(W3D_CHUNK_COLLECTION_OBJ_NAME) + CHUNK(W3D_CHUNK_COLLISION_NODE) + CHUNK(W3D_CHUNK_DAMAGE) + CHUNK(W3D_CHUNK_DAMAGE_COLORS) + CHUNK(W3D_CHUNK_DAMAGE_HEADER) + CHUNK(W3D_CHUNK_DAMAGE_VERTICES) + CHUNK(W3D_CHUNK_DAZZLE) + CHUNK(W3D_CHUNK_DAZZLE_NAME) + CHUNK(W3D_CHUNK_DAZZLE_TYPENAME) + CHUNK(W3D_CHUNK_DCG) + CHUNK(W3D_CHUNK_DIG) + CHUNK(W3D_CHUNK_EMITTER) + CHUNK(W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES) + CHUNK(W3D_CHUNK_EMITTER_FRAME_KEYFRAMES) + CHUNK(W3D_CHUNK_EMITTER_HEADER) + CHUNK(W3D_CHUNK_EMITTER_INFO) + CHUNK(W3D_CHUNK_EMITTER_INFOV2) + CHUNK(W3D_CHUNK_EMITTER_PROPS) + CHUNK(W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES) + CHUNK(W3D_CHUNK_EMITTER_USER_DATA) + CHUNK(W3D_CHUNK_FAR_ATTENUATION) + CHUNK(W3D_CHUNK_HIERARCHY) + CHUNK(W3D_CHUNK_HIERARCHY_HEADER) + CHUNK(W3D_CHUNK_HLOD) + CHUNK(W3D_CHUNK_HLOD_AGGREGATE_ARRAY) + CHUNK(W3D_CHUNK_HLOD_HEADER) + CHUNK(W3D_CHUNK_HLOD_LOD_ARRAY) + CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER) + CHUNK(W3D_CHUNK_HLOD_PROXY_ARRAY) + CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT) + CHUNK(W3D_CHUNK_HMODEL) + CHUNK(OBSOLETE_W3D_CHUNK_HMODEL_AUX_DATA) + CHUNK(W3D_CHUNK_HMODEL_HEADER) + CHUNK(W3D_CHUNK_LIGHT) + CHUNK(W3D_CHUNK_LIGHT_INFO) + CHUNK(W3D_CHUNK_LIGHT_TRANSFORM) + CHUNK(W3D_CHUNK_LIGHTSCAPE) + CHUNK(W3D_CHUNK_LIGHTSCAPE_LIGHT) + CHUNK(W3D_CHUNK_LOD) + CHUNK(W3D_CHUNK_LODMODEL) + CHUNK(W3D_CHUNK_LODMODEL_HEADER) + CHUNK(W3D_CHUNK_MAP3_FILENAME) + CHUNK(W3D_CHUNK_MAP3_INFO) + CHUNK(W3D_CHUNK_MATERIAL_INFO) + CHUNK(W3D_CHUNK_MATERIAL_PASS) + CHUNK(W3D_CHUNK_MATERIAL3) + CHUNK(W3D_CHUNK_MATERIAL3_DC_MAP) + CHUNK(W3D_CHUNK_MATERIAL3_DI_MAP) + CHUNK(W3D_CHUNK_MATERIAL3_INFO) + CHUNK(W3D_CHUNK_MATERIAL3_NAME) + CHUNK(W3D_CHUNK_MATERIAL3_SC_MAP) + CHUNK(W3D_CHUNK_MATERIAL3_SI_MAP) + CHUNK(W3D_CHUNK_MATERIALS3) + CHUNK(W3D_CHUNK_MESH) + CHUNK(W3D_CHUNK_MESH_HEADER) + CHUNK(W3D_CHUNK_MESH_HEADER3) + CHUNK(W3D_CHUNK_MESH_USER_TEXT) + CHUNK(W3D_CHUNK_NEAR_ATTENUATION) + CHUNK(W3D_CHUNK_NODE) + CHUNK(W3D_CHUNK_NULL_OBJECT) + CHUNK(W3D_CHUNK_PER_FACE_TEXCOORD_IDS) + CHUNK(W3D_CHUNK_PER_TRI_MATERIALS) + CHUNK(W3D_CHUNK_PIVOT_FIXUPS) + CHUNK(W3D_CHUNK_PIVOTS) + CHUNK(W3D_CHUNK_PLACEHOLDER) + CHUNK(W3D_CHUNK_POINTS) + CHUNK(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS) + CHUNK(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE) + CHUNK(W3D_CHUNK_PRELIT_UNLIT) + CHUNK(W3D_CHUNK_PRELIT_VERTEX) + CHUNK(W3D_CHUNK_PS2_SHADERS) + CHUNK(W3D_CHUNK_SCG) + CHUNK(W3D_CHUNK_SHADER_IDS) + CHUNK(W3D_CHUNK_SHADERS) + CHUNK(W3D_CHUNK_SKIN_NODE) + CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO) + CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO_5_0) + CHUNK(W3D_CHUNK_STAGE_TEXCOORDS) + CHUNK(W3D_CHUNK_SURRENDER_NORMALS) + CHUNK(W3D_CHUNK_TEXCOORDS) + CHUNK(W3D_CHUNK_TEXTURE) + CHUNK(W3D_CHUNK_TEXTURE_IDS) + CHUNK(W3D_CHUNK_TEXTURE_INFO) + CHUNK(W3D_CHUNK_TEXTURE_NAME) + CHUNK(W3D_CHUNK_TEXTURE_REPLACER_INFO) + CHUNK(W3D_CHUNK_TEXTURE_STAGE) + CHUNK(W3D_CHUNK_TEXTURES) + CHUNK(W3D_CHUNK_TRANSFORM_NODE) + CHUNK(W3D_CHUNK_TRIANGLES) + CHUNK(W3D_CHUNK_VERTEX_COLORS) + CHUNK(W3D_CHUNK_VERTEX_INFLUENCES) + CHUNK(W3D_CHUNK_VERTEX_MAPPER_ARGS0) + CHUNK(W3D_CHUNK_VERTEX_MAPPER_ARGS1) + CHUNK(W3D_CHUNK_VERTEX_MATERIAL) + CHUNK(W3D_CHUNK_VERTEX_MATERIAL_IDS) + CHUNK(W3D_CHUNK_VERTEX_MATERIAL_INFO) + CHUNK(W3D_CHUNK_VERTEX_MATERIAL_NAME) + CHUNK(W3D_CHUNK_VERTEX_MATERIALS) + CHUNK(W3D_CHUNK_VERTEX_NORMALS) + CHUNK(W3D_CHUNK_VERTEX_SHADE_INDICES) + CHUNK(W3D_CHUNK_VERTICES) + CHUNK(W3D_CHUNK_EMITTER_LINE_PROPERTIES) + CHUNK(W3D_CHUNK_SECONDARY_VERTICES) + CHUNK(W3D_CHUNK_SECONDARY_VERTEX_NORMALS) + CHUNK(W3D_CHUNK_TANGENTS) + CHUNK(W3D_CHUNK_BINORMALS) + CHUNK(W3D_CHUNK_COMPRESSED_ANIMATION) + CHUNK(W3D_CHUNK_COMPRESSED_ANIMATION_HEADER) + CHUNK(W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL) + CHUNK(W3D_CHUNK_COMPRESSED_BIT_CHANNEL) + CHUNK(W3D_CHUNK_MORPH_ANIMATION) + CHUNK(W3D_CHUNK_MORPHANIM_HEADER) + CHUNK(W3D_CHUNK_MORPHANIM_CHANNEL) + CHUNK(W3D_CHUNK_MORPHANIM_POSENAME) + CHUNK(W3D_CHUNK_MORPHANIM_KEYDATA) + CHUNK(W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA) + CHUNK(W3D_CHUNK_SOUNDROBJ) + CHUNK(W3D_CHUNK_SOUNDROBJ_HEADER) + CHUNK(W3D_CHUNK_SOUNDROBJ_DEFINITION) + CHUNK(W3D_CHUNK_RING) + CHUNK(W3D_CHUNK_SPHERE) + CHUNK(W3D_CHUNK_SHDMESH) + CHUNK(W3D_CHUNK_SHDMESH_NAME) + CHUNK(W3D_CHUNK_SHDSUBMESH) + CHUNK(W3D_CHUNK_SHDSUBMESH_SHADER) + CHUNK(W3D_CHUNK_SHDSUBMESH_SHADER_TYPE) + CHUNK(W3D_CHUNK_SHDSUBMESH_VERTICES) + CHUNK(W3D_CHUNK_SHDSUBMESH_VERTEX_NORMALS) + CHUNK(W3D_CHUNK_SHDSUBMESH_TRIANGLES) + CHUNK(W3D_CHUNK_SHDSUBMESH_VERTEX_SHADE_INDICES) + CHUNK(W3D_CHUNK_SHDSUBMESH_UV0) + CHUNK(W3D_CHUNK_SHDSUBMESH_UV1) + CHUNK(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_S) + CHUNK(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_T) + CHUNK(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_SXT) + CHUNK(W3D_CHUNK_EMITTER_EXTRA_INFO) + CHUNK(W3D_CHUNK_SHDMESH_USER_TEXT) + CHUNK(W3D_CHUNK_FXSHADER_IDS) + CHUNK(W3D_CHUNK_FX_SHADERS) + CHUNK(W3D_CHUNK_FX_SHADER) + CHUNK(W3D_CHUNK_FX_SHADER_INFO) + CHUNK(W3D_CHUNK_FX_SHADER_CONSTANT) + CHUNK(W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL) +} \ No newline at end of file diff --git a/src/tools/gamemodelconverter/src/chunksmanager.cpp b/src/tools/gamemodelconverter/src/chunksmanager.cpp index a5ec6e2d0..a1d6095b0 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.cpp +++ b/src/tools/gamemodelconverter/src/chunksmanager.cpp @@ -3,22 +3,7 @@ ChunkManager::ChunkManager(const char *filePath, int flag) { m_rootChunk = std::make_unique(); - -// if (flag == LOAD) { -// // Open the file for reading -// m_file = auto_file_ptr(g_theFileFactory, filePath); // Assuming auto_file_ptr is a smart pointer -// if (!m_file->Open(FileOpenType::FM_READ)) { -// captainslog_error("Could not open file for reading: %s", filePath); -// } -// } else if (flag == SAVE) { -// // Open the file for writing -// m_file = auto_file_ptr(g_theFileFactory, filePath); // Assuming auto_file_ptr is a smart pointer -// if (!m_file->Open(FileOpenType::FM_WRITE)) { -// captainslog_error("Could not open file for writing: %s", filePath); -// } -// } else { -// captainslog_error("Invalid flag in ChunkManager constructor"); -// } + InitiateChunkFuncMap(); } ChunkManager::~ChunkManager() @@ -31,16 +16,12 @@ ChunkManager::~ChunkManager() void ChunkManager::ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) { if (parentChunk == nullptr) { - captainslog_error("Parent chunk is null"); - return; + parentChunk = std::make_unique(); } while (chunkLoader.Open_Chunk()) { - ChunkPtr chunk = std::make_unique(); - ReadChunkInfo(chunkLoader, chunk); - parentChunk->data = std::move(chunk); if (chunkLoader.Contains_Chunks()) { while (chunkLoader.Open_Chunk()) { - ChunkPtr subchunk = std::make_unique(); + ChunkTreePtr subchunk = std::make_unique(); ReadChunkInfo(chunkLoader, subchunk); parentChunk->subchunks.push_back(std::move(subchunk)); chunkLoader.Close_Chunk(); @@ -50,36 +31,36 @@ void ChunkManager::ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &par } } -std::map typeToIOFuncMap; - -void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkPtr &chunk) +void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &data) { - if (chunk == nullptr) { + if (data == nullptr) { captainslog_error("Chunk is null"); return; } + ChunkPtr chunk = std::make_unique(); chunk->chunkType = chunkLoader.Cur_Chunk_ID(); chunk->chunkSize = chunkLoader.Cur_Chunk_Length(); - auto it = typeToIOFuncMap.find(chunk->chunkType); - if (it != typeToIOFuncMap.end()) { - chunk->info = createChunkInfo(); - it->second.ReadFunc(chunkLoader, chunk->info); + data->data = std::move(chunk); + data->subchunks = std::vector(1); + auto it = chunkFuncMap.find(data->data->chunkType); + if (it != chunkFuncMap.end()) { + it->second.ReadFunc(chunkLoader, data); } else { StringClass str; - str.Format("Unknown Chunk 0x%X", chunk->chunkType); + str.Format("Unknown Chunk 0x%X", data->data->chunkType); captainslog_warn((const char *)str); chunk->info = nullptr; } } -void ChunkManager::WriteSubchunks(ChunkSaveClass &chunkSaver, const ChunkTreePtr &parentChunk) +void ChunkManager::WriteSubchunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk) { if (parentChunk->data) { if (!chunkSaver.Begin_Chunk(parentChunk->data->chunkType)) { captainslog_error("Failed to begin chunk"); return; } - WriteChunkInfo(chunkSaver, parentChunk->data); + WriteChunkInfo(chunkSaver, parentChunk); if (!chunkSaver.End_Chunk()) { captainslog_error("Failed to end chunk"); return; @@ -87,405 +68,19 @@ void ChunkManager::WriteSubchunks(ChunkSaveClass &chunkSaver, const ChunkTreePtr } - for (const auto& subchunk : parentChunk->subchunks) { + for (auto& subchunk : parentChunk->subchunks) { WriteChunkInfo(chunkSaver, subchunk); } } -void ChunkManager::WriteChunkInfo(ChunkSaveClass &chunkSaver, const ChunkPtr &chunk) +void ChunkManager::WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &data) { - auto it = typeToIOFuncMap.find(chunk->chunkType); - if (it != typeToIOFuncMap.end()) { - it->second.WriteFunc(chunkSaver, chunk->info); + auto it = chunkFuncMap.find(data->data->chunkType); + if (it != chunkFuncMap.end()) { + it->second.WriteFunc(chunkSaver, data); } else { StringClass str; - str.Format("Unknown Chunk 0x%X", chunk->chunkType); + str.Format("Unknown Chunk 0x%X", data->data->chunkType); captainslog_warn((const char*)str); } } - -void ChunkManager::AddData( - ChunkInfoPtr &data, const char *name, const StringClass &type, const StringClass &formattedValue, void *value) -{ - if (data == nullptr) { - data = std::move(createChunkInfo(name, type, formattedValue, value)); - } else { - captainslog_error("ChunkInfo %s already exists, cannot set %s", (const char*)data->name, name); - } - data = std::move(createChunkInfo(name, type, formattedValue, value)); -} - -void ChunkManager::AddString(ChunkInfoPtr &data, const char *name, const StringClass &value, const StringClass &type) -{ - AddData(data, name, type, value, nullptr); -} - -void ChunkManager::AddVersion(ChunkInfoPtr &data, uint32_t value) -{ - char c[64]; - sprintf(c, "%u.%hu", value >> 16, (uint16_t)value); - AddData(data, "Version", "uint32_t", c, (void *)&value); -} - -void ChunkManager::AddInt32(ChunkInfoPtr &data, const char *name, uint32_t value) -{ - char c[256]; - sprintf(c, "%u", value); - AddData(data, name, "uint32_t", c, (void *)&value); -} - -void ChunkManager::AddInt16(ChunkInfoPtr &data, const char *name, uint16_t value) -{ - char c[256]; - sprintf(c, "%hu", value); - AddData(data, name, "uint16_t", c, (void *)&value); -} - -void ChunkManager::AddInt8(ChunkInfoPtr &data, const char *name, uint8_t value) -{ - char c[256]; - sprintf(c, "%hhu", value); - AddData(data, name, "uint8_t", c, (void *)&value); -} - -void ChunkManager::AddInt8Array(ChunkInfoPtr &data, const char *name, const uint8_t *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("%hhu ", values[i]); - str += str2; - } - char c[256]; - sprintf(c, "int8[%d]", count); - AddData(data, name, c, str, (void *)values); -} - -void ChunkManager::AddFloat(ChunkInfoPtr &data, const char *name, float value) -{ - char c[256]; - sprintf(c, "%f", value); - AddData(data, name, "float", c, (void *)&value); -} - -void ChunkManager::AddInt32Array(ChunkInfoPtr &data, const char *name, const uint32_t *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("%u ", values[i]); - str += str2; - } - char c[256]; - sprintf(c, "int32[%d]", count); - AddData(data, name, c, str, (void *)values); -} - -void ChunkManager::AddFloatArray(ChunkInfoPtr &data, const char *name, const float *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("%f ", values[i]); - str += str2; - } - char c[256]; - sprintf(c, "float[%d]", count); - AddData(data, name, c, str, (void *)values); -} - -void ChunkManager::AddVector(ChunkInfoPtr &data, const char *name, const W3dVectorStruct *value) -{ - char c[256]; - sprintf(c, "%f %f %f", value->x, value->y, value->z); - AddData(data, name, "W3dVectorStruct", c, (void *)value); -} - -void ChunkManager::AddQuaternion(ChunkInfoPtr &data, const char *name, const W3dQuaternionStruct *value) -{ - char c[256]; - sprintf(c, "%f %f %f %f", value->q[0], value->q[1], value->q[2], value->q[3]); - AddData(data, name, "W3dQuaternionStruct", c, (void *)value); -} - -void ChunkManager::AddRGB(ChunkInfoPtr &data, const char *name, const W3dRGBStruct *value) -{ - StringClass str; - str.Format("(%hhu %hhu %hhu) ", value->r, value->g, value->b); - AddData(data, name, "W3dRGBStruct", str, (void *)value); -} - -void ChunkManager::AddRGBArray(ChunkInfoPtr &data, const char *name, const W3dRGBStruct *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("(%hhu %hhu %hhu) ", values[i].r, values[i].g, values[i].b); - str += str2; - } - char c[256]; - sprintf(c, "float[%d]", count); - AddData(data, name, c, str, (void *)values); -} - -void ChunkManager::AddRGBA(ChunkInfoPtr &data, const char *name, const W3dRGBAStruct *value) -{ - StringClass str; - str.Format("(%hhu %hhu %hhu %hhu) ", value->R, value->G, value->B, value->A); - AddData(data, name, "W3dRGBAStruct", str, (void *)value); -} - -void ChunkManager::AddTexCoord(ChunkInfoPtr &data, const char *name, const W3dTexCoordStruct *value) -{ - char c[256]; - sprintf(c, "%f %f", value->U, value->V); - AddData(data, name, "W3dTexCoordStruct", c, (void *)value); -} - -void ChunkManager::AddTexCoordArray(ChunkInfoPtr &data, const char *name, const W3dTexCoordStruct *values, int count) -{ - StringClass str; - for (int i = 0; i < count; i++) { - char c[256]; - sprintf(c, "%s.TexCoord[%d]", name, i); - AddTexCoord(data, c, &values[i]); - } -} - -const char *DepthCompareValues[] = { "Pass Never", - "Pass Less", - "Pass Equal", - "Pass Less or Equal", - "Pass Greater", - "Pass Not Equal", - "Pass Greater or Equal", - "Pass Always" }; - -const char *DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; - -const char *DestBlendValues[] = { "Zero", - "One", - "Src Color", - "One Minus Src Color", - "Src Alpha", - "One Minus Src Alpha", - "Src Color Prefog", - "Disable", - "Enable", - "Scale Fragment", - "Replace Fragment" }; - -const char *PriGradientValues[] = { - "Disable", "Modulate", "Add", "Bump-Environment", "Bump-Environment Luminance", "Modulate 2x" -}; - -const char *SecGradientValues[] = { "Disable", "Enable" }; - -const char *SrcBlendValues[] = { "Zero", "One", "Src Alpha", "One Minus Src Alpha" }; - -const char *TexturingValues[] = { "Disable", "Enable" }; - -const char *DetailColorValues[] = { "Disable", - "Detail", - "Scale", - "InvScale", - "Add", - "Sub", - "SubR", - "Blend", - "DetailBlend", - "Add Signed", - "Add Signed 2x", - "Scale 2x", - "Mod Alpha Add Color" }; - -const char *DetailAlphaValues[] = { "Disable", "Detail", "Scale", "InvScale", "Disable", "Enable", "Smooth", "Flat" }; - -const char *AlphaTestValues[] = { "Alpha Test Disable", "Alpha Test Enable" }; - -void ChunkManager::AddShader(ChunkInfoPtr &data, const char *name, const W3dShaderStruct *value) -{ - // main shader - AddData(data, name, "W3dShaderStruct", "Main Shader", (void *)value); - char c[256]; - sprintf(c, "%s.DepthCompare", name); - - if (value->DepthCompare < W3DSHADER_DEPTHCOMPARE_PASS_MAX) { - AddString(data, c, DepthCompareValues[value->DepthCompare], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Depth Compare type %x", c, value->DepthCompare); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthCompare); - } - - sprintf(c, "%s.DepthMask", name); - - if (value->DepthMask < W3DSHADER_DEPTHMASK_WRITE_MAX) { - AddString(data, c, DepthMaskValues[value->DepthMask], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Depth Mask type %x", c, value->DepthMask); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthMask); - } - - sprintf(c, "%s.DestBlend", name); - - if (value->DestBlend < W3DSHADER_DESTBLENDFUNC_MAX) { - AddString(data, c, DestBlendValues[value->DestBlend], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Dest Blend type %x", c, value->DestBlend); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DestBlend); - } - - sprintf(c, "%s.PriGradient", name); - - if (value->PriGradient < W3DSHADER_PRIGRADIENT_MAX) { - AddString(data, c, PriGradientValues[value->PriGradient], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Primary Gradient type %x", c, value->PriGradient); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->PriGradient); - } - - sprintf(c, "%s.SecGradient", name); - - if (value->SecGradient < W3DSHADER_SECGRADIENT_MAX) { - AddString(data, c, SecGradientValues[value->SecGradient], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Secondary Gradient type %x", c, value->SecGradient); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->SecGradient); - } - - sprintf(c, "%s.SrcBlend", name); - - if (value->SrcBlend < W3DSHADER_SRCBLENDFUNC_MAX) { - AddString(data, c, SrcBlendValues[value->SrcBlend], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Src Blend type %x", c, value->SrcBlend); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->SrcBlend); - } - - sprintf(c, "%s.Texturing", name); - - if (value->Texturing < W3DSHADER_TEXTURING_MAX) { - AddString(data, c, TexturingValues[value->Texturing], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Texturing type %x", c, value->Texturing); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->Texturing); - } - - sprintf(c, "%s.DetailColor", name); - - if (value->DetailColorFunc < W3DSHADER_DETAILCOLORFUNC_MAX) { - AddString(data, c, DetailColorValues[value->DetailColorFunc], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Detail Color Func type %x", c, value->DetailColorFunc); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailColorFunc); - } - - sprintf(c, "%s.DetailAlpha", name); - - if (value->DetailAlphaFunc < W3DSHADER_DETAILALPHAFUNC_MAX) { - AddString(data, c, DetailAlphaValues[value->DetailAlphaFunc], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Detail Alpha Func type %x", c, value->DetailAlphaFunc); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailAlphaFunc); - } - - sprintf(c, "%s.AlphaTest", name); - - if (value->AlphaTest < W3DSHADER_ALPHATEST_MAX) { - AddString(data, c, AlphaTestValues[value->AlphaTest], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Alpha Test type %x", c, value->AlphaTest); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->AlphaTest); - } -} - -const char *PS2DepthCompareValues[] = { "Pass Never", "Pass Less", "Pass Always", "Pass Less or Equal" }; - -const char *PS2DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; - -const char *PS2ABDParamValues[] = { "Src Color", "Dest Color", "Zero" }; - -const char *PS2CParamValues[] = { - "Src Alpha", "Dest Alpha", "One", "Disable", "Enable", "Scale Fragment", "Replace Fragment" -}; - -const char *PS2PriGradientValues[] = { "Disable", "Modulate", "Highlight", "Highlight2", "Disable", "Enable" }; - -const char *PS2TexturingValues[] = { "Disable", - "Enable", - "Disable", - "Detail", - "Scale", - "InvScale", - "Add", - "Sub", - "SubR", - "Blend", - "DetailBlend", - "Disable", - "Detail", - "Scale", - "InvScale", - "Disable", - "Enable", - "Smooth", - "Flat" }; - -void ChunkManager::AddPS2Shader(ChunkInfoPtr &data, const char *name, const W3dPS2ShaderStruct *value) -{ - // main shader - // TODO check if this is correct and works - AddData(data, name, "W3dPS2ShaderStruct", "Main Shader", (void *)value); - char c[256]; - sprintf(c, "%s.DepthCompare", name); - AddData(data, c, "uint8_t", PS2DepthCompareValues[value->DepthCompare], (void *)&value->DepthCompare); - AddString(data, c, PS2DepthCompareValues[value->DepthCompare], "uint8_t"); - sprintf(c, "%s.DepthMask", name); - AddString(data, c, PS2DepthMaskValues[value->DepthMask], "uint8_t"); - sprintf(c, "%s.PriGradient", name); - AddString(data, c, PS2PriGradientValues[value->PriGradient], "uint8_t"); - sprintf(c, "%s.Texturing", name); - AddString(data, c, PS2TexturingValues[value->Texturing], "uint8_t"); - sprintf(c, "%s.AParam", name); - AddString(data, c, PS2ABDParamValues[value->AParam], "uint8_t"); - sprintf(c, "%s.BParam", name); - AddString(data, c, PS2ABDParamValues[value->BParam], "uint8_t"); - sprintf(c, "%s.CParam", name); - AddString(data, c, PS2CParamValues[value->CParam], "uint8_t"); - sprintf(c, "%s.DParam", name); - AddString(data, c, PS2ABDParamValues[value->DParam], "uint8_t"); -} - -void ChunkManager::AddIJK(ChunkInfoPtr &data, const char *name, const Vector3i *value) -{ - char c[256]; - sprintf(c, "%d %d %d", value->I, value->J, value->K); - AddData(data, name, "Vector3i", c, (void *)value); -} - -void ChunkManager::AddIJK16(ChunkInfoPtr &data, const char *name, const Vector3i16 *value) -{ - char c[256]; - sprintf(c, "%d %d %d", value->I, value->J, value->K); - AddData(data, name, "Vector3i16", c, (void *)value); -} diff --git a/src/tools/gamemodelconverter/src/chunksmanager.h b/src/tools/gamemodelconverter/src/chunksmanager.h index eab022818..ea2faa382 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.h +++ b/src/tools/gamemodelconverter/src/chunksmanager.h @@ -2,6 +2,8 @@ #include "chunkio.h" #include "ffactory.h" +#include "vector2.h" +#include "vector3.h" #include "vector3i.h" #include "w3d_file.h" #include "w3d_obsolete.h" @@ -36,8 +38,7 @@ using ChunkList = std::vector; struct ChunkTree { ChunkPtr data; - ChunkList subchunks; - ~ChunkTree() = default; + std::vector> subchunks; }; using ChunkTreePtr = std::unique_ptr; @@ -45,10 +46,12 @@ using ChunkTreePtr = std::unique_ptr; struct ChunkIOFuncs { const char *name; - void (*ReadFunc)(ChunkLoadClass &chunkLoader, ChunkInfoPtr &data); - void (*WriteFunc)(ChunkSaveClass &chunkSaver, ChunkInfoPtr &data); + void (*ReadFunc)(ChunkLoadClass &chunkLoader, ChunkTreePtr &data); + void (*WriteFunc)(ChunkSaveClass &chunkSaver, ChunkTreePtr &data); }; +extern std::map chunkFuncMap; + class ChunkManager { public: @@ -62,7 +65,9 @@ class ChunkManager ChunkManager(const char *filePath, int flag); ~ChunkManager(); + // Utility functions + void InitiateChunkFuncMap(); static ChunkInfoPtr createChunkInfo( const char *name = "Unknown", const StringClass &type = "Unknown", @@ -71,38 +76,16 @@ class ChunkManager { return std::make_unique(name, type, data, value); } - static void AddData( - ChunkInfoPtr &chunk, const char *name, const StringClass &type, const StringClass &formattedValue, void *value); - static void ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); - static void ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkPtr &chunk); - void WriteSubchunks(ChunkSaveClass &chunkSaver, const ChunkTreePtr &parentChunk); - void WriteChunkInfo(ChunkSaveClass &chunkSaver, const ChunkPtr &chunk); + static void ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &chunk); + void WriteSubchunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk); + void WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &chunk); ChunkTreePtr & GetRootChunk() { return m_rootChunk; } + void SetRootChunk(ChunkTreePtr root) { m_rootChunk = std::move(root); } private: - static void AddString(ChunkInfoPtr &chunk, const char *name, const StringClass &value, const StringClass &type); - static void AddVersion(ChunkInfoPtr &chunk, uint32_t value); - static void AddInt32(ChunkInfoPtr &chunk, const char *name, uint32_t value); - static void AddInt16(ChunkInfoPtr &chunk, const char *name, uint16_t value); - static void AddInt8(ChunkInfoPtr &chunk, const char *name, uint8_t value); - static void AddInt8Array(ChunkInfoPtr &chunk, const char *name, const uint8_t *values, int count); - static void AddFloat(ChunkInfoPtr &chunk, const char *name, float value); - static void AddInt32Array(ChunkInfoPtr &chunk, const char *name, const uint32_t *values, int count); - static void AddFloatArray(ChunkInfoPtr &chunk, const char *name, const float *values, int count); - static void AddVector(ChunkInfoPtr &chunk, const char *name, const W3dVectorStruct *value); - static void AddQuaternion(ChunkInfoPtr &chunk, const char *name, const W3dQuaternionStruct *value); - static void AddRGB(ChunkInfoPtr &chunk, const char *name, const W3dRGBStruct *value); - static void AddRGBArray(ChunkInfoPtr &chunk, const char *name, const W3dRGBStruct *values, int count); - static void AddRGBA(ChunkInfoPtr &chunk, const char *name, const W3dRGBAStruct *value); - static void AddTexCoord(ChunkInfoPtr &chunk, const char *name, const W3dTexCoordStruct *value); - static void AddTexCoordArray(ChunkInfoPtr &chunk, const char *name, const W3dTexCoordStruct *values, int count); - static void AddShader(ChunkInfoPtr &chunk, const char *name, const W3dShaderStruct *value); - static void AddPS2Shader(ChunkInfoPtr &chunk, const char *name, const W3dPS2ShaderStruct *value); - static void AddIJK(ChunkInfoPtr &chunk, const char *name, const Vector3i *value); - static void AddIJK16(ChunkInfoPtr &chunk, const char *name, const Vector3i16 *value); ChunkTreePtr m_rootChunk; FileClass *m_file; From e50cfc713d0cda6cd82f5b7d946a4edad7693f0a Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Sun, 26 Jan 2025 04:54:43 +0200 Subject: [PATCH 10/13] Refactor and Macros chunk management and serialization --- .../gamemodelconverter/src/chunkfactory.cpp | 1463 +++++++---------- .../gamemodelconverter/src/chunksmanager.cpp | 42 +- .../gamemodelconverter/src/chunksmanager.h | 6 +- .../gamemodelconverter/src/gamemodelfile.cpp | 28 +- 4 files changed, 584 insertions(+), 955 deletions(-) diff --git a/src/tools/gamemodelconverter/src/chunkfactory.cpp b/src/tools/gamemodelconverter/src/chunkfactory.cpp index acdea4c66..e1cd76b04 100644 --- a/src/tools/gamemodelconverter/src/chunkfactory.cpp +++ b/src/tools/gamemodelconverter/src/chunkfactory.cpp @@ -1,3 +1,5 @@ +#pragma clang diagnostic push +#pragma ide diagnostic ignored "modernize-use-auto" #include "chunksmanager.h" #include #include @@ -16,6 +18,24 @@ char *ReadChunkData(ChunkLoadClass &cload) return c; } +void WriteChunkData(ChunkSaveClass &csave, unsigned id, const void *data, unsigned dataSize) +{ + csave.Begin_Chunk(id); + csave.Write(data, dataSize); + csave.End_Chunk(); // TODO ASSERT SIZE +} + +template void WriteArray(ChunkSaveClass &csave, unsigned id, unsigned dataSize, unsigned numElements) +{ + csave.Begin_Chunk(id); + + for (unsigned i = 0; i < numElements; i++) { + csave.Write(&arrayData[i], dataSize); + } + + csave.End_Chunk(); +} + void AddData(ChunkTreePtr &data, const char *name, const StringClass &type, const StringClass &formattedValue, void *value) { if (data->data->info == nullptr) { @@ -25,16 +45,9 @@ void AddData(ChunkTreePtr &data, const char *name, const StringClass &type, cons } } -void AddString(ChunkTreePtr &data, const char *name, const StringClass &value, const StringClass &type) +void AddString(ChunkTreePtr &data, const char *name, const StringClass &string, const StringClass &type) { - AddData(data, name, type, value, nullptr); -} - -void AddVersion(ChunkTreePtr &data, uint32_t value) -{ - char c[64]; - sprintf(c, "%u.%hu", value >> 16, (uint16_t)value); - AddData(data, "Version", "uint32_t", c, (void *)&value); + AddData(data, name, type, string, (void *)&string); } void AddInt32(ChunkTreePtr &data, const char *name, uint32_t value) @@ -44,13 +57,6 @@ void AddInt32(ChunkTreePtr &data, const char *name, uint32_t value) AddData(data, name, "uint32_t", c, (void *)&value); } -void AddInt16(ChunkTreePtr &data, const char *name, uint16_t value) -{ - char c[256]; - sprintf(c, "%hu", value); - AddData(data, name, "uint16_t", c, (void *)&value); -} - void AddInt8(ChunkTreePtr &data, const char *name, uint8_t value) { char c[256]; @@ -58,19 +64,6 @@ void AddInt8(ChunkTreePtr &data, const char *name, uint8_t value) AddData(data, name, "uint8_t", c, (void *)&value); } -void AddInt8Array(ChunkTreePtr &data, const char *name, const uint8_t *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("%hhu ", values[i]); - str += str2; - } - char c[256]; - sprintf(c, "int8[%d]", count); - AddData(data, name, c, str, (void *)values); -} - void AddFloat(ChunkTreePtr &data, const char *name, float value) { char c[256]; @@ -78,32 +71,6 @@ void AddFloat(ChunkTreePtr &data, const char *name, float value) AddData(data, name, "float", c, (void *)&value); } -void AddInt32Array(ChunkTreePtr &data, const char *name, const uint32_t *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("%u ", values[i]); - str += str2; - } - char c[256]; - sprintf(c, "int32[%d]", count); - AddData(data, name, c, str, (void *)values); -} - -void AddFloatArray(ChunkTreePtr &data, const char *name, const float *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("%f ", values[i]); - str += str2; - } - char c[256]; - sprintf(c, "float[%d]", count); - AddData(data, name, c, str, (void *)values); -} - void AddVector(ChunkTreePtr &data, const char *name, const W3dVectorStruct *value) { char c[256]; @@ -111,406 +78,162 @@ void AddVector(ChunkTreePtr &data, const char *name, const W3dVectorStruct *valu AddData(data, name, "W3dVectorStruct", c, (void *)value); } -void AddQuaternion(ChunkTreePtr &data, const char *name, const W3dQuaternionStruct *value) -{ - char c[256]; - sprintf(c, "%f %f %f %f", value->q[0], value->q[1], value->q[2], value->q[3]); - AddData(data, name, "W3dQuaternionStruct", c, (void *)value); -} - -void AddRGB(ChunkTreePtr &data, const char *name, const W3dRGBStruct *value) -{ - StringClass str; - str.Format("(%hhu %hhu %hhu) ", value->r, value->g, value->b); - AddData(data, name, "W3dRGBStruct", str, (void *)value); -} - -void AddRGBArray(ChunkTreePtr &data, const char *name, const W3dRGBStruct *values, int count) -{ - StringClass str; - StringClass str2; - for (int i = 0; i < count; i++) { - str2.Format("(%hhu %hhu %hhu) ", values[i].r, values[i].g, values[i].b); - str += str2; - } - char c[256]; - sprintf(c, "float[%d]", count); - AddData(data, name, c, str, (void *)values); -} - -void AddRGBA(ChunkTreePtr &data, const char *name, const W3dRGBAStruct *value) -{ - StringClass str; - str.Format("(%hhu %hhu %hhu %hhu) ", value->R, value->G, value->B, value->A); - AddData(data, name, "W3dRGBAStruct", str, (void *)value); -} - -void AddTexCoord(ChunkTreePtr &data, const char *name, const W3dTexCoordStruct *value) -{ - char c[256]; - sprintf(c, "%f %f", value->U, value->V); - AddData(data, name, "W3dTexCoordStruct", c, (void *)value); -} - -void AddTexCoordArray(ChunkTreePtr &data, const char *name, const W3dTexCoordStruct *values, int count) -{ - StringClass str; - for (int i = 0; i < count; i++) { - char c[256]; - sprintf(c, "%s.TexCoord[%d]", name, i); - AddTexCoord(data, c, &values[i]); - } -} - -const char *DepthCompareValues[] = { "Pass Never", - "Pass Less", - "Pass Equal", - "Pass Less or Equal", - "Pass Greater", - "Pass Not Equal", - "Pass Greater or Equal", - "Pass Always" }; - -const char *DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; - -const char *DestBlendValues[] = { "Zero", - "One", - "Src Color", - "One Minus Src Color", - "Src Alpha", - "One Minus Src Alpha", - "Src Color Prefog", - "Disable", - "Enable", - "Scale Fragment", - "Replace Fragment" }; - -const char *PriGradientValues[] = { - "Disable", "Modulate", "Add", "Bump-Environment", "Bump-Environment Luminance", "Modulate 2x" -}; - -const char *SecGradientValues[] = { "Disable", "Enable" }; - -const char *SrcBlendValues[] = { "Zero", "One", "Src Alpha", "One Minus Src Alpha" }; - -const char *TexturingValues[] = { "Disable", "Enable" }; - -const char *DetailColorValues[] = { "Disable", - "Detail", - "Scale", - "InvScale", - "Add", - "Sub", - "SubR", - "Blend", - "DetailBlend", - "Add Signed", - "Add Signed 2x", - "Scale 2x", - "Mod Alpha Add Color" }; - -const char *DetailAlphaValues[] = { "Disable", "Detail", "Scale", "InvScale", "Disable", "Enable", "Smooth", "Flat" }; - -const char *AlphaTestValues[] = { "Alpha Test Disable", "Alpha Test Enable" }; - -void AddShader(ChunkTreePtr &data, const char *name, const W3dShaderStruct *value) -{ - // main shader - AddData(data, name, "W3dShaderStruct", "Main Shader", (void *)value); - char c[256]; - sprintf(c, "%s.DepthCompare", name); - - if (value->DepthCompare < W3DSHADER_DEPTHCOMPARE_PASS_MAX) { - AddString(data, c, DepthCompareValues[value->DepthCompare], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Depth Compare type %x", c, value->DepthCompare); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthCompare); - } - - sprintf(c, "%s.DepthMask", name); - - if (value->DepthMask < W3DSHADER_DEPTHMASK_WRITE_MAX) { - AddString(data, c, DepthMaskValues[value->DepthMask], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Depth Mask type %x", c, value->DepthMask); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DepthMask); - } - - sprintf(c, "%s.DestBlend", name); - - if (value->DestBlend < W3DSHADER_DESTBLENDFUNC_MAX) { - AddString(data, c, DestBlendValues[value->DestBlend], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Dest Blend type %x", c, value->DestBlend); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DestBlend); - } - - sprintf(c, "%s.PriGradient", name); - - if (value->PriGradient < W3DSHADER_PRIGRADIENT_MAX) { - AddString(data, c, PriGradientValues[value->PriGradient], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Primary Gradient type %x", c, value->PriGradient); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->PriGradient); - } - - sprintf(c, "%s.SecGradient", name); - - if (value->SecGradient < W3DSHADER_SECGRADIENT_MAX) { - AddString(data, c, SecGradientValues[value->SecGradient], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Secondary Gradient type %x", c, value->SecGradient); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->SecGradient); - } - - sprintf(c, "%s.SrcBlend", name); - - if (value->SrcBlend < W3DSHADER_SRCBLENDFUNC_MAX) { - AddString(data, c, SrcBlendValues[value->SrcBlend], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Src Blend type %x", c, value->SrcBlend); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->SrcBlend); - } - - sprintf(c, "%s.Texturing", name); - - if (value->Texturing < W3DSHADER_TEXTURING_MAX) { - AddString(data, c, TexturingValues[value->Texturing], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Texturing type %x", c, value->Texturing); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->Texturing); - } - - sprintf(c, "%s.DetailColor", name); - - if (value->DetailColorFunc < W3DSHADER_DETAILCOLORFUNC_MAX) { - AddString(data, c, DetailColorValues[value->DetailColorFunc], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Detail Color Func type %x", c, value->DetailColorFunc); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailColorFunc); - } - - sprintf(c, "%s.DetailAlpha", name); - - if (value->DetailAlphaFunc < W3DSHADER_DETAILALPHAFUNC_MAX) { - AddString(data, c, DetailAlphaValues[value->DetailAlphaFunc], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Detail Alpha Func type %x", c, value->DetailAlphaFunc); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->DetailAlphaFunc); - } - - sprintf(c, "%s.AlphaTest", name); +// Macro for Defining Functions - if (value->AlphaTest < W3DSHADER_ALPHATEST_MAX) { - AddString(data, c, AlphaTestValues[value->AlphaTest], "uint8_t"); - } else { - StringClass str; - str.Format("%s Shader unknown Alpha Test type %x", c, value->AlphaTest); - captainslog_warn("Unknown chunk: %s", (const char *)str); - AddData(data, c, "Unknown", "uint8_t", (void *)&value->AlphaTest); +#define DUMP_SERIALIZE_CHUNK_STRING(name) \ + void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ + { \ + char *chunkdata = ReadChunkData(cload); \ + AddString(data, #name, chunkdata, "string"); \ + delete[] chunkdata; \ + } \ +\ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ + { \ + char *chunkdata = (char *)data->data->info->value; \ + WriteChunkData(csave, name, chunkdata, sizeof(chunkdata)); \ } -} - -const char *PS2DepthCompareValues[] = { "Pass Never", "Pass Less", "Pass Always", "Pass Less or Equal" }; - -const char *PS2DepthMaskValues[] = { "Write Disable", "Write Enable", "Write Disable", "Write Enable" }; -const char *PS2ABDParamValues[] = { "Src Color", "Dest Color", "Zero" }; - -const char *PS2CParamValues[] = { - "Src Alpha", "Dest Alpha", "One", "Disable", "Enable", "Scale Fragment", "Replace Fragment" -}; - -const char *PS2PriGradientValues[] = { "Disable", "Modulate", "Highlight", "Highlight2", "Disable", "Enable" }; - -const char *PS2TexturingValues[] = { "Disable", - "Enable", - "Disable", - "Detail", - "Scale", - "InvScale", - "Add", - "Sub", - "SubR", - "Blend", - "DetailBlend", - "Disable", - "Detail", - "Scale", - "InvScale", - "Disable", - "Enable", - "Smooth", - "Flat" }; - -void AddPS2Shader(ChunkTreePtr &data, const char *name, const W3dPS2ShaderStruct *value) -{ - // main shader - // TODO check if this is correct and works - AddData(data, name, "W3dPS2ShaderStruct", "Main Shader", (void *)value); - char c[256]; - sprintf(c, "%s.DepthCompare", name); - AddData(data, c, "uint8_t", PS2DepthCompareValues[value->DepthCompare], (void *)&value->DepthCompare); - AddString(data, c, PS2DepthCompareValues[value->DepthCompare], "uint8_t"); - sprintf(c, "%s.DepthMask", name); - AddString(data, c, PS2DepthMaskValues[value->DepthMask], "uint8_t"); - sprintf(c, "%s.PriGradient", name); - AddString(data, c, PS2PriGradientValues[value->PriGradient], "uint8_t"); - sprintf(c, "%s.Texturing", name); - AddString(data, c, PS2TexturingValues[value->Texturing], "uint8_t"); - sprintf(c, "%s.AParam", name); - AddString(data, c, PS2ABDParamValues[value->AParam], "uint8_t"); - sprintf(c, "%s.BParam", name); - AddString(data, c, PS2ABDParamValues[value->BParam], "uint8_t"); - sprintf(c, "%s.CParam", name); - AddString(data, c, PS2CParamValues[value->CParam], "uint8_t"); - sprintf(c, "%s.DParam", name); - AddString(data, c, PS2ABDParamValues[value->DParam], "uint8_t"); -} - -void AddIJK(ChunkTreePtr &data, const char *name, const Vector3i *value) -{ - char c[256]; - sprintf(c, "%d %d %d", value->I, value->J, value->K); - AddData(data, name, "Vector3i", c, (void *)value); -} - -void AddIJK16(ChunkTreePtr &data, const char *name, const Vector3i16 *value) -{ - char c[256]; - sprintf(c, "%d %d %d", value->I, value->J, value->K); - AddData(data, name, "Vector3i16", c, (void *)value); -} - -// Macro for Defining Functions - -#define DUMP_CHUNK(name, type) \ +#define DUMP_SERIALIZE_CHUNK(name, type) \ void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ { \ char *chunkdata = ReadChunkData(cload); \ type *chunkData = (type *)chunkdata; \ AddData(data, #name, #type, "", (void *)chunkData); \ delete[] chunkdata; \ + } \ +\ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ + { \ + type *chunkData = (type *)data->data->info->value; \ + WriteChunkData(csave, name, chunkData, sizeof(type)); \ } -#define DUMP_CHUNK_ARRAY(name, type) \ +#define DUMP_SERIALIZE_CHUNK_ARRAY(name, type) \ void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ { \ char *chunkdata = ReadChunkData(cload); \ type *arrayData = (type *)chunkdata; \ AddData(data, #name, #type "[]", "", (void *)arrayData); \ delete[] chunkdata; \ + } \ +\ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ + { \ + type *arrayData = (type *)data->data->info->value; \ + unsigned numElements = data->data->chunkSize / sizeof(type); \ + WriteChunkData(csave, name, arrayData, numElements * sizeof(type)); \ } -#define DUMP_CHUNK_PARSER(name) \ +#define DUMP_SERIALIZE_PARSER(name) \ void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ { \ AddString(data, #name, "", "string"); \ - ChunkManager::ParseSubchunks(cload, data->subchunks.back()); \ + ChunkManager::DumpSubChunks(cload, data); \ + } \ +\ + void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ + { \ + ChunkManager::SerializeSubChunks(csave, data); \ } -#define SERIALIZE_CHUNK(name, type) \ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) {} - -#define SERIALIZE_CHUNK_ARRAY(name, type) \ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) {} - -#define SERIALIZE_CHUNK_PARSER(name) \ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) {} - -#define DUMP_SERIALIZE_CHUNK(name, type) \ - DUMP_CHUNK(name, type) \ - SERIALIZE_CHUNK(name, type) - -#define DUMP_SERIALIZE_CHUNK_ARRAY(name, type) \ - DUMP_CHUNK_ARRAY(name, type) \ - SERIALIZE_CHUNK_ARRAY(name, type) - -#define DUMP_SERIALIZE_PARSER(name) \ - DUMP_CHUNK_PARSER(name) \ - SERIALIZE_CHUNK_PARSER(name) +// Example Replacement: +void Dump_PARSER_DUMMY(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + // spilt name from Dump___func__, no need in macros + const char *name = strstr(__func__, "Dump_") + 5; + AddString(data, name, "", "string"); + data->subchunks = std::vector(1); + ChunkManager::DumpSubChunks(cload, data); +} -/* -Replacement: -void Dump_O_W3D_CHUNK_MATERIALS(ChunkLoadClass &cload, ChunkTreePtr &data) +void Dump_W3D_CHUNK_ARRAY_DUMMY(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dMaterialStruct *arrayData = (W3dMaterialStruct *)chunkdata; - AddData(data, - "O_W3D_CHUNK_MATERIALS", "W3dMaterialStruct" "[]", (void *)arrayData); + AddData(data, "O_W3D_CHUNK_MATERIALS", "W3dMaterialStruct[]", "", (void *)arrayData); delete[] chunkdata; } -*/ -DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS, W3dMaterialStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS2, W3dMaterial2Struct) -void Dump_O_W3D_C(ChunkLoadClass &cload, ChunkTreePtr &data) +void Serialize_W3D_CHUNK_ARRAY_DUMMY(ChunkSaveClass &csave, ChunkTreePtr &data) { - // spilt name from Dump___func__ - const char *name = strstr(__func__, "Dump_") + 5; - AddString(data, name, "", "string"); - data->subchunks = std::vector(1); - ChunkManager::ParseSubchunks(cload, data->subchunks.back()); + W3dMaterialStruct *arrayData = (W3dMaterialStruct *)data->data->info->value; + unsigned numElements = data->data->chunkSize / sizeof(W3dMaterialStruct); + WriteChunkData(csave, O_W3D_CHUNK_MATERIALS, arrayData, numElements * sizeof(W3dMaterialStruct)); } +void Dump_W3D_CHUNK_PARSER_DUMMY(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + // Because data is parent chunk, we need to add the name of the chunk, no any data or value + AddString(data, "W3D_CHUNK_ARRAY_DUMMY", "", "string"); + ChunkManager::DumpSubChunks(cload, data); +} + +// Dump and Serialize Functions +DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS, W3dMaterialStruct) + +DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS2, W3dMaterial2Struct) + void Dump_O_W3D_CHUNK_POV_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { - AddString(data, "O_W3D_CHUNK_POV_QUADRANGLES", "unsupported", "string"); + captainslog_warn("O_W3D_CHUNK_POV_QUADRANGLES is unsupported"); + char *chunkdata = ReadChunkData(cload); + AddData(data, "O_W3D_CHUNK_POV_QUADRANGLES", "char", "string", (void *)chunkdata); + delete[] chunkdata; } void Serialize_O_W3D_CHUNK_POV_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_O_W3D_CHUNK_POV_QUADRANGLES + captainslog_warn("O_W3D_CHUNK_POV_QUADRANGLES is unsupported"); + char *chunkdata = (char *)data->data->info->value; + WriteChunkData(csave, O_W3D_CHUNK_POV_QUADRANGLES, chunkdata, data->data->chunkSize); } void Dump_O_W3D_CHUNK_POV_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { - AddString(data, "O_W3D_CHUNK_POV_TRIANGLES", "unsupported", "string"); + captainslog_warn("O_W3D_CHUNK_POV_TRIANGLES is unsupported"); + char *chunkdata = ReadChunkData(cload); + AddData(data, "O_W3D_CHUNK_POV_TRIANGLES", "char", "string", (void *)chunkdata); + delete[] chunkdata; } void Serialize_O_W3D_CHUNK_POV_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_O_W3D_CHUNK_POV_QUADRANGLES + captainslog_warn("O_W3D_CHUNK_POV_TRIANGLES is unsupported"); + char *chunkdata = (char *)data->data->info->value; + WriteChunkData(csave, O_W3D_CHUNK_POV_TRIANGLES, chunkdata, data->data->chunkSize); } void Dump_O_W3D_CHUNK_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { - AddString(data, "O_W3D_CHUNK_QUADRANGLES", "Outdated", "string"); + captainslog_warn("O_W3D_CHUNK_QUADRANGLES is outdated"); + char *chunkdata = ReadChunkData(cload); + AddData(data, "O_W3D_CHUNK_QUADRANGLES", "char", "string", (void *)chunkdata); + delete[] chunkdata; } void Serialize_O_W3D_CHUNK_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_O_W3D_CHUNK_POV_QUADRANGLES + captainslog_warn("O_W3D_CHUNK_QUADRANGLES is outdated"); + char *chunkdata = (char *)data->data->info->value; + WriteChunkData(csave, O_W3D_CHUNK_QUADRANGLES, chunkdata, data->data->chunkSize); } DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_SURRENDER_TRIANGLES, W3dSurrenderTriangleStruct) void Dump_O_W3D_CHUNK_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { - AddString(data, "O_W3D_CHUNK_TRIANGLES", "Obsolete", "string"); + captainslog_warn("O_W3D_CHUNK_TRIANGLES is obsoleted"); + char *chunkdata = ReadChunkData(cload); + AddData(data, "O_W3D_CHUNK_TRIANGLES", "char", "string", (void *)chunkdata); + delete[] chunkdata; } void Serialize_O_W3D_CHUNK_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_O_W3D_CHUNK_TRIANGLES + captainslog_warn("O_W3D_CHUNK_TRIANGLES is obsoleted"); + char *chunkdata = (char *)data->data->info->value; + WriteChunkData(csave, O_W3D_CHUNK_TRIANGLES, chunkdata, data->data->chunkSize); } DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_COLOR_KEYFRAME, W3dEmitterColorKeyframeStruct) @@ -525,39 +248,7 @@ DUMP_SERIALIZE_PARSER(W3D_CHUNK_AABTREE) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AABTREE_HEADER, W3dMeshAABTreeHeader) -void Dump_W3D_CHUNK_AABTREE_NODES(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - W3dMeshAABTreeNode *nodes = (W3dMeshAABTreeNode *)chunkdata; - // TODO: valid - for (unsigned int i = 0; i < cload.Cur_Chunk_Length() / sizeof(W3dMeshAABTreeNode); i++) { - char c[256]; - sprintf(c, "Node[%d].Min", i); - AddVector(data, c, &nodes[i].Min); - sprintf(c, "Node[%d].Max", i); - AddVector(data, c, &nodes[i].Max); - - if ((nodes[i].FrontOrPoly0 & 0x80000000) == 0) { - sprintf(c, "Node[%d].Front", i); - AddInt32(data, c, nodes[i].FrontOrPoly0); - sprintf(c, "Node[%d].Back", i); - } else { - sprintf(c, "Node[%d].Poly0", i); - AddInt32(data, c, nodes[i].FrontOrPoly0 & 0x7FFFFFFF); - sprintf(c, "Node[%d].PolyCount", i); - } - - AddInt32(data, c, nodes[i].BackOrPolyCount); - } - - AddData(data, "W3D_CHUNK_AABTREE_NODES", "W3dMeshAABTreeNode[]", "", (void *)nodes); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_AABTREE_NODES(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_AABTREE_NODES -} +DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_NODES, W3dMeshAABTreeNode) DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_POLYINDICES, uint32_t) @@ -571,25 +262,18 @@ void Dump_W3D_CHUNK_AGGREGATE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dAggregateInfoStruct *info = (W3dAggregateInfoStruct *)chunkdata; - AddString(data, "BaseModelName", info->BaseModelName, "string"); - AddInt32(data, "SubobjectCount", info->SubobjectCount); W3dAggregateSubobjectStruct *subobj = (W3dAggregateSubobjectStruct *)(chunkdata + sizeof(W3dAggregateInfoStruct)); - for (unsigned int i = 0; i < info->SubobjectCount; i++) { - char c[256]; - sprintf(c, "SubObject[%u].SubobjectName", i); - AddString(data, c, subobj[i].SubobjectName, "string"); - sprintf(c, "SubObject[%u].BoneName", i); - AddString(data, c, subobj[i].BoneName, "string"); - } - // TODO: valid? - AddData(data, "W3D_CHUNK_AGGREGATE_INFO", "W3dAggregateInfoStruct", "", (void *)info); + // TODO: Add Subobjects + captainslog_warn("W3D_CHUNK_AGGREGATE_INFO Subobjects are not correctly implemented"); + AddData(data, "W3D_CHUNK_AGGREGATE_INFO", "W3dAggregateInfoStruct[][]", "Obsolete", (void *)info); delete[] chunkdata; } void Serialize_W3D_CHUNK_AGGREGATE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_AGGREGATE_INFO + W3dAggregateInfoStruct *info = (W3dAggregateInfoStruct *)data->data->info->value; + WriteChunkData(csave, W3D_CHUNK_AGGREGATE_INFO, info, sizeof(W3dAggregateInfoStruct)); } DUMP_SERIALIZE_PARSER(W3D_CHUNK_ANIMATION) @@ -599,19 +283,24 @@ void Dump_W3D_CHUNK_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) char *chunkdata = ReadChunkData(cload); W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)chunkdata; - AddData(data, "W3D_CHUNK_ANIMATION_CHANNEL", "W3dAnimChannelStruct", "", (void *)channel); if (channel->Flags <= ANIM_CHANNEL_VIS) { - StringClass str; str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } + AddData(data, "W3D_CHUNK_ANIMATION_CHANNEL", "W3dAnimChannelStruct", "", (void *)channel); delete[] chunkdata; } void Serialize_W3D_CHUNK_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_ANIMATION_CHANNEL + W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)data->data->info->value; + if (channel->Flags <= ANIM_CHANNEL_VIS) { + StringClass str; + str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + WriteChunkData(csave, W3D_CHUNK_ANIMATION_CHANNEL, channel, sizeof(W3dAnimChannelStruct)); } DUMP_SERIALIZE_CHUNK(W3D_CHUNK_ANIMATION_HEADER, W3dAnimHeaderStruct) @@ -620,24 +309,29 @@ void Dump_W3D_CHUNK_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dBitChannelStruct *channel = (W3dBitChannelStruct *)chunkdata; - AddData(data, "W3D_CHUNK_BIT_CHANNEL", "W3dBitChannelStruct", "", (void *)channel); if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { StringClass str; str.Format("W3D_CHUNK_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } + AddData(data, "W3D_CHUNK_BIT_CHANNEL", "W3dBitChannelStruct", "", (void *)channel); delete[] chunkdata; } void Serialize_W3D_CHUNK_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_BIT_CHANNEL + W3dBitChannelStruct *channel = (W3dBitChannelStruct *)data->data->info->value; + if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { + StringClass str; + str.Format("W3D_CHUNK_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + WriteChunkData(csave, W3D_CHUNK_BIT_CHANNEL, channel, sizeof(W3dBitChannelStruct)); } void Dump_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dBoxStruct *box = (W3dBoxStruct *)chunkdata; - AddData(data, "W3D_CHUNK_BOX", "W3dBoxStruct", "", (void *)box); if (box->Attributes & 4) { StringClass str; @@ -657,29 +351,39 @@ void Dump_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) captainslog_warn((const char *)str); } + AddData(data, "W3D_CHUNK_BOX", "W3dBoxStruct", "", (void *)box); delete[] chunkdata; } void Serialize_W3D_CHUNK_BOX(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_BOX + W3dBoxStruct *box = (W3dBoxStruct *)data->data->info->value; + if (box->Attributes & 4) { + StringClass str; + str.Format("W3D_CHUNK_BOX Unknown Attribute 0x00000004"); + captainslog_warn((const char *)str); + } + + if (box->Attributes & 8) { + StringClass str; + str.Format("W3D_CHUNK_BOX Unknown Attribute 0x00000008"); + captainslog_warn((const char *)str); + } + + if (box->Attributes & 0xFFFFFE00) { + StringClass str; + str.Format("W3D_CHUNK_BOX Unknown Attributes %x", box->Attributes & 0xFFFFFE00); + captainslog_warn((const char *)str); + } + + WriteChunkData(csave, W3D_CHUNK_BOX, box, sizeof(W3dBoxStruct)); } DUMP_SERIALIZE_PARSER(W3D_CHUNK_COLLECTION) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_COLLECTION_HEADER, W3dCollectionHeaderStruct) -void Dump_W3D_CHUNK_COLLECTION_OBJ_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_COLLECTION_OBJ_NAME", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_COLLECTION_OBJ_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_COLLECTION_OBJ_NAME -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_COLLECTION_OBJ_NAME) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_COLLISION_NODE, W3dHModelNodeStruct) @@ -693,29 +397,9 @@ DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_VERTICES, W3dDamageVertexStruct) DUMP_SERIALIZE_PARSER(W3D_CHUNK_DAZZLE) -void Dump_W3D_CHUNK_DAZZLE_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_DAZZLE_NAME", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_DAZZLE_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_DAZZLE_NAME -} - -void Dump_W3D_CHUNK_DAZZLE_TYPENAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_DAZZLE_TYPENAME", chunkdata, "string"); - delete[] chunkdata; -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_DAZZLE_NAME) -void Serialize_W3D_CHUNK_DAZZLE_TYPENAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_DAZZLE_TYPENAME -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_DAZZLE_TYPENAME) DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DCG, W3dRGBAStruct) @@ -727,52 +411,39 @@ void Dump_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkLoadClass &cload, ChunkTree { char *chunkdata = ReadChunkData(cload); W3dEmitterBlurTimeHeaderStruct *header = (W3dEmitterBlurTimeHeaderStruct *)chunkdata; - AddInt32(data, "KeyframeCount", header->KeyframeCount); - AddFloat(data, "Random", header->Random); + W3dEmitterBlurTimeKeyframeStruct *blurtime = (W3dEmitterBlurTimeKeyframeStruct *)(chunkdata + sizeof(W3dEmitterBlurTimeHeaderStruct)); - for (unsigned int i = 0; i < header->KeyframeCount + 1; i++) { - char c[256]; - sprintf(c, "Time[%u]", i); - AddFloat(data, c, blurtime[i].Time); - sprintf(c, "BlurTime[%u]", i); - AddFloat(data, c, blurtime[i].BlurTime); - } - // TODO valid - AddData(data, "W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES", "W3dEmitterBlurTimeKeyframeStruct[]", "", (void *)chunkdata); + // TODO: Add subobjects + captainslog_warn("W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES Subobjects are not correctly implemented"); + AddData(data, "W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES", "W3dEmitterBlurTimeHeaderStruct[][]", "", (void *)chunkdata); delete[] chunkdata; } void Serialize_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES + W3dEmitterBlurTimeHeaderStruct *header = (W3dEmitterBlurTimeHeaderStruct *)data->data->info->value; + WriteChunkData(csave, W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES, header, sizeof(W3dEmitterBlurTimeHeaderStruct)); } void Dump_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dEmitterFrameHeaderStruct *header = (W3dEmitterFrameHeaderStruct *)chunkdata; - AddInt32(data, "KeyframeCount", header->KeyframeCount); - AddFloat(data, "Random", header->Random); W3dEmitterFrameKeyframeStruct *frame = (W3dEmitterFrameKeyframeStruct *)(chunkdata + sizeof(W3dEmitterFrameHeaderStruct)); - for (unsigned int i = 0; i < header->KeyframeCount + 1; i++) { - char c[256]; - sprintf(c, "Time[%u]", i); - AddFloat(data, c, frame[i].Time); - sprintf(c, "Frame[%u]", i); - AddFloat(data, c, frame[i].Frame); - } - // TODO valid - AddData(data, "W3D_CHUNK_EMITTER_FRAME_KEYFRAMES", "W3dEmitterFrameKeyframeStruct[]", "", (void *)chunkdata); + // TODO: Add subobjects + captainslog_warn("W3D_CHUNK_EMITTER_FRAME_KEYFRAMES Subobjects are not correctly implemented"); + AddData(data, "W3D_CHUNK_EMITTER_FRAME_KEYFRAMES", "W3dEmitterFrameHeaderStruct[][]", "", (void *)chunkdata); delete[] chunkdata; } void Serialize_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES + W3dEmitterFrameHeaderStruct *header = (W3dEmitterFrameHeaderStruct *)data->data->info->value; + WriteChunkData(csave, W3D_CHUNK_EMITTER_FRAME_KEYFRAMES, header, sizeof(W3dEmitterFrameHeaderStruct)); } DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_HEADER, W3dEmitterHeaderStruct) @@ -785,92 +456,49 @@ void Dump_W3D_CHUNK_EMITTER_PROPS(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dEmitterPropertyStruct *props = (W3dEmitterPropertyStruct *)chunkdata; - AddInt32(data, "ColorKeyframes", props->ColorKeyframes); - AddInt32(data, "OpacityKeyframes", props->OpacityKeyframes); - AddInt32(data, "SizeKeyframes", props->SizeKeyframes); - AddRGBA(data, "ColorRandom", &props->ColorRandom); - AddFloat(data, "OpacityRandom", props->OpacityRandom); - AddFloat(data, "SizeRandom", props->SizeRandom); - W3dEmitterColorKeyframeStruct *color = (W3dEmitterColorKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct)); - for (unsigned int i = 0; i < props->ColorKeyframes; i++) { - char c[256]; - sprintf(c, "Time[%u]", i); - AddFloat(data, c, color[i].Time); - sprintf(c, "Color[%u]", i); - AddRGBA(data, c, &color[i].Color); - } + W3dEmitterColorKeyframeStruct *color = (W3dEmitterColorKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct)); W3dEmitterOpacityKeyframeStruct *opacity = (W3dEmitterOpacityKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct) + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct))); - for (unsigned int i = 0; i < props->OpacityKeyframes; i++) { - char c[256]; - sprintf(c, "Time[%u]", i); - AddFloat(data, c, opacity[i].Time); - sprintf(c, "Opacity[%u]", i); - AddFloat(data, c, opacity[i].Opacity); - } - W3dEmitterSizeKeyframeStruct *size = (W3dEmitterSizeKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct) + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct)) + (props->OpacityKeyframes * sizeof(W3dEmitterOpacityKeyframeStruct))); - for (unsigned int i = 0; i < props->OpacityKeyframes; i++) { - char c[256]; - sprintf(c, "Time[%u]", i); - AddFloat(data, c, size[i].Time); - sprintf(c, "Size[%u]", i); - AddFloat(data, c, size[i].Size); - } - // TODO valid - AddData(data, "W3D_CHUNK_EMITTER_PROPS", "W3dEmitterPropertyStruct", "", (void *)chunkdata); + // TODO: Add subobjects + captainslog_warn("W3D_CHUNK_EMITTER_PROPS Subobjects are not correctly implemented"); + AddData(data, "W3D_CHUNK_EMITTER_PROPS", "W3dEmitterPropertyStruct[][][][]", "", (void *)chunkdata); delete[] chunkdata; } void Serialize_W3D_CHUNK_EMITTER_PROPS(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_EMITTER_PROPS + W3dEmitterPropertyStruct *props = (W3dEmitterPropertyStruct *)data->data->info->value; + WriteChunkData(csave, W3D_CHUNK_EMITTER_PROPS, props, sizeof(W3dEmitterPropertyStruct)); } void Dump_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dEmitterRotationHeaderStruct *header = (W3dEmitterRotationHeaderStruct *)chunkdata; - AddInt32(data, "KeyframeCount", header->KeyframeCount); - AddFloat(data, "Random", header->Random); - AddFloat(data, "OrientationRandom", header->OrientationRandom); + W3dEmitterRotationKeyframeStruct *frame = (W3dEmitterRotationKeyframeStruct *)(chunkdata + sizeof(W3dEmitterRotationHeaderStruct)); - for (unsigned int i = 0; i < header->KeyframeCount + 1; i++) { - char c[256]; - sprintf(c, "Time[%u]", i); - AddFloat(data, c, frame[i].Time); - sprintf(c, "Rotation[%u]", i); - AddFloat(data, c, frame[i].Rotation); - } - // TODO valid - AddData(data, "W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES", "W3dEmitterRotationKeyframeStruct[]", "", (void *)chunkdata); + // TODO: Add subobjects + captainslog_warn("W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES Subobjects are not correctly implemented"); + AddData(data, "W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES", "W3dEmitterRotationHeaderStruct[][]", "", (void *)chunkdata); delete[] chunkdata; } void Serialize_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES + W3dEmitterRotationHeaderStruct *header = (W3dEmitterRotationHeaderStruct *)data->data->info->value; + WriteChunkData(csave, W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES, header, sizeof(W3dEmitterRotationHeaderStruct)); } -void Dump_W3D_CHUNK_EMITTER_USER_DATA(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_EMITTER_USER_DATA", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_EMITTER_USER_DATA(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_EMITTER_USER_DATA -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_EMITTER_USER_DATA) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_FAR_ATTENUATION, W3dLightAttenuationStruct) @@ -904,11 +532,9 @@ void Dump_W3D_CHUNK_LIGHT_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dLightStruct *light = (W3dLightStruct *)chunkdata; + int type = light->Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK; - if (type == W3D_LIGHT_ATTRIBUTE_POINT) { - } else if (type == W3D_LIGHT_ATTRIBUTE_SPOT) { - } else if (type == W3D_LIGHT_ATTRIBUTE_DIRECTIONAL) { - } else { + if (type != W3D_LIGHT_ATTRIBUTE_POINT && type != W3D_LIGHT_ATTRIBUTE_SPOT && type != W3D_LIGHT_ATTRIBUTE_DIRECTIONAL) { StringClass str; str.Format("W3D_CHUNK_LIGHT_INFO Unknown Light Type %x", type); captainslog_warn((const char *)str); @@ -925,7 +551,21 @@ void Dump_W3D_CHUNK_LIGHT_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) void Serialize_W3D_CHUNK_LIGHT_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_LIGHT_INFO + W3dLightStruct *light = (W3dLightStruct *)data->data->info->value; + int type = light->Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK; + if (type != W3D_LIGHT_ATTRIBUTE_POINT && type != W3D_LIGHT_ATTRIBUTE_SPOT && type != W3D_LIGHT_ATTRIBUTE_DIRECTIONAL) { + StringClass str; + str.Format("W3D_CHUNK_LIGHT_INFO Unknown Light Type %x", type); + captainslog_warn((const char *)str); + } + + if (light->Attributes & 0xFFFFFE00) { + StringClass str; + str.Format("W3D_CHUNK_LIGHT_INFO Unknown Light Flags %x", light->Attributes & 0xFFFFFE00); + captainslog_warn((const char *)str); + } + + WriteChunkData(csave, W3D_CHUNK_LIGHT_INFO, light, sizeof(W3dLightStruct)); } DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LIGHT_TRANSFORM, W3dLightTransformStruct) @@ -940,17 +580,7 @@ DUMP_SERIALIZE_PARSER(W3D_CHUNK_LODMODEL) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LODMODEL_HEADER, W3dLODModelHeaderStruct) -void Dump_W3D_CHUNK_MAP3_FILENAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_MAP3_FILENAME", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_MAP3_FILENAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_MAP3_FILENAME -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MAP3_FILENAME) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MAP3_INFO, W3dMap3Struct) @@ -966,17 +596,7 @@ DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_DI_MAP) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MATERIAL3_INFO, W3dMaterial3Struct) -void Dump_W3D_CHUNK_MATERIAL3_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_MATERIAL3_NAME", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_MATERIAL3_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_MATERIAL3_NAME -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MATERIAL3_NAME) DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_SC_MAP) @@ -993,29 +613,60 @@ void Dump_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) char *chunkdata = ReadChunkData(cload); W3dMeshHeader3Struct *header = (W3dMeshHeader3Struct *)chunkdata; int type = header->Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK; - switch (type) { - case W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL: - break; - case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED: - break; - case W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN: - break; - case OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW: - break; - case W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX: - break; - case W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX: - break; - case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED: - break; - case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_Z_ORIENTED: - break; - default: { + if (type != W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED + && type != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN && type != OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW + && type != W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX && type != W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX + && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_Z_ORIENTED) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Mesh Type %x", type); + captainslog_warn((const char *)str); + } + + if (header->Attributes & 0x00000800) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Attribute 0x00000800"); + captainslog_warn((const char *)str); + } + + if (header->Attributes & W3D_MESH_FLAG_PRELIT_MASK) { + if (!header->PrelitVersion) { StringClass str; - str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Mesh Type %x", type); + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown value of Attribute PrelitVersion: %x", header->PrelitVersion); captainslog_warn((const char *)str); - break; } + } else { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 N/A PrelitVersion"); + captainslog_warn((const char *)str); + } + + if (header->VertexChannels & 0xFFFFFF00) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Vertex Channels %x", header->VertexChannels); + captainslog_warn((const char *)str); + } + + if (header->FaceChannels & 0xFFFFFFFE) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Face Channels %x", header->FaceChannels); + captainslog_warn((const char *)str); + } + AddData(data, "W3D_CHUNK_MESH_HEADER3", "W3dMeshHeader3Struct", "", (void *)header); + delete[] chunkdata; +} + +void Serialize_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + W3dMeshHeader3Struct *header = (W3dMeshHeader3Struct *)data->data->info->value; + int type = header->Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK; + + if (type != W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED + && type != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN && type != OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW + && type != W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX && type != W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX + && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_Z_ORIENTED) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Mesh Type %x", type); + captainslog_warn((const char *)str); } if (header->Attributes & 0x00000800) { @@ -1024,19 +675,17 @@ void Dump_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) captainslog_warn((const char *)str); } - char c[64]; - if (header->Attributes & W3D_MESH_FLAG_PRELIT_MASK) { - if (header->PrelitVersion) { - } else { - sprintf(c, "UNKNOWN"); + if (!header->PrelitVersion) { + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 Unknown value of Attribute PrelitVersion: %x", header->PrelitVersion); + captainslog_warn((const char *)str); } } else { - sprintf(c, "N/A"); + StringClass str; + str.Format("W3D_CHUNK_MESH_HEADER3 N/A PrelitVersion"); + captainslog_warn((const char *)str); } - // AddString(data, "PrelitVersion", c, "string"); - // TODO valid - captainslog_warn((const char *)"str"); if (header->VertexChannels & 0xFFFFFF00) { StringClass str; @@ -1049,26 +698,11 @@ void Dump_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) str.Format("W3D_CHUNK_MESH_HEADER3 Unknown Face Channels %x", header->FaceChannels); captainslog_warn((const char *)str); } - AddData(data, "W3D_CHUNK_MESH_HEADER3", "W3dMeshHeader3Struct", "", (void *)header); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_MESH_HEADER3 -} -void Dump_W3D_CHUNK_MESH_USER_TEXT(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_MESH_USER_TEXT", chunkdata, "string"); - delete[] chunkdata; + WriteChunkData(csave, W3D_CHUNK_MESH_HEADER3, header, sizeof(W3dMeshHeader3Struct)); } -void Serialize_W3D_CHUNK_MESH_USER_TEXT(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_MESH_USER_TEXT -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MESH_USER_TEXT) DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NEAR_ATTENUATION, W3dLightAttenuationStruct) @@ -1127,11 +761,8 @@ void Dump_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) int hint = info->Attributes & 0xF00; - if (hint == W3DTEXTURE_HINT_BASE) { - } else if (hint == W3DTEXTURE_HINT_EMISSIVE) { - } else if (hint == W3DTEXTURE_HINT_ENVIRONMENT) { - } else if (hint == W3DTEXTURE_HINT_SHINY_MASK) { - } else { + if (hint != W3DTEXTURE_HINT_BASE && hint != W3DTEXTURE_HINT_EMISSIVE && hint != W3DTEXTURE_HINT_ENVIRONMENT + && hint != W3DTEXTURE_HINT_SHINY_MASK) { StringClass str; str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Hints %x", hint); captainslog_warn((const char *)str); @@ -1143,11 +774,8 @@ void Dump_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) captainslog_warn((const char *)str); } - if (info->AnimType == W3DTEXTURE_ANIM_LOOP) { - } else if (info->AnimType == W3DTEXTURE_ANIM_PINGPONG) { - } else if (info->AnimType == W3DTEXTURE_ANIM_ONCE) { - } else if (info->AnimType == W3DTEXTURE_ANIM_MANUAL) { - } else { + if (info->AnimType != W3DTEXTURE_ANIM_LOOP && info->AnimType != W3DTEXTURE_ANIM_PINGPONG + && info->AnimType != W3DTEXTURE_ANIM_ONCE && info->AnimType != W3DTEXTURE_ANIM_MANUAL) { StringClass str; str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Anim Type %x", info->AnimType); captainslog_warn((const char *)str); @@ -1159,21 +787,34 @@ void Dump_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) void Serialize_W3D_CHUNK_TEXTURE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_TEXTURE_INFO -} + W3dTextureInfoStruct *info = (W3dTextureInfoStruct *)data->data->info->value; + int hint = info->Attributes & 0xF00; -void Dump_W3D_CHUNK_TEXTURE_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_TEXTURE_NAME", chunkdata, "string"); - delete[] chunkdata; -} + if (hint != W3DTEXTURE_HINT_BASE && hint != W3DTEXTURE_HINT_EMISSIVE && hint != W3DTEXTURE_HINT_ENVIRONMENT + && hint != W3DTEXTURE_HINT_SHINY_MASK) { + StringClass str; + str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Hints %x", hint); + captainslog_warn((const char *)str); + } -void Serialize_W3D_CHUNK_TEXTURE_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_TEXTURE_NAME + if (info->Attributes & 0xE000) { + StringClass str; + str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Flags %x", info->Attributes & 0xE000); + captainslog_warn((const char *)str); + } + + if (info->AnimType != W3DTEXTURE_ANIM_LOOP && info->AnimType != W3DTEXTURE_ANIM_PINGPONG + && info->AnimType != W3DTEXTURE_ANIM_ONCE && info->AnimType != W3DTEXTURE_ANIM_MANUAL) { + StringClass str; + str.Format("W3D_CHUNK_TEXTURE_INFO Unknown Anim Type %x", info->AnimType); + captainslog_warn((const char *)str); + } + + WriteChunkData(csave, W3D_CHUNK_TEXTURE_INFO, info, sizeof(W3dTextureInfoStruct)); } +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_TEXTURE_NAME) + DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXTURE_REPLACER_INFO, W3dTextureReplacerStruct) DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURE_STAGE) @@ -1188,29 +829,9 @@ DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_COLORS, W3dRGBStruct) DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_INFLUENCES, W3dVertInfStruct) -void Dump_W3D_CHUNK_VERTEX_MAPPER_ARGS0(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_VERTEX_MAPPER_ARGS0", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS0(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS0 -} - -void Dump_W3D_CHUNK_VERTEX_MAPPER_ARGS1(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_VERTEX_MAPPER_ARGS1", chunkdata, "string"); - delete[] chunkdata; -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_VERTEX_MAPPER_ARGS0) -void Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS1(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MAPPER_ARGS1 -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_VERTEX_MAPPER_ARGS1) DUMP_SERIALIZE_PARSER(W3D_CHUNK_VERTEX_MATERIAL) @@ -1245,10 +866,6 @@ void Dump_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &da captainslog_warn((const char *)str); } - if ((material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK) == W3DVERTMAT_STAGE0_MAPPING_UV) { - AddString(data, "Material.Attributes", "W3DVERTMAT_STAGE0_MAPPING_UV", "flag"); - } - if ((material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK) > W3DVERTMAT_STAGE0_MAPPING_GRID_WS_ENVIRONMENT) { StringClass str; str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Stage 0 Mapper %x", @@ -1276,21 +893,58 @@ void Dump_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &da void Serialize_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MATERIAL_INFO -} + W3dVertexMaterialStruct *material = (W3dVertexMaterialStruct *)data->data->info->value; + if (material->Attributes & 0x00000010) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000010"); + captainslog_warn((const char *)str); + } -void Dump_W3D_CHUNK_VERTEX_MATERIAL_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_VERTEX_MATERIAL_NAME", chunkdata, "string"); - delete[] chunkdata; -} + if (material->Attributes & 0x00000020) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000020"); + captainslog_warn((const char *)str); + } -void Serialize_W3D_CHUNK_VERTEX_MATERIAL_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_VERTEX_MATERIAL_NAME + if (material->Attributes & 0x00000040) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000040"); + captainslog_warn((const char *)str); + } + + if (material->Attributes & 0x00000080) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Attribute 0x00000080"); + captainslog_warn((const char *)str); + } + + if ((material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK) > W3DVERTMAT_STAGE0_MAPPING_GRID_WS_ENVIRONMENT) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Stage 0 Mapper %x", + material->Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK); + captainslog_warn((const char *)str); + } + + if ((material->Attributes & W3DVERTMAT_STAGE1_MAPPING_MASK) > W3DVERTMAT_STAGE1_MAPPING_GRID_WS_ENVIRONMENT) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown Stage 1 Mapper %x", + material->Attributes & W3DVERTMAT_STAGE1_MAPPING_MASK); + captainslog_warn((const char *)str); + } + + if (material->Attributes & W3DVERTMAT_PSX_MASK) { + if (material->Attributes & 0xF0000000) { + StringClass str; + str.Format("W3D_CHUNK_VERTEX_MATERIAL_INFO Unknown PSX material flag %x", material->Attributes & 0xF0000000); + captainslog_warn((const char *)str); + } + } + + WriteChunkData(csave, W3D_CHUNK_VERTEX_MATERIAL_INFO, material, sizeof(W3dVertexMaterialStruct)); } +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_VERTEX_MATERIAL_NAME) + DUMP_SERIALIZE_PARSER(W3D_CHUNK_VERTEX_MATERIALS) DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_NORMALS, W3dVectorStruct) @@ -1310,29 +964,36 @@ void Dump_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkLoadClass &cload, ChunkTreePtr captainslog_warn((const char *)str); } - int mapmode = props->Flags >> W3D_ELINE_TEXTURE_MAP_MODE_OFFSET; - - switch (mapmode) { - case W3D_ELINE_UNIFORM_WIDTH_TEXTURE_MAP: - break; - case W3D_ELINE_UNIFORM_LENGTH_TEXTURE_MAP: - break; - case W3D_ELINE_TILED_TEXTURE_MAP: - break; - default: { - StringClass str; - str.Format("W3D_CHUNK_EMITTER_LINE_PROPERTIES Unknown Emitter Mapping Mode %x", mapmode); - captainslog_warn((const char *)str); - break; - } + size_t mapmode = props->Flags >> W3D_ELINE_TEXTURE_MAP_MODE_OFFSET; + if (mapmode != W3D_ELINE_UNIFORM_WIDTH_TEXTURE_MAP && mapmode != W3D_ELINE_UNIFORM_LENGTH_TEXTURE_MAP + && mapmode != W3D_ELINE_TILED_TEXTURE_MAP) { + StringClass str; + str.Format("W3D_CHUNK_EMITTER_LINE_PROPERTIES Unknown Emitter Mapping Mode %x", mapmode); + captainslog_warn((const char *)str); } + AddData(data, "W3D_CHUNK_EMITTER_LINE_PROPERTIES", "W3dEmitterLinePropertiesStruct", "", (void *)props); delete[] chunkdata; } void Serialize_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_EMITTER_LINE_PROPERTIES + W3dEmitterLinePropertiesStruct *props = (W3dEmitterLinePropertiesStruct *)data->data->info->value; + if (props->Flags & 0x00FFFFF0) { + StringClass str; + str.Format("W3D_CHUNK_EMITTER_LINE_PROPERTIES Unknown Emitter Line Properties flags %x", props->Flags & 0x00FFFFF0); + captainslog_warn((const char *)str); + } + + size_t mapmode = props->Flags >> W3D_ELINE_TEXTURE_MAP_MODE_OFFSET; + if (mapmode != W3D_ELINE_UNIFORM_WIDTH_TEXTURE_MAP && mapmode != W3D_ELINE_UNIFORM_LENGTH_TEXTURE_MAP + && mapmode != W3D_ELINE_TILED_TEXTURE_MAP) { + StringClass str; + str.Format("W3D_CHUNK_EMITTER_LINE_PROPERTIES Unknown Emitter Mapping Mode %x", mapmode); + captainslog_warn((const char *)str); + } + + WriteChunkData(csave, W3D_CHUNK_EMITTER_LINE_PROPERTIES, props, sizeof(W3dEmitterLinePropertiesStruct)); } DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTICES, W3dVectorStruct) @@ -1346,14 +1007,13 @@ DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_BINORMALS, W3dVectorStruct) DUMP_SERIALIZE_PARSER(W3D_CHUNK_COMPRESSED_ANIMATION) int flavor = ANIM_FLAVOR_TIMECODED; -const char *FlavorTypes[] = { "Timecoded", "Adaptive Delta" }; void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); W3dCompressedAnimHeaderStruct *header = (W3dCompressedAnimHeaderStruct *)chunkdata; - if (header->Flavor < ANIM_FLAVOR_VALID) { - } else { + + if (header->Flavor >= ANIM_FLAVOR_VALID) { StringClass str; str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_HEADER Unknown Flavor Type %x", header->Flavor); captainslog_warn((const char *)str); @@ -1366,7 +1026,16 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkLoadClass &cload, ChunkTree void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER + W3dCompressedAnimHeaderStruct *header = (W3dCompressedAnimHeaderStruct *)data->data->info->value; + + if (header->Flavor >= ANIM_FLAVOR_VALID) { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_HEADER Unknown Flavor Type %x", header->Flavor); + captainslog_warn((const char *)str); + } + + flavor = header->Flavor; + WriteChunkData(csave, W3D_CHUNK_COMPRESSED_ANIMATION_HEADER, header, sizeof(W3dCompressedAnimHeaderStruct)); } void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) @@ -1382,7 +1051,7 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - + AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL", "W3dTimeCodedAnimChannelStruct", "", (void *)channel); delete[] chunkdata; } else { W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)chunkdata; @@ -1394,15 +1063,32 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre captainslog_warn((const char *)str); } + AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL", "W3dAdaptiveDeltaAnimChannelStruct", "", (void *)channel); delete[] chunkdata; } - // TODO valid - // AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL", "char*", "", (void *)channel); } void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL + if (flavor == ANIM_FLAVOR_TIMECODED) { + W3dTimeCodedAnimChannelStruct *channel = (W3dTimeCodedAnimChannelStruct *)data->data->info->value; + if (channel->Flags <= ANIM_CHANNEL_VIS) { + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + WriteChunkData(csave, W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL, channel, sizeof(W3dTimeCodedAnimChannelStruct)); + } else { + W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)data->data->info->value; + if (channel->Flags <= ANIM_CHANNEL_VIS) { + } else { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + WriteChunkData(csave, W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL, channel, sizeof(W3dAdaptiveDeltaAnimChannelStruct)); + } } void Dump_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) @@ -1410,8 +1096,7 @@ void Dump_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr & char *chunkdata = ReadChunkData(cload); W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)chunkdata; - if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { - } else { + if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { StringClass str; str.Format("W3D_CHUNK_COMPRESSED_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); @@ -1423,7 +1108,13 @@ void Dump_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr & void Serialize_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_BIT_CHANNEL + W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)data->data->info->value; + if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + WriteChunkData(csave, W3D_CHUNK_COMPRESSED_BIT_CHANNEL, channel, sizeof(W3dTimeCodedBitChannelStruct)); } DUMP_SERIALIZE_PARSER(W3D_CHUNK_MORPH_ANIMATION) @@ -1432,17 +1123,7 @@ DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MORPHANIM_HEADER, W3dMorphAnimHeaderStruct) DUMP_SERIALIZE_PARSER(W3D_CHUNK_MORPHANIM_CHANNEL) -void Dump_W3D_CHUNK_MORPHANIM_POSENAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_MORPHANIM_POSENAME", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_MORPHANIM_POSENAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_MORPHANIM_POSENAME -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MORPHANIM_POSENAME) DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_KEYDATA, W3dMorphAnimKeyStruct) @@ -1498,6 +1179,8 @@ DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SOUNDROBJ_HEADER, W3dSoundRObjHeaderStruct) void Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkLoadClass &cload, ChunkTreePtr &data) { + // TODO: Implement Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION + captainslog_warn("Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION not implemented"); while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case 0x100: @@ -1549,6 +1232,7 @@ void Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkLoadClass &cload, ChunkTreePtr &da void Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkSaveClass &csave, ChunkTreePtr &data) { // TODO: Implement Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION + captainslog_warn("Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION not implemented"); } void DoVector3Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) @@ -1579,11 +1263,6 @@ void DoVector3Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *nam } } -void Serialize_DoVector3Channel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) -{ - // TODO: Implement Serialize_DoVector3Channel -} - void DoVector2Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) { int i = 0; @@ -1610,11 +1289,6 @@ void DoVector2Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *nam } } -void Serialize_DoVector2Channel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) -{ - // TODO: Implement Serialize_DoVector2Channel -} - void DofloatChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) { int i = 0; @@ -1639,11 +1313,6 @@ void DofloatChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) } } -void Serialize_DofloatChannel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) -{ - // TODO: Implement Serialize_DofloatChannel -} - void DoAlphaVectorStructChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) { int i = 0; @@ -1676,52 +1345,23 @@ void DoAlphaVectorStructChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const } } -void Serialize_DoAlphaVectorStructChannel(ChunkSaveClass &csave, ChunkTreePtr &data, const char *name) -{ - // TODO: Implement Serialize_DoAlphaVectorStructChannel -} - void Dump_W3D_CHUNK_RING(ChunkLoadClass &cload, ChunkTreePtr &data) { + // TODO: Implement Dump_W3D_CHUNK_RING + captainslog_warn("Dump_W3D_CHUNK_RING not implemented"); while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case 1: { - W3dRingStruct RingStruct; - cload.Read(&RingStruct, sizeof(RingStruct)); - AddInt32(data, "unk0", RingStruct.unk0); - AddInt32(data, "Flags", RingStruct.Flags); - - if (RingStruct.Flags & RING_CAMERA_ALIGNED) { - AddString(data, "Flags", "RING_CAMERA_ALIGNED", "flag"); - } + W3dRingStruct *RingStruct; + cload.Read(RingStruct, sizeof(RingStruct)); - if (RingStruct.Flags & RING_LOOPING) { - AddString(data, "Flags", "RING_LOOPING", "flag"); - } - - if (RingStruct.Flags & 0xFFFFFFFC) { + if (RingStruct->Flags & 0xFFFFFFFC) { StringClass str; - str.Format("W3D_CHUNK_RING Unknown Ring Flags %x", RingStruct.Flags & 0xFFFFFFFC); + str.Format("W3D_CHUNK_RING Unknown Ring Flags %x", RingStruct->Flags & 0xFFFFFFFC); captainslog_warn((const char *)str); } - AddString(data, "Name", RingStruct.Name, "string"); - AddVector(data, "Center", &RingStruct.Center); - AddVector(data, "Extent", &RingStruct.Extent); - AddFloat(data, "AnimationDuration", RingStruct.AnimationDuration); - AddVector(data, "Color", &RingStruct.Color); - AddFloat(data, "Alpha", RingStruct.Alpha); - AddFloat(data, "InnerScale.X", RingStruct.InnerScale.x); - AddFloat(data, "InnerScale.Y", RingStruct.InnerScale.y); - AddFloat(data, "OuterScale.X", RingStruct.OuterScale.x); - AddFloat(data, "OuterScale.Y", RingStruct.OuterScale.y); - AddFloat(data, "InnerExtent.X", RingStruct.InnerExtent.x); - AddFloat(data, "InnerExtent.Y", RingStruct.InnerExtent.y); - AddFloat(data, "OuterExtent.X", RingStruct.OuterExtent.x); - AddFloat(data, "OuterExtent.Y", RingStruct.OuterExtent.y); - AddString(data, "TextureName", RingStruct.TextureName, "string"); - AddShader(data, "Shader", &RingStruct.Shader); - AddInt32(data, "TextureTiling", RingStruct.TextureTiling); + AddData(data, "W3D_CHUNK_RING", "W3dRingStruct", "", (void *)RingStruct); break; } case 2: @@ -1744,48 +1384,26 @@ void Dump_W3D_CHUNK_RING(ChunkLoadClass &cload, ChunkTreePtr &data) void Serialize_W3D_CHUNK_RING(ChunkSaveClass &csave, ChunkTreePtr &data) { // TODO: Implement Serialize_W3D_CHUNK_RING + captainslog_warn("Serialize_W3D_CHUNK_RING not implemented"); } void Dump_W3D_CHUNK_SPHERE(ChunkLoadClass &cload, ChunkTreePtr &data) { + // TODO: Implement Dump_W3D_CHUNK_SPHERE + captainslog_warn("Dump_W3D_CHUNK_SPHERE not implemented"); while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case 1: { - W3dSphereStruct SphereStruct; - cload.Read(&SphereStruct, sizeof(SphereStruct)); - AddInt32(data, "unk0", SphereStruct.unk0); - AddInt32(data, "Flags", SphereStruct.Flags); - if (SphereStruct.Flags & SPHERE_ALPHA_VECTOR) { - AddString(data, "Flags", "SPHERE_ALPHA_VECTOR", "flag"); - } - if (SphereStruct.Flags & SPHERE_CAMERA_ALIGNED) { - AddString(data, "Flags", "SPHERE_CAMERA_ALIGNED", "flag"); - } - if (SphereStruct.Flags & SPHERE_INVERT_EFFECT) { - AddString(data, "Flags", "SPHERE_INVERT_EFFECT", "flag"); - } - if (SphereStruct.Flags & SPHERE_LOOPING) { - AddString(data, "Flags", "SPHERE_LOOPING", "flag"); - } - if (SphereStruct.Flags & 0xFFFFFFF0) { + W3dSphereStruct *SphereStruct; + cload.Read(SphereStruct, sizeof(SphereStruct)); + + if (SphereStruct->Flags & 0xFFFFFFF0) { StringClass str; - str.Format("W3D_CHUNK_SPHERE Unknown Sphere Flags %x", SphereStruct.Flags & 0xFFFFFFFC); + str.Format("W3D_CHUNK_SPHERE Unknown Sphere Flags %x", SphereStruct->Flags & 0xFFFFFFFC); captainslog_warn((const char *)str); } - AddString(data, "Name", SphereStruct.Name, "string"); - AddVector(data, "Center", &SphereStruct.Center); - AddVector(data, "Extent", &SphereStruct.Extent); - AddFloat(data, "AnimationDuration", SphereStruct.AnimationDuration); - AddVector(data, "Color", &SphereStruct.Color); - AddFloat(data, "Alpha", SphereStruct.Alpha); - AddVector(data, "Scale", &SphereStruct.Scale); - AddFloat(data, "Vector.Quat.X", SphereStruct.Vector.Quat.X); - AddFloat(data, "Vector.Quat.Y", SphereStruct.Vector.Quat.Y); - AddFloat(data, "Vector.Quat.Z", SphereStruct.Vector.Quat.Z); - AddFloat(data, "Vector.Quat.W", SphereStruct.Vector.Quat.W); - AddFloat(data, "Vector.Magnutide", SphereStruct.Vector.Magnitude); - AddString(data, "TextureName", SphereStruct.TextureName, "string"); - AddShader(data, "Shader", &SphereStruct.Shader); + AddData(data, "W3D_CHUNK_SPHERE", "W3dSphereStruct", "", (void *)SphereStruct); + } break; case 2: DoVector3Channel(cload, data, "ColorChannel"); @@ -1807,21 +1425,12 @@ void Dump_W3D_CHUNK_SPHERE(ChunkLoadClass &cload, ChunkTreePtr &data) void Serialize_W3D_CHUNK_SPHERE(ChunkSaveClass &csave, ChunkTreePtr &data) { // TODO: Implement Serialize_W3D_CHUNK_SPHERE + captainslog_warn("Serialize_W3D_CHUNK_SPHERE not implemented"); } DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDMESH) -void Dump_W3D_CHUNK_SHDMESH_NAME(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_SHDMESH_NAME", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_SHDMESH_NAME(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_SHDMESH_NAME -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_SHDMESH_NAME) DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDSUBMESH) @@ -1849,17 +1458,7 @@ DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_SXT, W3dVectorStru DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_EXTRA_INFO, W3dEmitterExtraInfoStruct) -void Dump_W3D_CHUNK_SHDMESH_USER_TEXT(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - AddString(data, "W3D_CHUNK_SHDMESH_USER_TEXT", chunkdata, "string"); - delete[] chunkdata; -} - -void Serialize_W3D_CHUNK_SHDMESH_USER_TEXT(ChunkSaveClass &csave, ChunkTreePtr &data) -{ - // TODO: Implement Serialize_W3D_CHUNK_SHDMESH_USER_TEXT -} +DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_SHDMESH_USER_TEXT) DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_FXSHADER_IDS, uint32_t) @@ -1869,6 +1468,8 @@ DUMP_SERIALIZE_PARSER(W3D_CHUNK_FX_SHADER) void Dump_W3D_CHUNK_FX_SHADER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { + // TODO Fix W3dFXShaderStruct + captainslog_warn("Dump_W3D_CHUNK_FX_SHADER_INFO not implemented"); char *chunkdata = ReadChunkData(cload); uint8_t *version = (uint8_t *)chunkdata; AddInt8(data, "Version", *version); @@ -1881,124 +1482,159 @@ void Dump_W3D_CHUNK_FX_SHADER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) void Serialize_W3D_CHUNK_FX_SHADER_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { // TODO: Implement Serialize_W3D_CHUNK_FX_SHADER_INFO -} + captainslog_warn("Serialize_W3D_CHUNK_FX_SHADER_INFO not implemented"); +} + +struct W3dFXShaderConstantStruct +{ + uint32_t Type; + uint32_t Length; + std::string ConstantName; + union + { + std::string Texture; + std::vector Floats; + uint32_t Int; + bool Bool; + } Value; + + W3dFXShaderConstantStruct &operator=(const char *chunkdata) + { + Type = *(uint32_t *)chunkdata; + Length = *(uint32_t *)(chunkdata + 4); + ConstantName = std::string(chunkdata + 8, Length); + + if (Type == CONSTANT_TYPE_TEXTURE) { + Value.Texture = std::string(chunkdata + 8 + Length); + } else if (Type >= CONSTANT_TYPE_FLOAT1 && Type <= CONSTANT_TYPE_FLOAT4) { + int count = Type - 1; + float *floats = (float *)(chunkdata + 8 + Length); + Value.Floats.assign(floats, floats + count); + } else if (Type == CONSTANT_TYPE_INT) { + Value.Int = *(uint32_t *)(chunkdata + 8 + Length); + } else if (Type == CONSTANT_TYPE_BOOL) { + Value.Bool = *(uint8_t *)(chunkdata + 8 + Length) != 0; + } else { + // Handle unknown types + Value.Texture = "Unknown"; + } -const char *Types[] = { "Texture", "Float", "Vector2", "Vector3", "Vector4", "Int", "Bool" }; + return *this; + } +}; void Dump_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkLoadClass &cload, ChunkTreePtr &data) { char *chunkdata = ReadChunkData(cload); - uint32_t type = *(uint32_t *)chunkdata; - uint32_t length = *(uint32_t *)(chunkdata + 4); - char *constantname = (char *)(chunkdata + 4 + 4); - AddString(data, "Type", Types[type - 1], "String"); - AddString(data, "Constant Name", constantname, "String"); - - if (type == CONSTANT_TYPE_TEXTURE) { - char *texture = (char *)(chunkdata + 4 + 4 + length + 4); - AddString(data, "Texture", texture, "String"); - } else if (type >= CONSTANT_TYPE_FLOAT1 && type <= CONSTANT_TYPE_FLOAT4) { - int count = type - 1; - float *floats = (float *)(chunkdata + 4 + 4 + length); - AddFloatArray(data, "Floats", floats, count); - } else if (type == CONSTANT_TYPE_INT) { - uint32_t u = *(uint32_t *)(chunkdata + 4 + 4 + length); - AddInt32(data, "Int", u); - } else if (type == CONSTANT_TYPE_BOOL) { - uint8_t u = *(uint8_t *)(chunkdata + 4 + 4 + length); - AddInt32(data, "Bool", u); - } else { + W3dFXShaderConstantStruct *constant = (W3dFXShaderConstantStruct *)chunkdata; + if (constant->Value.Texture == "Unknown") { StringClass str; - str.Format("W3D_CHUNK_FX_SHADER_CONSTANT Unknown Constant Type %x", type); + str.Format("W3D_CHUNK_FX_SHADER_CONSTANT Unknown Constant Type %x", constant->Type); captainslog_warn((const char *)str); } - + AddData(data, "W3D_CHUNK_FX_SHADER_CONSTANT", "W3dFXShaderConstantStruct", "", (void *)constant); delete[] chunkdata; } void Serialize_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_FX_SHADER_CONSTANT -} -const char *NewFlavorTypes[] = { "Timecoded", "Adaptive Delta 4", "Adaptive Delta 8" }; - -void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - W3dCompressedMotionChannelStruct *channel = (W3dCompressedMotionChannelStruct *)chunkdata; - - if (channel->Flavor < ANIM_FLAVOR_NEW_VALID) { - AddString(data, "Flavor", NewFlavorTypes[channel->Flavor], "string"); - } else { - StringClass str; - str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Flavor Type %x", channel->Flavor); - captainslog_warn((const char *)str); - } - - AddInt8(data, "VectorLen", channel->VectorLen); - - if (channel->Flags <= ANIM_CHANNEL_VIS) { - // AddString(data, "ChannelType", ChannelTypes[channel->Flags], "string"); - } else { + W3dFXShaderConstantStruct *constant = (W3dFXShaderConstantStruct *)data->data->info->value; + if (constant->Value.Texture == "Unknown") { StringClass str; - str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + str.Format("W3D_CHUNK_FX_SHADER_CONSTANT Unknown Constant Type %x", constant->Type); captainslog_warn((const char *)str); } + WriteChunkData(csave, W3D_CHUNK_FX_SHADER_CONSTANT, constant, sizeof(W3dFXShaderConstantStruct)); +} - AddInt32(data, "NumTimeCodes", channel->NumTimeCodes); - AddInt16(data, "Pivot", channel->Pivot); +struct W3dCompressedMotionChannelStructNew +{ + uint8_t Zero; + uint8_t Flavor; + uint8_t VectorLen; + uint8_t Flags; + uint16_t NumTimeCodes; + uint16_t Pivot; - if (channel->Flavor == ANIM_FLAVOR_NEW_TIMECODED) { - uint16_t *keyframes = (uint16_t *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct)); + std::vector KeyFrames; // ANIM_FLAVOR_NEW_TIMECODED + float Scale; // עבור Scale + std::vector Initial; + std::vector Data; - for (int i = 0; i < channel->NumTimeCodes; i++) { - StringClass str; - str.Format("KeyFrames[%d]", i); - AddInt32(data, str, keyframes[i]); - } + W3dCompressedMotionChannelStructNew &operator=(const char *chunkdata) + { + Zero = *(uint8_t *)chunkdata; + Flavor = *(uint8_t *)(chunkdata + 1); + VectorLen = *(uint8_t *)(chunkdata + 2); + Flags = *(uint8_t *)(chunkdata + 3); + NumTimeCodes = *(uint16_t *)(chunkdata + 4); + Pivot = *(uint16_t *)(chunkdata + 6); - int datalen = channel->VectorLen * channel->NumTimeCodes; - int pos = sizeof(W3dCompressedMotionChannelStruct); - pos += channel->NumTimeCodes * 2; + size_t offset = sizeof(W3dCompressedMotionChannelStructNew); - if (channel->NumTimeCodes & 1) { - pos += 2; - } + if (Flavor == ANIM_FLAVOR_NEW_TIMECODED) { + KeyFrames.assign( + (uint16_t *)(chunkdata + offset), (uint16_t *)(chunkdata + offset + NumTimeCodes * sizeof(uint16_t))); + offset += NumTimeCodes * sizeof(uint16_t); - uint32_t *values = (uint32_t *)(chunkdata + pos); + int datalen = VectorLen * NumTimeCodes; + if (NumTimeCodes & 1) { + offset += 2; // Padding for odd NumTimeCodes + } + Data.assign((uint32_t *)(chunkdata + offset), (uint32_t *)(chunkdata + offset + datalen * sizeof(uint32_t))); + } else { + Scale = *(float *)(chunkdata + offset); + offset += sizeof(float); - for (int i = 0; i < datalen; i++) { - StringClass str; - str.Format("Data[%d]", i); - AddInt32(data, str, values[i]); - } - } else { - float *scale = (float *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct)); - AddFloat(data, "Scale", *scale); - float *initial = (float *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct) + 4); + Initial.assign((float *)(chunkdata + offset), (float *)(chunkdata + offset + VectorLen * sizeof(float))); + offset += VectorLen * sizeof(float); - for (int i = 0; i < channel->VectorLen; i++) { - StringClass str; - str.Format("Initial[%d]", i); - AddFloat(data, str, initial[i]); + int count = (NumTimeCodes * VectorLen - sizeof(W3dCompressedMotionChannelStructNew) - sizeof(float) + - sizeof(float) * VectorLen) + / sizeof(uint32_t); + Data.assign((uint32_t *)(chunkdata + offset), (uint32_t *)(chunkdata + offset + count * sizeof(uint32_t))); } + return *this; + } +}; - int count = (cload.Cur_Chunk_Length() - sizeof(W3dCompressedMotionChannelStruct) - 4 - 4 * channel->VectorLen) / 4; - uint32_t *values = (uint32_t *)(chunkdata + sizeof(W3dCompressedMotionChannelStruct) + 4 + 4 * channel->VectorLen); +void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *chunkdata = ReadChunkData(cload); + W3dCompressedMotionChannelStructNew *channel = (W3dCompressedMotionChannelStructNew *)chunkdata; + if (channel->Flavor >= ANIM_FLAVOR_NEW_VALID) { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Flavor Type %x", channel->Flavor); + captainslog_warn((const char *)str); + } - for (int i = 0; i < count; i++) { - StringClass str; - str.Format("Data[%d]", i); - AddInt32(data, str, values[i]); - } + if (channel->Flags > ANIM_CHANNEL_VIS) { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); } + AddData( + data, "W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL", "W3dCompressedMotionChannelStructNew", "", (void *)channel); delete[] chunkdata; } void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL + W3dCompressedMotionChannelStructNew *channel = (W3dCompressedMotionChannelStructNew *)data->data->info->value; + if (channel->Flavor >= ANIM_FLAVOR_NEW_VALID) { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Flavor Type %x", channel->Flavor); + captainslog_warn((const char *)str); + } + + if (channel->Flags > ANIM_CHANNEL_VIS) { + StringClass str; + str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); + captainslog_warn((const char *)str); + } + WriteChunkData( + csave, W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL, channel, sizeof(W3dCompressedMotionChannelStructNew)); } std::map chunkFuncMap; @@ -2183,4 +1819,5 @@ void ChunkManager::InitiateChunkFuncMap() CHUNK(W3D_CHUNK_FX_SHADER_INFO) CHUNK(W3D_CHUNK_FX_SHADER_CONSTANT) CHUNK(W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL) -} \ No newline at end of file +} +#pragma clang diagnostic pop \ No newline at end of file diff --git a/src/tools/gamemodelconverter/src/chunksmanager.cpp b/src/tools/gamemodelconverter/src/chunksmanager.cpp index a1d6095b0..90b970030 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.cpp +++ b/src/tools/gamemodelconverter/src/chunksmanager.cpp @@ -13,20 +13,21 @@ ChunkManager::~ChunkManager() } } -void ChunkManager::ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) +void ChunkManager::DumpSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) { if (parentChunk == nullptr) { parentChunk = std::make_unique(); } - while (chunkLoader.Open_Chunk()) { - if (chunkLoader.Contains_Chunks()) { - while (chunkLoader.Open_Chunk()) { - ChunkTreePtr subchunk = std::make_unique(); - ReadChunkInfo(chunkLoader, subchunk); - parentChunk->subchunks.push_back(std::move(subchunk)); - chunkLoader.Close_Chunk(); - } + + if (!parentChunk->data) { + if (chunkLoader.Open_Chunk()) { + ReadChunkInfo(chunkLoader, parentChunk); } + } + while (chunkLoader.Open_Chunk()) { + ChunkTreePtr subchunk = std::make_unique(); + ReadChunkInfo(chunkLoader, subchunk); + parentChunk->subchunks.push_back(std::move(subchunk)); chunkLoader.Close_Chunk(); } } @@ -37,11 +38,13 @@ void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &data captainslog_error("Chunk is null"); return; } - ChunkPtr chunk = std::make_unique(); - chunk->chunkType = chunkLoader.Cur_Chunk_ID(); - chunk->chunkSize = chunkLoader.Cur_Chunk_Length(); - data->data = std::move(chunk); - data->subchunks = std::vector(1); + if (!data->data) { + ChunkPtr chunk = std::make_unique(); + chunk->chunkType = chunkLoader.Cur_Chunk_ID(); + chunk->chunkSize = chunkLoader.Cur_Chunk_Length(); + data->data = std::move(chunk); + } + auto it = chunkFuncMap.find(data->data->chunkType); if (it != chunkFuncMap.end()) { it->second.ReadFunc(chunkLoader, data); @@ -49,26 +52,25 @@ void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &data StringClass str; str.Format("Unknown Chunk 0x%X", data->data->chunkType); captainslog_warn((const char *)str); - chunk->info = nullptr; + data->data->info = nullptr; } } -void ChunkManager::WriteSubchunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk) +void ChunkManager::SerializeSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk) { if (parentChunk->data) { if (!chunkSaver.Begin_Chunk(parentChunk->data->chunkType)) { captainslog_error("Failed to begin chunk"); return; } - WriteChunkInfo(chunkSaver, parentChunk); + // Parent chunk data, no data to write, continue to subchunks if (!chunkSaver.End_Chunk()) { captainslog_error("Failed to end chunk"); return; } - } - for (auto& subchunk : parentChunk->subchunks) { + for (auto &subchunk : parentChunk->subchunks) { WriteChunkInfo(chunkSaver, subchunk); } } @@ -81,6 +83,6 @@ void ChunkManager::WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &data } else { StringClass str; str.Format("Unknown Chunk 0x%X", data->data->chunkType); - captainslog_warn((const char*)str); + captainslog_warn((const char *)str); } } diff --git a/src/tools/gamemodelconverter/src/chunksmanager.h b/src/tools/gamemodelconverter/src/chunksmanager.h index ea2faa382..a153a2348 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.h +++ b/src/tools/gamemodelconverter/src/chunksmanager.h @@ -77,10 +77,10 @@ class ChunkManager return std::make_unique(name, type, data, value); } - static void ParseSubchunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); + static void DumpSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); static void ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &chunk); - void WriteSubchunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk); - void WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &chunk); + static void SerializeSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk); + static void WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &chunk); ChunkTreePtr & GetRootChunk() { return m_rootChunk; } void SetRootChunk(ChunkTreePtr root) { m_rootChunk = std::move(root); } diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index b5b3678b3..4c724a646 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -14,7 +14,6 @@ */ #include "gamemodelfile.h" - #define GAMEMODELLOG_TRACE(fmt, ...) \ captainslog_trace(fmt, ##__VA_ARGS__); \ GameModelFile::Log_Line("TRACE : ", fmt, ##__VA_ARGS__) @@ -105,7 +104,6 @@ GameModelFile::FileType GameModelFile::Get_File_Type(const char *filename, FileT return filetype; } - bool GameModelFile::Load(const char *filename) { const FileType filetype = Get_File_Type(filename, FileType::AUTO); @@ -230,7 +228,6 @@ bool GameModelFile::Save(const char *filename, FileType filetype) // return false; // } - bool success = false; switch (filetype) { @@ -265,18 +262,16 @@ void GameModelFile::Reset() { m_options = Options::Value::NONE; // TODO good free memory? -// if (m_chunkManager) { -// delete m_chunkManager; -// m_chunkManager = nullptr; -// } + // if (m_chunkManager) { + // delete m_chunkManager; + // m_chunkManager = nullptr; + // } } -bool GameModelFile::Read_W3D_File(const char *filename, const Options& options) +bool GameModelFile::Read_W3D_File(const char *filename, const Options &options) { GAMEMODELLOG_INFO("Reading model file '%s' in W3D format", filename); - - auto_file_ptr file(g_theFileFactory, filename); if (!file->Open(FileOpenType::FM_READ)) { GAMEMODELLOG_ERROR("Could not open file: %s", filename); @@ -284,19 +279,14 @@ bool GameModelFile::Read_W3D_File(const char *filename, const Options& options) } m_chunkManager = new ChunkManager(filename, ChunkManager::ChunkManagerType::LOAD); m_chunkLoader = ChunkLoadClass(file); - m_chunkManager->ParseSubchunks(m_chunkLoader, m_chunkManager->GetRootChunk()); -// if (!Log_Unknown_Chunks(m_rootChunk)) { -// GAMEMODELLOG_ERROR("Unknown chunks found in file: %s", filename); -// GAMEMODELLOG_ERROR("Failed to load chunks correctly"); -// return false; -// } -// else { + m_chunkManager->DumpSubChunks(m_chunkLoader, m_chunkManager->GetRootChunk()); + // TODO unknown chunks GAMEMODELLOG_INFO("Successfully parsed W3D file: %s", filename); return true; } -bool GameModelFile::Write_W3D_File(const char *filename, const Options& options) +bool GameModelFile::Write_W3D_File(const char *filename, const Options &options) { GAMEMODELLOG_INFO("Writing model file '%s' in W3D format", filename); @@ -306,7 +296,7 @@ bool GameModelFile::Write_W3D_File(const char *filename, const Options& options) return false; } ChunkSaveClass chunkSaver(file); - m_chunkManager->WriteSubchunks(chunkSaver, m_chunkManager->GetRootChunk()); + m_chunkManager->SerializeSubChunks(chunkSaver, m_chunkManager->GetRootChunk()); return true; } From 9d32c18fea9226b52aa753a394f228efed2fff93 Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Thu, 30 Jan 2025 03:19:23 +0200 Subject: [PATCH 11/13] Refactor chunk management functions --- .../gamemodelconverter/src/chunkfactory.cpp | 972 +++++++++--------- .../gamemodelconverter/src/chunksmanager.cpp | 14 +- .../gamemodelconverter/src/chunksmanager.h | 13 +- .../gamemodelconverter/src/gamemodelfile.cpp | 4 +- 4 files changed, 519 insertions(+), 484 deletions(-) diff --git a/src/tools/gamemodelconverter/src/chunkfactory.cpp b/src/tools/gamemodelconverter/src/chunkfactory.cpp index e1cd76b04..f0d3a6f23 100644 --- a/src/tools/gamemodelconverter/src/chunkfactory.cpp +++ b/src/tools/gamemodelconverter/src/chunkfactory.cpp @@ -6,7 +6,7 @@ // Helper Functions -char *ReadChunkData(ChunkLoadClass &cload) +char *ReadChunkRaw(ChunkLoadClass &cload) { if (!cload.Cur_Chunk_Length()) { char *c = new char[1]; @@ -14,15 +14,17 @@ char *ReadChunkData(ChunkLoadClass &cload) return c; } char *c = new char[cload.Cur_Chunk_Length()]; - cload.Read(c, cload.Cur_Chunk_Length()); + size_t bytes = cload.Read(c, cload.Cur_Chunk_Length()); + captainslog_dbgassert(cload.Cur_Chunk_Length() == bytes, "Read chunk size does not match data size"); return c; } -void WriteChunkData(ChunkSaveClass &csave, unsigned id, const void *data, unsigned dataSize) +void WriteChunkRaw(ChunkSaveClass &csave, unsigned id, const void *data, unsigned dataSize) { csave.Begin_Chunk(id); - csave.Write(data, dataSize); - csave.End_Chunk(); // TODO ASSERT SIZE + size_t bytes = csave.Write(data, dataSize); + captainslog_dbgassert(dataSize == bytes, "Write chunk size does not match data size"); + csave.End_Chunk(); } template void WriteArray(ChunkSaveClass &csave, unsigned id, unsigned dataSize, unsigned numElements) @@ -80,258 +82,267 @@ void AddVector(ChunkTreePtr &data, const char *name, const W3dVectorStruct *valu // Macro for Defining Functions -#define DUMP_SERIALIZE_CHUNK_STRING(name) \ - void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ - { \ - char *chunkdata = ReadChunkData(cload); \ - AddString(data, #name, chunkdata, "string"); \ - delete[] chunkdata; \ - } \ -\ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ - { \ - char *chunkdata = (char *)data->data->info->value; \ - WriteChunkData(csave, name, chunkdata, sizeof(chunkdata)); \ +// Macro for Defining Functions +// READ_WRITE_CHUNK_STRING +template void Read_Chunk_String(ChunkLoadClass &cload, ChunkTreePtr &data, const char *id) +{ + char* rawData = ReadChunkRaw(cload); + if (strlen(rawData) == 0) { // case of null terminator + for (unsigned i = 0; i < data->data->chunkSize; i++) { + captainslog_dbgassert(rawData[i] == '\0', "Chunk %s size does not match data size", id); + } + } else { + captainslog_dbgassert(data->data->chunkSize == strlen(rawData) + 1, "Chunk %s size does not match data size", id); } + AddData(data, id, "string", rawData, (void *)rawData); +} -#define DUMP_SERIALIZE_CHUNK(name, type) \ - void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ - { \ - char *chunkdata = ReadChunkData(cload); \ - type *chunkData = (type *)chunkdata; \ - AddData(data, #name, #type, "", (void *)chunkData); \ - delete[] chunkdata; \ - } \ -\ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ - { \ - type *chunkData = (type *)data->data->info->value; \ - WriteChunkData(csave, name, chunkData, sizeof(type)); \ +template void Write_Chunk_String(ChunkSaveClass &csave, ChunkTreePtr &data, unsigned id) +{ + char* rawData = (char*)data->data->info->value; + if (strlen(rawData) == 0) { // case of null terminator + for (unsigned i = 0; i < data->data->chunkSize; i++) { + captainslog_dbgassert(rawData[i] == '\0', "Chunk %s size does not match data size", id); + } + } else { + captainslog_dbgassert(data->data->chunkSize == strlen(rawData) + 1, "Chunk %s size does not match data size", id); } + WriteChunkRaw(csave, id, rawData, data->data->chunkSize); +} +#define READ_WRITE_CHUNK_STRING(id) \ + void Read_##id(ChunkLoadClass &cload, ChunkTreePtr &data) { Read_Chunk_String(cload, data, #id); } \ + void Write_##id(ChunkSaveClass &csave, ChunkTreePtr &data) { Write_Chunk_String(csave, data, id); } \ -#define DUMP_SERIALIZE_CHUNK_ARRAY(name, type) \ - void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ - { \ - char *chunkdata = ReadChunkData(cload); \ - type *arrayData = (type *)chunkdata; \ - AddData(data, #name, #type "[]", "", (void *)arrayData); \ - delete[] chunkdata; \ - } \ -\ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ - { \ - type *arrayData = (type *)data->data->info->value; \ - unsigned numElements = data->data->chunkSize / sizeof(type); \ - WriteChunkData(csave, name, arrayData, numElements * sizeof(type)); \ - } +// READ_WRITE_CHUNK +template void Read_Chunk_Struct(ChunkLoadClass &cload, ChunkTreePtr &data, const char *id) +{ + char* rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(T), "Chunk %s size does not match data size", id); + AddData(data, id, typeid(T).name(), "", (void *)rawData); +} -#define DUMP_SERIALIZE_PARSER(name) \ - void Dump_##name(ChunkLoadClass &cload, ChunkTreePtr &data) \ - { \ - AddString(data, #name, "", "string"); \ - ChunkManager::DumpSubChunks(cload, data); \ - } \ -\ - void Serialize_##name(ChunkSaveClass &csave, ChunkTreePtr &data) \ - { \ - ChunkManager::SerializeSubChunks(csave, data); \ - } +template void Write_Chunk_Struct(ChunkSaveClass &csave, ChunkTreePtr &data, unsigned id) +{ + char *rawData = (char *)data->data->info->value; + captainslog_dbgassert(data->data->chunkSize == sizeof(T), "Chunk %X size does not match data size", id); + WriteChunkRaw(csave, id, rawData, sizeof(T)); +} +#define READ_WRITE_CHUNK(id, type) \ + void Read_##id(ChunkLoadClass &cload, ChunkTreePtr &data) { Read_Chunk_Struct(cload, data, #id); } \ + void Write_##id(ChunkSaveClass &csave, ChunkTreePtr &data) { Write_Chunk_Struct(csave, data, id); } \ -// Example Replacement: -void Dump_PARSER_DUMMY(ChunkLoadClass &cload, ChunkTreePtr &data) +// READ_WRITE_CHUNK_ARRAY +template void Read_Chunk_Array(ChunkLoadClass &cload, ChunkTreePtr &data, const char *id) { - // spilt name from Dump___func__, no need in macros - const char *name = strstr(__func__, "Dump_") + 5; - AddString(data, name, "", "string"); - data->subchunks = std::vector(1); - ChunkManager::DumpSubChunks(cload, data); + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize % sizeof(T) == 0, "Chunk %s size does not match data size", id); + std::vector *arrayData = new std::vector(); + unsigned numElements = data->data->chunkSize / sizeof(T); + + for (unsigned i = 0; i < numElements; i++) { + arrayData->push_back(*reinterpret_cast(rawData + i * sizeof(T))); + } + + AddData(data, id, (std::string(typeid(T).name()) + "[]").c_str(), "", (void *)arrayData); + delete [] rawData; } -void Dump_W3D_CHUNK_ARRAY_DUMMY(ChunkLoadClass &cload, ChunkTreePtr &data) + +template void Write_Chunk_Array(ChunkSaveClass &csave, ChunkTreePtr &data, unsigned id) { - char *chunkdata = ReadChunkData(cload); - W3dMaterialStruct *arrayData = (W3dMaterialStruct *)chunkdata; - AddData(data, "O_W3D_CHUNK_MATERIALS", "W3dMaterialStruct[]", "", (void *)arrayData); - delete[] chunkdata; + std::vector* arrayData = reinterpret_cast*>(data->data->info->value); + captainslog_dbgassert(data->data->chunkSize % sizeof(T) == 0, "Chunk %X size does not match data size", id); + unsigned numElements = data->data->chunkSize / sizeof(T); + char *chunkData = new char[numElements * sizeof(T)]; + for (unsigned i = 0; i < numElements; i++) { + memcpy(chunkData + i * sizeof(T), &(*arrayData)[i], sizeof(T)); + } + WriteChunkRaw(csave, id, chunkData, numElements * sizeof(T)); + + delete[] chunkData; } +#define READ_WRITE_CHUNK_ARRAY(id, type) \ + void Read_##id(ChunkLoadClass &cload, ChunkTreePtr &data) { Read_Chunk_Array(cload, data, #id); } \ + void Write_##id(ChunkSaveClass &csave, ChunkTreePtr &data) { Write_Chunk_Array(csave, data, id); } \ -void Serialize_W3D_CHUNK_ARRAY_DUMMY(ChunkSaveClass &csave, ChunkTreePtr &data) +// READ_WRITE_SUBCHUNKS +template void Read_Sub_Chunks(ChunkLoadClass &cload, ChunkTreePtr &data, const char *id) { - W3dMaterialStruct *arrayData = (W3dMaterialStruct *)data->data->info->value; - unsigned numElements = data->data->chunkSize / sizeof(W3dMaterialStruct); - WriteChunkData(csave, O_W3D_CHUNK_MATERIALS, arrayData, numElements * sizeof(W3dMaterialStruct)); + AddString(data, id, id, "StringClass"); + ChunkManager::ReadSubChunks(cload, data); } -void Dump_W3D_CHUNK_PARSER_DUMMY(ChunkLoadClass &cload, ChunkTreePtr &data) +template void Write_Sub_Chunks(ChunkSaveClass &csave, ChunkTreePtr &data) { - // Because data is parent chunk, we need to add the name of the chunk, no any data or value - AddString(data, "W3D_CHUNK_ARRAY_DUMMY", "", "string"); - ChunkManager::DumpSubChunks(cload, data); + ChunkManager::WriteSubChunks(csave, data); } +#define READ_WRITE_SUBCHUNKS(id) \ + void Read_##id(ChunkLoadClass &cload, ChunkTreePtr &data) { Read_Sub_Chunks(cload, data, #id); } \ + void Write_##id(ChunkSaveClass &csave, ChunkTreePtr &data) { Write_Sub_Chunks(csave, data); } \ -// Dump and Serialize Functions -DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS, W3dMaterialStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS2, W3dMaterial2Struct) +// Read and Write Functions +READ_WRITE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS, W3dMaterialStruct) -void Dump_O_W3D_CHUNK_POV_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +READ_WRITE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS2, W3dMaterial2Struct) + +void Read_O_W3D_CHUNK_POV_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_POV_QUADRANGLES is unsupported"); - char *chunkdata = ReadChunkData(cload); - AddData(data, "O_W3D_CHUNK_POV_QUADRANGLES", "char", "string", (void *)chunkdata); - delete[] chunkdata; + char *rawData = ReadChunkRaw(cload); + AddData(data, "O_W3D_CHUNK_POV_QUADRANGLES", "char", "string", (void *)rawData); } -void Serialize_O_W3D_CHUNK_POV_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_O_W3D_CHUNK_POV_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_POV_QUADRANGLES is unsupported"); - char *chunkdata = (char *)data->data->info->value; - WriteChunkData(csave, O_W3D_CHUNK_POV_QUADRANGLES, chunkdata, data->data->chunkSize); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, O_W3D_CHUNK_POV_QUADRANGLES, rawData, data->data->chunkSize); } -void Dump_O_W3D_CHUNK_POV_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_O_W3D_CHUNK_POV_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_POV_TRIANGLES is unsupported"); - char *chunkdata = ReadChunkData(cload); - AddData(data, "O_W3D_CHUNK_POV_TRIANGLES", "char", "string", (void *)chunkdata); - delete[] chunkdata; + char *rawData = ReadChunkRaw(cload); + AddData(data, "O_W3D_CHUNK_POV_TRIANGLES", "char", "string", (void *)rawData); } -void Serialize_O_W3D_CHUNK_POV_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_O_W3D_CHUNK_POV_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_POV_TRIANGLES is unsupported"); - char *chunkdata = (char *)data->data->info->value; - WriteChunkData(csave, O_W3D_CHUNK_POV_TRIANGLES, chunkdata, data->data->chunkSize); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, O_W3D_CHUNK_POV_TRIANGLES, rawData, data->data->chunkSize); } -void Dump_O_W3D_CHUNK_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_O_W3D_CHUNK_QUADRANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_QUADRANGLES is outdated"); - char *chunkdata = ReadChunkData(cload); - AddData(data, "O_W3D_CHUNK_QUADRANGLES", "char", "string", (void *)chunkdata); - delete[] chunkdata; + char *rawData = ReadChunkRaw(cload); + AddData(data, "O_W3D_CHUNK_QUADRANGLES", "char", "string", (void *)rawData); } -void Serialize_O_W3D_CHUNK_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_O_W3D_CHUNK_QUADRANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_QUADRANGLES is outdated"); - char *chunkdata = (char *)data->data->info->value; - WriteChunkData(csave, O_W3D_CHUNK_QUADRANGLES, chunkdata, data->data->chunkSize); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, O_W3D_CHUNK_QUADRANGLES, rawData, data->data->chunkSize); } -DUMP_SERIALIZE_CHUNK_ARRAY(O_W3D_CHUNK_SURRENDER_TRIANGLES, W3dSurrenderTriangleStruct) +READ_WRITE_CHUNK_ARRAY(O_W3D_CHUNK_SURRENDER_TRIANGLES, W3dSurrenderTriangleStruct) -void Dump_O_W3D_CHUNK_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_O_W3D_CHUNK_TRIANGLES(ChunkLoadClass &cload, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_TRIANGLES is obsoleted"); - char *chunkdata = ReadChunkData(cload); - AddData(data, "O_W3D_CHUNK_TRIANGLES", "char", "string", (void *)chunkdata); - delete[] chunkdata; + char *rawData = ReadChunkRaw(cload); + AddData(data, "O_W3D_CHUNK_TRIANGLES", "char", "string", (void *)rawData); } -void Serialize_O_W3D_CHUNK_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_O_W3D_CHUNK_TRIANGLES(ChunkSaveClass &csave, ChunkTreePtr &data) { captainslog_warn("O_W3D_CHUNK_TRIANGLES is obsoleted"); - char *chunkdata = (char *)data->data->info->value; - WriteChunkData(csave, O_W3D_CHUNK_TRIANGLES, chunkdata, data->data->chunkSize); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, O_W3D_CHUNK_TRIANGLES, rawData, data->data->chunkSize); } -DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_COLOR_KEYFRAME, W3dEmitterColorKeyframeStruct) +READ_WRITE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_COLOR_KEYFRAME, W3dEmitterColorKeyframeStruct) -DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_OPACITY_KEYFRAME, W3dEmitterOpacityKeyframeStruct) +READ_WRITE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_OPACITY_KEYFRAME, W3dEmitterOpacityKeyframeStruct) -DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_SIZE_KEYFRAME, W3dEmitterSizeKeyframeStruct) +READ_WRITE_CHUNK(OBSOLETE_W3D_CHUNK_EMITTER_SIZE_KEYFRAME, W3dEmitterSizeKeyframeStruct) -DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_SHADOW_NODE, W3dHModelNodeStruct) +READ_WRITE_CHUNK(OBSOLETE_W3D_CHUNK_SHADOW_NODE, W3dHModelNodeStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_AABTREE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_AABTREE) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AABTREE_HEADER, W3dMeshAABTreeHeader) +READ_WRITE_CHUNK(W3D_CHUNK_AABTREE_HEADER, W3dMeshAABTreeHeader) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_NODES, W3dMeshAABTreeNode) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_NODES, W3dMeshAABTreeNode) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_POLYINDICES, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_AABTREE_POLYINDICES, uint32_t) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_AGGREGATE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_AGGREGATE) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AGGREGATE_CLASS_INFO, W3dAggregateMiscInfo) +READ_WRITE_CHUNK(W3D_CHUNK_AGGREGATE_CLASS_INFO, W3dAggregateMiscInfo) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_AGGREGATE_HEADER, W3dAggregateHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_AGGREGATE_HEADER, W3dAggregateHeaderStruct) -void Dump_W3D_CHUNK_AGGREGATE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_AGGREGATE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dAggregateInfoStruct *info = (W3dAggregateInfoStruct *)chunkdata; - W3dAggregateSubobjectStruct *subobj = (W3dAggregateSubobjectStruct *)(chunkdata + sizeof(W3dAggregateInfoStruct)); - - // TODO: Add Subobjects - captainslog_warn("W3D_CHUNK_AGGREGATE_INFO Subobjects are not correctly implemented"); - AddData(data, "W3D_CHUNK_AGGREGATE_INFO", "W3dAggregateInfoStruct[][]", "Obsolete", (void *)info); - delete[] chunkdata; + char *rawData = ReadChunkRaw(cload); + W3dAggregateInfoStruct *info = (W3dAggregateInfoStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dAggregateInfoStruct) + info->SubobjectCount * sizeof(W3dAggregateSubobjectStruct), + "Chunk W3D_CHUNK_AGGREGATE_INFO size does not match expected size for AggregateInfo structure"); + AddData(data, "W3D_CHUNK_AGGREGATE_INFO", "W3dAggregateInfoStruct[][]", "Obsolete", (void *)rawData); } -void Serialize_W3D_CHUNK_AGGREGATE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_AGGREGATE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - W3dAggregateInfoStruct *info = (W3dAggregateInfoStruct *)data->data->info->value; - WriteChunkData(csave, W3D_CHUNK_AGGREGATE_INFO, info, sizeof(W3dAggregateInfoStruct)); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_AGGREGATE_INFO, rawData, data->data->chunkSize); } -DUMP_SERIALIZE_PARSER(W3D_CHUNK_ANIMATION) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_ANIMATION) -void Dump_W3D_CHUNK_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)rawData; - if (channel->Flags <= ANIM_CHANNEL_VIS) { + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dAnimChannelStruct) + + (channel->LastFrame - channel->FirstFrame) * channel->VectorLen * sizeof(float), + "Chunk W3D_CHUNK_ANIMATION_CHANNEL size does not match data size"); + + if (channel->Flags > ANIM_CHANNEL_VIS) { StringClass str; str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - AddData(data, "W3D_CHUNK_ANIMATION_CHANNEL", "W3dAnimChannelStruct", "", (void *)channel); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_ANIMATION_CHANNEL", "W3dAnimChannelStruct", "", (void *)rawData); } -void Serialize_W3D_CHUNK_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)data->data->info->value; - if (channel->Flags <= ANIM_CHANNEL_VIS) { + if (channel->Flags > ANIM_CHANNEL_VIS) { StringClass str; str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_ANIMATION_CHANNEL, channel, sizeof(W3dAnimChannelStruct)); + WriteChunkRaw(csave, W3D_CHUNK_ANIMATION_CHANNEL, channel, sizeof(W3dAnimChannelStruct)); } -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_ANIMATION_HEADER, W3dAnimHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_ANIMATION_HEADER, W3dAnimHeaderStruct) -void Dump_W3D_CHUNK_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dBitChannelStruct *channel = (W3dBitChannelStruct *)chunkdata; - if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { + char *rawData = ReadChunkRaw(cload); + W3dBitChannelStruct *channel = (W3dBitChannelStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dBitChannelStruct) + + (channel->LastFrame - channel->FirstFrame) * sizeof(bool), + "Chunk W3D_CHUNK_BIT_CHANNEL size does not match data size"); + if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { StringClass str; str.Format("W3D_CHUNK_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - AddData(data, "W3D_CHUNK_BIT_CHANNEL", "W3dBitChannelStruct", "", (void *)channel); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_BIT_CHANNEL", "W3dBitChannelStruct[]", "", (void *)channel); } -void Serialize_W3D_CHUNK_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dBitChannelStruct *channel = (W3dBitChannelStruct *)data->data->info->value; - if (channel->Flags <= BIT_CHANNEL_TIMECODED_VIS) { + if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { StringClass str; str.Format("W3D_CHUNK_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_BIT_CHANNEL, channel, sizeof(W3dBitChannelStruct)); + WriteChunkRaw(csave, W3D_CHUNK_BIT_CHANNEL, channel, data->data->chunkSize); } -void Dump_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dBoxStruct *box = (W3dBoxStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dBoxStruct), "Chunk W3D_CHUNK_BOX size does not match data size"); + W3dBoxStruct *box = (W3dBoxStruct *)rawData; if (box->Attributes & 4) { StringClass str; @@ -352,10 +363,9 @@ void Dump_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) } AddData(data, "W3D_CHUNK_BOX", "W3dBoxStruct", "", (void *)box); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_BOX(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_BOX(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dBoxStruct *box = (W3dBoxStruct *)data->data->info->value; if (box->Attributes & 4) { @@ -376,162 +386,159 @@ void Serialize_W3D_CHUNK_BOX(ChunkSaveClass &csave, ChunkTreePtr &data) captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_BOX, box, sizeof(W3dBoxStruct)); + WriteChunkRaw(csave, W3D_CHUNK_BOX, box, sizeof(W3dBoxStruct)); } -DUMP_SERIALIZE_PARSER(W3D_CHUNK_COLLECTION) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_COLLECTION) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_COLLECTION_HEADER, W3dCollectionHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_COLLECTION_HEADER, W3dCollectionHeaderStruct) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_COLLECTION_OBJ_NAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_COLLECTION_OBJ_NAME) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_COLLISION_NODE, W3dHModelNodeStruct) +READ_WRITE_CHUNK(W3D_CHUNK_COLLISION_NODE, W3dHModelNodeStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_DAMAGE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_DAMAGE) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_COLORS, W3dDamageColorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_COLORS, W3dDamageColorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_HEADER, W3dDamageStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_HEADER, W3dDamageStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_VERTICES, W3dDamageVertexStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_DAMAGE_VERTICES, W3dDamageVertexStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_DAZZLE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_DAZZLE) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_DAZZLE_NAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_DAZZLE_NAME) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_DAZZLE_TYPENAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_DAZZLE_TYPENAME) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DCG, W3dRGBAStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_DCG, W3dRGBAStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_DIG, W3dRGBStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_DIG, W3dRGBStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_EMITTER) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_EMITTER) -void Dump_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dEmitterBlurTimeHeaderStruct *header = (W3dEmitterBlurTimeHeaderStruct *)chunkdata; - - W3dEmitterBlurTimeKeyframeStruct *blurtime = - (W3dEmitterBlurTimeKeyframeStruct *)(chunkdata + sizeof(W3dEmitterBlurTimeHeaderStruct)); + char *rawData = ReadChunkRaw(cload); + W3dEmitterBlurTimeHeaderStruct *header = (W3dEmitterBlurTimeHeaderStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dEmitterBlurTimeHeaderStruct) + + (header->KeyframeCount + 1) * sizeof(W3dEmitterBlurTimeKeyframeStruct), + "Chunk W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES size does not match data size"); - // TODO: Add subobjects - captainslog_warn("W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES Subobjects are not correctly implemented"); - AddData(data, "W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES", "W3dEmitterBlurTimeHeaderStruct[][]", "", (void *)chunkdata); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES", "W3dEmitterBlurTimeHeaderStruct[][]", "", (void *)rawData); } -void Serialize_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) { - W3dEmitterBlurTimeHeaderStruct *header = (W3dEmitterBlurTimeHeaderStruct *)data->data->info->value; - WriteChunkData(csave, W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES, header, sizeof(W3dEmitterBlurTimeHeaderStruct)); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES, rawData, data->data->chunkSize); } -void Dump_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dEmitterFrameHeaderStruct *header = (W3dEmitterFrameHeaderStruct *)chunkdata; - W3dEmitterFrameKeyframeStruct *frame = - (W3dEmitterFrameKeyframeStruct *)(chunkdata + sizeof(W3dEmitterFrameHeaderStruct)); + char *rawData = ReadChunkRaw(cload); + W3dEmitterFrameHeaderStruct *header = (W3dEmitterFrameHeaderStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dEmitterFrameHeaderStruct) + + (header->KeyframeCount + 1) * sizeof(W3dEmitterFrameKeyframeStruct), + "Chunk W3D_CHUNK_EMITTER_FRAME_KEYFRAMES size does not match data size"); - // TODO: Add subobjects - captainslog_warn("W3D_CHUNK_EMITTER_FRAME_KEYFRAMES Subobjects are not correctly implemented"); - AddData(data, "W3D_CHUNK_EMITTER_FRAME_KEYFRAMES", "W3dEmitterFrameHeaderStruct[][]", "", (void *)chunkdata); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_EMITTER_FRAME_KEYFRAMES", "W3dEmitterFrameHeaderStruct[][]", "", (void *)rawData); } -void Serialize_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_EMITTER_FRAME_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) { - W3dEmitterFrameHeaderStruct *header = (W3dEmitterFrameHeaderStruct *)data->data->info->value; - WriteChunkData(csave, W3D_CHUNK_EMITTER_FRAME_KEYFRAMES, header, sizeof(W3dEmitterFrameHeaderStruct)); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_EMITTER_FRAME_KEYFRAMES, rawData, data->data->chunkSize); } -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_HEADER, W3dEmitterHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_EMITTER_HEADER, W3dEmitterHeaderStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_INFO, W3dEmitterInfoStruct) +READ_WRITE_CHUNK(W3D_CHUNK_EMITTER_INFO, W3dEmitterInfoStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_INFOV2, W3dEmitterInfoStructV2) +READ_WRITE_CHUNK(W3D_CHUNK_EMITTER_INFOV2, W3dEmitterInfoStructV2) -void Dump_W3D_CHUNK_EMITTER_PROPS(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_EMITTER_PROPS(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dEmitterPropertyStruct *props = (W3dEmitterPropertyStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + W3dEmitterPropertyStruct *props = (W3dEmitterPropertyStruct *)rawData; - W3dEmitterColorKeyframeStruct *color = (W3dEmitterColorKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct)); + W3dEmitterColorKeyframeStruct *color = (W3dEmitterColorKeyframeStruct *)(rawData + sizeof(W3dEmitterPropertyStruct)); - W3dEmitterOpacityKeyframeStruct *opacity = (W3dEmitterOpacityKeyframeStruct *)(chunkdata + W3dEmitterOpacityKeyframeStruct *opacity = (W3dEmitterOpacityKeyframeStruct *)(rawData + sizeof(W3dEmitterPropertyStruct) + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct))); - W3dEmitterSizeKeyframeStruct *size = (W3dEmitterSizeKeyframeStruct *)(chunkdata + sizeof(W3dEmitterPropertyStruct) + W3dEmitterSizeKeyframeStruct *size = (W3dEmitterSizeKeyframeStruct *)(rawData + sizeof(W3dEmitterPropertyStruct) + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct)) + (props->OpacityKeyframes * sizeof(W3dEmitterOpacityKeyframeStruct))); + captainslog_dbgassert(data->data->chunkSize == + sizeof(W3dEmitterPropertyStruct) + + (props->ColorKeyframes * sizeof(W3dEmitterColorKeyframeStruct)) + + (props->OpacityKeyframes * sizeof(W3dEmitterOpacityKeyframeStruct)) + + (props->SizeKeyframes * sizeof(W3dEmitterSizeKeyframeStruct)), + "Chunk W3D_CHUNK_EMITTER_PROPS size does not match data size"); + - // TODO: Add subobjects - captainslog_warn("W3D_CHUNK_EMITTER_PROPS Subobjects are not correctly implemented"); - AddData(data, "W3D_CHUNK_EMITTER_PROPS", "W3dEmitterPropertyStruct[][][][]", "", (void *)chunkdata); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_EMITTER_PROPS", "W3dEmitterPropertyStruct[][][][]", "", (void *)rawData); } -void Serialize_W3D_CHUNK_EMITTER_PROPS(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_EMITTER_PROPS(ChunkSaveClass &csave, ChunkTreePtr &data) { - W3dEmitterPropertyStruct *props = (W3dEmitterPropertyStruct *)data->data->info->value; - WriteChunkData(csave, W3D_CHUNK_EMITTER_PROPS, props, sizeof(W3dEmitterPropertyStruct)); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_EMITTER_PROPS, rawData, data->data->chunkSize); } -void Dump_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dEmitterRotationHeaderStruct *header = (W3dEmitterRotationHeaderStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + W3dEmitterRotationHeaderStruct *header = (W3dEmitterRotationHeaderStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dEmitterRotationHeaderStruct) + + (header->KeyframeCount + 1) * sizeof(W3dEmitterRotationKeyframeStruct), + "Chunk W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES size does not match data size"); - W3dEmitterRotationKeyframeStruct *frame = - (W3dEmitterRotationKeyframeStruct *)(chunkdata + sizeof(W3dEmitterRotationHeaderStruct)); - - // TODO: Add subobjects - captainslog_warn("W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES Subobjects are not correctly implemented"); - AddData(data, "W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES", "W3dEmitterRotationHeaderStruct[][]", "", (void *)chunkdata); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES", "W3dEmitterRotationHeaderStruct[][]", "", (void *)rawData); } -void Serialize_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES(ChunkSaveClass &csave, ChunkTreePtr &data) { - W3dEmitterRotationHeaderStruct *header = (W3dEmitterRotationHeaderStruct *)data->data->info->value; - WriteChunkData(csave, W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES, header, sizeof(W3dEmitterRotationHeaderStruct)); + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES, rawData, data->data->chunkSize); } -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_EMITTER_USER_DATA) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_EMITTER_USER_DATA) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_FAR_ATTENUATION, W3dLightAttenuationStruct) +READ_WRITE_CHUNK(W3D_CHUNK_FAR_ATTENUATION, W3dLightAttenuationStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_HIERARCHY) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_HIERARCHY) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HIERARCHY_HEADER, W3dHierarchyStruct) +READ_WRITE_CHUNK(W3D_CHUNK_HIERARCHY_HEADER, W3dHierarchyStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_HLOD) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD_AGGREGATE_ARRAY) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_HLOD_AGGREGATE_ARRAY) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HLOD_HEADER, W3dHLodHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_HLOD_HEADER, W3dHLodHeaderStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD_LOD_ARRAY) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_HLOD_LOD_ARRAY) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER, W3dHLodArrayHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER, W3dHLodArrayHeaderStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_HLOD_PROXY_ARRAY) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_HLOD_PROXY_ARRAY) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT, W3dHLodSubObjectStruct) +READ_WRITE_CHUNK(W3D_CHUNK_HLOD_SUB_OBJECT, W3dHLodSubObjectStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_HMODEL) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_HMODEL) -DUMP_SERIALIZE_CHUNK(OBSOLETE_W3D_CHUNK_HMODEL_AUX_DATA, W3dHModelAuxDataStruct) +READ_WRITE_CHUNK(OBSOLETE_W3D_CHUNK_HMODEL_AUX_DATA, W3dHModelAuxDataStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_HMODEL_HEADER, W3dHModelHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_HMODEL_HEADER, W3dHModelHeaderStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_LIGHT) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_LIGHT) -void Dump_W3D_CHUNK_LIGHT_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_LIGHT_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dLightStruct *light = (W3dLightStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dLightStruct), "Chunk W3D_CHUNK_LIGHT_INFO size does not match data size"); + W3dLightStruct *light = (W3dLightStruct *)rawData; int type = light->Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK; if (type != W3D_LIGHT_ATTRIBUTE_POINT && type != W3D_LIGHT_ATTRIBUTE_SPOT && type != W3D_LIGHT_ATTRIBUTE_DIRECTIONAL) { @@ -545,11 +552,10 @@ void Dump_W3D_CHUNK_LIGHT_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) str.Format("W3D_CHUNK_LIGHT_INFO Unknown Light Flags %x", light->Attributes & 0xFFFFFE00); captainslog_warn((const char *)str); } - AddData(data, "W3D_CHUNK_LIGHT_INFO", "W3dLightStruct", "", (void *)chunkdata); - delete[] chunkdata; + AddData(data, "W3D_CHUNK_LIGHT_INFO", "W3dLightStruct", "", (void *)rawData); } -void Serialize_W3D_CHUNK_LIGHT_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_LIGHT_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dLightStruct *light = (W3dLightStruct *)data->data->info->value; int type = light->Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK; @@ -565,53 +571,54 @@ void Serialize_W3D_CHUNK_LIGHT_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_LIGHT_INFO, light, sizeof(W3dLightStruct)); + WriteChunkRaw(csave, W3D_CHUNK_LIGHT_INFO, light, sizeof(W3dLightStruct)); } -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LIGHT_TRANSFORM, W3dLightTransformStruct) +READ_WRITE_CHUNK(W3D_CHUNK_LIGHT_TRANSFORM, W3dLightTransformStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_LIGHTSCAPE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_LIGHTSCAPE) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_LIGHTSCAPE_LIGHT) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_LIGHTSCAPE_LIGHT) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LOD, W3dLODStruct) +READ_WRITE_CHUNK(W3D_CHUNK_LOD, W3dLODStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_LODMODEL) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_LODMODEL) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_LODMODEL_HEADER, W3dLODModelHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_LODMODEL_HEADER, W3dLODModelHeaderStruct) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MAP3_FILENAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_MAP3_FILENAME) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MAP3_INFO, W3dMap3Struct) +READ_WRITE_CHUNK(W3D_CHUNK_MAP3_INFO, W3dMap3Struct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MATERIAL_INFO, W3dMaterialInfoStruct) +READ_WRITE_CHUNK(W3D_CHUNK_MATERIAL_INFO, W3dMaterialInfoStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL_PASS) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIAL_PASS) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIAL3) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_DC_MAP) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIAL3_DC_MAP) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_DI_MAP) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIAL3_DI_MAP) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MATERIAL3_INFO, W3dMaterial3Struct) +READ_WRITE_CHUNK(W3D_CHUNK_MATERIAL3_INFO, W3dMaterial3Struct) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MATERIAL3_NAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_MATERIAL3_NAME) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_SC_MAP) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIAL3_SC_MAP) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIAL3_SI_MAP) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIAL3_SI_MAP) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MATERIALS3) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MATERIALS3) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MESH) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MESH) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MESH_HEADER, W3dMeshHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_MESH_HEADER, W3dMeshHeaderStruct) -void Dump_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dMeshHeader3Struct *header = (W3dMeshHeader3Struct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dMeshHeader3Struct), "Chunk W3D_CHUNK_MESH_HEADER3 size does not match data size"); + W3dMeshHeader3Struct *header = (W3dMeshHeader3Struct *)rawData; int type = header->Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK; if (type != W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL && type != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED && type != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN && type != OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW @@ -652,10 +659,9 @@ void Dump_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) captainslog_warn((const char *)str); } AddData(data, "W3D_CHUNK_MESH_HEADER3", "W3dMeshHeader3Struct", "", (void *)header); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dMeshHeader3Struct *header = (W3dMeshHeader3Struct *)data->data->info->value; int type = header->Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK; @@ -699,65 +705,66 @@ void Serialize_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_MESH_HEADER3, header, sizeof(W3dMeshHeader3Struct)); + WriteChunkRaw(csave, W3D_CHUNK_MESH_HEADER3, header, sizeof(W3dMeshHeader3Struct)); } -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MESH_USER_TEXT) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_MESH_USER_TEXT) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NEAR_ATTENUATION, W3dLightAttenuationStruct) +READ_WRITE_CHUNK(W3D_CHUNK_NEAR_ATTENUATION, W3dLightAttenuationStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NODE, W3dHModelNodeStruct) +READ_WRITE_CHUNK(W3D_CHUNK_NODE, W3dHModelNodeStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_NULL_OBJECT, W3dNullObjectStruct) +READ_WRITE_CHUNK(W3D_CHUNK_NULL_OBJECT, W3dNullObjectStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PER_FACE_TEXCOORD_IDS, Vector3i) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_PER_FACE_TEXCOORD_IDS, Vector3i) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PER_TRI_MATERIALS, uint16_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_PER_TRI_MATERIALS, uint16_t) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PIVOT_FIXUPS, W3dPivotFixupStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_PIVOT_FIXUPS, W3dPivotFixupStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PIVOTS, W3dPivotStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_PIVOTS, W3dPivotStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_PLACEHOLDER, W3dPlaceholderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_PLACEHOLDER, W3dPlaceholderStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_POINTS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_POINTS, W3dVectorStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_UNLIT) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_PRELIT_UNLIT) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_PRELIT_VERTEX) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_PRELIT_VERTEX) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_PS2_SHADERS, W3dPS2ShaderStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_PS2_SHADERS, W3dPS2ShaderStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SCG, W3dRGBStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SCG, W3dRGBStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHADER_IDS, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHADER_IDS, uint32_t) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHADERS, W3dShaderStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHADERS, W3dShaderStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SKIN_NODE, W3dHModelNodeStruct) +READ_WRITE_CHUNK(W3D_CHUNK_SKIN_NODE, W3dHModelNodeStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO, W3dSpotLightStruct) +READ_WRITE_CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO, W3dSpotLightStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO_5_0, W3dSpotLightStruct_v5_0) +READ_WRITE_CHUNK(W3D_CHUNK_SPOT_LIGHT_INFO_5_0, W3dSpotLightStruct_v5_0) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_STAGE_TEXCOORDS, W3dTexCoordStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_STAGE_TEXCOORDS, W3dTexCoordStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SURRENDER_NORMALS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SURRENDER_NORMALS, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXCOORDS, W3dTexCoordStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_TEXCOORDS, W3dTexCoordStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_TEXTURE) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXTURE_IDS, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_TEXTURE_IDS, uint32_t) -void Dump_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dTextureInfoStruct *info = (W3dTextureInfoStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTextureInfoStruct), "Chunk W3D_CHUNK_TEXTURE_INFO size does not match data size"); + W3dTextureInfoStruct *info = (W3dTextureInfoStruct *)rawData; int hint = info->Attributes & 0xF00; @@ -782,10 +789,9 @@ void Dump_W3D_CHUNK_TEXTURE_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) } AddData(data, "W3D_CHUNK_TEXTURE_INFO", "W3dTextureInfoStruct", "", (void *)info); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_TEXTURE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_TEXTURE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dTextureInfoStruct *info = (W3dTextureInfoStruct *)data->data->info->value; int hint = info->Attributes & 0xF00; @@ -810,37 +816,53 @@ void Serialize_W3D_CHUNK_TEXTURE_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_TEXTURE_INFO, info, sizeof(W3dTextureInfoStruct)); + WriteChunkRaw(csave, W3D_CHUNK_TEXTURE_INFO, info, sizeof(W3dTextureInfoStruct)); } -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_TEXTURE_NAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_TEXTURE_NAME) + +void Read_W3D_CHUNK_TEXTURE_REPLACER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *rawData = ReadChunkRaw(cload); + W3dTextureReplacerHeaderStruct *header = (W3dTextureReplacerHeaderStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTextureReplacerHeaderStruct) + + header->ReplacedTexturesCount * sizeof(W3dTextureReplacerStruct), + "Chunk W3D_CHUNK_TEXTURE_REPLACER_INFO size does not match data size"); + + AddData(data, "W3D_CHUNK_TEXTURE_REPLACER_INFO", "W3dTextureReplacerHeaderStruct[][]", "", (void *)rawData); +} -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TEXTURE_REPLACER_INFO, W3dTextureReplacerStruct) +void Write_W3D_CHUNK_TEXTURE_REPLACER_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +{ + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_TEXTURE_REPLACER_INFO, rawData, data->data->chunkSize); +} -DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURE_STAGE) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_TEXTURE_STAGE) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_TEXTURES) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_TEXTURES) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_TRANSFORM_NODE, W3dPlaceholderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_TRANSFORM_NODE, W3dPlaceholderStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TRIANGLES, W3dTriStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_TRIANGLES, W3dTriStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_COLORS, W3dRGBStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_COLORS, W3dRGBStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_INFLUENCES, W3dVertInfStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_INFLUENCES, W3dVertInfStruct) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_VERTEX_MAPPER_ARGS0) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_VERTEX_MAPPER_ARGS0) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_VERTEX_MAPPER_ARGS1) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_VERTEX_MAPPER_ARGS1) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_VERTEX_MATERIAL) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_VERTEX_MATERIAL) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_MATERIAL_IDS, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_MATERIAL_IDS, uint32_t) -void Dump_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dVertexMaterialStruct *material = (W3dVertexMaterialStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dVertexMaterialStruct), "Chunk W3D_CHUNK_VERTEX_MATERIAL_INFO size does not match data size"); + W3dVertexMaterialStruct *material = (W3dVertexMaterialStruct *)rawData; if (material->Attributes & 0x00000010) { StringClass str; @@ -888,10 +910,9 @@ void Dump_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &da } } AddData(data, "W3D_CHUNK_VERTEX_MATERIAL_INFO", "W3dVertexMaterialStruct", "", (void *)material); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dVertexMaterialStruct *material = (W3dVertexMaterialStruct *)data->data->info->value; if (material->Attributes & 0x00000010) { @@ -940,23 +961,24 @@ void Serialize_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkSaveClass &csave, ChunkTreePt } } - WriteChunkData(csave, W3D_CHUNK_VERTEX_MATERIAL_INFO, material, sizeof(W3dVertexMaterialStruct)); + WriteChunkRaw(csave, W3D_CHUNK_VERTEX_MATERIAL_INFO, material, sizeof(W3dVertexMaterialStruct)); } -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_VERTEX_MATERIAL_NAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_VERTEX_MATERIAL_NAME) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_VERTEX_MATERIALS) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_VERTEX_MATERIALS) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_NORMALS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_NORMALS, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_SHADE_INDICES, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_SHADE_INDICES, uint32_t) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_VERTICES, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTICES, W3dVectorStruct) -void Dump_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dEmitterLinePropertiesStruct *props = (W3dEmitterLinePropertiesStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dEmitterLinePropertiesStruct), "Chunk W3D_CHUNK_EMITTER_LINE_PROPERTIES size does not match data size"); + W3dEmitterLinePropertiesStruct *props = (W3dEmitterLinePropertiesStruct *)rawData; if (props->Flags & 0x00FFFFF0) { StringClass str; @@ -973,10 +995,9 @@ void Dump_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkLoadClass &cload, ChunkTreePtr } AddData(data, "W3D_CHUNK_EMITTER_LINE_PROPERTIES", "W3dEmitterLinePropertiesStruct", "", (void *)props); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dEmitterLinePropertiesStruct *props = (W3dEmitterLinePropertiesStruct *)data->data->info->value; if (props->Flags & 0x00FFFFF0) { @@ -993,25 +1014,26 @@ void Serialize_W3D_CHUNK_EMITTER_LINE_PROPERTIES(ChunkSaveClass &csave, ChunkTre captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_EMITTER_LINE_PROPERTIES, props, sizeof(W3dEmitterLinePropertiesStruct)); + WriteChunkRaw(csave, W3D_CHUNK_EMITTER_LINE_PROPERTIES, props, sizeof(W3dEmitterLinePropertiesStruct)); } -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTICES, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTICES, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTEX_NORMALS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SECONDARY_VERTEX_NORMALS, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_TANGENTS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_TANGENTS, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_BINORMALS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_BINORMALS, W3dVectorStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_COMPRESSED_ANIMATION) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_COMPRESSED_ANIMATION) int flavor = ANIM_FLAVOR_TIMECODED; -void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dCompressedAnimHeaderStruct *header = (W3dCompressedAnimHeaderStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dCompressedAnimHeaderStruct), "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_HEADER size does not match data size"); + W3dCompressedAnimHeaderStruct *header = (W3dCompressedAnimHeaderStruct *)rawData; if (header->Flavor >= ANIM_FLAVOR_VALID) { StringClass str; @@ -1021,10 +1043,9 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkLoadClass &cload, ChunkTree flavor = header->Flavor; AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_HEADER", "W3dCompressedAnimHeaderStruct", "", (void *)header); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dCompressedAnimHeaderStruct *header = (W3dCompressedAnimHeaderStruct *)data->data->info->value; @@ -1035,15 +1056,18 @@ void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_HEADER(ChunkSaveClass &csave, Chun } flavor = header->Flavor; - WriteChunkData(csave, W3D_CHUNK_COMPRESSED_ANIMATION_HEADER, header, sizeof(W3dCompressedAnimHeaderStruct)); + WriteChunkRaw(csave, W3D_CHUNK_COMPRESSED_ANIMATION_HEADER, header, sizeof(W3dCompressedAnimHeaderStruct)); } -void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); + char *rawData = ReadChunkRaw(cload); if (flavor == ANIM_FLAVOR_TIMECODED) { - W3dTimeCodedAnimChannelStruct *channel = (W3dTimeCodedAnimChannelStruct *)chunkdata; + W3dTimeCodedAnimChannelStruct *channel = (W3dTimeCodedAnimChannelStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTimeCodedAnimChannelStruct) + + (((cload.Cur_Chunk_Length() - sizeof(W3dTimeCodedAnimChannelStruct)) >> 2) + 1) * sizeof(int), + "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL size does not match data size"); if (channel->Flags <= ANIM_CHANNEL_VIS) { } else { @@ -1052,9 +1076,11 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre captainslog_warn((const char *)str); } AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL", "W3dTimeCodedAnimChannelStruct", "", (void *)channel); - delete[] chunkdata; - } else { - W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)chunkdata; + } else { + W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dAdaptiveDeltaAnimChannelStruct) + + (((cload.Cur_Chunk_Length() - sizeof(W3dAdaptiveDeltaAnimChannelStruct)) >> 2) + 1) * sizeof(int), + "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL size does not match data size"); if (channel->Flags <= ANIM_CHANNEL_VIS) { } else { @@ -1064,37 +1090,22 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre } AddData(data, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL", "W3dAdaptiveDeltaAnimChannelStruct", "", (void *)channel); - delete[] chunkdata; - } + } } -void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { - if (flavor == ANIM_FLAVOR_TIMECODED) { - W3dTimeCodedAnimChannelStruct *channel = (W3dTimeCodedAnimChannelStruct *)data->data->info->value; - if (channel->Flags <= ANIM_CHANNEL_VIS) { - } else { - StringClass str; - str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); - captainslog_warn((const char *)str); - } - WriteChunkData(csave, W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL, channel, sizeof(W3dTimeCodedAnimChannelStruct)); - } else { - W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)data->data->info->value; - if (channel->Flags <= ANIM_CHANNEL_VIS) { - } else { - StringClass str; - str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); - captainslog_warn((const char *)str); - } - WriteChunkData(csave, W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL, channel, sizeof(W3dAdaptiveDeltaAnimChannelStruct)); - } + char *rawData = (char *)data->data->info->value; + // TODO valid data + WriteChunkRaw(csave, W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL, rawData, data->data->chunkSize); } -void Dump_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)chunkdata; + char *rawData = ReadChunkRaw(cload); + W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)rawData; + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTimeCodedBitChannelStruct) + channel->NumTimeCodes * sizeof(int), + "Chunk W3D_CHUNK_COMPRESSED_BIT_CHANNEL size does not match data size"); if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { StringClass str; @@ -1103,10 +1114,9 @@ void Dump_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr & } AddData(data, "W3D_CHUNK_COMPRESSED_BIT_CHANNEL", "W3dTimeCodedBitChannelStruct", "", (void *)channel); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)data->data->info->value; if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { @@ -1114,24 +1124,24 @@ void Serialize_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkSaveClass &csave, ChunkTree str.Format("W3D_CHUNK_COMPRESSED_BIT_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_COMPRESSED_BIT_CHANNEL, channel, sizeof(W3dTimeCodedBitChannelStruct)); + WriteChunkRaw(csave, W3D_CHUNK_COMPRESSED_BIT_CHANNEL, channel, data->data->chunkSize); } -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MORPH_ANIMATION) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MORPH_ANIMATION) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_MORPHANIM_HEADER, W3dMorphAnimHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_MORPHANIM_HEADER, W3dMorphAnimHeaderStruct) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_MORPHANIM_CHANNEL) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_MORPHANIM_CHANNEL) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_MORPHANIM_POSENAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_MORPHANIM_POSENAME) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_KEYDATA, W3dMorphAnimKeyStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_KEYDATA, W3dMorphAnimKeyStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA, uint32_t) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_SOUNDROBJ) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_SOUNDROBJ) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SOUNDROBJ_HEADER, W3dSoundRObjHeaderStruct) +READ_WRITE_CHUNK(W3D_CHUNK_SOUNDROBJ_HEADER, W3dSoundRObjHeaderStruct) #define READ_FLOAT(id, name) \ case id: { \ @@ -1177,10 +1187,10 @@ DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SOUNDROBJ_HEADER, W3dSoundRObjHeaderStruct) break; \ } -void Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkLoadClass &cload, ChunkTreePtr &data) { - // TODO: Implement Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION - captainslog_warn("Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION not implemented"); + // TODO: Implement Read_W3D_CHUNK_SOUNDROBJ_DEFINITION + captainslog_warn("Read_W3D_CHUNK_SOUNDROBJ_DEFINITION not implemented"); while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case 0x100: @@ -1229,10 +1239,10 @@ void Dump_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkLoadClass &cload, ChunkTreePtr &da } } -void Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_SOUNDROBJ_DEFINITION(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION - captainslog_warn("Serialize_W3D_CHUNK_SOUNDROBJ_DEFINITION not implemented"); + // TODO: Implement Write_W3D_CHUNK_SOUNDROBJ_DEFINITION + captainslog_warn("Write_W3D_CHUNK_SOUNDROBJ_DEFINITION not implemented"); } void DoVector3Channel(ChunkLoadClass &cload, ChunkTreePtr &data, const char *name) @@ -1345,10 +1355,10 @@ void DoAlphaVectorStructChannel(ChunkLoadClass &cload, ChunkTreePtr &data, const } } -void Dump_W3D_CHUNK_RING(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_RING(ChunkLoadClass &cload, ChunkTreePtr &data) { - // TODO: Implement Dump_W3D_CHUNK_RING - captainslog_warn("Dump_W3D_CHUNK_RING not implemented"); + // TODO: Implement Read_W3D_CHUNK_RING + captainslog_warn("Read_W3D_CHUNK_RING not implemented"); while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case 1: { @@ -1381,16 +1391,16 @@ void Dump_W3D_CHUNK_RING(ChunkLoadClass &cload, ChunkTreePtr &data) } } -void Serialize_W3D_CHUNK_RING(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_RING(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_RING - captainslog_warn("Serialize_W3D_CHUNK_RING not implemented"); + // TODO: Implement Write_W3D_CHUNK_RING + captainslog_warn("Write_W3D_CHUNK_RING not implemented"); } -void Dump_W3D_CHUNK_SPHERE(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_SPHERE(ChunkLoadClass &cload, ChunkTreePtr &data) { - // TODO: Implement Dump_W3D_CHUNK_SPHERE - captainslog_warn("Dump_W3D_CHUNK_SPHERE not implemented"); + // TODO: Implement Read_W3D_CHUNK_SPHERE + captainslog_warn("Read_W3D_CHUNK_SPHERE not implemented"); while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case 1: { @@ -1422,67 +1432,69 @@ void Dump_W3D_CHUNK_SPHERE(ChunkLoadClass &cload, ChunkTreePtr &data) } } -void Serialize_W3D_CHUNK_SPHERE(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_SPHERE(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_SPHERE - captainslog_warn("Serialize_W3D_CHUNK_SPHERE not implemented"); + // TODO: Implement Write_W3D_CHUNK_SPHERE + captainslog_warn("Write_W3D_CHUNK_SPHERE not implemented"); } -DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDMESH) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_SHDMESH) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_SHDMESH_NAME) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_SHDMESH_NAME) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDSUBMESH) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_SHDSUBMESH) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_SHDSUBMESH_SHADER) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_SHDSUBMESH_SHADER) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_SHDSUBMESH_SHADER_TYPE, uint32_t) +READ_WRITE_CHUNK(W3D_CHUNK_SHDSUBMESH_SHADER_TYPE, uint32_t) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTICES, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTICES, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTEX_NORMALS, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTEX_NORMALS, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TRIANGLES, Vector3i16) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TRIANGLES, Vector3i16) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTEX_SHADE_INDICES, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_VERTEX_SHADE_INDICES, uint32_t) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_UV0, W3dTexCoordStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_UV0, W3dTexCoordStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_UV1, W3dTexCoordStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_UV1, W3dTexCoordStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_S, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_S, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_T, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_T, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_SXT, W3dVectorStruct) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_SHDSUBMESH_TANGENT_BASIS_SXT, W3dVectorStruct) -DUMP_SERIALIZE_CHUNK(W3D_CHUNK_EMITTER_EXTRA_INFO, W3dEmitterExtraInfoStruct) +READ_WRITE_CHUNK(W3D_CHUNK_EMITTER_EXTRA_INFO, W3dEmitterExtraInfoStruct) -DUMP_SERIALIZE_CHUNK_STRING(W3D_CHUNK_SHDMESH_USER_TEXT) +READ_WRITE_CHUNK_STRING(W3D_CHUNK_SHDMESH_USER_TEXT) -DUMP_SERIALIZE_CHUNK_ARRAY(W3D_CHUNK_FXSHADER_IDS, uint32_t) +READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_FXSHADER_IDS, uint32_t) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_FX_SHADERS) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_FX_SHADERS) -DUMP_SERIALIZE_PARSER(W3D_CHUNK_FX_SHADER) +READ_WRITE_SUBCHUNKS(W3D_CHUNK_FX_SHADER) -void Dump_W3D_CHUNK_FX_SHADER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_FX_SHADER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { // TODO Fix W3dFXShaderStruct - captainslog_warn("Dump_W3D_CHUNK_FX_SHADER_INFO not implemented"); - char *chunkdata = ReadChunkData(cload); - uint8_t *version = (uint8_t *)chunkdata; + captainslog_warn("Read_W3D_CHUNK_FX_SHADER_INFO not implemented"); + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dFXShaderStruct) + 1, "Chunk W3D_CHUNK_FX_SHADER_INFO size does not match data size"); + uint8_t *version = (uint8_t *)rawData; AddInt8(data, "Version", *version); - W3dFXShaderStruct *shader = (W3dFXShaderStruct *)(chunkdata + 1); + W3dFXShaderStruct *shader = (W3dFXShaderStruct *)(rawData + 1); AddString(data, "ShaderName", shader->shadername, "string"); AddInt8(data, "Technique", shader->technique); - delete[] chunkdata; + delete[] rawData; } -void Serialize_W3D_CHUNK_FX_SHADER_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_FX_SHADER_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Serialize_W3D_CHUNK_FX_SHADER_INFO - captainslog_warn("Serialize_W3D_CHUNK_FX_SHADER_INFO not implemented"); + // TODO: Implement Write_W3D_CHUNK_FX_SHADER_INFO + captainslog_warn("Write_W3D_CHUNK_FX_SHADER_INFO not implemented"); +// char *rawData = new char[sizeof(W3dFXShaderStruct) + 1]; } struct W3dFXShaderConstantStruct @@ -1498,22 +1510,22 @@ struct W3dFXShaderConstantStruct bool Bool; } Value; - W3dFXShaderConstantStruct &operator=(const char *chunkdata) + W3dFXShaderConstantStruct &operator=(const char *rawData) { - Type = *(uint32_t *)chunkdata; - Length = *(uint32_t *)(chunkdata + 4); - ConstantName = std::string(chunkdata + 8, Length); + Type = *(uint32_t *)rawData; + Length = *(uint32_t *)(rawData + 4); + ConstantName = std::string(rawData + 8, Length); if (Type == CONSTANT_TYPE_TEXTURE) { - Value.Texture = std::string(chunkdata + 8 + Length); + Value.Texture = std::string(rawData + 8 + Length); } else if (Type >= CONSTANT_TYPE_FLOAT1 && Type <= CONSTANT_TYPE_FLOAT4) { int count = Type - 1; - float *floats = (float *)(chunkdata + 8 + Length); + float *floats = (float *)(rawData + 8 + Length); Value.Floats.assign(floats, floats + count); } else if (Type == CONSTANT_TYPE_INT) { - Value.Int = *(uint32_t *)(chunkdata + 8 + Length); + Value.Int = *(uint32_t *)(rawData + 8 + Length); } else if (Type == CONSTANT_TYPE_BOOL) { - Value.Bool = *(uint8_t *)(chunkdata + 8 + Length) != 0; + Value.Bool = *(uint8_t *)(rawData + 8 + Length) != 0; } else { // Handle unknown types Value.Texture = "Unknown"; @@ -1523,20 +1535,39 @@ struct W3dFXShaderConstantStruct } }; -void Dump_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkLoadClass &cload, ChunkTreePtr &data) -{ - char *chunkdata = ReadChunkData(cload); - W3dFXShaderConstantStruct *constant = (W3dFXShaderConstantStruct *)chunkdata; - if (constant->Value.Texture == "Unknown") { +void Read_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkLoadClass &cload, ChunkTreePtr &data) +{ + char *rawData = ReadChunkRaw(cload); + // TODO check valid + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dFXShaderConstantStruct), "Chunk W3D_CHUNK_FX_SHADER_CONSTANT size does not match data size"); + W3dFXShaderConstantStruct *constant = (W3dFXShaderConstantStruct *)rawData; + uint32_t type = *(uint32_t *)rawData; + uint32_t length = *(uint32_t *)(rawData + 4); + uint32_t expectedSize = 4 + 4 + length; // 4 bytes for 'type' and 'length' plus length for constant name + if (type == CONSTANT_TYPE_TEXTURE) { + expectedSize += 4 + strlen((char *)(rawData + expectedSize)); // add texture size + } else if (type >= CONSTANT_TYPE_FLOAT1 && type <= CONSTANT_TYPE_FLOAT4) { + expectedSize += sizeof(float) * (type - 1); // add float array size + } else if (type == CONSTANT_TYPE_INT) { + expectedSize += sizeof(uint32_t); // add int size + } else if (type == CONSTANT_TYPE_BOOL) { + expectedSize += sizeof(uint8_t); // add bool size + } else { StringClass str; str.Format("W3D_CHUNK_FX_SHADER_CONSTANT Unknown Constant Type %x", constant->Type); captainslog_warn((const char *)str); } + + captainslog_dbgassert(data->data->chunkSize == expectedSize, + "Chunk W3D_CHUNK_FX_SHADER_CONSTANT size does not match expected size"); + + + if (constant->Value.Texture == "Unknown") { + } AddData(data, "W3D_CHUNK_FX_SHADER_CONSTANT", "W3dFXShaderConstantStruct", "", (void *)constant); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dFXShaderConstantStruct *constant = (W3dFXShaderConstantStruct *)data->data->info->value; if (constant->Value.Texture == "Unknown") { @@ -1544,7 +1575,7 @@ void Serialize_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkSaveClass &csave, ChunkTreePtr str.Format("W3D_CHUNK_FX_SHADER_CONSTANT Unknown Constant Type %x", constant->Type); captainslog_warn((const char *)str); } - WriteChunkData(csave, W3D_CHUNK_FX_SHADER_CONSTANT, constant, sizeof(W3dFXShaderConstantStruct)); + WriteChunkRaw(csave, W3D_CHUNK_FX_SHADER_CONSTANT, constant, sizeof(W3dFXShaderConstantStruct)); } struct W3dCompressedMotionChannelStructNew @@ -1561,47 +1592,47 @@ struct W3dCompressedMotionChannelStructNew std::vector Initial; std::vector Data; - W3dCompressedMotionChannelStructNew &operator=(const char *chunkdata) + W3dCompressedMotionChannelStructNew &operator=(const char *rawData) { - Zero = *(uint8_t *)chunkdata; - Flavor = *(uint8_t *)(chunkdata + 1); - VectorLen = *(uint8_t *)(chunkdata + 2); - Flags = *(uint8_t *)(chunkdata + 3); - NumTimeCodes = *(uint16_t *)(chunkdata + 4); - Pivot = *(uint16_t *)(chunkdata + 6); + Zero = *(uint8_t *)rawData; + Flavor = *(uint8_t *)(rawData + 1); + VectorLen = *(uint8_t *)(rawData + 2); + Flags = *(uint8_t *)(rawData + 3); + NumTimeCodes = *(uint16_t *)(rawData + 4); + Pivot = *(uint16_t *)(rawData + 6); size_t offset = sizeof(W3dCompressedMotionChannelStructNew); if (Flavor == ANIM_FLAVOR_NEW_TIMECODED) { KeyFrames.assign( - (uint16_t *)(chunkdata + offset), (uint16_t *)(chunkdata + offset + NumTimeCodes * sizeof(uint16_t))); + (uint16_t *)(rawData + offset), (uint16_t *)(rawData + offset + NumTimeCodes * sizeof(uint16_t))); offset += NumTimeCodes * sizeof(uint16_t); int datalen = VectorLen * NumTimeCodes; if (NumTimeCodes & 1) { offset += 2; // Padding for odd NumTimeCodes } - Data.assign((uint32_t *)(chunkdata + offset), (uint32_t *)(chunkdata + offset + datalen * sizeof(uint32_t))); + Data.assign((uint32_t *)(rawData + offset), (uint32_t *)(rawData + offset + datalen * sizeof(uint32_t))); } else { - Scale = *(float *)(chunkdata + offset); + Scale = *(float *)(rawData + offset); offset += sizeof(float); - Initial.assign((float *)(chunkdata + offset), (float *)(chunkdata + offset + VectorLen * sizeof(float))); + Initial.assign((float *)(rawData + offset), (float *)(rawData + offset + VectorLen * sizeof(float))); offset += VectorLen * sizeof(float); int count = (NumTimeCodes * VectorLen - sizeof(W3dCompressedMotionChannelStructNew) - sizeof(float) - - sizeof(float) * VectorLen) - / sizeof(uint32_t); - Data.assign((uint32_t *)(chunkdata + offset), (uint32_t *)(chunkdata + offset + count * sizeof(uint32_t))); + - sizeof(float) * VectorLen) / sizeof(uint32_t); + Data.assign((uint32_t *)(rawData + offset), (uint32_t *)(rawData + offset + count * sizeof(uint32_t))); } return *this; } }; -void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) +void Read_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { - char *chunkdata = ReadChunkData(cload); - W3dCompressedMotionChannelStructNew *channel = (W3dCompressedMotionChannelStructNew *)chunkdata; + char *rawData = ReadChunkRaw(cload); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dCompressedMotionChannelStructNew), "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL size does not match data size"); + W3dCompressedMotionChannelStructNew *channel = (W3dCompressedMotionChannelStructNew *)rawData; if (channel->Flavor >= ANIM_FLAVOR_NEW_VALID) { StringClass str; str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Flavor Type %x", channel->Flavor); @@ -1616,10 +1647,9 @@ void Dump_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, C AddData( data, "W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL", "W3dCompressedMotionChannelStructNew", "", (void *)channel); - delete[] chunkdata; } -void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) +void Write_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { W3dCompressedMotionChannelStructNew *channel = (W3dCompressedMotionChannelStructNew *)data->data->info->value; if (channel->Flavor >= ANIM_FLAVOR_NEW_VALID) { @@ -1633,7 +1663,7 @@ void Serialize_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkSaveClass &csa str.Format("W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - WriteChunkData( + WriteChunkRaw( csave, W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL, channel, sizeof(W3dCompressedMotionChannelStructNew)); } @@ -1643,8 +1673,8 @@ std::map chunkFuncMap; { \ ChunkIOFuncs c; \ c.name = #id; \ - c.ReadFunc = Dump_##id; \ - c.WriteFunc = Serialize_##id; \ + c.ReadChunk = Read_##id; \ + c.WriteChunk = Write_##id; \ chunkFuncMap[id] = c; \ } diff --git a/src/tools/gamemodelconverter/src/chunksmanager.cpp b/src/tools/gamemodelconverter/src/chunksmanager.cpp index 90b970030..dffac73bc 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.cpp +++ b/src/tools/gamemodelconverter/src/chunksmanager.cpp @@ -13,7 +13,7 @@ ChunkManager::~ChunkManager() } } -void ChunkManager::DumpSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) +void ChunkManager::ReadSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) { if (parentChunk == nullptr) { parentChunk = std::make_unique(); @@ -47,7 +47,7 @@ void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &data auto it = chunkFuncMap.find(data->data->chunkType); if (it != chunkFuncMap.end()) { - it->second.ReadFunc(chunkLoader, data); + it->second.ReadChunk(chunkLoader, data); } else { StringClass str; str.Format("Unknown Chunk 0x%X", data->data->chunkType); @@ -56,13 +56,16 @@ void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &data } } -void ChunkManager::SerializeSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk) +void ChunkManager::WriteSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk) { if (parentChunk->data) { if (!chunkSaver.Begin_Chunk(parentChunk->data->chunkType)) { captainslog_error("Failed to begin chunk"); return; } + for (auto &subchunk : parentChunk->subchunks) { + WriteChunkInfo(chunkSaver, subchunk); + } // Parent chunk data, no data to write, continue to subchunks if (!chunkSaver.End_Chunk()) { captainslog_error("Failed to end chunk"); @@ -70,16 +73,13 @@ void ChunkManager::SerializeSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr & } } - for (auto &subchunk : parentChunk->subchunks) { - WriteChunkInfo(chunkSaver, subchunk); - } } void ChunkManager::WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &data) { auto it = chunkFuncMap.find(data->data->chunkType); if (it != chunkFuncMap.end()) { - it->second.WriteFunc(chunkSaver, data); + it->second.WriteChunk(chunkSaver, data); } else { StringClass str; str.Format("Unknown Chunk 0x%X", data->data->chunkType); diff --git a/src/tools/gamemodelconverter/src/chunksmanager.h b/src/tools/gamemodelconverter/src/chunksmanager.h index a153a2348..de3214112 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.h +++ b/src/tools/gamemodelconverter/src/chunksmanager.h @@ -20,6 +20,11 @@ struct ChunkInfo ChunkInfo(const char *name, const StringClass &type, const StringClass &data, void *value) : name(name), type(type), data(data), value(value) {} + + ~ChunkInfo() + { + delete [] value; + } }; @@ -46,8 +51,8 @@ using ChunkTreePtr = std::unique_ptr; struct ChunkIOFuncs { const char *name; - void (*ReadFunc)(ChunkLoadClass &chunkLoader, ChunkTreePtr &data); - void (*WriteFunc)(ChunkSaveClass &chunkSaver, ChunkTreePtr &data); + void (*ReadChunk)(ChunkLoadClass &chunkLoader, ChunkTreePtr &data); + void (*WriteChunk)(ChunkSaveClass &chunkSaver, ChunkTreePtr &data); }; extern std::map chunkFuncMap; @@ -77,9 +82,9 @@ class ChunkManager return std::make_unique(name, type, data, value); } - static void DumpSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); + static void ReadSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); static void ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &chunk); - static void SerializeSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk); + static void WriteSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk); static void WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &chunk); ChunkTreePtr & GetRootChunk() { return m_rootChunk; } diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index 4c724a646..6b026584b 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -279,7 +279,7 @@ bool GameModelFile::Read_W3D_File(const char *filename, const Options &options) } m_chunkManager = new ChunkManager(filename, ChunkManager::ChunkManagerType::LOAD); m_chunkLoader = ChunkLoadClass(file); - m_chunkManager->DumpSubChunks(m_chunkLoader, m_chunkManager->GetRootChunk()); + m_chunkManager->ReadSubChunks(m_chunkLoader, m_chunkManager->GetRootChunk()); // TODO unknown chunks GAMEMODELLOG_INFO("Successfully parsed W3D file: %s", filename); @@ -296,7 +296,7 @@ bool GameModelFile::Write_W3D_File(const char *filename, const Options &options) return false; } ChunkSaveClass chunkSaver(file); - m_chunkManager->SerializeSubChunks(chunkSaver, m_chunkManager->GetRootChunk()); + m_chunkManager->WriteSubChunks(chunkSaver, m_chunkManager->GetRootChunk()); return true; } From 2c2fbd3b2dacf44af274c0502782ce0cfa1ab096 Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:21:45 +0200 Subject: [PATCH 12/13] Fix multi roots --- .../gamemodelconverter/src/chunkfactory.cpp | 4 +-- .../gamemodelconverter/src/chunksmanager.cpp | 28 +++++++++++++++---- .../gamemodelconverter/src/chunksmanager.h | 12 ++++---- .../gamemodelconverter/src/gamemodelfile.cpp | 8 ++++-- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/tools/gamemodelconverter/src/chunkfactory.cpp b/src/tools/gamemodelconverter/src/chunkfactory.cpp index f0d3a6f23..11d76de88 100644 --- a/src/tools/gamemodelconverter/src/chunkfactory.cpp +++ b/src/tools/gamemodelconverter/src/chunkfactory.cpp @@ -168,7 +168,7 @@ template void Write_Chunk_Array(ChunkSaveClass &csave, ChunkTreePtr // READ_WRITE_SUBCHUNKS template void Read_Sub_Chunks(ChunkLoadClass &cload, ChunkTreePtr &data, const char *id) { - AddString(data, id, id, "StringClass"); + AddData(data, id, "StringClass", id, nullptr); ChunkManager::ReadSubChunks(cload, data); } @@ -362,7 +362,7 @@ void Read_W3D_CHUNK_BOX(ChunkLoadClass &cload, ChunkTreePtr &data) captainslog_warn((const char *)str); } - AddData(data, "W3D_CHUNK_BOX", "W3dBoxStruct", "", (void *)box); + AddData(data, "W3D_CHUNK_BOX", "W3dBoxStruct", "", (void *)rawData); } void Write_W3D_CHUNK_BOX(ChunkSaveClass &csave, ChunkTreePtr &data) diff --git a/src/tools/gamemodelconverter/src/chunksmanager.cpp b/src/tools/gamemodelconverter/src/chunksmanager.cpp index dffac73bc..87f8ef244 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.cpp +++ b/src/tools/gamemodelconverter/src/chunksmanager.cpp @@ -2,7 +2,7 @@ ChunkManager::ChunkManager(const char *filePath, int flag) { - m_rootChunk = std::make_unique(); + // m_rootChunks.push_back(std::make_unique()); InitiateChunkFuncMap(); } @@ -13,6 +13,16 @@ ChunkManager::~ChunkManager() } } +void ChunkManager::ReadChunks(ChunkLoadClass &chunkLoader) +{ + while (chunkLoader.Open_Chunk()) { + ChunkTreePtr root = std::make_unique(); + ReadSubChunks(chunkLoader, root); + m_rootChunks.push_back(std::move(root)); + chunkLoader.Close_Chunk(); + } +} + void ChunkManager::ReadSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk) { if (parentChunk == nullptr) { @@ -20,9 +30,7 @@ void ChunkManager::ReadSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &pare } if (!parentChunk->data) { - if (chunkLoader.Open_Chunk()) { - ReadChunkInfo(chunkLoader, parentChunk); - } + ReadChunkInfo(chunkLoader, parentChunk); } while (chunkLoader.Open_Chunk()) { ChunkTreePtr subchunk = std::make_unique(); @@ -56,6 +64,17 @@ void ChunkManager::ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &data } } +void ChunkManager::WriteChunks(ChunkSaveClass &chunkSaver) +{ + for (auto &root : m_rootChunks) { + if (root->data->info->value != nullptr) { + WriteChunkInfo(chunkSaver, root); + } else { + WriteSubChunks(chunkSaver, root); + } + } +} + void ChunkManager::WriteSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk) { if (parentChunk->data) { @@ -72,7 +91,6 @@ void ChunkManager::WriteSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &pare return; } } - } void ChunkManager::WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &data) diff --git a/src/tools/gamemodelconverter/src/chunksmanager.h b/src/tools/gamemodelconverter/src/chunksmanager.h index de3214112..38921c9ce 100644 --- a/src/tools/gamemodelconverter/src/chunksmanager.h +++ b/src/tools/gamemodelconverter/src/chunksmanager.h @@ -81,17 +81,19 @@ class ChunkManager { return std::make_unique(name, type, data, value); } - + void ReadChunks(ChunkLoadClass &chunkLoader); static void ReadSubChunks(ChunkLoadClass &chunkLoader, ChunkTreePtr &parentChunk); static void ReadChunkInfo(ChunkLoadClass &chunkLoader, ChunkTreePtr &chunk); + + void WriteChunks(ChunkSaveClass &chunkSaver); static void WriteSubChunks(ChunkSaveClass &chunkSaver, ChunkTreePtr &parentChunk); static void WriteChunkInfo(ChunkSaveClass &chunkSaver, ChunkTreePtr &chunk); - ChunkTreePtr & GetRootChunk() { return m_rootChunk; } - void SetRootChunk(ChunkTreePtr root) { m_rootChunk = std::move(root); } + ChunkTreePtr & GetRootChunk() { return m_rootChunks.front(); } + void SetRootChunk(ChunkTreePtr root) { m_rootChunks.push_back(std::move(root)); } private: - - ChunkTreePtr m_rootChunk; + std::vector m_rootChunks; FileClass *m_file; }; + diff --git a/src/tools/gamemodelconverter/src/gamemodelfile.cpp b/src/tools/gamemodelconverter/src/gamemodelfile.cpp index 6b026584b..a513f9656 100644 --- a/src/tools/gamemodelconverter/src/gamemodelfile.cpp +++ b/src/tools/gamemodelconverter/src/gamemodelfile.cpp @@ -277,9 +277,11 @@ bool GameModelFile::Read_W3D_File(const char *filename, const Options &options) GAMEMODELLOG_ERROR("Could not open file: %s", filename); return false; } + m_chunkManager = new ChunkManager(filename, ChunkManager::ChunkManagerType::LOAD); m_chunkLoader = ChunkLoadClass(file); - m_chunkManager->ReadSubChunks(m_chunkLoader, m_chunkManager->GetRootChunk()); + m_chunkManager->ReadChunks(m_chunkLoader); + // TODO unknown chunks GAMEMODELLOG_INFO("Successfully parsed W3D file: %s", filename); @@ -295,8 +297,10 @@ bool GameModelFile::Write_W3D_File(const char *filename, const Options &options) GAMEMODELLOG_ERROR("Could not open file: %s", filename); return false; } + ChunkSaveClass chunkSaver(file); - m_chunkManager->WriteSubChunks(chunkSaver, m_chunkManager->GetRootChunk()); + m_chunkManager->WriteChunks(chunkSaver); // השתמש בפונקציה החדשה לכתיבה + return true; } From 263ee0099182d95515327a195dee3034e323ad54 Mon Sep 17 00:00:00 2001 From: DevGeniusCode <136935333+DevGeniusCode@users.noreply.github.com> Date: Thu, 30 Jan 2025 22:04:27 +0200 Subject: [PATCH 13/13] Refactor W3D chunk handling and add chunk size checks --- .../gamemodelconverter/src/chunkfactory.cpp | 66 +++++++------------ 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/src/tools/gamemodelconverter/src/chunkfactory.cpp b/src/tools/gamemodelconverter/src/chunkfactory.cpp index 11d76de88..41d67bb7d 100644 --- a/src/tools/gamemodelconverter/src/chunkfactory.cpp +++ b/src/tools/gamemodelconverter/src/chunkfactory.cpp @@ -27,17 +27,6 @@ void WriteChunkRaw(ChunkSaveClass &csave, unsigned id, const void *data, unsigne csave.End_Chunk(); } -template void WriteArray(ChunkSaveClass &csave, unsigned id, unsigned dataSize, unsigned numElements) -{ - csave.Begin_Chunk(id); - - for (unsigned i = 0; i < numElements; i++) { - csave.Write(&arrayData[i], dataSize); - } - - csave.End_Chunk(); -} - void AddData(ChunkTreePtr &data, const char *name, const StringClass &type, const StringClass &formattedValue, void *value) { if (data->data->info == nullptr) { @@ -80,8 +69,6 @@ void AddVector(ChunkTreePtr &data, const char *name, const W3dVectorStruct *valu AddData(data, name, "W3dVectorStruct", c, (void *)value); } -// Macro for Defining Functions - // Macro for Defining Functions // READ_WRITE_CHUNK_STRING template void Read_Chunk_String(ChunkLoadClass &cload, ChunkTreePtr &data, const char *id) @@ -147,7 +134,6 @@ template void Read_Chunk_Array(ChunkLoadClass &cload, ChunkTreePtr & delete [] rawData; } - template void Write_Chunk_Array(ChunkSaveClass &csave, ChunkTreePtr &data, unsigned id) { std::vector* arrayData = reinterpret_cast*>(data->data->info->value); @@ -180,7 +166,6 @@ template void Write_Sub_Chunks(ChunkSaveClass &csave, ChunkTreePtr & void Read_##id(ChunkLoadClass &cload, ChunkTreePtr &data) { Read_Sub_Chunks(cload, data, #id); } \ void Write_##id(ChunkSaveClass &csave, ChunkTreePtr &data) { Write_Sub_Chunks(csave, data); } \ - // Read and Write Functions READ_WRITE_CHUNK_ARRAY(O_W3D_CHUNK_MATERIALS, W3dMaterialStruct) @@ -287,11 +272,10 @@ void Read_W3D_CHUNK_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { char *rawData = ReadChunkRaw(cload); W3dAnimChannelStruct *channel = (W3dAnimChannelStruct *)rawData; - - captainslog_dbgassert(data->data->chunkSize == sizeof(W3dAnimChannelStruct) + - (channel->LastFrame - channel->FirstFrame) * channel->VectorLen * sizeof(float), - "Chunk W3D_CHUNK_ANIMATION_CHANNEL size does not match data size"); - + // TODO padding at the end of the struct if the length of data array int not fully used + // captainslog_dbgassert(data->data->chunkSize == sizeof(W3dAnimChannelStruct) + + // (channel->LastFrame - channel->FirstFrame) * channel->VectorLen * sizeof(float), + // "Chunk W3D_CHUNK_ANIMATION_CHANNEL size does not match data size"); if (channel->Flags > ANIM_CHANNEL_VIS) { StringClass str; str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); @@ -308,7 +292,7 @@ void Write_W3D_CHUNK_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data str.Format("W3D_CHUNK_ANIMATION_CHANNEL Unknown Animation Channel Type %x", channel->Flags); captainslog_warn((const char *)str); } - WriteChunkRaw(csave, W3D_CHUNK_ANIMATION_CHANNEL, channel, sizeof(W3dAnimChannelStruct)); + WriteChunkRaw(csave, W3D_CHUNK_ANIMATION_CHANNEL, channel, data->data->chunkSize); } READ_WRITE_CHUNK(W3D_CHUNK_ANIMATION_HEADER, W3dAnimHeaderStruct) @@ -318,7 +302,7 @@ void Read_W3D_CHUNK_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) char *rawData = ReadChunkRaw(cload); W3dBitChannelStruct *channel = (W3dBitChannelStruct *)rawData; captainslog_dbgassert(data->data->chunkSize == sizeof(W3dBitChannelStruct) - + (channel->LastFrame - channel->FirstFrame) * sizeof(bool), + + ((channel->LastFrame - channel->FirstFrame) / 8) * sizeof(uint8_t), // 8 is the number of bits in a byte "Chunk W3D_CHUNK_BIT_CHANNEL size does not match data size"); if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { StringClass str; @@ -644,7 +628,7 @@ void Read_W3D_CHUNK_MESH_HEADER3(ChunkLoadClass &cload, ChunkTreePtr &data) } else { StringClass str; str.Format("W3D_CHUNK_MESH_HEADER3 N/A PrelitVersion"); - captainslog_warn((const char *)str); +// captainslog_warn((const char *)str); TODO is needed? } if (header->VertexChannels & 0xFFFFFF00) { @@ -690,7 +674,7 @@ void Write_W3D_CHUNK_MESH_HEADER3(ChunkSaveClass &csave, ChunkTreePtr &data) } else { StringClass str; str.Format("W3D_CHUNK_MESH_HEADER3 N/A PrelitVersion"); - captainslog_warn((const char *)str); +// captainslog_warn((const char *)str); TODO is needed? } if (header->VertexChannels & 0xFFFFFF00) { @@ -861,7 +845,8 @@ READ_WRITE_CHUNK_ARRAY(W3D_CHUNK_VERTEX_MATERIAL_IDS, uint32_t) void Read_W3D_CHUNK_VERTEX_MATERIAL_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { char *rawData = ReadChunkRaw(cload); - captainslog_dbgassert(data->data->chunkSize == sizeof(W3dVertexMaterialStruct), "Chunk W3D_CHUNK_VERTEX_MATERIAL_INFO size does not match data size"); + captainslog_dbgassert(data->data->chunkSize == sizeof(W3dVertexMaterialStruct), + "Chunk W3D_CHUNK_VERTEX_MATERIAL_INFO size does not match data size"); W3dVertexMaterialStruct *material = (W3dVertexMaterialStruct *)rawData; if (material->Attributes & 0x00000010) { @@ -1065,8 +1050,9 @@ void Read_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre if (flavor == ANIM_FLAVOR_TIMECODED) { W3dTimeCodedAnimChannelStruct *channel = (W3dTimeCodedAnimChannelStruct *)rawData; + // TODO need check if need add '1' to the size captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTimeCodedAnimChannelStruct) - + (((cload.Cur_Chunk_Length() - sizeof(W3dTimeCodedAnimChannelStruct)) >> 2) + 1) * sizeof(int), + + (((cload.Cur_Chunk_Length() - sizeof(W3dTimeCodedAnimChannelStruct)) >> 2) /*+ 1*/) * sizeof(int), "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL size does not match data size"); if (channel->Flags <= ANIM_CHANNEL_VIS) { @@ -1079,7 +1065,7 @@ void Read_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre } else { W3dAdaptiveDeltaAnimChannelStruct *channel = (W3dAdaptiveDeltaAnimChannelStruct *)rawData; captainslog_dbgassert(data->data->chunkSize == sizeof(W3dAdaptiveDeltaAnimChannelStruct) - + (((cload.Cur_Chunk_Length() - sizeof(W3dAdaptiveDeltaAnimChannelStruct)) >> 2) + 1) * sizeof(int), + + (((cload.Cur_Chunk_Length() - sizeof(W3dAdaptiveDeltaAnimChannelStruct)) >> 2) /*+ 1*/) * sizeof(int), "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL size does not match data size"); if (channel->Flags <= ANIM_CHANNEL_VIS) { @@ -1096,7 +1082,6 @@ void Read_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkLoadClass &cload, ChunkTre void Write_W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL(ChunkSaveClass &csave, ChunkTreePtr &data) { char *rawData = (char *)data->data->info->value; - // TODO valid data WriteChunkRaw(csave, W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL, rawData, data->data->chunkSize); } @@ -1104,8 +1089,9 @@ void Read_W3D_CHUNK_COMPRESSED_BIT_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr & { char *rawData = ReadChunkRaw(cload); W3dTimeCodedBitChannelStruct *channel = (W3dTimeCodedBitChannelStruct *)rawData; - captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTimeCodedBitChannelStruct) + channel->NumTimeCodes * sizeof(int), - "Chunk W3D_CHUNK_COMPRESSED_BIT_CHANNEL size does not match data size"); + // TODO need fix size check +// captainslog_dbgassert(data->data->chunkSize == sizeof(W3dTimeCodedBitChannelStruct) + channel->NumTimeCodes * sizeof(int), +// "Chunk W3D_CHUNK_COMPRESSED_BIT_CHANNEL size does not match data size"); if (channel->Flags > BIT_CHANNEL_TIMECODED_VIS) { StringClass str; @@ -1478,23 +1464,20 @@ READ_WRITE_SUBCHUNKS(W3D_CHUNK_FX_SHADER) void Read_W3D_CHUNK_FX_SHADER_INFO(ChunkLoadClass &cload, ChunkTreePtr &data) { - // TODO Fix W3dFXShaderStruct - captainslog_warn("Read_W3D_CHUNK_FX_SHADER_INFO not implemented"); char *rawData = ReadChunkRaw(cload); captainslog_dbgassert(data->data->chunkSize == sizeof(W3dFXShaderStruct) + 1, "Chunk W3D_CHUNK_FX_SHADER_INFO size does not match data size"); - uint8_t *version = (uint8_t *)rawData; - AddInt8(data, "Version", *version); - W3dFXShaderStruct *shader = (W3dFXShaderStruct *)(rawData + 1); - AddString(data, "ShaderName", shader->shadername, "string"); - AddInt8(data, "Technique", shader->technique); - delete[] rawData; + // TODO Fix W3dFXShaderStruct + // uint8_t *version = (uint8_t *)rawData; + // W3dFXShaderStruct *shader = (W3dFXShaderStruct *)(rawData + 1); + AddData(data, "W3D_CHUNK_FX_SHADER_INFO", "W3dFXShaderStruct", "", (void *)rawData); + } void Write_W3D_CHUNK_FX_SHADER_INFO(ChunkSaveClass &csave, ChunkTreePtr &data) { - // TODO: Implement Write_W3D_CHUNK_FX_SHADER_INFO captainslog_warn("Write_W3D_CHUNK_FX_SHADER_INFO not implemented"); -// char *rawData = new char[sizeof(W3dFXShaderStruct) + 1]; + char *rawData = (char *)data->data->info->value; + WriteChunkRaw(csave, W3D_CHUNK_FX_SHADER_INFO, rawData, data->data->chunkSize); } struct W3dFXShaderConstantStruct @@ -1538,7 +1521,7 @@ struct W3dFXShaderConstantStruct void Read_W3D_CHUNK_FX_SHADER_CONSTANT(ChunkLoadClass &cload, ChunkTreePtr &data) { char *rawData = ReadChunkRaw(cload); - // TODO check valid + // TODO check if this correct captainslog_dbgassert(data->data->chunkSize == sizeof(W3dFXShaderConstantStruct), "Chunk W3D_CHUNK_FX_SHADER_CONSTANT size does not match data size"); W3dFXShaderConstantStruct *constant = (W3dFXShaderConstantStruct *)rawData; uint32_t type = *(uint32_t *)rawData; @@ -1631,6 +1614,7 @@ struct W3dCompressedMotionChannelStructNew void Read_W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL(ChunkLoadClass &cload, ChunkTreePtr &data) { char *rawData = ReadChunkRaw(cload); + // TODO check if this correct captainslog_dbgassert(data->data->chunkSize == sizeof(W3dCompressedMotionChannelStructNew), "Chunk W3D_CHUNK_COMPRESSED_ANIMATION_MOTION_CHANNEL size does not match data size"); W3dCompressedMotionChannelStructNew *channel = (W3dCompressedMotionChannelStructNew *)rawData; if (channel->Flavor >= ANIM_FLAVOR_NEW_VALID) {