Merge branch 'main' into patch-4

This commit is contained in:
cobalt2727 2023-11-18 17:22:57 -06:00 committed by GitHub
commit 8d81106681
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1460 changed files with 30377 additions and 188740 deletions

View File

@ -2,8 +2,8 @@ name: Build
on: on:
push: push:
branches-ignore: # branches-ignore:
- main # - main
paths-ignore: paths-ignore:
- '*.json' - '*.json'
- '*.md' - '*.md'
@ -18,7 +18,7 @@ env:
jobs: jobs:
build-linux: build-linux:
name: Build Linux (${{matrix.name}} x86_64) name: Build Linux (${{matrix.name}} x86_64)
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
env: env:
BUILDCACHE_DIR: ${{github.workspace}}/.buildcache BUILDCACHE_DIR: ${{github.workspace}}/.buildcache
@ -46,10 +46,8 @@ jobs:
sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
sudo apt-get -y install ninja-build clang lld libcurl4-openssl-dev intel-oneapi-ipp-devel \ sudo apt-get -y install ninja-build clang lld libcurl4-openssl-dev intel-oneapi-ipp-devel \
zlib1g-dev libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev \ zlib1g-dev libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev \
libpulse-dev libudev-dev libpng-dev libncurses5-dev libx11-xcb-dev qt5-default libpulse-dev libudev-dev libpng-dev libncurses5-dev libx11-xcb-dev libfreetype-dev \
libxinerama-dev libxcursor-dev python3-markupsafe libgtk-3-dev
yarn global add @sentry/cli
echo "$(yarn global bin)" >> $GITHUB_PATH
# setup buildcache # setup buildcache
curl -LSfs https://github.com/encounter/buildcache/releases/download/$BUILDCACHE_VERSION/buildcache-linux.tar.gz | tar xz -C "$RUNNER_WORKSPACE" curl -LSfs https://github.com/encounter/buildcache/releases/download/$BUILDCACHE_VERSION/buildcache-linux.tar.gz | tar xz -C "$RUNNER_WORKSPACE"
@ -84,12 +82,22 @@ jobs:
- name: Print buildcache stats - name: Print buildcache stats
run: buildcache -s run: buildcache -s
- name: Generate AppImage
run: ci/build-appimage.sh
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: metaforce-${{env.METAFORCE_VERSION}}-linux-${{matrix.preset}}-x86_64
path: |
build/install/Metaforce-*.AppImage
build/install/debug.tar.*
build-macos: build-macos:
name: Build macOS (AppleClang universal) name: Build macOS (AppleClang universal)
runs-on: macos-11 runs-on: macos-latest
env: env:
Qt_VERSION: 5.15.2
IPP_VERSION: 2021.2.0.192 IPP_VERSION: 2021.2.0.192
BUILDCACHE_DIR: ${{github.workspace}}/.buildcache BUILDCACHE_DIR: ${{github.workspace}}/.buildcache
@ -105,11 +113,7 @@ jobs:
brew upgrade --formula brew upgrade --formula
brew install ninja graphicsmagick imagemagick brew install ninja graphicsmagick imagemagick
yarn global add create-dmg yarn global add create-dmg
pip3 install markupsafe
# universal qt5 from macports
curl -LSfs https://axiodl.com/files/qt-$Qt_VERSION.mpkg -o /tmp/qt-$Qt_VERSION.mpkg
sudo installer -pkg /tmp/qt-$Qt_VERSION.mpkg -target /
echo /opt/local/libexec/qt5/bin >> $GITHUB_PATH
# setup buildcache # setup buildcache
curl -LSfs https://github.com/encounter/buildcache/releases/download/$BUILDCACHE_VERSION/buildcache-macos.zip -o /tmp/buildcache-macos.zip curl -LSfs https://github.com/encounter/buildcache/releases/download/$BUILDCACHE_VERSION/buildcache-macos.zip -o /tmp/buildcache-macos.zip
@ -141,11 +145,103 @@ jobs:
run: cmake --build --preset x-macos-ci run: cmake --build --preset x-macos-ci
- name: Print buildcache stats - name: Print buildcache stats
if: 'false' # temporarily disabled
run: buildcache -s run: buildcache -s
- name: Import signing certificate
uses: devbotsxyz/xcode-import-certificate@master
with:
certificate-data: ${{secrets.MACOS_CERTIFICATE_DATA}}
certificate-passphrase: ${{secrets.MACOS_CERTIFICATE_PASSWORD}}
keychain-password: ${{secrets.MACOS_KEYCHAIN_PASSWORD}}
- name: Deploy & codesign application
env:
ASC_USERNAME: ${{secrets.MACOS_ASC_USERNAME}}
ASC_PASSWORD: ${{secrets.MACOS_ASC_PASSWORD}}
ASC_TEAM_ID: ${{secrets.MACOS_ASC_TEAM_ID}}
CODESIGN_IDENT: ${{secrets.MACOS_CODESIGN_IDENT}}
run: ci/build-dmg.sh
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: metaforce-${{env.METAFORCE_VERSION}}-macos-appleclang-universal
path: |
build/install/Metaforce *.dmg
build/install/debug.tar.*
build-ios:
name: Build iOS (AppleClang arm64)
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
- name: Install dependencies
run: |
brew update
brew upgrade --formula
brew install ninja
pip3 install markupsafe
- name: Configure CMake
run: cmake --preset ios-default
- name: Build
run: cmake --build --preset ios-default --target install
- name: Generate IPA
run: ci/build-ipa.sh
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: metaforce-${{env.METAFORCE_VERSION}}-ios-appleclang-arm64
path: |
build/install/Metaforce.ipa
build/install/debug.tar.*
build-tvos:
name: Build tvOS (AppleClang arm64)
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
- name: Install dependencies
run: |
brew update
brew upgrade --formula
brew install ninja
pip3 install markupsafe
- name: Configure CMake
run: cmake --preset tvos-default
- name: Build
run: cmake --build --preset tvos-default --target install
- name: Generate IPA
run: ci/build-ipa.sh
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: metaforce-${{env.METAFORCE_VERSION}}-tvos-appleclang-arm64
path: |
build/install/Metaforce.ipa
build/install/debug.tar.*
build-windows: build-windows:
name: Build Windows (${{matrix.name}} x86_64) name: Build Windows (${{matrix.name}} x86_64)
runs-on: windows-2019 runs-on: windows-latest
env: env:
Qt_VERSION: 5.15.2 Qt_VERSION: 5.15.2
@ -158,11 +254,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
# Disabled due to memory constraints - name: MSVC
# - name: MSVC preset: msvc
# preset: msvc #- name: Clang
- name: Clang # preset: clang
preset: clang
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -191,6 +286,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
choco install ninja vulkan-sdk choco install ninja vulkan-sdk
pip install markupsafe
# set up buildcache # set up buildcache
$TempDir = "$env:RUNNER_WORKSPACE\temp" $TempDir = "$env:RUNNER_WORKSPACE\temp"
@ -221,3 +317,11 @@ jobs:
- name: Print buildcache stats - name: Print buildcache stats
run: buildcache -s run: buildcache -s
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: metaforce-${{env.METAFORCE_VERSION}}-win32-${{matrix.preset}}-x86_64
path: |
${{env.BUILD_DIR}}/install/*.exe
${{env.BUILD_DIR}}/install/debug.7z

View File

@ -1,13 +1,14 @@
name: Release name: Release
on: on: workflow_dispatch
push: #on:
branches: # push:
- main # branches:
paths-ignore: # - main
- '*.json' # paths-ignore:
- '*.md' # - '*.json'
- '*LICENSE' # - '*.md'
# - '*LICENSE'
env: env:
BUILDCACHE_VERSION: v0.27.3 BUILDCACHE_VERSION: v0.27.3
@ -46,7 +47,7 @@ jobs:
sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
sudo apt-get -y install ninja-build clang lld libcurl4-openssl-dev intel-oneapi-ipp-devel \ sudo apt-get -y install ninja-build clang lld libcurl4-openssl-dev intel-oneapi-ipp-devel \
zlib1g-dev libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev \ zlib1g-dev libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev \
libpulse-dev libudev-dev libpng-dev libncurses5-dev libx11-xcb-dev qt5-default libpulse-dev libudev-dev libpng-dev libncurses5-dev libx11-xcb-dev qt5-default libfreetype-dev
yarn global add @sentry/cli yarn global add @sentry/cli
echo "$(yarn global bin)" >> $GITHUB_PATH echo "$(yarn global bin)" >> $GITHUB_PATH
@ -121,7 +122,7 @@ jobs:
run: | run: |
brew update brew update
brew upgrade --formula brew upgrade --formula
brew install ninja graphicsmagick imagemagick getsentry/tools/sentry-cli brew install ninja graphicsmagick imagemagick getsentry/tools/sentry-cli freetype
yarn global add create-dmg yarn global add create-dmg
# universal qt5 from macports # universal qt5 from macports

49
.gitmodules vendored
View File

@ -1,59 +1,48 @@
[submodule "nod"] [submodule "extern/nod"]
path = extern/nod path = extern/nod
url = ../nod.git url = ../nod.git
branch = master branch = master
[submodule "amuse"] [submodule "extern/kabufuda"]
path = extern/amuse
url = ../amuse.git
branch = master
[submodule "kabufuda"]
path = extern/kabufuda path = extern/kabufuda
url = ../kabufuda.git url = ../kabufuda.git
branch = master branch = master
[submodule "jbus"] [submodule "extern/jbus"]
path = extern/jbus path = extern/jbus
url = ../jbus.git url = ../jbus.git
branch = master branch = master
[submodule "assetnameparser/tinyxml2"] [submodule "extern/discord-rpc"]
path = extern/tinyxml2
url = ../tinyxml2.git
branch = master
[submodule "sanitizers-cmake"]
path = extern/sanitizers-cmake
url = https://github.com/arsenm/sanitizers-cmake.git
branch = master
[submodule "discord-rpc"]
path = extern/discord-rpc path = extern/discord-rpc
url = https://github.com/discordapp/discord-rpc.git url = https://github.com/discordapp/discord-rpc.git
branch = master branch = master
[submodule "rapidjson"] [submodule "extern/rapidjson"]
path = extern/rapidjson path = extern/rapidjson
url = https://github.com/Tencent/rapidjson.git url = https://github.com/Tencent/rapidjson.git
branch = master branch = master
[submodule "NESEmulator/fixNES"] [submodule "extern/fixNES"]
path = extern/fixNES path = extern/fixNES
url = https://github.com/FIX94/fixNES.git url = https://github.com/FIX94/fixNES.git
branch = master branch = master
[submodule "extern/libSquish"]
path = extern/libSquish
url = ../libSquish.git
branch = master
[submodule "extern/athena"] [submodule "extern/athena"]
path = extern/athena path = extern/athena
url = ../../libAthena/athena.git url = ../../libAthena/athena.git
branch = master branch = master
[submodule "extern/boo"]
path = extern/boo
url = ../boo.git
branch = master
[submodule "extern/libjpeg-turbo"] [submodule "extern/libjpeg-turbo"]
path = extern/libjpeg-turbo path = extern/libjpeg-turbo
url = ../libjpeg-turbo.git url = ../libjpeg-turbo.git
branch = thp branch = thp
[submodule "zeus"] [submodule "extern/zeus"]
path = extern/zeus path = extern/zeus
url = ../zeus.git url = ../zeus.git
branch = master branch = master
[submodule "extern/imgui"] [submodule "extern/nativefiledialog-extended"]
path = extern/imgui path = extern/nativefiledialog-extended
url = https://github.com/ocornut/imgui.git url = https://github.com/encounter/nativefiledialog-extended.git
branch = nfd-install-option
[submodule "extern/optick"]
path = extern/optick
url = https://github.com/AxioDL/optick.git
branch = master
[submodule "extern/aurora"]
path = extern/aurora
url = https://github.com/encounter/aurora.git
branch = main

View File

@ -50,7 +50,7 @@ endif ()
if (METAFORCE_WC_DESCRIBE) if (METAFORCE_WC_DESCRIBE)
string(REGEX REPLACE "v([0-9]+)\.([0-9]+)\.([0-9]+)\-([0-9]+).*" "\\1.\\2.\\3.\\4" METAFORCE_VERSION_STRING "${METAFORCE_WC_DESCRIBE}") string(REGEX REPLACE "v([0-9]+)\.([0-9]+)\.([0-9]+)\-([0-9]+).*" "\\1.\\2.\\3.\\4" METAFORCE_VERSION_STRING "${METAFORCE_WC_DESCRIBE}")
string(REGEX REPLACE "v([0-9]+)\.([0-9]+)\.([0-9]+).*" "\\1.\\2.\\3" METAFORCE_VERSION_STRING "${METAFORCE_VERSION_STRING}") string(REGEX REPLACE "v([0-9]+)\.([0-9]+)\.([0-9]+).*" "\\1.\\2.\\3" METAFORCE_SHORT_VERSION_STRING "${METAFORCE_WC_DESCRIBE}")
else () else ()
set(METAFORCE_WC_DESCRIBE "UNKNOWN-VERSION") set(METAFORCE_WC_DESCRIBE "UNKNOWN-VERSION")
set(METAFORCE_VERSION_STRING "0.0.0") set(METAFORCE_VERSION_STRING "0.0.0")
@ -64,20 +64,36 @@ if(DEFINED ENV{GITHUB_ENV})
endif() endif()
message(STATUS "Metaforce version set to ${METAFORCE_WC_DESCRIBE}") message(STATUS "Metaforce version set to ${METAFORCE_WC_DESCRIBE}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
project(metaforce LANGUAGES C CXX ASM VERSION ${METAFORCE_VERSION_STRING}) if(APPLE)
set(EXTRA_LANGUAGES OBJC)
endif()
project(metaforce LANGUAGES C CXX ASM ${EXTRA_LANGUAGES} VERSION ${METAFORCE_VERSION_STRING})
if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS)
# ios.toolchain.cmake hack for SDL
set(TVOS ON)
set(IOS OFF)
endif ()
if (EMSCRIPTEN)
set(CMAKE_EXECUTABLE_SUFFIX .html)
endif ()
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ATHENA_ARCH) string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ATHENA_ARCH)
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" ATHENA_HOST_ARCH) string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" ATHENA_HOST_ARCH)
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" HOST_PLATFORM_NAME)
string(TOLOWER "${CMAKE_SYSTEM_NAME}" PLATFORM_NAME)
set(ATHENA_EXTENSION "tar.gz") set(ATHENA_EXTENSION "tar.gz")
if (CMAKE_SYSTEM_NAME STREQUAL Darwin) if (CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
set(PLATFORM_NAME macos) set(HOST_PLATFORM_NAME macos)
set(ATHENA_ARCH universal) set(ATHENA_ARCH universal)
set(ATHENA_HOST_ARCH universal) set(ATHENA_HOST_ARCH universal)
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(HOST_PLATFORM_NAME win32)
set(ATHENA_EXTENSION ".7z")
endif ()
if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
set(PLATFORM_NAME macos)
elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) elseif (CMAKE_SYSTEM_NAME STREQUAL Windows)
set(PLATFORM_NAME win32) set(PLATFORM_NAME win32)
set(ATHENA_EXTENSION ".7z")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(PLATFORM_NAME linux)
endif () endif ()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Binaries) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Binaries)
@ -89,15 +105,6 @@ if(APPLE AND NOT CMAKE_OSX_SYSROOT)
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
endif() endif()
option(METAFORCE_CROSSCOMPILING "Don't build tools; attempt package import" OFF)
if (METAFORCE_CROSSCOMPILING)
set(CMAKE_CROSSCOMPILING On)
endif()
if(CMAKE_CROSSCOMPILING)
set(HAVE_WORDS_BIGENDIAN_EXITCODE 0 CACHE INTEGER "Makes soxr happy" FORCE)
endif()
# MSVC has a "latest" flag, which always uses the newest standard # MSVC has a "latest" flag, which always uses the newest standard
# when available. GCC and Clang posess no such flag, and must be # when available. GCC and Clang posess no such flag, and must be
# manually enforced. CMake, curiously, also doesn't have a "latest" # manually enforced. CMake, curiously, also doesn't have a "latest"
@ -110,9 +117,6 @@ endif()
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Force shared libs off" FORCE) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Force shared libs off" FORCE)
set(BUILD_STATIC_LIBS ON CACHE BOOL "Force static libs on" FORCE) set(BUILD_STATIC_LIBS ON CACHE BOOL "Force static libs on" FORCE)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/extern/sanitizers-cmake/cmake")
find_package(Sanitizers)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64) if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64)
set(METAFORCE_VECTOR_ISA "sse41" CACHE STRING "Vector ISA to build for (sse2, sse3, sse41, avx, avx2)") set(METAFORCE_VECTOR_ISA "sse41" CACHE STRING "Vector ISA to build for (sse2, sse3, sse41, avx, avx2)")
endif () endif ()
@ -240,15 +244,20 @@ else()
add_compile_options(-fno-asynchronous-unwind-tables) add_compile_options(-fno-asynchronous-unwind-tables)
endif() endif()
if(METAFORCE_MSAN) if (METAFORCE_ASAN)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++> -fsanitize=address
-fsanitize-address-use-after-scope)
add_link_options($<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++> -fsanitize=address
-fsanitize-address-use-after-scope)
elseif(METAFORCE_MSAN)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++> -fsanitize=memory add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++> -fsanitize=memory
-fsanitize-memory-track-origins -fsanitize-recover=all) -fsanitize-memory-track-origins -fsanitize-recover=all)
endif() endif()
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-rtti> add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions> $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
-Wall -Wno-multichar -Werror=implicit-fallthrough -Wall -Wno-multichar
-Wno-unused-variable -Wno-unused-result -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unused-result -Wno-unused-but-set-variable
-Wno-unused-function -Wno-sign-compare -Wno-unknown-pragmas -Werror) -Wno-unused-function -Wno-sign-compare -Wno-unknown-pragmas)
# doesn't work with generator expression in add_compile_options? # doesn't work with generator expression in add_compile_options?
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
add_compile_options(-Wno-unknown-warning-option -Wno-unused-private-field) add_compile_options(-Wno-unknown-warning-option -Wno-unused-private-field)
@ -259,10 +268,6 @@ else()
if(APPLE) if(APPLE)
add_compile_options(-Wno-error=deprecated-declarations add_compile_options(-Wno-error=deprecated-declarations
$<$<CONFIG:Release>:-flto=thin>) $<$<CONFIG:Release>:-flto=thin>)
if (METAFORCE_ASAN)
add_compile_options(-fsanitize=address -fsanitize-address-use-after-scope)
add_link_options(-fsanitize=address -fsanitize-address-use-after-scope)
endif ()
endif() endif()
endif() endif()
@ -341,161 +346,18 @@ if(USE_LD_GOLD)
endif() endif()
endif() endif()
# Add discord-rpc here find_package(ZLIB REQUIRED)
if(NOT GEKKO AND NOT NX) set(ZLIB_LIBRARIES ZLIB::ZLIB CACHE STRING "zlib libraries" FORCE)
set(PROJECT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/discord-rpc)
if (NOT CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR ${CMAKE_BINARY_DIR}/fake-prefix)
endif()
add_subdirectory(extern/discord-rpc/src EXCLUDE_FROM_ALL)
target_include_directories(discord-rpc PRIVATE extern/rapidjson/include PUBLIC extern/discord-rpc/include)
if (APPLE)
# remove their nasty hack
get_target_property(DISCORD_LINK_LIBRARIES discord-rpc INTERFACE_LINK_LIBRARIES)
list(REMOVE_ITEM DISCORD_LINK_LIBRARIES "-framework AppKit, -mmacosx-version-min=10.10")
set_target_properties(discord-rpc PROPERTIES INTERFACE_LINK_LIBRARIES "${DISCORD_LINK_LIBRARIES}")
endif ()
if (UNIX)
# remove another nasty hack
get_target_property(DISCORD_COMPILE_OPTIONS discord-rpc COMPILE_OPTIONS)
list(REMOVE_ITEM DISCORD_COMPILE_OPTIONS "-g")
set_target_properties(discord-rpc PROPERTIES COMPILE_OPTIONS "${DISCORD_COMPILE_OPTIONS}")
endif ()
endif()
if (NOT WIN32)
find_package(ZLIB REQUIRED)
set(ZLIB_LIBRARIES ZLIB::ZLIB CACHE STRING "zlib libraries" FORCE)
endif()
option(BUILD_ATHENA "Build Athena libraries from source" ON)
if (WIN32 OR APPLE)
# Default to binary atdna on Windows & macOS
option(BUILD_ATDNA "Build atdna utility from source (requires LLVM)" OFF)
else ()
option(BUILD_ATDNA "Build atdna utility from source (requires LLVM)" ON)
endif ()
if (NOT BUILD_ATDNA)
set(ATHENA_BASE_URL "https://github.com/libAthena/athena/releases/download/latest")
if (WIN32)
set(ATHENA_EXT 7z)
else()
set(ATHENA_EXT tar.gz)
endif()
include(FetchContent)
FetchContent_Declare(athena-host
URL "${ATHENA_BASE_URL}/athena-${PLATFORM_NAME}-${ATHENA_HOST_ARCH}.${ATHENA_EXT}")
message(STATUS "Fetching atdna host binary")
FetchContent_Populate(athena-host)
include(${athena-host_SOURCE_DIR}/lib/cmake/atdna/atdnaConfig.cmake)
endif ()
if (BUILD_ATHENA OR BUILD_ATDNA)
add_subdirectory(extern/athena EXCLUDE_FROM_ALL)
else()
if (ATHENA_ARCH STREQUAL ATHENA_HOST_ARCH)
set(athena_SOURCE_DIR "${athena-host_SOURCE_DIR}")
else()
FetchContent_Declare(athena
URL "${ATHENA_BASE_URL}/athena-${PLATFORM_NAME}-${ATHENA_ARCH}.tar.gz")
FetchContent_Populate(athena)
endif()
include(${athena_SOURCE_DIR}/lib/cmake/athena/AthenaConfig.cmake)
include(${athena_SOURCE_DIR}/lib/cmake/lzokay/lzokayConfig.cmake)
add_library(lzokay ALIAS lzokay::lzokay)
include(extern/athena/atdna/atdnaHelpers.cmake)
endif()
set(DATA_SPEC_LIBS RetroDataSpec AssetNameMap)
set(HECL_DATASPEC_DECLS
"/* RetroCommon specs */
namespace DataSpec
{
extern hecl::Database::DataSpecEntry SpecEntMP1;
extern hecl::Database::DataSpecEntry SpecEntMP1PC;
extern hecl::Database::DataSpecEntry SpecEntMP1ORIG;
extern hecl::Database::DataSpecEntry SpecEntMP2;
extern hecl::Database::DataSpecEntry SpecEntMP2PC;
extern hecl::Database::DataSpecEntry SpecEntMP2ORIG;
extern hecl::Database::DataSpecEntry SpecEntMP3;
extern hecl::Database::DataSpecEntry SpecEntMP3PC;
extern hecl::Database::DataSpecEntry SpecEntMP3ORIG;
}")
set(HECL_DATASPEC_PUSHES
" /* RetroCommon */
hecl::Database::DATA_SPEC_REGISTRY.reserve(9);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP1);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP1PC);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP1ORIG);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP2);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP2PC);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP2ORIG);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP3);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP3PC);
hecl::Database::DATA_SPEC_REGISTRY.push_back(&DataSpec::SpecEntMP3ORIG);")
add_subdirectory(extern/nod EXCLUDE_FROM_ALL)
add_subdirectory(extern/boo EXCLUDE_FROM_ALL)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(shaderc ExternalProject_Add(bintoc
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/hecl/shaderc" SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/bintoc"
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
INSTALL_COMMAND ${CMAKE_COMMAND} --build . --config Release --target install) INSTALL_COMMAND ${CMAKE_COMMAND} --build . --config Release --target install)
include(${CMAKE_CURRENT_LIST_DIR}/bintoc/bintocHelpers.cmake)
function(shaderc out) add_subdirectory(extern)
if(IS_ABSOLUTE ${out})
set(theOut ${out})
else()
set(theOut ${CMAKE_CURRENT_BINARY_DIR}/${out})
endif()
unset(theInsList)
foreach(in ${ARGN})
if(IS_ABSOLUTE ${in})
list(APPEND theInsList ${in})
else()
list(APPEND theInsList ${CMAKE_CURRENT_SOURCE_DIR}/${in})
endif()
endforeach()
get_filename_component(outDir ${theOut} DIRECTORY)
file(MAKE_DIRECTORY ${outDir})
file(RELATIVE_PATH outRel ${CMAKE_BINARY_DIR} ${theOut})
ExternalProject_Get_Property(shaderc INSTALL_DIR)
add_custom_command(OUTPUT ${theOut}.cpp ${theOut}.hpp
COMMAND "${INSTALL_DIR}/bin/shaderc" ARGS -o ${theOut} ${theInsList}
DEPENDS ${theInsList} shaderc
COMMENT "Compiling shader ${outRel}.shader")
endfunction()
include(hecl/ApplicationTools.cmake)
add_subdirectory(Shaders)
add_subdirectory(imgui) add_subdirectory(imgui)
add_subdirectory(extern/libSquish EXCLUDE_FROM_ALL)
add_subdirectory(extern/libpng EXCLUDE_FROM_ALL)
add_subdirectory(extern/libjpeg-turbo EXCLUDE_FROM_ALL)
add_subdirectory(hecl EXCLUDE_FROM_ALL)
add_subdirectory(extern/zeus EXCLUDE_FROM_ALL)
target_include_directories(hecl-full PRIVATE ${CMAKE_SOURCE_DIR})
target_include_directories(hecl-light PRIVATE ${CMAKE_SOURCE_DIR})
target_link_libraries(hecl-full PRIVATE zeus nod)
target_link_libraries(hecl-light PRIVATE zeus nod)
bintoc(CModelShaders.common.glsl.cpp Shaders/CModelShaders.common.glsl CMODELSHADERS_COMMON_GLSL)
bintoc(CModelShaders.vert.glsl.cpp Shaders/CModelShaders.vert.glsl CMODELSHADERS_VERT_GLSL)
bintoc(CModelShaders.frag.glsl.cpp Shaders/CModelShaders.frag.glsl CMODELSHADERS_FRAG_GLSL)
bintoc(CModelShaders.common.hlsl.cpp Shaders/CModelShaders.common.hlsl CMODELSHADERS_COMMON_HLSL)
bintoc(CModelShaders.vert.hlsl.cpp Shaders/CModelShaders.vert.hlsl CMODELSHADERS_VERT_HLSL)
bintoc(CModelShaders.frag.hlsl.cpp Shaders/CModelShaders.frag.hlsl CMODELSHADERS_FRAG_HLSL)
bintoc(CModelShaders.common.metal.cpp Shaders/CModelShaders.common.metal CMODELSHADERS_COMMON_METAL)
bintoc(CModelShaders.vert.metal.cpp Shaders/CModelShaders.vert.metal CMODELSHADERS_VERT_METAL)
bintoc(CModelShaders.frag.metal.cpp Shaders/CModelShaders.frag.metal CMODELSHADERS_FRAG_METAL)
add_library(CModelShaders
CModelShaders.common.glsl.cpp CModelShaders.vert.glsl.cpp CModelShaders.frag.glsl.cpp
CModelShaders.common.hlsl.cpp CModelShaders.vert.hlsl.cpp CModelShaders.frag.hlsl.cpp
CModelShaders.common.metal.cpp CModelShaders.vert.metal.cpp CModelShaders.frag.metal.cpp)
target_link_libraries(CModelShaders PUBLIC zeus)
target_link_libraries(shader_CModelShaders PUBLIC CModelShaders)
if(NOT TARGET atdna) if(NOT TARGET atdna)
# Import native atdna if cross-compiling # Import native atdna if cross-compiling
@ -505,86 +367,64 @@ if(NOT TARGET atdna)
endif() endif()
endif() endif()
add_subdirectory(extern/amuse EXCLUDE_FROM_ALL)
if (NOT CMAKE_CROSSCOMPILING)
add_subdirectory(assetnameparser EXCLUDE_FROM_ALL)
endif ()
add_compile_definitions(URDE_ZIP_INPUT_STREAM=1) # Enable CZipInputStream now that zlib header is known
add_subdirectory(DataSpec)
add_subdirectory(extern/kabufuda EXCLUDE_FROM_ALL)
add_subdirectory(extern/jbus EXCLUDE_FROM_ALL)
set(JBUS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/jbus/include)
add_subdirectory(NESEmulator EXCLUDE_FROM_ALL) add_subdirectory(NESEmulator EXCLUDE_FROM_ALL)
add_subdirectory(Runtime) add_subdirectory(Runtime)
add_subdirectory(mpcksum EXCLUDE_FROM_ALL)
add_subdirectory(gbalink EXCLUDE_FROM_ALL) add_subdirectory(gbalink EXCLUDE_FROM_ALL)
add_subdirectory(visigen)
add_dependencies(hecl visigen)
if (NOT WINDOWS_STORE AND NOT NX)
if (APPLE AND EXISTS /opt/local/libexec/qt5)
# macports qt5 (build with +universal)
set(Qt5Widgets_DIR /opt/local/libexec/qt5)
elseif (APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(QT_HOMEBREW_PATH /usr/local/opt/qt)
elseif (APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL arm64)
set(QT_HOMEBREW_PATH /opt/homebrew/opt/qt)
else ()
set(QT_HOMEBREW_PATH "")
endif ()
find_package(Qt6Widgets QUIET PATHS ${QT_HOMEBREW_PATH})
find_package(Qt5Widgets QUIET PATHS ${QT_HOMEBREW_PATH})
if (Qt6Widgets_FOUND)
message(STATUS "Qt6 found, metaforce-gui will be built")
add_subdirectory(metaforce-gui)
elseif(Qt5Widgets_FOUND)
message(STATUS "Qt5 found, metaforce-gui will be built")
add_subdirectory(metaforce-gui)
else()
message(STATUS "Qt5-6 not found, metaforce-gui will not be built")
endif()
endif()
configure_file(${CMAKE_SOURCE_DIR}/version.h.in ${CMAKE_BINARY_DIR}/version.h) configure_file(${CMAKE_SOURCE_DIR}/version.h.in ${CMAKE_BINARY_DIR}/version.h)
# Packaging logic # Packaging logic
list(APPEND BINARY_TARGETS metaforce hecl visigen) function(get_target_output_name target result_var)
set(DSYM_ONLY_TARGETS "") get_target_property(output_name ${target} OUTPUT_NAME)
if (output_name STREQUAL "output_name-NOTFOUND")
set(${result_var} "${target}" PARENT_SCOPE)
else ()
set(${result_var} "${output_name}" PARENT_SCOPE)
endif ()
endfunction()
function(get_target_prefix target result_var)
set(${result_var} "" PARENT_SCOPE)
if (APPLE)
# Have to recreate some bundle logic here, since CMake can't tell us
get_target_property(is_bundle ${target} MACOSX_BUNDLE)
if (is_bundle)
get_target_output_name(${target} output_name)
if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
set(${result_var} "${output_name}.app/Contents/MacOS/" PARENT_SCOPE)
else ()
set(${result_var} "${output_name}.app/" PARENT_SCOPE)
endif ()
endif ()
endif ()
endfunction()
list(APPEND BINARY_TARGETS metaforce)
set(EXTRA_TARGETS "")
if (TARGET crashpad_handler) if (TARGET crashpad_handler)
list(APPEND BINARY_TARGETS crashpad_handler) list(APPEND EXTRA_TARGETS crashpad_handler)
endif () endif ()
set(BIN_PREFIX "${CMAKE_INSTALL_PREFIX}") set(BIN_PREFIX "${CMAKE_INSTALL_PREFIX}")
if (TARGET metaforce-gui) install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${BIN_PREFIX})
if (APPLE)
# app bundle already has all needed binaries
install(TARGETS metaforce-gui DESTINATION ${BIN_PREFIX})
list(APPEND DSYM_ONLY_TARGETS metaforce-gui)
# we have to rename here, cmake is inflexible about bundle naming
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND rm -fr Metaforce.app)")
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND mv metaforce-gui.app Metaforce.app)")
set(BIN_PREFIX "${BIN_PREFIX}/Metaforce.app/Contents/MacOS")
else()
list(APPEND BINARY_TARGETS metaforce-gui)
endif ()
endif ()
install(TARGETS ${BINARY_TARGETS} DESTINATION ${BIN_PREFIX})
if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo) if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo)
foreach (target IN LISTS BINARY_TARGETS DSYM_ONLY_TARGETS) set(DEBUG_FILES_LIST "")
foreach (target IN LISTS BINARY_TARGETS EXTRA_TARGETS)
get_target_output_name(${target} output_name)
if (WIN32) if (WIN32)
install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${BIN_PREFIX} OPTIONAL) install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${BIN_PREFIX} OPTIONAL)
elseif (APPLE) elseif (APPLE)
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND dsymutil ${target})") get_target_prefix(${target} target_prefix)
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND strip -S ${target})") install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND rm -fr \"$<TARGET_FILE_NAME:${target}>.dSYM\")")
elseif (UNIX) install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND dsymutil \"${target_prefix}$<TARGET_FILE_NAME:${target}>\")")
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND objcopy --only-keep-debug ${target} ${target}.dbg)") install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND strip -S \"${target_prefix}$<TARGET_FILE_NAME:${target}>\")")
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND objcopy --strip-debug --add-gnu-debuglink=${target}.dbg ${target})") if (NOT target_prefix STREQUAL "")
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND mv \"${target_prefix}$<TARGET_FILE_NAME:${target}>.dSYM\" .)")
endif () endif ()
elseif (UNIX)
get_target_prefix(${target} target_prefix)
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND objcopy --only-keep-debug \"${target_prefix}$<TARGET_FILE_NAME:${target}>\" \"${target_prefix}$<TARGET_FILE_NAME:${target}>.dbg\")")
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND objcopy --strip-debug --add-gnu-debuglink=$<TARGET_FILE_NAME:${target}>.dbg \"${target_prefix}$<TARGET_FILE_NAME:${target}>\")")
endif ()
list(APPEND DEBUG_FILES_LIST "${output_name}")
endforeach () endforeach ()
set(DEBUG_FILES_LIST ${BINARY_TARGETS} ${DSYM_ONLY_TARGETS})
if (WIN32) if (WIN32)
list(TRANSFORM DEBUG_FILES_LIST APPEND ".pdb") list(TRANSFORM DEBUG_FILES_LIST APPEND ".pdb")
list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES) list(JOIN DEBUG_FILES_LIST " " DEBUG_FILES)
@ -599,3 +439,13 @@ if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo)
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND tar -I \"xz -9 -T0\" -cvf \"${CMAKE_INSTALL_PREFIX}/debug.tar.xz\" ${DEBUG_FILES})") install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND tar -I \"xz -9 -T0\" -cvf \"${CMAKE_INSTALL_PREFIX}/debug.tar.xz\" ${DEBUG_FILES})")
endif () endif ()
endif () endif ()
foreach (target IN LISTS BINARY_TARGETS)
get_target_prefix(${target} target_prefix)
foreach (extra_target IN LISTS EXTRA_TARGETS)
get_target_prefix(${extra_target} extra_prefix)
if (NOT "${target_prefix}" STREQUAL "${extra_prefix}")
# Copy extra target to target prefix
install(CODE "execute_process(WORKING_DIRECTORY \"${BIN_PREFIX}\" COMMAND cp \"${extra_prefix}$<TARGET_FILE_NAME:${extra_target}>\" \"${target_prefix}$<TARGET_FILE_NAME:${extra_target}>\")")
endif ()
endforeach ()
endforeach ()

View File

@ -29,7 +29,11 @@
"generator": "Ninja", "generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}", "binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": { "cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install" "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
"USE_LTO": {
"type": "BOOL",
"value": false
}
}, },
"vendor": { "vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "microsoft.com/VisualStudioSettings/CMake/1.0": {
@ -83,7 +87,39 @@
"inherits": [ "inherits": [
"relwithdebinfo", "relwithdebinfo",
"linux-clang" "linux-clang"
] ],
"cacheVariables": {
"USE_LTO": {
"type": "BOOL",
"value": true
}
}
},
{
"name": "linux-clang-debug-asan",
"displayName": "Linux (Clang) Debug w/ ASAN",
"inherits": [
"linux-clang-debug"
],
"cacheVariables": {
"METAFORCE_ASAN": {
"type": "BOOL",
"value": true
}
}
},
{
"name": "linux-clang-relwithdebinfo-asan",
"displayName": "Linux (Clang) RelWithDebInfo w/ ASAN",
"inherits": [
"linux-clang-relwithdebinfo"
],
"cacheVariables": {
"METAFORCE_ASAN": {
"type": "BOOL",
"value": true
}
}
}, },
{ {
"name": "windows-msvc", "name": "windows-msvc",
@ -102,7 +138,11 @@
"type": "FILEPATH", "type": "FILEPATH",
"value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" "value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}, },
"VCPKG_TARGET_TRIPLET": "x64-windows-static" "VCPKG_TARGET_TRIPLET": "x64-windows-static",
"VCPKG_SETUP_CMAKE_PROGRAM_PATH": {
"type": "BOOL",
"value": false
}
}, },
"vendor": { "vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "microsoft.com/VisualStudioSettings/CMake/1.0": {
@ -193,6 +233,52 @@
"macos-default" "macos-default"
] ]
}, },
{
"name": "ios-default",
"displayName": "iOS",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "ios.toolchain.cmake",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
"PLATFORM": "OS64",
"DEPLOYMENT_TARGET": "13.0",
"ENABLE_BITCODE": {
"type": "BOOL",
"value": false
}
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [
"macOS"
]
}
}
},
{
"name": "tvos-default",
"displayName": "tvOS",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "ios.toolchain.cmake",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
"PLATFORM": "TVOS",
"DEPLOYMENT_TARGET": "14.5",
"ENABLE_BITCODE": {
"type": "BOOL",
"value": false
}
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [
"macOS"
]
}
}
},
{ {
"name": "x-linux-ci", "name": "x-linux-ci",
"hidden": true, "hidden": true,
@ -232,9 +318,11 @@
"macos-default-relwithdebinfo" "macos-default-relwithdebinfo"
], ],
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER_LAUNCHER": "buildcache", "CMAKE_OSX_ARCHITECTURES": "arm64;x86_64",
"CMAKE_CXX_COMPILER_LAUNCHER": "buildcache", "IMGUI_USE_FREETYPE": {
"CMAKE_OSX_ARCHITECTURES": "arm64;x86_64" "type": "BOOL",
"value": false
}
} }
}, },
{ {
@ -295,6 +383,18 @@
"description": "Linux (Clang) release build with debug info", "description": "Linux (Clang) release build with debug info",
"displayName": "Linux (Clang) RelWithDebInfo" "displayName": "Linux (Clang) RelWithDebInfo"
}, },
{
"name": "linux-clang-debug-asan",
"configurePreset": "linux-clang-debug-asan",
"description": "Linux (Clang) debug build w/ ASAN",
"displayName": "Linux (Clang) Debug w/ ASAN"
},
{
"name": "linux-clang-relwithdebinfo-asan",
"configurePreset": "linux-clang-relwithdebinfo-asan",
"description": "Linux (Clang) release build with debug info w/ ASAN",
"displayName": "Linux (Clang) RelWithDebInfo w/ ASAN"
},
{ {
"name": "macos-default-debug", "name": "macos-default-debug",
"configurePreset": "macos-default-debug", "configurePreset": "macos-default-debug",
@ -307,6 +407,24 @@
"description": "macOS release build with debug info", "description": "macOS release build with debug info",
"displayName": "macOS RelWithDebInfo" "displayName": "macOS RelWithDebInfo"
}, },
{
"name": "ios-default",
"configurePreset": "ios-default",
"description": "iOS release build with debug info",
"displayName": "iOS RelWithDebInfo",
"targets": [
"metaforce"
]
},
{
"name": "tvos-default",
"configurePreset": "tvos-default",
"description": "tvOS release build with debug info",
"displayName": "tvOS RelWithDebInfo",
"targets": [
"metaforce"
]
},
{ {
"name": "windows-msvc-debug", "name": "windows-msvc-debug",
"configurePreset": "windows-msvc-debug", "configurePreset": "windows-msvc-debug",

View File

@ -1,3 +0,0 @@
message(STATUS "32-bit asset name map not found; downloading to '${CMAKE_CURRENT_BINARY_DIR}/AssetNameMap32.bin'")
file(DOWNLOAD "https://axiodl.com/files/AssetNameMap32.dat"
${CMAKE_CURRENT_BINARY_DIR}/AssetNameMap32.bin SHOW_PROGRESS EXPECTED_HASH SHA1=90b4e941c192eef41c81e60314f348bc787d1336)

View File

@ -1,3 +0,0 @@
message(STATUS "64-bit asset name map not found; downloading to '${CMAKE_CURRENT_BINARY_DIR}/AssetNameMap64.bin'")
file(DOWNLOAD "https://axiodl.com/files/AssetNameMap64.dat"
${CMAKE_CURRENT_BINARY_DIR}/AssetNameMap64.bin SHOW_PROGRESS EXPECTED_HASH SHA1=e49c03c9fff66adccec7af8120dda091636513e2)

View File

@ -1,95 +0,0 @@
#include "AssetNameMap.hpp"
#include "athena/Compression.hpp"
#include "athena/MemoryReader.hpp"
extern "C" const uint8_t ASSET_NAME_MP32[];
extern "C" const size_t ASSET_NAME_MP32_SZ;
extern "C" const size_t ASSET_NAME_MP32_DECOMPRESSED_SZ;
extern "C" const uint8_t ASSET_NAME_MP64[];
extern "C" const size_t ASSET_NAME_MP64_SZ;
extern "C" const size_t ASSET_NAME_MP64_DECOMPRESSED_SZ;
namespace DataSpec::AssetNameMap {
logvisor::Module Log("AssetNameMap");
struct SAsset {
std::string name;
std::string directory;
hecl::FourCC type;
SAsset() = default;
SAsset(const hecl::FourCC& typeIn, athena::io::IStreamReader& in) : type(typeIn) {
uint32_t nameLen = in.readUint32Big();
name = in.readString(nameLen);
uint32_t dirLen = in.readUint32Big();
directory = in.readString(dirLen);
}
};
static std::unordered_map<uint64_t, SAsset> g_AssetNameMap;
static bool g_AssetNameMapInit = false;
void LoadAssetMap(athena::io::MemoryReader& ar) {
if (!ar.hasError()) {
hecl::FourCC magic;
if (ar.length() >= 4)
ar.readBytesToBuf(&magic, 4);
if (magic != FOURCC('AIDM'))
Log.report(
logvisor::Warning,
FMT_STRING("Unable to load asset map; Assets will not have proper filenames for most files."));
else {
uint32_t assetCount = ar.readUint32Big();
g_AssetNameMap.reserve(assetCount);
for (uint32_t i = 0; i < assetCount; ++i) {
hecl::FourCC type;
ar.readBytesToBuf(&type, 4);
uint64_t id = ar.readUint64Big();
g_AssetNameMap[id] = SAsset(type, ar);
}
}
}
}
void InitAssetNameMap() {
if (g_AssetNameMapInit)
return;
Log.report(logvisor::Info, FMT_STRING("Initializing asset name database..."));
/* First load the 32bit map for MP1/2 */
if (ASSET_NAME_MP32_DECOMPRESSED_SZ != 0u) {
auto* decompressed = new uint8_t[ASSET_NAME_MP32_DECOMPRESSED_SZ];
athena::io::Compression::decompressZlib(ASSET_NAME_MP32, ASSET_NAME_MP32_SZ, decompressed,
ASSET_NAME_MP32_DECOMPRESSED_SZ);
athena::io::MemoryReader ar(decompressed, ASSET_NAME_MP32_DECOMPRESSED_SZ);
LoadAssetMap(ar);
delete[](decompressed);
} else {
Log.report(
logvisor::Warning,
FMT_STRING("AssetNameMap32 unavailable; Assets will not have proper filenames for most files."));
}
/* Now load the 64bit map for MP3 */
if (ASSET_NAME_MP64_DECOMPRESSED_SZ != 0u) {
auto* decompressed = new uint8_t[ASSET_NAME_MP64_DECOMPRESSED_SZ];
athena::io::Compression::decompressZlib(ASSET_NAME_MP64, ASSET_NAME_MP64_SZ, decompressed,
ASSET_NAME_MP64_DECOMPRESSED_SZ);
athena::io::MemoryReader ar(decompressed, ASSET_NAME_MP64_DECOMPRESSED_SZ);
LoadAssetMap(ar);
delete[](decompressed);
} else {
Log.report(
logvisor::Warning,
FMT_STRING("AssetNameMap64 unavailable; Assets will not have proper filenames for most files."));
}
g_AssetNameMapInit = true;
}
const std::string* TranslateIdToName(const UniqueID32& id) {
if (g_AssetNameMap.find(id.toUint64()) == g_AssetNameMap.cend())
return nullptr;
return &g_AssetNameMap[id.toUint64()].name;
}
} // namespace DataSpec::AssetNameMap

View File

@ -1,11 +0,0 @@
#pragma once
#include <unordered_map>
#include <string>
#include "DNACommon/DNACommon.hpp"
namespace DataSpec::AssetNameMap {
void InitAssetNameMap();
const std::string* TranslateIdToName(const UniqueID32&);
const std::string* TranslateIdToName(const UniqueID64&);
} // namespace DataSpec::AssetNameMap

View File

@ -1,9 +0,0 @@
#include <cstddef>
#include <cstdint>
extern "C" const uint8_t ASSET_NAME_MP32[] = {0};
extern "C" const size_t ASSET_NAME_MP32_SZ = 0;
extern "C" const size_t ASSET_NAME_MP32_DECOMPRESSED_SZ = 0;
extern "C" const uint8_t ASSET_NAME_MP64[] = {0};
extern "C" const size_t ASSET_NAME_MP64_SZ = 0;
extern "C" const size_t ASSET_NAME_MP64_DECOMPRESSED_SZ = 0;

View File

@ -1,22 +0,0 @@
#include <cstdint>
#include "hecl/Blender/Connection.hpp"
#include "BlenderSupport.hpp"
extern "C" uint8_t RETRO_MASTER_SHADER[];
extern "C" size_t RETRO_MASTER_SHADER_SZ;
namespace DataSpec::Blender {
bool BuildMasterShader(const hecl::ProjectPath& path) {
hecl::blender::Connection& conn = hecl::blender::Connection::SharedConnection();
if (!conn.createBlend(path, hecl::blender::BlendType::None))
return false;
{
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << std::string_view((char*)RETRO_MASTER_SHADER, RETRO_MASTER_SHADER_SZ);
os << "make_master_shader_library()\n"sv;
}
return conn.saveBlend();
}
} // namespace DataSpec::Blender

View File

@ -1,9 +0,0 @@
#pragma once
#include <hecl/hecl.hpp>
namespace DataSpec::Blender {
bool BuildMasterShader(const hecl::ProjectPath& path);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +0,0 @@
# Assembles a source/header pair list for use in a DNA library
macro(make_dnalist)
file(RELATIVE_PATH subdir "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_LIST_DIR}")
set(CMAKE_CURRENT_LIST_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${subdir}")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_LIST_BINARY_DIR}")
foreach (type ${ARGN})
get_filename_component(dir ${type} DIRECTORY)
if (dir)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_LIST_BINARY_DIR}/${dir}")
set(dir "${dir}/")
endif ()
get_filename_component(name ${type} NAME)
list(APPEND DNA_SOURCES "${subdir}/${dir}atdna_${name}.cpp")
list(APPEND DNA_HEADERS "${subdir}/${dir}${name}.hpp")
endforeach ()
endmacro()
# Assembles source files together for the main DataSpecCommon library
macro(dataspec_add_list rel_path a_list)
unset(tmp_list)
foreach (path IN LISTS ${a_list})
if (IS_ABSOLUTE ${path})
list(APPEND tmp_list "${path}")
else ()
list(APPEND tmp_list "${rel_path}/${path}")
endif ()
endforeach (path)
set(${a_list} "${tmp_list}")
endmacro(dataspec_add_list)
# Each game's DNA library
unset(DNA_SOURCES)
unset(DNA_HEADERS)
include(DNACommon/CMakeLists.txt)
include(DNAMP1/CMakeLists.txt)
include(DNAMP2/CMakeLists.txt)
include(DNAMP3/CMakeLists.txt)
# Embed master shader script
bintoc(RetroMasterShader.cpp Blender/RetroMasterShader.py RETRO_MASTER_SHADER)
# Download asset name databases
add_custom_command(OUTPUT AssetNameMap32.bin COMMAND ${CMAKE_COMMAND} ARGS -P
${CMAKE_CURRENT_SOURCE_DIR}/AssetMap32Download.cmake)
bintoc_compress(AssetNameMap32.cpp ${CMAKE_CURRENT_BINARY_DIR}/AssetNameMap32.bin ASSET_NAME_MP32)
add_custom_command(OUTPUT AssetNameMap64.bin COMMAND ${CMAKE_COMMAND} ARGS -P
${CMAKE_CURRENT_SOURCE_DIR}/AssetMap64Download.cmake)
bintoc_compress(AssetNameMap64.cpp ${CMAKE_CURRENT_BINARY_DIR}/AssetNameMap64.bin ASSET_NAME_MP64)
# Each game's DataSpec implementation
add_library(RetroDataSpec
SpecBase.cpp
${DNACOMMON_SOURCES}
SpecMP1.cpp
${DNAMP1_SOURCES}
${ScriptObjectsMP1_SOURCES}
${DNAMP1_SFX_SOURCES}
SpecMP2.cpp
${DNAMP2_SOURCES}
SpecMP3.cpp
${DNAMP3_SOURCES}
Blender/BlenderSupport.hpp
Blender/BlenderSupport.cpp
Blender/RetroMasterShader.py
AssetNameMap.hpp
AssetNameMap.cpp
RetroMasterShader.cpp)
add_library(AssetNameMap
AssetNameMap32.bin AssetNameMap32.cpp
AssetNameMap64.bin AssetNameMap64.cpp)
add_library(AssetNameMapNull
AssetNameMapNull.cpp)
get_target_property(HECL_INCLUDES hecl-full INCLUDE_DIRECTORIES)
target_include_directories(RetroDataSpec PUBLIC ${HECL_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR})
target_link_libraries(RetroDataSpec PUBLIC amuse zeus nod squish ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} lzokay logvisor)
if (COMMAND add_sanitizers)
add_sanitizers(RetroDataSpec)
endif ()
# Resolve all DNA sources into target
list(LENGTH DNA_SOURCES count)
math(EXPR count "${count}-1")
foreach (i RANGE ${count})
list(GET DNA_SOURCES ${i} src)
list(GET DNA_HEADERS ${i} header)
target_atdna(RetroDataSpec ${src} ${header})
endforeach ()
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:RetroDataSpec,INCLUDE_DIRECTORIES>")

View File

@ -1,282 +0,0 @@
#include "DataSpec/DNACommon/ANCS.hpp"
#include "DataSpec/DNACommon/CMDL.hpp"
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/RigInverter.hpp"
#include "DataSpec/DNAMP1/DNAMP1.hpp"
#include "DataSpec/DNAMP1/ANCS.hpp"
#include "DataSpec/DNAMP2/DNAMP2.hpp"
#include "DataSpec/DNAMP2/ANCS.hpp"
#include "DataSpec/DNAMP3/DNAMP3.hpp"
#include "DataSpec/DNAMP3/CHAR.hpp"
#include <hecl/Blender/Connection.hpp>
namespace DataSpec::DNAANCS {
template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion>
bool ReadANCSToBlender(hecl::blender::Token& btok, const ANCSDNA& ancs, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec,
std::function<void(const char*)> fileChanged, bool force) {
auto& conn = btok.getBlenderConnection();
/* Extract character CMDL/CSKR/CINF first */
std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo;
ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo) {
const nod::Node* node;
if (const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl, &node, true, false)) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone()) {
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
return false;
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
fileChanged(bestName.c_str());
typename ANCSDNA::CSKRType cskr;
pakRouter.lookupAndReadDNA(info.cskr, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(info.cinf, cinf);
using RigPair = std::pair<std::pair<typename PAKRouter::IDType, typename ANCSDNA::CSKRType*>,
std::pair<typename PAKRouter::IDType, typename ANCSDNA::CINFType*>>;
RigPair rigPair({info.cskr, &cskr}, {info.cinf, &cinf});
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RigPair, SurfaceHeader, CMDLVersion>(
conn, rs, pakRouter, *cmdlE, dataspec, rigPair);
conn.saveBlend();
}
}
if (const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(info.cinf, &node, true, false)) {
hecl::ProjectPath cinfPath = pakRouter.getWorking(cinfE);
if (cinfPath.getPathType() == hecl::ProjectPath::Type::None) {
PAKEntryReadStream rs = cinfE->beginReadStream(*node);
ANCSDNA::CINFType::Extract(dataspec, rs, cinfPath, pakRouter, *cinfE, false, btok, fileChanged);
}
}
}
/* Extract attachment CMDL/CSKR/CINFs first */
auto attRange = pakRouter.lookupCharacterAttachmentRigs(entry.id);
for (auto it = attRange.first; it != attRange.second; ++it) {
auto cinfid = it->second.first.cinf;
auto cmdlid = it->second.first.cmdl;
const nod::Node* node;
if (const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(cmdlid, &node, true, false)) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone()) {
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh)) {
return false;
}
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
fileChanged(bestName.c_str());
const auto* rp = pakRouter.lookupCMDLRigPair(cmdlid);
typename ANCSDNA::CSKRType cskr;
pakRouter.lookupAndReadDNA(rp->cskr, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(rp->cinf, cinf);
using RigPair = std::pair<std::pair<typename PAKRouter::IDType, typename ANCSDNA::CSKRType*>,
std::pair<typename PAKRouter::IDType, typename ANCSDNA::CINFType*>>;
RigPair rigPair({rp->cskr, &cskr}, {rp->cinf, &cinf});
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RigPair, SurfaceHeader, CMDLVersion>(
conn, rs, pakRouter, *cmdlE, dataspec, rigPair);
conn.saveBlend();
}
}
if (cinfid.isValid()) {
if (const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(cinfid, &node, true, false)) {
hecl::ProjectPath cinfPath = pakRouter.getWorking(cinfE);
if (cinfPath.getPathType() == hecl::ProjectPath::Type::None) {
PAKEntryReadStream rs = cinfE->beginReadStream(*node);
ANCSDNA::CINFType::Extract(dataspec, rs, cinfPath, pakRouter, *cinfE, false, btok, fileChanged);
}
}
}
}
std::string bestName = pakRouter.getBestEntryName(entry);
fileChanged(bestName.c_str());
/* Establish ANCS blend */
if (!conn.createBlend(outPath, hecl::blender::BlendType::Actor))
return false;
std::string firstName;
typename ANCSDNA::CINFType firstCinf;
{
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os.format(FMT_STRING("import bpy\n"
"from mathutils import Vector\n"
"bpy.context.scene.name = '{}'\n"
"bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n"
"\n"
"# Clear Scene\n"
"if len(bpy.data.collections):\n"
" bpy.data.collections.remove(bpy.data.collections[0])\n"
"\n"
"actor_data = bpy.context.scene.hecl_sact_data\n"
"arm_obj = None\n"),
pakRouter.getBestEntryName(entry));
std::unordered_set<typename PAKRouter::IDType> cinfsDone;
for (const auto& info : chResInfo) {
/* Provide data to add-on */
os.format(FMT_STRING("actor_subtype = actor_data.subtypes.add()\n"
"actor_subtype.name = '{}'\n\n"),
info.name);
/* Build CINF if needed */
if (cinfsDone.find(info.cinf) == cinfsDone.end()) {
if (const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(info.cinf, nullptr, true, false)) {
hecl::ProjectPath cinfPath = pakRouter.getWorking(cinfE);
os.linkArmature(cinfPath.getAbsolutePath(), fmt::format(FMT_STRING("CINF_{}"), info.cinf));
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.collection.objects.link(obj)\n";
}
if (cinfsDone.empty()) {
firstName = ANCSDNA::CINFType::GetCINFArmatureName(info.cinf);
pakRouter.lookupAndReadDNA(info.cinf, firstCinf);
}
cinfsDone.insert(info.cinf);
}
os.format(FMT_STRING("arm_obj = bpy.data.objects['CINF_{}']\n"), info.cinf);
os << "actor_subtype.linked_armature = arm_obj.name\n";
/* Link CMDL */
if (const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl, nullptr, true, false)) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkMesh(cmdlPath.getAbsolutePath(), pakRouter.getBestEntryName(*cmdlE));
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.collection.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"actor_subtype.linked_mesh = obj.name\n\n";
}
/* Link overlays */
for (const auto& overlay : info.overlays) {
os << "overlay = actor_subtype.overlays.add()\n";
os.format(FMT_STRING("overlay.name = '{}'\n"), overlay.first);
/* Link CMDL */
if (const typename PAKRouter::EntryType* cmdlE =
pakRouter.lookupEntry(overlay.second.first, nullptr, true, false)) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkMesh(cmdlPath.getAbsolutePath(), pakRouter.getBestEntryName(*cmdlE));
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.collection.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"overlay.linked_mesh = obj.name\n\n";
}
}
}
/* Link attachments */
for (auto it = attRange.first; it != attRange.second; ++it) {
os << "attachment = actor_data.attachments.add()\n";
os.format(FMT_STRING("attachment.name = '{}'\n"), it->second.second);
auto cinfid = it->second.first.cinf;
auto cmdlid = it->second.first.cmdl;
if (cinfid.isValid()) {
/* Build CINF if needed */
if (cinfsDone.find(cinfid) == cinfsDone.end()) {
if (const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(cinfid, nullptr, true, false)) {
hecl::ProjectPath cinfPath = pakRouter.getWorking(cinfE);
os.linkArmature(cinfPath.getAbsolutePath(), fmt::format(FMT_STRING("CINF_{}"), cinfid));
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.collection.objects.link(obj)\n";
}
if (cinfsDone.empty()) {
firstName = ANCSDNA::CINFType::GetCINFArmatureName(cinfid);
pakRouter.lookupAndReadDNA(cinfid, firstCinf);
}
cinfsDone.insert(cinfid);
}
os.format(FMT_STRING("arm_obj = bpy.data.objects['CINF_{}']\n"), cinfid);
os << "attachment.linked_armature = arm_obj.name\n";
}
/* Link CMDL */
if (const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(cmdlid, nullptr, true, false)) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkMesh(cmdlPath.getAbsolutePath(), pakRouter.getBestEntryName(*cmdlE));
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.collection.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"attachment.linked_mesh = obj.name\n\n";
}
}
}
{
hecl::blender::DataStream ds = conn.beginData();
std::unordered_map<std::string, hecl::blender::Matrix3f> matrices = ds.getBoneMatrices(firstName);
ds.close();
DNAANIM::RigInverter<typename ANCSDNA::CINFType> inverter(firstCinf, matrices);
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy\n"
"actor_data = bpy.context.scene.hecl_sact_data\n";
/* Get animation primitives */
std::map<atUint32, AnimationResInfo<typename PAKRouter::IDType>> animResInfo;
ancs.getAnimationResInfo(&pakRouter, animResInfo);
for (const auto& id : animResInfo) {
typename ANCSDNA::ANIMType anim;
if (pakRouter.lookupAndReadDNA(id.second.animId, anim, true)) {
os.format(FMT_STRING("act = bpy.data.actions.new('{}')\n"
"act.use_fake_user = True\n"
"act.anim_id = '{}'\n"),
id.second.name, id.second.animId);
anim.sendANIMToBlender(os, inverter, id.second.additive);
}
os.format(FMT_STRING("actor_action = actor_data.actions.add()\n"
"actor_action.name = '{}'\n"),
id.second.name);
/* Extract EVNT if present */
anim.extractEVNT(id.second, outPath, pakRouter, force);
}
}
conn.saveBlend();
return true;
}
template bool
ReadANCSToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::ANCS, DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, 2>(
hecl::blender::Token& btok, const DNAMP1::ANCS& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const char*)> fileChanged, bool force);
template bool
ReadANCSToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::ANCS, DNAMP2::MaterialSet, DNACMDL::SurfaceHeader_2, 4>(
hecl::blender::Token& btok, const DNAMP2::ANCS& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const char*)> fileChanged, bool force);
template bool
ReadANCSToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::CHAR, DNAMP3::MaterialSet, DNACMDL::SurfaceHeader_3, 4>(
hecl::blender::Token& btok, const DNAMP3::CHAR& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const char*)> fileChanged, bool force);
} // namespace DataSpec::DNAANCS

View File

@ -1,47 +0,0 @@
#pragma once
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "athena/Types.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec {
struct SpecBase;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAANCS {
using Actor = hecl::blender::Actor;
using Armature = Actor::ActorArmature;
using Action = hecl::blender::Action;
template <typename IDTYPE>
struct CharacterResInfo {
std::string name;
IDTYPE cmdl;
IDTYPE cskr;
IDTYPE cinf;
std::vector<std::pair<std::string, std::pair<IDTYPE, IDTYPE>>> overlays;
};
template <typename IDTYPE>
struct AnimationResInfo {
std::string name;
IDTYPE animId;
IDTYPE evntId;
bool additive;
};
template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion>
bool ReadANCSToBlender(hecl::blender::Token& btok, const ANCSDNA& ancs, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec,
std::function<void(const char*)> fileChanged, bool force = false);
} // namespace DataSpec::DNAANCS

View File

@ -1,462 +0,0 @@
#include "DataSpec/DNACommon/ANIM.hpp"
#include <cfloat>
#include <cmath>
#include <cstring>
#include <hecl/hecl.hpp>
#include <zeus/Global.hpp>
#include <zeus/Math.hpp>
#define DUMP_KEYS 0
#if DUMP_KEYS
#include <cstdio>
#include <fmt/format.h>
#endif
namespace DataSpec::DNAANIM {
size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& channels) {
size_t bitsPerKeyFrame = 0;
for (const Channel& chan : channels) {
switch (chan.type) {
case Channel::Type::Rotation:
bitsPerKeyFrame += 1;
[[fallthrough]];
case Channel::Type::Translation:
case Channel::Type::Scale:
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
break;
case Channel::Type::KfHead:
bitsPerKeyFrame += 1;
break;
case Channel::Type::RotationMP3:
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
bitsPerKeyFrame += chan.q[3];
break;
default:
break;
}
}
return (bitsPerKeyFrame * keyFrameCount + 31) / 32 * 4;
}
static QuantizedRot QuantizeRotation(const Value& quat, atUint32 div) {
float q = float(div) / (M_PIF / 2.0f);
zeus::simd_floats f(quat.simd);
assert(std::abs(f[1]) <= 1.f && "Out of range quat X component");
assert(std::abs(f[2]) <= 1.f && "Out of range quat Y component");
assert(std::abs(f[3]) <= 1.f && "Out of range quat Z component");
return {{
atInt32(std::asin(f[1]) * q),
atInt32(std::asin(f[2]) * q),
atInt32(std::asin(f[3]) * q),
},
(f[0] < 0.f)};
}
static Value DequantizeRotation(const QuantizedRot& v, atUint32 div) {
float q = (M_PIF / 2.0f) / float(div);
athena::simd_floats f = {
0.0f,
std::sin(v.v[0] * q),
std::sin(v.v[1] * q),
std::sin(v.v[2] * q),
};
f[0] = std::sqrt(std::max((1.0f - (f[1] * f[1] + f[2] * f[2] + f[3] * f[3])), 0.0f));
f[0] = v.w ? -f[0] : f[0];
Value retval;
retval.simd.copy_from(f);
return retval;
}
static Value DequantizeRotation_3(const QuantizedRot& v, atUint32 div) {
float q = 1.0f / float(div);
athena::simd_floats f = {
0.0f,
v.v[0] * q,
v.v[1] * q,
v.v[2] * q,
};
f[0] = std::sqrt(std::max((1.0f - (f[1] * f[1] + f[2] * f[2] + f[3] * f[3])), 0.0f));
f[0] = v.w ? -f[0] : f[0];
Value retval;
retval.simd.copy_from(f);
return retval;
}
bool BitstreamReader::dequantizeBit(const atUint8* data) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
/* That's it */
m_bitCur += 1;
return tempBuf & 0x1;
}
atInt32 BitstreamReader::dequantize(const atUint8* data, atUint8 q) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32) {
atUint32 tempBuf2 = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur + 4));
tempBuf |= (tempBuf2 << (32 - bitRem));
}
/* Mask it */
atUint32 mask = (1 << q) - 1;
tempBuf &= mask;
/* Sign extend */
atUint32 sign = (tempBuf >> (q - 1)) & 0x1;
if (sign)
tempBuf |= ~0u << q;
/* Return delta value */
m_bitCur += q;
return atInt32(tempBuf);
}
std::vector<std::vector<Value>> BitstreamReader::read(const atUint8* data, size_t keyFrameCount,
const std::vector<Channel>& channels, atUint32 rotDiv,
float transMult, float scaleMult) {
m_bitCur = 0;
std::vector<std::vector<Value>> chanKeys;
std::vector<QuantizedValue> chanAccum;
chanKeys.reserve(channels.size());
chanAccum.reserve(channels.size());
for (const Channel& chan : channels) {
chanAccum.push_back(chan.i);
chanKeys.emplace_back();
std::vector<Value>& keys = chanKeys.back();
keys.reserve(keyFrameCount);
switch (chan.type) {
case Channel::Type::Rotation: {
QuantizedRot qr = {{chan.i[0], chan.i[1], chan.i[2]}, false};
keys.emplace_back(DequantizeRotation(qr, rotDiv));
break;
}
case Channel::Type::Translation: {
keys.push_back({chan.i[0] * transMult, chan.i[1] * transMult, chan.i[2] * transMult});
break;
}
case Channel::Type::Scale: {
keys.push_back({chan.i[0] * scaleMult, chan.i[1] * scaleMult, chan.i[2] * scaleMult});
break;
}
case Channel::Type::KfHead: {
break;
}
case Channel::Type::RotationMP3: {
QuantizedRot qr = {{chan.i[1], chan.i[2], chan.i[3]}, bool(chan.i[0] & 0x1)};
keys.emplace_back(DequantizeRotation_3(qr, rotDiv));
break;
}
default:
break;
}
}
for (size_t f = 0; f < keyFrameCount; ++f) {
#if DUMP_KEYS
fmt::print(stderr, FMT_STRING("\nFRAME {} {} {}\n"), f, (m_bitCur / 32) * 4, m_bitCur % 32);
int lastId = -1;
#endif
auto kit = chanKeys.begin();
auto ait = chanAccum.begin();
for (const Channel& chan : channels) {
#if DUMP_KEYS
if (chan.id != lastId) {
lastId = chan.id;
std::fputc('\n', stderr);
}
#endif
QuantizedValue& p = *ait;
switch (chan.type) {
case Channel::Type::Rotation: {
bool wBit = dequantizeBit(data);
p[0] += dequantize(data, chan.q[0]);
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
QuantizedRot qr = {{p[0], p[1], p[2]}, wBit};
kit->emplace_back(DequantizeRotation(qr, rotDiv));
#if DUMP_KEYS
fmt::print(stderr, FMT_STRING("{} R: {} {} {} {}\t"), chan.id, wBit, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::Translation: {
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
atInt32 val3 = dequantize(data, chan.q[2]);
p[2] += val3;
kit->push_back({p[0] * transMult, p[1] * transMult, p[2] * transMult});
#if DUMP_KEYS
fmt::print(stderr, FMT_STRING("{} T: {} {} {}\t"), chan.id, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::Scale: {
p[0] += dequantize(data, chan.q[0]);
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
kit->push_back({p[0] * scaleMult, p[1] * scaleMult, p[2] * scaleMult});
#if DUMP_KEYS
fmt::print(stderr, FMT_STRING("{} S: {} {} {}\t"), chan.id, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::KfHead: {
dequantizeBit(data);
break;
}
case Channel::Type::RotationMP3: {
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
atInt32 val3 = dequantize(data, chan.q[2]);
p[2] += val3;
atInt32 val4 = dequantize(data, chan.q[3]);
p[3] += val4;
QuantizedRot qr = {{p[1], p[2], p[3]}, bool(p[0] & 0x1)};
kit->emplace_back(DequantizeRotation_3(qr, rotDiv));
break;
}
default:
break;
}
++kit;
++ait;
}
#if DUMP_KEYS
std::fputc('\n', stderr);
#endif
}
return chanKeys;
}
void BitstreamWriter::quantizeBit(atUint8* data, bool val) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) = hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (val << bitRem));
m_bitCur += 1;
}
void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt32 val) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
atUint32 masked = val & ((1 << q) - 1);
assert(((((val >> 31) & 0x1) == 0x1) || (((masked >> (q - 1)) & 0x1) == 0)) && "Twos compliment fail");
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) = hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (masked << bitRem));
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32) {
*(atUint32*)(data + byteCur + 4) =
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur + 4)) | (masked >> (32 - bitRem)));
}
m_bitCur += q;
}
std::unique_ptr<atUint8[]> BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys, size_t keyFrameCount,
std::vector<Channel>& channels, atUint32 quantRange,
atUint32& rotDivOut, float& transMultOut, float& scaleMultOut,
size_t& sizeOut) {
m_bitCur = 0;
rotDivOut = quantRange; /* Normalized range of values */
float quantRangeF = float(quantRange);
/* Pre-pass to calculate translation multiplier */
float maxTransDelta = 0.0f;
float maxScaleDelta = 0.0f;
auto kit = chanKeys.begin();
for (Channel& chan : channels) {
switch (chan.type) {
case Channel::Type::Translation: {
zeus::simd<float> lastVal = {};
for (auto it = kit->begin(); it != kit->end(); ++it) {
const Value* key = &*it;
zeus::simd_floats f(key->simd - lastVal);
lastVal = key->simd;
maxTransDelta = std::max(maxTransDelta, std::fabs(f[0]));
maxTransDelta = std::max(maxTransDelta, std::fabs(f[1]));
maxTransDelta = std::max(maxTransDelta, std::fabs(f[2]));
}
break;
}
case Channel::Type::Scale: {
zeus::simd<float> lastVal = {};
for (auto it = kit->begin(); it != kit->end(); ++it) {
const Value* key = &*it;
zeus::simd_floats f(key->simd - lastVal);
lastVal = key->simd;
maxScaleDelta = std::max(maxScaleDelta, std::fabs(f[0]));
maxScaleDelta = std::max(maxScaleDelta, std::fabs(f[1]));
maxScaleDelta = std::max(maxScaleDelta, std::fabs(f[2]));
}
break;
}
default:
break;
}
++kit;
}
transMultOut = maxTransDelta / quantRangeF + FLT_EPSILON;
scaleMultOut = maxScaleDelta / quantRangeF + FLT_EPSILON;
/* Output channel inits */
std::vector<QuantizedValue> initVals;
initVals.reserve(channels.size());
kit = chanKeys.begin();
for (Channel& chan : channels) {
chan.q[0] = 1;
chan.q[1] = 1;
chan.q[2] = 1;
switch (chan.type) {
case Channel::Type::Rotation: {
QuantizedRot qr = QuantizeRotation((*kit)[0], rotDivOut);
chan.i = qr.v;
initVals.push_back(chan.i);
break;
}
case Channel::Type::Translation: {
zeus::simd_floats f((*kit)[0].simd);
chan.i = {atInt32(f[0] / transMultOut), atInt32(f[1] / transMultOut), atInt32(f[2] / transMultOut)};
initVals.push_back(chan.i);
break;
}
case Channel::Type::Scale: {
zeus::simd_floats f((*kit)[0].simd);
chan.i = {atInt32(f[0] / scaleMultOut), atInt32(f[1] / scaleMultOut), atInt32(f[2] / scaleMultOut)};
initVals.push_back(chan.i);
break;
}
default:
break;
}
++kit;
}
/* Pre-pass to analyze quantization factors for channels */
std::vector<QuantizedValue> lastVals = initVals;
kit = chanKeys.begin();
auto vit = lastVals.begin();
for (Channel& chan : channels) {
QuantizedValue& last = *vit++;
switch (chan.type) {
case Channel::Type::Rotation: {
for (auto it = kit->begin() + 1; it != kit->end(); ++it) {
QuantizedRot qrCur = QuantizeRotation(*it, rotDivOut);
chan.q[0] = std::max(chan.q[0], atUint8(qrCur.v.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(qrCur.v.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(qrCur.v.qFrom(last, 2)));
last = qrCur.v;
}
break;
}
case Channel::Type::Translation: {
for (auto it = kit->begin() + 1; it != kit->end(); ++it) {
zeus::simd_floats f(it->simd);
QuantizedValue cur = {atInt32(f[0] / transMultOut), atInt32(f[1] / transMultOut), atInt32(f[2] / transMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(cur.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(cur.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(cur.qFrom(last, 2)));
last = cur;
}
break;
}
case Channel::Type::Scale: {
for (auto it = kit->begin() + 1; it != kit->end(); ++it) {
zeus::simd_floats f(it->simd);
QuantizedValue cur = {atInt32(f[0] / scaleMultOut), atInt32(f[1] / scaleMultOut), atInt32(f[2] / scaleMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(cur.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(cur.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(cur.qFrom(last, 2)));
last = cur;
}
break;
}
default:
break;
}
++kit;
}
/* Generate Bitstream */
sizeOut = ComputeBitstreamSize(keyFrameCount, channels);
std::unique_ptr<atUint8[]> newData(new atUint8[sizeOut]);
memset(newData.get(), 0, sizeOut);
lastVals = initVals;
for (size_t frame = 0; frame < keyFrameCount; ++frame) {
kit = chanKeys.begin();
vit = lastVals.begin();
for (const Channel& chan : channels) {
const Value& val = (*kit++)[frame + 1];
QuantizedValue& last = *vit++;
switch (chan.type) {
case Channel::Type::Rotation: {
QuantizedRot qrCur = QuantizeRotation(val, rotDivOut);
quantizeBit(newData.get(), qrCur.w);
quantize(newData.get(), chan.q[0], qrCur.v[0] - last.v[0]);
quantize(newData.get(), chan.q[1], qrCur.v[1] - last.v[1]);
quantize(newData.get(), chan.q[2], qrCur.v[2] - last.v[2]);
last = qrCur.v;
break;
}
case Channel::Type::Translation: {
zeus::simd_floats f(val.simd);
QuantizedValue cur = {atInt32(f[0] / transMultOut), atInt32(f[1] / transMultOut), atInt32(f[2] / transMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
break;
}
case Channel::Type::Scale: {
zeus::simd_floats f(val.simd);
QuantizedValue cur = {atInt32(f[0] / scaleMultOut), atInt32(f[1] / scaleMultOut), atInt32(f[2] / scaleMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
break;
}
default:
break;
}
}
}
return newData;
}
} // namespace DataSpec::DNAANIM

View File

@ -1,73 +0,0 @@
#pragma once
#include <cassert>
#include <cmath>
#include <cstddef>
#include <memory>
#include <vector>
#include <athena/Types.hpp>
namespace DataSpec::DNAANIM {
struct Value {
athena::simd<float> simd;
Value() = default;
Value(const athena::simd<float>& s) : simd(s) {}
Value(const atVec3f& v) : simd(v.simd) {}
Value(const atVec4f& v) : simd(v.simd) {}
Value(float x, float y, float z) : simd(x, y, z, 0.f) {}
Value(float w, float x, float y, float z) : simd(w, x, y, z) {}
};
struct QuantizedValue {
atInt32 v[4];
atInt32& operator[](size_t idx) { return v[idx]; }
atInt32 operator[](size_t idx) const { return v[idx]; }
int qFrom(const QuantizedValue& other, size_t idx) const {
atInt32 delta = v[idx] - other.v[idx];
atInt32 absDelta = std::abs(delta);
if (absDelta == 0)
return 1;
int ret = int(std::ceil(std::log2(absDelta))) + 1;
if (delta > 0 && (delta >> (ret - 1)))
++ret;
assert(ret <= 24 && "Bad q value");
return ret;
}
};
struct QuantizedRot {
QuantizedValue v;
bool w;
};
struct Channel {
enum class Type { Rotation, Translation, Scale, KfHead, RotationMP3 } type;
atInt32 id = -1;
QuantizedValue i = {};
atUint8 q[4] = {};
};
size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& channels);
class BitstreamReader {
size_t m_bitCur;
atInt32 dequantize(const atUint8* data, atUint8 q);
bool dequantizeBit(const atUint8* data);
public:
std::vector<std::vector<Value>> read(const atUint8* data, size_t keyFrameCount, const std::vector<Channel>& channels,
atUint32 rotDiv, float transMult, float scaleMult);
};
class BitstreamWriter {
size_t m_bitCur;
void quantize(atUint8* data, atUint8 q, atInt32 val);
void quantizeBit(atUint8* data, bool val);
public:
std::unique_ptr<atUint8[]> write(const std::vector<std::vector<Value>>& chanKeys, size_t keyFrameCount,
std::vector<Channel>& channels, atUint32 quantRange, atUint32& rotDivOut,
float& transMultOut, float& scaleMultOut, size_t& sizeOut);
};
} // namespace DataSpec::DNAANIM

View File

@ -1,440 +0,0 @@
#include "AROTBuilder.hpp"
#include <algorithm>
#include <array>
#include "hecl/Blender/Connection.hpp"
#include "PATH.hpp"
namespace DataSpec {
logvisor::Module Log("AROTBuilder");
constexpr s32 AROT_MAX_LEVEL = 10;
constexpr s32 AROT_MIN_MODELS = 8;
constexpr s32 COLLISION_MIN_NODE_TRIANGLES = 8;
constexpr s32 PATH_MIN_NODE_REGIONS = 16;
constexpr float AROT_MIN_SUBDIV = 8.f;
static zeus::CAABox SplitAABB(const zeus::CAABox& aabb, int i) {
zeus::CAABox pos, neg;
aabb.splitZ(neg, pos);
if (i & 4) {
zeus::CAABox(pos).splitY(neg, pos);
if (i & 2) {
zeus::CAABox(pos).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
} else {
zeus::CAABox(neg).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
} else {
zeus::CAABox(neg).splitY(neg, pos);
if (i & 2) {
zeus::CAABox(pos).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
} else {
zeus::CAABox(neg).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
}
}
void AROTBuilder::Node::mergeSets(int a, int b) {
childNodes[a].childIndices.insert(childNodes[b].childIndices.cbegin(), childNodes[b].childIndices.cend());
childNodes[b].childIndices = childNodes[a].childIndices;
}
bool AROTBuilder::Node::compareSets(int a, int b) const {
return childNodes[a].childIndices != childNodes[b].childIndices;
}
void AROTBuilder::Node::addChild(int level, int minChildren, const std::vector<zeus::CAABox>& triBoxes,
const zeus::CAABox& curAABB, BspNodeType& typeOut) {
/* Gather intersecting faces */
for (size_t i = 0; i < triBoxes.size(); ++i)
if (triBoxes[i].intersects(curAABB))
childIndices.insert(i);
zeus::CVector3f extents = curAABB.extents();
/* Return early if empty, triangle intersection below performance threshold, or at max level */
if (childIndices.empty()) {
typeOut = BspNodeType::Invalid;
return;
} else if (childIndices.size() < minChildren || level == AROT_MAX_LEVEL ||
std::max(extents.x(), std::max(extents.y(), extents.z())) < AROT_MIN_SUBDIV) {
typeOut = BspNodeType::Leaf;
return;
}
/* Subdivide */
typeOut = BspNodeType::Branch;
childNodes.resize(8);
for (int i = 0; i < 8; ++i) {
BspNodeType chType;
childNodes[i].addChild(level + 1, minChildren, triBoxes, SplitAABB(curAABB, i), chType);
flags |= int(chType) << (i * 2);
}
/* Unsubdivide minimum axis dimensions */
if (extents.x() < AROT_MIN_SUBDIV) {
mergeSets(0, 1);
mergeSets(4, 5);
mergeSets(2, 3);
mergeSets(6, 7);
}
if (extents.y() < AROT_MIN_SUBDIV) {
mergeSets(0, 2);
mergeSets(1, 3);
mergeSets(4, 6);
mergeSets(5, 7);
}
if (extents.z() < AROT_MIN_SUBDIV) {
mergeSets(0, 4);
mergeSets(1, 5);
mergeSets(2, 6);
mergeSets(3, 7);
}
/* Unsubdivide */
compSubdivs = 0;
if (compareSets(0, 1) || compareSets(4, 5) || compareSets(2, 3) || compareSets(6, 7))
compSubdivs |= 0x1;
if (compareSets(0, 2) || compareSets(1, 3) || compareSets(4, 6) || compareSets(5, 7))
compSubdivs |= 0x2;
if (compareSets(0, 4) || compareSets(1, 5) || compareSets(2, 6) || compareSets(3, 7))
compSubdivs |= 0x4;
if (!compSubdivs) {
typeOut = BspNodeType::Leaf;
childNodes = std::vector<Node>();
flags = 0;
}
}
size_t AROTBuilder::BitmapPool::addIndices(const std::set<int>& indices) {
for (size_t i = 0; i < m_pool.size(); ++i)
if (m_pool[i] == indices)
return i;
m_pool.push_back(indices);
return m_pool.size() - 1;
}
constexpr std::array<uint32_t, 8> AROTChildCounts{
0, 2, 2, 4, 2, 4, 4, 8,
};
void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff) {
sz += 1;
poolIdx = bmpPool.addIndices(childIndices);
if (poolIdx > 65535)
Log.report(logvisor::Fatal, FMT_STRING("AROT bitmap exceeds 16-bit node addressing; area too complex"));
uint32_t childCount = AROTChildCounts[compSubdivs];
nodeOff = curOff;
nodeSz = childCount * 2 + 4;
curOff += nodeSz;
if (childNodes.size()) {
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].nodeCount(sz, idxRefs, bmpPool, curOff);
}
}
}
idxRefs += childCount;
}
}
void AROTBuilder::Node::writeIndirectionTable(athena::io::MemoryWriter& w) {
w.writeUint32Big(nodeOff);
if (childNodes.size()) {
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].writeIndirectionTable(w);
}
}
}
}
}
void AROTBuilder::Node::writeNodes(athena::io::MemoryWriter& w, int nodeIdx) {
w.writeUint16Big(poolIdx);
w.writeUint16Big(compSubdivs);
if (childNodes.size()) {
int curIdx = nodeIdx + 1;
if (curIdx > 65535)
Log.report(logvisor::Fatal, FMT_STRING("AROT node exceeds 16-bit node addressing; area too complex"));
std::array<int, 8> childIndices;
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
w.writeUint16Big(curIdx);
childIndices[idx] = curIdx;
childNodes[idx].advanceIndex(curIdx);
}
}
}
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].writeNodes(w, childIndices[idx]);
}
}
}
}
}
void AROTBuilder::Node::advanceIndex(int& nodeIdx) {
++nodeIdx;
if (childNodes.size()) {
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].advanceIndex(nodeIdx);
}
}
}
}
}
void AROTBuilder::Node::colSize(size_t& totalSz) {
if (childIndices.size()) {
nodeOff = totalSz;
if (childNodes.empty()) {
totalSz += 26 + childIndices.size() * 2;
} else {
totalSz += 36;
for (int i = 0; i < 8; ++i)
childNodes[i].colSize(totalSz);
}
}
}
void AROTBuilder::Node::writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB) {
if (childIndices.size()) {
if (childNodes.empty()) {
float* aabbOut = reinterpret_cast<float*>(ptr);
aabbOut[0] = hecl::SBig(curAABB.min[0]);
aabbOut[1] = hecl::SBig(curAABB.min[1]);
aabbOut[2] = hecl::SBig(curAABB.min[2]);
aabbOut[3] = hecl::SBig(curAABB.max[0]);
aabbOut[4] = hecl::SBig(curAABB.max[1]);
aabbOut[5] = hecl::SBig(curAABB.max[2]);
athena::io::MemoryWriter w(ptr + 24, INT32_MAX);
w.writeUint16Big(childIndices.size());
for (int idx : childIndices)
w.writeUint16Big(idx);
ptr += 26 + childIndices.size() * 2;
} else {
uint16_t* pflags = reinterpret_cast<uint16_t*>(ptr);
uint32_t* offsets = reinterpret_cast<uint32_t*>(ptr + 4);
memset(pflags, 0, sizeof(uint32_t) * 9);
for (int i = 0; i < 8; ++i) {
const Node& chNode = childNodes[i];
BspNodeType type = BspNodeType((flags >> (i * 2)) & 0x3);
if (type != BspNodeType::Invalid)
offsets[i] = hecl::SBig(uint32_t(chNode.nodeOff - nodeOff - 36));
}
*pflags = hecl::SBig(flags);
ptr += 36;
for (int i = 0; i < 8; ++i)
childNodes[i].writeColNodes(ptr, SplitAABB(curAABB, i));
}
}
}
void AROTBuilder::Node::pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount) {
++nodeCount;
if (childNodes.empty()) {
lookupCount += childIndices.size();
} else {
for (int i = 0; i < 8; ++i)
childNodes[i].pathCountNodesAndLookups(nodeCount, lookupCount);
}
}
template <class PAKBridge>
void AROTBuilder::Node::pathWrite(DNAPATH::PATH<PAKBridge>& path, const zeus::CAABox& curAABB) {
if (childNodes.empty()) {
auto& n = path.octree.emplace_back();
n.isLeaf = 1;
n.aabb[0] = curAABB.min;
n.aabb[1] = curAABB.max;
n.centroid = curAABB.center();
std::fill(std::begin(n.children), std::end(n.children), 0xFFFFFFFF);
n.regionCount = childIndices.size();
n.regionStart = path.octreeRegionLookup.size();
for (int r : childIndices)
path.octreeRegionLookup.push_back(r);
} else {
std::array<atUint32, 8> children;
for (size_t i = 0; i < children.size(); ++i) {
/* Head recursion (first node will be a leaf) */
childNodes[i].pathWrite(path, SplitAABB(curAABB, static_cast<int>(i)));
children[i] = path.octree.size() - 1;
}
auto& n = path.octree.emplace_back();
n.isLeaf = 0;
n.aabb[0] = curAABB.min;
n.aabb[1] = curAABB.max;
n.centroid = curAABB.center();
std::copy(children.cbegin(), children.cend(), std::begin(n.children));
n.regionCount = 0;
n.regionStart = 0;
}
}
template void AROTBuilder::Node::pathWrite(DNAPATH::PATH<DNAMP1::PAKBridge>& path, const zeus::CAABox& curAABB);
template void AROTBuilder::Node::pathWrite(DNAPATH::PATH<DNAMP2::PAKBridge>& path, const zeus::CAABox& curAABB);
template void AROTBuilder::Node::pathWrite(DNAPATH::PATH<DNAMP3::PAKBridge>& path, const zeus::CAABox& curAABB);
void AROTBuilder::build(std::vector<std::vector<uint8_t>>& secs, const zeus::CAABox& fullAabb,
const std::vector<zeus::CAABox>& meshAabbs, const std::vector<DNACMDL::Mesh>& meshes) {
/* Recursively split */
BspNodeType rootType;
rootNode.addChild(0, AROT_MIN_MODELS, meshAabbs, fullAabb, rootType);
/* Calculate indexing metrics */
size_t totalNodeCount = 0;
size_t idxRefCount = 0;
size_t curOff = 0;
rootNode.nodeCount(totalNodeCount, idxRefCount, bmpPool, curOff);
size_t bmpWordCount = ROUND_UP_32(meshes.size()) / 32;
size_t arotSz = 64 + bmpWordCount * bmpPool.m_pool.size() * 4 + totalNodeCount * 8 + idxRefCount * 2;
/* Write header */
secs.emplace_back(arotSz, 0);
athena::io::MemoryWriter w(secs.back().data(), secs.back().size());
w.writeUint32Big('AROT');
w.writeUint32Big(1);
w.writeUint32Big(bmpPool.m_pool.size());
w.writeUint32Big(meshes.size());
w.writeUint32Big(totalNodeCount);
w.writeVec3fBig(fullAabb.min);
w.writeVec3fBig(fullAabb.max);
w.seekAlign32();
/* Write bitmap */
std::vector<uint32_t> bmpWords;
bmpWords.reserve(bmpWordCount);
for (const std::set<int>& bmp : bmpPool.m_pool) {
bmpWords.clear();
bmpWords.resize(bmpWordCount);
auto bmpIt = bmp.cbegin();
if (bmpIt != bmp.cend()) {
int curIdx = 0;
for (size_t word = 0; word < bmpWordCount; ++word) {
for (u32 b = 0; b < 32; ++b) {
if (*bmpIt == curIdx) {
bmpWords[word] |= 1U << b;
++bmpIt;
if (bmpIt == bmp.cend()) {
break;
}
}
++curIdx;
}
if (bmpIt == bmp.cend()) {
break;
}
}
}
for (uint32_t word : bmpWords)
w.writeUint32Big(word);
}
/* Write the rest */
rootNode.writeIndirectionTable(w);
rootNode.writeNodes(w, 0);
}
std::pair<std::unique_ptr<uint8_t[]>, uint32_t> AROTBuilder::buildCol(const ColMesh& mesh, BspNodeType& rootOut) {
/* Accumulate total AABB */
zeus::CAABox fullAABB;
for (const auto& vert : mesh.verts)
fullAABB.accumulateBounds(zeus::CVector3f(vert));
/* Predetermine triangle AABBs */
std::vector<zeus::CAABox> triBoxes;
triBoxes.reserve(mesh.trianges.size());
for (const ColMesh::Triangle& tri : mesh.trianges) {
zeus::CAABox& aabb = triBoxes.emplace_back();
for (const u32 edgeIdx : tri.edges) {
const ColMesh::Edge& edge = mesh.edges[edgeIdx];
for (const u32 vertIdx : edge.verts) {
const auto& vert = mesh.verts[vertIdx];
aabb.accumulateBounds(zeus::CVector3f(vert));
}
}
}
/* Recursively split */
rootNode.addChild(0, COLLISION_MIN_NODE_TRIANGLES, triBoxes, fullAABB, rootOut);
/* Calculate offsets and write out */
size_t totalSize = 0;
rootNode.colSize(totalSize);
std::unique_ptr<uint8_t[]> ret(new uint8_t[totalSize]);
uint8_t* ptr = ret.get();
rootNode.writeColNodes(ptr, fullAABB);
return {std::move(ret), totalSize};
}
template <class PAKBridge>
void AROTBuilder::buildPath(DNAPATH::PATH<PAKBridge>& path) {
/* Accumulate total AABB and gather region boxes */
std::vector<zeus::CAABox> regionBoxes;
regionBoxes.reserve(path.regions.size());
zeus::CAABox fullAABB;
for (const auto& r : path.regions)
fullAABB.accumulateBounds(regionBoxes.emplace_back(r.aabb[0], r.aabb[1]));
/* Recursively split */
BspNodeType dontCare;
rootNode.addChild(0, PATH_MIN_NODE_REGIONS, regionBoxes, fullAABB, dontCare);
/* Write out */
size_t nodeCount = 0;
size_t lookupCount = 0;
rootNode.pathCountNodesAndLookups(nodeCount, lookupCount);
path.octreeNodeCount = nodeCount;
path.octree.reserve(nodeCount);
path.octreeRegionLookupCount = lookupCount;
path.octreeRegionLookup.reserve(lookupCount);
rootNode.pathWrite(path, fullAABB);
}
template void AROTBuilder::buildPath(DNAPATH::PATH<DNAMP1::PAKBridge>& path);
template void AROTBuilder::buildPath(DNAPATH::PATH<DNAMP2::PAKBridge>& path);
template void AROTBuilder::buildPath(DNAPATH::PATH<DNAMP3::PAKBridge>& path);
} // namespace DataSpec

View File

@ -1,57 +0,0 @@
#pragma once
#include "DNACommon.hpp"
#include "DeafBabe.hpp"
#include "zeus/CAABox.hpp"
#include "CMDL.hpp"
#include <set>
namespace DataSpec {
namespace DNAPATH {
template <class PAKBridge>
struct PATH;
}
struct AROTBuilder {
using ColMesh = hecl::blender::ColMesh;
struct BitmapPool {
std::vector<std::set<int>> m_pool;
size_t addIndices(const std::set<int>& indices);
} bmpPool;
struct Node {
std::vector<Node> childNodes;
std::set<int> childIndices;
size_t poolIdx = 0;
uint16_t flags = 0;
uint16_t compSubdivs = 0;
size_t nodeOff = 0;
size_t nodeSz = 4;
void addChild(int level, int minChildren, const std::vector<zeus::CAABox>& triBoxes, const zeus::CAABox& curAABB,
BspNodeType& typeOut);
void mergeSets(int a, int b);
bool compareSets(int a, int b) const;
void nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff);
void writeIndirectionTable(athena::io::MemoryWriter& w);
void writeNodes(athena::io::MemoryWriter& w, int nodeIdx);
void advanceIndex(int& nodeIdx);
void colSize(size_t& totalSz);
void writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB);
void pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount);
template <class PAKBridge>
void pathWrite(DNAPATH::PATH<PAKBridge>& path, const zeus::CAABox& curAABB);
} rootNode;
void build(std::vector<std::vector<uint8_t>>& secs, const zeus::CAABox& fullAabb,
const std::vector<zeus::CAABox>& meshAabbs, const std::vector<DNACMDL::Mesh>& meshes);
std::pair<std::unique_ptr<uint8_t[]>, uint32_t> buildCol(const ColMesh& mesh, BspNodeType& rootOut);
template <class PAKBridge>
void buildPath(DNAPATH::PATH<PAKBridge>& path);
};
} // namespace DataSpec

View File

@ -1,66 +0,0 @@
#include "DataSpec/DNACommon/ATBL.hpp"
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
#include <athena/FileReader.hpp>
#include <athena/FileWriter.hpp>
#include <athena/YAMLDocReader.hpp>
#include <athena/YAMLDocWriter.hpp>
#include <fmt/format.h>
namespace DataSpec::DNAAudio {
bool ATBL::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
uint32_t idxCount = rs.readUint32Big();
athena::io::YAMLDocWriter w("ATBL");
for (uint32_t i = 0; i < idxCount; ++i) {
uint16_t idx = rs.readUint16Big();
if (idx == 0xffff)
continue;
w.writeUint16(fmt::format(FMT_STRING("0x{:04X}"), i), idx);
}
athena::io::FileWriter fw(outPath.getAbsolutePath());
w.finish(&fw);
return true;
}
bool ATBL::Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath) {
athena::io::FileReader r(inPath.getAbsolutePath());
if (r.hasError())
return false;
athena::io::YAMLDocReader dr;
if (!dr.parse(&r))
return false;
unsigned long maxI = 0;
for (const auto& pair : dr.getRootNode()->m_mapChildren) {
unsigned long i = strtoul(pair.first.c_str(), nullptr, 0);
maxI = std::max(maxI, i);
}
std::vector<uint16_t> vecOut(maxI + 1, 0xffff);
for (const auto& pair : dr.getRootNode()->m_mapChildren) {
unsigned long i = strtoul(pair.first.c_str(), nullptr, 0);
vecOut[i] = hecl::SBig(uint16_t(strtoul(pair.second->m_scalarString.c_str(), nullptr, 0)));
}
athena::io::FileWriter w(outPath.getAbsolutePath());
if (w.hasError())
return false;
w.writeUint32Big(uint32_t(vecOut.size()));
w.writeBytes(vecOut.data(), vecOut.size() * 2);
return true;
}
} // namespace DataSpec::DNAAudio

View File

@ -1,19 +0,0 @@
#pragma once
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAAudio {
class ATBL {
public:
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
};
} // namespace DataSpec::DNAAudio

View File

@ -1,161 +0,0 @@
#include "DataSpec/DNACommon/BabeDead.hpp"
#include "DataSpec/DNAMP1/MREA.hpp"
#include "DataSpec/DNAMP3/MREA.hpp"
#include <cfloat>
#include <hecl/Blender/Connection.hpp>
#include <zeus/CTransform.hpp>
#include <zeus/Math.hpp>
#include <fmt/format.h>
namespace DataSpec {
template <class BabeDeadLight>
void ReadBabeDeadLightToBlender(hecl::blender::PyOutStream& os, const BabeDeadLight& light, unsigned s, unsigned l) {
switch (light.lightType) {
case BabeDeadLight::LightType::LocalAmbient:
case BabeDeadLight::LightType::LocalAmbient2:
os.format(FMT_STRING("bg_node.inputs[0].default_value = ({},{},{},1.0)\n"
"bg_node.inputs[1].default_value = {}\n"),
light.color.simd[0], light.color.simd[1], light.color.simd[2], light.q / 8.f);
return;
case BabeDeadLight::LightType::Directional:
os.format(FMT_STRING("lamp = bpy.data.lights.new('LAMP_{:01d}_{:03d}', 'SUN')\n"
"lamp.color = ({},{},{})\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp_obj.rotation_mode = 'QUATERNION'\n"
"lamp_obj.rotation_quaternion = Vector((0,0,-1)).rotation_difference(Vector(({},{},{})))\n"
"lamp.use_shadow = {}\n"
"\n"),
s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2], light.direction.simd[0],
light.direction.simd[1], light.direction.simd[2], light.castShadows ? "True" : "False");
return;
case BabeDeadLight::LightType::Custom:
os.format(FMT_STRING("lamp = bpy.data.lights.new('LAMP_{:01d}_{:03d}', 'POINT')\n"
"lamp.color = ({},{},{})\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp.shadow_soft_size = 1.0\n"
"lamp.use_shadow = {}\n"
"\n"),
s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.castShadows ? "True" : "False");
break;
case BabeDeadLight::LightType::Spot:
case BabeDeadLight::LightType::Spot2:
os.format(FMT_STRING("lamp = bpy.data.lights.new('LAMP_{:01d}_{:03d}', 'SPOT')\n"
"lamp.color = ({},{},{})\n"
"lamp.spot_size = {:.6g}\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp_obj.rotation_mode = 'QUATERNION'\n"
"lamp_obj.rotation_quaternion = Vector((0,0,-1)).rotation_difference(Vector(({},{},{})))\n"
"lamp.shadow_soft_size = 0.5\n"
"lamp.use_shadow = {}\n"
"\n"),
s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2], zeus::degToRad(light.spotCutoff),
light.direction.simd[0], light.direction.simd[1], light.direction.simd[2],
light.castShadows ? "True" : "False");
break;
default:
return;
}
os.format(FMT_STRING("lamp.retro_layer = {}\n"
"lamp.retro_origtype = {}\n"
"lamp.falloff_type = 'INVERSE_COEFFICIENTS'\n"
"lamp.constant_coefficient = 0\n"
"lamp.use_nodes = True\n"
"falloff_node = lamp.node_tree.nodes.new('ShaderNodeLightFalloff')\n"
"lamp.energy = 0.0\n"
"falloff_node.inputs[0].default_value = {}\n"
"hue_sat_node = lamp.node_tree.nodes.new('ShaderNodeHueSaturation')\n"
"hue_sat_node.inputs[1].default_value = 1.25\n"
"hue_sat_node.inputs[4].default_value = ({},{},{},1.0)\n"
"lamp.node_tree.links.new(hue_sat_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[0])\n"
"lamp_obj.location = ({},{},{})\n"
"bpy.context.scene.collection.objects.link(lamp_obj)\n"
"\n"),
s, unsigned(light.lightType), light.q / 8.f, light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.position.simd[0], light.position.simd[1], light.position.simd[2]);
switch (light.falloff) {
case BabeDeadLight::Falloff::Constant:
os << "falloff_node.inputs[0].default_value *= 150.0\n"
"lamp.node_tree.links.new(falloff_node.outputs[2], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format(FMT_STRING("lamp.constant_coefficient = 2.0 / {}\n"), light.q);
break;
case BabeDeadLight::Falloff::Linear:
os << "lamp.node_tree.links.new(falloff_node.outputs[1], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format(FMT_STRING("lamp.linear_coefficient = 250 / {}\n"), light.q);
break;
case BabeDeadLight::Falloff::Quadratic:
os << "lamp.node_tree.links.new(falloff_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format(FMT_STRING("lamp.quadratic_coefficient = 25000 / {}\n"), light.q);
break;
default:
break;
}
}
template void ReadBabeDeadLightToBlender<DNAMP1::MREA::BabeDeadLight>(hecl::blender::PyOutStream& os,
const DNAMP1::MREA::BabeDeadLight& light,
unsigned s, unsigned l);
template void ReadBabeDeadLightToBlender<DNAMP3::MREA::BabeDeadLight>(hecl::blender::PyOutStream& os,
const DNAMP3::MREA::BabeDeadLight& light,
unsigned s, unsigned l);
template <class BabeDeadLight>
void WriteBabeDeadLightFromBlender(BabeDeadLight& lightOut, const hecl::blender::Light& lightIn) {
using InterType = hecl::blender::Light::Type;
switch (lightIn.type) {
case InterType::Ambient:
lightOut.lightType = BabeDeadLight::LightType::LocalAmbient;
break;
case InterType::Directional:
lightOut.lightType = BabeDeadLight::LightType::Directional;
break;
case InterType::Custom:
default:
lightOut.lightType = BabeDeadLight::LightType::Custom;
break;
case InterType::Spot:
lightOut.lightType = BabeDeadLight::LightType::Spot;
break;
}
if (lightIn.type == InterType::Ambient) {
lightOut.falloff = BabeDeadLight::Falloff::Constant;
lightOut.q = lightIn.energy * 8.f;
} else if (lightIn.linear > lightIn.constant && lightIn.linear > lightIn.quadratic) {
lightOut.falloff = BabeDeadLight::Falloff::Linear;
lightOut.q = 250.f / lightIn.linear;
} else if (lightIn.quadratic > lightIn.constant && lightIn.quadratic > lightIn.linear) {
lightOut.falloff = BabeDeadLight::Falloff::Quadratic;
lightOut.q = 25000.f / lightIn.quadratic;
} else {
lightOut.falloff = BabeDeadLight::Falloff::Constant;
lightOut.q = 2.f / lightIn.constant;
}
lightOut.color = lightIn.color;
lightOut.spotCutoff = zeus::radToDeg(lightIn.spotCutoff);
lightOut.castShadows = lightIn.shadow;
lightOut.position.simd[0] = lightIn.sceneXf[0].simd[3];
lightOut.position.simd[1] = lightIn.sceneXf[1].simd[3];
lightOut.position.simd[2] = lightIn.sceneXf[2].simd[3];
zeus::CTransform lightXf(&lightIn.sceneXf[0]);
lightOut.direction = (lightXf.basis.transposed() * zeus::CVector3f(0.f, 0.f, -1.f)).normalized();
}
template void WriteBabeDeadLightFromBlender<DNAMP1::MREA::BabeDeadLight>(DNAMP1::MREA::BabeDeadLight& lightOut,
const hecl::blender::Light& lightIn);
template void WriteBabeDeadLightFromBlender<DNAMP3::MREA::BabeDeadLight>(DNAMP3::MREA::BabeDeadLight& lightOut,
const hecl::blender::Light& lightIn);
} // namespace DataSpec

View File

@ -1,16 +0,0 @@
#pragma once
namespace hecl::blender {
struct Light;
class PyOutStream;
} // namespace hecl::blender
namespace DataSpec {
template <class BabeDeadLight>
void ReadBabeDeadLightToBlender(hecl::blender::PyOutStream& os, const BabeDeadLight& light, unsigned s, unsigned l);
template <class BabeDeadLight>
void WriteBabeDeadLightFromBlender(BabeDeadLight& lightOut, const hecl::blender::Light& lightIn);
} // namespace DataSpec

File diff suppressed because it is too large Load Diff

View File

@ -1,168 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <vector>
#include "DataSpec/DNACommon/GX.hpp"
#include "DataSpec/DNACommon/TXTR.hpp"
#include <athena/DNA.hpp>
#include <athena/Types.hpp>
#include <hecl/Blender/Connection.hpp>
namespace hecl {
class ProjectPath;
}
namespace zeus {
class CAABox;
}
namespace DataSpec::DNACMDL {
using Mesh = hecl::blender::Mesh;
using Material = hecl::blender::Material;
struct Header : BigDNA {
AT_DECL_DNA
Value<atUint32> magic;
Value<atUint32> version;
struct Flags : BigDNA {
AT_DECL_DNA
Value<atUint32> flags = 0;
bool skinned() const { return (flags & 0x1) != 0; }
void setSkinned(bool val) {
flags &= ~0x1;
flags |= val;
}
bool shortNormals() const { return (flags & 0x2) != 0; }
void setShortNormals(bool val) {
flags &= ~0x2;
flags |= val << 1;
}
bool shortUVs() const { return (flags & 0x4) != 0; }
void setShortUVs(bool val) {
flags &= ~0x4;
flags |= val << 2;
}
} flags;
Value<atVec3f> aabbMin;
Value<atVec3f> aabbMax;
Value<atUint32> secCount;
Value<atUint32> matSetCount;
Vector<atUint32, AT_DNA_COUNT(secCount)> secSizes;
Align<32> align;
};
struct SurfaceHeader_1 : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atVec3f> aabb[2];
Align<32> align;
static constexpr bool UseMatrixSkinning() { return false; }
static constexpr atInt16 skinMatrixBankIdx() { return -1; }
};
struct SurfaceHeader_2 : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx;
Value<atUint16> surfaceGroup;
Value<atVec3f> aabb[2];
Align<32> align;
static constexpr bool UseMatrixSkinning() { return false; }
atInt16 skinMatrixBankIdx() const { return skinMtxBankIdx; }
};
struct SurfaceHeader_3 : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx;
Value<atUint16> surfaceGroup;
Value<atVec3f> aabb[2];
Value<atUint8> unk3;
Align<32> align;
static constexpr bool UseMatrixSkinning() { return true; }
atInt16 skinMatrixBankIdx() const { return skinMtxBankIdx; }
};
struct VertexAttributes {
GX::AttrType pos = GX::NONE;
GX::AttrType norm = GX::NONE;
GX::AttrType color0 = GX::NONE;
GX::AttrType color1 = GX::NONE;
unsigned uvCount = 0;
GX::AttrType uvs[7] = {GX::NONE};
GX::AttrType pnMtxIdx = GX::NONE;
unsigned texMtxIdxCount = 0;
GX::AttrType texMtxIdx[7] = {GX::NONE};
bool shortUVs;
};
template <class MaterialSet>
void GetVertexAttributes(const MaterialSet& matSet, std::vector<VertexAttributes>& attributesOut);
template <class PAKRouter, class MaterialSet>
void ReadMaterialSetToBlender_1_2(hecl::blender::PyOutStream& os, const MaterialSet& matSet, const PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, unsigned setIdx);
template <class PAKRouter, class MaterialSet>
void ReadMaterialSetToBlender_3(hecl::blender::PyOutStream& os, const MaterialSet& matSet, const PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, unsigned setIdx);
void InitGeomBlenderContext(hecl::blender::PyOutStream& os, const hecl::ProjectPath& masterShaderPath);
void FinishBlenderMesh(hecl::blender::PyOutStream& os, unsigned matSetCount, int meshIdx);
template <class PAKRouter, class MaterialSet, class RigPair, class SurfaceHeader>
atUint32 ReadGeomSectionsToBlender(hecl::blender::PyOutStream& os, athena::io::IStreamReader& reader,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const RigPair& rp,
bool shortNormals, bool shortUVs, std::vector<VertexAttributes>& vertAttribs,
int meshIdx, atUint32 secCount, atUint32 matSetCount, const atUint32* secSizes,
atUint32 surfaceCount = 0);
template <class PAKRouter, class MaterialSet, class RigPair, class SurfaceHeader, atUint32 Version>
bool ReadCMDLToBlender(hecl::blender::Connection& conn, athena::io::IStreamReader& reader, PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, const SpecBase& dataspec, const RigPair& rp);
template <class PAKRouter, class MaterialSet>
void NameCMDL(athena::io::IStreamReader& reader, PAKRouter& pakRouter, typename PAKRouter::EntryType& entry,
const SpecBase& dataspec);
template <class MaterialSet, class SurfaceHeader, atUint32 Version>
bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh);
template <class MaterialSet, class SurfaceHeader, atUint32 Version>
bool WriteHMDLCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh,
hecl::blender::PoolSkinIndex& poolSkinIndex);
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
bool WriteMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs);
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
bool WriteHMDLMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs);
} // namespace DataSpec::DNACMDL

View File

@ -1,60 +0,0 @@
make_dnalist(CMDL
FONT
DGRP
FSM2
MAPA
MAPU
PATH
MayaSpline
EGMC
SAVWCommon
ParticleCommon
MetaforceVersionInfo
Tweaks/ITweakPlayerGun)
set(DNACOMMON_SOURCES
DNACommon.hpp DNACommon.cpp
PAK.hpp PAK.cpp
GX.hpp GX.cpp
FSM2.hpp FSM2.cpp
MLVL.hpp MLVL.cpp
CMDL.cpp
MAPA.cpp
MAPU.cpp
PATH.hpp PATH.cpp
STRG.hpp STRG.cpp
TXTR.hpp TXTR.cpp
ANCS.hpp ANCS.cpp
ANIM.hpp ANIM.cpp
PART.hpp PART.cpp
SWHC.hpp SWHC.cpp
CRSC.hpp CRSC.cpp
ELSC.hpp ELSC.cpp
WPSC.hpp WPSC.cpp
DPSC.hpp DPSC.cpp
ParticleCommon.cpp
FONT.cpp
DGRP.cpp
ATBL.hpp ATBL.cpp
DeafBabe.hpp DeafBabe.cpp
BabeDead.hpp BabeDead.cpp
RigInverter.hpp RigInverter.cpp
AROTBuilder.hpp AROTBuilder.cpp
OBBTreeBuilder.hpp OBBTreeBuilder.cpp
MetaforceVersionInfo.hpp
Tweaks/ITweak.hpp
Tweaks/TweakWriter.hpp
Tweaks/ITweakGame.hpp
Tweaks/ITweakParticle.hpp
Tweaks/ITweakPlayer.hpp
Tweaks/ITweakPlayerControl.hpp
Tweaks/ITweakGunRes.hpp
Tweaks/ITweakPlayerRes.hpp
Tweaks/ITweakGui.hpp
Tweaks/ITweakSlideShow.hpp
Tweaks/ITweakTargeting.hpp
Tweaks/ITweakAutoMapper.hpp
Tweaks/ITweakBall.hpp
Tweaks/ITweakGuiColors.hpp)
dataspec_add_list(DNACommon DNACOMMON_SOURCES)

View File

@ -1,50 +0,0 @@
#include "DataSpec/DNACommon/CRSC.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNAParticle {
template struct PPImpl<_CRSM<UniqueID32>>;
template struct PPImpl<_CRSM<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_CRSM<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_CRSM<UniqueID64>>)
template <>
std::string_view PPImpl<_CRSM<UniqueID32>>::DNAType() {
return "CRSM<UniqueID32>"sv;
}
template <>
std::string_view PPImpl<_CRSM<UniqueID64>>::DNAType() {
return "CRSM<UniqueID64>"sv;
}
template <class IDType>
bool ExtractCRSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
CRSM<IDType> crsm;
crsm.read(rs);
athena::io::ToYAMLStream(crsm, writer);
return true;
}
return false;
}
template bool ExtractCRSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractCRSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteCRSM(const CRSM<IDType>& crsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
crsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteCRSM<UniqueID32>(const CRSM<UniqueID32>& crsm, const hecl::ProjectPath& outPath);
template bool WriteCRSM<UniqueID64>(const CRSM<UniqueID64>& crsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,222 +0,0 @@
#ifndef ENTRY
#define ENTRY(name, identifier)
#endif
#ifndef RES_ENTRY
#define RES_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef U32_ENTRY
#define U32_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef FLOAT_ENTRY
#define FLOAT_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
RES_ENTRY('NODP', NODP)
RES_ENTRY('DEFS', DEFS)
RES_ENTRY('CRTS', CRTS)
RES_ENTRY('MTLS', MTLS)
RES_ENTRY('GRAS', GRAS)
RES_ENTRY('ICEE', ICEE)
RES_ENTRY('GOOO', GOOO)
RES_ENTRY('WODS', WODS)
RES_ENTRY('WATR', WATR)
RES_ENTRY('1MUD', _1MUD)
RES_ENTRY('1LAV', _1LAV)
RES_ENTRY('1SAN', _1SAN)
RES_ENTRY('1PRJ', _1PRJ)
RES_ENTRY('DCHR', DCHR)
RES_ENTRY('DCHS', DCHS)
RES_ENTRY('DCSH', DCSH)
RES_ENTRY('DENM', DENM)
RES_ENTRY('DESP', DESP)
RES_ENTRY('DESH', DESH)
RES_ENTRY('BTLE', BTLE)
RES_ENTRY('WASP', WASP)
RES_ENTRY('TALP', TALP)
RES_ENTRY('PTGM', PTGM)
RES_ENTRY('SPIR', SPIR)
RES_ENTRY('FPIR', FPIR)
RES_ENTRY('FFLE', FFLE)
RES_ENTRY('PARA', PARA)
RES_ENTRY('BMON', BMON)
RES_ENTRY('BFLR', BFLR)
RES_ENTRY('PBOS', PBOS)
RES_ENTRY('IBOS', IBOS)
RES_ENTRY('1SVA', _1SVA)
RES_ENTRY('1RPR', _1RPR)
RES_ENTRY('1MTR', _1MTR)
RES_ENTRY('1PDS', _1PDS)
RES_ENTRY('1FLB', _1FLB)
RES_ENTRY('1DRN', _1DRN)
RES_ENTRY('1MRE', _1MRE)
RES_ENTRY('CHOZ', CHOZ)
RES_ENTRY('JZAP', JZAP)
RES_ENTRY('1ISE', _1ISE)
RES_ENTRY('1BSE', _1BSE)
RES_ENTRY('1ATB', _1ATB)
RES_ENTRY('1ATA', _1ATA)
RES_ENTRY('BTSP', BTSP)
RES_ENTRY('WWSP', WWSP)
RES_ENTRY('TASP', TASP)
RES_ENTRY('TGSP', TGSP)
RES_ENTRY('SPSP', SPSP)
RES_ENTRY('FPSP', FPSP)
RES_ENTRY('FFSP', FFSP)
RES_ENTRY('PSSP', PSSP)
RES_ENTRY('BMSP', BMSP)
RES_ENTRY('BFSP', BFSP)
RES_ENTRY('PBSP', PBSP)
RES_ENTRY('IBSP', IBSP)
RES_ENTRY('2SVA', _2SVA)
RES_ENTRY('2RPR', _2RPR)
RES_ENTRY('2MTR', _2MTR)
RES_ENTRY('2PDS', _2PDS)
RES_ENTRY('2FLB', _2FLB)
RES_ENTRY('2DRN', _2DRN)
RES_ENTRY('2MRE', _2MRE)
RES_ENTRY('CHSP', CHSP)
RES_ENTRY('JZSP', JZSP)
RES_ENTRY('3ISE', _3ISE)
RES_ENTRY('3BSE', _3BSE)
RES_ENTRY('3ATB', _3ATB)
RES_ENTRY('3ATA', _3ATA)
RES_ENTRY('BTSH', BTSH)
RES_ENTRY('WWSH', WWSH)
RES_ENTRY('TASH', TASH)
RES_ENTRY('TGSH', TGSH)
RES_ENTRY('SPSH', SPSH)
RES_ENTRY('FPSH', FPSH)
RES_ENTRY('FFSH', FFSH)
RES_ENTRY('PSSH', PSSH)
RES_ENTRY('BMSH', BMSH)
RES_ENTRY('BFSH', BFSH)
RES_ENTRY('PBSH', PBSH)
RES_ENTRY('IBSH', IBSH)
RES_ENTRY('3SVA', _3SVA)
RES_ENTRY('3RPR', _3RPR)
RES_ENTRY('3MTR', _3MTR)
RES_ENTRY('3PDS', _3PDS)
RES_ENTRY('3FLB', _3FLB)
RES_ENTRY('3DRN', _3DRN)
RES_ENTRY('3MRE', _3MRE)
RES_ENTRY('CHSH', CHSH)
RES_ENTRY('JZSH', JZSH)
RES_ENTRY('5ISE', _5ISE)
RES_ENTRY('5BSE', _5BSE)
RES_ENTRY('5ATB', _5ATB)
RES_ENTRY('5ATA', _5ATA)
RES_ENTRY('NCDL', NCDL)
RES_ENTRY('DDCL', DDCL)
RES_ENTRY('CODL', CODL)
RES_ENTRY('MEDL', MEDL)
RES_ENTRY('GRDL', GRDL)
RES_ENTRY('ICDL', ICDL)
RES_ENTRY('GODL', GODL)
RES_ENTRY('WODL', WODL)
RES_ENTRY('WTDL', WTDL)
RES_ENTRY('3MUD', _3MUD)
RES_ENTRY('3LAV', _3LAV)
RES_ENTRY('3SAN', _3SAN)
RES_ENTRY('CHDL', CHDL)
RES_ENTRY('ENDL', ENDL)
U32_ENTRY('NSFX', NSFX)
U32_ENTRY('DSFX', DSFX)
U32_ENTRY('CSFX', CSFX)
U32_ENTRY('MSFX', MSFX)
U32_ENTRY('GRFX', GRFX)
U32_ENTRY('ICFX', ICFX)
U32_ENTRY('GOFX', GOFX)
U32_ENTRY('WSFX', WSFX)
U32_ENTRY('WTFX', WTFX)
U32_ENTRY('2MUD', _2MUD)
U32_ENTRY('2LAV', _2LAV)
U32_ENTRY('2SAN', _2SAN)
U32_ENTRY('2PRJ', _2PRJ)
U32_ENTRY('DCFX', DCFX)
U32_ENTRY('DSHX', DSHX)
U32_ENTRY('DEFX', DEFX)
U32_ENTRY('ESFX', ESFX)
U32_ENTRY('SHFX', SHFX)
U32_ENTRY('BEFX', BEFX)
U32_ENTRY('WWFX', WWFX)
U32_ENTRY('TAFX', TAFX)
U32_ENTRY('GTFX', GTFX)
U32_ENTRY('SPFX', SPFX)
U32_ENTRY('FPFX', FPFX)
U32_ENTRY('FFFX', FFFX)
U32_ENTRY('PAFX', PAFX)
U32_ENTRY('BMFX', BMFX)
U32_ENTRY('BFFX', BFFX)
U32_ENTRY('PBFX', PBFX)
U32_ENTRY('IBFX', IBFX)
U32_ENTRY('4SVA', _4SVA)
U32_ENTRY('4RPR', _4RPR)
U32_ENTRY('4MTR', _4MTR)
U32_ENTRY('4PDS', _4PDS)
U32_ENTRY('4FLB', _4FLB)
U32_ENTRY('4DRN', _4DRN)
U32_ENTRY('4MRE', _4MRE)
U32_ENTRY('CZFX', CZFX)
U32_ENTRY('JZAS', JZAS)
U32_ENTRY('2ISE', _2ISE)
U32_ENTRY('2BSE', _2BSE)
U32_ENTRY('2ATB', _2ATB)
U32_ENTRY('2ATA', _2ATA)
U32_ENTRY('BSFX', BSFX)
U32_ENTRY('TSFX', TSFX)
U32_ENTRY('GSFX', GSFX)
U32_ENTRY('SSFX', SSFX)
U32_ENTRY('FSFX', FSFX)
U32_ENTRY('SFFX', SFFX)
U32_ENTRY('PSFX', PSFX)
U32_ENTRY('SBFX', SBFX)
U32_ENTRY('PBSX', PBSX)
U32_ENTRY('IBSX', IBSX)
U32_ENTRY('5SVA', _5SVA)
U32_ENTRY('5RPR', _5RPR)
U32_ENTRY('5MTR', _5MTR)
U32_ENTRY('5PDS', _5PDS)
U32_ENTRY('5FLB', _5FLB)
U32_ENTRY('5DRN', _5DRN)
U32_ENTRY('5MRE', _5MRE)
U32_ENTRY('JZPS', JZPS)
U32_ENTRY('4ISE', _4ISE)
U32_ENTRY('4BSE', _4BSE)
U32_ENTRY('4ATB', _4ATB)
U32_ENTRY('4ATA', _4ATA)
U32_ENTRY('BHFX', BHFX)
U32_ENTRY('WHFX', WHFX)
U32_ENTRY('THFX', THFX)
U32_ENTRY('GHFX', GHFX)
U32_ENTRY('FHFX', FHFX)
U32_ENTRY('HFFX', HFFX)
U32_ENTRY('PHFX', PHFX)
U32_ENTRY('MHFX', MHFX)
U32_ENTRY('HBFX', HBFX)
U32_ENTRY('PBHX', PBHX)
U32_ENTRY('IBHX', IBHX)
U32_ENTRY('6SVA', _6SVA)
U32_ENTRY('6RPR', _6RPR)
U32_ENTRY('6MTR', _6MTR)
U32_ENTRY('6PDS', _6PDS)
U32_ENTRY('6FLB', _6FLB)
U32_ENTRY('6DRN', _6DRN)
U32_ENTRY('6MRE', _6MRE)
U32_ENTRY('CHFX', CHFX)
U32_ENTRY('JZHS', JZHS)
U32_ENTRY('6ISE', _6ISE)
U32_ENTRY('6BSE', _6BSE)
U32_ENTRY('6ATB', _6ATB)
U32_ENTRY('6ATA', _6ATA)
FLOAT_ENTRY('RNGE', x30_RNGE)
FLOAT_ENTRY('FOFF', x34_FOFF)
#undef ENTRY
#undef RES_ENTRY
#undef U32_ENTRY
#undef FLOAT_ENTRY

View File

@ -1,57 +0,0 @@
#pragma once
#include <cstdint>
#include <unordered_map>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/ParticleCommon.hpp"
#include <athena/DNA.hpp>
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAParticle {
template <class IDType>
struct _CRSM {
static constexpr ParticleType Type = ParticleType::CRSM;
#define RES_ENTRY(name, identifier) ChildResourceFactory<IDType> identifier;
#define U32_ENTRY(name, identifier) uint32_t identifier = ~0;
#define FLOAT_ENTRY(name, identifier) float identifier = 0.f;
#include "CRSC.def"
template <typename _Func>
void constexpr Enumerate(_Func f) {
#define ENTRY(name, identifier) f(FOURCC(name), identifier);
#include "CRSC.def"
}
template <typename _Func>
bool constexpr Lookup(FourCC fcc, _Func f) {
switch (fcc.toUint32()) {
#define ENTRY(name, identifier) \
case SBIG(name): \
f(identifier); \
return true;
#include "CRSC.def"
default:
return false;
}
}
};
template <class IDType>
using CRSM = PPImpl<_CRSM<IDType>>;
template <class IDType>
bool ExtractCRSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteCRSM(const CRSM<IDType>& crsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,40 +0,0 @@
#include "DataSpec/DNACommon/DGRP.hpp"
#include <athena/DNAYaml.hpp>
#include <athena/FileWriter.hpp>
#include <athena/IStreamWriter.hpp>
#include <hecl/hecl.hpp>
namespace DataSpec::DNADGRP {
template <class IDType>
bool ExtractDGRP(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
DGRP<IDType> dgrp;
dgrp.read(rs);
athena::io::ToYAMLStream(dgrp, writer);
return true;
}
return false;
}
template bool ExtractDGRP<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractDGRP<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDGRP(const DGRP<IDType>& dgrp, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
dgrp.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteDGRP<UniqueID32>(const DGRP<UniqueID32>& dgrp, const hecl::ProjectPath& outPath);
template bool WriteDGRP<UniqueID64>(const DGRP<UniqueID64>& dgrp, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNADGRP

View File

@ -1,45 +0,0 @@
#pragma once
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNADGRP {
template <class IDType>
struct AT_SPECIALIZE_PARMS(DataSpec::UniqueID32, DataSpec::UniqueID64) DGRP : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> dependCount;
struct ObjectTag : BigDNA {
AT_DECL_DNA_YAML
DNAFourCC type;
Value<IDType> id;
bool validate() const {
if (!id.isValid())
return false;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
return path && !path.isNone();
}
};
Vector<ObjectTag, AT_DNA_COUNT(dependCount)> depends;
void validateDeps() {
std::vector<ObjectTag> newDeps;
newDeps.reserve(depends.size());
for (const ObjectTag& tag : depends)
if (tag.validate())
newDeps.push_back(tag);
depends = std::move(newDeps);
dependCount = atUint32(depends.size());
}
};
template <class IDType>
bool ExtractDGRP(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDGRP(const DGRP<IDType>& dgrp, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNADGRP

View File

@ -1,199 +0,0 @@
#include "DNACommon.hpp"
#include "PAK.hpp"
#include "boo/ThreadLocalPtr.hpp"
namespace DataSpec {
logvisor::Module LogDNACommon("DataSpec::DNACommon");
ThreadLocalPtr<SpecBase> g_curSpec;
ThreadLocalPtr<PAKRouterBase> g_PakRouter;
ThreadLocalPtr<hecl::blender::Token> g_ThreadBlenderToken;
ThreadLocalPtr<hecl::Database::Project> UniqueIDBridge::s_Project;
UniqueID32 UniqueID32::kInvalidId;
template <class IDType>
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const IDType& id, bool silenceWarnings) {
/* Try PAKRouter first (only available at extract) */
PAKRouterBase* pakRouter = g_PakRouter.get();
if (pakRouter) {
hecl::ProjectPath path = pakRouter->getWorking(id, silenceWarnings);
if (path)
return path;
}
/* Try project cache second (populated with paths read from YAML resources) */
hecl::Database::Project* project = s_Project.get();
if (!project) {
if (pakRouter) {
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id.isValid())
LogDNACommon.report(logvisor::Warning, FMT_STRING("unable to translate {} to path"), id);
return {};
}
LogDNACommon.report(logvisor::Fatal, FMT_STRING("g_PakRouter or s_Project must be set to non-null before "
"calling UniqueIDBridge::TranslatePakIdToPath"));
return {};
}
const hecl::ProjectPath* search = project->lookupBridgePath(id.toUint64());
if (!search) {
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id.isValid())
LogDNACommon.report(logvisor::Warning, FMT_STRING("unable to translate {} to path"), id);
return {};
}
return *search;
}
template hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID32& id, bool silenceWarnings);
template hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID64& id, bool silenceWarnings);
template hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID128& id, bool silenceWarnings);
template <class IDType>
hecl::ProjectPath UniqueIDBridge::MakePathFromString(std::string_view str) {
if (str.empty())
return {};
hecl::Database::Project* project = s_Project.get();
if (!project)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("UniqueIDBridge::setGlobalProject must be called before MakePathFromString"));
hecl::ProjectPath path = hecl::ProjectPath(*project, str);
project->addBridgePathToCache(IDType(path).toUint64(), path);
return path;
}
template hecl::ProjectPath UniqueIDBridge::MakePathFromString<UniqueID32>(std::string_view str);
template hecl::ProjectPath UniqueIDBridge::MakePathFromString<UniqueID64>(std::string_view str);
void UniqueIDBridge::SetThreadProject(hecl::Database::Project& project) { s_Project.reset(&project); }
/** PAK 32-bit Unique ID */
template <>
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
assign(reader.readUint32Big());
}
template <>
void UniqueID32::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint32Big(m_id);
}
template <>
void UniqueID32::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
*this = UniqueIDBridge::MakePathFromString<UniqueID32>(reader.readString());
}
template <>
void UniqueID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!isValid())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(path.getEncodableString());
}
template <>
void UniqueID32::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
}
std::string UniqueID32::toString() const { return fmt::format(FMT_STRING("{}"), *this); }
template <>
void UniqueID32Zero::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
UniqueID32::Enumerate<BigDNA::Read>(reader);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint32Big(isValid() ? m_id : 0);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
UniqueID32::Enumerate<BigDNA::ReadYaml>(reader);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
UniqueID32::Enumerate<BigDNA::WriteYaml>(writer);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
UniqueID32::Enumerate<BigDNA::BinarySize>(s);
}
/** PAK 64-bit Unique ID */
template <>
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
assign(reader.readUint64Big());
}
template <>
void UniqueID64::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint64Big(m_id);
}
template <>
void UniqueID64::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
*this = UniqueIDBridge::MakePathFromString<UniqueID64>(reader.readString());
}
template <>
void UniqueID64::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!isValid())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(path.getEncodableString());
}
template <>
void UniqueID64::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 8;
}
std::string UniqueID64::toString() const { return fmt::format(FMT_STRING("{}"), *this); }
/** PAK 128-bit Unique ID */
template <>
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
m_id.id[0] = reader.readUint64Big();
m_id.id[1] = reader.readUint64Big();
}
template <>
void UniqueID128::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint64Big(m_id.id[0]);
writer.writeUint64Big(m_id.id[1]);
}
template <>
void UniqueID128::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
*this = UniqueIDBridge::MakePathFromString<UniqueID128>(reader.readString());
}
template <>
void UniqueID128::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!isValid())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(path.getEncodableString());
}
template <>
void UniqueID128::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 16;
}
std::string UniqueID128::toString() const { return fmt::format(FMT_STRING("{}"), *this); }
/** Word Bitmap reader/writer */
void WordBitmap::read(athena::io::IStreamReader& reader, size_t bitCount) {
m_bitCount = bitCount;
size_t wordCount = (bitCount + 31) / 32;
m_words.clear();
m_words.reserve(wordCount);
for (size_t w = 0; w < wordCount; ++w)
m_words.push_back(reader.readUint32Big());
}
void WordBitmap::write(athena::io::IStreamWriter& writer) const {
for (atUint32 word : m_words)
writer.writeUint32Big(word);
}
void WordBitmap::binarySize(size_t& __isz) const { __isz += m_words.size() * 4; }
hecl::ProjectPath GetPathBeginsWith(const hecl::DirectoryEnumerator& dEnum, const hecl::ProjectPath& parentPath,
std::string_view test) {
for (const auto& ent : dEnum)
if (hecl::StringUtils::BeginsWith(ent.m_name, test))
return hecl::ProjectPath(parentPath, ent.m_name);
return {};
}
} // namespace DataSpec

View File

@ -1,394 +0,0 @@
#pragma once
#include <cstdio>
#include "logvisor/logvisor.hpp"
#include "athena/DNAYaml.hpp"
#include "hecl/Database.hpp"
#include "../SpecBase.hpp"
#include "boo/ThreadLocalPtr.hpp"
#include "zeus/CColor.hpp"
namespace DataSpec {
struct SpecBase;
extern logvisor::Module LogDNACommon;
extern ThreadLocalPtr<SpecBase> g_curSpec;
extern ThreadLocalPtr<class PAKRouterBase> g_PakRouter;
extern ThreadLocalPtr<hecl::blender::Token> g_ThreadBlenderToken;
/* This comes up a great deal */
using BigDNA = athena::io::DNA<athena::Endian::Big>;
using BigDNAV = athena::io::DNAV<athena::Endian::Big>;
using BigDNAVYaml = athena::io::DNAVYaml<athena::Endian::Big>;
/** FourCC with DNA read/write */
using DNAFourCC = hecl::DNAFourCC;
class DNAColor final : public BigDNA, public zeus::CColor {
public:
DNAColor() = default;
DNAColor(const zeus::CColor& color) : zeus::CColor(color) {}
AT_DECL_EXPLICIT_DNA_YAML
};
template <>
inline void DNAColor::Enumerate<BigDNA::Read>(typename Read::StreamT& _r) {
zeus::CColor::readRGBABig(_r);
}
template <>
inline void DNAColor::Enumerate<BigDNA::Write>(typename Write::StreamT& _w) {
zeus::CColor::writeRGBABig(_w);
}
template <>
inline void DNAColor::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& _r) {
size_t count;
if (auto v = _r.enterSubVector(count)) {
zeus::simd_floats f;
f[0] = (count >= 1) ? _r.readFloat() : 0.f;
f[1] = (count >= 2) ? _r.readFloat() : 0.f;
f[2] = (count >= 3) ? _r.readFloat() : 0.f;
f[3] = (count >= 4) ? _r.readFloat() : 0.f;
mSimd.copy_from(f);
}
}
template <>
inline void DNAColor::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& _w) {
if (auto v = _w.enterSubVector()) {
zeus::simd_floats f(mSimd);
_w.writeFloat(f[0]);
_w.writeFloat(f[1]);
_w.writeFloat(f[2]);
_w.writeFloat(f[3]);
}
}
template <>
inline void DNAColor::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& _s) {
_s += 16;
}
using FourCC = hecl::FourCC;
class UniqueID32;
class UniqueID64;
class UniqueID128;
/** Common virtual interface for runtime ambiguity resolution */
class PAKRouterBase {
protected:
const SpecBase& m_dataSpec;
public:
PAKRouterBase(const SpecBase& dataSpec) : m_dataSpec(dataSpec) {}
hecl::Database::Project& getProject() const { return m_dataSpec.getProject(); }
virtual hecl::ProjectPath getWorking(const UniqueID32&, bool silenceWarnings = false) const {
LogDNACommon.report(logvisor::Fatal, FMT_STRING("PAKRouter IDType mismatch; expected UniqueID32 specialization"));
return hecl::ProjectPath();
}
virtual hecl::ProjectPath getWorking(const UniqueID64&, bool silenceWarnings = false) const {
LogDNACommon.report(logvisor::Fatal, FMT_STRING("PAKRouter IDType mismatch; expected UniqueID64 specialization"));
return hecl::ProjectPath();
}
virtual hecl::ProjectPath getWorking(const UniqueID128&, bool silenceWarnings = false) const {
LogDNACommon.report(logvisor::Fatal, FMT_STRING("PAKRouter IDType mismatch; expected UniqueID128 specialization"));
return hecl::ProjectPath();
}
};
/** Globally-accessed manager allowing UniqueID* classes to directly
* lookup destination paths of resources */
class UniqueIDBridge {
friend class UniqueID32;
friend class UniqueID64;
static ThreadLocalPtr<hecl::Database::Project> s_Project;
public:
template <class IDType>
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings = false);
template <class IDType>
static hecl::ProjectPath MakePathFromString(std::string_view str);
static void SetThreadProject(hecl::Database::Project& project);
};
/** PAK 32-bit Unique ID */
class UniqueID32 : public BigDNA {
protected:
uint32_t m_id = 0xffffffff;
public:
using value_type = uint32_t;
static UniqueID32 kInvalidId;
AT_DECL_EXPLICIT_DNA_YAML
bool isValid() const noexcept { return m_id != 0xffffffff && m_id != 0; }
void assign(uint32_t id) noexcept { m_id = id ? id : 0xffffffff; }
UniqueID32& operator=(const hecl::ProjectPath& path) noexcept {
assign(path.parsedHash32());
return *this;
}
bool operator!=(const UniqueID32& other) const noexcept { return m_id != other.m_id; }
bool operator==(const UniqueID32& other) const noexcept { return m_id == other.m_id; }
bool operator<(const UniqueID32& other) const noexcept { return m_id < other.m_id; }
uint32_t toUint32() const noexcept { return m_id; }
uint64_t toUint64() const noexcept { return m_id; }
std::string toString() const;
void clear() noexcept { m_id = 0xffffffff; }
UniqueID32() noexcept = default;
UniqueID32(uint32_t idin) noexcept { assign(idin); }
UniqueID32(athena::io::IStreamReader& reader) { read(reader); }
UniqueID32(const hecl::ProjectPath& path) noexcept { *this = path; }
UniqueID32(const char* hexStr) noexcept {
char copy[9];
strncpy(copy, hexStr, 8);
copy[8] = '\0';
assign(strtoul(copy, nullptr, 16));
}
static constexpr size_t BinarySize() noexcept { return 4; }
};
/** PAK 32-bit Unique ID - writes zero when invalid */
class UniqueID32Zero : public UniqueID32 {
public:
AT_DECL_DNA_YAML
Delete __d2;
using UniqueID32::UniqueID32;
};
/** PAK 64-bit Unique ID */
class UniqueID64 : public BigDNA {
uint64_t m_id = 0xffffffffffffffff;
public:
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
bool isValid() const noexcept { return m_id != 0xffffffffffffffff && m_id != 0; }
void assign(uint64_t id) noexcept { m_id = id ? id : 0xffffffffffffffff; }
UniqueID64& operator=(const hecl::ProjectPath& path) noexcept {
assign(path.hash().val64());
return *this;
}
bool operator!=(const UniqueID64& other) const noexcept { return m_id != other.m_id; }
bool operator==(const UniqueID64& other) const noexcept { return m_id == other.m_id; }
bool operator<(const UniqueID64& other) const noexcept { return m_id < other.m_id; }
uint64_t toUint64() const noexcept { return m_id; }
std::string toString() const;
void clear() noexcept { m_id = 0xffffffffffffffff; }
UniqueID64() noexcept = default;
UniqueID64(uint64_t idin) noexcept { assign(idin); }
UniqueID64(athena::io::IStreamReader& reader) { read(reader); }
UniqueID64(const hecl::ProjectPath& path) noexcept { *this = path; }
UniqueID64(const char* hexStr) noexcept {
char copy[17];
std::strncpy(copy, hexStr, 16);
copy[16] = '\0';
assign(std::strtoull(copy, nullptr, 16));
}
static constexpr size_t BinarySize() noexcept { return 8; }
};
/** PAK 128-bit Unique ID */
class UniqueID128 : public BigDNA {
public:
union Value {
uint64_t id[2];
#if __SSE__
__m128i id128;
#endif
};
private:
Value m_id;
public:
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
UniqueID128() noexcept {
m_id.id[0] = 0xffffffffffffffff;
m_id.id[1] = 0xffffffffffffffff;
}
UniqueID128(uint64_t idin) noexcept {
m_id.id[0] = idin;
m_id.id[1] = 0;
}
bool isValid() const noexcept {
return m_id.id[0] != 0xffffffffffffffff && m_id.id[0] != 0 && m_id.id[1] != 0xffffffffffffffff && m_id.id[1] != 0;
}
UniqueID128& operator=(const hecl::ProjectPath& path) noexcept {
m_id.id[0] = path.hash().val64();
m_id.id[1] = 0;
return *this;
}
UniqueID128(const hecl::ProjectPath& path) noexcept { *this = path; }
bool operator!=(const UniqueID128& other) const noexcept {
#if __SSE__
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask != 0xffff;
#else
return (m_id.id[0] != other.m_id.id[0]) || (m_id.id[1] != other.m_id.id[1]);
#endif
}
bool operator==(const UniqueID128& other) const noexcept {
#if __SSE__
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask == 0xffff;
#else
return (m_id.id[0] == other.m_id.id[0]) && (m_id.id[1] == other.m_id.id[1]);
#endif
}
bool operator<(const UniqueID128& other) const noexcept {
return m_id.id[0] < other.m_id.id[0] || (m_id.id[0] == other.m_id.id[0] && m_id.id[1] < other.m_id.id[1]);
}
void clear() noexcept {
m_id.id[0] = 0xffffffffffffffff;
m_id.id[1] = 0xffffffffffffffff;
}
uint64_t toUint64() const noexcept { return m_id.id[0]; }
uint64_t toHighUint64() const noexcept { return m_id.id[0]; }
uint64_t toLowUint64() const noexcept { return m_id.id[1]; }
std::string toString() const;
static constexpr size_t BinarySize() noexcept { return 16; }
};
/** Casts ID type to its null-zero equivalent */
template <class T>
using CastIDToZero = typename std::conditional_t<std::is_same_v<T, UniqueID32>, UniqueID32Zero, T>;
/** Word Bitmap reader/writer */
class WordBitmap {
std::vector<atUint32> m_words;
size_t m_bitCount = 0;
public:
void read(athena::io::IStreamReader& reader, size_t bitCount);
void write(athena::io::IStreamWriter& writer) const;
void reserve(size_t bitCount) { m_words.reserve((bitCount + 31) / 32); }
void binarySize(size_t& __isz) const;
size_t getBitCount() const { return m_bitCount; }
bool getBit(size_t idx) const {
size_t wordIdx = idx / 32;
if (wordIdx >= m_words.size())
return false;
size_t wordCur = idx % 32;
return (m_words[wordIdx] >> wordCur) & 0x1;
}
void setBit(size_t idx) {
size_t wordIdx = idx / 32;
while (wordIdx >= m_words.size())
m_words.push_back(0);
size_t wordCur = idx % 32;
m_words[wordIdx] |= (1 << wordCur);
m_bitCount = std::max(m_bitCount, idx + 1);
}
void unsetBit(size_t idx) {
size_t wordIdx = idx / 32;
while (wordIdx >= m_words.size())
m_words.push_back(0);
size_t wordCur = idx % 32;
m_words[wordIdx] &= ~(1 << wordCur);
m_bitCount = std::max(m_bitCount, idx + 1);
}
void clear() {
m_words.clear();
m_bitCount = 0;
}
class Iterator {
friend class WordBitmap;
const WordBitmap& m_bmp;
size_t m_idx = 0;
Iterator(const WordBitmap& bmp, size_t idx) : m_bmp(bmp), m_idx(idx) {}
public:
using iterator_category = std::forward_iterator_tag;
using value_type = bool;
using difference_type = std::ptrdiff_t;
using pointer = bool*;
using reference = bool&;
Iterator& operator++() {
++m_idx;
return *this;
}
bool operator*() const { return m_bmp.getBit(m_idx); }
bool operator!=(const Iterator& other) const { return m_idx != other.m_idx; }
};
Iterator begin() const { return Iterator(*this, 0); }
Iterator end() const { return Iterator(*this, m_bitCount); }
};
/** Resource cooker function */
using ResCooker = std::function<bool(const hecl::ProjectPath&, const hecl::ProjectPath&)>;
/** Mappings of resources involved in extracting characters */
template <class IDType>
struct CharacterAssociations {
struct RigPair {
IDType cskr, cinf;
};
struct ModelRigPair {
IDType cinf, cmdl;
};
/* CMDL -> (CSKR, CINF) */
std::unordered_map<IDType, RigPair> m_cmdlRigs;
/* CSKR -> ANCS */
std::unordered_map<IDType, std::pair<IDType, std::string>> m_cskrToCharacter;
/* ANCS -> (CINF, CMDL) */
std::unordered_multimap<IDType, std::pair<ModelRigPair, std::string>> m_characterToAttachmentRigs;
using MultimapIteratorPair =
std::pair<typename std::unordered_multimap<IDType, std::pair<ModelRigPair, std::string>>::const_iterator,
typename std::unordered_multimap<IDType, std::pair<ModelRigPair, std::string>>::const_iterator>;
void addAttachmentRig(IDType character, IDType cinf, IDType cmdl, const char* name) {
auto range = m_characterToAttachmentRigs.equal_range(character);
for (auto it = range.first; it != range.second; ++it)
if (it->second.second == name)
return;
m_characterToAttachmentRigs.insert(std::make_pair(character, std::make_pair(ModelRigPair{cinf, cmdl}, name)));
}
};
hecl::ProjectPath GetPathBeginsWith(const hecl::DirectoryEnumerator& dEnum, const hecl::ProjectPath& parentPath,
std::string_view test);
inline hecl::ProjectPath GetPathBeginsWith(const hecl::ProjectPath& parentPath, std::string_view test) {
return GetPathBeginsWith(hecl::DirectoryEnumerator(parentPath.getAbsolutePath()), parentPath, test);
}
} // namespace DataSpec
/* Hash template-specializations for UniqueID types */
namespace std {
template <>
struct hash<DataSpec::DNAFourCC> {
size_t operator()(const DataSpec::DNAFourCC& fcc) const noexcept { return fcc.toUint32(); }
};
template <>
struct hash<DataSpec::UniqueID32> {
size_t operator()(const DataSpec::UniqueID32& id) const noexcept { return id.toUint32(); }
};
template <>
struct hash<DataSpec::UniqueID64> {
size_t operator()(const DataSpec::UniqueID64& id) const noexcept { return id.toUint64(); }
};
template <>
struct hash<DataSpec::UniqueID128> {
size_t operator()(const DataSpec::UniqueID128& id) const noexcept { return id.toHighUint64() ^ id.toLowUint64(); }
};
} // namespace std
FMT_CUSTOM_FORMATTER(DataSpec::UniqueID32, "{:08X}", obj.toUint32())
FMT_CUSTOM_FORMATTER(DataSpec::UniqueID32Zero, "{:08X}", obj.toUint32())
FMT_CUSTOM_FORMATTER(DataSpec::UniqueID64, "{:016X}", obj.toUint64())
FMT_CUSTOM_FORMATTER(DataSpec::UniqueID128, "{:016X}{:016X}", obj.toHighUint64(), obj.toLowUint64())

View File

@ -1,51 +0,0 @@
#include "DataSpec/DNACommon/DPSC.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNAParticle {
template struct PPImpl<_DPSM<UniqueID32>>;
template struct PPImpl<_DPSM<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_DPSM<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_DPSM<UniqueID64>>)
template <>
std::string_view PPImpl<_DPSM<UniqueID32>>::DNAType() {
return "DPSM<UniqueID32>"sv;
}
template <>
std::string_view PPImpl<_DPSM<UniqueID64>>::DNAType() {
return "DPSM<UniqueID64>"sv;
}
template <class IDType>
bool ExtractDPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
DPSM<IDType> dpsm;
dpsm.read(rs);
athena::io::ToYAMLStream(dpsm, writer);
return true;
}
return false;
}
template bool ExtractDPSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractDPSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDPSM(const DPSM<IDType>& dpsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
dpsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteDPSM<UniqueID32>(const DPSM<UniqueID32>& dpsm, const hecl::ProjectPath& outPath);
template bool WriteDPSM<UniqueID64>(const DPSM<UniqueID64>& dpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,28 +0,0 @@
#ifndef ENTRY
#define ENTRY(name, identifier)
#endif
ENTRY('1LFT', x0_quad.x0_LFT)
ENTRY('1SZE', x0_quad.x4_SZE)
ENTRY('1ROT', x0_quad.x8_ROT)
ENTRY('1OFF', x0_quad.xc_OFF)
ENTRY('1CLR', x0_quad.x10_CLR)
ENTRY('1TEX', x0_quad.x14_TEX)
ENTRY('1ADD', x0_quad.x18_ADD)
ENTRY('2LFT', x1c_quad.x0_LFT)
ENTRY('2SZE', x1c_quad.x4_SZE)
ENTRY('2ROT', x1c_quad.x8_ROT)
ENTRY('2OFF', x1c_quad.xc_OFF)
ENTRY('2CLR', x1c_quad.x10_CLR)
ENTRY('2TEX', x1c_quad.x14_TEX)
ENTRY('2ADD', x1c_quad.x18_ADD)
ENTRY('DMDL', x38_DMDL)
ENTRY('DLFT', x48_DLFT)
ENTRY('DMOP', x4c_DMOP)
ENTRY('DMRT', x50_DMRT)
ENTRY('DMSC', x54_DMSC)
ENTRY('DMCL', x58_DMCL)
ENTRY('DMAB', x5c_24_DMAB)
ENTRY('DMOO', x5c_25_DMOO)
#undef ENTRY

View File

@ -1,76 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/ParticleCommon.hpp"
#include <athena/FileWriter.hpp>
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAParticle {
template <class IDType>
struct _DPSM {
static constexpr ParticleType Type = ParticleType::DPSM;
struct SQuadDescr {
IntElementFactory x0_LFT;
RealElementFactory x4_SZE;
RealElementFactory x8_ROT;
VectorElementFactory xc_OFF;
ColorElementFactory x10_CLR;
UVElementFactory<IDType> x14_TEX;
bool x18_ADD = false;
};
SQuadDescr x0_quad;
SQuadDescr x1c_quad;
ChildResourceFactory<IDType> x38_DMDL;
IntElementFactory x48_DLFT;
VectorElementFactory x4c_DMOP;
VectorElementFactory x50_DMRT;
VectorElementFactory x54_DMSC;
ColorElementFactory x58_DMCL;
bool x5c_24_DMAB = false;
bool x5c_25_DMOO = false;
template <typename _Func>
void constexpr Enumerate(_Func f) {
#define ENTRY(name, identifier) f(FOURCC(name), identifier);
#include "DPSC.def"
}
template <typename _Func>
bool constexpr Lookup(FourCC fcc, _Func f) {
switch (fcc.toUint32()) {
#define ENTRY(name, identifier) \
case SBIG(name): \
f(identifier); \
return true;
#include "DPSC.def"
default:
return false;
}
}
};
template <class IDType>
using DPSM = PPImpl<_DPSM<IDType>>;
template <class IDType>
bool ExtractDPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDPSM(const DPSM<IDType>& dpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,258 +0,0 @@
#include "DataSpec/DNACommon/DeafBabe.hpp"
#include <cinttypes>
#include <cstddef>
#include <memory>
#include <type_traits>
#include "DataSpec/DNACommon/AROTBuilder.hpp"
#include "DataSpec/DNAMP1/DeafBabe.hpp"
#include "DataSpec/DNAMP1/DCLN.hpp"
#include "DataSpec/DNAMP2/DeafBabe.hpp"
#include <fmt/format.h>
#include <hecl/Blender/Connection.hpp>
#include <zeus/Global.hpp>
namespace DataSpec {
template <class DEAFBABE>
void DeafBabeSendToBlender(hecl::blender::PyOutStream& os, const DEAFBABE& db, bool isDcln, atInt32 idx) {
os << "material_index = []\n"
"col_bm = bmesh.new()\n";
for (const atVec3f& vert : db.verts) {
zeus::simd_floats f(vert.simd);
os.format(FMT_STRING("col_bm.verts.new(({},{},{}))\n"), f[0], f[1], f[2]);
}
os << "col_bm.verts.ensure_lookup_table()\n";
int triIdx = 0;
for (const typename DEAFBABE::Triangle& tri : db.triangleEdgeConnections) {
const typename DEAFBABE::Material& triMat = db.materials[db.triMats[triIdx++]];
const typename DEAFBABE::Edge& edge0 = db.edgeVertConnections[tri.edges[0]];
const typename DEAFBABE::Edge& edge1 = db.edgeVertConnections[tri.edges[1]];
const typename DEAFBABE::Edge& edge2 = db.edgeVertConnections[tri.edges[2]];
if (!edge0.verts[0] && !edge1.verts[0] && !edge2.verts[0])
break;
int vindices[3];
vindices[2] =
(edge1.verts[0] != edge0.verts[0] && edge1.verts[0] != edge0.verts[1]) ? edge1.verts[0] : edge1.verts[1];
if (triMat.flipFace()) {
vindices[0] = edge0.verts[1];
vindices[1] = edge0.verts[0];
} else {
vindices[0] = edge0.verts[0];
vindices[1] = edge0.verts[1];
}
os << "tri_verts = []\n";
os.format(FMT_STRING("tri_verts.append(col_bm.verts[{}])\n"), vindices[0]);
os.format(FMT_STRING("tri_verts.append(col_bm.verts[{}])\n"), vindices[1]);
os.format(FMT_STRING("tri_verts.append(col_bm.verts[{}])\n"), vindices[2]);
os.format(FMT_STRING("face = col_bm.faces.get(tri_verts)\n"
"if face is None:\n"
" face = col_bm.faces.new(tri_verts)\n"
"else:\n"
" face = face.copy()\n"
" for i in range(3):\n"
" face.verts[i].co = tri_verts[i].co\n"
" col_bm.verts.ensure_lookup_table()\n"
"face.material_index = select_material(0x{:016X}"
")\n"
"face.smooth = False\n"
"\n"),
atUint64(triMat.material));
}
db.insertNoClimb(os);
if (isDcln)
os.format(FMT_STRING("col_mesh = bpy.data.meshes.new('CMESH_{}')\n"), idx);
else
os << "col_mesh = bpy.data.meshes.new('CMESH')\n";
os << "col_bm.to_mesh(col_mesh)\n"
"col_mesh_obj = bpy.data.objects.new(col_mesh.name, col_mesh)\n"
"\n"
"for mat_name in material_index:\n"
" mat = material_dict[mat_name]\n"
" col_mesh.materials.append(mat)\n"
"\n"
"if 'Collision' not in bpy.data.collections:\n"
" coll = bpy.data.collections.new('Collision')\n"
" bpy.context.scene.collection.children.link(coll)\n"
"else:\n"
" coll = bpy.data.collections['Collision']\n"
"coll.objects.link(col_mesh_obj)\n"
"bpy.context.view_layer.objects.active = col_mesh_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"bpy.ops.mesh.tris_convert_to_quads()\n"
"bpy.ops.object.mode_set(mode='OBJECT')\n"
"bpy.context.view_layer.objects.active = None\n"
"col_mesh_obj.display_type = 'SOLID'\n"
"\n";
}
template void DeafBabeSendToBlender<DNAMP1::DeafBabe>(hecl::blender::PyOutStream& os, const DNAMP1::DeafBabe& db,
bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP2::DeafBabe>(hecl::blender::PyOutStream& os, const DNAMP2::DeafBabe& db,
bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP1::DCLN::Collision>(hecl::blender::PyOutStream& os,
const DNAMP1::DCLN::Collision& db, bool isDcln,
atInt32 idx);
template <class DEAFBABE>
static void PopulateAreaFields(
DEAFBABE& db, const hecl::blender::ColMesh& colMesh, const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DeafBabe>::value || std::is_same<DEAFBABE, DNAMP2::DeafBabe>::value,
int>* = 0) {
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
db.unk1 = 0x1000000;
size_t dbSize = 0;
db.binarySize(dbSize);
db.length = dbSize - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
}
template <class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db, const hecl::blender::ColMesh& colMesh, const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DCLN::Collision>::value, int>* = 0) {
db.magic = 0xDEAFBABE;
db.version = 2;
db.memSize = 0;
}
class MaterialPool {
std::unordered_map<u64, int> m_materials;
public:
template <class M, class V>
int AddOrLookup(const M& mat, V& vec) {
auto search = m_materials.find(mat.material);
if (search != m_materials.end())
return search->second;
auto idx = int(vec.size());
vec.push_back(mat);
m_materials[mat.material] = idx;
return idx;
}
};
template <class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::blender::ColMesh& colMesh) {
using BlendMat = hecl::blender::ColMesh::Material;
auto MakeMat = [](const BlendMat& mat, bool flipFace) -> typename DEAFBABE::Material {
typename DEAFBABE::Material dbMat = {};
dbMat.setUnknown(mat.unknown);
dbMat.setSurfaceStone(mat.surfaceStone);
dbMat.setSurfaceMetal(mat.surfaceMetal);
dbMat.setSurfaceGrass(mat.surfaceGrass);
dbMat.setSurfaceIce(mat.surfaceIce);
dbMat.setPillar(mat.pillar);
dbMat.setSurfaceMetalGrating(mat.surfaceMetalGrating);
dbMat.setSurfacePhazon(mat.surfacePhazon);
dbMat.setSurfaceDirt(mat.surfaceDirt);
dbMat.setSurfaceLava(mat.surfaceLava);
dbMat.setSurfaceSPMetal(mat.surfaceSPMetal);
dbMat.setSurfaceLavaStone(mat.surfaceLavaStone);
dbMat.setSurfaceSnow(mat.surfaceSnow);
dbMat.setSurfaceMudSlow(mat.surfaceMudSlow);
dbMat.setSurfaceFabric(mat.surfaceFabric);
dbMat.setHalfPipe(mat.halfPipe);
dbMat.setSurfaceMud(mat.surfaceMud);
dbMat.setSurfaceGlass(mat.surfaceGlass);
dbMat.setUnused3(mat.unused3);
dbMat.setUnused4(mat.unused4);
dbMat.setSurfaceShield(mat.surfaceShield);
dbMat.setSurfaceSand(mat.surfaceSand);
dbMat.setSurfaceMothOrSeedOrganics(mat.surfaceMothOrSeedOrganics);
dbMat.setSurfaceWeb(mat.surfaceWeb);
dbMat.setProjectilePassthrough(mat.projPassthrough);
dbMat.setSolid(mat.solid);
dbMat.setNoPlatformCollision(mat.noPlatformCollision);
dbMat.setCameraPassthrough(mat.camPassthrough);
dbMat.setSurfaceWood(mat.surfaceWood);
dbMat.setSurfaceOrganic(mat.surfaceOrganic);
dbMat.setNoEdgeCollision(mat.noEdgeCollision);
dbMat.setSurfaceRubber(mat.surfaceRubber);
dbMat.setSeeThrough(mat.seeThrough);
dbMat.setScanPassthrough(mat.scanPassthrough);
dbMat.setAiPassthrough(mat.aiPassthrough);
dbMat.setCeiling(mat.ceiling);
dbMat.setWall(mat.wall);
dbMat.setFloor(mat.floor);
dbMat.setAiBlock(mat.aiBlock);
dbMat.setJumpNotAllowed(mat.jumpNotAllowed);
dbMat.setSpiderBall(mat.spiderBall);
dbMat.setScrewAttackWallJump(mat.screwAttackWallJump);
dbMat.setFlipFace(flipFace);
return dbMat;
};
MaterialPool matPool;
db.materials.reserve(colMesh.materials.size() * 2);
zeus::CAABox fullAABB;
db.verts.reserve(colMesh.verts.size());
db.vertMats.resize(colMesh.verts.size());
for (const auto& vert : colMesh.verts) {
fullAABB.accumulateBounds(zeus::CVector3f(vert));
db.verts.push_back(vert);
}
db.vertMatsCount = colMesh.verts.size();
db.vertCount = colMesh.verts.size();
db.edgeVertConnections.reserve(colMesh.edges.size());
db.edgeMats.resize(colMesh.edges.size());
for (const auto& edge : colMesh.edges) {
db.edgeVertConnections.emplace_back();
db.edgeVertConnections.back().verts[0] = edge.verts[0];
db.edgeVertConnections.back().verts[1] = edge.verts[1];
}
db.edgeMatsCount = colMesh.edges.size();
db.edgeVertsCount = colMesh.edges.size();
db.triMats.reserve(colMesh.trianges.size());
db.triangleEdgeConnections.reserve(colMesh.trianges.size());
for (const auto& tri : colMesh.trianges) {
int triMatIdx = matPool.AddOrLookup(MakeMat(colMesh.materials[tri.matIdx], tri.flip), db.materials);
db.triMats.push_back(triMatIdx);
db.triangleEdgeConnections.emplace_back();
db.triangleEdgeConnections.back().edges[0] = tri.edges[0];
db.triangleEdgeConnections.back().edges[1] = tri.edges[1];
db.triangleEdgeConnections.back().edges[2] = tri.edges[2];
for (int e = 0; e < 3; ++e) {
db.edgeMats[tri.edges[e]] = triMatIdx;
for (int v = 0; v < 2; ++v)
db.vertMats[colMesh.edges[e].verts[v]] = triMatIdx;
}
}
db.triMatsCount = colMesh.trianges.size();
db.triangleEdgesCount = colMesh.trianges.size() * 3;
db.materialCount = db.materials.size();
PopulateAreaFields(db, colMesh, fullAABB);
}
template void DeafBabeBuildFromBlender<DNAMP1::DeafBabe>(DNAMP1::DeafBabe& db, const hecl::blender::ColMesh& colMesh);
template void DeafBabeBuildFromBlender<DNAMP2::DeafBabe>(DNAMP2::DeafBabe& db, const hecl::blender::ColMesh& colMesh);
template void DeafBabeBuildFromBlender<DNAMP1::DCLN::Collision>(DNAMP1::DCLN::Collision& db,
const hecl::blender::ColMesh& colMesh);
} // namespace DataSpec

View File

@ -1,20 +0,0 @@
#pragma once
#include <athena/Types.hpp>
namespace hecl::blender {
class PyOutStream;
struct ColMesh;
} // namespace hecl::blender
namespace DataSpec {
enum class BspNodeType : atUint32 { Invalid, Branch, Leaf };
template <class DEAFBABE>
void DeafBabeSendToBlender(hecl::blender::PyOutStream& os, const DEAFBABE& db, bool isDcln = false, atInt32 idx = -1);
template <class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::blender::ColMesh& colMesh);
} // namespace DataSpec

View File

@ -1,18 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace DataSpec::DNACommon {
struct EGMC : public BigDNA {
AT_DECL_DNA
Value<atUint32> count;
struct Object : BigDNA {
AT_DECL_DNA
Value<atUint32> mesh;
Value<atUint32> instanceId;
};
Vector<Object, AT_DNA_COUNT(count)> objects;
};
} // namespace DataSpec::DNACommon

View File

@ -1,51 +0,0 @@
#include "DataSpec/DNACommon/ELSC.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNAParticle {
template struct PPImpl<_ELSM<UniqueID32>>;
template struct PPImpl<_ELSM<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_ELSM<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_ELSM<UniqueID64>>)
template <>
std::string_view ELSM<UniqueID32>::DNAType() {
return "ELSM<UniqueID32>"sv;
}
template <>
std::string_view ELSM<UniqueID64>::DNAType() {
return "ELSM<UniqueID64>"sv;
}
template <class IDType>
bool ExtractELSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
ELSM<IDType> elsm;
elsm.read(rs);
athena::io::ToYAMLStream(elsm, writer);
return true;
}
return false;
}
template bool ExtractELSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractELSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteELSM(const ELSM<IDType>& elsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
elsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteELSM<UniqueID32>(const ELSM<UniqueID32>& gpsm, const hecl::ProjectPath& outPath);
template bool WriteELSM<UniqueID64>(const ELSM<UniqueID64>& gpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,56 +0,0 @@
#ifndef ENTRY
#define ENTRY(name, identifier)
#endif
#ifndef INT_ENTRY
#define INT_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef REAL_ENTRY
#define REAL_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef COLOR_ENTRY
#define COLOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef EMITTER_ENTRY
#define EMITTER_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef RES_ENTRY
#define RES_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef BOOL_ENTRY
#define BOOL_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
INT_ENTRY('LIFE', x0_LIFE)
INT_ENTRY('SLIF', x4_SLIF)
REAL_ENTRY('GRAT', x8_GRAT)
INT_ENTRY('SCNT', xc_SCNT)
INT_ENTRY('SSEG', x10_SSEG)
COLOR_ENTRY('COLR', x14_COLR)
EMITTER_ENTRY('IEMT', x18_IEMT)
EMITTER_ENTRY('FEMT', x1c_FEMT)
REAL_ENTRY('AMPL', x20_AMPL)
REAL_ENTRY('AMPD', x24_AMPD)
REAL_ENTRY('LWD1', x28_LWD1)
REAL_ENTRY('LWD2', x2c_LWD2)
REAL_ENTRY('LWD3', x30_LWD3)
COLOR_ENTRY('LCL1', x34_LCL1)
COLOR_ENTRY('LCL2', x38_LCL2)
COLOR_ENTRY('LCL3', x3c_LCL3)
RES_ENTRY('SSWH', x40_SSWH)
RES_ENTRY('GPSM', x50_GPSM)
RES_ENTRY('EPSM', x60_EPSM)
BOOL_ENTRY('ZERY', x70_ZERY)
#undef ENTRY
#undef INT_ENTRY
#undef REAL_ENTRY
#undef COLOR_ENTRY
#undef EMITTER_ENTRY
#undef RES_ENTRY
#undef BOOL_ENTRY

View File

@ -1,56 +0,0 @@
#pragma once
#include <vector>
#include "DataSpec/DNACommon/ParticleCommon.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
#include <athena/FileWriter.hpp>
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAParticle {
template <class IDType>
struct _ELSM {
static constexpr ParticleType Type = ParticleType::ELSM;
#define INT_ENTRY(name, identifier) IntElementFactory identifier;
#define REAL_ENTRY(name, identifier) RealElementFactory identifier;
#define COLOR_ENTRY(name, identifier) ColorElementFactory identifier;
#define EMITTER_ENTRY(name, identifier) EmitterElementFactory identifier;
#define RES_ENTRY(name, identifier) ChildResourceFactory<IDType> identifier;
#define BOOL_ENTRY(name, identifier) bool identifier = false;
#include "ELSC.def"
template <typename _Func>
void constexpr Enumerate(_Func f) {
#define ENTRY(name, identifier) f(FOURCC(name), identifier);
#include "ELSC.def"
}
template <typename _Func>
bool constexpr Lookup(FourCC fcc, _Func f) {
switch (fcc.toUint32()) {
#define ENTRY(name, identifier) \
case SBIG(name): \
f(identifier); \
return true;
#include "ELSC.def"
default:
return false;
}
}
};
template <class IDType>
using ELSM = PPImpl<_ELSM<IDType>>;
template <class IDType>
bool ExtractELSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteELSM(const ELSM<IDType>& elsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,235 +0,0 @@
#include "DataSpec/DNACommon/FONT.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
#include <logvisor/logvisor.hpp>
namespace DataSpec::DNAFont {
logvisor::Module LogModule("DataSpec::DNAFont");
template <class IDType>
void FONT<IDType>::_read(athena::io::IStreamReader& __dna_reader) {
/* magic */
DNAFourCC magic;
magic.read(__dna_reader);
if (magic != SBIG('FONT')) {
LogModule.report(logvisor::Fatal, FMT_STRING("Invalid FONT magic '{}'"), magic);
return;
}
/* version */
version = __dna_reader.readUint32Big();
/* unknown1 */
unknown1 = __dna_reader.readUint32Big();
/* lineHeight */
lineHeight = __dna_reader.readInt32Big();
/* verticalOffset */
verticalOffset = __dna_reader.readInt32Big();
/* lineMargin */
lineMargin = __dna_reader.readInt32Big();
/* unknown2 */
unknown2 = __dna_reader.readBool();
/* unknown3 */
unknown3 = __dna_reader.readBool();
/* unknown4 */
unknown4 = __dna_reader.readUint32Big();
/* fontSize */
fontSize = __dna_reader.readUint32Big();
/* name */
name = __dna_reader.readString(-1);
/* textureId */
textureId.read(__dna_reader);
/* textureFormat */
textureFormat = __dna_reader.readUint32Big();
/* glyphCount */
glyphCount = __dna_reader.readUint32Big();
/* glyphs */
for (atUint32 i = 0; i < glyphCount; i++) {
if (version < 4)
glyphs.emplace_back(new GlyphMP1);
else
glyphs.emplace_back(new GlyphMP2);
glyphs.back()->read(__dna_reader);
}
/* kerningInfoCount */
kerningInfoCount = __dna_reader.readUint32Big();
/* kerningInfo */
__dna_reader.enumerate(kerningInfo, kerningInfoCount);
}
template <class IDType>
void FONT<IDType>::_write(athena::io::IStreamWriter& __dna_writer) const {
/* magic */
__dna_writer.writeBytes((atInt8*)"FONT", 4);
/* version */
__dna_writer.writeUint32Big(version);
/* unknown1 */
__dna_writer.writeUint32Big(unknown1);
/* lineHeight */
__dna_writer.writeInt32Big(lineHeight);
/* verticalOffset */
__dna_writer.writeInt32Big(verticalOffset);
/* lineMargin */
__dna_writer.writeInt32Big(lineMargin);
/* unknown2 */
__dna_writer.writeBool(unknown2);
/* unknown3 */
__dna_writer.writeBool(unknown3);
/* unknown4 */
__dna_writer.writeUint32Big(unknown4);
/* fontSize */
__dna_writer.writeUint32Big(fontSize);
/* name */
__dna_writer.writeString(name, -1);
/* textureId */
textureId.write(__dna_writer);
/* textureFormat */
__dna_writer.writeUint32Big(textureFormat);
/* glyphCount */
__dna_writer.writeUint32Big(glyphCount);
/* glyphs */
for (const std::unique_ptr<IGlyph>& glyph : glyphs)
glyph->write(__dna_writer);
/* kerningInfoCount */
__dna_writer.writeUint32Big(kerningInfoCount);
/* kerningInfo */
__dna_writer.enumerate(kerningInfo);
}
template <class IDType>
void FONT<IDType>::_read(athena::io::YAMLDocReader& __dna_docin) {
/* version */
version = __dna_docin.readUint32("version");
/* unknown1 */
unknown1 = __dna_docin.readUint32("unknown1");
/* lineHeight */
lineHeight = __dna_docin.readInt32("lineHeight");
/* verticalOffset */
verticalOffset = __dna_docin.readInt32("verticalOffset");
/* lineMargin */
lineMargin = __dna_docin.readInt32("lineMargin");
/* unknown2 */
unknown2 = __dna_docin.readBool("unknown2");
/* unknown3 */
unknown3 = __dna_docin.readBool("unknown3");
/* unknown4 */
unknown4 = __dna_docin.readUint32("unknown4");
/* fontSize */
fontSize = __dna_docin.readUint32("fontSize");
/* name */
name = __dna_docin.readString("name");
/* textureId */
__dna_docin.enumerate("textureId", textureId);
/* textureFormat */
textureFormat = __dna_docin.readUint32("textureFormat");
/* glyphCount */
/* glyphs */
size_t count;
if (auto v = __dna_docin.enterSubVector("glyphs", count)) {
glyphCount = count;
for (atUint32 i = 0; i < glyphCount; i++) {
if (version < 4)
glyphs.emplace_back(new GlyphMP1);
else
glyphs.emplace_back(new GlyphMP2);
if (auto rec = __dna_docin.enterSubRecord())
glyphs.back()->read(__dna_docin);
}
}
/* kerningInfoCount squelched */
/* kerningInfo */
kerningInfoCount = __dna_docin.enumerate("kerningInfo", kerningInfo);
}
template <class IDType>
void FONT<IDType>::_write(athena::io::YAMLDocWriter& __dna_docout) const {
/* version */
__dna_docout.writeUint32("version", version);
/* unknown1 */
__dna_docout.writeUint32("unknown1", unknown1);
/* lineHeight */
__dna_docout.writeInt32("lineHeight", lineHeight);
/* verticalOffset */
__dna_docout.writeInt32("verticalOffset", verticalOffset);
/* lineMargin */
__dna_docout.writeInt32("lineMargin", lineMargin);
/* unknown2 */
__dna_docout.writeBool("unknown2", unknown2);
/* unknown3 */
__dna_docout.writeBool("unknown3", unknown3);
/* unknown4 */
__dna_docout.writeUint32("unknown4", unknown4);
/* fontSize */
__dna_docout.writeUint32("fontSize", fontSize);
/* name */
__dna_docout.writeString("name", name);
/* textureId */
__dna_docout.enumerate("textureId", textureId);
/* textureFormat */
__dna_docout.writeUint32("textureFormat", textureFormat);
/* glyphCount squelched */
/* glyphs */
if (auto v = __dna_docout.enterSubVector("glyphs"))
for (const std::unique_ptr<IGlyph>& glyph : glyphs)
if (auto rec = __dna_docout.enterSubRecord())
glyph->write(__dna_docout);
/* kerningInfoCount squelched */
/* kerningInfo */
__dna_docout.enumerate("kerningInfo", kerningInfo);
}
template <>
std::string_view FONT<UniqueID32>::DNAType() {
return "FONT<UniqueID32>"sv;
}
template <>
std::string_view FONT<UniqueID64>::DNAType() {
return "FONT<UniqueID64>"sv;
}
template <class IDType>
void FONT<IDType>::_binarySize(size_t& __isz) const {
__isz += name.size() + 1;
textureId.binarySize(__isz);
for (const std::unique_ptr<IGlyph>& glyph : glyphs)
glyph->binarySize(__isz);
for (const KerningInfo& k : kerningInfo)
k.binarySize(__isz);
__isz += 46;
}
AT_SUBSPECIALIZE_DNA_YAML(FONT<UniqueID32>)
AT_SUBSPECIALIZE_DNA_YAML(FONT<UniqueID64>)
template <class IDType>
bool ExtractFONT(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
FONT<IDType> font;
font.read(rs);
athena::io::ToYAMLStream(font, writer);
return true;
}
return false;
}
template bool ExtractFONT<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractFONT<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteFONT(const FONT<IDType>& font, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
font.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteFONT<UniqueID32>(const FONT<UniqueID32>& font, const hecl::ProjectPath& outPath);
template bool WriteFONT<UniqueID64>(const FONT<UniqueID64>& font, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAFont

View File

@ -1,127 +0,0 @@
#pragma once
#include <memory>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include <athena/FileWriter.hpp>
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAFont {
struct GlyphRect : BigDNA {
AT_DECL_DNA_YAML
Value<float> left;
Value<float> top;
Value<float> right;
Value<float> bottom;
};
struct IGlyph : BigDNAVYaml {
AT_DECL_DNA_YAMLV
Value<atUint16> m_character;
GlyphRect m_glyphRect;
atUint16 character() const { return m_character; }
float left() const { return m_glyphRect.left; }
float top() const { return m_glyphRect.top; }
float right() const { return m_glyphRect.right; }
float bottom() const { return m_glyphRect.bottom; }
GlyphRect rect() const { return m_glyphRect; }
virtual atInt32 layer() const { return 0; }
virtual atInt32 leftPadding() const = 0;
virtual atInt32 advance() const = 0;
virtual atInt32 rightPadding() const = 0;
virtual atInt32 width() const = 0;
virtual atInt32 height() const = 0;
virtual atInt32 baseline() const = 0;
virtual atInt32 kerningIndex() const = 0;
};
struct GlyphMP1 : IGlyph {
AT_DECL_DNA_YAMLV
Value<atInt32> m_leftPadding;
Value<atInt32> m_advance;
Value<atInt32> m_rightPadding;
Value<atInt32> m_width;
Value<atInt32> m_height;
Value<atInt32> m_baseline;
Value<atInt32> m_kerningIndex;
atInt32 leftPadding() const override { return m_leftPadding; }
atInt32 advance() const override { return m_advance; }
atInt32 rightPadding() const override { return m_rightPadding; }
atInt32 width() const override { return m_width; }
atInt32 height() const override { return m_height; }
atInt32 baseline() const override { return m_baseline; }
atInt32 kerningIndex() const override { return m_kerningIndex; }
};
struct GlyphMP2 : IGlyph {
AT_DECL_DNA_YAMLV
Value<atInt8> m_layer;
Value<atInt8> m_leftPadding;
Value<atInt8> m_advance;
Value<atInt8> m_rightPadding;
Value<atInt8> m_width;
Value<atInt8> m_height;
Value<atInt8> m_baseline;
Value<atInt16> m_kerningIndex;
atInt32 layer() const override { return m_layer; }
atInt32 leftPadding() const override { return m_leftPadding; }
atInt32 advance() const override { return m_advance; }
atInt32 rightPadding() const override { return m_rightPadding; }
atInt32 width() const override { return m_width; }
atInt32 height() const override { return m_height; }
atInt32 baseline() const override { return m_baseline; }
atInt32 kerningIndex() const override { return m_kerningIndex; }
};
struct KerningInfo : BigDNA {
AT_DECL_DNA_YAML
Value<atUint16> thisChar;
Value<atUint16> nextChar;
Value<atInt32> adjust;
};
template <class IDType>
struct AT_SPECIALIZE_PARMS(DataSpec::UniqueID32, DataSpec::UniqueID64) FONT : BigDNA {
AT_DECL_EXPLICIT_DNA_YAML
AT_SUBDECL_DNA
Value<atUint32> version;
Value<atUint32> unknown1;
Value<atInt32> lineHeight;
Value<atInt32> verticalOffset;
Value<atInt32> lineMargin;
Value<bool> unknown2;
Value<bool> unknown3;
Value<atUint32> unknown4;
Value<atUint32> fontSize; // in points
String<-1> name;
Value<IDType> textureId;
Value<atUint32> textureFormat;
Value<atUint32> glyphCount;
std::vector<std::unique_ptr<IGlyph>> glyphs;
Value<atUint32> kerningInfoCount;
Vector<KerningInfo, AT_DNA_COUNT(kerningInfoCount)> kerningInfo;
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {
g_curSpec->flattenDependencies(textureId, pathsOut);
}
};
template <class IDType>
bool ExtractFONT(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteFONT(const FONT<IDType>& font, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAFont

View File

@ -1,82 +0,0 @@
#include "DataSpec/DNACommon/FSM2.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
#include <athena/FileWriter.hpp>
#include <athena/Global.hpp>
#include <athena/IStreamWriter.hpp>
#include <logvisor/logvisor.hpp>
namespace DataSpec::DNAFSM2 {
logvisor::Module LogDNAFSM2("DataSpec::DNAFSM2");
template <class IDType>
template <class Op>
void FSM2<IDType>::Enumerate(typename Op::StreamT& s) {
Do<Op>(athena::io::PropId{"header"}, header, s);
if (header.magic != SBIG('FSM2')) {
LogDNAFSM2.report(logvisor::Fatal, FMT_STRING("Invalid FSM2 magic '{}' expected 'FSM2'"), header.magic);
return;
}
if (header.version == 1) {
if (!detail)
detail.reset(new FSMV1);
Do<Op>(athena::io::PropId{"detail"}, static_cast<FSMV1&>(*detail), s);
} else if (header.version == 2) {
if (!detail)
detail.reset(new FSMV2);
Do<Op>(athena::io::PropId{"detail"}, static_cast<FSMV2&>(*detail), s);
} else {
LogDNAFSM2.report(logvisor::Fatal, FMT_STRING("Invalid FSM2 version '{}'"), header.version);
return;
}
}
AT_SPECIALIZE_DNA(FSM2<UniqueID32>)
AT_SPECIALIZE_DNA(FSM2<UniqueID64>)
template <>
std::string_view FSM2<UniqueID32>::DNAType() {
return "FSM2<UniqueID32>"sv;
}
template <>
std::string_view FSM2<UniqueID64>::DNAType() {
return "FSM2<UniqueID64>"sv;
}
template struct FSM2<UniqueID32>;
template struct FSM2<UniqueID64>;
template <class IDType>
bool ExtractFSM2(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
FSM2<IDType> fsm2;
fsm2.read(rs);
athena::io::ToYAMLStream(fsm2, writer);
return true;
}
return false;
}
template bool ExtractFSM2<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractFSM2<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteFSM2(const FSM2<IDType>& fsm2, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
fsm2.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteFSM2<UniqueID32>(const FSM2<UniqueID32>& fsm2, const hecl::ProjectPath& outPath);
template bool WriteFSM2<UniqueID64>(const FSM2<UniqueID64>& fsm2, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAFSM2

View File

@ -1,147 +0,0 @@
#pragma once
#include <memory>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include <athena/DNA.hpp>
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAFSM2 {
struct IFSM : BigDNAVYaml {
Delete _d;
};
template <class IDType>
struct AT_SPECIALIZE_PARMS(DataSpec::UniqueID32, DataSpec::UniqueID64) FSM2 : BigDNA {
struct Header : BigDNA {
AT_DECL_DNA_YAML
DNAFourCC magic = FOURCC('FSM2');
Value<atUint32> version;
} header;
struct CommonStruct : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknown;
};
struct FSMV1 : IFSM {
AT_DECL_DNA_YAMLV
Value<atUint32> stateCount;
Value<atUint32> unknown1Count;
Value<atUint32> unknown2Count;
Value<atUint32> unknown3Count;
struct State : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknownCount;
Vector<CommonStruct, AT_DNA_COUNT(unknownCount)> unknown;
};
struct Unknown1 : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<float> unknown1;
Value<atUint32> unknown2Count;
Vector<CommonStruct, AT_DNA_COUNT(unknown2Count)> unknown2;
Value<atUint8> unknown3;
};
struct Unknown2 : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknownCount;
Vector<CommonStruct, AT_DNA_COUNT(unknownCount)> unknown;
};
struct Unknown3 : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknownCount;
Vector<CommonStruct, AT_DNA_COUNT(unknownCount)> unknown;
Value<IDType> fsmId;
};
Vector<State, AT_DNA_COUNT(stateCount)> states;
Vector<Unknown1, AT_DNA_COUNT(unknown1Count)> unknown1;
Vector<Unknown2, AT_DNA_COUNT(unknown2Count)> unknown2;
Vector<Unknown3, AT_DNA_COUNT(unknown3Count)> unknown3;
};
struct FSMV2 : IFSM {
AT_DECL_DNA_YAMLV
Value<atUint32> stateCount;
Value<atUint32> unknown1Count;
Value<atUint32> unknown2Count;
Value<atUint32> unknown3Count;
struct State : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknown1;
Value<atUint32> unknown2;
Value<atUint32> unknown3;
Value<atUint32> unknown4;
Value<atUint32> unknown5Count;
Vector<CommonStruct, AT_DNA_COUNT(unknown5Count)> unknown5;
};
struct Unknown1 : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknown1;
Value<atUint32> unknown2;
Value<atUint32> unknown3;
Value<atUint32> unknown4;
Value<float> unknown5;
Value<atUint32> unknown6Count;
Vector<CommonStruct, AT_DNA_COUNT(unknown6Count)> unknown6;
Value<atUint8> unknown7;
};
struct Unknown2 : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknown1;
Value<atUint32> unknown2;
Value<atUint32> unknown3;
Value<atUint32> unknown4;
Value<atUint32> unknown5Count;
Vector<CommonStruct, AT_DNA_COUNT(unknown5Count)> unknown5;
};
struct Unknown3 : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unknown1;
Value<atUint32> unknown2;
Value<atUint32> unknown3;
Value<atUint32> unknown4;
Value<atUint32> unknown5Count;
Vector<CommonStruct, AT_DNA_COUNT(unknown5Count)> unknown5;
Value<IDType> fsmId;
};
Vector<State, AT_DNA_COUNT(stateCount)> states;
Vector<Unknown1, AT_DNA_COUNT(unknown1Count)> unknown1;
Vector<Unknown2, AT_DNA_COUNT(unknown2Count)> unknown2;
Vector<Unknown3, AT_DNA_COUNT(unknown3Count)> unknown3;
};
std::unique_ptr<IFSM> detail;
AT_DECL_EXPLICIT_DNA_YAML
};
template <class IDType>
bool ExtractFSM2(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteFSM2(const FSM2<IDType>& fsm2, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAFSM2

View File

@ -1,18 +0,0 @@
#include "GX.hpp"
namespace GX {
template <>
void Color::Enumerate<athena::io::DNA<athena::Endian::Big>::Read>(Read::StreamT& reader) {
reader.readUBytesToBuf(&num, 4);
}
template <>
void Color::Enumerate<athena::io::DNA<athena::Endian::Big>::Write>(Write::StreamT& writer) {
writer.writeUBytes(reinterpret_cast<const atUint8*>(&num), 4);
}
template <>
void Color::Enumerate<athena::io::DNA<athena::Endian::Big>::BinarySize>(BinarySize::StreamT& s) {
s += 4;
}
} // namespace GX

View File

@ -1,298 +0,0 @@
#pragma once
#include <cstdint>
#include <athena/DNA.hpp>
namespace GX {
enum AttrType { NONE, DIRECT, INDEX8, INDEX16 };
enum TevColorArg {
CC_CPREV = 0,
CC_APREV = 1,
CC_C0 = 2,
CC_A0 = 3,
CC_C1 = 4,
CC_A1 = 5,
CC_C2 = 6,
CC_A2 = 7,
CC_TEXC = 8,
CC_TEXA = 9,
CC_RASC = 10,
CC_RASA = 11,
CC_ONE = 12,
CC_HALF = 13,
CC_KONST = 14,
CC_ZERO = 15,
};
enum TevAlphaArg {
CA_APREV = 0,
CA_A0 = 1,
CA_A1 = 2,
CA_A2 = 3,
CA_TEXA = 4,
CA_RASA = 5,
CA_KONST = 6,
CA_ZERO = 7,
};
enum TevKColorSel {
TEV_KCSEL_8_8 = 0x00,
TEV_KCSEL_7_8 = 0x01,
TEV_KCSEL_6_8 = 0x02,
TEV_KCSEL_5_8 = 0x03,
TEV_KCSEL_4_8 = 0x04,
TEV_KCSEL_3_8 = 0x05,
TEV_KCSEL_2_8 = 0x06,
TEV_KCSEL_1_8 = 0x07,
TEV_KCSEL_1 = TEV_KCSEL_8_8,
TEV_KCSEL_3_4 = TEV_KCSEL_6_8,
TEV_KCSEL_1_2 = TEV_KCSEL_4_8,
TEV_KCSEL_1_4 = TEV_KCSEL_2_8,
TEV_KCSEL_K0 = 0x0C,
TEV_KCSEL_K1 = 0x0D,
TEV_KCSEL_K2 = 0x0E,
TEV_KCSEL_K3 = 0x0F,
TEV_KCSEL_K0_R = 0x10,
TEV_KCSEL_K1_R = 0x11,
TEV_KCSEL_K2_R = 0x12,
TEV_KCSEL_K3_R = 0x13,
TEV_KCSEL_K0_G = 0x14,
TEV_KCSEL_K1_G = 0x15,
TEV_KCSEL_K2_G = 0x16,
TEV_KCSEL_K3_G = 0x17,
TEV_KCSEL_K0_B = 0x18,
TEV_KCSEL_K1_B = 0x19,
TEV_KCSEL_K2_B = 0x1A,
TEV_KCSEL_K3_B = 0x1B,
TEV_KCSEL_K0_A = 0x1C,
TEV_KCSEL_K1_A = 0x1D,
TEV_KCSEL_K2_A = 0x1E,
TEV_KCSEL_K3_A = 0x1F
};
enum TevKAlphaSel {
TEV_KASEL_8_8 = 0x00,
TEV_KASEL_7_8 = 0x01,
TEV_KASEL_6_8 = 0x02,
TEV_KASEL_5_8 = 0x03,
TEV_KASEL_4_8 = 0x04,
TEV_KASEL_3_8 = 0x05,
TEV_KASEL_2_8 = 0x06,
TEV_KASEL_1_8 = 0x07,
TEV_KASEL_1 = TEV_KASEL_8_8,
TEV_KASEL_3_4 = TEV_KASEL_6_8,
TEV_KASEL_1_2 = TEV_KASEL_4_8,
TEV_KASEL_1_4 = TEV_KASEL_2_8,
TEV_KASEL_K0_R = 0x10,
TEV_KASEL_K1_R = 0x11,
TEV_KASEL_K2_R = 0x12,
TEV_KASEL_K3_R = 0x13,
TEV_KASEL_K0_G = 0x14,
TEV_KASEL_K1_G = 0x15,
TEV_KASEL_K2_G = 0x16,
TEV_KASEL_K3_G = 0x17,
TEV_KASEL_K0_B = 0x18,
TEV_KASEL_K1_B = 0x19,
TEV_KASEL_K2_B = 0x1A,
TEV_KASEL_K3_B = 0x1B,
TEV_KASEL_K0_A = 0x1C,
TEV_KASEL_K1_A = 0x1D,
TEV_KASEL_K2_A = 0x1E,
TEV_KASEL_K3_A = 0x1F
};
enum TevOp {
TEV_ADD = 0,
TEV_SUB = 1,
TEV_COMP_R8_GT = 8,
TEV_COMP_R8_EQ = 9,
TEV_COMP_GR16_GT = 10,
TEV_COMP_GR16_EQ = 11,
TEV_COMP_BGR24_GT = 12,
TEV_COMP_BGR24_EQ = 13,
TEV_COMP_RGB8_GT = 14,
TEV_COMP_RGB8_EQ = 15,
TEV_COMP_A8_GT = TEV_COMP_RGB8_GT,
TEV_COMP_A8_EQ = TEV_COMP_RGB8_EQ
};
enum TevBias {
TB_ZERO = 0,
TB_ADDHALF = 1,
TB_SUBHALF = 2,
};
enum TevScale { CS_SCALE_1 = 0, CS_SCALE_2 = 1, CS_SCALE_4 = 2, CS_DIVIDE_2 = 3 };
enum TexGenType {
TG_MTX3x4 = 0,
TG_MTX2x4,
TG_BUMP0,
TG_BUMP1,
TG_BUMP2,
TG_BUMP3,
TG_BUMP4,
TG_BUMP5,
TG_BUMP6,
TG_BUMP7,
TG_SRTG
};
enum TexGenSrc {
TG_POS = 0,
TG_NRM,
TG_BINRM,
TG_TANGENT,
TG_TEX0,
TG_TEX1,
TG_TEX2,
TG_TEX3,
TG_TEX4,
TG_TEX5,
TG_TEX6,
TG_TEX7,
TG_TEXCOORD0,
TG_TEXCOORD1,
TG_TEXCOORD2,
TG_TEXCOORD3,
TG_TEXCOORD4,
TG_TEXCOORD5,
TG_TEXCOORD6,
TG_COLOR0,
TG_COLOR1
};
enum TexMtx {
TEXMTX0 = 30,
TEXMTX1 = 33,
TEXMTX2 = 36,
TEXMTX3 = 39,
TEXMTX4 = 42,
TEXMTX5 = 45,
TEXMTX6 = 48,
TEXMTX7 = 51,
TEXMTX8 = 54,
TEXMTX9 = 57,
IDENTITY = 60
};
enum PTTexMtx {
PTTEXMTX0 = 64,
PTTEXMTX1 = 67,
PTTEXMTX2 = 70,
PTTEXMTX3 = 73,
PTTEXMTX4 = 76,
PTTEXMTX5 = 79,
PTTEXMTX6 = 82,
PTTEXMTX7 = 85,
PTTEXMTX8 = 88,
PTTEXMTX9 = 91,
PTTEXMTX10 = 94,
PTTEXMTX11 = 97,
PTTEXMTX12 = 100,
PTTEXMTX13 = 103,
PTTEXMTX14 = 106,
PTTEXMTX15 = 109,
PTTEXMTX16 = 112,
PTTEXMTX17 = 115,
PTTEXMTX18 = 118,
PTTEXMTX19 = 121,
PTIDENTITY = 125
};
enum TevRegID { TEVPREV = 0, TEVREG0 = 1, TEVREG1 = 2, TEVREG2 = 3, TEVLAZY = 5 };
enum DiffuseFn { DF_NONE = 0, DF_SIGN, DF_CLAMP };
enum AttnFn { AF_SPEC = 0, AF_SPOT = 1, AF_NONE };
enum Primitive {
POINTS = 0xb8,
LINES = 0xa8,
LINESTRIP = 0xb0,
TRIANGLES = 0x90,
TRIANGLESTRIP = 0x98,
TRIANGLEFAN = 0xa0,
QUADS = 0x80
};
enum ChannelID {
GX_COLOR0,
GX_COLOR1,
GX_ALPHA0,
GX_ALPHA1,
GX_COLOR0A0,
GX_COLOR1A1,
GX_COLOR_ZERO,
GX_ALPHA_BUMP,
GX_ALPHA_BUMPN,
GX_COLOR_NULL = 0xff
};
enum BlendFactor : uint16_t {
BL_ZERO,
BL_ONE,
BL_SRCCLR,
BL_INVSRCCLR,
BL_SRCALPHA,
BL_INVSRCALPHA,
BL_DSTALPHA,
BL_INVDSTALPHA
};
struct Color : athena::io::DNA<athena::Endian::Big> {
union {
uint8_t color[4];
uint32_t num = 0;
};
Color() = default;
Color& operator=(const atVec4f& vec) {
athena::simd_floats f(vec.simd);
color[0] = uint8_t(std::min(std::max(f[0] * 255.f, 0.f), 255.f));
color[1] = uint8_t(std::min(std::max(f[1] * 255.f, 0.f), 255.f));
color[2] = uint8_t(std::min(std::max(f[2] * 255.f, 0.f), 255.f));
color[3] = uint8_t(std::min(std::max(f[3] * 255.f, 0.f), 255.f));
return *this;
}
Color& operator=(const atVec3f& vec) {
athena::simd_floats f(vec.simd);
color[0] = uint8_t(std::min(std::max(f[0] * 255.f, 0.f), 255.f));
color[1] = uint8_t(std::min(std::max(f[1] * 255.f, 0.f), 255.f));
color[2] = uint8_t(std::min(std::max(f[2] * 255.f, 0.f), 255.f));
color[3] = 0xff;
return *this;
}
Color& operator=(uint8_t val) {
color[0] = val;
color[1] = val;
color[2] = val;
color[3] = val;
return *this;
}
atVec4f toVec4f() const {
atVec4f out;
athena::simd_floats f;
f[0] = color[0] / 255.f;
f[1] = color[1] / 255.f;
f[2] = color[2] / 255.f;
f[3] = color[3] / 255.f;
out.simd.copy_from(f);
return out;
}
Color(const atVec4f& vec) { *this = vec; }
Color(const atVec3f& vec) { *this = vec; }
Color(uint8_t val) { *this = val; }
bool operator==(const Color& other) const { return num == other.num; }
bool operator!=(const Color& other) const { return num != other.num; }
uint8_t operator[](size_t idx) const { return color[idx]; }
uint8_t& operator[](size_t idx) { return color[idx]; }
AT_DECL_EXPLICIT_DNA
};
} // namespace GX

View File

@ -1,426 +0,0 @@
#include "DataSpec/DNACommon/MAPA.hpp"
#include "DataSpec/DNACommon/GX.hpp"
#include "DataSpec/DNAMP1/DNAMP1.hpp"
#include "DataSpec/DNAMP2/DNAMP2.hpp"
#include "DataSpec/DNAMP3/DNAMP3.hpp"
#include "DataSpec/DNAMP1/MAPA.hpp"
#include "DataSpec/DNAMP2/MAPA.hpp"
#include "DataSpec/DNAMP3/MAPA.hpp"
#include <hecl/Blender/Connection.hpp>
#include <logvisor/logvisor.hpp>
#include <zeus/CAABox.hpp>
namespace DataSpec::DNAMAPA {
static logvisor::Module Log("DNAMAPA");
template <>
void MAPA::Enumerate<BigDNA::Read>(typename Read::StreamT& __dna_reader) {
/* magic */
magic = __dna_reader.readUint32Big();
if (magic != 0xDEADD00D) {
LogDNACommon.report(logvisor::Error, FMT_STRING("invalid MAPA magic"));
return;
}
/* version */
version = __dna_reader.readUint32Big();
if (version == 2)
header = std::make_unique<HeaderMP1>();
else if (version == 3)
header = std::make_unique<HeaderMP2>();
else if (version == 5)
header = std::make_unique<HeaderMP3>();
else {
LogDNACommon.report(logvisor::Error, FMT_STRING("invalid MAPA version"));
return;
}
header->read(__dna_reader);
for (atUint32 i = 0; i < header->mappableObjectCount(); i++) {
std::unique_ptr<IMappableObject> mo = nullptr;
if (version != 5) {
mo = std::make_unique<MappableObjectMP1_2>();
} else {
mo = std::make_unique<MappableObjectMP3>();
}
mo->read(__dna_reader);
mappableObjects.push_back(std::move(mo));
}
/* vertices */
__dna_reader.enumerateBig(vertices, header->vertexCount());
/* surfaceHeaders */
__dna_reader.enumerate(surfaceHeaders, header->surfaceCount());
/* surfaces */
__dna_reader.enumerate(surfaces, header->surfaceCount());
}
template <>
void MAPA::Enumerate<BigDNA::Write>(typename Write::StreamT& __dna_writer) {
/* magic */
__dna_writer.writeUint32Big(magic);
/* version */
__dna_writer.writeUint32Big(version);
header->write(__dna_writer);
/* mappableObjects */
for (const std::unique_ptr<IMappableObject>& mo : mappableObjects)
mo->write(__dna_writer);
/* vertices */
__dna_writer.enumerateBig(vertices);
/* surfaceHeaders */
__dna_writer.enumerate(surfaceHeaders);
/* surfaces */
__dna_writer.enumerate(surfaces);
}
template <>
void MAPA::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
header->binarySize(s);
for (const std::unique_ptr<IMappableObject>& mo : mappableObjects)
mo->binarySize(s);
s += vertices.size() * 12;
for (const SurfaceHeader& sh : surfaceHeaders)
sh.binarySize(s);
for (const Surface& su : surfaces)
su.binarySize(s);
s += 8;
}
static const char* RetroMapVisModes[] = {"ALWAYS", "MAPSTATIONORVISIT", "VISIT", "NEVER"};
static const char* RetroMapObjVisModes[] = {"ALWAYS", "MAPSTATIONORVISIT", "VISIT", "NEVER", "MAPSTATIONORVISIT2"};
template <typename PAKRouter>
bool ReadMAPAToBlender(hecl::blender::Connection& conn, const MAPA& mapa, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, bool force) {
if (!force && outPath.isFile())
return true;
if (!conn.createBlend(outPath, hecl::blender::BlendType::MapArea))
return false;
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy, bmesh\n"
"from mathutils import Matrix\n"
"\n"
"bpy.types.Object.retro_mappable_type = bpy.props.IntProperty(name='Retro: MAPA object type', default=-1)\n"
"bpy.types.Object.retro_mappable_sclyid = bpy.props.StringProperty(name='Retro: MAPA object SCLY ID')\n"
"bpy.types.Scene.retro_map_vis_mode = bpy.props.EnumProperty(items=[('ALWAYS', 'Always', 'Always Visible', 0),"
"('MAPSTATIONORVISIT', 'Map Station or Visit', 'Visible after Map Station or Visit', 1),"
"('VISIT', 'Visit', 'Visible after Visit', 2),"
"('NEVER', 'Never', 'Never Visible', 3)],"
"name='Retro: Map Visibility Mode')\n"
"bpy.types.Object.retro_mapobj_vis_mode = bpy.props.EnumProperty(items=[('ALWAYS', 'Always', 'Always Visible', "
"0),"
"('MAPSTATIONORVISIT', 'Map Station or Visit', 'Visible after Map Station or Visit', 1),"
"('VISIT', 'Visit', 'Visible after Door Visit', 2),"
"('NEVER', 'Never', 'Never Visible', 3),"
"('MAPSTATIONORVISIT2', 'Map Station or Visit 2', 'Visible after Map Station or Visit', 4)],"
"name='Retro: Map Object Visibility Mode')\n"
"\n"
"# Clear Scene\n"
"if len(bpy.data.collections):\n"
" bpy.data.collections.remove(bpy.data.collections[0])\n"
"\n"
"def add_triangle(bm, verts):\n"
" verts = [bm.verts[vi] for vi in verts]\n"
" face = bm.faces.get(verts)\n"
" if face:\n"
" face = face.copy()\n"
" bm.verts.ensure_lookup_table()\n"
" face.normal_flip()\n"
" else:\n"
" bm.faces.new(verts)\n"
"\n"
"def add_border(bm, verts):\n"
" verts = [bm.verts[vi] for vi in verts]\n"
" edge = bm.edges.get(verts)\n"
" if not edge:\n"
" edge = bm.edges.new(verts)\n"
" edge.seam = True\n"
"\n";
os.format(FMT_STRING("bpy.context.scene.name = 'MAPA_{}'\n"
"bpy.context.scene.retro_map_vis_mode = '{}'\n"),
entry.id, RetroMapVisModes[mapa.header->visMode()]);
/* Add empties representing MappableObjects */
int moIdx = 0;
for (const std::unique_ptr<MAPA::IMappableObject>& mo : mapa.mappableObjects) {
if (mapa.version < 5) {
const MAPA::MappableObjectMP1_2* moMP12 = static_cast<const MAPA::MappableObjectMP1_2*>(mo.get());
zeus::simd_floats mtxF[3];
for (int i = 0; i < 3; ++i)
moMP12->transformMtx[i].simd.copy_to(mtxF[i]);
os.format(FMT_STRING("obj = bpy.data.objects.new('MAPOBJ_{:02d}', None)\n"
"bpy.context.scene.collection.objects.link(obj)\n"
"obj.retro_mappable_type = {}\n"
"obj.retro_mapobj_vis_mode = '{}'\n"
"obj.retro_mappable_sclyid = '0x{:08X}'\n"
"mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n"),
moIdx, int(moMP12->type), RetroMapObjVisModes[moMP12->visMode], moMP12->sclyId, mtxF[0][0], mtxF[0][1],
mtxF[0][2], mtxF[0][3], mtxF[1][0], mtxF[1][1], mtxF[1][2], mtxF[1][3], mtxF[2][0], mtxF[2][1],
mtxF[2][2], mtxF[2][3]);
++moIdx;
continue;
} else {
const MAPA::MappableObjectMP3* moMP3 = static_cast<const MAPA::MappableObjectMP3*>(mo.get());
zeus::simd_floats mtxF[3];
for (int i = 0; i < 3; ++i)
moMP3->transformMtx[i].simd.copy_to(mtxF[i]);
os.format(FMT_STRING("obj = bpy.data.objects.new('MAPOBJ_{:02d}', None)\n"
"bpy.context.scene.collection.objects.link(obj)\n"
"obj.retro_mappable_type = {}\n"
"obj.retro_mapobj_vis_mode = '{}'\n"
"obj.retro_mappable_sclyid = '0x{:08X}'\n"
"mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n"),
moIdx, int(moMP3->type), RetroMapObjVisModes[moMP3->visMode], moMP3->sclyId, mtxF[0][0], mtxF[0][1],
mtxF[0][2], mtxF[0][3], mtxF[1][0], mtxF[1][1], mtxF[1][2], mtxF[1][3], mtxF[2][0], mtxF[2][1],
mtxF[2][2], mtxF[2][3]);
++moIdx;
continue;
}
}
os << "# Begin bmesh\n"
"bm = bmesh.new()\n"
"\n";
/* Read in verts */
for (const atVec3f& vert : mapa.vertices) {
zeus::simd_floats f(vert.simd);
os.format(FMT_STRING("bm.verts.new(({},{},{}))\n"), f[0], f[1], f[2]);
}
os << "bm.verts.ensure_lookup_table()\n";
/* Read in surfaces */
for (const typename MAPA::Surface& surf : mapa.surfaces) {
for (const typename MAPA::Surface::Primitive& prim : surf.primitives) {
auto iit = prim.indices.cbegin();
/* 3 Prim Verts to start */
int c = 0;
unsigned int primVerts[3] = {*iit++, *iit++, *iit++};
if (GX::Primitive(prim.type) == GX::TRIANGLESTRIP) {
atUint8 flip = 0;
for (size_t v = 0; v < prim.indexCount - 2; ++v) {
if (flip) {
os.format(FMT_STRING("add_triangle(bm, ({},{},{}))\n"), primVerts[c % 3], primVerts[(c + 2) % 3],
primVerts[(c + 1) % 3]);
} else {
os.format(FMT_STRING("add_triangle(bm, ({},{},{}))\n"), primVerts[c % 3], primVerts[(c + 1) % 3],
primVerts[(c + 2) % 3]);
}
flip ^= 1;
/* Break if done */
if (iit == prim.indices.cend())
break;
bool peek = (v >= prim.indexCount - 3);
/* Advance one prim vert */
if (peek)
primVerts[c % 3] = *iit;
else
primVerts[c % 3] = *iit++;
++c;
}
} else if (GX::Primitive(prim.type) == GX::TRIANGLES) {
for (size_t v = 0; v < prim.indexCount; v += 3) {
os.format(FMT_STRING("add_triangle(bm, ({},{},{}))\n"), primVerts[0], primVerts[1], primVerts[2]);
/* Break if done */
if (v + 3 >= prim.indexCount)
break;
/* Advance 3 Prim Verts */
for (int pv = 0; pv < 3; ++pv)
primVerts[pv] = *iit++;
}
}
}
for (const typename MAPA::Surface::Border& border : surf.borders) {
auto iit = border.indices.cbegin();
for (size_t i = 0; i < border.indexCount - 1; ++i) {
os.format(FMT_STRING("add_border(bm, ({},{}))\n"), *iit, *(iit + 1));
++iit;
}
}
}
os << "mesh = bpy.data.meshes.new('MAP')\n"
"obj = bpy.data.objects.new(mesh.name, mesh)\n"
"bm.to_mesh(mesh)\n"
"bpy.context.scene.collection.objects.link(obj)\n"
"bm.free()\n";
const zeus::CMatrix4f* tmpMtx = pakRouter.lookupMAPATransform(entry.id);
const zeus::CMatrix4f& mtx = tmpMtx ? *tmpMtx : zeus::skIdentityMatrix4f;
os.format(FMT_STRING("mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n"),
mtx[0][0], mtx[1][0], mtx[2][0], mtx[3][0], mtx[0][1], mtx[1][1], mtx[2][1], mtx[3][1], mtx[0][2],
mtx[1][2], mtx[2][2], mtx[3][2]);
/* World background */
hecl::ProjectPath worldDir = outPath.getParentPath().getParentPath();
for (const auto& ent : hecl::DirectoryEnumerator(worldDir.getAbsolutePath())) {
if (hecl::StringUtils::BeginsWith(ent.m_name, "!world") &&
hecl::StringUtils::EndsWith(ent.m_name, ".blend")) {
os.linkBackground(fmt::format(FMT_STRING("//../{}"), ent.m_name), "World"sv);
break;
}
}
os.centerView();
os.close();
conn.saveBlend();
return true;
}
template bool ReadMAPAToBlender<PAKRouter<DNAMP1::PAKBridge>>(hecl::blender::Connection& conn, const MAPA& mapa,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter,
const PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
bool force);
template bool ReadMAPAToBlender<PAKRouter<DNAMP2::PAKBridge>>(hecl::blender::Connection& conn, const MAPA& mapa,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter,
const PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
bool force);
template bool ReadMAPAToBlender<PAKRouter<DNAMP3::PAKBridge>>(hecl::blender::Connection& conn, const MAPA& mapa,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter,
const PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
bool force);
template <typename MAPAType>
bool Cook(const hecl::blender::MapArea& mapaIn, const hecl::ProjectPath& out) {
if (mapaIn.verts.size() >= 256) {
Log.report(logvisor::Error, FMT_STRING("MAPA {} vertex range exceeded [{}/{}]"), out.getRelativePath(),
mapaIn.verts.size(), 255);
return false;
}
MAPAType mapa;
mapa.magic = 0xDEADD00D;
mapa.version = MAPAType::Version();
zeus::CAABox aabb;
for (const hecl::blender::Vector3f& vert : mapaIn.verts)
aabb.accumulateBounds(vert.val);
mapa.header = std::make_unique<typename MAPAType::Header>();
typename MAPAType::Header& header = static_cast<typename MAPAType::Header&>(*mapa.header);
header.unknown1 = 0;
header.mapVisMode = mapaIn.visType;
header.boundingBox[0] = aabb.min;
header.boundingBox[1] = aabb.max;
header.moCount = mapaIn.pois.size();
header.vtxCount = mapaIn.verts.size();
header.surfCount = mapaIn.surfaces.size();
mapa.mappableObjects.reserve(mapaIn.pois.size());
for (const hecl::blender::MapArea::POI& poi : mapaIn.pois) {
mapa.mappableObjects.push_back(std::make_unique<typename MAPAType::MappableObject>());
typename MAPAType::MappableObject& mobj =
static_cast<typename MAPAType::MappableObject&>(*mapa.mappableObjects.back());
mobj.type = MAPA::IMappableObject::Type(poi.type);
mobj.visMode = poi.visMode;
mobj.sclyId = poi.objid;
mobj.transformMtx[0] = poi.xf.val[0];
mobj.transformMtx[1] = poi.xf.val[1];
mobj.transformMtx[2] = poi.xf.val[2];
}
mapa.vertices.reserve(mapaIn.verts.size());
for (const hecl::blender::Vector3f& vert : mapaIn.verts)
mapa.vertices.push_back(vert.val);
size_t offsetCur = 0;
for (const auto& mo : mapa.mappableObjects)
mo->binarySize(offsetCur);
offsetCur += mapa.vertices.size() * 12;
offsetCur += mapaIn.surfaces.size() * 32;
mapa.surfaceHeaders.reserve(mapaIn.surfaces.size());
mapa.surfaces.reserve(mapaIn.surfaces.size());
for (const hecl::blender::MapArea::Surface& surfIn : mapaIn.surfaces) {
mapa.surfaceHeaders.emplace_back();
DNAMAPA::MAPA::SurfaceHeader& surfHead = mapa.surfaceHeaders.back();
mapa.surfaces.emplace_back();
DNAMAPA::MAPA::Surface& surf = mapa.surfaces.back();
surf.primitiveCount = 1;
surf.primitives.emplace_back();
DNAMAPA::MAPA::Surface::Primitive& prim = surf.primitives.back();
prim.type = GX::TRIANGLESTRIP;
prim.indexCount = surfIn.count;
prim.indices.reserve(surfIn.count);
auto itBegin = mapaIn.indices.begin() + surfIn.start;
auto itEnd = itBegin + surfIn.count;
for (auto it = itBegin; it != itEnd; ++it)
prim.indices.push_back(*it);
surf.borderCount = surfIn.borders.size();
surf.borders.reserve(surfIn.borders.size());
for (const auto& borderIn : surfIn.borders) {
surf.borders.emplace_back();
DNAMAPA::MAPA::Surface::Border& border = surf.borders.back();
border.indexCount = borderIn.second;
border.indices.reserve(borderIn.second);
auto it2Begin = mapaIn.indices.begin() + borderIn.first;
auto it2End = it2Begin + borderIn.second;
for (auto it = it2Begin; it != it2End; ++it)
border.indices.push_back(*it);
}
surfHead.normal = surfIn.normal.val;
surfHead.centroid = surfIn.centerOfMass;
surfHead.polyOff = offsetCur;
offsetCur += 4;
prim.binarySize(offsetCur);
surfHead.edgeOff = offsetCur;
offsetCur += 4;
for (const auto& border : surf.borders)
border.binarySize(offsetCur);
}
athena::io::FileWriter f(out.getAbsolutePath());
mapa.write(f);
int64_t rem = f.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
f.writeBytes((atInt8*)"\xff", 1);
return true;
}
template bool Cook<DNAMP1::MAPA>(const hecl::blender::MapArea& mapa, const hecl::ProjectPath& out);
template bool Cook<DNAMP2::MAPA>(const hecl::blender::MapArea& mapa, const hecl::ProjectPath& out);
template bool Cook<DNAMP3::MAPA>(const hecl::blender::MapArea& mapa, const hecl::ProjectPath& out);
} // namespace DataSpec::DNAMAPA

View File

@ -1,177 +0,0 @@
#pragma once
#include <memory>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace hecl {
class ProjectPath;
}
namespace hecl::blender {
class Connection;
struct MapArea;
} // namespace hecl::blender
namespace DataSpec::DNAMAPA {
struct MAPA : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atUint32> magic;
Value<atUint32> version;
struct IMAPAHeader : BigDNAV {
Delete _d;
virtual atUint32 visMode() const = 0;
virtual atUint32 mappableObjectCount() const = 0;
virtual atUint32 vertexCount() const = 0;
virtual atUint32 surfaceCount() const = 0;
};
struct HeaderMP1 : IMAPAHeader {
AT_DECL_DNAV
Value<atUint32> unknown1 = 0;
Value<atUint32> mapVisMode = 0;
Value<atVec3f> boundingBox[2] = {};
Value<atUint32> moCount = 0;
Value<atUint32> vtxCount = 0;
Value<atUint32> surfCount = 0;
atUint32 visMode() const override { return mapVisMode; }
atUint32 mappableObjectCount() const override { return moCount; }
atUint32 vertexCount() const override { return vtxCount; }
atUint32 surfaceCount() const override { return surfCount; }
};
struct HeaderMP2 : IMAPAHeader {
AT_DECL_DNAV
Value<atUint32> unknown1 = 0;
Value<atUint32> mapVisMode = 0;
Value<atVec3f> boundingBox[2] = {};
Value<atUint32> unknown3 = 0;
Value<atUint32> unknown4 = 0;
Value<atUint32> unknown5 = 0;
Value<atUint32> moCount = 0;
Value<atUint32> vtxCount = 0;
Value<atUint32> surfCount = 0;
atUint32 visMode() const override { return mapVisMode; }
atUint32 mappableObjectCount() const override { return moCount; }
atUint32 vertexCount() const override { return vtxCount; }
atUint32 surfaceCount() const override { return surfCount; }
};
struct HeaderMP3 : IMAPAHeader {
AT_DECL_DNAV
Value<atUint32> unknown1 = 0;
Value<atUint32> mapVisMode = 0;
Value<atVec3f> boundingBox[2] = {};
Value<atUint32> unknown3 = 0;
Value<atUint32> unknown4 = 0;
Value<atUint32> unknown5 = 0;
Value<atUint32> unknown6 = 0;
Value<atUint32> moCount = 0;
Value<atUint32> vtxCount = 0;
Value<atUint32> surfCount = 0;
Value<atUint32> internalNameLength = 0;
Value<atUint32> unknown7 = 0;
String<AT_DNA_COUNT(internalNameLength)> internalName;
atUint32 visMode() const override { return mapVisMode; }
atUint32 mappableObjectCount() const override { return moCount; }
atUint32 vertexCount() const override { return vtxCount; }
atUint32 surfaceCount() const override { return surfCount; }
};
std::unique_ptr<IMAPAHeader> header;
struct IMappableObject : BigDNAV {
Delete _d;
enum class Type : atUint32 {
BlueDoor = 0,
ShieldDoor = 1,
IceDoor = 2,
WaveDoor = 3,
PlasmaDoor = 4,
BigDoor1 = 5,
BigDoor2 = 6,
IceDoorCeiling = 7,
IceDoorFloor = 8,
WaveDoorCeiling = 9,
WaveDoorFloor = 10,
IceDoorFloor2 = 13,
WaveDoorFloor2 = 14,
DownArrowYellow = 27, /* Maintenance Tunnel */
UpArrowYellow = 28, /* Phazon Processing Center */
DownArrowGreen = 29, /* Elevator A */
UpArrowGreen = 30, /* Elite Control Access */
DownArrowRed = 31, /* Elevator B */
UpArrowRed = 32, /* Fungal Hall Access */
TransportLift = 33,
SaveStation = 34,
MissileStation = 37
};
};
struct MappableObjectMP1_2 : IMappableObject {
AT_DECL_DNAV
Value<Type> type;
Value<atUint32> visMode;
Value<atUint32> sclyId;
Value<atInt32> seek1 = -1;
Value<atVec4f> transformMtx[3];
Value<atInt32> seek2[4] = {-1, -1, -1, -1};
};
struct MappableObjectMP3 : IMappableObject {
AT_DECL_DNAV
Value<Type> type;
Value<atUint32> visMode;
Value<atUint32> sclyId;
Buffer<AT_DNA_COUNT(0x10)> unknownHash;
Value<atInt32> seek1 = -1;
Value<atVec4f> transformMtx[3];
Value<atInt32> seek2[4] = {-1, -1, -1, -1};
};
std::vector<std::unique_ptr<IMappableObject>> mappableObjects;
Vector<atVec3f, AT_DNA_COUNT(header->vertexCount())> vertices;
struct SurfaceHeader : BigDNA {
AT_DECL_DNA
Value<atVec3f> normal;
Value<atVec3f> centroid;
Value<atUint32> polyOff;
Value<atUint32> edgeOff;
};
Vector<SurfaceHeader, AT_DNA_COUNT(header->surfaceCount())> surfaceHeaders;
struct Surface : BigDNA {
AT_DECL_DNA
Value<atUint32> primitiveCount;
struct Primitive : BigDNA {
AT_DECL_DNA
Value<atUint32> type;
Value<atUint32> indexCount;
Vector<atUint8, AT_DNA_COUNT(indexCount)> indices;
Align<4> align;
};
Vector<Primitive, AT_DNA_COUNT(primitiveCount)> primitives;
Value<atUint32> borderCount;
struct Border : BigDNA {
AT_DECL_DNA
Value<atUint32> indexCount;
Vector<atUint8, AT_DNA_COUNT(indexCount)> indices;
Align<4> align;
};
Vector<Border, AT_DNA_COUNT(borderCount)> borders;
};
Vector<Surface, AT_DNA_COUNT(header->surfaceCount())> surfaces;
};
template <typename PAKRouter>
bool ReadMAPAToBlender(hecl::blender::Connection& conn, const MAPA& mapa, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, bool force);
template <typename MAPAType>
bool Cook(const hecl::blender::MapArea& mapa, const hecl::ProjectPath& out);
} // namespace DataSpec::DNAMAPA

View File

@ -1,146 +0,0 @@
#include "DataSpec/DNACommon/MAPU.hpp"
#include "DataSpec/DNAMP1/DNAMP1.hpp"
#include "DataSpec/DNAMP2/DNAMP2.hpp"
#include "DataSpec/DNAMP3/DNAMP3.hpp"
#include <hecl/Blender/Connection.hpp>
#include <zeus/Global.hpp>
namespace DataSpec::DNAMAPU {
template <typename PAKRouter>
bool ReadMAPUToBlender(hecl::blender::Connection& conn, const MAPU& mapu, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, bool force) {
if (!force && outPath.isFile())
return true;
if (!conn.createBlend(outPath, hecl::blender::BlendType::MapUniverse))
return false;
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy\n"
"from mathutils import Matrix\n"
"\n"
"# Clear Scene\n"
"if len(bpy.data.collections):\n"
" bpy.data.collections.remove(bpy.data.collections[0])\n"
"\n"
"bpy.types.Object.retro_mapworld_color = bpy.props.FloatVectorProperty(name='Retro: MapWorld Color',"
" description='Sets map world color', subtype='COLOR', size=4, min=0.0, max=1.0)\n"
"bpy.types.Object.retro_mapworld_path = bpy.props.StringProperty(name='Retro: MapWorld Path',"
" description='Sets path to World root')\n"
"\n";
hecl::ProjectPath hexPath = pakRouter.getWorking(mapu.hexMapa);
os.linkMesh(hexPath.getAbsolutePath(), "MAP");
os << "hexMesh = bpy.data.objects['MAP'].data\n";
for (const MAPU::World& wld : mapu.worlds) {
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(wld.mlvl);
const MAPU::Transform& wldXf = wld.transform;
zeus::simd_floats wldXfF[3];
for (int i = 0; i < 3; ++i)
wldXf.xf[i].simd.copy_to(wldXfF[i]);
zeus::simd_floats hexColorF(wld.hexColor.mSimd);
os.format(FMT_STRING("wldObj = bpy.data.objects.new('{}', None)\n"
"mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"wldObj.rotation_mode = 'QUATERNION'\n"
"wldObj.location = mtxd[0]\n"
"wldObj.rotation_quaternion = mtxd[1]\n"
"wldObj.scale = mtxd[2]\n"
"wldObj.retro_mapworld_color = ({}, {}, {}, {})\n"
"wldObj.retro_mapworld_path = '''{}'''\n"
"bpy.context.scene.collection.objects.link(wldObj)\n"),
wld.name, wldXfF[0][0], wldXfF[0][1], wldXfF[0][2], wldXfF[0][3], wldXfF[1][0], wldXfF[1][1],
wldXfF[1][2], wldXfF[1][3], wldXfF[2][0], wldXfF[2][1], wldXfF[2][2], wldXfF[2][3], hexColorF[0],
hexColorF[1], hexColorF[2], hexColorF[3], path.getParentPath().getRelativePath());
int idx = 0;
for (const MAPU::Transform& hexXf : wld.hexTransforms) {
zeus::simd_floats hexXfF[3];
for (int i = 0; i < 3; ++i)
hexXf.xf[i].simd.copy_to(hexXfF[i]);
os.format(FMT_STRING("obj = bpy.data.objects.new('{}_{}', hexMesh)\n"
"mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = mtxd[2]\n"
"bpy.context.scene.collection.objects.link(obj)\n"
"obj.parent = wldObj\n"),
wld.name, idx++, hexXfF[0][0], hexXfF[0][1], hexXfF[0][2], hexXfF[0][3], hexXfF[1][0], hexXfF[1][1],
hexXfF[1][2], hexXfF[1][3], hexXfF[2][0], hexXfF[2][1], hexXfF[2][2], hexXfF[2][3]);
}
}
os << "for screen in bpy.data.screens:\n"
" for area in screen.areas:\n"
" for space in area.spaces:\n"
" if space.type == 'VIEW_3D':\n"
" space.clip_end = 8000.0\n";
os.centerView();
os.close();
conn.saveBlend();
return true;
}
template bool ReadMAPUToBlender<PAKRouter<DNAMP1::PAKBridge>>(hecl::blender::Connection& conn, const MAPU& mapu,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter,
const PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
bool force);
template bool ReadMAPUToBlender<PAKRouter<DNAMP2::PAKBridge>>(hecl::blender::Connection& conn, const MAPU& mapu,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter,
const PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
bool force);
bool MAPU::Cook(const hecl::blender::MapUniverse& mapuIn, const hecl::ProjectPath& out) {
MAPU mapu;
mapu.magic = 0xABCDEF01;
mapu.version = 1;
mapu.hexMapa = mapuIn.hexagonPath;
mapu.worldCount = mapuIn.worlds.size();
mapu.worlds.reserve(mapuIn.worlds.size());
for (const hecl::blender::MapUniverse::World& wld : mapuIn.worlds) {
mapu.worlds.emplace_back();
MAPU::World& wldOut = mapu.worlds.back();
wldOut.name = wld.name;
for (const auto& ent : wld.worldPath.enumerateDir()) {
if (hecl::StringUtils::BeginsWith(ent.m_name, "!world") &&
hecl::StringUtils::EndsWith(ent.m_name, ".blend")) {
wldOut.mlvl = hecl::ProjectPath(wld.worldPath, ent.m_name);
break;
}
}
wldOut.transform.xf[0] = wld.xf.val[0];
wldOut.transform.xf[1] = wld.xf.val[1];
wldOut.transform.xf[2] = wld.xf.val[2];
wldOut.hexCount = wld.hexagons.size();
wldOut.hexTransforms.reserve(wld.hexagons.size());
for (const hecl::blender::Matrix4f& mtx : wld.hexagons) {
wldOut.hexTransforms.emplace_back();
MAPU::Transform& xf = wldOut.hexTransforms.back();
xf.xf[0] = mtx.val[0];
xf.xf[1] = mtx.val[1];
xf.xf[2] = mtx.val[2];
}
wldOut.hexColor = zeus::CColor(wld.color.val);
}
athena::io::FileWriter f(out.getAbsolutePath());
mapu.write(f);
int64_t rem = f.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
f.writeBytes((atInt8*)"\xff", 1);
return true;
}
} // namespace DataSpec::DNAMAPU

View File

@ -1,45 +0,0 @@
#pragma once
#include <cstdint>
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace hecl {
class ProjectPath;
}
namespace hecl::blender {
class Connection;
struct MapUniverse;
} // namespace hecl::blender
namespace DataSpec::DNAMAPU {
struct MAPU : BigDNA {
AT_DECL_DNA
Value<uint32_t> magic;
Value<uint32_t> version;
UniqueID32 hexMapa;
Value<uint32_t> worldCount;
struct Transform : BigDNA {
AT_DECL_DNA
Value<atVec4f> xf[3];
};
struct World : BigDNA {
AT_DECL_DNA
String<-1> name;
UniqueID32 mlvl;
Transform transform;
Value<uint32_t> hexCount;
Vector<Transform, AT_DNA_COUNT(hexCount)> hexTransforms;
DNAColor hexColor;
};
Vector<World, AT_DNA_COUNT(worldCount)> worlds;
static bool Cook(const hecl::blender::MapUniverse& mapu, const hecl::ProjectPath& out);
};
template <typename PAKRouter>
bool ReadMAPUToBlender(hecl::blender::Connection& conn, const MAPU& mapu, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, bool force);
} // namespace DataSpec::DNAMAPU

View File

@ -1,109 +0,0 @@
#include "DataSpec/DNACommon/MLVL.hpp"
#include "DataSpec/DNAMP1/MLVL.hpp"
#include "DataSpec/DNAMP2/MLVL.hpp"
#include "DataSpec/DNAMP3/MLVL.hpp"
#include <hecl/Blender/Connection.hpp>
#include <zeus/Global.hpp>
namespace DataSpec::DNAMLVL {
template <class PAKRouter, typename MLVL>
bool ReadMLVLToBlender(hecl::blender::Connection& conn, const MLVL& mlvl, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, bool force,
std::function<void(const char*)> fileChanged) {
hecl::ProjectPath blendPath = outPath.getWithExtension(".blend", true);
if (!force && blendPath.isFile())
return true;
/* Create World Blend */
if (!conn.createBlend(blendPath, hecl::blender::BlendType::World))
return false;
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy\n"
"import bmesh\n"
"from mathutils import Matrix\n"
"\n"
"bpy.context.scene.name = 'World'\n"
"\n"
"# Clear Scene\n"
"if len(bpy.data.collections):\n"
" bpy.data.collections.remove(bpy.data.collections[0])\n";
/* Insert area empties */
int areaIdx = 0;
for (const auto& area : mlvl.areas) {
const typename PAKRouter::EntryType* mreaEntry = pakRouter.lookupEntry(area.areaMREAId);
os.AABBToBMesh(area.aabb[0], area.aabb[1]);
zeus::simd_floats xfMtxF[3];
for (int i = 0; i < 3; ++i)
area.transformMtx[i].simd.copy_to(xfMtxF[i]);
os.format(FMT_STRING("box_mesh = bpy.data.meshes.new('''{}''')\n"
"bm.to_mesh(box_mesh)\n"
"bm.free()\n"
"box = bpy.data.objects.new(box_mesh.name, box_mesh)\n"
"bpy.context.scene.collection.objects.link(box)\n"
"mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"box.rotation_mode = 'QUATERNION'\n"
"box.location = mtxd[0]\n"
"box.rotation_quaternion = mtxd[1]\n"
"box.scale = mtxd[2]\n"),
*mreaEntry->unique.m_areaName, xfMtxF[0][0], xfMtxF[0][1], xfMtxF[0][2], xfMtxF[0][3], xfMtxF[1][0], xfMtxF[1][1],
xfMtxF[1][2], xfMtxF[1][3], xfMtxF[2][0], xfMtxF[2][1], xfMtxF[2][2], xfMtxF[2][3]);
/* Insert dock planes */
int dockIdx = 0;
for (const auto& dock : area.docks) {
os << "bm = bmesh.new()\n";
zeus::CVector3f pvAvg;
for (const atVec3f& pv : dock.planeVerts)
pvAvg += pv;
pvAvg /= zeus::CVector3f(dock.planeVerts.size());
int idx = 0;
for (const atVec3f& pv : dock.planeVerts) {
const zeus::CVector3f pvRel = zeus::CVector3f(pv) - pvAvg;
os.format(FMT_STRING("bm.verts.new(({},{},{}))\n"
"bm.verts.ensure_lookup_table()\n"),
pvRel[0], pvRel[1], pvRel[2]);
if (idx)
os << "bm.edges.new((bm.verts[-2], bm.verts[-1]))\n";
++idx;
}
os << "bm.edges.new((bm.verts[-1], bm.verts[0]))\n";
os.format(FMT_STRING("dockMesh = bpy.data.meshes.new('DOCK_{:02d}_{:02d}')\n"), areaIdx, dockIdx);
os << "dockObj = bpy.data.objects.new(dockMesh.name, dockMesh)\n"
"bpy.context.scene.collection.objects.link(dockObj)\n"
"bm.to_mesh(dockMesh)\n"
"bm.free()\n"
"dockObj.parent = box\n";
os.format(FMT_STRING("dockObj.location = ({},{},{})\n"), float(pvAvg[0]), float(pvAvg[1]), float(pvAvg[2]));
++dockIdx;
}
++areaIdx;
}
os.centerView();
os.close();
conn.saveBlend();
return true;
}
template bool ReadMLVLToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::MLVL>(
hecl::blender::Connection& conn, const DNAMP1::MLVL& mlvl, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter, const PAKRouter<DNAMP1::PAKBridge>::EntryType& entry, bool force,
std::function<void(const char*)> fileChanged);
template bool ReadMLVLToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::MLVL>(
hecl::blender::Connection& conn, const DNAMP2::MLVL& mlvl, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter, const PAKRouter<DNAMP2::PAKBridge>::EntryType& entry, bool force,
std::function<void(const char*)> fileChanged);
template bool ReadMLVLToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::MLVL>(
hecl::blender::Connection& conn, const DNAMP3::MLVL& mlvl, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter, const PAKRouter<DNAMP3::PAKBridge>::EntryType& entry, bool force,
std::function<void(const char*)> fileChanged);
} // namespace DataSpec::DNAMLVL

View File

@ -1,22 +0,0 @@
#pragma once
#include <functional>
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace hecl {
class ProjectPath;
}
namespace hecl::blender {
class Connection;
}
namespace DataSpec::DNAMLVL {
template <class PAKRouter, typename MLVL>
bool ReadMLVLToBlender(hecl::blender::Connection& conn, const MLVL& mlvl, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, bool force,
std::function<void(const char*)> fileChanged);
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace DataSpec {
struct MayaSpline : public BigDNA {
AT_DECL_DNA_YAML
Value<atUint8> preInf;
Value<atUint8> postInf;
Value<atUint32> knotCount;
struct Knot : BigDNA {
AT_DECL_DNA_YAML
Value<float> time;
Value<float> amplitude;
Value<atUint8> unk1;
Value<atUint8> unk2;
Vector<atVec2f, AT_DNA_COUNT(unk1 == 5)> unk1Floats;
Vector<atVec2f, AT_DNA_COUNT(unk2 == 5)> unk2Floats;
};
Vector<Knot, AT_DNA_COUNT(knotCount)> knots;
Value<atUint8> clampMode;
Value<float> minAmp;
Value<float> maxAmp;
};
} // namespace DataSpec

View File

@ -1,24 +0,0 @@
#pragma once
#include <string>
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace DataSpec {
enum class ERegion { Invalid = -1, NTSC_U = 'E', PAL = 'P', NTSC_J = 'J' };
enum class EGame {
Invalid = 0,
MetroidPrime1,
MetroidPrime2,
MetroidPrime3,
};
struct MetaforceVersionInfo : BigDNA {
AT_DECL_DNA_YAML
String<-1> version;
Value<ERegion> region;
Value<EGame> game;
Value<bool> isTrilogy;
};
} // namespace DataSpec

View File

@ -1,258 +0,0 @@
#include "DataSpec/DNACommon/OBBTreeBuilder.hpp"
#include <cstddef>
#include <unordered_set>
#include <vector>
#include "DataSpec/DNAMP1/DCLN.hpp"
#include <athena/Types.hpp>
#include <gmm/gmm.h>
#include <hecl/Blender/Connection.hpp>
#include <zeus/CTransform.hpp>
namespace DataSpec {
using ColMesh = hecl::blender::ColMesh;
struct FittedOBB {
zeus::CTransform xf;
zeus::CVector3f he;
};
static std::vector<int> MakeRootTriangleIndex(const ColMesh& mesh) {
std::vector<int> ret;
ret.reserve(mesh.trianges.size());
for (size_t i = 0; i < mesh.trianges.size(); ++i)
ret.push_back(i);
return ret;
}
static std::unordered_set<uint32_t> GetTriangleVerts(const ColMesh& mesh, int triIdx) {
const ColMesh::Triangle& T = mesh.trianges[triIdx];
std::unordered_set<uint32_t> verts;
verts.insert(mesh.edges[T.edges[0]].verts[0]);
verts.insert(mesh.edges[T.edges[0]].verts[1]);
verts.insert(mesh.edges[T.edges[1]].verts[0]);
verts.insert(mesh.edges[T.edges[1]].verts[1]);
verts.insert(mesh.edges[T.edges[2]].verts[0]);
verts.insert(mesh.edges[T.edges[2]].verts[1]);
return verts;
}
// method to set the OBB parameters which produce a box oriented according to
// the covariance matrix C, which just containts the points pnts
static FittedOBB BuildFromCovarianceMatrix(gmm::dense_matrix<float>& C, const ColMesh& mesh,
const std::vector<int>& index) {
FittedOBB ret;
// extract the eigenvalues and eigenvectors from C
gmm::dense_matrix<float> eigvec(3, 3);
std::vector<float> eigval(3);
using namespace gmm;
using MAT1 = gmm::dense_matrix<float>;
gmm::symmetric_qr_algorithm(C, eigval, eigvec, default_tol_for_qr);
// find the right, up and forward vectors from the eigenvectors
zeus::CVector3f r(eigvec(0, 0), eigvec(1, 0), eigvec(2, 0));
zeus::CVector3f f(eigvec(0, 1), eigvec(1, 1), eigvec(2, 1));
zeus::CVector3f u(eigvec(0, 2), eigvec(1, 2), eigvec(2, 2));
r.normalize();
f.normalize();
u.normalize();
// set the rotation matrix using the eigvenvectors
ret.xf.basis[0] = r;
ret.xf.basis[1] = f;
ret.xf.basis[2] = u;
ret.xf.orthonormalize();
// now build the bounding box extents in the rotated frame
zeus::CVector3f minim(1e10f, 1e10f, 1e10f), maxim(-1e10f, -1e10f, -1e10f);
for (int triIdx : index) {
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, triIdx);
for (uint32_t v : verts) {
const zeus::CVector3f& p = mesh.verts[v].val;
zeus::CVector3f p_prime(ret.xf.basis[0].dot(p), ret.xf.basis[1].dot(p), ret.xf.basis[2].dot(p));
minim = zeus::min(minim, p_prime);
maxim = zeus::max(maxim, p_prime);
}
}
// set the center of the OBB to be the average of the
// minimum and maximum, and the extents be half of the
// difference between the minimum and maximum
zeus::CVector3f center = (maxim + minim) * 0.5f;
ret.xf.origin = ret.xf.basis * center;
ret.he = (maxim - minim) * 0.5f;
return ret;
}
// builds an OBB from triangles specified as an array of
// points with integer indices into the point array. Forms
// the covariance matrix for the triangles, then uses the
// method build_from_covariance_matrix() method to fit
// the box. ALL points will be fit in the box, regardless
// of whether they are indexed by a triangle or not.
static FittedOBB FitOBB(const ColMesh& mesh, const std::vector<int>& index) {
float Ai, Am = 0.0;
zeus::CVector3f mu, mui;
gmm::dense_matrix<float> C(3, 3);
float cxx = 0.0, cxy = 0.0, cxz = 0.0, cyy = 0.0, cyz = 0.0, czz = 0.0;
// loop over the triangles this time to find the
// mean location
for (int i : index) {
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
auto it = verts.begin();
zeus::CVector3f p = mesh.verts[*it++].val;
zeus::CVector3f q = mesh.verts[*it++].val;
zeus::CVector3f r = mesh.verts[*it++].val;
mui = (p + q + r) / 3.f;
Ai = (q - p).cross(r - p).magnitude() / 2.f;
mu += mui * Ai;
Am += Ai;
// these bits set the c terms to Am*E[xx], Am*E[xy], Am*E[xz]....
cxx += (9.0 * mui.x() * mui.x() + p.x() * p.x() + q.x() * q.x() + r.x() * r.x()) * (Ai / 12.0);
cxy += (9.0 * mui.x() * mui.y() + p.x() * p.y() + q.x() * q.y() + r.x() * r.y()) * (Ai / 12.0);
cxz += (9.0 * mui.x() * mui.z() + p.x() * p.z() + q.x() * q.z() + r.x() * r.z()) * (Ai / 12.0);
cyy += (9.0 * mui.y() * mui.y() + p.y() * p.y() + q.y() * q.y() + r.y() * r.y()) * (Ai / 12.0);
cyz += (9.0 * mui.y() * mui.z() + p.y() * p.z() + q.y() * q.z() + r.y() * r.z()) * (Ai / 12.0);
}
if (zeus::close_enough(Am, 0.f))
return {};
// divide out the Am fraction from the average position and
// covariance terms
mu = mu / Am;
cxx /= Am;
cxy /= Am;
cxz /= Am;
cyy /= Am;
cyz /= Am;
czz /= Am;
// now subtract off the E[x]*E[x], E[x]*E[y], ... terms
cxx -= mu.x() * mu.x();
cxy -= mu.x() * mu.y();
cxz -= mu.x() * mu.z();
cyy -= mu.y() * mu.y();
cyz -= mu.y() * mu.z();
czz -= mu.z() * mu.z();
// now build the covariance matrix
C(0, 0) = cxx;
C(0, 1) = cxy;
C(0, 2) = cxz;
C(1, 0) = cxy;
C(1, 1) = cyy;
C(1, 2) = cyz;
C(2, 0) = cxz;
C(2, 1) = cyz;
C(2, 2) = czz;
// set the obb parameters from the covariance matrix
return BuildFromCovarianceMatrix(C, mesh, index);
}
template <typename Node>
static void MakeLeaf(const ColMesh& mesh, const std::vector<int>& index, Node& n) {
n.left.reset();
n.right.reset();
n.isLeaf = true;
n.leafData = std::make_unique<typename Node::LeafData>();
n.leafData->triangleIndexCount = atUint32(index.size());
n.leafData->triangleIndices.reserve(n.leafData->triangleIndexCount);
for (int i : index)
n.leafData->triangleIndices.push_back(i);
}
template <typename Node>
static std::unique_ptr<Node> RecursiveMakeNode(const ColMesh& mesh, const std::vector<int>& index) {
// calculate root OBB
FittedOBB obb = FitOBB(mesh, index);
// make results row-major and also invert the rotation basis
obb.xf.basis.transpose();
std::unique_ptr<Node> n = std::make_unique<Node>();
for (int i = 0; i < 3; ++i) {
n->xf[i] = zeus::CVector4f{obb.xf.basis[i]};
n->xf[i].simd[3] = float(obb.xf.origin[i]);
}
n->halfExtent = obb.he;
// terminate branch when volume < 1.0
if (obb.he[0] * obb.he[1] * obb.he[2] < 1.f) {
MakeLeaf(mesh, index, *n);
return n;
}
n->isLeaf = false;
std::vector<int> indexNeg[3];
std::vector<int> indexPos[3];
for (int c = 0; c < 3; ++c) {
// subdivide negative side
indexNeg[c].reserve(index.size());
for (int i : index) {
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
for (uint32_t vtx : verts) {
zeus::CVector3f v = mesh.verts[vtx].val;
v = obb.xf.basis * (v - obb.xf.origin);
if (v[c] < 0.f) {
indexNeg[c].push_back(i);
break;
}
}
}
// subdivide positive side
indexPos[c].reserve(index.size());
for (int i : index) {
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
for (uint32_t vtx : verts) {
zeus::CVector3f v = mesh.verts[vtx].val;
v = obb.xf.basis * (v - obb.xf.origin);
if (v[c] >= 0.f) {
indexPos[c].push_back(i);
break;
}
}
}
}
size_t idxMin = index.size();
int minComp = -1;
for (int c = 0; c < 3; ++c) {
size_t test = std::max(indexNeg[c].size(), indexPos[c].size());
if (test < idxMin && test < index.size() * 3 / 4) {
minComp = c;
idxMin = test;
}
}
if (minComp == -1) {
MakeLeaf(mesh, index, *n);
return n;
}
n->left = RecursiveMakeNode<Node>(mesh, indexNeg[minComp]);
n->right = RecursiveMakeNode<Node>(mesh, indexPos[minComp]);
return n;
}
template <typename Node>
std::unique_ptr<Node> OBBTreeBuilder::buildCol(const ColMesh& mesh) {
std::vector<int> root = MakeRootTriangleIndex(mesh);
return RecursiveMakeNode<Node>(mesh, root);
}
template std::unique_ptr<DNAMP1::DCLN::Collision::Node>
OBBTreeBuilder::buildCol<DNAMP1::DCLN::Collision::Node>(const ColMesh& mesh);
} // namespace DataSpec

View File

@ -1,15 +0,0 @@
#pragma once
#include <memory>
#include <hecl/Blender/Connection.hpp>
namespace DataSpec {
struct OBBTreeBuilder {
using ColMesh = hecl::blender::ColMesh;
template <typename Node>
static std::unique_ptr<Node> buildCol(const ColMesh& mesh);
};
} // namespace DataSpec

View File

@ -1,679 +0,0 @@
#include "DataSpec/DNACommon/PAK.hpp"
#include "DataSpec/DNAMP1/DNAMP1.hpp"
#include "DataSpec/DNAMP2/DNAMP2.hpp"
#include "DataSpec/DNAMP3/DNAMP3.hpp"
namespace DataSpec {
template <class PAKBRIDGE>
void UniqueResult::checkEntry(const PAKBRIDGE& pakBridge, const typename PAKBRIDGE::PAKType::Entry& entry) {
UniqueResult::Type resultType = UniqueResult::Type::NotFound;
bool foundOneLayer = false;
const std::string* levelName = nullptr;
typename PAKBRIDGE::PAKType::IDType useLevelId;
typename PAKBRIDGE::PAKType::IDType useAreaId;
unsigned layerIdx = 0;
for (const auto& [levelId, level] : pakBridge.m_levelDeps) {
if (entry.id == levelId || level.resources.find(entry.id) != level.resources.end()) {
levelName = &level.name;
resultType = UniqueResult::Type::Level;
break;
}
for (const auto& [areaId, area] : level.areas) {
unsigned l = 0;
for (const auto& layer : area.layers) {
if (layer.resources.find(entry.id) != layer.resources.end()) {
if (foundOneLayer) {
if (useAreaId == areaId) {
resultType = UniqueResult::Type::Area;
} else if (useLevelId == levelId) {
resultType = UniqueResult::Type::Level;
break;
} else {
m_type = UniqueResult::Type::Pak;
return;
}
continue;
} else
resultType = UniqueResult::Type::Layer;
levelName = &level.name;
useLevelId = levelId;
useAreaId = areaId;
layerIdx = l;
foundOneLayer = true;
}
++l;
}
if (area.resources.find(entry.id) != area.resources.end()) {
if (foundOneLayer) {
if (useAreaId == areaId) {
resultType = UniqueResult::Type::Area;
} else if (useLevelId == levelId) {
resultType = UniqueResult::Type::Level;
break;
} else {
m_type = UniqueResult::Type::Pak;
return;
}
continue;
} else
resultType = UniqueResult::Type::Area;
levelName = &level.name;
useLevelId = levelId;
useAreaId = areaId;
foundOneLayer = true;
}
}
}
m_type = resultType;
m_levelName = levelName;
if (resultType == UniqueResult::Type::Layer || resultType == UniqueResult::Type::Area) {
const typename PAKBRIDGE::Level::Area& area = pakBridge.m_levelDeps.at(useLevelId).areas.at(useAreaId);
m_areaName = &area.name;
if (resultType == UniqueResult::Type::Layer) {
const typename PAKBRIDGE::Level::Area::Layer& layer = area.layers[layerIdx];
m_layerName = &layer.name;
}
}
}
template void UniqueResult::checkEntry(const DNAMP1::PAKBridge& pakBridge,
const DNAMP1::PAKBridge::PAKType::Entry& entry);
template void UniqueResult::checkEntry(const DNAMP2::PAKBridge& pakBridge,
const DNAMP2::PAKBridge::PAKType::Entry& entry);
template void UniqueResult::checkEntry(const DNAMP3::PAKBridge& pakBridge,
const DNAMP3::PAKBridge::PAKType::Entry& entry);
hecl::ProjectPath UniqueResult::uniquePath(const hecl::ProjectPath& pakPath) const {
if (m_type == Type::Pak)
return pakPath;
hecl::ProjectPath levelDir;
if (m_levelName)
levelDir.assign(pakPath, *m_levelName);
else
levelDir = pakPath;
if (m_type == Type::Area) {
hecl::ProjectPath areaDir(levelDir, *m_areaName);
return areaDir;
} else if (m_type == Type::Layer) {
hecl::ProjectPath areaDir(levelDir, *m_areaName);
hecl::ProjectPath layerDir(areaDir, *m_layerName);
return layerDir;
}
return levelDir;
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress) {
m_bridges = &bridges;
m_bridgePaths.clear();
m_uniqueEntries.clear();
m_sharedEntries.clear();
m_charAssoc.m_cmdlRigs.clear();
size_t count = 0;
float bridgesSz = bridges.size();
/* Route entries unique/shared per-pak */
size_t bridgeIdx = 0;
for (BRIDGETYPE& bridge : bridges) {
const auto& name = bridge.getName();
std::string_view::const_iterator extit = name.end() - 4;
std::string baseName(name.begin(), extit);
m_bridgePaths.emplace_back(
std::make_pair(hecl::ProjectPath(m_gameWorking, baseName), hecl::ProjectPath(m_gameCooked, baseName)));
/* Index this PAK */
bridge.build();
/* Add to global entry lookup */
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& entry : pak.m_entries) {
if (!pak.m_noShare) {
auto sSearch = m_sharedEntries.find(entry.first);
if (sSearch != m_sharedEntries.end())
continue;
auto uSearch = m_uniqueEntries.find(entry.first);
if (uSearch != m_uniqueEntries.end()) {
m_uniqueEntries.erase(uSearch);
m_sharedEntries[entry.first] = std::make_pair(bridgeIdx, &entry.second);
} else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, &entry.second);
} else
m_uniqueEntries[entry.first] = std::make_pair(bridgeIdx, &entry.second);
}
/* Add RigPairs to global map */
bridge.addCMDLRigPairs(*this, m_charAssoc);
progress(++count / bridgesSz);
++bridgeIdx;
}
/* Add named resources to catalog YAML files */
for (BRIDGETYPE& bridge : bridges) {
athena::io::YAMLDocWriter catalogWriter;
enterPAKBridge(bridge);
/* Add MAPA transforms to global map */
bridge.addMAPATransforms(*this, m_mapaTransforms, m_overrideEntries);
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
for (const auto& namedEntry : pak.m_nameEntries) {
if (namedEntry.name == "holo_cinf")
continue; /* Problematic corner case */
if (auto rec = catalogWriter.enterSubRecord(namedEntry.name)) {
hecl::ProjectPath working = getWorking(namedEntry.id);
if (working.getAuxInfo().size()) {
if (auto v = catalogWriter.enterSubVector()) {
catalogWriter.writeString(working.getRelativePath());
catalogWriter.writeString(working.getAuxInfo());
}
} else
catalogWriter.writeString(working.getRelativePath());
}
}
/* Write catalog */
intptr_t curBridgeIdx = reinterpret_cast<intptr_t>(m_curBridgeIdx.get());
const hecl::ProjectPath& pakPath = m_bridgePaths[curBridgeIdx].first;
pakPath.makeDirChain(true);
athena::io::FileWriter writer(hecl::ProjectPath(pakPath, "!catalog.yaml").getAbsolutePath());
catalogWriter.finish(&writer);
}
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::enterPAKBridge(const BRIDGETYPE& pakBridge) {
g_PakRouter.reset(this);
auto pit = m_bridgePaths.begin();
size_t bridgeIdx = 0;
for (const BRIDGETYPE& bridge : *m_bridges) {
if (&bridge == &pakBridge) {
m_pak.reset(&pakBridge.getPAK());
m_node.reset(&pakBridge.getNode());
m_curBridgeIdx.reset(reinterpret_cast<void*>(bridgeIdx));
return;
}
++pit;
++bridgeIdx;
}
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKBridge provided to PAKRouter::enterPAKBridge() was not part of build()"));
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getCharacterWorking(const EntryType* entry) const {
auto characterSearch = m_charAssoc.m_cskrToCharacter.find(entry->id);
if (characterSearch != m_charAssoc.m_cskrToCharacter.cend()) {
hecl::ProjectPath characterPath = getWorking(characterSearch->second.first);
if (entry->type == FOURCC('EVNT')) {
std::string extension(characterSearch->second.second);
return characterPath.getWithExtension((std::string(".") + extension.c_str()).c_str(), true);
}
return characterPath.ensureAuxInfo(characterSearch->second.second);
}
return {};
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const EntryType* entry,
const ResExtractor<BRIDGETYPE>& extractor) const {
if (!entry)
return hecl::ProjectPath();
auto overrideSearch = m_overrideEntries.find(entry->id);
if (overrideSearch != m_overrideEntries.end())
return overrideSearch->second;
const PAKType* pak = m_pak.get();
intptr_t curBridgeIdx = reinterpret_cast<intptr_t>(m_curBridgeIdx.get());
if (pak && pak->m_noShare) {
const EntryType* singleSearch = pak->lookupEntry(entry->id);
if (singleSearch) {
const hecl::ProjectPath& pakPath = m_bridgePaths[curBridgeIdx].first;
std::string entName = getBestEntryName(*entry);
std::string auxInfo;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
else if (extractor.fileExts[0])
entName += ".*";
else if (hecl::ProjectPath chWork = getCharacterWorking(entry))
return chWork;
return hecl::ProjectPath(pakPath, entName).ensureAuxInfo(auxInfo);
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end()) {
const BRIDGETYPE& bridge = m_bridges->at(uniqueSearch->second.first);
const hecl::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].first;
std::string entName = getBestEntryName(*entry);
std::string auxInfo;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
else if (extractor.fileExts[0])
entName += ".*";
else if (hecl::ProjectPath chWork = getCharacterWorking(entry))
return chWork;
if (bridge.getPAK().m_noShare) {
return hecl::ProjectPath(pakPath, entName).ensureAuxInfo(auxInfo);
} else {
hecl::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
return hecl::ProjectPath(uniquePath, entName).ensureAuxInfo(auxInfo);
}
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end()) {
std::string entBase = getBestEntryName(*entry);
std::string auxInfo;
std::string entName = entBase;
if (extractor.fileExts[0] && !extractor.fileExts[1])
entName += extractor.fileExts[0];
else if (extractor.fileExts[0])
entName += ".*";
else if (hecl::ProjectPath chWork = getCharacterWorking(entry))
return chWork;
hecl::ProjectPath sharedPath(m_sharedWorking, entName);
return sharedPath.ensureAuxInfo(auxInfo);
}
LogDNACommon.report(logvisor::Fatal, FMT_STRING("Unable to find entry {}"), entry->id);
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const EntryType* entry) const {
if (!entry)
return hecl::ProjectPath();
return getWorking(entry, BRIDGETYPE::LookupExtractor(*m_node.get(), *m_pak.get(), *entry));
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getWorking(const IDType& id, bool silenceWarnings) const {
return getWorking(lookupEntry(id, nullptr, silenceWarnings, false));
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getCooked(const EntryType* entry) const {
if (!entry)
return hecl::ProjectPath();
auto overrideSearch = m_overrideEntries.find(entry->id);
if (overrideSearch != m_overrideEntries.end()) {
return overrideSearch->second.getCookedPath(
*m_dataSpec.overrideDataSpec(overrideSearch->second, m_dataSpec.getDataSpecEntry()));
}
const PAKType* pak = m_pak.get();
intptr_t curBridgeIdx = reinterpret_cast<intptr_t>(m_curBridgeIdx.get());
if (pak && pak->m_noShare) {
const EntryType* singleSearch = pak->lookupEntry(entry->id);
if (singleSearch) {
const hecl::ProjectPath& pakPath = m_bridgePaths[curBridgeIdx].second;
return hecl::ProjectPath(pakPath, getBestEntryName(*entry));
}
}
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end()) {
const BRIDGETYPE& bridge = m_bridges->at(uniqueSearch->second.first);
const hecl::ProjectPath& pakPath = m_bridgePaths[uniqueSearch->second.first].second;
if (bridge.getPAK().m_noShare) {
return hecl::ProjectPath(pakPath, getBestEntryName(*entry));
} else {
hecl::ProjectPath uniquePath = entry->unique.uniquePath(pakPath);
return hecl::ProjectPath(uniquePath, getBestEntryName(*entry));
}
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end()) {
return hecl::ProjectPath(m_sharedCooked, getBestEntryName(*entry));
}
LogDNACommon.report(logvisor::Fatal, FMT_STRING("Unable to find entry {}"), entry->id);
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getCooked(const IDType& id, bool silenceWarnings) const {
return getCooked(lookupEntry(id, nullptr, silenceWarnings, false));
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getResourceRelativePath(const EntryType& a, const IDType& b) const {
const nod::Node* node = m_node.get();
const PAKType* pak = m_pak.get();
if (!pak)
LogDNACommon.report(
logvisor::Fatal,
FMT_STRING("PAKRouter::enterPAKBridge() must be called before PAKRouter::getResourceRelativePath()"));
const typename BRIDGETYPE::PAKType::Entry* be = lookupEntry(b);
if (!be)
return std::string();
hecl::ProjectPath aPath = getWorking(&a, BRIDGETYPE::LookupExtractor(*node, *pak, a));
std::string ret;
for (size_t i = 0; i < aPath.levelCount(); ++i)
ret += "../";
hecl::ProjectPath bPath = getWorking(be, BRIDGETYPE::LookupExtractor(*node, *pak, *be));
ret += bPath.getRelativePath();
return ret;
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getBestEntryName(const EntryType& entry, bool stdOverride) const {
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges) {
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
const typename BRIDGETYPE::PAKType::Entry* e = pak.lookupEntry(entry.id);
if (!e)
continue;
if (stdOverride && !pak.m_noShare) {
if (entry.type == FOURCC('MLVL'))
return fmt::format(FMT_STRING("!world_{}"), entry.id);
else if (entry.type == FOURCC('MREA'))
return fmt::format(FMT_STRING("!area_{}"), entry.id);
else if (entry.type == FOURCC('MAPA'))
return fmt::format(FMT_STRING("!map_{}"), entry.id);
else if (entry.type == FOURCC('PATH'))
return fmt::format(FMT_STRING("!path_{}"), entry.id);
else if (entry.type == FOURCC('MAPW'))
return fmt::format(FMT_STRING("!mapw_{}"), entry.id);
else if (entry.type == FOURCC('SAVW'))
return fmt::format(FMT_STRING("!savw_{}"), entry.id);
}
std::string catalogueName;
name = pak.bestEntryName(bridge.getNode(), entry, catalogueName);
if (!catalogueName.empty())
return name;
}
return name;
}
template <class BRIDGETYPE>
std::string PAKRouter<BRIDGETYPE>::getBestEntryName(const IDType& entry, bool stdOverride) const {
std::string name;
for (const BRIDGETYPE& bridge : *m_bridges) {
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
const typename BRIDGETYPE::PAKType::Entry* e = pak.lookupEntry(entry);
if (!e)
continue;
if (stdOverride && !pak.m_noShare) {
if (e->type == FOURCC('MLVL'))
return fmt::format(FMT_STRING("!world_{}"), e->id);
else if (e->type == FOURCC('MREA'))
return fmt::format(FMT_STRING("!area_{}"), e->id);
else if (e->type == FOURCC('MAPA'))
return fmt::format(FMT_STRING("!map_{}"), e->id);
else if (e->type == FOURCC('PATH'))
return fmt::format(FMT_STRING("!path_{}"), e->id);
else if (e->type == FOURCC('MAPW'))
return fmt::format(FMT_STRING("!mapw_{}"), e->id);
else if (e->type == FOURCC('SAVW'))
return fmt::format(FMT_STRING("!savw_{}"), e->id);
}
std::string catalogueName;
name = pak.bestEntryName(bridge.getNode(), *e, catalogueName);
if (!catalogueName.empty())
return name;
}
return name;
}
template <class BRIDGETYPE>
bool PAKRouter<BRIDGETYPE>::extractResources(const BRIDGETYPE& pakBridge, bool force, hecl::blender::Token& btok,
std::function<void(const char*, float)> progress) {
enterPAKBridge(pakBridge);
size_t count = 0;
size_t sz = m_pak->m_entries.size();
float fsz = sz;
for (unsigned w = 0; count < sz; ++w) {
for (const auto& item : m_pak->m_firstEntries) {
const auto* entryPtr = m_pak->lookupEntry(item);
ResExtractor<BRIDGETYPE> extractor = BRIDGETYPE::LookupExtractor(*m_node.get(), *m_pak.get(), *entryPtr);
if (extractor.weight != w)
continue;
std::string bestName = getBestEntryName(*entryPtr, false);
float thisFac = ++count / fsz;
progress(bestName.c_str(), thisFac);
const nod::Node* node = m_node.get();
hecl::ProjectPath working = getWorking(entryPtr, extractor);
working.makeDirChain(false);
hecl::ResourceLock resLk(working);
if (!resLk)
continue;
/* Extract to unmodified directory */
hecl::ProjectPath cooked = working.getCookedPath(m_dataSpec.getUnmodifiedSpec());
if (force || cooked.isNone()) {
cooked.makeDirChain(false);
PAKEntryReadStream s = entryPtr->beginReadStream(*node);
const auto fout = hecl::FopenUnique(cooked.getAbsolutePath().data(), "wb");
std::fwrite(s.data(), 1, s.length(), fout.get());
}
if (extractor.func_a) /* Doesn't need PAKRouter access */
{
if (force || !extractor.IsFullyExtracted(working)) {
PAKEntryReadStream s = entryPtr->beginReadStream(*node);
extractor.func_a(s, working);
}
} else if (extractor.func_b) /* Needs PAKRouter access */
{
if (force || !extractor.IsFullyExtracted(working)) {
PAKEntryReadStream s = entryPtr->beginReadStream(*node);
extractor.func_b(m_dataSpec, s, working, *this, *entryPtr, force, btok,
[&progress, thisFac](const char* update) { progress(update, thisFac); });
}
}
}
}
return true;
}
template <class BRIDGETYPE>
const typename BRIDGETYPE::PAKType::Entry*
PAKRouter<BRIDGETYPE>::lookupEntry(const IDType& entry, const nod::Node** nodeOut, bool silenceWarnings,
bool currentPAK) const {
if (!entry.isValid())
return nullptr;
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKRouter::build() must be called before PAKRouter::lookupEntry()"));
const PAKType* pak = m_pak.get();
const nod::Node* node = m_node.get();
if (pak) {
const EntryType* ent = pak->lookupEntry(entry);
if (ent) {
if (nodeOut)
*nodeOut = node;
return ent;
}
}
if (currentPAK) {
#ifndef NDEBUG
if (!silenceWarnings)
LogDNACommon.report(logvisor::Warning, FMT_STRING("unable to find PAK entry {} in current PAK"), entry);
#endif
return nullptr;
}
for (const BRIDGETYPE& bridge : *m_bridges) {
const PAKType& pak = bridge.getPAK();
const EntryType* ent = pak.lookupEntry(entry);
if (ent) {
if (nodeOut)
*nodeOut = &bridge.getNode();
return ent;
}
}
#ifndef NDEBUG
if (!silenceWarnings)
LogDNACommon.report(logvisor::Warning, FMT_STRING("unable to find PAK entry {}"), entry);
#endif
if (nodeOut)
*nodeOut = nullptr;
return nullptr;
}
template <class BRIDGETYPE>
const typename CharacterAssociations<typename PAKRouter<BRIDGETYPE>::IDType>::RigPair*
PAKRouter<BRIDGETYPE>::lookupCMDLRigPair(const IDType& id) const {
auto search = m_charAssoc.m_cmdlRigs.find(id);
if (search == m_charAssoc.m_cmdlRigs.end())
return nullptr;
return &search->second;
}
template <class BRIDGETYPE>
const typename CharacterAssociations<typename PAKRouter<BRIDGETYPE>::IDType>::MultimapIteratorPair
PAKRouter<BRIDGETYPE>::lookupCharacterAttachmentRigs(const IDType& id) const {
return m_charAssoc.m_characterToAttachmentRigs.equal_range(id);
}
template <class BRIDGETYPE>
const zeus::CMatrix4f* PAKRouter<BRIDGETYPE>::lookupMAPATransform(const IDType& id) const {
auto search = m_mapaTransforms.find(id);
if (search == m_mapaTransforms.end())
return nullptr;
return &search->second;
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerWorking(const IDType& areaId, int layerIdx) const {
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->first, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return hecl::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerWorking(const IDType& areaId, int layerIdx,
bool& activeOut) const {
activeOut = false;
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->first, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
const typename Level<IDType>::Area::Layer& layer = area.second.layers.at(layerIdx);
activeOut = layer.active;
return hecl::ProjectPath(areaPath, layer.name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerCooked(const IDType& areaId, int layerIdx) const {
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->second, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
return hecl::ProjectPath(areaPath, area.second.layers.at(layerIdx).name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
hecl::ProjectPath PAKRouter<BRIDGETYPE>::getAreaLayerCooked(const IDType& areaId, int layerIdx, bool& activeOut) const {
activeOut = false;
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()"));
auto bridgePathIt = m_bridgePaths.cbegin();
for (const BRIDGETYPE& bridge : *m_bridges) {
for (const auto& level : bridge.m_levelDeps)
for (const auto& area : level.second.areas)
if (area.first == areaId) {
hecl::ProjectPath levelPath(bridgePathIt->second, level.second.name);
hecl::ProjectPath areaPath(levelPath, area.second.name);
if (layerIdx < 0)
return areaPath;
const typename Level<IDType>::Area::Layer& layer = area.second.layers.at(layerIdx);
activeOut = layer.active;
return hecl::ProjectPath(areaPath, layer.name);
}
++bridgePathIt;
}
return hecl::ProjectPath();
}
template <class BRIDGETYPE>
void PAKRouter<BRIDGETYPE>::enumerateResources(const std::function<bool(const EntryType*)>& func) {
if (!m_bridges)
LogDNACommon.report(logvisor::Fatal,
FMT_STRING("PAKRouter::build() must be called before PAKRouter::enumerateResources()"));
for (const auto& entryPair : m_uniqueEntries)
if (!func(entryPair.second.second))
return;
for (const auto& entryPair : m_sharedEntries)
if (!func(entryPair.second.second))
return;
}
template <class BRIDGETYPE>
bool PAKRouter<BRIDGETYPE>::mreaHasDupeResources(const IDType& id) const {
const PAKType* pak = m_pak.get();
if (!pak)
LogDNACommon.report(
logvisor::Fatal,
FMT_STRING("PAKRouter::enterPAKBridge() must be called before PAKRouter::mreaHasDupeResources()"));
return pak->mreaHasDupeResources(id);
}
template class PAKRouter<DNAMP1::PAKBridge>;
template class PAKRouter<DNAMP2::PAKBridge>;
template class PAKRouter<DNAMP3::PAKBridge>;
} // namespace DataSpec

View File

@ -1,234 +0,0 @@
#pragma once
#include <array>
#include <cstring>
#include <functional>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include <boo/ThreadLocalPtr.hpp>
#include <zeus/CMatrix4f.hpp>
#include <zeus/Global.hpp>
namespace DataSpec {
/** PAK entry stream reader */
class PAKEntryReadStream : public athena::io::IStreamReader {
std::unique_ptr<atUint8[]> m_buf;
atUint64 m_sz = 0;
atUint64 m_pos = 0;
public:
PAKEntryReadStream() = default;
explicit operator bool() const { return m_buf.operator bool(); }
PAKEntryReadStream(const PAKEntryReadStream& other) = delete;
PAKEntryReadStream(PAKEntryReadStream&& other) = default;
PAKEntryReadStream& operator=(const PAKEntryReadStream& other) = delete;
PAKEntryReadStream& operator=(PAKEntryReadStream&& other) = default;
PAKEntryReadStream(std::unique_ptr<atUint8[]>&& buf, atUint64 sz, atUint64 pos)
: m_buf(std::move(buf)), m_sz(sz), m_pos(pos) {
if (m_pos >= m_sz)
LogDNACommon.report(logvisor::Fatal, FMT_STRING("PAK stream cursor overrun"));
}
void seek(atInt64 pos, athena::SeekOrigin origin) override {
if (origin == athena::SeekOrigin::Begin) {
m_pos = pos;
} else if (origin == athena::SeekOrigin::Current) {
m_pos += pos;
} else if (origin == athena::SeekOrigin::End) {
m_pos = m_sz + pos;
}
if (m_pos > m_sz) {
LogDNACommon.report(logvisor::Fatal, FMT_STRING("PAK stream cursor overrun"));
}
}
atUint64 position() const override { return m_pos; }
atUint64 length() const override { return m_sz; }
const atUint8* data() const { return m_buf.get(); }
atUint64 readUBytesToBuf(void* buf, atUint64 len) override {
atUint64 bufEnd = m_pos + len;
if (bufEnd > m_sz)
len -= bufEnd - m_sz;
memmove(buf, m_buf.get() + m_pos, len);
m_pos += len;
return len;
}
};
struct UniqueResult {
enum class Type { NotFound, Pak, Level, Area, Layer } m_type = Type::NotFound;
const std::string* m_levelName = nullptr;
const std::string* m_areaName = nullptr;
const std::string* m_layerName = nullptr;
UniqueResult() = default;
UniqueResult(Type tp) : m_type(tp) {}
template <class PAKBRIDGE>
void checkEntry(const PAKBRIDGE& pakBridge, const typename PAKBRIDGE::PAKType::Entry& entry);
hecl::ProjectPath uniquePath(const hecl::ProjectPath& pakPath) const;
};
template <class BRIDGETYPE>
class PAKRouter;
/** Resource extractor type */
template <class PAKBRIDGE>
struct ResExtractor {
std::function<bool(PAKEntryReadStream&, const hecl::ProjectPath&)> func_a;
std::function<bool(const SpecBase&, PAKEntryReadStream&, const hecl::ProjectPath&, PAKRouter<PAKBRIDGE>&,
const typename PAKBRIDGE::PAKType::Entry&, bool, hecl::blender::Token&,
std::function<void(const char*)>)>
func_b;
std::array<const char*, 6> fileExts = {};
unsigned weight = 0;
std::function<void(const SpecBase&, PAKEntryReadStream&, PAKRouter<PAKBRIDGE>&, typename PAKBRIDGE::PAKType::Entry&)>
func_name;
ResExtractor() = default;
ResExtractor(std::function<bool(PAKEntryReadStream&, const hecl::ProjectPath&)> func,
std::array<const char*, 6>&& fileExtsIn, unsigned weightin = 0,
std::function<void(const SpecBase&, PAKEntryReadStream&, PAKRouter<PAKBRIDGE>&,
typename PAKBRIDGE::PAKType::Entry&)>
nfunc = {})
: func_a(std::move(func)), fileExts(std::move(fileExtsIn)), weight(weightin), func_name(std::move(nfunc)) {}
ResExtractor(std::function<bool(const SpecBase&, PAKEntryReadStream&, const hecl::ProjectPath&, PAKRouter<PAKBRIDGE>&,
const typename PAKBRIDGE::PAKType::Entry&, bool, hecl::blender::Token&,
std::function<void(const char*)>)>
func,
std::array<const char*, 6>&& fileExtsIn, unsigned weightin = 0,
std::function<void(const SpecBase&, PAKEntryReadStream&, PAKRouter<PAKBRIDGE>&,
typename PAKBRIDGE::PAKType::Entry&)>
nfunc = {})
: func_b(std::move(func)), fileExts(std::move(fileExtsIn)), weight(weightin), func_name(std::move(nfunc)) {}
bool IsFullyExtracted(const hecl::ProjectPath& path) const {
hecl::ProjectPath::Type tp = path.getPathType();
if (tp == hecl::ProjectPath::Type::None)
return false;
else if (tp == hecl::ProjectPath::Type::Glob) {
for (int i = 0; i < 6; ++i) {
if (!fileExts[i])
break;
hecl::ProjectPath withExt = path.getWithExtension(fileExts[i], true);
if (withExt.isNone())
return false;
}
}
return true;
}
};
/** Level hierarchy representation */
template <class IDType>
struct Level {
std::string name;
struct Area {
std::string name;
struct Layer {
std::string name;
bool active;
std::unordered_set<IDType> resources;
};
std::vector<Layer> layers;
std::unordered_set<IDType> resources;
};
std::unordered_map<IDType, Area> areas;
std::unordered_set<IDType> resources;
};
/** PAKRouter (for detecting shared entry locations) */
template <class BRIDGETYPE>
class PAKRouter : public PAKRouterBase {
public:
using PAKType = typename BRIDGETYPE::PAKType;
using IDType = typename PAKType::IDType;
using EntryType = typename PAKType::Entry;
private:
const std::vector<BRIDGETYPE>* m_bridges = nullptr;
std::vector<std::pair<hecl::ProjectPath, hecl::ProjectPath>> m_bridgePaths;
ThreadLocalPtr<void> m_curBridgeIdx;
const hecl::ProjectPath& m_gameWorking;
const hecl::ProjectPath& m_gameCooked;
hecl::ProjectPath m_sharedWorking;
hecl::ProjectPath m_sharedCooked;
ThreadLocalPtr<const PAKType> m_pak;
ThreadLocalPtr<const nod::Node> m_node;
std::unordered_map<IDType, std::pair<size_t, const EntryType*>> m_uniqueEntries;
std::unordered_map<IDType, std::pair<size_t, const EntryType*>> m_sharedEntries;
std::unordered_map<IDType, hecl::ProjectPath> m_overrideEntries;
CharacterAssociations<IDType> m_charAssoc;
std::unordered_map<IDType, zeus::CMatrix4f> m_mapaTransforms;
hecl::ProjectPath getCharacterWorking(const EntryType* entry) const;
public:
PAKRouter(const SpecBase& dataSpec, const hecl::ProjectPath& working, const hecl::ProjectPath& cooked)
: PAKRouterBase(dataSpec)
, m_gameWorking(working)
, m_gameCooked(cooked)
, m_sharedWorking(working, "Shared")
, m_sharedCooked(cooked, "Shared") {}
void build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress);
void enterPAKBridge(const BRIDGETYPE& pakBridge);
const BRIDGETYPE& getCurrentBridge() const { return (*m_bridges)[reinterpret_cast<intptr_t>(m_curBridgeIdx.get())]; }
using PAKRouterBase::getWorking;
hecl::ProjectPath getWorking(const EntryType* entry, const ResExtractor<BRIDGETYPE>& extractor) const;
hecl::ProjectPath getWorking(const EntryType* entry) const;
hecl::ProjectPath getWorking(const IDType& id, bool silenceWarnings = false) const override;
hecl::ProjectPath getCooked(const EntryType* entry) const;
hecl::ProjectPath getCooked(const IDType& id, bool silenceWarnings = false) const;
std::string getResourceRelativePath(const EntryType& a, const IDType& b) const;
std::string getBestEntryName(const EntryType& entry, bool stdOverride = true) const;
std::string getBestEntryName(const IDType& entry, bool stdOverride = true) const;
bool extractResources(const BRIDGETYPE& pakBridge, bool force, hecl::blender::Token& btok,
std::function<void(const char*, float)> progress);
const typename BRIDGETYPE::PAKType::Entry* lookupEntry(const IDType& entry, const nod::Node** nodeOut = nullptr,
bool silenceWarnings = false, bool currentPAK = false) const;
template <typename DNA>
bool lookupAndReadDNA(const IDType& id, DNA& out, bool silenceWarnings = false) {
const nod::Node* node;
const EntryType* entry = lookupEntry(id, &node, silenceWarnings);
if (!entry)
return false;
PAKEntryReadStream rs = entry->beginReadStream(*node);
out.read(rs);
return true;
}
PAKEntryReadStream beginReadStreamForId(const IDType& id, bool silenceWarnings = false) {
const nod::Node* node;
const EntryType* entry = lookupEntry(id, &node, silenceWarnings);
return entry->beginReadStream(*node);
}
const typename CharacterAssociations<IDType>::RigPair* lookupCMDLRigPair(const IDType& id) const;
const typename CharacterAssociations<IDType>::MultimapIteratorPair
lookupCharacterAttachmentRigs(const IDType& id) const;
const zeus::CMatrix4f* lookupMAPATransform(const IDType& mapaId) const;
hecl::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx) const;
hecl::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx, bool& activeOut) const;
hecl::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx) const;
hecl::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx, bool& activeOut) const;
void enumerateResources(const std::function<bool(const EntryType*)>& func);
bool mreaHasDupeResources(const IDType& id) const;
};
} // namespace DataSpec

View File

@ -1,51 +0,0 @@
#include "DataSpec/DNACommon/PART.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNAParticle {
template struct PPImpl<_GPSM<UniqueID32>>;
template struct PPImpl<_GPSM<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_GPSM<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_GPSM<UniqueID64>>)
template <>
std::string_view GPSM<UniqueID32>::DNAType() {
return "GPSM<UniqueID32>"sv;
}
template <>
std::string_view GPSM<UniqueID64>::DNAType() {
return "GPSM<UniqueID64>"sv;
}
template <class IDType>
bool ExtractGPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
GPSM<IDType> gpsm;
gpsm.read(rs);
athena::io::ToYAMLStream(gpsm, writer);
return true;
}
return false;
}
template bool ExtractGPSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractGPSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteGPSM(const GPSM<IDType>& gpsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
gpsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteGPSM<UniqueID32>(const GPSM<UniqueID32>& gpsm, const hecl::ProjectPath& outPath);
template bool WriteGPSM<UniqueID64>(const GPSM<UniqueID64>& gpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,141 +0,0 @@
#ifndef ENTRY
#define ENTRY(name, identifier)
#endif
#ifndef INT_ENTRY
#define INT_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef REAL_ENTRY
#define REAL_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef VECTOR_ENTRY
#define VECTOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef MOD_VECTOR_ENTRY
#define MOD_VECTOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef COLOR_ENTRY
#define COLOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef EMITTER_ENTRY
#define EMITTER_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef UV_ENTRY
#define UV_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef RES_ENTRY
#define RES_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef KSSM_ENTRY
#define KSSM_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef BOOL_ENTRY
#define BOOL_ENTRY(name, identifier, def) ENTRY(name, identifier)
#endif
VECTOR_ENTRY('PSIV', x0_PSIV)
MOD_VECTOR_ENTRY('PSVM', x4_PSVM)
VECTOR_ENTRY('PSOV', x8_PSOV)
INT_ENTRY('PSLT', xc_PSLT)
INT_ENTRY('PSWT', x10_PSWT)
REAL_ENTRY('PSTS', x14_PSTS)
VECTOR_ENTRY('POFS', x18_POFS)
INT_ENTRY('SEED', x1c_SEED)
REAL_ENTRY('LENG', x20_LENG)
REAL_ENTRY('WIDT', x24_WIDT)
INT_ENTRY('MAXP', x28_MAXP)
REAL_ENTRY('GRTE', x2c_GRTE)
COLOR_ENTRY('COLR', x30_COLR)
INT_ENTRY('LTME', x34_LTME)
VECTOR_ENTRY('ILOC', x38_ILOC)
VECTOR_ENTRY('IVEC', x3c_IVEC)
EMITTER_ENTRY('EMTR', x40_EMTR)
INT_ENTRY('MBSP', x48_MBSP)
REAL_ENTRY('SIZE', x4c_SIZE)
REAL_ENTRY('ROTA', x50_ROTA)
UV_ENTRY('TEXR', x54_TEXR)
UV_ENTRY('TIND', x58_TIND)
RES_ENTRY('PMDL', x5c_PMDL)
VECTOR_ENTRY('PMOP', x6c_PMOP)
VECTOR_ENTRY('PMRT', x70_PMRT)
VECTOR_ENTRY('PMSC', x74_PMSC)
COLOR_ENTRY('PMCL', x78_PMCL)
MOD_VECTOR_ENTRY('VEL1', x7c_VEL1)
MOD_VECTOR_ENTRY('VEL2', x80_VEL2)
MOD_VECTOR_ENTRY('VEL3', x84_VEL3)
MOD_VECTOR_ENTRY('VEL4', x88_VEL4)
RES_ENTRY('ICTS', x8c_ICTS)
INT_ENTRY('NCSY', x9c_NCSY)
INT_ENTRY('CSSD', xa0_CSSD)
RES_ENTRY('IDTS', xa4_IDTS)
INT_ENTRY('NDSY', xb4_NDSY)
RES_ENTRY('IITS', xb8_IITS)
INT_ENTRY('PISY', xc8_PISY)
INT_ENTRY('SISY', xcc_SISY)
KSSM_ENTRY('KSSM', xd0_KSSM)
RES_ENTRY('SSWH', xd4_SSWH)
INT_ENTRY('SSSD', xe4_SSSD)
VECTOR_ENTRY('SSPO', xe8_SSPO)
INT_ENTRY('SESD', xf8_SESD)
VECTOR_ENTRY('SEPO', xfc_SEPO)
RES_ENTRY('PMLC', xec_PMLC)
INT_ENTRY('LTYP', x100_LTYP)
COLOR_ENTRY('LCLR', x104_LCLR)
REAL_ENTRY('LINT', x108_LINT)
VECTOR_ENTRY('LOFF', x10c_LOFF)
VECTOR_ENTRY('LDIR', x110_LDIR)
INT_ENTRY('LFOT', x114_LFOT)
REAL_ENTRY('LFOR', x118_LFOR)
REAL_ENTRY('LSLA', x11c_LSLA)
/* 0-00 additions */
RES_ENTRY('SELC', xd8_SELC)
REAL_ENTRY('ADV1', x10c_ADV1)
REAL_ENTRY('ADV2', x110_ADV2)
REAL_ENTRY('ADV3', x114_ADV3)
REAL_ENTRY('ADV4', x118_ADV4)
REAL_ENTRY('ADV5', x11c_ADV5)
REAL_ENTRY('ADV6', x120_ADV6)
REAL_ENTRY('ADV7', x124_ADV7)
REAL_ENTRY('ADV8', x128_ADV8)
BOOL_ENTRY('SORT', x44_28_SORT, false)
BOOL_ENTRY('MBLR', x44_30_MBLR, false)
BOOL_ENTRY('LINE', x44_24_LINE, false)
BOOL_ENTRY('LIT_', x44_29_LIT_, false)
BOOL_ENTRY('AAPH', x44_26_AAPH, false)
BOOL_ENTRY('ZBUF', x44_27_ZBUF, false)
BOOL_ENTRY('FXLL', x44_25_FXLL, false)
BOOL_ENTRY('PMAB', x44_31_PMAB, false)
BOOL_ENTRY('VMD4', x45_29_VMD4, false)
BOOL_ENTRY('VMD3', x45_28_VMD3, false)
BOOL_ENTRY('VMD2', x45_27_VMD2, false)
BOOL_ENTRY('VMD1', x45_26_VMD1, false)
BOOL_ENTRY('OPTS', x45_31_OPTS, false)
BOOL_ENTRY('PMUS', x45_24_PMUS, false)
BOOL_ENTRY('PMOO', x45_25_PMOO, true)
BOOL_ENTRY('CIND', x45_30_CIND, false)
BOOL_ENTRY('ORNT', x30_30_ORNT, false)
BOOL_ENTRY('RSOP', x30_31_RSOP, false)
#undef ENTRY
#undef INT_ENTRY
#undef REAL_ENTRY
#undef VECTOR_ENTRY
#undef MOD_VECTOR_ENTRY
#undef COLOR_ENTRY
#undef EMITTER_ENTRY
#undef UV_ENTRY
#undef RES_ENTRY
#undef KSSM_ENTRY
#undef BOOL_ENTRY

View File

@ -1,64 +0,0 @@
#pragma once
#include <cstdint>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/ParticleCommon.hpp"
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAParticle {
template <class IDType>
struct _GPSM {
static constexpr ParticleType Type = ParticleType::GPSM;
#define INT_ENTRY(name, identifier) IntElementFactory identifier;
#define REAL_ENTRY(name, identifier) RealElementFactory identifier;
#define VECTOR_ENTRY(name, identifier) VectorElementFactory identifier;
#define MOD_VECTOR_ENTRY(name, identifier) ModVectorElementFactory identifier;
#define COLOR_ENTRY(name, identifier) ColorElementFactory identifier;
#define EMITTER_ENTRY(name, identifier) EmitterElementFactory identifier;
#define UV_ENTRY(name, identifier) UVElementFactory<IDType> identifier;
#define RES_ENTRY(name, identifier) ChildResourceFactory<IDType> identifier;
#define KSSM_ENTRY(name, identifier) SpawnSystemKeyframeData<IDType> identifier;
#define BOOL_ENTRY(name, identifier, def) bool identifier = def;
#include "PART.def"
template <typename _Func>
void constexpr Enumerate(_Func f) {
#define ENTRY(name, identifier) f(FOURCC(name), identifier);
#define BOOL_ENTRY(name, identifier, def) f(FOURCC(name), identifier, def);
#include "PART.def"
}
template <typename _Func>
bool constexpr Lookup(FourCC fcc, _Func f) {
switch (fcc.toUint32()) {
#define ENTRY(name, identifier) \
case SBIG(name): \
f(identifier); \
return true;
#include "PART.def"
default:
return false;
}
}
};
template <class IDType>
using GPSM = PPImpl<_GPSM<IDType>>;
template <class IDType>
bool ExtractGPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteGPSM(const GPSM<IDType>& gpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,248 +0,0 @@
#include "PATH.hpp"
#include "hecl/Blender/Connection.hpp"
#include "zeus/CAABox.hpp"
#include "DataSpec/DNACommon/AROTBuilder.hpp"
namespace DataSpec::DNAPATH {
#define DUMP_OCTREE 0
#if DUMP_OCTREE
/* octree dumper */
static void OutputOctreeNode(hecl::blender::PyOutStream& os, int idx, const zeus::CAABox& aabb) {
const zeus::CVector3f pos = aabb.center();
const zeus::CVector3f extent = aabb.extents();
os.format(
"obj = bpy.data.objects.new('Leaf_%d', None)\n"
"bpy.context.scene.collection.objects.link(obj)\n"
"obj.location = (%f,%f,%f)\n"
"obj.scale = (%f,%f,%f)\n"
"obj.empty_display_type = 'CUBE'\n"
"obj.layers[1] = True\n"
"obj.layers[0] = False\n",
idx, pos.x(), pos.y(), pos.z(), extent.x(), extent.y(), extent.z());
}
#endif
template <class PAKBridge>
void PATH<PAKBridge>::sendToBlender(hecl::blender::Connection& conn, std::string_view entryName,
const zeus::CMatrix4f* xf, const std::string& areaPath) {
/* Open Py Stream and read sections */
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy\n"
"import bmesh\n"
"from mathutils import Vector, Matrix\n"
"\n"
"bpy.types.Material.retro_path_idx_mask = bpy.props.IntProperty(name='Retro: Path Index Mask')\n"
"bpy.types.Material.retro_path_type_mask = bpy.props.IntProperty(name='Retro: Path Type Mask')\n"
"\n"
"material_dict = {}\n"
"material_index = []\n"
"def make_ground_material(idxMask):\n"
" mat = bpy.data.materials.new('Ground %X' % idxMask)\n"
" mat.diffuse_color = (0.8, 0.460, 0.194, 1.0)\n"
" return mat\n"
"def make_flyer_material(idxMask):\n"
" mat = bpy.data.materials.new('Flyer %X' % idxMask)\n"
" mat.diffuse_color = (0.016, 0.8, 0.8, 1.0)\n"
" return mat\n"
"def make_swimmer_material(idxMask):\n"
" mat = bpy.data.materials.new('Swimmer %X' % idxMask)\n"
" mat.diffuse_color = (0.074, 0.293, 0.8, 1.0)\n"
" return mat\n"
"def select_material(meshIdxMask, meshTypeMask):\n"
" key = (meshIdxMask, meshTypeMask)\n"
" if key in material_index:\n"
" return material_index.index(key)\n"
" elif key in material_dict:\n"
" material_index.append(key)\n"
" return len(material_index)-1\n"
" else:\n"
" if meshTypeMask == 0x2:\n"
" mat = make_flyer_material(meshIdxMask)\n"
" elif meshTypeMask == 0x4:\n"
" mat = make_swimmer_material(meshIdxMask)\n"
" else:\n"
" mat = make_ground_material(meshIdxMask)\n"
" mat.retro_path_idx_mask = meshIdxMask\n"
" mat.retro_path_type_mask = meshTypeMask\n"
" material_dict[key] = mat\n"
" material_index.append(key)\n"
" return len(material_index)-1\n"
"\n";
os.format(FMT_STRING("bpy.context.scene.name = '{}'\n"), entryName);
os << "# Clear Scene\n"
"if len(bpy.data.collections):\n"
" bpy.data.collections.remove(bpy.data.collections[0])\n"
"\n"
"bm = bmesh.new()\n"
"height_lay = bm.faces.layers.float.new('Height')\n";
for (const Node& n : nodes) {
zeus::simd_floats f(n.position.simd);
os.format(FMT_STRING("bm.verts.new(({},{},{}))\n"), f[0], f[1], f[2]);
}
os << "bm.verts.ensure_lookup_table()\n";
for (const Region& r : regions) {
os << "tri_verts = []\n";
for (atUint32 i = 0; i < r.nodeCount; ++i)
os.format(FMT_STRING("tri_verts.append(bm.verts[{}])\n"), r.nodeStart + i);
os.format(FMT_STRING("face = bm.faces.get(tri_verts)\n"
"if face is None:\n"
" face = bm.faces.new(tri_verts)\n"
" face.normal_flip()\n"
"face.material_index = select_material(0x{:04X}, 0x{:04X})\n"
"face.smooth = False\n"
"face[height_lay] = {}\n"
"\n"),
r.meshIndexMask, r.meshTypeMask, r.height);
#if 0
const zeus::CVector3f center = xf->multiplyOneOverW(r.centroid);
zeus::CAABox aabb(xf->multiplyOneOverW(r.aabb[0]), xf->multiplyOneOverW(r.aabb[1]));
os.format(FMT_STRING("aabb = bpy.data.objects.new('AABB', None)\n")
"aabb.location = (%f,%f,%f)\n"
"aabb.scale = (%f,%f,%f)\n"
"aabb.empty_display_type = 'CUBE'\n"
"bpy.context.scene.collection.objects.link(aabb)\n"
"centr = bpy.data.objects.new('Center', None)\n"
"centr.location = (%f,%f,%f)\n"
"bpy.context.scene.collection.objects.link(centr)\n",
aabb.min[0] + (aabb.max[0] - aabb.min[0]) / 2.f,
aabb.min[1] + (aabb.max[1] - aabb.min[1]) / 2.f,
aabb.min[2] + (aabb.max[2] - aabb.min[2]) / 2.f,
(aabb.max[0] - aabb.min[0]) / 2.f,
(aabb.max[1] - aabb.min[1]) / 2.f,
(aabb.max[2] - aabb.min[2]) / 2.f,
center.x(), center.y(), center.z());
#endif
}
#if 0
for (const Node& n : nodes) {
zeus::simd_floats f(n.position.simd);
zeus::simd_floats no(n.position.simd + n.normal.simd);
os.format(FMT_STRING("v = bm.verts.new((%f,%f,%f))\n")
"v2 = bm.verts.new((%f,%f,%f))\n"
"bm.edges.new((v, v2))\n", f[0], f[1], f[2], no[0], no[1], no[2]);
}
#endif
os << "bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001)\n"
"path_mesh = bpy.data.meshes.new('PATH')\n"
"bm.to_mesh(path_mesh)\n"
"path_mesh_obj = bpy.data.objects.new(path_mesh.name, path_mesh)\n"
"\n"
"for mat_name in material_index:\n"
" mat = material_dict[mat_name]\n"
" path_mesh.materials.append(mat)\n"
"\n"
"bpy.context.scene.collection.objects.link(path_mesh_obj)\n"
"path_mesh_obj.display_type = 'SOLID'\n"
"bpy.context.scene.hecl_path_obj = path_mesh_obj.name\n"
"\n";
if (xf) {
const zeus::CMatrix4f& w = *xf;
zeus::simd_floats xfMtxF[4];
for (int i = 0; i < 4; ++i)
w.m[i].mSimd.copy_to(xfMtxF[i]);
os.format(FMT_STRING("mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"path_mesh_obj.rotation_mode = 'QUATERNION'\n"
"path_mesh_obj.location = mtxd[0]\n"
"path_mesh_obj.rotation_quaternion = mtxd[1]\n"
"path_mesh_obj.scale = mtxd[2]\n"),
xfMtxF[0][0], xfMtxF[1][0], xfMtxF[2][0], xfMtxF[3][0], xfMtxF[0][1], xfMtxF[1][1], xfMtxF[2][1],
xfMtxF[3][1], xfMtxF[0][2], xfMtxF[1][2], xfMtxF[2][2], xfMtxF[3][2]);
}
#if DUMP_OCTREE
{
int idx = 0;
for (const auto& n : octree) {
if (n.isLeaf)
OutputOctreeNode(os, idx, zeus::CAABox(n.aabb[0], n.aabb[1]));
++idx;
}
}
#endif
os.linkBackground(fmt::format(FMT_STRING("//{}"), areaPath));
os.centerView();
os.close();
}
template <class PAKBridge>
bool PATH<PAKBridge>::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const typename PAKBridge::PAKType::Entry& entry,
bool force, hecl::blender::Token& btok,
std::function<void(const char*)> fileChanged) {
PATH path;
path.read(rs);
hecl::blender::Connection& conn = btok.getBlenderConnection();
if (!conn.createBlend(outPath, hecl::blender::BlendType::PathMesh))
return false;
std::string areaPath;
for (const auto& ent : hecl::DirectoryEnumerator(outPath.getParentPath().getAbsolutePath())) {
if (hecl::StringUtils::BeginsWith(ent.m_name, "!area_")) {
areaPath = ent.m_name;
break;
}
}
const zeus::CMatrix4f* xf = pakRouter.lookupMAPATransform(entry.id);
path.sendToBlender(conn, pakRouter.getBestEntryName(entry, false), xf, areaPath);
return conn.saveBlend();
}
template <class PAKBridge>
bool PATH<PAKBridge>::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const PathMesh& mesh,
hecl::blender::Token& btok) {
athena::io::MemoryReader r(mesh.data.data(), mesh.data.size());
PATH path;
path.read(r);
if (!path.regions.empty()) {
AROTBuilder octreeBuilder;
octreeBuilder.buildPath(path);
} else {
path.octreeNodeCount = 1;
path.octree.emplace_back();
OctreeNode& n = path.octree.back();
n.isLeaf = 1;
n.aabb[0] = zeus::CVector3f{FLT_MAX, FLT_MAX, FLT_MAX};
n.aabb[1] = zeus::CVector3f{-FLT_MAX, -FLT_MAX, -FLT_MAX};
for (int i = 0; i < 8; ++i)
n.children[i] = 0xffffffff;
}
#if DUMP_OCTREE
{
hecl::blender::Connection& conn = btok.getBlenderConnection();
if (!conn.createBlend(inPath.getWithExtension(".octree.blend", true), hecl::blender::BlendType::PathMesh))
return false;
zeus::CMatrix4f xf;
path.sendToBlender(conn, "PATH"sv, &xf);
conn.saveBlend();
}
#endif
athena::io::FileWriter w(outPath.getAbsolutePath());
path.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template struct PATH<DataSpec::DNAMP1::PAKBridge>;
template struct PATH<DataSpec::DNAMP2::PAKBridge>;
template struct PATH<DataSpec::DNAMP3::PAKBridge>;
} // namespace DataSpec::DNAPATH

View File

@ -1,112 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
#include "DataSpec/DNAMP1/DNAMP1.hpp"
#include "DataSpec/DNAMP2/DNAMP2.hpp"
#include "DataSpec/DNAMP3/DNAMP3.hpp"
namespace DataSpec::DNAPATH {
template <class PAKBridge>
struct RegionPointers {};
template <>
struct RegionPointers<DataSpec::DNAMP1::PAKBridge> : BigDNA {
AT_DECL_DNA
Value<atUint32> regionIdxPtr;
};
template <>
struct RegionPointers<DataSpec::DNAMP2::PAKBridge> : BigDNA {
AT_DECL_DNA
Value<atUint32> unk0;
Value<atUint32> unk1;
Value<atUint32> unk2;
Value<atUint32> regionIdxPtr;
};
template <>
struct RegionPointers<DataSpec::DNAMP3::PAKBridge> : BigDNA {
AT_DECL_DNA
Value<atUint32> unk0;
Value<atUint32> unk1;
Value<atUint32> unk2;
Value<atUint32> regionIdxPtr;
};
template <class PAKBridge>
struct AT_SPECIALIZE_PARMS(DataSpec::DNAMP1::PAKBridge, DataSpec::DNAMP2::PAKBridge, DataSpec::DNAMP3::PAKBridge) PATH
: BigDNA {
using PathMesh = hecl::blender::PathMesh;
AT_DECL_DNA
Value<atUint32> version;
struct Node : BigDNA {
AT_DECL_DNA
Value<atVec3f> position;
Value<atVec3f> normal;
};
Value<atUint32> nodeCount;
Vector<Node, AT_DNA_COUNT(nodeCount)> nodes;
struct Link : BigDNA {
AT_DECL_DNA
Value<atUint32> nodeIdx;
Value<atUint32> regionIdx;
Value<float> width2d;
Value<float> oneOverWidth2d;
};
Value<atUint32> linkCount;
Vector<Link, AT_DNA_COUNT(linkCount)> links;
struct Region : BigDNA {
AT_DECL_DNA
Value<atUint32> nodeCount;
Value<atUint32> nodeStart;
Value<atUint32> linkCount;
Value<atUint32> linkStart;
Value<atUint16> meshIndexMask;
Value<atUint16> meshTypeMask;
Value<float> height;
Value<atVec3f> normal;
Value<atUint32> regionIdx;
Value<atVec3f> centroid;
Value<atVec3f> aabb[2];
Value<RegionPointers<PAKBridge>> pointers;
};
Value<atUint32> regionCount;
Vector<Region, AT_DNA_COUNT(regionCount)> regions;
Vector<atUint32, AT_DNA_COUNT((((regionCount * (regionCount - 1)) / 2) + 31) / 32)> bitmap1;
Vector<atUint32, AT_DNA_COUNT(bitmap1.size())> bitmap2;
/* Unused in all games, removed in MP3 */
Vector<atUint32, AT_DNA_COUNT(std::is_same_v<PAKBridge, DataSpec::DNAMP3::PAKBridge>
? 0
: (((((regionCount * regionCount) + 31) / 32) - bitmap1.size()) * 2))>
bitmap3;
Value<atUint32> octreeRegionLookupCount;
Vector<atUint32, AT_DNA_COUNT(octreeRegionLookupCount)> octreeRegionLookup;
struct OctreeNode : BigDNA {
AT_DECL_DNA
Value<atUint32> isLeaf;
Value<atVec3f> aabb[2];
Value<atVec3f> centroid;
Value<atUint32> children[8];
Value<atUint32> regionCount;
Value<atUint32> regionStart;
};
Value<atUint32> octreeNodeCount;
Vector<OctreeNode, AT_DNA_COUNT(octreeNodeCount)> octree;
void sendToBlender(hecl::blender::Connection& conn, std::string_view entryName, const zeus::CMatrix4f* xf,
const std::string& areaPath);
static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const typename PAKBridge::PAKType::Entry& entry, bool force,
hecl::blender::Token& btok, std::function<void(const char*)> fileChanged);
static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const PathMesh& mesh,
hecl::blender::Token& btok);
};
} // namespace DataSpec::DNAPATH

View File

@ -1,586 +0,0 @@
#include "ParticleCommon.hpp"
namespace DataSpec::DNAParticle {
logvisor::Module LogModule("DataSpec::DNAParticle");
template struct PEImpl<_RealElementFactory>;
template struct PEImpl<_IntElementFactory>;
template struct PEImpl<_VectorElementFactory>;
template struct PEImpl<_ColorElementFactory>;
template struct PEImpl<_ModVectorElementFactory>;
template struct PEImpl<_EmitterElementFactory>;
template struct PEImpl<_UVElementFactory<UniqueID32>>;
template struct PEImpl<_UVElementFactory<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_RealElementFactory>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_IntElementFactory>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_VectorElementFactory>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_ColorElementFactory>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_ModVectorElementFactory>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_EmitterElementFactory>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_UVElementFactory<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PEImpl<_UVElementFactory<UniqueID64>>)
template <>
void REConstant::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
val = r.readFloat();
}
template <>
void REConstant::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
w.writeFloat(val);
}
template <>
void REConstant::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
}
template <>
void REConstant::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
val = r.readFloatBig();
}
template <>
void REConstant::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
w.writeFloatBig(val);
}
template <>
void IEConstant::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
val = r.readUint32();
}
template <>
void IEConstant::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
w.writeUint32(val);
}
template <>
void IEConstant::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
}
template <>
void IEConstant::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
val = r.readUint32Big();
}
template <>
void IEConstant::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
w.writeUint32Big(val);
}
template <>
void VEConstant::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
size_t elemCount;
if (auto v = r.enterSubVector(elemCount)) {
for (size_t i = 0; i < 3 && i < elemCount; ++i) {
if (auto rec = r.enterSubRecord())
comps[i].read(r);
}
}
}
template <>
void VEConstant::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
if (auto v = w.enterSubVector())
for (int i = 0; i < 3; ++i)
if (auto rec = w.enterSubRecord())
comps[i].write(w);
}
template <>
void VEConstant::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
comps[0].binarySize(s);
comps[1].binarySize(s);
comps[2].binarySize(s);
}
template <>
void VEConstant::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
comps[0].read(r);
comps[1].read(r);
comps[2].read(r);
}
template <>
void VEConstant::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
comps[0].write(w);
comps[1].write(w);
comps[2].write(w);
}
template <>
void CEConstant::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
for (int i = 0; i < 4; ++i)
if (auto rec = r.enterSubRecord())
comps[i].read(r);
}
template <>
void CEConstant::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
if (auto v = w.enterSubVector())
for (int i = 0; i < 4; ++i)
if (auto rec = w.enterSubRecord())
comps[i].write(w);
}
template <>
void CEConstant::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
comps[0].binarySize(s);
comps[1].binarySize(s);
comps[2].binarySize(s);
comps[3].binarySize(s);
}
template <>
void CEConstant::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
comps[0].read(r);
comps[1].read(r);
comps[2].read(r);
comps[3].read(r);
}
template <>
void CEConstant::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
comps[0].write(w);
comps[1].write(w);
comps[2].write(w);
comps[3].write(w);
}
template <>
void MVEConstant::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
for (int i = 0; i < 3; ++i)
if (auto rec = r.enterSubRecord())
comps[i].read(r);
}
template <>
void MVEConstant::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
if (auto v = w.enterSubVector())
for (int i = 0; i < 3; ++i)
if (auto rec = w.enterSubRecord())
comps[i].write(w);
}
template <>
void MVEConstant::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
comps[0].binarySize(s);
comps[1].binarySize(s);
comps[2].binarySize(s);
}
template <>
void MVEConstant::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
comps[0].read(r);
comps[1].read(r);
comps[2].read(r);
}
template <>
void MVEConstant::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
comps[0].write(w);
comps[1].write(w);
comps[2].write(w);
}
template <>
void BoolHelper::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
value = r.readBool();
}
template <>
void BoolHelper::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
w.writeBool(value);
}
template <>
void BoolHelper::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 5;
}
template <>
void BoolHelper::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('CNST'))
value = r.readBool();
else
value = false;
}
template <>
void BoolHelper::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
w.writeBytes("CNST", 4);
w.writeBool(value);
}
template struct ValueHelper<uint32_t>;
template struct ValueHelper<float>;
AT_SUBSPECIALIZE_DNA_YAML(ValueHelper<uint32_t>)
AT_SUBSPECIALIZE_DNA_YAML(ValueHelper<float>)
template <>
void EESimpleEmitterTR::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
position.reset();
velocity.reset();
if (auto rec = r.enterSubRecord("ILOC"))
position.read(r);
if (auto rec = r.enterSubRecord("IVEC"))
velocity.read(r);
}
template <>
void EESimpleEmitterTR::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
if (auto rec = w.enterSubRecord("ILOC"))
position.write(w);
if (auto rec = w.enterSubRecord("IVEC"))
velocity.write(w);
}
template <>
void EESimpleEmitterTR::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 8;
position.binarySize(s);
velocity.binarySize(s);
}
template <>
void EESimpleEmitterTR::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
position.reset();
velocity.reset();
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('ILOC')) {
position.read(r);
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('IVEC'))
velocity.read(r);
}
}
template <>
void EESimpleEmitterTR::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
w.writeBytes("ILOC", 4);
position.write(w);
w.writeBytes("IVEC", 4);
velocity.write(w);
}
template <>
std::string_view UVEConstant<UniqueID32>::DNAType() {
return "UVEConstant<UniqueID32>"sv;
}
template <>
std::string_view UVEConstant<UniqueID64>::DNAType() {
return "UVEConstant<UniqueID64>"sv;
}
template <class IDType>
void UVEConstant<IDType>::_read(typename ReadYaml::StreamT& r) {
tex.clear();
if (auto rec = r.enterSubRecord("tex"))
tex.read(r);
}
template <class IDType>
void UVEConstant<IDType>::_write(typename WriteYaml::StreamT& w) const {
if (auto rec = w.enterSubRecord("tex"))
tex.write(w);
}
template <class IDType>
void UVEConstant<IDType>::_binarySize(typename BinarySize::StreamT& _s) const {
_s += 4;
tex.binarySize(_s);
}
template <class IDType>
void UVEConstant<IDType>::_read(typename Read::StreamT& r) {
tex.clear();
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('CNST'))
tex.read(r);
}
template <class IDType>
void UVEConstant<IDType>::_write(typename Write::StreamT& w) const {
w.writeBytes("CNST", 4);
tex.write(w);
}
AT_SUBSPECIALIZE_DNA_YAML(UVEConstant<UniqueID32>)
AT_SUBSPECIALIZE_DNA_YAML(UVEConstant<UniqueID64>)
template struct UVEConstant<UniqueID32>;
template struct UVEConstant<UniqueID64>;
template <>
std::string_view UVEAnimTexture<UniqueID32>::DNAType() {
return "UVEAnimTexture<UniqueID32>"sv;
}
template <>
std::string_view UVEAnimTexture<UniqueID64>::DNAType() {
return "UVEAnimTexture<UniqueID64>"sv;
}
template <class IDType>
void UVEAnimTexture<IDType>::_read(typename ReadYaml::StreamT& r) {
tex.clear();
if (auto rec = r.enterSubRecord("tex"))
tex.read(r);
if (auto rec = r.enterSubRecord("tileW"))
tileW.read(r);
if (auto rec = r.enterSubRecord("tileH"))
tileH.read(r);
if (auto rec = r.enterSubRecord("strideW"))
strideW.read(r);
if (auto rec = r.enterSubRecord("strideH"))
strideH.read(r);
if (auto rec = r.enterSubRecord("cycleFrames"))
cycleFrames.read(r);
if (auto rec = r.enterSubRecord("loop"))
loop = r.readBool();
}
template <class IDType>
void UVEAnimTexture<IDType>::_write(typename WriteYaml::StreamT& w) const {
if (auto rec = w.enterSubRecord("tex"))
tex.write(w);
if (auto rec = w.enterSubRecord("tileW"))
tileW.write(w);
if (auto rec = w.enterSubRecord("tileH"))
tileH.write(w);
if (auto rec = w.enterSubRecord("strideW"))
strideW.write(w);
if (auto rec = w.enterSubRecord("strideH"))
strideH.write(w);
if (auto rec = w.enterSubRecord("cycleFrames"))
cycleFrames.write(w);
w.writeBool("loop", loop);
}
template <class IDType>
void UVEAnimTexture<IDType>::_binarySize(typename BinarySize::StreamT& _s) const {
_s += 9;
tex.binarySize(_s);
tileW.binarySize(_s);
tileH.binarySize(_s);
strideW.binarySize(_s);
strideH.binarySize(_s);
cycleFrames.binarySize(_s);
}
template <class IDType>
void UVEAnimTexture<IDType>::_read(typename Read::StreamT& r) {
tex.clear();
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('CNST'))
tex.read(r);
tileW.read(r);
tileH.read(r);
strideW.read(r);
strideH.read(r);
cycleFrames.read(r);
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('CNST'))
loop = r.readBool();
}
template <class IDType>
void UVEAnimTexture<IDType>::_write(typename Write::StreamT& w) const {
w.writeBytes("CNST", 4);
tex.write(w);
tileW.write(w);
tileH.write(w);
strideW.write(w);
strideH.write(w);
cycleFrames.write(w);
w.writeBytes("CNST", 4);
w.writeBool(loop);
}
AT_SUBSPECIALIZE_DNA_YAML(UVEAnimTexture<UniqueID32>)
AT_SUBSPECIALIZE_DNA_YAML(UVEAnimTexture<UniqueID64>)
template struct UVEAnimTexture<UniqueID32>;
template struct UVEAnimTexture<UniqueID64>;
template <>
std::string_view UVElementFactory<UniqueID32>::DNAType() {
return "UVElementFactory<UniqueID32>"sv;
}
template <>
std::string_view UVElementFactory<UniqueID64>::DNAType() {
return "UVElementFactory<UniqueID64>"sv;
}
template <>
std::string_view SpawnSystemKeyframeData<UniqueID32>::SpawnSystemKeyframeInfo::DNAType() {
return "SpawnSystemKeyframeData<UniqueID32>::SpawnSystemKeyframeInfo"sv;
}
template <>
std::string_view SpawnSystemKeyframeData<UniqueID64>::SpawnSystemKeyframeInfo::DNAType() {
return "SpawnSystemKeyframeData<UniqueID64>::SpawnSystemKeyframeInfo"sv;
}
template <class IDType>
template <class Op>
void SpawnSystemKeyframeData<IDType>::SpawnSystemKeyframeInfo::Enumerate(typename Op::StreamT& s) {
Do<Op>(athena::io::PropId{"id"}, id, s);
Do<Op>(athena::io::PropId{"a"}, a, s);
Do<Op>(athena::io::PropId{"b"}, b, s);
Do<Op>(athena::io::PropId{"c"}, c, s);
}
template <>
std::string_view SpawnSystemKeyframeData<UniqueID32>::DNAType() {
return "SpawnSystemKeyframeData<UniqueID32>"sv;
}
template <>
std::string_view SpawnSystemKeyframeData<UniqueID64>::DNAType() {
return "SpawnSystemKeyframeData<UniqueID64>"sv;
}
template <class IDType>
void SpawnSystemKeyframeData<IDType>::_read(typename ReadYaml::StreamT& r) {
if (auto rec = r.enterSubRecord("a"))
a = r.readUint32();
if (auto rec = r.enterSubRecord("b"))
b = r.readUint32();
if (auto rec = r.enterSubRecord("endFrame"))
endFrame = r.readUint32();
if (auto rec = r.enterSubRecord("d"))
d = r.readUint32();
spawns.clear();
size_t spawnCount;
if (auto v = r.enterSubVector("spawns", spawnCount)) {
spawns.reserve(spawnCount);
for (const auto& child : r.getCurNode()->m_seqChildren) {
(void)child;
if (auto rec = r.enterSubRecord()) {
spawns.emplace_back();
spawns.back().first = r.readUint32("startFrame");
size_t systemCount;
if (auto v = r.enterSubVector("systems", systemCount)) {
spawns.back().second.reserve(systemCount);
for (const auto& in : r.getCurNode()->m_seqChildren) {
(void)in;
spawns.back().second.emplace_back();
SpawnSystemKeyframeInfo& info = spawns.back().second.back();
if (auto rec = r.enterSubRecord())
info.read(r);
}
}
}
}
}
}
template <class IDType>
void SpawnSystemKeyframeData<IDType>::_write(typename WriteYaml::StreamT& w) const {
if (spawns.empty())
return;
w.writeUint32("a", a);
w.writeUint32("b", b);
w.writeUint32("endFrame", endFrame);
w.writeUint32("d", d);
if (auto v = w.enterSubVector("spawns")) {
for (const auto& spawn : spawns) {
if (auto rec = w.enterSubRecord()) {
w.writeUint32("startFrame", spawn.first);
if (auto v = w.enterSubVector("systems"))
for (const auto& info : spawn.second)
if (auto rec = w.enterSubRecord())
info.write(w);
}
}
}
}
template <class IDType>
void SpawnSystemKeyframeData<IDType>::_binarySize(typename BinarySize::StreamT& s) const {
s += 20;
for (const auto& spawn : spawns) {
s += 8;
for (const auto& info : spawn.second)
info.binarySize(s);
}
}
template <class IDType>
void SpawnSystemKeyframeData<IDType>::_read(typename Read::StreamT& r) {
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId != SBIG('CNST'))
return;
a = r.readUint32Big();
b = r.readUint32Big();
endFrame = r.readUint32Big();
d = r.readUint32Big();
uint32_t count = r.readUint32Big();
spawns.clear();
spawns.reserve(count);
for (size_t i = 0; i < count; ++i) {
spawns.emplace_back();
spawns.back().first = r.readUint32Big();
uint32_t infoCount = r.readUint32Big();
spawns.back().second.reserve(infoCount);
for (size_t j = 0; j < infoCount; ++j) {
spawns.back().second.emplace_back();
spawns.back().second.back().read(r);
}
}
}
template <class IDType>
void SpawnSystemKeyframeData<IDType>::_write(typename Write::StreamT& w) const {
if (spawns.empty()) {
w.writeBytes("NONE", 4);
return;
}
w.writeBytes("CNST", 4);
w.writeUint32Big(a);
w.writeUint32Big(b);
w.writeUint32Big(endFrame);
w.writeUint32Big(d);
w.writeUint32Big(spawns.size());
for (const auto& spawn : spawns) {
w.writeUint32Big(spawn.first);
w.writeUint32Big(spawn.second.size());
for (const auto& info : spawn.second)
info.write(w);
}
}
AT_SUBSPECIALIZE_DNA_YAML(SpawnSystemKeyframeData<UniqueID32>)
AT_SUBSPECIALIZE_DNA_YAML(SpawnSystemKeyframeData<UniqueID64>)
template struct SpawnSystemKeyframeData<UniqueID32>;
template struct SpawnSystemKeyframeData<UniqueID64>;
template <>
std::string_view ChildResourceFactory<UniqueID32>::DNAType() {
return "ChildResourceFactory<UniqueID32>"sv;
}
template <>
std::string_view ChildResourceFactory<UniqueID64>::DNAType() {
return "ChildResourceFactory<UniqueID64>"sv;
}
template <class IDType>
void ChildResourceFactory<IDType>::_read(typename ReadYaml::StreamT& r) {
id.clear();
if (auto rec = r.enterSubRecord("CNST"))
id.read(r);
}
template <class IDType>
void ChildResourceFactory<IDType>::_write(typename WriteYaml::StreamT& w) const {
if (id.isValid())
if (auto rec = w.enterSubRecord("CNST"))
id.write(w);
}
template <class IDType>
void ChildResourceFactory<IDType>::_binarySize(typename BinarySize::StreamT& s) const {
if (id.isValid())
id.binarySize(s);
s += 4;
}
template <class IDType>
void ChildResourceFactory<IDType>::_read(typename Read::StreamT& r) {
id.clear();
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId == SBIG('CNST'))
id.read(r);
}
template <class IDType>
void ChildResourceFactory<IDType>::_write(typename Write::StreamT& w) const {
if (id.isValid()) {
w.writeBytes("CNST", 4);
id.write(w);
} else
w.writeBytes("NONE", 4);
}
AT_SUBSPECIALIZE_DNA_YAML(ChildResourceFactory<UniqueID32>)
AT_SUBSPECIALIZE_DNA_YAML(ChildResourceFactory<UniqueID64>)
template struct ChildResourceFactory<UniqueID32>;
template struct ChildResourceFactory<UniqueID64>;
} // namespace DataSpec::DNAParticle

File diff suppressed because it is too large Load Diff

View File

@ -1,145 +0,0 @@
#include "DataSpec/DNACommon/RigInverter.hpp"
#include "DataSpec/DNAMP1/CINF.hpp"
#include "DataSpec/DNAMP2/CINF.hpp"
#include "DataSpec/DNAMP3/CINF.hpp"
#include <hecl/Blender/Connection.hpp>
namespace DataSpec::DNAANIM {
template <class CINFType>
RigInverter<CINFType>::Bone::Bone(const CINFType& cinf, const typename CINFType::Bone& origBone)
: m_origBone(origBone) {
atUint32 parentIdx = cinf.getInternalBoneIdxFromId(origBone.parentId);
zeus::CVector3f boneOrigin(origBone.origin);
zeus::CVector3f naturalTail = boneOrigin + zeus::CVector3f{0.f, 0.5f, 0.f};
if (parentIdx != UINT32_MAX) {
const typename CINFType::Bone& pBone = cinf.bones[parentIdx];
m_parentDelta = boneOrigin - zeus::CVector3f(pBone.origin);
}
size_t actualChildren = 0;
for (atUint32 chId : origBone.linked) {
if (chId == origBone.parentId)
continue;
atUint32 chIdx = cinf.getInternalBoneIdxFromId(chId);
if (chIdx != UINT32_MAX)
++actualChildren;
}
const std::string* bName = cinf.getBoneNameFromId(origBone.id);
bool isLCTR = false;
if (bName)
isLCTR = bName->find("_LCTR") != std::string::npos;
if (parentIdx == UINT32_MAX) {
/* Root will always use +Y tail */
m_tail = naturalTail;
} else if (actualChildren) {
/* Position tail to average of children */
for (atUint32 chId : origBone.linked) {
if (chId == origBone.parentId)
continue;
atUint32 chIdx = cinf.getInternalBoneIdxFromId(chId);
if (chIdx != UINT32_MAX) {
const typename CINFType::Bone& chBone = cinf.bones[chIdx];
m_tail += chBone.origin;
}
}
m_tail /= zeus::CVector3f(float(actualChildren));
if ((m_tail - boneOrigin).magSquared() < 0.001f)
m_tail = naturalTail;
else if (isLCTR)
m_tail = boneOrigin + zeus::CVector3f{0.f, 1.0f, 0.f} * (m_tail - boneOrigin).magnitude();
} else {
/* Extrapolate by delta with parent */
m_tail = boneOrigin + m_parentDelta;
float deltaMag = m_parentDelta.magnitude();
if (deltaMag < 0.001f) {
deltaMag = 0.5f;
m_tail = naturalTail;
} else if (deltaMag > 0.5f) {
/* Extreme bones capped to +0.5 value */
deltaMag = 0.5f;
m_tail = boneOrigin + m_parentDelta.normalized() * 0.5f;
}
if (isLCTR)
m_tail = boneOrigin + zeus::CVector3f{0.f, 1.0f, 0.f} * deltaMag;
}
}
template <class CINFType>
RigInverter<CINFType>::RigInverter(const CINFType& cinf) : m_cinf(cinf) {
m_bones.reserve(cinf.bones.size());
for (const typename CINFType::Bone& b : cinf.bones)
m_bones.emplace_back(cinf, b);
}
template <class CINFType>
RigInverter<CINFType>::RigInverter(const CINFType& cinf,
const std::unordered_map<std::string, hecl::blender::Matrix3f>& matrices)
: m_cinf(cinf) {
m_bones.reserve(cinf.bones.size());
for (const typename CINFType::Bone& b : cinf.bones) {
m_bones.emplace_back(cinf, b);
const std::string* name = cinf.getBoneNameFromId(b.id);
if (name) {
auto search = matrices.find(*name);
if (search != matrices.cend()) {
zeus::CMatrix3f boneMtx(search->second[0], search->second[1], search->second[2]);
m_bones.back().m_restorer = boneMtx;
m_bones.back().m_inverter = m_bones.back().m_restorer.inverse();
}
}
}
}
template <class CINFType>
zeus::CQuaternion RigInverter<CINFType>::invertRotation(atUint32 boneId, const zeus::CQuaternion& origRot) const {
for (const Bone& b : m_bones)
if (b.m_origBone.id == boneId)
return b.m_restorer * origRot * b.m_inverter;
return origRot;
}
template <class CINFType>
zeus::CVector3f RigInverter<CINFType>::invertPosition(atUint32 boneId, const zeus::CVector3f& origPos,
bool subDelta) const {
for (const Bone& b : m_bones)
if (b.m_origBone.id == boneId) {
zeus::CVector3f localPos = origPos;
if (subDelta)
localPos -= b.m_parentDelta;
return b.m_restorer.transform(localPos);
}
return origPos;
}
template <class CINFType>
zeus::CQuaternion RigInverter<CINFType>::restoreRotation(atUint32 boneId, const zeus::CQuaternion& origRot) const {
for (const Bone& b : m_bones)
if (b.m_origBone.id == boneId)
return b.m_inverter * origRot * b.m_restorer;
return origRot;
}
template <class CINFType>
zeus::CVector3f RigInverter<CINFType>::restorePosition(atUint32 boneId, const zeus::CVector3f& origPos,
bool subDelta) const {
for (const Bone& b : m_bones)
if (b.m_origBone.id == boneId) {
zeus::CVector3f localPos = b.m_inverter.transform(origPos);
if (subDelta)
localPos += b.m_parentDelta;
return localPos;
}
return origPos;
}
template class RigInverter<DNAMP1::CINF>;
template class RigInverter<DNAMP2::CINF>;
} // namespace DataSpec::DNAANIM

View File

@ -1,44 +0,0 @@
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include <hecl/hecl.hpp>
#include <zeus/CQuaternion.hpp>
#include <zeus/CVector3f.hpp>
namespace DataSpec::DNAANIM {
/** One-shot process to invert CINF armature into connected rig,
* inverting rotations/translations of ANIM data to match */
template <class CINFType>
class RigInverter {
public:
struct Bone {
const typename CINFType::Bone& m_origBone;
zeus::CQuaternion m_inverter;
zeus::CQuaternion m_restorer;
zeus::CVector3f m_tail;
zeus::CVector3f m_parentDelta;
Bone(const CINFType& cinf, const typename CINFType::Bone& origBone);
};
private:
const CINFType& m_cinf;
std::vector<Bone> m_bones;
public:
RigInverter(const CINFType& cinf);
RigInverter(const CINFType& cinf, const std::unordered_map<std::string, hecl::blender::Matrix3f>& matrices);
const CINFType& getCINF() const { return m_cinf; }
const std::vector<Bone>& getBones() const { return m_bones; }
zeus::CQuaternion invertRotation(atUint32 boneId, const zeus::CQuaternion& origRot) const;
zeus::CVector3f invertPosition(atUint32 boneId, const zeus::CVector3f& origPos, bool subDelta) const;
zeus::CQuaternion restoreRotation(atUint32 boneId, const zeus::CQuaternion& origRot) const;
zeus::CVector3f restorePosition(atUint32 boneId, const zeus::CVector3f& origPos, bool subDelta) const;
};
} // namespace DataSpec::DNAANIM

View File

@ -1,39 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::SAVWCommon {
enum class EScanCategory { None, Data, Lore, Creature, Research, Artifact };
struct Header : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> magic;
Value<atUint32> version;
Value<atUint32> areaCount;
};
struct EnvironmentVariable : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> unk1;
Value<atUint32> unk2;
Value<atUint32> unk3;
};
struct Layer : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> areaId;
Value<atUint32> layer;
};
template <class SAVW>
static bool ExtractSAVW(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
SAVW savw;
savw.read(rs);
athena::io::FileWriter writer(outPath.getAbsolutePath());
athena::io::ToYAMLStream(savw, writer);
return true;
}
} // namespace DataSpec::SAVWCommon

View File

@ -1,43 +0,0 @@
#include "DataSpec/DNACommon/STRG.hpp"
#include "DataSpec/DNAMP1/STRG.hpp"
#include "DataSpec/DNAMP2/STRG.hpp"
#include "DataSpec/DNAMP3/STRG.hpp"
#include <logvisor/logvisor.hpp>
namespace DataSpec {
void ISTRG::gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const { /* TODO: parse out resource tokens */
}
std::unique_ptr<ISTRG> LoadSTRG(athena::io::IStreamReader& reader) {
uint32_t magic = reader.readUint32Big();
if (magic != 0x87654321) {
LogDNACommon.report(logvisor::Error, FMT_STRING("invalid STRG magic"));
return {};
}
uint32_t version = reader.readUint32Big();
switch (version) {
case 0: {
auto* newStrg = new DNAMP1::STRG;
newStrg->_read(reader);
return std::unique_ptr<ISTRG>(newStrg);
}
case 1: {
auto* newStrg = new DNAMP2::STRG;
newStrg->_read(reader);
return std::unique_ptr<ISTRG>(newStrg);
}
case 3: {
auto* newStrg = new DNAMP3::STRG;
newStrg->_read(reader);
return std::unique_ptr<ISTRG>(newStrg);
}
default:
break;
}
return {};
}
} // namespace DataSpec

View File

@ -1,30 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include <hecl/hecl.hpp>
namespace athena::io {
class IStreamReader;
}
namespace DataSpec {
struct ISTRG : BigDNAVYaml {
~ISTRG() override = default;
virtual size_t count() const = 0;
virtual std::string getUTF8(const FourCC& lang, size_t idx) const = 0;
virtual std::u16string getUTF16(const FourCC& lang, size_t idx) const = 0;
virtual int32_t lookupIdx(std::string_view name) const = 0;
virtual void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const;
};
std::unique_ptr<ISTRG> LoadSTRG(athena::io::IStreamReader& reader);
} // namespace DataSpec

View File

@ -1,51 +0,0 @@
#include "DataSpec/DNACommon/SWHC.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNAParticle {
template struct PPImpl<_SWSH<UniqueID32>>;
template struct PPImpl<_SWSH<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_SWSH<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_SWSH<UniqueID64>>)
template <>
std::string_view SWSH<UniqueID32>::DNAType() {
return "SWSH<UniqueID32>"sv;
}
template <>
std::string_view SWSH<UniqueID64>::DNAType() {
return "SWSH<UniqueID64>"sv;
}
template <class IDType>
bool ExtractSWSH(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
SWSH<IDType> swsh;
swsh.read(rs);
athena::io::ToYAMLStream(swsh, writer);
return true;
}
return false;
}
template bool ExtractSWSH<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractSWSH<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteSWSH(const SWSH<IDType>& swsh, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
swsh.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteSWSH<UniqueID32>(const SWSH<UniqueID32>& swsh, const hecl::ProjectPath& outPath);
template bool WriteSWSH<UniqueID64>(const SWSH<UniqueID64>& swsh, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,69 +0,0 @@
#ifndef ENTRY
#define ENTRY(name, identifier)
#endif
#ifndef INT_ENTRY
#define INT_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef REAL_ENTRY
#define REAL_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef VECTOR_ENTRY
#define VECTOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef MOD_VECTOR_ENTRY
#define MOD_VECTOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef COLOR_ENTRY
#define COLOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef UV_ENTRY
#define UV_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef BOOL_ENTRY
#define BOOL_ENTRY(name, identifier, def) ENTRY(name, identifier)
#endif
INT_ENTRY('PSLT', x0_PSLT)
REAL_ENTRY('TIME', x4_TIME)
REAL_ENTRY('LRAD', x8_LRAD)
REAL_ENTRY('RRAD', xc_RRAD)
INT_ENTRY('LENG', x10_LENG)
COLOR_ENTRY('COLR', x14_COLR)
INT_ENTRY('SIDE', x18_SIDE)
REAL_ENTRY('IROT', x1c_IROT)
REAL_ENTRY('ROTM', x20_ROTM)
VECTOR_ENTRY('POFS', x24_POFS)
VECTOR_ENTRY('IVEL', x28_IVEL)
VECTOR_ENTRY('NPOS', x2c_NPOS)
MOD_VECTOR_ENTRY('VELM', x30_VELM)
MOD_VECTOR_ENTRY('VLM2', x34_VLM2)
INT_ENTRY('SPLN', x38_SPLN)
UV_ENTRY('TEXR', x3c_TEXR)
INT_ENTRY('TSPN', x40_TSPN)
BOOL_ENTRY('LLRD', x44_24_LLRD, false)
BOOL_ENTRY('CROS', x44_25_CROS, true)
BOOL_ENTRY('VLS1', x44_26_VLS1, false)
BOOL_ENTRY('VLS2', x44_27_VLS2, false)
BOOL_ENTRY('SROT', x44_28_SROT, false)
BOOL_ENTRY('WIRE', x44_29_WIRE, false)
BOOL_ENTRY('TEXW', x44_30_TEXW, false)
BOOL_ENTRY('AALP', x44_31_AALP, false)
BOOL_ENTRY('ZBUF', x45_24_ZBUF, false)
BOOL_ENTRY('ORNT', x45_25_ORNT, false)
BOOL_ENTRY('CRND', x45_26_CRND, false)
#undef ENTRY
#undef INT_ENTRY
#undef REAL_ENTRY
#undef VECTOR_ENTRY
#undef MOD_VECTOR_ENTRY
#undef COLOR_ENTRY
#undef UV_ENTRY
#undef BOOL_ENTRY

View File

@ -1,59 +0,0 @@
#pragma once
#include <vector>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/ParticleCommon.hpp"
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAParticle {
template <class IDType>
struct _SWSH {
static constexpr ParticleType Type = ParticleType::SWSH;
#define INT_ENTRY(name, identifier) IntElementFactory identifier;
#define REAL_ENTRY(name, identifier) RealElementFactory identifier;
#define VECTOR_ENTRY(name, identifier) VectorElementFactory identifier;
#define MOD_VECTOR_ENTRY(name, identifier) ModVectorElementFactory identifier;
#define COLOR_ENTRY(name, identifier) ColorElementFactory identifier;
#define UV_ENTRY(name, identifier) UVElementFactory<IDType> identifier;
#define BOOL_ENTRY(name, identifier, def) bool identifier = def;
#include "SWHC.def"
template <typename _Func>
void constexpr Enumerate(_Func f) {
#define ENTRY(name, identifier) f(FOURCC(name), identifier);
#define BOOL_ENTRY(name, identifier, def) f(FOURCC(name), identifier, def);
#include "SWHC.def"
}
template <typename _Func>
bool constexpr Lookup(FourCC fcc, _Func f) {
switch (fcc.toUint32()) {
#define ENTRY(name, identifier) \
case SBIG(name): \
f(identifier); \
return true;
#include "SWHC.def"
default:
return false;
}
}
};
template <class IDType>
using SWSH = PPImpl<_SWSH<IDType>>;
template <class IDType>
bool ExtractSWSH(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteSWSH(const SWSH<IDType>& gpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
#pragma once
#include <climits>
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace hecl {
class ProjectPath;
}
namespace DataSpec {
class PAKEntryReadStream;
struct TXTR {
struct PaletteMeta : BigDNAVYaml {
AT_DECL_EXPLICIT_DNA_YAMLV
Value<atUint32> format = UINT_MAX;
Value<atUint32> elementCount = 0;
Value<atUint64> dolphinHash = 0;
};
struct Meta : BigDNAVYaml {
AT_DECL_EXPLICIT_DNA_YAMLV
Value<atUint32> format = UINT_MAX;
Value<atUint32> mips = 0;
Value<atUint16> width = 0;
Value<atUint16> height = 0;
Value<atUint64> dolphinHash = 0;
Value<bool> hasPalette = false;
PaletteMeta palette;
};
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
static bool CookPC(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
static TXTR::Meta GetMetaData(PAKEntryReadStream& rs);
};
} // namespace DataSpec

View File

@ -1,13 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
namespace hecl {
class CVarManager;
}
namespace DataSpec {
struct ITweak : BigDNA {
virtual void initCVars(hecl::CVarManager*) {}
};
} // namespace DataSpec

View File

@ -1,11 +0,0 @@
#pragma once
#include "ITweak.hpp"
namespace DataSpec {
struct ITweakPlayerControl : ITweak {
virtual atUint32 GetMapping(atUint32) const = 0;
};
} // namespace DataSpec

View File

@ -1,32 +0,0 @@
#pragma once
#include "../PAK.hpp"
namespace DataSpec {
template <class T>
bool WriteTweak(const T& tweak, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
tweak.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template <class T>
bool ExtractTweak(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
T tweak;
tweak.read(rs);
athena::io::ToYAMLStream(tweak, writer);
return true;
}
return false;
}
} // namespace DataSpec

View File

@ -1,51 +0,0 @@
#include "DataSpec/DNACommon/WPSC.hpp"
#include "DataSpec/DNACommon/PAK.hpp"
namespace DataSpec::DNAParticle {
template struct PPImpl<_WPSM<UniqueID32>>;
template struct PPImpl<_WPSM<UniqueID64>>;
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_WPSM<UniqueID32>>)
AT_SUBSPECIALIZE_DNA_YAML(PPImpl<_WPSM<UniqueID64>>)
template <>
std::string_view WPSM<UniqueID32>::DNAType() {
return "WPSM<UniqueID32>"sv;
}
template <>
std::string_view WPSM<UniqueID64>::DNAType() {
return "WPSM<UniqueID64>"sv;
}
template <class IDType>
bool ExtractWPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
WPSM<IDType> wpsm;
wpsm.read(rs);
athena::io::ToYAMLStream(wpsm, writer);
return true;
}
return false;
}
template bool ExtractWPSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractWPSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteWPSM(const WPSM<IDType>& wpsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
wpsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteWPSM<UniqueID32>(const WPSM<UniqueID32>& wpsm, const hecl::ProjectPath& outPath);
template bool WriteWPSM<UniqueID64>(const WPSM<UniqueID64>& wpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,87 +0,0 @@
#ifndef ENTRY
#define ENTRY(name, identifier)
#endif
#ifndef INT_ENTRY
#define INT_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef U32_ENTRY
#define U32_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef REAL_ENTRY
#define REAL_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef VECTOR_ENTRY
#define VECTOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef MOD_VECTOR_ENTRY
#define MOD_VECTOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef COLOR_ENTRY
#define COLOR_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef UV_ENTRY
#define UV_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef RES_ENTRY
#define RES_ENTRY(name, identifier) ENTRY(name, identifier)
#endif
#ifndef BOOL_ENTRY
#define BOOL_ENTRY(name, identifier, def) ENTRY(name, identifier)
#endif
VECTOR_ENTRY('IORN', x0_IORN)
VECTOR_ENTRY('IVEC', x4_IVEC)
VECTOR_ENTRY('PSOV', x8_PSOV)
MOD_VECTOR_ENTRY('PSVM', xc_PSVM)
INT_ENTRY('PSLT', x14_PSLT)
VECTOR_ENTRY('PSCL', x18_PSCL)
COLOR_ENTRY('PCOL', x1c_PCOL)
VECTOR_ENTRY('POFS', x20_POFS)
VECTOR_ENTRY('OFST', x24_OFST)
REAL_ENTRY('TRAT', x30_TRAT)
RES_ENTRY('APSM', x34_APSM)
RES_ENTRY('APS2', x44_APS2)
RES_ENTRY('ASW1', x54_ASW1)
RES_ENTRY('ASW2', x64_ASW2)
RES_ENTRY('ASW3', x74_ASW3)
RES_ENTRY('OHEF', x84_OHEF)
RES_ENTRY('COLR', x94_COLR)
U32_ENTRY('PJFX', xa8_PJFX)
REAL_ENTRY('RNGE', xac_RNGE)
REAL_ENTRY('FOFF', xb0_FOFF)
BOOL_ENTRY('VMD2', x10_VMD2, false)
BOOL_ENTRY('APSO', x28_APSO, false)
BOOL_ENTRY('HOMG', x29_HOMG, false)
BOOL_ENTRY('AP11', x2a_AP11, false)
BOOL_ENTRY('AP21', x2b_AP21, false)
BOOL_ENTRY('AS11', x2c_AS11, false)
BOOL_ENTRY('AS12', x2d_AS12, false)
BOOL_ENTRY('AS13', x2e_AS13, false)
BOOL_ENTRY('EWTR', xa4_EWTR, true)
BOOL_ENTRY('LWTR', xa5_LWTR, true)
BOOL_ENTRY('SWTR', xa6_SWTR, true)
BOOL_ENTRY('FC60', xunk_FC60, false)
BOOL_ENTRY('SPS1', xunk_SPS1, false)
BOOL_ENTRY('SPS2', xunk_SPS2, false)
#undef ENTRY
#undef INT_ENTRY
#undef U32_ENTRY
#undef REAL_ENTRY
#undef VECTOR_ENTRY
#undef MOD_VECTOR_ENTRY
#undef COLOR_ENTRY
#undef UV_ENTRY
#undef RES_ENTRY
#undef BOOL_ENTRY

View File

@ -1,60 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/ParticleCommon.hpp"
namespace DataSpec {
class PAKEntryReadStream;
}
namespace hecl {
class ProjectPath;
}
namespace DataSpec::DNAParticle {
template <class IDType>
struct _WPSM {
static constexpr ParticleType Type = ParticleType::WPSM;
#define INT_ENTRY(name, identifier) IntElementFactory identifier;
#define U32_ENTRY(name, identifier) uint32_t identifier = ~0;
#define REAL_ENTRY(name, identifier) RealElementFactory identifier;
#define VECTOR_ENTRY(name, identifier) VectorElementFactory identifier;
#define MOD_VECTOR_ENTRY(name, identifier) ModVectorElementFactory identifier;
#define COLOR_ENTRY(name, identifier) ColorElementFactory identifier;
#define UV_ENTRY(name, identifier) UVElementFactory<IDType> identifier;
#define RES_ENTRY(name, identifier) ChildResourceFactory<IDType> identifier;
#define BOOL_ENTRY(name, identifier, def) bool identifier = def;
#include "WPSC.def"
template <typename _Func>
void constexpr Enumerate(_Func f) {
#define ENTRY(name, identifier) f(FOURCC(name), identifier);
#define BOOL_ENTRY(name, identifier, def) f(FOURCC(name), identifier, def);
#include "WPSC.def"
}
template <typename _Func>
bool constexpr Lookup(FourCC fcc, _Func f) {
switch (fcc.toUint32()) {
#define ENTRY(name, identifier) \
case SBIG(name): \
f(identifier); \
return true;
#include "WPSC.def"
default:
return false;
}
}
};
template <class IDType>
using WPSM = PPImpl<_WPSM<IDType>>;
template <class IDType>
bool ExtractWPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteWPSM(const WPSM<IDType>& wpsm, const hecl::ProjectPath& outPath);
} // namespace DataSpec::DNAParticle

View File

@ -1,104 +0,0 @@
#include "AFSM.hpp"
namespace DataSpec::DNAMP1 {
template <>
void AFSM::State::Transition::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
triggerCount = r.readUint32Big();
int i = 0;
r.enumerate<Trigger>(triggers, triggerCount, [&](athena::io::IStreamReader& in, Trigger& tr) {
tr.first = i == 0;
tr.read(in);
i++;
});
}
template <>
void AFSM::State::Transition::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
w.writeInt32Big(triggerCount);
w.enumerate(triggers);
}
template <>
void AFSM::State::Transition::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
int i = 0;
/* triggers */
triggerCount = r.enumerate<Trigger>("triggers", triggers, [&](athena::io::YAMLDocReader& in, Trigger& tr) {
tr.first = i == 0;
tr.read(in);
i++;
});
}
template <>
void AFSM::State::Transition::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
/* triggers */
w.enumerate("triggers", triggers);
}
template <>
void AFSM::State::Transition::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
for (const Trigger& trig : triggers)
trig.binarySize(s);
}
std::string_view AFSM::State::Transition::DNAType() { return "DNAMP1::AFSM::Transition"sv; }
template <>
void AFSM::State::Transition::Trigger::Enumerate<BigDNA::Read>(athena::io::IStreamReader& __dna_reader) {
/* name */
name = __dna_reader.readString(-1);
/* parameter */
parameter = __dna_reader.readFloatBig();
if (first) {
/* targetState */
targetState = __dna_reader.readUint32Big();
}
}
template <>
void AFSM::State::Transition::Trigger::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& __dna_writer) {
/* name */
__dna_writer.writeString(name, -1);
/* parameter */
__dna_writer.writeFloatBig(parameter);
if (first) {
/* targetState */
__dna_writer.writeUint32Big(targetState);
}
}
template <>
void AFSM::State::Transition::Trigger::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& __dna_docin) {
/* name */
name = __dna_docin.readString("name");
/* parameter */
parameter = __dna_docin.readFloat("parameter");
if (first) {
/* targetState */
targetState = __dna_docin.readUint32("targetState");
}
}
template <>
void AFSM::State::Transition::Trigger::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& __dna_docout) {
/* name */
__dna_docout.writeString("name", name);
/* parameter */
__dna_docout.writeFloat("parameter", parameter);
if (first) {
/* targetState */
__dna_docout.writeUint32("targetState", targetState);
}
}
template <>
void AFSM::State::Transition::Trigger::Enumerate<BigDNA::BinarySize>(size_t& __isz) {
__isz += name.size() + 1;
__isz += (first ? 8 : 4);
}
std::string_view AFSM::State::Transition::Trigger::DNAType() { return "DNAMP1::AFSM::State::Transition::Trigger"sv; }
} // namespace DataSpec::DNAMP1

View File

@ -1,51 +0,0 @@
#pragma once
#include <athena/FileWriter.hpp>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DNAMP1.hpp"
namespace DataSpec::DNAMP1 {
struct AFSM : public BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> stateCount;
Vector<String<-1>, AT_DNA_COUNT(stateCount)> stateNames;
Value<atUint32> triggerCount;
struct State : public BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> transitionCount;
struct Transition : public BigDNA {
AT_DECL_EXPLICIT_DNA_YAML
Value<atUint32> triggerCount;
struct Trigger : public BigDNA {
AT_DECL_EXPLICIT_DNA_YAML
bool first = false;
String<-1> name;
Value<float> parameter;
Value<atUint32> targetState;
};
Vector<Trigger, AT_DNA_COUNT(triggerCount)> triggers;
};
Vector<Transition, AT_DNA_COUNT(transitionCount)> transitions;
};
Vector<State, AT_DNA_COUNT(stateCount)> states;
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
AFSM afsm;
afsm.read(rs);
athena::io::FileWriter writer(outPath.getAbsolutePath());
athena::io::ToYAMLStream(afsm, writer);
return true;
}
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath) {
AFSM afsm;
athena::io::FileReader reader(inPath.getAbsolutePath());
athena::io::FromYAMLStream(afsm, reader);
athena::io::FileWriter ws(outPath.getAbsolutePath());
afsm.write(ws);
return true;
}
};
} // namespace DataSpec::DNAMP1

View File

@ -1,266 +0,0 @@
#include "AGSC.hpp"
#include "amuse/AudioGroup.hpp"
#include "amuse/AudioGroupData.hpp"
extern "C" const uint8_t Atomic_H[];
extern "C" const uint8_t BetaBeetle_H[];
extern "C" const uint8_t Bird_H[];
extern "C" const uint8_t BloodFlower_H[];
extern "C" const uint8_t Burrower_H[];
extern "C" const uint8_t ChozoGhost_H[];
extern "C" const uint8_t ChubbWeed_H[];
extern "C" const uint8_t CineBoots_H[];
extern "C" const uint8_t CineGeneral_H[];
extern "C" const uint8_t CineGun_H[];
extern "C" const uint8_t CineMorphball_H[];
extern "C" const uint8_t CineSuit_H[];
extern "C" const uint8_t CineVisor_H[];
extern "C" const uint8_t Crater_H[];
extern "C" const uint8_t Crystallite_H[];
extern "C" const uint8_t Drones_H[];
extern "C" const uint8_t EliteSpacePirate_H[];
extern "C" const uint8_t FireFlea_H[];
extern "C" const uint8_t Flaaghra_H[];
extern "C" const uint8_t FlickerBat_H[];
extern "C" const uint8_t FlyingPirate_H[];
extern "C" const uint8_t FrontEnd_H[];
extern "C" const uint8_t GagantuanBeatle_H[];
extern "C" const uint8_t Gnats_H[];
extern "C" const uint8_t Gryzbee_H[];
extern "C" const uint8_t IceCrack_H[];
extern "C" const uint8_t IceWorld_H[];
extern "C" const uint8_t InjuredPirates_H[];
extern "C" const uint8_t IntroBoss_H[];
extern "C" const uint8_t IntroWorld_H[];
extern "C" const uint8_t JellyZap_H[];
extern "C" const uint8_t LavaWorld_H[];
extern "C" const uint8_t Magdolite_H[];
extern "C" const uint8_t Metaree_H[];
extern "C" const uint8_t MetroidPrime_H[];
extern "C" const uint8_t Metroid_H[];
extern "C" const uint8_t MinesWorld_H[];
extern "C" const uint8_t MiscSamus_H[];
extern "C" const uint8_t Misc_H[];
extern "C" const uint8_t OmegaPirate_H[];
extern "C" const uint8_t OverWorld_H[];
extern "C" const uint8_t Parasite_H[];
extern "C" const uint8_t PhazonGun_H[];
extern "C" const uint8_t Phazon_H[];
extern "C" const uint8_t PuddleSpore_H[];
extern "C" const uint8_t PuddleToad_H[];
extern "C" const uint8_t Puffer_H[];
extern "C" const uint8_t ReactorDoor_H[];
extern "C" const uint8_t Ridley_H[];
extern "C" const uint8_t Ripper_H[];
extern "C" const uint8_t RuinsWorld_H[];
extern "C" const uint8_t SamusShip_H[];
extern "C" const uint8_t Scarab_H[];
extern "C" const uint8_t Seedling_H[];
extern "C" const uint8_t SheeGoth_H[];
extern "C" const uint8_t SnakeWeed_H[];
extern "C" const uint8_t Sova_H[];
extern "C" const uint8_t SpacePirate_H[];
extern "C" const uint8_t SpankWeed_H[];
extern "C" const uint8_t Thardus_H[];
extern "C" const uint8_t TheEnd_H[];
extern "C" const uint8_t Torobyte_H[];
extern "C" const uint8_t Triclops_H[];
extern "C" const uint8_t Turret_H[];
extern "C" const uint8_t UI_H[];
extern "C" const uint8_t WarWasp_H[];
extern "C" const uint8_t Weapons_H[];
extern "C" const uint8_t ZZZ_H[];
extern "C" const uint8_t Zoomer_H[];
extern "C" const uint8_t lumigek_H[];
extern "C" const uint8_t test_H[];
namespace DataSpec::DNAMP1 {
using namespace std::literals;
static const std::pair<std::string_view, const uint8_t*> Headers[] = {{"Atomic"sv, Atomic_H},
{"BetaBeetle"sv, BetaBeetle_H},
{"Bird"sv, Bird_H},
{"BloodFlower"sv, BloodFlower_H},
{"Burrower"sv, Burrower_H},
{"ChozoGhost"sv, ChozoGhost_H},
{"ChubbWeed"sv, ChubbWeed_H},
{"CineBoots"sv, CineBoots_H},
{"CineGeneral"sv, CineGeneral_H},
{"CineGun"sv, CineGun_H},
{"CineMorphball"sv, CineMorphball_H},
{"CineSuit"sv, CineSuit_H},
{"CineVisor"sv, CineVisor_H},
{"Crater"sv, Crater_H},
{"Crystallite"sv, Crystallite_H},
{"Drones"sv, Drones_H},
{"EliteSpacePirate"sv, EliteSpacePirate_H},
{"FireFlea"sv, FireFlea_H},
{"Flaaghra"sv, Flaaghra_H},
{"FlickerBat"sv, FlickerBat_H},
{"FlyingPirate"sv, FlyingPirate_H},
{"FrontEnd"sv, FrontEnd_H},
{"GagantuanBeatle"sv, GagantuanBeatle_H},
{"Gnats"sv, Gnats_H},
{"Gryzbee"sv, Gryzbee_H},
{"IceCrack"sv, IceCrack_H},
{"IceWorld"sv, IceWorld_H},
{"InjuredPirates"sv, InjuredPirates_H},
{"IntroBoss"sv, IntroBoss_H},
{"IntroWorld"sv, IntroWorld_H},
{"JellyZap"sv, JellyZap_H},
{"LavaWorld"sv, LavaWorld_H},
{"Magdolite"sv, Magdolite_H},
{"Metaree"sv, Metaree_H},
{"MetroidPrime"sv, MetroidPrime_H},
{"Metroid"sv, Metroid_H},
{"MinesWorld"sv, MinesWorld_H},
{"MiscSamus"sv, MiscSamus_H},
{"Misc"sv, Misc_H},
{"OmegaPirate"sv, OmegaPirate_H},
{"OverWorld"sv, OverWorld_H},
{"Parasite"sv, Parasite_H},
{"Phazon"sv, Phazon_H},
{"PhazonGun"sv, PhazonGun_H},
{"PuddleSpore"sv, PuddleSpore_H},
{"PuddleToad"sv, PuddleToad_H},
{"Puffer"sv, Puffer_H},
{"ReactorDoor"sv, ReactorDoor_H},
{"Ridley"sv, Ridley_H},
{"Ripper"sv, Ripper_H},
{"RuinsWorld"sv, RuinsWorld_H},
{"SamusShip"sv, SamusShip_H},
{"Scarab"sv, Scarab_H},
{"Seedling"sv, Seedling_H},
{"SheeGoth"sv, SheeGoth_H},
{"SnakeWeed"sv, SnakeWeed_H},
{"Sova"sv, Sova_H},
{"SpacePirate"sv, SpacePirate_H},
{"SpankWeed"sv, SpankWeed_H},
{"Thardus"sv, Thardus_H},
{"TheEnd"sv, TheEnd_H},
{"Torobyte"sv, Torobyte_H},
{"Triclops"sv, Triclops_H},
{"Turret"sv, Turret_H},
{"UI"sv, UI_H},
{"WarWasp"sv, WarWasp_H},
{"Weapons"sv, Weapons_H},
{"ZZZ"sv, ZZZ_H},
{"Zoomer"sv, Zoomer_H},
{"lumigek"sv, lumigek_H},
{"test"sv, test_H}};
bool AGSC::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& dir) {
dir.makeDirChain(true);
Header head;
head.read(rs);
uint32_t poolLen = rs.readUint32Big();
auto pool = rs.readUBytes(poolLen);
uint32_t projLen = rs.readUint32Big();
auto proj = rs.readUBytes(projLen);
uint32_t sampLen = rs.readUint32Big();
auto samp = rs.readUBytes(sampLen);
uint32_t sdirLen = rs.readUint32Big();
auto sdir = rs.readUBytes(sdirLen);
amuse::AudioGroupData data(proj.get(), projLen, pool.get(), poolLen, sdir.get(), sdirLen, samp.get(), sampLen,
amuse::GCNDataTag{});
/* Load into amuse representation */
amuse::ProjectDatabase projDb;
projDb.setIdDatabases();
amuse::AudioGroupDatabase group(data);
group.setGroupPath(dir.getAbsolutePath());
/* Extract samples */
group.getSdir().extractAllCompressed(dir.getAbsolutePath(), data.getSamp());
/* Import C headers */
auto search = std::lower_bound(std::cbegin(Headers), std::cend(Headers), head.groupName,
[](const auto& a, const auto& b) { return a.first < b; });
if (search != std::cend(Headers) && search->first == head.groupName)
group.importCHeader((char*)search->second);
/* Write out project/pool */
{
auto projd = group.getProj().toYAML();
athena::io::FileWriter fo(hecl::ProjectPath(dir, "!project.yaml").getAbsolutePath());
if (fo.hasError())
return false;
fo.writeUBytes(projd.data(), projd.size());
}
{
auto poold = group.getPool().toYAML();
athena::io::FileWriter fo(hecl::ProjectPath(dir, "!pool.yaml").getAbsolutePath());
if (fo.hasError())
return false;
fo.writeUBytes(poold.data(), poold.size());
}
return true;
}
static std::atomic_bool DidCook = {false};
bool AGSC::Cook(const hecl::ProjectPath& dir, const hecl::ProjectPath& refOutPath) {
/* This will cook all AGSCs in the local directory, ensuring unique ObjectIDs
* across all Amuse subprojects */
if (DidCook.exchange(true))
return true; /* We've already cooked all AGSCs */
amuse::ProjectDatabase projDb;
projDb.setIdDatabases();
auto parentDir = dir.getParentPath();
auto outParentDir = refOutPath.getParentPath();
for (const auto& ent : dir.getParentPath().enumerateDir()) {
if (!ent.m_isDir)
continue;
hecl::ProjectPath path(parentDir, ent.m_name);
if (IsPathAudioGroup(path)) {
hecl::ProjectPath outPath(outParentDir, ent.m_name);
athena::io::FileWriter w(outPath.getAbsolutePath());
if (w.hasError())
return false;
Header head;
head.audioDir = "Audio/"sv;
auto lastComp = path.getLastComponent();
auto str = fmt::format(FMT_STRING("_{:8X}"), path.parsedHash32());
auto it = lastComp.rfind(str);
if (it != std::string_view::npos) {
lastComp = lastComp.substr(0, it);
}
head.groupName = lastComp;
head.write(w);
amuse::AudioGroupDatabase group(path.getAbsolutePath());
auto proj = group.getProj().toGCNData(group.getPool(), group.getSdir());
auto pool = group.getPool().toData<athena::Endian::Big>();
auto sdirSamp = group.getSdir().toGCNData(group);
w.writeUint32Big(pool.size());
w.writeUBytes(pool.data(), pool.size());
w.writeUint32Big(proj.size());
w.writeUBytes(proj.data(), proj.size());
w.writeUint32Big(sdirSamp.second.size());
w.writeUBytes(sdirSamp.second.data(), sdirSamp.second.size());
w.writeUint32Big(sdirSamp.first.size());
w.writeUBytes(sdirSamp.first.data(), sdirSamp.first.size());
}
}
return true;
}
} // namespace DataSpec::DNAMP1

View File

@ -1,19 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DNAMP1.hpp"
namespace DataSpec::DNAMP1 {
class AGSC {
public:
struct Header : BigDNA {
AT_DECL_DNA
String<-1> audioDir;
String<-1> groupName;
};
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
};
} // namespace DataSpec::DNAMP1

File diff suppressed because it is too large Load Diff

View File

@ -1,420 +0,0 @@
#pragma once
#include <map>
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/ANCS.hpp"
#include "CMDLMaterials.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
#include "ANIM.hpp"
#include "EVNT.hpp"
#include "athena/FileReader.hpp"
namespace DataSpec::DNAMP1 {
struct ANCS : BigDNA {
using CINFType = CINF;
using CSKRType = CSKR;
using ANIMType = ANIM;
AT_DECL_DNA_YAML
Value<atUint16> version;
struct CharacterSet : BigDNA {
AT_DECL_DNA_YAML
Value<atUint16> version;
Value<atUint32> characterCount;
struct CharacterInfo : BigDNA {
AT_DECL_DNA_YAML
Delete expl;
atUint32 idx;
std::string name;
UniqueID32 cmdl;
UniqueID32 cskr;
UniqueID32 cinf;
struct Animation : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> animIdx;
String<-1> strA;
String<-1> strB;
};
std::vector<Animation> animations;
struct PASDatabase : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> magic;
Value<atUint32> animStateCount;
Value<atUint32> defaultState;
struct AnimState : BigDNA {
AT_DECL_DNA_YAML
Delete expl;
atUint32 id;
struct ParmInfo : BigDNA {
AT_DECL_DNA_YAML
Delete expl;
enum class DataType { Int32 = 0, UInt32 = 1, Float = 2, Bool = 3, Enum = 4 };
union Parm {
atInt32 int32;
atUint32 uint32;
float float32;
bool bool1;
Parm() : int32(0) {}
Parm(atInt32 val) : int32(val) {}
Parm(atUint32 val) : uint32(val) {}
Parm(float val) : float32(val) {}
Parm(bool val) : bool1(val) {}
};
atUint32 parmType;
atUint32 weightFunction;
float weight;
Parm range[2];
};
std::vector<ParmInfo> parmInfos;
struct AnimInfo {
atUint32 id;
std::vector<ParmInfo::Parm> parmVals;
};
std::vector<AnimInfo> animInfos;
};
Vector<AnimState, AT_DNA_COUNT(animStateCount)> animStates;
} pasDatabase;
struct ParticleResData {
std::vector<UniqueID32> part;
std::vector<UniqueID32> swhc;
std::vector<UniqueID32> unk;
std::vector<UniqueID32> elsc;
} partResData;
atUint32 unk1 = 0;
struct ActionAABB : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atVec3f> aabb[2];
};
std::vector<ActionAABB> animAABBs;
struct Effect : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
Value<atUint32> compCount;
struct EffectComponent : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
DNAFourCC type;
UniqueID32 id;
String<-1> locator;
Value<float> scale;
Value<atUint32> parentMode;
Value<atUint32> flags;
};
Vector<EffectComponent, AT_DNA_COUNT(compCount)> comps;
};
std::vector<Effect> effects;
UniqueID32Zero cmdlIce;
UniqueID32Zero cskrIce;
std::vector<atUint32> animIdxs;
};
Vector<CharacterInfo, AT_DNA_COUNT(characterCount)> characters;
} characterSet;
struct AnimationSet : BigDNA {
AT_DECL_DNA_YAML
Delete expl;
struct MetaAnimPrimitive;
struct IMetaAnim : BigDNAVYaml {
Delete expl;
enum class Type { Primitive = 0, Blend = 1, PhaseBlend = 2, Random = 3, Sequence = 4 } m_type;
const char* m_typeStr;
IMetaAnim(Type type, const char* typeStr) : m_type(type), m_typeStr(typeStr) {}
virtual void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) = 0;
virtual bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) = 0;
};
struct MetaAnimFactory : BigDNA {
AT_DECL_EXPLICIT_DNA_YAML
std::unique_ptr<IMetaAnim> m_anim;
};
struct MetaAnimPrimitive : IMetaAnim {
AT_DECL_DNA_YAMLV
MetaAnimPrimitive() : IMetaAnim(Type::Primitive, "Primitive") {}
UniqueID32 animId;
Value<atUint32> animIdx;
String<-1> animName;
Value<float> unk1;
Value<atUint32> unk2;
void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) override;
bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) override {
return func(*this);
}
};
struct MetaAnimBlend : IMetaAnim {
MetaAnimBlend() : IMetaAnim(Type::Blend, "Blend") {}
AT_DECL_DNA_YAMLV
MetaAnimFactory animA;
MetaAnimFactory animB;
Value<float> unkFloat;
Value<atUint8> unk;
void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) override {
animA.m_anim->gatherPrimitives(pakRouter, out);
animB.m_anim->gatherPrimitives(pakRouter, out);
}
bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) override {
if (!animA.m_anim->enumeratePrimitives(func))
return false;
if (!animB.m_anim->enumeratePrimitives(func))
return false;
return true;
}
};
struct MetaAnimPhaseBlend : IMetaAnim {
MetaAnimPhaseBlend() : IMetaAnim(Type::PhaseBlend, "PhaseBlend") {}
AT_DECL_DNA_YAMLV
MetaAnimFactory animA;
MetaAnimFactory animB;
Value<float> unkFloat;
Value<atUint8> unk;
void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) override {
animA.m_anim->gatherPrimitives(pakRouter, out);
animB.m_anim->gatherPrimitives(pakRouter, out);
}
bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) override {
if (!animA.m_anim->enumeratePrimitives(func))
return false;
if (!animB.m_anim->enumeratePrimitives(func))
return false;
return true;
}
};
struct MetaAnimRandom : IMetaAnim {
MetaAnimRandom() : IMetaAnim(Type::Random, "Random") {}
AT_DECL_DNA_YAMLV
Value<atUint32> animCount;
struct Child : BigDNA {
AT_DECL_DNA
MetaAnimFactory anim;
Value<atUint32> probability;
};
Vector<Child, AT_DNA_COUNT(animCount)> children;
void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) override {
for (const auto& child : children)
child.anim.m_anim->gatherPrimitives(pakRouter, out);
}
bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) override {
for (auto& child : children)
if (!child.anim.m_anim->enumeratePrimitives(func))
return false;
return true;
}
};
struct MetaAnimSequence : IMetaAnim {
MetaAnimSequence() : IMetaAnim(Type::Sequence, "Sequence") {}
AT_DECL_DNA_YAMLV
Value<atUint32> animCount;
Vector<MetaAnimFactory, AT_DNA_COUNT(animCount)> children;
void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) override {
for (const auto& child : children)
child.m_anim->gatherPrimitives(pakRouter, out);
}
bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) override {
for (auto& child : children)
if (!child.m_anim->enumeratePrimitives(func))
return false;
return true;
}
};
struct Animation : BigDNA {
AT_DECL_DNA_YAML
String<-1> name;
MetaAnimFactory metaAnim;
};
std::vector<Animation> animations;
struct IMetaTrans : BigDNAVYaml {
Delete expl;
enum class Type {
MetaAnim = 0,
Trans = 1,
PhaseTrans = 2,
NoTrans = 3,
} m_type;
const char* m_typeStr;
IMetaTrans(Type type, const char* typeStr) : m_type(type), m_typeStr(typeStr) {}
virtual void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) {}
virtual bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) { return true; }
};
struct MetaTransFactory : BigDNA {
AT_DECL_DNA_YAML
Delete expl;
std::unique_ptr<IMetaTrans> m_trans;
};
struct MetaTransMetaAnim : IMetaTrans {
MetaTransMetaAnim() : IMetaTrans(Type::MetaAnim, "MetaAnim") {}
AT_DECL_DNA_YAMLV
MetaAnimFactory anim;
void gatherPrimitives(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) override {
anim.m_anim->gatherPrimitives(pakRouter, out);
}
bool enumeratePrimitives(const std::function<bool(MetaAnimPrimitive& prim)>& func) override {
return anim.m_anim->enumeratePrimitives(func);
}
};
struct MetaTransTrans : IMetaTrans {
MetaTransTrans() : IMetaTrans(Type::Trans, "Trans") {}
AT_DECL_DNA_YAMLV
Value<float> transDurTime;
Value<atUint32> transDurTimeMode;
Value<bool> unk2;
Value<bool> runA;
Value<atUint32> flags;
};
struct MetaTransPhaseTrans : IMetaTrans {
MetaTransPhaseTrans() : IMetaTrans(Type::PhaseTrans, "PhaseTrans") {}
AT_DECL_DNA_YAMLV
Value<float> transDurTime;
Value<atUint32> transDurTimeMode;
Value<bool> unk2;
Value<bool> runA;
Value<atUint32> flags;
};
struct Transition : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> unk;
Value<atUint32> animIdxA;
Value<atUint32> animIdxB;
MetaTransFactory metaTrans;
};
std::vector<Transition> transitions;
MetaTransFactory defaultTransition;
struct AdditiveAnimationInfo : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> animIdx;
Value<float> fadeInDur;
Value<float> fadeOutDur;
};
std::vector<AdditiveAnimationInfo> additiveAnims;
float additiveDefaultFadeInDur = 0.0;
float additiveDefaultFadeOutDur = 0.0;
struct HalfTransition : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> animIdx;
MetaTransFactory metaTrans;
};
std::vector<HalfTransition> halfTransitions;
struct AnimationResources : BigDNA {
AT_DECL_DNA_YAML
UniqueID32 animId;
UniqueID32 evntId;
};
std::vector<AnimationResources> animResources;
} animationSet;
void getCharacterResInfo(std::vector<DNAANCS::CharacterResInfo<UniqueID32>>& out) const {
out.clear();
out.reserve(characterSet.characters.size());
for (const CharacterSet::CharacterInfo& ci : characterSet.characters) {
out.emplace_back();
DNAANCS::CharacterResInfo<UniqueID32>& chOut = out.back();
chOut.name = ci.name;
chOut.cmdl = ci.cmdl;
chOut.cskr = ci.cskr;
chOut.cinf = ci.cinf;
if (ci.cmdlIce.isValid())
chOut.overlays.emplace_back("ICE", std::make_pair(ci.cmdlIce, ci.cskrIce));
}
}
void getAnimationResInfo(PAKRouter<PAKBridge>* pakRouter,
std::map<atUint32, DNAANCS::AnimationResInfo<UniqueID32>>& out) const {
out.clear();
for (const AnimationSet::Animation& ai : animationSet.animations)
if (AnimationSet::IMetaAnim* anim = ai.metaAnim.m_anim.get())
anim->gatherPrimitives(pakRouter, out);
for (const AnimationSet::Transition& ti : animationSet.transitions)
if (AnimationSet::IMetaTrans* trans = ti.metaTrans.m_trans.get())
trans->gatherPrimitives(pakRouter, out);
if (AnimationSet::IMetaTrans* trans = animationSet.defaultTransition.m_trans.get())
trans->gatherPrimitives(pakRouter, out);
}
void enumeratePrimitives(const std::function<bool(AnimationSet::MetaAnimPrimitive& prim)>& func) {
for (const AnimationSet::Animation& ai : animationSet.animations)
if (AnimationSet::IMetaAnim* anim = ai.metaAnim.m_anim.get())
anim->enumeratePrimitives(func);
for (const AnimationSet::Transition& ti : animationSet.transitions)
if (AnimationSet::IMetaTrans* trans = ti.metaTrans.m_trans.get())
trans->enumeratePrimitives(func);
if (AnimationSet::IMetaTrans* trans = animationSet.defaultTransition.m_trans.get())
trans->enumeratePrimitives(func);
}
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut, int charIdx) const {
auto doCi = [&](const CharacterSet::CharacterInfo& ci) {
for (const auto& id : ci.partResData.part)
g_curSpec->flattenDependencies(id, pathsOut);
for (const auto& id : ci.partResData.swhc)
g_curSpec->flattenDependencies(id, pathsOut);
for (const auto& id : ci.partResData.unk)
g_curSpec->flattenDependencies(id, pathsOut);
for (const auto& id : ci.partResData.elsc)
g_curSpec->flattenDependencies(id, pathsOut);
};
if (charIdx < 0)
for (const CharacterSet::CharacterInfo& ci : characterSet.characters)
doCi(ci);
else if (charIdx < characterSet.characters.size())
doCi(characterSet.characters[charIdx]);
}
static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok,
std::function<void(const char*)> fileChanged);
static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNAANCS::Actor& actor);
static bool CookCSKR(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
static bool CookCSKRPC(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
static bool CookANIM(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNAANCS::Actor& actor,
hecl::blender::DataStream& ds, bool pc);
};
} // namespace DataSpec::DNAMP1

View File

@ -1,624 +0,0 @@
#include "ANIM.hpp"
#include "zeus/CVector3f.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec::DNAMP1 {
using ANIMOutStream = hecl::blender::ANIMOutStream;
void ANIM::IANIM::sendANIMToBlender(hecl::blender::PyOutStream& os, const DNAANIM::RigInverter<CINF>& rig) const {
os.format(FMT_STRING("act.hecl_fps = round({})\n"
"act.hecl_looping = {}\n"),
(1.0f / mainInterval), looping ? "True" : "False");
auto kit = chanKeys.begin();
std::vector<zeus::CQuaternion> fixedRotKeys;
std::vector<zeus::CVector3f> fixedTransKeys;
for (const std::pair<atUint32, bool>& bone : bones) {
const std::string* bName = rig.getCINF().getBoneNameFromId(bone.first);
if (!bName) {
++kit;
if (bone.second)
++kit;
continue;
}
os.format(FMT_STRING("bone_string = '{}'\n"), *bName);
os << "action_group = act.groups.new(bone_string)\n"
"\n"
"rotCurves = []\n"
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=0, "
"action_group=bone_string))\n"
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=1, "
"action_group=bone_string))\n"
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=2, "
"action_group=bone_string))\n"
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=3, "
"action_group=bone_string))\n"
"\n";
if (bone.second)
os << "transCurves = []\n"
"transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=0, "
"action_group=bone_string))\n"
"transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=1, "
"action_group=bone_string))\n"
"transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=2, "
"action_group=bone_string))\n"
"\n";
ANIMOutStream ao = os.beginANIMCurve();
{
const std::vector<DNAANIM::Value>& rotKeys = *kit++;
fixedRotKeys.clear();
fixedRotKeys.resize(rotKeys.size());
for (int c = 0; c < 4; ++c) {
size_t idx = 0;
for (const DNAANIM::Value& val : rotKeys)
fixedRotKeys[idx++][c] = val.simd[c];
}
for (zeus::CQuaternion& rot : fixedRotKeys)
rot = rig.invertRotation(bone.first, rot);
for (int c = 0; c < 4; ++c) {
auto frameit = frames.begin();
ao.changeCurve(ANIMOutStream::CurveType::Rotate, c, rotKeys.size());
for (const zeus::CQuaternion& val : fixedRotKeys)
ao.write(*frameit++, val[c]);
}
}
if (bone.second) {
const std::vector<DNAANIM::Value>& transKeys = *kit++;
fixedTransKeys.clear();
fixedTransKeys.resize(transKeys.size());
for (int c = 0; c < 3; ++c) {
size_t idx = 0;
for (const DNAANIM::Value& val : transKeys)
fixedTransKeys[idx++][c] = val.simd[c];
}
for (zeus::CVector3f& t : fixedTransKeys)
t = rig.invertPosition(bone.first, t, true);
for (int c = 0; c < 3; ++c) {
auto frameit = frames.begin();
ao.changeCurve(ANIMOutStream::CurveType::Translate, c, fixedTransKeys.size());
for (const zeus::CVector3f& val : fixedTransKeys)
ao.write(*frameit++, val[c]);
}
}
}
}
UniqueID32 ANIM::GetEVNTId(athena::io::IStreamReader& reader) {
atUint32 version = reader.readUint32Big();
switch (version) {
case 0: {
ANIM0 anim0;
anim0.read(reader);
return anim0.evnt;
}
case 2:
case 3:
reader.seek(4);
return reader.readUint32Big();
default:
Log.report(logvisor::Error, FMT_STRING("unrecognized ANIM version"));
break;
}
return {};
}
template <>
void ANIM::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
atUint32 version = reader.readUint32Big();
switch (version) {
case 0:
m_anim = std::make_unique<ANIM0>();
m_anim->read(reader);
break;
case 2:
m_anim = std::make_unique<ANIM2>(false);
m_anim->read(reader);
break;
case 3:
m_anim = std::make_unique<ANIM2>(true);
m_anim->read(reader);
break;
default:
Log.report(logvisor::Error, FMT_STRING("unrecognized ANIM version"));
break;
}
}
template <>
void ANIM::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint32Big(m_anim->m_version);
m_anim->write(writer);
}
template <>
void ANIM::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
m_anim->binarySize(s);
}
std::string_view ANIM::ANIM0::DNAType() { return "ANIM0"sv; }
template <>
void ANIM::ANIM0::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) {
Header head;
head.read(reader);
mainInterval = head.interval;
frames.clear();
frames.reserve(head.keyCount);
for (size_t k = 0; k < head.keyCount; ++k)
frames.push_back(k);
std::map<atUint8, atUint32> boneMap;
for (size_t b = 0; b < head.boneSlotCount; ++b) {
atUint8 idx = reader.readUByte();
if (idx == 0xff)
continue;
boneMap[idx] = b;
}
atUint32 boneCount = reader.readUint32Big();
bones.clear();
bones.reserve(boneCount);
channels.clear();
for (size_t b = 0; b < boneCount; ++b) {
bones.emplace_back(boneMap[b], false);
atUint8 idx = reader.readUByte();
channels.emplace_back();
DNAANIM::Channel& chan = channels.back();
chan.type = DNAANIM::Channel::Type::Rotation;
if (idx != 0xff) {
bones.back().second = true;
channels.emplace_back();
DNAANIM::Channel& chan = channels.back();
chan.type = DNAANIM::Channel::Type::Translation;
}
}
reader.readUint32Big();
chanKeys.clear();
chanKeys.reserve(channels.size());
for (const std::pair<atUint32, bool>& bone : bones) {
chanKeys.emplace_back();
std::vector<DNAANIM::Value>& keys = chanKeys.back();
for (size_t k = 0; k < head.keyCount; ++k)
keys.emplace_back(reader.readVec4fBig());
if (bone.second)
chanKeys.emplace_back();
}
reader.readUint32Big();
auto kit = chanKeys.begin();
for (const std::pair<atUint32, bool>& bone : bones) {
++kit;
if (bone.second) {
std::vector<DNAANIM::Value>& keys = *kit++;
for (size_t k = 0; k < head.keyCount; ++k)
keys.emplace_back(reader.readVec3fBig());
}
}
evnt.read(reader);
}
template <>
void ANIM::ANIM0::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) {
Header head;
head.unk0 = 0;
head.unk1 = 0;
head.unk2 = 0;
head.keyCount = frames.size();
head.duration = head.keyCount * mainInterval;
head.interval = mainInterval;
atUint32 maxId = 0;
for (const std::pair<atUint32, bool>& bone : bones)
maxId = std::max(maxId, bone.first);
head.boneSlotCount = maxId + 1;
head.write(writer);
for (size_t s = 0; s < head.boneSlotCount; ++s) {
size_t boneIdx = 0;
bool found = false;
for (const std::pair<atUint32, bool>& bone : bones) {
if (s == bone.first) {
writer.writeUByte(boneIdx);
found = true;
break;
}
++boneIdx;
}
if (!found)
writer.writeUByte(0xff);
}
writer.writeUint32Big(bones.size());
size_t boneIdx = 0;
for (const std::pair<atUint32, bool>& bone : bones) {
if (bone.second)
writer.writeUByte(boneIdx);
else
writer.writeUByte(0xff);
++boneIdx;
}
writer.writeUint32Big(bones.size() * head.keyCount);
auto cit = chanKeys.begin();
atUint32 transKeyCount = 0;
for (const std::pair<atUint32, bool>& bone : bones) {
const std::vector<DNAANIM::Value>& keys = *cit++;
auto kit = keys.begin();
for (size_t k = 0; k < head.keyCount; ++k)
writer.writeVec4fBig(atVec4f{(*kit++).simd});
if (bone.second) {
transKeyCount += head.keyCount;
++cit;
}
}
writer.writeUint32Big(transKeyCount);
cit = chanKeys.begin();
for (const std::pair<atUint32, bool>& bone : bones) {
++cit;
if (bone.second) {
const std::vector<DNAANIM::Value>& keys = *cit++;
auto kit = keys.begin();
for (size_t k = 0; k < head.keyCount; ++k)
writer.writeVec3fBig(atVec3f{(*kit++).simd});
}
}
evnt.write(writer);
}
template <>
void ANIM::ANIM0::Enumerate<BigDNA::BinarySize>(size_t& __isz) {
Header head;
atUint32 maxId = 0;
for (const std::pair<atUint32, bool>& bone : bones)
maxId = std::max(maxId, bone.first);
head.binarySize(__isz);
__isz += maxId + 1;
__isz += bones.size() + 4;
__isz += 8;
for (const std::pair<atUint32, bool>& bone : bones) {
__isz += head.keyCount * 16;
if (bone.second)
__isz += head.keyCount * 12;
}
__isz += 4;
}
std::string_view ANIM::ANIM2::DNAType() { return "ANIM2"sv; }
template <>
void ANIM::ANIM2::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) {
Header head;
head.read(reader);
evnt = head.evnt;
mainInterval = head.interval;
looping = bool(head.looping);
WordBitmap keyBmp;
keyBmp.read(reader, head.keyBitmapBitCount);
frames.clear();
atUint32 frameAccum = 0;
for (bool bit : keyBmp) {
if (bit)
frames.push_back(frameAccum);
++frameAccum;
}
reader.seek(8);
bones.clear();
bones.reserve(head.boneChannelCount);
channels.clear();
channels.reserve(head.boneChannelCount);
atUint32 keyframeCount = 0;
if (m_version == 3) {
for (size_t b = 0; b < head.boneChannelCount; ++b) {
ChannelDescPC desc;
desc.read(reader);
bones.emplace_back(desc.id, desc.keyCount2 != 0);
if (desc.keyCount1) {
channels.emplace_back();
DNAANIM::Channel& chan = channels.back();
chan.type = DNAANIM::Channel::Type::Rotation;
chan.id = desc.id;
chan.i[0] = atInt32(desc.QinitRX) >> 8;
chan.q[0] = desc.QinitRX & 0xff;
chan.i[1] = atInt32(desc.QinitRY) >> 8;
chan.q[1] = desc.QinitRY & 0xff;
chan.i[2] = atInt32(desc.QinitRZ) >> 8;
chan.q[2] = desc.QinitRZ & 0xff;
}
keyframeCount = std::max(keyframeCount, desc.keyCount1);
if (desc.keyCount2) {
channels.emplace_back();
DNAANIM::Channel& chan = channels.back();
chan.type = DNAANIM::Channel::Type::Translation;
chan.id = desc.id;
chan.i[0] = atInt32(desc.QinitTX) >> 8;
chan.q[0] = desc.QinitTX & 0xff;
chan.i[1] = atInt32(desc.QinitTY) >> 8;
chan.q[1] = desc.QinitTY & 0xff;
chan.i[2] = atInt32(desc.QinitTZ) >> 8;
chan.q[2] = desc.QinitTZ & 0xff;
}
}
} else {
for (size_t b = 0; b < head.boneChannelCount; ++b) {
ChannelDesc desc;
desc.read(reader);
bones.emplace_back(desc.id, desc.keyCount2 != 0);
if (desc.keyCount1) {
channels.emplace_back();
DNAANIM::Channel& chan = channels.back();
chan.type = DNAANIM::Channel::Type::Rotation;
chan.id = desc.id;
chan.i[0] = desc.initRX;
chan.q[0] = desc.qRX;
chan.i[1] = desc.initRY;
chan.q[1] = desc.qRY;
chan.i[2] = desc.initRZ;
chan.q[2] = desc.qRZ;
}
keyframeCount = std::max(keyframeCount, atUint32(desc.keyCount1));
if (desc.keyCount2) {
channels.emplace_back();
DNAANIM::Channel& chan = channels.back();
chan.type = DNAANIM::Channel::Type::Translation;
chan.id = desc.id;
chan.i[0] = desc.initTX;
chan.q[0] = desc.qTX;
chan.i[1] = desc.initTY;
chan.q[1] = desc.qTY;
chan.i[2] = desc.initTZ;
chan.q[2] = desc.qTZ;
}
}
}
size_t bsSize = DNAANIM::ComputeBitstreamSize(keyframeCount, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader;
chanKeys = bsReader.read(bsData.get(), keyframeCount, channels, head.rotDiv, head.translationMult, 0.f);
}
template <>
void ANIM::ANIM2::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) {
Header head;
head.evnt = evnt;
head.unk0 = 1;
head.interval = mainInterval;
head.rootBoneId = 3;
head.looping = looping;
head.unk3 = 1;
WordBitmap keyBmp;
size_t frameCount = 0;
for (atUint32 frame : frames) {
if (!keyBmp.getBit(frame)) {
keyBmp.setBit(frame);
frameCount += 1;
}
}
head.keyBitmapBitCount = keyBmp.getBitCount();
head.duration = frames.back() * mainInterval;
head.boneChannelCount = bones.size();
size_t keyframeCount = frameCount - 1;
std::vector<DNAANIM::Channel> qChannels = channels;
DNAANIM::BitstreamWriter bsWriter;
size_t bsSize;
float scaleMult;
std::unique_ptr<atUint8[]> bsData =
bsWriter.write(chanKeys, keyframeCount, qChannels, m_version == 3 ? 0x7fffff : 0x7fff, head.rotDiv,
head.translationMult, scaleMult, bsSize);
/* Tally up buffer size */
size_t scratchSize = 0;
head.binarySize(scratchSize);
keyBmp.binarySize(scratchSize);
scratchSize += bsSize;
if (m_version == 3) {
for (const std::pair<atUint32, bool>& bone : bones) {
ChannelDescPC desc;
desc.keyCount1 = keyframeCount;
if (bone.second)
desc.keyCount2 = keyframeCount;
desc.binarySize(scratchSize);
}
} else {
for (const std::pair<atUint32, bool>& bone : bones) {
ChannelDesc desc;
desc.keyCount1 = keyframeCount;
if (bone.second)
desc.keyCount2 = keyframeCount;
desc.binarySize(scratchSize);
}
}
head.scratchSize = scratchSize;
head.write(writer);
keyBmp.write(writer);
writer.writeUint32Big(head.boneChannelCount);
writer.writeUint32Big(head.boneChannelCount);
auto cit = qChannels.begin();
if (m_version == 3) {
for (const std::pair<atUint32, bool>& bone : bones) {
ChannelDescPC desc;
desc.id = bone.first;
DNAANIM::Channel& chan = *cit++;
desc.keyCount1 = keyframeCount;
desc.QinitRX = (chan.i[0] << 8) | chan.q[0];
desc.QinitRY = (chan.i[1] << 8) | chan.q[1];
desc.QinitRZ = (chan.i[2] << 8) | chan.q[2];
if (bone.second) {
DNAANIM::Channel& chan = *cit++;
desc.keyCount2 = keyframeCount;
desc.QinitTX = (chan.i[0] << 8) | chan.q[0];
desc.QinitTY = (chan.i[1] << 8) | chan.q[1];
desc.QinitTZ = (chan.i[2] << 8) | chan.q[2];
}
desc.write(writer);
}
} else {
for (const std::pair<atUint32, bool>& bone : bones) {
ChannelDesc desc;
desc.id = bone.first;
DNAANIM::Channel& chan = *cit++;
desc.keyCount1 = keyframeCount;
desc.initRX = chan.i[0];
desc.qRX = chan.q[0];
desc.initRY = chan.i[1];
desc.qRY = chan.q[1];
desc.initRZ = chan.i[2];
desc.qRZ = chan.q[2];
if (bone.second) {
DNAANIM::Channel& chan = *cit++;
desc.keyCount2 = keyframeCount;
desc.initTX = chan.i[0];
desc.qTX = chan.q[0];
desc.initTY = chan.i[1];
desc.qTY = chan.q[1];
desc.initTZ = chan.i[2];
desc.qTZ = chan.q[2];
}
desc.write(writer);
}
}
writer.writeUBytes(bsData.get(), bsSize);
}
template <>
void ANIM::ANIM2::Enumerate<BigDNA::BinarySize>(size_t& __isz) {
Header head;
WordBitmap keyBmp;
for (atUint32 frame : frames)
keyBmp.setBit(frame);
head.binarySize(__isz);
keyBmp.binarySize(__isz);
__isz += 8;
if (m_version == 3) {
for (const std::pair<atUint32, bool>& bone : bones) {
__isz += 24;
if (bone.second)
__isz += 12;
}
} else {
for (const std::pair<atUint32, bool>& bone : bones) {
__isz += 17;
if (bone.second)
__isz += 9;
}
}
__isz += DNAANIM::ComputeBitstreamSize(frames.size(), channels);
}
ANIM::ANIM(const BlenderAction& act, const std::unordered_map<std::string, atInt32>& idMap,
const DNAANIM::RigInverter<CINF>& rig, bool pc) {
m_anim = std::make_unique<ANIM2>(pc);
IANIM& newAnim = *m_anim;
newAnim.looping = act.looping;
newAnim.bones.reserve(act.channels.size());
size_t extChanCount = 0;
std::unordered_set<atInt32> addedBones;
addedBones.reserve(act.channels.size());
for (const BlenderAction::Channel& chan : act.channels) {
auto search = idMap.find(chan.boneName);
if (search == idMap.cend()) {
Log.report(logvisor::Warning, FMT_STRING("unable to find id for bone '{}'"), chan.boneName);
continue;
}
if (addedBones.find(search->second) != addedBones.cend())
continue;
addedBones.insert(search->second);
extChanCount += std::max(zeus::PopCount(chan.attrMask), 2);
newAnim.bones.emplace_back(search->second, (chan.attrMask & 0x2) != 0);
}
newAnim.frames.reserve(act.frames.size());
for (int32_t frame : act.frames)
newAnim.frames.push_back(frame);
newAnim.channels.reserve(extChanCount);
newAnim.chanKeys.reserve(extChanCount);
for (const BlenderAction::Channel& chan : act.channels) {
auto search = idMap.find(chan.boneName);
if (search == idMap.cend())
continue;
newAnim.channels.emplace_back();
DNAANIM::Channel& newChan = newAnim.channels.back();
newChan.type = DNAANIM::Channel::Type::Rotation;
newChan.id = search->second;
newAnim.chanKeys.emplace_back();
std::vector<DNAANIM::Value>& rotVals = newAnim.chanKeys.back();
rotVals.reserve(chan.keys.size());
float sign = 0.f;
for (const BlenderAction::Channel::Key& key : chan.keys) {
zeus::CQuaternion q(key.rotation.val);
q = rig.restoreRotation(newChan.id, q);
if (sign == 0.f)
sign = q.w() < 0.f ? -1.f : 1.f;
q *= sign;
q.normalize();
rotVals.emplace_back(q.mSimd);
}
if (chan.attrMask & 0x2) {
newAnim.channels.emplace_back();
DNAANIM::Channel& newChan = newAnim.channels.back();
newChan.type = DNAANIM::Channel::Type::Translation;
newChan.id = search->second;
newAnim.chanKeys.emplace_back();
std::vector<DNAANIM::Value>& transVals = newAnim.chanKeys.back();
transVals.reserve(chan.keys.size());
for (const BlenderAction::Channel::Key& key : chan.keys) {
zeus::CVector3f pos(key.position.val);
pos = rig.restorePosition(newChan.id, pos, true);
transVals.emplace_back(pos.mSimd);
}
}
}
/* Retro's original data uses microsecond precision */
newAnim.mainInterval = std::trunc(act.interval * 1000000.0) / 1000000.0;
}
} // namespace DataSpec::DNAMP1

View File

@ -1,214 +0,0 @@
#pragma once
#include "DNAMP1.hpp"
#include "DataSpec/DNACommon/ANIM.hpp"
#include "DataSpec/DNACommon/RigInverter.hpp"
#include "CINF.hpp"
#include "EVNT.hpp"
#include "DataSpec/DNACommon/ANCS.hpp"
namespace DataSpec::DNAMP1 {
struct ANIM : BigDNA {
AT_DECL_EXPLICIT_DNA
static UniqueID32 GetEVNTId(athena::io::IStreamReader& r);
struct IANIM : BigDNAV {
Delete expl;
atUint32 m_version;
IANIM(atUint32 version) : m_version(version) {}
std::vector<std::pair<atUint32, bool>> bones;
std::vector<atUint32> frames;
std::vector<DNAANIM::Channel> channels;
std::vector<std::vector<DNAANIM::Value>> chanKeys;
float mainInterval = 0.0;
UniqueID32Zero evnt;
bool looping = false;
void sendANIMToBlender(hecl::blender::PyOutStream&, const DNAANIM::RigInverter<CINF>& rig) const;
};
struct ANIM0 : IANIM {
AT_DECL_EXPLICIT_DNAV
ANIM0() : IANIM(0) {}
struct Header : BigDNA {
AT_DECL_DNA
Value<float> duration;
Value<atUint32> unk0;
Value<float> interval;
Value<atUint32> unk1;
Value<atUint32> keyCount;
Value<atUint32> unk2;
Value<atUint32> boneSlotCount;
};
};
struct ANIM2 : IANIM {
AT_DECL_EXPLICIT_DNAV
ANIM2(bool pc) : IANIM(pc ? 3 : 2) {}
struct Header : BigDNA {
AT_DECL_DNA
Value<atUint32> scratchSize;
UniqueID32Zero evnt;
Value<atUint32> unk0 = 1;
Value<float> duration;
Value<float> interval;
Value<atUint32> rootBoneId = 3;
Value<atUint32> looping = 0;
Value<atUint32> rotDiv;
Value<float> translationMult;
Value<atUint32> boneChannelCount;
Value<atUint32> unk3;
Value<atUint32> keyBitmapBitCount;
};
struct ChannelDesc : BigDNA {
Delete expl;
Value<atUint32> id = 0;
Value<atUint16> keyCount1 = 0;
Value<atInt16> initRX = 0;
Value<atUint8> qRX = 0;
Value<atInt16> initRY = 0;
Value<atUint8> qRY = 0;
Value<atInt16> initRZ = 0;
Value<atUint8> qRZ = 0;
Value<atUint16> keyCount2 = 0;
Value<atInt16> initTX = 0;
Value<atUint8> qTX = 0;
Value<atInt16> initTY = 0;
Value<atUint8> qTY = 0;
Value<atInt16> initTZ = 0;
Value<atUint8> qTZ = 0;
void read(athena::io::IStreamReader& reader) {
id = reader.readUint32Big();
keyCount1 = reader.readUint16Big();
initRX = reader.readInt16Big();
qRX = reader.readUByte();
initRY = reader.readInt16Big();
qRY = reader.readUByte();
initRZ = reader.readInt16Big();
qRZ = reader.readUByte();
keyCount2 = reader.readUint16Big();
if (keyCount2) {
initTX = reader.readInt16Big();
qTX = reader.readUByte();
initTY = reader.readInt16Big();
qTY = reader.readUByte();
initTZ = reader.readInt16Big();
qTZ = reader.readUByte();
}
}
void write(athena::io::IStreamWriter& writer) const {
writer.writeUint32Big(id);
writer.writeUint16Big(keyCount1);
writer.writeInt16Big(initRX);
writer.writeUByte(qRX);
writer.writeInt16Big(initRY);
writer.writeUByte(qRY);
writer.writeInt16Big(initRZ);
writer.writeUByte(qRZ);
writer.writeUint16Big(keyCount2);
if (keyCount2) {
writer.writeInt16Big(initTX);
writer.writeUByte(qTX);
writer.writeInt16Big(initTY);
writer.writeUByte(qTY);
writer.writeInt16Big(initTZ);
writer.writeUByte(qTZ);
}
}
void binarySize(size_t& __isz) const {
__isz += 17;
if (keyCount2)
__isz += 9;
}
};
struct ChannelDescPC : BigDNA {
Delete expl;
Value<atUint32> id = 0;
Value<atUint32> keyCount1 = 0;
Value<atUint32> QinitRX = 0;
Value<atUint32> QinitRY = 0;
Value<atUint32> QinitRZ = 0;
Value<atUint32> keyCount2 = 0;
Value<atUint32> QinitTX = 0;
Value<atUint32> QinitTY = 0;
Value<atUint32> QinitTZ = 0;
void read(athena::io::IStreamReader& reader) {
id = reader.readUint32Big();
keyCount1 = reader.readUint32Big();
QinitRX = reader.readUint32Big();
QinitRY = reader.readUint32Big();
QinitRZ = reader.readUint32Big();
keyCount2 = reader.readUint32Big();
if (keyCount2) {
QinitTX = reader.readUint32Big();
QinitTY = reader.readUint32Big();
QinitTZ = reader.readUint32Big();
}
}
void write(athena::io::IStreamWriter& writer) const {
writer.writeUint32Big(id);
writer.writeUint32Big(keyCount1);
writer.writeUint32Big(QinitRX);
writer.writeUint32Big(QinitRY);
writer.writeUint32Big(QinitRZ);
writer.writeUint32Big(keyCount2);
if (keyCount2) {
writer.writeUint32Big(QinitTX);
writer.writeUint32Big(QinitTY);
writer.writeUint32Big(QinitTZ);
}
}
void binarySize(size_t& __isz) const {
__isz += 24;
if (keyCount2)
__isz += 12;
}
};
};
std::unique_ptr<IANIM> m_anim;
void sendANIMToBlender(hecl::blender::PyOutStream& os, const DNAANIM::RigInverter<CINF>& rig, bool) const {
m_anim->sendANIMToBlender(os, rig);
}
bool isLooping() const {
if (!m_anim)
return false;
return m_anim->looping;
}
void extractEVNT(const DNAANCS::AnimationResInfo<UniqueID32>& animInfo, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, bool force) const {
if (m_anim->evnt.isValid()) {
hecl::ProjectPath evntYamlPath = outPath.getWithExtension(
fmt::format(FMT_STRING(".{}_{}.evnt.yaml"), animInfo.name, m_anim->evnt).c_str(), true);
hecl::ProjectPath::Type evntYamlType = evntYamlPath.getPathType();
if (force || evntYamlType == hecl::ProjectPath::Type::None) {
EVNT evnt;
if (pakRouter.lookupAndReadDNA(m_anim->evnt, evnt, true)) {
athena::io::FileWriter writer(evntYamlPath.getAbsolutePath());
athena::io::ToYAMLStream(evnt, writer);
}
}
}
}
using BlenderAction = hecl::blender::Action;
ANIM() = default;
ANIM(const BlenderAction& act, const std::unordered_map<std::string, atInt32>& idMap,
const DNAANIM::RigInverter<CINF>& rig, bool pc);
};
} // namespace DataSpec::DNAMP1

View File

@ -1,198 +0,0 @@
#include "CINF.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec::DNAMP1 {
atUint32 CINF::getInternalBoneIdxFromId(atUint32 id) const {
atUint32 idx = 0;
for (const Bone& b : bones) {
if (b.id == id)
return idx;
++idx;
}
return -1;
}
atUint32 CINF::getBoneIdxFromId(atUint32 id) const {
atUint32 idx = 0;
for (atUint32 bid : boneIds) {
if (bid == id)
return idx;
++idx;
}
return 0;
}
const std::string* CINF::getBoneNameFromId(atUint32 id) const {
for (const Name& name : names)
if (id == name.boneId)
return &name.name;
return nullptr;
}
void CINF::sendVertexGroupsToBlender(hecl::blender::PyOutStream& os) const {
for (atUint32 bid : boneIds) {
for (const Name& name : names) {
if (name.boneId == bid) {
os.format(FMT_STRING("obj.vertex_groups.new(name='{}')\n"), name.name);
break;
}
}
}
}
void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& cinfId) const {
DNAANIM::RigInverter<CINF> inverter(*this);
os.format(FMT_STRING("arm = bpy.data.armatures.new('CINF_{}')\n"
"arm_obj = bpy.data.objects.new(arm.name, arm)\n"
"bpy.context.scene.collection.objects.link(arm_obj)\n"
"bpy.context.view_layer.objects.active = arm_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"arm_bone_table = {{}}\n"),
cinfId);
for (const DNAANIM::RigInverter<CINF>::Bone& bone : inverter.getBones()) {
zeus::simd_floats originF(bone.m_origBone.origin.simd);
zeus::simd_floats tailF(bone.m_tail.mSimd);
os.format(FMT_STRING("bone = arm.edit_bones.new('{}')\n"
"bone.head = ({},{},{})\n"
"bone.tail = ({},{},{})\n"
"bone.use_inherit_scale = False\n"
"arm_bone_table[{}] = bone\n"),
*getBoneNameFromId(bone.m_origBone.id), originF[0], originF[1], originF[2], tailF[0], tailF[1], tailF[2],
bone.m_origBone.id);
}
for (const Bone& bone : bones)
if (bone.parentId != 2)
os.format(FMT_STRING("arm_bone_table[{}].parent = arm_bone_table[{}]\n"), bone.id, bone.parentId);
os << "bpy.ops.object.mode_set(mode='OBJECT')\n";
for (const DNAANIM::RigInverter<CINF>::Bone& bone : inverter.getBones())
os.format(FMT_STRING("arm_obj.pose.bones['{}'].rotation_mode = 'QUATERNION'\n"),
*getBoneNameFromId(bone.m_origBone.id));
}
std::string CINF::GetCINFArmatureName(const UniqueID32& cinfId) { return fmt::format(FMT_STRING("CINF_{}"), cinfId); }
int CINF::RecursiveAddArmatureBone(const Armature& armature, const BlenderBone* bone, int parent, int& curId,
std::unordered_map<std::string, atInt32>& idMap,
std::map<std::string, int>& nameMap) {
int selId;
auto search = idMap.find(bone->name);
if (search == idMap.end()) {
selId = curId++;
idMap.emplace(std::make_pair(bone->name, selId));
} else
selId = search->second;
bones.emplace_back();
Bone& boneOut = bones.back();
nameMap[bone->name] = selId;
boneOut.id = selId;
boneOut.parentId = parent;
boneOut.origin = bone->origin;
boneOut.linkedCount = bone->children.size() + 1;
boneOut.linked.reserve(boneOut.linkedCount);
const BlenderBone* child;
boneOut.linked.push_back(parent);
for (size_t i = 0; (child = armature.getChild(bone, i)); ++i)
boneOut.linked.push_back(RecursiveAddArmatureBone(armature, child, boneOut.id, curId, idMap, nameMap));
return boneOut.id;
}
CINF::CINF(const Armature& armature, std::unordered_map<std::string, atInt32>& idMap) {
idMap.reserve(armature.bones.size());
bones.reserve(armature.bones.size());
std::map<std::string, int> nameMap;
const BlenderBone* bone = armature.getRoot();
if (bone) {
if (bone->children.size()) {
int curId = 4;
const BlenderBone* child;
for (size_t i = 0; (child = armature.getChild(bone, i)); ++i)
RecursiveAddArmatureBone(armature, child, 3, curId, idMap, nameMap);
}
bones.emplace_back();
Bone& boneOut = bones.back();
nameMap[bone->name] = 3;
boneOut.id = 3;
boneOut.parentId = 2;
boneOut.origin = bone->origin;
idMap.emplace(std::make_pair(bone->name, 3));
if (bone->children.size()) {
boneOut.linkedCount = 2;
boneOut.linked = {2, 4};
} else {
boneOut.linkedCount = 1;
boneOut.linked = {2};
}
}
boneCount = bones.size();
names.reserve(nameMap.size());
nameCount = nameMap.size();
for (const auto& name : nameMap) {
names.emplace_back();
Name& nameOut = names.back();
nameOut.name = name.first;
nameOut.boneId = name.second;
}
boneIdCount = boneCount;
boneIds.reserve(boneIdCount);
for (auto it = bones.crbegin(); it != bones.crend(); ++it)
boneIds.push_back(it->id);
}
bool CINF::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok,
std::function<void(const char*)> fileChanged) {
if (!force && outPath.isFile())
return true;
auto& conn = btok.getBlenderConnection();
if (!conn.createBlend(outPath, hecl::blender::BlendType::Armature))
return false;
auto os = conn.beginPythonOut(true);
os.format(FMT_STRING("import bpy\n"
"from mathutils import Vector\n"
"bpy.context.scene.name = 'CINF_{}'\n"
"bpy.context.scene.hecl_arm_obj = bpy.context.scene.name\n"
"\n"
"# Clear Scene\n"
"if len(bpy.data.collections):\n"
" bpy.data.collections.remove(bpy.data.collections[0])\n"
"\n"),
entry.id);
CINF cinf;
cinf.read(rs);
cinf.sendCINFToBlender(os, entry.id);
os.centerView();
os.close();
return conn.saveBlend();
}
bool CINF::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath,
const hecl::blender::Armature& armature) {
std::unordered_map<std::string, atInt32> boneIdMap;
CINF cinf(armature, boneIdMap);
/* Write out CINF resource */
athena::io::TransactionalFileWriter w(outPath.getAbsolutePath());
cinf.write(w);
return true;
}
} // namespace DataSpec::DNAMP1

View File

@ -1,57 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/RigInverter.hpp"
#include "DNAMP1.hpp"
namespace DataSpec::DNAMP1 {
struct CINF : BigDNA {
AT_DECL_DNA
Value<atUint32> boneCount;
struct Bone : BigDNA {
AT_DECL_DNA
Value<atUint32> id;
Value<atUint32> parentId;
Value<atVec3f> origin;
Value<atUint32> linkedCount;
Vector<atUint32, AT_DNA_COUNT(linkedCount)> linked;
};
Vector<Bone, AT_DNA_COUNT(boneCount)> bones;
Value<atUint32> boneIdCount;
Vector<atUint32, AT_DNA_COUNT(boneIdCount)> boneIds;
Value<atUint32> nameCount;
struct Name : BigDNA {
AT_DECL_DNA
String<-1> name;
Value<atUint32> boneId;
};
Vector<Name, AT_DNA_COUNT(nameCount)> names;
atUint32 getInternalBoneIdxFromId(atUint32 id) const;
atUint32 getBoneIdxFromId(atUint32 id) const;
const std::string* getBoneNameFromId(atUint32 id) const;
void sendVertexGroupsToBlender(hecl::blender::PyOutStream& os) const;
void sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& cinfId) const;
static std::string GetCINFArmatureName(const UniqueID32& cinfId);
CINF() = default;
using Armature = hecl::blender::Armature;
using BlenderBone = hecl::blender::Bone;
int RecursiveAddArmatureBone(const Armature& armature, const BlenderBone* bone, int parent, int& curId,
std::unordered_map<std::string, atInt32>& idMap, std::map<std::string, int>& nameMap);
CINF(const Armature& armature, std::unordered_map<std::string, atInt32>& idMap);
static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok,
std::function<void(const char*)> fileChanged);
static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath,
const hecl::blender::Armature& armature);
};
} // namespace DataSpec::DNAMP1

View File

@ -1,125 +0,0 @@
#include "CMDL.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec::DNAMP1 {
bool CMDL::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok,
std::function<void(const char*)> fileChanged) {
/* Check for RigPair */
CINF cinf;
CSKR cskr;
using RigPair = std::pair<std::pair<UniqueID32, CSKR*>, std::pair<UniqueID32, CINF*>>;
RigPair loadRp = {};
if (const typename CharacterAssociations<UniqueID32>::RigPair* rp = pakRouter.lookupCMDLRigPair(entry.id)) {
pakRouter.lookupAndReadDNA(rp->cskr, cskr);
pakRouter.lookupAndReadDNA(rp->cinf, cinf);
loadRp.first = {rp->cskr, &cskr};
loadRp.second = {rp->cinf, &cinf};
}
/* Do extract */
hecl::blender::Connection& conn = btok.getBlenderConnection();
if (!conn.createBlend(outPath, hecl::blender::BlendType::Mesh))
return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, RigPair, DNACMDL::SurfaceHeader_1, 2>(
conn, rs, pakRouter, entry, dataSpec, loadRp);
conn.saveBlend();
#if 0
/* Cook and re-extract test */
hecl::ProjectPath tempOut = outPath.getWithExtension(".recook", true);
hecl::blender::Connection::DataStream ds = conn.beginData();
DNACMDL::Mesh mesh = ds.compileMesh(hecl::TopologyTriStrips, -1);
ds.close();
DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1_2, 2>(tempOut, outPath, mesh);
athena::io::FileReader reader(tempOut.getAbsolutePath());
hecl::ProjectPath tempBlend = outPath.getWithExtension(".recook.blend", true);
if (!conn.createBlend(tempBlend, hecl::blender::Connection::TypeMesh))
return false;
DNACMDL::ReadCMDLToBlender<PAKRouter<PAKBridge>, MaterialSet, std::pair<CSKR*,CINF*>, DNACMDL::SurfaceHeader_1_2, 2>
(conn, reader, pakRouter, entry, dataSpec, loadRp);
return conn.saveBlend();
#elif 0
/* HMDL cook test */
hecl::ProjectPath tempOut = outPath.getWithExtension(".recook", true);
hecl::blender::Connection::DataStream ds = conn.beginData();
DNACMDL::Mesh mesh = ds.compileMesh(hecl::HMDLTopology::TriStrips, 16);
ds.close();
DNACMDL::WriteHMDLCMDL<HMDLMaterialSet, DNACMDL::SurfaceHeader_1, 2>(tempOut, outPath, mesh);
#endif
return true;
}
bool CMDL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNACMDL::Mesh& mesh) {
if (!mesh.skins.empty()) {
DNACMDL::Mesh skinMesh = mesh.getContiguousSkinningVersion();
if (!DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1, 2>(outPath, inPath, skinMesh))
return false;
/* Output skinning intermediate */
auto vertCountIt = skinMesh.contiguousSkinVertCounts.cbegin();
athena::io::FileWriter writer(outPath.getWithExtension(".skinint").getAbsolutePath());
writer.writeUint32Big(skinMesh.boneNames.size());
for (const std::string& boneName : skinMesh.boneNames)
writer.writeString(boneName);
writer.writeUint32Big(skinMesh.skins.size());
for (const auto& skin : skinMesh.skins) {
size_t numBinds = skinMesh.countSkinBinds(skin);
writer.writeUint32Big(numBinds);
for (size_t i = 0; i < numBinds; ++i) {
writer.writeUint32Big(skin[i].vg_idx);
writer.writeFloatBig(skin[i].weight);
}
writer.writeUint32Big(*vertCountIt++);
}
writer.writeUint32Big(skinMesh.pos.size());
writer.writeUint32Big(skinMesh.norm.size());
} else if (!DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1, 2>(outPath, inPath, mesh))
return false;
return true;
}
bool CMDL::HMDLCook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNACMDL::Mesh& mesh) {
hecl::blender::PoolSkinIndex poolSkinIndex;
if (mesh.skins.size()) {
if (!DNACMDL::WriteHMDLCMDL<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, 2>(outPath, inPath, mesh, poolSkinIndex))
return false;
/* Output skinning intermediate */
athena::io::FileWriter writer(outPath.getWithExtension(".skinint").getAbsolutePath());
writer.writeUint32Big(mesh.skinBanks.banks.size());
for (const DNACMDL::Mesh::SkinBanks::Bank& sb : mesh.skinBanks.banks) {
writer.writeUint32Big(sb.m_boneIdxs.size());
for (uint32_t bind : sb.m_boneIdxs)
writer.writeUint32Big(bind);
}
writer.writeUint32Big(mesh.boneNames.size());
for (const std::string& boneName : mesh.boneNames)
writer.writeString(boneName);
/* CVirtualBone structure just like original (for CPU skinning) */
writer.writeUint32Big(mesh.skins.size());
for (auto& s : mesh.skins) {
size_t numBinds = mesh.countSkinBinds(s);
writer.writeUint32Big(numBinds);
for (size_t i = 0; i < numBinds; ++i) {
writer.writeUint32Big(s[i].vg_idx);
writer.writeFloatBig(s[i].weight);
}
}
/* Write indirection table mapping pool verts to CVirtualBones */
writer.writeUint32Big(poolSkinIndex.m_poolSz);
for (uint32_t i = 0; i < poolSkinIndex.m_poolSz; ++i)
writer.writeUint32Big(poolSkinIndex.m_poolToSkinIndex[i]);
} else if (!DNACMDL::WriteHMDLCMDL<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, 2>(outPath, inPath, mesh,
poolSkinIndex))
return false;
return true;
}
} // namespace DataSpec::DNAMP1

View File

@ -1,29 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/CMDL.hpp"
#include "CMDLMaterials.hpp"
#include "DNAMP1.hpp"
#include "CINF.hpp"
#include "CSKR.hpp"
#include <athena/FileReader.hpp>
namespace DataSpec::DNAMP1 {
struct CMDL {
static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok,
std::function<void(const char*)> fileChanged);
static void Name(const SpecBase& dataSpec, PAKEntryReadStream& rs, PAKRouter<PAKBridge>& pakRouter,
PAK::Entry& entry) {
DNACMDL::NameCMDL<PAKRouter<PAKBridge>, MaterialSet>(rs, pakRouter, entry, dataSpec);
}
static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNACMDL::Mesh& mesh);
static bool HMDLCook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const DNACMDL::Mesh& mesh);
};
} // namespace DataSpec::DNAMP1

File diff suppressed because it is too large Load Diff

View File

@ -1,640 +0,0 @@
#pragma once
#include "DataSpec/DNACommon/DNACommon.hpp"
#include "DataSpec/DNACommon/GX.hpp"
#include "DataSpec/DNACommon/CMDL.hpp"
#include "DNAMP1.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec::DNAMP1 {
struct MaterialSet : BigDNA {
static constexpr bool OneSection() { return false; }
AT_DECL_DNA
struct MaterialSetHead : BigDNA {
AT_DECL_DNA
Value<atUint32> textureCount = 0;
Vector<UniqueID32, AT_DNA_COUNT(textureCount)> textureIDs;
Value<atUint32> materialCount = 0;
Vector<atUint32, AT_DNA_COUNT(materialCount)> materialEndOffs;
void addTexture(const UniqueID32& id) {
textureIDs.push_back(id);
++textureCount;
}
void addMaterialEndOff(atUint32 off) {
materialEndOffs.push_back(off);
++materialCount;
}
template <class PAKBRIDGE>
void ensureTexturesExtracted(PAKRouter<PAKBRIDGE>& pakRouter) const {
for (const auto& id : textureIDs) {
const nod::Node* node;
const PAK::Entry* texEntry = pakRouter.lookupEntry(id, &node);
if (!texEntry)
continue;
hecl::ProjectPath txtrPath = pakRouter.getWorking(texEntry);
if (txtrPath.isNone()) {
txtrPath.makeDirChain(false);
PAKEntryReadStream rs = texEntry->beginReadStream(*node);
TXTR::Extract(rs, txtrPath);
}
}
}
} head;
struct Material : BigDNA {
AT_DECL_DNA
struct Flags : BigDNA {
AT_DECL_DNA
Value<atUint32> flags = 0;
bool konstValuesEnabled() const { return (flags & 0x8) != 0; }
void setKonstValuesEnabled(bool enabled) {
flags &= ~0x8;
flags |= atUint32(enabled) << 3;
}
bool depthSorting() const { return (flags & 0x10) != 0; }
void setDepthSorting(bool enabled) {
flags &= ~0x10;
flags |= atUint32(enabled) << 4;
}
bool alphaTest() const { return (flags & 0x20) != 0; }
void setAlphaTest(bool enabled) {
flags &= ~0x20;
flags |= atUint32(enabled) << 5;
}
bool samusReflection() const { return (flags & 0x40) != 0; }
void setSamusReflection(bool enabled) {
flags &= ~0x40;
flags |= atUint32(enabled) << 6;
}
bool depthWrite() const { return (flags & 0x80) != 0; }
void setDepthWrite(bool enabled) {
flags &= ~0x80;
flags |= atUint32(enabled) << 7;
}
bool samusReflectionSurfaceEye() const { return (flags & 0x100) != 0; }
void setSamusReflectionSurfaceEye(bool enabled) {
flags &= ~0x100;
flags |= atUint32(enabled) << 8;
}
bool shadowOccluderMesh() const { return (flags & 0x200) != 0; }
void setShadowOccluderMesh(bool enabled) {
flags &= ~0x200;
flags |= atUint32(enabled) << 9;
}
bool samusReflectionIndirectTexture() const { return (flags & 0x400) != 0; }
void setSamusReflectionIndirectTexture(bool enabled) {
flags &= ~0x400;
flags |= atUint32(enabled) << 10;
}
bool lightmap() const { return (flags & 0x800) != 0; }
void setLightmap(bool enabled) {
flags &= ~0x800;
flags |= atUint32(enabled) << 11;
}
bool lightmapUVArray() const { return (flags & 0x2000) != 0; }
void setLightmapUVArray(bool enabled) {
flags &= ~0x2000;
flags |= atUint32(enabled) << 13;
}
atUint16 textureSlots() const { return (flags >> 16) != 0; }
void setTextureSlots(atUint16 texslots) {
flags &= ~0xffff0000;
flags |= atUint32(texslots) << 16;
}
} flags;
const Flags& getFlags() const { return flags; }
Value<atUint32> textureCount = 0;
Vector<atUint32, AT_DNA_COUNT(textureCount)> textureIdxs;
struct VAFlags : BigDNA {
AT_DECL_DNA
Value<atUint32> vaFlags = 0;
GX::AttrType position() const { return GX::AttrType(vaFlags & 0x3); }
void setPosition(GX::AttrType val) {
vaFlags &= ~0x3;
vaFlags |= atUint32(val);
}
GX::AttrType normal() const { return GX::AttrType(vaFlags >> 2 & 0x3); }
void setNormal(GX::AttrType val) {
vaFlags &= ~0xC;
vaFlags |= atUint32(val) << 2;
}
GX::AttrType color0() const { return GX::AttrType(vaFlags >> 4 & 0x3); }
void setColor0(GX::AttrType val) {
vaFlags &= ~0x30;
vaFlags |= atUint32(val) << 4;
}
GX::AttrType color1() const { return GX::AttrType(vaFlags >> 6 & 0x3); }
void setColor1(GX::AttrType val) {
vaFlags &= ~0xC0;
vaFlags |= atUint32(val) << 6;
}
GX::AttrType tex0() const { return GX::AttrType(vaFlags >> 8 & 0x3); }
void setTex0(GX::AttrType val) {
vaFlags &= ~0x300;
vaFlags |= atUint32(val) << 8;
}
GX::AttrType tex1() const { return GX::AttrType(vaFlags >> 10 & 0x3); }
void setTex1(GX::AttrType val) {
vaFlags &= ~0xC00;
vaFlags |= atUint32(val) << 10;
}
GX::AttrType tex2() const { return GX::AttrType(vaFlags >> 12 & 0x3); }
void setTex2(GX::AttrType val) {
vaFlags &= ~0x3000;
vaFlags |= atUint32(val) << 12;
}
GX::AttrType tex3() const { return GX::AttrType(vaFlags >> 14 & 0x3); }
void setTex3(GX::AttrType val) {
vaFlags &= ~0xC000;
vaFlags |= atUint32(val) << 14;
}
GX::AttrType tex4() const { return GX::AttrType(vaFlags >> 16 & 0x3); }
void setTex4(GX::AttrType val) {
vaFlags &= ~0x30000;
vaFlags |= atUint32(val) << 16;
}
GX::AttrType tex5() const { return GX::AttrType(vaFlags >> 18 & 0x3); }
void setTex5(GX::AttrType val) {
vaFlags &= ~0xC0000;
vaFlags |= atUint32(val) << 18;
}
GX::AttrType tex6() const { return GX::AttrType(vaFlags >> 20 & 0x3); }
void setTex6(GX::AttrType val) {
vaFlags &= ~0x300000;
vaFlags |= atUint32(val) << 20;
}
GX::AttrType pnMatIdx() const { return GX::AttrType(vaFlags >> 24 & 0x1); }
void setPnMatIdx(GX::AttrType val) {
vaFlags &= ~0x1000000;
vaFlags |= atUint32(val & 0x1) << 24;
}
GX::AttrType tex0MatIdx() const { return GX::AttrType(vaFlags >> 25 & 0x1); }
void setTex0MatIdx(GX::AttrType val) {
vaFlags &= ~0x2000000;
vaFlags |= atUint32(val & 0x1) << 25;
}
GX::AttrType tex1MatIdx() const { return GX::AttrType(vaFlags >> 26 & 0x1); }
void setTex1MatIdx(GX::AttrType val) {
vaFlags &= ~0x4000000;
vaFlags |= atUint32(val & 0x1) << 26;
}
GX::AttrType tex2MatIdx() const { return GX::AttrType(vaFlags >> 27 & 0x1); }
void setTex2MatIdx(GX::AttrType val) {
vaFlags &= ~0x8000000;
vaFlags |= atUint32(val & 0x1) << 27;
}
GX::AttrType tex3MatIdx() const { return GX::AttrType(vaFlags >> 28 & 0x1); }
void setTex3MatIdx(GX::AttrType val) {
vaFlags &= ~0x10000000;
vaFlags |= atUint32(val & 0x1) << 28;
}
GX::AttrType tex4MatIdx() const { return GX::AttrType(vaFlags >> 29 & 0x1); }
void setTex4MatIdx(GX::AttrType val) {
vaFlags &= ~0x20000000;
vaFlags |= atUint32(val & 0x1) << 29;
}
GX::AttrType tex5MatIdx() const { return GX::AttrType(vaFlags >> 30 & 0x1); }
void setTex5MatIdx(GX::AttrType val) {
vaFlags &= ~0x40000000;
vaFlags |= atUint32(val & 0x1) << 30;
}
GX::AttrType tex6MatIdx() const { return GX::AttrType(vaFlags >> 31 & 0x1); }
void setTex6MatIdx(GX::AttrType val) {
vaFlags &= ~0x80000000;
vaFlags |= atUint32(val & 0x1) << 31;
}
size_t vertDLSize() const {
static size_t ATTR_SZ[] = {0, 1, 1, 2};
size_t ret = 0;
ret += ATTR_SZ[position()];
ret += ATTR_SZ[normal()];
ret += ATTR_SZ[color0()];
ret += ATTR_SZ[color1()];
ret += ATTR_SZ[tex0()];
ret += ATTR_SZ[tex1()];
ret += ATTR_SZ[tex2()];
ret += ATTR_SZ[tex3()];
ret += ATTR_SZ[tex4()];
ret += ATTR_SZ[tex5()];
ret += ATTR_SZ[tex6()];
ret += ATTR_SZ[pnMatIdx()];
ret += ATTR_SZ[tex0MatIdx()];
ret += ATTR_SZ[tex1MatIdx()];
ret += ATTR_SZ[tex2MatIdx()];
ret += ATTR_SZ[tex3MatIdx()];
ret += ATTR_SZ[tex4MatIdx()];
ret += ATTR_SZ[tex5MatIdx()];
ret += ATTR_SZ[tex6MatIdx()];
return ret;
}
} vaFlags;
const VAFlags& getVAFlags() const { return vaFlags; }
Value<atUint32> uniqueIdx;
Vector<atUint32, AT_DNA_COUNT(flags.konstValuesEnabled())> konstCount;
Vector<GX::Color, AT_DNA_COUNT(flags.konstValuesEnabled() ? konstCount[0] : 0)> konstColors;
using BlendFactor = GX::BlendFactor;
Value<BlendFactor> blendDstFac;
Value<BlendFactor> blendSrcFac;
Vector<atUint32, AT_DNA_COUNT(flags.samusReflectionIndirectTexture())> indTexSlot;
Value<atUint32> colorChannelCount = 0;
struct ColorChannel : BigDNA {
AT_DECL_DNA
Value<atUint32> flags = 0;
bool lighting() const { return (flags & 0x1) != 0; }
void setLighting(bool enabled) {
flags &= ~0x1;
flags |= atUint32(enabled);
}
bool useAmbient() const { return (flags & 0x2) != 0; }
void setUseAmbient(bool enabled) {
flags &= ~0x2;
flags |= atUint32(enabled) << 1;
}
bool useMaterial() const { return (flags & 0x4) != 0; }
void setUseMaterial(bool enabled) {
flags &= ~0x4;
flags |= atUint32(enabled) << 2;
}
atUint8 lightmask() const { return atUint8(flags >> 3 & 0xff); }
void setLightmask(atUint8 mask) {
flags &= ~0x7f8;
flags |= atUint32(mask) << 3;
}
GX::DiffuseFn diffuseFn() const { return GX::DiffuseFn(flags >> 11 & 0x3); }
void setDiffuseFn(GX::DiffuseFn fn) {
flags &= ~0x1800;
flags |= atUint32(fn) << 11;
}
GX::AttnFn attenuationFn() const { return GX::AttnFn(flags >> 13 & 0x3); }
void setAttenuationFn(GX::AttnFn fn) {
flags &= ~0x6000;
flags |= atUint32(fn) << 13;
}
};
Vector<ColorChannel, AT_DNA_COUNT(colorChannelCount)> colorChannels;
Value<atUint32> tevStageCount = 0;
struct TEVStage : BigDNA {
AT_DECL_DNA
Value<atUint32> ciFlags = 0;
Value<atUint32> aiFlags = 0;
Value<atUint32> ccFlags = 0;
Value<atUint32> acFlags = 0;
Value<atUint8> pad = 0;
Value<atUint8> kaInput = 0;
Value<atUint8> kcInput = 0;
Value<atUint8> rascInput = 0;
GX::TevColorArg colorInA() const { return GX::TevColorArg(ciFlags & 0xf); }
void setColorInA(GX::TevColorArg val) {
ciFlags &= ~0x1f;
ciFlags |= atUint32(val);
}
GX::TevColorArg colorInB() const { return GX::TevColorArg(ciFlags >> 5 & 0xf); }
void setColorInB(GX::TevColorArg val) {
ciFlags &= ~0x3e0;
ciFlags |= atUint32(val) << 5;
}
GX::TevColorArg colorInC() const { return GX::TevColorArg(ciFlags >> 10 & 0xf); }
void setColorInC(GX::TevColorArg val) {
ciFlags &= ~0x7c00;
ciFlags |= atUint32(val) << 10;
}
GX::TevColorArg colorInD() const { return GX::TevColorArg(ciFlags >> 15 & 0xf); }
void setColorInD(GX::TevColorArg val) {
ciFlags &= ~0xf8000;
ciFlags |= atUint32(val) << 15;
}
GX::TevAlphaArg alphaInA() const { return GX::TevAlphaArg(aiFlags & 0x7); }
void setAlphaInA(GX::TevAlphaArg val) {
aiFlags &= ~0x1f;
aiFlags |= atUint32(val);
}
GX::TevAlphaArg alphaInB() const { return GX::TevAlphaArg(aiFlags >> 5 & 0x7); }
void setAlphaInB(GX::TevAlphaArg val) {
aiFlags &= ~0x3e0;
aiFlags |= atUint32(val) << 5;
}
GX::TevAlphaArg alphaInC() const { return GX::TevAlphaArg(aiFlags >> 10 & 0x7); }
void setAlphaInC(GX::TevAlphaArg val) {
aiFlags &= ~0x7c00;
aiFlags |= atUint32(val) << 10;
}
GX::TevAlphaArg alphaInD() const { return GX::TevAlphaArg(aiFlags >> 15 & 0x7); }
void setAlphaInD(GX::TevAlphaArg val) {
aiFlags &= ~0xf8000;
aiFlags |= atUint32(val) << 15;
}
GX::TevOp colorOp() const { return GX::TevOp(ccFlags & 0xf); }
void setColorOp(GX::TevOp val) {
ccFlags &= ~0x1;
ccFlags |= atUint32(val);
}
GX::TevBias colorOpBias() const { return GX::TevBias(ccFlags >> 4 & 0x3); }
void setColorOpBias(GX::TevBias val) {
ccFlags &= ~0x30;
ccFlags |= atUint32(val) << 4;
}
GX::TevScale colorOpScale() const { return GX::TevScale(ccFlags >> 6 & 0x3); }
void setColorOpScale(GX::TevScale val) {
ccFlags &= ~0xc0;
ccFlags |= atUint32(val) << 6;
}
bool colorOpClamp() const { return ccFlags >> 8 & 0x1; }
void setColorOpClamp(bool val) {
ccFlags &= ~0x100;
ccFlags |= atUint32(val) << 8;
}
GX::TevRegID colorOpOutReg() const { return GX::TevRegID(ccFlags >> 9 & 0x3); }
void setColorOpOutReg(GX::TevRegID val) {
ccFlags &= ~0x600;
ccFlags |= atUint32(val) << 9;
}
GX::TevOp alphaOp() const { return GX::TevOp(acFlags & 0xf); }
void setAlphaOp(GX::TevOp val) {
acFlags &= ~0x1;
acFlags |= atUint32(val);
}
GX::TevBias alphaOpBias() const { return GX::TevBias(acFlags >> 4 & 0x3); }
void setAlphaOpBias(GX::TevBias val) {
acFlags &= ~0x30;
acFlags |= atUint32(val) << 4;
}
GX::TevScale alphaOpScale() const { return GX::TevScale(acFlags >> 6 & 0x3); }
void setAlphaOpScale(GX::TevScale val) {
acFlags &= ~0xc0;
acFlags |= atUint32(val) << 6;
}
bool alphaOpClamp() const { return acFlags >> 8 & 0x1; }
void setAlphaOpClamp(bool val) {
acFlags &= ~0x100;
acFlags |= atUint32(val) << 8;
}
GX::TevRegID alphaOpOutReg() const { return GX::TevRegID(acFlags >> 9 & 0x3); }
void setAlphaOpOutReg(GX::TevRegID val) {
acFlags &= ~0x600;
acFlags |= atUint32(val) << 9;
}
GX::TevKColorSel kColorIn() const { return GX::TevKColorSel(kcInput); }
void setKColorIn(GX::TevKColorSel val) { kcInput = val; }
GX::TevKAlphaSel kAlphaIn() const { return GX::TevKAlphaSel(kaInput); }
void setKAlphaIn(GX::TevKAlphaSel val) { kaInput = val; }
GX::ChannelID rasIn() const { return GX::ChannelID(rascInput); }
void setRASIn(GX::ChannelID id) { rascInput = id; }
};
Vector<TEVStage, AT_DNA_COUNT(tevStageCount)> tevStages;
struct TEVStageTexInfo : BigDNA {
AT_DECL_DNA
Value<atUint16> pad = 0;
Value<atUint8> texSlot = 0xff;
Value<atUint8> tcgSlot = 0xff;
};
Vector<TEVStageTexInfo, AT_DNA_COUNT(tevStageCount)> tevStageTexInfo;
Value<atUint32> tcgCount = 0;
struct TexCoordGen : BigDNA {
AT_DECL_DNA
Value<atUint32> flags = 0;
GX::TexGenType type() const { return GX::TexGenType(flags & 0xf); }
void setType(GX::TexGenType val) {
flags &= ~0xf;
flags |= atUint32(val);
}
GX::TexGenSrc source() const { return GX::TexGenSrc(flags >> 4 & 0x1f); }
void setSource(GX::TexGenSrc val) {
flags &= ~0x1f0;
flags |= atUint32(val) << 4;
}
GX::TexMtx mtx() const { return GX::TexMtx((flags >> 9 & 0x1f) + 30); }
void setMtx(GX::TexMtx val) {
flags &= ~0x3e00;
flags |= (atUint32(val) - 30) << 9;
}
bool normalize() const { return flags >> 14 & 0x1; }
void setNormalize(bool val) {
flags &= ~0x4000;
flags |= atUint32(val) << 14;
}
GX::PTTexMtx postMtx() const { return GX::PTTexMtx((flags >> 15 & 0x3f) + 64); }
void setPostMtx(GX::PTTexMtx val) {
flags &= ~0x1f8000;
flags |= (atUint32(val) - 64) << 15;
}
};
Vector<TexCoordGen, AT_DNA_COUNT(tcgCount)> tcgs;
Value<atUint32> uvAnimsSize = 4;
Value<atUint32> uvAnimsCount = 0;
struct UVAnimation : BigDNA {
AT_DECL_EXPLICIT_DNA
enum class Mode {
MvInvNoTranslation,
MvInv,
Scroll,
Rotation,
HStrip,
VStrip,
Model,
CylinderEnvironment,
Eight
} mode;
float vals[9];
UVAnimation() = default;
UVAnimation(const std::string& gameFunction, const std::vector<atVec4f>& gameArgs);
};
Vector<UVAnimation, AT_DNA_COUNT(uvAnimsCount)> uvAnims;
static void AddTexture(hecl::blender::PyOutStream& out, GX::TexGenSrc type, int mtxIdx, uint32_t texIdx,
bool diffuse);
static void AddTextureAnim(hecl::blender::PyOutStream& out, MaterialSet::Material::UVAnimation::Mode type,
unsigned idx, const float* vals);
static void AddKcolor(hecl::blender::PyOutStream& out, const GX::Color& col, unsigned idx);
static void AddDynamicColor(hecl::blender::PyOutStream& out, unsigned idx);
static void AddDynamicAlpha(hecl::blender::PyOutStream& out, unsigned idx);
Material() = default;
Material(const hecl::blender::Material& material, std::vector<hecl::ProjectPath>& texPathsOut, int colorCount,
bool lightmapUVs, bool matrixSkinning);
};
Vector<Material, AT_DNA_COUNT(head.materialCount)> materials;
static void RegisterMaterialProps(hecl::blender::PyOutStream& out);
static void ConstructMaterial(hecl::blender::PyOutStream& out, const MaterialSet::Material& material,
unsigned groupIdx, unsigned matIdx);
void readToBlender(hecl::blender::PyOutStream& os, const PAKRouter<PAKBridge>& pakRouter,
const PAKRouter<PAKBridge>::EntryType& entry, unsigned setIdx) {
DNACMDL::ReadMaterialSetToBlender_1_2(os, *this, pakRouter, entry, setIdx);
}
template <class PAKRouter>
void nameTextures(PAKRouter& pakRouter, const char* prefix, int setIdx) const {
int matIdx = 0;
for (const Material& mat : materials) {
int stageIdx = 0;
for (const Material::TEVStage& stage : mat.tevStages) {
(void)stage;
const Material::TEVStageTexInfo& texInfo = mat.tevStageTexInfo[stageIdx];
if (texInfo.texSlot == 0xff) {
++stageIdx;
continue;
}
const nod::Node* node;
typename PAKRouter::EntryType* texEntry = (typename PAKRouter::EntryType*)pakRouter.lookupEntry(
head.textureIDs[mat.textureIdxs[texInfo.texSlot]], &node);
if (texEntry->name.size()) {
if (texEntry->name.size() < 5 || texEntry->name.compare(0, 5, "mult_"))
texEntry->name = "mult_" + texEntry->name;
++stageIdx;
continue;
}
if (setIdx < 0)
texEntry->name = fmt::format(FMT_STRING("{}_{}_{}"), prefix, matIdx, stageIdx);
else
texEntry->name = fmt::format(FMT_STRING("{}_{}_{}_{}"), prefix, setIdx, matIdx, stageIdx);
if (mat.flags.lightmap() && stageIdx == 0) {
texEntry->name += "light";
++stageIdx;
continue;
}
++stageIdx;
}
++matIdx;
}
}
void ensureTexturesExtracted(PAKRouter<PAKBridge>& pakRouter) const { head.ensureTexturesExtracted(pakRouter); }
};
struct HMDLMaterialSet : BigDNA {
static constexpr bool OneSection() { return false; }
AT_DECL_DNA
Value<atUint32> materialCount = 0;
Vector<atUint32, AT_DNA_COUNT(materialCount)> materialEndOffs;
struct Material : BigDNA {
AT_DECL_DNA
MaterialSet::Material::Flags flags;
using BlendMaterial = hecl::blender::Material;
struct PASS : hecl::TypedRecordBigDNA<BlendMaterial::ChunkType::TexturePass> {
AT_DECL_EXPLICIT_DNA
Value<BlendMaterial::PassType> type;
UniqueID32 texId;
Value<BlendMaterial::TexCoordSource> source;
Value<BlendMaterial::UVAnimType> uvAnimType;
Value<float> uvAnimParms[9] = {};
Value<bool> alpha;
PASS() = default;
explicit PASS(const BlendMaterial::PASS& pass)
: type(pass.type), texId(pass.tex), source(pass.source), uvAnimType(pass.uvAnimType), alpha(pass.alpha) {
std::copy(pass.uvAnimParms.begin(), pass.uvAnimParms.end(), std::begin(uvAnimParms));
}
bool shouldNormalizeUv() const {
switch (uvAnimType) {
case BlendMaterial::UVAnimType::MvInvNoTranslation:
case BlendMaterial::UVAnimType::MvInv:
case BlendMaterial::UVAnimType::Model:
case BlendMaterial::UVAnimType::CylinderEnvironment:
return true;
default:
return false;
}
}
size_t uvAnimParamsCount() const {
switch (uvAnimType) {
default:
return 0;
case BlendMaterial::UVAnimType::Scroll:
case BlendMaterial::UVAnimType::HStrip:
case BlendMaterial::UVAnimType::VStrip:
return 4;
case BlendMaterial::UVAnimType::Rotation:
case BlendMaterial::UVAnimType::CylinderEnvironment:
return 2;
case BlendMaterial::UVAnimType::Eight:
return 9;
}
}
};
struct CLR : hecl::TypedRecordBigDNA<BlendMaterial::ChunkType::ColorPass> {
AT_DECL_DNA
Value<BlendMaterial::PassType> type;
Value<atVec4f> color;
CLR() = default;
explicit CLR(const BlendMaterial::CLR& clr) : type(clr.type), color(clr.color.val) {}
};
using Chunk = hecl::TypedVariantBigDNA<PASS, CLR>;
static unsigned TexMapIdx(BlendMaterial::PassType type) {
switch (type) {
case BlendMaterial::PassType::Lightmap:
return 0;
case BlendMaterial::PassType::Diffuse:
return 1;
case BlendMaterial::PassType::Emissive:
return 2;
case BlendMaterial::PassType::Specular:
return 3;
case BlendMaterial::PassType::ExtendedSpecular:
return 4;
case BlendMaterial::PassType::Reflection:
return 5;
case BlendMaterial::PassType::Alpha:
return 6;
case BlendMaterial::PassType::IndirectTex:
return 7;
default:
assert(false && "Unknown pass type");
return 0;
}
}
Value<atUint64> hash;
Value<BlendMaterial::ShaderType> shaderType;
Value<atUint32> chunkCount;
Vector<Chunk, AT_DNA_COUNT(chunkCount)> chunks;
Value<BlendMaterial::BlendMode> blendMode = BlendMaterial::BlendMode::Opaque;
std::pair<hecl::Backend::BlendFactor, hecl::Backend::BlendFactor> blendFactors() const {
switch (blendMode) {
case BlendMaterial::BlendMode::Opaque:
default:
return {hecl::Backend::BlendFactor::One, hecl::Backend::BlendFactor::Zero};
case BlendMaterial::BlendMode::Alpha:
return {hecl::Backend::BlendFactor::SrcAlpha, hecl::Backend::BlendFactor::InvSrcAlpha};
case BlendMaterial::BlendMode::Additive:
return {hecl::Backend::BlendFactor::SrcAlpha, hecl::Backend::BlendFactor::One};
}
}
Material() = default;
Material(const hecl::blender::Material& mat);
};
Vector<Material, AT_DNA_COUNT(materialCount)> materials;
};
} // namespace DataSpec::DNAMP1
AT_SPECIALIZE_TYPED_VARIANT_BIGDNA(DataSpec::DNAMP1::HMDLMaterialSet::Material::PASS,
DataSpec::DNAMP1::HMDLMaterialSet::Material::CLR)

View File

@ -1,69 +0,0 @@
include(DNAMP1/ScriptObjects/CMakeLists.txt)
include(DNAMP1/SFX/CMakeLists.txt)
make_dnalist(PAK
MLVL
AGSC
CSNG
AFSM
ANCS
ANIM
CINF
CSKR
EVNT
CMDLMaterials
MREA
DeafBabe
SCAN
FRME
SAVW
HINT
MazeSeeds
SnowForces
DCLN
Tweaks/CTweakGame
Tweaks/CTweakParticle
Tweaks/CTweakPlayer
Tweaks/CTweakPlayerControl
Tweaks/CTweakPlayerGun
Tweaks/CTweakGunRes
Tweaks/CTweakPlayerRes
Tweaks/CTweakGui
Tweaks/CTweakSlideShow
Tweaks/CTweakCameraBob
Tweaks/CTweakTargeting
Tweaks/CTweakAutoMapper
Tweaks/CTweakBall
Tweaks/CTweakGuiColors)
set(DNAMP1_SOURCES
DNAMP1.hpp DNAMP1.cpp
AFSM.cpp
PAK.cpp
MLVL.cpp
STRG.hpp STRG.cpp
AGSC.cpp
CSNG.cpp
CSKR.cpp
ANCS.cpp
ANIM.cpp
CINF.cpp
EVNT.cpp
PATH.hpp
CMDL.hpp CMDL.cpp
CMDLMaterials.cpp
DCLN.cpp
MAPA.hpp
MAPU.hpp
MREA.cpp
SCLY.hpp SCLY.cpp
FRME.cpp
SCAN.cpp
DeafBabe.cpp
Tweaks/CTweakAutoMapper.cpp
Tweaks/CTweakPlayer.cpp
Tweaks/CTweakTargeting.cpp
Tweaks/CTweakBall.cpp
Tweaks/CTweakGame.cpp)
dataspec_add_list(DNAMP1 DNAMP1_SOURCES)

View File

@ -1,16 +0,0 @@
#include "CSKR.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec::DNAMP1 {
void CSKR::weightVertex(hecl::blender::PyOutStream& os, const CINF& cinf, atUint32 idx) const {
atUint32 accum = 0;
for (const SkinningRule& rule : skinningRules) {
if (idx >= accum && idx < accum + rule.vertCount)
for (const SkinningRule::Weight& weight : rule.weights)
os.format(FMT_STRING("vert[dvert_lay][{}] = {}\n"), cinf.getBoneIdxFromId(weight.boneId), weight.weight);
accum += rule.vertCount;
}
}
} // namespace DataSpec::DNAMP1

Some files were not shown because too many files have changed in this diff Show More