mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2025-10-30 08:03:03 +00:00
Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42646e2cb1 | ||
|
|
54950a1040 | ||
|
|
24704d86f1 | ||
|
|
b5360b0546 | ||
|
|
46d9e92dda | ||
|
|
a215103002 | ||
|
|
bb7030bcd1 | ||
|
|
0bc0fd2610 | ||
|
|
54997438de |
28 changed files with 2724 additions and 61 deletions
2
.github/workflows/validate.yml
vendored
2
.github/workflows/validate.yml
vendored
|
|
@ -9,7 +9,7 @@ on:
|
|||
N64RECOMP_COMMIT:
|
||||
type: string
|
||||
required: false
|
||||
default: '989a86b36912403cd323de884bf834f2605ea770'
|
||||
default: 'a13e5cff96686776b0e03baf23923e3c1927b770'
|
||||
DXC_CHECKSUM:
|
||||
type: string
|
||||
required: false
|
||||
|
|
|
|||
4
.gitmodules
vendored
4
.gitmodules
vendored
|
|
@ -19,6 +19,4 @@
|
|||
[submodule "Zelda64RecompSyms"]
|
||||
path = Zelda64RecompSyms
|
||||
url = https://github.com/Zelda64Recomp/Zelda64RecompSyms
|
||||
[submodule "lib/slot_map"]
|
||||
path = lib/slot_map
|
||||
url = https://github.com/SergeyMakeev/slot_map
|
||||
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ target_include_directories(Zelda64Recompiled PRIVATE
|
|||
${CMAKE_SOURCE_DIR}/lib/rt64/src/render
|
||||
${CMAKE_SOURCE_DIR}/lib/freetype-windows-binaries/include
|
||||
${CMAKE_SOURCE_DIR}/lib/rt64/src/contrib/nativefiledialog-extended/src/include
|
||||
${CMAKE_SOURCE_DIR}/lib/slot_map/slot_map
|
||||
${CMAKE_SOURCE_DIR}/lib/SlotMap
|
||||
${CMAKE_BINARY_DIR}/shaders
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
|
@ -291,7 +291,7 @@ if (WIN32)
|
|||
)
|
||||
|
||||
target_sources(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/icons/app.rc)
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE SDL2)
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE SDL2 Winmm.lib)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
|
|
@ -309,8 +309,6 @@ endif()
|
|||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(X11 REQUIRED)
|
||||
|
||||
add_compile_definitions("RT64_SDL_WINDOW_VULKAN")
|
||||
|
||||
# Generate icon_bytes.c from the app icon PNG.
|
||||
|
|
@ -325,14 +323,6 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
|||
|
||||
target_include_directories(Zelda64Recompiled PRIVATE ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
message(STATUS "X11_FOUND = ${X11_FOUND}")
|
||||
message(STATUS "X11_Xrandr_FOUND = ${X11_Xrandr_FOUND}")
|
||||
message(STATUS "X11_INCLUDE_DIR = ${X11_INCLUDE_DIR}")
|
||||
message(STATUS "X11_LIBRARIES = ${X11_LIBRARIES}")
|
||||
|
||||
target_include_directories(Zelda64Recompiled PRIVATE ${X11_INCLUDE_DIR} ${X11_Xrandr_INCLUDE_PATH})
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE ${X11_LIBRARIES} ${X11_Xrandr_LIB})
|
||||
|
||||
find_package(Freetype REQUIRED)
|
||||
|
||||
message(STATUS "FREETYPE_FOUND = ${FREETYPE_FOUND}")
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -3,6 +3,10 @@ Zelda 64: Recompiled is a project that uses [N64: Recompiled](https://github.com
|
|||
|
||||
### [Check out the latest release here](https://github.com/Mr-Wiseguy/Zelda64Recomp/releases/latest).
|
||||
|
||||
Join the [N64: Recompiled Community Discord](https://discord.gg/AWZThJ4dPf) to discuss this and other N64: Recompiled projects!
|
||||
|
||||
[](https://discord.gg/AWZThJ4dPf)
|
||||
|
||||
### **This repository and its releases do not contain game assets. The original game is required to build or run this project.**
|
||||
|
||||
<div align="left" valign="middle">
|
||||
|
|
@ -48,7 +52,7 @@ A GPU supporting Direct3D 12.0 (Shader Model 6), Vulkan 1.2, or Metal Argument B
|
|||
* Intel HD 510 (Skylake)
|
||||
* A Mac with Apple Silicon or an Intel 7th Gen CPU with MacOS 13.0+
|
||||
|
||||
On x86-64 PCs, a CPU supporting the AVX instruction set is also required (Intel Core 2000 series or AMD Bulldozer and newer). ARM64 builds will work on any ARM64 CPU.
|
||||
On x86-64 PCs, a CPU supporting the SSE4.1 instruction set is also required (Intel Core 2 Penryn series or AMD Bulldozer and newer). ARM64 builds will work on any ARM64 CPU.
|
||||
|
||||
If you have issues with crashes on startup, make sure your graphics drivers are fully up to date.
|
||||
|
||||
|
|
@ -136,7 +140,10 @@ You'll probably also want to change the default behavior so that you don't need
|
|||
Instead, you can change the game by installing mods. See the [mod support](#mod-support) section for details.
|
||||
|
||||
#### Does this project have a randomizer?
|
||||
Yes, there is a randomizer available as a mod for this project which can be found on the thunderstore page linked in [mod support](#mod-support).
|
||||
Yes, there is a randomizer available as a mod for this project which can be found at https://github.com/RecompRando/MMRecompRando/releases/latest. Simply download MMRecompRando.zip from the releases and install it like any other mod.
|
||||
|
||||
#### Can you run this project as a portable application?
|
||||
Yes, if you place a file named `portable.txt` in the same folder as the executable then this project will run in portable mode. In portable mode, the save files, config files, and mods are placed in the same folder as the executable.
|
||||
|
||||
## Known Issues
|
||||
* Overlays such as MSI Afterburner and other software such as Wallpaper Engine can cause performance issues with this project that prevent the game from rendering correctly. Disabling such software is recommended.
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace zelda64 {
|
|||
|
||||
void enable_instant_present() override;
|
||||
void send_dl(const OSTask *task) override;
|
||||
void update_screen(uint32_t vi_origin) override;
|
||||
void update_screen() override;
|
||||
void shutdown() override;
|
||||
uint32_t get_display_framerate() const override;
|
||||
float get_resolution_scale() const override;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "Zelda64Recompiled.exe",
|
||||
"name": "Zelda64Recompiled.exe",
|
||||
"currentDir": "${workspaceRoot}"
|
||||
"currentDir": "${workspaceRoot}",
|
||||
"args": ["--show-console"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit c5e268aa0f71cf06a10a001da981dc3e02e7dff0
|
||||
Subproject commit df7e820d8c55e4fcb4616c210cbb2c01b25cd48c
|
||||
257
lib/SlotMap/README.md
Normal file
257
lib/SlotMap/README.md
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
This file is originally from the repo: https://github.com/SergeyMakeev/SlotMap
|
||||
|
||||
The original license and README are as follows:
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Sergey Makeev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
# Slot Map
|
||||
|
||||
[](https://github.com/SergeyMakeev/slot_map/actions)
|
||||
[](https://ci.appveyor.com/project/SergeyMakeev/slot-map)
|
||||
[](https://codecov.io/gh/SergeyMakeev/slot_map)
|
||||

|
||||
|
||||
A Slot Map is a high-performance associative container with persistent unique keys to access stored values. Upon insertion, a key is returned that can be used to later access or remove the values. Insertion, removal, and access are all guaranteed to take `O(1)` time (best, worst, and average case)
|
||||
Great for storing collections of objects that need stable, safe references but have no clear ownership.
|
||||
|
||||
The difference between a `std::unordered_map` and a `dod::slot_map` is that the slot map generates and returns the key when inserting a value. A key is always unique and will only refer to the value that was inserted.
|
||||
|
||||
Usage example:
|
||||
```cpp
|
||||
slot_map<std::string> strings;
|
||||
auto red = strings.emplace("Red");
|
||||
auto green = strings.emplace("Green");
|
||||
auto blue = strings.emplace("Blue");
|
||||
|
||||
const std::string* val1 = strings.get(red);
|
||||
if (val1)
|
||||
{
|
||||
printf("red = '%s'\n", val1->c_str());
|
||||
}
|
||||
|
||||
strings.erase(green);
|
||||
printf("%d\n", strings.has(green));
|
||||
printf("%d\n", strings.has(blue));
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
red = 'Red'
|
||||
0
|
||||
1
|
||||
```
|
||||
|
||||
# Implementation details
|
||||
|
||||
The slot map container will allocate memory in pages (default page size = 4096 elements) to avoid memory spikes during growth and be able to deallocate pages that are no longer needed.
|
||||
Also, the page-based memory allocator is very important since it guarantees "pointers stability"; hence, we never move values in memory.
|
||||
|
||||
|
||||
Keys are always uses `uint64_t/uint32_t` (configurable) and technically typless, but we "artificially" make them typed to get a few extra compile-time checks.
|
||||
i.e., the following code will produce a compiler error
|
||||
```cpp
|
||||
slot_map<std::string> strings;
|
||||
slot_map<int> numbers;
|
||||
slot_map<int>::key numKey = numbers.emplace(3);
|
||||
const std::string* value = strings.get(numKey); // <---- can not use slot_map<int>::key to index slot_map<std::string> !
|
||||
```
|
||||
|
||||
The keys can be converted to/from their numeric types if you do not need additional type checks.
|
||||
```cpp
|
||||
slot_map<int> numbers;
|
||||
slot_map<int>::key numKey = numbers.emplace(3);
|
||||
uint64_t rawKey = numKey; // convert to numeric type (like cast pointer to void*)
|
||||
...
|
||||
slot_map<int>::key numKey2{rawKey}; // create key from numeric type
|
||||
```
|
||||
|
||||
When a slot is reused, its version is automatically incremented (to invalidate all existing keys that refers to the same slot).
|
||||
But since we only use 20-bits *(10-bits for 32 bit keys)* for version counter, there is a possibility that the version counter will wrap around,
|
||||
and a new item will get the same key as a removed item.
|
||||
|
||||
To mitigate this potential issue, once the version counter overflows, we disable that slot so that no new keys are returned for this slot
|
||||
(this gives us a guarantee that there are no key collisions)
|
||||
|
||||
To prevent version overflow from happening too often, we need to ensure that we don't reuse the same slot too often.
|
||||
So we do not reuse recently freed slot-indices as long as their number is below a certain threshold (`kMinFreeIndices = 64`).
|
||||
|
||||
Keys also can carry a few extra bits of information provided by a user that we called `tag`.
|
||||
That might be handy to add application-specific data to keys.
|
||||
|
||||
For example:
|
||||
```cpp
|
||||
slot_map<std::string> strings;
|
||||
auto red = strings.emplace("Red");
|
||||
red.set_tag(13);
|
||||
|
||||
auto tag = red.get_tag();
|
||||
assert(tag == 13);
|
||||
```
|
||||
|
||||
Here is how a key structure looks like internally
|
||||
|
||||
64-bit key type
|
||||
|
||||
| Component | Number of bits |
|
||||
| ---------------|------------------------|
|
||||
| tag | 12 |
|
||||
| version | 20 (0..1,048,575 |
|
||||
| index | 32 (0..4,294,967,295) |
|
||||
|
||||
32-bit key type
|
||||
|
||||
| Component | Number of bits |
|
||||
| ---------------|---------------------|
|
||||
| tag | 2 |
|
||||
| version | 10 (0..1023) |
|
||||
| index | 20 (0..1,048,575) |
|
||||
|
||||
Note: To use your custom memory allocator define `SLOT_MAP_ALLOC`/`SLOT_MAP_FREE` before including `"slot_map.h"`
|
||||
|
||||
```cpp
|
||||
#define SLOT_MAP_ALLOC(sizeInBytes, alignment) aligned_alloc(alignment, sizeInBytes)
|
||||
#define SLOT_MAP_FREE(ptr) free(ptr)
|
||||
#include "slot_map.h"
|
||||
```
|
||||
|
||||
|
||||
# API
|
||||
|
||||
`bool has_key(key k) const noexcept`
|
||||
Returns true if the slot map contains a specific key
|
||||
|
||||
`void reset()`
|
||||
Clears the slot map and releases any allocated memory.
|
||||
Note: By calling this function, you must guarantee that no handles are in use!
|
||||
Otherwise calling this function might be dangerous and lead to key "collisions".
|
||||
You might consider using "clear()" instead.
|
||||
|
||||
`void clear()`
|
||||
Clears the slot map but keeps the allocated memory for reuse.
|
||||
Automatically increases version for all the removed elements (the same as calling "erase()" for all existing elements)
|
||||
|
||||
`const T* get(key k) const noexcept`
|
||||
If key exists returns a const pointer to the value corresponding to the given key or returns null elsewere.
|
||||
|
||||
`T* get(key k)`
|
||||
If key exists returns a pointer to the value corresponding to the given key or returns null elsewere.
|
||||
|
||||
`key emplace(Args&&... args)`
|
||||
Constructs element in-place and returns a unique key that can be used to access this value.
|
||||
|
||||
`void erase(key k)`
|
||||
Removes element (if such key exists) from the slot map.
|
||||
|
||||
`std::optional<T> pop(key k)`
|
||||
Removes element (if such key exists) from the slot map, returning the value at the key if the key was not previously removed.
|
||||
|
||||
`bool empty() const noexcept`
|
||||
Returns true if the slot map is empty.
|
||||
|
||||
`size_type size() const noexcept`
|
||||
Returns the number of elements in the slot map.
|
||||
|
||||
`void swap(slot_map& other) noexcept`
|
||||
Exchanges the content of the slot map by the content of another slot map object of the same type.
|
||||
|
||||
`slot_map(const slot_map& other)`
|
||||
Copy constructor
|
||||
|
||||
`slot_map& operator=(const slot_map& other)`
|
||||
Copy assignment
|
||||
|
||||
`slot_map(slot_map&& other) noexcept`
|
||||
Move constructor
|
||||
|
||||
`slot_map& operator=(slot_map&& other) noexcept`
|
||||
Move asignment
|
||||
|
||||
|
||||
`const_values_iterator begin() const noexcept`
|
||||
`const_values_iterator end() const noexcept`
|
||||
Const values iterator
|
||||
|
||||
```cpp
|
||||
for (const auto& value : slotMap)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
`Items items() const noexcept`
|
||||
Const key/value iterator
|
||||
|
||||
```cpp
|
||||
for (const auto& [key, value] : slotMap.items())
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
# References
|
||||
|
||||
Sean Middleditch
|
||||
Data Structures for Game Developers: The Slot Map, 2013
|
||||
https://web.archive.org/web/20180121142549/http://seanmiddleditch.com/data-structures-for-game-developers-the-slot-map/
|
||||
|
||||
Niklas Gray
|
||||
Building a Data-Oriented Entity System (part 1), 2014
|
||||
http://bitsquid.blogspot.com/2014/08/building-data-oriented-entity-system.html
|
||||
|
||||
Noel Llopis
|
||||
Managing Data Relationships, 2010
|
||||
https://gamesfromwithin.com/managing-data-relationships
|
||||
|
||||
Stefan Reinalter
|
||||
Adventures in data-oriented design - Part 3c: External References, 2013
|
||||
https://blog.molecular-matters.com/2013/07/24/adventures-in-data-oriented-design-part-3c-external-references/
|
||||
|
||||
Niklas Gray
|
||||
Managing Decoupling Part 4 - The ID Lookup Table, 2011
|
||||
https://bitsquid.blogspot.com/2011/09/managing-decoupling-part-4-id-lookup.html
|
||||
|
||||
Sander Mertens
|
||||
Making the most of ECS identifiers, 2020
|
||||
https://ajmmertens.medium.com/doing-a-lot-with-a-little-ecs-identifiers-25a72bd2647
|
||||
|
||||
Michele Caini
|
||||
ECS back and forth. Part 9 - Sparse sets and EnTT, 2020
|
||||
https://skypjack.github.io/2020-08-02-ecs-baf-part-9/
|
||||
|
||||
Andre Weissflog
|
||||
Handles are the better pointers, 2018
|
||||
https://floooh.github.io/2018/06/17/handles-vs-pointers.html
|
||||
|
||||
Allan Deutsch
|
||||
C++Now 2017: "The Slot Map Data Structure", 2017
|
||||
https://www.youtube.com/watch?v=SHaAR7XPtNU
|
||||
|
||||
Jeff Gates
|
||||
Init, Update, Draw - Data Arrays, 2012
|
||||
https://greysphere.tumblr.com/post/31601463396/data-arrays
|
||||
|
||||
Niklas Gray
|
||||
Data Structures Part 1: Bulk Data, 2019
|
||||
https://ourmachinery.com/post/data-structures-part-1-bulk-data/
|
||||
|
||||
|
||||
1366
lib/SlotMap/slot_map.h
Normal file
1366
lib/SlotMap/slot_map.h
Normal file
File diff suppressed because it is too large
Load diff
2
lib/rt64
2
lib/rt64
|
|
@ -1 +1 @@
|
|||
Subproject commit ada6cc62c421b142d9d90154765e44348115bd9e
|
||||
Subproject commit 23cab603c4f9f4a8b369b38e036f1aa484603878
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit b8ac8ebd89aa1cd18f20ce6e4ad1cac716f1933f
|
||||
|
|
@ -70,7 +70,13 @@ void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages);
|
|||
void recomp_reset_autosave_timer();
|
||||
void recomp_reset_autosave_timer_slow();
|
||||
|
||||
RECOMP_DECLARE_EVENT(recomp_on_autosave(PlayState* play));
|
||||
RECOMP_DECLARE_EVENT(recomp_after_autosave(PlayState* play));
|
||||
|
||||
RECOMP_EXPORT void recomp_do_autosave(PlayState* play) {
|
||||
|
||||
// @recomp_event recomp_on_autosave(PlayState* play): Autosave triggered.
|
||||
recomp_on_autosave(play);
|
||||
// Transfer the scene flags into the cycle flags.
|
||||
Play_SaveCycleSceneFlags(&play->state);
|
||||
// Transfer the cycle flags into the save buffer. Logic copied from func_8014546C.
|
||||
|
|
@ -97,6 +103,9 @@ RECOMP_EXPORT void recomp_do_autosave(PlayState* play) {
|
|||
Sram_SyncWriteToFlash(sramCtx, gFlashOwlSaveStartPages[fileNum * 2 + 1], gFlashOwlSaveNumPages[fileNum * 2 + 1]);
|
||||
|
||||
gSaveContext.save.isOwlSave = false;
|
||||
|
||||
// @recomp_event recomp_on_autosave(PlayState* play): Autosave finished.
|
||||
recomp_after_autosave(play);
|
||||
}
|
||||
|
||||
bool loading_deletes_owl_save = true;
|
||||
|
|
@ -401,7 +410,7 @@ void autosave_post_play_update(PlayState* play) {
|
|||
|
||||
OSTime time_now = osGetTime();
|
||||
|
||||
// Check the following conditions:
|
||||
// Check the following conditions for autosave safety:
|
||||
// * The UI is in a normal state.
|
||||
// * Time is passing.
|
||||
// * No message is on screen.
|
||||
|
|
@ -409,6 +418,10 @@ void autosave_post_play_update(PlayState* play) {
|
|||
// * No cutscene is running.
|
||||
// * The game is not in cutscene mode.
|
||||
// * The clock has not reached the final 3 hours.
|
||||
// * The player is not in an active/inactive minigame (not all minigames use this flag, default is STATUS_END)
|
||||
// * The player is not in a timed minigame in the first set (Shooting Gallery, Butler Race, Spirit House, etc)
|
||||
// * The player is not in a timed minigame in the second set (Goron Race, Treasure Game, Beaver Bros, etc)
|
||||
// * The player is not taking a boat cruise
|
||||
// * The player is allowed to pause.
|
||||
if (gSaveContext.hudVisibility == HUD_VISIBILITY_ALL &&
|
||||
R_TIME_SPEED != 0 &&
|
||||
|
|
@ -418,6 +431,10 @@ void autosave_post_play_update(PlayState* play) {
|
|||
gSaveContext.save.cutsceneIndex < 0xFFF0 &&
|
||||
!Play_InCsMode(play) &&
|
||||
!reached_final_three_hours() &&
|
||||
gSaveContext.minigameStatus == MINIGAME_STATUS_END &&
|
||||
gSaveContext.timerStates[TIMER_ID_MINIGAME_1] == TIMER_STATE_OFF &&
|
||||
gSaveContext.timerStates[TIMER_ID_MINIGAME_2] == TIMER_STATE_OFF &&
|
||||
!(CHECK_EVENTINF(EVENTINF_41)) &&
|
||||
gCanPause
|
||||
) {
|
||||
frames_since_autosave_ready++;
|
||||
|
|
@ -612,6 +629,9 @@ RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCt
|
|||
}
|
||||
// @recomp Handle autosaves.
|
||||
else if (gSaveContext.save.isOwlSave == SAVE_TYPE_AUTOSAVE) {
|
||||
// Clear Rock Sirloin from being held, due to MM hardcoding its behavior
|
||||
gSaveContext.unk_1014 = 0;
|
||||
|
||||
gSaveContext.save.entrance = spawn_entrance_from_autosave_entrance(gSaveContext.save.entrance);
|
||||
|
||||
// Skip the turtle cutscene that happens when entering Great Bay Temple.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,17 @@ void camera_post_play_update(PlayState* play) {
|
|||
if (force_interpolation) {
|
||||
force_camera_interpolation();
|
||||
}
|
||||
// Dedicated section for workarounds where the heuristic fails to detect small camera teleports.
|
||||
bool force_no_interpolation = false;
|
||||
|
||||
// Music Box House. The camera gets teleported by a very small amount when Link gets the Gibdo mask.
|
||||
if (play->sceneId == SCENE_MUSICHOUSE && play->csCtx.scriptIndex == 2 && play->csCtx.curFrame == 525 && active_cam->setting == CAM_SET_FREE0) {
|
||||
force_no_interpolation = true;
|
||||
}
|
||||
|
||||
if (force_no_interpolation) {
|
||||
force_camera_skip_interpolation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,3 +14,33 @@ symbols = [
|
|||
{ name = "FileSelect_Init_NORELOCATE", vram = 0x80813C98 },
|
||||
{ name = "DayTelop_Init_NORELOCATE", vram = 0x80815820 },
|
||||
]
|
||||
|
||||
[[section]]
|
||||
name = "..ovl_En_Hg"
|
||||
rom = 0x01034170
|
||||
vram = 0x80BCF1D0
|
||||
size = 0x10E0
|
||||
|
||||
symbols = [
|
||||
{ name = "sPamelasFatherGibdoAnimationInfo", vram = 0x80bd0008 },
|
||||
]
|
||||
|
||||
[[section]]
|
||||
name = "..ovl_En_Hgo"
|
||||
rom = 0x01035250
|
||||
vram = 0x80BD02B0
|
||||
size = 0xF30
|
||||
|
||||
symbols = [
|
||||
{ name = "sPamelasFatherHumanAnimationInfo", vram = 0x80BD0EA0 },
|
||||
]
|
||||
|
||||
[[section]]
|
||||
name = "..ovl_En_Pamera"
|
||||
rom = 0x0103D250
|
||||
vram = 0x80BD82B0
|
||||
size = 0x2780
|
||||
|
||||
symbols = [
|
||||
{ name = "sPamelaAnimationInfo", vram = 0x80BDA4B8 },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
typedef enum PamelasFatherGibdoLimb {
|
||||
/* 0x00 */ PAMELAS_FATHER_GIBDO_LIMB_NONE,
|
||||
/* 0x01 */ PAMELAS_FATHER_GIBDO_LIMB_ROOT,
|
||||
/* 0x02 */ PAMELAS_FATHER_GIBDO_LIMB_ABDOMEN,
|
||||
/* 0x03 */ PAMELAS_FATHER_GIBDO_LIMB_CHEST,
|
||||
/* 0x04 */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_UPPER_ARM,
|
||||
/* 0x05 */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_FOREARM,
|
||||
/* 0x06 */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_HAND,
|
||||
/* 0x07 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_UPPER_ARM,
|
||||
/* 0x08 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_FOREARM,
|
||||
/* 0x09 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_HAND,
|
||||
/* 0x0A */ PAMELAS_FATHER_GIBDO_LIMB_EYEBROWS,
|
||||
/* 0x0B */ PAMELAS_FATHER_GIBDO_LIMB_HEAD,
|
||||
/* 0x0C */ PAMELAS_FATHER_GIBDO_LIMB_PELVIS,
|
||||
/* 0x0D */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_THIGH,
|
||||
/* 0x0E */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_SHIN,
|
||||
/* 0x0F */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_FOOT,
|
||||
/* 0x10 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_THIGH,
|
||||
/* 0x11 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_SHIN,
|
||||
/* 0x12 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_FOOT,
|
||||
/* 0x13 */ PAMELAS_FATHER_GIBDO_LIMB_MAX
|
||||
} PamelasFatherGibdoLimb;
|
||||
|
||||
typedef enum PamelasFatherHumanLimb {
|
||||
/* 0x00 */ PAMELAS_FATHER_HUMAN_LIMB_NONE,
|
||||
/* 0x01 */ PAMELAS_FATHER_HUMAN_LIMB_ROOT,
|
||||
/* 0x02 */ PAMELAS_FATHER_HUMAN_LIMB_ABDOMEN,
|
||||
/* 0x03 */ PAMELAS_FATHER_HUMAN_LIMB_CHEST,
|
||||
/* 0x04 */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_UPPER_ARM,
|
||||
/* 0x05 */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_FOREARM,
|
||||
/* 0x06 */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_HAND,
|
||||
/* 0x07 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_UPPER_ARM,
|
||||
/* 0x08 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_FOREARM,
|
||||
/* 0x09 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_HAND,
|
||||
/* 0x0A */ PAMELAS_FATHER_HUMAN_LIMB_EYEBROWS,
|
||||
/* 0x0B */ PAMELAS_FATHER_HUMAN_LIMB_HEAD,
|
||||
/* 0x0C */ PAMELAS_FATHER_HUMAN_LIMB_PELVIS,
|
||||
/* 0x0D */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_THIGH,
|
||||
/* 0x0E */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_SHIN,
|
||||
/* 0x0F */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_FOOT,
|
||||
/* 0x10 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_THIGH,
|
||||
/* 0x11 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_SHIN,
|
||||
/* 0x12 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_FOOT,
|
||||
/* 0x13 */ PAMELAS_FATHER_HUMAN_LIMB_MAX
|
||||
} PamelasFatherHumanLimb;
|
||||
26
patches/dummy_headers/objects/object_pamera/object_pamera.h
Normal file
26
patches/dummy_headers/objects/object_pamera/object_pamera.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
typedef enum PamelaLimb {
|
||||
/* 0x00 */ PAMELA_LIMB_NONE,
|
||||
/* 0x01 */ PAMELA_LIMB_ROOT,
|
||||
/* 0x02 */ PAMELA_LIMB_UPPER_BODY_ROOT,
|
||||
/* 0x03 */ PAMELA_LIMB_LEFT_UPPER_ARM,
|
||||
/* 0x04 */ PAMELA_LIMB_LEFT_FOREARM,
|
||||
/* 0x05 */ PAMELA_LIMB_LEFT_HAND,
|
||||
/* 0x06 */ PAMELA_LIMB_RIGHT_UPPER_ARM,
|
||||
/* 0x07 */ PAMELA_LIMB_RIGHT_FOREARM,
|
||||
/* 0x08 */ PAMELA_LIMB_RIGHT_HAND,
|
||||
/* 0x09 */ PAMELA_LIMB_HEAD,
|
||||
/* 0x0A */ PAMELA_LIMB_HAIR_END,
|
||||
/* 0x0B */ PAMELA_LIMB_CHEST,
|
||||
/* 0x0C */ PAMELA_LIMB_NECK,
|
||||
/* 0x0D */ PAMELA_LIMB_LEFT_THIGH,
|
||||
/* 0x0E */ PAMELA_LIMB_LEFT_LEG,
|
||||
/* 0x0F */ PAMELA_LIMB_LEFT_FOOT,
|
||||
/* 0x10 */ PAMELA_LIMB_RIGHT_THIGH,
|
||||
/* 0x11 */ PAMELA_LIMB_RIGHT_LEG,
|
||||
/* 0x12 */ PAMELA_LIMB_RIGHT_FOOT,
|
||||
/* 0x13 */ PAMELA_LIMB_FRONT_DRESS,
|
||||
/* 0x14 */ PAMELA_LIMB_BACK_DRESS,
|
||||
/* 0x15 */ PAMELA_LIMB_ABDOMEN,
|
||||
/* 0x16 */ PAMELA_LIMB_PELVIS,
|
||||
/* 0x17 */ PAMELA_LIMB_MAX
|
||||
} PamelaLimb;
|
||||
107
patches/gibdo_mask_cutscene_father_human.c
Normal file
107
patches/gibdo_mask_cutscene_father_human.c
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#include "patches.h"
|
||||
#include "transform_ids.h"
|
||||
#include "overlays/actors/ovl_En_Hgo/z_en_hgo.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ HGO_ANIM_ARMS_FOLDED,
|
||||
/* 1 */ HGO_ANIM_ASTONISHED,
|
||||
/* 2 */ HGO_ANIM_KNEEL_DOWN_AND_HUG,
|
||||
/* 3 */ HGO_ANIM_CONSOLE,
|
||||
/* 4 */ HGO_ANIM_CONSOLE_HEAD_UP,
|
||||
/* 5 */ HGO_ANIM_REACH_DOWN_TO_LIFT,
|
||||
/* 6 */ HGO_ANIM_TOSS,
|
||||
/* 7 */ HGO_ANIM_MAX
|
||||
} HgoAnimation;
|
||||
|
||||
extern AnimationInfo sPamelasFatherHumanAnimationInfo[];
|
||||
extern void EnHgo_Draw(Actor* thisx, PlayState* play);
|
||||
extern void EnHgo_DoNothing(EnHgo* this, PlayState* play);
|
||||
extern void EnHgo_SetupInitCollision(EnHgo* this);
|
||||
|
||||
// @recomp Skip interpolation when the animations change during the cutscene, as the
|
||||
// animation changes are meant to happen at the same time as the camera cuts.
|
||||
RECOMP_PATCH s32 EnHgo_HandleCsAction(EnHgo* this, PlayState* play) {
|
||||
s32 cueChannel;
|
||||
|
||||
if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_486)) {
|
||||
cueChannel = Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_486);
|
||||
if (this->cueId != play->csCtx.actorCues[cueChannel]->id) {
|
||||
this->cueId = play->csCtx.actorCues[cueChannel]->id;
|
||||
switch (play->csCtx.actorCues[cueChannel]->id) {
|
||||
case 1:
|
||||
this->animIndex = HGO_ANIM_ARMS_FOLDED;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_ARMS_FOLDED);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this->actor.draw = EnHgo_Draw;
|
||||
this->animIndex = HGO_ANIM_ASTONISHED;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_ASTONISHED);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
this->animIndex = HGO_ANIM_KNEEL_DOWN_AND_HUG;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_KNEEL_DOWN_AND_HUG);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
this->animIndex = HGO_ANIM_CONSOLE;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_CONSOLE);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
this->animIndex = HGO_ANIM_CONSOLE_HEAD_UP;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_CONSOLE_HEAD_UP);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
this->animIndex = HGO_ANIM_REACH_DOWN_TO_LIFT;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_REACH_DOWN_TO_LIFT);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
actor_set_interpolation_skipped(&this->actor);
|
||||
} else if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) {
|
||||
switch (this->animIndex) {
|
||||
case HGO_ANIM_ASTONISHED:
|
||||
if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && !this->isInCutscene) {
|
||||
this->isInCutscene = true;
|
||||
if ((gSaveContext.sceneLayer == 0) &&
|
||||
((play->csCtx.scriptIndex == 2) || (play->csCtx.scriptIndex == 4))) {
|
||||
Actor_PlaySfx(&this->actor, NA_SE_VO_GBVO02);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HGO_ANIM_KNEEL_DOWN_AND_HUG:
|
||||
this->animIndex = HGO_ANIM_CONSOLE;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_CONSOLE);
|
||||
break;
|
||||
|
||||
case HGO_ANIM_REACH_DOWN_TO_LIFT:
|
||||
this->animIndex = HGO_ANIM_TOSS;
|
||||
Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_TOSS);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Cutscene_ActorTranslateAndYaw(&this->actor, play, cueChannel);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((play->csCtx.state == CS_STATE_IDLE) && CHECK_WEEKEVENTREG(WEEKEVENTREG_75_20) &&
|
||||
(this->actionFunc == EnHgo_DoNothing)) {
|
||||
this->actor.shape.rot.y = this->actor.world.rot.y;
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ELF_MSG2, this->actor.focus.pos.x, this->actor.focus.pos.y,
|
||||
this->actor.focus.pos.z, 7, 0, 0, 0x7F5A);
|
||||
EnHgo_SetupInitCollision(this);
|
||||
}
|
||||
|
||||
this->cueId = 99;
|
||||
return false;
|
||||
}
|
||||
26
patches/gibdo_mask_cutscene_mask.c
Normal file
26
patches/gibdo_mask_cutscene_mask.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "patches.h"
|
||||
#include "transform_ids.h"
|
||||
#include "overlays/actors/ovl_Dm_Char05/z_dm_char05.h"
|
||||
|
||||
extern void func_80AADF54(PlayState* play, DmChar05* this);
|
||||
|
||||
// @recomp Patched to avoid an interpolation glitch in Pamela's dad's cutscene
|
||||
// that happens when the mask is meant to teleport offscreen.
|
||||
RECOMP_PATCH void func_80AADB4C(Actor* thisx, PlayState* play) {
|
||||
DmChar05* this = (DmChar05*)thisx;
|
||||
if (this->unk_18E == 0) {
|
||||
if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_518) &&
|
||||
(play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_518)]->id != 1)) {
|
||||
// @recomp During this cue the mask does nothing other than teleport offscreen and stay still,
|
||||
// so we can just skip interpolation the entire time.
|
||||
if (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_518)]->id == 3) {
|
||||
actor_set_interpolation_skipped(thisx);
|
||||
}
|
||||
Gfx_SetupDL25_Opa(play->state.gfxCtx);
|
||||
SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
||||
this->skelAnime.dListCount, NULL, NULL, &this->actor);
|
||||
}
|
||||
} else if (this->unk_18E == 1) {
|
||||
func_80AADF54(play, this);
|
||||
}
|
||||
}
|
||||
74
patches/gibdo_mask_cutscene_pamela.c
Normal file
74
patches/gibdo_mask_cutscene_pamela.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include "patches.h"
|
||||
#include "transform_ids.h"
|
||||
#include "overlays/actors/ovl_En_Pamera/z_en_pamera.h"
|
||||
|
||||
extern void EnPamera_Draw(Actor* thisx, PlayState* play);
|
||||
extern void func_80BD9E88(EnPamera* this);
|
||||
extern void func_80BD9EE0(EnPamera* this);
|
||||
extern void func_80BDA038(EnPamera* this);
|
||||
extern void func_80BDA0A0(EnPamera* this);
|
||||
extern void func_80BDA170(EnPamera* this);
|
||||
extern void func_80BDA288(EnPamera* this);
|
||||
extern void func_80BD994C(EnPamera* this, PlayState* play);
|
||||
extern void EnPamera_HandleDialogue(EnPamera* this, PlayState* play);
|
||||
extern void func_80BD9904(EnPamera* this);
|
||||
extern void func_80BD9E60(EnPamera* this);
|
||||
|
||||
// @recomp Skip interpolation when the animations change during the cutscene, as the
|
||||
// animation changes are meant to happen at the same time as the camera cuts.
|
||||
RECOMP_PATCH s32 func_80BD9CB8(EnPamera* this, PlayState* play) {
|
||||
s32 cueChannel;
|
||||
|
||||
if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_485)) {
|
||||
cueChannel = Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_485);
|
||||
if (this->cueId != play->csCtx.actorCues[cueChannel]->id) {
|
||||
this->cueId = play->csCtx.actorCues[cueChannel]->id;
|
||||
|
||||
switch (play->csCtx.actorCues[cueChannel]->id) {
|
||||
case 1:
|
||||
func_80BD9E88(this);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (this->actor.draw == NULL) {
|
||||
this->actor.draw = EnPamera_Draw;
|
||||
this->actor.flags |= ACTOR_FLAG_TARGETABLE;
|
||||
}
|
||||
func_80BD9EE0(this);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
func_80BDA038(this);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
func_80BDA0A0(this);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
func_80BDA170(this);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
func_80BDA288(this);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
actor_set_interpolation_skipped(&this->actor);
|
||||
}
|
||||
Cutscene_ActorTranslateAndYaw(&this->actor, play, cueChannel);
|
||||
this->setupFunc(this, play);
|
||||
return true;
|
||||
}
|
||||
if ((play->csCtx.state == CS_STATE_IDLE) && CHECK_WEEKEVENTREG(WEEKEVENTREG_75_20)) {
|
||||
if ((this->actionFunc != func_80BD994C) && (this->actionFunc != EnPamera_HandleDialogue)) {
|
||||
this->actor.shape.rot.y = this->actor.world.rot.y;
|
||||
func_80BD9904(this);
|
||||
func_80BD9E60(this);
|
||||
}
|
||||
}
|
||||
this->cueId = 99;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -185,3 +185,6 @@ RECOMP_PATCH void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gf
|
|||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
RECOMP_EXPORT u32 z64recomp_get_bowstring_transform_id() {
|
||||
return BOWSTRING_TRANSFORM_ID;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "overlays/actors/ovl_En_Twig/z_en_twig.h"
|
||||
#include "overlays/actors/ovl_En_Honotrap/z_en_honotrap.h"
|
||||
#include "overlays/actors/ovl_En_Tanron1/z_en_tanron1.h"
|
||||
#include "overlays/actors/ovl_En_Kusa2/z_en_kusa2.h"
|
||||
#include "overlays/actors/ovl_Obj_Grass/z_obj_grass.h"
|
||||
|
||||
// Decomp renames, TODO update decomp and remove these
|
||||
#define EnHonotrap_FlameGroup func_8092F878
|
||||
|
|
@ -1331,3 +1333,154 @@ RECOMP_PATCH void func_80BB5AAC(EnTanron1* this, PlayState* play) {
|
|||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
extern Gfx gKakeraLeafTipDL[];
|
||||
extern Gfx gKakeraLeafMiddleDL[];
|
||||
extern EnKusa2UnkBssStruct D_80A5F1C0;
|
||||
|
||||
// Patched to tag the particles that spawn from Keaton grass.
|
||||
RECOMP_PATCH void func_80A5E6F0(Actor* thisx, PlayState* play) {
|
||||
static Gfx* D_80A5EB68[] = {
|
||||
gKakeraLeafTipDL,
|
||||
gKakeraLeafMiddleDL,
|
||||
};
|
||||
EnKusa2* this = (EnKusa2*)thisx;
|
||||
s32 i;
|
||||
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL25_Opa(play->state.gfxCtx);
|
||||
|
||||
// @recomp Get the base transform ID for this actor.
|
||||
u32 cur_transform_id = actor_transform_id(thisx);
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(D_80A5F1C0.unk_0480); i++) {
|
||||
EnKusa2UnkBssSubStruct2* s = &D_80A5F1C0.unk_0480[i];
|
||||
|
||||
if (s->unk_2C > 0) {
|
||||
Matrix_SetTranslateRotateYXZ(s->unk_04.x, s->unk_04.y, s->unk_04.z, &s->unk_20);
|
||||
Matrix_Scale(s->unk_00, s->unk_00, s->unk_00, MTXMODE_APPLY);
|
||||
|
||||
// @recomp Create a matrix group for this particle.
|
||||
gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, cur_transform_id + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
|
||||
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPDisplayList(POLY_OPA_DISP++, D_80A5EB68[i & 1]);
|
||||
|
||||
// @recomp Pop the matrix group.
|
||||
gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
extern Gfx gObjGrass_D_809AA9F0[];
|
||||
extern Gfx gObjGrass_D_809AAA68[];
|
||||
extern Gfx gObjGrass_D_809AAAE0[];
|
||||
void ObjGrass_OverrideMatrixCurrent(MtxF* matrix);
|
||||
|
||||
// @recomp Patched to set matrix groups for grass.
|
||||
RECOMP_PATCH void ObjGrass_DrawOpa(Actor* thisx, PlayState* play2) {
|
||||
ObjGrass* this = (ObjGrass*)thisx;
|
||||
PlayState* play = play2;
|
||||
Lights* lights;
|
||||
ObjGrassGroup* grassGroup;
|
||||
s32 i;
|
||||
s32 j;
|
||||
Vec3s rot = { 0, 0, 0 };
|
||||
ObjGrassElement* grassElem;
|
||||
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL25_Opa(play->state.gfxCtx);
|
||||
|
||||
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
|
||||
gSPDisplayList(POLY_OPA_DISP++, gObjGrass_D_809AA9F0);
|
||||
|
||||
// @recomp Extract this actor's ID.
|
||||
u32 actor_id = actor_transform_id(thisx);
|
||||
|
||||
for (i = 0; i < this->activeGrassGroups; i++) {
|
||||
grassGroup = &this->grassGroups[i];
|
||||
|
||||
if (grassGroup->flags & OBJ_GRASS_GROUP_DRAW) {
|
||||
lights = LightContext_NewLights(&play->lightCtx, play->state.gfxCtx);
|
||||
Lights_BindAll(lights, play->lightCtx.listHead, &grassGroup->homePos, play);
|
||||
Lights_Draw(lights, play->state.gfxCtx);
|
||||
|
||||
for (j = 0; j < grassGroup->count; j++) {
|
||||
grassElem = &grassGroup->elements[j];
|
||||
|
||||
if ((grassElem->flags & OBJ_GRASS_ELEM_DRAW) && (grassElem->alpha == 255)) {
|
||||
rot.y = grassElem->rotY;
|
||||
Matrix_SetTranslateRotateYXZ(grassElem->pos.x, grassElem->pos.y, grassElem->pos.z, &rot);
|
||||
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
|
||||
if (grassElem->flags & OBJ_GRASS_ELEM_ANIM) {
|
||||
ObjGrass_OverrideMatrixCurrent(&this->distortionMtx[j]);
|
||||
}
|
||||
|
||||
// @recomp Push a matrix group.
|
||||
gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, actor_id + i * OBJ_GRASS_GROUP_ELEM_COUNT_MAX + j, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx),
|
||||
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPDisplayList(POLY_OPA_DISP++, gObjGrass_D_809AAAE0);
|
||||
|
||||
// @recomp Pop the matrix group.
|
||||
gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
// @recomp Patched to set matrix groups for grass.
|
||||
RECOMP_PATCH void ObjGrass_DrawXlu(Actor* thisx, PlayState* play) {
|
||||
ObjGrass* this = (ObjGrass*)thisx;
|
||||
ObjGrassGroup* grassGroup;
|
||||
ObjGrassElement* grassElem;
|
||||
s32 i;
|
||||
s32 j;
|
||||
Vec3s rot = { 0, 0, 0 };
|
||||
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL25_Xlu(play->state.gfxCtx);
|
||||
|
||||
gSPDisplayList(POLY_XLU_DISP++, gObjGrass_D_809AAA68);
|
||||
|
||||
// @recomp Extract this actor's ID.
|
||||
u32 actor_id = actor_transform_id(thisx);
|
||||
|
||||
for (i = 0; i < this->activeGrassGroups; i++) {
|
||||
grassGroup = &this->grassGroups[i];
|
||||
|
||||
if (grassGroup->flags & OBJ_GRASS_GROUP_DRAW) {
|
||||
for (j = 0; j < grassGroup->count; j++) {
|
||||
grassElem = &grassGroup->elements[j];
|
||||
|
||||
if ((grassElem->flags & OBJ_GRASS_ELEM_DRAW) && (grassElem->alpha > 0) && (grassElem->alpha < 255)) {
|
||||
rot.y = grassElem->rotY;
|
||||
Matrix_SetTranslateRotateYXZ(grassElem->pos.x, grassElem->pos.y, grassElem->pos.z, &rot);
|
||||
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
|
||||
|
||||
// @recomp Push a matrix group.
|
||||
gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_id + i * OBJ_GRASS_GROUP_ELEM_COUNT_MAX + j, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
|
||||
|
||||
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx),
|
||||
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, grassElem->alpha);
|
||||
gSPDisplayList(POLY_XLU_DISP++, gObjGrass_D_809AAAE0);
|
||||
|
||||
// @recomp Pop the matrix group.
|
||||
gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
|
|
|||
509
patches/sword_trail_transform_tagging.c
Normal file
509
patches/sword_trail_transform_tagging.c
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
#include "patches.h"
|
||||
|
||||
#define VTX_EX_T(x, y, z, s, t, cr, cg, cb, a, px, py, pz) \
|
||||
{ { x, y, z }, 0, { s, t }, { cr, cg, cb, a }, {px, py, pz} }
|
||||
|
||||
void EffectBlure_GetComputedValues(EffectBlure* this, s32 index, f32 ratio, Vec3s* vec1, Vec3s* vec2,
|
||||
Color_RGBA8* color1, Color_RGBA8* color2);
|
||||
void EffectBlure_DrawSimple(EffectBlure* this2, GraphicsContext* gfxCtx);
|
||||
void EffectBlure_DrawSmooth(EffectBlure* this2, GraphicsContext* gfxCtx);
|
||||
|
||||
// @recomp Patched to interpolate the vertices towards the front of the trail section if this is the last trail being drawn currently.
|
||||
RECOMP_PATCH void EffectBlure_DrawElemNoInterpolation(EffectBlure* this, EffectBlureElement* elem, s32 index,
|
||||
GraphicsContext* gfxCtx) {
|
||||
// @recomp Change baseVtx to a VertexEX.
|
||||
static VertexEXColor baseVtx = VTX_EX_T(/* pos */ 0, 0, 0, /* st */ 0, 0, /* color */ 255, 255, 255, 255, /* prev pos */ 0, 0, 0);
|
||||
// @recomp Change the vertex type to VertexEX.
|
||||
VertexEX* vtx;
|
||||
Vec3s sp8C;
|
||||
Vec3s sp84;
|
||||
f32 ratio;
|
||||
Color_RGBA8 sp7C;
|
||||
Color_RGBA8 sp78;
|
||||
Vec3f sp6C;
|
||||
Vec3f sp60;
|
||||
Vec3f sp54;
|
||||
|
||||
OPEN_DISPS(gfxCtx);
|
||||
|
||||
Math_Vec3s_ToVec3f(&sp6C, &this->elements[0].p2);
|
||||
|
||||
// @recomp Debug print.
|
||||
// recomp_printf("No interpolation index %d:\n"
|
||||
// " Blure: calcMode %08X flags: %04X addAngle %04X addAngle %04X elemDuration %d\n"
|
||||
// " Element: state %08X timer: %d flags %04X\n",
|
||||
// index,
|
||||
// this->calcMode, this->flags, (u16)this->addAngleChange, (u16)this->addAngle, this->elemDuration,
|
||||
// elem->state, elem->timer, elem->flags);
|
||||
|
||||
// @recomp Allocate using the size of VertexEX instead.
|
||||
vtx = GRAPH_ALLOC(gfxCtx, 4 * sizeof(VertexEX));
|
||||
if (vtx == NULL) {
|
||||
} else {
|
||||
vtx[0].v = baseVtx;
|
||||
vtx[1].v = baseVtx;
|
||||
vtx[2].v = baseVtx;
|
||||
vtx[3].v = baseVtx;
|
||||
|
||||
ratio = (f32)elem->timer / (f32)this->elemDuration;
|
||||
EffectBlure_GetComputedValues(this, index, ratio, &sp8C, &sp84, &sp7C, &sp78);
|
||||
|
||||
sp60.x = sp84.x;
|
||||
sp60.y = sp84.y;
|
||||
sp60.z = sp84.z;
|
||||
Math_Vec3f_Diff(&sp60, &sp6C, &sp54);
|
||||
Math_Vec3f_Scale(&sp54, 10.0f);
|
||||
vtx[0].v.ob[0] = sp54.x;
|
||||
vtx[0].v.ob[1] = sp54.y;
|
||||
vtx[0].v.ob[2] = sp54.z;
|
||||
vtx[0].v.cn[0] = sp78.r;
|
||||
vtx[0].v.cn[1] = sp78.g;
|
||||
vtx[0].v.cn[2] = sp78.b;
|
||||
vtx[0].v.cn[3] = sp78.a;
|
||||
|
||||
sp60.x = sp8C.x;
|
||||
sp60.y = sp8C.y;
|
||||
sp60.z = sp8C.z;
|
||||
Math_Vec3f_Diff(&sp60, &sp6C, &sp54);
|
||||
Math_Vec3f_Scale(&sp54, 10.0f);
|
||||
vtx[1].v.ob[0] = sp54.x;
|
||||
vtx[1].v.ob[1] = sp54.y;
|
||||
vtx[1].v.ob[2] = sp54.z;
|
||||
vtx[1].v.cn[0] = sp7C.r;
|
||||
vtx[1].v.cn[1] = sp7C.g;
|
||||
vtx[1].v.cn[2] = sp7C.b;
|
||||
vtx[1].v.cn[3] = sp7C.a;
|
||||
|
||||
ratio = (f32)(elem + 1)->timer / (f32)this->elemDuration;
|
||||
EffectBlure_GetComputedValues(this, index + 1, ratio, &sp8C, &sp84, &sp7C, &sp78);
|
||||
|
||||
sp60.x = sp8C.x;
|
||||
sp60.y = sp8C.y;
|
||||
sp60.z = sp8C.z;
|
||||
Math_Vec3f_Diff(&sp60, &sp6C, &sp54);
|
||||
Math_Vec3f_Scale(&sp54, 10.0f);
|
||||
vtx[2].v.ob[0] = sp54.x;
|
||||
vtx[2].v.ob[1] = sp54.y;
|
||||
vtx[2].v.ob[2] = sp54.z;
|
||||
vtx[2].v.cn[0] = sp7C.r;
|
||||
vtx[2].v.cn[1] = sp7C.g;
|
||||
vtx[2].v.cn[2] = sp7C.b;
|
||||
vtx[2].v.cn[3] = sp7C.a;
|
||||
|
||||
sp60.x = sp84.x;
|
||||
sp60.y = sp84.y;
|
||||
sp60.z = sp84.z;
|
||||
Math_Vec3f_Diff(&sp60, &sp6C, &sp54);
|
||||
Math_Vec3f_Scale(&sp54, 10.0f);
|
||||
vtx[3].v.ob[0] = sp54.x;
|
||||
vtx[3].v.ob[1] = sp54.y;
|
||||
vtx[3].v.ob[2] = sp54.z;
|
||||
vtx[3].v.cn[0] = sp78.r;
|
||||
vtx[3].v.cn[1] = sp78.g;
|
||||
vtx[3].v.cn[2] = sp78.b;
|
||||
vtx[3].v.cn[3] = sp78.a;
|
||||
|
||||
// @recomp Set the previous position of the first two vertices to their current position.
|
||||
vtx[0].v.obp[0] = vtx[0].v.ob[0];
|
||||
vtx[0].v.obp[1] = vtx[0].v.ob[1];
|
||||
vtx[0].v.obp[2] = vtx[0].v.ob[2];
|
||||
vtx[1].v.obp[0] = vtx[1].v.ob[0];
|
||||
vtx[1].v.obp[1] = vtx[1].v.ob[1];
|
||||
vtx[1].v.obp[2] = vtx[1].v.ob[2];
|
||||
|
||||
// @recomp If this trail just spawned (timer == 2), set the previous vertex positions for the last two vertices to the positions of the last two (interpolation).
|
||||
// Otherwise, set them to the current position of the respective vertex (no interpolation).
|
||||
if (elem->timer == 2) {
|
||||
// Vertex 2 interpolates from a start position equal to the position of vertex 1.
|
||||
vtx[2].v.obp[0] = vtx[1].v.ob[0];
|
||||
vtx[2].v.obp[1] = vtx[1].v.ob[1];
|
||||
vtx[2].v.obp[2] = vtx[1].v.ob[2];
|
||||
// Vertex 3 interpolates from a start position equal to the position of vertex 0.
|
||||
vtx[3].v.obp[0] = vtx[0].v.ob[0];
|
||||
vtx[3].v.obp[1] = vtx[0].v.ob[1];
|
||||
vtx[3].v.obp[2] = vtx[0].v.ob[2];
|
||||
}
|
||||
else {
|
||||
vtx[2].v.obp[0] = vtx[2].v.ob[0];
|
||||
vtx[2].v.obp[1] = vtx[2].v.ob[1];
|
||||
vtx[2].v.obp[2] = vtx[2].v.ob[2];
|
||||
vtx[3].v.obp[0] = vtx[3].v.ob[0];
|
||||
vtx[3].v.obp[1] = vtx[3].v.ob[1];
|
||||
vtx[3].v.obp[2] = vtx[3].v.ob[2];
|
||||
}
|
||||
|
||||
// @recomp Use gEXVertex in place of gSPVertex.
|
||||
gEXVertex(POLY_XLU_DISP++, vtx, 4, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 0, 1, 2, 0, 0, 2, 3, 0);
|
||||
}
|
||||
|
||||
CLOSE_DISPS(gfxCtx);
|
||||
}
|
||||
|
||||
// @recomp Patched to interpolate the vertices towards the front of the trail section if this is the last trail being drawn currently.
|
||||
RECOMP_PATCH void EffectBlure_DrawElemHermiteInterpolation(EffectBlure* this, EffectBlureElement* elem, s32 index,
|
||||
GraphicsContext* gfxCtx) {
|
||||
// @recomp Change baseVtx to a VertexEX.
|
||||
static VertexEXColor baseVtx = VTX_EX_T(/* pos */ 0, 0, 0, /* st */ 0, 0, /* color */ 255, 255, 255, 255, /* prev pos */ 0, 0, 0);
|
||||
// @recomp Change the vertex type to VertexEX.
|
||||
VertexEX* vtx;
|
||||
Vec3s sp1EC;
|
||||
Vec3s sp1E4;
|
||||
f32 ratio;
|
||||
Color_RGBA8 sp1DC;
|
||||
Color_RGBA8 sp1D8;
|
||||
Vec3f sp1CC;
|
||||
Vec3f sp1C0;
|
||||
Vec3f sp1B4;
|
||||
Vec3f sp1A8;
|
||||
Color_RGBA8 sp1A4;
|
||||
Color_RGBA8 sp1A0;
|
||||
Color_RGBA8 sp19C;
|
||||
Color_RGBA8 sp198;
|
||||
Vec3f sp18C;
|
||||
Vec3f sp180;
|
||||
Vec3f sp174;
|
||||
Vec3f sp168;
|
||||
s32 i;
|
||||
Vec3f sp158;
|
||||
Vec3f sp14C;
|
||||
Color_RGBA8 sp148;
|
||||
Color_RGBA8 sp144;
|
||||
Vec3f sp138;
|
||||
|
||||
// @recomp Debug print.
|
||||
// recomp_printf("Hermite interpolation index %d:\n"
|
||||
// " Blure: calcMode %08X flags: %04X addAngle %04X addAngle %04X elemDuration %d\n"
|
||||
// " Element: state %08X timer: %d flags %04X\n",
|
||||
// index,
|
||||
// this->calcMode, this->flags, (u16)this->addAngleChange, (u16)this->addAngle, this->elemDuration,
|
||||
// elem->state, elem->timer, elem->flags);
|
||||
|
||||
OPEN_DISPS(gfxCtx);
|
||||
|
||||
Math_Vec3s_ToVec3f(&sp138, &this->elements[0].p2);
|
||||
|
||||
ratio = (f32)elem->timer / (f32)this->elemDuration;
|
||||
EffectBlure_GetComputedValues(this, index, ratio, &sp1EC, &sp1E4, &sp1A4, &sp1A0);
|
||||
Math_Vec3s_ToVec3f(&sp1CC, &sp1EC);
|
||||
Math_Vec3s_ToVec3f(&sp1C0, &sp1E4);
|
||||
|
||||
ratio = (f32)(elem + 1)->timer / (f32)this->elemDuration;
|
||||
EffectBlure_GetComputedValues(this, index + 1, ratio, &sp1EC, &sp1E4, &sp19C, &sp198);
|
||||
Math_Vec3s_ToVec3f(&sp18C, &sp1EC);
|
||||
Math_Vec3s_ToVec3f(&sp180, &sp1E4);
|
||||
|
||||
if ((elem->flags & (EFFECT_BLURE_ELEMENT_FLAG_1 | EFFECT_BLURE_ELEMENT_FLAG_2)) == EFFECT_BLURE_ELEMENT_FLAG_2) {
|
||||
Math_Vec3f_Diff(&sp18C, &sp1CC, &sp1B4);
|
||||
Math_Vec3f_Diff(&sp180, &sp1C0, &sp1A8);
|
||||
} else {
|
||||
Vec3f sp118;
|
||||
Vec3f sp10C;
|
||||
|
||||
ratio = (f32)(elem - 1)->timer / (f32)this->elemDuration;
|
||||
EffectBlure_GetComputedValues(this, index - 1, ratio, &sp1EC, &sp1E4, &sp1DC, &sp1D8);
|
||||
Math_Vec3s_ToVec3f(&sp118, &sp1EC);
|
||||
Math_Vec3s_ToVec3f(&sp10C, &sp1E4);
|
||||
Math_Vec3f_Diff(&sp18C, &sp118, &sp1B4);
|
||||
Math_Vec3f_Diff(&sp180, &sp10C, &sp1A8);
|
||||
}
|
||||
|
||||
Math_Vec3f_Scale(&sp1B4, 0.5f);
|
||||
Math_Vec3f_Scale(&sp1A8, 0.5f);
|
||||
|
||||
if (((elem + 1)->flags & (EFFECT_BLURE_ELEMENT_FLAG_1 | EFFECT_BLURE_ELEMENT_FLAG_2)) ==
|
||||
EFFECT_BLURE_ELEMENT_FLAG_2) {
|
||||
Math_Vec3f_Diff(&sp18C, &sp1CC, &sp174);
|
||||
Math_Vec3f_Diff(&sp180, &sp1C0, &sp168);
|
||||
} else {
|
||||
Vec3f sp100;
|
||||
Vec3f spF4;
|
||||
|
||||
ratio = (f32)(elem + 2)->timer / (f32)this->elemDuration;
|
||||
EffectBlure_GetComputedValues(this, index + 2, ratio, &sp1EC, &sp1E4, &sp1DC, &sp1D8);
|
||||
Math_Vec3s_ToVec3f(&sp100, &sp1EC);
|
||||
Math_Vec3s_ToVec3f(&spF4, &sp1E4);
|
||||
Math_Vec3f_Diff(&sp100, &sp1CC, &sp174);
|
||||
Math_Vec3f_Diff(&spF4, &sp1C0, &sp168);
|
||||
}
|
||||
|
||||
Math_Vec3f_Scale(&sp174, 0.5f);
|
||||
Math_Vec3f_Scale(&sp168, 0.5f);
|
||||
|
||||
// @recomp Allocate using the size of VertexEX instead.
|
||||
vtx = GRAPH_ALLOC(gfxCtx, 16 * sizeof(VertexEX));
|
||||
if (vtx == NULL) {
|
||||
} else {
|
||||
Math_Vec3f_Diff(&sp1CC, &sp138, &sp158);
|
||||
Math_Vec3f_Scale(&sp158, 10.0f);
|
||||
Math_Vec3f_Diff(&sp1C0, &sp138, &sp14C);
|
||||
Math_Vec3f_Scale(&sp14C, 10.0f);
|
||||
|
||||
Color_RGBA8_Copy(&sp148, &sp1A4);
|
||||
Color_RGBA8_Copy(&sp144, &sp1A0);
|
||||
|
||||
vtx[0].v = baseVtx;
|
||||
vtx[1].v = baseVtx;
|
||||
|
||||
vtx[0].v.ob[0] = Math_FNearbyIntF(sp158.x);
|
||||
vtx[0].v.ob[1] = Math_FNearbyIntF(sp158.y);
|
||||
vtx[0].v.ob[2] = Math_FNearbyIntF(sp158.z);
|
||||
vtx[0].v.cn[0] = sp148.r;
|
||||
vtx[0].v.cn[1] = sp148.g;
|
||||
vtx[0].v.cn[2] = sp148.b;
|
||||
vtx[0].v.cn[3] = sp148.a;
|
||||
vtx[1].v.ob[0] = Math_FNearbyIntF(sp14C.x);
|
||||
vtx[1].v.ob[1] = Math_FNearbyIntF(sp14C.y);
|
||||
vtx[1].v.ob[2] = Math_FNearbyIntF(sp14C.z);
|
||||
vtx[1].v.cn[0] = sp144.r;
|
||||
vtx[1].v.cn[1] = sp144.g;
|
||||
vtx[1].v.cn[2] = sp144.b;
|
||||
vtx[1].v.cn[3] = sp144.a;
|
||||
|
||||
// @recomp Set the previous position of the first two vertices to their current position.
|
||||
vtx[0].v.obp[0] = vtx[0].v.ob[0];
|
||||
vtx[0].v.obp[1] = vtx[0].v.ob[1];
|
||||
vtx[0].v.obp[2] = vtx[0].v.ob[2];
|
||||
vtx[1].v.obp[0] = vtx[1].v.ob[0];
|
||||
vtx[1].v.obp[1] = vtx[1].v.ob[1];
|
||||
vtx[1].v.obp[2] = vtx[1].v.ob[2];
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
s32 j1 = 2 * i;
|
||||
s32 j2 = 2 * i + 1;
|
||||
Vec3f spE0;
|
||||
f32 temp_f28 = i / 7.0f; // t
|
||||
f32 temp_f0 = SQ(temp_f28); // t^2
|
||||
f32 temp_f2 = temp_f0 * temp_f28; // t^3
|
||||
f32 temp_f20 = temp_f2 - temp_f0; // t^3 - t^2
|
||||
f32 temp_f22 = temp_f2 - 2.0f * temp_f0 + temp_f28; // t^3 - 2t^2 + t
|
||||
f32 temp_f24 = 2.0f * temp_f2 - temp_f0 * 3.0f + 1.0f; // 2t^3 - 3t^2 + 1
|
||||
f32 temp_f26 = temp_f0 * 3.0f - 2.0f * temp_f2; // 3t^2 - 2t^3
|
||||
s32 pad1;
|
||||
s32 pad2;
|
||||
|
||||
// p = (2t^3 - 3t^2 + 1)p0 + (3t^2 - 2t^3)p1 + (t^3 - 2t^2 + t)m0 + (t^3 - t^2)m1
|
||||
spE0.x = (temp_f24 * sp1CC.x) + (temp_f26 * sp18C.x) + (temp_f22 * sp1B4.x) + (temp_f20 * sp174.x);
|
||||
spE0.y = (temp_f24 * sp1CC.y) + (temp_f26 * sp18C.y) + (temp_f22 * sp1B4.y) + (temp_f20 * sp174.y);
|
||||
spE0.z = (temp_f24 * sp1CC.z) + (temp_f26 * sp18C.z) + (temp_f22 * sp1B4.z) + (temp_f20 * sp174.z);
|
||||
Math_Vec3f_Diff(&spE0, &sp138, &sp158);
|
||||
Math_Vec3f_Scale(&sp158, 10.0f);
|
||||
|
||||
spE0.x = (temp_f24 * sp1C0.x) + (temp_f26 * sp180.x) + (temp_f22 * sp1A8.x) + (temp_f20 * sp168.x);
|
||||
spE0.y = (temp_f24 * sp1C0.y) + (temp_f26 * sp180.y) + (temp_f22 * sp1A8.y) + (temp_f20 * sp168.y);
|
||||
spE0.z = (temp_f24 * sp1C0.z) + (temp_f26 * sp180.z) + (temp_f22 * sp1A8.z) + (temp_f20 * sp168.z);
|
||||
Math_Vec3f_Diff(&spE0, &sp138, &sp14C);
|
||||
Math_Vec3f_Scale(&sp14C, 10.0f);
|
||||
|
||||
vtx[j1].v = baseVtx;
|
||||
vtx[j2].v = baseVtx;
|
||||
|
||||
vtx[j1].v.ob[0] = Math_FNearbyIntF(sp158.x);
|
||||
vtx[j1].v.ob[1] = Math_FNearbyIntF(sp158.y);
|
||||
vtx[j1].v.ob[2] = Math_FNearbyIntF(sp158.z);
|
||||
vtx[j1].v.cn[0] = func_800B0A24(sp1A4.r, sp19C.r, temp_f28);
|
||||
vtx[j1].v.cn[1] = func_800B0A24(sp1A4.g, sp19C.g, temp_f28);
|
||||
vtx[j1].v.cn[2] = func_800B0A24(sp1A4.b, sp19C.b, temp_f28);
|
||||
vtx[j1].v.cn[3] = func_800B0A24(sp1A4.a, sp19C.a, temp_f28);
|
||||
|
||||
vtx[j2].v.ob[0] = Math_FNearbyIntF(sp14C.x);
|
||||
vtx[j2].v.ob[1] = Math_FNearbyIntF(sp14C.y);
|
||||
vtx[j2].v.ob[2] = Math_FNearbyIntF(sp14C.z);
|
||||
vtx[j2].v.cn[0] = func_800B0A24(sp1A0.r, sp198.r, temp_f28);
|
||||
vtx[j2].v.cn[1] = func_800B0A24(sp1A0.g, sp198.g, temp_f28);
|
||||
vtx[j2].v.cn[2] = func_800B0A24(sp1A0.b, sp198.b, temp_f28);
|
||||
vtx[j2].v.cn[3] = func_800B0A24(sp1A0.a, sp198.a, temp_f28);
|
||||
|
||||
// @recomp If this trail just spawned (timer == 2), set the previous vertex positions for the remaining vertices to the positions of the first two (interpolation).
|
||||
// Otherwise, set them to the current position of the respective vertex (no interpolation).
|
||||
if (elem->timer == 2) {
|
||||
vtx[j1].v.obp[0] = vtx[0].v.ob[0];
|
||||
vtx[j1].v.obp[1] = vtx[0].v.ob[1];
|
||||
vtx[j1].v.obp[2] = vtx[0].v.ob[2];
|
||||
vtx[j2].v.obp[0] = vtx[1].v.ob[0];
|
||||
vtx[j2].v.obp[1] = vtx[1].v.ob[1];
|
||||
vtx[j2].v.obp[2] = vtx[1].v.ob[2];
|
||||
}
|
||||
else {
|
||||
vtx[j1].v.obp[0] = vtx[j1].v.ob[0];
|
||||
vtx[j1].v.obp[1] = vtx[j1].v.ob[1];
|
||||
vtx[j1].v.obp[2] = vtx[j1].v.ob[2];
|
||||
vtx[j2].v.obp[0] = vtx[j2].v.ob[0];
|
||||
vtx[j2].v.obp[1] = vtx[j2].v.ob[1];
|
||||
vtx[j2].v.obp[2] = vtx[j2].v.ob[2];
|
||||
}
|
||||
}
|
||||
|
||||
// @recomp Use gEXVertex in place of gSPVertex.
|
||||
gEXVertex(POLY_XLU_DISP++, vtx, 16, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 0, 1, 3, 0, 0, 3, 2, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 2, 3, 5, 0, 2, 5, 4, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 4, 5, 7, 0, 4, 7, 6, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 6, 7, 9, 0, 6, 9, 8, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 8, 9, 11, 0, 8, 11, 10, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 10, 11, 13, 0, 10, 13, 12, 0);
|
||||
gSP2Triangles(POLY_XLU_DISP++, 12, 13, 15, 0, 12, 15, 14, 0);
|
||||
}
|
||||
|
||||
CLOSE_DISPS(gfxCtx);
|
||||
}
|
||||
|
||||
// @recomp Patched to interpolate the vertices towards the front of the trail section if this is the last trail being drawn currently.
|
||||
RECOMP_PATCH void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) {
|
||||
EffectBlure* this = (EffectBlure*)thisx;
|
||||
// @recomp Change the vertex type to VertexEX.
|
||||
VertexEX* vtx;
|
||||
EffectBlureElement* elem;
|
||||
s32 i;
|
||||
s32 j;
|
||||
s32 phi_t2;
|
||||
|
||||
OPEN_DISPS(gfxCtx);
|
||||
|
||||
gSPMatrix(POLY_XLU_DISP++, &gIdentityMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
|
||||
if (this->numElements != 0) {
|
||||
if (this->flags == 0) {
|
||||
Gfx_SetupDL38_Xlu(gfxCtx);
|
||||
gDPPipeSync(POLY_XLU_DISP++);
|
||||
|
||||
// @recomp Allocate using the size of VertexEX instead.
|
||||
vtx = GRAPH_ALLOC(gfxCtx, 32 * sizeof(VertexEX));
|
||||
if (vtx == NULL) {
|
||||
} else {
|
||||
j = 0;
|
||||
for (i = 0; i < this->numElements; i++) {
|
||||
elem = &this->elements[i];
|
||||
|
||||
// @recomp Debug print.
|
||||
// recomp_printf("Flag 0 %d:\n"
|
||||
// " Blure: calcMode %08X flags: %04X addAngle %04X addAngle %04X elemDuration %d\n"
|
||||
// " Element: state %08X timer: %d flags %04X\n",
|
||||
// i,
|
||||
// this->calcMode, this->flags, (u16)this->addAngleChange, (u16)this->addAngle, this->elemDuration,
|
||||
// elem->state, elem->timer, elem->flags);
|
||||
|
||||
if (elem->state == 1) {
|
||||
f32 ratio = (f32)elem->timer / (f32)this->elemDuration;
|
||||
|
||||
switch (this->calcMode) {
|
||||
case 1:
|
||||
vtx[j].v.ob[0] = func_800B09D0(elem->p1.x, elem->p2.x, ratio);
|
||||
vtx[j].v.ob[1] = func_800B09D0(elem->p1.y, elem->p2.y, ratio);
|
||||
vtx[j].v.ob[2] = func_800B09D0(elem->p1.z, elem->p2.z, ratio);
|
||||
vtx[j + 1].v.ob[0] = elem->p2.x;
|
||||
vtx[j + 1].v.ob[1] = elem->p2.y;
|
||||
vtx[j + 1].v.ob[2] = elem->p2.z;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
vtx[j].v.ob[0] = elem->p1.x;
|
||||
vtx[j].v.ob[1] = elem->p1.y;
|
||||
vtx[j].v.ob[2] = elem->p1.z;
|
||||
vtx[j + 1].v.ob[0] = func_800B09D0(elem->p2.x, elem->p1.x, ratio);
|
||||
vtx[j + 1].v.ob[1] = func_800B09D0(elem->p2.y, elem->p1.y, ratio);
|
||||
vtx[j + 1].v.ob[2] = func_800B09D0(elem->p2.z, elem->p1.z, ratio);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ratio *= 0.5f;
|
||||
vtx[j].v.ob[0] = func_800B09D0(elem->p1.x, elem->p2.x, ratio);
|
||||
vtx[j].v.ob[1] = func_800B09D0(elem->p1.y, elem->p2.y, ratio);
|
||||
vtx[j].v.ob[2] = func_800B09D0(elem->p1.z, elem->p2.z, ratio);
|
||||
vtx[j + 1].v.ob[0] = func_800B09D0(elem->p2.x, elem->p1.x, ratio);
|
||||
vtx[j + 1].v.ob[1] = func_800B09D0(elem->p2.y, elem->p1.y, ratio);
|
||||
vtx[j + 1].v.ob[2] = func_800B09D0(elem->p2.z, elem->p1.z, ratio);
|
||||
ratio *= 2.0f;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
vtx[j].v.ob[0] = elem->p1.x;
|
||||
vtx[j].v.ob[1] = elem->p1.y;
|
||||
vtx[j].v.ob[2] = elem->p1.z;
|
||||
vtx[j + 1].v.ob[0] = elem->p2.x;
|
||||
vtx[j + 1].v.ob[1] = elem->p2.y;
|
||||
vtx[j + 1].v.ob[2] = elem->p2.z;
|
||||
break;
|
||||
}
|
||||
|
||||
// @recomp If this trail just spawned (timer == 1), set the previous vertex positions for this vertex that of the second previous vertex (interpolation).
|
||||
// Otherwise, set them to the current position of the respective vertex (no interpolation).
|
||||
if (elem->timer == 1 && j >= 2) {
|
||||
vtx[j].v.obp[0] = vtx[j - 2].v.ob[0];
|
||||
vtx[j].v.obp[1] = vtx[j - 2].v.ob[1];
|
||||
vtx[j].v.obp[2] = vtx[j - 2].v.ob[2];
|
||||
}
|
||||
else {
|
||||
vtx[j].v.obp[0] = vtx[j].v.ob[0];
|
||||
vtx[j].v.obp[1] = vtx[j].v.ob[1];
|
||||
vtx[j].v.obp[2] = vtx[j].v.ob[2];
|
||||
}
|
||||
|
||||
vtx[j].v.flag = 0;
|
||||
vtx[j].v.tc[0] = 0;
|
||||
vtx[j].v.tc[1] = 0;
|
||||
vtx[j].v.cn[0] = func_800B0A24(this->p1StartColor[0], this->p1EndColor[0], ratio);
|
||||
vtx[j].v.cn[1] = func_800B0A24(this->p1StartColor[1], this->p1EndColor[1], ratio);
|
||||
vtx[j].v.cn[2] = func_800B0A24(this->p1StartColor[2], this->p1EndColor[2], ratio);
|
||||
vtx[j].v.cn[3] = func_800B0A24(this->p1StartColor[3], this->p1EndColor[3], ratio);
|
||||
j++;
|
||||
|
||||
// @recomp If this trail just spawned (timer == 1), set the previous vertex positions for this vertex that of the second previous vertex (interpolation).
|
||||
// Otherwise, set them to the current position of the respective vertex (no interpolation).
|
||||
if (elem->timer == 1 && j >= 2) {
|
||||
vtx[j].v.obp[0] = vtx[j - 2].v.ob[0];
|
||||
vtx[j].v.obp[1] = vtx[j - 2].v.ob[1];
|
||||
vtx[j].v.obp[2] = vtx[j - 2].v.ob[2];
|
||||
}
|
||||
else {
|
||||
vtx[j].v.obp[0] = vtx[j].v.ob[0];
|
||||
vtx[j].v.obp[1] = vtx[j].v.ob[1];
|
||||
vtx[j].v.obp[2] = vtx[j].v.ob[2];
|
||||
}
|
||||
|
||||
vtx[j].v.flag = 0;
|
||||
vtx[j].v.tc[0] = 0;
|
||||
vtx[j].v.tc[1] = 0;
|
||||
vtx[j].v.cn[0] = func_800B0A24(this->p2StartColor[0], this->p2EndColor[0], ratio);
|
||||
vtx[j].v.cn[1] = func_800B0A24(this->p2StartColor[1], this->p2EndColor[1], ratio);
|
||||
vtx[j].v.cn[2] = func_800B0A24(this->p2StartColor[2], this->p2EndColor[2], ratio);
|
||||
vtx[j].v.cn[3] = func_800B0A24(this->p2StartColor[3], this->p2EndColor[3], ratio);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
phi_t2 = 0;
|
||||
j = 0;
|
||||
|
||||
// @recomp Use gEXVertex in place of gSPVertex.
|
||||
gEXVertex(POLY_XLU_DISP++, vtx, 32, 0);
|
||||
|
||||
for (i = 0; i < this->numElements; i++) {
|
||||
elem = &this->elements[i];
|
||||
|
||||
if (elem->state == 0) {
|
||||
phi_t2 = 0;
|
||||
} else {
|
||||
if (phi_t2 == 0) {
|
||||
phi_t2 = 1;
|
||||
} else {
|
||||
gSP1Quadrangle(POLY_XLU_DISP++, j - 2, j - 1, j + 1, j, 0);
|
||||
|
||||
if (this->unkFlag == 1) {
|
||||
phi_t2 = 0;
|
||||
}
|
||||
}
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this->drawMode <= EFF_BLURE_DRAW_MODE_SIMPLE_ALT_COLORS) {
|
||||
EffectBlure_DrawSimple(this, gfxCtx);
|
||||
} else {
|
||||
EffectBlure_DrawSmooth(this, gfxCtx);
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE_DISPS(gfxCtx);
|
||||
}
|
||||
|
|
@ -17,8 +17,12 @@
|
|||
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
|
||||
03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
|
||||
0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows,
|
||||
03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
|
||||
030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
|
||||
030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows,
|
||||
03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
|
|
@ -30,8 +34,10 @@
|
|||
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows,
|
||||
03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
|
||||
03000000c82d00001930000000000000,8bitdo 64 BT,platform:Windows,a:b0,b:b1,back:b17,guide:b10,start:b11,leftstick:b13,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,
|
||||
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
|
||||
03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X,
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ extern "C" void recomp_register_actor_extension(uint8_t* rdram, recomp_context*
|
|||
}
|
||||
|
||||
if (actor_data_sizes.size() <= actor_type) {
|
||||
actor_data_sizes.resize(2 * actor_type);
|
||||
actor_data_sizes.resize(actor_type + 1);
|
||||
}
|
||||
|
||||
// Increase the actor type's extension data size by the provided size (rounded up to a multiple of 16).
|
||||
|
|
|
|||
|
|
@ -569,8 +569,18 @@ void recomputil_u32_slotmap_size(uint8_t* rdram, recomp_context* ctx) {
|
|||
// memory slotmap.
|
||||
|
||||
void recomputil_create_memory_slotmap(uint8_t* rdram, recomp_context* ctx) {
|
||||
(void)rdram;
|
||||
_return(ctx, memory_slotmaps.create());
|
||||
uint32_t element_size = _arg<0, uint32_t>(rdram, ctx);
|
||||
|
||||
// Create the map.
|
||||
uint32_t map_key = memory_slotmaps.create();
|
||||
|
||||
// Retrieve the map and set its element size to the provided value.
|
||||
MemorySlotmap* map;
|
||||
memory_slotmaps.get(map_key, &map);
|
||||
map->second = element_size;
|
||||
|
||||
// Return the created map's key.
|
||||
_return(ctx, map_key);
|
||||
}
|
||||
|
||||
void recomputil_destroy_memory_slotmap(uint8_t* rdram, recomp_context* ctx) {
|
||||
|
|
@ -628,7 +638,7 @@ void recomputil_memory_slotmap_create(uint8_t* rdram, recomp_context* ctx) {
|
|||
// Store the allocated pointer.
|
||||
PTR(void)* value_ptr;
|
||||
map->first.get(key, &value_ptr);
|
||||
MEM_W(0, *value_ptr) = addr;
|
||||
*value_ptr = static_cast<PTR(void)>(addr);
|
||||
|
||||
// Return the key.
|
||||
_return(ctx, key);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@
|
|||
#else
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_syswm.h"
|
||||
// Undefine x11 macros that get included by SDL_syswm.h.
|
||||
#undef None
|
||||
#undef Status
|
||||
#undef LockMask
|
||||
#undef ControlMask
|
||||
#undef Success
|
||||
#undef Always
|
||||
#endif
|
||||
|
||||
#include "recomp_ui.h"
|
||||
|
|
@ -43,12 +50,13 @@
|
|||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <timeapi.h>
|
||||
#include "SDL_syswm.h"
|
||||
#endif
|
||||
|
||||
#include "../../lib/rt64/src/contrib/stb/stb_image.h"
|
||||
|
||||
const std::string version_string = "1.2.0";
|
||||
const std::string version_string = "1.2.2";
|
||||
|
||||
template<typename... Ts>
|
||||
void exit_error(const char* str, Ts ...args) {
|
||||
|
|
@ -579,6 +587,26 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Set up high resolution timing period.
|
||||
timeBeginPeriod(1);
|
||||
|
||||
// Process arguments.
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "--show-console") == 0)
|
||||
{
|
||||
if (GetConsoleWindow() == nullptr)
|
||||
{
|
||||
AllocConsole();
|
||||
freopen("CONIN$", "r", stdin);
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up console output to accept UTF-8 on windows
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
|
|
@ -722,5 +750,10 @@ int main(int argc, char** argv) {
|
|||
release_preload(preload_context);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// End high resolution timing period.
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,21 +56,6 @@ unsigned int DPC_BUFBUSY_REG = 0;
|
|||
unsigned int DPC_PIPEBUSY_REG = 0;
|
||||
unsigned int DPC_TMEM_REG = 0;
|
||||
|
||||
unsigned int VI_STATUS_REG = 0;
|
||||
unsigned int VI_ORIGIN_REG = 0;
|
||||
unsigned int VI_WIDTH_REG = 0;
|
||||
unsigned int VI_INTR_REG = 0;
|
||||
unsigned int VI_V_CURRENT_LINE_REG = 0;
|
||||
unsigned int VI_TIMING_REG = 0;
|
||||
unsigned int VI_V_SYNC_REG = 0;
|
||||
unsigned int VI_H_SYNC_REG = 0;
|
||||
unsigned int VI_LEAP_REG = 0;
|
||||
unsigned int VI_H_START_REG = 0;
|
||||
unsigned int VI_V_START_REG = 0;
|
||||
unsigned int VI_V_BURST_REG = 0;
|
||||
unsigned int VI_X_SCALE_REG = 0;
|
||||
unsigned int VI_Y_SCALE_REG = 0;
|
||||
|
||||
void dummy_check_interrupts() {}
|
||||
|
||||
RT64::UserConfiguration::Antialiasing compute_max_supported_aa(RT64::RenderSampleCounts bits) {
|
||||
|
|
@ -250,20 +235,22 @@ zelda64::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::rendere
|
|||
appCore.DPC_PIPEBUSY_REG = &DPC_PIPEBUSY_REG;
|
||||
appCore.DPC_TMEM_REG = &DPC_TMEM_REG;
|
||||
|
||||
appCore.VI_STATUS_REG = &VI_STATUS_REG;
|
||||
appCore.VI_ORIGIN_REG = &VI_ORIGIN_REG;
|
||||
appCore.VI_WIDTH_REG = &VI_WIDTH_REG;
|
||||
appCore.VI_INTR_REG = &VI_INTR_REG;
|
||||
appCore.VI_V_CURRENT_LINE_REG = &VI_V_CURRENT_LINE_REG;
|
||||
appCore.VI_TIMING_REG = &VI_TIMING_REG;
|
||||
appCore.VI_V_SYNC_REG = &VI_V_SYNC_REG;
|
||||
appCore.VI_H_SYNC_REG = &VI_H_SYNC_REG;
|
||||
appCore.VI_LEAP_REG = &VI_LEAP_REG;
|
||||
appCore.VI_H_START_REG = &VI_H_START_REG;
|
||||
appCore.VI_V_START_REG = &VI_V_START_REG;
|
||||
appCore.VI_V_BURST_REG = &VI_V_BURST_REG;
|
||||
appCore.VI_X_SCALE_REG = &VI_X_SCALE_REG;
|
||||
appCore.VI_Y_SCALE_REG = &VI_Y_SCALE_REG;
|
||||
ultramodern::renderer::ViRegs* vi_regs = ultramodern::renderer::get_vi_regs();
|
||||
|
||||
appCore.VI_STATUS_REG = &vi_regs->VI_STATUS_REG;
|
||||
appCore.VI_ORIGIN_REG = &vi_regs->VI_ORIGIN_REG;
|
||||
appCore.VI_WIDTH_REG = &vi_regs->VI_WIDTH_REG;
|
||||
appCore.VI_INTR_REG = &vi_regs->VI_INTR_REG;
|
||||
appCore.VI_V_CURRENT_LINE_REG = &vi_regs->VI_V_CURRENT_LINE_REG;
|
||||
appCore.VI_TIMING_REG = &vi_regs->VI_TIMING_REG;
|
||||
appCore.VI_V_SYNC_REG = &vi_regs->VI_V_SYNC_REG;
|
||||
appCore.VI_H_SYNC_REG = &vi_regs->VI_H_SYNC_REG;
|
||||
appCore.VI_LEAP_REG = &vi_regs->VI_LEAP_REG;
|
||||
appCore.VI_H_START_REG = &vi_regs->VI_H_START_REG;
|
||||
appCore.VI_V_START_REG = &vi_regs->VI_V_START_REG;
|
||||
appCore.VI_V_BURST_REG = &vi_regs->VI_V_BURST_REG;
|
||||
appCore.VI_X_SCALE_REG = &vi_regs->VI_X_SCALE_REG;
|
||||
appCore.VI_Y_SCALE_REG = &vi_regs->VI_Y_SCALE_REG;
|
||||
|
||||
// Set up the RT64 application configuration fields.
|
||||
RT64::ApplicationConfiguration appConfig;
|
||||
|
|
@ -338,9 +325,7 @@ void zelda64::renderer::RT64Context::send_dl(const OSTask* task) {
|
|||
app->processDisplayLists(app->core.RDRAM, task->t.data_ptr & 0x3FFFFFF, 0, true);
|
||||
}
|
||||
|
||||
void zelda64::renderer::RT64Context::update_screen(uint32_t vi_origin) {
|
||||
VI_ORIGIN_REG = vi_origin;
|
||||
|
||||
void zelda64::renderer::RT64Context::update_screen() {
|
||||
app->updateScreen();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -900,6 +900,13 @@ void recompui::drop_files(const std::list<std::filesystem::path> &file_list) {
|
|||
return;
|
||||
}
|
||||
|
||||
recompui::set_config_tab(recompui::ConfigTab::Mods);
|
||||
// If the config menu isn't open, open it in the mods tab.
|
||||
if (!recompui::is_context_shown(recompui::get_config_context_id())) {
|
||||
recompui::hide_all_contexts();
|
||||
recompui::show_context(recompui::get_config_context_id(), "");
|
||||
}
|
||||
|
||||
recompui::open_notification("Installing Mods", "Please Wait");
|
||||
// TODO: Needs a progress callback and a prompt for every mod that needs to be confirmed to be overwritten.
|
||||
// TODO: Run this on a background thread and use the callbacks to advance the state instead of blocking.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue