Compare commits
362 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8280ac00a0 | |||
| 45ef0d72b1 | |||
| ad9c460ec9 | |||
| 23dc9bc39a | |||
| bf23d44389 | |||
| d0b9b6d10f | |||
| 2f83753260 | |||
| eeb0ad77a4 | |||
| 594cadcf7d | |||
| 4290726691 | |||
| 80dd5ff278 | |||
| 08efb9a3cf | |||
| d8a1dd1da4 | |||
| 13dd3c3932 | |||
| dd7885da9c | |||
| 5a05433a2b | |||
| c3ff3884d7 | |||
| e42c4d3174 | |||
| 06c77a6818 | |||
| 4d4a80891f | |||
| 71c892368d | |||
| d2a1dda523 | |||
| 78179eb93f | |||
| 34e10d3844 | |||
| 65e8577253 | |||
| a4fcc10f5f | |||
| a2c2988666 | |||
| abec043249 | |||
| 699d069b0a | |||
| 4d67033ff8 | |||
| 84ffd67622 | |||
| 1c85ee63eb | |||
| 81c7213993 | |||
| be82e606b2 | |||
| 44da1a9f7d | |||
| d0f8ea56f9 | |||
| e472b36cef | |||
| 3934e09c8f | |||
| 3136816ce9 | |||
| 6fd3762ffc | |||
| 97a1190713 | |||
| 73a3bd9ae8 | |||
| fc533dbdc7 | |||
| 6217e071d2 | |||
| 673ca7f686 | |||
| 29a1cff7ea | |||
| 3c5152a67b | |||
| 1c1a849095 | |||
| 89d393e57a | |||
| 2f27687d80 | |||
| 167a50c01d | |||
| 313f03f5e5 | |||
| 6cfdc3d8a3 | |||
| 9c24a0bc4b | |||
| b99ad920c4 | |||
| 912b18eca1 | |||
| 9e651a51db | |||
| c8b6e997a7 | |||
| 928e187524 | |||
| cf12d19860 | |||
| e3a3ac56fb | |||
| d15ed81cd5 | |||
| ff054f6f47 | |||
| 667cf70fa0 | |||
| 73eb401c93 | |||
| b11f3add06 | |||
| 92f888a152 | |||
| 78ed5cc716 | |||
| 3968b67c5d | |||
| 119830c979 | |||
| 647394c875 | |||
| c50d777309 | |||
| 4954685cca | |||
| 39d43a8d8f | |||
| b4761cc54e | |||
| 9aee2e9cfe | |||
| 7c7c8b228e | |||
| ca7714dafd | |||
| 1ad5ab8632 | |||
| c4e7838089 | |||
| 7313712263 | |||
| aa48d95f24 | |||
| c5baabbe9c | |||
| 1d2716139f | |||
| 742ad2c150 | |||
| 18eb0692f0 | |||
| b5f98f69db | |||
| 47593d0eb4 | |||
| 4404fce369 | |||
| 72c20f4dd0 | |||
| 3240885bfd | |||
| 7f0955f022 | |||
| c21bce0093 | |||
| 4e23472ed5 | |||
| cfe1f2304b | |||
| de6568d750 | |||
| 3aafe7fa16 | |||
| c1e65d19e7 | |||
| 5fdf954994 | |||
| 230868af3c | |||
| 66154d9de8 | |||
| 93ec3c7dbd | |||
| 945ce3e4bc | |||
| 782a8573e9 | |||
| 4e0ca51159 | |||
| 3cd160e1b2 | |||
| 93a236a9d2 | |||
| eaf3bc2f40 | |||
| 5ca0a2ba06 | |||
| ccd2bdbaac | |||
| 08321699cd | |||
| 7300c0e0f5 | |||
| 7e562824fe | |||
| ed8b5c96b9 | |||
| 14bccdffa6 | |||
| 39e465bcab | |||
| e53bb3a12d | |||
| 50fccd393f | |||
| 7993740ac8 | |||
| 8e5bb8ae59 | |||
| 8fefdd4114 | |||
| 64c8cee21b | |||
| 25fe686573 | |||
| 1c1ea98fdd | |||
| e098104f8f | |||
| 3c5ade5565 | |||
| b2ad75027e | |||
| fdfbf83b88 | |||
| 1b9ca0949e | |||
| 827037f0fa | |||
| d84c5790f5 | |||
| 49eb2282af | |||
| 741f9ecfab | |||
| 37b8122962 | |||
| 5f2cf68e80 | |||
| 74f2c58b29 | |||
| 208433047a | |||
| 2c01430035 | |||
| 5121437bcf | |||
| f61bd3e5ad | |||
| 835e409b32 | |||
| 010bdb7e25 | |||
| 7ba22b7714 | |||
| efcb19a3d0 | |||
| 55455bb1b5 | |||
| e49be12297 | |||
| 75f4940f5e | |||
| 8047330952 | |||
| 9105dcb078 | |||
| b8e38e03e2 | |||
| 331352878e | |||
| 62a88f1e9a | |||
| 43b603e70b | |||
| 95e6ac54cf | |||
| c4b2e2e501 | |||
| dccba23980 | |||
| bf27d10519 | |||
| 6c27011e32 | |||
| 6220990dc5 | |||
| 93e9767c9f | |||
| c774f53dad | |||
| 7fbfe5ad88 | |||
| ef02037990 | |||
| 23cc18ba0e | |||
| 924dbc7715 | |||
| 742f4938f2 | |||
| 02e0f586d3 | |||
| 5717aeef85 | |||
| da9b99f650 | |||
| 901ce2ee4c | |||
| dd2b993cd5 | |||
| 83577d3b82 | |||
| 1cb8b19520 | |||
| d109cd891e | |||
| 63c4002ca6 | |||
| 6954efcd15 | |||
| 78c2147771 | |||
| c938d5468e | |||
| 35590c5312 | |||
| e976b10e2a | |||
| 3949706b28 | |||
| ce55916845 | |||
| 9b252cbdd2 | |||
| 97fa09f6ee | |||
| 0e7a7cccb9 | |||
| 1c0cdcc176 | |||
| 280305c2ba | |||
| d1f1d579bc | |||
| eeeb3ffe25 | |||
| 1ee0f862e1 | |||
| 6b327c9f61 | |||
| f148e0ebc1 | |||
| 6f20f4d629 | |||
| 94670270d6 | |||
| 8e21247a97 | |||
| aa84004cb4 | |||
| e1c201f4bd | |||
| 425a1d15a0 | |||
| e3ad41792a | |||
| c1ba10fc8b | |||
| 1c5686f71b | |||
| b9e0f2b9ca | |||
| ede175f141 | |||
| a301874e30 | |||
| 9b4a9a6bd9 | |||
| 04274b1884 | |||
| ca783b8424 | |||
| 2e4c2b5b46 | |||
| 4c09d8b910 | |||
| fb1b260d09 | |||
| 98eb8f718e | |||
| 68b2e0ee2d | |||
| 81771a0522 | |||
| 93c8bcc210 | |||
| 176bf5f0c4 | |||
| 65a5945778 | |||
| 8f7b9cdfdd | |||
| acecba7ff7 | |||
| 507e0aadbc | |||
| 8406d9b192 | |||
| 6f3170cb56 | |||
| 835582224e | |||
| 52879f50f0 | |||
| 2b505f1be4 | |||
| f089f9024d | |||
| 43fb421a93 | |||
| f06d6b50a9 | |||
| 2c987b0211 | |||
| 3d860ad454 | |||
| b5bf19569b | |||
| 5a7f5cb4a7 | |||
| 1affefbbfc | |||
| e4ff38a712 | |||
| f2ac4d6f44 | |||
| 48b98a5432 | |||
| a4752154f7 | |||
| 0d973a497b | |||
| ab4eccf1df | |||
| e0c449f28e | |||
| ce9a5c06d5 | |||
| 2bbba1e4e8 | |||
| 39298f8d8f | |||
| 32b4c0567a | |||
| 7ff1b5332e | |||
| 5e77a60bd6 | |||
| 9629c000bd | |||
| 9dc5fed686 | |||
| 2cc9db77dd | |||
| 8aa08c9443 | |||
| dca3e2eba6 | |||
| 57061fba38 | |||
| cee6a24309 | |||
| 62edb3abc6 | |||
| 1c9e1c0a66 | |||
| a06aeb10c1 | |||
| b84b309e00 | |||
| 62eecb3ccd | |||
| ec07572ced | |||
| b45e2fa34d | |||
| 289a718446 | |||
| 292a2a6c34 | |||
| 2e8415b950 | |||
| dbf1f6e354 | |||
| 9a2fe9745d | |||
| b5ca343fac | |||
| 88c7ff63ff | |||
| 7a438ad30f | |||
| 89649de7c3 | |||
| a1960eaa33 | |||
| d6820c9233 | |||
| 5c4bb8d33d | |||
| e3ce1f01c9 | |||
| 9b6b344ecf | |||
| 3db85d5b44 | |||
| b5871d72d9 | |||
| b70a714f88 | |||
| cad5a8d1bc | |||
| 93f8a5fa8f | |||
| b0809ea78c | |||
| b0e9033736 | |||
| 1ac6df8de7 | |||
| 5899b2157a | |||
| 44f3828f68 | |||
| 3f560b060c | |||
| 3185f578fb | |||
| 4fc09799b6 | |||
| fe0e3cad72 | |||
| 37d1aa7f40 | |||
| 4a12554bf4 | |||
| fecd1d5683 | |||
| bce9bf6fd9 | |||
| fbf63b075a | |||
| b86d6e90e2 | |||
| 6425b452e7 | |||
| 1657fe8083 | |||
| ecd74a4cbd | |||
| 36dc43c602 | |||
| d92515f0d4 | |||
| f147dcac0c | |||
| ee4c84f39b | |||
| b8a83c6f59 | |||
| 4462c0ef69 | |||
| c803bfb545 | |||
| 2623c44cab | |||
| 24dd02fc81 | |||
| a97602b6dc | |||
| e2943e90dc | |||
| 3cb7fbd030 | |||
| afe54f22ab | |||
| e15f5bcee9 | |||
| 1e372a856d | |||
| b26896cad5 | |||
| f75faf6b06 | |||
| b48d9aa052 | |||
| d899706208 | |||
| 3e05789b58 | |||
| 9a7b62cbc6 | |||
| 8e0f0e878e | |||
| 79344edf0d | |||
| e59bfd1a9c | |||
| 4d12cc8ea2 | |||
| 2ed2268579 | |||
| 94a99e8da0 | |||
| ddaf50c01d | |||
| 7566949b42 | |||
| bb6db3caea | |||
| 2dc494dc1c | |||
| 3c25633ee9 | |||
| d99ed2729b | |||
| 782455d48b | |||
| 47863b34c2 | |||
| 92391d5eb8 | |||
| 0d37cb4e54 | |||
| ea528ed9d9 | |||
| f7b880c5ea | |||
| ff78bc8d6c | |||
| 6503b4e7eb | |||
| 8fb4ba8924 | |||
| 5f675c6f2b | |||
| b3333241c5 | |||
| e39079c0f8 | |||
| c3317d9232 | |||
| 025cb58493 | |||
| b3dee825e8 | |||
| f6c5aac3c8 | |||
| 25e9064d09 | |||
| 3e1e8f1244 | |||
| eaae8b6137 | |||
| 0bf663141a | |||
| d7dced7ddf | |||
| 78b0563c0e | |||
| 871d18e294 | |||
| c157564da6 | |||
| ecc3b00c51 | |||
| 8afb1141ab | |||
| 8c5673d9b8 | |||
| 916dfcd9da | |||
| d9a0ef760f | |||
| 842210e539 | |||
| 39d951d0cb | |||
| a4be0841e5 | |||
| 95470b830f |
@@ -2,7 +2,7 @@
|
|||||||
Language: Cpp
|
Language: Cpp
|
||||||
Standard: C++03
|
Standard: C++03
|
||||||
AccessModifierOffset: -4
|
AccessModifierOffset: -4
|
||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: DontAlign
|
||||||
AlignConsecutiveAssignments: false
|
AlignConsecutiveAssignments: false
|
||||||
AlignConsecutiveDeclarations: false
|
AlignConsecutiveDeclarations: false
|
||||||
AlignOperands: true
|
AlignOperands: true
|
||||||
|
|||||||
@@ -48,13 +48,15 @@ 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]+)(-([0-9]+).*)?$")
|
if (DUSK_WC_DESCRIBE MATCHES "^v([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}")
|
||||||
if (CMAKE_MATCH_5)
|
set(DUSK_VERSION_TWEAK "0")
|
||||||
set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.${CMAKE_MATCH_5}")
|
if (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-([0-9]+)(-dirty)?$")
|
||||||
else ()
|
set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}")
|
||||||
set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.0")
|
elseif (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-[0-9A-Za-z.-]+-([0-9]+)(-dirty)?$")
|
||||||
|
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")
|
||||||
@@ -69,7 +71,7 @@ message(STATUS "Dusk version set to ${DUSK_WC_DESCRIBE}")
|
|||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
project(dusk LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
|
project(dusk LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
enable_language(OBJC)
|
enable_language(OBJC OBJCXX)
|
||||||
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
|
||||||
@@ -100,20 +102,19 @@ 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)
|
||||||
@@ -282,9 +283,9 @@ 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("dusk" FILES ${DUSK_FILES})
|
source_group("dusk" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES})
|
||||||
|
|
||||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0)
|
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
|
||||||
|
|
||||||
set(GAME_INCLUDE_DIRS
|
set(GAME_INCLUDE_DIRS
|
||||||
include
|
include
|
||||||
@@ -296,8 +297,10 @@ 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)
|
||||||
|
|
||||||
@@ -310,6 +313,41 @@ 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 "dusk: 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 "dusk: 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 "dusk: 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 "dusk: Enabled update checker (libcurl)")
|
||||||
|
else ()
|
||||||
|
message(STATUS "dusk: Disabled update checker (libcurl + HTTPS/SSL not found)")
|
||||||
|
endif ()
|
||||||
|
else ()
|
||||||
|
message(STATUS "dusk: 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)
|
||||||
@@ -319,46 +357,13 @@ if (DUSK_MOVIE_SUPPORT)
|
|||||||
list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1)
|
list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
option(DUSK_ENABLE_DISCORD_RPC "Enable Discord Rich Presence support" ON)
|
set(DUSK_ENABLE_DISCORD_DEFAULT ON)
|
||||||
if (DUSK_ENABLE_DISCORD_RPC AND NOT ANDROID AND NOT IOS AND NOT TVOS)
|
if (DEFINED DUSK_ENABLE_DISCORD_RPC AND NOT DEFINED DUSK_ENABLE_DISCORD)
|
||||||
|
set(DUSK_ENABLE_DISCORD_DEFAULT ${DUSK_ENABLE_DISCORD_RPC})
|
||||||
FetchContent_Populate(discord_rpc
|
endif ()
|
||||||
URL https://github.com/discord/discord-rpc/archive/refs/tags/v3.4.0.tar.gz
|
option(DUSK_ENABLE_DISCORD "Enable Discord Rich Presence support" ${DUSK_ENABLE_DISCORD_DEFAULT})
|
||||||
URL_HASH SHA256=e13427019027acd187352dacba6c65953af66fdf3c35fcf38fc40b454a9d7855
|
if (DUSK_ENABLE_DISCORD AND NOT ANDROID AND NOT IOS AND NOT TVOS)
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
list(APPEND GAME_COMPILE_DEFS DUSK_DISCORD=1)
|
||||||
)
|
|
||||||
# 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 ()
|
||||||
|
|
||||||
# Edit & Continue
|
# Edit & Continue
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
|
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
|
||||||
"DUSK_ENABLE_SENTRY_NATIVE": {
|
"DUSK_ENABLE_SENTRY_NATIVE": {
|
||||||
"type": "BOOL",
|
"type": "BOOL",
|
||||||
"value": true
|
"value": false
|
||||||
},
|
},
|
||||||
"DUSK_SENTRY_DSN": "$env{SENTRY_DSN}",
|
"DUSK_SENTRY_DSN": "$env{SENTRY_DSN}",
|
||||||
"DUSK_SENTRY_ENVIRONMENT": "production"
|
"DUSK_SENTRY_ENVIRONMENT": "production"
|
||||||
|
|||||||
@@ -1,31 +1,66 @@
|
|||||||

|
<div align="center">
|
||||||
|
<img src="res/logo-mascot.png" alt="Logo" width="640">
|
||||||
|
|
||||||
- ### **[Official Website](https://twilitrealm.dev)**
|
<p align="center">
|
||||||
- ### **[Discord](https://discord.gg/QACynxeyna)**
|
<a href="https://twilitrealm.dev">Official Website</a>
|
||||||
|
•
|
||||||
|
<a href="https://discord.gg/dusktp">Discord</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
Dusk 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.**
|
|
||||||
|
|
||||||
### 1. Verify your ROM dump
|
> [!IMPORTANT]
|
||||||
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.
|
> Dusk does *not* provide any copyrighted assets. You must provide your own copy of the original game.
|
||||||
|
|
||||||
| Version | sha1 hash |
|
### 1. Verify your dump
|
||||||
|--------------| ---------------------------------------- |
|
|
||||||
| GameCube USA | 75edd3ddff41f125d1b4ce1a40378f1b565519e7 |
|
First, make sure your dump of the game is clean and supported by Dusk. You can do this by checking the SHA-1 hash of your dump against this list of supported versions:
|
||||||
| GameCube PAL | 2601822a488eeb86fb89db16ca8f29c2c953e1ca |
|
|
||||||
|
| Version | SHA-1 hash |
|
||||||
|
|--------------| ------------------------------------------ |
|
||||||
|
| GameCube USA | `75edd3ddff41f125d1b4ce1a40378f1b565519e7` |
|
||||||
|
| GameCube EUR | `2601822a488eeb86fb89db16ca8f29c2c953e1ca` |
|
||||||
|
|
||||||
|
*Support for other versions of the game is planned in the future.
|
||||||
|
|
||||||
### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases)
|
### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases)
|
||||||
|
|
||||||
### 3. Setup the game
|
### 3. Setup the game
|
||||||
- Extract the zip folder
|
**Windows / macOS / Linux**
|
||||||
|
- Extract the .zip file
|
||||||
- Launch Dusk
|
- Launch Dusk
|
||||||
- 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 Dusk apk
|
||||||
|
- Launch Dusk
|
||||||
|
- 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 Dusk 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.
|
||||||
|
|
||||||
# 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/dusk/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>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 85 KiB |
@@ -0,0 +1,66 @@
|
|||||||
|
<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>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,46 @@
|
|||||||
|
# Installing Dusk on iOS via AltStore
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Mac with Homebrew installed
|
||||||
|
- iPhone connected via USB
|
||||||
|
- Dusk IPA file (download the latest `Dusk-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
|
||||||
@@ -1429,11 +1429,15 @@ 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/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
|
||||||
@@ -1446,31 +1450,79 @@ set(DUSK_FILES
|
|||||||
src/dusk/imgui/ImGuiBloomWindow.hpp
|
src/dusk/imgui/ImGuiBloomWindow.hpp
|
||||||
src/dusk/imgui/ImGuiMenuTools.cpp
|
src/dusk/imgui/ImGuiMenuTools.cpp
|
||||||
src/dusk/imgui/ImGuiMenuTools.hpp
|
src/dusk/imgui/ImGuiMenuTools.hpp
|
||||||
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/imgui/ImGuiAchievements.hpp
|
src/dusk/ui/achievements.cpp
|
||||||
src/dusk/imgui/ImGuiAchievements.cpp
|
src/dusk/ui/achievements.hpp
|
||||||
|
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/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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|||||||
@@ -4552,6 +4552,18 @@ 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,6 +80,12 @@ 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,6 +73,12 @@ 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,6 +81,15 @@ 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,6 +74,12 @@ 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,6 +63,15 @@ 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,6 +77,12 @@ 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,6 +27,7 @@ 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,6 +31,10 @@ 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;
|
||||||
@@ -42,6 +46,14 @@ 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,6 +25,10 @@ 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)
|
||||||
};
|
};
|
||||||
@@ -50,6 +54,13 @@ 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,6 +118,18 @@ 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 {
|
||||||
@@ -1028,6 +1040,8 @@ 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);
|
||||||
@@ -1376,6 +1390,10 @@ 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,6 +1845,12 @@ 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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,10 @@ 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,6 +81,10 @@ 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();
|
||||||
|
|
||||||
@@ -165,6 +169,12 @@ 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;
|
||||||
@@ -330,6 +340,10 @@ 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,6 +66,16 @@ 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,6 +67,9 @@ 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,6 +486,9 @@ 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,16 +4,18 @@
|
|||||||
#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 {
|
||||||
Story,
|
|
||||||
Collection,
|
|
||||||
Challenge,
|
Challenge,
|
||||||
|
Collection,
|
||||||
Minigame,
|
Minigame,
|
||||||
|
Misc,
|
||||||
Glitched
|
Glitched
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,10 +42,13 @@ 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 {
|
||||||
@@ -57,9 +62,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
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#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();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,18 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef DUSK_DISCORD_RPC
|
#ifdef DUSK_DISCORD
|
||||||
|
|
||||||
namespace dusk {
|
namespace dusk::discord {
|
||||||
namespace discord {
|
|
||||||
|
|
||||||
void Initialize();
|
void initialize();
|
||||||
|
void run_callbacks();
|
||||||
|
void update_presence();
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
void RunCallbacks();
|
} // namespace dusk::discord
|
||||||
|
|
||||||
void UpdatePresence();
|
#endif // DUSK_DISCORD
|
||||||
|
|
||||||
void Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // DUSK_DISCORD_RPC
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ 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,14 +1,27 @@
|
|||||||
#ifndef DUSK_MAIN_H
|
#ifndef DUSK_MAIN_H
|
||||||
#define DUSK_MAIN_H
|
#define DUSK_MAIN_H
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DUSK_MAIN_H
|
#endif // DUSK_MAIN_H
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
struct RoomEntry {
|
struct RoomEntry {
|
||||||
u8 roomNo;
|
u8 roomNo;
|
||||||
std::vector<s16> roomPoints = {};
|
std::vector<s16> roomPoints = {};
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
#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
|
||||||
@@ -19,139 +16,6 @@ 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_
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#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
|
||||||
@@ -21,6 +21,17 @@ 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> {
|
||||||
@@ -33,6 +44,18 @@ 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
|
||||||
@@ -45,6 +68,8 @@ 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 {
|
||||||
@@ -55,6 +80,8 @@ 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
|
||||||
@@ -65,7 +92,6 @@ 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;
|
||||||
@@ -80,14 +106,15 @@ 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> disableMainHUD;
|
ConfigVar<bool> minimalHUD;
|
||||||
ConfigVar<bool> pauseOnFocusLost;
|
ConfigVar<bool> pauseOnFocusLost;
|
||||||
ConfigVar<bool> enableLinkDollRotation;
|
ConfigVar<bool> enableLinkDollRotation;
|
||||||
ConfigVar<bool> enableAchievementNotifications;
|
ConfigVar<bool> enableAchievementToasts;
|
||||||
|
ConfigVar<bool> enableControllerToasts;
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
ConfigVar<BloomMode> bloomMode;
|
ConfigVar<BloomMode> bloomMode;
|
||||||
@@ -104,6 +131,7 @@ struct UserSettings {
|
|||||||
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;
|
||||||
@@ -117,6 +145,9 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> invertCameraXAxis;
|
ConfigVar<bool> invertCameraXAxis;
|
||||||
ConfigVar<bool> invertCameraYAxis;
|
ConfigVar<bool> invertCameraYAxis;
|
||||||
ConfigVar<float> freeCameraSensitivity;
|
ConfigVar<float> freeCameraSensitivity;
|
||||||
|
ConfigVar<bool> debugFlyCam;
|
||||||
|
ConfigVar<bool> debugFlyCamLockEvents;
|
||||||
|
ConfigVar<bool> allowBackgroundInput;
|
||||||
|
|
||||||
// Cheats
|
// Cheats
|
||||||
ConfigVar<bool> infiniteHearts;
|
ConfigVar<bool> infiniteHearts;
|
||||||
@@ -143,17 +174,20 @@ struct UserSettings {
|
|||||||
// Tools
|
// Tools
|
||||||
ConfigVar<bool> speedrunMode;
|
ConfigVar<bool> speedrunMode;
|
||||||
ConfigVar<bool> liveSplitEnabled;
|
ConfigVar<bool> liveSplitEnabled;
|
||||||
|
ConfigVar<bool> recordingMode;
|
||||||
} 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> enableCrashReporting;
|
ConfigVar<bool> enableCrashReporting;
|
||||||
ConfigVar<bool> duskMenuOpen;
|
ConfigVar<bool> checkForUpdates;
|
||||||
ConfigVar<int> cardFileType;
|
ConfigVar<int> cardFileType;
|
||||||
|
ConfigVar<bool> enableAdvancedSettings;
|
||||||
} backend;
|
} backend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
#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,6 +5,7 @@
|
|||||||
#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:
|
||||||
@@ -132,6 +133,18 @@ 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,6 +59,9 @@ 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,13 +127,6 @@ 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,15 +61,6 @@ 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,4 +207,11 @@ 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,6 +24,9 @@ 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,6 +40,9 @@ 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,6 +75,7 @@ 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; }
|
||||||
@@ -82,7 +83,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
|
||||||
&& field_0x2c == other.field_0x2c
|
&& mPalette == other.mPalette
|
||||||
&& mWrapS == other.mWrapS
|
&& mWrapS == other.mWrapS
|
||||||
&& mWrapT == other.mWrapT
|
&& mWrapT == other.mWrapT
|
||||||
&& mMinFilter == other.mMinFilter
|
&& mMinFilter == other.mMinFilter
|
||||||
@@ -100,7 +101,7 @@ private:
|
|||||||
/* 0x20 */ const ResTIMG* mTexInfo;
|
/* 0x20 */ const ResTIMG* mTexInfo;
|
||||||
/* 0x24 */ void* mTexData;
|
/* 0x24 */ void* mTexData;
|
||||||
/* 0x28 */ JUTPalette* mEmbPalette;
|
/* 0x28 */ JUTPalette* mEmbPalette;
|
||||||
/* 0x2C */ JUTPalette* field_0x2c;
|
/* 0x2C */ JUTPalette* mPalette;
|
||||||
/* 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,6 +1,9 @@
|
|||||||
#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"
|
||||||
@@ -170,7 +173,12 @@ 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;
|
||||||
switch (JASDriver::getOutputMode()) {
|
#if TARGET_PC
|
||||||
|
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,7 +302,6 @@ 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,6 +442,7 @@ 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,11 +10,6 @@
|
|||||||
#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;
|
||||||
@@ -76,49 +71,21 @@ 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;
|
||||||
}
|
|
||||||
|
|
||||||
#if TARGET_PC
|
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
|
||||||
u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
|
u8* dataPtr = (memory + expHeapSize);
|
||||||
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);
|
||||||
@@ -135,16 +102,9 @@ 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);
|
||||||
#endif
|
if (!parent2)
|
||||||
if (!parent2) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
parent2 = parent;
|
parent2 = parent;
|
||||||
}
|
}
|
||||||
@@ -176,15 +136,6 @@ 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) {
|
||||||
@@ -212,11 +163,6 @@ 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() {
|
||||||
@@ -268,24 +214,6 @@ 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(
|
||||||
@@ -294,16 +222,11 @@ 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;
|
||||||
@@ -311,6 +234,14 @@ 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
|
||||||
@@ -563,49 +494,6 @@ 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,11 +7,6 @@
|
|||||||
#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) {
|
||||||
@@ -24,56 +19,18 @@ 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();
|
||||||
@@ -87,11 +44,6 @@ 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);
|
||||||
@@ -107,15 +59,6 @@ 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);
|
||||||
@@ -167,11 +110,6 @@ 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) {
|
||||||
@@ -199,15 +137,6 @@ 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;
|
||||||
@@ -229,47 +158,6 @@ 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,6 +9,9 @@
|
|||||||
#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) {
|
||||||
@@ -418,50 +421,95 @@ static projectionFunc p_prj[3] = {
|
|||||||
loadPrjAnm,
|
loadPrjAnm,
|
||||||
};
|
};
|
||||||
|
|
||||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
#if TARGET_PC
|
||||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||||
|
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> local_48;
|
JGeometry::TVec3<f32> pos;
|
||||||
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
#if TARGET_PC
|
||||||
Mtx local_38;
|
Mtx ptclPosMtx;
|
||||||
local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
||||||
local_38[0][3] = local_48.x;
|
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
||||||
local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
||||||
local_38[1][3] = local_48.y;
|
} else
|
||||||
local_38[2][2] = 1.0f;
|
#endif
|
||||||
local_38[2][3] = local_48.z;
|
{
|
||||||
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;
|
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
|
||||||
GXLoadPosMtxImm(local_38, 0);
|
}
|
||||||
p_prj[work->mPrjType](work, local_38);
|
Mtx posMtx;
|
||||||
|
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* param_1) {
|
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JGeometry::TVec3<f32> local_48;
|
if (work->mpRes->getUsrIdx() == 0x89d7) {
|
||||||
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
int a = 0;
|
||||||
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;
|
|
||||||
|
|
||||||
Mtx local_38;
|
JGeometry::TVec3<f32> pos;
|
||||||
local_38[0][0] = cosRot * particleX;
|
f32 sinRot, cosRot;
|
||||||
local_38[0][1] = -sinRot * particleY;
|
#if TARGET_PC
|
||||||
local_38[0][3] = local_48.x;
|
Mtx ptclPosMtx;
|
||||||
local_38[1][0] = sinRot * particleX;
|
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
||||||
local_38[1][1] = cosRot * particleY;
|
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
||||||
local_38[1][3] = local_48.y;
|
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
||||||
local_38[2][2] = 1.0f;
|
sinRot = ptclPosMtx[1][0];
|
||||||
local_38[2][3] = local_48.z;
|
cosRot = ptclPosMtx[0][0];
|
||||||
local_38[0][2] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
|
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
||||||
GXLoadPosMtxImm(local_38, 0);
|
} else
|
||||||
p_prj[work->mPrjType](work, local_38);
|
#endif
|
||||||
|
{
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,7 +532,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, 0);
|
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||||
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));
|
||||||
}
|
}
|
||||||
@@ -517,7 +565,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, 0);
|
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||||
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));
|
||||||
}
|
}
|
||||||
@@ -681,103 +729,197 @@ static u8* p_dl[2] = {
|
|||||||
jpa_dl_x,
|
jpa_dl_x,
|
||||||
};
|
};
|
||||||
|
|
||||||
void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
#if TARGET_PC
|
||||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||||
|
JGeometry::TVec3<f32> axisY;
|
||||||
|
JGeometry::TVec3<f32> axisZ;
|
||||||
|
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||||
|
|
||||||
|
if (axisY.isZero()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneScoped;
|
axisY.normalize();
|
||||||
|
axisZ.cross(ptcl->mBaseAxis, axisY);
|
||||||
|
|
||||||
JGeometry::TVec3<f32> local_6c;
|
if (axisZ.isZero()) {
|
||||||
JGeometry::TVec3<f32> local_78;
|
|
||||||
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
|
||||||
|
|
||||||
if (local_6c.isZero()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_6c.normalize();
|
axisZ.normalize();
|
||||||
local_78.cross(param_1->mBaseAxis, local_6c);
|
ptcl->mBaseAxis.cross(axisY, axisZ);
|
||||||
|
ptcl->mBaseAxis.normalize();
|
||||||
if (local_78.isZero()) {
|
Mtx posMtx;
|
||||||
return;
|
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||||
}
|
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||||
|
posMtx[0][0] = ptcl->mBaseAxis.x;
|
||||||
local_78.normalize();
|
posMtx[0][1] = axisY.x;
|
||||||
param_1->mBaseAxis.cross(local_6c, local_78);
|
posMtx[0][2] = axisZ.x;
|
||||||
param_1->mBaseAxis.normalize();
|
posMtx[0][3] = ptcl->mPosition.x;
|
||||||
Mtx local_60;
|
posMtx[1][0] = ptcl->mBaseAxis.y;
|
||||||
f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
posMtx[1][1] = axisY.y;
|
||||||
f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
posMtx[1][2] = axisZ.y;
|
||||||
local_60[0][0] = param_1->mBaseAxis.x;
|
posMtx[1][3] = ptcl->mPosition.y;
|
||||||
local_60[0][1] = local_6c.x;
|
posMtx[2][0] = ptcl->mBaseAxis.z;
|
||||||
local_60[0][2] = local_78.x;
|
posMtx[2][1] = axisY.z;
|
||||||
local_60[0][3] = param_1->mPosition.x;
|
posMtx[2][2] = axisZ.z;
|
||||||
local_60[1][0] = param_1->mBaseAxis.y;
|
posMtx[2][3] = ptcl->mPosition.z;
|
||||||
local_60[1][1] = local_6c.y;
|
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
||||||
local_60[1][2] = local_78.y;
|
dusk::frame_interp::record_final_mtx(posMtx, ptcl);
|
||||||
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* param_0, JPABaseParticle* param_1) {
|
void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
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;
|
||||||
|
|
||||||
f32 sinRot = JMASSin(param_1->mRotateAngle);
|
Mtx posMtx;
|
||||||
f32 cosRot = JMASCos(param_1->mRotateAngle);
|
#if TARGET_PC
|
||||||
JGeometry::TVec3<f32> local_6c;
|
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx))
|
||||||
JGeometry::TVec3<f32> local_78;
|
#endif
|
||||||
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
{
|
||||||
|
JGeometry::TVec3<f32> axisY;
|
||||||
|
JGeometry::TVec3<f32> axisZ;
|
||||||
|
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||||
|
|
||||||
if (local_6c.isZero()) {
|
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;
|
||||||
|
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);
|
||||||
|
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||||
|
p_prj[work->mPrjType](work, posMtx);
|
||||||
|
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||||
|
}
|
||||||
|
|
||||||
|
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||||
|
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_6c.normalize();
|
ZoneScoped;
|
||||||
local_78.cross(param_1->mBaseAxis, local_6c);
|
|
||||||
|
|
||||||
if (local_78.isZero()) {
|
Mtx mtx1;
|
||||||
return;
|
Mtx mtx2;
|
||||||
|
#if TARGET_PC
|
||||||
|
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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);
|
||||||
local_78.normalize();
|
GXLoadPosMtxImm(mtx2, GX_PNMTX0);
|
||||||
param_1->mBaseAxis.cross(local_6c, local_78);
|
p_prj[work->mPrjType](work, mtx2);
|
||||||
param_1->mBaseAxis.normalize();
|
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||||
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,6 +204,28 @@ 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;
|
||||||
@@ -247,6 +269,17 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +322,23 @@ 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,6 +8,10 @@
|
|||||||
#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;
|
||||||
@@ -63,14 +67,24 @@ 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);
|
||||||
|
|||||||
@@ -38,3 +38,9 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
field_0x2c = NULL;
|
mPalette = 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);
|
||||||
field_0x2c = NULL;
|
mPalette = 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) {
|
||||||
field_0x2c = mEmbPalette;
|
mPalette = mEmbPalette;
|
||||||
} else {
|
} else {
|
||||||
field_0x2c = param_0;
|
mPalette = param_0;
|
||||||
}
|
}
|
||||||
initTexObj(field_0x2c->getTlutName());
|
initTexObj(mPalette->getTlutName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +133,9 @@ void JUTTexture::init() {
|
|||||||
initTexObj();
|
initTexObj();
|
||||||
} else {
|
} else {
|
||||||
if (mEmbPalette != NULL) {
|
if (mEmbPalette != NULL) {
|
||||||
field_0x2c = mEmbPalette;
|
mPalette = mEmbPalette;
|
||||||
|
|
||||||
initTexObj(field_0x2c->getTlutName());
|
initTexObj(mPalette->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 (field_0x2c) {
|
if (mPalette) {
|
||||||
field_0x2c->load();
|
mPalette->load();
|
||||||
}
|
}
|
||||||
GXLoadTexObj(&mTexObj, param_0);
|
GXLoadTexObj(&mTexObj, param_0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,12 +66,11 @@ 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 com.twilitrealm.dusk/.DuskActivity \
|
adb shell am start -n dev.twilitrealm.dusk/.DuskActivity \
|
||||||
--es dusk_args "'/sdcard/Download/The Legend of Zelda: Twilight Princess (USA).iso'"
|
--es dusk_args "--backend vulkan"
|
||||||
```
|
```
|
||||||
|
|
||||||
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,12 +2,22 @@ plugins {
|
|||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def duskRepoDir = rootProject.projectDir.parentFile.parentFile
|
||||||
|
def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusk').get().asFile
|
||||||
|
def syncDuskAssets = tasks.register('syncDuskAssets', Sync) {
|
||||||
|
from(new File(duskRepoDir, 'res')) {
|
||||||
|
into 'res'
|
||||||
|
exclude '**/.DS_Store'
|
||||||
|
}
|
||||||
|
into duskGeneratedAssetsDir
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'com.twilitrealm.dusk'
|
namespace 'dev.twilitrealm.dusk'
|
||||||
compileSdk 36
|
compileSdk 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId 'com.twilitrealm.dusk'
|
applicationId 'dev.twilitrealm.dusk'
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 36
|
targetSdk 36
|
||||||
versionCode 1
|
versionCode 1
|
||||||
@@ -27,7 +37,7 @@ android {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
jniLibs.srcDirs = ['src/main/jniLibs']
|
jniLibs.srcDirs = ['src/main/jniLibs']
|
||||||
assets.srcDirs = ['../../assets']
|
assets.srcDirs = [duskGeneratedAssetsDir]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,3 +58,10 @@ 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,2 +1,4 @@
|
|||||||
# 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,6 +10,7 @@
|
|||||||
<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,7 +25,7 @@
|
|||||||
android:resource="@xml/game_mode_config" />
|
android:resource="@xml/game_mode_config" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.twilitrealm.dusk.DuskActivity"
|
android:name="dev.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,18 +1,28 @@
|
|||||||
package com.twilitrealm.dusk;
|
package dev.twilitrealm.dusk;
|
||||||
|
|
||||||
import android.app.ActionBar;
|
import android.app.ActionBar;
|
||||||
|
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.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 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();
|
||||||
@@ -61,18 +71,46 @@ 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) {
|
||||||
getWindow().getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
|
window.setDecorFitsSystemWindows(false);
|
||||||
}else {
|
WindowInsetsController ctrl = window.getDecorView().getWindowInsetsController();
|
||||||
View decorView = getWindow().getDecorView();
|
if (ctrl != null) {
|
||||||
// Hide the status bar.
|
ctrl.setSystemBarsBehavior(
|
||||||
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
|
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||||
|
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();
|
||||||
actionBar.hide();
|
if (actionBar != null) {
|
||||||
|
actionBar.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,12 +138,96 @@ 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);
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 : "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
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,6 +256,7 @@ 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 = 2;
|
private static final int SDL_MICRO_VERSION = 4;
|
||||||
/*
|
/*
|
||||||
// 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 e) {
|
} catch (FileNotFoundException | SecurityException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -2227,4 +2227,3 @@ class SDLClipboardHandler implements
|
|||||||
SDLActivity.onNativeClipboardChanged();
|
SDLActivity.onNativeClipboardChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,17 +65,15 @@ class SDLInputConnection extends BaseInputConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||||
if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) {
|
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection
|
||||||
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection
|
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
||||||
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
if (beforeLength > 0 && afterLength == 0) {
|
||||||
if (beforeLength > 0 && afterLength == 0) {
|
// backspace(s)
|
||||||
// backspace(s)
|
while (beforeLength-- > 0) {
|
||||||
while (beforeLength-- > 0) {
|
nativeGenerateScancodeForUnichar('\b');
|
||||||
nativeGenerateScancodeForUnichar('\b');
|
}
|
||||||
}
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ 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;
|
||||||
@@ -96,6 +98,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +106,7 @@ 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;
|
||||||
@@ -192,6 +196,7 @@ 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();
|
||||||
|
|||||||
@@ -14,9 +14,22 @@ 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
|
||||||
TOOLCHAIN_BIN="$ANDROID_HOME_DIR/ndk/$ANDROID_NDK_VER/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
case "$(uname -s)" in
|
||||||
if [[ -x "$TOOLCHAIN_BIN/llvm-strip" ]]; then
|
Darwin) HOST_TAG="darwin-x86_64" ;;
|
||||||
STRIP_TOOL="$TOOLCHAIN_BIN/llvm-strip"
|
Linux) HOST_TAG="linux-x86_64" ;;
|
||||||
|
*) 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
|
||||||
|
|
||||||
@@ -25,29 +38,35 @@ 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" "$dst"
|
cp -f "$src" "$tmp"
|
||||||
if [[ "$ANDROID_STAGE_STRIP" != "0" ]] && [[ -n "$STRIP_TOOL" ]]; then
|
if [[ "$ANDROID_STAGE_STRIP" != "0" ]] && [[ -n "$STRIP_TOOL" ]]; then
|
||||||
"$STRIP_TOOL" --strip-debug "$dst"
|
"$STRIP_TOOL" --strip-unneeded "$tmp"
|
||||||
echo "Staged and stripped $src -> $dst"
|
mv -f "$tmp" "$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
|
||||||
src="${ABI_TO_LIB[$abi]:-}"
|
case "$abi" in
|
||||||
if [[ -z "$src" ]]; then
|
arm64-v8a) src="$ROOT_DIR/build/android-arm64/libmain.so" ;;
|
||||||
echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2
|
x86_64) src="$ROOT_DIR/build/android-x86_64/libmain.so" ;;
|
||||||
exit 1
|
*)
|
||||||
fi
|
echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
copy_lib "$abi" "$src"
|
copy_lib "$abi" "$src"
|
||||||
done
|
done
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 928 KiB |
|
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 79 B After Width: | Height: | Size: 1014 B |
|
Before Width: | Height: | Size: 761 B After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 99 B After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 123 B After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 8.7 KiB |
@@ -6,4 +6,4 @@ Exec=dusk
|
|||||||
Icon=dusk
|
Icon=dusk
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Graphics;3DGraphics;Game
|
Categories=Game;
|
||||||
|
|||||||
|
After Width: | Height: | Size: 457 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,291 @@
|
|||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: visible;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Fira Sans";
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 20dp;
|
||||||
|
color: #E0DBC8;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: stretch;
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
fps,
|
||||||
|
toast {
|
||||||
|
position: absolute;
|
||||||
|
border: 1dp #92875B;
|
||||||
|
background-color: rgba(21, 22, 16, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast {
|
||||||
|
top: 40dp;
|
||||||
|
right: 40dp;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
border-radius: 14dp;
|
||||||
|
overflow: hidden;
|
||||||
|
backdrop-filter: blur(5dp);
|
||||||
|
box-shadow: 0 0 15dp 3dp;
|
||||||
|
filter: opacity(0);
|
||||||
|
transform: scale(0.9);
|
||||||
|
transform-origin: center;
|
||||||
|
transition: filter transform 0.2s cubic-in-out;
|
||||||
|
padding: 18dp 24dp;
|
||||||
|
gap: 8dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast[open] {
|
||||||
|
filter: opacity(1);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*toast:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: rgba(61, 59, 36, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast:active {
|
||||||
|
background-color: rgba(45, 43, 26, 80%);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
toast heading {
|
||||||
|
display: flex;
|
||||||
|
gap: 18dp;
|
||||||
|
align-items: center;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-size: 18dp;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #92875B;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast heading > span {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast heading > row {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast message {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
gap: 8dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast message row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast message row.muted {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast progress {
|
||||||
|
height: 4dp;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast progress fill {
|
||||||
|
background-color: rgba(194, 164, 45, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.achievement {
|
||||||
|
border: 1dp #C2A42D;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.achievement heading {
|
||||||
|
color: #C2A42D;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.controller-warning {
|
||||||
|
top: auto;
|
||||||
|
right: auto;
|
||||||
|
bottom: 40dp;
|
||||||
|
left: 50%;
|
||||||
|
width: 440dp;
|
||||||
|
max-width: 90%;
|
||||||
|
transform: translateX(-50%) scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.controller-warning[open] {
|
||||||
|
transform: translateX(-50%) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.controller-warning heading {
|
||||||
|
color: #C2A42D;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.menu-notification {
|
||||||
|
top: 40dp;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
left: 50%;
|
||||||
|
max-width: 90%;
|
||||||
|
transform: translateX(-50%) scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.menu-notification[open] {
|
||||||
|
transform: translateX(-50%) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.menu-notification message {
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.menu-notification message row {
|
||||||
|
align-items: center;
|
||||||
|
gap: 6dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon {
|
||||||
|
font-family: "Material Symbols Rounded";
|
||||||
|
font-weight: normal;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.arrow-forward {
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.trophy {
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.controller {
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.warning {
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
fps {
|
||||||
|
display: none;
|
||||||
|
z-index: 99;
|
||||||
|
font-size: 18dp;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 9dp 12dp;
|
||||||
|
border-radius: 7dp;
|
||||||
|
pointer-events: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
fps[open] {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
fps[corner=tl] {
|
||||||
|
top: 12dp;
|
||||||
|
left: 12dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fps[corner=tr] {
|
||||||
|
top: 12dp;
|
||||||
|
right: 12dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fps[corner=bl] {
|
||||||
|
bottom: 12dp;
|
||||||
|
left: 12dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fps[corner=br] {
|
||||||
|
bottom: 12dp;
|
||||||
|
right: 12dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo {
|
||||||
|
position: absolute;
|
||||||
|
width: 100dp;
|
||||||
|
height: 100dp;
|
||||||
|
bottom: 40dp;
|
||||||
|
left: 40dp;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.5s linear-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo[open] {
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
filter: drop-shadow(#0008 0 0 14dp);
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo img.inner {
|
||||||
|
animation: 24s linear-in-out infinite logo-inner-spin;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo img.outer {
|
||||||
|
animation: 8s linear-in-out infinite logo-outer-spin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes logo-inner-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes logo-outer-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 640dp) {
|
||||||
|
toast {
|
||||||
|
top: 20dp;
|
||||||
|
right: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.controller-warning {
|
||||||
|
bottom: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.menu-notification {
|
||||||
|
top: 20dp;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: visible;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18dp;
|
||||||
|
color: #E0DBC8;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
focus: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
height: 64dp;
|
||||||
|
background-color: rgba(21, 22, 16, 80%);
|
||||||
|
border-bottom: 2dp #92875B;
|
||||||
|
backdrop-filter: blur(5dp);
|
||||||
|
transform: translateY(-64dp);
|
||||||
|
transition: transform 0.2s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup[open] {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
popup tab-bar {
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup tab-bar tab {
|
||||||
|
opacity: 0.35;
|
||||||
|
color: #E0DBC8;
|
||||||
|
}
|
||||||
@@ -0,0 +1,497 @@
|
|||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-family: "Fira Sans";
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 20dp;
|
||||||
|
color: #FFFFFF;
|
||||||
|
filter: opacity(0);
|
||||||
|
transition: filter 1s 0.2s linear-in-out;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* The color gradient from the Figma bands really badly. A fully black gradient does as well, but not as badly. */
|
||||||
|
decorator: horizontal-gradient(#000000FF #00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored .gradient {
|
||||||
|
decorator: horizontal-gradient(#00000000 #000000FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
.background {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
decorator: image(../prelaunch-bg.png cover left center);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 1s linear-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[open] {
|
||||||
|
filter: opacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body[open] .background {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.disc-ready .background {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
content {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
filter: opacity(0);
|
||||||
|
transition: filter 0.2s linear-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
content[open] {
|
||||||
|
filter: opacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu {
|
||||||
|
position: absolute;
|
||||||
|
left: 96dp;
|
||||||
|
right: auto;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
/* Scale based on a reference screen width, 428/1216 */
|
||||||
|
width: 35.230264vw;
|
||||||
|
min-width: 428dp;
|
||||||
|
max-width: 856dp;
|
||||||
|
height: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 48dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored menu {
|
||||||
|
left: auto;
|
||||||
|
right: 96dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
hero {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored hero {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
hero img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
font-family: "Alegreya SC";
|
||||||
|
font-size: 32dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1216dp) {
|
||||||
|
.eyebrow {
|
||||||
|
/* Same logic as .menu, 32/1216 */
|
||||||
|
font-size: 2.631579vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12dp;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list button {
|
||||||
|
width: 428dp;
|
||||||
|
height: 54dp;
|
||||||
|
padding: 8dp 16dp;
|
||||||
|
border-radius: 8dp;
|
||||||
|
text-align: left;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-size: 32dp;
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
/* Define a fully transparent gradient as the default state, otherwise a white flash occurs */
|
||||||
|
decorator: horizontal-gradient(#00000000 #00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list button:disabled {
|
||||||
|
opacity: 0.75;
|
||||||
|
cursor: default;
|
||||||
|
decorator: horizontal-gradient(#00000000 #00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list button.anim-done {
|
||||||
|
transition: decorator color opacity 0.1s linear-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list button:hover,
|
||||||
|
#menu-list button:focus-visible {
|
||||||
|
color: black;
|
||||||
|
decorator: horizontal-gradient(#FEE685FF #FEE68500);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #menu-list {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #menu-list button {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #menu-list button:hover,
|
||||||
|
body.mirrored #menu-list button:focus-visible {
|
||||||
|
decorator: horizontal-gradient(#FEE68500 #FEE685FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
disc-info {
|
||||||
|
position: absolute;
|
||||||
|
left: 96dp;
|
||||||
|
right: auto;
|
||||||
|
bottom: 72dp;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12dp;
|
||||||
|
font-size: 24dp;
|
||||||
|
font-effect: glow(0dp 4dp 0dp 4dp black);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored disc-info {
|
||||||
|
left: auto;
|
||||||
|
right: 96dp;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
version-info {
|
||||||
|
position: absolute;
|
||||||
|
right: 96dp;
|
||||||
|
left: auto;
|
||||||
|
bottom: 72dp;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12dp;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 24dp;
|
||||||
|
font-effect: glow(0dp 4dp 0dp 4dp black);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored version-info {
|
||||||
|
right: auto;
|
||||||
|
left: 96dp;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=good] {
|
||||||
|
color: #D8F999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=bad] {
|
||||||
|
color: #FFC9C9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=verifying] {
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=mismatch] {
|
||||||
|
color: #FFD6A7;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=unknown] {
|
||||||
|
color: rgba(224, 219, 200, 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=pending] {
|
||||||
|
color: #FEE685;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status icon {
|
||||||
|
display: none;
|
||||||
|
width: 24dp;
|
||||||
|
height: 24dp;
|
||||||
|
font-family: "Material Symbols Rounded";
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 24dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status] icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=good] icon {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=bad] icon {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=verifying] icon {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=mismatch] icon {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=unknown] icon {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status[status=pending] icon {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-version {
|
||||||
|
font-size: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update {
|
||||||
|
display: none;
|
||||||
|
color: #A6A09B;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8dp;
|
||||||
|
font-size: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update[state=checking],
|
||||||
|
.update[state=failed] {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update[state=available] {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#update-download {
|
||||||
|
display: none;
|
||||||
|
margin: 0dp;
|
||||||
|
padding: 0dp;
|
||||||
|
border-width: 0dp;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #D8F999;
|
||||||
|
cursor: pointer;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: bold;
|
||||||
|
decorator: horizontal-gradient(#00000000 #00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.update[state=available] #update-download {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#update-download icon {
|
||||||
|
display: block;
|
||||||
|
width: 18dp;
|
||||||
|
height: 18dp;
|
||||||
|
font-family: "Material Symbols Rounded";
|
||||||
|
font-weight: normal;
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
color: #A6A09B;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored .update {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Startup animation */
|
||||||
|
.intro-item {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10dp);
|
||||||
|
transition: opacity transform 0.3s 0.1s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.animate-in .intro-item {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-0 {
|
||||||
|
transition: opacity transform 0.3s 0.1s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-1 {
|
||||||
|
transition: opacity transform 0.3s 0.2s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-2 {
|
||||||
|
transition: opacity transform 0.3s 0.3s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-3 {
|
||||||
|
transition: opacity transform 0.3s 0.4s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-4 {
|
||||||
|
transition: opacity transform 0.3s 0.5s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-5 {
|
||||||
|
transition: opacity transform 0.3s 0.6s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile layout */
|
||||||
|
@media (max-height: 640dp) {
|
||||||
|
.gradient {
|
||||||
|
decorator: horizontal-gradient(#00000000 #000000FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored .gradient {
|
||||||
|
decorator: horizontal-gradient(#000000FF #00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu {
|
||||||
|
left: 32dp;
|
||||||
|
right: 32dp;
|
||||||
|
width: auto;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: none;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored menu {
|
||||||
|
left: 32dp;
|
||||||
|
right: 32dp;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
hero {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 48%;
|
||||||
|
margin-left: 32dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored hero {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
hero img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 52%;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list button {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-list button:hover,
|
||||||
|
#menu-list button:focus-visible {
|
||||||
|
decorator: horizontal-gradient(#FEE68500 #FEE685FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #menu-list {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #menu-list button {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #menu-list button:hover,
|
||||||
|
body.mirrored #menu-list button:focus-visible {
|
||||||
|
decorator: horizontal-gradient(#FEE685FF #FEE68500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
disc-info {
|
||||||
|
right: 32dp;
|
||||||
|
left: auto;
|
||||||
|
bottom: 32dp;
|
||||||
|
top: auto;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 16dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-status icon {
|
||||||
|
font-size: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disc-version {
|
||||||
|
font-size: 16dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
version-info {
|
||||||
|
right: 32dp;
|
||||||
|
left: auto;
|
||||||
|
bottom: auto;
|
||||||
|
top: 32dp;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 16dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update {
|
||||||
|
font-size: 16dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored disc-info {
|
||||||
|
right: auto;
|
||||||
|
left: 32dp;
|
||||||
|
bottom: 32dp;
|
||||||
|
top: auto;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored version-info {
|
||||||
|
right: auto;
|
||||||
|
left: 32dp;
|
||||||
|
bottom: auto;
|
||||||
|
top: 32dp;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mirrored #disc-status {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
tab-bar {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: auto hidden;
|
||||||
|
clip: always;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar scrollbarhorizontal,
|
||||||
|
tab-bar scrollbarhorizontal sliderarrowdec,
|
||||||
|
tab-bar scrollbarhorizontal sliderarrowinc,
|
||||||
|
tab-bar scrollbarhorizontal slidertrack,
|
||||||
|
tab-bar scrollbarhorizontal sliderbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar tab {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 0 24dp;
|
||||||
|
line-height: 64dp;
|
||||||
|
white-space: nowrap;
|
||||||
|
decorator: vertical-gradient(#c2a42d00 #c2a42d00);
|
||||||
|
transition: decorator 0.1s linear-in-out, opacity 0.1s linear-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar tab:selected {
|
||||||
|
opacity: 1;
|
||||||
|
border-bottom: 4dp #C2A42D;
|
||||||
|
font-effect: glow(0dp 4dp 0dp 4dp black);
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar tab:focus-visible,
|
||||||
|
tab-bar tab:hover {
|
||||||
|
opacity: 1;
|
||||||
|
font-effect: glow(0dp 4dp 0dp 4dp black);
|
||||||
|
decorator: vertical-gradient(#c2a42d00 #c2a42d26);
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar tab:active {
|
||||||
|
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar[closable] tab-end-spacer {
|
||||||
|
display: block;
|
||||||
|
flex: 0 0 64dp;
|
||||||
|
width: 64dp;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar[closable] close {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
top: 8dp;
|
||||||
|
right: 8dp;
|
||||||
|
z-index: 1;
|
||||||
|
width: 48dp;
|
||||||
|
height: 48dp;
|
||||||
|
font-family: "Material Symbols Rounded";
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 24dp;
|
||||||
|
color: rgba(224, 219, 200, 70%);
|
||||||
|
backdrop-filter: blur(2dp);
|
||||||
|
border-radius: 6dp;
|
||||||
|
decorator: text("" center center);
|
||||||
|
transition: color background-color 0.12s linear-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar[closable] close:hover,
|
||||||
|
tab-bar[closable] close:focus-visible {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(194, 164, 45, 24%);
|
||||||
|
}
|
||||||
|
|
||||||
|
tab-bar[closable] close:active {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(194, 164, 45, 40%);
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: visible;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-size: 24dp;
|
||||||
|
color: #FFFFFF;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuner-root {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 45%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: stretch;
|
||||||
|
decorator: vertical-gradient(#00000000 #151610F2);
|
||||||
|
filter: opacity(0);
|
||||||
|
transition: filter 0.2s linear-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuner-root[open] {
|
||||||
|
filter: opacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuner {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1216dp;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24dp;
|
||||||
|
padding: 48dp 64dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 800dp) {
|
||||||
|
.tuner-root {
|
||||||
|
min-height: 38%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tuner {
|
||||||
|
gap: 16dp;
|
||||||
|
padding: 32dp 48dp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-container {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-size: 18dp;
|
||||||
|
line-height: 22dp;
|
||||||
|
color: rgba(255, 255, 255, 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
margin: 1dp 0;
|
||||||
|
border-top: 1dp rgba(217, 217, 217, 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer-button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 220dp;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20dp;
|
||||||
|
line-height: 24dp;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #FFFFFF;
|
||||||
|
opacity: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer-button.return {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer-button.reset {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepped-carousel {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16dp;
|
||||||
|
width: auto;
|
||||||
|
min-width: 246dp;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepped-carousel-value {
|
||||||
|
line-height: 29dp;
|
||||||
|
min-width: 166dp;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepped-carousel-arrow {
|
||||||
|
width: 24dp;
|
||||||
|
height: 24dp;
|
||||||
|
min-width: 24dp;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
opacity: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: "Material Symbols Rounded";
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,506 @@
|
|||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 64dp;
|
||||||
|
font-family: "Fira Sans";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 15dp;
|
||||||
|
color: #E0DBC8;
|
||||||
|
}
|
||||||
|
|
||||||
|
window {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1088dp;
|
||||||
|
max-height: 768dp;
|
||||||
|
margin: auto;
|
||||||
|
border-radius: 14dp;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 2dp #92875B;
|
||||||
|
backdrop-filter: blur(5dp);
|
||||||
|
box-shadow: 0 0 25dp 5dp;
|
||||||
|
background-color: rgba(21, 22, 16, 90%);
|
||||||
|
filter: opacity(0);
|
||||||
|
transform: scale(0.9);
|
||||||
|
transform-origin: center;
|
||||||
|
transition: filter transform 0.2s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.small {
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.modal {
|
||||||
|
max-width: 640dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
window[open] {
|
||||||
|
filter: opacity(1);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 640dp) {
|
||||||
|
body {
|
||||||
|
padding: 16dp;
|
||||||
|
}
|
||||||
|
window {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window tab-bar {
|
||||||
|
flex: 0 0 64dp;
|
||||||
|
height: 64dp;
|
||||||
|
background-color: rgba(217, 217, 217, 10%);
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18dp;
|
||||||
|
border-bottom: 2dp #92875B;
|
||||||
|
}
|
||||||
|
|
||||||
|
window tab-bar tab {
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
window content {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
window content pane {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 24dp;
|
||||||
|
padding-bottom: 0dp;
|
||||||
|
gap: 8dp;
|
||||||
|
overflow: hidden auto;
|
||||||
|
font-size: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
window content pane:not(:last-of-type) {
|
||||||
|
border-right: 1dp #92875B;
|
||||||
|
}
|
||||||
|
|
||||||
|
window content pane > * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
window content pane:last-of-type > div {
|
||||||
|
line-height: 1.625;
|
||||||
|
}
|
||||||
|
|
||||||
|
window content pane > spacer {
|
||||||
|
display: block;
|
||||||
|
/* Completes the 24dp bottom inset after the pane's 8dp gap. */
|
||||||
|
flex: 0 0 16dp;
|
||||||
|
height: 16dp;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarvertical {
|
||||||
|
width: 8dp;
|
||||||
|
margin: 4dp 4dp 4dp 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarvertical sliderarrowdec,
|
||||||
|
scrollbarvertical sliderarrowinc {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarvertical slidertrack {
|
||||||
|
width: 8dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarvertical sliderbar {
|
||||||
|
width: 8dp;
|
||||||
|
min-height: 24dp;
|
||||||
|
background-color: rgba(224, 219, 200, 45%);
|
||||||
|
border-radius: 2dp;
|
||||||
|
transition: background-color 0.2s cubic-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarvertical sliderbar:hover,
|
||||||
|
scrollbarvertical sliderbar:active {
|
||||||
|
background-color: rgba(194, 164, 45, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarhorizontal {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarhorizontal sliderarrowdec,
|
||||||
|
scrollbarhorizontal sliderarrowinc {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbarhorizontal slidertrack,
|
||||||
|
scrollbarhorizontal sliderbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-heading {
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 22dp;
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-heading:not(:first-of-type) {
|
||||||
|
padding-top: 12dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
text-align: center;
|
||||||
|
background-color: rgba(17, 16, 10, 20%);
|
||||||
|
opacity: 0.9;
|
||||||
|
padding: 8dp 16dp;
|
||||||
|
border-radius: 14dp;
|
||||||
|
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
|
||||||
|
font-size: 20dp;
|
||||||
|
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
focus: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled):hover,
|
||||||
|
button:not(:disabled):focus-visible {
|
||||||
|
background-color: rgba(204, 184, 119, 20%);
|
||||||
|
box-shadow: #C2A42D 0 0 0 2dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled):selected {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: rgba(204, 184, 119, 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled):active {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: rgba(204, 184, 119, 40%);
|
||||||
|
box-shadow: #C2A42D 0 0 0 2dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.modal-btn {
|
||||||
|
flex: 1 1 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8dp;
|
||||||
|
background-color: rgba(17, 16, 10, 20%);
|
||||||
|
opacity: 0.9;
|
||||||
|
padding: 8dp 16dp;
|
||||||
|
border-radius: 14dp;
|
||||||
|
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
|
||||||
|
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
focus: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button:not(:disabled):hover,
|
||||||
|
select-button:not(:disabled):focus-visible {
|
||||||
|
background-color: rgba(204, 184, 119, 20%);
|
||||||
|
box-shadow: #C2A42D 0 0 0 2dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button:not(:disabled):selected {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: rgba(204, 184, 119, 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button:not(:disabled):active {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: rgba(204, 184, 119, 40%);
|
||||||
|
box-shadow: #C2A42D 0 0 0 2dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button:disabled {
|
||||||
|
opacity: 0.35;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button key {
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18dp;
|
||||||
|
text-transform: uppercase;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button value {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button value.modified {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
select-button input {
|
||||||
|
text-align: right;
|
||||||
|
font-size: 20dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
font-family: "Material Symbols Rounded";
|
||||||
|
font-weight: normal;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.warning {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.error {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.verifying {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.celebration {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.question-mark {
|
||||||
|
decorator: text("" center center);
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-total {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 64dp;
|
||||||
|
height: 64dp;
|
||||||
|
line-height: 64dp;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16dp;
|
||||||
|
color: rgba(224, 219, 200, 55%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10dp;
|
||||||
|
padding: 12dp 0;
|
||||||
|
border-bottom: 1dp rgba(146, 135, 91, 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-info {
|
||||||
|
display: block;
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-name {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-name.unlocked {
|
||||||
|
color: #ffa826;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-badge {
|
||||||
|
font-size: 14dp;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-badge.unlocked {
|
||||||
|
color: #44cc55;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-badge.locked {
|
||||||
|
color: #cc4444;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-desc {
|
||||||
|
display: block;
|
||||||
|
color: rgba(224, 219, 200, 55%);
|
||||||
|
font-size: 16dp;
|
||||||
|
margin: 4dp 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.achievement-progress {
|
||||||
|
display: block;
|
||||||
|
font-size: 13dp;
|
||||||
|
color: rgba(224, 219, 200, 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 6dp;
|
||||||
|
border-radius: 3dp;
|
||||||
|
background-color: rgba(255, 255, 255, 10%);
|
||||||
|
margin: 6dp 0 2dp 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.progress-done fill {
|
||||||
|
background-color: #44aa22;
|
||||||
|
border-radius: 3dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.progress-ongoing fill {
|
||||||
|
background-color: #2255bb;
|
||||||
|
border-radius: 3dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.achievement-clear {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
align-self: center;
|
||||||
|
font-size: 14dp;
|
||||||
|
padding: 2dp 8dp;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 20dp;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-col {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
gap: 12dp;
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-desc {
|
||||||
|
display: block;
|
||||||
|
font-size: 16dp;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 24dp;
|
||||||
|
gap: 20dp;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.modal.danger {
|
||||||
|
border: 2dp #852221;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
gap: 16dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header icon {
|
||||||
|
font-size: 24dp;
|
||||||
|
color: #92875B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
display: block;
|
||||||
|
font-family: "Fira Sans Condensed";
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 18dp;
|
||||||
|
color: #92875B;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.modal.danger .modal-title,
|
||||||
|
window.modal.danger .modal-header icon {
|
||||||
|
color: #B3261E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 20dp;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body span.tip {
|
||||||
|
font-size: 14dp;
|
||||||
|
color: #92875B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification-progress {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10dp;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification-file {
|
||||||
|
display: block;
|
||||||
|
font-size: 17dp;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.verification-progress-bar {
|
||||||
|
height: 8dp;
|
||||||
|
margin: 2dp 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification-detail {
|
||||||
|
display: block;
|
||||||
|
font-size: 14dp;
|
||||||
|
color: rgba(224, 219, 200, 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 12dp;
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding-top: 4dp;
|
||||||
|
}
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
#include "Z2AudioLib/Z2Audience.h"
|
#include "Z2AudioLib/Z2Audience.h"
|
||||||
#include "Z2AudioLib/Z2SoundInfo.h"
|
#include "Z2AudioLib/Z2SoundInfo.h"
|
||||||
|
#if TARGET_PC
|
||||||
|
#include "dusk/audio/DuskDsp.hpp"
|
||||||
|
#include "dusk/settings.h"
|
||||||
|
#include <cmath>
|
||||||
|
#endif
|
||||||
#include "Z2AudioLib/Z2Calc.h"
|
#include "Z2AudioLib/Z2Calc.h"
|
||||||
#include "Z2AudioLib/Z2Param.h"
|
#include "Z2AudioLib/Z2Param.h"
|
||||||
#include "JSystem/JAudio2/JAISound.h"
|
#include "JSystem/JAudio2/JAISound.h"
|
||||||
@@ -701,6 +706,11 @@ f32 Z2Audience::calcRelPosVolume(const Vec& param_0, f32 param_1, int camID) {
|
|||||||
f32 Z2Audience::calcRelPosPan(const Vec& param_0, int camID) {
|
f32 Z2Audience::calcRelPosPan(const Vec& param_0, int camID) {
|
||||||
Vec local_54 = param_0;
|
Vec local_54 = param_0;
|
||||||
local_54.y = 0.0f;
|
local_54.y = 0.0f;
|
||||||
|
#if TARGET_PC
|
||||||
|
if (dusk::getSettings().game.enableMirrorMode) {
|
||||||
|
local_54.x = -local_54.x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
f32 dVar6 = VECMag(&local_54);
|
f32 dVar6 = VECMag(&local_54);
|
||||||
if (dVar6 < 0.1f) {
|
if (dVar6 < 0.1f) {
|
||||||
@@ -734,9 +744,22 @@ f32 Z2Audience::calcRelPosPan(const Vec& param_0, int camID) {
|
|||||||
|
|
||||||
f32 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) {
|
f32 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) {
|
||||||
f32 fVar1 = param_0.z + mAudioCamera[camID].getDolbyCenterZ();
|
f32 fVar1 = param_0.z + mAudioCamera[camID].getDolbyCenterZ();
|
||||||
|
#if TARGET_PC
|
||||||
|
if (dusk::audio::EnableHrtf) {
|
||||||
|
// Normalize the direction so result is purely front/back orientation,
|
||||||
|
// independent of how far away the sound is
|
||||||
|
f32 lenSq = param_0.x * param_0.x + param_0.y * param_0.y + param_0.z * param_0.z;
|
||||||
|
if (lenSq < 0.0001f) {
|
||||||
|
return 0.5f;
|
||||||
|
}
|
||||||
|
f32 zNorm = param_0.z / sqrtf(lenSq);
|
||||||
|
f32 t = (zNorm + 1.0f) * 0.5f;
|
||||||
|
return 0.5f - 0.5f * cosf(t * static_cast<f32>(M_PI));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (fVar1 > mSetting.field_0x48) {
|
if (fVar1 > mSetting.field_0x48) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fVar1 < mSetting.field_0x44) {
|
if (fVar1 < mSetting.field_0x44) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
#include "d/actor/d_a_ni.h"
|
#include "d/actor/d_a_ni.h"
|
||||||
#include "d/d_s_play.h"
|
#include "d/d_s_play.h"
|
||||||
|
|
||||||
|
#include "dusk/frame_interpolation.h"
|
||||||
#include "dusk/settings.h"
|
#include "dusk/settings.h"
|
||||||
#include "res/Object/Alink.h"
|
#include "res/Object/Alink.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -4962,13 +4963,16 @@ int daAlink_c::create() {
|
|||||||
|
|
||||||
setArcName(checkWolf());
|
setArcName(checkWolf());
|
||||||
setOriginalHeap(&mpArcHeap, 0xA2800);
|
setOriginalHeap(&mpArcHeap, 0xA2800);
|
||||||
|
JKRHEAP_NAME(mpArcHeap, "Alink ArcHeap");
|
||||||
if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) {
|
if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) {
|
||||||
return cPhs_INIT_e;
|
return cPhs_INIT_e;
|
||||||
}
|
}
|
||||||
|
|
||||||
setShieldArcName();
|
setShieldArcName();
|
||||||
setOriginalHeap(&mpShieldArcHeap, 0x7000);
|
setOriginalHeap(&mpShieldArcHeap, 0x7000);
|
||||||
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e) {
|
JKRHEAP_NAME(mpShieldArcHeap, "Alink ShieldArcHeap");
|
||||||
|
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e)
|
||||||
|
{
|
||||||
return cPhs_INIT_e;
|
return cPhs_INIT_e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14784,6 +14788,10 @@ void daAlink_c::deleteEquipItem(BOOL i_isPlaySound, BOOL i_isDeleteKantera) {
|
|||||||
mIronBallChainPos = NULL;
|
mIronBallChainPos = NULL;
|
||||||
mIronBallChainAngle = NULL;
|
mIronBallChainAngle = NULL;
|
||||||
field_0x3848 = NULL;
|
field_0x3848 = NULL;
|
||||||
|
#if TARGET_PC
|
||||||
|
mIBChainInterpPrevValid = false;
|
||||||
|
mIBChainInterpCurrValid = false;
|
||||||
|
#endif
|
||||||
field_0x0774 = NULL;
|
field_0x0774 = NULL;
|
||||||
field_0x0778 = NULL;
|
field_0x0778 = NULL;
|
||||||
mpHookshotLinChk = NULL;
|
mpHookshotLinChk = NULL;
|
||||||
@@ -19714,6 +19722,27 @@ int daAlink_c::draw() {
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0);
|
dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0);
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
if (dusk::getSettings().game.enableFrameInterpolation &&
|
||||||
|
mEquipItem == dItemNo_IRONBALL_e &&
|
||||||
|
mIronBallChainPos != NULL && mIronBallChainAngle != NULL)
|
||||||
|
{
|
||||||
|
if (mIBChainInterpCurrValid) {
|
||||||
|
memcpy(mIBChainInterpPrevPos, mIBChainInterpCurrPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz));
|
||||||
|
memcpy(mIBChainInterpPrevAngle, mIBChainInterpCurrAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz));
|
||||||
|
mIBChainInterpPrevHandRoot = mIBChainInterpCurrHandRoot;
|
||||||
|
mIBChainInterpPrevValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(mIBChainInterpCurrPos, mIronBallChainPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz));
|
||||||
|
memcpy(mIBChainInterpCurrAngle, mIronBallChainAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz));
|
||||||
|
mIBChainInterpCurrHandRoot = mHookshotTopPos;
|
||||||
|
mIBChainInterpCurrValid = true;
|
||||||
|
|
||||||
|
dusk::frame_interp::add_interpolation_callback(&ironBallChainInterpCallback, this);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||