Compare commits

...

59 Commits

Author SHA1 Message Date
SuperDude88 3eeb9a19a1 Fix for Mobile Testing 2026-07-07 19:04:14 -04:00
SuperDude88 060f0eb419 Use OSGetSystemTime Extension
- Fixes desyncing issues with save file time and a couple other odd instances, particularly on mobile platforms that suspend apps
2026-07-07 18:52:16 -04:00
SuperDude88 e491d254f8 Don't Use OSCalendarTime for Speedrun Timing
- Shouldn't rely on OSTicksToCalendarTime since it will be changed to handle time zone conversion, and that doesn't make sense on elapsed time
2026-07-07 18:12:15 -04:00
TakaRikka 84c5729c4e Merge pull request #2175 from TwilitRealm/mirror-mode-fixes
Mirror Mode Map Fixes
2026-07-07 04:00:07 -07:00
Luke Street e0ab36b7d9 Stable game ABI: Use PARTIAL_DEBUG
To make sure that mods can work across debug and release build, we can utilize PARTIAL_DEBUG to enable only DEBUG changes that affect struct and vtable layout
2026-07-07 01:14:29 -06:00
Luke Street d40a30ee13 Config: renaming & add change subscriptions 2026-07-07 00:50:11 -06:00
SuperDude88 074b43a089 Merge pull request #2173 from Lypopp/Invincible-enemies-activated-with-speedrun-mode-activated
Fixed invincible enemies cheat not deactivating on game startup when speedrun mode is activated
2026-07-06 19:48:53 -04:00
SuperDude88 8e8dc305e6 Update Pane Mirroring
- Update mirroring of Link + the dungeon map icon properly when the setting changes
2026-07-05 23:33:15 -04:00
SuperDude88 41389f4a8e Remove Extra Mirror
Accidentally left this in from testing
2026-07-05 22:58:45 -04:00
SuperDude88 8145dec2a1 Remove Outdated MIrror Mode TODO
This was done!
2026-07-05 20:19:42 -04:00
SuperDude88 4089a80a17 Mirror Mode Map Fixes
Will probably need to resolve conflicts with Wii code once decomp has related PR merged + we sync things

Change to setPlusZoomCenterX is not present on Wii (but fixes controls), probably from its lack of CStick
2026-07-05 20:19:33 -04:00
hector.bonhoure@gmail.com b772b6d952 Fixed invincible enemies cheat not deactivating on game startup when speedrun mode is activated 2026-07-05 16:05:55 +02:00
Irastris 42910ab2fd Restore simultaneous gyro and joystick input for first person aiming (#2164) 2026-07-02 00:13:22 -06:00
Olivia!! f54892b2c2 do not disable regular touch input if menu touch is disabled (#2152) 2026-07-02 00:03:53 -06:00
Luke Street f32e069c4b Improve mouse hiding logic (#2163)
* Improve mouse hiding logic

* Restore ImGui logic
2026-07-02 02:03:18 -04:00
Luke Street 09f087656a Guard against null dMsgObject_getMsgObjectClass() in a few places 2026-06-30 15:19:30 -06:00
Irastris fe15366912 Make Ganondorf cape tearing deterministic when using texture replacements (#2145)
* Make Ganondorf cape tearing deterministic when using texture replacements

* GXIsTexObjReplaced -> has_replacement

* Only check for a replacement once during creation

* Update Aurora
2026-06-28 22:44:26 -06:00
jdflyer cfadf7607a Various Mirror Mode Fixes (#2149)
* Various Mirror Mode Fixes

* Avoid mutating mArrowPos2DX

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-06-28 22:42:52 -06:00
Luke Street f81d25b425 Add "Touch Targeting" option 2026-06-27 21:20:14 -06:00
qubitnano ebf6f31719 flake.nix: patchelf libvulkan (#2124)
Since aurora 7ccdae18077caa67acb0f61a525aa5a423cc3b2c, dusklight can't
find libvulkan.so on nix
2026-06-27 21:15:57 -06:00
Luke Street 590d209f76 Update README.md 2026-06-27 21:09:04 -06:00
Luke Street ed21cd4fd0 Update README.md 2026-06-27 20:35:17 -06:00
Luke Street 277538bb81 New pipeline progress UI 2026-06-24 22:03:58 -07:00
Luke Street 5418b1831d Update aurora & flake.nix versions 2026-06-17 23:12:49 -06:00
Luke Street 2d4e69466b Refine menu_pointer click events
Only short clicks/taps count & they must
not move between targets
2026-06-17 22:48:44 -06:00
Luke Street 427dcfab82 Show active Graphics Backend in Settings; not configured 2026-06-17 18:09:00 -06:00
Luke Street f5642f3073 UI: Split active/visible concepts & fix nav forwarding 2026-06-16 15:10:09 -06:00
Luke Street cc9c15de54 Hawkeye support in touch controls 2026-06-16 13:51:17 -06:00
Luke Street 1fd8a2ca3c More fixes for clawshot touch controls 2026-06-16 13:37:04 -06:00
Luke Street 0c9c8795ce Update aurora 2026-06-16 13:12:37 -06:00
Luke Street 9eb9acfa11 Move frame limiter after aurora_end_frame 2026-06-16 12:56:02 -06:00
Luke Street facbf35343 Update aurora 2026-06-16 01:53:04 -06:00
Luke Street 7a34830dc7 Update aurora 2026-06-16 01:40:00 -06:00
Luke Street e4557efb23 Disable PkgConfig on Windows 2026-06-16 01:39:54 -06:00
Luke Street 42e12eb5ab Update aurora & fix RCSS warning 2026-06-16 00:14:19 -06:00
Luke Street 16cc37ca10 Android: Call Surface.setFrameRate & update it 2026-06-15 23:39:36 -06:00
Luke Street 44cb2c84ba Update aurora 2026-06-15 23:07:00 -06:00
Luke Street 8e9d4d624a Fix hookshot hanging w/ touch controls 2026-06-15 22:55:30 -06:00
Luke Street db87b91954 Update aurora & redraw hearts guage on HUD scale change 2026-06-15 22:46:50 -06:00
Luke Street ad53af5c78 Touch controls (#2053)
* WIP touch controls

* Action icons

* Updates

* Don't mutate freeCamera config; allow switching between touch and controller cam

* Wow

* Fix build & add Skip button

* Fix build & add settings

* RCSS cleanup

* Dpad and fishing, might redo

* Add menu mouse controls

* More pointer & fix icons

* Optimizations & introduce layout system

* Update aurora

* Implement touch controls layout editor

* Cleanup & fixes

* Allow disabling mouse/touch in menus

* More fixes
2026-06-15 12:48:04 -06:00
qubitnano a6e5160c71 flake.nix: xxHash -> xxhash (#2058)
warning: 'xxHash' has been renamed to 'xxhash'
2026-06-15 12:47:40 -06:00
doop 38a0a7be0b Always create a save file if one doesn't exist (#2028)
* Always create a save file if one doesn't exist

* Fix MSVC build

* Re-add accidentally deleted line

* Integrate into d_file_select state machine & put behind instantSaves

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-06-15 12:47:23 -06:00
Luke Street 02fdde3768 Scale map rendering with IR (#2056)
* Scale map rendering with IR + scale config

* Remove config option
2026-06-14 22:41:33 -06:00
Luke Street 33e13d508b Use Aurora-provided FPS for overlay 2026-06-14 11:28:19 -06:00
Luke Street afc3376aec Update aurora 2026-06-14 01:11:14 -06:00
matthewdavidrichardanderson b07fb50128 monkey crash fix (#2034)
* monkey fix 🐒

* wrap saru_p clear in target_pc

* Clear monkey leader pointer on delete

---------

Co-authored-by: matthewdavidrichardanderson <matthewdavidrichardanderson@mfb.com>
Co-authored-by: Luke Street <luke@street.dev>
2026-06-13 22:39:30 -06:00
Kyrio d0894853d7 Add setting to memorize window size (#2025)
* Add "Memorize Window Size" setting

* Code review #2025

* memorize -> remember, helpText revision

---------

Co-authored-by: Irastris <irastris15@gmail.com>
2026-06-13 22:47:18 -04:00
Luke Street cacb768725 Updatea aurora & set DOWNLOAD_EXTRACT_TIMESTAMP FALSE 2026-06-13 10:44:51 -06:00
Luke Street 00707024bb Update aurora & flower/grass draw batching 2026-06-13 10:40:57 -06:00
Luke Street 7c5ed6a0e1 Fix OSWaitCond implementation 2026-06-10 00:18:14 -06:00
Luke Street 131a09f317 Implement JPA particle batching 2026-06-09 23:47:45 -06:00
Luke Street a58f9c7b43 Update Android shell to SDL 3.4.10 2026-06-09 22:51:23 -06:00
Luke Street 7290649bb8 Prune old logs & dawn_cache.db entries 2026-06-09 00:58:17 -06:00
Luke Street 34e1e740ab Update aurora 2026-06-08 23:14:51 -06:00
Luke Street a58f64ed80 Update aurora 2026-06-08 22:49:28 -06:00
Luke Street 28a37f6b4f Check for sNoUseDrawMtxPtr in J3DModel::entry 2026-06-08 22:14:34 -06:00
Luke Street 285691cd19 Add -debug-asan presets with AddressSanitizer 2026-06-08 22:14:10 -06:00
Luke Street 93e33ecf1a Cap map resolution multiplier
Resolves #1058
Resolves #1422
Resolves #1668
2026-06-08 00:08:00 -06:00
Reilly Brogan e26fab71d6 Add DUSK_PACKAGE_INSTALL (#1966)
Signed-off-by: Reilly Brogan <reilly@reillybrogan.com>
2026-06-07 23:33:49 -06:00
149 changed files with 10499 additions and 1137 deletions
+55 -13
View File
@@ -126,6 +126,33 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "_cmake") set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "_cmake")
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
if (ENABLE_ASAN)
if (CMAKE_C_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" AND
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/fsanitize=address>)
add_link_options(/fsanitize=address /INCREMENTAL:NO)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "ProgramDatabase")
foreach (_lang C CXX)
foreach (_rtc_flag /RTC1 /RTCc /RTCs /RTCu)
string(REPLACE "${_rtc_flag}" "" CMAKE_${_lang}_FLAGS_DEBUG "${CMAKE_${_lang}_FLAGS_DEBUG}")
endforeach ()
endforeach ()
elseif (CMAKE_C_COMPILER_FRONTEND_VARIANT STREQUAL "GNU" AND
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
add_compile_options(
$<$<COMPILE_LANGUAGE:C,CXX,OBJC,OBJCXX>:-fsanitize=address>
$<$<COMPILE_LANGUAGE:C,CXX,OBJC,OBJCXX>:-fno-omit-frame-pointer>
)
add_link_options(-fsanitize=address)
else ()
message(FATAL_ERROR "ENABLE_ASAN requires GNU-like or MSVC-like C/C++ compiler frontends")
endif ()
add_compile_definitions(NDEBUG_SANITIZER) # Avoids absl issue with SwissTable debug code
message(STATUS "dusklight: Enabled AddressSanitizer")
endif ()
if (CMAKE_SYSTEM_NAME STREQUAL Linux) if (CMAKE_SYSTEM_NAME STREQUAL Linux)
set(DAWN_USE_WAYLAND ON CACHE BOOL "Enable support for Wayland surface" FORCE) set(DAWN_USE_WAYLAND ON CACHE BOOL "Enable support for Wayland surface" FORCE)
endif () endif ()
@@ -148,6 +175,7 @@ option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled
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) option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON)
option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF) option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF)
option(DUSK_PACKAGE_INSTALL "Install Dusklight with a Linux-native file structure" OFF)
option(DUSK_GFX_DEBUG_GROUPS "Report debug groups to the native graphics API" ${DUSK_GFX_DEBUG_GROUPS_DEFAULT}) option(DUSK_GFX_DEBUG_GROUPS "Report debug groups to the native graphics API" ${DUSK_GFX_DEBUG_GROUPS_DEFAULT})
set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN") set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN")
set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment") set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment")
@@ -256,7 +284,6 @@ elseif (MSVC)
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/utf-8>) add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/utf-8>)
endif () endif ()
include(FetchContent) include(FetchContent)
# Declare all dependencies first so CMake can download them in parallel # Declare all dependencies first so CMake can download them in parallel
@@ -264,13 +291,13 @@ message(STATUS "dusklight: Fetching cxxopts")
FetchContent_Declare(cxxopts FetchContent_Declare(cxxopts
URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz
URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072 URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072
DOWNLOAD_EXTRACT_TIMESTAMP TRUE DOWNLOAD_EXTRACT_TIMESTAMP FALSE
) )
message(STATUS "dusklight: Fetching nlohmann/json") message(STATUS "dusklight: Fetching nlohmann/json")
FetchContent_Declare(json FetchContent_Declare(json
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa
DOWNLOAD_EXTRACT_TIMESTAMP TRUE DOWNLOAD_EXTRACT_TIMESTAMP FALSE
) )
FetchContent_MakeAvailable(cxxopts json) FetchContent_MakeAvailable(cxxopts json)
@@ -336,7 +363,8 @@ set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES}) source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
source_group("dusklight" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES}) source_group("dusklight" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES})
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1) # PARTIAL_DEBUG makes debug and release share one struct/vtable ABI so a mod binary loads into either
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1 PARTIAL_DEBUG=1)
set(GAME_INCLUDE_DIRS set(GAME_INCLUDE_DIRS
include include
@@ -351,9 +379,7 @@ set(GAME_INCLUDE_DIRS
find_package(Threads REQUIRED) 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) Threads::Threads zstd::libzstd)
list(APPEND GAME_LIBS zstd::libzstd)
if (DUSK_ENABLE_SENTRY_NATIVE) if (DUSK_ENABLE_SENTRY_NATIVE)
list(APPEND GAME_LIBS sentry) list(APPEND GAME_LIBS sentry)
@@ -425,6 +451,11 @@ if(ANDROID)
list(APPEND GAME_COMPILE_DEFS TARGET_ANDROID=1) list(APPEND GAME_COMPILE_DEFS TARGET_ANDROID=1)
endif () endif ()
if (DUSK_PACKAGE_INSTALL)
include(GNUInstallDirs)
list(APPEND GAME_COMPILE_DEFS DUSK_ASSET_DIR="${CMAKE_INSTALL_FULL_DATADIR}/dusklight/")
endif ()
if (DUSK_GFX_DEBUG_GROUPS) if (DUSK_GFX_DEBUG_GROUPS)
list(APPEND GAME_COMPILE_DEFS DUSK_GFX_DEBUG_GROUPS=1) list(APPEND GAME_COMPILE_DEFS DUSK_GFX_DEBUG_GROUPS=1)
target_compile_definitions(aurora_gx PRIVATE AURORA_GFX_DEBUG_GROUPS) target_compile_definitions(aurora_gx PRIVATE AURORA_GFX_DEBUG_GROUPS)
@@ -444,7 +475,7 @@ set(GAME_DEBUG_FILES
set_source_files_properties( set_source_files_properties(
${GAME_DEBUG_FILES} ${GAME_DEBUG_FILES}
PROPERTIES PROPERTIES
COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:DEBUG=1>;$<$<CONFIG:Debug>:PARTIAL_DEBUG=1>" COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:DEBUG=1>;PARTIAL_DEBUG=1"
) )
# game_base is for all other game code files # game_base is for all other game code files
@@ -458,14 +489,14 @@ set(GAME_BASE_FILES
set_source_files_properties( set_source_files_properties(
${GAME_BASE_FILES} ${GAME_BASE_FILES}
PROPERTIES PROPERTIES
COMPILE_DEFINITIONS "NDEBUG=1;NDEBUG_DEFINED=1;DEBUG_DEFINED=0;$<$<CONFIG:Debug>:PARTIAL_DEBUG=1>" COMPILE_DEFINITIONS "NDEBUG=1;NDEBUG_DEFINED=1;DEBUG_DEFINED=0;PARTIAL_DEBUG=1"
) )
foreach(jsystem_lib IN LISTS JSYSTEM_LIBRARIES) foreach(jsystem_lib IN LISTS JSYSTEM_LIBRARIES)
target_compile_definitions(${jsystem_lib} PRIVATE target_compile_definitions(${jsystem_lib} PRIVATE
${GAME_COMPILE_DEFS} ${GAME_COMPILE_DEFS}
$<$<CONFIG:Debug>:DEBUG=1> $<$<CONFIG:Debug>:DEBUG=1>
$<$<CONFIG:Debug>:PARTIAL_DEBUG=1> PARTIAL_DEBUG=1
) )
target_include_directories(${jsystem_lib} PRIVATE ${GAME_INCLUDE_DIRS}) target_include_directories(${jsystem_lib} PRIVATE ${GAME_INCLUDE_DIRS})
target_link_libraries(${jsystem_lib} PRIVATE ${GAME_LIBS}) target_link_libraries(${jsystem_lib} PRIVATE ${GAME_LIBS})
@@ -486,6 +517,9 @@ if(ANDROID)
else () else ()
add_executable(dusklight ${DUSK_FILES}) add_executable(dusklight ${DUSK_FILES})
endif () endif ()
if (ENABLE_ASAN)
target_sources(dusklight PRIVATE src/dusk/asan_options.c)
endif ()
target_compile_definitions(dusklight PRIVATE ${GAME_COMPILE_DEFS}) target_compile_definitions(dusklight PRIVATE ${GAME_COMPILE_DEFS})
target_include_directories(dusklight PRIVATE ${GAME_INCLUDE_DIRS}) target_include_directories(dusklight PRIVATE ${GAME_INCLUDE_DIRS})
@@ -648,12 +682,20 @@ set(EXTRA_TARGETS "")
if (TARGET crashpad_handler) if (TARGET crashpad_handler)
list(APPEND EXTRA_TARGETS crashpad_handler) list(APPEND EXTRA_TARGETS crashpad_handler)
endif () endif ()
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX}) if (DUSK_PACKAGE_INSTALL)
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_BINDIR})
else()
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
aurora_install_runtime_dlls(dusklight ${CMAKE_INSTALL_PREFIX}) aurora_install_runtime_dlls(dusklight ${CMAKE_INSTALL_PREFIX})
if (NOT APPLE) if (NOT APPLE)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX}) if (DUSK_PACKAGE_INSTALL)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/dusklight)
else()
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
endif () endif ()
if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo) if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo AND NOT DUSK_PACKAGE_INSTALL)
set(DEBUG_FILES_LIST "") set(DEBUG_FILES_LIST "")
foreach (target IN LISTS BINARY_TARGETS EXTRA_TARGETS) foreach (target IN LISTS BINARY_TARGETS EXTRA_TARGETS)
get_target_output_name(${target} output_name) get_target_output_name(${target} output_name)
+75 -1
View File
@@ -52,6 +52,16 @@
} }
} }
}, },
{
"name": "asan",
"hidden": true,
"cacheVariables": {
"ENABLE_ASAN": {
"type": "BOOL",
"value": true
}
}
},
{ {
"name": "linux-default", "name": "linux-default",
"displayName": "Linux (default)", "displayName": "Linux (default)",
@@ -83,6 +93,15 @@
"linux-default" "linux-default"
] ]
}, },
{
"name": "linux-default-debug-asan",
"displayName": "Linux (default) Debug ASan",
"inherits": [
"debug",
"linux-default",
"asan"
]
},
{ {
"name": "linux-default-relwithdebinfo", "name": "linux-default-relwithdebinfo",
"displayName": "Linux (default) RelWithDebInfo", "displayName": "Linux (default) RelWithDebInfo",
@@ -110,6 +129,15 @@
"linux-clang" "linux-clang"
] ]
}, },
{
"name": "linux-clang-debug-asan",
"displayName": "Linux (Clang) Debug ASan",
"inherits": [
"debug",
"linux-clang",
"asan"
]
},
{ {
"name": "linux-clang-relwithdebinfo", "name": "linux-clang-relwithdebinfo",
"displayName": "Linux (Clang) RelWithDebInfo", "displayName": "Linux (Clang) RelWithDebInfo",
@@ -130,7 +158,11 @@
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER": "cl", "CMAKE_C_COMPILER": "cl",
"CMAKE_CXX_COMPILER": "cl", "CMAKE_CXX_COMPILER": "cl",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install" "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
"CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": {
"type": "BOOL",
"value": true
}
}, },
"vendor": { "vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "microsoft.com/VisualStudioSettings/CMake/1.0": {
@@ -148,6 +180,15 @@
"windows-msvc" "windows-msvc"
] ]
}, },
{
"name": "windows-msvc-debug-asan",
"displayName": "Windows (MSVC) Debug ASan",
"inherits": [
"debug",
"windows-msvc",
"asan"
]
},
{ {
"name": "windows-msvc-relwithdebinfo", "name": "windows-msvc-relwithdebinfo",
"displayName": "Windows (MSVC) RelWithDebInfo", "displayName": "Windows (MSVC) RelWithDebInfo",
@@ -239,6 +280,15 @@
"macos-default" "macos-default"
] ]
}, },
{
"name": "macos-default-debug-asan",
"displayName": "macOS (default) Debug ASan",
"inherits": [
"debug",
"macos-default",
"asan"
]
},
{ {
"name": "macos-default-relwithdebinfo", "name": "macos-default-relwithdebinfo",
"displayName": "macOS (default) RelWithDebInfo", "displayName": "macOS (default) RelWithDebInfo",
@@ -529,6 +579,12 @@
"description": "Linux (default) debug build", "description": "Linux (default) debug build",
"displayName": "Linux (default) Debug" "displayName": "Linux (default) Debug"
}, },
{
"name": "linux-default-debug-asan",
"configurePreset": "linux-default-debug-asan",
"description": "Linux (default) debug build with AddressSanitizer",
"displayName": "Linux (default) Debug ASan"
},
{ {
"name": "linux-default-relwithdebinfo", "name": "linux-default-relwithdebinfo",
"configurePreset": "linux-default-relwithdebinfo", "configurePreset": "linux-default-relwithdebinfo",
@@ -541,6 +597,12 @@
"description": "Linux (Clang) debug build", "description": "Linux (Clang) debug build",
"displayName": "Linux (Clang) Debug" "displayName": "Linux (Clang) Debug"
}, },
{
"name": "linux-clang-debug-asan",
"configurePreset": "linux-clang-debug-asan",
"description": "Linux (Clang) debug build with AddressSanitizer",
"displayName": "Linux (Clang) Debug ASan"
},
{ {
"name": "linux-clang-relwithdebinfo", "name": "linux-clang-relwithdebinfo",
"configurePreset": "linux-clang-relwithdebinfo", "configurePreset": "linux-clang-relwithdebinfo",
@@ -553,6 +615,12 @@
"description": "macOS debug build", "description": "macOS debug build",
"displayName": "macOS Debug" "displayName": "macOS Debug"
}, },
{
"name": "macos-default-debug-asan",
"configurePreset": "macos-default-debug-asan",
"description": "macOS debug build with AddressSanitizer",
"displayName": "macOS Debug ASan"
},
{ {
"name": "macos-default-relwithdebinfo", "name": "macos-default-relwithdebinfo",
"configurePreset": "macos-default-relwithdebinfo", "configurePreset": "macos-default-relwithdebinfo",
@@ -610,6 +678,12 @@
"description": "Windows (MSVC) debug build", "description": "Windows (MSVC) debug build",
"displayName": "Windows (MSVC) Debug" "displayName": "Windows (MSVC) Debug"
}, },
{
"name": "windows-msvc-debug-asan",
"configurePreset": "windows-msvc-debug-asan",
"description": "Windows (MSVC) debug build with AddressSanitizer",
"displayName": "Windows (MSVC) Debug ASan"
},
{ {
"name": "windows-msvc-relwithdebinfo", "name": "windows-msvc-relwithdebinfo",
"configurePreset": "windows-msvc-relwithdebinfo", "configurePreset": "windows-msvc-relwithdebinfo",
+4 -18
View File
@@ -20,31 +20,17 @@ It aims to be as accurate as possible to the original while also providing new o
> Dusklight does *not* provide any copyrighted assets. You must provide your own copy of the original game. > Dusklight does *not* provide any copyrighted assets. You must provide your own copy of the original game.
> [!IMPORTANT] > [!IMPORTANT]
> At a minimum, Dusklight requires a GPU with support for either D3D12, Vulkan, or Metal. Your experience with specific hardware, operating systems, and drivers may vary. In particular, older Intel iGPUs have a high likelihood of incompatibility. We are also aware of a number of issues on devices with Adreno GPUs and are working to resolve them. > At a minimum, Dusklight requires a GPU with support for D3D12, Vulkan 1.1+, or Metal. For older devices, best-effort support is provided for D3D11 and OpenGL ES (Android), but will not achieve full accuracy or performance. Your experience with specific hardware, operating systems, and drivers may vary.
### 1. Dump your game ### 1. Dump your game
You must dump your own copy of the game, please see [this article](https://wiki.dolphin-emu.org/index.php?title=Ripping_Games) for instructions. After dumping, you can use a program like [Dolphin](https://dolphin-emu.org/) or [nodtool](https://github.com/encounter/nod/releases) to convert the `.iso` to a `.rvz` to save space. You must dump your own copy of the game. Please see [this article](https://wiki.dolphin-emu.org/index.php?title=Ripping_Games) for instructions. After dumping, you can use a program like [Dolphin](https://dolphin-emu.org/) or [nodtool](https://github.com/encounter/nod/releases) to convert the `.iso` to `.rvz` to save space.
Currently, only the GameCube USA and EUR releases are supported. Support for other versions of the game is planned in the future. Currently, only the GameCube USA and EUR releases are supported. Support for other versions of the game is planned in the future.
### 2. Download [Dusklight](https://github.com/TwilitRealm/dusklight/releases) ### 2. Install Dusklight
### 3. Setup the game Visit the [official installation guide](https://twilitrealm.dev/install/) for full instructions.
**Windows / macOS / Linux**
- Extract the .zip file
- Launch Dusklight
- Press **Select Disc Image** and provide the path to your supported game dump
- Press **Play**!
**iOS**
- Follow the [iOS setup guide](docs/ios-install-altstore.md)
**Android**
- Install the Dusklight APK
- Launch Dusklight
- Press **Select Disc Image** and provide the path to your supported game dump
- Press **Play**!
# Building # Building
+4
View File
@@ -180,6 +180,7 @@ cmake --build --preset macos-default-relwithdebinfo
Alternate presets available: Alternate presets available:
* `macos-default-debug`: Clang, Debug * `macos-default-debug`: Clang, Debug
* `macos-default-debug-asan`: Clang, Debug, AddressSanitizer
**ninja (Linux)** **ninja (Linux)**
@@ -191,8 +192,10 @@ cmake --build --preset linux-default-relwithdebinfo
Alternate presets available: Alternate presets available:
* `linux-default-debug`: GCC, Debug * `linux-default-debug`: GCC, Debug
* `linux-default-debug-asan`: GCC, Debug, AddressSanitizer
* `linux-clang-relwithdebinfo`: Clang, RelWithDebInfo * `linux-clang-relwithdebinfo`: Clang, RelWithDebInfo
* `linux-clang-debug`: Clang, Debug * `linux-clang-debug`: Clang, Debug
* `linux-clang-debug-asan`: Clang, Debug, AddressSanitizer
**ninja (Windows)** **ninja (Windows)**
@@ -204,6 +207,7 @@ cmake --build --preset windows-msvc-relwithdebinfo
Alternate presets available: Alternate presets available:
* `windows-msvc-debug`: MSVC, Debug * `windows-msvc-debug`: MSVC, Debug
* `windows-msvc-debug-asan`: MSVC, Debug, AddressSanitizer
* `windows-clang-relwithdebinfo`: Clang-cl, RelWithDebInfo * `windows-clang-relwithdebinfo`: Clang-cl, RelWithDebInfo
* `windows-clang-debug`: Clang-cl, Debug * `windows-clang-debug`: Clang-cl, Debug
+1 -1
+16
View File
@@ -1418,7 +1418,11 @@ set(DUSK_FILES
include/dusk/scope_guard.hpp include/dusk/scope_guard.hpp
src/dusk/dvd_asset.cpp src/dusk/dvd_asset.cpp
src/d/actor/d_a_alink_dusk.cpp src/d/actor/d_a_alink_dusk.cpp
src/dusk/android_frame_rate.hpp
src/dusk/android_frame_rate.cpp
src/dusk/asserts.cpp src/dusk/asserts.cpp
src/dusk/batch.cpp
src/dusk/batch.hpp
src/dusk/config.cpp src/dusk/config.cpp
src/dusk/crash_handler.cpp src/dusk/crash_handler.cpp
src/dusk/crash_reporting.cpp src/dusk/crash_reporting.cpp
@@ -1432,6 +1436,8 @@ set(DUSK_FILES
src/dusk/game_clock.cpp src/dusk/game_clock.cpp
src/dusk/globals.cpp src/dusk/globals.cpp
src/dusk/gyro.cpp src/dusk/gyro.cpp
include/dusk/menu_pointer.h
src/dusk/menu_pointer.cpp
src/dusk/mouse.cpp src/dusk/mouse.cpp
src/dusk/gamepad_color.cpp src/dusk/gamepad_color.cpp
src/dusk/autosave.cpp src/dusk/autosave.cpp
@@ -1445,6 +1451,7 @@ set(DUSK_FILES
src/dusk/stubs.cpp src/dusk/stubs.cpp
include/dusk/texture_replacements.hpp include/dusk/texture_replacements.hpp
src/dusk/texture_replacements.cpp src/dusk/texture_replacements.cpp
src/dusk/touch_camera.cpp
src/dusk/update_check.cpp src/dusk/update_check.cpp
src/dusk/update_check.hpp src/dusk/update_check.hpp
#src/dusk/m_Do_ext_dusk.cpp #src/dusk/m_Do_ext_dusk.cpp
@@ -1474,6 +1481,7 @@ set(DUSK_FILES
src/dusk/ui/button.hpp src/dusk/ui/button.hpp
src/dusk/ui/component.cpp src/dusk/ui/component.cpp
src/dusk/ui/component.hpp src/dusk/ui/component.hpp
src/dusk/ui/controls.hpp
src/dusk/ui/controller_config.cpp src/dusk/ui/controller_config.cpp
src/dusk/ui/controller_config.hpp src/dusk/ui/controller_config.hpp
src/dusk/ui/document.cpp src/dusk/ui/document.cpp
@@ -1486,6 +1494,8 @@ set(DUSK_FILES
src/dusk/ui/graphics_tuner.hpp src/dusk/ui/graphics_tuner.hpp
src/dusk/ui/input.cpp src/dusk/ui/input.cpp
src/dusk/ui/input.hpp src/dusk/ui/input.hpp
src/dusk/ui/icon_provider.cpp
src/dusk/ui/icon_provider.hpp
src/dusk/ui/modal.cpp src/dusk/ui/modal.cpp
src/dusk/ui/modal.hpp src/dusk/ui/modal.hpp
src/dusk/ui/nav_types.hpp src/dusk/ui/nav_types.hpp
@@ -1511,6 +1521,12 @@ set(DUSK_FILES
src/dusk/ui/string_button.hpp src/dusk/ui/string_button.hpp
src/dusk/ui/tab_bar.cpp src/dusk/ui/tab_bar.cpp
src/dusk/ui/tab_bar.hpp src/dusk/ui/tab_bar.hpp
src/dusk/ui/touch_controls_common.cpp
src/dusk/ui/touch_controls_common.hpp
src/dusk/ui/touch_controls.cpp
src/dusk/ui/touch_controls.hpp
src/dusk/ui/touch_controls_editor.cpp
src/dusk/ui/touch_controls_editor.hpp
src/dusk/ui/ui.cpp src/dusk/ui/ui.cpp
src/dusk/ui/ui.hpp src/dusk/ui/ui.hpp
src/dusk/ui/warp.cpp src/dusk/ui/warp.cpp
+22 -16
View File
@@ -16,37 +16,37 @@
]; ];
forAllSystems = lib.genAttrs supportedSystems; forAllSystems = lib.genAttrs supportedSystems;
dawnVersion = "v20260423.175430"; dawnVersion = "v20260618.032059";
nodVersion = "v2.0.0-alpha.8"; nodVersion = "v2.0.0-alpha.10";
versionSuffix = "nix-" + (self.shortRev or self.dirtyShortRev or "dirty"); versionSuffix = "nix-" + (self.shortRev or self.dirtyShortRev or "dirty");
dawnInfo = { dawnInfo = {
"x86_64-linux" = { "x86_64-linux" = {
triple = "linux-x86_64"; triple = "linux-x86_64";
hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs="; hash = "sha256-GFSd573b+VQx/VmFdNQgWDd0V9ayQlcw0Zuopke12ak=";
}; };
"aarch64-linux" = { "aarch64-linux" = {
triple = "linux-aarch64"; triple = "linux-aarch64";
hash = "sha256-34yyFpfqBZUwoFXQ41F0AwAU78FaNihOSY0oriwn6B0="; hash = "sha256-ZaoP7BAjBMnfAv2/AMRi3FNH2ZtyqASCSFyU/oB2Mzg=";
}; };
"aarch64-darwin" = { "aarch64-darwin" = {
triple = "darwin-arm64"; triple = "darwin-arm64";
hash = "sha256-eQnzrBp6gjiBek1VYQ9A5W13ClYWrDDKjIqv/7eNTR4="; hash = "sha256-HT+qtlLaSHyoXPrUcXgcTGa877X5YfzbxRD4bJb7i1Y=";
}; };
"x86_64-darwin" = { "x86_64-darwin" = {
triple = "darwin-x86_64"; triple = "darwin-x86_64";
hash = "sha256-QGWiGdxiI9kci3NPXH6QFFirxn16851zB/w3jqhIBJ4="; hash = "sha256-cUNaCbA7rlKSukDVKGaVEVw0Zt1+mSbaHbmUCMvMVWc=";
}; };
}; };
nodPrebuiltInfo = { nodPrebuiltInfo = {
"x86_64-linux" = { "x86_64-linux" = {
triple = "linux-x86_64"; triple = "linux-x86_64";
hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE="; hash = "sha256-FVQWECVA2gWdc+n5OQ/Tvwn8z0qdgjSd1WlFt5HKOec=";
}; };
"aarch64-darwin" = { "aarch64-darwin" = {
triple = "macos-arm64"; triple = "macos-arm64";
hash = "sha256-UPy1ywCcv0K6VJOU3uUelJuUdBh3UNaPRlyP5LOBeDw="; hash = "sha256-8ZEejxksVgShNKUVRCBYaLOp9x/qOC9pAeVrElQUGUk=";
}; };
}; };
@@ -75,7 +75,7 @@
''; '';
dawn = pkgs.fetchzip { dawn = pkgs.fetchzip {
url = "https://github.com/encounter/dawn-build/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz"; url = "https://github.com/encounter/dawn/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz";
hash = dawnInfo.${system}.hash; hash = dawnInfo.${system}.hash;
stripRoot = false; stripRoot = false;
}; };
@@ -94,7 +94,7 @@
owner = "encounter"; owner = "encounter";
repo = "nod"; repo = "nod";
rev = nodVersion; rev = nodVersion;
hash = "sha256-+zrtVzjo0+X/6uMcNUn1+FaSR+jOhrcQSDNBFjw0NDs="; hash = "sha256-r8qDlOVxv5iKiFjJQrcBuL9HVoOM3yEjRVnQIMqaICs=";
}; };
patches = [ ./fix-cmake-paths.patch ]; patches = [ ./fix-cmake-paths.patch ];
cargoDeps = pkgs.rustPlatform.importCargoLock { cargoDeps = pkgs.rustPlatform.importCargoLock {
@@ -138,15 +138,15 @@
NOD_PREBUILT = nod; NOD_PREBUILT = nod;
CXXOPTS = pkgs.cxxopts.src; CXXOPTS = pkgs.cxxopts.src;
JSON = pkgs.nlohmann_json.src; JSON = pkgs.nlohmann_json.src;
XXHASH = pkgs.xxHash.src; XXHASH = pkgs.xxhash.src;
ZSTD = pkgs.zstd.src; ZSTD = pkgs.zstd.src;
FMT = pkgs.fetchzip { FMT = pkgs.fetchzip {
url = "https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz"; url = "https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz";
hash = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA="; hash = "sha256-ZmI1Dv0ZabPlxa02OpERI47jp7zFfjpeWCy1WyuPYZ0=";
}; };
TRACY = pkgs.fetchzip { TRACY = pkgs.fetchzip {
url = "https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz"; url = "https://github.com/wolfpld/tracy/archive/6789e7d6f9a65ec98926b602097a33a9676d2606.tar.gz";
hash = "sha256-hbNGOsGeyGSvCJ2No8RkwOib1lX2on3vNZSzyVkZdXw="; hash = "sha256-Xxyd7G/mnXEPpN+ehmwl0AkAhS3CwObpJNDgcqbdUJg=";
}; };
IMGUI = pkgs.fetchFromGitHub { IMGUI = pkgs.fetchFromGitHub {
owner = "ocornut"; owner = "ocornut";
@@ -194,7 +194,7 @@
pkgs.zstd pkgs.zstd
pkgs.cxxopts pkgs.cxxopts
pkgs.nlohmann_json pkgs.nlohmann_json
pkgs.xxHash pkgs.xxhash
pkgs.abseil-cpp pkgs.abseil-cpp
pkgs.zlib pkgs.zlib
pkgs.libpng pkgs.libpng
@@ -269,6 +269,12 @@
runHook postInstall runHook postInstall
''; '';
postFixup = lib.optionalString (!isDarwin) ''
patchelf \
--add-needed "${pkgs.vulkan-loader}/lib/libvulkan.so" \
$out/bin/dusklight
'';
dontStrip = true; dontStrip = true;
meta = { meta = {
@@ -20,7 +20,7 @@ public:
/* 0x14 */ cM3dGAab mM3dGAab; /* 0x14 */ cM3dGAab mM3dGAab;
/* 0x30 */ cBgS_ShdwDraw_Callback mCallbackFun; /* 0x30 */ cBgS_ShdwDraw_Callback mCallbackFun;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x34 */ int field_0x34; /* 0x34 */ int field_0x34;
#endif #endif
}; };
+2
View File
@@ -48,6 +48,8 @@ public:
/* 0x1370 */ Z2FxLineMgr mFxLineMgr; /* 0x1370 */ Z2FxLineMgr mFxLineMgr;
#if DEBUG #if DEBUG
/* 0x13BC */ Z2DebugSys mDebugSys; /* 0x13BC */ Z2DebugSys mDebugSys;
#elif PARTIAL_DEBUG
alignas(Z2DebugSys) u8 mDebugSys[sizeof(Z2DebugSys)];
#endif #endif
}; // Size: 0x138C }; // Size: 0x138C
+1 -1
View File
@@ -194,7 +194,7 @@ public:
JAISoundHandle* getMainBgmHandle() { return &mMainBgmHandle; } JAISoundHandle* getMainBgmHandle() { return &mMainBgmHandle; }
JAISoundHandle* getSubBgmHandle() { return &mSubBgmHandle; } JAISoundHandle* getSubBgmHandle() { return &mSubBgmHandle; }
#if DEBUG #if PARTIAL_DEBUG || DEBUG
f32 field_0x00_debug; f32 field_0x00_debug;
u8 field_0x04_debug; u8 field_0x04_debug;
#endif #endif
+2 -2
View File
@@ -100,13 +100,13 @@ public:
bool isForceBattle() { return forceBattle_; } bool isForceBattle() { return forceBattle_; }
JSUList<Z2CreatureEnemy>* getEnemyList() { return &field_0x0; } JSUList<Z2CreatureEnemy>* getEnemyList() { return &field_0x0; }
#if DEBUG #if PARTIAL_DEBUG || DEBUG
JSUList<Z2SoundObjBase>* getAllList() { return &allList_; } JSUList<Z2SoundObjBase>* getAllList() { return &allList_; }
#endif #endif
private: private:
/* 0x00 */ JSUList<Z2CreatureEnemy> field_0x0; /* 0x00 */ JSUList<Z2CreatureEnemy> field_0x0;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x0C */ JSUList<Z2SoundObjBase> allList_; /* 0x0C */ JSUList<Z2SoundObjBase> allList_;
#endif #endif
/* 0x0C */ Z2EnemyArea enemyArea_; /* 0x0C */ Z2EnemyArea enemyArea_;
+1 -1
View File
@@ -7,7 +7,7 @@
struct Z2SoundStarter; struct Z2SoundStarter;
class Z2SoundObjBase : public Z2SoundHandles class Z2SoundObjBase : public Z2SoundHandles
#if DEBUG #if PARTIAL_DEBUG || DEBUG
, public JSULink<Z2SoundObjBase> , public JSULink<Z2SoundObjBase>
#endif #endif
{ {
+1
View File
@@ -4556,6 +4556,7 @@ public:
void handleWolfHowl(); void handleWolfHowl();
void handleQuickTransform(); void handleQuickTransform();
bool checkAimContext(); bool checkAimContext();
bool checkAimInputContext();
void onIronBallChainInterpCallback(); void onIronBallChainInterpCallback();
+7 -2
View File
@@ -88,9 +88,14 @@ public:
/* 0x396A */ u8 field_0x396A[0x399E - 0x396A]; /* 0x396A */ u8 field_0x396A[0x399E - 0x396A];
/* 0x399E */ s16 field_0x399e; /* 0x399E */ s16 field_0x399e;
/* 0x39A0 */ u8 field_0x39A0[0x39A4 - 0x39A0]; /* 0x39A0 */ u8 field_0x39A0[0x39A4 - 0x39A0];
#if TARGET_PC
/* 0x39A4 */ cM_rnd_c mMantRng;
#endif
}; };
#if TARGET_PC
STATIC_ASSERT(sizeof(mant_class) == 0x39ac);
#else
STATIC_ASSERT(sizeof(mant_class) == 0x39a4); STATIC_ASSERT(sizeof(mant_class) == 0x39a4);
#endif
#endif /* D_A_MANT_H */ #endif /* D_A_MANT_H */
+10
View File
@@ -4,6 +4,10 @@
#include "JSystem/J3DGraphBase/J3DPacket.h" #include "JSystem/J3DGraphBase/J3DPacket.h"
#include "SSystem/SComponent/c_xyz.h" #include "SSystem/SComponent/c_xyz.h"
#if TARGET_PC
#include "dusk/batch.hpp"
#endif
class cCcD_Obj; class cCcD_Obj;
class dCcMassS_HitInf; class dCcMassS_HitInf;
class fopAc_ac_c; class fopAc_ac_c;
@@ -107,6 +111,12 @@ public:
#if TARGET_PC #if TARGET_PC
TGXTexObj mTexObj_l_J_Ohana00_64TEX; TGXTexObj mTexObj_l_J_Ohana00_64TEX;
TGXTexObj mTexObj_l_J_Ohana01_64128_0419TEX; TGXTexObj mTexObj_l_J_Ohana01_64128_0419TEX;
dusk::batch::LeafTemplate mTplHana00; // l_J_hana00DL
dusk::batch::LeafTemplate mTplHana00Cut; // l_J_hana00_cDL
dusk::batch::LeafTemplate mTplHana01; // l_J_hana01DL
dusk::batch::LeafTemplate mTplHana01Cut00; // l_J_hana01_c_00DL
dusk::batch::LeafTemplate mTplHana01Cut; // l_J_hana01_c_01DL
#endif #endif
}; // Size: 0x12A54 }; // Size: 0x12A54
+8
View File
@@ -4,6 +4,10 @@
#include "JSystem/J3DGraphBase/J3DPacket.h" #include "JSystem/J3DGraphBase/J3DPacket.h"
#include "SSystem/SComponent/c_xyz.h" #include "SSystem/SComponent/c_xyz.h"
#if TARGET_PC
#include "../../../src/dusk/batch.hpp"
#endif
class cCcD_Obj; class cCcD_Obj;
class csXyz; class csXyz;
class dCcMassS_HitInf; class dCcMassS_HitInf;
@@ -110,6 +114,10 @@ public:
#if TARGET_PC #if TARGET_PC
TGXTexObj mTexObj_l_M_Hijiki00TEX; TGXTexObj mTexObj_l_M_Hijiki00TEX;
TGXTexObj mTexObj_l_M_kusa05_RGBATEX; TGXTexObj mTexObj_l_M_kusa05_RGBATEX;
dusk::batch::LeafTemplate mTplKusa9q; // l_M_Kusa_9qDL
dusk::batch::LeafTemplate mTplKusa9qCut; // l_M_Kusa_9q_cDL
dusk::batch::LeafTemplate mTplTengusa; // l_M_TenGusaDL
#endif #endif
}; // Size: 0x1D718 }; // Size: 0x1D718
+2 -2
View File
@@ -45,7 +45,7 @@ private:
class dAttParam_c : public JORReflexible { class dAttParam_c : public JORReflexible {
public: public:
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x04 */ s8 mHIOChildNo; /* 0x04 */ s8 mHIOChildNo;
#endif #endif
@@ -66,7 +66,7 @@ public:
/* 0x35 */ u8 mAttnCursorDisappearFrames; /* 0x35 */ u8 mAttnCursorDisappearFrames;
/* 0x38 */ f32 field_0x38; /* 0x38 */ f32 field_0x38;
/* 0x3C */ f32 field_0x3c; /* 0x3C */ f32 field_0x3c;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x44 */ s32 mDebugDispPosX; /* 0x44 */ s32 mDebugDispPosX;
/* 0x48 */ s32 mDebugDispPosY; /* 0x48 */ s32 mDebugDispPosY;
#endif #endif
+2 -2
View File
@@ -201,7 +201,7 @@ private:
/* 0x02C */ u32 m_flags; /* 0x02C */ u32 m_flags;
/* 0x030 */ cXyz* pm_pos; /* 0x030 */ cXyz* pm_pos;
/* 0x034 */ cXyz* pm_old_pos; /* 0x034 */ cXyz* pm_old_pos;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x038 */ cXyz unk_0x38; /* 0x038 */ cXyz unk_0x38;
#endif #endif
/* 0x038 */ cXyz* pm_speed; /* 0x038 */ cXyz* pm_speed;
@@ -229,7 +229,7 @@ private:
/* 0x0CC */ f32 field_0xcc; /* 0x0CC */ f32 field_0xcc;
/* 0x0D0 */ f32 m_wtr_chk_offset; /* 0x0D0 */ f32 m_wtr_chk_offset;
/* 0x0D4 */ cBgS_PolyInfo* pm_out_poly_info; /* 0x0D4 */ cBgS_PolyInfo* pm_out_poly_info;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x0E4 */ cXyz unk_0xe4; /* 0x0E4 */ cXyz unk_0xe4;
#endif #endif
/* 0x0D8 */ f32 field_0xd8; /* 0x0D8 */ f32 field_0xd8;
+1 -1
View File
@@ -1037,7 +1037,7 @@ public:
bool test1Camera(s32); bool test1Camera(s32);
bool test2Camera(s32); bool test2Camera(s32);
#if TARGET_PC #if TARGET_PC
static bool canUseFreeCam(); static bool isAimActive();
bool freeCamera(); bool freeCamera();
bool executeDebugFlyCam(); bool executeDebugFlyCam();
void deactivateDebugFlyCam(); void deactivateDebugFlyCam();
+1 -1
View File
@@ -79,7 +79,7 @@ public:
// /* 0x0000 */ cCcS mCCcS; // /* 0x0000 */ cCcS mCCcS;
/* 0x284C */ dCcMassS_Mng mMass_Mng; /* 0x284C */ dCcMassS_Mng mMass_Mng;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x2AD0 */ u8 m_is_mass_all_timer; /* 0x2AD0 */ u8 m_is_mass_all_timer;
#endif #endif
}; // Size = 0x2AC4 }; // Size = 0x2AC4
+1 -1
View File
@@ -1037,7 +1037,7 @@ public:
/* 0x1DE09 */ u8 field_0x1de09; /* 0x1DE09 */ u8 field_0x1de09;
/* 0x1DE0A */ u8 field_0x1de0a; /* 0x1DE0A */ u8 field_0x1de0a;
/* 0x1DE0B */ u8 mIsDebugMode; /* 0x1DE0B */ u8 mIsDebugMode;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x1DE0C */ OSStopwatch mStopwatch; /* 0x1DE0C */ OSStopwatch mStopwatch;
#endif #endif
+1 -1
View File
@@ -41,7 +41,7 @@ public:
BASE_ROOM5, BASE_ROOM5,
BASE_DEMO, BASE_DEMO,
#if DEBUG #if PARTIAL_DEBUG || DEBUG
BASE_DEBUG, BASE_DEBUG,
#endif #endif
+13
View File
@@ -287,6 +287,11 @@ public:
MEMCARDCHECKPROC_ERR_YESNO_CURSOR_MOVE_ANM, MEMCARDCHECKPROC_ERR_YESNO_CURSOR_MOVE_ANM,
MEMCARDCHECKPROC_SAVEDATA_CLEAR, MEMCARDCHECKPROC_SAVEDATA_CLEAR,
#if TARGET_PC
MEMCARDCHECKPROC_AUTO_MAKE_GAMEFILE,
MEMCARDCHECKPROC_AUTO_MAKE_GAMEFILE_ERR_WAIT,
#endif
#if PLATFORM_WII || PLATFORM_SHIELD #if PLATFORM_WII || PLATFORM_SHIELD
MEMCARDCHECKPROC_NAND_STAT_CHECK, MEMCARDCHECKPROC_NAND_STAT_CHECK,
MEMCARDCHECKPROC_GAMEFILE_INIT_SEL, MEMCARDCHECKPROC_GAMEFILE_INIT_SEL,
@@ -411,6 +416,10 @@ public:
bool yesnoWakuAlpahAnm(u8); bool yesnoWakuAlpahAnm(u8);
#if TARGET_PC #if TARGET_PC
void fileSelectWide(); void fileSelectWide();
bool pointerDataSelect();
bool pointerMenuSelect();
bool pointerCopyDataToSelect();
bool pointerYesNoSelect(bool errorSelect);
#endif #endif
void _draw(); void _draw();
void errorMoveAnmInitSet(int, int); void errorMoveAnmInitSet(int, int);
@@ -445,6 +454,10 @@ public:
void MemCardMakeGameFile(); void MemCardMakeGameFile();
void MemCardMakeGameFileWait(); void MemCardMakeGameFileWait();
void MemCardMakeGameFileCheck(); void MemCardMakeGameFileCheck();
#if TARGET_PC
void MemCardAutoMakeGameFile();
void MemCardAutoMakeGameFileErrWait();
#endif
void MemCardMsgWindowInitOpen(); void MemCardMsgWindowInitOpen();
void MemCardMsgWindowOpen(); void MemCardMsgWindowOpen();
void MemCardMsgWindowClose(); void MemCardMsgWindowClose();
+1 -1
View File
@@ -259,7 +259,7 @@ public:
/* 0x09B8 */ DUNGEON_LIGHT dungeonlight[8]; /* 0x09B8 */ DUNGEON_LIGHT dungeonlight[8];
/* 0x0C18 */ BOSS_LIGHT field_0x0c18[8]; /* 0x0C18 */ BOSS_LIGHT field_0x0c18[8];
/* 0x0D58 */ BOSS_LIGHT field_0x0d58[6]; /* 0x0D58 */ BOSS_LIGHT field_0x0d58[6];
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x0E48 */ NAVYCHAN navy; /* 0x0E48 */ NAVYCHAN navy;
/* 0x0E58 */ u8 field_0xe58[0xE68 - 0xE58]; // part of NAVYCHAN? /* 0x0E58 */ u8 field_0xe58[0xE68 - 0xE58]; // part of NAVYCHAN?
#endif #endif
+3
View File
@@ -157,6 +157,9 @@ public:
int getDispType() const; int getDispType() const;
void _move(f32, f32, int, f32); void _move(f32, f32, int, f32);
void _draw(); void _draw();
#if TARGET_PC
bool refreshTextureSize();
#endif
virtual ~dMap_c() { virtual ~dMap_c() {
#if DEBUG #if DEBUG
+2
View File
@@ -74,6 +74,8 @@ public:
#if TARGET_PC #if TARGET_PC
void menuCollectWide(); void menuCollectWide();
bool pointerWait();
void pointerActivateCurrent();
#endif #endif
void _create(); void _create();
+4
View File
@@ -51,6 +51,10 @@ public:
void setBButtonString(u16); void setBButtonString(u16);
void setHIO(bool); void setHIO(bool);
#if TARGET_PC
bool pointerWait();
#endif
virtual void draw() { _draw(); } virtual void draw() { _draw(); }
virtual ~dMenu_Insect_c(); virtual ~dMenu_Insect_c();
+4
View File
@@ -55,6 +55,10 @@ public:
u8 getLetterNum(); u8 getLetterNum();
void setHIO(bool); void setHIO(bool);
#if TARGET_PC
bool pointerWait();
#endif
virtual void draw() { _draw(); } virtual void draw() { _draw(); }
virtual ~dMenu_Letter_c(); virtual ~dMenu_Letter_c();
+3
View File
@@ -80,6 +80,9 @@ public:
void setBButtonString(u16); void setBButtonString(u16);
bool isRumbleSupported(); bool isRumbleSupported();
bool dpdMenuMove(); bool dpdMenuMove();
#if TARGET_PC
bool pointerConfirmSelect();
#endif
void paneResize(u64); void paneResize(u64);
void initialize(); void initialize();
void yesnoMenuMoveAnmInitSet(int, int); void yesnoMenuMoveAnmInitSet(int, int);
+4
View File
@@ -74,6 +74,9 @@ public:
void clacEllipsePlotAverage(int, f32, f32); void clacEllipsePlotAverage(int, f32, f32);
bool dpdMove(); bool dpdMove();
u8 openExplain(u8); u8 openExplain(u8);
#if TARGET_PC
bool pointerMove();
#endif
virtual void draw() { _draw(); } virtual void draw() { _draw(); }
virtual ~dMenu_Ring_c(); virtual ~dMenu_Ring_c();
@@ -215,6 +218,7 @@ private:
bool mCursorInterpPrevAngular; bool mCursorInterpPrevAngular;
bool mCursorInterpCurrAngular; bool mCursorInterpCurrAngular;
bool mCursorInterpInit; bool mCursorInterpInit;
bool mPointerTouchPressHoveredCurrent;
#endif #endif
}; };
+2
View File
@@ -266,6 +266,8 @@ public:
#if TARGET_PC #if TARGET_PC
void menuSaveWide(); void menuSaveWide();
bool pointerSaveSelect();
bool pointerYesNoSelect(bool errorSelect, u8 errParam = 0, u8 soundParam = 0);
#endif #endif
void _draw2(); void _draw2();
+4
View File
@@ -49,6 +49,10 @@ public:
u8 getSkillNum(); u8 getSkillNum();
void setHIO(bool); void setHIO(bool);
#if TARGET_PC
bool pointerWait();
#endif
virtual void draw() { _draw(); } virtual void draw() { _draw(); }
virtual ~dMenu_Skill_c(); virtual ~dMenu_Skill_c();
+10
View File
@@ -360,7 +360,12 @@ inline void dMsgObject_demoMessageGroup() {
} }
inline bool dMsgObject_isTalkNowCheck() { inline bool dMsgObject_isTalkNowCheck() {
#if TARGET_PC
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
return msgObject != NULL && msgObject->getStatus() != 1;
#else
return dMsgObject_getMsgObjectClass()->getStatus() == 1 ? false : true; return dMsgObject_getMsgObjectClass()->getStatus() == 1 ? false : true;
#endif
} }
inline bool dMsgObject_isKillMessageFlag() { inline bool dMsgObject_isKillMessageFlag() {
@@ -497,7 +502,12 @@ inline void dMsgObject_onMsgSend() {
} }
inline bool dMsgObject_isFukidashiCheck() { inline bool dMsgObject_isFukidashiCheck() {
#if TARGET_PC
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
return msgObject != NULL && msgObject->getScrnDrawPtr() != NULL;
#else
return dMsgObject_getMsgObjectClass()->getScrnDrawPtr() == NULL ? false : true; return dMsgObject_getMsgObjectClass()->getScrnDrawPtr() == NULL ? false : true;
#endif
} }
inline void* dMsgObject_getTalkHeap() { inline void* dMsgObject_getTalkHeap() {
+4
View File
@@ -49,6 +49,10 @@ public:
void selectScale(); void selectScale();
void selectTrans(); void selectTrans();
void selectAnimeTransform(int); void selectAnimeTransform(int);
#if TARGET_PC
bool pointerMove();
bool consumePointerClick();
#endif
void setOffsetX(f32 i_offsetX) { mOffsetX = i_offsetX; } void setOffsetX(f32 i_offsetX) { mOffsetX = i_offsetX; }
bool isAnimeUpdate(int param_0) { return (field_0x114 & (u8)(1 << param_0)) ? TRUE : FALSE; } bool isAnimeUpdate(int param_0) { return (field_0x114 & (u8)(1 << param_0)) ? TRUE : FALSE; }
+2 -2
View File
@@ -521,13 +521,13 @@ private:
/* 0x019 */ u8 field_0x19; /* 0x019 */ u8 field_0x19;
/* 0x01A */ u8 field_0x1a; /* 0x01A */ u8 field_0x1a;
/* 0x01B */ u8 field_0x1b; /* 0x01B */ u8 field_0x1b;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x01C */ dPa_simpleEcallBack field_0x1c[48]; /* 0x01C */ dPa_simpleEcallBack field_0x1c[48];
#else #else
/* 0x01C */ dPa_simpleEcallBack field_0x1c[25]; /* 0x01C */ dPa_simpleEcallBack field_0x1c[25];
#endif #endif
/* 0x210 */ level_c field_0x210; /* 0x210 */ level_c field_0x210;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
u8 mSceneCount; u8 mSceneCount;
#endif #endif
}; };
+1 -1
View File
@@ -59,7 +59,7 @@ private:
/* 0x18 */ JKRHeap* heap; /* 0x18 */ JKRHeap* heap;
/* 0x1C */ JKRSolidHeap* mDataHeap; /* 0x1C */ JKRSolidHeap* mDataHeap;
/* 0x20 */ void** mRes; /* 0x20 */ void** mRes;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x24 */ int mSize; /* 0x24 */ int mSize;
#endif #endif
}; // Size: 0x24 }; // Size: 0x24
+4 -1
View File
@@ -1008,7 +1008,7 @@ public:
static const int ZONE_MAX = 0x20; static const int ZONE_MAX = 0x20;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x000 */ u8 unk_0x0; /* 0x000 */ u8 unk_0x0;
/* 0x001 */ char unk_0x1; /* 0x001 */ char unk_0x1;
/* 0x000 */ u8 unk_0x2[0x48 - 0x2]; /* 0x000 */ u8 unk_0x2[0x48 - 0x2];
@@ -1029,6 +1029,9 @@ public:
/* 0xF30 */ s64 mSaveTotalTime; /* 0xF30 */ s64 mSaveTotalTime;
#if DEBUG #if DEBUG
/* 0xF80 */ flagFile_c mFlagFile; /* 0xF80 */ flagFile_c mFlagFile;
#elif PARTIAL_DEBUG
// flagFile_c's ctor/virtuals are only defined under #if DEBUG (d_save.cpp)
alignas(flagFile_c) u8 mFlagFile[sizeof(flagFile_c)];
#endif #endif
}; // Size: 0xF38 }; // Size: 0xF38
+4 -4
View File
@@ -538,7 +538,7 @@ public:
/* vt[86] */ virtual stage_tgsc_class* getDrTg(void) const = 0; /* vt[86] */ virtual stage_tgsc_class* getDrTg(void) const = 0;
/* vt[87] */ virtual void setDoor(stage_tgsc_class*) = 0; /* vt[87] */ virtual void setDoor(stage_tgsc_class*) = 0;
/* vt[88] */ virtual stage_tgsc_class* getDoor(void) const = 0; /* vt[88] */ virtual stage_tgsc_class* getDoor(void) const = 0;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
virtual void setUnit(void*) = 0; virtual void setUnit(void*) = 0;
virtual void* getUnit() = 0; virtual void* getUnit() = 0;
#endif #endif
@@ -796,7 +796,7 @@ public:
virtual stage_tgsc_class* getDrTg(void) const { return mDrTg; } virtual stage_tgsc_class* getDrTg(void) const { return mDrTg; }
virtual void setDoor(stage_tgsc_class* i_Door) { mDoor = i_Door; } virtual void setDoor(stage_tgsc_class* i_Door) { mDoor = i_Door; }
virtual stage_tgsc_class* getDoor(void) const { return mDoor; } virtual stage_tgsc_class* getDoor(void) const { return mDoor; }
#if DEBUG #if PARTIAL_DEBUG || DEBUG
virtual void setUnit(void* i_Unit) { mUnit = i_Unit; } virtual void setUnit(void* i_Unit) { mUnit = i_Unit; }
virtual void* getUnit() { return mUnit; } virtual void* getUnit() { return mUnit; }
#endif #endif
@@ -845,7 +845,7 @@ public:
/* 0x54 */ stage_tgsc_class* mDrTg; /* 0x54 */ stage_tgsc_class* mDrTg;
/* 0x58 */ stage_tgsc_class* mDoor; /* 0x58 */ stage_tgsc_class* mDoor;
/* 0x5C */ dStage_FloorInfo_c* mFloorInfo; /* 0x5C */ dStage_FloorInfo_c* mFloorInfo;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x60 */ void* mUnit; /* 0x60 */ void* mUnit;
#endif #endif
/* 0x60 */ u16 mPlayerNum; /* 0x60 */ u16 mPlayerNum;
@@ -990,7 +990,7 @@ public:
/* vt[86] */ virtual stage_tgsc_class* getDrTg(void) const { return mDrTg; } /* vt[86] */ virtual stage_tgsc_class* getDrTg(void) const { return mDrTg; }
/* vt[87] */ virtual void setDoor(stage_tgsc_class* i_Door) { mDoor = i_Door; } /* vt[87] */ virtual void setDoor(stage_tgsc_class* i_Door) { mDoor = i_Door; }
/* vt[88] */ virtual stage_tgsc_class* getDoor(void) const { return mDoor; } /* vt[88] */ virtual stage_tgsc_class* getDoor(void) const { return mDoor; }
#if DEBUG #if PARTIAL_DEBUG || DEBUG
virtual void setUnit(void* i_Unit) { virtual void setUnit(void* i_Unit) {
UNUSED(i_Unit); UNUSED(i_Unit);
OSReport("stage non unit list data !!\n"); OSReport("stage non unit list data !!\n");
+3
View File
@@ -97,6 +97,9 @@ public:
private: private:
#if DEBUG #if DEBUG
/* 0x00 */ dVibTest_c mVibTest; /* 0x00 */ dVibTest_c mVibTest;
#elif PARTIAL_DEBUG
// dVibTest_c's ctor/virtuals are only defined under #if DEBUG (d_vibration.cpp)
alignas(dVibTest_c) u8 mVibTest[sizeof(dVibTest_c)];
#endif #endif
class { class {
+8
View File
@@ -9,6 +9,8 @@ namespace dusk {
enum class ActionBinds { enum class ActionBinds {
FIRST_PERSON_CAMERA, FIRST_PERSON_CAMERA,
CALL_MIDNA, CALL_MIDNA,
OPEN_MAP_SCREEN,
TOGGLE_MINIMAP,
OPEN_DUSKLIGHT_MENU, OPEN_DUSKLIGHT_MENU,
TURBO_SPEED_BUTTON, TURBO_SPEED_BUTTON,
COUNT, COUNT,
@@ -32,6 +34,12 @@ bool isActionBound(ActionBinds action, u32 port);
void updateActionBindings(); void updateActionBindings();
void setVirtualActionBind(ActionBinds action, u32 port, bool pressed, bool available = true);
void clearVirtualActionBind(ActionBinds action, u32 port);
void clearAllVirtualActionBinds();
bool getActionBindTrig(ActionBinds action, u32 port); bool getActionBindTrig(ActionBinds action, u32 port);
bool getActionBindHold(ActionBinds action, u32 port); bool getActionBindHold(ActionBinds action, u32 port);
+70 -7
View File
@@ -1,9 +1,11 @@
#ifndef DUSK_CONFIG_HPP #ifndef DUSK_CONFIG_HPP
#define DUSK_CONFIG_HPP #define DUSK_CONFIG_HPP
#include <concepts>
#include <functional> #include <functional>
#include <nlohmann/json.hpp>
#include <stdexcept> #include <stdexcept>
#include "nlohmann/json.hpp"
#include "config_var.hpp" #include "config_var.hpp"
namespace dusk::config { namespace dusk::config {
@@ -40,7 +42,7 @@ public:
[[nodiscard]] virtual nlohmann::json dumpToJson(const ConfigVarBase& cVar) const = 0; [[nodiscard]] virtual nlohmann::json dumpToJson(const ConfigVarBase& cVar) const = 0;
}; };
template<ConfigValue T> template <ConfigValue T>
class ConfigImpl : public ConfigImplBase { class ConfigImpl : public ConfigImplBase {
// Just downcasting the references... // Just downcasting the references...
void loadFromJson(ConfigVarBase& cVar, const nlohmann::json& jsonValue) const final { void loadFromJson(ConfigVarBase& cVar, const nlohmann::json& jsonValue) const final {
@@ -90,20 +92,28 @@ public:
void Register(ConfigVarBase& configVar); void Register(ConfigVarBase& configVar);
/** /**
* \brief Indicate that all registrations have happened and everything should lock in. * \brief Unregister a CVar, detaching it from the config system.
*
* If the CVar carries a user-set value (Value or Speedrun layer), it is stashed as an
* unregistered key: Save() keeps writing it, and a later Register() of the same name restores
* it through the normal back-fill path. The CVar may be destroyed after this returns.
*/ */
void FinishRegistration(); void unregister(ConfigVarBase& configVar);
/** /**
* \brief Load config from the standard user preferences location. * \brief Load config from the standard user preferences location.
*/ */
void LoadFromUserPreferences(); void load_from_user_preferences();
void LoadFromFileName(const char* path); void load_from_file_name(const char* path);
void load_arg_override(std::string_view name, std::string_view value);
void shutdown();
/** /**
* \brief Save the config to file. * \brief Save the config to file.
*/ */
void Save(); void save();
/** /**
* \brief Get a registered CVar by name. * \brief Get a registered CVar by name.
@@ -124,6 +134,59 @@ void ClearAllActionBindings(int port);
*/ */
void EnumerateRegistered(std::function<void(ConfigVarBase&)> callback); void EnumerateRegistered(std::function<void(ConfigVarBase&)> callback);
/**
* \brief Type-erased change callback. previousValue points at the value before the mutation
* (a `const T*` for a `ConfigVar<T>`) and is valid only for the duration of the call.
*/
using ChangeCallback = std::function<void(ConfigVarBase& cVar, const void* previousValue)>;
/**
* \brief Token identifying a change subscription. 0 is never a valid token.
*/
using Subscription = u64;
/**
* \brief Subscribe to changes of the named CVar (registered or not yet registered).
*
* Fired synchronously on the mutating thread (in practice the game thread) whenever the CVar's
* effective value changes at runtime: setValue, override/speedrun setters and clears. Values
* applied by config load or launch arguments do *not* notify: loads happen during startup
* before the subsystems callbacks push values into are initialized, and each subsystem reads
* its initial value itself at its own init. Callbacks may mutate other CVars; a nested
* mutation of the same CVar applies but does not re-notify.
*/
Subscription subscribe(std::string_view name, ChangeCallback callback);
/**
* \brief Typed convenience overload: the callback receives the current and previous values.
*/
template <ConfigValue T, typename Callback>
requires std::invocable<Callback, const T&, const T&> Subscription subscribe(
ConfigVar<T>& cVar, Callback&& callback) {
return subscribe(cVar.getName(),
[&cVar, cb = std::forward<Callback>(callback)](ConfigVarBase&, const void* previousValue) {
cb(cVar.getValue(), *static_cast<const T*>(previousValue));
});
}
void unsubscribe(Subscription token);
/**
* \brief Register a CVar and attach a change callback in one step.
*
* Useful for pushing settings into external systems (e.g. aurora) from one place instead of
* every UI setter. The callback fires only for runtime changes (see subscribe); the value
* loaded from config or launch arguments does not fire it the external system reads its
* initial value itself at its own initialization.
*/
template <ConfigValue T, typename Callback>
requires std::invocable<Callback, const T&, const T&> Subscription Register(
ConfigVar<T>& cVar, Callback&& onChange) {
auto subscription = subscribe(cVar, std::forward<Callback>(onChange));
Register(static_cast<ConfigVarBase&>(cVar));
return subscription;
}
template <ConfigValue T> template <ConfigValue T>
const ConfigImplBase* GetConfigImpl() { const ConfigImplBase* GetConfigImpl() {
static ConfigImpl<T> config; static ConfigImpl<T> config;
+91 -8
View File
@@ -2,9 +2,12 @@
#define DUSK_CONFIG_VAR_HPP #define DUSK_CONFIG_VAR_HPP
#include "dolphin/types.h" #include "dolphin/types.h"
#include <type_traits> #include <concepts>
#include <cstdlib> #include <cstdlib>
#include <limits>
#include <optional>
#include <string> #include <string>
#include <type_traits>
/** /**
* The configuration system. * The configuration system.
@@ -68,7 +71,7 @@ protected:
/** /**
* The name of this CVar, used in the configuration file. * The name of this CVar, used in the configuration file.
*/ */
const char* name; std::string name;
/** /**
* Whether this CVar has been registered with the global managing logic. * Whether this CVar has been registered with the global managing logic.
@@ -86,8 +89,8 @@ protected:
*/ */
const ConfigImplBase* impl; const ConfigImplBase* impl;
ConfigVarBase(const char* name, const ConfigImplBase* impl); ConfigVarBase(const ConfigVarBase&) = delete;
virtual ~ConfigVarBase() = default; ConfigVarBase(std::string name, const ConfigImplBase* impl);
/** /**
* Check that the CVar is registered, aborting if this is not the case. * Check that the CVar is registered, aborting if this is not the case.
@@ -97,7 +100,22 @@ protected:
abort(); abort();
} }
/**
* Whether any change subscriber (see config::subscribe) is attached to this CVar's name.
*/
[[nodiscard]] bool has_subscribers() const;
/**
* Notify change subscribers (see config::subscribe) that the effective value of this CVar
* changed. Called by mutators after the change has been applied; previousValue points at
* the old value (a `const T*` for a `ConfigVar<T>`), valid only for the duration of the
* call.
*/
void notify_changed(const void* previousValue);
public: public:
virtual ~ConfigVarBase();
/** /**
* Get the name of this CVar, used in the configuration file. * Get the name of this CVar, used in the configuration file.
*/ */
@@ -120,6 +138,7 @@ public:
* This is necessary to make it legal to access. * This is necessary to make it legal to access.
*/ */
void markRegistered(); void markRegistered();
void unmarkRegistered();
/** /**
* Clear a speedrun-mode override if one is active on this CVar. * Clear a speedrun-mode override if one is active on this CVar.
@@ -139,26 +158,36 @@ concept ConfigValueInteger =
|| std::is_same_v<T, s64> || std::is_same_v<T, s64>
|| std::is_same_v<T, u64>; || std::is_same_v<T, u64>;
template <typename T>
struct ConfigValueTraits {
static constexpr bool enabled = false;
};
/** /**
* \brief Concept that defines the legal set of types that can be used for CVar values. * \brief Concept that defines the legal set of types that can be used for CVar values.
* *
* Valid types cannot be cv-qualified and must be basic primitive types (int, float, bool), * Valid types cannot be cv-qualified and must be basic primitive types (int, float, bool),
* strings, or enums of the basic primitives. * strings, enums of the basic primitives, or explicitly-enabled structured settings.
*/ */
template <typename T> template <typename T>
concept ConfigValue = concept ConfigValue =
!std::is_const_v<T> !std::is_const_v<T>
&& !std::is_volatile_v<T> && !std::is_volatile_v<T>
&& std::equality_comparable<T>
&& (std::is_same_v<T, bool> && (std::is_same_v<T, bool>
|| ConfigValueInteger<T> || ConfigValueInteger<T>
|| std::is_same_v<T, f32> || std::is_same_v<T, f32>
|| std::is_same_v<T, f64> || std::is_same_v<T, f64>
|| std::is_same_v<T, std::string> || std::is_same_v<T, std::string>
|| (std::is_enum_v<T> && ConfigValueInteger<std::underlying_type_t<T>>)); || (std::is_enum_v<T> && ConfigValueInteger<std::underlying_type_t<T>>)
|| ConfigValueTraits<T>::enabled);
template <ConfigValue T> template <ConfigValue T>
const ConfigImplBase* GetConfigImpl(); const ConfigImplBase* GetConfigImpl();
template <ConfigValue T>
class ConfigImpl;
template <typename T> template <typename T>
struct ConfigEnumRange { struct ConfigEnumRange {
static constexpr auto min = std::numeric_limits<std::underlying_type_t<T>>::min(); static constexpr auto min = std::numeric_limits<std::underlying_type_t<T>>::min();
@@ -185,10 +214,12 @@ public:
* @param arg Arguments to forward to construct the default value. * @param arg Arguments to forward to construct the default value.
*/ */
template <typename... Args> template <typename... Args>
ConfigVar(const char* name, Args&&... arg) ConfigVar(std::string name, Args&&... arg)
: ConfigVarBase(name, GetConfigImpl<T>()), defaultValue(std::forward<Args>(arg)...), : ConfigVarBase(std::move(name), GetConfigImpl<T>()), defaultValue(std::forward<Args>(arg)...),
value(), overrideValue() {} value(), overrideValue() {}
ConfigVar(ConfigVar const&) = delete;
/** /**
* \brief Get the current value of the CVar. * \brief Get the current value of the CVar.
* *
@@ -227,6 +258,7 @@ public:
*/ */
void setValue(T newValue, bool replaceOverride = true) { void setValue(T newValue, bool replaceOverride = true) {
checkRegistered(); checkRegistered();
const auto previous = previous_for_notify();
value = std::move(newValue); value = std::move(newValue);
if (replaceOverride) { if (replaceOverride) {
@@ -235,6 +267,7 @@ public:
} else if (layer != ConfigVarLayer::Override) { } else if (layer != ConfigVarLayer::Override) {
layer = ConfigVarLayer::Value; layer = ConfigVarLayer::Value;
} }
notify_if_changed(previous);
} }
operator const T&() { operator const T&() {
@@ -251,8 +284,10 @@ public:
*/ */
void setOverrideValue(T newValue) { void setOverrideValue(T newValue) {
checkRegistered(); checkRegistered();
const auto previous = previous_for_notify();
overrideValue = std::move(newValue); overrideValue = std::move(newValue);
layer = ConfigVarLayer::Override; layer = ConfigVarLayer::Override;
notify_if_changed(previous);
} }
/** /**
@@ -266,25 +301,31 @@ public:
void setSpeedrunValue(T newValue) { void setSpeedrunValue(T newValue) {
checkRegistered(); checkRegistered();
if (layer != ConfigVarLayer::Override) { if (layer != ConfigVarLayer::Override) {
const auto previous = previous_for_notify();
priorLayer = layer; priorLayer = layer;
overrideValue = std::move(newValue); overrideValue = std::move(newValue);
layer = ConfigVarLayer::Speedrun; layer = ConfigVarLayer::Speedrun;
notify_if_changed(previous);
} }
} }
void clearOverride() { void clearOverride() {
checkRegistered(); checkRegistered();
if (layer == ConfigVarLayer::Override) { if (layer == ConfigVarLayer::Override) {
const auto previous = previous_for_notify();
overrideValue = {}; overrideValue = {};
layer = ConfigVarLayer::Value; layer = ConfigVarLayer::Value;
notify_if_changed(previous);
} }
} }
void clearSpeedrunOverride() override { void clearSpeedrunOverride() override {
checkRegistered(); checkRegistered();
if (layer == ConfigVarLayer::Speedrun) { if (layer == ConfigVarLayer::Speedrun) {
const auto previous = previous_for_notify();
overrideValue = {}; overrideValue = {};
layer = priorLayer; layer = priorLayer;
notify_if_changed(previous);
} }
} }
@@ -298,6 +339,48 @@ public:
const ConfigVarLayer effectiveLayer = (layer == ConfigVarLayer::Speedrun) ? priorLayer : layer; const ConfigVarLayer effectiveLayer = (layer == ConfigVarLayer::Speedrun) ? priorLayer : layer;
return effectiveLayer == ConfigVarLayer::Default ? defaultValue : value; return effectiveLayer == ConfigVarLayer::Default ? defaultValue : value;
} }
private:
// The config loader applies values through the silent load_* methods below.
friend class ConfigImpl<T>;
/**
* Copy of the effective value before a mutation, taken only when someone is subscribed.
*/
[[nodiscard]] std::optional<T> previous_for_notify() const {
return has_subscribers() ? std::optional<T>{getValue()} : std::nullopt;
}
/**
* Notify subscribers if the effective value actually changed across a mutation.
*/
void notify_if_changed(const std::optional<T>& previous) {
if (previous.has_value() && !(getValue() == *previous)) {
notify_changed(&*previous);
}
}
/**
* setValue(newValue, false) without notifying change subscribers. Used when loading config:
* loads happen during startup before the subsystems change callbacks push values into are
* initialized, and each subsystem applies the loaded value itself at its own init.
*/
void load_value(T newValue) {
checkRegistered();
value = std::move(newValue);
if (layer != ConfigVarLayer::Override) {
layer = ConfigVarLayer::Value;
}
}
/**
* setOverrideValue without notifying change subscribers (see load_value).
*/
void load_override_value(T newValue) {
checkRegistered();
overrideValue = std::move(newValue);
layer = ConfigVarLayer::Override;
}
}; };
using ActionBindConfigVar = ConfigVar<int>; using ActionBindConfigVar = ConfigVar<int>;
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include "dolphin/types.h"
class CPaneMgr;
namespace dusk::menu_pointer {
using TargetId = u16;
constexpr TargetId InvalidTarget = 0xffff;
enum class Context {
None,
FileSelect,
Save,
ItemWheel,
Collection,
Options,
Dialog,
};
enum class Phase {
Move,
Press,
Release,
Cancel,
};
struct State {
f32 x = 0.0f;
f32 y = 0.0f;
bool valid = false;
bool down = false;
bool pressed = false;
bool released = false;
bool clicked = false;
bool touch = false;
};
void begin_game_frame() noexcept;
void end_game_frame() noexcept;
void begin_context(Context context) noexcept;
bool handle_fallthrough_pointer(f32 x, f32 y, Phase phase, bool touch, s32 mouseButton = -1) noexcept;
bool active() noexcept;
bool enabled() noexcept;
bool mouse_capture_active() noexcept;
const State& state() noexcept;
void set_hover_target(TargetId target) noexcept;
bool consume_click() noexcept;
bool peek_click() noexcept;
void set_dialog_choice(u8 choice, bool clicked) noexcept;
bool get_dialog_choice(u8& choice) noexcept;
bool consume_dialog_click(u8& choice) noexcept;
void defer_activation(Context context, TargetId target) noexcept;
bool consume_deferred_activation(Context context, TargetId target) noexcept;
void clear_deferred_activation(Context context) noexcept;
u32 suppressed_pad_buttons(u32 port) noexcept;
void finish_pad_suppression_read(u32 port) noexcept;
bool hit_rect(f32 left, f32 top, f32 right, f32 bottom, f32 padding = 0.0f) noexcept;
bool hit_pane(CPaneMgr* pane, f32 padding = 0.0f) noexcept;
bool hit_pane(J2DPane* pane, f32 padding = 0.0f) noexcept;
} // namespace dusk::menu_pointer
+4 -4
View File
@@ -4,9 +4,9 @@
namespace dusk::mouse { namespace dusk::mouse {
void read(); void read();
void getAimDeltas(float& out_yaw, float& out_pitch); void get_aim_deltas(float& out_yaw, float& out_pitch);
void getCameraDeltas(float& out_yaw, float& out_pitch); void get_camera_deltas(float& out_yaw, float& out_pitch);
void handle_event(const SDL_Event& event) noexcept; void handle_event(const SDL_Event& event) noexcept;
void onFocusLost(); void on_focus_lost();
void onFocusGained(); void on_focus_gained();
} // namespace dusk::mouse } // namespace dusk::mouse
+33 -18
View File
@@ -1,13 +1,14 @@
#ifndef DUSK_CONFIG_H #pragma once
#define DUSK_CONFIG_H
#include <array> #include <array>
#include "dusk/config_var.hpp" #include "dusk/config_var.hpp"
#include "dusk/ui/controls.hpp"
namespace dusk { namespace dusk {
using namespace config; using config::ConfigVar;
using config::ActionBindConfigVar;
enum class BloomMode : int { enum class BloomMode : int {
Off = 0, Off = 0,
@@ -40,17 +41,18 @@ enum class DiscVerificationState : u8 {
HashMismatch, HashMismatch,
}; };
enum class GyroMode : u8 {
Sensor = 0,
Mouse = 1,
};
enum class FrameInterpMode : u8 { enum class FrameInterpMode : u8 {
Off = 0, Off = 0,
Capped = 1, Capped = 1,
Unlimited = 2, Unlimited = 2,
}; };
enum class TouchTargeting : u8 {
Hybrid = 0,
Hold = 1,
Switch = 2,
};
enum class MenuScaling : u8 { enum class MenuScaling : u8 {
GameCube = 0, GameCube = 0,
Wii = 1, Wii = 1,
@@ -96,18 +98,18 @@ struct ConfigEnumRange<DiscVerificationState> {
static constexpr auto max = DiscVerificationState::HashMismatch; static constexpr auto max = DiscVerificationState::HashMismatch;
}; };
template <>
struct ConfigEnumRange<GyroMode> {
static constexpr auto min = GyroMode::Sensor;
static constexpr auto max = GyroMode::Mouse;
};
template <> template <>
struct ConfigEnumRange<FrameInterpMode> { struct ConfigEnumRange<FrameInterpMode> {
static constexpr auto min = FrameInterpMode::Off; static constexpr auto min = FrameInterpMode::Off;
static constexpr auto max = FrameInterpMode::Unlimited; static constexpr auto max = FrameInterpMode::Unlimited;
}; };
template <>
struct ConfigEnumRange<TouchTargeting> {
static constexpr auto min = TouchTargeting::Hybrid;
static constexpr auto max = TouchTargeting::Switch;
};
template <> template <>
struct ConfigEnumRange<MenuScaling> { struct ConfigEnumRange<MenuScaling> {
static constexpr auto min = MenuScaling::GameCube; static constexpr auto min = MenuScaling::GameCube;
@@ -119,6 +121,11 @@ struct ConfigEnumRange<MagicArmorMode> {
static constexpr auto min = MagicArmorMode::NORMAL; static constexpr auto min = MagicArmorMode::NORMAL;
static constexpr auto max = MagicArmorMode::COSMETIC; static constexpr auto max = MagicArmorMode::COSMETIC;
}; };
template <>
struct ConfigValueTraits<ui::ControlLayout> {
static constexpr bool enabled = true;
};
} // namespace config } // namespace config
// Persistent user settings // Persistent user settings
@@ -134,6 +141,9 @@ struct UserSettings {
ConfigVar<bool> enableFpsOverlay; ConfigVar<bool> enableFpsOverlay;
ConfigVar<int> fpsOverlayCorner; ConfigVar<int> fpsOverlayCorner;
ConfigVar<int> maxFrameRate; ConfigVar<int> maxFrameRate;
ConfigVar<bool> rememberWindowSize;
ConfigVar<int> lastWindowWidth;
ConfigVar<int> lastWindowHeight;
} video; } video;
struct { struct {
@@ -218,6 +228,10 @@ struct UserSettings {
ConfigVar<float> mouseCameraSensitivity; ConfigVar<float> mouseCameraSensitivity;
ConfigVar<bool> invertMouseY; ConfigVar<bool> invertMouseY;
ConfigVar<bool> freeCamera; ConfigVar<bool> freeCamera;
ConfigVar<bool> enableTouchControls;
ConfigVar<TouchTargeting> touchTargeting;
ConfigVar<bool> enableMenuPointer;
ConfigVar<ui::ControlLayout> touchControlsLayout;
ConfigVar<bool> invertCameraXAxis; ConfigVar<bool> invertCameraXAxis;
ConfigVar<bool> invertCameraYAxis; ConfigVar<bool> invertCameraYAxis;
ConfigVar<bool> invertFirstPersonXAxis; ConfigVar<bool> invertFirstPersonXAxis;
@@ -226,6 +240,8 @@ struct UserSettings {
ConfigVar<bool> invertAirSwimY; ConfigVar<bool> invertAirSwimY;
ConfigVar<float> freeCameraXSensitivity; ConfigVar<float> freeCameraXSensitivity;
ConfigVar<float> freeCameraYSensitivity; ConfigVar<float> freeCameraYSensitivity;
ConfigVar<float> touchCameraXSensitivity;
ConfigVar<float> touchCameraYSensitivity;
ConfigVar<bool> debugFlyCam; ConfigVar<bool> debugFlyCam;
ConfigVar<bool> debugFlyCamLockEvents; ConfigVar<bool> debugFlyCamLockEvents;
ConfigVar<bool> allowBackgroundInput; ConfigVar<bool> allowBackgroundInput;
@@ -273,7 +289,6 @@ struct UserSettings {
ConfigVar<DiscVerificationState> isoVerification; ConfigVar<DiscVerificationState> isoVerification;
ConfigVar<std::string> graphicsBackend; ConfigVar<std::string> graphicsBackend;
ConfigVar<bool> skipPreLaunchUI; ConfigVar<bool> skipPreLaunchUI;
ConfigVar<bool> showPipelineCompilation;
ConfigVar<bool> wasPresetChosen; ConfigVar<bool> wasPresetChosen;
ConfigVar<bool> checkForUpdates; ConfigVar<bool> checkForUpdates;
ConfigVar<int> cardFileType; ConfigVar<int> cardFileType;
@@ -284,6 +299,8 @@ struct UserSettings {
struct { struct {
std::array<ActionBindConfigVar, 4> firstPersonCamera; std::array<ActionBindConfigVar, 4> firstPersonCamera;
std::array<ActionBindConfigVar, 4> callMidna; std::array<ActionBindConfigVar, 4> callMidna;
std::array<ActionBindConfigVar, 4> openMapScreen;
std::array<ActionBindConfigVar, 4> toggleMinimap;
std::array<ActionBindConfigVar, 4> openDusklightMenu; std::array<ActionBindConfigVar, 4> openDusklightMenu;
std::array<ActionBindConfigVar, 4> turboSpeedButton; std::array<ActionBindConfigVar, 4> turboSpeedButton;
} actionBindings; } actionBindings;
@@ -315,6 +332,4 @@ struct TransientSettings {
TransientSettings& getTransientSettings(); TransientSettings& getTransientSettings();
} } // namespace dusk
#endif // DUSK_CONFIG_H
+12
View File
@@ -0,0 +1,12 @@
#pragma once
namespace dusk::touch_camera {
constexpr float YAW_DEGREES_PER_DP = 0.34f;
constexpr float PITCH_DEGREES_PER_DP = 0.22f;
void add_delta(float yaw_dp, float pitch_dp) noexcept;
bool consume_delta(float& yaw_dp, float& pitch_dp) noexcept;
void clear() noexcept;
} // namespace dusk::touch_camera
+1 -1
View File
@@ -36,7 +36,7 @@ typedef struct node_create_request {
/* 0x58 */ s16 name; /* 0x58 */ s16 name;
/* 0x5C */ void* data; /* 0x5C */ void* data;
/* 0x60 */ s16 unk_0x60; /* 0x60 */ s16 unk_0x60;
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x64 */ int unk_0x64; /* 0x64 */ int unk_0x64;
/* 0x68 */ int unk_0x68; /* 0x68 */ int unk_0x68;
#endif #endif
+2 -2
View File
@@ -11,13 +11,13 @@ class mDoAud_zelAudio_c : public Z2AudioMgr {
public: public:
void reset(); void reset();
mDoAud_zelAudio_c() { mDoAud_zelAudio_c() {
#if DEBUG #if PARTIAL_DEBUG || DEBUG
setMode(2); setMode(2);
#endif #endif
} }
~mDoAud_zelAudio_c() {} ~mDoAud_zelAudio_c() {}
#if DEBUG #if PARTIAL_DEBUG || DEBUG
u8 getMode() { return field_0x13bd; } u8 getMode() { return field_0x13bd; }
void setMode(u8 mode) { field_0x13bd = mode; } void setMode(u8 mode) { field_0x13bd = mode; }
+5
View File
@@ -35,6 +35,11 @@ public:
/* 0x4 */ s8 mNo; /* 0x4 */ s8 mNo;
/* 0x5 */ u8 mCount; /* 0x5 */ u8 mCount;
#else #else
#if PARTIAL_DEBUG
// Initialized here since the DEBUG ctor doesn't run.
/* 0x4 */ s8 mNo = -1;
/* 0x5 */ u8 mCount = 0;
#endif
virtual ~mDoHIO_entry_c() {} virtual ~mDoHIO_entry_c() {}
#endif #endif
}; };
@@ -212,6 +212,9 @@ public:
void setCornerColor(JUtility::TColor c0) { void setCornerColor(JUtility::TColor c0) {
setCornerColor(c0, c0, c0, c0); setCornerColor(c0, c0, c0, c0);
} }
#if TARGET_PC
JUtility::TColor corner(size_t index) const { return mCornerColor[index]; }
#endif
protected: protected:
/* 0x100 */ JUTTexture* mTexture[2]; /* 0x100 */ JUTTexture* mTexture[2];
@@ -12,12 +12,23 @@ struct JORNodeEvent;
class JORMContext; class JORMContext;
class JORServer; class JORServer;
// NOTE (stable game ABI): these classes stay non-polymorphic outside DEBUG
// on purpose. Making them polymorphic under PARTIAL_DEBUG would give every one of the ~250
// derived HIO classes a vptr and turn their plain `void genMessage(JORMContext*);`
// declarations into implicit virtual overrides whose definitions are #if DEBUG-gated; every
// instantiated one then fails to link (missing vtable). Closure types shared with DEBUG TUs
// either declare their own unconditional virtuals (vptr in all TUs anyway) or add a
// PARTIAL_DEBUG-only virtual dtor for vptr parity (see dAttParam_c).
class JOREventListener { class JOREventListener {
public: public:
#if DEBUG #if DEBUG
JOREventListener() {} JOREventListener() {}
#if TARGET_PC
virtual void listenPropertyEvent(const JORPropertyEvent*) {}
#else
virtual void listenPropertyEvent(const JORPropertyEvent*) = 0; virtual void listenPropertyEvent(const JORPropertyEvent*) = 0;
#endif #endif
#endif
}; };
class JORReflexible : public JOREventListener { class JORReflexible : public JOREventListener {
@@ -30,7 +41,11 @@ public:
virtual void listenPropertyEvent(const JORPropertyEvent*); virtual void listenPropertyEvent(const JORPropertyEvent*);
virtual void listen(u32, const JOREvent*); virtual void listen(u32, const JOREvent*);
virtual void genObjectInfo(const JORGenEvent*); virtual void genObjectInfo(const JORGenEvent*);
#if TARGET_PC
virtual void genMessage(JORMContext*) {}
#else
virtual void genMessage(JORMContext*) = 0; virtual void genMessage(JORMContext*) = 0;
#endif
virtual void listenNodeEvent(const JORNodeEvent*); virtual void listenNodeEvent(const JORNodeEvent*);
#endif #endif
}; };
@@ -3,6 +3,20 @@
#include <gx.h> #include <gx.h>
#if TARGET_PC
#include <mtx.h>
struct ParticleDrawCtx {
bool batch; // off = immediate mode
bool useTexMtx; // UVs transformed by texMtx
bool useClr0; // prm color in GX_VA_CLR0
bool useClr1; // env color in GX_VA_CLR1
Mtx texMtx;
GXColor clr0;
GXColor clr1;
};
#endif
struct JPAEmitterWorkData; struct JPAEmitterWorkData;
class JPABaseParticle; class JPABaseParticle;
class JKRHeap; class JKRHeap;
@@ -75,6 +89,9 @@ public:
const GXTevColorArg* getTevColorArg() const { return st_ca[(pBsd->mFlags >> 0x0F) & 0x07]; } const GXTevColorArg* getTevColorArg() const { return st_ca[(pBsd->mFlags >> 0x0F) & 0x07]; }
const GXTevAlphaArg* getTevAlphaArg() const { return st_aa[(pBsd->mFlags >> 0x12) & 0x01]; } const GXTevAlphaArg* getTevAlphaArg() const { return st_aa[(pBsd->mFlags >> 0x12) & 0x01]; }
#if TARGET_PC
u32 getTevColorArgSel() const { return (pBsd->mFlags >> 0x0F) & 0x07; }
#endif
u32 getType() const { return (pBsd->mFlags >> 0) & 0x0F; } u32 getType() const { return (pBsd->mFlags >> 0) & 0x0F; }
u32 getDirType() const { return (pBsd->mFlags >> 4) & 0x07; } u32 getDirType() const { return (pBsd->mFlags >> 4) & 0x07; }
@@ -186,26 +203,34 @@ void JPARegistPrm(JPAEmitterWorkData*);
void JPARegistEnv(JPAEmitterWorkData*); void JPARegistEnv(JPAEmitterWorkData*);
void JPARegistPrmEnv(JPAEmitterWorkData*); void JPARegistPrmEnv(JPAEmitterWorkData*);
void JPADrawPoint(JPAEmitterWorkData*, JPABaseParticle*); #if TARGET_PC
void JPADrawLine(JPAEmitterWorkData*, JPABaseParticle*); #define JPA_DRAW_PARTICLE_ARGS JPAEmitterWorkData*, JPABaseParticle*, ParticleDrawCtx*
void JPADrawRotBillboard(JPAEmitterWorkData*, JPABaseParticle*); #else
void JPADrawBillboard(JPAEmitterWorkData*, JPABaseParticle*); #define JPA_DRAW_PARTICLE_ARGS JPAEmitterWorkData*, JPABaseParticle*
void JPADrawRotDirection(JPAEmitterWorkData*, JPABaseParticle*); #endif
void JPADrawDirection(JPAEmitterWorkData*, JPABaseParticle*);
void JPADrawRotation(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawPoint(JPA_DRAW_PARTICLE_ARGS);
void JPADrawDBillboard(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawLine(JPA_DRAW_PARTICLE_ARGS);
void JPADrawRotYBillboard(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawRotBillboard(JPA_DRAW_PARTICLE_ARGS);
void JPADrawYBillboard(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawBillboard(JPA_DRAW_PARTICLE_ARGS);
void JPADrawParticleCallBack(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawRotDirection(JPA_DRAW_PARTICLE_ARGS);
void JPALoadTexAnm(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawDirection(JPA_DRAW_PARTICLE_ARGS);
void JPASetPointSize(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawRotation(JPA_DRAW_PARTICLE_ARGS);
void JPASetLineWidth(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawDBillboard(JPA_DRAW_PARTICLE_ARGS);
void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawRotYBillboard(JPA_DRAW_PARTICLE_ARGS);
void JPARegistAlpha(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawYBillboard(JPA_DRAW_PARTICLE_ARGS);
void JPARegistEnv(JPAEmitterWorkData*, JPABaseParticle*); void JPADrawParticleCallBack(JPA_DRAW_PARTICLE_ARGS);
void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*); void JPALoadTexAnm(JPA_DRAW_PARTICLE_ARGS);
void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*); void JPASetPointSize(JPA_DRAW_PARTICLE_ARGS);
void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*); void JPASetLineWidth(JPA_DRAW_PARTICLE_ARGS);
void JPALoadCalcTexCrdMtxAnm(JPA_DRAW_PARTICLE_ARGS);
void JPARegistAlpha(JPA_DRAW_PARTICLE_ARGS);
void JPARegistEnv(JPA_DRAW_PARTICLE_ARGS);
void JPARegistAlphaEnv(JPA_DRAW_PARTICLE_ARGS);
void JPARegistPrmAlpha(JPA_DRAW_PARTICLE_ARGS);
void JPARegistPrmAlphaEnv(JPA_DRAW_PARTICLE_ARGS);
#undef JPA_DRAW_PARTICLE_ARGS
#if TARGET_PC #if TARGET_PC
void JPAInterpBillboard(JPAEmitterWorkData*, JPABaseParticle*); void JPAInterpBillboard(JPAEmitterWorkData*, JPABaseParticle*);
@@ -17,6 +17,10 @@ class JPADynamicsBlock;
class JPAFieldBlock; class JPAFieldBlock;
class JPAKeyBlock; class JPAKeyBlock;
#if TARGET_PC
struct ParticleDrawCtx;
#endif
/** /**
* @ingroup jsystem-jparticle * @ingroup jsystem-jparticle
* *
@@ -50,13 +54,19 @@ public:
public: public:
typedef void (*EmitterFunc)(JPAEmitterWorkData*); typedef void (*EmitterFunc)(JPAEmitterWorkData*);
typedef void (*ParticleFunc)(JPAEmitterWorkData*, JPABaseParticle*); typedef void (*ParticleFunc)(JPAEmitterWorkData*, JPABaseParticle*);
#if TARGET_PC
typedef void (*DrawParticleFunc)(JPAEmitterWorkData*, JPABaseParticle*,
ParticleDrawCtx*);
#else
typedef ParticleFunc DrawParticleFunc;
#endif
/* 0x00 */ EmitterFunc* mpCalcEmitterFuncList; /* 0x00 */ EmitterFunc* mpCalcEmitterFuncList;
/* 0x04 */ EmitterFunc* mpDrawEmitterFuncList; /* 0x04 */ EmitterFunc* mpDrawEmitterFuncList;
/* 0x08 */ EmitterFunc* mpDrawEmitterChildFuncList; /* 0x08 */ EmitterFunc* mpDrawEmitterChildFuncList;
/* 0x0C */ ParticleFunc* mpCalcParticleFuncList; /* 0x0C */ ParticleFunc* mpCalcParticleFuncList;
/* 0x10 */ ParticleFunc* mpDrawParticleFuncList; /* 0x10 */ DrawParticleFunc* mpDrawParticleFuncList;
/* 0x14 */ ParticleFunc* mpCalcParticleChildFuncList; /* 0x14 */ ParticleFunc* mpCalcParticleChildFuncList;
/* 0x18 */ ParticleFunc* mpDrawParticleChildFuncList; /* 0x18 */ DrawParticleFunc* mpDrawParticleChildFuncList;
/* 0x1C */ JPABaseShape* pBsp; /* 0x1C */ JPABaseShape* pBsp;
/* 0x20 */ JPAExtraShape* pEsp; /* 0x20 */ JPAExtraShape* pEsp;
@@ -77,6 +87,20 @@ public:
/* 0x45 */ u8 mpDrawParticleFuncListNum; /* 0x45 */ u8 mpDrawParticleFuncListNum;
/* 0x46 */ u8 mpCalcParticleChildFuncListNum; /* 0x46 */ u8 mpCalcParticleChildFuncListNum;
/* 0x47 */ u8 mpDrawParticleChildFuncListNum; /* 0x47 */ u8 mpDrawParticleChildFuncListNum;
#if TARGET_PC
struct BatchInfo {
f32 vtxPos[8][3];
f32 vtxUv[8][2];
u8 vtxCount; // 4 (quad) or 8 (cross)
bool supported; // draw func list contains only batchable funcs
bool hasPtclColor; // per-particle JPARegist* func is present
bool hasPtclTexMtx; // JPALoadCalcTexCrdMtxAnm is present
};
BatchInfo mBatchInfo;
void initBatchInfo();
#endif
}; };
#endif /* JPARESOURCE_H */ #endif /* JPARESOURCE_H */
@@ -314,7 +314,7 @@ public:
> >
{ {
TIterator_data_(const TFunctionValue_list_parameter& rParent, const f32* value) { TIterator_data_(const TFunctionValue_list_parameter& rParent, const f32* value) {
#if DEBUG #if PARTIAL_DEBUG || DEBUG
pOwn_ = &rParent; pOwn_ = &rParent;
#endif #endif
pf_ = value; pf_ = value;
@@ -372,7 +372,7 @@ public:
return (r1.pf_ - r2.pf_) / suData_size; return (r1.pf_ - r2.pf_) / suData_size;
} }
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x00 */ const TFunctionValue_list_parameter* pOwn_; /* 0x00 */ const TFunctionValue_list_parameter* pOwn_;
#endif #endif
/* 0x00 */ const f32* pf_; /* 0x00 */ const f32* pf_;
@@ -425,7 +425,7 @@ public:
> >
{ {
TIterator_data_(const TFunctionValue_hermite& rParent, const f32* value) { TIterator_data_(const TFunctionValue_hermite& rParent, const f32* value) {
#if DEBUG #if PARTIAL_DEBUG || DEBUG
pOwn_ = &rParent; pOwn_ = &rParent;
#endif #endif
pf_ = value; pf_ = value;
@@ -491,7 +491,7 @@ public:
return (r1.pf_ - r2.pf_) / r1.uSize_; return (r1.pf_ - r2.pf_) / r1.uSize_;
} }
#if DEBUG #if PARTIAL_DEBUG || DEBUG
/* 0x00 */ const TFunctionValue_hermite* pOwn_; /* 0x00 */ const TFunctionValue_hermite* pOwn_;
/* 0x04 */ const f32* pf_; /* 0x04 */ const f32* pf_;
/* 0x08 */ u32 uSize_; /* 0x08 */ u32 uSize_;
@@ -542,8 +542,11 @@ void J3DModel::viewCalc() {
} }
#ifdef TARGET_PC #ifdef TARGET_PC
for (u16 i = 0; i < mModelData->getDrawMtxNum(); ++i) { Mtx* drawMtx = getDrawMtxPtr();
dusk::frame_interp::record_final_mtx(getDrawMtxPtr()[i]); if (drawMtx != J3DMtxBuffer::sNoUseDrawMtxPtr) {
for (u16 i = 0; i < mModelData->getDrawMtxNum(); ++i) {
dusk::frame_interp::record_final_mtx(drawMtx[i]);
}
} }
#endif #endif
+2 -2
View File
@@ -136,8 +136,8 @@ void J3DLoadCPCmd(u8 addr, u32 val) {
#if TARGET_PC #if TARGET_PC
static void J3DLoadArrayBasePtr(GXAttr attr, void* data, u32 size, bool le) { static void J3DLoadArrayBasePtr(GXAttr attr, void* data, u32 size, bool le) {
u32 idx = (attr == GX_VA_NBT) ? 1 : (attr - GX_VA_POS); u32 idx = (attr == GX_VA_NBT) ? 1 : (attr - GX_VA_POS);
GXCmd1u8(GX_LOAD_AURORA); GXCmd1u8(GX_AURORA);
GXCmd1u16(GX_LOAD_AURORA_ARRAYBASE | idx); GXCmd1u16(GX_AURORA_LOAD_ARRAYBASE | idx);
GXCmd1u64((u64)data); GXCmd1u64((u64)data);
GXCmd1u32(size); GXCmd1u32(size);
GXCmd1u8(le ? 1 : 0); GXCmd1u8(le ? 1 : 0);
+55 -293
View File
@@ -7,265 +7,11 @@
#include "JSystem/JKernel/JKRHeap.h" #include "JSystem/JKernel/JKRHeap.h"
#if TARGET_PC #if TARGET_PC
#include <algorithm> #include <aurora/dl.hpp>
#include <tracy/Tracy.hpp> #include <tracy/Tracy.hpp>
#include <vector>
#include "dusk/logging.h"
namespace { namespace {
u16 read_be16(const u8* data) {
return (u16(data[0]) << 8) | data[1];
}
void append_be16(std::vector<u8>& out, u16 value) {
out.push_back(value >> 8);
out.push_back(value & 0xFF);
}
void append_bytes(std::vector<u8>& out, const u8* data, u32 size) {
out.insert(out.end(), data, data + size);
}
bool is_matrix_idx_attr(GXAttr attr) {
return attr >= GX_VA_PNMTXIDX && attr <= GX_VA_TEX7MTXIDX;
}
bool is_draw_opcode(u8 opcode) {
return opcode == GX_QUADS || opcode == GX_TRIANGLES || opcode == GX_TRIANGLESTRIP ||
opcode == GX_TRIANGLEFAN || opcode == GX_LINES || opcode == GX_LINESTRIP ||
opcode == GX_POINTS;
}
bool is_mergeable_draw_opcode(u8 opcode) {
return opcode == GX_QUADS || opcode == GX_TRIANGLES || opcode == GX_TRIANGLESTRIP ||
opcode == GX_TRIANGLEFAN;
}
bool calc_vtx_stride(const GXVtxDescList* vtxDesc, u32& stride) {
stride = 0;
for (; vtxDesc->attr != GX_VA_NULL; vtxDesc++) {
switch (vtxDesc->type) {
case GX_NONE:
break;
case GX_DIRECT:
if (!is_matrix_idx_attr(vtxDesc->attr)) {
return false;
}
stride += 1;
break;
case GX_INDEX8:
stride += 1;
break;
case GX_INDEX16:
stride += 2;
break;
default:
return false;
}
}
return stride != 0;
}
bool get_command_size(const u8* dlStart, u32 dlSize, u32 offset, u32 stride, u32& cmdSize) {
if (offset >= dlSize) {
return false;
}
const u8 cmd = dlStart[offset];
const u8 opcode = cmd & GX_OPCODE_MASK;
switch (opcode) {
case GX_NOP:
case GX_CMD_INVL_VC:
cmdSize = 1;
return true;
case (GX_LOAD_BP_REG & GX_OPCODE_MASK):
cmdSize = 5;
return offset + cmdSize <= dlSize;
case GX_LOAD_CP_REG:
cmdSize = 6;
return offset + cmdSize <= dlSize;
case GX_LOAD_XF_REG: {
if (offset + 5 > dlSize) {
return false;
}
const u16 count = read_be16(dlStart + offset + 1) + 1;
cmdSize = 5 + count * 4;
return offset + cmdSize <= dlSize;
}
case GX_LOAD_INDX_A:
case GX_LOAD_INDX_B:
case GX_LOAD_INDX_C:
case GX_LOAD_INDX_D:
cmdSize = 5;
return offset + cmdSize <= dlSize;
case GX_CMD_CALL_DL:
cmdSize = 9;
return offset + cmdSize <= dlSize;
default:
if (is_draw_opcode(opcode)) {
if (offset + 3 > dlSize) {
return false;
}
const u16 vtxCount = read_be16(dlStart + offset + 1);
cmdSize = 3 + vtxCount * stride;
return offset + cmdSize <= dlSize;
}
return false;
}
}
struct MergeRun {
u8 cmd = 0;
u16 vtxCount = 0;
std::vector<u8> vertices;
};
void flush_merge_run(std::vector<u8>& out, MergeRun& run) {
if (run.vtxCount == 0) {
return;
}
out.push_back(run.cmd);
append_be16(out, run.vtxCount);
append_bytes(out, run.vertices.data(), run.vertices.size());
run.vertices.clear();
run.vtxCount = 0;
}
void append_vertex(std::vector<u8>& out, const u8* vertices, u32 stride, u16 idx) {
append_bytes(out, vertices + idx * stride, stride);
}
bool triangulate_draw(
std::vector<u8>& out, u8 opcode, const u8* vertices, u32 stride, u16 vtxCount) {
switch (opcode) {
case GX_TRIANGLES:
append_bytes(out, vertices, vtxCount * stride);
return true;
case GX_TRIANGLEFAN:
if (vtxCount < 3) {
return false;
}
for (u16 v = 2; v < vtxCount; v++) {
append_vertex(out, vertices, stride, 0);
append_vertex(out, vertices, stride, v - 1);
append_vertex(out, vertices, stride, v);
}
return true;
case GX_TRIANGLESTRIP:
if (vtxCount < 3) {
return false;
}
for (u16 v = 2; v < vtxCount; v++) {
if ((v & 1) == 0) {
append_vertex(out, vertices, stride, v - 2);
append_vertex(out, vertices, stride, v - 1);
} else {
append_vertex(out, vertices, stride, v - 1);
append_vertex(out, vertices, stride, v - 2);
}
append_vertex(out, vertices, stride, v);
}
return true;
case GX_QUADS:
if ((vtxCount & 3) != 0) {
return false;
}
for (u16 v = 0; v < vtxCount; v += 4) {
append_vertex(out, vertices, stride, v);
append_vertex(out, vertices, stride, v + 1);
append_vertex(out, vertices, stride, v + 2);
append_vertex(out, vertices, stride, v + 2);
append_vertex(out, vertices, stride, v + 3);
append_vertex(out, vertices, stride, v);
}
return true;
default:
return false;
}
}
void append_triangles_to_run(
std::vector<u8>& out, MergeRun& run, u8 cmd, const std::vector<u8>& vertices, u32 stride) {
u32 offset = 0;
u32 remaining = vertices.size() / stride;
while (remaining != 0) {
if (run.vtxCount != 0 && run.cmd != cmd) {
flush_merge_run(out, run);
}
if (run.vtxCount == 0) {
run.cmd = cmd;
}
u32 available = 0xFFFF - run.vtxCount;
if (available == 0) {
flush_merge_run(out, run);
continue;
}
u32 toCopy = std::min(remaining, available);
append_bytes(run.vertices, vertices.data() + offset * stride, toCopy * stride);
run.vtxCount += toCopy;
offset += toCopy;
remaining -= toCopy;
if (run.vtxCount == 0xFFFF) {
flush_merge_run(out, run);
}
}
}
bool optimize_display_list(const u8* dlStart, u32 dlSize, u32 stride, std::vector<u8>& out) {
MergeRun run;
out.reserve(dlSize);
for (u32 offset = 0; offset < dlSize;) {
u32 cmdSize = 0;
if (!get_command_size(dlStart, dlSize, offset, stride, cmdSize)) {
return false;
}
const u8 cmd = dlStart[offset];
const u8 opcode = cmd & GX_OPCODE_MASK;
if (opcode == GX_NOP) {
offset += cmdSize;
continue;
}
if (!is_draw_opcode(opcode)) {
flush_merge_run(out, run);
append_bytes(out, dlStart + offset, cmdSize);
offset += cmdSize;
continue;
}
if (!is_mergeable_draw_opcode(opcode)) {
flush_merge_run(out, run);
append_bytes(out, dlStart + offset, cmdSize);
offset += cmdSize;
continue;
}
const u16 vtxCount = read_be16(dlStart + offset + 1);
const u8* vertices = dlStart + offset + 3;
std::vector<u8> triangles;
if (!triangulate_draw(triangles, opcode, vertices, stride, vtxCount)) {
flush_merge_run(out, run);
append_bytes(out, dlStart + offset, cmdSize);
offset += cmdSize;
continue;
}
append_triangles_to_run(out, run, (GX_TRIANGLES | (cmd & GX_VAT_MASK)), triangles, stride);
offset += cmdSize;
}
flush_merge_run(out, run);
return true;
}
void set_display_list_copy(void*& displayList, u32& displayListSize, const u8* data, u32 size) { void set_display_list_copy(void*& displayList, u32& displayListSize, const u8* data, u32 size) {
const u32 alignedSize = ALIGN_NEXT(size, 0x20); const u32 alignedSize = ALIGN_NEXT(size, 0x20);
u8* newDL = JKR_NEW_ARRAY_ARGS(u8, alignedSize, 0x20); u8* newDL = JKR_NEW_ARRAY_ARGS(u8, alignedSize, 0x20);
@@ -289,20 +35,11 @@ u32 J3DShapeDraw::countVertex(u32 stride) {
u8* dlStart = (u8*)getDisplayList(); u8* dlStart = (u8*)getDisplayList();
#if TARGET_PC #if TARGET_PC
for (u32 offset = 0; offset < getDisplayListSize();) { aurora::gx::dl::Reader reader{dlStart, getDisplayListSize(), static_cast<u8>(stride)};
u8 cmd = dlStart[offset]; while (const auto cmd = reader.next()) {
u8 opcode = cmd & GX_OPCODE_MASK; if (cmd->kind != aurora::gx::dl::Command::Kind::Passthrough) {
u32 cmdSize = 0; count += cmd->draw.vtxCount;
if (!get_command_size(dlStart, getDisplayListSize(), offset, stride, cmdSize)) {
break;
} }
if (!is_draw_opcode(opcode)) {
offset += cmdSize;
continue;
}
int vtxNum = be16(*reinterpret_cast<u16*>(dlStart + offset + 1));
count += vtxNum;
offset += 3 + stride * vtxNum;
} }
#else #else
for (u8* dl = dlStart; (dl - dlStart) < getDisplayListSize();) { for (u8* dl = dlStart; (dl - dlStart) < getDisplayListSize();) {
@@ -320,6 +57,53 @@ u32 J3DShapeDraw::countVertex(u32 stride) {
return count; return count;
} }
#if TARGET_PC
void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) {
u32 byteNum = countVertex(stride);
u32 oldSize = mDisplayListSize;
u32 newSize = ALIGN_NEXT(oldSize + byteNum, 0x20);
u8* newDLStart = JKR_NEW_ARRAY_ARGS(u8, newSize, 0x20);
u8* oldDLStart = (u8*)mDisplayList;
u8* newDL = newDLStart;
aurora::gx::dl::Reader reader{oldDLStart, mDisplayListSize, static_cast<u8>(stride)};
while (const auto cmd = reader.next()) {
if (cmd->kind == aurora::gx::dl::Command::Kind::Passthrough) {
std::memcpy(newDL, cmd->data, cmd->size);
newDL += cmd->size;
continue;
}
const auto& draw = cmd->draw;
const u32 headerSize = draw.vertices - cmd->data;
std::memcpy(newDL, cmd->data, headerSize);
newDL += headerSize;
for (u32 i = 0; i < draw.vtxCount; i++) {
const u8* oldVtx = draw.vertices + stride * i;
u8 pnmtxidx = oldVtx[0];
std::memcpy(newDL, oldVtx, attrOffs);
newDL += attrOffs;
*newDL++ = valueBase + pnmtxidx;
std::memcpy(newDL, oldVtx + attrOffs, stride - attrOffs);
newDL += stride - attrOffs;
}
}
if (reader.failed()) {
// preserve the remainder untouched
std::memcpy(newDL, oldDLStart + reader.pos(), mDisplayListSize - reader.pos());
newDL += mDisplayListSize - reader.pos();
}
u32 realSize = ALIGN_NEXT((uintptr_t)newDL - (uintptr_t)newDLStart, 0x20);
for (; (newDL - newDLStart) < newSize; newDL++)
*newDL = 0;
mDisplayListSize = realSize;
mDisplayList = newDLStart;
DCStoreRange(newDLStart, mDisplayListSize);
}
#else
void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) { void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) {
u32 byteNum = countVertex(stride); u32 byteNum = countVertex(stride);
u32 oldSize = mDisplayListSize; u32 oldSize = mDisplayListSize;
@@ -330,32 +114,13 @@ void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) {
u8* newDL = newDLStart; u8* newDL = newDLStart;
for (; (oldDL - oldDLStart) < mDisplayListSize;) { for (; (oldDL - oldDLStart) < mDisplayListSize;) {
#if TARGET_PC
u32 oldOffset = oldDL - oldDLStart;
u32 cmdSize = 0;
if (!get_command_size(oldDLStart, mDisplayListSize, oldOffset, stride, cmdSize)) {
memcpy(newDL, oldDL, mDisplayListSize - oldOffset);
newDL += mDisplayListSize - oldOffset;
break;
}
#endif
// Copy command // Copy command
u8 cmd = *(u8*)oldDL; u8 cmd = *(u8*)oldDL;
oldDL++; oldDL++;
*newDL++ = cmd; *newDL++ = cmd;
#if TARGET_PC
u8 opcode = cmd & GX_OPCODE_MASK;
if (!is_draw_opcode(opcode)) {
memcpy(newDL, oldDL, cmdSize - 1);
oldDL += cmdSize - 1;
newDL += cmdSize - 1;
continue;
}
#else
if (cmd != GX_TRIANGLEFAN && cmd != GX_TRIANGLESTRIP) if (cmd != GX_TRIANGLEFAN && cmd != GX_TRIANGLESTRIP)
break; break;
#endif
// Copy count // Copy count
int vtxNum = *(u16*)oldDL; int vtxNum = *(u16*)oldDL;
@@ -384,6 +149,7 @@ void J3DShapeDraw::addTexMtxIndexInDL(u32 stride, u32 attrOffs, u32 valueBase) {
mDisplayList = newDLStart; mDisplayList = newDLStart;
DCStoreRange(newDLStart, mDisplayListSize); DCStoreRange(newDLStart, mDisplayListSize);
} }
#endif
J3DShapeDraw::J3DShapeDraw(const u8* displayList, u32 displayListSize) { J3DShapeDraw::J3DShapeDraw(const u8* displayList, u32 displayListSize) {
#if TARGET_PC #if TARGET_PC
@@ -397,12 +163,8 @@ J3DShapeDraw::J3DShapeDraw(const u8* displayList, u32 displayListSize) {
#if TARGET_PC #if TARGET_PC
J3DShapeDraw::J3DShapeDraw( J3DShapeDraw::J3DShapeDraw(
const u8* displayList, u32 displayListSize, const GXVtxDescList* vtxDesc) { const u8* displayList, u32 displayListSize, const GXVtxDescList* vtxDesc) {
u32 stride = 0; if (const auto optimized = aurora::gx::dl::optimize(displayList, displayListSize, vtxDesc)) {
std::vector<u8> optimized; set_display_list_copy(mDisplayList, mDisplayListSize, optimized->data(), optimized->size());
if (calc_vtx_stride(vtxDesc, stride) &&
optimize_display_list(displayList, displayListSize, stride, optimized))
{
set_display_list_copy(mDisplayList, mDisplayListSize, optimized.data(), optimized.size());
} else { } else {
set_display_list_copy(mDisplayList, mDisplayListSize, displayList, displayListSize); set_display_list_copy(mDisplayList, mDisplayListSize, displayList, displayListSize);
} }
+269 -30
View File
@@ -14,6 +14,33 @@
#endif #endif
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
#if TARGET_PC
#define JPA_DRAW_CTX_PARAM , ParticleDrawCtx* ctx
namespace {
GXColor emitter_prm_color(JPAEmitterWorkData* work) {
JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = emtr->mPrmClr;
prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
return prm;
}
GXColor emitter_env_color(JPAEmitterWorkData* work) {
JPABaseEmitter* emtr = work->mpEmtr;
GXColor env = emtr->mEnvClr;
env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
return env;
}
} // namespace
#else
#define JPA_DRAW_CTX_PARAM
#endif
void JPASetPointSize(JPAEmitterWorkData* work) { void JPASetPointSize(JPAEmitterWorkData* work) {
GXSetPointSize((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE); GXSetPointSize((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE);
} }
@@ -22,15 +49,16 @@ void JPASetLineWidth(JPAEmitterWorkData* work) {
GXSetLineWidth((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE); GXSetLineWidth((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE);
} }
void JPASetPointSize(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPASetPointSize(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
GXSetPointSize((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE); GXSetPointSize((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE);
} }
void JPASetLineWidth(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPASetLineWidth(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
GXSetLineWidth((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE); GXSetLineWidth((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE);
} }
void JPARegistPrm(JPAEmitterWorkData* work) { void JPARegistPrm(JPAEmitterWorkData* work) {
ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = emtr->mPrmClr; GXColor prm = emtr->mPrmClr;
prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r); prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
@@ -41,6 +69,7 @@ void JPARegistPrm(JPAEmitterWorkData* work) {
} }
void JPARegistEnv(JPAEmitterWorkData* work) { void JPARegistEnv(JPAEmitterWorkData* work) {
ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor env = emtr->mEnvClr; GXColor env = emtr->mEnvClr;
env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r); env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
@@ -50,6 +79,7 @@ void JPARegistEnv(JPAEmitterWorkData* work) {
} }
void JPARegistPrmEnv(JPAEmitterWorkData* work) { void JPARegistPrmEnv(JPAEmitterWorkData* work) {
ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = emtr->mPrmClr; GXColor prm = emtr->mPrmClr;
GXColor env = emtr->mEnvClr; GXColor env = emtr->mEnvClr;
@@ -64,7 +94,8 @@ void JPARegistPrmEnv(JPAEmitterWorkData* work) {
GXSetTevColor(GX_TEVREG1, env); GXSetTevColor(GX_TEVREG1, env);
} }
void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = emtr->mPrmClr; GXColor prm = emtr->mPrmClr;
prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r); prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
@@ -72,10 +103,19 @@ void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b); prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a); prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm); prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm);
#if TARGET_PC
if (ctx->batch) {
ctx->clr0 = prm;
if (ctx->useClr1) {
ctx->clr1 = emitter_env_color(work);
}
return;
}
#endif
GXSetTevColor(GX_TEVREG0, prm); GXSetTevColor(GX_TEVREG0, prm);
} }
void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
ZoneScoped; ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = ptcl->mPrmClr; GXColor prm = ptcl->mPrmClr;
@@ -84,10 +124,19 @@ void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b); prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a); prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm); prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm);
#if TARGET_PC
if (ctx->batch) {
ctx->clr0 = prm;
if (ctx->useClr1) {
ctx->clr1 = emitter_env_color(work);
}
return;
}
#endif
GXSetTevColor(GX_TEVREG0, prm); GXSetTevColor(GX_TEVREG0, prm);
} }
void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
ZoneScoped; ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = ptcl->mPrmClr; GXColor prm = ptcl->mPrmClr;
@@ -100,11 +149,19 @@ void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r); env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g); env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b); env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
#if TARGET_PC
if (ctx->batch) {
ctx->clr0 = prm;
ctx->clr1 = env;
return;
}
#endif
GXSetTevColor(GX_TEVREG0, prm); GXSetTevColor(GX_TEVREG0, prm);
GXSetTevColor(GX_TEVREG1, env); GXSetTevColor(GX_TEVREG1, env);
} }
void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = emtr->mPrmClr; GXColor prm = emtr->mPrmClr;
GXColor env = ptcl->mEnvClr; GXColor env = ptcl->mEnvClr;
@@ -116,16 +173,31 @@ void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r); env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g); env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b); env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
#if TARGET_PC
if (ctx->batch) {
ctx->clr0 = prm;
ctx->clr1 = env;
return;
}
#endif
GXSetTevColor(GX_TEVREG0, prm); GXSetTevColor(GX_TEVREG0, prm);
GXSetTevColor(GX_TEVREG1, env); GXSetTevColor(GX_TEVREG1, env);
} }
void JPARegistEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPARegistEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
GXColor env = ptcl->mEnvClr; GXColor env = ptcl->mEnvClr;
env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r); env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g); env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b); env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
#if TARGET_PC
if (ctx->batch) {
ctx->clr0 = emitter_prm_color(work);
ctx->clr1 = env;
return;
}
#endif
GXSetTevColor(GX_TEVREG1, env); GXSetTevColor(GX_TEVREG1, env);
} }
@@ -258,7 +330,7 @@ void JPAGenCalcTexCrdMtxAnm(JPAEmitterWorkData* work) {
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0); GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
} }
void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1) { void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
ZoneScoped; ZoneScoped;
JPABaseShape* shape = work->mpRes->getBsp(); JPABaseShape* shape = work->mpRes->getBsp();
f32 dVar16 = param_1->mAge; f32 dVar16 = param_1->mAge;
@@ -286,6 +358,12 @@ void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1)
local_108[2][1] = 0.0f; local_108[2][1] = 0.0f;
local_108[2][2] = 1.0f; local_108[2][2] = 1.0f;
local_108[2][3] = 0.0f; local_108[2][3] = 0.0f;
#if TARGET_PC
if (ctx->batch) {
MTXCopy(local_108, ctx->texMtx);
return;
}
#endif
GXLoadTexMtxImm(local_108, 0x1e, GX_MTX2x4); GXLoadTexMtxImm(local_108, 0x1e, GX_MTX2x4);
} }
@@ -299,7 +377,7 @@ void JPALoadTexAnm(JPAEmitterWorkData* work) {
work->mpResMgr->load(work->mpRes->getTexIdx(work->mpEmtr->mTexAnmIdx), GX_TEXMAP0); work->mpResMgr->load(work->mpRes->getTexIdx(work->mpEmtr->mTexAnmIdx), GX_TEXMAP0);
} }
void JPALoadTexAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPALoadTexAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
ZoneScoped; ZoneScoped;
work->mpResMgr->load(work->mpRes->getTexIdx(ptcl->mTexAnmIdx), GX_TEXMAP0); work->mpResMgr->load(work->mpRes->getTexIdx(ptcl->mTexAnmIdx), GX_TEXMAP0);
} }
@@ -429,6 +507,47 @@ static projectionFunc p_prj[3] = {
}; };
#if TARGET_PC #if TARGET_PC
static void emit_batch_quad(JPAEmitterWorkData* work, const ParticleDrawCtx* ctx,
const Mtx posMtx) {
const JPAResource::BatchInfo& info = work->mpRes->mBatchInfo;
for (int i = 0; i < info.vtxCount; i++) {
Vec localPos = {info.vtxPos[i][0], info.vtxPos[i][1], info.vtxPos[i][2]};
Vec drawPos;
MTXMultVec(posMtx, &localPos, &drawPos);
f32 texS = info.vtxUv[i][0];
f32 texT = info.vtxUv[i][1];
if (ctx->useTexMtx) {
f32 srcS = texS;
f32 srcT = texT;
texS = ctx->texMtx[0][0] * srcS + ctx->texMtx[0][1] * srcT + ctx->texMtx[0][3];
texT = ctx->texMtx[1][0] * srcS + ctx->texMtx[1][1] * srcT + ctx->texMtx[1][3];
}
GXPosition3f32(drawPos.x, drawPos.y, drawPos.z);
if (ctx->useClr0) {
GXColor4u8(ctx->clr0.r, ctx->clr0.g, ctx->clr0.b, ctx->clr0.a);
}
if (ctx->useClr1) {
GXColor4u8(ctx->clr1.r, ctx->clr1.g, ctx->clr1.b, ctx->clr1.a);
}
GXTexCoord2f32(texS, texT);
}
}
static void submit_particle_quad(
JPAEmitterWorkData* work, ParticleDrawCtx* ctx, const Mtx posMtx, const u8* dl, u32 dlSize) {
if (ctx->batch) {
emit_batch_quad(work, ctx, posMtx);
return;
}
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(dl, dlSize);
}
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
Mtx ptclPosMtx; Mtx ptclPosMtx;
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z); MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
@@ -448,7 +567,7 @@ void JPAInterpRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
} }
#endif #endif
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -473,12 +592,16 @@ void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
posMtx[2][2] = 1.0f; posMtx[2][2] = 1.0f;
posMtx[2][3] = pos.z; 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; posMtx[0][1] = posMtx[0][2] = posMtx[1][0] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
#if TARGET_PC
submit_particle_quad(work, ctx, posMtx, jpa_dl, sizeof(jpa_dl));
#else
GXLoadPosMtxImm(posMtx, GX_PNMTX0); GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx); p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
#endif
} }
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -517,12 +640,16 @@ void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
posMtx[2][2] = 1.0f; posMtx[2][2] = 1.0f;
posMtx[2][3] = pos.z; posMtx[2][3] = pos.z;
posMtx[0][2] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f; posMtx[0][2] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
#if TARGET_PC
submit_particle_quad(work, ctx, posMtx, jpa_dl, sizeof(jpa_dl));
#else
GXLoadPosMtxImm(posMtx, GX_PNMTX0); GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx); p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
#endif
} }
void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) { void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -542,12 +669,16 @@ 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;
#if TARGET_PC
submit_particle_quad(work, ctx, local_38, jpa_dl, sizeof(jpa_dl));
#else
GXLoadPosMtxImm(local_38, GX_PNMTX0); 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));
#endif
} }
void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) { void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -576,9 +707,13 @@ 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;
#if TARGET_PC
submit_particle_quad(work, ctx, local_38, jpa_dl, sizeof(jpa_dl));
#else
GXLoadPosMtxImm(local_38, GX_PNMTX0); 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));
#endif
} }
void dirTypeVel(JPAEmitterWorkData const* work, JPABaseParticle const* param_1, void dirTypeVel(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
@@ -741,6 +876,88 @@ static u8* p_dl[2] = {
}; };
#if TARGET_PC #if TARGET_PC
static bool make_direction_mtx(JPAEmitterWorkData* work, JPABaseParticle* ptcl, Mtx posMtx) {
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
JGeometry::TVec3<f32> baseAxis(ptcl->mBaseAxis);
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) {
return false;
}
axisY.normalize();
axisZ.cross(baseAxis, axisY);
if (axisZ.isZero()) {
return false;
}
axisZ.normalize();
baseAxis.cross(axisY, axisZ);
baseAxis.normalize();
ptcl->mBaseAxis.set(baseAxis);
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
posMtx[0][0] = baseAxis.x;
posMtx[0][1] = axisY.x;
posMtx[0][2] = axisZ.x;
posMtx[0][3] = ptcl->mPosition.x;
posMtx[1][0] = baseAxis.y;
posMtx[1][1] = axisY.y;
posMtx[1][2] = axisZ.y;
posMtx[1][3] = ptcl->mPosition.y;
posMtx[2][0] = baseAxis.z;
posMtx[2][1] = axisY.z;
posMtx[2][2] = axisZ.z;
posMtx[2][3] = ptcl->mPosition.z;
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
return true;
}
static bool make_rot_direction_mtx(JPAEmitterWorkData* work, JPABaseParticle* ptcl, Mtx posMtx) {
f32 sinRot = JMASSin(ptcl->mRotateAngle);
f32 cosRot = JMASCos(ptcl->mRotateAngle);
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
JGeometry::TVec3<f32> baseAxis(ptcl->mBaseAxis);
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) {
return false;
}
axisY.normalize();
axisZ.cross(baseAxis, axisY);
if (axisZ.isZero()) {
return false;
}
axisZ.normalize();
baseAxis.cross(axisY, axisZ);
baseAxis.normalize();
ptcl->mBaseAxis.set(baseAxis);
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
Mtx rotMtx;
Mtx dirMtx;
p_rot[work->mRotType](sinRot, cosRot, rotMtx);
p_plane[work->mPlaneType](rotMtx, scaleX, scaleY);
dirMtx[0][0] = baseAxis.x;
dirMtx[0][1] = axisY.x;
dirMtx[0][2] = axisZ.x;
dirMtx[0][3] = ptcl->mPosition.x;
dirMtx[1][0] = baseAxis.y;
dirMtx[1][1] = axisY.y;
dirMtx[1][2] = axisZ.y;
dirMtx[1][3] = ptcl->mPosition.y;
dirMtx[2][0] = baseAxis.z;
dirMtx[2][1] = axisY.z;
dirMtx[2][2] = axisZ.z;
dirMtx[2][3] = ptcl->mPosition.z;
MTXConcat(dirMtx, rotMtx, posMtx);
return true;
}
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
JGeometry::TVec3<f32> axisY; JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ; JGeometry::TVec3<f32> axisZ;
@@ -823,7 +1040,7 @@ void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
} }
#endif #endif
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -832,8 +1049,12 @@ void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
Mtx posMtx; Mtx posMtx;
#if TARGET_PC #if TARGET_PC
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx)) if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx) &&
#endif !make_direction_mtx(work, ptcl, posMtx))
{
return;
}
#else
{ {
JGeometry::TVec3<f32> axisY; JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ; JGeometry::TVec3<f32> axisZ;
@@ -869,14 +1090,19 @@ void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
posMtx[2][3] = ptcl->mPosition.z; posMtx[2][3] = ptcl->mPosition.z;
p_plane[work->mPlaneType](posMtx, scaleX, scaleY); p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
} }
#endif
MTXConcat(work->mPosCamMtx, posMtx, posMtx); MTXConcat(work->mPosCamMtx, posMtx, posMtx);
#if TARGET_PC
submit_particle_quad(work, ctx, posMtx, p_dl[work->mDLType], sizeof(jpa_dl));
#else
GXLoadPosMtxImm(posMtx, GX_PNMTX0); GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx); p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl)); GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
#endif
} }
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -886,8 +1112,12 @@ void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
Mtx mtx1; Mtx mtx1;
Mtx mtx2; Mtx mtx2;
#if TARGET_PC #if TARGET_PC
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1)) if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1) &&
#endif !make_rot_direction_mtx(work, ptcl, mtx1))
{
return;
}
#else
{ {
f32 sinRot = JMASSin(ptcl->mRotateAngle); f32 sinRot = JMASSin(ptcl->mRotateAngle);
f32 cosRot = JMASCos(ptcl->mRotateAngle); f32 cosRot = JMASCos(ptcl->mRotateAngle);
@@ -927,13 +1157,18 @@ void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
mtx2[2][3] = ptcl->mPosition.z; mtx2[2][3] = ptcl->mPosition.z;
MTXConcat(mtx2, mtx1, mtx1); MTXConcat(mtx2, mtx1, mtx1);
} }
#endif
MTXConcat(work->mPosCamMtx, mtx1, mtx2); MTXConcat(work->mPosCamMtx, mtx1, mtx2);
#if TARGET_PC
submit_particle_quad(work, ctx, mtx2, p_dl[work->mDLType], sizeof(jpa_dl));
#else
GXLoadPosMtxImm(mtx2, GX_PNMTX0); GXLoadPosMtxImm(mtx2, GX_PNMTX0);
p_prj[work->mPrjType](work, mtx2); p_prj[work->mPrjType](work, mtx2);
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl)); GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
#endif
} }
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -970,7 +1205,7 @@ void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -988,12 +1223,16 @@ void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
auStack_88[1][3] = param_1->mPosition.y; auStack_88[1][3] = param_1->mPosition.y;
auStack_88[2][3] = param_1->mPosition.z; auStack_88[2][3] = param_1->mPosition.z;
MTXConcat(param_0->mPosCamMtx, auStack_88, auStack_88); MTXConcat(param_0->mPosCamMtx, auStack_88, auStack_88);
#if TARGET_PC
submit_particle_quad(param_0, ctx, auStack_88, p_dl[param_0->mDLType], sizeof(jpa_dl));
#else
GXLoadPosMtxImm(auStack_88, 0); GXLoadPosMtxImm(auStack_88, 0);
p_prj[param_0->mPrjType](param_0, auStack_88); p_prj[param_0->mPrjType](param_0, auStack_88);
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl)); GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
#endif
} }
void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -1010,7 +1249,7 @@ void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8); GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
} }
void JPADrawLine(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { void JPADrawLine(JPAEmitterWorkData* param_0, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
@@ -1086,7 +1325,7 @@ void JPADrawStripe(JPAEmitterWorkData* param_0) {
GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1); GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd(); for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
node = node_func(node), coord += step) { node = node_func(node), coord += step) {
param_0->mpCurNode = node; param_0->mpCurNode = node;
JPABaseParticle* particle = node->getObject(); JPABaseParticle* particle = node->getObject();
@@ -1111,7 +1350,7 @@ void JPADrawStripe(JPAEmitterWorkData* param_0) {
} }
particle->mBaseAxis.cross(local_f8, local_104); particle->mBaseAxis.cross(local_f8, local_104);
particle->mBaseAxis.normalize(); particle->mBaseAxis.normalize();
local_c8[0][0] = local_104.x; local_c8[0][0] = local_104.x;
local_c8[0][1] = local_f8.x; local_c8[0][1] = local_f8.x;
local_c8[0][2] = particle->mBaseAxis.x; local_c8[0][2] = particle->mBaseAxis.x;
@@ -1177,7 +1416,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1); GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd(); for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
node = node_func(node), coord += step) { node = node_func(node), coord += step) {
param_0->mpCurNode = node; param_0->mpCurNode = node;
JPABaseParticle* particle = node->getObject(); JPABaseParticle* particle = node->getObject();
@@ -1202,7 +1441,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
} }
particle->mBaseAxis.cross(local_c0, local_cc); particle->mBaseAxis.cross(local_c0, local_cc);
particle->mBaseAxis.normalize(); particle->mBaseAxis.normalize();
local_90[0][0] = local_cc.x; local_90[0][0] = local_cc.x;
local_90[0][1] = local_c0.x; local_90[0][1] = local_c0.x;
local_90[0][2] = particle->mBaseAxis.x; local_90[0][2] = particle->mBaseAxis.x;
@@ -1227,7 +1466,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
coord = start_coord; coord = start_coord;
GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1); GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd(); for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
node = node_func(node), coord += step) { node = node_func(node), coord += step) {
param_0->mpCurNode = node; param_0->mpCurNode = node;
JPABaseParticle* particle = node->getObject(); JPABaseParticle* particle = node->getObject();
@@ -1252,7 +1491,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
} }
particle->mBaseAxis.cross(local_c0, local_cc); particle->mBaseAxis.cross(local_c0, local_cc);
particle->mBaseAxis.normalize(); particle->mBaseAxis.normalize();
local_90[0][0] = local_cc.x; local_90[0][0] = local_cc.x;
local_90[0][1] = local_c0.x; local_90[0][1] = local_c0.x;
local_90[0][2] = particle->mBaseAxis.x; local_90[0][2] = particle->mBaseAxis.x;
@@ -1289,7 +1528,7 @@ void JPADrawEmitterCallBackB(JPAEmitterWorkData* work) {
emtr->mpEmtrCallBack->draw(emtr); emtr->mpEmtrCallBack->draw(emtr);
} }
void JPADrawParticleCallBack(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawParticleCallBack(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
JPABaseEmitter* emtr = work->mpEmtr; JPABaseEmitter* emtr = work->mpEmtr;
if (emtr->mpPtclCallBack == NULL) { if (emtr->mpPtclCallBack == NULL) {
return; return;
+275 -6
View File
@@ -18,9 +18,21 @@
#include "global.h" #include "global.h"
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
#if TARGET_PC
#define JPA_DRAW_CTX_ARG , &ctx
#else
#define JPA_DRAW_CTX_ARG
#endif
JPAResource::JPAResource() { JPAResource::JPAResource() {
mpCalcEmitterFuncList = mpDrawEmitterFuncList = mpDrawEmitterChildFuncList = NULL; mpCalcEmitterFuncList = mpDrawEmitterFuncList = mpDrawEmitterChildFuncList = NULL;
#if TARGET_PC
mpCalcParticleFuncList = mpCalcParticleChildFuncList = NULL;
mpDrawParticleFuncList = mpDrawParticleChildFuncList = NULL;
mBatchInfo = {};
#else
mpCalcParticleFuncList = mpDrawParticleFuncList = mpCalcParticleChildFuncList = mpDrawParticleChildFuncList = NULL; mpCalcParticleFuncList = mpDrawParticleFuncList = mpCalcParticleChildFuncList = mpDrawParticleChildFuncList = NULL;
#endif
pBsp = NULL; pBsp = NULL;
pEsp = NULL; pEsp = NULL;
pCsp = NULL; pCsp = NULL;
@@ -61,6 +73,60 @@ static u8 jpa_crd[32] ATTRIBUTE_ALIGN(32) = {
0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02,
}; };
#if TARGET_PC
void JPAResource::initBatchInfo() {
mBatchInfo = {};
bool hasDrawFunc = false;
for (int i = 0; i < mpDrawParticleFuncListNum; i++) {
DrawParticleFunc func = mpDrawParticleFuncList[i];
if (func == JPADrawBillboard || func == JPADrawRotBillboard ||
func == JPADrawYBillboard || func == JPADrawRotYBillboard ||
func == JPADrawDirection || func == JPADrawRotDirection || func == JPADrawRotation)
{
hasDrawFunc = true;
} else if (func == JPADrawParticleCallBack) {
// Batchable only for emitters without a particle callback; checked per draw
} else if (func == JPALoadCalcTexCrdMtxAnm) {
mBatchInfo.hasPtclTexMtx = true;
} else if (func == JPARegistAlpha || func == JPARegistPrmAlpha ||
func == JPARegistPrmAlphaEnv || func == JPARegistAlphaEnv ||
func == static_cast<DrawParticleFunc>(JPARegistEnv)) // overloaded
{
mBatchInfo.hasPtclColor = true;
} else {
// JPADrawPoint, JPADrawLine, JPADrawDBillboard, JPALoadTexAnm,
// JPASetPointSize, JPASetLineWidth
return;
}
}
if (!hasDrawFunc) {
return;
}
// Template array offsets, same math as setPTev
int base_plane_type = (pBsp->getType() == 3 || pBsp->getType() == 7) ?
pBsp->getBasePlaneType() : 0;
int center_offset = pEsp != nullptr ? (pEsp->getScaleCenterX() + 3 * pEsp->getScaleCenterY()) * 0xC : 0x30;
const s8* pos = reinterpret_cast<const s8*>(jpa_pos) + center_offset + base_plane_type * 0x6C;
const s8* crd = reinterpret_cast<const s8*>(jpa_crd) + (pBsp->getTilingS() + 2 * pBsp->getTilingT()) * 8;
bool cross = pBsp->getType() == 4 || pBsp->getType() == 8;
mBatchInfo.vtxCount = cross ? 8 : 4;
for (int i = 0; i < mBatchInfo.vtxCount; i++) {
int posIdx = i < 4 ? i : 72 + (i - 4);
int crdIdx = i & 3;
mBatchInfo.vtxPos[i][0] = pos[posIdx * 3 + 0];
mBatchInfo.vtxPos[i][1] = pos[posIdx * 3 + 1];
mBatchInfo.vtxPos[i][2] = pos[posIdx * 3 + 2];
mBatchInfo.vtxUv[i][0] = crd[crdIdx * 2 + 0];
mBatchInfo.vtxUv[i][1] = crd[crdIdx * 2 + 1];
}
mBatchInfo.supported = true;
}
#endif
void JPAResource::init(JKRHeap* heap) { void JPAResource::init(JKRHeap* heap) {
BOOL is_glbl_clr_anm = pBsp->isGlblClrAnm(); BOOL is_glbl_clr_anm = pBsp->isGlblClrAnm();
BOOL is_glbl_tex_anm = pBsp->isGlblTexAnm(); BOOL is_glbl_tex_anm = pBsp->isGlblTexAnm();
@@ -525,7 +591,10 @@ void JPAResource::init(JKRHeap* heap) {
if (mpDrawParticleFuncListNum != 0) { if (mpDrawParticleFuncListNum != 0) {
mpDrawParticleFuncList = mpDrawParticleFuncList =
(ParticleFunc*)JKRAllocFromHeap(heap, mpDrawParticleFuncListNum * sizeof(ParticleFunc), alignof(ParticleFunc)); (DrawParticleFunc*)JKRAllocFromHeap(
heap,
mpDrawParticleFuncListNum * sizeof(DrawParticleFunc),
alignof(DrawParticleFunc));
} }
func_no = 0; func_no = 0;
@@ -635,7 +704,10 @@ void JPAResource::init(JKRHeap* heap) {
if (mpDrawParticleChildFuncListNum != 0) { if (mpDrawParticleChildFuncListNum != 0) {
mpDrawParticleChildFuncList = mpDrawParticleChildFuncList =
(ParticleFunc*)JKRAllocFromHeap(heap, mpDrawParticleChildFuncListNum * sizeof(ParticleFunc), sizeof(EmitterFunc)); (DrawParticleFunc*)JKRAllocFromHeap(
heap,
mpDrawParticleChildFuncListNum * sizeof(DrawParticleFunc),
alignof(DrawParticleFunc));
} }
func_no = 0; func_no = 0;
@@ -699,6 +771,10 @@ void JPAResource::init(JKRHeap* heap) {
mpDrawParticleChildFuncList[func_no] = &JPARegistPrmAlphaEnv; mpDrawParticleChildFuncList[func_no] = &JPARegistPrmAlphaEnv;
func_no++; func_no++;
} }
#if TARGET_PC
initBatchInfo();
#endif
} }
bool JPAResource::calc(JPAEmitterWorkData* work, JPABaseEmitter* emtr) { bool JPAResource::calc(JPAEmitterWorkData* work, JPABaseEmitter* emtr) {
@@ -808,6 +884,183 @@ void JPAResource::draw(JPAEmitterWorkData* work, JPABaseEmitter* emtr) {
} }
} }
#if TARGET_PC
static GXTevAlphaArg to_vtx_alpha_arg(GXTevAlphaArg arg) {
return arg == GX_CA_A0 ? GX_CA_RASA : arg;
}
static void batch_set_tev_op(GXTevStageID stage) {
GXSetTevColorOp(stage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaOp(stage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
}
static void batch_setup_tev(JPAEmitterWorkData* work, bool useClr1) {
JPABaseShape* shape = work->mpRes->getBsp();
JPAExTexShape* ets = work->mpRes->getEts();
bool useIndirect = ets != nullptr && ets->isUseIndirect();
// JPAEmitterManager::draw configures both channels to pass vertex color through
GXSetNumChans(useClr1 ? 2 : 1);
const GXTevAlphaArg* alphaArg = shape->getTevAlphaArg();
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GXSetTevAlphaIn(GX_TEVSTAGE0, to_vtx_alpha_arg(alphaArg[0]), to_vtx_alpha_arg(alphaArg[1]),
to_vtx_alpha_arg(alphaArg[2]), to_vtx_alpha_arg(alphaArg[3]));
batch_set_tev_op(GX_TEVSTAGE0);
if (!useIndirect) {
GXSetTevDirect(GX_TEVSTAGE0);
}
GXTevStageID nextStage = GX_TEVSTAGE1;
switch (shape->getTevColorArgSel()) {
case 0: // TEXC
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_ONE, GX_CC_ZERO);
break;
case 1: // C0 * TEXC
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
break;
case 2: // lerp(C0, 1, TEXC)
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO);
break;
case 3: // lerp(C1, C0, TEXC) = C0 * TEXC (stage 0) + C1 * (1 - TEXC) (stage 1)
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
GXSetTevOrder(nextStage, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR1A1);
GXSetTevColorIn(nextStage, GX_CC_RASC, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV);
GXSetTevAlphaIn(nextStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
batch_set_tev_op(nextStage);
GXSetTevDirect(nextStage);
nextStage = static_cast<GXTevStageID>(nextStage + 1);
break;
case 4: // TEXC * C0 + C1: C0 * TEXC (stage 0), + C1 (stage 1)
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
GXSetTevOrder(nextStage, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR1A1);
GXSetTevColorIn(nextStage, GX_CC_CPREV, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
GXSetTevAlphaIn(nextStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
batch_set_tev_op(nextStage);
GXSetTevDirect(nextStage);
nextStage = static_cast<GXTevStageID>(nextStage + 1);
break;
case 5: // C0
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
break;
}
if (ets != nullptr && ets->isUseSecTex()) {
// Mirrors setPTev's secondary texture stage, at the next free stage
GXTexCoordID texCoord = useIndirect ? GX_TEXCOORD2 : GX_TEXCOORD1;
GXSetTevOrder(nextStage, texCoord, GX_TEXMAP3, GX_COLOR_NULL);
GXSetTevColorIn(nextStage, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV, GX_CC_ZERO);
GXSetTevAlphaIn(nextStage, GX_CA_ZERO, GX_CA_TEXA, GX_CA_APREV, GX_CA_ZERO);
batch_set_tev_op(nextStage);
GXSetTevDirect(nextStage);
nextStage = static_cast<GXTevStageID>(nextStage + 1);
}
GXSetNumTevStages(nextStage);
}
static void batch_setup_vtx_desc(bool useClr0, bool useClr1) {
static Mtx identityMtx = {
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
};
GXLoadPosMtxImm(identityMtx, GX_PNMTX0);
GXSetCurrentMtx(GX_PNMTX0);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
if (useClr0) {
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
}
if (useClr1) {
GXSetVtxDesc(GX_VA_CLR1, GX_DIRECT);
}
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
if (useClr0) {
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
}
if (useClr1) {
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR1, GX_CLR_RGBA, GX_RGBA8, 0);
}
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
}
static void batch_restore_gx(JPAEmitterWorkData* work, bool changedTev, bool changedTexMtx) {
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S8, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetCurrentMtx(GX_PNMTX0);
if (changedTexMtx) {
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
}
if (changedTev) {
GXSetNumChans(0);
work->mpRes->getBsp()->setGX(work);
work->mpRes->setPTev();
}
}
static bool draw_particle_batch(JPAEmitterWorkData* work) {
ZoneScoped;
JPAResource* res = work->mpRes;
const JPAResource::BatchInfo& info = res->mBatchInfo;
if (!info.supported || work->mPrjType != 0 || work->mpEmtr->mpPtclCallBack != nullptr) {
return false;
}
bool useClr0 = false;
bool useClr1 = false;
if (info.hasPtclColor) {
u32 colorSel = res->getBsp()->getTevColorArgSel();
if (colorSel >= 6) {
return false;
}
useClr0 = true;
useClr1 = colorSel == 3 || colorSel == 4;
batch_setup_tev(work, useClr1);
}
if (info.hasPtclTexMtx) {
// UVs are CPU-transformed; drop the texgen
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
}
batch_setup_vtx_desc(useClr0, useClr1);
ParticleDrawCtx ctx{};
ctx.batch = true;
ctx.useTexMtx = info.hasPtclTexMtx;
ctx.useClr0 = useClr0;
ctx.useClr1 = useClr1;
bool fwdAhead = res->getBsp()->isDrawFwdAhead();
JPANode<JPABaseParticle>* node = fwdAhead ? work->mpEmtr->mAlivePtclBase.getLast() :
work->mpEmtr->mAlivePtclBase.getFirst();
GXBegin(GX_QUADS, GX_VTXFMT1, GX_AUTO);
while (node != work->mpEmtr->mAlivePtclBase.getEnd()) {
work->mpCurNode = node;
for (int i = res->mpDrawParticleFuncListNum - 1; i >= 0; i--) {
(*res->mpDrawParticleFuncList[i])(work, node->getObject(), &ctx);
}
node = fwdAhead ? node->getPrev() : node->getNext();
}
GXEnd();
batch_restore_gx(work, useClr0, info.hasPtclTexMtx);
return true;
}
#endif
void JPAResource::drawP(JPAEmitterWorkData* work) { void JPAResource::drawP(JPAEmitterWorkData* work) {
ZoneScoped; ZoneScoped;
work->mpEmtr->clearStatus(0x80); work->mpEmtr->clearStatus(0x80);
@@ -842,13 +1095,25 @@ void JPAResource::drawP(JPAEmitterWorkData* work) {
(*mpDrawEmitterFuncList[i])(work); (*mpDrawEmitterFuncList[i])(work);
} }
#if TARGET_PC
if (draw_particle_batch(work)) {
GXSetMisc(GX_MT_XF_FLUSH, 0);
if (work->mpEmtr->mpEmtrCallBack != nullptr) {
work->mpEmtr->mpEmtrCallBack->drawAfter(work->mpEmtr);
}
return;
}
ParticleDrawCtx ctx{}; // immediate mode
#endif
if (pBsp->isDrawFwdAhead()) { if (pBsp->isDrawFwdAhead()) {
JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclBase.getLast(); JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclBase.getLast();
for (; node != work->mpEmtr->mAlivePtclBase.getEnd(); node = node->getPrev()) { for (; node != work->mpEmtr->mAlivePtclBase.getEnd(); node = node->getPrev()) {
work->mpCurNode = node; work->mpCurNode = node;
if (mpDrawParticleFuncList != NULL) { if (mpDrawParticleFuncList != NULL) {
for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) { for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) {
(*mpDrawParticleFuncList[i])(work, node->getObject()); (*mpDrawParticleFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
} }
} }
} }
@@ -858,7 +1123,7 @@ void JPAResource::drawP(JPAEmitterWorkData* work) {
work->mpCurNode = node; work->mpCurNode = node;
if (mpDrawParticleFuncList != NULL) { if (mpDrawParticleFuncList != NULL) {
for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) { for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) {
(*mpDrawParticleFuncList[i])(work, node->getObject()); (*mpDrawParticleFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
} }
} }
} }
@@ -905,13 +1170,17 @@ void JPAResource::drawC(JPAEmitterWorkData* work) {
(*mpDrawEmitterChildFuncList[i])(work); (*mpDrawEmitterChildFuncList[i])(work);
} }
#if TARGET_PC
ParticleDrawCtx ctx{}; // immediate mode
#endif
if (pBsp->isDrawFwdAhead()) { if (pBsp->isDrawFwdAhead()) {
JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclChld.getLast(); JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclChld.getLast();
for (; node != work->mpEmtr->mAlivePtclChld.getEnd(); node = node->getPrev()) { for (; node != work->mpEmtr->mAlivePtclChld.getEnd(); node = node->getPrev()) {
work->mpCurNode = node; work->mpCurNode = node;
if (mpDrawParticleChildFuncList != NULL) { if (mpDrawParticleChildFuncList != NULL) {
for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) { for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) {
(*mpDrawParticleChildFuncList[i])(work, node->getObject()); (*mpDrawParticleChildFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
} }
} }
} }
@@ -921,7 +1190,7 @@ void JPAResource::drawC(JPAEmitterWorkData* work) {
work->mpCurNode = node; work->mpCurNode = node;
if (mpDrawParticleChildFuncList != NULL) { if (mpDrawParticleChildFuncList != NULL) {
for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) { for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) {
(*mpDrawParticleChildFuncList[i])(work, node->getObject()); (*mpDrawParticleChildFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
} }
} }
} }
@@ -4,6 +4,7 @@ import android.app.ActionBar;
import android.app.Activity; import android.app.Activity;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.ClipData; import android.content.ClipData;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
@@ -14,12 +15,16 @@ import android.provider.DocumentsContract;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.provider.Settings; import android.provider.Settings;
import android.util.Log; import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.WindowInsetsController; import android.view.WindowInsetsController;
import org.libsdl.app.SDLActivity; import org.libsdl.app.SDLActivity;
import org.libsdl.app.SDLSurface;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@@ -27,6 +32,7 @@ import java.util.List;
public class DuskActivity extends SDLActivity { public class DuskActivity extends SDLActivity {
private static final String TAG = "DuskActivity"; private static final String TAG = "DuskActivity";
private static final float DEFAULT_SURFACE_FRAME_RATE = 60.0f;
private static final int FOLDER_DIALOG_REQUEST_CODE = 0x4455; private static final int FOLDER_DIALOG_REQUEST_CODE = 0x4455;
private static final int MANAGE_STORAGE_REQUEST_CODE = 0x4456; private static final int MANAGE_STORAGE_REQUEST_CODE = 0x4456;
private static final String EXTERNAL_STORAGE_AUTHORITY = private static final String EXTERNAL_STORAGE_AUTHORITY =
@@ -88,6 +94,11 @@ public class DuskActivity extends SDLActivity {
hideSystemBars(); hideSystemBars();
} }
@Override
protected SDLSurface createSDLSurface(Context context) {
return new DuskSurface(context);
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
@@ -139,6 +150,77 @@ public class DuskActivity extends SDLActivity {
}; };
} }
public void setPreferredSurfaceFrameRate(float frameRate) {
runOnUiThread(() -> {
if (mSurface instanceof DuskSurface) {
((DuskSurface)mSurface).setPreferredFrameRate(frameRate);
}
});
}
private static final class DuskSurface extends SDLSurface {
private float preferredFrameRate = DEFAULT_SURFACE_FRAME_RATE;
DuskSurface(Context context) {
super(context);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.surfaceChanged(holder, format, width, height);
setTargetFrameRate(holder);
}
void setPreferredFrameRate(float frameRate) {
preferredFrameRate = frameRate;
setTargetFrameRate(getHolder());
}
private void setTargetFrameRate(SurfaceHolder holder) {
if (!mIsSurfaceReady || Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
return;
}
Surface surface = holder != null ? holder.getSurface() : getHolder().getSurface();
if (surface == null || !surface.isValid()) {
return;
}
float targetFrameRate = getMaxSupportedFrameRate();
if (preferredFrameRate > 0.0f) {
targetFrameRate = preferredFrameRate;
}
if (targetFrameRate <= 0.0f) {
return;
}
try {
surface.setFrameRate(
targetFrameRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT);
Log.v(TAG, "Requested surface frame rate " + targetFrameRate + " fps");
} catch (RuntimeException e) {
Log.w(TAG, "Failed to request surface frame rate", e);
}
}
private float getMaxSupportedFrameRate() {
if (mDisplay == null) {
return 0.0f;
}
float maxFrameRate = mDisplay.getRefreshRate();
Display.Mode[] modes = mDisplay.getSupportedModes();
if (modes == null) {
return maxFrameRate;
}
for (Display.Mode mode : modes) {
maxFrameRate = Math.max(maxFrameRate, mode.getRefreshRate());
}
return maxFrameRate;
}
}
@Override @Override
protected String[] getArguments() { protected String[] getArguments() {
Intent intent = getIntent(); Intent intent = getIntent();
@@ -19,9 +19,13 @@ import android.os.*;
import java.lang.Runnable; import java.lang.Runnable;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice { class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
private static final String TAG = "hidapi"; private static final String TAG = "hidapi";
@@ -33,10 +37,19 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
private boolean mIsConnected = false; private boolean mIsConnected = false;
private boolean mIsChromebook = false; private boolean mIsChromebook = false;
private boolean mIsReconnecting = false; private boolean mIsReconnecting = false;
private boolean mHasEnabledNotifications = false;
private boolean mHasSeenInputUpdate = false;
private boolean mFrozen = false; private boolean mFrozen = false;
private LinkedList<GattOperation> mOperations; private LinkedList<GattOperation> mOperations;
GattOperation mCurrentOperation = null; GattOperation mCurrentOperation = null;
private Handler mHandler; private Handler mHandler;
private int mProductId = -1;
private int mReportId = 0;
private UUID mInputCharacteristic;
private static final int D0G_BLE2_PID = 0x1106;
private static final int TRITON_BLE_PID = 0x1303;
private static final int TRANSPORT_AUTO = 0; private static final int TRANSPORT_AUTO = 0;
private static final int TRANSPORT_BREDR = 1; private static final int TRANSPORT_BREDR = 1;
@@ -45,10 +58,14 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000; private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
static final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3"); static final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
static final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3"); static final UUID inputCharacteristicD0G = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
static final UUID inputCharacteristicTriton_0x45 = UUID.fromString("100F6C7A-1735-4313-B402-38567131E5F3");
static final UUID inputCharacteristicTriton_0x47 = UUID.fromString("100F6C7C-1735-4313-B402-38567131E5F3");
static final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3"); static final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 }; static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
private HashMap<Integer, BluetoothGattCharacteristic> mOutputReportChars = new HashMap<Integer, BluetoothGattCharacteristic>();
static class GattOperation { static class GattOperation {
private enum Operation { private enum Operation {
CHR_READ, CHR_READ,
@@ -61,6 +78,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
byte[] mValue; byte[] mValue;
BluetoothGatt mGatt; BluetoothGatt mGatt;
boolean mResult = true; boolean mResult = true;
int mDelayMs = 0;
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) { private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
mGatt = gatt; mGatt = gatt;
@@ -68,6 +86,13 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mUuid = uuid; mUuid = uuid;
} }
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, int delayMs) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mDelayMs = delayMs;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) { private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
mGatt = gatt; mGatt = gatt;
mOp = operation; mOp = operation;
@@ -75,6 +100,14 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mValue = value; mValue = value;
} }
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value, int delayMs) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mValue = value;
mDelayMs = delayMs;
}
public void run() { public void run() {
// This is executed in main thread // This is executed in main thread
BluetoothGattCharacteristic chr; BluetoothGattCharacteristic chr;
@@ -136,6 +169,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
return mResult; return mResult;
} }
public int getDelayMs() { return mDelayMs; }
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) { private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattService valveService = mGatt.getService(steamControllerService); BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null) if (valveService == null)
@@ -154,6 +189,10 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) { static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid); return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
} }
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid, int delayMs) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid, delayMs);
}
} }
HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) { HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
@@ -166,6 +205,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mHandler = new Handler(Looper.getMainLooper()); mHandler = new Handler(Looper.getMainLooper());
mGatt = connectGatt(); mGatt = connectGatt();
mHasEnabledNotifications = false;
mHasSeenInputUpdate = false;
// final HIDDeviceBLESteamController finalThis = this; // final HIDDeviceBLESteamController finalThis = this;
// mHandler.postDelayed(new Runnable() { // mHandler.postDelayed(new Runnable() {
// @Override // @Override
@@ -314,8 +355,45 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
Log.v(TAG, "Found Valve steam controller service " + service.getUuid()); Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) { for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
if (chr.getUuid().equals(inputCharacteristic)) { if (chr.getUuid().equals(inputCharacteristicTriton_0x45)) {
Log.v(TAG, "Found input characteristic"); Log.v(TAG, "Found Triton input characteristic 0x45");
mProductId = TRITON_BLE_PID;
mReportId = 0x45;
mInputCharacteristic = chr.getUuid();
} else if (chr.getUuid().equals(inputCharacteristicTriton_0x47)) {
Log.v(TAG, "Found Triton input characteristic 0x47");
mProductId = TRITON_BLE_PID;
mReportId = 0x47;
mInputCharacteristic = chr.getUuid();
} else if (chr.getUuid().equals(inputCharacteristicD0G)) {
Log.v(TAG, "Found D0G input characteristic");
mProductId = D0G_BLE2_PID;
mReportId = 0x03;
mInputCharacteristic = chr.getUuid();
} else {
Pattern reportPattern = Pattern.compile("100F6C([0-9A-Z]{2})", Pattern.CASE_INSENSITIVE);
Matcher matcher = reportPattern.matcher(chr.getUuid().toString());
if (matcher.find()) {
try {
int reportId = Integer.parseInt(matcher.group(1), 16);
reportId -= 0x35;
if (reportId >= 0x80) {
// This is a Triton output report characteristic that we need to care about.
Log.v(TAG, "Found Triton output report 0x" + Integer.toString(reportId, 16));
mOutputReportChars.put(reportId, chr);
}
}
catch (NumberFormatException nfe) {
Log.w(TAG, "Could not parse report characteristic " + chr.getUuid().toString() + ": " + nfe.toString());
}
}
}
}
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
if (chr.getUuid().equals(mInputCharacteristic)) {
// Start notifications // Start notifications
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) { if (cccd != null) {
@@ -372,21 +450,30 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mCurrentOperation = mOperations.removeFirst(); mCurrentOperation = mOperations.removeFirst();
} }
// Run in main thread Runnable gattOperationRunnable = new Runnable() {
mHandler.post(new Runnable() { @Override
@Override public void run() {
public void run() { synchronized (mOperations) {
synchronized (mOperations) { if (mCurrentOperation == null) {
if (mCurrentOperation == null) { Log.e(TAG, "Current operation null in executor?");
Log.e(TAG, "Current operation null in executor?"); return;
return; }
}
mCurrentOperation.run(); mCurrentOperation.run();
// now wait for the GATT callback and when it comes, finish this operation // now wait for the GATT callback and when it comes, finish this operation
}
} }
} };
});
if (mCurrentOperation.getDelayMs() == 0) {
// Run in main thread
mHandler.post(gattOperationRunnable);
}
else {
// If we have a delay on this operation, wait before we post it.
mHandler.postDelayed(gattOperationRunnable, mCurrentOperation.getDelayMs());
}
} }
private void queueGattOperation(GattOperation op) { private void queueGattOperation(GattOperation op) {
@@ -397,8 +484,39 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
} }
private void enableNotification(UUID chrUuid) { private void enableNotification(UUID chrUuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid); // Add a 500ms delay to notification write for Amazon Fire TV devices, as otherwise if we do this too quickly after connecting
// it will return success and then silently drop the operation on the floor.
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid, 500);
queueGattOperation(op); queueGattOperation(op);
// Amazon Fire devices can also silently timeout on writeDescriptor, so
// set up a little delayed check that will attempt to write a second time.
//
// While this only seems to be needed on Amazon Fire TV devices at present, it
// doesn't hurt to have a retry on other devices as well.
//
final HIDDeviceBLESteamController finalThis = this;
final UUID finalUuid = chrUuid;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (!finalThis.mHasEnabledNotifications) {
if (finalThis.mHasSeenInputUpdate) {
// Amazon Five devices may have enabled notifications on the input characteristic and not given us a callback. If we've seen
// input reports, though, somewhat by definition notifications are enabled.
Log.w(TAG, "WriteDescriptor has never returned, but we've seen input reports. Moving on with controller initialization.");
finalThis.mHasEnabledNotifications = true;
finalThis.enableValveMode();
return;
}
// Give one more try.
GattOperation retry = HIDDeviceBLESteamController.GattOperation.enableNotification(finalThis.mGatt, finalUuid, 500);
finalThis.queueGattOperation(retry);
}
}
}, 1000);
} }
void writeCharacteristic(UUID uuid, byte[] value) { void writeCharacteristic(UUID uuid, byte[] value) {
@@ -448,8 +566,16 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
mIsConnected = false; mIsConnected = false;
gatt.disconnect(); gatt.disconnect();
mGatt = connectGatt(false); mGatt = connectGatt(false);
} } else {
else { if (getProductId() == TRITON_BLE_PID) {
// Android will not properly play well with Data Length Extensions without manually requesting a large MTU,
// and Triton controllers require DLE support.
//
// 517 is basically a "magic number" as far as Android's bluetooth code is concerned, so do not change
// this value. It is functionally "please enable data length extensions" on some Android builds.
mGatt.requestMtu(517);
}
probeService(this); probeService(this);
} }
} }
@@ -474,7 +600,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
// Only register controller with the native side once it has been fully configured // Only register controller with the native side once it has been fully configured
if (!isRegistered()) { if (!isRegistered()) {
Log.v(TAG, "Registering Steam Controller with ID: " + getId()); Log.v(TAG, "Registering Steam Controller with ID: " + getId());
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true); mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true, mReportId);
setRegistered(); setRegistered();
} }
} }
@@ -487,7 +613,8 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
// Enable this for verbose logging of controller input reports // Enable this for verbose logging of controller input reports
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue())); //Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
if (characteristic.getUuid().equals(inputCharacteristic) && !mFrozen) { if (characteristic.getUuid().equals(mInputCharacteristic) && !mFrozen) {
mHasSeenInputUpdate = true;
mManager.HIDDeviceInputReport(getId(), characteristic.getValue()); mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
} }
} }
@@ -497,19 +624,36 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
//Log.v(TAG, "onDescriptorRead status=" + status); //Log.v(TAG, "onDescriptorRead status=" + status);
} }
private void enableValveMode()
{
BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null)
return;
BluetoothGattCharacteristic reportChr = valveService.getCharacteristic(reportCharacteristic);
if (reportChr != null) {
if (getProductId() == TRITON_BLE_PID) {
// For Triton we just mark things registered.
Log.v(TAG, "Registering Triton Steam Controller with ID: " + getId());
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0, true, mReportId);
setRegistered();
} else {
// For the original controller, we need to manually enter Valve mode.
Log.v(TAG, "Writing report characteristic to enter valve mode");
reportChr.setValue(enterValveMode);
mGatt.writeCharacteristic(reportChr);
}
}
}
@Override @Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
BluetoothGattCharacteristic chr = descriptor.getCharacteristic(); BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid()); //Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
if (chr.getUuid().equals(inputCharacteristic)) { if (chr.getUuid().equals(mInputCharacteristic)) {
boolean hasWrittenInputDescriptor = true; mHasEnabledNotifications = true;
BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic); enableValveMode();
if (reportChr != null) {
Log.v(TAG, "Writing report characteristic to enter valve mode");
reportChr.setValue(enterValveMode);
gatt.writeCharacteristic(reportChr);
}
} }
finishCurrentGattOperation(); finishCurrentGattOperation();
@@ -548,9 +692,20 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
@Override @Override
public int getProductId() { public int getProductId() {
// We don't have an easy way to query from the Bluetooth device, but we know what it is if (mProductId > 0) {
final int D0G_BLE2_PID = 0x1106; // We've already set a product ID.
return D0G_BLE2_PID; return mProductId;
}
if (mDevice.getName().startsWith("Steam Ctrl")) {
// We're a newer Triton device
mProductId = TRITON_BLE_PID;
} else {
// We're an OG Steam Controller
mProductId = D0G_BLE2_PID;
}
return mProductId;
} }
@Override @Override
@@ -601,10 +756,29 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
writeCharacteristic(reportCharacteristic, actual_report); writeCharacteristic(reportCharacteristic, actual_report);
return report.length; return report.length;
} else { } else {
//Log.v(TAG, "writeOutputReport " + HexDump.dumpHexString(report)); // If we're an original-recipe Steam Controller we just write to the characteristic directly.
writeCharacteristic(reportCharacteristic, report); if (getProductId() == D0G_BLE2_PID) {
return report.length; //Log.v(TAG, "writeOutputReport " + HexDump.dumpHexString(report));
writeCharacteristic(reportCharacteristic, report);
return report.length;
}
// If we're a Triton, we need to find the correct report characteristic.
if (report.length > 0) {
int reportId = report[0] & 0xFF;
BluetoothGattCharacteristic targetedReportCharacteristic = mOutputReportChars.get(reportId);
if (targetedReportCharacteristic != null) {
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
//Log.v(TAG, "writeOutputReport 0x" + Integer.toString(reportId, 16) + " " + HexDump.dumpHexString(report));
writeCharacteristic(targetedReportCharacteristic.getUuid(), actual_report);
return report.length;
} else {
Log.w(TAG, "Got report write request for unknown report type 0x" + Integer.toString(reportId, 16));
}
}
} }
return -1;
} }
@Override @Override
@@ -256,6 +256,7 @@ public class HIDDeviceManager {
0x24c6, // PowerA 0x24c6, // PowerA
0x2c22, // Qanba 0x2c22, // Qanba
0x2dc8, // 8BitDo 0x2dc8, // 8BitDo
0x3537, // GameSir
0x37d7, // Flydigi 0x37d7, // Flydigi
0x9886, // ASTRO Gaming 0x9886, // ASTRO Gaming
}; };
@@ -360,7 +361,7 @@ public class HIDDeviceManager {
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index); HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
int id = device.getId(); int id = device.getId();
mDevicesById.put(id, device); mDevicesById.put(id, device);
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol(), false); HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol(), false, 0);
} }
} }
} }
@@ -529,7 +530,13 @@ public class HIDDeviceManager {
return false; return false;
} }
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0); // Steam Controllers will always support Bluetooth Low Energy
if ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) == 0) {
return false;
}
// Match on the name either the original Steam Controller or the new second-generation one advertise with.
return bluetoothDevice.getName().equals("SteamController") || bluetoothDevice.getName().startsWith("Steam Ctrl");
} }
private void close() { private void close() {
@@ -681,7 +688,7 @@ public class HIDDeviceManager {
private native void HIDDeviceRegisterCallback(); private native void HIDDeviceRegisterCallback();
private native void HIDDeviceReleaseCallback(); private native void HIDDeviceReleaseCallback();
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol, boolean bBluetooth); native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol, boolean bBluetooth, int reportID);
native void HIDDeviceOpenPending(int deviceID); native void HIDDeviceOpenPending(int deviceID);
native void HIDDeviceOpenResult(int deviceID, boolean opened); native void HIDDeviceOpenResult(int deviceID, boolean opened);
native void HIDDeviceDisconnected(int deviceID); native void HIDDeviceDisconnected(int deviceID);
@@ -21,6 +21,7 @@ class HIDDeviceUSB implements HIDDevice {
protected InputThread mInputThread; protected InputThread mInputThread;
protected boolean mRunning; protected boolean mRunning;
protected boolean mFrozen; protected boolean mFrozen;
protected boolean mClaimed;
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) { public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
mManager = manager; mManager = manager;
@@ -29,6 +30,7 @@ class HIDDeviceUSB implements HIDDevice {
mInterface = mDevice.getInterface(mInterfaceIndex).getId(); mInterface = mDevice.getInterface(mInterfaceIndex).getId();
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier()); mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
mRunning = false; mRunning = false;
mClaimed = false;
} }
String getIdentifier() { String getIdentifier() {
@@ -114,6 +116,7 @@ class HIDDeviceUSB implements HIDDevice {
close(); close();
return false; return false;
} }
mClaimed = true;
// Find the endpoints // Find the endpoints
for (int j = 0; j < iface.getEndpointCount(); j++) { for (int j = 0; j < iface.getEndpointCount(); j++) {
@@ -132,9 +135,12 @@ class HIDDeviceUSB implements HIDDevice {
} }
} }
// Make sure the required endpoints were present // Make sure the required endpoints were present. The original Steam Controller and the wireless dongle for it do NOT
if (mInputEndpoint == null || mOutputEndpoint == null) { // actually have -- or require -- output endpoints, so we need to accept only an input one for them or else we'll fall
// back to the Android system gamepad functionality (and lose our paddles et al).
if (mInputEndpoint == null) {
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName()); Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
mConnection.releaseInterface(iface);
close(); close();
return false; return false;
} }
@@ -154,6 +160,11 @@ class HIDDeviceUSB implements HIDDevice {
return -1; return -1;
} }
if (!mClaimed) {
Log.w(TAG, "writeReport() called but some other process currently owns the USB device");
return -1;
}
if (feature) { if (feature) {
int res = -1; int res = -1;
int offset = 0; int offset = 0;
@@ -185,6 +196,11 @@ class HIDDeviceUSB implements HIDDevice {
} }
return length; return length;
} else { } else {
if (mOutputEndpoint == null)
{
Log.e(TAG, "Tried to write an output report to an interface with no output endpoint!");
return -1;
}
int res = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000); int res = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
if (res != report.length) { if (res != report.length) {
Log.w(TAG, "writeOutputReport() returned " + res + " on device " + getDeviceName()); Log.w(TAG, "writeOutputReport() returned " + res + " on device " + getDeviceName());
@@ -205,6 +221,12 @@ class HIDDeviceUSB implements HIDDevice {
Log.w(TAG, "readReport() called with no device connection"); Log.w(TAG, "readReport() called with no device connection");
return false; return false;
} }
if (!mClaimed) {
if (feature) {
return false;
}
return true;
}
if (report_number == 0x0) { if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID /* Offset the return buffer by 1, so that the report ID
@@ -258,10 +280,13 @@ class HIDDeviceUSB implements HIDDevice {
mInputThread = null; mInputThread = null;
} }
if (mConnection != null) { if (mConnection != null) {
UsbInterface iface = mDevice.getInterface(mInterfaceIndex); if (mClaimed) {
mConnection.releaseInterface(iface); UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
mConnection.releaseInterface(iface);
}
mConnection.close(); mConnection.close();
mConnection = null; mConnection = null;
mClaimed = false;
} }
} }
@@ -274,6 +299,22 @@ class HIDDeviceUSB implements HIDDevice {
@Override @Override
public void setFrozen(boolean frozen) { public void setFrozen(boolean frozen) {
mFrozen = frozen; mFrozen = frozen;
/* If we have a valid device connection and the claim state doesn't match what we want, try to correct that. */
if (mConnection != null && mClaimed == mFrozen) {
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
if (frozen) {
mClaimed = !mConnection.releaseInterface(iface);
if (mClaimed) {
Log.e(TAG, "Tried to release claim on USB device, but failed!");
}
} else {
mClaimed = mConnection.claimInterface(iface, true);
if (!mClaimed) {
Log.e(TAG, "Tried to regain claim on USB device, but failed!");
}
}
}
} }
protected class InputThread extends Thread { protected class InputThread extends Thread {
@@ -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 = 8; private static final int SDL_MICRO_VERSION = 10;
/* /*
// Display InputType.SOURCE/CLASS of events and devices // Display InputType.SOURCE/CLASS of events and devices
// //
@@ -530,7 +530,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (mHIDDeviceManager != null) { if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(true); mHIDDeviceManager.setFrozen(true);
} }
if (!mHasMultiWindow) { if (!mHasMultiWindow) {
pauseNativeThread(); pauseNativeThread();
} }
@@ -543,7 +544,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (mHIDDeviceManager != null) { if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(false); mHIDDeviceManager.setFrozen(false);
} }
if (!mHasMultiWindow) { if (!mHasMultiWindow) {
resumeNativeThread(); resumeNativeThread();
} }
@@ -616,6 +618,14 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
super.onWindowFocusChanged(hasFocus); super.onWindowFocusChanged(hasFocus);
Log.v(TAG, "onWindowFocusChanged(): " + hasFocus); Log.v(TAG, "onWindowFocusChanged(): " + hasFocus);
// If we are gaining focus, we can always try to restore our USB devices. If we are losing focus,
// only try to relinquish them if we don't have background events allowed (for multi-window Android setups).
if (hasFocus || !SDLActivity.nativeGetHintBoolean("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", false)) {
if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(!hasFocus);
}
}
if (SDLActivity.mBrokenLibraries) { if (SDLActivity.mBrokenLibraries) {
return; return;
} }
@@ -1481,11 +1491,11 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) { if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
// Note that we process events with specific key codes here // Note that we process events with specific key codes here
if (event.getAction() == KeyEvent.ACTION_DOWN) { if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (SDLControllerManager.onNativePadDown(deviceId, keyCode)) { if (SDLControllerManager.onNativePadDown(deviceId, keyCode, event.getScanCode())) {
return true; return true;
} }
} else if (event.getAction() == KeyEvent.ACTION_UP) { } else if (event.getAction() == KeyEvent.ACTION_UP) {
if (SDLControllerManager.onNativePadUp(deviceId, keyCode)) { if (SDLControllerManager.onNativePadUp(deviceId, keyCode, event.getScanCode())) {
return true; return true;
} }
} }
@@ -1963,7 +1973,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
Intent i = new Intent(Intent.ACTION_VIEW); Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url)); i.setData(Uri.parse(url));
int flags = Intent.FLAG_ACTIVITY_NO_HISTORY int flags = Intent.FLAG_ACTIVITY_NO_HISTORY
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
| Intent.FLAG_ACTIVITY_NEW_DOCUMENT; | Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
i.addFlags(flags); i.addFlags(flags);
@@ -2227,3 +2237,4 @@ class SDLClipboardHandler implements
SDLActivity.onNativeClipboardChanged(); SDLActivity.onNativeClipboardChanged();
} }
} }
@@ -10,6 +10,10 @@ import android.hardware.lights.Light;
import android.hardware.lights.LightsRequest; import android.hardware.lights.LightsRequest;
import android.hardware.lights.LightsManager; import android.hardware.lights.LightsManager;
import android.hardware.lights.LightState; import android.hardware.lights.LightState;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build; import android.os.Build;
import android.os.VibrationEffect; import android.os.VibrationEffect;
@@ -30,16 +34,18 @@ public class SDLControllerManager
static native void nativeAddJoystick(int device_id, String name, String desc, static native void nativeAddJoystick(int device_id, String name, String desc,
int vendor_id, int product_id, int vendor_id, int product_id,
int button_mask, int button_mask,
int naxes, int axis_mask, int nhats, boolean can_rumble, boolean has_rgb_led); int naxes, int axis_mask, int nhats, boolean can_rumble, boolean has_rgb_led,
boolean has_accelerometer, boolean has_gyroscope);
static native void nativeRemoveJoystick(int device_id); static native void nativeRemoveJoystick(int device_id);
static native void nativeAddHaptic(int device_id, String name); static native void nativeAddHaptic(int device_id, String name);
static native void nativeRemoveHaptic(int device_id); static native void nativeRemoveHaptic(int device_id);
static public native boolean onNativePadDown(int device_id, int keycode); static public native boolean onNativePadDown(int device_id, int keycode, int scancode);
static public native boolean onNativePadUp(int device_id, int keycode); static public native boolean onNativePadUp(int device_id, int keycode, int scancode);
static native void onNativeJoy(int device_id, int axis, static native void onNativeJoy(int device_id, int axis,
float value); float value);
static native void onNativeHat(int device_id, int hat_id, static native void onNativeHat(int device_id, int hat_id,
int x, int y); int x, int y);
static native void onNativeJoySensor(int device_id, int sensor_type, long sensor_timestamp, float x, float y, float z);
protected static SDLJoystickHandler mJoystickHandler; protected static SDLJoystickHandler mJoystickHandler;
protected static SDLHapticHandler mHapticHandler; protected static SDLHapticHandler mHapticHandler;
@@ -81,6 +87,13 @@ public class SDLControllerManager
mJoystickHandler.setLED(device_id, red, green, blue); mJoystickHandler.setLED(device_id, red, green, blue);
} }
/**
* This method is called by SDL using JNI.
*/
static void joystickSetSensorsEnabled(int device_id, boolean enabled) {
mJoystickHandler.setSensorsEnabled(device_id, enabled);
}
/** /**
* This method is called by SDL using JNI. * This method is called by SDL using JNI.
*/ */
@@ -153,6 +166,10 @@ class SDLJoystickHandler {
ArrayList<InputDevice.MotionRange> hats; ArrayList<InputDevice.MotionRange> hats;
ArrayList<Light> lights; ArrayList<Light> lights;
LightsManager.LightsSession lightsSession; LightsManager.LightsSession lightsSession;
SensorManager sensorManager;
SDLJoySensorListener sensorListener;
Sensor accelerometerSensor;
Sensor gyroscopeSensor;
} }
static class RangeComparator implements Comparator<InputDevice.MotionRange> { static class RangeComparator implements Comparator<InputDevice.MotionRange> {
@Override @Override
@@ -225,12 +242,13 @@ class SDLJoystickHandler {
joystick.desc = getJoystickDescriptor(joystickDevice); joystick.desc = getJoystickDescriptor(joystickDevice);
joystick.axes = new ArrayList<InputDevice.MotionRange>(); joystick.axes = new ArrayList<InputDevice.MotionRange>();
joystick.hats = new ArrayList<InputDevice.MotionRange>(); joystick.hats = new ArrayList<InputDevice.MotionRange>();
java.util.Set<Integer> axisStrsSet = new java.util.HashSet<Integer>();
joystick.lights = new ArrayList<Light>(); joystick.lights = new ArrayList<Light>();
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges(); List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator()); Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges) { for (InputDevice.MotionRange range : ranges) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { if (((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) && axisStrsSet.add(range.getAxis())) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joystick.hats.add(range); joystick.hats.add(range);
} else { } else {
@@ -241,6 +259,8 @@ class SDLJoystickHandler {
boolean can_rumble = false; boolean can_rumble = false;
boolean has_rgb_led = false; boolean has_rgb_led = false;
boolean has_accelerometer = false;
boolean has_gyroscope = false;
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) { if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
VibratorManager vibratorManager = joystickDevice.getVibratorManager(); VibratorManager vibratorManager = joystickDevice.getVibratorManager();
int[] vibrators = vibratorManager.getVibratorIds(); int[] vibrators = vibratorManager.getVibratorIds();
@@ -258,12 +278,26 @@ class SDLJoystickHandler {
joystick.lightsSession = lightsManager.openSession(); joystick.lightsSession = lightsManager.openSession();
has_rgb_led = true; has_rgb_led = true;
} }
SensorManager sensorManager = joystickDevice.getSensorManager();
if (sensorManager != null) {
joystick.sensorManager = sensorManager;
joystick.sensorListener = new SDLJoySensorListener(joystick.device_id);
joystick.accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (joystick.accelerometerSensor != null) {
has_accelerometer = true;
}
joystick.gyroscopeSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
if (joystick.gyroscopeSensor != null) {
has_gyroscope = true;
}
}
} }
mJoysticks.add(joystick); mJoysticks.add(joystick);
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
getVendorId(joystickDevice), getProductId(joystickDevice), getVendorId(joystickDevice), getProductId(joystickDevice),
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led); getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led,
has_accelerometer, has_gyroscope);
} }
} }
} }
@@ -508,6 +542,31 @@ class SDLJoystickHandler {
} }
joystick.lightsSession.requestLights(lightsRequest.build()); joystick.lightsSession.requestLights(lightsRequest.build());
} }
void setSensorsEnabled(int device_id, boolean enabled) {
if (Build.VERSION.SDK_INT < 31 /* Android 12.0 (S) */) {
return;
}
SDLJoystick joystick = getJoystick(device_id);
if (joystick == null || joystick.sensorManager == null) {
return;
}
if (enabled) {
if (joystick.accelerometerSensor != null) {
SDLSensorManager.registerListener(joystick.sensorManager, joystick.sensorListener, joystick.accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
}
if (joystick.gyroscopeSensor != null) {
SDLSensorManager.registerListener(joystick.sensorManager, joystick.sensorListener, joystick.gyroscopeSensor, SensorManager.SENSOR_DELAY_GAME);
}
} else {
if (joystick.accelerometerSensor != null) {
SDLSensorManager.unregisterListener(joystick.sensorManager, joystick.sensorListener, joystick.accelerometerSensor);
}
if (joystick.gyroscopeSensor != null) {
SDLSensorManager.unregisterListener(joystick.sensorManager, joystick.sensorListener, joystick.gyroscopeSensor);
}
}
}
} }
class SDLHapticHandler_API31 extends SDLHapticHandler { class SDLHapticHandler_API31 extends SDLHapticHandler {
@@ -933,3 +992,19 @@ class SDLGenericMotionListener_API29 extends SDLGenericMotionListener_API26 {
return penDevice.isExternal() ? SDL_PEN_DEVICE_TYPE_INDIRECT : SDL_PEN_DEVICE_TYPE_DIRECT; return penDevice.isExternal() ? SDL_PEN_DEVICE_TYPE_INDIRECT : SDL_PEN_DEVICE_TYPE_DIRECT;
} }
} }
class SDLJoySensorListener implements SensorEventListener {
int device_id;
public SDLJoySensorListener(int device_id) {
this.device_id = device_id;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
@Override
public void onSensorChanged(SensorEvent event) {
SDLControllerManager.onNativeJoySensor(device_id, event.sensor.getType(), event.timestamp, event.values[0], event.values[1], event.values[2]);
}
}
@@ -0,0 +1,32 @@
package org.libsdl.app;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
// This class coordinates synchronized access to sensor manager registration
//
// This prevents a java.util.ConcurrentModificationException exception on
// Android 16, specifically on the Samsung Tab S9 Ultra.
class SDLSensorManager
{
static private SDLSensorManager mManager = new SDLSensorManager();
public static void registerListener(SensorManager manager, SensorEventListener listener, Sensor sensor, int samplingPeriodUs) {
mManager.RegisterListener(manager, listener, sensor, samplingPeriodUs);
}
public static void unregisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor) {
mManager.UnregisterListener(manager, listener, sensor);
}
private synchronized void RegisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor, int samplingPeriodUs) {
manager.registerListener(listener, sensor, samplingPeriodUs, null);
}
private synchronized void UnregisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor) {
manager.unregisterListener(listener, sensor);
}
}
@@ -47,6 +47,9 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// Is SurfaceView ready for rendering // Is SurfaceView ready for rendering
protected boolean mIsSurfaceReady; protected boolean mIsSurfaceReady;
// Is on-screen keyboard visible
protected boolean mKeyboardVisible;
// Pinch events // Pinch events
private final ScaleGestureDetector scaleGestureDetector; private final ScaleGestureDetector scaleGestureDetector;
@@ -213,6 +216,18 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
WindowInsets.Type.displayCutout()); WindowInsets.Type.displayCutout());
SDLActivity.onNativeInsetsChanged(combined.left, combined.right, combined.top, combined.bottom); SDLActivity.onNativeInsetsChanged(combined.left, combined.right, combined.top, combined.bottom);
if (insets.isVisible(WindowInsets.Type.ime())) {
if (!mKeyboardVisible) {
mKeyboardVisible = true;
SDLActivity.onNativeScreenKeyboardShown();
}
} else {
if (mKeyboardVisible) {
mKeyboardVisible = false;
SDLActivity.onNativeScreenKeyboardHidden();
}
}
} }
// Pass these to any child views in case they need them // Pass these to any child views in case they need them
@@ -318,11 +333,11 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
protected void enableSensor(int sensortype, boolean enabled) { protected void enableSensor(int sensortype, boolean enabled) {
// TODO: This uses getDefaultSensor - what if we have >1 accels? // TODO: This uses getDefaultSensor - what if we have >1 accels?
if (enabled) { if (enabled) {
mSensorManager.registerListener(this, SDLSensorManager.registerListener(mSensorManager, this,
mSensorManager.getDefaultSensor(sensortype), mSensorManager.getDefaultSensor(sensortype),
SensorManager.SENSOR_DELAY_GAME, null); SensorManager.SENSOR_DELAY_GAME);
} else { } else {
mSensorManager.unregisterListener(this, SDLSensorManager.unregisterListener(mSensorManager, this,
mSensorManager.getDefaultSensor(sensortype)); mSensorManager.getDefaultSensor(sensortype));
} }
} }
+53 -3
View File
@@ -16,11 +16,12 @@ body {
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
align-items: stretch; align-items: stretch;
z-index: 1; z-index: 2;
pointer-events: none; pointer-events: none;
} }
fps, fps,
pipeline-progress,
toast { toast {
position: absolute; position: absolute;
border: 1dp #92875B; border: 1dp #92875B;
@@ -98,7 +99,7 @@ toast message row.muted {
opacity: 0.5; opacity: 0.5;
} }
toast progress { progress {
height: 4dp; height: 4dp;
position: absolute; position: absolute;
left: 0; left: 0;
@@ -106,10 +107,50 @@ toast progress {
width: 100%; width: 100%;
} }
toast progress fill { progress fill {
background-color: rgba(194, 164, 45, 80%); background-color: rgba(194, 164, 45, 80%);
} }
pipeline-progress {
left: 12dp;
bottom: 12dp;
display: flex;
flex-flow: column;
z-index: 100;
min-width: 260dp;
max-width: 90%;
padding: 10dp 16dp 12dp;
border-radius: 7dp;
overflow: hidden;
filter: opacity(0);
transition: filter 0.2s linear-in-out;
pointer-events: none;
}
pipeline-progress[open] {
filter: opacity(1);
}
pipeline-status {
display: flex;
align-items: center;
gap: 8dp;
font-size: 18dp;
font-weight: normal;
white-space: nowrap;
}
icon.pipeline-spinner {
width: 1.2em;
height: 1.2em;
line-height: 1.2em;
font-size: 1.2em;
color: #C2A42D;
text-align: center;
transform-origin: center;
animation: 1s linear infinite pipeline-spinner-spin;
}
toast.achievement { toast.achievement {
border: 1dp #C2A42D; border: 1dp #C2A42D;
} }
@@ -310,6 +351,15 @@ logo img.outer {
} }
} }
@keyframes pipeline-spinner-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (max-height: 640dp) { @media (max-height: 640dp) {
toast { toast {
top: 20dp; top: 20dp;
+339
View File
@@ -0,0 +1,339 @@
*, *:before, *:after {
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
font-family: "Fira Sans Condensed";
font-weight: bold;
color: rgba(248, 244, 232, 90%);
z-index: 1;
filter: opacity(0);
transition: filter 0.2s linear-in-out;
}
body[open] {
filter: opacity(1);
}
body:not([open]) {
pointer-events: none;
}
button {
display: flex;
align-items: center;
justify-content: center;
decorator: none;
padding: 0;
border: 1dp rgba(255, 255, 255, 22%);
background-color: rgba(22, 24, 28, 48%);
color: rgba(248, 244, 232, 90%);
text-align: center;
/* backdrop-filter: blur(7dp); */
/* box-shadow: 0 6dp 18dp rgba(0, 0, 0, 28%); */
transform-origin: center;
transition: background-color border-color filter transform 0.08s linear-in-out,
opacity 0.2s linear-in-out;
}
button.pressed,
button.active {
background-color: rgba(63, 78, 90, 68%);
border-color: rgba(255, 255, 255, 48%);
filter: brightness(1.18);
}
button:hidden {
opacity: 0;
pointer-events: none;
}
button span {
display: block;
line-height: 1;
}
button icon {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
button icon glyph {
display: block;
font-family: "Material Symbols Rounded";
font-weight: normal;
font-size: 24dp;
line-height: 1;
}
.midna-icon,
.item-icon,
.item-count,
.oil-meter {
display: none;
}
.midna-icon.visible,
.item-icon.visible,
.item-count.visible,
.oil-meter.visible {
display: block;
}
.control {
position: absolute;
}
.trigger-l.active {
background-color: rgba(57, 116, 133, 74%);
border-color: rgba(128, 222, 234, 72%);
}
.trigger,
.skip {
border-radius: 23dp;
}
.trigger {
font-size: 22dp;
}
.button-z {
background-color: rgba(118, 79, 158, 58%);
border-color: rgba(203, 170, 255, 36%);
}
.midna-icon {
position: absolute;
left: 9dp;
top: -1dp;
height: 48dp;
}
.button-z.has-icon span,
.face.has-item span {
position: absolute;
font-size: 13dp;
line-height: 1;
}
.button-z.has-icon span {
right: 9dp;
bottom: 7dp;
}
.button-z.pressed {
background-color: rgba(139, 91, 187, 82%);
border-color: rgba(220, 194, 255, 70%);
}
action-bar {
position: absolute;
display: flex;
align-items: center;
border: 1dp rgba(255, 255, 255, 22%);
border-radius: 23dp;
background-color: rgba(22, 24, 28, 48%);
/* backdrop-filter: blur(7dp); */
/* box-shadow: 0 -6dp 18dp rgba(0, 0, 0, 28%); */
overflow: hidden;
opacity: 1;
transform-origin: center;
transition: opacity 0.2s linear-in-out;
}
action-bar:hidden,
action-bar:hidden button,
action-bar:hidden separator {
opacity: 0;
pointer-events: none;
}
.utility {
position: relative;
flex: 1 1 auto;
width: 56dp;
height: 44dp;
margin: 0;
border-width: 0dp;
border-radius: 0;
background-color: transparent;
box-shadow: none;
}
.utility,
.skip {
opacity: 0.55;
}
.utility.pressed {
background-color: rgba(63, 78, 90, 68%);
}
.utility.pressed,
.skip.pressed {
opacity: 1;
}
.skip {
z-index: 1;
border-color: rgba(255, 255, 255, 36%);
}
separator {
display: block;
flex: 0 0 1dp;
width: 1dp;
height: 24dp;
background-color: rgba(255, 255, 255, 18%);
opacity: 1;
transition: opacity 0.2s linear-in-out;
}
.face {
position: absolute;
border-radius: 29dp;
font-size: 24dp;
overflow: visible;
}
.item-icon {
width: auto;
height: auto;
max-width: 76%;
max-height: 76%;
}
.item-count {
position: absolute;
left: 6dp;
bottom: 5dp;
min-width: 17dp;
height: 15dp;
padding: 1dp 3dp;
border-radius: 7dp;
background-color: rgba(0, 0, 0, 52%);
color: rgba(255, 255, 255, 92%);
font-size: 12dp;
line-height: 13dp;
text-align: center;
}
.oil-meter {
position: absolute;
left: 12dp;
bottom: -5dp;
width: 34dp;
height: 8dp;
padding: 2dp;
border: 1dp rgba(42, 32, 18, 82%);
border-radius: 4dp;
background-color: rgba(18, 14, 10, 70%);
/* box-shadow: 0 2dp 6dp rgba(0, 0, 0, 35%); */
}
oil-fill {
display: block;
width: 0%;
height: 100%;
border-radius: 2dp;
background-color: rgb(255, 232, 74);
}
.face.has-item span {
right: 6dp;
bottom: 6dp;
color: rgba(255, 255, 255, 88%);
}
.face.a {
border-radius: 37dp;
font-size: 31dp;
background-color: rgba(34, 112, 123, 62%);
}
.face.b {
background-color: rgba(161, 61, 66, 58%);
}
.face.x {
background-color: rgba(83, 115, 151, 56%);
}
.face.y {
background-color: rgba(113, 91, 150, 54%);
}
button.control.docked-top,
action-bar.docked-top {
border-top-width: 0dp;
border-top-left-radius: 0dp;
border-top-right-radius: 0dp;
}
button.control.docked-bottom,
action-bar.docked-bottom {
border-bottom-width: 0dp;
border-bottom-left-radius: 0dp;
border-bottom-right-radius: 0dp;
}
button.control.docked-left,
action-bar.docked-left {
border-left-width: 0dp;
border-top-left-radius: 0dp;
border-bottom-left-radius: 0dp;
}
button.control.docked-right,
action-bar.docked-right {
border-right-width: 0dp;
border-top-right-radius: 0dp;
border-bottom-right-radius: 0dp;
}
touch-stick {
display: block;
position: absolute;
width: 124dp;
height: 124dp;
border-radius: 62dp;
background-color: rgba(18, 20, 24, 35%);
border: 1dp rgba(255, 255, 255, 20%);
/* backdrop-filter: blur(7dp); */
/* box-shadow: 0 8dp 24dp rgba(0, 0, 0, 24%); */
opacity: 0;
pointer-events: none;
transition: opacity 0.18s linear-in-out;
}
touch-stick.active {
opacity: 1;
}
stick-ring {
position: absolute;
left: 18dp;
top: 18dp;
width: 88dp;
height: 88dp;
border-radius: 44dp;
border: 1dp rgba(255, 255, 255, 18%);
}
stick-knob {
position: absolute;
width: 48dp;
height: 48dp;
border-radius: 24dp;
background-color: rgba(238, 236, 226, 55%);
border: 1dp rgba(255, 255, 255, 45%);
}
+138
View File
@@ -0,0 +1,138 @@
body.touch-editor {
background-color: rgba(4, 6, 8, 34%);
z-index: 8;
}
body.touch-editor .control,
body.touch-editor action-bar {
opacity: 0.88;
cursor: move;
pointer-events: auto;
}
body.touch-editor .control:hover,
body.touch-editor action-bar:hover,
body.touch-editor .control.editor-selected,
body.touch-editor action-bar.editor-selected {
border-color: rgba(255, 232, 128, 80%);
filter: brightness(1.15);
}
body.touch-editor action-bar button,
body.touch-editor action-bar separator {
pointer-events: none;
}
selection-frame {
display: none;
position: absolute;
z-index: 20;
border: 2dp rgba(255, 232, 128, 88%);
background-color: rgba(255, 232, 128, 7%);
pointer-events: none;
}
selection-frame.visible {
display: block;
}
resize-handle {
display: block;
position: absolute;
width: 22dp;
height: 22dp;
border: 2dp rgba(255, 244, 190, 96%);
border-radius: 11dp;
background-color: rgba(34, 37, 42, 86%);
pointer-events: auto;
}
resize-handle.left {
left: -12dp;
}
resize-handle.right {
right: -12dp;
}
resize-handle.top {
top: -12dp;
}
resize-handle.bottom {
bottom: -12dp;
}
resize-handle.horizontal {
top: 50%;
margin-top: -11dp;
}
resize-handle.vertical {
left: 50%;
margin-left: -11dp;
}
resize-handle.corner.left {
left: -12dp;
}
resize-handle.corner.right {
right: -12dp;
}
resize-handle.corner.top {
top: -12dp;
}
resize-handle.corner.bottom {
bottom: -12dp;
}
editor-toolbar {
display: flex;
position: absolute;
left: 24dp;
right: 24dp;
top: 50%;
z-index: 30;
height: 48dp;
margin-top: -24dp;
gap: 8dp;
justify-content: center;
pointer-events: auto;
}
editor-toolbar button.editor-command {
flex: 0 1 150dp;
min-width: 96dp;
height: 48dp;
padding: 0 14dp;
border-radius: 8dp;
border: 1dp rgba(255, 255, 255, 26%);
background-color: rgba(17, 19, 24, 88%);
color: rgba(255, 250, 232, 94%);
font-family: "Fira Sans";
font-size: 18dp;
line-height: 48dp;
opacity: 1;
cursor: pointer;
}
editor-toolbar button.editor-command span {
display: block;
width: 100%;
line-height: 48dp;
text-align: center;
}
editor-toolbar button.editor-command.primary {
border-color: rgba(255, 232, 128, 70%);
background-color: rgba(96, 82, 38, 90%);
}
editor-toolbar button.editor-command:hover,
editor-toolbar button.editor-command:focus-visible {
border-color: rgba(255, 244, 190, 92%);
background-color: rgba(78, 85, 96, 92%);
}
+1 -1
View File
@@ -22,7 +22,7 @@
#include "os_report.h" #include "os_report.h"
Z2SoundObjBase::Z2SoundObjBase() Z2SoundObjBase::Z2SoundObjBase()
#if DEBUG #if PARTIAL_DEBUG || DEBUG
: JSULink<Z2SoundObjBase>(this) : JSULink<Z2SoundObjBase>(this)
#endif #endif
{ {
+10
View File
@@ -175,3 +175,13 @@ bool daAlink_c::checkAimContext() {
return false; return false;
} }
} }
bool daAlink_c::checkAimInputContext() {
switch (mProcID) {
case PROC_HOOKSHOT_ROOF_WAIT:
case PROC_HOOKSHOT_WALL_WAIT:
return false;
default:
return checkAimContext();
}
}
+33 -13
View File
@@ -14,6 +14,7 @@
#include "dusk/action_bindings.h" #include "dusk/action_bindings.h"
#include "dusk/gyro.h" #include "dusk/gyro.h"
#include "dusk/mouse.h" #include "dusk/mouse.h"
#include "dusk/touch_camera.h"
#endif #endif
bool daAlink_c::checkNoSubjectModeCamera() { bool daAlink_c::checkNoSubjectModeCamera() {
@@ -121,18 +122,11 @@ BOOL daAlink_c::setBodyAngleToCamera() {
var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c); var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c);
} }
#if TARGET_PC shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f)));
if (dusk::getSettings().game.enableMouseAim && checkAimContext()) { sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f)));
sp8 = mBodyAngle.x;
} else
#endif
{
shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f)));
sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f)));
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) { if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
sp8 = mBodyAngle.x; sp8 = mBodyAngle.x;
}
} }
} else { } else {
sp8 = mBodyAngle.x; sp8 = mBodyAngle.x;
@@ -141,7 +135,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
#if TARGET_PC #if TARGET_PC
if ((dusk::getSettings().game.enableGyroAim || if ((dusk::getSettings().game.enableGyroAim ||
dusk::getSettings().game.enableMouseAim) && dusk::getSettings().game.enableMouseAim) &&
checkAimContext()) checkAimInputContext())
{ {
f32 gyro_scale = 1.0f; f32 gyro_scale = 1.0f;
if (checkWolfEyeUp()) { if (checkWolfEyeUp()) {
@@ -155,7 +149,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
f32 final_yaw = 0.f; f32 final_yaw = 0.f;
f32 final_pitch = 0.f; f32 final_pitch = 0.f;
if (dusk::getSettings().game.enableMouseAim) { if (dusk::getSettings().game.enableMouseAim) {
dusk::mouse::getAimDeltas(final_yaw, final_pitch); dusk::mouse::get_aim_deltas(final_yaw, final_pitch);
} }
if (dusk::getSettings().game.enableGyroAim) { if (dusk::getSettings().game.enableGyroAim) {
f32 gyro_yaw = 0.f; f32 gyro_yaw = 0.f;
@@ -172,6 +166,32 @@ BOOL daAlink_c::setBodyAngleToCamera() {
sp8 = mBodyAngle.x; sp8 = mBodyAngle.x;
} }
} }
if (dusk::getSettings().game.enableTouchControls && checkAimInputContext()) {
f32 touchYawDp = 0.0f;
f32 touchPitchDp = 0.0f;
if (dusk::touch_camera::consume_delta(touchYawDp, touchPitchDp)) {
f32 scale = 1.0f;
if (checkWolfEyeUp()) {
scale *= 0.6f;
}
if (dComIfGp_checkPlayerStatus0(0, 0x200000)) {
scale /= dComIfGp_getCameraZoomScale(field_0x317c);
}
const f32 yawDeg = -touchYawDp * dusk::touch_camera::YAW_DEGREES_PER_DP * scale *
dusk::getSettings().game.touchCameraXSensitivity;
const f32 pitchDeg = touchPitchDp * dusk::touch_camera::PITCH_DEGREES_PER_DP *
scale * dusk::getSettings().game.touchCameraYSensitivity;
shape_angle.y = shape_angle.y + cM_deg2s(yawDeg);
sp8 = sp8 + cM_deg2s(pitchDeg);
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
sp8 = mBodyAngle.x;
}
}
}
#endif #endif
if (checkNotItemSinkLimit() && sp8 > 0) { if (checkNotItemSinkLimit() && sp8 > 0) {
+22 -3
View File
@@ -11,6 +11,7 @@
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#if TARGET_PC #if TARGET_PC
#include <aurora/texture.hpp>
#include "dusk/dvd_asset.hpp" #include "dusk/dvd_asset.hpp"
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
@@ -40,6 +41,8 @@ static f32* l_texCoord_get() { alignas(32) static f32 buf[338]; static bool _
//#define l_pos (l_pos_get()) //#define l_pos (l_pos_get())
#define l_normal (l_normal_get()) #define l_normal (l_normal_get())
#define l_texCoord (l_texCoord_get()) #define l_texCoord (l_texCoord_get())
static bool l_Egnd_mantTEX_hasReplacement = false;
#else #else
#include "assets/l_Egnd_mantTEX.h" #include "assets/l_Egnd_mantTEX.h"
@@ -223,6 +226,7 @@ void daMant_packet_c::draw() {
GXInitTexObjCI( GXInitTexObjCI(
&undersideTexObj, l_Egnd_mantTEX_U, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0); &undersideTexObj, l_Egnd_mantTEX_U, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0);
GXInitTexObjLOD(&undersideTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); GXInitTexObjLOD(&undersideTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1);
l_Egnd_mantTEX_hasReplacement = aurora::texture::has_replacement(&mainTexObj, &tlutObj);
textureObjsInitialized = true; textureObjsInitialized = true;
} }
#else #else
@@ -636,7 +640,11 @@ static int daMant_Execute(mant_class* i_this) {
iVar8 = 0; iVar8 = 0;
if (i_this->field_0x3967 != 0) { if (i_this->field_0x3967 != 0) {
#if TARGET_PC
mant_cut_type = l_Egnd_mantTEX_hasReplacement ? 1 : i_this->field_0x3967;
#else
mant_cut_type = i_this->field_0x3967; mant_cut_type = i_this->field_0x3967;
#endif
if (i_this->field_0x3968 < 15) { if (i_this->field_0x3968 < 15) {
i_this->field_0x3968++; i_this->field_0x3968++;
@@ -648,9 +656,18 @@ static int daMant_Execute(mant_class* i_this) {
iVar8 = 20; iVar8 = 20;
} }
unaff_r29 = cM_rndF(65536.0f); #if TARGET_PC
var_f31 = cM_rndFX(32.0f); if (l_Egnd_mantTEX_hasReplacement) {
var_f30 = cM_rndFX(32.0f); unaff_r29 = i_this->mMantRng.getF(65536.0f);
var_f31 = i_this->mMantRng.getFX(32.0f);
var_f30 = i_this->mMantRng.getFX(32.0f);
} else
#endif
{
unaff_r29 = cM_rndF(65536.0f);
var_f31 = cM_rndFX(32.0f);
var_f30 = cM_rndFX(32.0f);
}
} }
i_this->field_0x3967 = 0; i_this->field_0x3967 = 0;
@@ -760,6 +777,8 @@ static int daMant_Create(fopAc_ac_c* i_this) {
if(textureObjsInitialized) { if(textureObjsInitialized) {
GXInitTlutObjData(&tlutObj, l_Egnd_mantPAL); // make sure the cached textures are updated GXInitTlutObjData(&tlutObj, l_Egnd_mantPAL); // make sure the cached textures are updated
} }
m_this->mMantRng.init(66, 16983, 855);
#endif #endif
lbl_277_bss_0 = 0; lbl_277_bss_0 = 0;
+10
View File
@@ -6882,6 +6882,16 @@ static int daNpc_Ks_Delete(npc_ks_class* i_this) {
i_this->model->stopZelAnime(); i_this->model->stopZelAnime();
} }
#if TARGET_PC
if (leader == i_this) {
leader = NULL;
}
if (saru_p[i_this->set_id] == i_this) {
saru_p[i_this->set_id] = NULL;
}
#endif
return 1; return 1;
} }
+378
View File
@@ -15,6 +15,12 @@ const u16 l_J_Ohana00_64TEX__height = 63;
using GameVersion = dusk::version::GameVersion; using GameVersion = dusk::version::GameVersion;
static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9060}, {GameVersion::GcnPal, 0x9060}}, 0x800), true); return buf; } static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9060}, {GameVersion::GcnPal, 0x9060}}, 0x800), true); return buf; }
#define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get()) #define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get())
// from d_grass.inc
static MtxP get_model_mtx(Mtx modelMtx, Mtx storage);
static void transform_positions(
const dusk::batch::LeafTemplate& tpl, const Vec* posArray, const Mtx mtx, Vec* xfPos);
static void split_batch(u32& emitted, u32 vtxCount);
#else #else
#include "assets/l_J_Ohana00_64TEX.h" #include "assets/l_J_Ohana00_64TEX.h"
#endif #endif
@@ -588,6 +594,12 @@ dFlower_packet_c::dFlower_packet_c() {
GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX, GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX,
l_J_Ohana01_64128_0419TEX__width + 1, l_J_Ohana01_64128_0419TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE l_J_Ohana01_64128_0419TEX__width + 1, l_J_Ohana01_64128_0419TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
); );
dusk::batch::decode_leaf_template(l_J_hana00DL, 0x140, mTplHana00);
dusk::batch::decode_leaf_template(l_J_hana00_cDL, 0xC0, mTplHana00Cut);
dusk::batch::decode_leaf_template(l_J_hana01DL, 0x120, mTplHana01);
dusk::batch::decode_leaf_template(l_J_hana01_c_00DL, 0xC0, mTplHana01Cut00);
dusk::batch::decode_leaf_template(l_J_hana01_c_01DL, 0x120, mTplHana01Cut);
#endif #endif
m_deleteRoom = &dFlower_packet_c::deleteRoom; m_deleteRoom = &dFlower_packet_c::deleteRoom;
@@ -597,6 +609,371 @@ dFlower_packet_c::dFlower_packet_c() {
#endif #endif
} }
#if TARGET_PC
static void batch_setup_tev(u32 lightMask) {
GXSetCullMode(GX_CULL_NONE);
GXSetNumChans(2);
GXSetChanCtrl(GX_COLOR0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
GXSetChanCtrl(GX_COLOR1, GX_TRUE, GX_SRC_VTX, GX_SRC_REG, lightMask, GX_DF_CLAMP, GX_AF_SPOT);
GXSetNumTevStages(3);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR1A1);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_CPREV, GX_CC_RASC, GX_CC_ZERO);
GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE2, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV, GX_CC_C0);
GXSetTevColorOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_4, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE2, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
GXSetTevAlphaOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
}
static GXColor hana00_amb_color(const dFlower_data_c* flower, const dKy_tevstr_c* tevstr) {
GXColor amb = {0, 0, 0, 0xFF};
if (DEBUG && g_kankyoHIO.navy.grass_adjust_ON != 0) {
amb.r = g_kankyoHIO.navy.grass_ambcol.r * 2;
amb.g = g_kankyoHIO.navy.grass_ambcol.g * 2;
amb.b = g_kankyoHIO.navy.grass_ambcol.b * 2;
} else {
amb.r = (flower->field_0x04 & 0x1F) * 2;
amb.g = ((flower->field_0x04 >> 5) & 0x1F) * 2;
amb.b = ((flower->field_0x04 >> 0xA) & 0x1F) * 2;
}
if (daPy_py_c::checkNowWolfPowerUp()) {
f32 ambRate = g_env_light.bg_amb_col[0].r / 255.0f;
f32 col = (((flower->field_0x04 & 0x1F) * 2 + 0x10));
amb.r = col * (ambRate * 4.0f);
ambRate = g_env_light.bg_amb_col[0].g / 255.0f;
f32 col2 = (((flower->field_0x04 >> 5) & 0x1F) * 2 + 0x10);
amb.g = col2 * (4.0f * ambRate);
ambRate = g_env_light.bg_amb_col[0].b / 255.0f;
f32 col3 = (((flower->field_0x04 >> 10) & 0x1F) * 2 + 0x10);
amb.b = col3 * (4.0f * ambRate);
}
if (amb.r == 0x3E) {
amb.r = tevstr->AmbCol.r;
}
if (amb.g == 0x3E) {
amb.g = tevstr->AmbCol.g;
}
if (amb.b == 0x3E) {
amb.b = tevstr->AmbCol.b;
}
return amb;
}
static GXColor hana01_amb_color(int idx, const dKy_tevstr_c* tevstr) {
f32 rRate = tevstr->AmbCol.r * 0.03125f;
if (rRate > 1.0f) {
rRate = 1.0f;
}
f32 gRate = tevstr->AmbCol.g * 0.03125f;
if (gRate > 1.0f) {
gRate = 1.0f;
}
f32 bRate = tevstr->AmbCol.b * 0.03125f;
if (bRate > 1.0f) {
bRate = 1.0f;
}
GXColor amb = {1, 1, 1, 1};
GXColor sub;
sub.r = -0.4f * tevstr->AmbCol.r * rRate;
sub.g = -0.4f * tevstr->AmbCol.g * gRate;
sub.b = -0.4f * tevstr->AmbCol.b * bRate;
switch (idx & 7) {
case 0:
amb.r = tevstr->AmbCol.r + sub.r;
amb.g = tevstr->AmbCol.g;
amb.b = tevstr->AmbCol.b;
break;
case 1:
amb.r = tevstr->AmbCol.r;
amb.g = tevstr->AmbCol.g + sub.g;
amb.b = tevstr->AmbCol.b;
break;
case 2:
amb.r = tevstr->AmbCol.r;
amb.g = tevstr->AmbCol.g;
amb.b = tevstr->AmbCol.b + sub.b;
break;
case 3:
amb.r = tevstr->AmbCol.r + sub.r;
amb.g = tevstr->AmbCol.g + sub.g;
amb.b = tevstr->AmbCol.b;
break;
case 4:
amb.r = tevstr->AmbCol.r;
amb.g = tevstr->AmbCol.g + sub.g;
amb.b = tevstr->AmbCol.b + sub.b;
break;
case 5:
amb.r = tevstr->AmbCol.r + sub.r;
amb.g = tevstr->AmbCol.g;
amb.b = tevstr->AmbCol.b + sub.b;
break;
case 6:
amb.r = tevstr->AmbCol.r + sub.r;
amb.g = tevstr->AmbCol.g + sub.g;
amb.b = tevstr->AmbCol.b + sub.b;
break;
case 7:
break;
}
if (daPy_py_c::checkNowWolfPowerUp()) {
f32 ambRate = g_env_light.bg_amb_col[0].r / 255.0f;
amb.r = (amb.r + 8) * (6.0f * ambRate);
ambRate = g_env_light.bg_amb_col[0].g / 255.0f;
amb.g = (amb.g + 8) * (6.0f * ambRate);
ambRate = g_env_light.bg_amb_col[0].b / 255.0f;
amb.b = (amb.b + 8) * (6.0f * ambRate);
}
amb.a = 0xFF;
return amb;
}
static void flower_emit(const dusk::batch::LeafTemplate& tpl, const Vec* xformedPos, GXColor amb) {
for (u32 i = 0; i < tpl.vtxCount; i++) {
const dusk::batch::LeafTemplate::Vtx& v = tpl.vtx[i];
const Vec& p = xformedPos[v.pos];
GXPosition3f32(p.x, p.y, p.z);
GXNormal1x8(v.nrm);
GXColor1x8(v.clr);
GXColor4u8(amb.r, amb.g, amb.b, amb.a);
GXTexCoord1x8(v.tex);
}
}
void dFlower_packet_c::draw() {
ZoneScoped;
dScnKy_env_light_c* kankyo = dKy_getEnvlight();
j3dSys.reinitGX();
GXSetNumIndStages(0);
dKy_setLight_again();
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);
GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR1, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSETARRAY(GX_VA_POS, &l_flowerPos, sizeof(l_flowerPos), sizeof(Vec), true);
GXSETARRAY(GX_VA_NRM, &l_flowerNormal, sizeof(l_flowerNormal), sizeof(Vec), true);
GXSETARRAY(GX_VA_CLR0, &l_flowerColor, sizeof(l_flowerColor), sizeof(GXColor), true);
GXSETARRAY(GX_VA_TEX0, &l_flowerTexCoord, sizeof(l_flowerTexCoord), 8, true);
static GXVtxDescList vtxDescList[] = {
{GX_VA_POS, GX_DIRECT},
{GX_VA_NRM, GX_INDEX8},
{GX_VA_CLR0, GX_INDEX8},
{GX_VA_CLR1, GX_DIRECT},
{GX_VA_TEX0, GX_INDEX8},
{GX_VA_NULL, GX_NONE},
};
static Vec xfPos[256];
Mtx identity;
MTXIdentity(identity);
// --- hana00 ---
for (int i = 0; i < 64; i++) {
dFlower_data_c* first = m_room[i].getData();
if (first == nullptr || !dComIfGp_roomControl_checkStatusFlag(i, 0x10)) {
continue;
}
dKy_tevstr_c* tevstr = dComIfGp_roomControl_getTevStr(i);
int lightCount = 6;
if (dComIfGp_roomControl_getStatusRoomDt(i) != nullptr) {
lightCount = dComIfGp_roomControl_getStatusRoomDt(i)->getLightVecInfoNum();
}
if (dKy_SunMoon_Light_Check() && lightCount < 2) {
lightCount = 2;
}
for (int j = 0; j < 6; j++) {
if (kankyo->field_0x0c18[j].field_0x26 == 1) {
lightCount++;
}
}
if (lightCount <= 2) {
GXCallDisplayList(l_matLight4DL, 0x80);
} else {
GXCallDisplayList(l_matDL, 0x80);
}
GXSetTevColorS10(GX_TEVREG0, {0, 0, 0, 0});
dKy_Global_amb_set(tevstr);
dKy_GxFog_tevstr_set(tevstr);
dKy_setLight_nowroom_grass(tevstr->room_no, 1.0f);
GXLoadTexObj(&mTexObj_l_J_Ohana00_64TEX, GX_TEXMAP0);
batch_setup_tev(lightCount <= 2 ? (GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 | GX_LIGHT4) :
(GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 | GX_LIGHT4 |
GX_LIGHT5 | GX_LIGHT6 | GX_LIGHT7));
GXSetVtxDescv(vtxDescList);
GXLoadPosMtxImm(identity, GX_PNMTX0);
GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0);
for (int bucket = 0; bucket < 2; bucket++) {
const bool cut = bucket != 0;
const dusk::batch::LeafTemplate& tpl = cut ? mTplHana00Cut : mTplHana00;
bool open = false;
u32 emitted = 0;
for (dFlower_data_c* flower = first; flower != nullptr; flower = flower->mp_next) {
if (cLib_checkBit<u8>(flower->m_state, 4) ||
cLib_checkBit<u8>(flower->m_state, 0x40))
{
continue;
}
if ((cLib_checkBit<u8>(flower->m_state, 8) != 0) != cut) {
continue;
}
if (!open) {
GXBegin(GX_TRIANGLES, GX_VTXFMT1, GX_AUTO);
open = true;
}
split_batch(emitted, tpl.vtxCount);
Mtx interpMtx;
MtxP mtx = get_model_mtx(flower->m_modelMtx, interpMtx);
transform_positions(tpl, reinterpret_cast<Vec*>(l_flowerPos), mtx, xfPos);
flower_emit(tpl, xfPos, hana00_amb_color(flower, tevstr));
}
if (open) {
GXEnd();
}
}
}
// --- hana01 ---
GXSETARRAY(GX_VA_POS, mp_pos, sizeof(l_flowerPos2), sizeof(Vec), true);
GXSETARRAY(GX_VA_NRM, &l_flowerNormal2, sizeof(l_flowerNormal2), sizeof(Vec), true);
GXSETARRAY(GX_VA_CLR0, mp_colors, sizeof(l_flowerColor2), sizeof(GXColor), true);
GXSETARRAY(GX_VA_TEX0, mp_texCoords, sizeof(l_flowerTexCoord2), 8, true);
for (int i = 0; i < 64; i++) {
dFlower_data_c* first = m_room[i].getData();
if (first == NULL) {
continue;
}
dKy_tevstr_c* tevstr = dComIfGp_roomControl_getTevStr(i);
int lightCount = 6;
if (dComIfGp_roomControl_getStatusRoomDt(i) != NULL) {
lightCount = dComIfGp_roomControl_getStatusRoomDt(i)->getLightVecInfoNum();
}
#if DEBUG
if (g_kankyoHIO.light.m_HOSTIO_setting != 0) {
lightCount = g_kankyoHIO.dungeonLight.usedLights;
}
#endif
if (dKy_SunMoon_Light_Check() == TRUE && lightCount < 2) {
lightCount = 2;
}
if (lightCount <= 2) {
GXCallDisplayList(mp_mat2Light4DL, m_mat2Light4DL_size);
} else {
GXCallDisplayList(mp_mat2DL, m_mat2DL_size);
}
GXSetTevColorS10(GX_TEVREG0, {0, 0, 0, 0});
dKy_Global_amb_set(tevstr);
dKy_GxFog_tevstr_set(tevstr);
dKy_setLight_nowroom_grass(tevstr->room_no, 1.0f);
GXLoadTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, GX_TEXMAP0);
batch_setup_tev(lightCount <= 2 ? (GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 | GX_LIGHT4) :
(GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 | GX_LIGHT4 |
GX_LIGHT5 | GX_LIGHT6 | GX_LIGHT7));
GXSetVtxDescv(vtxDescList);
GXLoadPosMtxImm(identity, GX_PNMTX0);
GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0);
const dusk::batch::LeafTemplate* const buckets[3] = {
&mTplHana01, &mTplHana01Cut00, &mTplHana01Cut};
for (int bucket = 0; bucket < 3; bucket++) {
const dusk::batch::LeafTemplate& tpl = *buckets[bucket];
bool open = false;
u32 emitted = 0;
int idx = 0;
for (dFlower_data_c* flower = first; flower != NULL; flower = flower->mp_next, idx++) {
if (cLib_checkBit<u8>(flower->m_state, 4) ||
!cLib_checkBit<u8>(flower->m_state, 0x40))
{
continue;
}
const int flowerBucket = cLib_checkBit<u8>(flower->m_state, 8) ? 2 :
cLib_checkBit<u8>(flower->m_state, 0x10) ? 1 :
0;
if (flowerBucket != bucket) {
continue;
}
if (!open) {
GXBegin(GX_TRIANGLES, GX_VTXFMT1, GX_AUTO);
open = true;
}
split_batch(emitted, tpl.vtxCount);
Mtx interpMtx;
MtxP mtx = get_model_mtx(flower->m_modelMtx, interpMtx);
transform_positions(tpl, mp_pos, mtx, xfPos);
flower_emit(tpl, xfPos, hana01_amb_color(idx, tevstr));
}
if (open) {
GXEnd();
}
}
}
GXSetNumTevStages(1);
GXSetNumChans(1);
J3DShape::resetVcdVatCache();
}
#else
void dFlower_packet_c::draw() { void dFlower_packet_c::draw() {
ZoneScoped; ZoneScoped;
dScnKy_env_light_c* kankyo = dKy_getEnvlight(); dScnKy_env_light_c* kankyo = dKy_getEnvlight();
@@ -886,6 +1263,7 @@ void dFlower_packet_c::draw() {
J3DShape::resetVcdVatCache(); J3DShape::resetVcdVatCache();
} }
#endif
void dFlower_packet_c::calc() { void dFlower_packet_c::calc() {
dFlower_anm_c* anm_p = getAnm(); dFlower_anm_c* anm_p = getAnm();
+356
View File
@@ -512,11 +512,366 @@ dGrass_packet_c::dGrass_packet_c() {
m_Mkusa_9q_cDL_size = 0xC0; m_Mkusa_9q_cDL_size = 0xC0;
field_0x1d714 = 0; field_0x1d714 = 0;
#if TARGET_PC
dusk::batch::decode_leaf_template(mp_Mkusa_9q_DL, m_Mkusa_9q_DL_size, mTplKusa9q);
dusk::batch::decode_leaf_template(mp_Mkusa_9q_cDL, m_Mkusa_9q_cDL_size, mTplKusa9qCut);
dusk::batch::decode_leaf_template(l_M_TenGusaDL, 0xC0, mTplTengusa);
#endif
OS_REPORT("草群メモリ=%f\n", 117.7734375f); OS_REPORT("草群メモリ=%f\n", 117.7734375f);
m_deleteRoom = &dGrass_packet_c::deleteRoom; m_deleteRoom = &dGrass_packet_c::deleteRoom;
} }
#if TARGET_PC
static MtxP get_model_mtx(Mtx modelMtx, Mtx storage) {
if (dusk::frame_interp::lookup_replacement(modelMtx, storage)) {
cMtx_concat(j3dSys.getViewMtx(), storage, storage);
return storage;
}
return modelMtx;
}
static void transform_positions(
const dusk::batch::LeafTemplate& tpl, const Vec* posArray, const Mtx mtx, Vec* xfPos) {
for (u32 i = 0; i < tpl.posRefCount; i++) {
const u8 idx = tpl.posRefs[i];
MTXMultVec(mtx, &posArray[idx], &xfPos[idx]);
}
}
static void split_batch(u32& emitted, u32 vtxCount) {
if (emitted + vtxCount > 0xFFFF) {
GXEnd();
GXBegin(GX_TRIANGLES, GX_VTXFMT1, GX_AUTO);
emitted = 0;
}
emitted += vtxCount;
}
static GXColor blade_amb_color(const dGrass_data_c* blade, const dKy_tevstr_c* tevstr) {
GXColor amb;
amb.a = 0;
#if DEBUG
if (g_kankyoHIO.navy.grass_adjust_ON) {
amb.r = g_kankyoHIO.navy.grass_ambcol.r * 2;
amb.g = g_kankyoHIO.navy.grass_ambcol.g * 2;
amb.b = g_kankyoHIO.navy.grass_ambcol.b * 2;
return amb;
}
#endif
amb.r = (blade->m_addCol & 0x1F) * 2;
amb.g = ((blade->m_addCol >> 5) & 0x1F) * 2;
amb.b = ((blade->m_addCol >> 0xA) & 0x1F) * 2;
if (daPy_py_c::checkNowWolfPowerUp()) {
f32 ambRate = g_env_light.bg_amb_col[0].r / 255.0f;
f32 col = (((blade->m_addCol & 0x1F) * 2 + 0x10));
amb.r = col * (ambRate * 4.0f);
ambRate = g_env_light.bg_amb_col[0].g / 255.0f;
f32 col2 = (((blade->m_addCol >> 5) & 0x1F) * 2 + 0x10);
amb.g = col2 * (4.0f * ambRate);
ambRate = g_env_light.bg_amb_col[0].b / 255.0f;
f32 col3 = (((blade->m_addCol >> 10) & 0x1F) * 2 + 0x10);
amb.b = col3 * (4.0f * ambRate);
}
f32 roomAmbScale = 1.0f - (static_cast<int>(blade->m_pos.x) & 0xFF) * 0.001953125f;
f32 colScale = 1.1f - (static_cast<u8>(static_cast<int>(blade->m_pos.x)) & 0xFF) / 2000.0f;
colScale -= (static_cast<int>(blade->m_pos.z) & 0xFF) / 2000.0f;
if (colScale > 1.0f) {
colScale = 1.0f;
}
if (amb.r == 0x3E) {
amb.r = tevstr->AmbCol.r * roomAmbScale;
} else {
amb.r = amb.r * colScale;
}
if (amb.g == 0x3E) {
amb.g = tevstr->AmbCol.g * roomAmbScale;
} else {
amb.g = amb.g * colScale;
}
if (amb.b == 0x3E) {
amb.b = tevstr->AmbCol.b * roomAmbScale;
} else {
amb.b = amb.b * colScale;
}
return amb;
}
static void blade_emit(const dusk::batch::LeafTemplate& tpl, const Vec* xformedPos,
const GXColor* colors, GXColor amb) {
for (u32 i = 0; i < tpl.vtxCount; i++) {
const dusk::batch::LeafTemplate::Vtx& v = tpl.vtx[i];
const Vec& p = xformedPos[v.pos];
GXPosition3f32(p.x, p.y, p.z);
GXNormal1x8(v.nrm);
GXColor4u8(amb.r, amb.g, amb.b, colors[v.clr].a);
GXTexCoord1x8(v.tex);
}
}
void dGrass_packet_c::draw() {
ZoneScoped;
dScnKy_env_light_c* kankyo = dKy_getEnvlight();
j3dSys.reinitGX();
GXSetNumIndStages(0);
dKy_setLight_again();
GXClearVtxDesc();
static GXVtxDescList l_vtxDescList[] = {
{GX_VA_POS, GX_INDEX8},
{GX_VA_NRM, GX_INDEX8},
{GX_VA_CLR0, GX_INDEX8},
{GX_VA_TEX0, GX_INDEX8},
{GX_VA_NULL, GX_NONE},
};
static GXVtxDescList l_batchVtxDescList[] = {
{GX_VA_POS, GX_DIRECT},
{GX_VA_NRM, GX_INDEX8},
{GX_VA_CLR0, GX_DIRECT},
{GX_VA_TEX0, GX_INDEX8},
{GX_VA_NULL, GX_NONE},
};
GXSetVtxDescv(l_vtxDescList);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSETARRAY(GX_VA_POS, mp_pos, sizeof(l_pos), sizeof(Vec), true);
GXSETARRAY(GX_VA_NRM, mp_normal, sizeof(l_normal), sizeof(Vec), true);
GXSETARRAY(GX_VA_CLR0, mp_colors, sizeof(l_color), sizeof(GXColor), true);
GXSETARRAY(GX_VA_TEX0, mp_texCoords, sizeof(l_texCoord), 8, true);
GXColorS10 reg1 = {0, 0, 0, 0};
// daytime "shine" alpha curve (TEVREG1 alpha)
f32 daytime = g_env_light.getDaytime();
f32 ratio;
f32 shine;
if (daytime >= 90.0f && daytime < 135.0f) {
ratio = 1.0f - (0.022222223f * (135.0f - daytime));
shine = 100.0f - (18.0f * ratio);
} else if (daytime >= 135.0f && daytime < 225.0f) {
ratio = 1.0f - (0.011111111f * (225.0f - daytime));
shine = 82.0f - (25.0f * ratio);
} else if (daytime >= 225.0f && daytime < 270.0f) {
ratio = 1.0f - (0.022222223f * (270.0f - daytime));
shine = 57.0f - (-25.0f * ratio);
} else if (daytime >= 270.0f && daytime < 315.0f) {
ratio = (1.0f - (0.022222223f * (315.0f - daytime)));
shine = 82.0f - (-18.0f * ratio);
} else {
shine = 100.0f;
}
#if DEBUG
if (g_kankyoHIO.navy.grass_shine_value != 0.0f) {
shine = g_kankyoHIO.navy.grass_shine_value;
}
#endif
static Vec xfPos[256];
Mtx identity;
PSMTXIdentity(identity);
for (int i = 0; i < 64; i++) {
dGrass_data_c* first = m_room[i].getData();
if (first == NULL || !dComIfGp_roomControl_checkStatusFlag(i, 0x10)) {
continue;
}
int lightCount = 6;
dKy_tevstr_c* tevstr = dComIfGp_roomControl_getTevStr(i);
f32 lightInf = g_env_light.grass_light_inf_rate * g_env_light.bg_light_influence;
lightInf += 0.5f * (1.0f - lightInf);
J3DLightInfo* lightInfo = tevstr->mLights[0].getLightInfo();
reg1.r = lightInfo->mColor.r * lightInf;
reg1.g = lightInfo->mColor.g * lightInf;
reg1.b = lightInfo->mColor.b * lightInf;
reg1.a = shine;
if (memcmp(dComIfGp_getStartStageName(), "D_MN01", 6) == 0) {
reg1.r = 0;
reg1.g = 0x1E;
reg1.b = 5;
reg1.a = 0x50;
}
GFSetTevColorS10(GX_TEVREG1, reg1);
if (dComIfGp_roomControl_getStatusRoomDt(i) != nullptr) {
lightCount = dComIfGp_roomControl_getStatusRoomDt(i)->getLightVecInfoNum();
}
#if DEBUG
if (g_kankyoHIO.light.m_HOSTIO_setting != 0) {
lightCount = g_kankyoHIO.dungeonLight.usedLights;
}
#endif
if (dKy_SunMoon_Light_Check() == TRUE && lightCount < 2) {
lightCount = 2;
}
for (int j = 0; j < 6; j++) {
if (kankyo->field_0x0c18[j].field_0x26 == 1) {
lightCount++;
}
}
// room-level setup
if (first->field_0x05 <= 3 || first->field_0x05 >= 10) {
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
if (lightCount <= 3) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
}
} else {
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
}
GFSetTevColorS10(GX_TEVREG2, {0, 0, 0, 0});
dKy_Global_amb_set(tevstr);
dKy_GfFog_tevstr_set(tevstr);
dKy_setLight_nowroom_grass(tevstr->room_no, 0.0f);
GXSetVtxDescv(l_batchVtxDescList);
GXLoadPosMtxImm(identity, GX_PNMTX0);
GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0);
// buckets: (kusa05 vs tengusa) x (standing vs cut)
bool hasRegrowing = false;
for (int bucket = 0; bucket < 4; bucket++) {
const bool kusaTex = bucket < 2;
const bool cut = (bucket & 1) != 0;
const dusk::batch::LeafTemplate& tpl =
cut ? mTplKusa9qCut : (kusaTex ? mTplKusa9q : mTplTengusa);
bool open = false;
u32 emitted = 0;
for (dGrass_data_c* blade = first; blade != NULL; blade = blade->mp_next) {
if (cLib_checkBit<u8>(blade->field_0x01, 2)) {
continue; // clipped
}
if (blade->field_0x02 < -1) {
hasRegrowing = true;
continue;
}
const bool bladeKusaTex = blade->field_0x05 <= 3 || blade->field_0x05 >= 10;
if (bladeKusaTex != kusaTex || (blade->field_0x02 < 0) != cut) {
continue;
}
if (!open) {
if (kusaTex) {
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
if (lightCount <= 2) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
}
} else {
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
}
// change amb_src to GX_SRC_VTX
const u32 lightMask =
(kusaTex && lightCount <= 2)
? (GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 | GX_LIGHT4)
: (GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 | GX_LIGHT4 | GX_LIGHT5 |
GX_LIGHT6 | GX_LIGHT7);
GXSetChanCtrl(GX_COLOR0, GX_TRUE, GX_SRC_VTX, GX_SRC_REG, lightMask,
GX_DF_CLAMP, GX_AF_SPOT);
reg1.a = cut ? 0 : shine;
GFSetTevColorS10(GX_TEVREG1, reg1);
GXBegin(GX_TRIANGLES, GX_VTXFMT1, GX_AUTO);
open = true;
}
split_batch(emitted, tpl.vtxCount);
Mtx interpMtx;
MtxP mtx = get_model_mtx(blade->m_modelMtx, interpMtx);
transform_positions(tpl, mp_pos, mtx, xfPos);
blade_emit(tpl, xfPos, mp_colors, blade_amb_color(blade, tevstr));
}
if (open) {
GXEnd();
}
}
// regrowing blades have per-blade TEVREG2 alpha
// draw them with the original immediate path
if (hasRegrowing) {
GXSetVtxDescv(l_vtxDescList);
for (dGrass_data_c* blade = first; blade != NULL; blade = blade->mp_next) {
if (blade->field_0x02 >= -1 || cLib_checkBit<u8>(blade->field_0x01, 2)) {
continue;
}
const bool kusaTex = blade->field_0x05 <= 3 || blade->field_0x05 >= 10;
if (kusaTex) {
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
if (lightCount <= 2) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
}
} else {
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
}
reg1.a = 0;
GFSetTevColorS10(GX_TEVREG1, reg1);
GXSetChanAmbColor(GX_COLOR0A0, blade_amb_color(blade, tevstr));
Mtx modelMtx;
GXLoadPosMtxImm(get_model_mtx(blade->m_modelMtx, modelMtx), GX_PNMTX0);
GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0);
GFSetTevColorS10(GX_TEVREG2,
{0, 0, 0, static_cast<s16>(-0x100 - (blade->field_0x02 << 8) / 40)});
if (blade->field_0x02 != -2) {
if (kusaTex) {
GXCallDisplayList(mp_Mkusa_9q_DL, m_Mkusa_9q_DL_size);
} else {
GXCallDisplayList(l_M_TenGusaDL, 0xC0);
}
} else {
GXCallDisplayList(mp_Mkusa_9q_cDL, m_Mkusa_9q_cDL_size);
}
GFSetTevColorS10(GX_TEVREG2, {0, 0, 0, 0});
}
}
}
J3DShape::resetVcdVatCache();
}
#else
void dGrass_packet_c::draw() { void dGrass_packet_c::draw() {
ZoneScoped; ZoneScoped;
dScnKy_env_light_c* kankyo = dKy_getEnvlight(); dScnKy_env_light_c* kankyo = dKy_getEnvlight();
@@ -811,6 +1166,7 @@ void dGrass_packet_c::draw() {
J3DShape::resetVcdVatCache(); J3DShape::resetVcdVatCache();
} }
#endif
void dGrass_packet_c::calc() { void dGrass_packet_c::calc() {
cXyz* temp_r29 = dKyw_get_wind_vec(); cXyz* temp_r29 = dKyw_get_wind_vec();
+47 -8
View File
@@ -34,6 +34,7 @@
#include "dusk/action_bindings.h" #include "dusk/action_bindings.h"
#include "dusk/mouse.h" #include "dusk/mouse.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/touch_camera.h"
#include "imgui.h" #include "imgui.h"
#endif #endif
@@ -7499,6 +7500,15 @@ static constexpr s16 FLYCAM_ROLL_SPEED = 256;
static ImVec2 sFlyCamLastMousePos = {-1.f, -1.f}; static ImVec2 sFlyCamLastMousePos = {-1.f, -1.f};
#if TARGET_PC #if TARGET_PC
static constexpr f32 TOUCH_CAMERA_CSTICK_EXIT_THRESHOLD = 0.05f;
static bool sTouchFreeCameraActive = false;
bool dCamera_c::isAimActive() {
auto* link = daAlink_getAlinkActorClass();
return link != nullptr && link->checkAimInputContext() &&
dComIfGp_checkCameraAttentionStatus(link->field_0x317c, 0x10);
}
bool dCamera_c::executeDebugFlyCam() { bool dCamera_c::executeDebugFlyCam() {
if (!dusk::getSettings().game.debugFlyCam) { if (!dusk::getSettings().game.debugFlyCam) {
if (mDebugFlyCam.initialized) { if (mDebugFlyCam.initialized) {
@@ -7592,6 +7602,10 @@ bool dCamera_c::executeDebugFlyCam() {
sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f}; sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f};
} }
if (dusk::getSettings().game.enableMirrorMode) {
stickX *= -1.0f;
}
f32 verticalDisp = 0.0f; f32 verticalDisp = 0.0f;
if (trigR >= FLYCAM_TRIGGER_DEADZONE) { if (trigR >= FLYCAM_TRIGGER_DEADZONE) {
verticalDisp += trigR; verticalDisp += trigR;
@@ -7640,16 +7654,30 @@ void dCamera_c::deactivateDebugFlyCam() {
mDebugFlyCam.initialized = false; mDebugFlyCam.initialized = false;
} }
bool dCamera_c::canUseFreeCam() {
return dusk::getSettings().game.freeCamera || dusk::getSettings().game.enableMouseCamera;
}
bool dCamera_c::freeCamera() { bool dCamera_c::freeCamera() {
if (canUseFreeCam() && mGear == 1) { f32 touchYawDp = 0.0f;
f32 touchPitchDp = 0.0f;
bool touchCameraMoved = false;
const bool touchControlsEnabled = dusk::getSettings().game.enableTouchControls;
if (touchControlsEnabled && !isAimActive()) {
touchCameraMoved = dusk::touch_camera::consume_delta(touchYawDp, touchPitchDp);
}
if (!touchControlsEnabled ||
mPadInfo.mCStick.mLastValue > TOUCH_CAMERA_CSTICK_EXIT_THRESHOLD)
{
sTouchFreeCameraActive = false;
}
if (touchCameraMoved) {
sTouchFreeCameraActive = true;
}
const bool useFreeCamera = dusk::getSettings().game.freeCamera ||
dusk::getSettings().game.enableMouseCamera || sTouchFreeCameraActive;
if (useFreeCamera && mGear == 1) {
mGear = 0; mGear = 0;
} }
if (!canUseFreeCam() || mCamStyle == 70) if (!useFreeCamera || mCamStyle == 70)
{ {
mCamParam.mManualMode = 0; mCamParam.mManualMode = 0;
return false; return false;
@@ -7660,6 +7688,17 @@ bool dCamera_c::freeCamera() {
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree(); mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
} }
if (touchCameraMoved) {
mCamParam.mManualMode = 1;
const f32 yawInput = dusk::getSettings().game.invertCameraXAxis ? -touchYawDp : touchYawDp;
const f32 pitchInput =
touchPitchDp * (dusk::getSettings().game.invertCameraYAxis ? -1.0f : 1.0f);
mCamParam.freeXAngle += yawInput * dusk::getSettings().game.touchCameraXSensitivity *
dusk::touch_camera::YAW_DEGREES_PER_DP;
mCamParam.freeYAngle += pitchInput * dusk::getSettings().game.touchCameraYSensitivity *
dusk::touch_camera::PITCH_DEGREES_PER_DP;
}
cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f}; cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f};
f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY); f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY);
@@ -7677,7 +7716,7 @@ bool dCamera_c::freeCamera() {
f32 yaw_rad = 0.0f; f32 yaw_rad = 0.0f;
f32 pitch_rad = 0.0f; f32 pitch_rad = 0.0f;
dusk::mouse::getCameraDeltas(yaw_rad, pitch_rad); dusk::mouse::get_camera_deltas(yaw_rad, pitch_rad);
if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) && if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) &&
!dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8)) !dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8))
{ {
@@ -11359,7 +11398,7 @@ static int camera_execute(camera_process_class* i_this) {
const auto target = get_target_trim_height(i_this); const auto target = get_target_trim_height(i_this);
const auto step = dusk::frame_interp::get_interpolation_step(); const auto step = dusk::frame_interp::get_interpolation_step();
const auto cur = camera->TrimHeight(); const auto cur = camera->TrimHeight();
const auto prev = (4.0f * cur - target) / 3.0f; const auto prev = (4.0f * cur - target) / 3.0f;
const auto trim_height = prev + (cur - prev) * step; const auto trim_height = prev + (cur - prev) * step;
widezoom_correction(i_this, trim_height); widezoom_correction(i_this, trim_height);
+325
View File
@@ -23,8 +23,22 @@
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include <cstring> #include <cstring>
#if TARGET_PC
#include "dusk/menu_pointer.h"
#include "dusk/string.hpp" #include "dusk/string.hpp"
namespace {
constexpr u8 pointer_target(u8 group, u8 index) noexcept {
return static_cast<u8>((group << 4) | (index & 0x0F));
}
constexpr u8 s_pointerDataSelectTarget = 0;
constexpr u8 s_pointerMenuSelectTarget = 1;
constexpr u8 s_pointerCopySelectTarget = 2;
constexpr u8 s_pointerYesNoSelectTarget = 3;
} // namespace
#endif
static s32 SelStartFrameTbl[3] = { static s32 SelStartFrameTbl[3] = {
59, 59,
99, 99,
@@ -756,8 +770,147 @@ void dFile_select_c::dataSelectInit() {
} }
} }
#if TARGET_PC
bool dFile_select_c::pointerDataSelect() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
for (u8 i = 0; i < 3; ++i) {
if (!dusk::menu_pointer::hit_pane(mSelFilePanes[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerDataSelectTarget, i));
const bool clicked = dusk::menu_pointer::consume_click();
if (mSelectNum != i) {
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
mLastSelectNum = mSelectNum;
mSelectNum = i;
if (clicked) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerDataSelectTarget, i));
}
dataSelectAnmSet();
mDataSelProc = DATASELPROC_DATA_SELECT_MOVE_ANIME;
return true;
}
if (clicked) {
dataSelectStart();
return true;
}
}
return false;
}
bool dFile_select_c::pointerMenuSelect() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
for (u8 i = 0; i < 3; ++i) {
if (!dusk::menu_pointer::hit_pane(m3mSelPane[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerMenuSelectTarget, i));
const bool clicked = dusk::menu_pointer::consume_click();
if (!mIsDataNew[mSelectNum] && mSelectMenuNum != i) {
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
mLastSelectMenuNum = mSelectMenuNum;
mSelectMenuNum = i;
if (clicked) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerMenuSelectTarget, i));
}
menuSelectAnmSet();
mDataSelProc = DATASELPROC_MENU_SELECT_MOVE_ANM;
return true;
}
if (clicked) {
menuSelectStart();
return true;
}
}
return false;
}
bool dFile_select_c::pointerCopyDataToSelect() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
for (u8 i = 0; i < 2; ++i) {
if (!dusk::menu_pointer::hit_pane(mCpSelPane[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerCopySelectTarget, i));
const bool clicked = dusk::menu_pointer::consume_click();
if (field_0x026b != i) {
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
field_0x026c = field_0x026b;
field_0x026b = i;
if (clicked) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerCopySelectTarget, i));
}
copyDataToSelectMoveAnmSet();
mDataSelProc = DATASELPROC_COPY_DATA_TO_SELECT_MOVE_ANM;
return true;
}
if (clicked) {
copyDataToSelectStart();
return true;
}
}
return false;
}
bool dFile_select_c::pointerYesNoSelect(bool errorSelect) {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
for (u8 i = 0; i < 2; ++i) {
if (!dusk::menu_pointer::hit_pane(mYnSelPane[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, i));
const bool clicked =
(!errorSelect || field_0x0268 == i) && dusk::menu_pointer::consume_click();
if (field_0x0268 != i) {
field_0x0269 = field_0x0268;
field_0x0268 = i;
if (errorSelect) {
errCurMove(0);
return false;
} else {
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
if (clicked) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerYesNoSelectTarget, i));
}
yesnoSelectAnmSet();
mDataSelProc = DATASELPROC_YES_NO_CURSOR_MOVE_ANM;
return true;
}
}
if (clicked) {
if (errorSelect) {
if (field_0x0268 != 0) {
mDoAud_seStart(Z2SE_SY_CURSOR_OK, 0, 0, 0);
} else {
mDoAud_seStart(Z2SE_SY_CURSOR_CANCEL, 0, 0, 0);
}
mSelIcon->setAlphaRate(0.0f);
} else {
yesNoSelectStart();
}
return true;
}
}
return false;
}
#endif
// handles switching between quest logs // handles switching between quest logs
void dFile_select_c::dataSelect() { void dFile_select_c::dataSelect() {
#if TARGET_PC
if (pointerDataSelect()) {
return;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
// If A or Start was pressed // If A or Start was pressed
@@ -801,6 +954,9 @@ static u16 msgTbl[3] = {
}; };
void dFile_select_c::dataSelectStart() { void dFile_select_c::dataSelectStart() {
#if TARGET_PC
dusk::menu_pointer::clear_deferred_activation(dusk::menu_pointer::Context::FileSelect);
#endif
mSelIcon->setAlphaRate(0.0f); mSelIcon->setAlphaRate(0.0f);
if (mIsNoData[mSelectNum]) { if (mIsNoData[mSelectNum]) {
@@ -949,6 +1105,17 @@ void dFile_select_c::dataSelectAnmSet() {
} }
void dFile_select_c::dataSelectMoveAnime() { void dFile_select_c::dataSelectMoveAnime() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
if (mSelectNum != 0xFF && dusk::menu_pointer::hit_pane(mSelFilePanes[mSelectNum], 8.0f)) {
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerDataSelectTarget, mSelectNum));
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerDataSelectTarget, mSelectNum));
}
}
#endif
bool iVar7 = true; bool iVar7 = true;
bool iVar6 = true; bool iVar6 = true;
bool bVar1 = true; bool bVar1 = true;
@@ -997,6 +1164,14 @@ void dFile_select_c::dataSelectMoveAnime() {
mSelFilePanes[mLastSelectNum]->getPanePtr()->setAnimation((J2DAnmTransform*)NULL); mSelFilePanes[mLastSelectNum]->getPanePtr()->setAnimation((J2DAnmTransform*)NULL);
} }
#if TARGET_PC
if (dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerDataSelectTarget, mSelectNum))) {
dataSelectStart();
return;
}
#endif
mDataSelProc = DATASELPROC_DATA_SELECT; mDataSelProc = DATASELPROC_DATA_SELECT;
} }
} }
@@ -1161,6 +1336,12 @@ void dFile_select_c::selectDataOpenEraseMove() {
// Handles selecting between copy / start / delete menus in quest log // Handles selecting between copy / start / delete menus in quest log
void dFile_select_c::menuSelect() { void dFile_select_c::menuSelect() {
#if TARGET_PC
if (pointerMenuSelect()) {
return;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
// if a was pressed, do the menu selection process // if a was pressed, do the menu selection process
@@ -1191,6 +1372,9 @@ void dFile_select_c::menuSelect() {
// Handles copy / start / delete actions depending on which menu is selected from menuSelect // Handles copy / start / delete actions depending on which menu is selected from menuSelect
void dFile_select_c::menuSelectStart() { void dFile_select_c::menuSelectStart() {
#if TARGET_PC
dusk::menu_pointer::clear_deferred_activation(dusk::menu_pointer::Context::FileSelect);
#endif
#if TARGET_PC #if TARGET_PC
if (!dusk::getSettings().game.hideTvSettingsScreen || mSelectMenuNum != 1) { if (!dusk::getSettings().game.hideTvSettingsScreen || mSelectMenuNum != 1) {
mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0); mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0);
@@ -1312,6 +1496,19 @@ void dFile_select_c::menuSelectAnmSet() {
} }
void dFile_select_c::menuSelectMoveAnm() { void dFile_select_c::menuSelectMoveAnm() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
if (mSelectMenuNum != 0xFF &&
dusk::menu_pointer::hit_pane(m3mSelPane[mSelectMenuNum], 8.0f))
{
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerMenuSelectTarget, mSelectMenuNum));
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerMenuSelectTarget, mSelectMenuNum));
}
}
#endif
bool tmp1 = true; bool tmp1 = true;
if (mSelectMenuNum != 0xFF && if (mSelectMenuNum != 0xFF &&
@@ -1369,6 +1566,14 @@ void dFile_select_c::menuSelectMoveAnm() {
m3mSelPane[mLastSelectMenuNum]->getPanePtr()->setAnimation((J2DAnmTransform*)NULL); m3mSelPane[mLastSelectMenuNum]->getPanePtr()->setAnimation((J2DAnmTransform*)NULL);
} }
#if TARGET_PC
if (dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerMenuSelectTarget, mSelectMenuNum))) {
menuSelectStart();
return;
}
#endif
mDataSelProc = DATASELPROC_MENU_SELECT; mDataSelProc = DATASELPROC_MENU_SELECT;
} }
} }
@@ -1698,6 +1903,12 @@ void dFile_select_c::setSaveDataForCopySel() {
} }
void dFile_select_c::copyDataToSelect() { void dFile_select_c::copyDataToSelect() {
#if TARGET_PC
if (pointerCopyDataToSelect()) {
return;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
if (mDoCPd_c::getTrigA(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1)) {
@@ -1722,6 +1933,9 @@ void dFile_select_c::copyDataToSelect() {
} }
void dFile_select_c::copyDataToSelectStart() { void dFile_select_c::copyDataToSelectStart() {
#if TARGET_PC
dusk::menu_pointer::clear_deferred_activation(dusk::menu_pointer::Context::FileSelect);
#endif
mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0); mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0);
mCpDataToNum = getCptoNum(field_0x026b); mCpDataToNum = getCptoNum(field_0x026b);
@@ -1787,6 +2001,19 @@ void dFile_select_c::copyDataToSelectMoveAnmSet() {
} }
void dFile_select_c::copyDataToSelectMoveAnm() { void dFile_select_c::copyDataToSelectMoveAnm() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
if (field_0x026b != 0xFF &&
dusk::menu_pointer::hit_pane(mCpSelPane[field_0x026b], 8.0f))
{
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerCopySelectTarget, field_0x026b));
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerCopySelectTarget, field_0x026b));
}
}
#endif
bool iVar7 = true; bool iVar7 = true;
bool iVar6 = true; bool iVar6 = true;
bool bVar1 = true; bool bVar1 = true;
@@ -1836,6 +2063,14 @@ void dFile_select_c::copyDataToSelectMoveAnm() {
mSelIcon2->setAlphaRate(1.0f); mSelIcon2->setAlphaRate(1.0f);
} }
#if TARGET_PC
if (dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerCopySelectTarget, field_0x026b))) {
copyDataToSelectStart();
return;
}
#endif
mDataSelProc = DATASELPROC_COPY_DATA_TO_SELECT; mDataSelProc = DATASELPROC_COPY_DATA_TO_SELECT;
} }
} }
@@ -2105,6 +2340,12 @@ void dFile_select_c::yesnoCursorShow() {
} }
void dFile_select_c::YesNoSelect() { void dFile_select_c::YesNoSelect() {
#if TARGET_PC
if (pointerYesNoSelect(false)) {
return;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
if (mDoCPd_c::getTrigA(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1)) {
@@ -2129,6 +2370,9 @@ void dFile_select_c::YesNoSelect() {
} }
void dFile_select_c::yesNoSelectStart() { void dFile_select_c::yesNoSelectStart() {
#if TARGET_PC
dusk::menu_pointer::clear_deferred_activation(dusk::menu_pointer::Context::FileSelect);
#endif
if (field_0x0268 != 0) { if (field_0x0268 != 0) {
mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0); mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0);
field_0x03b1 = 1; field_0x03b1 = 1;
@@ -2284,10 +2528,31 @@ void dFile_select_c::YesNoCancelMove() {
} }
void dFile_select_c::yesNoCursorMoveAnm() { void dFile_select_c::yesNoCursorMoveAnm() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
if (field_0x0268 != 0xFF &&
dusk::menu_pointer::hit_pane(mYnSelPane[field_0x0268], 8.0f))
{
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, field_0x0268));
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerYesNoSelectTarget, field_0x0268));
}
}
#endif
bool isYnSelMove = yesnoSelectMoveAnm(); bool isYnSelMove = yesnoSelectMoveAnm();
bool isYnWakuAlpha = yesnoWakuAlpahAnm(field_0x0269); bool isYnWakuAlpha = yesnoWakuAlpahAnm(field_0x0269);
if (isYnSelMove == true && isYnWakuAlpha == true) { if (isYnSelMove == true && isYnWakuAlpha == true) {
yesnoCursorShow(); yesnoCursorShow();
#if TARGET_PC
if (dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::FileSelect,
pointer_target(s_pointerYesNoSelectTarget, field_0x0268))) {
yesNoSelectStart();
return;
}
#endif
mDataSelProc = DATASELPROC_YES_NO_SELECT; mDataSelProc = DATASELPROC_YES_NO_SELECT;
} }
} }
@@ -4238,6 +4503,11 @@ static MemCardCheckFuncT MemCardCheckProc[] = {
&dFile_select_c::MemCardErrYesNoCursorMoveAnm, &dFile_select_c::MemCardErrYesNoCursorMoveAnm,
&dFile_select_c::MemCardSaveDataClear, &dFile_select_c::MemCardSaveDataClear,
#if TARGET_PC
&dFile_select_c::MemCardAutoMakeGameFile,
&dFile_select_c::MemCardAutoMakeGameFileErrWait,
#endif
#if PLATFORM_WII || PLATFORM_SHIELD #if PLATFORM_WII || PLATFORM_SHIELD
&dFile_select_c::nandStatCheck, &dFile_select_c::nandStatCheck,
&dFile_select_c::gameFileInitSel, &dFile_select_c::gameFileInitSel,
@@ -4321,11 +4591,33 @@ void dFile_select_c::MemCardStatCheck() {
mDoMemCd_Load(); mDoMemCd_Load();
mCardCheckProc = MEMCARDCHECKPROC_LOAD_WAIT; mCardCheckProc = MEMCARDCHECKPROC_LOAD_WAIT;
break; break;
#if TARGET_PC
case 1: { // no save file
if (dusk::getSettings().game.instantSaves) {
field_0x03b1 = 1;
setInitSaveData();
dataSave();
mCardCheckProc = MEMCARDCHECKPROC_AUTO_MAKE_GAMEFILE;
} else {
errDispInitSet(22, 0);
field_0x0280 = true;
mNextCardCheckProc = MEMCARDCHECKPROC_MAKE_GAMEFILE_SEL;
}
break;
}
case 4: // card is writing
if (dusk::getSettings().game.instantSaves) {
field_0x03b1 = 1;
mCardCheckProc = MEMCARDCHECKPROC_AUTO_MAKE_GAMEFILE;
}
break;
#else
case 1: case 1:
errDispInitSet(22, 0); errDispInitSet(22, 0);
field_0x0280 = true; field_0x0280 = true;
mNextCardCheckProc = MEMCARDCHECKPROC_MAKE_GAMEFILE_SEL; mNextCardCheckProc = MEMCARDCHECKPROC_MAKE_GAMEFILE_SEL;
break; break;
#endif
} }
#else #else
switch (status) { switch (status) {
@@ -5031,6 +5323,33 @@ void dFile_select_c::MemCardMakeGameFileCheck() {
} }
} }
#if TARGET_PC
void dFile_select_c::MemCardAutoMakeGameFile() {
field_0x03b4 = mDoMemCd_SaveSync();
if (field_0x03b4 == 0) {
return;
}
field_0x03b1 = 0;
if (field_0x03b4 == 1) {
mDoMemCd_Load();
mCardCheckProc = MEMCARDCHECKPROC_LOAD_WAIT;
} else {
errDispInitSet(0x1A, 0);
field_0x0280 = false;
mWindowCloseMsgDispCb = NULL;
mKeyWaitMsgDispCb = NULL;
mNextCardCheckProc = MEMCARDCHECKPROC_AUTO_MAKE_GAMEFILE_ERR_WAIT;
}
}
void dFile_select_c::MemCardAutoMakeGameFileErrWait() {
mNextCardCheckProc = MEMCARDCHECKPROC_STAT_CHECK;
mKeyWaitCardCheckProc = MEMCARDCHECKPROC_MSG_WINDOW_CLOSE;
mCardCheckProc = MEMCARDCHECKPROC_ERRMSG_WAIT_KEY;
}
#endif
#if PLATFORM_WII || PLATFORM_SHIELD #if PLATFORM_WII || PLATFORM_SHIELD
void dFile_select_c::gameFileInitSel() { void dFile_select_c::gameFileInitSel() {
if (errYesNoSelect() != 0) { if (errYesNoSelect() != 0) {
@@ -5184,6 +5503,12 @@ void dFile_select_c::MemCardMsgWindowClose() {
bool dFile_select_c::errYesNoSelect() { bool dFile_select_c::errYesNoSelect() {
bool rv = false; bool rv = false;
#if TARGET_PC
if (pointerYesNoSelect(true)) {
return true;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
if (mDoCPd_c::getTrigA(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1)) {
+1 -1
View File
@@ -118,7 +118,7 @@ static int dKyeff_Create(kankyo_class* i_this) {
if (strcmp(dComIfGp_getStartStageName(), "Name") == 0) { if (strcmp(dComIfGp_getStartStageName(), "Name") == 0) {
camera_process_class* camera = dComIfGp_getCamera(0); camera_process_class* camera = dComIfGp_getCamera(0);
OSTime time = OSGetTime(); OSTime time = DUSK_IF_ELSE(OSGetSystemTime(), OSGetTime());
OSTicksToCalendarTime(time, &calendar); OSTicksToCalendarTime(time, &calendar);
g_env_light.global_wind_influence.vec.x = 1.0f; g_env_light.global_wind_influence.vec.x = 1.0f;
+28 -1
View File
@@ -1213,6 +1213,10 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) {
JUT_ASSERT(2672, mImage_p != NULL); JUT_ASSERT(2672, mImage_p != NULL);
JUT_ASSERT(2673, mResTIMG != NULL); JUT_ASSERT(2673, mResTIMG != NULL);
#if TARGET_PC
GXDestroyCopyTex(mImage_p);
#endif
mTexSizeX = param_1 >> param_3; mTexSizeX = param_1 >> param_3;
mTexSizeY = param_2 >> param_3; mTexSizeY = param_2 >> param_3;
@@ -1226,6 +1230,24 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) {
} }
#endif #endif
#if TARGET_PC
bool dMap_c::refreshTextureSize() {
JUT_ASSERT(2688, mImage_p != NULL);
JUT_ASSERT(2689, mResTIMG != NULL);
const u16 oldWidth = mResTIMG->width;
const u16 oldHeight = mResTIMG->height;
makeResTIMG(mResTIMG, mTexSizeX, mTexSizeY, mImage_p, (u8*)m_res, 0x33);
if (mResTIMG->width == oldWidth && mResTIMG->height == oldHeight) {
return false;
}
GXDestroyCopyTex(mImage_p);
return true;
}
#endif
void dMap_c::_remove() { void dMap_c::_remove() {
if (mImage_p != NULL) { if (mImage_p != NULL) {
#if TARGET_PC #if TARGET_PC
@@ -1618,7 +1640,7 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -mPackX :) mPackX; mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -mPackX :) mPackX;
mCenterZ -= mPackZ; mCenterZ -= mPackZ;
mCenterX += field_0x64; mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -field_0x64 : ) field_0x64;
mCenterZ += mPackPlusZ; mCenterZ += mPackPlusZ;
} }
@@ -1627,6 +1649,8 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
{ {
#if DEBUG #if DEBUG
field_0x64 = 33830.0f; field_0x64 = 33830.0f;
#elif TARGET_PC
field_0x64 = dusk::getSettings().game.enableMirrorMode ? 33830.0f : 0.0f;
#else #else
field_0x64 = 0.0f; field_0x64 = 0.0f;
#endif #endif
@@ -1635,6 +1659,9 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
f32 temp = (field_0x58 * (f32)(field_0x74 + 4)) * 0.5f; f32 temp = (field_0x58 * (f32)(field_0x74 + 4)) * 0.5f;
#if DEBUG #if DEBUG
mRightEdgePlus = -(((dMpath_c::getMinZ() - (-127103.67f)) - temp) / field_0x58); mRightEdgePlus = -(((dMpath_c::getMinZ() - (-127103.67f)) - temp) / field_0x58);
#elif TARGET_PC
mRightEdgePlus = dusk::getSettings().game.enableMirrorMode ? -(((dMpath_c::getMinX() - (-127103.67f)) - temp) / field_0x58) : 0.0f;
#else #else
mRightEdgePlus = 0.0f; mRightEdgePlus = 0.0f;
#endif #endif
+50 -19
View File
@@ -15,16 +15,51 @@
#include <cstring> #include <cstring>
#ifdef TARGET_PC #ifdef TARGET_PC
#include <span> #include "dusk/settings.h"
#include <numbers> #include "m_Do/m_Do_graphic.h"
#include <array> #include <dolphin/gx/GXAurora.h>
#include <aurora/math.hpp>
constexpr u16 kMapResolutionMultiplier = 4; #include <algorithm>
constexpr u16 kMapImageSide = 16 * kMapResolutionMultiplier; #include <array>
#include <cmath>
#include <functional>
#include <limits>
#include <numbers>
#include <span>
constexpr u16 kMapIconResolutionMultiplier = 4;
constexpr u16 kMapImageSide = 16 * kMapIconResolutionMultiplier;
constexpr u32 kMapImageTotalPixels = kMapImageSide * kMapImageSide; constexpr u32 kMapImageTotalPixels = kMapImageSide * kMapImageSide;
typedef std::function<u8(size_t, size_t)> PaintI8Fn; typedef std::function<u8(size_t, size_t)> PaintI8Fn;
u16 scaled_map_axis(u16 value, f32 scale) {
const auto scaledValue =
static_cast<u32>(std::max(1.0f, std::round(static_cast<f32>(value) * scale)));
return static_cast<u16>(std::min<u32>(scaledValue, std::numeric_limits<u16>::max()));
}
aurora::Vec2<u16> map_render_size_for(u16 width, u16 height) {
if (width == 0 || height == 0) {
return {width, height};
}
u32 renderWidth = 0;
u32 renderHeight = 0;
AuroraGetRenderSize(&renderWidth, &renderHeight);
const f32 logicalWidth = std::max(mDoGph_gInf_c::getWidthF(), 1.0f);
const f32 logicalHeight = std::max(mDoGph_gInf_c::getHeightF(), 1.0f);
const f32 irScaleX = renderWidth > 0 ? static_cast<f32>(renderWidth) / logicalWidth : 1.0f;
const f32 irScaleY = renderHeight > 0 ? static_cast<f32>(renderHeight) / logicalHeight : 1.0f;
const f32 hudScale = std::clamp(dusk::getSettings().game.hudScale.getValue(), 0.5f, 2.0f);
return {
scaled_map_axis(width, irScaleX * hudScale),
scaled_map_axis(height, irScaleY * hudScale),
};
}
void paint_i8(std::span<u8> dst, size_t width, PaintI8Fn paint) { void paint_i8(std::span<u8> dst, size_t width, PaintI8Fn paint) {
const auto blocksAcross = width >> 3; const auto blocksAcross = width >> 3;
@@ -478,9 +513,9 @@ void dRenderingMap_c::makeResTIMG(ResTIMG* p_image, u16 width, u16 height, u8* p
p_image->format = GX_TF_C8; p_image->format = GX_TF_C8;
p_image->alphaEnabled = 2; p_image->alphaEnabled = 2;
#ifdef TARGET_PC #ifdef TARGET_PC
// Increase map render resolution const auto [rw, rh] = map_render_size_for(width, height);
p_image->width = width * kMapResolutionMultiplier; p_image->width = rw;
p_image->height = height * kMapResolutionMultiplier; p_image->height = rh;
#else #else
p_image->width = width; p_image->width = width;
p_image->height = height; p_image->height = height;
@@ -563,16 +598,14 @@ void dRenderingFDAmap_c::drawBack() const {
void dRenderingFDAmap_c::preRenderingMap() { void dRenderingFDAmap_c::preRenderingMap() {
#ifdef TARGET_PC #ifdef TARGET_PC
// Increase map render resolution const auto [rw, rh] = map_render_size_for(mTexWidth, mTexHeight);
const u16 w = mTexWidth * kMapResolutionMultiplier; GXCreateFrameBuffer(rw, rh);
const u16 h = mTexHeight * kMapResolutionMultiplier;
GXCreateFrameBuffer(w, h);
// Set logical viewport dimensions // Set logical viewport dimensions
GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f); GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f);
GXSetScissor(0, 0, mTexWidth, mTexHeight); GXSetScissor(0, 0, mTexWidth, mTexHeight);
// Set render viewport dimensions // Set render viewport dimensions
GXSetViewportRender(0.0f, 0.0f, w, h, 0.0f, 1.0f); GXSetViewportRender(0.0f, 0.0f, rw, rh, 0.0f, 1.0f);
GXSetScissorRender(0, 0, w, h); GXSetScissorRender(0, 0, rw, rh);
#else #else
GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f); GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f);
GXSetScissor(0, 0, mTexWidth, mTexHeight); GXSetScissor(0, 0, mTexWidth, mTexHeight);
@@ -610,11 +643,9 @@ void dRenderingFDAmap_c::preRenderingMap() {
void dRenderingFDAmap_c::postRenderingMap() { void dRenderingFDAmap_c::postRenderingMap() {
GXSetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); GXSetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL);
#ifdef TARGET_PC #ifdef TARGET_PC
// Increase map render resolution const auto [rw, rh] = map_render_size_for(mTexWidth, mTexHeight);
const u16 w = mTexWidth * kMapResolutionMultiplier; GXSetTexCopySrc(0, 0, rw, rh);
const u16 h = mTexHeight * kMapResolutionMultiplier; GXSetTexCopyDst(rw, rh, GX_CTF_R8, GX_FALSE);
GXSetTexCopySrc(0, 0, w, h);
GXSetTexCopyDst(w, h, GX_CTF_R8, GX_FALSE);
GXCopyTex(field_0x4, GX_TRUE); GXCopyTex(field_0x4, GX_TRUE);
GXRestoreFrameBuffer(); GXRestoreFrameBuffer();
#else #else
+92
View File
@@ -36,6 +36,10 @@
#include "d/d_menu_window.h" #include "d/d_menu_window.h"
#include "JSystem/J3DGraphBase/J3DMaterial.h" #include "JSystem/J3DGraphBase/J3DMaterial.h"
#if TARGET_PC
#include "dusk/menu_pointer.h"
#endif
typedef void (dMenu_Collect2D_c::*initFunc)(); typedef void (dMenu_Collect2D_c::*initFunc)();
static DUSK_CONSTEXPR initFunc init[] = { static DUSK_CONSTEXPR initFunc init[] = {
&dMenu_Collect2D_c::wait_init, &dMenu_Collect2D_c::save_open_init, &dMenu_Collect2D_c::wait_init, &dMenu_Collect2D_c::save_open_init,
@@ -1786,6 +1790,12 @@ void dMenu_Collect2D_c::wait_init() {
} }
void dMenu_Collect2D_c::wait_proc() { void dMenu_Collect2D_c::wait_proc() {
#if TARGET_PC
if (pointerWait()) {
return;
}
#endif
if (dMw_A_TRIGGER()) { if (dMw_A_TRIGGER()) {
if (mCursorX == 0 && mCursorY == 5) { if (mCursorX == 0 && mCursorY == 5) {
if (mDoGph_gInf_c::getFader()->mStatus == 1) { if (mDoGph_gInf_c::getFader()->mStatus == 1) {
@@ -1887,6 +1897,88 @@ void dMenu_Collect2D_c::wait_proc() {
} }
} }
#if TARGET_PC
void dMenu_Collect2D_c::pointerActivateCurrent() {
if (mCursorX == 0 && mCursorY == 5) {
if (mDoGph_gInf_c::getFader()->mStatus == 1) {
mSubWindowOpenCheck = 1;
Z2GetAudioMgr()->seStart(Z2SE_SY_MENU_CHANGE_WINDOW, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibrationM();
}
} else if (mCursorX == 1 && mCursorY == 5) {
if (mDoGph_gInf_c::getFader()->mStatus == 1) {
mSubWindowOpenCheck = 2;
Z2GetAudioMgr()->seStart(Z2SE_SY_MENU_CHANGE_WINDOW, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibrationM();
}
} else if (mCursorX == 3 && mCursorY == 4) {
if (field_0x22d[3][4] != 0 && mDoGph_gInf_c::getFader()->mStatus == 1) {
mSubWindowOpenCheck = 3;
dMeter2Info_set2DVibration();
}
} else if (mCursorX == 2 && mCursorY == 4) {
if (isFishIconVisible() && mDoGph_gInf_c::getFader()->mStatus == 1) {
mSubWindowOpenCheck = 4;
dMeter2Info_set2DVibration();
}
} else if (mCursorX == 3 && mCursorY == 3) {
if (isSkillIconVisible() && mDoGph_gInf_c::getFader()->mStatus == 1) {
mSubWindowOpenCheck = 5;
dMeter2Info_set2DVibration();
}
} else if (mCursorX == 2 && mCursorY == 3) {
if (isInsectIconVisible() && mDoGph_gInf_c::getFader()->mStatus == 1) {
mSubWindowOpenCheck = 6;
dMeter2Info_set2DVibration();
}
} else if (field_0x22d[mCursorX][mCursorY] != 0 && !mIsWolf) {
if ((mCursorX >= 3 && mCursorX <= 4) || (mCursorX == 5 && mCursorY == 2)) {
u8 cursorY = mCursorY;
if (cursorY == 0) {
if (daPy_getPlayerActorClass()->getSwordChangeWaitTimer() == 0) {
changeSword();
}
} else if (cursorY == 1) {
if (daPy_getPlayerActorClass()->getShieldChangeWaitTimer() == 0) {
changeShield();
}
} else if (cursorY == 2 &&
daPy_getPlayerActorClass()->getClothesChangeWaitTimer() == 0)
{
changeClothe();
}
}
}
}
bool dMenu_Collect2D_c::pointerWait() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Collection);
for (u8 y = 0; y < 6; ++y) {
for (u8 x = 0; x < 7; ++x) {
if (getItemTag(x, y, true) == 0 || !dusk::menu_pointer::hit_pane(mpSelPm[x][y], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(static_cast<dusk::menu_pointer::TargetId>(x + y * 7));
if (mCursorX != x || mCursorY != y) {
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
mCursorX = x;
mCursorY = y;
cursorPosSet();
setItemNameString(mCursorX, mCursorY);
}
if (dusk::menu_pointer::consume_click()) {
pointerActivateCurrent();
return true;
}
return false;
}
}
return false;
}
#endif
void dMenu_Collect2D_c::save_open_init() { void dMenu_Collect2D_c::save_open_init() {
JKRHeap* heap = mDoExt_setCurrentHeap(mpSubHeap); JKRHeap* heap = mDoExt_setCurrentHeap(mpSubHeap);
+24 -1
View File
@@ -914,6 +914,20 @@ void dMenu_DmapBg_c::dMapBgWide() {
void dMenu_DmapBg_c::draw() { void dMenu_DmapBg_c::draw() {
#if TARGET_PC #if TARGET_PC
dMapBgWide(); dMapBgWide();
static bool prevMirror = false; // default state of panes is not mirrored
if(prevMirror != dusk::getSettings().game.enableMirrorMode) {
if(dusk::getSettings().game.enableMirrorMode) {
static_cast<J2DPicture*>(mFloorScreen->search(MULTI_CHAR('rink')))->setMirror(J2DMirror_X);
static_cast<J2DPicture*>(mBaseScreen->search(MULTI_CHAR('map000')))->setMirror(J2DMirror_X);
}
else {
static_cast<J2DPicture*>(mFloorScreen->search(MULTI_CHAR('rink')))->setMirror(MIRROR0);
static_cast<J2DPicture*>(mBaseScreen->search(MULTI_CHAR('map000')))->setMirror(MIRROR0);
}
prevMirror = dusk::getSettings().game.enableMirrorMode;
}
#endif #endif
u32 scissor_left; u32 scissor_left;
@@ -960,6 +974,15 @@ void dMenu_DmapBg_c::draw() {
mpBackTexture->setAlpha(dVar17 * (field_0xdbc * field_0xd9c)); mpBackTexture->setAlpha(dVar17 * (field_0xdbc * field_0xd9c));
f32 local_28c = mpBackTexture->getBounds().i.x; f32 local_28c = mpBackTexture->getBounds().i.x;
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
CPaneMgr mgr;
Vec local_94 = mgr.getGlobalVtxCenter(mMapPane, true, 0);
local_28c = (local_94.x * 2.0f) - (local_28c + 0.5f * mpBackTexture->getWidth()) - 0.5f * mpBackTexture->getWidth();
}
#endif
mpBackTexture->setBlackWhite(color_black, color_white); mpBackTexture->setBlackWhite(color_black, color_white);
mpBackTexture->draw(local_28c, field_0xd94 + mpBackTexture->getBounds().i.y, mpBackTexture->getWidth(), mpBackTexture->draw(local_28c, field_0xd94 + mpBackTexture->getBounds().i.y, mpBackTexture->getWidth(),
mpBackTexture->getHeight(), mpBackTexture->getHeight(),
@@ -1981,7 +2004,7 @@ void dMenu_Dmap_c::mapControl() {
f32 temp_f28 = (var_f29 / 100.0f) * var_f31; f32 temp_f28 = (var_f29 / 100.0f) * var_f31;
f32 sp18 = temp_f28 * cM_ssin(stick_angle); f32 sp18 = temp_f28 * cM_ssin(stick_angle);
f32 sp14 = temp_f28 * cM_scos(stick_angle); f32 sp14 = temp_f28 * cM_scos(stick_angle);
mMapCtrl->setPlusZoomCenterX(sp18); mMapCtrl->setPlusZoomCenterX(IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -sp18 :) sp18);
mMapCtrl->setPlusZoomCenterZ(sp14); mMapCtrl->setPlusZoomCenterZ(sp14);
} }
+1 -20
View File
@@ -359,14 +359,7 @@ f32 dMenu_StageMapCtrl_c::getPixelStageSizeZ() const {
f32 dMenu_StageMapCtrl_c::getPixelCenterX() const { f32 dMenu_StageMapCtrl_c::getPixelCenterX() const {
f32 var_f31 = dMpath_c::getCenterX(); f32 var_f31 = dMpath_c::getCenterX();
#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
return (1.0f / field_0xbc) * (field_0x9c + var_f31);
}
else return (1.0f / field_0xbc) * (field_0x9c - var_f31);
#else
return (1.0f / field_0xbc) * (field_0x9c - var_f31); return (1.0f / field_0xbc) * (field_0x9c - var_f31);
#endif
} }
f32 dMenu_StageMapCtrl_c::getPixelCenterZ() const { f32 dMenu_StageMapCtrl_c::getPixelCenterZ() const {
@@ -425,18 +418,7 @@ inline static f32 rightModeCnvPos(f32 param_0) {
void dMenu_StageMapCtrl_c::cnvPosTo2Dpos(f32 param_0, f32 param_1, f32* param_2, void dMenu_StageMapCtrl_c::cnvPosTo2Dpos(f32 param_0, f32 param_1, f32* param_2,
f32* param_3) const { f32* param_3) const {
if (param_2 != NULL) { if (param_2 != NULL) {
#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
*param_2 =
(0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (field_0x9c + param_0));
} else {
*param_2 =
(0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c));
}
#else
*param_2 = (0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c)); *param_2 = (0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c));
#endif
} }
if (param_3 != NULL) { if (param_3 != NULL) {
@@ -933,8 +915,7 @@ void dMenu_StageMapCtrl_c::move() {
void dMenu_DmapMapCtrl_c::draw() { void dMenu_DmapMapCtrl_c::draw() {
if (field_0xef != 0) { if (field_0xef != 0) {
setPos(field_0xeb, field_0xec, setPos(field_0xeb, field_0xec, field_0x9c,
IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -field_0x9c :) field_0x9c,
field_0xa0, field_0xbc, true, field_0xd8); field_0xa0, field_0xbc, true, field_0xd8);
} }
} }
+10 -15
View File
@@ -931,17 +931,8 @@ void dMenu_Fmap_c::region_map_proc() {
mpDraw2DBack->regionMapMove(mpStick); mpDraw2DBack->regionMapMove(mpStick);
int stage_no, room_no; int stage_no, room_no;
#if TARGET_PC
f32 arrow_pos_x = mpDraw2DBack->getArrowPos2DX();
if (dusk::getSettings().game.enableMirrorMode) {
arrow_pos_x = mpDraw2DBack->getMirrorPosX(arrow_pos_x, 0.0f);
}
f32 pos_x = arrow_pos_x - mDoGph_gInf_c::getMinXF() - mDoGph_gInf_c::getWidthF() * 0.5f;
#else
f32 pos_x = mpDraw2DBack->getArrowPos2DX() - mDoGph_gInf_c::getMinXF() f32 pos_x = mpDraw2DBack->getArrowPos2DX() - mDoGph_gInf_c::getMinXF()
- mDoGph_gInf_c::getWidthF() * 0.5f; - mDoGph_gInf_c::getWidthF() * 0.5f;
#endif
f32 pos_y = mpDraw2DBack->getArrowPos2DY() - mDoGph_gInf_c::getHeightF() * 0.5f; f32 pos_y = mpDraw2DBack->getArrowPos2DY() - mDoGph_gInf_c::getHeightF() * 0.5f;
mpMenuFmapMap->getPointStagePathInnerNo(getNowFmapRegionData(), pos_x, pos_y, mpMenuFmapMap->getPointStagePathInnerNo(getNowFmapRegionData(), pos_x, pos_y,
@@ -2486,12 +2477,6 @@ void dMenu_Fmap_c::portalWarpMapMove(STControl* i_stick) {
f32 arrow_y = mpDraw2DBack->getArrowPos2DY(); f32 arrow_y = mpDraw2DBack->getArrowPos2DY();
u8 uVar6 = 0xff; u8 uVar6 = 0xff;
#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
arrow_x = mpDraw2DBack->getMirrorPosX(arrow_x, 0.0f);
}
#endif
for (int i = 0; i < portal_dat->mCount; i++) { for (int i = 0; i < portal_dat->mCount; i++) {
if (portals[i].mRegionNo == mpDraw2DBack->getRegionCursor() + 1 if (portals[i].mRegionNo == mpDraw2DBack->getRegionCursor() + 1
@@ -2561,6 +2546,11 @@ void dMenu_Fmap_c::drawIcon(f32 param_0, bool param_1) {
if (mProcess == PROC_PORTAL_DEMO1) { if (mProcess == PROC_PORTAL_DEMO1) {
is_portal_demo1 = 1; is_portal_demo1 = 1;
} }
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
angle = 0x10000 - angle;
}
#endif
mpDraw2DBack->setIcon2DPos(0x11, stage_name, pos.x, pos.z, cM_sht2d(angle), mpDraw2DBack->setIcon2DPos(0x11, stage_name, pos.x, pos.z, cM_sht2d(angle),
is_portal_demo1, param_1); is_portal_demo1, param_1);
@@ -2649,6 +2639,11 @@ void dMenu_Fmap_c::drawPlayEnterIcon() {
angle = dComIfGs_getPlayerFieldLastStayAngleY(); angle = dComIfGs_getPlayerFieldLastStayAngleY();
SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName()); SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName());
} }
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
angle = 0x10000 - angle;
}
#endif
mpDraw2DBack->setIcon2DPos(0x15, stage_name, pos.x, pos.z, cM_sht2d(angle), 0, false); mpDraw2DBack->setIcon2DPos(0x15, stage_name, pos.x, pos.z, cM_sht2d(angle), 0, false);
} }
} }
+86 -19
View File
@@ -17,7 +17,10 @@
#include "d/d_msg_scrn_explain.h" #include "d/d_msg_scrn_explain.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include "d/actor/d_a_midna.h" #include "d/actor/d_a_midna.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/ui/touch_controls.hpp"
#endif
#include <cstring> #include <cstring>
#if TARGET_PC #if TARGET_PC
@@ -423,7 +426,15 @@ void dMenu_Fmap2DBack_c::draw() {
} }
mpPointParent->setAlphaRate(mArrowAlpha * mSpotTextureFadeAlpha); mpPointParent->setAlphaRate(mArrowAlpha * mSpotTextureFadeAlpha);
mpPointParent->translate(mArrowPos2DX + mTransX, mArrowPos2DY + mTransZ);
f32 drawX = mArrowPos2DX + mTransX;
#ifdef TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
drawX = getMirrorPosX(drawX, 0.0f);
}
#endif
mpPointParent->translate(drawX, mArrowPos2DY + mTransZ);
mpPointScreen->draw(0.0f, 0.0f, grafPort); mpPointScreen->draw(0.0f, 0.0f, grafPort);
} }
@@ -742,7 +753,7 @@ void dMenu_Fmap2DBack_c::zoomMapCalc(f32 i_zoom) {
f32 tmp2 = (dVar12 + (i_zoom * (centerX - dVar12))); f32 tmp2 = (dVar12 + (i_zoom * (centerX - dVar12)));
f32 tmp2_ = (dVar11 + (i_zoom * (centerY - dVar11))); f32 tmp2_ = (dVar11 + (i_zoom * (centerY - dVar11)));
field_0xf0c[mRegionCursor] = field_0xf0c[mRegionCursor] =
((tmp2 + (tmp3 * mZoom)) - mRegionMapSizeX[mRegionCursor] * mZoom * 0.5f) - ((tmp2 + (tmp3 * mZoom)) - mRegionMapSizeX[mRegionCursor] * mZoom * 0.5f) -
mRegionMinMapX[mRegionCursor]; mRegionMinMapX[mRegionCursor];
@@ -1015,6 +1026,11 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) {
f32 delta_y = speed * cM_ssin(angle); f32 delta_y = speed * cM_ssin(angle);
f32 delta_x = speed * cM_scos(angle); f32 delta_x = speed * cM_scos(angle);
#ifdef TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
delta_y = -delta_y;
}
#endif
control_xpos = control_xpos + delta_y; control_xpos = control_xpos + delta_y;
control_ypos = control_ypos + delta_x; control_ypos = control_ypos + delta_x;
} }
@@ -1043,11 +1059,6 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) {
calcAllMapPos2D((mArrowPos3DX + control_xpos) - mStageTransX, calcAllMapPos2D((mArrowPos3DX + control_xpos) - mStageTransX,
(mArrowPos3DZ + control_ypos) - mStageTransZ, &sp14, &sp10); (mArrowPos3DZ + control_ypos) - mStageTransZ, &sp14, &sp10);
#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
sp14 = getMirrorPosX(sp14, 0.0f);
}
#endif
mSelectRegion = 0xff; mSelectRegion = 0xff;
for (int i = 7; i >= 0; i--) { for (int i = 7; i >= 0; i--) {
@@ -1462,6 +1473,12 @@ void dMenu_Fmap2DBack_c::worldGridDraw() {
f32 dVar8 = -mStageTransZ; f32 dVar8 = -mStageTransZ;
calcAllMapPos2D(dVar9, dVar8, &local_74, &local_78); calcAllMapPos2D(dVar9, dVar8, &local_74, &local_78);
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
local_74 = getMirrorPosX(local_74, 0.0f);
}
#endif
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74, J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(), mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
JUtility::TColor(255, 255, 255, 255), 6); JUtility::TColor(255, 255, 255, 255), 6);
@@ -1470,6 +1487,11 @@ void dMenu_Fmap2DBack_c::worldGridDraw() {
while (true) { while (true) {
calcAllMapPos2D(xPos, dVar8, &local_74, &local_78); calcAllMapPos2D(xPos, dVar8, &local_74, &local_78);
if (local_74 >= getMapScissorAreaLX()) { if (local_74 >= getMapScissorAreaLX()) {
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
local_74 = getMirrorPosX(local_74, 0.0f);
}
#endif
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74, J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(), mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
JUtility::TColor(255, 255, 255, 255), 6); JUtility::TColor(255, 255, 255, 255), 6);
@@ -1531,6 +1553,12 @@ void dMenu_Fmap2DBack_c::regionGridDraw() {
f32 dVar8 = mRegionOriginZ[mRegionCursor] - mStageTransZ; f32 dVar8 = mRegionOriginZ[mRegionCursor] - mStageTransZ;
calcAllMapPos2D(dVar9, dVar8, &local_74, &local_78); calcAllMapPos2D(dVar9, dVar8, &local_74, &local_78);
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
local_74 = getMirrorPosX(local_74, 0.0f);
}
#endif
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74, J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(), mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
JUtility::TColor(180, 0, 0, 255), 6); JUtility::TColor(180, 0, 0, 255), 6);
@@ -1539,6 +1567,12 @@ void dMenu_Fmap2DBack_c::regionGridDraw() {
while (true) { while (true) {
calcAllMapPos2D(xPos, dVar8, &local_74, &local_78); calcAllMapPos2D(xPos, dVar8, &local_74, &local_78);
if (local_74 >= getMapScissorAreaLX()) { if (local_74 >= getMapScissorAreaLX()) {
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
local_74 = getMirrorPosX(local_74, 0.0f);
}
#endif
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74, J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(), mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
JUtility::TColor(180, 0, 0, 255), 6); JUtility::TColor(180, 0, 0, 255), 6);
@@ -1601,6 +1635,12 @@ void dMenu_Fmap2DBack_c::worldOriginDraw() {
f32 local_44, local_48; f32 local_44, local_48;
calcAllMapPos2D(-mStageTransX, -mStageTransZ, &local_44, &local_48); calcAllMapPos2D(-mStageTransX, -mStageTransZ, &local_44, &local_48);
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
local_44 = getMirrorPosX(local_44, 0.0f);
}
#endif
J2DDrawLine(mDoGph_gInf_c::getMinXF(), local_48 - local_44 + mDoGph_gInf_c::getMinXF(), J2DDrawLine(mDoGph_gInf_c::getMinXF(), local_48 - local_44 + mDoGph_gInf_c::getMinXF(),
mDoGph_gInf_c::getMinXF() + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getMinXF() + mDoGph_gInf_c::getWidthF(),
local_48 - local_44 + (mDoGph_gInf_c::getMinXF() + mDoGph_gInf_c::getWidthF()), local_48 - local_44 + (mDoGph_gInf_c::getMinXF() + mDoGph_gInf_c::getWidthF()),
@@ -1635,6 +1675,13 @@ void dMenu_Fmap2DBack_c::scrollAreaDraw() {
calcAllMapPos2D(x_min - mStageTransX, z_min - mStageTransZ, &local_4c, &local_50); calcAllMapPos2D(x_min - mStageTransX, z_min - mStageTransZ, &local_4c, &local_50);
calcAllMapPos2D(x_max - mStageTransX, z_max - mStageTransZ, &local_54, &local_58); calcAllMapPos2D(x_max - mStageTransX, z_max - mStageTransZ, &local_54, &local_58);
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
local_4c = getMirrorPosX(local_4c, 0.0f);
local_54 = getMirrorPosX(local_54, 0.0f);
}
#endif
J2DDrawLine(local_4c, local_50, local_4c, local_58, J2DDrawLine(local_4c, local_50, local_4c, local_58,
JUtility::TColor(255, 255, 255, 255), 6); JUtility::TColor(255, 255, 255, 255), 6);
J2DDrawLine(local_54, local_50, local_54, local_58, J2DDrawLine(local_54, local_50, local_54, local_58,
@@ -1655,6 +1702,11 @@ void dMenu_Fmap2DBack_c::regionOriginDraw() {
f32 center_x, center_y; f32 center_x, center_y;
calcAllMapPos2D(mRegionOriginX[i] - mStageTransX, mRegionOriginZ[i] - mStageTransZ, calcAllMapPos2D(mRegionOriginX[i] - mStageTransX, mRegionOriginZ[i] - mStageTransZ,
&center_x, &center_y); &center_x, &center_y);
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
center_x = getMirrorPosX(center_x - 3.0f, 3.0f);
}
#endif
J2DFillBox(center_x - 3.0f, center_y - 3.0f, 6.0f, 6.0f, JUtility::TColor(255, 0, 0, 255)); J2DFillBox(center_x - 3.0f, center_y - 3.0f, 6.0f, 6.0f, JUtility::TColor(255, 0, 0, 255));
} }
} }
@@ -1672,6 +1724,11 @@ void dMenu_Fmap2DBack_c::stageOriginDraw() {
f32 v1 = mRegionOriginX[mRegionCursor] + stage_data[i].mOffsetX - mStageTransX; f32 v1 = mRegionOriginX[mRegionCursor] + stage_data[i].mOffsetX - mStageTransX;
f32 v2 = mRegionOriginZ[mRegionCursor] + stage_data[i].mOffsetZ - mStageTransZ; f32 v2 = mRegionOriginZ[mRegionCursor] + stage_data[i].mOffsetZ - mStageTransZ;
calcAllMapPos2D(v1, v2, &center_x, &center_y); calcAllMapPos2D(v1, v2, &center_x, &center_y);
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
center_x = getMirrorPosX(center_x - 3.0f, 3.0f);
}
#endif
J2DFillBox(center_x - 3.0f, center_y - 3.0f, 6.0f, 6.0f, J2DFillBox(center_x - 3.0f, center_y - 3.0f, 6.0f, 6.0f,
JUtility::TColor(0, 0, 255, 255)); JUtility::TColor(0, 0, 255, 255));
} }
@@ -1918,7 +1975,7 @@ void dMenu_Fmap2DBack_c::regionMapMove(STControl* i_stick) {
f32 speed = base_speed / 100.0f * local_78; f32 speed = base_speed / 100.0f * local_78;
f32 speed_y = speed * cM_ssin(angle); f32 speed_y = speed * cM_ssin(angle);
f32 speed_x = speed * cM_scos(angle); f32 speed_x = speed * cM_scos(angle);
control_xpos += speed_y; control_xpos += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -speed_y :) speed_y;
control_ypos += speed_x; control_ypos += speed_x;
} }
} }
@@ -1943,11 +2000,6 @@ void dMenu_Fmap2DBack_c::regionMapMove(STControl* i_stick) {
calcAllMapPos2D(mArrowPos3DX + control_xpos - mStageTransX, calcAllMapPos2D(mArrowPos3DX + control_xpos - mStageTransX,
mArrowPos3DZ + control_ypos - mStageTransZ, &pos_x, &pos_y); mArrowPos3DZ + control_ypos - mStageTransZ, &pos_x, &pos_y);
#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
pos_x = getMirrorPosX(pos_x, 0.0f);
}
#endif
mSelectRegion = 0xff; mSelectRegion = 0xff;
int region = mRegionCursor; int region = mRegionCursor;
@@ -1979,11 +2031,6 @@ void dMenu_Fmap2DBack_c::stageMapMove(STControl* i_stick, u8 param_1, bool param
if (stick_value >= slow_bound && param_2 && field_0x1238 != 2) { if (stick_value >= slow_bound && param_2 && field_0x1238 != 2) {
bVar6 = true; bVar6 = true;
s16 angle = i_stick->getAngleStick(); s16 angle = i_stick->getAngleStick();
#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
angle = -angle;
}
#endif
f32 local_68 = mTexMaxX - mTexMinX; f32 local_68 = mTexMaxX - mTexMinX;
f32 spot_zoom = getSpotMapZoomRate(); f32 spot_zoom = getSpotMapZoomRate();
f32 region_zoom = getRegionMapZoomRate(mRegionCursor); f32 region_zoom = getRegionMapZoomRate(mRegionCursor);
@@ -1998,7 +2045,7 @@ void dMenu_Fmap2DBack_c::stageMapMove(STControl* i_stick, u8 param_1, bool param
f32 speed = base_speed / 100.0f * local_78; f32 speed = base_speed / 100.0f * local_78;
f32 speed_x = speed * cM_ssin(angle); f32 speed_x = speed * cM_ssin(angle);
f32 speed_z = speed * cM_scos(angle); f32 speed_z = speed * cM_scos(angle);
mStageTransX += speed_x; mStageTransX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -speed_x :) speed_x;
mStageTransZ += speed_z; mStageTransZ += speed_z;
} else if (!param_2) { } else if (!param_2) {
return; return;
@@ -2092,6 +2139,11 @@ void dMenu_Fmap2DBack_c::drawDebugStageArea() {
if (stage_no >= 0) { if (stage_no >= 0) {
f32 v = i + mDoGph_gInf_c::getMinXF(); f32 v = i + mDoGph_gInf_c::getMinXF();
f32 v2 = j; f32 v2 = j;
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
v = getMirrorPosX(v - 3.0f, 3.0f);
}
#endif
J2DFillBox(v - 3.0f, v2 - 3.0f, 6.0f, 6.0f, colors[stage_no % 6]); J2DFillBox(v - 3.0f, v2 - 3.0f, 6.0f, 6.0f, colors[stage_no % 6]);
} }
} }
@@ -2127,6 +2179,11 @@ void dMenu_Fmap2DBack_c::drawDebugRegionArea() {
mRegionMapSizeX[region] * mZoom, mRegionMapSizeY[region] * mZoom, mRegionMapSizeX[region] * mZoom, mRegionMapSizeY[region] * mZoom,
mpAreaTex[region]->getTexture(0)->getTexInfo()); mpAreaTex[region]->getTexture(0)->getTexInfo());
if (u) { if (u) {
#if TARGET_PC
if(dusk::getSettings().game.enableMirrorMode) {
pos_x = getMirrorPosX(pos_x - 3.0f, 3.0f);
}
#endif
J2DFillBox(pos_x - 3.0f, pos_y - 3.0f, 6.0f, 6.0f, colors[region]); J2DFillBox(pos_x - 3.0f, pos_y - 3.0f, 6.0f, 6.0f, colors[region]);
break; break;
} }
@@ -2509,6 +2566,10 @@ dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) {
} }
dMenu_Fmap2DTop_c::~dMenu_Fmap2DTop_c() { dMenu_Fmap2DTop_c::~dMenu_Fmap2DTop_c() {
#if TARGET_PC
dusk::ui::set_control_override(dusk::ui::Control::Z, dusk::ui::ControlOverride::Default);
#endif
deleteExplain(); deleteExplain();
JKR_DELETE(mpTitleScreen); JKR_DELETE(mpTitleScreen);
mpTitleScreen = NULL; mpTitleScreen = NULL;
@@ -2782,6 +2843,12 @@ void dMenu_Fmap2DTop_c::setZButtonString(u32 param_0, u8 i_alpha) {
param_0 = 0x533; param_0 = 0x533;
} }
#if TARGET_PC
dusk::ui::set_control_override(dusk::ui::Control::Z,
param_0 != 0 && isWarpAccept() ? dusk::ui::ControlOverride::Action :
dusk::ui::ControlOverride::Default);
#endif
#if VERSION == VERSION_GCN_JPN #if VERSION == VERSION_GCN_JPN
static const u64 cont_zt[5] = {MULTI_CHAR('cont_zt'), MULTI_CHAR('cont_zt1'), MULTI_CHAR('cont_zt2'), MULTI_CHAR('cont_zt3'), MULTI_CHAR('cont_zt4')}; static const u64 cont_zt[5] = {MULTI_CHAR('cont_zt'), MULTI_CHAR('cont_zt1'), MULTI_CHAR('cont_zt2'), MULTI_CHAR('cont_zt3'), MULTI_CHAR('cont_zt4')};
#define setZButtonString_font_zt cont_zt #define setZButtonString_font_zt cont_zt
+44
View File
@@ -22,6 +22,10 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#if TARGET_PC
#include "dusk/menu_pointer.h"
#endif
typedef void (dMenu_Insect_c::*initFunc)(); typedef void (dMenu_Insect_c::*initFunc)();
static initFunc map_init_process[] = { static initFunc map_init_process[] = {
&dMenu_Insect_c::wait_init, &dMenu_Insect_c::explain_open_init, &dMenu_Insect_c::wait_init, &dMenu_Insect_c::explain_open_init,
@@ -280,6 +284,12 @@ void dMenu_Insect_c::wait_init() {
void dMenu_Insect_c::wait_move() { void dMenu_Insect_c::wait_move() {
if (mDoGph_gInf_c::getFader()->getStatus() == 1) { if (mDoGph_gInf_c::getFader()->getStatus() == 1) {
#if TARGET_PC
if (pointerWait()) {
return;
}
#endif
if (mDoCPd_c::getTrigB(PAD_1) || field_0xf7 == 0) { if (mDoCPd_c::getTrigB(PAD_1) || field_0xf7 == 0) {
if (mDoCPd_c::getTrigB(PAD_1) && field_0xf6 == 1) { if (mDoCPd_c::getTrigB(PAD_1) && field_0xf6 == 1) {
dMeter2Info_setInsectSelectType(0); dMeter2Info_setInsectSelectType(0);
@@ -301,6 +311,40 @@ void dMenu_Insect_c::wait_move() {
} }
} }
#if TARGET_PC
bool dMenu_Insect_c::pointerWait() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Collection);
for (u8 y = 0; y < 4; ++y) {
for (u8 x = 0; x < 6; ++x) {
const int index = x + y * 6;
if (!isGetInsect(x, y) || !dusk::menu_pointer::hit_pane(mpINSParent[index], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(index);
if (field_0xf4 != x || field_0xf5 != y) {
field_0xf4 = x;
field_0xf5 = y;
setCursorPos();
setAButtonString(0x368);
Z2GetAudioMgr()->seStart(Z2SE_SY_CURSOR_ITEM, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
if (dusk::menu_pointer::consume_click()) {
field_0xf3 = 1;
Z2GetAudioMgr()->seStart(Z2SE_SY_EXP_WIN_OPEN, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibration();
return true;
}
return false;
}
}
return false;
}
#endif
void dMenu_Insect_c::explain_open_init() { void dMenu_Insect_c::explain_open_init() {
char local_78[32]; char local_78[32];
char local_98[32]; char local_98[32];
+68
View File
@@ -19,6 +19,15 @@
#ifdef TARGET_PC #ifdef TARGET_PC
#include "dusk/achievements.h" #include "dusk/achievements.h"
#include "dusk/menu_pointer.h"
#include "dusk/ui/touch_controls.hpp"
static void enable_turn_page_controls(bool enabled) {
const auto controlOverride =
enabled ? dusk::ui::ControlOverride::Action : dusk::ui::ControlOverride::Default;
dusk::ui::set_control_override(dusk::ui::Control::L, controlOverride);
dusk::ui::set_control_override(dusk::ui::Control::R, controlOverride);
}
#endif #endif
#if VERSION == VERSION_GCN_JPN #if VERSION == VERSION_GCN_JPN
@@ -82,6 +91,10 @@ dMenu_Letter_c::dMenu_Letter_c(JKRExpHeap* i_heap, STControl* i_stick, CSTContro
dMenu_Letter_c::~dMenu_Letter_c() { dMenu_Letter_c::~dMenu_Letter_c() {
#if TARGET_PC
enable_turn_page_controls(false);
#endif
JKR_DELETE(mpDrawCursor); JKR_DELETE(mpDrawCursor);
mpDrawCursor = NULL; mpDrawCursor = NULL;
@@ -357,6 +370,10 @@ int dMenu_Letter_c::_open() {
} }
int dMenu_Letter_c::_close() { int dMenu_Letter_c::_close() {
#if TARGET_PC
enable_turn_page_controls(false);
#endif
s16 closeWindowFrame = s16 closeWindowFrame =
g_drawHIO.mLetterSelectScreen.mCloseFrame[dMeter_drawLetterHIO_c::WINDOW_FRAME]; g_drawHIO.mLetterSelectScreen.mCloseFrame[dMeter_drawLetterHIO_c::WINDOW_FRAME];
field_0x368 = 0; field_0x368 = 0;
@@ -386,6 +403,10 @@ int dMenu_Letter_c::_close() {
} }
void dMenu_Letter_c::wait_init() { void dMenu_Letter_c::wait_init() {
#if TARGET_PC
enable_turn_page_controls(field_0x374 > 1);
#endif
setAButtonString(0x40c); setAButtonString(0x40c);
setBButtonString(0x3f9); setBButtonString(0x3f9);
} }
@@ -393,6 +414,12 @@ void dMenu_Letter_c::wait_init() {
void dMenu_Letter_c::wait_move() { void dMenu_Letter_c::wait_move() {
u8 oldIndex = mIndex; u8 oldIndex = mIndex;
if (mDoGph_gInf_c::getFader()->getStatus() == 1) { if (mDoGph_gInf_c::getFader()->getStatus() == 1) {
#if TARGET_PC
if (pointerWait()) {
return;
}
#endif
if (mDoCPd_c::getTrigB(PAD_1) != 0) { if (mDoCPd_c::getTrigB(PAD_1) != 0) {
mpDrawCursor->offPlayAnime(0); mpDrawCursor->offPlayAnime(0);
mStatus = 3; mStatus = 3;
@@ -448,8 +475,41 @@ void dMenu_Letter_c::wait_move() {
} }
} }
#if TARGET_PC
bool dMenu_Letter_c::pointerWait() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Collection);
for (u8 i = 0; i < field_0x373; ++i) {
if (!dusk::menu_pointer::hit_pane(mpLetterParent[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(i);
if (mIndex != i) {
mIndex = i;
changeActiveColor();
Z2GetAudioMgr()->seStart(Z2SE_SY_CURSOR_ITEM, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
if (dusk::menu_pointer::consume_click()) {
mProcess = 3;
Z2GetAudioMgr()->seStart(Z2SE_SY_LETTER_OPEN, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibration();
return true;
}
return false;
}
return false;
}
#endif
void dMenu_Letter_c::slide_right_init() { void dMenu_Letter_c::slide_right_init() {
#if TARGET_PC
enable_turn_page_controls(false);
#endif
field_0x358 = -field_0x1ec->getWidth() * mDoGph_gInf_c::getInvScale(); field_0x358 = -field_0x1ec->getWidth() * mDoGph_gInf_c::getInvScale();
field_0x35c = field_0x1ec->getWidth() IF_NOT_DUSK(* mDoGph_gInf_c::getInvScale()); field_0x35c = field_0x1ec->getWidth() IF_NOT_DUSK(* mDoGph_gInf_c::getInvScale());
changePageLight(); changePageLight();
@@ -467,6 +527,10 @@ void dMenu_Letter_c::slide_right_move() {
} }
void dMenu_Letter_c::slide_left_init() { void dMenu_Letter_c::slide_left_init() {
#if TARGET_PC
enable_turn_page_controls(false);
#endif
field_0x358 = field_0x1ec->getWidth() * mDoGph_gInf_c::getInvScale(); field_0x358 = field_0x1ec->getWidth() * mDoGph_gInf_c::getInvScale();
field_0x35c = -field_0x1ec->getWidth() IF_NOT_DUSK(* mDoGph_gInf_c::getInvScale()); field_0x35c = -field_0x1ec->getWidth() IF_NOT_DUSK(* mDoGph_gInf_c::getInvScale());
changePageLight(); changePageLight();
@@ -484,6 +548,10 @@ void dMenu_Letter_c::slide_left_move() {
} }
void dMenu_Letter_c::read_open_init() { void dMenu_Letter_c::read_open_init() {
#if TARGET_PC
enable_turn_page_controls(false);
#endif
field_0x36a = 0; field_0x36a = 0;
u8 idx = field_0x3ac[field_0x36f * 6 + mIndex] - 1; u8 idx = field_0x3ac[field_0x36f * 6 + mIndex] - 1;
field_0x3e3 = 1; field_0x3e3 = 1;
+7 -15
View File
@@ -394,21 +394,8 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
icon_size_y *= _c7c; icon_size_y *= _c7c;
} }
#if TARGET_PC
f32 rotation = mIconInfo[info_idx].rotation;
if (dusk::getSettings().game.enableMirrorMode &&
(mIconInfo[info_idx].icon_no == ICON_LINK_e ||
mIconInfo[info_idx].icon_no == ICON_LINK_ENTER_e))
{
rotation = -rotation;
}
mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z,
rotation);
#else
mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z, mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z,
mIconInfo[info_idx].rotation); mIconInfo[info_idx].rotation);
#endif
if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) { if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) {
mPictures[mIconInfo[info_idx].icon_no]->setAlpha((180.0f * _c80) / 255.0f); mPictures[mIconInfo[info_idx].icon_no]->setAlpha((180.0f * _c80) / 255.0f);
@@ -423,10 +410,15 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
} }
f32 pos_x = i_posX + (icon_pos_x - (icon_size_x / 2)); f32 pos_x = i_posX + (icon_pos_x - (icon_size_x / 2));
bool r4 = false;
#if TARGET_PC #if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) { if (dusk::getSettings().game.enableMirrorMode) {
pos_x = getMirrorCenterPosX(i_posX + (icon_pos_x - (icon_size_x / 2)), icon_size_x / 2); pos_x = getMirrorCenterPosX(i_posX + (icon_pos_x - (icon_size_x / 2)), icon_size_x / 2);
} }
if(mIconInfo[info_idx].icon_no == ICON_GOLD_WOLF_e) {
r4 = true;
}
#endif #endif
mPictures[mIconInfo[info_idx].icon_no]->draw(pos_x, (i_posY + (icon_pos_y - icon_size_y / 2)), mPictures[mIconInfo[info_idx].icon_no]->draw(pos_x, (i_posY + (icon_pos_y - icon_size_y / 2)),
@@ -435,7 +427,7 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) { if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) {
mLightDropPic->draw((pos_x + (icon_size_x / 2)) - (var_f29 / 2), mLightDropPic->draw((pos_x + (icon_size_x / 2)) - (var_f29 / 2),
((icon_size_y / 2) + (i_posY + (icon_pos_y - icon_size_y / 2))) - (var_f28 / 2), ((icon_size_y / 2) + (i_posY + (icon_pos_y - icon_size_y / 2))) - (var_f28 / 2),
var_f29, var_f28, false, false, false); var_f29, var_f28, r4, false, false);
} }
} }
} }
@@ -869,4 +861,4 @@ void dMenuMapCommon_c::getFmapPoeCount(const int regionNo, int& nowCount, int& t
} }
} }
} }
#endif #endif
+172
View File
@@ -26,6 +26,11 @@
#include "JSystem/JAudio2/JASDriverIF.h" #include "JSystem/JAudio2/JASDriverIF.h"
#if TARGET_PC
#include "dusk/menu_pointer.h"
#include "dusk/ui/touch_controls.hpp"
#endif
typedef void (dMenu_Option_c::*initFunc)(); typedef void (dMenu_Option_c::*initFunc)();
static initFunc init[] = { static initFunc init[] = {
&dMenu_Option_c::atten_init, &dMenu_Option_c::atten_init,
@@ -78,6 +83,12 @@ enum SelectType {
SelectType8, SelectType8,
}; };
#if TARGET_PC
static dusk::menu_pointer::TargetId option_yes_no_target(u8 index) noexcept {
return static_cast<dusk::menu_pointer::TargetId>(0x100 + index);
}
#endif
dMenu_Option_c::dMenu_Option_c(JKRArchive* i_archive, STControl* i_stick) { dMenu_Option_c::dMenu_Option_c(JKRArchive* i_archive, STControl* i_stick) {
mUseFlag = 0; mUseFlag = 0;
mBarScale[0] = g_drawHIO.mOptionScreen.mBarScale[0]; mBarScale[0] = g_drawHIO.mOptionScreen.mBarScale[0];
@@ -293,6 +304,10 @@ void dMenu_Option_c::_create() {
} }
void dMenu_Option_c::_delete() { void dMenu_Option_c::_delete() {
#if TARGET_PC
dusk::ui::set_control_override(dusk::ui::Control::Z, dusk::ui::ControlOverride::Default);
#endif
JKR_DELETE(mpString); JKR_DELETE(mpString);
mpString = NULL; mpString = NULL;
@@ -518,6 +533,15 @@ void dMenu_Option_c::_move() {
(this->*init[field_0x3ef])(); (this->*init[field_0x3ef])();
} }
} }
#if TARGET_PC
if (field_0x3f4 == 5 && field_0x3ef != SelectType3 && field_0x3f3 == 5 &&
field_0x3ef != SelectType4 && field_0x3ef != SelectType5 && field_0x3ef != SelectType6 &&
field_0x3ef != SelectType7 && pointerConfirmSelect())
{
goto skip;
}
#endif
} }
skip: skip:
u8 oldValue = field_0x3ef; u8 oldValue = field_0x3ef;
@@ -1074,6 +1098,44 @@ void dMenu_Option_c::confirm_move_move() {
bool leftTrigger = checkLeftTrigger(); bool leftTrigger = checkLeftTrigger();
bool rightTrigger = checkRightTrigger(); bool rightTrigger = checkRightTrigger();
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
for (u8 i = 0; i < 2; ++i) {
if (!dusk::menu_pointer::hit_pane(mpYesNoSelBase_c[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(option_yes_no_target(i));
const bool clicked = dusk::menu_pointer::consume_click();
if (field_0x3f9 != i) {
Z2GetAudioMgr()->seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
field_0x3fa = field_0x3f9;
field_0x3f9 = i;
if (clicked) {
yesNoSelectStart();
field_0x3ef = SelectType7;
dMeter2Info_set2DVibrationM();
mpWarning->_move();
setAnimation();
return;
}
yesnoSelectAnmSet();
field_0x3ef = SelectType6;
mpWarning->_move();
setAnimation();
return;
}
if (clicked) {
yesNoSelectStart();
field_0x3ef = SelectType7;
dMeter2Info_set2DVibrationM();
mpWarning->_move();
setAnimation();
return;
}
}
#endif
if (mDoCPd_c::getTrigA(PAD_1) != 0) { if (mDoCPd_c::getTrigA(PAD_1) != 0) {
yesNoSelectStart(); yesNoSelectStart();
field_0x3ef = SelectType7; field_0x3ef = SelectType7;
@@ -1110,11 +1172,36 @@ void dMenu_Option_c::confirm_select_init() {
} }
void dMenu_Option_c::confirm_select_move() { void dMenu_Option_c::confirm_select_move() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
if (field_0x3f9 != 0xff &&
dusk::menu_pointer::hit_pane(mpYesNoSelBase_c[field_0x3f9], 8.0f))
{
const dusk::menu_pointer::TargetId target = option_yes_no_target(field_0x3f9);
dusk::menu_pointer::set_hover_target(target);
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(dusk::menu_pointer::Context::Options, target);
}
}
#endif
u8 selectMoveAnm = yesnoSelectMoveAnm(); u8 selectMoveAnm = yesnoSelectMoveAnm();
u8 wakuAlphaAnm = yesnoWakuAlpahAnm(field_0x3fa); u8 wakuAlphaAnm = yesnoWakuAlpahAnm(field_0x3fa);
if (selectMoveAnm == 1 && wakuAlphaAnm == 1) { if (selectMoveAnm == 1 && wakuAlphaAnm == 1) {
yesnoCursorShow(); yesnoCursorShow();
#if TARGET_PC
if (field_0x3f9 != 0xff &&
dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::Options, option_yes_no_target(field_0x3f9)))
{
yesNoSelectStart();
field_0x3ef = SelectType7;
dMeter2Info_set2DVibrationM();
mpWarning->_move();
setAnimation();
return;
}
#endif
field_0x3ef = SelectType5; field_0x3ef = SelectType5;
} }
mpWarning->_move(); mpWarning->_move();
@@ -2063,6 +2150,11 @@ void dMenu_Option_c::cursorAnime(f32 i_cursorValue) {
} }
void dMenu_Option_c::setZButtonString(u16 i_stringID) { void dMenu_Option_c::setZButtonString(u16 i_stringID) {
#if TARGET_PC
dusk::ui::set_control_override(dusk::ui::Control::Z,
i_stringID != 0 ? dusk::ui::ControlOverride::Action : dusk::ui::ControlOverride::Default);
#endif
if (i_stringID == 0) { if (i_stringID == 0) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (mpZButtonText[i] != NULL) { if (mpZButtonText[i] != NULL) {
@@ -2142,7 +2234,87 @@ bool dMenu_Option_c::isRumbleSupported() {
return JUTGamePad::sRumbleSupported >> 0x1f; return JUTGamePad::sRumbleSupported >> 0x1f;
} }
#if TARGET_PC
bool dMenu_Option_c::pointerConfirmSelect() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
for (u8 i = 0; i < SelectType3; ++i) {
if (dusk::menu_pointer::hit_pane(mpMenuPane[i], 8.0f)) {
dusk::menu_pointer::set_hover_target(i);
return false;
}
}
dusk::menu_pointer::set_hover_target(0x200);
if (!dusk::menu_pointer::consume_click()) {
return false;
}
field_0x3f7 = 1;
field_0x3f5 = field_0x3ef;
field_0x3ef = SelectType4;
dMeter2Info_set2DVibration();
(this->*init[field_0x3ef])();
return true;
}
#endif
bool dMenu_Option_c::dpdMenuMove() { bool dMenu_Option_c::dpdMenuMove() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
for (u8 i = 0; i < SelectType3; ++i) {
if (!dusk::menu_pointer::hit_pane(mpMenuPane[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(i);
if (getSelectType() != i) {
field_0x3ef = i;
setCursorPos(i);
Z2GetAudioMgr()->seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
if (!dusk::menu_pointer::consume_click()) {
return true;
}
switch (i) {
case SelectType0:
field_0x3e4 ^= 1;
field_0x3da = 5;
field_0x3ef = SelectType3;
field_0x3f5 = SelectType0;
Z2GetAudioMgr()->seStart(Z2SE_SY_OPTION_SWITCH, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
return true;
case SelectType1:
if (isRumbleSupported()) {
field_0x3ea ^= 1;
if (field_0x3ea != 0) {
mDoCPd_c::startMotorWave(0, &field_0x3e0, JUTGamePad::CRumble::VAL_0, 0x3c);
}
field_0x3da = 5;
field_0x3ef = SelectType3;
field_0x3f5 = SelectType1;
Z2GetAudioMgr()->seStart(Z2SE_SY_OPTION_SWITCH, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
return true;
case SelectType2:
if (field_0x3e9 == 0) {
field_0x3e9 = 2;
} else {
field_0x3e9--;
}
field_0x3da = 5;
mDoAud_setOutputMode(dMo_soundMode[field_0x3e9]);
setSoundMode(dMo_soundMode[field_0x3e9]);
field_0x3ef = SelectType3;
field_0x3f5 = SelectType2;
Z2GetAudioMgr()->seStart(Z2SE_SY_OPTION_SWITCH, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
return true;
}
}
#endif
return false; return false;
} }
+103
View File
@@ -31,7 +31,9 @@
#if TARGET_PC #if TARGET_PC
#include "dusk/game_clock.h" #include "dusk/game_clock.h"
#include "dusk/menu_pointer.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/ui/touch_controls.hpp"
#endif #endif
typedef void (dMenu_Ring_c::*initFunc)(); typedef void (dMenu_Ring_c::*initFunc)();
@@ -196,6 +198,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
mCursorInterpPrevAngular = false; mCursorInterpPrevAngular = false;
mCursorInterpCurrAngular = false; mCursorInterpCurrAngular = false;
mCursorInterpInit = false; mCursorInterpInit = false;
mPointerTouchPressHoveredCurrent = false;
#endif #endif
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
field_0x674[i] = 0; field_0x674[i] = 0;
@@ -614,6 +617,9 @@ void dMenu_Ring_c::_delete() {
* initializes a new process if mStatus changes * initializes a new process if mStatus changes
*/ */
void dMenu_Ring_c::_move() { void dMenu_Ring_c::_move() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::ItemWheel);
#endif
mRingRadiusH = g_ringHIO.mRingRadiusH; mRingRadiusH = g_ringHIO.mRingRadiusH;
mRingRadiusV = g_ringHIO.mRingRadiusV; mRingRadiusV = g_ringHIO.mRingRadiusV;
mOldStatus = mStatus; // Save current status for check mOldStatus = mStatus; // Save current status for check
@@ -1517,6 +1523,11 @@ void dMenu_Ring_c::stick_wait_proc() {
setDoStatus(0); setDoStatus(0);
return; return;
} }
#if TARGET_PC
if (pointerMove()) {
return;
}
#endif
if (dMw_A_TRIGGER() && !dMeter2Info_isTouchKeyCheck(0xe)) { if (dMw_A_TRIGGER() && !dMeter2Info_isTouchKeyCheck(0xe)) {
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
} }
@@ -1528,6 +1539,70 @@ void dMenu_Ring_c::stick_wait_proc() {
} }
} }
#if TARGET_PC
bool dMenu_Ring_c::pointerMove() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::ItemWheel);
const auto& pointer = dusk::menu_pointer::state();
if (!pointer.valid || mItemsTotal == 0) {
return false;
}
int hoveredSlot = -1;
f32 bestDistance = 42.0f;
for (u8 i = 0; i < mItemsTotal; ++i) {
const f32 x = mItemSlotPosX[i] + mCenterPosX;
const f32 y = mItemSlotPosY[i] + mCenterPosY;
const f32 distance = calcDistance(pointer.x, pointer.y, x, y);
if (distance < bestDistance) {
bestDistance = distance;
hoveredSlot = i;
}
}
if (hoveredSlot < 0) {
return false;
}
if (pointer.pressed) {
mPointerTouchPressHoveredCurrent = pointer.touch && hoveredSlot == mCurrentSlot;
}
dusk::menu_pointer::set_hover_target(static_cast<dusk::menu_pointer::TargetId>(hoveredSlot));
if (mCurrentSlot != hoveredSlot) {
mDirectSelectCursorPos.x = mItemSlotPosX[mCurrentSlot];
mDirectSelectCursorPos.z = mItemSlotPosY[mCurrentSlot];
mCurrentSlot = hoveredSlot;
mDirectSelectActive = true;
field_0x670 = field_0x63e[mCurrentSlot];
setStatus(STATUS_MOVE);
field_0x6b2 = 0;
return true;
}
const bool clickOpensExplain = !pointer.touch || mPointerTouchPressHoveredCurrent;
if (clickOpensExplain && dusk::menu_pointer::consume_click()) {
const u8 item = dComIfGs_getItem(mItemSlots[mCurrentSlot], false);
if (!dMeter2Info_isTouchKeyCheck(0xe) && openExplain(item)) {
dMeter2Info_setItemExplainWindowStatus(1);
field_0x6c4 = mCurrentSlot;
setStatus(STATUS_EXPLAIN);
dMeter2Info_set2DVibration();
setDoStatus(0);
} else {
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
mPointerTouchPressHoveredCurrent = false;
return true;
}
if (pointer.released) {
mPointerTouchPressHoveredCurrent = false;
}
return false;
}
#endif
void dMenu_Ring_c::stick_move_init() { void dMenu_Ring_c::stick_move_init() {
if (mCursorSpeed == 0) { if (mCursorSpeed == 0) {
mCursorSpeed = g_ringHIO.mCursorInitSpeed; mCursorSpeed = g_ringHIO.mCursorInitSpeed;
@@ -1672,12 +1747,40 @@ void dMenu_Ring_c::drawSelectItem() {
#else #else
if (field_0x674[i] < 10) { if (field_0x674[i] < 10) {
#endif #endif
#if TARGET_PC
f32 initSizeX;
f32 initSizeY;
f32 initScaleX;
f32 initScaleY;
Vec pos;
dusk::ui::EquipTarget touchTarget;
if (dusk::ui::get_equip_target(i, touchTarget)) {
initSizeX = touchTarget.width;
initSizeY = touchTarget.height;
initScaleX = 1.0f;
initScaleY = 1.0f;
pos.x = touchTarget.left;
pos.y = touchTarget.top;
pos.z = 0.0f;
} else {
CPaneMgr* meterItemPane = dMeter2Info_getMeterItemPanePtr(i);
if (meterItemPane == NULL) {
continue;
}
initSizeX = meterItemPane->getInitSizeX() * 1.7f;
initSizeY = meterItemPane->getInitSizeY() * 1.7f;
initScaleX = meterItemPane->getInitScaleX();
initScaleY = meterItemPane->getInitScaleY();
pos = meterItemPane->getGlobalVtxCenter(meterItemPane->mPane, true, 0);
}
#else
f32 initSizeX = dMeter2Info_getMeterItemPanePtr(i)->getInitSizeX() * 1.7f; f32 initSizeX = dMeter2Info_getMeterItemPanePtr(i)->getInitSizeX() * 1.7f;
f32 initSizeY = dMeter2Info_getMeterItemPanePtr(i)->getInitSizeY() * 1.7f; f32 initSizeY = dMeter2Info_getMeterItemPanePtr(i)->getInitSizeY() * 1.7f;
f32 initScaleX = dMeter2Info_getMeterItemPanePtr(i)->getInitScaleX(); f32 initScaleX = dMeter2Info_getMeterItemPanePtr(i)->getInitScaleX();
f32 initScaleY = dMeter2Info_getMeterItemPanePtr(i)->getInitScaleY(); f32 initScaleY = dMeter2Info_getMeterItemPanePtr(i)->getInitScaleY();
Vec pos = dMeter2Info_getMeterItemPanePtr(i)->getGlobalVtxCenter( Vec pos = dMeter2Info_getMeterItemPanePtr(i)->getGlobalVtxCenter(
dMeter2Info_getMeterItemPanePtr(i)->mPane, true, 0); dMeter2Info_getMeterItemPanePtr(i)->mPane, true, 0);
#endif
#if TARGET_PC #if TARGET_PC
f32 fVar14 = 0.1f + 0.8f * u; f32 fVar14 = 0.1f + 0.8f * u;
+159 -2
View File
@@ -18,11 +18,15 @@
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include "d/d_msg_scrn_explain.h" #include "d/d_msg_scrn_explain.h"
#include "dusk/frame_interpolation.h"
#include "dusk/settings.h"
#include "JSystem/J2DGraph/J2DAnmLoader.h" #include "JSystem/J2DGraph/J2DAnmLoader.h"
#include "f_op/f_op_msg_mng.h" #include "f_op/f_op_msg_mng.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#include "dusk/menu_pointer.h"
#include "dusk/settings.h"
#endif
static int SelStartFrameTbl[3] = { static int SelStartFrameTbl[3] = {
59, 59,
99, 99,
@@ -54,6 +58,17 @@ static int YnSelStartFrameTbl[2][2] = {
static int YnSelEndFrameTbl[2][2] = {{2138, 3171}, {2150, 3181}}; static int YnSelEndFrameTbl[2][2] = {{2138, 3171}, {2150, 3181}};
#if TARGET_PC
namespace {
constexpr u8 pointer_target(u8 group, u8 index) noexcept {
return static_cast<u8>((group << 4) | (index & 0x0F));
}
constexpr u8 s_pointerSaveSelectTarget = 0;
constexpr u8 s_pointerYesNoSelectTarget = 1;
} // namespace
#endif
static dMs_HIO_c g_msHIO; static dMs_HIO_c g_msHIO;
dMs_HIO_c::dMs_HIO_c() { dMs_HIO_c::dMs_HIO_c() {
@@ -1766,6 +1781,12 @@ void dMenu_save_c::openSaveSelect3() {
void dMenu_save_c::saveSelect() { void dMenu_save_c::saveSelect() {
if (!mDoRst::isReset()) { if (!mDoRst::isReset()) {
#if TARGET_PC
if (pointerSaveSelect()) {
return;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
if (mDoCPd_c::getTrigA(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1)) {
@@ -1792,7 +1813,86 @@ void dMenu_save_c::saveSelect() {
} }
} }
#if TARGET_PC
bool dMenu_save_c::pointerSaveSelect() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
for (u8 i = 0; i < 3; ++i) {
if (!dusk::menu_pointer::hit_pane(mpSelData[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerSaveSelectTarget, i));
const bool clicked = dusk::menu_pointer::consume_click();
if (mSelectedFile != i) {
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
mLastSelFile = mSelectedFile;
mSelectedFile = i;
if (clicked) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::Save,
pointer_target(s_pointerSaveSelectTarget, i));
}
dataSelectAnmSet();
mMenuProc = PROC_SAVE_SELECT_MOVE_ANM;
return true;
}
if (clicked) {
saveSelectStart();
return true;
}
}
return false;
}
bool dMenu_save_c::pointerYesNoSelect(bool errorSelect, u8 errParam, u8 soundParam) {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
for (u8 i = 0; i < 2; ++i) {
if (!dusk::menu_pointer::hit_pane(mpNoYes[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, i));
const bool clicked =
(!errorSelect || mYesNoCursor == i) && dusk::menu_pointer::consume_click();
if (mYesNoCursor != i) {
if (errorSelect) {
errCurMove(errParam, soundParam);
return false;
}
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
mYesNoPrevCursor = mYesNoCursor;
mYesNoCursor = i;
if (clicked) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::Save,
pointer_target(s_pointerYesNoSelectTarget, i));
}
yesnoSelectAnmSet(0);
mMenuProc = PROC_YES_NO_CURSOR_MOVE_ANM;
return true;
}
if (clicked) {
if (errorSelect) {
if (mYesNoCursor != CURSOR_NO) {
if (soundParam == 0) {
mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0);
}
} else if (soundParam == 0) {
mDoAud_seStart(Z2SE_SY_CURSOR_CANCEL, NULL, 0, 0);
}
mSelIcon->setAlphaRate(0.0f);
} else {
yesnoSelectStart();
}
return true;
}
}
return false;
}
#endif
void dMenu_save_c::saveSelectStart() { void dMenu_save_c::saveSelectStart() {
#if TARGET_PC
dusk::menu_pointer::clear_deferred_activation(dusk::menu_pointer::Context::Save);
#endif
mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0); mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0);
selectDataMoveAnmInitSet(SelOpenStartFrameTbl[mSelectedFile], selectDataMoveAnmInitSet(SelOpenStartFrameTbl[mSelectedFile],
SelOpenEndFrameTbl[mSelectedFile]); SelOpenEndFrameTbl[mSelectedFile]);
@@ -1851,6 +1951,19 @@ void dMenu_save_c::dataSelectAnmSet() {
} }
void dMenu_save_c::saveSelectMoveAnime() { void dMenu_save_c::saveSelectMoveAnime() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
if (mSelectedFile != 0xFF &&
dusk::menu_pointer::hit_pane(mpSelData[mSelectedFile], 8.0f))
{
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerSaveSelectTarget, mSelectedFile));
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::Save,
pointer_target(s_pointerSaveSelectTarget, mSelectedFile));
}
}
#endif
bool bookWakuAnmComplete = true; bool bookWakuAnmComplete = true;
bool selWakuAnmComplete = true; bool selWakuAnmComplete = true;
bool var_r29 = true; bool var_r29 = true;
@@ -1900,12 +2013,26 @@ void dMenu_save_c::saveSelectMoveAnime() {
if (mLastSelFile != 0xFF) { if (mLastSelFile != 0xFF) {
mpSelData[mLastSelFile]->getPanePtr()->setAnimation((J2DAnmTransformKey*)NULL); mpSelData[mLastSelFile]->getPanePtr()->setAnimation((J2DAnmTransformKey*)NULL);
} }
#if TARGET_PC
if (dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::Save,
pointer_target(s_pointerSaveSelectTarget, mSelectedFile))) {
saveSelectStart();
return;
}
#endif
mMenuProc = PROC_SAVE_SELECT; mMenuProc = PROC_SAVE_SELECT;
} }
} }
void dMenu_save_c::saveYesNoSelect() { void dMenu_save_c::saveYesNoSelect() {
if (!mDoRst::isReset()) { if (!mDoRst::isReset()) {
#if TARGET_PC
if (pointerYesNoSelect(false)) {
return;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
if (mDoCPd_c::getTrigA(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1)) {
@@ -1933,6 +2060,9 @@ void dMenu_save_c::saveYesNoSelect() {
} }
void dMenu_save_c::yesnoSelectStart() { void dMenu_save_c::yesnoSelectStart() {
#if TARGET_PC
dusk::menu_pointer::clear_deferred_activation(dusk::menu_pointer::Context::Save);
#endif
if (mYesNoCursor != CURSOR_NO) { if (mYesNoCursor != CURSOR_NO) {
mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0); mDoAud_seStart(Z2SE_SY_CURSOR_OK, NULL, 0, 0);
mSelIcon->setAlphaRate(0.0f); mSelIcon->setAlphaRate(0.0f);
@@ -2001,11 +2131,32 @@ void dMenu_save_c::yesnoSelectAnmSet(u8 param_0) {
} }
void dMenu_save_c::yesNoCursorMoveAnm() { void dMenu_save_c::yesNoCursorMoveAnm() {
#if TARGET_PC
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
if (mYesNoCursor != 0xFF &&
dusk::menu_pointer::hit_pane(mpNoYes[mYesNoCursor], 8.0f))
{
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, mYesNoCursor));
if (dusk::menu_pointer::consume_click()) {
dusk::menu_pointer::defer_activation(
dusk::menu_pointer::Context::Save,
pointer_target(s_pointerYesNoSelectTarget, mYesNoCursor));
}
}
#endif
bool selAnmComplete = yesnoSelectMoveAnm(0); bool selAnmComplete = yesnoSelectMoveAnm(0);
bool wakuAnmComplete = yesnoWakuAlpahAnm(mYesNoPrevCursor); bool wakuAnmComplete = yesnoWakuAlpahAnm(mYesNoPrevCursor);
if (selAnmComplete == true && wakuAnmComplete == true) { if (selAnmComplete == true && wakuAnmComplete == true) {
yesnoCursorShow(); yesnoCursorShow();
#if TARGET_PC
if (dusk::menu_pointer::consume_deferred_activation(
dusk::menu_pointer::Context::Save,
pointer_target(s_pointerYesNoSelectTarget, mYesNoCursor))) {
yesnoSelectStart();
return;
}
#endif
mMenuProc = PROC_SAVE_YES_NO_SELECT; mMenuProc = PROC_SAVE_YES_NO_SELECT;
} }
} }
@@ -2181,6 +2332,12 @@ bool dMenu_save_c::errYesNoSelect(u8 param_0, u8 param_1) {
return false; return false;
} }
#if TARGET_PC
if (pointerYesNoSelect(true, param_0, param_1)) {
return true;
}
#endif
stick->checkTrigger(); stick->checkTrigger();
if (mDoCPd_c::getTrigA(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1)) {
+39
View File
@@ -18,6 +18,10 @@
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include <cstring> #include <cstring>
#if TARGET_PC
#include "dusk/menu_pointer.h"
#endif
typedef void (dMenu_Skill_c::*initFunc)(); typedef void (dMenu_Skill_c::*initFunc)();
static initFunc map_init_process[] = { static initFunc map_init_process[] = {
&dMenu_Skill_c::wait_init, &dMenu_Skill_c::wait_init,
@@ -275,6 +279,12 @@ void dMenu_Skill_c::wait_init() {
void dMenu_Skill_c::wait_move() { void dMenu_Skill_c::wait_move() {
u8 oldIndex = mIndex; u8 oldIndex = mIndex;
if (mDoGph_gInf_c::getFader()->getStatus() == 1) { if (mDoGph_gInf_c::getFader()->getStatus() == 1) {
#if TARGET_PC
if (pointerWait()) {
return;
}
#endif
if (mDoCPd_c::getTrigB(PAD_1) != 0) { if (mDoCPd_c::getTrigB(PAD_1) != 0) {
mpDrawCursor->offPlayAnime(0); mpDrawCursor->offPlayAnime(0);
mStatus = 3; mStatus = 3;
@@ -299,6 +309,35 @@ void dMenu_Skill_c::wait_move() {
} }
} }
#if TARGET_PC
bool dMenu_Skill_c::pointerWait() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Collection);
for (u8 i = 0; i < mSkillNum; ++i) {
if (!dusk::menu_pointer::hit_pane(mpLetterParent[i], 8.0f)) {
continue;
}
dusk::menu_pointer::set_hover_target(i);
if (mIndex != i) {
mIndex = i;
changeActiveColor();
Z2GetAudioMgr()->seStart(Z2SE_SY_CURSOR_ITEM, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
if (dusk::menu_pointer::consume_click()) {
mProcess = PROC_WAIT_MOVE;
Z2GetAudioMgr()->seStart(Z2SE_SY_EXP_WIN_OPEN, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibration();
return true;
}
return false;
}
return false;
}
#endif
void dMenu_Skill_c::read_open_init() { void dMenu_Skill_c::read_open_init() {
static const u32 i_id[7] = { static const u32 i_id[7] = {
1716, 1715, 1717, 1718, 1719, 1720, 1721, 1716, 1715, 1717, 1718, 1719, 1720, 1721,
+28 -2
View File
@@ -437,7 +437,12 @@ void dMeter2_c::checkStatus() {
field_0x128 = daPy_py_c::checkNowWolf(); field_0x128 = daPy_py_c::checkNowWolf();
#if TARGET_PC
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
if (!dComIfGp_2dShowCheck() || (msgObject != NULL && msgObject->isPlaceMessage())) {
#else
if (!dComIfGp_2dShowCheck() || dMsgObject_getMsgObjectClass()->isPlaceMessage()) { if (!dComIfGp_2dShowCheck() || dMsgObject_getMsgObjectClass()->isPlaceMessage()) {
#endif
mStatus |= 0x4000; mStatus |= 0x4000;
} else if (dComIfGp_checkPlayerStatus1(0, 1) && dComIfGp_getAStatus() == 0x12) { } else if (dComIfGp_checkPlayerStatus1(0, 1) && dComIfGp_getAStatus() == 0x12) {
mStatus |= 0x200000; mStatus |= 0x200000;
@@ -663,8 +668,15 @@ void dMeter2_c::moveLife() {
draw_life = true; draw_life = true;
} }
if (mLifeGaugeScale != g_drawHIO.mLifeParentScale) { #if TARGET_PC
mLifeGaugeScale = g_drawHIO.mLifeParentScale; const f32 lifeGaugeScale =
g_drawHIO.mLifeParentScale *
std::clamp(dusk::getSettings().game.hudScale.getValue(), 0.5f, 2.0f);
#else
const f32 lifeGaugeScale = g_drawHIO.mLifeParentScale;
#endif
if (mLifeGaugeScale != lifeGaugeScale) {
mLifeGaugeScale = lifeGaugeScale;
draw_life = true; draw_life = true;
} }
@@ -2863,8 +2875,14 @@ void dMeter2_c::alphaAnimeButton() {
u8 var_31; u8 var_31;
var_31 = 0; var_31 = 0;
#if TARGET_PC
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
if ((mStatus & 0x4000) ||
((mStatus & 0x100) && (msgObject != NULL && msgObject->isAutoMessageFlag())) ||
#else
if ((mStatus & 0x4000) || if ((mStatus & 0x4000) ||
((mStatus & 0x100) && dMsgObject_getMsgObjectClass()->isAutoMessageFlag()) || ((mStatus & 0x100) && dMsgObject_getMsgObjectClass()->isAutoMessageFlag()) ||
#endif
((mStatus & 0x40000000) && !(mStatus & 0x100)) || (mStatus & 0x80000000) || (mStatus & 8) || ((mStatus & 0x40000000) && !(mStatus & 0x100)) || (mStatus & 0x80000000) || (mStatus & 8) ||
(mStatus & 0x10) || (mStatus & 0x20) || (mStatus & 0x04000000) || (mStatus & 0x10000000)) (mStatus & 0x10) || (mStatus & 0x20) || (mStatus & 0x04000000) || (mStatus & 0x10000000))
{ {
@@ -2966,7 +2984,15 @@ void dMeter2_c::alphaAnimeButtonCross() {
field_0x190++; field_0x190++;
} }
} else { } else {
#if TARGET_PC
if (dusk::getSettings().game.enableTouchControls) {
mpMeterDraw->setAlphaButtonCrossAnimeMin();
} else {
mpMeterDraw->setAlphaButtonCrossAnimeMax();
}
#else
mpMeterDraw->setAlphaButtonCrossAnimeMax(); mpMeterDraw->setAlphaButtonCrossAnimeMax();
#endif
if (field_0x190 < 5) { if (field_0x190 < 5) {
field_0x190++; field_0x190++;
+35
View File
@@ -25,6 +25,7 @@
#if TARGET_PC #if TARGET_PC
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/ui/icon_provider.hpp"
#include <algorithm> #include <algorithm>
namespace { namespace {
@@ -653,10 +654,22 @@ void dMeter2Draw_c::draw() {
J2DGrafContext* graf_ctx = dComIfGp_getCurrentGrafPort(); J2DGrafContext* graf_ctx = dComIfGp_getCurrentGrafPort();
graf_ctx->setup2D(); graf_ctx->setup2D();
#if TARGET_PC
const bool touchControlsEnabled = dusk::getSettings().game.enableTouchControls;
if (touchControlsEnabled) {
mpButtonParent->hide();
} else {
mpButtonParent->show();
}
#endif
mpScreen->draw(0.0f, 0.0f, graf_ctx); mpScreen->draw(0.0f, 0.0f, graf_ctx);
drawKanteraScreen(1); drawKanteraScreen(1);
drawKanteraScreen(2); drawKanteraScreen(2);
#if TARGET_PC
if (!touchControlsEnabled) {
#endif
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (mpItemXY[i] != NULL) { if (mpItemXY[i] != NULL) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
@@ -705,6 +718,9 @@ void dMeter2Draw_c::draw() {
} }
} }
} }
#if TARGET_PC
}
#endif
if (mpLightDropParent->getAlphaRate() != 0.0f) { if (mpLightDropParent->getAlphaRate() != 0.0f) {
f32 var_f28 = g_drawHIO.mLightDrop.mPikariScaleNormal; f32 var_f28 = g_drawHIO.mLightDrop.mPikariScaleNormal;
@@ -787,7 +803,11 @@ void dMeter2Draw_c::draw() {
} }
} }
#if TARGET_PC
if (!touchControlsEnabled && field_0x738 > 0.0f) {
#else
if (field_0x738 > 0.0f) { if (field_0x738 > 0.0f) {
#endif
drawPikari(mpButtonMidona, &field_0x738, g_drawHIO.mMidnaIconPikariScale, drawPikari(mpButtonMidona, &field_0x738, g_drawHIO.mMidnaIconPikariScale,
g_drawHIO.mMidnaIconPikariFrontOuter, g_drawHIO.mMidnaIconPikariFrontInner, g_drawHIO.mMidnaIconPikariFrontOuter, g_drawHIO.mMidnaIconPikariFrontInner,
g_drawHIO.mMidnaIconPikariBackOuter, g_drawHIO.mMidnaIconPikariBackInner, g_drawHIO.mMidnaIconPikariBackOuter, g_drawHIO.mMidnaIconPikariBackInner,
@@ -2452,6 +2472,11 @@ void dMeter2Draw_c::drawButtonB(u8 i_action, bool param_1, f32 i_posX, f32 i_pos
SAFE_STRCPY(static_cast<J2DTextBox*>(mpBText[i]->getPanePtr())->getStringPtr(), mp_string); SAFE_STRCPY(static_cast<J2DTextBox*>(mpBText[i]->getPanePtr())->getStringPtr(), mp_string);
} }
#if TARGET_PC
if (dusk::getSettings().game.enableTouchControls) {
mpScreen->search(MULTI_CHAR('item_b_n'))->hide();
} else
#endif
if (i_action == 0x26 || i_action == 0x2E) { if (i_action == 0x26 || i_action == 0x2E) {
mpScreen->search(MULTI_CHAR('item_b_n'))->show(); mpScreen->search(MULTI_CHAR('item_b_n'))->show();
var_r31 = 1; var_r31 = 1;
@@ -2729,6 +2754,12 @@ void dMeter2Draw_c::drawButtonXY(int i_no, u8 i_itemNo, u8 i_action, bool param_
mpTextXY[i_no]->scale(g_drawHIO.mButtonXYTextScale, g_drawHIO.mButtonXYTextScale); mpTextXY[i_no]->scale(g_drawHIO.mButtonXYTextScale, g_drawHIO.mButtonXYTextScale);
mpTextXY[i_no]->paneTrans(g_drawHIO.mButtonXYTextPosX, g_drawHIO.mButtonXYTextPosY); mpTextXY[i_no]->paneTrans(g_drawHIO.mButtonXYTextPosX, g_drawHIO.mButtonXYTextPosY);
} }
#if TARGET_PC
if (dusk::getSettings().game.enableTouchControls) {
mpScreen->search(tag[i_no])->hide();
}
#endif
} }
} }
@@ -3294,6 +3325,10 @@ void dMeter2Draw_c::setButtonIconMidonaAlpha(u32 param_0) {
} }
mpButtonXY[2]->setAlpha(255.0f * field_0x724 * temp_f30_2); mpButtonXY[2]->setAlpha(255.0f * field_0x724 * temp_f30_2);
#if TARGET_PC
dusk::ui::update_midna_icon_texture(mpButtonMidona != NULL ? mpButtonMidona->getPanePtr() : NULL);
#endif
} }
void dMeter2Draw_c::setButtonIconAlpha(int i_no, u8 unused0, u32 unused1, bool unused2) { void dMeter2Draw_c::setButtonIconAlpha(int i_no, u8 unused0, u32 unused1, bool unused2) {
+57 -2
View File
@@ -22,6 +22,10 @@
#endif #endif
#include <cstring> #include <cstring>
#if TARGET_PC
#include "dusk/action_bindings.h"
#endif
#if (PLATFORM_WII || PLATFORM_SHIELD) #if (PLATFORM_WII || PLATFORM_SHIELD)
dMeter_map_HIO_c g_meter_mapHIO; dMeter_map_HIO_c g_meter_mapHIO;
#endif #endif
@@ -539,6 +543,12 @@ void dMeterMap_c::_move(u32 param_0) {
} }
#endif #endif
#if TARGET_PC
if (mMap->refreshTextureSize()) {
mMapJ2DPicture->changeTexture(mMap->getResTIMGPointer(), 0);
}
#endif
int stayNo = dComIfGp_roomControl_getStayNo(); int stayNo = dComIfGp_roomControl_getStayNo();
field_0x14 = param_0; field_0x14 = param_0;
@@ -732,7 +742,38 @@ void dMeterMap_c::ctrlShowMap() {
} }
} }
} else if (!mDoCPd_c::getTrigUp(PAD_1) && !mDoCPd_c::getTrigDown(PAD_1)) { }
#if TARGET_PC
else if (!isEventRunCheck() &&
(dMeter2Info_getMapStatus() == 0 || dMeter2Info_getMapStatus() == 1) &&
!dMeter2Info_isSub2DStatus(1) && (isFmapScreen() || isDmapScreen()) &&
dusk::getActionBindTrig(dusk::ActionBinds::OPEN_MAP_SCREEN, PAD_1))
{
dMeter2Info_setMapStatus(2);
dMeter2Info_setMapKeyDirection(0x400);
Z2GetAudioMgr()->seStart(Z2SE_SY_MAP_OPEN_S, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibration();
} else if (!isEventRunCheck() &&
(dMeter2Info_getMapStatus() == 0 || dMeter2Info_getMapStatus() == 1) &&
isEnableDispMapAndMapDispSizeTypeNo() &&
dusk::getActionBindTrig(dusk::ActionBinds::TOGGLE_MINIMAP, PAD_1))
{
if (isDispPosInsideFlg()) {
setDispPosOutsideFlg_SE_On();
Z2GetAudioMgr()->seStart(Z2SE_SY_MAP_CLOSE_S, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_setMapStatus(0);
} else {
setDispPosInsideFlg_SE_On();
Z2GetAudioMgr()->seStart(Z2SE_SY_MAP_OPEN_S, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibration();
dMeter2Info_setMapStatus(1);
}
}
#endif
else if (!mDoCPd_c::getTrigUp(PAD_1) && !mDoCPd_c::getTrigDown(PAD_1)) {
keyCheck(); keyCheck();
} }
@@ -827,7 +868,21 @@ void dMeterMap_c::meter_map_move(u32 param_0) {
dMeter2Info_set2DVibration(); dMeter2Info_set2DVibration();
} }
dMeter2Info_resetPauseStatus(); dMeter2Info_resetPauseStatus();
} else if ( }
#if TARGET_PC
else if (!dComIfGp_event_runCheck() && !dMsgObject_isTalkNowCheck() &&
(dMeter2Info_getMapStatus() == 0 || dMeter2Info_getMapStatus() == 1) &&
!dMeter2Info_isSub2DStatus(1) && (isFmapScreen() || isDmapScreen()) &&
dusk::getActionBindTrig(dusk::ActionBinds::OPEN_MAP_SCREEN, PAD_1))
{
dMeter2Info_setMapStatus(2);
dMeter2Info_setMapKeyDirection(0x400);
Z2GetAudioMgr()->seStart(Z2SE_SY_MAP_OPEN_S, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
dMeter2Info_set2DVibration();
}
#endif
else if (
#if DEBUG #if DEBUG
dMw_RIGHT_TRIGGER() && dMw_RIGHT_TRIGGER() &&
#else #else
+15
View File
@@ -13,6 +13,7 @@
#include "JSystem/JUtility/JUTFont.h" #include "JSystem/JUtility/JUTFont.h"
#if TARGET_PC #if TARGET_PC
#include "dusk/menu_pointer.h"
#include "dusk/scope_guard.hpp" #include "dusk/scope_guard.hpp"
#endif #endif
@@ -575,6 +576,20 @@ void jmessage_tReference::pageSend() {
void jmessage_tReference::selectMessage() { void jmessage_tReference::selectMessage() {
if (mSelectNum != 0) { if (mSelectNum != 0) {
#if TARGET_PC
u8 pointerChoice = 0xFF;
if (dusk::menu_pointer::get_dialog_choice(pointerChoice) && pointerChoice < mSelectNum &&
pointerChoice != mSelectPos)
{
mSelectPos = pointerChoice;
if (mSelectType != 0) {
getObjectPtr()->getSequenceProcessor()->calcStringLength();
}
Z2GetAudioMgr()->seStart(Z2SE_SY_TALK_CURSOR, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
-1.0f, 0);
}
#endif
mpStick->checkTrigger(); mpStick->checkTrigger();
if (mSelectType == 0) { if (mSelectType == 0) {
+18 -13
View File
@@ -26,12 +26,13 @@
#include <cstring> #include <cstring>
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "dusk/version.hpp"
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_lib.h" #include "m_Do/m_Do_lib.h"
#if TARGET_PC #if TARGET_PC
#include "dusk/menu_pointer.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/version.hpp"
#include <vector> #include <vector>
#include <array> #include <array>
#include <algorithm> #include <algorithm>
@@ -427,17 +428,6 @@ static void dummyStrings() {
dMsgObject_HIO_c g_MsgObject_HIO_c; dMsgObject_HIO_c g_MsgObject_HIO_c;
int dMsgObject_c::_execute() { int dMsgObject_c::_execute() {
// TODO: enabling wii message overrides fixes direction text, but gives wrong item control text
/*#if TARGET_PC
if (dusk::getSettings().game.enableMirrorMode) {
// enable wii message index override
g_MsgObject_HIO_c.mMessageDisplay = 1;
} else if (!dusk::getSettings().game.enableMirrorMode && g_MsgObject_HIO_c.mMessageDisplay == 1) {
g_MsgObject_HIO_c.mMessageDisplay = 0;
}
#endif*/
field_0x4c7 = 0; field_0x4c7 = 0;
if (mpTalkHeap != NULL) { if (mpTalkHeap != NULL) {
field_0x148 = mDoExt_setCurrentHeap(mpTalkHeap); field_0x148 = mDoExt_setCurrentHeap(mpTalkHeap);
@@ -1123,7 +1113,20 @@ void dMsgObject_c::selectProc() {
dComIfGp_setAStatusForce(0x2a, 0); dComIfGp_setAStatusForce(0x2a, 0);
} }
} }
if (mDoCPd_c::getTrigA(0)) { #if TARGET_PC
jmessage_tReference* pRef = (jmessage_tReference*)mpRenProc->getReference();
u8 pointerChoice = 0xFF;
bool pointerConfirm = dusk::menu_pointer::consume_dialog_click(pointerChoice) &&
pointerChoice < pRef->getSelectNum();
if (pointerConfirm) {
pRef->setSelectPos(pointerChoice);
}
#endif
if (mDoCPd_c::getTrigA(0)
#if TARGET_PC
|| pointerConfirm
#endif
) {
if (getSelectCursorPosLocal() != 0xff) { if (getSelectCursorPosLocal() != 0xff) {
field_0x1a3 = 1; field_0x1a3 = 1;
} }
@@ -1145,7 +1148,9 @@ void dMsgObject_c::selectProc() {
} }
field_0x1a3 = 2; field_0x1a3 = 2;
} }
#ifndef TARGET_PC
jmessage_tReference* pRef = (jmessage_tReference*)mpRenProc->getReference(); jmessage_tReference* pRef = (jmessage_tReference*)mpRenProc->getReference();
#endif
if (getStatusLocal() == 8) { if (getStatusLocal() == 8) {
if (isMidonaMessage() && field_0x1a3 != 0) { if (isMidonaMessage() && field_0x1a3 != 0) {
if (field_0x1a3 == 2 && getSelectCancelPos() == 3) { if (field_0x1a3 == 2 && getSelectCancelPos() == 3) {
+56
View File
@@ -16,6 +16,17 @@
#include "d/d_msg_object.h" #include "d/d_msg_object.h"
#include "d/d_pane_class.h" #include "d/d_pane_class.h"
#if TARGET_PC
#include "dusk/menu_pointer.h"
namespace {
bool hit_choice_pane(CPaneMgr* pane, f32 padding) {
return pane != NULL && pane->getPanePtr() != NULL && pane->getPanePtr()->isVisible() &&
dusk::menu_pointer::hit_pane(pane, padding);
}
} // namespace
#endif
typedef void (dMsgScrn3Select_c::*processFn)(); typedef void (dMsgScrn3Select_c::*processFn)();
processFn process[] = { processFn process[] = {
&dMsgScrn3Select_c::open1Proc, &dMsgScrn3Select_c::open2Proc, &dMsgScrn3Select_c::waitProc, &dMsgScrn3Select_c::open1Proc, &dMsgScrn3Select_c::open2Proc, &dMsgScrn3Select_c::waitProc,
@@ -470,6 +481,9 @@ bool dMsgScrn3Select_c::selAnimeMove(u8 i_selNum, u8 param_1, bool param_2) {
mSelNum = i_selNum; mSelNum = i_selNum;
field_0x114 = 0; field_0x114 = 0;
field_0x108 = param_2; field_0x108 = param_2;
#if TARGET_PC
pointerMove();
#endif
(this->*process[mProcess])(); (this->*process[mProcess])();
@@ -518,6 +532,48 @@ bool dMsgScrn3Select_c::selAnimeMove(u8 i_selNum, u8 param_1, bool param_2) {
return mProcess == PROC_SELECT_e ? TRUE : FALSE; return mProcess == PROC_SELECT_e ? TRUE : FALSE;
} }
#if TARGET_PC
bool dMsgScrn3Select_c::pointerMove() {
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Dialog);
mDPDPoint = 0xFF;
const u8 firstPane = mSelNum == 2 ? 1 : 0;
for (u8 choice = 0; choice < mSelNum; ++choice) {
const u8 paneIndex = firstPane + choice;
if (paneIndex >= 3) {
continue;
}
// TODO: this sucks and should be replaced with Wii mpTouchArea
bool hit = hit_choice_pane(mpSel_c[paneIndex], 8.0f) ||
hit_choice_pane(mpTmSel_c[paneIndex], 24.0f) ||
hit_choice_pane(mpTmrSel_c[paneIndex], 24.0f) ||
hit_choice_pane(mpKahen_c[paneIndex], 8.0f) ||
hit_choice_pane(mpCursor_c[paneIndex], 8.0f);
for (int i = 0; i < 5 && !hit; ++i) {
hit = hit_choice_pane(mpSelCldw_c[i][paneIndex], 8.0f);
}
if (!hit) {
continue;
}
mDPDPoint = choice;
field_0x110 = paneIndex;
dusk::menu_pointer::set_hover_target(choice);
dusk::menu_pointer::set_dialog_choice(choice, dusk::menu_pointer::peek_click());
return true;
}
return false;
}
bool dMsgScrn3Select_c::consumePointerClick() {
u8 choice = 0xFF;
return dusk::menu_pointer::consume_dialog_click(choice);
}
#endif
bool dMsgScrn3Select_c::selAnimeEnd() { bool dMsgScrn3Select_c::selAnimeEnd() {
if (mProcess == PROC_MAX_e) { if (mProcess == PROC_MAX_e) {
return true; return true;

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