From b3ed387711af6997180bd5e012d38fefb80873cf Mon Sep 17 00:00:00 2001 From: MysterD Date: Wed, 9 Mar 2022 18:01:03 -0800 Subject: [PATCH] Added DynOS v1.1 without the dynamic options - Added support for coop-specific actors - Added support for coop-specific geo functions - Added support for coop-specific model functions --- Makefile | 3 + data/dynos.c.h | 18 + data/dynos.cpp.h | 701 ++++++ data/dynos.h | 38 + data/dynos_c.cpp | 30 + data/dynos_gfx_init.cpp | 63 + data/dynos_gfx_load.cpp | 313 +++ data/dynos_gfx_read.cpp | 1887 +++++++++++++++++ data/dynos_gfx_texture.cpp | 285 +++ data/dynos_gfx_update.cpp | 161 ++ data/dynos_gfx_write.cpp | 318 +++ data/dynos_level.cpp | 825 +++++++ data/dynos_main.cpp | 78 + data/dynos_misc.cpp | 502 +++++ data/dynos_warps.cpp | 485 +++++ dynos.mk | 15 + include/types.h | 2 + src/engine/geo_layout.c | 3 + src/engine/level_script.c | 3 + src/game/area.c | 1 + src/game/game_init.c | 4 +- src/game/object_helpers.c | 2 + src/game/rendering_graph_node.c | 4 + src/pc/controller/controller_keyboard_debug.c | 4 + src/pc/gfx/gfx_pc.c | 9 +- 25 files changed, 5744 insertions(+), 10 deletions(-) create mode 100644 data/dynos.c.h create mode 100644 data/dynos.cpp.h create mode 100644 data/dynos.h create mode 100644 data/dynos_c.cpp create mode 100644 data/dynos_gfx_init.cpp create mode 100644 data/dynos_gfx_load.cpp create mode 100644 data/dynos_gfx_read.cpp create mode 100644 data/dynos_gfx_texture.cpp create mode 100644 data/dynos_gfx_update.cpp create mode 100644 data/dynos_gfx_write.cpp create mode 100644 data/dynos_level.cpp create mode 100644 data/dynos_main.cpp create mode 100644 data/dynos_misc.cpp create mode 100644 data/dynos_warps.cpp create mode 100644 dynos.mk diff --git a/Makefile b/Makefile index f4a40965..d2ad5968 100644 --- a/Makefile +++ b/Makefile @@ -543,6 +543,9 @@ DEP_FILES := $(O_FILES:.o=.d) $(ULTRA_O_FILES:.o=.d) $(GODDARD_O_FILES:.o=.d) $( # Segment elf files SEG_FILES := $(SEGMENT_ELF_FILES) $(ACTOR_ELF_FILES) $(LEVEL_ELF_FILES) +# Dynos +include dynos.mk + ##################### Compiler Options ####################### INCLUDE_CFLAGS := -I include -I $(BUILD_DIR) -I $(BUILD_DIR)/include -I src -I . $(EXTRA_INCLUDES) ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth diff --git a/data/dynos.c.h b/data/dynos.c.h new file mode 100644 index 00000000..37db3eb1 --- /dev/null +++ b/data/dynos.c.h @@ -0,0 +1,18 @@ +#ifndef DYNOS_C_H +#define DYNOS_C_H +#ifndef __cplusplus + +#include "dynos.h" + +void *dynos_update_cmd (void *cmd); +void dynos_update_gfx (); +void dynos_update_opt (void *pad); +s32 dynos_gfx_import_texture (void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize); +void dynos_gfx_swap_animations(void *ptr); + +#ifdef COOP +bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct); +#endif + +#endif +#endif diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h new file mode 100644 index 00000000..7a58d02f --- /dev/null +++ b/data/dynos.cpp.h @@ -0,0 +1,701 @@ +#ifndef DYNOS_CPP_H +#define DYNOS_CPP_H +#ifdef __cplusplus + +#include "dynos.h" +extern "C" { +#include "engine/math_util.h" +} + +#define FUNCTION_CODE (u32) 0x434E5546 +#define POINTER_CODE (u32) 0x52544E50 + +// +// Enums +// + +enum { + DATA_TYPE_NONE = 0, + DATA_TYPE_LIGHT, + DATA_TYPE_TEXTURE, + DATA_TYPE_VERTEX, + DATA_TYPE_DISPLAY_LIST, + DATA_TYPE_GEO_LAYOUT, + DATA_TYPE_ANIMATION_VALUE, + DATA_TYPE_ANIMATION_INDEX, + DATA_TYPE_ANIMATION, + DATA_TYPE_ANIMATION_TABLE, + DATA_TYPE_GFXDYNCMD, + DATA_TYPE_UNUSED, +}; + +enum { + DOPT_NONE = 0, + + DOPT_TOGGLE, + DOPT_CHOICE, + DOPT_SCROLL, + DOPT_BIND, + DOPT_BUTTON, + DOPT_SUBMENU, + + // These ones are used by the Warp to Level built-in submenu + DOPT_CHOICELEVEL, + DOPT_CHOICEAREA, + DOPT_CHOICESTAR, + DOPT_CHOICEPARAM, +}; + +// +// DynOS Array +// A vector-like array, implemented to be processed really fast, but cannot handle C++ complex classes like std::string +// + +template +class Array { +public: + inline Array() : mBuffer(NULL), mCount(0), mCapacity(0) { + } + + inline Array(const std::initializer_list &aList) : mBuffer(NULL), mCount(0), mCapacity(0) { + Resize(aList.size()); + memcpy(mBuffer, aList.begin(), mCount * sizeof(T)); + } + + inline Array(const T *aBegin, const T *aEnd) : mBuffer(NULL), mCount(0), mCapacity(0) { + Resize(aEnd - aBegin); + memcpy(mBuffer, aBegin, mCount * sizeof(T)); + } + + inline Array(const Array &aOther) : mBuffer(NULL), mCount(0), mCapacity(0) { + Resize(aOther.mCount); + memcpy(mBuffer, aOther.mBuffer, mCount * sizeof(T)); + } + + inline void operator=(const Array &aOther) { + Resize(aOther.mCount); + memcpy(mBuffer, aOther.mBuffer, mCount * sizeof(T)); + } + + inline ~Array() { + Clear(); + } + +public: + void Resize(s32 aCount) { + if (aCount > mCapacity) { + mCapacity = MAX(aCount, MAX(16, mCapacity * 2)); + T *_Buffer = (T *) calloc(mCapacity, sizeof(T)); + if (mBuffer) { + memcpy(_Buffer, mBuffer, mCount * sizeof(T)); + free(mBuffer); + } + mBuffer = _Buffer; + } + mCount = aCount; + } + + void Add(const T& aItem) { + Resize(mCount + 1); + mBuffer[mCount - 1] = aItem; + } + + void Remove(s32 aIndex) { + memmove(mBuffer + aIndex, mBuffer + aIndex + 1, (mCount - aIndex - 1) * sizeof(T)); + mCount--; + } + + void Pop() { + mCount--; + } + + void RemoveAll() { + mCount = 0; + } + + void Clear() { + if (mBuffer) free(mBuffer); + mBuffer = NULL; + mCount = 0; + mCapacity = 0; + } + + s32 Find(const T& aItem) const { + for (s32 i = 0; i != mCount; ++i) { + if (mBuffer[i] == aItem) { + return i; + } + } + return -1; + } + + template + s32 FindIf(Predicate aPredicate) const { + for (s32 i = 0; i != mCount; ++i) { + if (aPredicate(mBuffer[i])) { + return i; + } + } + return -1; + } + +public: + inline const T *begin() const { return mBuffer; } + inline const T *end() const { return mBuffer + mCount; } + inline T *begin() { return mBuffer; } + inline T *end() { return mBuffer + mCount; } + + inline const T &operator[](s32 aIndex) const { return mBuffer[aIndex]; } + inline T &operator[](s32 aIndex) { return mBuffer[aIndex]; } + + inline s32 Count() const { return mCount; } + inline bool Empty() const { return mCount == 0; } + +public: + void Read(FILE *aFile) { + s32 _Length = 0; fread(&_Length, sizeof(s32), 1, aFile); + Resize(_Length); + fread(mBuffer, sizeof(T), _Length, aFile); + } + + void Write(FILE *aFile) const { + fwrite(&mCount, sizeof(s32), 1, aFile); + fwrite(mBuffer, sizeof(T), mCount, aFile); + } + +private: + T *mBuffer; + s32 mCount; + s32 mCapacity; +}; + +// +// DynOS String +// A fixed-size string that doesn't require heap memory allocation +// + +#define STRING_SIZE 127 +class String { +public: + inline String() : mCount(0) { + mBuffer[0] = 0; + } + + inline String(const char *aString) : mCount(0) { + if (aString) { + u64 _Length = strlen(aString); + mCount = MIN(_Length, STRING_SIZE - 1); + memcpy(mBuffer, aString, _Length); + } + mBuffer[mCount] = 0; + } + + template + inline String(const char *aFmt, Args... aArgs) : mCount(0) { + snprintf(mBuffer, STRING_SIZE, aFmt, aArgs...); + mCount = (u8) strlen(mBuffer); + mBuffer[mCount] = 0; + } + + inline String(const String &aOther) : mCount(0) { + mCount = aOther.mCount; + memcpy(mBuffer, aOther.mBuffer, mCount); + mBuffer[mCount] = 0; + } + + inline void operator=(const String &aOther) { + mCount = aOther.mCount; + memcpy(mBuffer, aOther.mBuffer, mCount); + mBuffer[mCount] = 0; + } + +public: + void Add(char aChar) { + if (mCount == STRING_SIZE - 1) return; + mBuffer[mCount++] = aChar; + mBuffer[mCount] = 0; + } + + void Remove(s32 aIndex) { + memmove(mBuffer + aIndex, mBuffer + aIndex + 1, (mCount-- - aIndex - 1)); + mBuffer[mCount] = 0; + } + + void RemoveAll() { + mCount = 0; + mBuffer[0] = 0; + } + + void Clear() { + mCount = 0; + mBuffer[0] = 0; + } + + s32 Find(char aChar, s32 aStart = 0) const { + for (u8 i = (u8) aStart; i < mCount; ++i) { + if (mBuffer[i] == aChar) { + return (s32) i; + } + } + return -1; + } + + s32 Find(const char *aString, s32 aStart = 0) const { + const char *_Ptr = strstr(mBuffer + aStart, aString); + if (_Ptr) return (s32) (_Ptr - mBuffer); + return -1; + } + + s32 FindLast(char aChar) const { + for (u8 i = mCount; i != 0; --i) { + if (mBuffer[i - 1] == aChar) { + return (s32) (i - 1); + } + } + return -1; + } + + String SubString(s32 aStart, s32 aCount = STRING_SIZE - 1) const { + if (aStart >= mCount) return String(); + if (aCount < 0) aCount = STRING_SIZE - 1; + aCount = MIN(aCount, mCount - aStart); + String _String; + _String.mCount = aCount; + memcpy(_String.mBuffer, mBuffer + aStart, aCount); + _String.mBuffer[aCount] = 0; + return _String; + } + +public: + inline const char *begin() const { return mBuffer; } + inline const char *end() const { return mBuffer + mCount; } + inline char *begin() { return mBuffer; } + inline char *end() { return mBuffer + mCount; } + + inline const char &operator[](s32 aIndex) const { return mBuffer[aIndex]; } + inline char &operator[](s32 aIndex) { return mBuffer[aIndex]; } + + inline s32 Length() const { return (s32) mCount; } + inline bool Empty() const { return mCount == 0; } + +public: + bool operator==(const char *aString) const { + if (strlen(aString) != mCount) return false; + for (u8 i = 0; i != mCount; ++i) { + if (aString[i] != mBuffer[i]) { + return false; + } + } + return true; + } + + bool operator==(const String &aOther) const { + if (aOther.mCount != mCount) return false; + for (u8 i = 0; i != mCount; ++i) { + if (aOther.mBuffer[i] != mBuffer[i]) { + return false; + } + } + return true; + } + + bool operator!=(const char *aString) const { + if (strlen(aString) != mCount) return true; + for (u8 i = 0; i != mCount; ++i) { + if (aString[i] != mBuffer[i]) { + return true; + } + } + return false; + } + + bool operator!=(const String &aOther) const { + if (aOther.mCount != mCount) return true; + for (u8 i = 0; i != mCount; ++i) { + if (aOther.mBuffer[i] != mBuffer[i]) { + return true; + } + } + return false; + } + +public: + void Read(FILE *aFile) { + fread(&mCount, sizeof(u8), 1, aFile); + fread(mBuffer, sizeof(char), mCount, aFile); + mBuffer[mCount] = 0; + } + + void Write(FILE *aFile) const { + fwrite(&mCount, sizeof(u8), 1, aFile); + fwrite(mBuffer, sizeof(char), mCount, aFile); + } + + s32 ParseInt() const { + s32 i = 0; + if (mBuffer[1] == 'x') { + sscanf(mBuffer + 2, "%x", &i); + } else { + sscanf(mBuffer, "%d", &i); + } + return i; + } + + f32 ParseFloat() const { + f32 f = 0.f; + sscanf(mBuffer, "%f", &f); + return f; + } + +private: + char mBuffer[STRING_SIZE]; + u8 mCount; +}; +static_assert(sizeof(String) == (STRING_SIZE + 1), "sizeof(String) must be (STRING_SIZE + 1)"); + +// +// Types +// + +template +using Pair = std::pair; + +typedef std::string SysPath; + +class NoCopy { + protected: + NoCopy() {} + ~NoCopy() {} + private: + NoCopy(const NoCopy &) = delete; + void operator=(const NoCopy &) = delete; +}; + +struct TexData : NoCopy { + Array mPngData; + Array mRawData; + s32 mRawWidth = -1; + s32 mRawHeight = -1; + s32 mRawFormat = -1; + s32 mRawSize = -1; + bool mUploaded = false; +}; + +struct AnimData : NoCopy { + s16 mFlags = 0; + s16 mUnk02 = 0; + s16 mUnk04 = 0; + s16 mUnk06 = 0; + s16 mUnk08 = 0; + Pair mUnk0A; + Pair> mValues; + Pair> mIndex; + u32 mLength = 0; +}; + +template +struct DataNode : NoCopy { + String mName; + T* mData = NULL; + u32 mSize = 0; + Array mTokens; + u64 mModelIdentifier = 0; + u64 mLoadIndex = 0; +}; +template +using DataNodes = Array*>; + +struct GfxContext { + DataNode* mCurrentTexture = NULL; + DataNode* mCurrentPalette = NULL; +}; + +template +using AnimBuffer = Pair>; +struct GfxData : NoCopy { + + // Model data + DataNodes mLights; + DataNodes mTextures; + DataNodes mVertices; + DataNodes mDisplayLists; + DataNodes mGeoLayouts; + + // Animation data + Array *> mAnimValues; + Array *> mAnimIndices; + DataNodes mAnimations; + Array> mAnimationTable; + + // Current + u64 mLoadIndex = 0; + s32 mErrorCount = 0; + u32 mModelIdentifier = 0; + SysPath mPackFolder; + Array mPointerList; + GfxContext mGfxContext; + Array mGeoNodeStack; +}; + +struct ActorGfx { + GfxData *mGfxData = NULL; + GraphNode *mGraphNode = NULL; + s32 mPackIndex = 0; +}; + +struct PackData { + SysPath mPath; +}; + +typedef Pair Label; +struct DynosOption : NoCopy { + String mName; + String mConfigName; // Name used in the config file + Label mLabel; + Label mTitle; // Full caps label, displayed with colored font + DynosOption *mPrev; + DynosOption *mNext; + DynosOption *mParent; + bool mDynos; // true from create, false from convert + u8 mType; + + // TOGGLE + struct Toggle : NoCopy { + bool *mTog; + } mToggle; + + // CHOICE + struct Choice : NoCopy { + Array