Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1520205403 | |||
| d2d7459d05 | |||
| c71272af05 |
@@ -2,7 +2,7 @@
|
|||||||
Language: Cpp
|
Language: Cpp
|
||||||
Standard: C++03
|
Standard: C++03
|
||||||
AccessModifierOffset: -4
|
AccessModifierOffset: -4
|
||||||
AlignAfterOpenBracket: DontAlign
|
AlignAfterOpenBracket: Align
|
||||||
AlignConsecutiveAssignments: false
|
AlignConsecutiveAssignments: false
|
||||||
AlignConsecutiveDeclarations: false
|
AlignConsecutiveDeclarations: false
|
||||||
AlignOperands: true
|
AlignOperands: true
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SCCACHE_GHA_ENABLED: "true"
|
# SCCACHE_GHA_ENABLED: "true"
|
||||||
RUSTC_WRAPPER: "sccache"
|
RUSTC_WRAPPER: "sccache"
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: GCC x86_64
|
- name: GCC x86_64
|
||||||
runner: ubuntu-latest
|
runner: [self-hosted, Linux]
|
||||||
preset: gcc
|
preset: gcc
|
||||||
artifact_arch: x86_64
|
artifact_arch: x86_64
|
||||||
# - name: GCC aarch64
|
# - name: GCC aarch64
|
||||||
@@ -41,6 +41,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
if: 'false' # disabled for self-hosted
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y install ninja-build clang lld openssl libcurl4-openssl-dev \
|
sudo apt-get -y install ninja-build clang lld openssl libcurl4-openssl-dev \
|
||||||
@@ -50,7 +51,8 @@ jobs:
|
|||||||
libxss-dev libfuse2 libusb-1.0-0-dev libdecor-0-dev libpipewire-0.3-dev libunwind-dev
|
libxss-dev libfuse2 libusb-1.0-0-dev libdecor-0-dev libpipewire-0.3-dev libunwind-dev
|
||||||
|
|
||||||
- name: Setup sccache
|
- name: Setup sccache
|
||||||
uses: mozilla-actions/sccache-action@v0.0.10
|
if: 'false' # disabled for self-hosted
|
||||||
|
uses: mozilla-actions/sccache-action@v0.0.9
|
||||||
|
|
||||||
- name: Print sccache stats
|
- name: Print sccache stats
|
||||||
run: sccache --show-stats
|
run: sccache --show-stats
|
||||||
@@ -65,16 +67,17 @@ jobs:
|
|||||||
run: ci/build-appimage.sh
|
run: ci/build-appimage.sh
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
|
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: dusklight-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}}
|
name: dusk-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}}
|
||||||
path: |
|
path: |
|
||||||
build/install/Dusklight-*.AppImage
|
build/install/Dusk-*.AppImage
|
||||||
build/install/debug.tar.*
|
build/install/debug.tar.*
|
||||||
|
|
||||||
build-apple:
|
build-apple:
|
||||||
name: Build Apple (${{matrix.name}})
|
name: Build Apple (${{matrix.name}})
|
||||||
runs-on: macos-latest
|
runs-on: [self-hosted, macOS]
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -83,14 +86,14 @@ jobs:
|
|||||||
platform: macos
|
platform: macos
|
||||||
preset: x-macos-ci-arm64
|
preset: x-macos-ci-arm64
|
||||||
artifact_name: macos-appleclang-arm64
|
artifact_name: macos-appleclang-arm64
|
||||||
- name: AppleClang macOS x86_64
|
# - name: AppleClang macOS x86_64
|
||||||
platform: macos
|
# platform: macos
|
||||||
preset: x-macos-ci-x86_64
|
# preset: x-macos-ci-x86_64
|
||||||
artifact_name: macos-appleclang-x86_64
|
# artifact_name: macos-appleclang-x86_64
|
||||||
- name: AppleClang iOS arm64
|
# - name: AppleClang iOS arm64
|
||||||
platform: ios
|
# platform: ios
|
||||||
preset: x-ios-ci
|
# preset: x-ios-ci
|
||||||
artifact_name: ios-appleclang-arm64
|
# artifact_name: ios-appleclang-arm64
|
||||||
# - name: AppleClang tvOS arm64
|
# - name: AppleClang tvOS arm64
|
||||||
# platform: tvos
|
# platform: tvos
|
||||||
# preset: x-tvos-ci
|
# preset: x-tvos-ci
|
||||||
@@ -103,6 +106,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
if: 'false'
|
||||||
run: brew install cmake ninja
|
run: brew install cmake ninja
|
||||||
|
|
||||||
- name: Install Rust iOS target
|
- name: Install Rust iOS target
|
||||||
@@ -124,7 +128,7 @@ jobs:
|
|||||||
rustup target add x86_64-apple-darwin
|
rustup target add x86_64-apple-darwin
|
||||||
|
|
||||||
- name: Setup sccache
|
- name: Setup sccache
|
||||||
uses: mozilla-actions/sccache-action@v0.0.10
|
uses: mozilla-actions/sccache-action@v0.0.9
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
run: cmake --preset ${{matrix.preset}}
|
run: cmake --preset ${{matrix.preset}}
|
||||||
@@ -133,80 +137,14 @@ jobs:
|
|||||||
run: cmake --build --preset ${{matrix.preset}}
|
run: cmake --build --preset ${{matrix.preset}}
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
|
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: dusklight-${{env.DUSK_VERSION}}-${{matrix.artifact_name}}
|
name: dusk-${{env.DUSK_VERSION}}-${{matrix.artifact_name}}
|
||||||
path: |
|
path: |
|
||||||
build/install/Dusklight.app
|
build/install/Dusk.app
|
||||||
build/install/debug.tar.*
|
build/install/debug.tar.*
|
||||||
|
|
||||||
build-android:
|
|
||||||
name: Build Android (${{matrix.name}})
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: Clang arm64-v8a
|
|
||||||
preset: x-android-ci-arm64
|
|
||||||
abi: arm64-v8a
|
|
||||||
artifact_arch: arm64
|
|
||||||
rust_target: aarch64-linux-android
|
|
||||||
|
|
||||||
env:
|
|
||||||
ANDROID_NDK_VERSION: "29.0.14206865"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y install ninja-build
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Android SDK
|
|
||||||
uses: android-actions/setup-android@v4
|
|
||||||
|
|
||||||
- name: Install Android SDK packages
|
|
||||||
run: sdkmanager "platforms;android-36" "build-tools;36.1.0" "ndk;${ANDROID_NDK_VERSION}"
|
|
||||||
|
|
||||||
- name: Install Rust Android target
|
|
||||||
run: |
|
|
||||||
rustup toolchain install stable
|
|
||||||
rustup target add ${{matrix.rust_target}}
|
|
||||||
|
|
||||||
- name: Setup sccache
|
|
||||||
uses: mozilla-actions/sccache-action@v0.0.10
|
|
||||||
|
|
||||||
- name: Configure CMake
|
|
||||||
run: cmake --preset ${{matrix.preset}}
|
|
||||||
|
|
||||||
- name: Build native library
|
|
||||||
run: cmake --build --preset ${{matrix.preset}} --target dusklight
|
|
||||||
|
|
||||||
- name: Stage stripped JNI library
|
|
||||||
run: ANDROID_STAGE_ABIS="${{matrix.abi}}" platforms/android/scripts/stage-jni-libs.sh
|
|
||||||
|
|
||||||
- name: Build APK
|
|
||||||
working-directory: platforms/android
|
|
||||||
run: ./gradlew :app:assembleRelease --rerun-tasks
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: dusklight-${{env.DUSK_VERSION}}-android-${{matrix.artifact_arch}}
|
|
||||||
path: platforms/android/app/build/outputs/apk/release/app-${{matrix.abi}}-release-unsigned.apk
|
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
name: Build Windows (${{matrix.name}})
|
name: Build Windows (${{matrix.name}})
|
||||||
runs-on: ${{matrix.runner}}
|
runs-on: ${{matrix.runner}}
|
||||||
@@ -216,7 +154,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: MSVC x86_64
|
- name: MSVC x86_64
|
||||||
runner: windows-latest
|
runner: [self-hosted, Windows]
|
||||||
preset: msvc
|
preset: msvc
|
||||||
msvc_arch: amd64
|
msvc_arch: amd64
|
||||||
vcpkg_arch: x64
|
vcpkg_arch: x64
|
||||||
@@ -253,6 +191,7 @@ jobs:
|
|||||||
uses: mozilla-actions/sccache-action@v0.0.9
|
uses: mozilla-actions/sccache-action@v0.0.9
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
if: 'false' # disabled for self-hosted
|
||||||
run: |
|
run: |
|
||||||
choco install ninja
|
choco install ninja
|
||||||
vcpkg install freetype:${{matrix.vcpkg_arch}}-windows-static zstd:${{matrix.vcpkg_arch}}-windows-static
|
vcpkg install freetype:${{matrix.vcpkg_arch}}-windows-static zstd:${{matrix.vcpkg_arch}}-windows-static
|
||||||
@@ -264,9 +203,10 @@ jobs:
|
|||||||
run: cmake --build --preset x-windows-ci-${{matrix.preset}}
|
run: cmake --build --preset x-windows-ci-${{matrix.preset}}
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
|
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: dusklight-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}}
|
name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}}
|
||||||
path: |
|
path: |
|
||||||
build/install/*.exe
|
build/install/*.exe
|
||||||
build/install/*.dll
|
build/install/*.dll
|
||||||
|
|||||||
@@ -41,10 +41,6 @@ compile_commands.json
|
|||||||
# MacOS
|
# MacOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# direnv / nix
|
|
||||||
.direnv/
|
|
||||||
.envrc
|
|
||||||
|
|
||||||
# ISOs
|
# ISOs
|
||||||
*.iso
|
*.iso
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "(gdb) Launch Dusklight MSVC",
|
"name": "(gdb) Launch Dusk MSVC",
|
||||||
"type": "cppvsdbg",
|
"type": "cppvsdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"cmake.buildDirectory": "${workspaceFolder}/build/dusklight/${buildType}/${variant:tp_version}",
|
"cmake.buildDirectory": "${workspaceFolder}/build/dusk/${buildType}/${variant:tp_version}",
|
||||||
"cmake.generator": "Ninja",
|
"cmake.generator": "Ninja",
|
||||||
"cmake.configureSettings": {
|
"cmake.configureSettings": {
|
||||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||||
|
|||||||
@@ -48,15 +48,13 @@ else ()
|
|||||||
message(STATUS "Unable to find git, commit information will not be available")
|
message(STATUS "Unable to find git, commit information will not be available")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (DUSK_WC_DESCRIBE MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)([-+].*)?$")
|
if (DUSK_WC_DESCRIBE MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)(-([0-9]+).*)?$")
|
||||||
set(DUSK_SHORT_VERSION_STRING "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
|
set(DUSK_SHORT_VERSION_STRING "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
|
||||||
set(DUSK_VERSION_TWEAK "0")
|
if (CMAKE_MATCH_5)
|
||||||
if (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-([0-9]+)(-dirty)?$")
|
set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.${CMAKE_MATCH_5}")
|
||||||
set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}")
|
else ()
|
||||||
elseif (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-[0-9A-Za-z.-]+-([0-9]+)(-dirty)?$")
|
set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.0")
|
||||||
set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}")
|
|
||||||
endif ()
|
endif ()
|
||||||
set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.${DUSK_VERSION_TWEAK}")
|
|
||||||
else ()
|
else ()
|
||||||
set(DUSK_WC_DESCRIBE "UNKNOWN-VERSION")
|
set(DUSK_WC_DESCRIBE "UNKNOWN-VERSION")
|
||||||
set(DUSK_VERSION_STRING "0.0.0.0")
|
set(DUSK_VERSION_STRING "0.0.0.0")
|
||||||
@@ -67,11 +65,11 @@ endif ()
|
|||||||
if(DEFINED ENV{GITHUB_ENV})
|
if(DEFINED ENV{GITHUB_ENV})
|
||||||
file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION=${DUSK_WC_DESCRIBE}\n")
|
file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION=${DUSK_WC_DESCRIBE}\n")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "Dusklight version set to ${DUSK_WC_DESCRIBE}")
|
message(STATUS "Dusk version set to ${DUSK_WC_DESCRIBE}")
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
project(dusklight LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
|
project(dusk LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
enable_language(OBJC OBJCXX)
|
enable_language(OBJC)
|
||||||
endif ()
|
endif ()
|
||||||
if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS)
|
if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS)
|
||||||
# ios.toolchain.cmake hack for SDL
|
# ios.toolchain.cmake hack for SDL
|
||||||
@@ -102,41 +100,32 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
|||||||
endif ()
|
endif ()
|
||||||
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
|
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
|
||||||
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
|
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
|
||||||
set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
|
|
||||||
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||||
target_compile_definitions(aurora_mtx PRIVATE MTX_USE_PS=1)
|
|
||||||
|
|
||||||
add_subdirectory(libs/freeverb)
|
add_subdirectory(libs/freeverb)
|
||||||
|
|
||||||
option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)")
|
option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)")
|
||||||
option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.")
|
option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.")
|
||||||
option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON)
|
option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON)
|
||||||
option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON)
|
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
set(DUSK_MOVIE_SUPPORT OFF)
|
set(DUSK_MOVIE_SUPPORT OFF)
|
||||||
|
set(NOD_COMPRESS_BZIP2 OFF CACHE BOOL "" FORCE)
|
||||||
|
set(NOD_COMPRESS_LZMA OFF CACHE BOOL "" FORCE)
|
||||||
|
set(NOD_COMPRESS_ZLIB OFF CACHE BOOL "" FORCE)
|
||||||
|
set(NOD_COMPRESS_ZSTD OFF CACHE BOOL "" FORCE)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF)
|
option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF)
|
||||||
set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN")
|
set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN")
|
||||||
set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment")
|
set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment")
|
||||||
|
|
||||||
# Edit & Continue
|
|
||||||
if (MSVC)
|
|
||||||
if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}" STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue")
|
|
||||||
endif ()
|
|
||||||
if (CMAKE_MSVC_DEBUG_INFORMATION_FORMAT STREQUAL "EditAndContinue")
|
|
||||||
add_link_options("/INCREMENTAL")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (DUSK_MOVIE_SUPPORT)
|
if (DUSK_MOVIE_SUPPORT)
|
||||||
find_package(libjpeg-turbo 3.0 CONFIG QUIET)
|
find_package(libjpeg-turbo 3.0 CONFIG QUIET)
|
||||||
if (libjpeg-turbo_FOUND)
|
if (libjpeg-turbo_FOUND)
|
||||||
message(STATUS "dusklight: Using system libjpeg-turbo")
|
message(STATUS "dusk: Using system libjpeg-turbo")
|
||||||
else ()
|
else ()
|
||||||
message(STATUS "dusklight: Fetching libjpeg-turbo")
|
message(STATUS "dusk: Fetching libjpeg-turbo")
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
set(_jpeg_install_dir ${CMAKE_BINARY_DIR}/libjpeg-turbo-install)
|
set(_jpeg_install_dir ${CMAKE_BINARY_DIR}/libjpeg-turbo-install)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
@@ -160,7 +149,6 @@ if (DUSK_MOVIE_SUPPORT)
|
|||||||
CMAKE_C_COMPILER_LAUNCHER
|
CMAKE_C_COMPILER_LAUNCHER
|
||||||
CMAKE_MAKE_PROGRAM
|
CMAKE_MAKE_PROGRAM
|
||||||
CMAKE_MSVC_RUNTIME_LIBRARY
|
CMAKE_MSVC_RUNTIME_LIBRARY
|
||||||
CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
|
|
||||||
CMAKE_OSX_ARCHITECTURES
|
CMAKE_OSX_ARCHITECTURES
|
||||||
DEPLOYMENT_TARGET
|
DEPLOYMENT_TARGET
|
||||||
ENABLE_ARC
|
ENABLE_ARC
|
||||||
@@ -226,13 +214,13 @@ endif ()
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
# Declare all dependencies first so CMake can download them in parallel
|
# Declare all dependencies first so CMake can download them in parallel
|
||||||
message(STATUS "dusklight: Fetching cxxopts")
|
message(STATUS "dusk: Fetching cxxopts")
|
||||||
FetchContent_Declare(cxxopts
|
FetchContent_Declare(cxxopts
|
||||||
URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz
|
URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz
|
||||||
URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072
|
URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||||
)
|
)
|
||||||
message(STATUS "dusklight: Fetching nlohmann/json")
|
message(STATUS "dusk: Fetching nlohmann/json")
|
||||||
FetchContent_Declare(json
|
FetchContent_Declare(json
|
||||||
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
|
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
|
||||||
URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa
|
URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa
|
||||||
@@ -241,7 +229,7 @@ FetchContent_Declare(json
|
|||||||
FetchContent_MakeAvailable(cxxopts json)
|
FetchContent_MakeAvailable(cxxopts json)
|
||||||
|
|
||||||
if (DUSK_ENABLE_SENTRY_NATIVE)
|
if (DUSK_ENABLE_SENTRY_NATIVE)
|
||||||
message(STATUS "dusklight: Fetching sentry-native")
|
message(STATUS "dusk: Fetching sentry-native")
|
||||||
set(SENTRY_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
set(SENTRY_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
set(SENTRY_BACKEND crashpad CACHE STRING "" FORCE)
|
set(SENTRY_BACKEND crashpad CACHE STRING "" FORCE)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
@@ -286,17 +274,17 @@ include(files.cmake)
|
|||||||
|
|
||||||
# TODO: version handling for res includes
|
# TODO: version handling for res includes
|
||||||
|
|
||||||
set(DUSK_BUNDLE_NAME Dusklight)
|
set(DUSK_BUNDLE_NAME Dusk)
|
||||||
set(DUSK_BUNDLE_IDENTIFIER dev.twilitrealm.dusk)
|
set(DUSK_BUNDLE_IDENTIFIER dev.twilitrealm.dusk)
|
||||||
set(DUSK_COMPANY_NAME "Twilit Realm")
|
set(DUSK_COMPANY_NAME "Twilit Realm")
|
||||||
set(DUSK_FILE_DESCRIPTION "Dusklight")
|
set(DUSK_FILE_DESCRIPTION "Dusk")
|
||||||
set(DUSK_PRODUCT_NAME "Dusklight")
|
set(DUSK_PRODUCT_NAME "Dusk")
|
||||||
set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
|
set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
|
||||||
|
|
||||||
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
|
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
|
||||||
source_group("dusklight" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES})
|
source_group("dusk" FILES ${DUSK_FILES})
|
||||||
|
|
||||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
|
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0)
|
||||||
|
|
||||||
set(GAME_INCLUDE_DIRS
|
set(GAME_INCLUDE_DIRS
|
||||||
include
|
include
|
||||||
@@ -308,10 +296,8 @@ set(GAME_INCLUDE_DIRS
|
|||||||
extern
|
extern
|
||||||
${CMAKE_BINARY_DIR})
|
${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd
|
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd
|
||||||
aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt
|
aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt)
|
||||||
Threads::Threads)
|
|
||||||
|
|
||||||
list(APPEND GAME_LIBS libzstd_static)
|
list(APPEND GAME_LIBS libzstd_static)
|
||||||
|
|
||||||
@@ -324,41 +310,6 @@ if (WIN32)
|
|||||||
list(APPEND GAME_LIBS Ws2_32)
|
list(APPEND GAME_LIBS Ws2_32)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/no_backend.cpp)
|
|
||||||
if (DUSK_ENABLE_UPDATE_CHECKER)
|
|
||||||
list(APPEND GAME_COMPILE_DEFS DUSK_ENABLE_UPDATE_CHECKER=1)
|
|
||||||
if (WIN32)
|
|
||||||
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/winhttp.cpp)
|
|
||||||
list(APPEND GAME_LIBS winhttp)
|
|
||||||
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_WINHTTP=1)
|
|
||||||
message(STATUS "dusklight: Enabled update checker (WinHTTP)")
|
|
||||||
elseif (ANDROID)
|
|
||||||
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/android.cpp)
|
|
||||||
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_ANDROID=1)
|
|
||||||
message(STATUS "dusklight: Enabled update checker (Android)")
|
|
||||||
elseif (APPLE)
|
|
||||||
find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED)
|
|
||||||
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/url_session.mm)
|
|
||||||
set_source_files_properties(src/dusk/http/url_session.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
|
||||||
list(APPEND GAME_LIBS ${FOUNDATION_FRAMEWORK})
|
|
||||||
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_URLSESSION=1)
|
|
||||||
message(STATUS "dusklight: Enabled update checker (NSURLSession)")
|
|
||||||
elseif (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
|
||||||
find_package(CURL QUIET OPTIONAL_COMPONENTS HTTPS SSL)
|
|
||||||
if (CURL_FOUND AND CURL_HTTPS_FOUND AND CURL_SSL_FOUND)
|
|
||||||
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/curl.cpp)
|
|
||||||
list(APPEND GAME_LIBS CURL::libcurl)
|
|
||||||
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_LIBCURL=1)
|
|
||||||
message(STATUS "dusklight: Enabled update checker (libcurl)")
|
|
||||||
else ()
|
|
||||||
message(STATUS "dusklight: Disabled update checker (libcurl + HTTPS/SSL not found)")
|
|
||||||
endif ()
|
|
||||||
else ()
|
|
||||||
message(STATUS "dusklight: Disabled update checker (unsupported platform)")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
list(APPEND DUSK_FILES ${DUSK_HTTP_BACKEND_SOURCE})
|
|
||||||
|
|
||||||
if (DUSK_MOVIE_SUPPORT)
|
if (DUSK_MOVIE_SUPPORT)
|
||||||
if (TARGET libjpeg-turbo::turbojpeg-static)
|
if (TARGET libjpeg-turbo::turbojpeg-static)
|
||||||
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static)
|
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static)
|
||||||
@@ -368,13 +319,56 @@ if (DUSK_MOVIE_SUPPORT)
|
|||||||
list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1)
|
list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(DUSK_ENABLE_DISCORD_DEFAULT ON)
|
option(DUSK_ENABLE_DISCORD_RPC "Enable Discord Rich Presence support" ON)
|
||||||
if (DEFINED DUSK_ENABLE_DISCORD_RPC AND NOT DEFINED DUSK_ENABLE_DISCORD)
|
if (DUSK_ENABLE_DISCORD_RPC AND NOT ANDROID AND NOT IOS AND NOT TVOS)
|
||||||
set(DUSK_ENABLE_DISCORD_DEFAULT ${DUSK_ENABLE_DISCORD_RPC})
|
|
||||||
|
FetchContent_Populate(discord_rpc
|
||||||
|
URL https://github.com/discord/discord-rpc/archive/refs/tags/v3.4.0.tar.gz
|
||||||
|
URL_HASH SHA256=e13427019027acd187352dacba6c65953af66fdf3c35fcf38fc40b454a9d7855
|
||||||
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||||
|
)
|
||||||
|
# RapidJSON is a git submodule absent from the discord-rpc tarball; fetch separately.
|
||||||
|
FetchContent_Populate(rapidjson
|
||||||
|
URL https://github.com/Tencent/rapidjson/archive/refs/tags/v1.1.0.tar.gz
|
||||||
|
URL_HASH SHA256=bf7ced29704a1e696fbccf2a2b4ea068e7774fa37f6d7dd4039d0787f8bed98e
|
||||||
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT TARGET discord-rpc)
|
||||||
|
set(_drpc ${discord_rpc_SOURCE_DIR}/src)
|
||||||
|
set(_drpc_src
|
||||||
|
${_drpc}/discord_rpc.cpp
|
||||||
|
${_drpc}/rpc_connection.cpp
|
||||||
|
${_drpc}/serialization.cpp
|
||||||
|
)
|
||||||
|
if (WIN32)
|
||||||
|
list(APPEND _drpc_src ${_drpc}/connection_win.cpp ${_drpc}/discord_register_win.cpp)
|
||||||
|
elseif (APPLE)
|
||||||
|
list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_osx.m)
|
||||||
|
else ()
|
||||||
|
list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_linux.cpp)
|
||||||
|
endif ()
|
||||||
|
add_library(discord-rpc STATIC ${_drpc_src})
|
||||||
|
target_include_directories(discord-rpc PUBLIC
|
||||||
|
${discord_rpc_SOURCE_DIR}/include
|
||||||
|
${rapidjson_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
if (UNIX)
|
||||||
|
target_link_libraries(discord-rpc PUBLIC pthread)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
list(APPEND GAME_LIBS discord-rpc)
|
||||||
|
list(APPEND GAME_COMPILE_DEFS DUSK_DISCORD_RPC=1)
|
||||||
endif ()
|
endif ()
|
||||||
option(DUSK_ENABLE_DISCORD "Enable Discord Rich Presence support" ${DUSK_ENABLE_DISCORD_DEFAULT})
|
|
||||||
if (DUSK_ENABLE_DISCORD AND NOT ANDROID AND NOT IOS AND NOT TVOS)
|
# Edit & Continue
|
||||||
list(APPEND GAME_COMPILE_DEFS DUSK_DISCORD=1)
|
if (MSVC)
|
||||||
|
if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}" STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue")
|
||||||
|
endif ()
|
||||||
|
if (CMAKE_MSVC_DEBUG_INFORMATION_FORMAT STREQUAL "EditAndContinue")
|
||||||
|
add_link_options("/INCREMENTAL")
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
@@ -432,37 +426,31 @@ endif ()
|
|||||||
|
|
||||||
set(DUSK_FILES src/dusk/main.cpp ${GAME_BASE_FILES} ${GAME_DEBUG_FILES})
|
set(DUSK_FILES src/dusk/main.cpp ${GAME_BASE_FILES} ${GAME_DEBUG_FILES})
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
add_library(dusklight SHARED ${DUSK_FILES})
|
add_library(dusk SHARED ${DUSK_FILES})
|
||||||
set_target_properties(dusklight PROPERTIES OUTPUT_NAME main)
|
set_target_properties(dusk PROPERTIES OUTPUT_NAME main)
|
||||||
else ()
|
else ()
|
||||||
add_executable(dusklight ${DUSK_FILES})
|
add_executable(dusk ${DUSK_FILES})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_compile_definitions(dusklight PRIVATE ${GAME_COMPILE_DEFS})
|
target_compile_definitions(dusk PRIVATE ${GAME_COMPILE_DEFS})
|
||||||
target_include_directories(dusklight PRIVATE ${GAME_INCLUDE_DIRS})
|
target_include_directories(dusk PRIVATE ${GAME_INCLUDE_DIRS})
|
||||||
target_link_libraries(dusklight PRIVATE aurora::main ${GAME_LIBS} ${JSYSTEM_LINK_LIBRARIES})
|
target_link_libraries(dusk PRIVATE aurora::main ${GAME_LIBS} ${JSYSTEM_LINK_LIBRARIES})
|
||||||
target_precompile_headers(dusklight PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>")
|
target_precompile_headers(dusk PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>")
|
||||||
if (TARGET crashpad_handler)
|
if (TARGET crashpad_handler)
|
||||||
add_dependencies(dusklight crashpad_handler)
|
add_dependencies(dusk crashpad_handler)
|
||||||
add_custom_command(TARGET dusklight POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
"$<TARGET_FILE:crashpad_handler>"
|
|
||||||
"$<TARGET_FILE_DIR:dusklight>"
|
|
||||||
COMMENT "Copying crashpad handler"
|
|
||||||
)
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
# SDLActivity loads SDL_main via dlsym on Android. Since aurora::main is a static
|
# SDLActivity loads SDL_main via dlsym on Android. Since aurora::main is a static
|
||||||
# archive, force an undefined reference so the linker keeps the SDL_main object.
|
# archive, force an undefined reference so the linker keeps the SDL_main object.
|
||||||
target_link_options(dusklight PRIVATE "-Wl,-u,SDL_main")
|
target_link_options(dusk PRIVATE "-Wl,-u,SDL_main")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (NOT APPLE)
|
if (NOT APPLE)
|
||||||
add_custom_command(TARGET dusklight POST_BUILD
|
add_custom_command(TARGET dusk POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
"${CMAKE_SOURCE_DIR}/res"
|
"${CMAKE_SOURCE_DIR}/res"
|
||||||
"$<TARGET_FILE_DIR:dusklight>/res"
|
"$<TARGET_FILE_DIR:dusk>/res"
|
||||||
COMMENT "Copying resources"
|
COMMENT "Copying resources"
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
@@ -470,9 +458,9 @@ endif ()
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(DUSK_WINDOWS_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/windows)
|
set(DUSK_WINDOWS_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/windows)
|
||||||
set(DUSK_WINDOWS_ICON_PNG ${CMAKE_CURRENT_SOURCE_DIR}/res/icon.png)
|
set(DUSK_WINDOWS_ICON_PNG ${CMAKE_CURRENT_SOURCE_DIR}/res/icon.png)
|
||||||
set(DUSK_WINDOWS_ICON_ICO ${CMAKE_CURRENT_BINARY_DIR}/dusklight.ico)
|
set(DUSK_WINDOWS_ICON_ICO ${CMAKE_CURRENT_BINARY_DIR}/dusk.ico)
|
||||||
set(DUSK_WINDOWS_RC ${CMAKE_CURRENT_BINARY_DIR}/dusklight.rc)
|
set(DUSK_WINDOWS_RC ${CMAKE_CURRENT_BINARY_DIR}/dusk.rc)
|
||||||
set(DUSK_WINDOWS_MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/dusklight.manifest)
|
set(DUSK_WINDOWS_MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/dusk.manifest)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${DUSK_WINDOWS_ICON_ICO}
|
OUTPUT ${DUSK_WINDOWS_ICON_ICO}
|
||||||
@@ -485,14 +473,14 @@ if (WIN32)
|
|||||||
COMMENT "Generating Windows icon"
|
COMMENT "Generating Windows icon"
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusklight.manifest.in ${DUSK_WINDOWS_MANIFEST} @ONLY)
|
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusk.manifest.in ${DUSK_WINDOWS_MANIFEST} @ONLY)
|
||||||
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusklight.rc.in ${DUSK_WINDOWS_RC} @ONLY)
|
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusk.rc.in ${DUSK_WINDOWS_RC} @ONLY)
|
||||||
|
|
||||||
target_sources(dusklight PRIVATE ${DUSK_WINDOWS_ICON_ICO} ${DUSK_WINDOWS_RC})
|
target_sources(dusk PRIVATE ${DUSK_WINDOWS_ICON_ICO} ${DUSK_WINDOWS_RC})
|
||||||
set_target_properties(dusklight PROPERTIES WIN32_EXECUTABLE TRUE)
|
set_target_properties(dusk PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_link_options(dusklight PRIVATE /MANIFEST:NO)
|
target_link_options(dusk PRIVATE /MANIFEST:NO)
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
@@ -508,10 +496,10 @@ if (APPLE)
|
|||||||
file(GLOB_RECURSE DUSK_RESOURCE_FILES
|
file(GLOB_RECURSE DUSK_RESOURCE_FILES
|
||||||
"${DUSK_RESOURCE_DIR}/Assets.car"
|
"${DUSK_RESOURCE_DIR}/Assets.car"
|
||||||
"${DUSK_RESOURCE_DIR}/Base.lproj/*"
|
"${DUSK_RESOURCE_DIR}/Base.lproj/*"
|
||||||
"${DUSK_RESOURCE_DIR}/Dusklight.icns")
|
"${DUSK_RESOURCE_DIR}/Dusk.icns")
|
||||||
file(GLOB_RECURSE DUSK_APP_RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/res/*")
|
file(GLOB_RECURSE DUSK_APP_RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/res/*")
|
||||||
target_sources(dusklight PRIVATE ${DUSK_RESOURCE_FILES})
|
target_sources(dusk PRIVATE ${DUSK_RESOURCE_FILES})
|
||||||
target_sources(dusklight PRIVATE ${DUSK_APP_RESOURCE_FILES})
|
target_sources(dusk PRIVATE ${DUSK_APP_RESOURCE_FILES})
|
||||||
foreach (FILE ${DUSK_RESOURCE_FILES})
|
foreach (FILE ${DUSK_RESOURCE_FILES})
|
||||||
file(RELATIVE_PATH NEW_FILE "${DUSK_RESOURCE_DIR}" ${FILE})
|
file(RELATIVE_PATH NEW_FILE "${DUSK_RESOURCE_DIR}" ${FILE})
|
||||||
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
|
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
|
||||||
@@ -523,36 +511,29 @@ if (APPLE)
|
|||||||
set_property(SOURCE ${FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}")
|
set_property(SOURCE ${FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}")
|
||||||
endforeach ()
|
endforeach ()
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
dusklight PROPERTIES
|
dusk PROPERTIES
|
||||||
MACOSX_BUNDLE TRUE
|
MACOSX_BUNDLE TRUE
|
||||||
MACOSX_BUNDLE_BUNDLE_NAME ${DUSK_BUNDLE_NAME}
|
MACOSX_BUNDLE_BUNDLE_NAME ${DUSK_BUNDLE_NAME}
|
||||||
MACOSX_BUNDLE_GUI_IDENTIFIER ${DUSK_BUNDLE_IDENTIFIER}
|
MACOSX_BUNDLE_GUI_IDENTIFIER ${DUSK_BUNDLE_IDENTIFIER}
|
||||||
MACOSX_BUNDLE_BUNDLE_VERSION ${DUSK_VERSION_STRING}
|
MACOSX_BUNDLE_BUNDLE_VERSION ${DUSK_VERSION_STRING}
|
||||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${DUSK_SHORT_VERSION_STRING}
|
MACOSX_BUNDLE_SHORT_VERSION_STRING ${DUSK_SHORT_VERSION_STRING}
|
||||||
MACOSX_BUNDLE_INFO_PLIST ${DUSK_INFO_PLIST}
|
MACOSX_BUNDLE_INFO_PLIST ${DUSK_INFO_PLIST}
|
||||||
OUTPUT_NAME Dusklight
|
OUTPUT_NAME Dusk
|
||||||
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "YES"
|
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "YES"
|
||||||
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES"
|
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES"
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (APPLE AND NOT IOS AND NOT TVOS)
|
|
||||||
find_library(APPKIT_FRAMEWORK AppKit REQUIRED)
|
|
||||||
target_sources(dusklight PRIVATE src/dusk/file_select_macos.mm)
|
|
||||||
set_source_files_properties(src/dusk/file_select_macos.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
|
||||||
target_link_libraries(dusklight PRIVATE ${APPKIT_FRAMEWORK})
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (IOS)
|
if (IOS)
|
||||||
find_library(UIKIT_FRAMEWORK UIKit REQUIRED)
|
find_library(UIKIT_FRAMEWORK UIKit REQUIRED)
|
||||||
find_library(UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK UniformTypeIdentifiers REQUIRED)
|
find_library(UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK UniformTypeIdentifiers REQUIRED)
|
||||||
target_sources(dusklight PRIVATE src/dusk/ios/FileSelectDialog.m)
|
target_sources(dusk PRIVATE src/dusk/ios/FileSelectDialog.m)
|
||||||
set_source_files_properties(src/dusk/ios/FileSelectDialog.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
set_source_files_properties(src/dusk/ios/FileSelectDialog.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||||
target_link_libraries(dusklight PRIVATE ${UIKIT_FRAMEWORK} ${UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK})
|
target_link_libraries(dusk PRIVATE ${UIKIT_FRAMEWORK} ${UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake)
|
include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake)
|
||||||
aurora_copy_runtime_dlls(dusklight)
|
aurora_copy_runtime_dlls(dusk)
|
||||||
|
|
||||||
if (DUSK_SELECTED_OPT)
|
if (DUSK_SELECTED_OPT)
|
||||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
@@ -590,13 +571,13 @@ function(get_target_prefix target result_var)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
endfunction()
|
endfunction()
|
||||||
list(APPEND BINARY_TARGETS dusklight)
|
list(APPEND BINARY_TARGETS dusk)
|
||||||
set(EXTRA_TARGETS "")
|
set(EXTRA_TARGETS "")
|
||||||
if (TARGET crashpad_handler)
|
if (TARGET crashpad_handler)
|
||||||
list(APPEND EXTRA_TARGETS crashpad_handler)
|
list(APPEND EXTRA_TARGETS crashpad_handler)
|
||||||
endif ()
|
endif ()
|
||||||
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX})
|
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||||
aurora_install_runtime_dlls(dusklight ${CMAKE_INSTALL_PREFIX})
|
aurora_install_runtime_dlls(dusk ${CMAKE_INSTALL_PREFIX})
|
||||||
if (NOT APPLE)
|
if (NOT APPLE)
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX})
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||||
endif ()
|
endif ()
|
||||||
|
|||||||
@@ -352,31 +352,6 @@
|
|||||||
"ANDROID_ABI": "x86_64"
|
"ANDROID_ABI": "x86_64"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "x-android-ci",
|
|
||||||
"hidden": true,
|
|
||||||
"inherits": [
|
|
||||||
"android-base",
|
|
||||||
"ci"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"DUSK_ENABLE_SENTRY_NATIVE": {
|
|
||||||
"type": "BOOL",
|
|
||||||
"value": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "x-android-ci-arm64",
|
|
||||||
"binaryDir": "${sourceDir}/build/android-arm64",
|
|
||||||
"inherits": [
|
|
||||||
"x-android-ci"
|
|
||||||
],
|
|
||||||
"cacheVariables": {
|
|
||||||
"ANDROID_ABI": "arm64-v8a",
|
|
||||||
"Rust_CARGO_TARGET": "aarch64-linux-android"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "x-linux-ci",
|
"name": "x-linux-ci",
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
@@ -437,7 +412,6 @@
|
|||||||
"x-macos-ci"
|
"x-macos-ci"
|
||||||
],
|
],
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"AURORA_DAWN_PROVIDER": "vendor",
|
|
||||||
"CMAKE_OSX_ARCHITECTURES": "x86_64",
|
"CMAKE_OSX_ARCHITECTURES": "x86_64",
|
||||||
"Rust_CARGO_TARGET": "x86_64-apple-darwin"
|
"Rust_CARGO_TARGET": "x86_64-apple-darwin"
|
||||||
}
|
}
|
||||||
@@ -551,7 +525,7 @@
|
|||||||
"description": "iOS release build with debug info",
|
"description": "iOS release build with debug info",
|
||||||
"displayName": "iOS RelWithDebInfo",
|
"displayName": "iOS RelWithDebInfo",
|
||||||
"targets": [
|
"targets": [
|
||||||
"dusklight"
|
"dusk"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -560,7 +534,7 @@
|
|||||||
"description": "tvOS release build with debug info",
|
"description": "tvOS release build with debug info",
|
||||||
"displayName": "tvOS RelWithDebInfo",
|
"displayName": "tvOS RelWithDebInfo",
|
||||||
"targets": [
|
"targets": [
|
||||||
"dusklight"
|
"dusk"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -569,7 +543,7 @@
|
|||||||
"description": "Android arm64-v8a release build with debug info",
|
"description": "Android arm64-v8a release build with debug info",
|
||||||
"displayName": "Android arm64-v8a RelWithDebInfo",
|
"displayName": "Android arm64-v8a RelWithDebInfo",
|
||||||
"targets": [
|
"targets": [
|
||||||
"dusklight"
|
"dusk"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -578,16 +552,7 @@
|
|||||||
"description": "Android x86_64 release build with debug info",
|
"description": "Android x86_64 release build with debug info",
|
||||||
"displayName": "Android x86_64 RelWithDebInfo",
|
"displayName": "Android x86_64 RelWithDebInfo",
|
||||||
"targets": [
|
"targets": [
|
||||||
"dusklight"
|
"dusk"
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "x-android-ci-arm64",
|
|
||||||
"configurePreset": "x-android-ci-arm64",
|
|
||||||
"description": "(Internal) Android CI arm64-v8a",
|
|
||||||
"displayName": "(Internal) Android CI arm64-v8a",
|
|
||||||
"targets": [
|
|
||||||
"dusklight"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,69 +1,31 @@
|
|||||||
<div align="center">
|

|
||||||
<img src="res/logo.png" alt="Logo" width="640">
|
|
||||||
|
|
||||||
<p align="center">
|
- ### **[Official Website](https://twilitrealm.dev)**
|
||||||
<a href="https://twilitrealm.dev">Official Website</a>
|
- ### **[Discord](https://discord.gg/QACynxeyna)**
|
||||||
•
|
|
||||||
<a href="https://discord.gg/6NpMhefCK9">Discord</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# Overview
|
|
||||||
|
|
||||||
Dusklight is a reverse-engineered reimplementation of Twilight Princess.
|
|
||||||
|
|
||||||
It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience.
|
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
|
**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.**
|
||||||
|
|
||||||
> [!IMPORTANT]
|
### 1. Verify your ROM dump
|
||||||
> Dusklight does *not* provide any copyrighted assets. You must provide your own copy of the original game.
|
First make sure your dump of the game is clean and supported by Dusk. You can do this by checking the sha1 hash of your dump against this list of supported versions.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
| Version | sha1 hash |
|
||||||
> At a minimum, Dusklight requires a GPU with support for either D3D12, Vulkan, or Metal. Your experience with specific hardware, operating systems, and drivers may vary. In particular, older Intel iGPUs have a high likelihood of incompatibility. We are also aware of a number of issues on devices with Adreno GPUs and are working to resolve them.
|
|--------------| ---------------------------------------- |
|
||||||
|
| GameCube USA | 75edd3ddff41f125d1b4ce1a40378f1b565519e7 |
|
||||||
|
| GameCube PAL | 2601822a488eeb86fb89db16ca8f29c2c953e1ca |
|
||||||
|
|
||||||
### 1. Verify your dump
|
### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases)
|
||||||
|
|
||||||
First, make sure your dump of the game is clean and supported by Dusklight. You can do this by checking the SHA-1 hash of your dump against this list of supported versions:
|
|
||||||
|
|
||||||
| Version | SHA-1 hash |
|
|
||||||
|--------------| ------------------------------------------ |
|
|
||||||
| GameCube USA | `75edd3ddff41f125d1b4ce1a40378f1b565519e7` |
|
|
||||||
| GameCube EUR | `2601822a488eeb86fb89db16ca8f29c2c953e1ca` |
|
|
||||||
|
|
||||||
*Support for other versions of the game is planned in the future.
|
|
||||||
|
|
||||||
### 2. Download [Dusklight](https://github.com/TwilitRealm/dusklight/releases)
|
|
||||||
|
|
||||||
### 3. Setup the game
|
### 3. Setup the game
|
||||||
**Windows / macOS / Linux**
|
- Extract the zip folder
|
||||||
- Extract the .zip file
|
- Launch Dusk
|
||||||
- Launch Dusklight
|
- Select Options, then set the ISO Path to your supported game dump
|
||||||
- Press **Select Disc Image** and provide the path to your supported game dump
|
- Press Start Game to play!
|
||||||
- Press **Play**!
|
|
||||||
|
|
||||||
**iOS**
|

|
||||||
- Follow the [iOS setup guide](docs/ios-install-altstore.md)
|
|
||||||
|
|
||||||
**Android**
|
|
||||||
- Install the Dusklight APK
|
|
||||||
- Launch Dusklight
|
|
||||||
- Press **Select Disc Image** and provide the path to your supported game dump
|
|
||||||
- Press **Play**!
|
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md).
|
||||||
If you'd like to build Dusklight from source, please read the [build instructions](docs/building.md).
|
|
||||||
|
|
||||||
Pull requests are welcomed! Note that we do not accept contributions that are primarily AI-generated and will close your PR if we suspect as much. Please also see the [code conventions](docs/code-conventions.md).
|
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
|
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors).
|
||||||
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusklight/graphs/contributors).
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<div align="center">
|
|
||||||
<a href="https://github.com/encounter/aurora">
|
|
||||||
<img src="assets/aurora-powered.png" alt="Powered by Aurora" width="800">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 85 KiB |
@@ -1,66 +0,0 @@
|
|||||||
<svg width="600" height="600" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx="150" cy="150" r="105" fill="none" stroke="white" stroke-width="4"/>
|
|
||||||
<circle cx="150" cy="150" r="95" fill="none" stroke="white" stroke-width="4"/>
|
|
||||||
<circle cx="150" cy="150" r="60" fill="none" stroke="white" stroke-width="4"/>
|
|
||||||
<circle cx="150" cy="150" r="75" fill="none" stroke="white" stroke-width="4"/>
|
|
||||||
|
|
||||||
<defs>
|
|
||||||
<line id="ray" x1="150" y1="55" x2="150" y2="45"/>
|
|
||||||
<clipPath id="zigzag-clip">
|
|
||||||
<circle cx="150" cy="150" r="75"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<g stroke="white" stroke-width="3">
|
|
||||||
<use href="#ray"/>
|
|
||||||
<use href="#ray" transform="rotate(18 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(36 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(54 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(72 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(90 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(108 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(126 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(144 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(162 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(180 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(198 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(216 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(234 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(252 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(270 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(288 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(306 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(324 150 150)"/>
|
|
||||||
<use href="#ray" transform="rotate(342 150 150)"/>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<polygon fill="none" stroke="white" stroke-width="4" opacity="1" clip-path="url(#zigzag-clip)"
|
|
||||||
points="
|
|
||||||
126.82,78.67
|
|
||||||
150,90
|
|
||||||
173.18,78.67
|
|
||||||
185.27,101.46
|
|
||||||
210.68,105.92
|
|
||||||
207.06,131.46
|
|
||||||
225,150
|
|
||||||
207.06,168.54
|
|
||||||
210.68,194.08
|
|
||||||
185.27,198.54
|
|
||||||
173.18,221.33
|
|
||||||
150,210
|
|
||||||
126.82,221.33
|
|
||||||
114.73,198.54
|
|
||||||
89.32,194.08
|
|
||||||
92.94,168.54
|
|
||||||
75,150
|
|
||||||
92.94,131.46
|
|
||||||
89.32,105.92
|
|
||||||
114.73,101.46
|
|
||||||
"/>
|
|
||||||
|
|
||||||
<g fill="none" stroke="white" stroke-width="4">
|
|
||||||
<polygon points="150,105 130,140 170,140"/>
|
|
||||||
<polygon points="130,140 110,175 150,175"/>
|
|
||||||
<polygon points="170,140 150,175 190,175"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,26 +1,18 @@
|
|||||||
#!/bin/bash -ex
|
#!/bin/bash -ex
|
||||||
|
shopt -s extglob
|
||||||
if [[ -n "${GITHUB_WORKSPACE:-}" ]]; then
|
|
||||||
cd "$GITHUB_WORKSPACE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
build_dir="$PWD/build"
|
|
||||||
linuxdeploy="$build_dir/linuxdeploy-$(uname -m).AppImage"
|
|
||||||
|
|
||||||
# Get linuxdeploy
|
# Get linuxdeploy
|
||||||
mkdir -p "$build_dir"
|
cd "$RUNNER_WORKSPACE"
|
||||||
curl -fL "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$(uname -m).AppImage" -o "$linuxdeploy"
|
curl -fOL https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$(uname -m).AppImage
|
||||||
chmod +x "$linuxdeploy"
|
chmod +x linuxdeploy-$(uname -m).AppImage
|
||||||
|
|
||||||
# Build AppImage
|
# Build AppImage
|
||||||
|
cd "$GITHUB_WORKSPACE"
|
||||||
mkdir -p build/appdir/usr/{bin,share/{applications,icons/hicolor}}
|
mkdir -p build/appdir/usr/{bin,share/{applications,icons/hicolor}}
|
||||||
for install_path in build/install/*; do
|
cp -r build/install/!(*.*) build/appdir/usr/bin
|
||||||
[[ "$(basename "$install_path")" == *.* ]] && continue
|
|
||||||
cp -r "$install_path" build/appdir/usr/bin
|
|
||||||
done
|
|
||||||
cp -r platforms/freedesktop/{16x16,32x32,48x48,64x64,128x128,256x256,512x512,1024x1024} build/appdir/usr/share/icons/hicolor
|
cp -r platforms/freedesktop/{16x16,32x32,48x48,64x64,128x128,256x256,512x512,1024x1024} build/appdir/usr/share/icons/hicolor
|
||||||
cp platforms/freedesktop/dusklight.desktop build/appdir/usr/share/applications
|
cp platforms/freedesktop/dusk.desktop build/appdir/usr/share/applications
|
||||||
|
|
||||||
cd build/install
|
cd build/install
|
||||||
VERSION="$DUSK_VERSION" NO_STRIP=1 "$linuxdeploy" \
|
VERSION="$DUSK_VERSION" NO_STRIP=1 "$RUNNER_WORKSPACE"/linuxdeploy-$(uname -m).AppImage \
|
||||||
-l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$build_dir/appdir" --output appimage
|
-l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$GITHUB_WORKSPACE"/build/appdir --output appimage
|
||||||
|
|||||||
@@ -36,10 +36,10 @@
|
|||||||
sudo dnf groupinstall "Development Tools" "Development Libraries"
|
sudo dnf groupinstall "Development Tools" "Development Libraries"
|
||||||
```
|
```
|
||||||
#### Setup
|
#### Setup
|
||||||
Clone and initialize the Dusklight repository
|
Clone and initialize the Dusk repository
|
||||||
```sh
|
```sh
|
||||||
git clone --recursive https://github.com/TwilitRealm/dusklight.git
|
git clone --recursive https://github.com/TwilitRealm/dusk.git
|
||||||
cd dusklight
|
cd dusk
|
||||||
git pull
|
git pull
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
@@ -93,6 +93,6 @@ Alternate presets available:
|
|||||||
#### Running
|
#### Running
|
||||||
Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
|
Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
|
||||||
```sh
|
```sh
|
||||||
build/{preset}/dusklight/path/to/game.rvz
|
build/{preset}/dusk /path/to/game.rvz
|
||||||
```
|
```
|
||||||
If no path is specified, Dusklight defaults to `game.iso` in the current working directory.
|
If no path is specified, Dusk defaults to `game.iso` in the current working directory.
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# Code conventions for Dusk
|
|
||||||
|
|
||||||
## Upstream when appropriate
|
|
||||||
|
|
||||||
Bug fixes, documentation improvements, code cleanup, etc that also apply to the [original decompilation project](https://github.com/zeldaret/tp) should preferably be PR'd there.
|
|
||||||
|
|
||||||
## Properly indicate Dusk-modified code
|
|
||||||
|
|
||||||
When modifying original game code (i.e. in decomp) for Dusk's purposes, please clearly delineate such code as being Dusk-specific. Generally, this can be done by using `#if TARGET_PC` and keeping the original code in place. Use `#if AVOID_UB` for Undefined Behavior fixes to the original codebase.
|
|
||||||
|
|
||||||
## Miscellaneous things
|
|
||||||
|
|
||||||
* The original codebase makes heavy use of global `operator new` and similar overloads to allocate into a strict tree of heaps. This would cause many linkage headaches for us, so effectively all uses of `new` or `delete` in the original game code have been replaced with `JKR_NEW`, `JKR_DELETE`, or similar macros. See `JKRHeap.h` for the full list.
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# Installing Dusklight on iOS via AltStore
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Mac with Homebrew installed
|
|
||||||
- iPhone connected via USB
|
|
||||||
- Dusklight IPA file (download the latest `Dusklight-vX.X.X-ios-arm64.ipa` from the [releases page](https://github.com/TwilitRealm/dusk/releases))
|
|
||||||
- Game disc - `GZ2E01` (Gamecube USA) or `GZ2PE01` (Gamecube PAL)
|
|
||||||
|
|
||||||
## 1. Install AltServer
|
|
||||||
|
|
||||||
```sh
|
|
||||||
brew install altserver
|
|
||||||
open -a AltServer
|
|
||||||
```
|
|
||||||
|
|
||||||
AltServer will appear in your menu bar.
|
|
||||||
|
|
||||||
## 2. Enable Developer Mode (iOS 16+)
|
|
||||||
|
|
||||||
- On your iPhone, go to **Settings > Privacy & Security > Developer Mode**
|
|
||||||
- Toggle it on and restart when prompted
|
|
||||||
|
|
||||||
## 3. Install AltStore on Your iPhone
|
|
||||||
|
|
||||||
- Click AltServer in the menu bar
|
|
||||||
- Click **Install AltStore > [Your iPhone]**
|
|
||||||
- Enter your Apple ID credentials when prompted
|
|
||||||
- On your iPhone, go to **Settings > General > VPN & Device Management**
|
|
||||||
- Tap your Apple ID under "Developer App" and tap **Trust**
|
|
||||||
|
|
||||||
## 4. Copy Files to Your iPhone
|
|
||||||
|
|
||||||
Transfer the IPA and game disc to your iPhone so they're accessible in the Files app. A few ways to do this:
|
|
||||||
|
|
||||||
- **AirDrop** - Right-click the files on your Mac and choose Share > AirDrop
|
|
||||||
- **iCloud Drive** - Place files in iCloud Drive on your Mac and they'll sync to Files on your iPhone
|
|
||||||
- **USB transfer** - Connect your iPhone and drag files via Finder's sidebar
|
|
||||||
- **Cloud storage** - Upload to Google Drive, Dropbox, etc. and download on your iPhone
|
|
||||||
|
|
||||||
## 5. Install via AltStore
|
|
||||||
|
|
||||||
- Open **AltStore** on your iPhone
|
|
||||||
- Go to the **My Apps** tab
|
|
||||||
- Tap the **+** button (top left)
|
|
||||||
- Open the **Files** app and select the `.ipa` file
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
set(DOLZEL_FILES
|
set(DOLZEL_FILES
|
||||||
src/m_Do/m_Do_main.cpp
|
src/m_Do/m_Do_main.cpp
|
||||||
#src/m_Do/m_Do_printf.cpp
|
src/m_Do/m_Do_printf.cpp
|
||||||
src/m_Do/m_Do_audio.cpp
|
src/m_Do/m_Do_audio.cpp
|
||||||
src/m_Do/m_Do_controller_pad.cpp
|
src/m_Do/m_Do_controller_pad.cpp
|
||||||
#src/m_Do/m_Re_controller_pad.cpp
|
#src/m_Do/m_Re_controller_pad.cpp
|
||||||
@@ -1411,7 +1411,6 @@ set(DOLPHIN_FILES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(DUSK_FILES
|
set(DUSK_FILES
|
||||||
include/dusk/action_bindings.h
|
|
||||||
include/dusk/endian_gx.hpp
|
include/dusk/endian_gx.hpp
|
||||||
include/dusk/config.hpp
|
include/dusk/config.hpp
|
||||||
include/dusk/dvd_asset.hpp
|
include/dusk/dvd_asset.hpp
|
||||||
@@ -1421,8 +1420,6 @@ set(DUSK_FILES
|
|||||||
src/dusk/asserts.cpp
|
src/dusk/asserts.cpp
|
||||||
src/dusk/config.cpp
|
src/dusk/config.cpp
|
||||||
src/dusk/crash_reporting.cpp
|
src/dusk/crash_reporting.cpp
|
||||||
src/dusk/data.cpp
|
|
||||||
src/dusk/data.hpp
|
|
||||||
src/dusk/endian.cpp
|
src/dusk/endian.cpp
|
||||||
src/dusk/extras.c
|
src/dusk/extras.c
|
||||||
src/dusk/file_select.cpp
|
src/dusk/file_select.cpp
|
||||||
@@ -1432,105 +1429,48 @@ set(DUSK_FILES
|
|||||||
src/dusk/globals.cpp
|
src/dusk/globals.cpp
|
||||||
src/dusk/gyro.cpp
|
src/dusk/gyro.cpp
|
||||||
src/dusk/gamepad_color.cpp
|
src/dusk/gamepad_color.cpp
|
||||||
src/dusk/autosave.cpp
|
|
||||||
src/dusk/http/http.hpp
|
|
||||||
src/dusk/io.cpp
|
src/dusk/io.cpp
|
||||||
src/dusk/layout.cpp
|
src/dusk/layout.cpp
|
||||||
src/dusk/logging.cpp
|
src/dusk/logging.cpp
|
||||||
src/dusk/settings.cpp
|
src/dusk/settings.cpp
|
||||||
src/dusk/speedrun.cpp
|
|
||||||
src/dusk/stubs.cpp
|
src/dusk/stubs.cpp
|
||||||
src/dusk/update_check.cpp
|
|
||||||
src/dusk/update_check.hpp
|
|
||||||
#src/dusk/m_Do_ext_dusk.cpp
|
#src/dusk/m_Do_ext_dusk.cpp
|
||||||
src/dusk/imgui/ImGuiConfig.hpp
|
src/dusk/imgui/ImGuiConfig.hpp
|
||||||
src/dusk/imgui/ImGuiConsole.hpp
|
src/dusk/imgui/ImGuiConsole.hpp
|
||||||
src/dusk/imgui/ImGuiConsole.cpp
|
src/dusk/imgui/ImGuiConsole.cpp
|
||||||
src/dusk/imgui/ImGuiEngine.cpp
|
src/dusk/imgui/ImGuiEngine.cpp
|
||||||
src/dusk/imgui/ImGuiEngine.hpp
|
src/dusk/imgui/ImGuiEngine.hpp
|
||||||
|
src/dusk/imgui/ImGuiMenuGame.cpp
|
||||||
|
src/dusk/imgui/ImGuiMenuGame.hpp
|
||||||
src/dusk/imgui/ImGuiBloomWindow.cpp
|
src/dusk/imgui/ImGuiBloomWindow.cpp
|
||||||
src/dusk/imgui/ImGuiBloomWindow.hpp
|
src/dusk/imgui/ImGuiBloomWindow.hpp
|
||||||
src/dusk/imgui/ImGuiEnhancedLightingWindow.cpp
|
|
||||||
src/dusk/imgui/ImGuiEnhancedLightingWindow.hpp
|
|
||||||
src/dusk/imgui/ImGuiMenuTools.cpp
|
src/dusk/imgui/ImGuiMenuTools.cpp
|
||||||
src/dusk/imgui/ImGuiMenuTools.hpp
|
src/dusk/imgui/ImGuiMenuTools.hpp
|
||||||
src/dusk/imgui/ImGuiActorSpawner.cpp
|
src/dusk/imgui/ImGuiPreLaunchWindow.cpp
|
||||||
|
src/dusk/imgui/ImGuiPreLaunchWindow.hpp
|
||||||
|
src/dusk/imgui/ImGuiFirstRunPreset.hpp
|
||||||
|
src/dusk/imgui/ImGuiFirstRunPreset.cpp
|
||||||
src/dusk/imgui/ImGuiProcessOverlay.cpp
|
src/dusk/imgui/ImGuiProcessOverlay.cpp
|
||||||
src/dusk/imgui/ImGuiCameraOverlay.cpp
|
src/dusk/imgui/ImGuiCameraOverlay.cpp
|
||||||
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
||||||
|
src/dusk/imgui/ImGuiActorSpawner.cpp
|
||||||
|
src/dusk/imgui/ImGuiDebugPad.cpp
|
||||||
src/dusk/imgui/ImGuiControllerOverlay.cpp
|
src/dusk/imgui/ImGuiControllerOverlay.cpp
|
||||||
src/dusk/imgui/ImGuiStubLog.cpp
|
src/dusk/imgui/ImGuiStubLog.cpp
|
||||||
src/dusk/imgui/ImGuiMapLoader.cpp
|
src/dusk/imgui/ImGuiMapLoader.cpp
|
||||||
src/dusk/imgui/ImGuiSaveEditor.cpp
|
src/dusk/imgui/ImGuiSaveEditor.cpp
|
||||||
src/dusk/imgui/ImGuiStateShare.hpp
|
src/dusk/imgui/ImGuiStateShare.hpp
|
||||||
src/dusk/imgui/ImGuiStateShare.cpp
|
src/dusk/imgui/ImGuiStateShare.cpp
|
||||||
src/dusk/ui/achievements.cpp
|
src/dusk/imgui/ImGuiAchievements.hpp
|
||||||
src/dusk/ui/achievements.hpp
|
src/dusk/imgui/ImGuiAchievements.cpp
|
||||||
src/dusk/ui/bool_button.cpp
|
|
||||||
src/dusk/ui/bool_button.hpp
|
|
||||||
src/dusk/ui/button.cpp
|
|
||||||
src/dusk/ui/button.hpp
|
|
||||||
src/dusk/ui/component.cpp
|
|
||||||
src/dusk/ui/component.hpp
|
|
||||||
src/dusk/ui/controller_config.cpp
|
|
||||||
src/dusk/ui/controller_config.hpp
|
|
||||||
src/dusk/ui/document.cpp
|
|
||||||
src/dusk/ui/document.hpp
|
|
||||||
src/dusk/ui/editor.cpp
|
|
||||||
src/dusk/ui/editor.hpp
|
|
||||||
src/dusk/ui/event.cpp
|
|
||||||
src/dusk/ui/event.hpp
|
|
||||||
src/dusk/ui/graphics_tuner.cpp
|
|
||||||
src/dusk/ui/graphics_tuner.hpp
|
|
||||||
src/dusk/ui/input.cpp
|
|
||||||
src/dusk/ui/input.hpp
|
|
||||||
src/dusk/ui/modal.cpp
|
|
||||||
src/dusk/ui/modal.hpp
|
|
||||||
src/dusk/ui/nav_types.hpp
|
|
||||||
src/dusk/ui/number_button.cpp
|
|
||||||
src/dusk/ui/number_button.hpp
|
|
||||||
src/dusk/ui/overlay.cpp
|
|
||||||
src/dusk/ui/overlay.hpp
|
|
||||||
src/dusk/ui/pane.cpp
|
|
||||||
src/dusk/ui/pane.hpp
|
|
||||||
src/dusk/ui/menu_bar.cpp
|
|
||||||
src/dusk/ui/menu_bar.hpp
|
|
||||||
src/dusk/ui/prelaunch.cpp
|
|
||||||
src/dusk/ui/prelaunch.hpp
|
|
||||||
src/dusk/ui/preset.cpp
|
|
||||||
src/dusk/ui/preset.hpp
|
|
||||||
src/dusk/ui/reporting.cpp
|
|
||||||
src/dusk/ui/reporting.hpp
|
|
||||||
src/dusk/ui/select_button.cpp
|
|
||||||
src/dusk/ui/select_button.hpp
|
|
||||||
src/dusk/ui/settings.cpp
|
|
||||||
src/dusk/ui/settings.hpp
|
|
||||||
src/dusk/ui/string_button.cpp
|
|
||||||
src/dusk/ui/string_button.hpp
|
|
||||||
src/dusk/ui/tab_bar.cpp
|
|
||||||
src/dusk/ui/tab_bar.hpp
|
|
||||||
src/dusk/ui/ui.cpp
|
|
||||||
src/dusk/ui/ui.hpp
|
|
||||||
src/dusk/ui/window.cpp
|
|
||||||
src/dusk/ui/window.hpp
|
|
||||||
src/dusk/achievements.cpp
|
src/dusk/achievements.cpp
|
||||||
src/dusk/iso_validate.cpp
|
src/dusk/iso_validate.cpp
|
||||||
src/dusk/livesplit.cpp
|
src/dusk/livesplit.cpp
|
||||||
src/dusk/offset_ptr.cpp
|
src/dusk/offset_ptr.cpp
|
||||||
|
src/dusk/vmem.cpp
|
||||||
src/dusk/OSContext.cpp
|
src/dusk/OSContext.cpp
|
||||||
src/dusk/OSReport.cpp
|
|
||||||
src/dusk/OSThread.cpp
|
src/dusk/OSThread.cpp
|
||||||
src/dusk/OSMutex.cpp
|
src/dusk/OSMutex.cpp
|
||||||
src/dusk/discord.cpp
|
|
||||||
src/dusk/discord.hpp
|
|
||||||
src/dusk/discord_presence.cpp
|
src/dusk/discord_presence.cpp
|
||||||
src/dusk/version.cpp
|
src/dusk/version.cpp
|
||||||
src/dusk/action_bindings.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(DUSK_HTTP_BACKEND_FILES
|
|
||||||
src/dusk/http/no_backend.cpp
|
|
||||||
src/dusk/http/curl.cpp
|
|
||||||
src/dusk/http/winhttp.cpp
|
|
||||||
src/dusk/http/url_session.mm
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,212 +4,30 @@
|
|||||||
};
|
};
|
||||||
outputs = { self, nixpkgs }:
|
outputs = { self, nixpkgs }:
|
||||||
let
|
let
|
||||||
supportedSystems = [
|
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||||
"x86_64-linux"
|
dusk = pkgs.stdenv.mkDerivation {
|
||||||
"aarch64-linux"
|
name = "dusk";
|
||||||
"x86_64-darwin"
|
src = ./.;
|
||||||
"aarch64-darwin"
|
nativeBuildInputs = [
|
||||||
];
|
pkgs.cmake
|
||||||
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
pkgs.pkg-config
|
||||||
pkgsFor = system: import nixpkgs { inherit system; };
|
pkgs.wayland
|
||||||
|
];
|
||||||
# Dependencies that are not packaged in nixpkgs (used by the Linux package build):
|
buildInputs = [
|
||||||
buildSources = pkgs: {
|
pkgs.libGL
|
||||||
aurora-src = pkgs.fetchFromGitHub {
|
pkgs.libX11
|
||||||
owner = "encounter";
|
pkgs.libXcursor
|
||||||
repo = "aurora";
|
pkgs.libxi
|
||||||
rev = "63606a43265a3bc18dafd500ab4d7a2108f109e6";
|
pkgs.libxcb
|
||||||
hash = "sha256-xBvnAwGwNzav67Ac6oUz7RqDUwqgL2bsME3OOMn8Tqw=";
|
pkgs.libxrandr
|
||||||
};
|
pkgs.libxscrnsaver
|
||||||
dawn-src = pkgs.fetchzip {
|
pkgs.libxtst
|
||||||
url = "https://github.com/encounter/dawn-build/releases/download/v20260423.175430/dawn-linux-x86_64.tar.gz";
|
pkgs.libjpeg8
|
||||||
hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs=";
|
pkgs.libxkbcommon
|
||||||
stripRoot = false;
|
pkgs.libglvnd
|
||||||
};
|
];
|
||||||
nod-src = pkgs.fetchzip {
|
|
||||||
url = "https://github.com/encounter/nod/releases/download/v2.0.0-alpha.8/libnod-linux-x86_64.tar.gz";
|
|
||||||
hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE=";
|
|
||||||
stripRoot = false;
|
|
||||||
};
|
|
||||||
# The version of imgui on nixpkgs does not map cleanly.
|
|
||||||
imgui-src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "ocornut";
|
|
||||||
repo = "imgui";
|
|
||||||
rev = "v1.91.9b-docking";
|
|
||||||
hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ=";
|
|
||||||
};
|
|
||||||
sqlite-src = pkgs.fetchzip {
|
|
||||||
url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip";
|
|
||||||
hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM=";
|
|
||||||
};
|
|
||||||
rmlui-src = pkgs.fetchzip {
|
|
||||||
url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz";
|
|
||||||
hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg=";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Dusklight Actual (Linux x86_64 only — relies on prebuilt dawn/nod binaries)
|
|
||||||
mkDusklight = pkgs:
|
|
||||||
let srcs = buildSources pkgs; in
|
|
||||||
pkgs.stdenv.mkDerivation {
|
|
||||||
name = "dusklight";
|
|
||||||
src = ./.;
|
|
||||||
postUnpack = ''
|
|
||||||
mkdir -p $sourceRoot/extern/aurora
|
|
||||||
cp -r ${srcs.aurora-src}/. $sourceRoot/extern/aurora/
|
|
||||||
chmod -R u+w $sourceRoot/extern/aurora
|
|
||||||
sed -i '/add_subdirectory(tests)/d' $sourceRoot/extern/aurora/CMakeLists.txt
|
|
||||||
'';
|
|
||||||
# Remove last line to re-enable tests
|
|
||||||
cmakeFlags = [
|
|
||||||
"-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT=${srcs.dawn-src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_XXHASH=${pkgs.xxHash.src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_FMT=${pkgs.fmt.src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_TRACY=${pkgs.tracy.src}"
|
|
||||||
"-DAURORA_SDL3_PROVIDER=system"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_NOD_PREBUILT=${srcs.nod-src}"
|
|
||||||
"-DAURORA_NOD_PROVIDER=package"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_FREETYPE=${pkgs.freetype.src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_SQLITE3=${srcs.sqlite-src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_IMGUI=${srcs.imgui-src}"
|
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_RMLUI=${srcs.rmlui-src}"
|
|
||||||
"-DCMAKE_CROSSCOMPILING=ON" # Tests are not working as I didn't want to work through getting google's test suite working as well. This is the only guard I could find to disable it.
|
|
||||||
];
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp dusklight $out/bin/dusklight
|
|
||||||
cp -r ./res $out/bin/res
|
|
||||||
'';
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pkgs.cmake
|
|
||||||
pkgs.pkg-config
|
|
||||||
pkgs.wayland
|
|
||||||
];
|
|
||||||
buildInputs = [
|
|
||||||
pkgs.libGL
|
|
||||||
pkgs.libX11
|
|
||||||
pkgs.libXcursor
|
|
||||||
pkgs.libxi
|
|
||||||
pkgs.libxcb
|
|
||||||
pkgs.libxrandr
|
|
||||||
pkgs.libxscrnsaver
|
|
||||||
pkgs.libxtst
|
|
||||||
pkgs.libjpeg8
|
|
||||||
pkgs.libxkbcommon
|
|
||||||
pkgs.libglvnd
|
|
||||||
pkgs.cxxopts
|
|
||||||
pkgs.abseil-cpp
|
|
||||||
pkgs.sdl3
|
|
||||||
pkgs.fmt
|
|
||||||
pkgs.tracy
|
|
||||||
pkgs.freetype
|
|
||||||
pkgs.zstd
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Tooling common to every supported host (Linux and macOS).
|
|
||||||
commonDevTools = pkgs: [
|
|
||||||
pkgs.cmake
|
|
||||||
pkgs.ninja
|
|
||||||
pkgs.pkg-config
|
|
||||||
pkgs.git
|
|
||||||
pkgs.python3
|
|
||||||
pkgs.python3Packages.markupsafe
|
|
||||||
pkgs.rustc
|
|
||||||
pkgs.cargo
|
|
||||||
pkgs.sccache
|
|
||||||
];
|
|
||||||
|
|
||||||
# Linux-only system libraries — mirrors the apt deps from .github/workflows/build.yml
|
|
||||||
# so the cmake presets resolve the same set of headers as CI.
|
|
||||||
linuxDevDeps = pkgs: [
|
|
||||||
# Compilers / linkers
|
|
||||||
pkgs.clang
|
|
||||||
pkgs.lld
|
|
||||||
# C/C++ utilities
|
|
||||||
pkgs.curl
|
|
||||||
pkgs.openssl
|
|
||||||
pkgs.zlib
|
|
||||||
pkgs.libpng
|
|
||||||
pkgs.libjpeg_turbo
|
|
||||||
pkgs.freetype
|
|
||||||
pkgs.zstd
|
|
||||||
pkgs.fmt
|
|
||||||
pkgs.tracy
|
|
||||||
pkgs.cxxopts
|
|
||||||
pkgs.abseil-cpp
|
|
||||||
pkgs.sdl3
|
|
||||||
pkgs.ncurses
|
|
||||||
pkgs.libunwind
|
|
||||||
pkgs.libusb1
|
|
||||||
pkgs.fuse
|
|
||||||
# Wayland / display server
|
|
||||||
pkgs.wayland
|
|
||||||
pkgs.wayland-protocols
|
|
||||||
pkgs.libxkbcommon
|
|
||||||
pkgs.libdecor
|
|
||||||
# OpenGL / Vulkan
|
|
||||||
pkgs.libGL
|
|
||||||
pkgs.libGLU
|
|
||||||
pkgs.libglvnd
|
|
||||||
pkgs.vulkan-headers
|
|
||||||
pkgs.vulkan-loader
|
|
||||||
# X11
|
|
||||||
pkgs.libX11
|
|
||||||
pkgs.libxcb
|
|
||||||
pkgs.libXcursor
|
|
||||||
pkgs.libxi
|
|
||||||
pkgs.libxrandr
|
|
||||||
pkgs.libxscrnsaver
|
|
||||||
pkgs.libxtst
|
|
||||||
pkgs.libxinerama
|
|
||||||
# Audio
|
|
||||||
pkgs.alsa-lib
|
|
||||||
pkgs.libpulseaudio
|
|
||||||
pkgs.pipewire
|
|
||||||
# System integration
|
|
||||||
pkgs.dbus
|
|
||||||
pkgs.udev
|
|
||||||
pkgs.gtk3
|
|
||||||
];
|
|
||||||
|
|
||||||
# On macOS we deliberately avoid pulling Nix's cc-wrapper so CMake picks up
|
|
||||||
# Apple Clang and the Xcode SDK directly, matching the macOS CI workflow.
|
|
||||||
mkDarwinShell = pkgs:
|
|
||||||
pkgs.mkShellNoCC {
|
|
||||||
packages = commonDevTools pkgs;
|
|
||||||
shellHook = ''
|
|
||||||
echo "Dusklight dev shell (macOS)"
|
|
||||||
echo "Requires Xcode Command Line Tools for Apple Clang and the macOS SDK."
|
|
||||||
echo "Configure: cmake --preset macos-default-relwithdebinfo"
|
|
||||||
echo "Build: cmake --build --preset macos-default-relwithdebinfo"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
mkLinuxShell = pkgs:
|
|
||||||
pkgs.mkShell {
|
|
||||||
packages = (commonDevTools pkgs) ++ (linuxDevDeps pkgs);
|
|
||||||
shellHook = ''
|
|
||||||
echo "Dusklight dev shell (Linux)"
|
|
||||||
echo "Configure: cmake --preset linux-default-relwithdebinfo"
|
|
||||||
echo " cmake --preset linux-clang-relwithdebinfo"
|
|
||||||
echo "Build: cmake --build --preset <preset>"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
mkDevShell = pkgs:
|
|
||||||
if pkgs.stdenv.isDarwin
|
|
||||||
then mkDarwinShell pkgs
|
|
||||||
else mkLinuxShell pkgs;
|
|
||||||
in {
|
in {
|
||||||
packages.x86_64-linux.default = mkDusklight (pkgsFor "x86_64-linux");
|
packages.x86_64-linux.default = dusk;
|
||||||
|
|
||||||
devShells = forAllSystems (system: {
|
|
||||||
default = mkDevShell (pkgsFor system);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4552,18 +4552,6 @@ public:
|
|||||||
void handleWolfHowl();
|
void handleWolfHowl();
|
||||||
void handleQuickTransform();
|
void handleQuickTransform();
|
||||||
bool checkGyroAimContext();
|
bool checkGyroAimContext();
|
||||||
|
|
||||||
void onIronBallChainInterpCallback();
|
|
||||||
|
|
||||||
static const int IRON_BALL_CHAIN_COUNT = 102;
|
|
||||||
cXyz mIBChainInterpPrevPos[IRON_BALL_CHAIN_COUNT];
|
|
||||||
cXyz mIBChainInterpCurrPos[IRON_BALL_CHAIN_COUNT];
|
|
||||||
csXyz mIBChainInterpPrevAngle[IRON_BALL_CHAIN_COUNT];
|
|
||||||
csXyz mIBChainInterpCurrAngle[IRON_BALL_CHAIN_COUNT];
|
|
||||||
cXyz mIBChainInterpPrevHandRoot;
|
|
||||||
cXyz mIBChainInterpCurrHandRoot;
|
|
||||||
bool mIBChainInterpPrevValid;
|
|
||||||
bool mIBChainInterpCurrValid;
|
|
||||||
#endif
|
#endif
|
||||||
}; // Size: 0x385C
|
}; // Size: 0x385C
|
||||||
|
|
||||||
|
|||||||
@@ -80,12 +80,6 @@ public:
|
|||||||
/* 0x125C */ u32 field_0x125c;
|
/* 0x125C */ u32 field_0x125c;
|
||||||
/* 0x1260 */ u8 field_0x1260[0x126C - 0x1260];
|
/* 0x1260 */ u8 field_0x1260[0x126C - 0x1260];
|
||||||
/* 0x126C */ u8 HIOInit;
|
/* 0x126C */ u8 HIOInit;
|
||||||
#if TARGET_PC
|
|
||||||
cXyz mStalkLineInterpPrev[12];
|
|
||||||
cXyz mStalkLineInterpCurr[12];
|
|
||||||
bool mStalkLineInterpPrevValid;
|
|
||||||
bool mStalkLineInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(e_db_class) == 0x1270);
|
STATIC_ASSERT(sizeof(e_db_class) == 0x1270);
|
||||||
|
|||||||
@@ -73,12 +73,6 @@ public:
|
|||||||
/* 0x124C */ f32 field_0x124c;
|
/* 0x124C */ f32 field_0x124c;
|
||||||
/* 0x1250 */ u8 field_0x1250[0x1264 - 0x1250];
|
/* 0x1250 */ u8 field_0x1250[0x1264 - 0x1250];
|
||||||
/* 0x1264 */ u8 HIOInit;
|
/* 0x1264 */ u8 HIOInit;
|
||||||
#if TARGET_PC
|
|
||||||
cXyz mStalkLineInterpPrev[12];
|
|
||||||
cXyz mStalkLineInterpCurr[12];
|
|
||||||
bool mStalkLineInterpPrevValid;
|
|
||||||
bool mStalkLineInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(e_hb_class) == 0x1268);
|
STATIC_ASSERT(sizeof(e_hb_class) == 0x1268);
|
||||||
|
|||||||
@@ -81,15 +81,6 @@ public:
|
|||||||
/* 0x306D */ u8 field_0x306D[0x307C - 0x306D];
|
/* 0x306D */ u8 field_0x306D[0x307C - 0x306D];
|
||||||
/* 0x307C */ u32 mBodyEffEmtrID;
|
/* 0x307C */ u32 mBodyEffEmtrID;
|
||||||
/* 0x3080 */ u8 mInitHIO;
|
/* 0x3080 */ u8 mInitHIO;
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
static const int HAIR_STRAND_COUNT = 22;
|
|
||||||
static const int HAIR_SEGMENT_COUNT = 16;
|
|
||||||
cXyz mHairInterpPrev[HAIR_STRAND_COUNT * HAIR_SEGMENT_COUNT];
|
|
||||||
cXyz mHairInterpCurr[HAIR_STRAND_COUNT * HAIR_SEGMENT_COUNT];
|
|
||||||
bool mHairInterpPrevValid;
|
|
||||||
bool mHairInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(e_s1_class) == 0x3084);
|
STATIC_ASSERT(sizeof(e_s1_class) == 0x3084);
|
||||||
|
|||||||
@@ -74,12 +74,6 @@ public:
|
|||||||
/* 0x1250 */ f32 field_0x1250;
|
/* 0x1250 */ f32 field_0x1250;
|
||||||
/* 0x1254 */ u8 field_0x1254[0x1268 - 0x1254];
|
/* 0x1254 */ u8 field_0x1254[0x1268 - 0x1254];
|
||||||
/* 0x1268 */ u8 field_0x1268;
|
/* 0x1268 */ u8 field_0x1268;
|
||||||
#if TARGET_PC
|
|
||||||
cXyz mLineMatInterpPrev[12];
|
|
||||||
cXyz mLineMatInterpCurr[12];
|
|
||||||
bool mLineMatInterpPrevValid;
|
|
||||||
bool mLineMatInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(e_yd_class) == 0x126c);
|
STATIC_ASSERT(sizeof(e_yd_class) == 0x126c);
|
||||||
|
|||||||
@@ -63,15 +63,6 @@ public:
|
|||||||
/* 0x0BB4 */ yg_ke_s mYgKes[13];
|
/* 0x0BB4 */ yg_ke_s mYgKes[13];
|
||||||
/* 0x1880 */ mDoExt_3DlineMat0_c mLineMat;
|
/* 0x1880 */ mDoExt_3DlineMat0_c mLineMat;
|
||||||
/* 0x189C */ u8 mIsFirstSpawn;
|
/* 0x189C */ u8 mIsFirstSpawn;
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
static const int TENTACLE_STRAND_COUNT = 13;
|
|
||||||
static const int TENTACLE_SEGMENT_COUNT = 10;
|
|
||||||
cXyz mTentacleInterpPrev[TENTACLE_STRAND_COUNT * TENTACLE_SEGMENT_COUNT];
|
|
||||||
cXyz mTentacleInterpCurr[TENTACLE_STRAND_COUNT * TENTACLE_SEGMENT_COUNT];
|
|
||||||
bool mTentacleInterpPrevValid;
|
|
||||||
bool mTentacleInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(e_yg_class) == 0x18a0);
|
STATIC_ASSERT(sizeof(e_yg_class) == 0x18a0);
|
||||||
|
|||||||
@@ -77,12 +77,6 @@ public:
|
|||||||
/* 0x1260 */ u32 field_0x1260;
|
/* 0x1260 */ u32 field_0x1260;
|
||||||
/* 0x1260 */ u8 field_0x1264[0x1270 - 0x1264];
|
/* 0x1260 */ u8 field_0x1264[0x1270 - 0x1264];
|
||||||
/* 0x1270 */ bool mIsHIOOwner;
|
/* 0x1270 */ bool mIsHIOOwner;
|
||||||
#if TARGET_PC
|
|
||||||
cXyz mLineInterpPrev[12];
|
|
||||||
cXyz mLineInterpCurr[12];
|
|
||||||
bool mLineInterpPrevValid;
|
|
||||||
bool mLineInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(e_yh_class) == 0x1274);
|
STATIC_ASSERT(sizeof(e_yh_class) == 0x1274);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ public:
|
|||||||
/* 0x17C */ cXyz mViewScale;
|
/* 0x17C */ cXyz mViewScale;
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
bool mbReset = false;
|
bool mbReset = false;
|
||||||
bool mbHadEntry = false;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ public:
|
|||||||
csXyz* getAngle() { return field_0x8a4; }
|
csXyz* getAngle() { return field_0x8a4; }
|
||||||
J3DModelData* getModelData() { return mModelData; }
|
J3DModelData* getModelData() { return mModelData; }
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void onInterpCallback();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* 0x568 */ request_of_phase_process_class mPhase;
|
/* 0x568 */ request_of_phase_process_class mPhase;
|
||||||
/* 0x570 */ J3DModelData* mModelData;
|
/* 0x570 */ J3DModelData* mModelData;
|
||||||
@@ -46,14 +42,6 @@ private:
|
|||||||
/* 0x694 */ cXyz field_0x694[22];
|
/* 0x694 */ cXyz field_0x694[22];
|
||||||
/* 0x79C */ cXyz field_0x79c[22];
|
/* 0x79C */ cXyz field_0x79c[22];
|
||||||
/* 0x8A4 */ csXyz field_0x8a4[22];
|
/* 0x8A4 */ csXyz field_0x8a4[22];
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
static const int CHAIN_COUNT = 22;
|
|
||||||
cXyz mChainInterpPrev[CHAIN_COUNT];
|
|
||||||
cXyz mChainInterpCurr[CHAIN_COUNT];
|
|
||||||
bool mChainInterpPrevValid;
|
|
||||||
bool mChainInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(daObjFchain_c) == 0x928);
|
STATIC_ASSERT(sizeof(daObjFchain_c) == 0x928);
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ public:
|
|||||||
int Draw();
|
int Draw();
|
||||||
int Delete();
|
int Delete();
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void onInterpCallback();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum Param_e {
|
enum Param_e {
|
||||||
LOCK_e = (1 << 6), NO_BASE_DISP = (1 << 7)
|
LOCK_e = (1 << 6), NO_BASE_DISP = (1 << 7)
|
||||||
};
|
};
|
||||||
@@ -54,13 +50,6 @@ private:
|
|||||||
/* 0x1020 */ dCcD_Cyl mCylinderCollider;
|
/* 0x1020 */ dCcD_Cyl mCylinderCollider;
|
||||||
/* 0x115C */ s32 mStopSwingingFrames;
|
/* 0x115C */ s32 mStopSwingingFrames;
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
cXyz mChainInterpPrev[64];
|
|
||||||
cXyz mChainInterpCurr[64];
|
|
||||||
bool mChainInterpPrevValid;
|
|
||||||
bool mChainInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Number of chain models
|
// Number of chain models
|
||||||
u32 getArg0() {
|
u32 getArg0() {
|
||||||
return fopAcM_GetParamBit(this, 0, 6);
|
return fopAcM_GetParamBit(this, 0, 6);
|
||||||
|
|||||||
@@ -118,18 +118,6 @@ class camera_class;
|
|||||||
class dCamera_c;
|
class dCamera_c;
|
||||||
typedef bool (dCamera_c::*engine_fn)(s32);
|
typedef bool (dCamera_c::*engine_fn)(s32);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
struct DebugFlyCam {
|
|
||||||
bool initialized;
|
|
||||||
f32 pitch;
|
|
||||||
f32 yaw;
|
|
||||||
cXyz savedCenter;
|
|
||||||
cXyz savedEye;
|
|
||||||
f32 savedFovy;
|
|
||||||
cSAngle savedBank;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class dCamera_c {
|
class dCamera_c {
|
||||||
public:
|
public:
|
||||||
class dCamInfo_c {
|
class dCamInfo_c {
|
||||||
@@ -1040,8 +1028,6 @@ public:
|
|||||||
bool test2Camera(s32);
|
bool test2Camera(s32);
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
bool freeCamera();
|
bool freeCamera();
|
||||||
bool executeDebugFlyCam();
|
|
||||||
void deactivateDebugFlyCam();
|
|
||||||
#endif
|
#endif
|
||||||
bool towerCamera(s32);
|
bool towerCamera(s32);
|
||||||
bool hookshotCamera(s32);
|
bool hookshotCamera(s32);
|
||||||
@@ -1390,10 +1376,6 @@ public:
|
|||||||
/* 0x970 */ dCamSetup_c mCamSetup;
|
/* 0x970 */ dCamSetup_c mCamSetup;
|
||||||
/* 0xAEC */ dCamParam_c mCamParam;
|
/* 0xAEC */ dCamParam_c mCamParam;
|
||||||
/* 0xB0C */ u8 field_0xb0c;
|
/* 0xB0C */ u8 field_0xb0c;
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
DebugFlyCam mDebugFlyCam;
|
|
||||||
#endif
|
|
||||||
}; // Size: 0xB10
|
}; // Size: 0xB10
|
||||||
|
|
||||||
dCamera_c* dCam_getBody();
|
dCamera_c* dCam_getBody();
|
||||||
|
|||||||
@@ -1845,12 +1845,6 @@ inline void dComIfGs_addDeathCount() {
|
|||||||
g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().addDeathCount();
|
g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().addDeathCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
inline u16 dComIfGs_getDeathCount() {
|
|
||||||
return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getDeathCount();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline char* dComIfGs_getPlayerName() {
|
inline char* dComIfGs_getPlayerName() {
|
||||||
return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getPlayerName();
|
return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getPlayerName();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,11 +196,7 @@ public:
|
|||||||
/* 0x108 */ int mSkipTimer;
|
/* 0x108 */ int mSkipTimer;
|
||||||
/* 0x10C */ int mSkipParameter;
|
/* 0x10C */ int mSkipParameter;
|
||||||
/* 0x110 */ BOOL mIsSkipFade;
|
/* 0x110 */ BOOL mIsSkipFade;
|
||||||
#if TARGET_PC
|
|
||||||
/* 0x114 */ char mSkipEventName[21];
|
|
||||||
#else
|
|
||||||
/* 0x114 */ char mSkipEventName[20];
|
/* 0x114 */ char mSkipEventName[20];
|
||||||
#endif
|
|
||||||
/* 0x128 */ u8 mCompulsory;
|
/* 0x128 */ u8 mCompulsory;
|
||||||
/* 0x129 */ bool mRoomInfoSet;
|
/* 0x129 */ bool mRoomInfoSet;
|
||||||
/* 0x12C */ int mRoomNo;
|
/* 0x12C */ int mRoomNo;
|
||||||
|
|||||||
@@ -223,9 +223,6 @@ private:
|
|||||||
/* 0x8F */ u8 field_0x8f;
|
/* 0x8F */ u8 field_0x8f;
|
||||||
/* 0x90 */ u8 field_0x90;
|
/* 0x90 */ u8 field_0x90;
|
||||||
/* 0x91 */ u8 field_0x91;
|
/* 0x91 */ u8 field_0x91;
|
||||||
#if TARGET_PC
|
|
||||||
bool previousMirror;
|
|
||||||
#endif
|
|
||||||
}; // Size: 0x94
|
}; // Size: 0x94
|
||||||
|
|
||||||
class dMap_HIO_list_c : public dMpath_HIO_n::hioList_c {
|
class dMap_HIO_list_c : public dMpath_HIO_n::hioList_c {
|
||||||
|
|||||||
@@ -91,10 +91,6 @@ public:
|
|||||||
void calcCursor();
|
void calcCursor();
|
||||||
void drawCursor();
|
void drawCursor();
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void dMapBgWide();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
|
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
|
||||||
|
|
||||||
f32 getMapWidth() { return mMapWidth; }
|
f32 getMapWidth() { return mMapWidth; }
|
||||||
|
|||||||
@@ -81,10 +81,6 @@ public:
|
|||||||
void calcDrawPriority();
|
void calcDrawPriority();
|
||||||
void setArrowPosAxis(f32, f32);
|
void setArrowPosAxis(f32, f32);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void fMapBackWide();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual void draw();
|
virtual void draw();
|
||||||
virtual ~dMenu_Fmap2DBack_c();
|
virtual ~dMenu_Fmap2DBack_c();
|
||||||
|
|
||||||
@@ -169,12 +165,6 @@ public:
|
|||||||
|
|
||||||
void mapBlink() {}
|
void mapBlink() {}
|
||||||
|
|
||||||
#if PLATFORM_WII || TARGET_PC
|
|
||||||
f32 getMirrorPosX(f32 param_0, f32 param_1) {
|
|
||||||
return (field_0x11dc * 2.0f - (param_0 + param_1)) - param_1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Unknown name
|
// Unknown name
|
||||||
struct RegionTexData {
|
struct RegionTexData {
|
||||||
/* 0x00 */ float mMinX;
|
/* 0x00 */ float mMinX;
|
||||||
@@ -340,10 +330,6 @@ public:
|
|||||||
void setHIO(bool);
|
void setHIO(bool);
|
||||||
bool isWarpAccept();
|
bool isWarpAccept();
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void fMapTopWide();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual void draw();
|
virtual void draw();
|
||||||
virtual ~dMenu_Fmap2DTop_c();
|
virtual ~dMenu_Fmap2DTop_c();
|
||||||
|
|
||||||
|
|||||||
@@ -66,16 +66,6 @@ public:
|
|||||||
_c90 = param_2;
|
_c90 = param_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PLATFORM_WII || TARGET_PC
|
|
||||||
f32 getMirrorCenterPosX(f32 param_0, f32 param_1) {
|
|
||||||
if (_c90) {
|
|
||||||
return (mCenterPosX * 2.0f - (param_0 + param_1)) - param_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return param_0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct Stage_c {
|
struct Stage_c {
|
||||||
// Incomplete class
|
// Incomplete class
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,6 @@ public:
|
|||||||
bool isStaffMessage();
|
bool isStaffMessage();
|
||||||
bool isSaveMessage();
|
bool isSaveMessage();
|
||||||
bool isTalkMessage();
|
bool isTalkMessage();
|
||||||
#if TARGET_PC
|
|
||||||
bool isShopItemMessage();
|
|
||||||
#endif
|
|
||||||
const char* getSmellName();
|
const char* getSmellName();
|
||||||
const char* getPortalName();
|
const char* getPortalName();
|
||||||
const char* getBombName();
|
const char* getBombName();
|
||||||
|
|||||||
@@ -486,9 +486,6 @@ public:
|
|||||||
mDeathCount++;
|
mDeathCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if TARGET_PC
|
|
||||||
u16 getDeathCount() const { return mDeathCount; }
|
|
||||||
#endif
|
|
||||||
char* getPlayerName() const { return const_cast<char*>(mPlayerName); }
|
char* getPlayerName() const { return const_cast<char*>(mPlayerName); }
|
||||||
void setPlayerName(const char* i_name) {
|
void setPlayerName(const char* i_name) {
|
||||||
#if AVOID_UB
|
#if AVOID_UB
|
||||||
|
|||||||
@@ -4,18 +4,16 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
|
|
||||||
namespace dusk {
|
namespace dusk {
|
||||||
|
|
||||||
enum class AchievementCategory : uint8_t {
|
enum class AchievementCategory : uint8_t {
|
||||||
Challenge,
|
Story,
|
||||||
Collection,
|
Collection,
|
||||||
|
Challenge,
|
||||||
Minigame,
|
Minigame,
|
||||||
Misc,
|
|
||||||
Glitched
|
Glitched
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,13 +40,10 @@ public:
|
|||||||
void save();
|
void save();
|
||||||
void tick();
|
void tick();
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearOne(const char* key);
|
|
||||||
|
|
||||||
// Signals are visible to all achievement checks within the same tick, then cleared.
|
|
||||||
void signal(const char* key);
|
|
||||||
bool hasSignal(const char* key) const;
|
|
||||||
|
|
||||||
std::vector<Achievement> getAchievements() const;
|
std::vector<Achievement> getAchievements() const;
|
||||||
|
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
|
||||||
|
std::string consumePendingUnlock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@@ -62,9 +57,9 @@ private:
|
|||||||
void processEntry(Entry& e);
|
void processEntry(Entry& e);
|
||||||
|
|
||||||
std::vector<Entry> m_entries;
|
std::vector<Entry> m_entries;
|
||||||
std::unordered_set<std::string_view> m_signals;
|
|
||||||
bool m_loaded = false;
|
bool m_loaded = false;
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
|
std::queue<std::string> m_pendingUnlocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dusk
|
} // namespace dusk
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "dusk/config_var.hpp"
|
|
||||||
|
|
||||||
namespace dusk {
|
|
||||||
|
|
||||||
enum class ActionBinds {
|
|
||||||
FIRST_PERSON_CAMERA,
|
|
||||||
CALL_MIDNA,
|
|
||||||
OPEN_DUSKLIGHT_MENU,
|
|
||||||
TURBO_SPEED_BUTTON,
|
|
||||||
COUNT,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ActionBindData {
|
|
||||||
std::array<config::ActionBindConfigVar, 4>* configVars{};
|
|
||||||
std::string actionName{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ActionBindPressData {
|
|
||||||
bool pressedCurFrame{false};
|
|
||||||
bool pressedPrevFrame{false};
|
|
||||||
};
|
|
||||||
|
|
||||||
using ActionBindsMap = std::unordered_map<ActionBinds, ActionBindData>;
|
|
||||||
|
|
||||||
ActionBindsMap& getActionBinds();
|
|
||||||
|
|
||||||
bool isActionBound(ActionBinds action, u32 port);
|
|
||||||
|
|
||||||
void updateActionBindings();
|
|
||||||
|
|
||||||
bool getActionBindTrig(ActionBinds action, u32 port);
|
|
||||||
|
|
||||||
bool getActionBindHold(ActionBinds action, u32 port);
|
|
||||||
|
|
||||||
bool getActionBindHoldAnyPort(ActionBinds action);
|
|
||||||
|
|
||||||
int getActionBindButton(ActionBinds action, u32 port);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,12 +7,7 @@ namespace dusk {
|
|||||||
*
|
*
|
||||||
* This gets used for file paths and such, and cannot be changed!
|
* This gets used for file paths and such, and cannot be changed!
|
||||||
*/
|
*/
|
||||||
constexpr auto AppName = "Dusklight";
|
constexpr auto AppName = "Dusk";
|
||||||
|
|
||||||
/**
|
|
||||||
* Previous AppName to migrate data from.
|
|
||||||
*/
|
|
||||||
constexpr auto LegacyAppName = "Dusk";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief The internal organization name for the game.
|
* \brief The internal organization name for the game.
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef AUTOSAVE_H
|
|
||||||
#define AUTOSAVE_H
|
|
||||||
|
|
||||||
#include <m_Do/m_Do_MemCardRWmng.h>
|
|
||||||
#include <m_Do/m_Do_MemCard.h>
|
|
||||||
|
|
||||||
void noAutoSave();
|
|
||||||
void triggerAutoSave();
|
|
||||||
void updateAutoSave();
|
|
||||||
void enterAutoSave();
|
|
||||||
void autoSaving();
|
|
||||||
void waitingForWrite();
|
|
||||||
void endAutoSave();
|
|
||||||
void toggleAutoSave(bool enabled);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifndef DUSK_CONFIG_HPP
|
#ifndef DUSK_CONFIG_HPP
|
||||||
#define DUSK_CONFIG_HPP
|
#define DUSK_CONFIG_HPP
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
#include "config_var.hpp"
|
#include "config_var.hpp"
|
||||||
@@ -112,18 +111,6 @@ void Save();
|
|||||||
*/
|
*/
|
||||||
ConfigVarBase* GetConfigVar(std::string_view name);
|
ConfigVarBase* GetConfigVar(std::string_view name);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Resets all custom action bindings for a specific port to nothing
|
|
||||||
*
|
|
||||||
* @param port The port to be cleared of action bindings
|
|
||||||
*/
|
|
||||||
void ClearAllActionBindings(int port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Call a function on every registered CVar.
|
|
||||||
*/
|
|
||||||
void EnumerateRegistered(std::function<void(ConfigVarBase&)> callback);
|
|
||||||
|
|
||||||
template <ConfigValue T>
|
template <ConfigValue T>
|
||||||
const ConfigImplBase* GetConfigImpl() {
|
const ConfigImplBase* GetConfigImpl() {
|
||||||
static ConfigImpl<T> config;
|
static ConfigImpl<T> config;
|
||||||
|
|||||||
@@ -48,13 +48,6 @@ enum class ConfigVarLayer : u8 {
|
|||||||
* Will not get saved to config.
|
* Will not get saved to config.
|
||||||
*/
|
*/
|
||||||
Override,
|
Override,
|
||||||
|
|
||||||
/**
|
|
||||||
* The CVar is temporarily overridden by speedrun mode.
|
|
||||||
* Will not get saved to config. Cleared when speedrun mode is disabled.
|
|
||||||
* Lower priority than Override, so launch args still win.
|
|
||||||
*/
|
|
||||||
Speedrun,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfigImplBase;
|
class ConfigImplBase;
|
||||||
@@ -120,12 +113,6 @@ public:
|
|||||||
* This is necessary to make it legal to access.
|
* This is necessary to make it legal to access.
|
||||||
*/
|
*/
|
||||||
void markRegistered();
|
void markRegistered();
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear a speedrun-mode override if one is active on this CVar.
|
|
||||||
* Safe to call on any CVar, no-op if not at the Speedrun layer.
|
|
||||||
*/
|
|
||||||
virtual void clearSpeedrunOverride() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -202,7 +189,6 @@ public:
|
|||||||
case ConfigVarLayer::Value:
|
case ConfigVarLayer::Value:
|
||||||
return value;
|
return value;
|
||||||
case ConfigVarLayer::Override:
|
case ConfigVarLayer::Override:
|
||||||
case ConfigVarLayer::Speedrun:
|
|
||||||
return overrideValue;
|
return overrideValue;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
@@ -253,42 +239,8 @@ public:
|
|||||||
overrideValue = std::move(newValue);
|
overrideValue = std::move(newValue);
|
||||||
layer = ConfigVarLayer::Override;
|
layer = ConfigVarLayer::Override;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Give a CVar a speedrun-mode override value.
|
|
||||||
*
|
|
||||||
* Lower priority than a launch-arg override. Cleared when speedrun mode is disabled.
|
|
||||||
* The overridden value will not get saved to config.
|
|
||||||
*
|
|
||||||
* @param newValue The new value the CVar will get.
|
|
||||||
*/
|
|
||||||
void setSpeedrunValue(T newValue) {
|
|
||||||
checkRegistered();
|
|
||||||
if (layer != ConfigVarLayer::Override) {
|
|
||||||
overrideValue = std::move(newValue);
|
|
||||||
layer = ConfigVarLayer::Speedrun;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearOverride() {
|
|
||||||
checkRegistered();
|
|
||||||
if (layer == ConfigVarLayer::Override) {
|
|
||||||
overrideValue = {};
|
|
||||||
layer = ConfigVarLayer::Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearSpeedrunOverride() override {
|
|
||||||
checkRegistered();
|
|
||||||
if (layer == ConfigVarLayer::Speedrun) {
|
|
||||||
overrideValue = {};
|
|
||||||
layer = ConfigVarLayer::Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using ActionBindConfigVar = ConfigVar<int>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DUSK_CONFIG_VAR_HPP
|
#endif // DUSK_CONFIG_VAR_HPP
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace dusk::crash_reporting {
|
namespace dusk {
|
||||||
|
|
||||||
enum class Consent {
|
void InitializeCrashReporting();
|
||||||
Unavailable,
|
void ShutdownCrashReporting();
|
||||||
Unknown,
|
|
||||||
Given,
|
|
||||||
Revoked,
|
|
||||||
};
|
|
||||||
|
|
||||||
void initialize();
|
} // namespace dusk
|
||||||
void shutdown();
|
|
||||||
Consent get_consent();
|
|
||||||
void set_consent(bool enabled);
|
|
||||||
|
|
||||||
} // namespace dusk::crash_reporting
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef DUSK_DISCORD
|
#ifdef DUSK_DISCORD_RPC
|
||||||
|
|
||||||
namespace dusk::discord {
|
namespace dusk {
|
||||||
|
namespace discord {
|
||||||
|
|
||||||
void initialize();
|
void Initialize();
|
||||||
void run_callbacks();
|
|
||||||
void update_presence();
|
|
||||||
void shutdown();
|
|
||||||
|
|
||||||
} // namespace dusk::discord
|
void RunCallbacks();
|
||||||
|
|
||||||
#endif // DUSK_DISCORD
|
void UpdatePresence();
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DUSK_DISCORD_RPC
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ void rollgoalTableOffset(s16& out_ax, s16& out_az);
|
|||||||
extern bool s_sensor_keep_alive;
|
extern bool s_sensor_keep_alive;
|
||||||
bool get_sensor_keep_alive();
|
bool get_sensor_keep_alive();
|
||||||
void set_sensor_keep_alive(bool value);
|
void set_sensor_keep_alive(bool value);
|
||||||
bool rollgoal_gyro_enabled();
|
|
||||||
} // namespace dusk::gyro
|
} // namespace dusk::gyro
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#ifndef DUSK_IO_HPP
|
#ifndef DUSK_IO_HPP
|
||||||
#define DUSK_IO_HPP
|
#define DUSK_IO_HPP
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// I can't believe it's 2026 and neither SDL (no error codes) nor
|
// I can't believe it's 2026 and neither SDL (no error codes) nor
|
||||||
@@ -16,7 +15,7 @@ namespace dusk::io {
|
|||||||
* Methods on this class throw appropriate C++ exceptions when an error occurs.
|
* Methods on this class throw appropriate C++ exceptions when an error occurs.
|
||||||
*/
|
*/
|
||||||
class FileStream {
|
class FileStream {
|
||||||
FILE* file;
|
void* file;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileStream() noexcept;
|
FileStream() noexcept;
|
||||||
@@ -24,7 +23,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* \brief Take ownership of a FILE* handle.
|
* \brief Take ownership of a FILE* handle.
|
||||||
*/
|
*/
|
||||||
explicit FileStream(FILE* file);
|
explicit FileStream(void* file);
|
||||||
FileStream(const FileStream& other) = delete;
|
FileStream(const FileStream& other) = delete;
|
||||||
FileStream(FileStream&& other) noexcept;
|
FileStream(FileStream&& other) noexcept;
|
||||||
|
|
||||||
@@ -35,11 +34,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
static FileStream OpenRead(const char* utf8Path);
|
static FileStream OpenRead(const char* utf8Path);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Open a file for reading at the given path.
|
|
||||||
*/
|
|
||||||
static FileStream OpenRead(const std::filesystem::path& path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Create a file for writing.
|
* \brief Create a file for writing.
|
||||||
*
|
*
|
||||||
@@ -47,33 +41,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
static FileStream Create(const char* utf8Path);
|
static FileStream Create(const char* utf8Path);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Create a file for writing.
|
|
||||||
*
|
|
||||||
* If there is an existing file, its contents are demolished.
|
|
||||||
*/
|
|
||||||
static FileStream Create(const std::filesystem::path& path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Read the byte contents of a file directly into a vector.
|
* \brief Read the byte contents of a file directly into a vector.
|
||||||
*/
|
*/
|
||||||
static std::vector<u8> ReadAllBytes(const char* utf8Path);
|
static std::vector<u8> ReadAllBytes(const char* utf8Path);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read the byte contents of a file directly into a vector.
|
|
||||||
*/
|
|
||||||
static std::vector<u8> ReadAllBytes(const std::filesystem::path& path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Read the byte contents of a file directly into a vector.
|
* \brief Read the byte contents of a file directly into a vector.
|
||||||
*/
|
*/
|
||||||
static void WriteAllText(const char* utf8Path, std::string_view text);
|
static void WriteAllText(const char* utf8Path, std::string_view text);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read the byte contents of a file directly into a vector.
|
|
||||||
*/
|
|
||||||
static void WriteAllText(const std::filesystem::path& path, std::string_view text);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Read the remaining contents of the file directly into a vector.
|
* \brief Read the remaining contents of the file directly into a vector.
|
||||||
*/
|
*/
|
||||||
@@ -82,24 +59,17 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Get direct access to the underlying FILE* handle.
|
* Get direct access to the underlying FILE* handle.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] void* GetFileHandle() const noexcept { return file; }
|
[[nodiscard]] void* GetFileHandle() const noexcept {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data to the file.
|
* Write data to the file.
|
||||||
*/
|
*/
|
||||||
void Write(const char* data, size_t dataLen);
|
void Write(const char* data, size_t dataLen);
|
||||||
|
|
||||||
FILE* ToInner();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a std::filesystem::path to a std::string, UTF-8, without exploding on Windows.
|
|
||||||
*/
|
|
||||||
inline std::string fs_path_to_string(const std::filesystem::path& path) {
|
|
||||||
const auto u8str = path.u8string();
|
|
||||||
return {reinterpret_cast<const char*>(u8str.c_str())};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dusk::io
|
|
||||||
|
|
||||||
#endif // DUSK_IO_HPP
|
#endif // DUSK_IO_HPP
|
||||||
|
|||||||
@@ -4,22 +4,11 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace dusk {
|
namespace dusk {
|
||||||
|
extern bool IsRunning;
|
||||||
extern bool IsRunning;
|
extern bool IsShuttingDown;
|
||||||
extern bool IsShuttingDown;
|
extern bool IsGameLaunched;
|
||||||
extern bool IsGameLaunched;
|
extern bool IsFocusPaused;
|
||||||
extern bool RestartRequested;
|
extern std::filesystem::path ConfigPath;
|
||||||
extern std::filesystem::path ConfigPath;
|
}
|
||||||
|
|
||||||
#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \
|
|
||||||
(defined(TARGET_OS_TV) && TARGET_OS_TV)
|
|
||||||
inline constexpr bool SupportsProcessRestart = false;
|
|
||||||
#else
|
|
||||||
inline constexpr bool SupportsProcessRestart = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void RequestRestart() noexcept;
|
|
||||||
|
|
||||||
} // namespace dusk
|
|
||||||
|
|
||||||
#endif // DUSK_MAIN_H
|
#endif // DUSK_MAIN_H
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
struct RoomEntry {
|
struct RoomEntry {
|
||||||
u8 roomNo;
|
u8 roomNo;
|
||||||
std::vector<s16> roomPoints = {};
|
std::vector<s16> roomPoints = {};
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
#define _SRC_DUSK_MATH_H_
|
#define _SRC_DUSK_MATH_H_
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <array>
|
||||||
|
#include <limits>
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846f
|
#define M_PI 3.14159265358979323846f
|
||||||
@@ -16,6 +19,139 @@ inline float i_cosf(float x) { return cos(x); }
|
|||||||
inline float i_tanf(float x) { return tan(x); }
|
inline float i_tanf(float x) { return tan(x); }
|
||||||
inline float i_acosf(float x) { return acos(x); }
|
inline float i_acosf(float x) { return acos(x); }
|
||||||
|
|
||||||
#include <dolphin/ppc_math.h>
|
|
||||||
|
// frsqrte matching courtesy of Geotale, with reference to https://achurch.org/cpu-tests/ppc750cl.s
|
||||||
|
|
||||||
|
struct BaseAndDec32 {
|
||||||
|
uint32_t base;
|
||||||
|
int32_t dec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BaseAndDec64 {
|
||||||
|
uint64_t base;
|
||||||
|
int64_t dec;
|
||||||
|
};
|
||||||
|
|
||||||
|
union c32 {
|
||||||
|
constexpr c32(const float p) {
|
||||||
|
f = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr c32(const uint32_t p) {
|
||||||
|
u = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t u;
|
||||||
|
float f;
|
||||||
|
};
|
||||||
|
|
||||||
|
union c64 {
|
||||||
|
constexpr c64(const double p) {
|
||||||
|
f = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr c64(const uint64_t p) {
|
||||||
|
u = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t u;
|
||||||
|
double f;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr uint64_t EXPONENT_SHIFT_F64 = 52;
|
||||||
|
static constexpr uint64_t MANTISSA_MASK_F64 = 0x000fffffffffffffULL;
|
||||||
|
static constexpr uint64_t EXPONENT_MASK_F64 = 0x7ff0000000000000ULL;
|
||||||
|
static constexpr uint64_t SIGN_MASK_F64 = 0x8000000000000000ULL;
|
||||||
|
|
||||||
|
static constexpr std::array<BaseAndDec64, 32> RSQRTE_TABLE = {{
|
||||||
|
{0x69fa000000000ULL, -0x15a0000000LL},
|
||||||
|
{0x5f2e000000000ULL, -0x13cc000000LL},
|
||||||
|
{0x554a000000000ULL, -0x1234000000LL},
|
||||||
|
{0x4c30000000000ULL, -0x10d4000000LL},
|
||||||
|
{0x43c8000000000ULL, -0x0f9c000000LL},
|
||||||
|
{0x3bfc000000000ULL, -0x0e88000000LL},
|
||||||
|
{0x34b8000000000ULL, -0x0d94000000LL},
|
||||||
|
{0x2df0000000000ULL, -0x0cb8000000LL},
|
||||||
|
{0x2794000000000ULL, -0x0bf0000000LL},
|
||||||
|
{0x219c000000000ULL, -0x0b40000000LL},
|
||||||
|
{0x1bfc000000000ULL, -0x0aa0000000LL},
|
||||||
|
{0x16ae000000000ULL, -0x0a0c000000LL},
|
||||||
|
{0x11a8000000000ULL, -0x0984000000LL},
|
||||||
|
{0x0ce6000000000ULL, -0x090c000000LL},
|
||||||
|
{0x0862000000000ULL, -0x0898000000LL},
|
||||||
|
{0x0416000000000ULL, -0x082c000000LL},
|
||||||
|
{0xffe8000000000ULL, -0x1e90000000LL},
|
||||||
|
{0xf0a4000000000ULL, -0x1c00000000LL},
|
||||||
|
{0xe2a8000000000ULL, -0x19c0000000LL},
|
||||||
|
{0xd5c8000000000ULL, -0x17c8000000LL},
|
||||||
|
{0xc9e4000000000ULL, -0x1610000000LL},
|
||||||
|
{0xbedc000000000ULL, -0x1490000000LL},
|
||||||
|
{0xb498000000000ULL, -0x1330000000LL},
|
||||||
|
{0xab00000000000ULL, -0x11f8000000LL},
|
||||||
|
{0xa204000000000ULL, -0x10e8000000LL},
|
||||||
|
{0x9994000000000ULL, -0x0fe8000000LL},
|
||||||
|
{0x91a0000000000ULL, -0x0f08000000LL},
|
||||||
|
{0x8a1c000000000ULL, -0x0e38000000LL},
|
||||||
|
{0x8304000000000ULL, -0x0d78000000LL},
|
||||||
|
{0x7c48000000000ULL, -0x0cc8000000LL},
|
||||||
|
{0x75e4000000000ULL, -0x0c28000000LL},
|
||||||
|
{0x6fd0000000000ULL, -0x0b98000000LL},
|
||||||
|
}};
|
||||||
|
|
||||||
|
[[nodiscard]] static inline double frsqrte(const double val) {
|
||||||
|
c64 bits(val);
|
||||||
|
|
||||||
|
uint64_t mantissa = bits.u & MANTISSA_MASK_F64;
|
||||||
|
int64_t exponent = bits.u & EXPONENT_MASK_F64;
|
||||||
|
bool sign = (bits.u & SIGN_MASK_F64) != 0;
|
||||||
|
|
||||||
|
// Handle 0 case
|
||||||
|
if (mantissa == 0 && exponent == 0) {
|
||||||
|
return std::copysign(std::numeric_limits<double>::infinity(), bits.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle NaN-like
|
||||||
|
if (exponent == EXPONENT_MASK_F64) {
|
||||||
|
if (mantissa == 0) {
|
||||||
|
return sign ? std::numeric_limits<double>::quiet_NaN() : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle negative inputs
|
||||||
|
if (sign) {
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exponent == 0) {
|
||||||
|
// Shift so one bit goes to where the exponent would be,
|
||||||
|
// then clear that bit to mimic a not-subnormal number!
|
||||||
|
// Aka, if there are 12 leading zeroes, shift left once
|
||||||
|
uint32_t shift = std::countl_zero(mantissa) - static_cast<uint32_t>(63 - EXPONENT_SHIFT_F64);
|
||||||
|
|
||||||
|
mantissa <<= shift;
|
||||||
|
mantissa &= MANTISSA_MASK_F64;
|
||||||
|
// The shift is subtracted by 1 because denormals by default
|
||||||
|
// are offset by 1 (exponent 0 doesn't have implied 1 bit)
|
||||||
|
exponent -= static_cast<int64_t>(shift - 1) << EXPONENT_SHIFT_F64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In reality this doesn't get the full exponent -- Only the least significant bit
|
||||||
|
// Only that's needed because square roots of higher exponent bits simply multiply the
|
||||||
|
// result by 2!!
|
||||||
|
uint32_t key = static_cast<uint32_t>((static_cast<uint64_t>(exponent) | mantissa) >> 37);
|
||||||
|
uint64_t new_exp =
|
||||||
|
(static_cast<uint64_t>((0xbfcLL << EXPONENT_SHIFT_F64) - exponent) >> 1) & EXPONENT_MASK_F64;
|
||||||
|
|
||||||
|
// Remove the bits relating to anything higher than the LSB of the exponent
|
||||||
|
const auto &entry = RSQRTE_TABLE[0x1f & (key >> 11)];
|
||||||
|
|
||||||
|
// The result is given by an estimate then an adjustment based on the original
|
||||||
|
// key that was computed
|
||||||
|
uint64_t new_mantissa = static_cast<uint64_t>(entry.base + entry.dec * static_cast<int64_t>(key & 0x7ff));
|
||||||
|
|
||||||
|
return c64(new_exp | new_mantissa).f;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _SRC_DUSK_MATH_H_
|
#endif // _SRC_DUSK_MATH_H_
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#ifndef DUSK_MEMORY_H
|
|
||||||
#define DUSK_MEMORY_H
|
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
#define HEAP_SIZE(original, dusk) (dusk)
|
|
||||||
#else
|
|
||||||
#define HEAP_SIZE(original, dusk) (original)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
#ifndef DUSK_CONFIG_H
|
#ifndef DUSK_CONFIG_H
|
||||||
#define DUSK_CONFIG_H
|
#define DUSK_CONFIG_H
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "dusk/config_var.hpp"
|
#include "dusk/config_var.hpp"
|
||||||
|
|
||||||
namespace dusk {
|
namespace dusk {
|
||||||
@@ -23,17 +21,6 @@ enum class GameLanguage : u8 {
|
|||||||
Italian = OS_LANGUAGE_ITALIAN,
|
Italian = OS_LANGUAGE_ITALIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DiscVerificationState : u8 {
|
|
||||||
Unknown = 0,
|
|
||||||
Success,
|
|
||||||
HashMismatch,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class GyroMode : u8 {
|
|
||||||
Sensor = 0,
|
|
||||||
Mouse = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace config {
|
namespace config {
|
||||||
template <>
|
template <>
|
||||||
struct ConfigEnumRange<BloomMode> {
|
struct ConfigEnumRange<BloomMode> {
|
||||||
@@ -46,18 +33,6 @@ struct ConfigEnumRange<GameLanguage> {
|
|||||||
static constexpr auto min = GameLanguage::English;
|
static constexpr auto min = GameLanguage::English;
|
||||||
static constexpr auto max = GameLanguage::Italian;
|
static constexpr auto max = GameLanguage::Italian;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
struct ConfigEnumRange<DiscVerificationState> {
|
|
||||||
static constexpr auto min = DiscVerificationState::Unknown;
|
|
||||||
static constexpr auto max = DiscVerificationState::HashMismatch;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct ConfigEnumRange<GyroMode> {
|
|
||||||
static constexpr auto min = GyroMode::Sensor;
|
|
||||||
static constexpr auto max = GyroMode::Mouse;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistent user settings
|
// Persistent user settings
|
||||||
@@ -70,8 +45,6 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> enableFullscreen;
|
ConfigVar<bool> enableFullscreen;
|
||||||
ConfigVar<bool> enableVsync;
|
ConfigVar<bool> enableVsync;
|
||||||
ConfigVar<bool> lockAspectRatio;
|
ConfigVar<bool> lockAspectRatio;
|
||||||
ConfigVar<bool> enableFpsOverlay;
|
|
||||||
ConfigVar<int> fpsOverlayCorner;
|
|
||||||
} video;
|
} video;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -82,8 +55,6 @@ struct UserSettings {
|
|||||||
ConfigVar<int> soundEffectsVolume;
|
ConfigVar<int> soundEffectsVolume;
|
||||||
ConfigVar<int> fanfareVolume;
|
ConfigVar<int> fanfareVolume;
|
||||||
ConfigVar<bool> enableReverb;
|
ConfigVar<bool> enableReverb;
|
||||||
ConfigVar<bool> enableHrtf;
|
|
||||||
ConfigVar<bool> menuSounds;
|
|
||||||
} audio;
|
} audio;
|
||||||
|
|
||||||
// Game settings
|
// Game settings
|
||||||
@@ -94,6 +65,7 @@ struct UserSettings {
|
|||||||
// QoL
|
// QoL
|
||||||
ConfigVar<bool> enableQuickTransform;
|
ConfigVar<bool> enableQuickTransform;
|
||||||
ConfigVar<bool> hideTvSettingsScreen;
|
ConfigVar<bool> hideTvSettingsScreen;
|
||||||
|
ConfigVar<bool> skipWarningScreen;
|
||||||
ConfigVar<bool> biggerWallets;
|
ConfigVar<bool> biggerWallets;
|
||||||
ConfigVar<bool> noReturnRupees;
|
ConfigVar<bool> noReturnRupees;
|
||||||
ConfigVar<bool> disableRupeeCutscenes;
|
ConfigVar<bool> disableRupeeCutscenes;
|
||||||
@@ -108,25 +80,16 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> instantSaves;
|
ConfigVar<bool> instantSaves;
|
||||||
ConfigVar<bool> instantText;
|
ConfigVar<bool> instantText;
|
||||||
ConfigVar<bool> sunsSong;
|
ConfigVar<bool> sunsSong;
|
||||||
ConfigVar<bool> autoSave;
|
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
ConfigVar<bool> enableMirrorMode;
|
ConfigVar<bool> enableMirrorMode;
|
||||||
ConfigVar<bool> minimalHUD;
|
ConfigVar<bool> disableMainHUD;
|
||||||
ConfigVar<bool> pauseOnFocusLost;
|
ConfigVar<bool> pauseOnFocusLost;
|
||||||
ConfigVar<bool> enableLinkDollRotation;
|
ConfigVar<bool> enableLinkDollRotation;
|
||||||
ConfigVar<bool> enableAchievementToasts;
|
ConfigVar<bool> enableAchievementNotifications;
|
||||||
ConfigVar<bool> enableControllerToasts;
|
|
||||||
ConfigVar<bool> enableDiscordPresence;
|
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
ConfigVar<bool> enhancedLighting;
|
|
||||||
ConfigVar<bool> enableSpecularLighting;
|
|
||||||
ConfigVar<bool> enableRimLighting;
|
|
||||||
ConfigVar<float> specularIntensity;
|
|
||||||
ConfigVar<float> rimIntensity;
|
|
||||||
ConfigVar<float> ambientLightMultiplier;
|
|
||||||
ConfigVar<float> diffuseLightMultiplier;
|
|
||||||
ConfigVar<BloomMode> bloomMode;
|
ConfigVar<BloomMode> bloomMode;
|
||||||
ConfigVar<float> bloomMultiplier;
|
ConfigVar<float> bloomMultiplier;
|
||||||
ConfigVar<bool> disableWaterRefraction;
|
ConfigVar<bool> disableWaterRefraction;
|
||||||
@@ -135,14 +98,12 @@ struct UserSettings {
|
|||||||
ConfigVar<int> shadowResolutionMultiplier;
|
ConfigVar<int> shadowResolutionMultiplier;
|
||||||
ConfigVar<bool> enableDepthOfField;
|
ConfigVar<bool> enableDepthOfField;
|
||||||
ConfigVar<bool> enableMapBackground;
|
ConfigVar<bool> enableMapBackground;
|
||||||
ConfigVar<bool> disableCutscenePillarboxing;
|
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
ConfigVar<bool> noLowHpSound;
|
ConfigVar<bool> noLowHpSound;
|
||||||
ConfigVar<bool> midnasLamentNonStop;
|
ConfigVar<bool> midnasLamentNonStop;
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
ConfigVar<GyroMode> gyroMode;
|
|
||||||
ConfigVar<bool> enableGyroAim;
|
ConfigVar<bool> enableGyroAim;
|
||||||
ConfigVar<bool> enableGyroRollgoal;
|
ConfigVar<bool> enableGyroRollgoal;
|
||||||
ConfigVar<float> gyroSensitivityX;
|
ConfigVar<float> gyroSensitivityX;
|
||||||
@@ -155,12 +116,7 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> freeCamera;
|
ConfigVar<bool> freeCamera;
|
||||||
ConfigVar<bool> invertCameraXAxis;
|
ConfigVar<bool> invertCameraXAxis;
|
||||||
ConfigVar<bool> invertCameraYAxis;
|
ConfigVar<bool> invertCameraYAxis;
|
||||||
ConfigVar<bool> invertFirstPersonXAxis;
|
|
||||||
ConfigVar<bool> invertFirstPersonYAxis;
|
|
||||||
ConfigVar<float> freeCameraSensitivity;
|
ConfigVar<float> freeCameraSensitivity;
|
||||||
ConfigVar<bool> debugFlyCam;
|
|
||||||
ConfigVar<bool> debugFlyCamLockEvents;
|
|
||||||
ConfigVar<bool> allowBackgroundInput;
|
|
||||||
|
|
||||||
// Cheats
|
// Cheats
|
||||||
ConfigVar<bool> infiniteHearts;
|
ConfigVar<bool> infiniteHearts;
|
||||||
@@ -175,7 +131,6 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> alwaysGreatspin;
|
ConfigVar<bool> alwaysGreatspin;
|
||||||
ConfigVar<bool> enableFastIronBoots;
|
ConfigVar<bool> enableFastIronBoots;
|
||||||
ConfigVar<bool> canTransformAnywhere;
|
ConfigVar<bool> canTransformAnywhere;
|
||||||
ConfigVar<bool> fastRoll;
|
|
||||||
ConfigVar<bool> fastSpinner;
|
ConfigVar<bool> fastSpinner;
|
||||||
ConfigVar<bool> freeMagicArmor;
|
ConfigVar<bool> freeMagicArmor;
|
||||||
|
|
||||||
@@ -184,36 +139,22 @@ struct UserSettings {
|
|||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
ConfigVar<bool> enableTurboKeybind;
|
ConfigVar<bool> enableTurboKeybind;
|
||||||
ConfigVar<bool> enableResetKeybind;
|
|
||||||
|
|
||||||
// Tools
|
// Tools
|
||||||
ConfigVar<bool> speedrunMode;
|
ConfigVar<bool> speedrunMode;
|
||||||
ConfigVar<bool> liveSplitEnabled;
|
ConfigVar<bool> liveSplitEnabled;
|
||||||
ConfigVar<bool> showSpeedrunRTATimer;
|
|
||||||
ConfigVar<bool> recordingMode;
|
|
||||||
ConfigVar<bool> showInputViewer;
|
|
||||||
ConfigVar<bool> showInputViewerGyro;
|
|
||||||
} game;
|
} game;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
ConfigVar<std::string> isoPath;
|
ConfigVar<std::string> isoPath;
|
||||||
ConfigVar<DiscVerificationState> isoVerification;
|
|
||||||
ConfigVar<std::string> graphicsBackend;
|
ConfigVar<std::string> graphicsBackend;
|
||||||
ConfigVar<bool> skipPreLaunchUI;
|
ConfigVar<bool> skipPreLaunchUI;
|
||||||
ConfigVar<bool> showPipelineCompilation;
|
ConfigVar<bool> showPipelineCompilation;
|
||||||
ConfigVar<bool> wasPresetChosen;
|
ConfigVar<bool> wasPresetChosen;
|
||||||
ConfigVar<bool> checkForUpdates;
|
ConfigVar<bool> enableCrashReporting;
|
||||||
|
ConfigVar<bool> duskMenuOpen;
|
||||||
ConfigVar<int> cardFileType;
|
ConfigVar<int> cardFileType;
|
||||||
ConfigVar<bool> enableAdvancedSettings;
|
|
||||||
} backend;
|
} backend;
|
||||||
|
|
||||||
// Arrays of size 4 for 4 ports
|
|
||||||
struct {
|
|
||||||
std::array<ActionBindConfigVar, 4> firstPersonCamera;
|
|
||||||
std::array<ActionBindConfigVar, 4> callMidna;
|
|
||||||
std::array<ActionBindConfigVar, 4> openDusklightMenu;
|
|
||||||
std::array<ActionBindConfigVar, 4> turboSpeedButton;
|
|
||||||
} actionBindings;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
UserSettings& getSettings();
|
UserSettings& getSettings();
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <aurora/aurora.h>
|
|
||||||
|
|
||||||
namespace dusk {
|
|
||||||
|
|
||||||
struct SpeedrunInfo {
|
|
||||||
void startRun() {
|
|
||||||
m_isRunStarted = true;
|
|
||||||
m_startTimestamp = OSGetTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopRun() {
|
|
||||||
m_isRunStarted = false;
|
|
||||||
m_endTimestamp = OSGetTime() - m_startTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
m_isRunStarted = false;
|
|
||||||
m_startTimestamp = 0;
|
|
||||||
m_endTimestamp = 0;
|
|
||||||
m_isPauseIGT = false;
|
|
||||||
m_loadStartTimestamp = 0;
|
|
||||||
m_totalLoadTime = 0;
|
|
||||||
m_igtTimer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool m_isRunStarted = false;
|
|
||||||
OSTime m_startTimestamp = 0;
|
|
||||||
OSTime m_endTimestamp = 0;
|
|
||||||
|
|
||||||
bool m_isPauseIGT = false;
|
|
||||||
OSTime m_loadStartTimestamp = 0;
|
|
||||||
OSTime m_totalLoadTime = 0;
|
|
||||||
OSTime m_igtTimer = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern SpeedrunInfo m_speedrunInfo;
|
|
||||||
|
|
||||||
void resetForSpeedrunMode();
|
|
||||||
|
|
||||||
} // namespace dusk
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace dusk {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Reserve a contiguous virtual address range without committing physical pages
|
||||||
|
void* vmem_reserve(size_t size);
|
||||||
|
|
||||||
|
// Commit physical backing for pages in a previously reserved range, ptr and size should be page-aligned
|
||||||
|
bool vmem_commit(void* ptr, size_t size);
|
||||||
|
|
||||||
|
// Decommit physical pages in a reserved range, releasing RAM without releasing address space
|
||||||
|
void vmem_decommit(void* ptr, size_t size);
|
||||||
|
|
||||||
|
// Release an entire virtual reservation obtained from vmem_reserve
|
||||||
|
void vmem_release(void* ptr, size_t size);
|
||||||
|
|
||||||
|
// Returns the OS page size
|
||||||
|
size_t vmem_page_size();
|
||||||
|
|
||||||
|
// Shared vmem arena
|
||||||
|
// All JKR heap vmem reservations are sub-allocated from a single large reservation,
|
||||||
|
// keeping the total entry count at 1 regardless of how many heaps exist
|
||||||
|
|
||||||
|
// Must be called once before any JKR heap is created
|
||||||
|
void vmem_arena_init();
|
||||||
|
|
||||||
|
// Allocate a slot of size bytes (page-aligned) from the arena
|
||||||
|
void* vmem_arena_alloc(size_t size);
|
||||||
|
|
||||||
|
// Return a slot to the arena and decommit its physical pages
|
||||||
|
void vmem_arena_free(void* ptr, size_t size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // namespace dusk
|
||||||
|
|
||||||
|
// Total virtual address space reserved for the shared JKR heap arena
|
||||||
|
inline constexpr size_t JKR_VMEM_ARENA_SIZE = 128ULL * 1024 * 1024 * 1024; // 128 GB
|
||||||
|
|
||||||
|
// Virtual address space reserved per JKR heap (one slot in the shared arena)
|
||||||
|
inline constexpr size_t JKR_HEAP_VIRTUAL_RESERVE = 64ULL * 1024 * 1024; // 64 MB
|
||||||
|
|
||||||
|
// Minimum growth increment when a JKR heap expands into reserved but uncommitted pages
|
||||||
|
inline constexpr size_t JKR_HEAP_GROW_CHUNK = 4ULL * 1024 * 1024; // 4 MB
|
||||||
|
|
||||||
|
// Maximum number of free slots the arena can track (= total slots in the arena)
|
||||||
|
inline constexpr size_t JKR_VMEM_MAX_FREE_SLOTS = JKR_VMEM_ARENA_SIZE / JKR_HEAP_VIRTUAL_RESERVE;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
#include "Z2AudioLib/Z2EnvSeMgr.h"
|
#include "Z2AudioLib/Z2EnvSeMgr.h"
|
||||||
#include "Z2AudioLib/Z2LinkMgr.h"
|
#include "Z2AudioLib/Z2LinkMgr.h"
|
||||||
#include "dusk/audio.h"
|
#include "dusk/audio.h"
|
||||||
#include "dusk/settings.h"
|
|
||||||
|
|
||||||
class mDoAud_zelAudio_c : public Z2AudioMgr {
|
class mDoAud_zelAudio_c : public Z2AudioMgr {
|
||||||
public:
|
public:
|
||||||
@@ -133,18 +132,6 @@ inline void mDoAud_seStart(u32 i_sfxID, const Vec* i_sePos, u32 param_2, s8 i_re
|
|||||||
-1.0f, -1.0f, 0);
|
-1.0f, -1.0f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
inline void mDoAud_seStartMenu(u32 i_sfxID) {
|
|
||||||
if (!mDoAud_zelAudio_c::isInitFlag()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!dusk::getSettings().audio.menuSounds.getValue()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mDoAud_seStart(i_sfxID, nullptr, 0, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline void mDoAud_seStartLevel(u32 i_sfxID, const Vec* i_sePos, u32 param_2, s8 i_reverb) {
|
inline void mDoAud_seStartLevel(u32 i_sfxID, const Vec* i_sePos, u32 param_2, s8 i_reverb) {
|
||||||
DUSK_AUDIO_SKIP()
|
DUSK_AUDIO_SKIP()
|
||||||
Z2AudioMgr::getInterface()->seStartLevel(i_sfxID, i_sePos, param_2, i_reverb, 1.0f, 1.0f,
|
Z2AudioMgr::getInterface()->seStartLevel(i_sfxID, i_sePos, param_2, i_reverb, 1.0f, 1.0f,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#ifndef J3DSTRUCT_H
|
#ifndef J3DSTRUCT_H
|
||||||
#define J3DSTRUCT_H
|
#define J3DSTRUCT_H
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <gx.h>
|
#include <gx.h>
|
||||||
#include <mtx.h>
|
#include <mtx.h>
|
||||||
|
#include <mtx.h>
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "JSystem/JMath/JMath.h"
|
#include "JSystem/JMath/JMath.h"
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DLightInfo {
|
struct J3DLightInfo {
|
||||||
bool operator==(J3DLightInfo& other) const;
|
bool operator==(J3DLightInfo& other) const;
|
||||||
@@ -28,7 +28,7 @@ struct J3DLightInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTextureSRTInfo {
|
struct J3DTextureSRTInfo {
|
||||||
// NOTE: Big endian when loaded from file!
|
// NOTE: Big endian when loaded from file!
|
||||||
@@ -79,7 +79,7 @@ enum J3DTexMtxMode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTexMtxInfo {
|
struct J3DTexMtxInfo {
|
||||||
bool operator==(J3DTexMtxInfo& other) const;
|
bool operator==(J3DTexMtxInfo& other) const;
|
||||||
@@ -97,7 +97,7 @@ struct J3DTexMtxInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DIndTexMtxInfo {
|
struct J3DIndTexMtxInfo {
|
||||||
J3DIndTexMtxInfo& operator=(J3DIndTexMtxInfo const&);
|
J3DIndTexMtxInfo& operator=(J3DIndTexMtxInfo const&);
|
||||||
@@ -107,7 +107,7 @@ struct J3DIndTexMtxInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DFogInfo {
|
struct J3DFogInfo {
|
||||||
bool operator==(J3DFogInfo&) const;
|
bool operator==(J3DFogInfo&) const;
|
||||||
@@ -126,7 +126,7 @@ struct J3DFogInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DNBTScaleInfo {
|
struct J3DNBTScaleInfo {
|
||||||
bool operator==(const J3DNBTScaleInfo& other) const;
|
bool operator==(const J3DNBTScaleInfo& other) const;
|
||||||
@@ -153,7 +153,7 @@ struct J3DIndTexOrderInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTevSwapModeInfo {
|
struct J3DTevSwapModeInfo {
|
||||||
/* 0x0 */ u8 mRasSel;
|
/* 0x0 */ u8 mRasSel;
|
||||||
@@ -164,7 +164,7 @@ struct J3DTevSwapModeInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTevSwapModeTableInfo {
|
struct J3DTevSwapModeTableInfo {
|
||||||
/* 0x0 */ u8 field_0x0;
|
/* 0x0 */ u8 field_0x0;
|
||||||
@@ -175,7 +175,7 @@ struct J3DTevSwapModeTableInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTevStageInfo {
|
struct J3DTevStageInfo {
|
||||||
/* 0x0 */ u8 field_0x0;
|
/* 0x0 */ u8 field_0x0;
|
||||||
@@ -202,7 +202,7 @@ struct J3DTevStageInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DIndTevStageInfo {
|
struct J3DIndTevStageInfo {
|
||||||
/* 0x0 */ u8 mIndStage;
|
/* 0x0 */ u8 mIndStage;
|
||||||
@@ -219,7 +219,7 @@ struct J3DIndTevStageInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTexCoordInfo {
|
struct J3DTexCoordInfo {
|
||||||
/* 0x0 */ u8 mTexGenType;
|
/* 0x0 */ u8 mTexGenType;
|
||||||
@@ -265,7 +265,7 @@ struct J3DBlendInfo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup jsystem-j3d
|
* @ingroup jsystem-j3d
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct J3DTevOrderInfo {
|
struct J3DTevOrderInfo {
|
||||||
void operator=(const J3DTevOrderInfo& other) {
|
void operator=(const J3DTevOrderInfo& other) {
|
||||||
|
|||||||
@@ -59,9 +59,6 @@ public:
|
|||||||
bool isActive() const { return mSeqList.getNumLinks() != 0; }
|
bool isActive() const { return mSeqList.getNumLinks() != 0; }
|
||||||
int getNumActiveSeqs() const { return mSeqList.getNumLinks(); }
|
int getNumActiveSeqs() const { return mSeqList.getNumLinks(); }
|
||||||
void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; }
|
void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; }
|
||||||
#if TARGET_PC
|
|
||||||
JSUList<JAISeq>* getSeqList() { return &mSeqList; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* 0x08 */ JAIAudience* mAudience;
|
/* 0x08 */ JAIAudience* mAudience;
|
||||||
|
|||||||
@@ -127,6 +127,13 @@ public:
|
|||||||
[[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; }
|
[[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; }
|
||||||
[[nodiscard]] CMemBlock* getUsedHead() { return mHeadUsedList; }
|
[[nodiscard]] CMemBlock* getUsedHead() { return mHeadUsedList; }
|
||||||
[[nodiscard]] const CMemBlock* getUsedHead() const { return mHeadUsedList; }
|
[[nodiscard]] const CMemBlock* getUsedHead() const { return mHeadUsedList; }
|
||||||
|
|
||||||
|
void* mVmemBase; // base of VM reservation
|
||||||
|
size_t mVmemCapacity; // total reserved bytes
|
||||||
|
size_t mVmemCommitted; // page-aligned committed bytes so far
|
||||||
|
|
||||||
|
// Commit more pages and splice them into the free list
|
||||||
|
bool growHeap(u32 needed);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,15 @@ public:
|
|||||||
static JKRSolidHeap* create(u32, JKRHeap*, bool);
|
static JKRSolidHeap* create(u32, JKRHeap*, bool);
|
||||||
|
|
||||||
static void* getState_(TState* state) { return getState_buf_(state); }
|
static void* getState_(TState* state) { return getState_buf_(state); }
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
void* mVmemBase; // base of VM reservation
|
||||||
|
size_t mVmemCapacity; // total reserved bytes
|
||||||
|
size_t mVmemCommitted; // page-aligned committed bytes so far
|
||||||
|
|
||||||
|
// Commit more pages and extend the free region
|
||||||
|
bool growHeap(u32 needed);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
inline JKRSolidHeap* JKRCreateSolidHeap(u32 param_0, JKRHeap* heap, bool param_2) {
|
inline JKRSolidHeap* JKRCreateSolidHeap(u32 param_0, JKRHeap* heap, bool param_2) {
|
||||||
|
|||||||
@@ -207,11 +207,4 @@ void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
|
|||||||
void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*);
|
void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*);
|
||||||
void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
|
void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void JPAInterpBillboard(JPAEmitterWorkData*, JPABaseParticle*);
|
|
||||||
void JPAInterpRotBillboard(JPAEmitterWorkData*, JPABaseParticle*);
|
|
||||||
void JPAInterpDirection(JPAEmitterWorkData*, JPABaseParticle*);
|
|
||||||
void JPAInterpRotDirection(JPAEmitterWorkData*, JPABaseParticle*);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* JPABASESHAPE_H */
|
#endif /* JPABASESHAPE_H */
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ public:
|
|||||||
void init_c(JPAEmitterWorkData*, JPABaseParticle*);
|
void init_c(JPAEmitterWorkData*, JPABaseParticle*);
|
||||||
bool calc_p(JPAEmitterWorkData*);
|
bool calc_p(JPAEmitterWorkData*);
|
||||||
bool calc_c(JPAEmitterWorkData*);
|
bool calc_c(JPAEmitterWorkData*);
|
||||||
#if TARGET_PC
|
|
||||||
void interp(JPAEmitterWorkData*, void const* drawFunc);
|
|
||||||
#endif
|
|
||||||
bool canCreateChild(JPAEmitterWorkData*);
|
bool canCreateChild(JPAEmitterWorkData*);
|
||||||
f32 getWidth(JPABaseEmitter const*) const;
|
f32 getWidth(JPABaseEmitter const*) const;
|
||||||
f32 getHeight(JPABaseEmitter const*) const;
|
f32 getHeight(JPABaseEmitter const*) const;
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ public:
|
|||||||
JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); }
|
JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); }
|
||||||
u16 getNumColors() const { return mNumColors; }
|
u16 getNumColors() const { return mNumColors; }
|
||||||
ResTLUT* getColorTable() const { return mColorTable; }
|
ResTLUT* getColorTable() const { return mColorTable; }
|
||||||
#if TARGET_PC
|
|
||||||
void dataUploaded();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* 0x00 */ GXTlutObj mTlutObj;
|
/* 0x00 */ GXTlutObj mTlutObj;
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ public:
|
|||||||
s32 getTransparency() const { return mTexInfo->alphaEnabled; }
|
s32 getTransparency() const { return mTexInfo->alphaEnabled; }
|
||||||
s32 getWidth() const { return mTexInfo->width; }
|
s32 getWidth() const { return mTexInfo->width; }
|
||||||
s32 getHeight() const { return mTexInfo->height; }
|
s32 getHeight() const { return mTexInfo->height; }
|
||||||
JUTPalette* getPalette() const { return mPalette; }
|
|
||||||
void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
|
void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
|
||||||
bool getCaptureFlag() const { return mFlags & 1; }
|
bool getCaptureFlag() const { return mFlags & 1; }
|
||||||
bool getEmbPaletteDelFlag() const { return mFlags & 2; }
|
bool getEmbPaletteDelFlag() const { return mFlags & 2; }
|
||||||
@@ -83,7 +82,7 @@ public:
|
|||||||
int getTlutName() const { return mTlutName; }
|
int getTlutName() const { return mTlutName; }
|
||||||
bool operator==(const JUTTexture& other) {
|
bool operator==(const JUTTexture& other) {
|
||||||
return mTexInfo == other.mTexInfo
|
return mTexInfo == other.mTexInfo
|
||||||
&& mPalette == other.mPalette
|
&& field_0x2c == other.field_0x2c
|
||||||
&& mWrapS == other.mWrapS
|
&& mWrapS == other.mWrapS
|
||||||
&& mWrapT == other.mWrapT
|
&& mWrapT == other.mWrapT
|
||||||
&& mMinFilter == other.mMinFilter
|
&& mMinFilter == other.mMinFilter
|
||||||
@@ -101,7 +100,7 @@ private:
|
|||||||
/* 0x20 */ const ResTIMG* mTexInfo;
|
/* 0x20 */ const ResTIMG* mTexInfo;
|
||||||
/* 0x24 */ void* mTexData;
|
/* 0x24 */ void* mTexData;
|
||||||
/* 0x28 */ JUTPalette* mEmbPalette;
|
/* 0x28 */ JUTPalette* mEmbPalette;
|
||||||
/* 0x2C */ JUTPalette* mPalette;
|
/* 0x2C */ JUTPalette* field_0x2c;
|
||||||
/* 0x30 */ u8 mWrapS;
|
/* 0x30 */ u8 mWrapS;
|
||||||
/* 0x31 */ u8 mWrapT;
|
/* 0x31 */ u8 mWrapT;
|
||||||
/* 0x32 */ u8 mMinFilter;
|
/* 0x32 */ u8 mMinFilter;
|
||||||
|
|||||||
@@ -556,8 +556,8 @@ void J3DModelLoader::readVertexData(const J3DVertexBlock& block, J3DVertexData&
|
|||||||
|
|
||||||
if (attr == GX_VA_POS) {
|
if (attr == GX_VA_POS) {
|
||||||
// can be a little off due to 0x20 alignment, account for that
|
// can be a little off due to 0x20 alignment, account for that
|
||||||
// u32 expect = ((data.mVtxNum * vertStride) + 0x1F) & ~0x1F;
|
u32 expect = ((data.mVtxNum * vertStride) + 0x1F) & ~0x1F;
|
||||||
// JUT_ASSERT(1234, expect == addrDiff);
|
JUT_ASSERT(1234, expect == addrDiff);
|
||||||
} else if (attr == GX_VA_NRM) {
|
} else if (attr == GX_VA_NRM) {
|
||||||
data.mNrmNum = num;
|
data.mNrmNum = num;
|
||||||
} else if (attr == GX_VA_CLR0) {
|
} else if (attr == GX_VA_CLR0) {
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include "JSystem/JAudio2/JASChannel.h"
|
#include "JSystem/JAudio2/JASChannel.h"
|
||||||
#if TARGET_PC
|
|
||||||
#include "dusk/audio/DuskDsp.hpp"
|
|
||||||
#endif
|
|
||||||
#include "JSystem/JAudio2/JASAiCtrl.h"
|
#include "JSystem/JAudio2/JASAiCtrl.h"
|
||||||
#include "JSystem/JAudio2/JASCalc.h"
|
#include "JSystem/JAudio2/JASCalc.h"
|
||||||
#include "JSystem/JAudio2/JASDriverIF.h"
|
#include "JSystem/JAudio2/JASDriverIF.h"
|
||||||
@@ -173,12 +170,7 @@ void JASChannel::updateEffectorParam(JASDsp::TChannel* i_channel, u16* i_mixerVo
|
|||||||
|
|
||||||
f32 pan = 0.5f;
|
f32 pan = 0.5f;
|
||||||
f32 dolby = 0.0f;
|
f32 dolby = 0.0f;
|
||||||
#if TARGET_PC
|
switch (JASDriver::getOutputMode()) {
|
||||||
u32 effectiveOutputMode = dusk::audio::EnableHrtf ? JAS_OUTPUT_SURROUND : JASDriver::getOutputMode();
|
|
||||||
#else
|
|
||||||
u32 effectiveOutputMode = JASDriver::getOutputMode();
|
|
||||||
#endif
|
|
||||||
switch (effectiveOutputMode) {
|
|
||||||
case JAS_OUTPUT_MONO:
|
case JAS_OUTPUT_MONO:
|
||||||
break;
|
break;
|
||||||
case JAS_OUTPUT_STEREO:
|
case JAS_OUTPUT_STEREO:
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ void JASKernel::setupRootHeap(JKRSolidHeap* heap, u32 size) {
|
|||||||
JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap");
|
JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap");
|
||||||
JUT_ASSERT(787, sSystemHeap);
|
JUT_ASSERT(787, sSystemHeap);
|
||||||
sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>;
|
sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>;
|
||||||
|
JKRHEAP_NAME(sSystemHeap, "JASKernel::sCommandHeap");
|
||||||
JUT_ASSERT(790, sCommandHeap);
|
JUT_ASSERT(790, sCommandHeap);
|
||||||
JASDram = heap;
|
JASDram = heap;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -442,7 +442,6 @@ static JAUSectionHeap* JAUNewSectionHeap(JKRSolidHeap* heap, bool param_1) {
|
|||||||
JAUSectionHeap* JAUNewSectionHeap(bool param_0) {
|
JAUSectionHeap* JAUNewSectionHeap(bool param_0) {
|
||||||
s32 freeSize = JASDram->getFreeSize();
|
s32 freeSize = JASDram->getFreeSize();
|
||||||
JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true);
|
JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true);
|
||||||
JKRHEAP_NAME(sectionHeap, "sectionHeap");
|
|
||||||
JUT_ASSERT(821, sectionHeap);
|
JUT_ASSERT(821, sectionHeap);
|
||||||
return JAUNewSectionHeap(sectionHeap, param_0);
|
return JAUNewSectionHeap(sectionHeap, param_0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,11 @@
|
|||||||
#include "JSystem/JUtility/JUTConsole.h"
|
#include "JSystem/JUtility/JUTConsole.h"
|
||||||
#include "JSystem/JUtility/JUTException.h"
|
#include "JSystem/JUtility/JUTException.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#if TARGET_PC
|
||||||
|
#include "dusk/vmem.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "dusk/logging.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) {
|
JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) {
|
||||||
JKRExpHeap* heap = NULL;
|
JKRExpHeap* heap = NULL;
|
||||||
@@ -71,21 +76,49 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
|
|||||||
|
|
||||||
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
||||||
|
|
||||||
if (alignedSize < expHeapSize + blockSize)
|
if (alignedSize < expHeapSize + blockSize) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
|
#if TARGET_PC
|
||||||
u8* dataPtr = (memory + expHeapSize);
|
u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
|
||||||
|
if (!vmemBase) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t pageSize = dusk::vmem_page_size();
|
||||||
|
size_t commitSize = ALIGN_NEXT((size_t)alignedSize, pageSize);
|
||||||
|
if (!dusk::vmem_commit(vmemBase, commitSize)) {
|
||||||
|
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* memory = vmemBase;
|
||||||
|
u8* dataPtr = memory + expHeapSize;
|
||||||
|
|
||||||
|
newHeap = JKR_NEW_ARGS(memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
|
||||||
|
if (newHeap == NULL) {
|
||||||
|
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newHeap->mVmemBase = vmemBase;
|
||||||
|
newHeap->mVmemCapacity = JKR_HEAP_VIRTUAL_RESERVE;
|
||||||
|
newHeap->mVmemCommitted = commitSize;
|
||||||
|
#else
|
||||||
|
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
|
||||||
|
u8* dataPtr = memory + expHeapSize;
|
||||||
if (!memory) {
|
if (!memory) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
newHeap = JKR_NEW_ARGS (memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
|
newHeap = JKR_NEW_ARGS(memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
|
||||||
|
|
||||||
if (newHeap == NULL) {
|
if (newHeap == NULL) {
|
||||||
JKRFree(memory);
|
JKRFree(memory);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (newHeap) {
|
if (newHeap) {
|
||||||
u8* local_30 = dataPtr + sizeof(CMemBlock);
|
u8* local_30 = dataPtr + sizeof(CMemBlock);
|
||||||
@@ -102,9 +135,16 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
|
|||||||
JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) {
|
JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) {
|
||||||
JKRHeap* parent2;
|
JKRHeap* parent2;
|
||||||
if (parent == NULL) {
|
if (parent == NULL) {
|
||||||
|
#if TARGET_PC
|
||||||
|
// VM-backed heaps live outside the root heap's address range, so find() fails
|
||||||
|
// findAllHeap() searches the full tree
|
||||||
|
parent2 = getRootHeap()->findAllHeap(ptr);
|
||||||
|
#else
|
||||||
parent2 = getRootHeap()->find(ptr);
|
parent2 = getRootHeap()->find(ptr);
|
||||||
if (!parent2)
|
#endif
|
||||||
|
if (!parent2) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
parent2 = parent;
|
parent2 = parent;
|
||||||
}
|
}
|
||||||
@@ -136,6 +176,15 @@ JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorF
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JKRExpHeap::do_destroy() {
|
void JKRExpHeap::do_destroy() {
|
||||||
|
#if TARGET_PC
|
||||||
|
if (mVmemBase) {
|
||||||
|
void* vmemBase = mVmemBase;
|
||||||
|
size_t vmemCapacity = mVmemCapacity;
|
||||||
|
this->~JKRExpHeap();
|
||||||
|
dusk::vmem_arena_free(vmemBase, vmemCapacity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (!field_0x6e) {
|
if (!field_0x6e) {
|
||||||
JKRHeap* heap = getParent();
|
JKRHeap* heap = getParent();
|
||||||
if (heap) {
|
if (heap) {
|
||||||
@@ -163,6 +212,11 @@ JKRExpHeap::JKRExpHeap(void* data, u32 size, JKRHeap* parent, bool errorFlag)
|
|||||||
mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0);
|
mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0);
|
||||||
mHeadUsedList = NULL;
|
mHeadUsedList = NULL;
|
||||||
mTailUsedList = NULL;
|
mTailUsedList = NULL;
|
||||||
|
#if TARGET_PC
|
||||||
|
mVmemBase = nullptr;
|
||||||
|
mVmemCapacity = 0;
|
||||||
|
mVmemCommitted = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JKRExpHeap::~JKRExpHeap() {
|
JKRExpHeap::~JKRExpHeap() {
|
||||||
@@ -214,6 +268,24 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
|
if (!ptr && mVmemBase) {
|
||||||
|
// Heap is full, commit the next chunk of reserved VM and retry
|
||||||
|
if (growHeap(size)) {
|
||||||
|
if (alignment >= 0) {
|
||||||
|
if (alignment <= 4) {
|
||||||
|
ptr = allocFromHead(size);
|
||||||
|
} else {
|
||||||
|
ptr = allocFromHead(size, alignment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (-alignment <= 4) {
|
||||||
|
ptr = allocFromTail(size);
|
||||||
|
} else {
|
||||||
|
ptr = allocFromTail(size, -alignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
// Allocation failed.
|
// Allocation failed.
|
||||||
OSReport_Error(
|
OSReport_Error(
|
||||||
@@ -222,11 +294,16 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
|||||||
OSReport_Error("Free block list as follows:\n");
|
OSReport_Error("Free block list as follows:\n");
|
||||||
OSReport_Error("Start | End | Size \n");
|
OSReport_Error("Start | End | Size \n");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) {
|
for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) {
|
||||||
if (block->mMagic) {
|
if (block->mMagic) {
|
||||||
// Allocated, ignore.
|
// Allocated, ignore.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (i++ > 10) {
|
||||||
|
OSReport_Error("<more>\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto blockStart = (uintptr_t)block - (uintptr_t)mStart;
|
auto blockStart = (uintptr_t)block - (uintptr_t)mStart;
|
||||||
auto blockEnd = (uintptr_t)block + block->size - (uintptr_t)mStart;
|
auto blockEnd = (uintptr_t)block + block->size - (uintptr_t)mStart;
|
||||||
@@ -234,14 +311,6 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
|||||||
OSReport_Error("%08X | %08X | %08X\n", (u32) blockStart, (u32) blockEnd, (u32) blockSize);
|
OSReport_Error("%08X | %08X | %08X\n", (u32) blockStart, (u32) blockEnd, (u32) blockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
OSReport_Error("Child heaps as follows:\n");
|
|
||||||
OSReport_Error("Start | End | Name \n");
|
|
||||||
|
|
||||||
const JSUTree<JKRHeap>& tree = getHeapTree();
|
|
||||||
for (JSUTreeIterator iter(tree.getFirstChild()); iter != tree.getEndChild(); ++iter) {
|
|
||||||
OSReport_Error("%08X | %08X | %s\n", iter->getStartAddr(), iter->getEndAddr(), iter->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
CRASH("Aborting due to allocation failure!");
|
CRASH("Aborting due to allocation failure!");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -494,6 +563,49 @@ static void dummy() {
|
|||||||
OS_REPORT("newSize > 0");
|
OS_REPORT("newSize > 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
bool JKRExpHeap::growHeap(u32 needed) {
|
||||||
|
// Determine how much to commit
|
||||||
|
// Always grow by at least JKR_HEAP_GROW_CHUNK
|
||||||
|
const size_t pageSize = dusk::vmem_page_size();
|
||||||
|
size_t wantBytes = (size_t)needed + sizeof(CMemBlock);
|
||||||
|
size_t growAmount = std::max(wantBytes, JKR_HEAP_GROW_CHUNK);
|
||||||
|
growAmount = ALIGN_NEXT(growAmount, pageSize);
|
||||||
|
|
||||||
|
size_t remaining = mVmemCapacity - mVmemCommitted;
|
||||||
|
if (growAmount > remaining) {
|
||||||
|
// Clamp to whatever reservation is left
|
||||||
|
growAmount = ALIGN_PREV(remaining, pageSize);
|
||||||
|
if (growAmount < wantBytes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* commitBase = (u8*)mVmemBase + mVmemCommitted;
|
||||||
|
if (!dusk::vmem_commit(commitBase, growAmount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Splice the new committed region into the free list as a single block at mEnd
|
||||||
|
CMemBlock* newBlock = (CMemBlock*)mEnd;
|
||||||
|
newBlock->size = (u32)(growAmount - sizeof(CMemBlock));
|
||||||
|
newBlock->mFlags = 0;
|
||||||
|
|
||||||
|
mEnd = (u8*)mEnd + growAmount;
|
||||||
|
mSize += (u32)growAmount;
|
||||||
|
mVmemCommitted += growAmount;
|
||||||
|
|
||||||
|
recycleFreeBlock(newBlock);
|
||||||
|
|
||||||
|
DuskLog.debug("[JKRExpHeap] '{}' grew by {} MB (committed: {} MB / reserved: {} MB)\n",
|
||||||
|
getName(),
|
||||||
|
growAmount / (1024 * 1024),
|
||||||
|
mVmemCommitted / (1024 * 1024),
|
||||||
|
mVmemCapacity / (1024 * 1024));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void JKRExpHeap::do_freeAll() {
|
void JKRExpHeap::do_freeAll() {
|
||||||
lock();
|
lock();
|
||||||
JKRHeap::callAllDisposer();
|
JKRHeap::callAllDisposer();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include "JSystem/JKernel/JKRSolidHeap.h"
|
#include "JSystem/JKernel/JKRSolidHeap.h"
|
||||||
#include "JSystem/JGadget/binary.h"
|
#include "JSystem/JGadget/binary.h"
|
||||||
@@ -7,6 +7,11 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#if TARGET_PC
|
||||||
|
#include "dusk/vmem.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "dusk/logging.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler) {
|
JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler) {
|
||||||
if (!heap) {
|
if (!heap) {
|
||||||
@@ -19,18 +24,56 @@ JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
||||||
if (alignedSize < solidHeapSize)
|
if (alignedSize < solidHeapSize) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
|
||||||
|
if (!vmemBase) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const size_t pageSize = dusk::vmem_page_size();
|
||||||
|
size_t commitSize = ALIGN_NEXT((size_t)alignedSize, pageSize);
|
||||||
|
if (!dusk::vmem_commit(vmemBase, commitSize)) {
|
||||||
|
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* mem = vmemBase;
|
||||||
|
void* dataPtr = mem + solidHeapSize;
|
||||||
|
|
||||||
|
JKRSolidHeap* newHeap = JKR_NEW_ARGS(mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
|
||||||
|
if (newHeap == NULL) {
|
||||||
|
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newHeap->mVmemBase = vmemBase;
|
||||||
|
newHeap->mVmemCapacity = JKR_HEAP_VIRTUAL_RESERVE;
|
||||||
|
newHeap->mVmemCommitted = commitSize;
|
||||||
|
return newHeap;
|
||||||
|
#else
|
||||||
u8* mem = (u8*)JKRAllocFromHeap(heap, alignedSize, 0x10);
|
u8* mem = (u8*)JKRAllocFromHeap(heap, alignedSize, 0x10);
|
||||||
void* dataPtr = mem + solidHeapSize;
|
void* dataPtr = mem + solidHeapSize;
|
||||||
if (!mem)
|
if (!mem) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
|
return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void JKRSolidHeap::do_destroy(void) {
|
void JKRSolidHeap::do_destroy(void) {
|
||||||
|
#if TARGET_PC
|
||||||
|
if (mVmemBase) {
|
||||||
|
void* vmemBase = mVmemBase;
|
||||||
|
size_t vmemCapacity = mVmemCapacity;
|
||||||
|
this->~JKRSolidHeap();
|
||||||
|
dusk::vmem_arena_free(vmemBase, vmemCapacity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
JKRHeap* parent = getParent();
|
JKRHeap* parent = getParent();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
this->~JKRSolidHeap();
|
this->~JKRSolidHeap();
|
||||||
@@ -44,6 +87,11 @@ JKRSolidHeap::JKRSolidHeap(void* start, u32 size, JKRHeap* parent, bool useError
|
|||||||
mSolidHead = (u8*)mStart;
|
mSolidHead = (u8*)mStart;
|
||||||
mSolidTail = (u8*)mEnd;
|
mSolidTail = (u8*)mEnd;
|
||||||
field_0x78 = NULL;
|
field_0x78 = NULL;
|
||||||
|
#if TARGET_PC
|
||||||
|
mVmemBase = nullptr;
|
||||||
|
mVmemCapacity = 0;
|
||||||
|
mVmemCommitted = 0;
|
||||||
|
#endif
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (mDebugFill) {
|
if (mDebugFill) {
|
||||||
JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE);
|
JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE);
|
||||||
@@ -59,6 +107,15 @@ s32 JKRSolidHeap::adjustSize(void) {
|
|||||||
int r25 = 0;
|
int r25 = 0;
|
||||||
JKRHeap* parent = getParent();
|
JKRHeap* parent = getParent();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
#if TARGET_PC
|
||||||
|
if (mVmemBase) {
|
||||||
|
// VM-backed heap, can't resize in parent, but this is not a failure
|
||||||
|
// Return what the trimmed size would have been so the caller doesn't log an error
|
||||||
|
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
|
||||||
|
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
|
||||||
|
return (s32)(thisSize + newSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
lock();
|
lock();
|
||||||
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
|
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
|
||||||
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
|
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
|
||||||
@@ -110,6 +167,11 @@ void* JKRSolidHeap::allocFromHead(u32 size, int alignment) {
|
|||||||
void* ptr = NULL;
|
void* ptr = NULL;
|
||||||
uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1);
|
uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1);
|
||||||
u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead);
|
u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead);
|
||||||
|
#if TARGET_PC
|
||||||
|
if (totalSize > mFreeSize && mVmemBase) {
|
||||||
|
growHeap(totalSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (totalSize <= mFreeSize) {
|
if (totalSize <= mFreeSize) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (mCheckMemoryFilled) {
|
if (mCheckMemoryFilled) {
|
||||||
@@ -137,6 +199,15 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
|
|||||||
void* ptr = NULL;
|
void* ptr = NULL;
|
||||||
uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
|
uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
|
||||||
u32 totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
|
u32 totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
|
||||||
|
#if TARGET_PC
|
||||||
|
if (totalSize > mFreeSize && mVmemBase) {
|
||||||
|
if (growHeap(totalSize)) {
|
||||||
|
// mSolidTail moved to new mEnd; recompute from the new tail position
|
||||||
|
alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
|
||||||
|
totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (totalSize <= mFreeSize) {
|
if (totalSize <= mFreeSize) {
|
||||||
ptr = (void*)alignedStart;
|
ptr = (void*)alignedStart;
|
||||||
mSolidTail -= totalSize;
|
mSolidTail -= totalSize;
|
||||||
@@ -158,6 +229,47 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
bool JKRSolidHeap::growHeap(u32 needed) {
|
||||||
|
// Growth is only safe when no tail allocations exist yet
|
||||||
|
if (mSolidTail != mEnd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t pageSize = dusk::vmem_page_size();
|
||||||
|
size_t wantBytes = (size_t)needed;
|
||||||
|
size_t growAmount = std::max(wantBytes, JKR_HEAP_GROW_CHUNK);
|
||||||
|
growAmount = ALIGN_NEXT(growAmount, pageSize);
|
||||||
|
|
||||||
|
size_t remaining = mVmemCapacity - mVmemCommitted;
|
||||||
|
if (growAmount > remaining) {
|
||||||
|
growAmount = ALIGN_PREV(remaining, pageSize);
|
||||||
|
if (growAmount < wantBytes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* commitBase = (u8*)mVmemBase + mVmemCommitted;
|
||||||
|
if (!dusk::vmem_commit(commitBase, growAmount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend the heap end and the tail pointer
|
||||||
|
mEnd = (u8*)mEnd + growAmount;
|
||||||
|
mSolidTail = mEnd;
|
||||||
|
mFreeSize += (u32)growAmount;
|
||||||
|
mSize += (u32)growAmount;
|
||||||
|
mVmemCommitted += growAmount;
|
||||||
|
|
||||||
|
DuskLog.debug("[JKRSolidHeap] '{}' grew by {} MB (committed: {} MB / reserved: {} MB)\n",
|
||||||
|
getName(),
|
||||||
|
growAmount / (1024 * 1024),
|
||||||
|
mVmemCommitted / (1024 * 1024),
|
||||||
|
mVmemCapacity / (1024 * 1024));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void JKRSolidHeap::do_free(void* ptr) {
|
void JKRSolidHeap::do_free(void* ptr) {
|
||||||
JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr);
|
JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,6 @@
|
|||||||
#include <mtx.h>
|
#include <mtx.h>
|
||||||
#include <gx.h>
|
#include <gx.h>
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
#include "dusk/frame_interpolation.h"
|
|
||||||
#endif
|
|
||||||
#include "tracy/Tracy.hpp"
|
#include "tracy/Tracy.hpp"
|
||||||
|
|
||||||
void JPASetPointSize(JPAEmitterWorkData* work) {
|
void JPASetPointSize(JPAEmitterWorkData* work) {
|
||||||
@@ -421,95 +418,50 @@ static projectionFunc p_prj[3] = {
|
|||||||
loadPrjAnm,
|
loadPrjAnm,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if TARGET_PC
|
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||||
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||||
Mtx ptclPosMtx;
|
|
||||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
|
||||||
dusk::frame_interp::record_final_mtx(ptclPosMtx, ptcl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JPAInterpRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
|
||||||
Mtx ptclPosMtx;
|
|
||||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
|
||||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
|
||||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
|
||||||
ptclPosMtx[0][0] = cosRot;
|
|
||||||
ptclPosMtx[0][1] = -sinRot;
|
|
||||||
ptclPosMtx[1][0] = sinRot;
|
|
||||||
ptclPosMtx[1][1] = cosRot;
|
|
||||||
dusk::frame_interp::record_final_mtx(ptclPosMtx, ptcl);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
|
||||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JGeometry::TVec3<f32> pos;
|
JGeometry::TVec3<f32> local_48;
|
||||||
#if TARGET_PC
|
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
||||||
Mtx ptclPosMtx;
|
Mtx local_38;
|
||||||
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||||
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
local_38[0][3] = local_48.x;
|
||||||
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||||
} else
|
local_38[1][3] = local_48.y;
|
||||||
#endif
|
local_38[2][2] = 1.0f;
|
||||||
{
|
local_38[2][3] = local_48.z;
|
||||||
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
|
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
|
||||||
}
|
GXLoadPosMtxImm(local_38, 0);
|
||||||
Mtx posMtx;
|
p_prj[work->mPrjType](work, local_38);
|
||||||
posMtx[0][0] = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
|
||||||
posMtx[0][3] = pos.x;
|
|
||||||
posMtx[1][1] = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
|
||||||
posMtx[1][3] = pos.y;
|
|
||||||
posMtx[2][2] = 1.0f;
|
|
||||||
posMtx[2][3] = pos.z;
|
|
||||||
posMtx[0][1] = posMtx[0][2] = posMtx[1][0] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
|
|
||||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
|
||||||
p_prj[work->mPrjType](work, posMtx);
|
|
||||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (work->mpRes->getUsrIdx() == 0x89d7) {
|
JGeometry::TVec3<f32> local_48;
|
||||||
int a = 0;
|
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
||||||
}
|
f32 sinRot = JMASSin(param_1->mRotateAngle);
|
||||||
|
f32 cosRot = JMASCos(param_1->mRotateAngle);
|
||||||
|
f32 particleX = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||||
|
f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||||
|
|
||||||
JGeometry::TVec3<f32> pos;
|
Mtx local_38;
|
||||||
f32 sinRot, cosRot;
|
local_38[0][0] = cosRot * particleX;
|
||||||
#if TARGET_PC
|
local_38[0][1] = -sinRot * particleY;
|
||||||
Mtx ptclPosMtx;
|
local_38[0][3] = local_48.x;
|
||||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
local_38[1][0] = sinRot * particleX;
|
||||||
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
local_38[1][1] = cosRot * particleY;
|
||||||
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
local_38[1][3] = local_48.y;
|
||||||
sinRot = ptclPosMtx[1][0];
|
local_38[2][2] = 1.0f;
|
||||||
cosRot = ptclPosMtx[0][0];
|
local_38[2][3] = local_48.z;
|
||||||
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
local_38[0][2] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
|
||||||
} else
|
GXLoadPosMtxImm(local_38, 0);
|
||||||
#endif
|
p_prj[work->mPrjType](work, local_38);
|
||||||
{
|
|
||||||
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
|
|
||||||
sinRot = JMASSin(ptcl->mRotateAngle);
|
|
||||||
cosRot = JMASCos(ptcl->mRotateAngle);
|
|
||||||
}
|
|
||||||
f32 particleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
|
||||||
f32 particleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
|
||||||
Mtx posMtx;
|
|
||||||
posMtx[0][0] = cosRot * particleX;
|
|
||||||
posMtx[0][1] = -sinRot * particleY;
|
|
||||||
posMtx[0][3] = pos.x;
|
|
||||||
posMtx[1][0] = sinRot * particleX;
|
|
||||||
posMtx[1][1] = cosRot * particleY;
|
|
||||||
posMtx[1][3] = pos.y;
|
|
||||||
posMtx[2][2] = 1.0f;
|
|
||||||
posMtx[2][3] = pos.z;
|
|
||||||
posMtx[0][2] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
|
|
||||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
|
||||||
p_prj[work->mPrjType](work, posMtx);
|
|
||||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +484,7 @@ void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
|||||||
local_38[2][2] = work->mYBBCamMtx[2][2];
|
local_38[2][2] = work->mYBBCamMtx[2][2];
|
||||||
local_38[2][3] = local_48.z;
|
local_38[2][3] = local_48.z;
|
||||||
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[2][0] = 0.0f;
|
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[2][0] = 0.0f;
|
||||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
GXLoadPosMtxImm(local_38, 0);
|
||||||
p_prj[work->mPrjType](work, local_38);
|
p_prj[work->mPrjType](work, local_38);
|
||||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||||
}
|
}
|
||||||
@@ -565,7 +517,7 @@ void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
|||||||
local_38[2][1] = local_94 * fVar1;
|
local_38[2][1] = local_94 * fVar1;
|
||||||
local_38[2][2] = local_90;
|
local_38[2][2] = local_90;
|
||||||
local_38[2][3] = local_48.z;
|
local_38[2][3] = local_48.z;
|
||||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
GXLoadPosMtxImm(local_38, 0);
|
||||||
p_prj[work->mPrjType](work, local_38);
|
p_prj[work->mPrjType](work, local_38);
|
||||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||||
}
|
}
|
||||||
@@ -729,197 +681,103 @@ static u8* p_dl[2] = {
|
|||||||
jpa_dl_x,
|
jpa_dl_x,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if TARGET_PC
|
void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||||
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||||
JGeometry::TVec3<f32> axisY;
|
|
||||||
JGeometry::TVec3<f32> axisZ;
|
|
||||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
|
||||||
|
|
||||||
if (axisY.isZero()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axisY.normalize();
|
|
||||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
|
||||||
|
|
||||||
if (axisZ.isZero()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axisZ.normalize();
|
|
||||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
|
||||||
ptcl->mBaseAxis.normalize();
|
|
||||||
Mtx posMtx;
|
|
||||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
|
||||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
|
||||||
posMtx[0][0] = ptcl->mBaseAxis.x;
|
|
||||||
posMtx[0][1] = axisY.x;
|
|
||||||
posMtx[0][2] = axisZ.x;
|
|
||||||
posMtx[0][3] = ptcl->mPosition.x;
|
|
||||||
posMtx[1][0] = ptcl->mBaseAxis.y;
|
|
||||||
posMtx[1][1] = axisY.y;
|
|
||||||
posMtx[1][2] = axisZ.y;
|
|
||||||
posMtx[1][3] = ptcl->mPosition.y;
|
|
||||||
posMtx[2][0] = ptcl->mBaseAxis.z;
|
|
||||||
posMtx[2][1] = axisY.z;
|
|
||||||
posMtx[2][2] = axisZ.z;
|
|
||||||
posMtx[2][3] = ptcl->mPosition.z;
|
|
||||||
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
|
||||||
dusk::frame_interp::record_final_mtx(posMtx, ptcl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
|
||||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
|
||||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
|
||||||
JGeometry::TVec3<f32> axisY;
|
|
||||||
JGeometry::TVec3<f32> axisZ;
|
|
||||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
|
||||||
|
|
||||||
if (axisY.isZero()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axisY.normalize();
|
|
||||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
|
||||||
|
|
||||||
if (axisZ.isZero()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axisZ.normalize();
|
|
||||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
|
||||||
ptcl->mBaseAxis.normalize();
|
|
||||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
|
||||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
|
||||||
Mtx mtx1;
|
|
||||||
Mtx mtx2;
|
|
||||||
p_rot[work->mRotType](sinRot, cosRot, mtx1);
|
|
||||||
p_plane[work->mPlaneType](mtx1, scaleX, scaleY);
|
|
||||||
mtx2[0][0] = ptcl->mBaseAxis.x;
|
|
||||||
mtx2[0][1] = axisY.x;
|
|
||||||
mtx2[0][2] = axisZ.x;
|
|
||||||
mtx2[0][3] = ptcl->mPosition.x;
|
|
||||||
mtx2[1][0] = ptcl->mBaseAxis.y;
|
|
||||||
mtx2[1][1] = axisY.y;
|
|
||||||
mtx2[1][2] = axisZ.y;
|
|
||||||
mtx2[1][3] = ptcl->mPosition.y;
|
|
||||||
mtx2[2][0] = ptcl->mBaseAxis.z;
|
|
||||||
mtx2[2][1] = axisY.z;
|
|
||||||
mtx2[2][2] = axisZ.z;
|
|
||||||
mtx2[2][3] = ptcl->mPosition.z;
|
|
||||||
MTXConcat(mtx2, mtx1, mtx1);
|
|
||||||
dusk::frame_interp::record_final_mtx(mtx1, ptcl);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
|
||||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneScoped;
|
ZoneScoped;
|
||||||
|
|
||||||
Mtx posMtx;
|
JGeometry::TVec3<f32> local_6c;
|
||||||
#if TARGET_PC
|
JGeometry::TVec3<f32> local_78;
|
||||||
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx))
|
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
||||||
#endif
|
|
||||||
{
|
|
||||||
JGeometry::TVec3<f32> axisY;
|
|
||||||
JGeometry::TVec3<f32> axisZ;
|
|
||||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
|
||||||
|
|
||||||
if (axisY.isZero()) {
|
if (local_6c.isZero()) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
axisY.normalize();
|
|
||||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
|
||||||
|
|
||||||
if (axisZ.isZero()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axisZ.normalize();
|
|
||||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
|
||||||
ptcl->mBaseAxis.normalize();
|
|
||||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
|
||||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
|
||||||
posMtx[0][0] = ptcl->mBaseAxis.x;
|
|
||||||
posMtx[0][1] = axisY.x;
|
|
||||||
posMtx[0][2] = axisZ.x;
|
|
||||||
posMtx[0][3] = ptcl->mPosition.x;
|
|
||||||
posMtx[1][0] = ptcl->mBaseAxis.y;
|
|
||||||
posMtx[1][1] = axisY.y;
|
|
||||||
posMtx[1][2] = axisZ.y;
|
|
||||||
posMtx[1][3] = ptcl->mPosition.y;
|
|
||||||
posMtx[2][0] = ptcl->mBaseAxis.z;
|
|
||||||
posMtx[2][1] = axisY.z;
|
|
||||||
posMtx[2][2] = axisZ.z;
|
|
||||||
posMtx[2][3] = ptcl->mPosition.z;
|
|
||||||
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MTXConcat(work->mPosCamMtx, posMtx, posMtx);
|
local_6c.normalize();
|
||||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
local_78.cross(param_1->mBaseAxis, local_6c);
|
||||||
p_prj[work->mPrjType](work, posMtx);
|
|
||||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
if (local_78.isZero()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_78.normalize();
|
||||||
|
param_1->mBaseAxis.cross(local_6c, local_78);
|
||||||
|
param_1->mBaseAxis.normalize();
|
||||||
|
Mtx local_60;
|
||||||
|
f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||||
|
f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||||
|
local_60[0][0] = param_1->mBaseAxis.x;
|
||||||
|
local_60[0][1] = local_6c.x;
|
||||||
|
local_60[0][2] = local_78.x;
|
||||||
|
local_60[0][3] = param_1->mPosition.x;
|
||||||
|
local_60[1][0] = param_1->mBaseAxis.y;
|
||||||
|
local_60[1][1] = local_6c.y;
|
||||||
|
local_60[1][2] = local_78.y;
|
||||||
|
local_60[1][3] = param_1->mPosition.y;
|
||||||
|
local_60[2][0] = param_1->mBaseAxis.z;
|
||||||
|
local_60[2][1] = local_6c.z;
|
||||||
|
local_60[2][2] = local_78.z;
|
||||||
|
local_60[2][3] = param_1->mPosition.z;
|
||||||
|
p_plane[param_0->mPlaneType](local_60, fVar1, fVar2);
|
||||||
|
MTXConcat(param_0->mPosCamMtx, local_60, local_60);
|
||||||
|
GXLoadPosMtxImm(local_60, 0);
|
||||||
|
p_prj[param_0->mPrjType](param_0, local_60);
|
||||||
|
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
void JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneScoped;
|
ZoneScoped;
|
||||||
|
|
||||||
Mtx mtx1;
|
f32 sinRot = JMASSin(param_1->mRotateAngle);
|
||||||
Mtx mtx2;
|
f32 cosRot = JMASCos(param_1->mRotateAngle);
|
||||||
#if TARGET_PC
|
JGeometry::TVec3<f32> local_6c;
|
||||||
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1))
|
JGeometry::TVec3<f32> local_78;
|
||||||
#endif
|
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
||||||
{
|
|
||||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
|
||||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
|
||||||
JGeometry::TVec3<f32> axisY;
|
|
||||||
JGeometry::TVec3<f32> axisZ;
|
|
||||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
|
||||||
|
|
||||||
if (axisY.isZero()) {
|
if (local_6c.isZero()) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
axisY.normalize();
|
|
||||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
|
||||||
|
|
||||||
if (axisZ.isZero()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axisZ.normalize();
|
|
||||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
|
||||||
ptcl->mBaseAxis.normalize();
|
|
||||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
|
||||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
|
||||||
p_rot[work->mRotType](sinRot, cosRot, mtx1);
|
|
||||||
p_plane[work->mPlaneType](mtx1, scaleX, scaleY);
|
|
||||||
mtx2[0][0] = ptcl->mBaseAxis.x;
|
|
||||||
mtx2[0][1] = axisY.x;
|
|
||||||
mtx2[0][2] = axisZ.x;
|
|
||||||
mtx2[0][3] = ptcl->mPosition.x;
|
|
||||||
mtx2[1][0] = ptcl->mBaseAxis.y;
|
|
||||||
mtx2[1][1] = axisY.y;
|
|
||||||
mtx2[1][2] = axisZ.y;
|
|
||||||
mtx2[1][3] = ptcl->mPosition.y;
|
|
||||||
mtx2[2][0] = ptcl->mBaseAxis.z;
|
|
||||||
mtx2[2][1] = axisY.z;
|
|
||||||
mtx2[2][2] = axisZ.z;
|
|
||||||
mtx2[2][3] = ptcl->mPosition.z;
|
|
||||||
MTXConcat(mtx2, mtx1, mtx1);
|
|
||||||
}
|
}
|
||||||
MTXConcat(work->mPosCamMtx, mtx1, mtx2);
|
|
||||||
GXLoadPosMtxImm(mtx2, GX_PNMTX0);
|
local_6c.normalize();
|
||||||
p_prj[work->mPrjType](work, mtx2);
|
local_78.cross(param_1->mBaseAxis, local_6c);
|
||||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
|
||||||
|
if (local_78.isZero()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_78.normalize();
|
||||||
|
param_1->mBaseAxis.cross(local_6c, local_78);
|
||||||
|
param_1->mBaseAxis.normalize();
|
||||||
|
f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||||
|
f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||||
|
Mtx auStack_80;
|
||||||
|
Mtx local_60;
|
||||||
|
p_rot[param_0->mRotType](sinRot, cosRot, auStack_80);
|
||||||
|
p_plane[param_0->mPlaneType](auStack_80, particleX, particleY);
|
||||||
|
local_60[0][0] = param_1->mBaseAxis.x;
|
||||||
|
local_60[0][1] = local_6c.x;
|
||||||
|
local_60[0][2] = local_78.x;
|
||||||
|
local_60[0][3] = param_1->mPosition.x;
|
||||||
|
local_60[1][0] = param_1->mBaseAxis.y;
|
||||||
|
local_60[1][1] = local_6c.y;
|
||||||
|
local_60[1][2] = local_78.y;
|
||||||
|
local_60[1][3] = param_1->mPosition.y;
|
||||||
|
local_60[2][0] = param_1->mBaseAxis.z;
|
||||||
|
local_60[2][1] = local_6c.z;
|
||||||
|
local_60[2][2] = local_78.z;
|
||||||
|
local_60[2][3] = param_1->mPosition.z;
|
||||||
|
MTXConcat(local_60, auStack_80, auStack_80);
|
||||||
|
MTXConcat(param_0->mPosCamMtx, auStack_80, local_60);
|
||||||
|
GXLoadPosMtxImm(local_60, 0);
|
||||||
|
p_prj[param_0->mPrjType](param_0, local_60);
|
||||||
|
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||||
|
|||||||
@@ -204,28 +204,6 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent)
|
|||||||
mTexAnmIdx = 0;
|
mTexAnmIdx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void JPABaseParticle::interp(JPAEmitterWorkData* work, void const* drawFunc) {
|
|
||||||
static bool enable = false;
|
|
||||||
if (!enable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// don't interpolate the first frame
|
|
||||||
if (mAge == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (drawFunc == JPADrawBillboard) {
|
|
||||||
JPAInterpBillboard(work, this);
|
|
||||||
} else if (drawFunc == JPADrawRotBillboard) {
|
|
||||||
JPAInterpRotBillboard(work, this);
|
|
||||||
} else if (drawFunc == JPADrawDirection) {
|
|
||||||
JPAInterpDirection(work, this);
|
|
||||||
} else if (drawFunc == JPADrawRotDirection) {
|
|
||||||
JPAInterpRotDirection(work, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
|
bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
|
||||||
if (++mAge >= mLifeTime) {
|
if (++mAge >= mLifeTime) {
|
||||||
return true;
|
return true;
|
||||||
@@ -269,17 +247,6 @@ bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
|
|||||||
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
||||||
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
|
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
JPABaseShape* pBsp = work->mpRes->getBsp();
|
|
||||||
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pBsp->getBaseSizeX();
|
|
||||||
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pBsp->getBaseSizeY();
|
|
||||||
work->mDirType = pBsp->getDirType();
|
|
||||||
work->mRotType = pBsp->getRotType();
|
|
||||||
work->mDLType = pBsp->getType() == 4 || pBsp->getType() == 8;
|
|
||||||
work->mPlaneType = work->mDLType ? 2 : pBsp->getBasePlaneType();
|
|
||||||
interp(work, (void const*)work->mpRes->mpDrawParticleFuncList[0]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,23 +289,6 @@ bool JPABaseParticle::calc_c(JPAEmitterWorkData* work) {
|
|||||||
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
||||||
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
|
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
JPABaseShape* pBsp = work->mpRes->getBsp();
|
|
||||||
JPAChildShape* pCsp = work->mpRes->getCsp();
|
|
||||||
if (pCsp->isScaleInherited()) {
|
|
||||||
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pBsp->getBaseSizeX();
|
|
||||||
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pBsp->getBaseSizeY();
|
|
||||||
} else {
|
|
||||||
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pCsp->getScaleX();
|
|
||||||
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pCsp->getScaleY();
|
|
||||||
}
|
|
||||||
work->mDirType = pCsp->getDirType();
|
|
||||||
work->mRotType = pCsp->getRotType();
|
|
||||||
work->mDLType = pCsp->getType() == 4 || pCsp->getType() == 8;
|
|
||||||
work->mPlaneType = work->mDLType ? 2 : pCsp->getBasePlaneType();
|
|
||||||
interp(work, (void const*)work->mpRes->mpDrawParticleChildFuncList[0]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,6 @@
|
|||||||
#include "JSystem/JUtility/JUTFader.h"
|
#include "JSystem/JUtility/JUTFader.h"
|
||||||
#include "JSystem/J2DGraph/J2DOrthoGraph.h"
|
#include "JSystem/J2DGraph/J2DOrthoGraph.h"
|
||||||
|
|
||||||
#ifdef TARGET_PC
|
|
||||||
#include <algorithm>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JUTFader::JUTFader(int x, int y, int width, int height, JUtility::TColor pColor)
|
JUTFader::JUTFader(int x, int y, int width, int height, JUtility::TColor pColor)
|
||||||
: mColor(pColor), mBox(x, y, x + width, y + height) {
|
: mColor(pColor), mBox(x, y, x + width, y + height) {
|
||||||
mStatus = None;
|
mStatus = None;
|
||||||
@@ -67,24 +63,14 @@ void JUTFader::advance() {
|
|||||||
|
|
||||||
void JUTFader::control() {
|
void JUTFader::control() {
|
||||||
advance();
|
advance();
|
||||||
|
#ifndef TARGET_PC
|
||||||
|
// FRAME INTERP NOTE: Draw is called by JFWDisplay when interpolation is active
|
||||||
draw();
|
draw();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void JUTFader::draw() {
|
void JUTFader::draw() {
|
||||||
if (mColor.a != 0) {
|
if (mColor.a != 0) {
|
||||||
#ifdef TARGET_PC
|
|
||||||
if (dusk::frame_interp::is_enabled() && mDuration != 0) {
|
|
||||||
const auto step = dusk::frame_interp::get_interpolation_step();
|
|
||||||
const auto progress = static_cast<f32>(mTimer) / static_cast<f32>(mDuration);
|
|
||||||
const auto timer = mTimer - 1 + step + progress;
|
|
||||||
auto alpha = timer / mDuration;
|
|
||||||
if (mStatus == FadeIn) {
|
|
||||||
alpha = 1.0f - alpha;
|
|
||||||
}
|
|
||||||
alpha = std::clamp(alpha, 0.0f, 1.0f);
|
|
||||||
mColor.a = static_cast<u8>(alpha * 255.0f);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
J2DOrthoGraph orthograph;
|
J2DOrthoGraph orthograph;
|
||||||
orthograph.setColor(mColor);
|
orthograph.setColor(mColor);
|
||||||
orthograph.fillBox(mBox);
|
orthograph.fillBox(mBox);
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "os_report.h"
|
#include "os_report.h"
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
#include "dusk/action_bindings.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u32 JUTGamePad::CRumble::sChannelMask[4] = {
|
u32 JUTGamePad::CRumble::sChannelMask[4] = {
|
||||||
PAD_CHAN0_BIT,
|
PAD_CHAN0_BIT,
|
||||||
PAD_CHAN1_BIT,
|
PAD_CHAN1_BIT,
|
||||||
@@ -89,9 +85,6 @@ u32 JUTGamePad::sRumbleSupported;
|
|||||||
|
|
||||||
u32 JUTGamePad::read() {
|
u32 JUTGamePad::read() {
|
||||||
sRumbleSupported = PADRead(mPadStatus);
|
sRumbleSupported = PADRead(mPadStatus);
|
||||||
#if TARGET_PC
|
|
||||||
dusk::updateActionBindings();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (sClampMode) {
|
switch (sClampMode) {
|
||||||
case EClampStick:
|
case EClampStick:
|
||||||
|
|||||||
@@ -38,9 +38,3 @@ bool JUTPalette::load() {
|
|||||||
|
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void JUTPalette::dataUploaded() {
|
|
||||||
GXInitTlutObjData(&mTlutObj, (void*)mColorTable);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, u8 param_1) {
|
|||||||
mTexData = (void*)((intptr_t)mTexInfo + 0x20);
|
mTexData = (void*)((intptr_t)mTexInfo + 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
mPalette = NULL;
|
field_0x2c = NULL;
|
||||||
mTlutName = 0;
|
mTlutName = 0;
|
||||||
mWrapS = mTexInfo->wrapS;
|
mWrapS = mTexInfo->wrapS;
|
||||||
mWrapT = mTexInfo->wrapT;
|
mWrapT = mTexInfo->wrapT;
|
||||||
@@ -95,7 +95,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
|
|||||||
}
|
}
|
||||||
mEmbPalette = param_1;
|
mEmbPalette = param_1;
|
||||||
setEmbPaletteDelFlag(false);
|
setEmbPaletteDelFlag(false);
|
||||||
mPalette = NULL;
|
field_0x2c = NULL;
|
||||||
if (param_1 != NULL) {
|
if (param_1 != NULL) {
|
||||||
mTlutName = param_2;
|
mTlutName = param_2;
|
||||||
if (param_2 != param_1->getTlutName()) {
|
if (param_2 != param_1->getTlutName()) {
|
||||||
@@ -120,11 +120,11 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
|
|||||||
void JUTTexture::attachPalette(JUTPalette* param_0) {
|
void JUTTexture::attachPalette(JUTPalette* param_0) {
|
||||||
if (mTexInfo->indexTexture) {
|
if (mTexInfo->indexTexture) {
|
||||||
if (param_0 == NULL && mEmbPalette != NULL) {
|
if (param_0 == NULL && mEmbPalette != NULL) {
|
||||||
mPalette = mEmbPalette;
|
field_0x2c = mEmbPalette;
|
||||||
} else {
|
} else {
|
||||||
mPalette = param_0;
|
field_0x2c = param_0;
|
||||||
}
|
}
|
||||||
initTexObj(mPalette->getTlutName());
|
initTexObj(field_0x2c->getTlutName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +133,9 @@ void JUTTexture::init() {
|
|||||||
initTexObj();
|
initTexObj();
|
||||||
} else {
|
} else {
|
||||||
if (mEmbPalette != NULL) {
|
if (mEmbPalette != NULL) {
|
||||||
mPalette = mEmbPalette;
|
field_0x2c = mEmbPalette;
|
||||||
|
|
||||||
initTexObj(mPalette->getTlutName());
|
initTexObj(field_0x2c->getTlutName());
|
||||||
} else {
|
} else {
|
||||||
OS_REPORT("This texture is CI-Format, but EmbPalette is NULL.\n");
|
OS_REPORT("This texture is CI-Format, but EmbPalette is NULL.\n");
|
||||||
}
|
}
|
||||||
@@ -179,8 +179,8 @@ void JUTTexture::initTexObj(GXTlut param_0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JUTTexture::load(GXTexMapID param_0) {
|
void JUTTexture::load(GXTexMapID param_0) {
|
||||||
if (mPalette) {
|
if (field_0x2c) {
|
||||||
mPalette->load();
|
field_0x2c->load();
|
||||||
}
|
}
|
||||||
GXLoadTexObj(&mTexObj, param_0);
|
GXLoadTexObj(&mTexObj, param_0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Android Shell
|
# Android Shell
|
||||||
|
|
||||||
This directory contains a minimal SDLActivity-based Android app wrapper for Dusklight.
|
This directory contains a minimal SDLActivity-based Android app wrapper for Dusk.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -66,11 +66,12 @@ Output APK:
|
|||||||
You can pass command-line args through the activity intent:
|
You can pass command-line args through the activity intent:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
adb shell am start -n dev.twilitrealm.dusk/.DuskActivity \
|
adb shell am start -n com.twilitrealm.dusk/.DuskActivity \
|
||||||
--es dusk_args "--backend vulkan"
|
--es dusk_args "'/sdcard/Download/The Legend of Zelda: Twilight Princess (USA).iso'"
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported extras:
|
Supported extras:
|
||||||
|
|
||||||
- `dusk_args`: single shell-like argument string
|
- `dusk_args`: single shell-like argument string
|
||||||
- `dusk_argv`: string-array argv
|
- `dusk_argv`: string-array argv
|
||||||
|
- `dusk_disc`: compatibility shortcut (single ISO path)
|
||||||
|
|||||||
@@ -2,22 +2,12 @@ plugins {
|
|||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
}
|
}
|
||||||
|
|
||||||
def duskRepoDir = rootProject.projectDir.parentFile.parentFile
|
|
||||||
def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusklight').get().asFile
|
|
||||||
def syncDuskAssets = tasks.register('syncDuskAssets', Sync) {
|
|
||||||
from(new File(duskRepoDir, 'res')) {
|
|
||||||
into 'res'
|
|
||||||
exclude '**/.DS_Store'
|
|
||||||
}
|
|
||||||
into duskGeneratedAssetsDir
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'dev.twilitrealm.dusk'
|
namespace 'com.twilitrealm.dusk'
|
||||||
compileSdk 36
|
compileSdk 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId 'dev.twilitrealm.dusk'
|
applicationId 'com.twilitrealm.dusk'
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 36
|
targetSdk 36
|
||||||
versionCode 1
|
versionCode 1
|
||||||
@@ -37,7 +27,7 @@ android {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
jniLibs.srcDirs = ['src/main/jniLibs']
|
jniLibs.srcDirs = ['src/main/jniLibs']
|
||||||
assets.srcDirs = [duskGeneratedAssetsDir]
|
assets.srcDirs = ['../../assets']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,10 +48,3 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.configureEach { task ->
|
|
||||||
if ((task.name.startsWith('merge') && task.name.endsWith('Assets')) ||
|
|
||||||
task.name.toLowerCase().contains('lint')) {
|
|
||||||
task.dependsOn(syncDuskAssets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
# Keep SDL activity and related JNI bridge methods.
|
# Keep SDL activity and related JNI bridge methods.
|
||||||
-keep class org.libsdl.app.** { *; }
|
-keep class org.libsdl.app.** { *; }
|
||||||
-keep class dev.twilitrealm.dusk.DuskHttpClient { *; }
|
|
||||||
-keep class dev.twilitrealm.dusk.DuskHttpClient$Response { *; }
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
|
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -24,19 +23,8 @@
|
|||||||
<meta-data android:name="android.game_mode_config"
|
<meta-data android:name="android.game_mode_config"
|
||||||
android:resource="@xml/game_mode_config" />
|
android:resource="@xml/game_mode_config" />
|
||||||
|
|
||||||
<provider
|
|
||||||
android:name="dev.twilitrealm.dusk.DuskDocumentsProvider"
|
|
||||||
android:authorities="dev.twilitrealm.dusk.documents"
|
|
||||||
android:exported="true"
|
|
||||||
android:grantUriPermissions="true"
|
|
||||||
android:permission="android.permission.MANAGE_DOCUMENTS">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
|
||||||
</intent-filter>
|
|
||||||
</provider>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="dev.twilitrealm.dusk.DuskActivity"
|
android:name="com.twilitrealm.dusk.DuskActivity"
|
||||||
android:alwaysRetainTaskState="true"
|
android:alwaysRetainTaskState="true"
|
||||||
android:configChanges="layoutDirection|locale|grammaticalGender|fontScale|fontWeightAdjustment|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
android:configChanges="layoutDirection|locale|grammaticalGender|fontScale|fontWeightAdjustment|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
@@ -1,39 +1,18 @@
|
|||||||
package dev.twilitrealm.dusk;
|
package com.twilitrealm.dusk;
|
||||||
|
|
||||||
import android.app.ActionBar;
|
import android.app.ActionBar;
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.ClipData;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
import android.provider.DocumentsContract;
|
|
||||||
import android.provider.OpenableColumns;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.WindowInsetsController;
|
|
||||||
|
|
||||||
import org.libsdl.app.SDLActivity;
|
import org.libsdl.app.SDLActivity;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DuskActivity extends SDLActivity {
|
public class DuskActivity extends SDLActivity {
|
||||||
private static final String TAG = "DuskActivity";
|
|
||||||
private static final int FOLDER_DIALOG_REQUEST_CODE = 0x4455;
|
|
||||||
private static final String EXTERNAL_STORAGE_AUTHORITY =
|
|
||||||
"com.android.externalstorage.documents";
|
|
||||||
|
|
||||||
private long folderDialogUserdata = 0;
|
|
||||||
|
|
||||||
private static native void nativeFolderDialogResult(long userdata, String path, String error);
|
|
||||||
|
|
||||||
private static String[] splitArgs(String raw) {
|
private static String[] splitArgs(String raw) {
|
||||||
List<String> out = new ArrayList<>();
|
List<String> out = new ArrayList<>();
|
||||||
StringBuilder current = new StringBuilder();
|
StringBuilder current = new StringBuilder();
|
||||||
@@ -82,46 +61,18 @@ public class DuskActivity extends SDLActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
hideSystemBars();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
hideSystemBars();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWindowFocusChanged(boolean hasFocus) {
|
|
||||||
super.onWindowFocusChanged(hasFocus);
|
|
||||||
if (hasFocus) {
|
|
||||||
hideSystemBars();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideSystemBars() {
|
|
||||||
Window window = getWindow();
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
window.setDecorFitsSystemWindows(false);
|
getWindow().getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
|
||||||
WindowInsetsController ctrl = window.getDecorView().getWindowInsetsController();
|
}else {
|
||||||
if (ctrl != null) {
|
View decorView = getWindow().getDecorView();
|
||||||
ctrl.setSystemBarsBehavior(
|
// Hide the status bar.
|
||||||
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||||
ctrl.hide(WindowInsets.Type.systemBars());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
View decorView = window.getDecorView();
|
|
||||||
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN |
|
|
||||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
|
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
|
||||||
decorView.setSystemUiVisibility(uiOptions);
|
decorView.setSystemUiVisibility(uiOptions);
|
||||||
|
// Remember that you should never show the action bar if the
|
||||||
|
// status bar is hidden, so hide that too if necessary.
|
||||||
ActionBar actionBar = getActionBar();
|
ActionBar actionBar = getActionBar();
|
||||||
if (actionBar != null) {
|
actionBar.hide();
|
||||||
actionBar.hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,241 +100,12 @@ public class DuskActivity extends SDLActivity {
|
|||||||
return splitArgs(trimmed);
|
return splitArgs(trimmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String discPath = intent.getStringExtra("dusk_disc");
|
||||||
|
if (discPath != null && !discPath.isEmpty()) {
|
||||||
|
return new String[] { discPath };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
persistUriPermissions(data);
|
|
||||||
}
|
|
||||||
if (requestCode == FOLDER_DIALOG_REQUEST_CODE) {
|
|
||||||
finishFolderDialog(resultCode, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean showFolderDialog(long userdata) {
|
|
||||||
if (userdata == 0 || folderDialogUserdata != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
folderDialogUserdata = userdata;
|
|
||||||
runOnUiThread(() -> {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
|
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
|
|
||||||
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
|
|
||||||
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
|
|
||||||
|
|
||||||
try {
|
|
||||||
startActivityForResult(intent, FOLDER_DIALOG_REQUEST_CODE);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Log.w(TAG, "Unable to open folder dialog.", e);
|
|
||||||
finishFolderDialog(Activity.RESULT_CANCELED, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishFolderDialog(int resultCode, Intent data) {
|
|
||||||
long userdata = folderDialogUserdata;
|
|
||||||
folderDialogUserdata = 0;
|
|
||||||
if (userdata == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultCode == RESULT_OK && data != null && data.getData() != null) {
|
|
||||||
String path = getRealPathForUri(data.getData());
|
|
||||||
if (path != null && !path.isEmpty()) {
|
|
||||||
nativeFolderDialogResult(userdata, path, null);
|
|
||||||
} else {
|
|
||||||
nativeFolderDialogResult(
|
|
||||||
userdata, null, "Selected folder is not available as a filesystem path");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeFolderDialogResult(userdata, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRealPathForUri(Uri uri) {
|
|
||||||
if (uri == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String scheme = uri.getScheme();
|
|
||||||
if ("file".equals(scheme)) {
|
|
||||||
return uri.getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"content".equals(scheme) ||
|
|
||||||
!EXTERNAL_STORAGE_AUTHORITY.equals(uri.getAuthority()) ||
|
|
||||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return getExternalStoragePathForDocumentId(getExternalStorageDocumentId(uri));
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
Log.w(TAG, "Unable to resolve URI: " + uri, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getExternalStorageDocumentId(Uri uri) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isTreeDocumentUri(uri)) {
|
|
||||||
return DocumentsContract.getTreeDocumentId(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DocumentsContract.getDocumentId(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isTreeDocumentUri(Uri uri) {
|
|
||||||
List<String> segments = uri.getPathSegments();
|
|
||||||
return segments.size() >= 2 && "tree".equals(segments.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getExternalStoragePathForDocumentId(String documentId) {
|
|
||||||
if (documentId == null || documentId.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (documentId.startsWith("raw:")) {
|
|
||||||
return documentId.substring("raw:".length());
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] parts = documentId.split(":", 2);
|
|
||||||
String volumeId = parts[0];
|
|
||||||
String relativePath = parts.length > 1 ? parts[1] : "";
|
|
||||||
|
|
||||||
File root = getExternalStorageRoot(volumeId);
|
|
||||||
if (root == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return relativePath.isEmpty()
|
|
||||||
? root.getAbsolutePath()
|
|
||||||
: new File(root, relativePath).getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getExternalStorageRoot(String volumeId) {
|
|
||||||
if ("primary".equalsIgnoreCase(volumeId)) {
|
|
||||||
return Environment.getExternalStorageDirectory();
|
|
||||||
}
|
|
||||||
if ("home".equalsIgnoreCase(volumeId)) {
|
|
||||||
return new File(
|
|
||||||
Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOCUMENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
File[] externalFilesDirs = getExternalFilesDirs(null);
|
|
||||||
if (externalFilesDirs != null) {
|
|
||||||
for (File externalFilesDir : externalFilesDirs) {
|
|
||||||
File root = getStorageRootForExternalFilesDir(externalFilesDir);
|
|
||||||
if (root != null && volumeId.equalsIgnoreCase(root.getName())) {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File fallback = new File("/storage", volumeId);
|
|
||||||
return fallback.exists() ? fallback : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getStorageRootForExternalFilesDir(File externalFilesDir) {
|
|
||||||
if (externalFilesDir == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String path = externalFilesDir.getAbsolutePath();
|
|
||||||
int androidDir = path.indexOf("/Android/");
|
|
||||||
if (androidDir <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new File(path.substring(0, androidDir));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistUriPermissions(Intent data) {
|
|
||||||
if (data == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int permissionFlags =
|
|
||||||
data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
if (permissionFlags == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri = data.getData();
|
|
||||||
if (uri != null) {
|
|
||||||
persistUriPermission(uri, permissionFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClipData clipData = data.getClipData();
|
|
||||||
if (clipData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < clipData.getItemCount(); ++i) {
|
|
||||||
Uri itemUri = clipData.getItemAt(i).getUri();
|
|
||||||
if (itemUri != null) {
|
|
||||||
persistUriPermission(itemUri, permissionFlags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistUriPermission(Uri uri, int permissionFlags) {
|
|
||||||
if ((permissionFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
|
|
||||||
persistUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, "read");
|
|
||||||
}
|
|
||||||
if ((permissionFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
|
|
||||||
persistUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, "write");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistUriPermission(Uri uri, int permissionFlag, String permissionName) {
|
|
||||||
try {
|
|
||||||
getContentResolver().takePersistableUriPermission(uri, permissionFlag);
|
|
||||||
} catch (SecurityException | IllegalArgumentException e) {
|
|
||||||
Log.w(TAG, "Unable to persist " + permissionName + " URI permission for " + uri, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayNameForUri(String uriString) {
|
|
||||||
if (uriString == null || uriString.isEmpty()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri = Uri.parse(uriString);
|
|
||||||
if ("content".equals(uri.getScheme())) {
|
|
||||||
try (Cursor cursor = getContentResolver().query(
|
|
||||||
uri, new String[] { OpenableColumns.DISPLAY_NAME }, null, null, null))
|
|
||||||
{
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
int displayNameColumn = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
|
||||||
if (displayNameColumn >= 0) {
|
|
||||||
String displayName = cursor.getString(displayNameColumn);
|
|
||||||
if (displayName != null && !displayName.isEmpty()) {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SecurityException | IllegalArgumentException e) {
|
|
||||||
Log.w(TAG, "Unable to query display name for " + uri, e);
|
|
||||||
}
|
|
||||||
} else if ("file".equals(uri.getScheme())) {
|
|
||||||
String path = uri.getPath();
|
|
||||||
if (path != null && !path.isEmpty()) {
|
|
||||||
String name = new File(path).getName();
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String lastSegment = uri.getLastPathSegment();
|
|
||||||
return lastSegment != null ? lastSegment : "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,467 +0,0 @@
|
|||||||
package dev.twilitrealm.dusk;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.res.AssetFileDescriptor;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.MatrixCursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.CancellationSignal;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.provider.DocumentsContract;
|
|
||||||
import android.provider.DocumentsContract.Document;
|
|
||||||
import android.provider.DocumentsContract.Root;
|
|
||||||
import android.provider.DocumentsProvider;
|
|
||||||
import android.webkit.MimeTypeMap;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class DuskDocumentsProvider extends DocumentsProvider {
|
|
||||||
public static final String AUTHORITY = "dev.twilitrealm.dusk.documents";
|
|
||||||
|
|
||||||
private static final String ROOT_ID = "dusk";
|
|
||||||
private static final String ROOT_DOCUMENT_ID = "root";
|
|
||||||
private static final String LOCATION_DESCRIPTOR_NAME = "data_location.json";
|
|
||||||
private static final String DIRECTORY_MIME_TYPE = Document.MIME_TYPE_DIR;
|
|
||||||
|
|
||||||
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
|
|
||||||
Root.COLUMN_ROOT_ID,
|
|
||||||
Root.COLUMN_FLAGS,
|
|
||||||
Root.COLUMN_TITLE,
|
|
||||||
Root.COLUMN_DOCUMENT_ID,
|
|
||||||
Root.COLUMN_ICON,
|
|
||||||
Root.COLUMN_AVAILABLE_BYTES,
|
|
||||||
Root.COLUMN_SUMMARY
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
|
|
||||||
Document.COLUMN_DOCUMENT_ID,
|
|
||||||
Document.COLUMN_DISPLAY_NAME,
|
|
||||||
Document.COLUMN_FLAGS,
|
|
||||||
Document.COLUMN_MIME_TYPE,
|
|
||||||
Document.COLUMN_LAST_MODIFIED,
|
|
||||||
Document.COLUMN_SIZE
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreate() {
|
|
||||||
if (!isCustomDataPathEnabled()) {
|
|
||||||
ensureUserDirectories();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
|
|
||||||
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
|
|
||||||
if (isCustomDataPathEnabled()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
final File root = getRootDirectory();
|
|
||||||
final MatrixCursor.RowBuilder row = result.newRow();
|
|
||||||
|
|
||||||
row.add(Root.COLUMN_ROOT_ID, ROOT_ID);
|
|
||||||
row.add(Root.COLUMN_FLAGS,
|
|
||||||
Root.FLAG_LOCAL_ONLY |
|
|
||||||
Root.FLAG_SUPPORTS_CREATE |
|
|
||||||
Root.FLAG_SUPPORTS_IS_CHILD);
|
|
||||||
row.add(Root.COLUMN_TITLE, getContext().getString(R.string.app_name));
|
|
||||||
row.add(Root.COLUMN_DOCUMENT_ID, ROOT_DOCUMENT_ID);
|
|
||||||
row.add(Root.COLUMN_ICON, R.mipmap.icon);
|
|
||||||
row.add(Root.COLUMN_AVAILABLE_BYTES, root.getFreeSpace());
|
|
||||||
row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.documents_provider_summary));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
|
|
||||||
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
|
|
||||||
includeDocument(result, documentId, getFileForDocumentId(documentId));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
|
|
||||||
throws FileNotFoundException
|
|
||||||
{
|
|
||||||
return queryChildDocumentsInternal(parentDocumentId, projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, Bundle queryArgs)
|
|
||||||
throws FileNotFoundException
|
|
||||||
{
|
|
||||||
return queryChildDocumentsInternal(parentDocumentId, projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cursor queryChildDocumentsInternal(String parentDocumentId, String[] projection)
|
|
||||||
throws FileNotFoundException
|
|
||||||
{
|
|
||||||
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
|
|
||||||
final File parent = getFileForDocumentId(parentDocumentId);
|
|
||||||
final File[] files = parent.listFiles();
|
|
||||||
result.setNotificationUri(getContext().getContentResolver(), getChildDocumentsUri(parentDocumentId));
|
|
||||||
|
|
||||||
if (files == null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (File file : files) {
|
|
||||||
includeDocument(result, getDocumentIdForFile(file), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildDocument(String parentDocumentId, String documentId) {
|
|
||||||
try {
|
|
||||||
final File parent = getFileForDocumentId(parentDocumentId);
|
|
||||||
final File child = getFileForDocumentId(documentId);
|
|
||||||
return isInside(parent, child);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createDocument(String parentDocumentId, String mimeType, String displayName)
|
|
||||||
throws FileNotFoundException
|
|
||||||
{
|
|
||||||
final File parent = getFileForDocumentId(parentDocumentId);
|
|
||||||
if (!parent.isDirectory()) {
|
|
||||||
throw new FileNotFoundException("Parent is not a directory: " + parentDocumentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String safeDisplayName = sanitizeDisplayName(displayName);
|
|
||||||
final File file = buildUniqueFile(parent, safeDisplayName);
|
|
||||||
final boolean created;
|
|
||||||
if (DIRECTORY_MIME_TYPE.equals(mimeType)) {
|
|
||||||
created = file.mkdir();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
created = file.createNewFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw asFileNotFound("Unable to create document", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!created) {
|
|
||||||
throw new FileNotFoundException("Unable to create document: " + displayName);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyChildrenChanged(parentDocumentId);
|
|
||||||
return getDocumentIdForFile(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String renameDocument(String documentId, String displayName) throws FileNotFoundException {
|
|
||||||
final File file = getFileForDocumentId(documentId);
|
|
||||||
if (ROOT_DOCUMENT_ID.equals(documentId)) {
|
|
||||||
throw new FileNotFoundException("Cannot rename root document");
|
|
||||||
}
|
|
||||||
|
|
||||||
final File target = buildUniqueFile(file.getParentFile(), sanitizeDisplayName(displayName));
|
|
||||||
final String parentDocumentId = getDocumentIdForFile(file.getParentFile());
|
|
||||||
if (!file.renameTo(target)) {
|
|
||||||
throw new FileNotFoundException("Unable to rename document: " + documentId);
|
|
||||||
}
|
|
||||||
notifyDocumentChanged(documentId);
|
|
||||||
notifyDocumentChanged(getDocumentIdForFile(target));
|
|
||||||
notifyChildrenChanged(parentDocumentId);
|
|
||||||
return getDocumentIdForFile(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteDocument(String documentId) throws FileNotFoundException {
|
|
||||||
if (ROOT_DOCUMENT_ID.equals(documentId)) {
|
|
||||||
throw new FileNotFoundException("Cannot delete root document");
|
|
||||||
}
|
|
||||||
|
|
||||||
final File file = getFileForDocumentId(documentId);
|
|
||||||
final String parentDocumentId = getDocumentIdForFile(file.getParentFile());
|
|
||||||
deleteRecursively(file);
|
|
||||||
notifyDocumentChanged(documentId);
|
|
||||||
notifyChildrenChanged(parentDocumentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParcelFileDescriptor openDocument(String documentId, String mode, CancellationSignal signal)
|
|
||||||
throws FileNotFoundException
|
|
||||||
{
|
|
||||||
return ParcelFileDescriptor.open(getFileForDocumentId(documentId), modeToParcelMode(mode));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssetFileDescriptor openDocumentThumbnail(String documentId, android.graphics.Point sizeHint,
|
|
||||||
CancellationSignal signal) throws FileNotFoundException
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException("Thumbnails are not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void includeDocument(MatrixCursor result, String documentId, File file) throws FileNotFoundException {
|
|
||||||
final MatrixCursor.RowBuilder row = result.newRow();
|
|
||||||
final boolean isDirectory = file.isDirectory();
|
|
||||||
final String displayName = ROOT_DOCUMENT_ID.equals(documentId)
|
|
||||||
? getContext().getString(R.string.documents_provider_root_name)
|
|
||||||
: file.getName();
|
|
||||||
|
|
||||||
int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_RENAME;
|
|
||||||
if (isDirectory) {
|
|
||||||
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
|
||||||
} else if (file.canWrite()) {
|
|
||||||
flags |= Document.FLAG_SUPPORTS_WRITE;
|
|
||||||
}
|
|
||||||
if (ROOT_DOCUMENT_ID.equals(documentId)) {
|
|
||||||
flags &= ~(Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_RENAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
row.add(Document.COLUMN_DOCUMENT_ID, documentId);
|
|
||||||
row.add(Document.COLUMN_DISPLAY_NAME, displayName);
|
|
||||||
row.add(Document.COLUMN_FLAGS, flags);
|
|
||||||
row.add(Document.COLUMN_MIME_TYPE, isDirectory ? DIRECTORY_MIME_TYPE : getMimeType(file));
|
|
||||||
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
|
|
||||||
row.add(Document.COLUMN_SIZE, isDirectory ? null : file.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getRootDirectory() throws FileNotFoundException {
|
|
||||||
if (isCustomDataPathEnabled()) {
|
|
||||||
throw new FileNotFoundException(
|
|
||||||
"Dusk DocumentsProvider is disabled while a custom data path is configured");
|
|
||||||
}
|
|
||||||
|
|
||||||
final File root = getContext().getFilesDir();
|
|
||||||
if (root == null) {
|
|
||||||
throw new FileNotFoundException("Dusklight files directory is unavailable");
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getFileForDocumentId(String documentId) throws FileNotFoundException {
|
|
||||||
final File root = getRootDirectory();
|
|
||||||
if (ROOT_DOCUMENT_ID.equals(documentId)) {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
if (!documentId.startsWith(ROOT_DOCUMENT_ID + "/")) {
|
|
||||||
throw new FileNotFoundException("Invalid document id: " + documentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String relativePath = documentId.substring(ROOT_DOCUMENT_ID.length() + 1);
|
|
||||||
final File file = new File(root, relativePath);
|
|
||||||
if (!isInside(root, file)) {
|
|
||||||
throw new FileNotFoundException("Document escapes Dusklight files directory: " + documentId);
|
|
||||||
}
|
|
||||||
if (!file.exists()) {
|
|
||||||
throw new FileNotFoundException("Document does not exist: " + documentId);
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDocumentIdForFile(File file) throws FileNotFoundException {
|
|
||||||
final File root = getRootDirectory();
|
|
||||||
if (sameFile(root, file)) {
|
|
||||||
return ROOT_DOCUMENT_ID;
|
|
||||||
}
|
|
||||||
if (!isInside(root, file)) {
|
|
||||||
throw new FileNotFoundException("File escapes Dusklight files directory: " + file);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String rootPath = canonicalPath(root);
|
|
||||||
final String filePath = canonicalPath(file);
|
|
||||||
return ROOT_DOCUMENT_ID + "/" + filePath.substring(rootPath.length() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureUserDirectories() {
|
|
||||||
final File root = getContext().getFilesDir();
|
|
||||||
if (root == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
new File(root, "texture_replacements").mkdirs();
|
|
||||||
new File(root, "USA/Card A").mkdirs();
|
|
||||||
new File(root, "EUR/Card A").mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isCustomDataPathEnabled() {
|
|
||||||
if (getContext() == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final File filesDir = getContext().getFilesDir();
|
|
||||||
if (filesDir == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final File descriptor = new File(filesDir, LOCATION_DESCRIPTOR_NAME);
|
|
||||||
if (!descriptor.isFile()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final JSONObject json = new JSONObject(readText(descriptor));
|
|
||||||
return "custom".equals(json.optString("mode", "default"));
|
|
||||||
} catch (IOException | JSONException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String readText(File file) throws IOException {
|
|
||||||
try (FileInputStream input = new FileInputStream(file);
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream())
|
|
||||||
{
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = input.read(buffer)) != -1) {
|
|
||||||
output.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
return output.toString(StandardCharsets.UTF_8.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String[] resolveRootProjection(String[] projection) {
|
|
||||||
return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String[] resolveDocumentProjection(String[] projection) {
|
|
||||||
return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String sanitizeDisplayName(String displayName) throws FileNotFoundException {
|
|
||||||
if (displayName == null) {
|
|
||||||
throw new FileNotFoundException("Document name is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
final String sanitized = displayName.trim();
|
|
||||||
if (sanitized.isEmpty() || ".".equals(sanitized) || "..".equals(sanitized) ||
|
|
||||||
sanitized.contains("/") || sanitized.contains("\\"))
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException("Invalid document name: " + displayName);
|
|
||||||
}
|
|
||||||
return sanitized;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File buildUniqueFile(File parent, String displayName) {
|
|
||||||
File file = new File(parent, displayName);
|
|
||||||
if (!file.exists()) {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int dot = displayName.lastIndexOf('.');
|
|
||||||
final String baseName = dot > 0 ? displayName.substring(0, dot) : displayName;
|
|
||||||
final String extension = dot > 0 ? displayName.substring(dot) : "";
|
|
||||||
for (int i = 1; i < 100; ++i) {
|
|
||||||
file = new File(parent, baseName + " (" + i + ")" + extension);
|
|
||||||
if (!file.exists()) {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new File(parent, baseName + " (" + System.currentTimeMillis() + ")" + extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int modeToParcelMode(String mode) {
|
|
||||||
if ("r".equals(mode)) {
|
|
||||||
return ParcelFileDescriptor.MODE_READ_ONLY;
|
|
||||||
}
|
|
||||||
if ("w".equals(mode) || "wt".equals(mode)) {
|
|
||||||
return ParcelFileDescriptor.MODE_WRITE_ONLY |
|
|
||||||
ParcelFileDescriptor.MODE_CREATE |
|
|
||||||
ParcelFileDescriptor.MODE_TRUNCATE;
|
|
||||||
}
|
|
||||||
if ("wa".equals(mode)) {
|
|
||||||
return ParcelFileDescriptor.MODE_WRITE_ONLY |
|
|
||||||
ParcelFileDescriptor.MODE_CREATE |
|
|
||||||
ParcelFileDescriptor.MODE_APPEND;
|
|
||||||
}
|
|
||||||
if ("rw".equals(mode)) {
|
|
||||||
return ParcelFileDescriptor.MODE_READ_WRITE |
|
|
||||||
ParcelFileDescriptor.MODE_CREATE;
|
|
||||||
}
|
|
||||||
if ("rwt".equals(mode)) {
|
|
||||||
return ParcelFileDescriptor.MODE_READ_WRITE |
|
|
||||||
ParcelFileDescriptor.MODE_CREATE |
|
|
||||||
ParcelFileDescriptor.MODE_TRUNCATE;
|
|
||||||
}
|
|
||||||
return ParcelFileDescriptor.MODE_READ_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getMimeType(File file) {
|
|
||||||
final int dot = file.getName().lastIndexOf('.');
|
|
||||||
if (dot >= 0) {
|
|
||||||
final String extension = file.getName().substring(dot + 1).toLowerCase();
|
|
||||||
final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
|
||||||
if (mimeType != null) {
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "application/octet-stream";
|
|
||||||
}
|
|
||||||
|
|
||||||
private Uri getChildDocumentsUri(String parentDocumentId) {
|
|
||||||
return DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyChildrenChanged(String parentDocumentId) {
|
|
||||||
final ContentResolver resolver = getContext().getContentResolver();
|
|
||||||
resolver.notifyChange(getChildDocumentsUri(parentDocumentId), null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyDocumentChanged(String documentId) {
|
|
||||||
final ContentResolver resolver = getContext().getContentResolver();
|
|
||||||
resolver.notifyChange(DocumentsContract.buildDocumentUri(AUTHORITY, documentId), null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void deleteRecursively(File file) throws FileNotFoundException {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
final File[] children = file.listFiles();
|
|
||||||
if (children != null) {
|
|
||||||
for (File child : children) {
|
|
||||||
deleteRecursively(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!file.delete()) {
|
|
||||||
throw new FileNotFoundException("Unable to delete document: " + file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isInside(File parent, File child) {
|
|
||||||
try {
|
|
||||||
final String parentPath = canonicalPath(parent);
|
|
||||||
final String childPath = canonicalPath(child);
|
|
||||||
return childPath.equals(parentPath) || childPath.startsWith(parentPath + File.separator);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean sameFile(File a, File b) {
|
|
||||||
try {
|
|
||||||
return canonicalPath(a).equals(canonicalPath(b));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String canonicalPath(File file) throws FileNotFoundException {
|
|
||||||
try {
|
|
||||||
return file.getCanonicalPath();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw asFileNotFound("Unable to resolve path", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FileNotFoundException asFileNotFound(String message, IOException cause) {
|
|
||||||
final FileNotFoundException exception = new FileNotFoundException(message + ": " + cause.getMessage());
|
|
||||||
exception.initCause(cause);
|
|
||||||
return exception;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
package dev.twilitrealm.dusk;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
|
|
||||||
public final class DuskHttpClient {
|
|
||||||
public static final int ERROR_NONE = 0;
|
|
||||||
public static final int ERROR_INVALID_URL = 1;
|
|
||||||
public static final int ERROR_UNSUPPORTED_SCHEME = 2;
|
|
||||||
public static final int ERROR_TIMEOUT = 3;
|
|
||||||
public static final int ERROR_TOO_LARGE = 4;
|
|
||||||
public static final int ERROR_NETWORK = 5;
|
|
||||||
|
|
||||||
private static final int MAX_REDIRECTS = 5;
|
|
||||||
|
|
||||||
public static final class Response {
|
|
||||||
public int error;
|
|
||||||
public String message;
|
|
||||||
public int statusCode;
|
|
||||||
public String[] headerNames;
|
|
||||||
public String[] headerValues;
|
|
||||||
public byte[] body;
|
|
||||||
|
|
||||||
Response(int error, String message, int statusCode, String[] headerNames,
|
|
||||||
String[] headerValues, byte[] body) {
|
|
||||||
this.error = error;
|
|
||||||
this.message = message;
|
|
||||||
this.statusCode = statusCode;
|
|
||||||
this.headerNames = headerNames != null ? headerNames : new String[0];
|
|
||||||
this.headerValues = headerValues != null ? headerValues : new String[0];
|
|
||||||
this.body = body != null ? body : new byte[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DuskHttpClient() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Response get(String url, String[] headerNames, String[] headerValues,
|
|
||||||
int timeoutMs, long maxBodyBytes) {
|
|
||||||
if (url == null || url.isEmpty()) {
|
|
||||||
return fail(ERROR_INVALID_URL, "URL is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
URL currentUrl = new URL(url);
|
|
||||||
if (!isHttps(currentUrl)) {
|
|
||||||
return fail(ERROR_UNSUPPORTED_SCHEME, "Only https:// URLs are supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int redirect = 0; redirect <= MAX_REDIRECTS; ++redirect) {
|
|
||||||
HttpsURLConnection connection =
|
|
||||||
(HttpsURLConnection) currentUrl.openConnection();
|
|
||||||
try {
|
|
||||||
connection.setRequestMethod("GET");
|
|
||||||
connection.setConnectTimeout(timeoutMs);
|
|
||||||
connection.setReadTimeout(timeoutMs);
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setInstanceFollowRedirects(false);
|
|
||||||
applyHeaders(connection, headerNames, headerValues);
|
|
||||||
|
|
||||||
int statusCode = connection.getResponseCode();
|
|
||||||
if (isRedirect(statusCode)) {
|
|
||||||
String location = connection.getHeaderField("Location");
|
|
||||||
if (location == null || location.isEmpty()) {
|
|
||||||
return fail(ERROR_NETWORK, "Redirect response did not include Location",
|
|
||||||
statusCode, connection, new byte[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
URL nextUrl = new URL(currentUrl, location);
|
|
||||||
if (!isHttps(nextUrl)) {
|
|
||||||
return fail(ERROR_UNSUPPORTED_SCHEME,
|
|
||||||
"Only https:// redirects are supported", statusCode,
|
|
||||||
connection, new byte[0]);
|
|
||||||
}
|
|
||||||
currentUrl = nextUrl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] body = readBody(connection, statusCode, maxBodyBytes);
|
|
||||||
return success(statusCode, connection, body);
|
|
||||||
} catch (ResponseTooLargeException e) {
|
|
||||||
return fail(ERROR_TOO_LARGE, "Response body exceeded the configured limit",
|
|
||||||
safeStatusCode(connection), connection, e.partialBody);
|
|
||||||
} finally {
|
|
||||||
connection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fail(ERROR_NETWORK, "Too many redirects");
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
return fail(ERROR_INVALID_URL, "Failed to parse URL");
|
|
||||||
} catch (SocketTimeoutException e) {
|
|
||||||
return fail(ERROR_TIMEOUT, "Request timed out");
|
|
||||||
} catch (IOException e) {
|
|
||||||
String message = e.getMessage();
|
|
||||||
return fail(ERROR_NETWORK, message != null ? message : e.toString());
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return fail(ERROR_UNSUPPORTED_SCHEME, "Only https:// URLs are supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void applyHeaders(HttpsURLConnection connection, String[] names,
|
|
||||||
String[] values) {
|
|
||||||
if (names == null || values == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = Math.min(names.length, values.length);
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
if (names[i] != null && values[i] != null) {
|
|
||||||
connection.setRequestProperty(names[i], values[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isHttps(URL url) {
|
|
||||||
return "https".equalsIgnoreCase(url.getProtocol());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isRedirect(int statusCode) {
|
|
||||||
return statusCode == HttpURLConnection.HTTP_MOVED_PERM ||
|
|
||||||
statusCode == HttpURLConnection.HTTP_MOVED_TEMP ||
|
|
||||||
statusCode == HttpURLConnection.HTTP_SEE_OTHER ||
|
|
||||||
statusCode == 307 ||
|
|
||||||
statusCode == 308;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] readBody(HttpsURLConnection connection, int statusCode,
|
|
||||||
long maxBodyBytes) throws IOException,
|
|
||||||
ResponseTooLargeException {
|
|
||||||
InputStream stream = statusCode >= HttpURLConnection.HTTP_BAD_REQUEST ?
|
|
||||||
connection.getErrorStream() : connection.getInputStream();
|
|
||||||
if (stream == null) {
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream bodyStream = stream;
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
|
||||||
byte[] buffer = new byte[8192];
|
|
||||||
long total = 0;
|
|
||||||
while (true) {
|
|
||||||
int read = bodyStream.read(buffer);
|
|
||||||
if (read < 0) {
|
|
||||||
return out.toByteArray();
|
|
||||||
}
|
|
||||||
if (read == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (read > maxBodyBytes || total > maxBodyBytes - read) {
|
|
||||||
throw new ResponseTooLargeException(out.toByteArray());
|
|
||||||
}
|
|
||||||
out.write(buffer, 0, read);
|
|
||||||
total += read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int safeStatusCode(HttpsURLConnection connection) {
|
|
||||||
try {
|
|
||||||
return connection.getResponseCode();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Response success(int statusCode, HttpsURLConnection connection, byte[] body) {
|
|
||||||
HeaderLists headers = readHeaders(connection);
|
|
||||||
return new Response(ERROR_NONE, "", statusCode, headers.names, headers.values, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Response fail(int error, String message) {
|
|
||||||
return new Response(error, message, 0, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Response fail(int error, String message, int statusCode,
|
|
||||||
HttpsURLConnection connection, byte[] body) {
|
|
||||||
HeaderLists headers = readHeaders(connection);
|
|
||||||
return new Response(error, message, statusCode, headers.names, headers.values, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HeaderLists readHeaders(HttpsURLConnection connection) {
|
|
||||||
List<String> names = new ArrayList<>();
|
|
||||||
List<String> values = new ArrayList<>();
|
|
||||||
|
|
||||||
Map<String, List<String>> headerFields = connection.getHeaderFields();
|
|
||||||
if (headerFields == null) {
|
|
||||||
return new HeaderLists(new String[0], new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, List<String>> entry : headerFields.entrySet()) {
|
|
||||||
String name = entry.getKey();
|
|
||||||
if (name == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
List<String> entryValues = entry.getValue();
|
|
||||||
if (entryValues == null || entryValues.isEmpty()) {
|
|
||||||
names.add(name);
|
|
||||||
values.add("");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (String value : entryValues) {
|
|
||||||
names.add(name);
|
|
||||||
values.add(value != null ? value : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new HeaderLists(names.toArray(new String[0]), values.toArray(new String[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class HeaderLists {
|
|
||||||
final String[] names;
|
|
||||||
final String[] values;
|
|
||||||
|
|
||||||
HeaderLists(String[] names, String[] values) {
|
|
||||||
this.names = names;
|
|
||||||
this.values = values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ResponseTooLargeException extends Exception {
|
|
||||||
final byte[] partialBody;
|
|
||||||
|
|
||||||
ResponseTooLargeException(byte[] partialBody) {
|
|
||||||
this.partialBody = partialBody;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -256,7 +256,6 @@ public class HIDDeviceManager {
|
|||||||
0x24c6, // PowerA
|
0x24c6, // PowerA
|
||||||
0x2c22, // Qanba
|
0x2c22, // Qanba
|
||||||
0x2dc8, // 8BitDo
|
0x2dc8, // 8BitDo
|
||||||
0x37d7, // Flydigi
|
|
||||||
0x9886, // ASTRO Gaming
|
0x9886, // ASTRO Gaming
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
private static final String TAG = "SDL";
|
private static final String TAG = "SDL";
|
||||||
private static final int SDL_MAJOR_VERSION = 3;
|
private static final int SDL_MAJOR_VERSION = 3;
|
||||||
private static final int SDL_MINOR_VERSION = 4;
|
private static final int SDL_MINOR_VERSION = 4;
|
||||||
private static final int SDL_MICRO_VERSION = 4;
|
private static final int SDL_MICRO_VERSION = 2;
|
||||||
/*
|
/*
|
||||||
// Display InputType.SOURCE/CLASS of events and devices
|
// Display InputType.SOURCE/CLASS of events and devices
|
||||||
//
|
//
|
||||||
@@ -2032,7 +2032,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
try {
|
try {
|
||||||
ParcelFileDescriptor pfd = mSingleton.getContentResolver().openFileDescriptor(Uri.parse(uri), mode);
|
ParcelFileDescriptor pfd = mSingleton.getContentResolver().openFileDescriptor(Uri.parse(uri), mode);
|
||||||
return pfd != null ? pfd.detachFd() : -1;
|
return pfd != null ? pfd.detachFd() : -1;
|
||||||
} catch (FileNotFoundException | SecurityException e) {
|
} catch (FileNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -2227,3 +2227,4 @@ class SDLClipboardHandler implements
|
|||||||
SDLActivity.onNativeClipboardChanged();
|
SDLActivity.onNativeClipboardChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,15 +65,17 @@ class SDLInputConnection extends BaseInputConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||||
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection
|
if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) {
|
||||||
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection
|
||||||
if (beforeLength > 0 && afterLength == 0) {
|
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
||||||
// backspace(s)
|
if (beforeLength > 0 && afterLength == 0) {
|
||||||
while (beforeLength-- > 0) {
|
// backspace(s)
|
||||||
nativeGenerateScancodeForUnichar('\b');
|
while (beforeLength-- > 0) {
|
||||||
}
|
nativeGenerateScancodeForUnichar('\b');
|
||||||
return true;
|
}
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
View.OnApplyWindowInsetsListener, View.OnKeyListener, View.OnTouchListener,
|
View.OnApplyWindowInsetsListener, View.OnKeyListener, View.OnTouchListener,
|
||||||
SensorEventListener, ScaleGestureDetector.OnScaleGestureListener {
|
SensorEventListener, ScaleGestureDetector.OnScaleGestureListener {
|
||||||
|
|
||||||
private static native void auroraNativeSetSurfaceReady(boolean ready);
|
|
||||||
|
|
||||||
// Sensors
|
// Sensors
|
||||||
protected SensorManager mSensorManager;
|
protected SensorManager mSensorManager;
|
||||||
protected Display mDisplay;
|
protected Display mDisplay;
|
||||||
@@ -98,7 +96,6 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
Log.v("SDL", "surfaceCreated()");
|
Log.v("SDL", "surfaceCreated()");
|
||||||
auroraNativeSetSurfaceReady(false);
|
|
||||||
SDLActivity.onNativeSurfaceCreated();
|
SDLActivity.onNativeSurfaceCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +103,6 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
@Override
|
@Override
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
Log.v("SDL", "surfaceDestroyed()");
|
Log.v("SDL", "surfaceDestroyed()");
|
||||||
auroraNativeSetSurfaceReady(false);
|
|
||||||
|
|
||||||
// Transition to pause, if needed
|
// Transition to pause, if needed
|
||||||
SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
|
SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
|
||||||
@@ -196,7 +192,6 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
/* Surface is ready */
|
/* Surface is ready */
|
||||||
mIsSurfaceReady = true;
|
mIsSurfaceReady = true;
|
||||||
auroraNativeSetSurfaceReady(true);
|
|
||||||
|
|
||||||
SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
|
SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
|
||||||
SDLActivity.handleNativeState();
|
SDLActivity.handleNativeState();
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Dusklight</string>
|
<string name="app_name">Dusk</string>
|
||||||
<string name="documents_provider_root_name">Dusklight Data</string>
|
|
||||||
<string name="documents_provider_summary">Saves, texture packs, settings, and logs</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -14,22 +14,9 @@ if [[ -z "$ANDROID_NDK_VER" ]] && [[ -d "$ANDROID_HOME_DIR/ndk" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$ANDROID_NDK_VER" ]]; then
|
if [[ -n "$ANDROID_NDK_VER" ]]; then
|
||||||
case "$(uname -s)" in
|
TOOLCHAIN_BIN="$ANDROID_HOME_DIR/ndk/$ANDROID_NDK_VER/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
||||||
Darwin) HOST_TAG="darwin-x86_64" ;;
|
if [[ -x "$TOOLCHAIN_BIN/llvm-strip" ]]; then
|
||||||
Linux) HOST_TAG="linux-x86_64" ;;
|
STRIP_TOOL="$TOOLCHAIN_BIN/llvm-strip"
|
||||||
*) HOST_TAG="" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
PREBUILT_DIR="$ANDROID_HOME_DIR/ndk/$ANDROID_NDK_VER/toolchains/llvm/prebuilt"
|
|
||||||
if [[ -n "$HOST_TAG" && -x "$PREBUILT_DIR/$HOST_TAG/bin/llvm-strip" ]]; then
|
|
||||||
STRIP_TOOL="$PREBUILT_DIR/$HOST_TAG/bin/llvm-strip"
|
|
||||||
else
|
|
||||||
for candidate in "$PREBUILT_DIR"/*/bin/llvm-strip; do
|
|
||||||
if [[ -x "$candidate" ]]; then
|
|
||||||
STRIP_TOOL="$candidate"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -38,35 +25,29 @@ copy_lib() {
|
|||||||
local src="$2"
|
local src="$2"
|
||||||
local dst_dir="$APP_DIR/$abi"
|
local dst_dir="$APP_DIR/$abi"
|
||||||
local dst="$dst_dir/libmain.so"
|
local dst="$dst_dir/libmain.so"
|
||||||
local tmp="$dst_dir/.libmain.so.$$"
|
|
||||||
if [[ ! -f "$src" ]]; then
|
|
||||||
echo "Missing native library for $abi: $src" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$dst_dir"
|
mkdir -p "$dst_dir"
|
||||||
cp -f "$src" "$tmp"
|
cp -f "$src" "$dst"
|
||||||
if [[ "$ANDROID_STAGE_STRIP" != "0" ]] && [[ -n "$STRIP_TOOL" ]]; then
|
if [[ "$ANDROID_STAGE_STRIP" != "0" ]] && [[ -n "$STRIP_TOOL" ]]; then
|
||||||
"$STRIP_TOOL" --strip-unneeded "$tmp"
|
"$STRIP_TOOL" --strip-debug "$dst"
|
||||||
mv -f "$tmp" "$dst"
|
echo "Staged and stripped $src -> $dst"
|
||||||
echo "Stripped and staged $src -> $dst"
|
|
||||||
else
|
else
|
||||||
mv -f "$tmp" "$dst"
|
|
||||||
echo "Staged $src -> $dst (strip disabled or strip tool unavailable)"
|
echo "Staged $src -> $dst (strip disabled or strip tool unavailable)"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare -A ABI_TO_LIB=(
|
||||||
|
["arm64-v8a"]="$ROOT_DIR/build/android-arm64/libmain.so"
|
||||||
|
["x86_64"]="$ROOT_DIR/build/android-x86_64/libmain.so"
|
||||||
|
)
|
||||||
|
|
||||||
# Drop any previously staged ABI directories to avoid stale APK contents.
|
# Drop any previously staged ABI directories to avoid stale APK contents.
|
||||||
rm -rf "$APP_DIR/x86" "$APP_DIR/arm64-v8a" "$APP_DIR/x86_64"
|
rm -rf "$APP_DIR/x86" "$APP_DIR/arm64-v8a" "$APP_DIR/x86_64"
|
||||||
|
|
||||||
for abi in $ANDROID_STAGE_ABIS; do
|
for abi in $ANDROID_STAGE_ABIS; do
|
||||||
case "$abi" in
|
src="${ABI_TO_LIB[$abi]:-}"
|
||||||
arm64-v8a) src="$ROOT_DIR/build/android-arm64/libmain.so" ;;
|
if [[ -z "$src" ]]; then
|
||||||
x86_64) src="$ROOT_DIR/build/android-x86_64/libmain.so" ;;
|
echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2
|
||||||
*)
|
exit 1
|
||||||
echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2
|
fi
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
copy_lib "$abi" "$src"
|
copy_lib "$abi" "$src"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = "dusklight-android"
|
rootProject.name = "dusk-android"
|
||||||
include ':app'
|
include ':app'
|
||||||
|
|||||||
|
After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 928 KiB |
|
After Width: | Height: | Size: 306 B |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 79 B |
|
Before Width: | Height: | Size: 1014 B |
|
After Width: | Height: | Size: 761 B |
|
Before Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 99 B |