mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Added some more patch functionality, added recomp namespace
This commit is contained in:
		
							parent
							
								
									3b06ad52f0
								
							
						
					
					
						commit
						ec23ef02fd
					
				
					 18 changed files with 628 additions and 230 deletions
				
			
		|  | @ -93,6 +93,7 @@ set (SOURCES | |||
|     ${CMAKE_SOURCE_DIR}/src/recomp/flash.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/math_routines.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/overlays.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/patch_loading.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/pak.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/pi.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/ultra_stubs.cpp | ||||
|  | @ -102,8 +103,11 @@ set (SOURCES | |||
|     ${CMAKE_SOURCE_DIR}/src/recomp/rt64_layer.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/sp.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/recomp/vi.cpp | ||||
|      | ||||
| 
 | ||||
|     ${CMAKE_SOURCE_DIR}/src/main/main.cpp | ||||
|      | ||||
|     ${CMAKE_SOURCE_DIR}/src/game/input.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/game/controls.cpp | ||||
| 
 | ||||
|     ${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/ui/ui_events.cpp | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #define __RECOMP_HELPERS__ | ||||
| 
 | ||||
| #include "recomp.h" | ||||
| #include "../ultramodern/ultra64.h" | ||||
| 
 | ||||
| template<int index, typename T> | ||||
| T _arg(uint8_t* rdram, recomp_context* ctx) { | ||||
|  | @ -13,7 +14,10 @@ T _arg(uint8_t* rdram, recomp_context* ctx) { | |||
|             return ctx->f12.fl; | ||||
|         } | ||||
|         else { | ||||
|             return std::bit_cast<T>(raw_arg); | ||||
|             // static_assert in else workaround
 | ||||
|             [] <bool flag = false>() { | ||||
|                 static_assert(flag, "Floats in a2/a3 not supported"); | ||||
|             }(); | ||||
|         } | ||||
|     } | ||||
|     else if constexpr (std::is_pointer_v<T>) { | ||||
|  |  | |||
							
								
								
									
										63
									
								
								include/recomp_input.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								include/recomp_input.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| #ifndef __RECOMP_INPUT_H__ | ||||
| #define __RECOMP_INPUT_H__ | ||||
| 
 | ||||
| #include <cstdint> | ||||
| #include <variant> | ||||
| #include <vector> | ||||
| #include <type_traits> | ||||
| 
 | ||||
| namespace recomp { | ||||
|     struct ControllerState { | ||||
|         enum Button : uint32_t { | ||||
|             BUTTON_NORTH      = 1 << 0, | ||||
|             BUTTON_SOUTH      = 1 << 1, | ||||
|             BUTTON_EAST       = 1 << 2, | ||||
|             BUTTON_WEST       = 1 << 3, | ||||
|             BUTTON_L1         = 1 << 4, // Left Bumper
 | ||||
|             BUTTON_R1         = 1 << 5, // Right Bumper
 | ||||
|             BUTTON_L2         = 1 << 6, // Left Trigger Press
 | ||||
|             BUTTON_R2         = 1 << 7, // Right Trigger Press
 | ||||
|             BUTTON_L3         = 1 << 8, // Left Joystick Press
 | ||||
|             BUTTON_R3         = 1 << 9, // Right Joystick Press
 | ||||
|             BUTTON_DPAD_UP    = 1 << 10, | ||||
|             BUTTON_DPAD_DOWN  = 1 << 11, | ||||
|             BUTTON_DPAD_RIGHT = 1 << 12, | ||||
|             BUTTON_DPAD_LEFT  = 1 << 13, | ||||
|             BUTTON_START      = 1 << 14, | ||||
|         }; | ||||
|         enum Axis : size_t { | ||||
|             AXIS_LEFT_X, | ||||
|             AXIS_LEFT_Y, | ||||
|             AXIS_RIGHT_X, | ||||
|             AXIS_RIGHT_Y, | ||||
|             AXIS_LEFT_TRIGGER, | ||||
|             AXIS_RIGHT_TRIGGER, | ||||
|             AXIS_MAX | ||||
|         }; | ||||
|         uint32_t buttons; | ||||
|         float axes[AXIS_MAX]; | ||||
|     }; | ||||
| 
 | ||||
|     struct MouseState { | ||||
|         enum Button : uint32_t { | ||||
|             LEFT = 1 << 0, | ||||
|             RIGHT = 1 << 1, | ||||
|             MIDDLE = 1 << 2, | ||||
|             BACK = 1 << 3, | ||||
|             FORWARD = 1 << 4, | ||||
|         }; | ||||
|         int32_t wheel_pos; | ||||
|         int32_t position_x; | ||||
|         int32_t position_y; | ||||
|         uint32_t buttons; | ||||
|     }; | ||||
| 
 | ||||
|     using InputState = std::variant<ControllerState, MouseState>; | ||||
| 
 | ||||
|     void get_keyboard_input(uint16_t* buttons_out, float* x_out, float* y_out); | ||||
|     void get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out); | ||||
|     std::vector<InputState> get_input_states(); | ||||
|     void handle_events(); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -5,22 +5,25 @@ | |||
| 
 | ||||
| #include "SDL.h" | ||||
| 
 | ||||
| void queue_event(const SDL_Event& event); | ||||
| bool try_deque_event(SDL_Event& out); | ||||
| 
 | ||||
| namespace Rml { | ||||
| 	class ElementDocument; | ||||
| 	class EventListenerInstancer; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Rml::EventListenerInstancer> make_event_listener_instancer(); | ||||
| namespace recomp { | ||||
| 
 | ||||
| enum class Menu { | ||||
| 	Launcher, | ||||
| 	None | ||||
| }; | ||||
| 	void queue_event(const SDL_Event& event); | ||||
| 	bool try_deque_event(SDL_Event& out); | ||||
| 
 | ||||
| void set_current_menu(Menu menu); | ||||
| void destroy_ui(); | ||||
| 	std::unique_ptr<Rml::EventListenerInstancer> make_event_listener_instancer(); | ||||
| 
 | ||||
| 	enum class Menu { | ||||
| 		Launcher, | ||||
| 		None | ||||
| 	}; | ||||
| 
 | ||||
| 	void set_current_menu(Menu menu); | ||||
| 	void destroy_ui(); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										117
									
								
								patches/input.c
									
										
									
									
									
								
							
							
						
						
									
										117
									
								
								patches/input.c
									
										
									
									
									
								
							|  | @ -8,17 +8,126 @@ u32 sPlayerItemButtons[] = { | |||
|     BTN_CRIGHT, | ||||
| }; | ||||
| 
 | ||||
| // Return currently-pressed button, in order of priority B, CLEFT, CDOWN, CRIGHT.
 | ||||
| u32 prev_item_buttons = 0; | ||||
| u32 cur_item_buttons = 0; | ||||
| u32 pressed_item_buttons = 0; | ||||
| u32 released_item_buttons = 0; | ||||
| 
 | ||||
| typedef enum { | ||||
|     EQUIP_SLOT_EX_DEKU = -2, | ||||
|     EQUIP_SLOT_EX_GORON = -3, | ||||
|     EQUIP_SLOT_EX_ZORA = -4, | ||||
|     EQUIP_SLOT_EX_OCARINA = -5 | ||||
| } EquipSlotEx; | ||||
| 
 | ||||
| void GameState_GetInput(GameState* gameState) { | ||||
|     PadMgr_GetInput(gameState->input, true); | ||||
| 
 | ||||
| 
 | ||||
|     prev_item_buttons = cur_item_buttons; | ||||
|     recomp_get_item_inputs(&cur_item_buttons); | ||||
|     u32 button_diff = prev_item_buttons ^ cur_item_buttons; | ||||
|     pressed_item_buttons = cur_item_buttons & button_diff; | ||||
|     released_item_buttons = prev_item_buttons & button_diff; | ||||
| } | ||||
| 
 | ||||
| struct SlotMap { | ||||
|     u32 button; | ||||
|     EquipSlotEx slot; | ||||
| }; | ||||
| 
 | ||||
| struct SlotMap exSlotMapping[] = { | ||||
|     {BTN_DLEFT,  EQUIP_SLOT_EX_GORON}, | ||||
|     {BTN_DRIGHT, EQUIP_SLOT_EX_ZORA}, | ||||
|     {BTN_DUP,    EQUIP_SLOT_EX_DEKU}, | ||||
|     {BTN_DDOWN,  EQUIP_SLOT_EX_OCARINA}, | ||||
| }; | ||||
| 
 | ||||
| // D-Pad items
 | ||||
| // TODO restore this once UI is made
 | ||||
| // Return currently-pressed button, in order of priority D-Pad, B, CLEFT, CDOWN, CRIGHT.
 | ||||
| /*
 | ||||
| EquipSlot func_8082FDC4(void) { | ||||
|     EquipSlot i; | ||||
|     RecompInputs cur_inputs; | ||||
|     recomp_get_item_inputs(&cur_inputs); | ||||
| 
 | ||||
|     for (int mapping_index = 0; mapping_index < ARRAY_COUNT(exSlotMapping); mapping_index++) { | ||||
|         if (pressed_item_buttons & exSlotMapping[mapping_index].button) { | ||||
|             return (EquipSlot)exSlotMapping[mapping_index].slot; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < ARRAY_COUNT(sPlayerItemButtons); i++) { | ||||
|         if (CHECK_BTN_ALL(cur_inputs.buttons, sPlayerItemButtons[i])) { | ||||
|         if (CHECK_BTN_ALL(pressed_item_buttons, sPlayerItemButtons[i])) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return i; | ||||
| } | ||||
| 
 | ||||
| ItemId Player_GetItemOnButton(PlayState* play, Player* player, EquipSlot slot) { | ||||
|     if (slot >= EQUIP_SLOT_A) { | ||||
|         return ITEM_NONE; | ||||
|     } | ||||
| 
 | ||||
|     if (slot <= EQUIP_SLOT_EX_DEKU) { | ||||
|         ItemId dpad_item = ITEM_NONE; | ||||
|         switch ((EquipSlotEx)slot) { | ||||
|             case EQUIP_SLOT_EX_DEKU: | ||||
|                 dpad_item = ITEM_MASK_DEKU; | ||||
|                 break; | ||||
|             case EQUIP_SLOT_EX_GORON: | ||||
|                 dpad_item = ITEM_MASK_GORON; | ||||
|                 break; | ||||
|             case EQUIP_SLOT_EX_ZORA: | ||||
|                 dpad_item = ITEM_MASK_ZORA; | ||||
|                 break; | ||||
|             case EQUIP_SLOT_EX_OCARINA: | ||||
|                 dpad_item = ITEM_OCARINA_OF_TIME; | ||||
|                 break; | ||||
|         } | ||||
| 
 | ||||
|         if ((dpad_item != ITEM_NONE) && (INV_CONTENT(dpad_item) == dpad_item)) { | ||||
|             recomp_printf("Used dpad item %d\n", dpad_item); | ||||
|             return dpad_item; | ||||
|         } | ||||
|         else { | ||||
|             return ITEM_NONE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (slot == EQUIP_SLOT_B) { | ||||
|         ItemId item = Inventory_GetBtnBItem(play); | ||||
| 
 | ||||
|         if (item >= ITEM_FD) { | ||||
|             return item; | ||||
|         } | ||||
| 
 | ||||
|         if ((player->currentMask == PLAYER_MASK_BLAST) && (play->interfaceCtx.bButtonDoAction == DO_ACTION_EXPLODE)) { | ||||
|             return ITEM_F0; | ||||
|         } | ||||
| 
 | ||||
|         if ((player->currentMask == PLAYER_MASK_BREMEN) && (play->interfaceCtx.bButtonDoAction == DO_ACTION_MARCH)) { | ||||
|             return ITEM_F1; | ||||
|         } | ||||
| 
 | ||||
|         if ((player->currentMask == PLAYER_MASK_KAMARO) && (play->interfaceCtx.bButtonDoAction == DO_ACTION_DANCE)) { | ||||
|             return ITEM_F2; | ||||
|         } | ||||
| 
 | ||||
|         return item; | ||||
|     } | ||||
| 
 | ||||
|     if (slot == EQUIP_SLOT_C_LEFT) { | ||||
|         return C_BTN_ITEM(EQUIP_SLOT_C_LEFT); | ||||
|     } | ||||
| 
 | ||||
|     if (slot == EQUIP_SLOT_C_DOWN) { | ||||
|         return C_BTN_ITEM(EQUIP_SLOT_C_DOWN); | ||||
|     } | ||||
| 
 | ||||
|     // EQUIP_SLOT_C_RIGHT
 | ||||
| 
 | ||||
|     return C_BTN_ITEM(EQUIP_SLOT_C_RIGHT); | ||||
| } | ||||
| */ | ||||
|  |  | |||
|  | @ -11,13 +11,6 @@ | |||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct RecompInputs { | ||||
|     u32 buttons; | ||||
|     float x; | ||||
|     float y; | ||||
| } RecompInputs; | ||||
| 
 | ||||
| 
 | ||||
| #ifdef MIPS | ||||
| #   define DECLARE_FUNC(type, name, ...) \ | ||||
|         type name(__VA_ARGS__); | ||||
|  | @ -26,7 +19,9 @@ typedef struct RecompInputs { | |||
|         void name(uint8_t* rdram, recomp_context* ctx); | ||||
| #endif | ||||
| 
 | ||||
| DECLARE_FUNC(void, recomp_get_item_inputs, RecompInputs* inputs); | ||||
| DECLARE_FUNC(void, recomp_get_item_inputs, u32* buttons); | ||||
| // TODO move this
 | ||||
| DECLARE_FUNC(void, recomp_puts, const char* data, u32 size); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  |  | |||
|  | @ -3,4 +3,6 @@ | |||
| 
 | ||||
| #include "global.h" | ||||
| 
 | ||||
| int recomp_printf(const char* fmt, ...); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										18
									
								
								patches/print.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								patches/print.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| #include "patches.h" | ||||
| #include "input.h" | ||||
| 
 | ||||
| void* proutPrintf(void* dst, const char* fmt, size_t size) { | ||||
|     recomp_puts(fmt, size); | ||||
|     return (void*)1; | ||||
| } | ||||
| 
 | ||||
| int recomp_printf(const char* fmt, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, fmt); | ||||
| 
 | ||||
|     int ret = _Printf(&proutPrintf, NULL, fmt, args); | ||||
| 
 | ||||
|     va_end(args); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
|  | @ -2,6 +2,7 @@ __start = 0x80000000; | |||
| 
 | ||||
| /* Dummy addresses that get recompiled into function calls */ | ||||
| recomp_get_item_inputs = 0x81000000; | ||||
| recomp_puts = 0x81000004; | ||||
| 
 | ||||
| /* TODO pull these symbols from the elf file directly */ | ||||
| Player_PostLimbDrawGameplay = 0x80128BD0; | ||||
|  | @ -10,4 +11,7 @@ gRegEditor = 0x801f3f60; | |||
| Audio_PlaySfx = 0x8019f0c8; | ||||
| gSaveContext = 0x801ef670; | ||||
| Interface_SetHudVisibility = 0x8010ef68; | ||||
| Player_GetItemOnButton = 0x8012364C; | ||||
| PadMgr_GetInput = 0x80175f98; | ||||
| Inventory_GetBtnBItem = 0x8012ec80; | ||||
| gItemSlots = 0x801c2078; | ||||
| _Printf = 0x8008e050; | ||||
|  |  | |||
							
								
								
									
										163
									
								
								src/game/controls.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/game/controls.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,163 @@ | |||
| #include "recomp_helpers.h" | ||||
| #include "recomp_input.h" | ||||
| #include "../ultramodern/ultramodern.hpp" | ||||
| #include "../patches/input.h" | ||||
| 
 | ||||
| namespace N64Inputs { | ||||
|     enum Input : uint16_t { | ||||
|         A          = 0x8000, | ||||
|         B          = 0x4000, | ||||
|         Z          = 0x2000, | ||||
|         START      = 0x1000, | ||||
|         DPAD_UP    = 0x0800, | ||||
|         DPAD_DOWN  = 0x0400, | ||||
|         DPAD_LEFT  = 0x0200, | ||||
|         DPAD_RIGHT = 0x0100, | ||||
|         L          = 0x0020, | ||||
|         R          = 0x0010, | ||||
|         C_UP       = 0x0008, | ||||
|         C_DOWN     = 0x0004, | ||||
|         C_LEFT     = 0x0002, | ||||
|         C_RIGHT    = 0x0001, | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| constexpr float controller_default_threshold = 0.7f; | ||||
| struct GameControllerAxisMapping { | ||||
|     int32_t axis; | ||||
|     float threshold; // Positive or negative to indicate direction
 | ||||
|     uint32_t output_mask; | ||||
| }; | ||||
| using axis_map_t = std::vector<GameControllerAxisMapping>; | ||||
| 
 | ||||
| struct GameControllerButtonMapping { | ||||
|     uint32_t button; | ||||
|     uint32_t output_mask; | ||||
| }; | ||||
| using button_map_t = std::vector<GameControllerButtonMapping>; | ||||
| 
 | ||||
| uint32_t process_controller_mappings(const recomp::ControllerState& controller_state, const axis_map_t& axis_map, const button_map_t& button_map) { | ||||
|     uint32_t cur_buttons = 0; | ||||
| 
 | ||||
|     for (const auto& mapping : axis_map) { | ||||
|         float input_value = controller_state.axes[mapping.axis]; | ||||
|         if (mapping.threshold > 0) { | ||||
|             if (input_value > mapping.threshold) { | ||||
|                 cur_buttons |= mapping.output_mask; | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             if (input_value < mapping.threshold) { | ||||
|                 cur_buttons |= mapping.output_mask; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for (const auto& mapping : button_map) { | ||||
|         int input_value = controller_state.buttons & mapping.button; | ||||
|         if (input_value) { | ||||
|             cur_buttons |= mapping.output_mask; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return cur_buttons; | ||||
| } | ||||
| 
 | ||||
| void recomp::get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out) { | ||||
|     static const axis_map_t general_axis_map{ | ||||
|         { recomp::ControllerState::AXIS_RIGHT_X,      -controller_default_threshold, N64Inputs::C_LEFT }, | ||||
|         { recomp::ControllerState::AXIS_RIGHT_X,       controller_default_threshold, N64Inputs::C_RIGHT }, | ||||
|         { recomp::ControllerState::AXIS_RIGHT_Y,      -controller_default_threshold, N64Inputs::C_UP }, | ||||
|         { recomp::ControllerState::AXIS_RIGHT_Y,       controller_default_threshold, N64Inputs::C_DOWN }, | ||||
|         { recomp::ControllerState::AXIS_LEFT_TRIGGER, 0.30f,                         N64Inputs::Z }, | ||||
|     }; | ||||
|     static const button_map_t general_button_map{ | ||||
|         { recomp::ControllerState::BUTTON_START,      N64Inputs::START }, | ||||
|         { recomp::ControllerState::BUTTON_SOUTH,      N64Inputs::A }, | ||||
|         { recomp::ControllerState::BUTTON_EAST,       N64Inputs::B }, | ||||
|         { recomp::ControllerState::BUTTON_WEST,       N64Inputs::B }, | ||||
|         { recomp::ControllerState::BUTTON_L1,         N64Inputs::L }, | ||||
|         { recomp::ControllerState::BUTTON_R1,         N64Inputs::R }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_LEFT,  N64Inputs::DPAD_LEFT }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_RIGHT, N64Inputs::DPAD_RIGHT }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_UP,    N64Inputs::DPAD_UP }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_DOWN,  N64Inputs::DPAD_DOWN }, | ||||
|     }; | ||||
| 
 | ||||
|     uint16_t cur_buttons = 0; | ||||
|     float cur_x = 0.0f; | ||||
|     float cur_y = 0.0f; | ||||
| 
 | ||||
|     recomp::get_keyboard_input(&cur_buttons, &cur_x, &cur_y); | ||||
| 
 | ||||
|     std::vector<InputState> input_states = recomp::get_input_states(); | ||||
| 
 | ||||
|     for (const InputState& state : input_states) { | ||||
|         if (const auto* controller_state = std::get_if<ControllerState>(&state)) { | ||||
|             cur_x += controller_state->axes[ControllerState::AXIS_LEFT_X]; | ||||
|             cur_y -= controller_state->axes[ControllerState::AXIS_LEFT_Y]; | ||||
| 
 | ||||
|             cur_buttons |= (uint16_t)process_controller_mappings(*controller_state, general_axis_map, general_button_map); | ||||
|         } | ||||
|         else if (const auto* mouse_state = std::get_if<MouseState>(&state)) { | ||||
|             // Mouse currently unused
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *buttons_out = cur_buttons; | ||||
|     cur_x = std::clamp(cur_x, -1.0f, 1.0f); | ||||
|     cur_y = std::clamp(cur_y, -1.0f, 1.0f); | ||||
|     *x_out = cur_x; | ||||
|     *y_out = cur_y; | ||||
| } | ||||
| 
 | ||||
| extern "C" void recomp_get_item_inputs(uint8_t* rdram, recomp_context* ctx) { | ||||
|     static const axis_map_t item_axis_map{ | ||||
|         { recomp::ControllerState::AXIS_RIGHT_X, -controller_default_threshold, N64Inputs::C_LEFT }, | ||||
|         { recomp::ControllerState::AXIS_RIGHT_X,  controller_default_threshold, N64Inputs::C_RIGHT }, | ||||
|         { recomp::ControllerState::AXIS_RIGHT_Y,  controller_default_threshold, N64Inputs::C_DOWN }, | ||||
|     }; | ||||
| 
 | ||||
|     static const button_map_t item_button_map { | ||||
|         { recomp::ControllerState::BUTTON_EAST, N64Inputs::B }, | ||||
|         { recomp::ControllerState::BUTTON_WEST, N64Inputs::B }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_LEFT,  N64Inputs::DPAD_LEFT }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_RIGHT, N64Inputs::DPAD_RIGHT }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_UP,    N64Inputs::DPAD_UP }, | ||||
|         { recomp::ControllerState::BUTTON_DPAD_DOWN,  N64Inputs::DPAD_DOWN }, | ||||
|     }; | ||||
| 
 | ||||
|     u32* buttons_out = _arg<0, u32*>(rdram, ctx); | ||||
| 
 | ||||
|     uint32_t cur_buttons = 0; | ||||
| 
 | ||||
|     // TODO do this in a way that will allow for remapping keyboard inputs
 | ||||
|     uint16_t keyboard_buttons; | ||||
|     float dummy_x, dummy_y; | ||||
|     recomp::get_keyboard_input(&keyboard_buttons, &dummy_x, &dummy_y); | ||||
|     cur_buttons |= keyboard_buttons; | ||||
| 
 | ||||
|     // Process controller inputs
 | ||||
|     std::vector<recomp::InputState> input_states = recomp::get_input_states(); | ||||
| 
 | ||||
|     for (const recomp::InputState& state : input_states) { | ||||
|         if (const auto* controller_state = std::get_if<recomp::ControllerState>(&state)) { | ||||
|             cur_buttons |= process_controller_mappings(*controller_state, item_axis_map, item_button_map); | ||||
|         } | ||||
|         else if (const auto* mouse_state = std::get_if<recomp::MouseState>(&state)) { | ||||
|             // Mouse currently unused
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *buttons_out = cur_buttons; | ||||
| } | ||||
| 
 | ||||
| // TODO move this
 | ||||
| extern "C" void recomp_puts(uint8_t* rdram, recomp_context* ctx) { | ||||
|     PTR(char) cur_str = _arg<0, PTR(char)>(rdram, ctx); | ||||
|     u32 length = _arg<1, u32>(rdram, ctx); | ||||
| 
 | ||||
|     for (u32 i = 0; i < length; i++) { | ||||
|         fputc(MEM_B(i, (gpr)cur_str), stdout); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										197
									
								
								src/game/input.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/game/input.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,197 @@ | |||
| #include <atomic> | ||||
| 
 | ||||
| #include "../ultramodern/ultramodern.hpp" | ||||
| #include "recomp.h" | ||||
| #include "recomp_input.h" | ||||
| #include "recomp_ui.h" | ||||
| #include "SDL.h" | ||||
| 
 | ||||
| std::atomic_int32_t mouse_wheel_pos = 0; | ||||
| std::vector<SDL_JoystickID> controllers{}; | ||||
| 
 | ||||
| bool sdl_event_filter(void* userdata, SDL_Event* event) { | ||||
|     switch (event->type) { | ||||
|     //case SDL_EventType::SDL_KEYUP:
 | ||||
|     //case SDL_EventType::SDL_KEYDOWN:
 | ||||
|     //    {
 | ||||
|     //        const Uint8* key_states = SDL_GetKeyboardState(nullptr);
 | ||||
|     //        int new_button = 0;
 | ||||
| 
 | ||||
|     //        for (const auto& mapping : keyboard_button_map) {
 | ||||
|     //            if (key_states[mapping.first]) {
 | ||||
|     //                new_button |= mapping.second;
 | ||||
|     //            }
 | ||||
|     //        }
 | ||||
| 
 | ||||
|     //        button = new_button;
 | ||||
| 
 | ||||
|     //        stick_x = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_D] - key_states[SDL_Scancode::SDL_SCANCODE_A]);
 | ||||
|     //        stick_y = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_W] - key_states[SDL_Scancode::SDL_SCANCODE_S]);
 | ||||
|     //    }
 | ||||
|     //    break;
 | ||||
|     case SDL_EventType::SDL_CONTROLLERDEVICEADDED: | ||||
|         { | ||||
|             SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event; | ||||
|             SDL_GameController* controller = SDL_GameControllerOpen(controller_event->which); | ||||
|             printf("Controller added: %d\n", controller_event->which); | ||||
|             if (controller != nullptr) { | ||||
|                 printf("  Instance ID: %d\n", SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); | ||||
|                 controllers.push_back(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case SDL_EventType::SDL_CONTROLLERDEVICEREMOVED: | ||||
|         { | ||||
|             SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event; | ||||
|             printf("Controller removed: %d\n", controller_event->which); | ||||
|             std::erase(controllers, controller_event->which); | ||||
|         } | ||||
|         break; | ||||
|     case SDL_EventType::SDL_QUIT: | ||||
|         ultramodern::quit(); | ||||
|         return true; | ||||
|     case SDL_EventType::SDL_MOUSEWHEEL: | ||||
|         { | ||||
|             SDL_MouseWheelEvent* wheel_event = (SDL_MouseWheelEvent*)event;     | ||||
|             mouse_wheel_pos.fetch_add(wheel_event->y * (wheel_event->direction == SDL_MOUSEWHEEL_FLIPPED ? -1 : 1)); | ||||
|         } | ||||
|         recomp::queue_event(*event); | ||||
|         break; | ||||
|     default: | ||||
|         recomp::queue_event(*event); | ||||
|         break; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void recomp::handle_events() { | ||||
|     SDL_Event cur_event; | ||||
|     static bool exited = false; | ||||
|     while (SDL_PollEvent(&cur_event) && !exited) { | ||||
|         exited = sdl_event_filter(nullptr, &cur_event); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::vector<recomp::InputState> recomp::get_input_states() { | ||||
|     std::vector<InputState> ret{}; | ||||
| 
 | ||||
|     int32_t mouse_x; | ||||
|     int32_t mouse_y; | ||||
| 
 | ||||
|     Uint32 sdl_mouse_buttons = SDL_GetMouseState(&mouse_x, &mouse_y); | ||||
| 
 | ||||
|     struct MouseButtonMapping { | ||||
|         Sint32 input; | ||||
|         decltype(MouseState::buttons) output; | ||||
|     }; | ||||
|     static const std::vector<MouseButtonMapping> input_mouse_map{ | ||||
|         { SDL_BUTTON_LMASK,  MouseState::LEFT }, | ||||
|         { SDL_BUTTON_RMASK,  MouseState::RIGHT }, | ||||
|         { SDL_BUTTON_MMASK,  MouseState::MIDDLE }, | ||||
|         { SDL_BUTTON_X1MASK, MouseState::BACK }, | ||||
|         { SDL_BUTTON_X2MASK, MouseState::FORWARD }, | ||||
|     }; | ||||
| 
 | ||||
|     decltype(MouseState::buttons) mouse_buttons = 0; | ||||
|     for (const MouseButtonMapping& mapping : input_mouse_map) { | ||||
|         if (sdl_mouse_buttons & mapping.input) { | ||||
|             mouse_buttons |= mapping.output; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (mouse_buttons & MouseState::FORWARD) { | ||||
|         printf("forward\n"); | ||||
|     } | ||||
| 
 | ||||
|     if (mouse_buttons & MouseState::BACK) { | ||||
|         printf("back\n"); | ||||
|     } | ||||
| 
 | ||||
|     ret.emplace_back( | ||||
|         MouseState { | ||||
|             .wheel_pos = mouse_wheel_pos, | ||||
|             .position_x = mouse_x, | ||||
|             .position_y = mouse_y, | ||||
|             .buttons = mouse_buttons | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
|     for (SDL_JoystickID controller_id : controllers) { | ||||
|         struct InputButtonMapping { | ||||
|             SDL_GameControllerButton input; | ||||
|             decltype(ControllerState::buttons) output; | ||||
|         }; | ||||
|         static const std::vector<InputButtonMapping> input_button_map{ | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START,         ControllerState::BUTTON_START }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A,             ControllerState::BUTTON_SOUTH }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B,             ControllerState::BUTTON_EAST }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X,             ControllerState::BUTTON_WEST }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y,             ControllerState::BUTTON_NORTH }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,  ControllerState::BUTTON_L1 }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, ControllerState::BUTTON_R1 }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK,     ControllerState::BUTTON_L3 }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK,    ControllerState::BUTTON_R3 }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT,     ControllerState::BUTTON_DPAD_LEFT }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,    ControllerState::BUTTON_DPAD_RIGHT }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP,       ControllerState::BUTTON_DPAD_UP }, | ||||
|             { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN,     ControllerState::BUTTON_DPAD_DOWN }, | ||||
|         }; | ||||
|         SDL_GameController* controller = SDL_GameControllerFromInstanceID(controller_id); | ||||
|         decltype(ControllerState::buttons) buttons = 0; | ||||
| 
 | ||||
|         for (const InputButtonMapping& mapping : input_button_map) { | ||||
|             if (SDL_GameControllerGetButton(controller, mapping.input)) { | ||||
|                 buttons |= mapping.output; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         auto& new_input_state = ret.emplace_back( | ||||
|             ControllerState { | ||||
|                 .buttons = buttons, | ||||
|                 .axes = {}, | ||||
|             } | ||||
|         ); | ||||
|         auto& new_state = std::get<ControllerState>(new_input_state); | ||||
|         new_state.axes[ControllerState::AXIS_LEFT_X] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX) * (1/32768.0f); | ||||
|         new_state.axes[ControllerState::AXIS_LEFT_Y] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY) * (1/32768.0f); | ||||
|         new_state.axes[ControllerState::AXIS_RIGHT_X] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX) * (1/32768.0f); | ||||
|         new_state.axes[ControllerState::AXIS_RIGHT_Y] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY) * (1/32768.0f); | ||||
|         new_state.axes[ControllerState::AXIS_LEFT_TRIGGER] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT) * (1/32768.0f); | ||||
|         new_state.axes[ControllerState::AXIS_LEFT_TRIGGER] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT) * (1/32768.0f); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| // TODO figure out a way to handle this more generally without exposing SDL to controls.cpp
 | ||||
| void recomp::get_keyboard_input(uint16_t* buttons_out, float* x_out, float* y_out) { | ||||
|     static const std::vector<std::pair<SDL_Scancode, int>> keyboard_button_map{ | ||||
|         { SDL_Scancode::SDL_SCANCODE_LEFT,   0x0002 }, // c left
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_RIGHT,  0x0001 }, // c right
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_UP,     0x0008 }, // c up
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_DOWN,   0x0004 }, // c down
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_RETURN, 0x1000 }, // start
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_SPACE,  0x8000 }, // a
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_LSHIFT, 0x4000 }, // b
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_Q,      0x2000 }, // z
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_E,      0x0020 }, // l
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_R,      0x0010 }, // r
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_J,      0x0200 }, // dpad left
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_L,      0x0100 }, // dpad right
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_I,      0x0800 }, // dpad up
 | ||||
|         { SDL_Scancode::SDL_SCANCODE_K,      0x0400 }, // dpad down
 | ||||
|     }; | ||||
|      | ||||
|     const Uint8* key_states = SDL_GetKeyboardState(nullptr); | ||||
| 
 | ||||
|     *buttons_out = 0; | ||||
| 
 | ||||
|     for (const auto& mapping : keyboard_button_map) { | ||||
|         if (key_states[mapping.first]) { | ||||
|             *buttons_out |= mapping.second; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *x_out = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_D] - key_states[SDL_Scancode::SDL_SCANCODE_A]); | ||||
|     *y_out = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_W] - key_states[SDL_Scancode::SDL_SCANCODE_S]); | ||||
| } | ||||
|  | @ -15,6 +15,7 @@ | |||
| #endif | ||||
| 
 | ||||
| #include "recomp_ui.h" | ||||
| #include "recomp_input.h" | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
|  | @ -33,120 +34,6 @@ void exit_error(const char* str, Ts ...args) { | |||
|     std::quick_exit(EXIT_FAILURE); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::vector<std::pair<SDL_Scancode, int>> keyboard_button_map{ | ||||
|     { SDL_Scancode::SDL_SCANCODE_LEFT,   0x0002 }, // c left
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_RIGHT,  0x0001 }, // c right
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_UP,     0x0008 }, // c up
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_DOWN,   0x0004 }, // c down
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_RETURN, 0x1000 }, // start
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_SPACE,  0x8000 }, // a
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_LSHIFT, 0x4000 }, // b
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_Q,      0x2000 }, // z
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_E,      0x0020 }, // l
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_R,      0x0010 }, // r
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_J,      0x0200 }, // dpad left
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_L,      0x0100 }, // dpad right
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_I,      0x0800 }, // dpad up
 | ||||
|     { SDL_Scancode::SDL_SCANCODE_K,      0x0400 }, // dpad down
 | ||||
| }; | ||||
| 
 | ||||
| struct GameControllerAxisMapping { | ||||
|     SDL_GameControllerAxis axis; | ||||
|     int threshold; // Positive or negative to indicate direction
 | ||||
|     uint16_t output_mask; | ||||
| }; | ||||
| 
 | ||||
| constexpr int controller_default_threshold = 20000; | ||||
| 
 | ||||
| std::vector<GameControllerAxisMapping> controller_axis_map{ | ||||
|     { SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX,      -controller_default_threshold, 0x0002 }, // c left
 | ||||
|     { SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX,       controller_default_threshold, 0x0001 }, // c right
 | ||||
|     { SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY,      -controller_default_threshold, 0x0008 }, // c up
 | ||||
|     { SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY,       controller_default_threshold, 0x0004 }, // c down
 | ||||
|     { SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT, 10000,                         0x2000 }, // z
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_RIGHT,  0x0001 }, // c right
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_UP,     0x0008 }, // c up
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_DOWN,   0x0004 }, // c down
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_RETURN, 0x1000 }, // start
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_SPACE,  0x8000 }, // a
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_LSHIFT, 0x4000 }, // b
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_Q,      0x2000 }, // z
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_E,      0x0020 }, // l
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_R,      0x0010 }, // r
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_J,      0x0200 }, // dpad left
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_L,      0x0100 }, // dpad right
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_I,      0x0800 }, // dpad up
 | ||||
|     //{ SDL_Scancode::SDL_SCANCODE_K,      0x0400 }, // dpad down
 | ||||
| }; | ||||
| 
 | ||||
| struct GameControllerButtonMapping { | ||||
|     SDL_GameControllerButton button; | ||||
|     uint16_t output_mask; | ||||
| }; | ||||
| std::vector<GameControllerButtonMapping> controller_button_map{ | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START,         0x1000 }, // start
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A,             0x8000 }, // a
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B,             0x4000 }, // b
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X,             0x4000 }, // b
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,  0x0020 }, // l
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, 0x0010 }, // r
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT,     0x0200 }, // dpad left
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,    0x0100 }, // dpad right
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP,       0x0800 }, // dpad up
 | ||||
|     { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN,     0x0400 }, // dpad down
 | ||||
| }; | ||||
| 
 | ||||
| std::vector<SDL_JoystickID> controllers{}; | ||||
| 
 | ||||
| bool sdl_event_filter(void* userdata, SDL_Event* event) { | ||||
|     switch (event->type) { | ||||
|     //case SDL_EventType::SDL_KEYUP:
 | ||||
|     //case SDL_EventType::SDL_KEYDOWN:
 | ||||
|     //    {
 | ||||
|     //        const Uint8* key_states = SDL_GetKeyboardState(nullptr);
 | ||||
|     //        int new_button = 0;
 | ||||
| 
 | ||||
|     //        for (const auto& mapping : keyboard_button_map) {
 | ||||
|     //            if (key_states[mapping.first]) {
 | ||||
|     //                new_button |= mapping.second;
 | ||||
|     //            }
 | ||||
|     //        }
 | ||||
| 
 | ||||
|     //        button = new_button;
 | ||||
| 
 | ||||
|     //        stick_x = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_D] - key_states[SDL_Scancode::SDL_SCANCODE_A]);
 | ||||
|     //        stick_y = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_W] - key_states[SDL_Scancode::SDL_SCANCODE_S]);
 | ||||
|     //    }
 | ||||
|     //    break;
 | ||||
|     case SDL_EventType::SDL_CONTROLLERDEVICEADDED: | ||||
|         { | ||||
|             SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event; | ||||
|             SDL_GameController* controller = SDL_GameControllerOpen(controller_event->which); | ||||
|             printf("Controller added: %d\n", controller_event->which); | ||||
|             if (controller != nullptr) { | ||||
|                 printf("  Instance ID: %d\n", SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); | ||||
|                 controllers.push_back(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case SDL_EventType::SDL_CONTROLLERDEVICEREMOVED: | ||||
|         { | ||||
|             SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event; | ||||
|             printf("Controller removed: %d\n", controller_event->which); | ||||
|             std::erase(controllers, controller_event->which); | ||||
|         } | ||||
|         break; | ||||
|     case SDL_EventType::SDL_QUIT: | ||||
|         ultramodern::quit(); | ||||
|         return true; | ||||
|     default: | ||||
|         queue_event(*event); | ||||
|         break; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| ultramodern::gfx_callbacks_t::gfx_data_t create_gfx() { | ||||
|     SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "system"); | ||||
|     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) > 0) { | ||||
|  | @ -181,67 +68,7 @@ ultramodern::WindowHandle create_window(ultramodern::gfx_callbacks_t::gfx_data_t | |||
| } | ||||
| 
 | ||||
| void update_gfx(void*) { | ||||
|     // Handle events
 | ||||
|     constexpr int max_events_per_frame = 16; | ||||
|     SDL_Event cur_event; | ||||
|     int i = 0; | ||||
|     static bool exited = false; | ||||
|     while (i++ < max_events_per_frame && SDL_PollEvent(&cur_event) && !exited) { | ||||
|         exited = sdl_event_filter(nullptr, &cur_event); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void get_input(uint16_t* buttons_out, float* x_out, float* y_out) { | ||||
|     uint16_t cur_buttons = 0; | ||||
|     float cur_x = 0.0f; | ||||
|     float cur_y = 0.0f; | ||||
| 
 | ||||
|     const Uint8* key_states = SDL_GetKeyboardState(nullptr); | ||||
|     int new_button = 0; | ||||
| 
 | ||||
|     for (const auto& mapping : keyboard_button_map) { | ||||
|         if (key_states[mapping.first]) { | ||||
|             cur_buttons |= mapping.second; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     cur_x += (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_D] - key_states[SDL_Scancode::SDL_SCANCODE_A]); | ||||
|     cur_y += (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_W] - key_states[SDL_Scancode::SDL_SCANCODE_S]); | ||||
| 
 | ||||
|     for (SDL_JoystickID controller_id : controllers) { | ||||
|         SDL_GameController* controller = SDL_GameControllerFromInstanceID(controller_id); | ||||
|         if (controller != nullptr) { | ||||
|             cur_x += SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX) * (1/32768.0f); | ||||
|             cur_y -= SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY) * (1/32768.0f); | ||||
|         } | ||||
| 
 | ||||
|         for (const auto& mapping : controller_axis_map) { | ||||
|             int input_value = SDL_GameControllerGetAxis(controller, mapping.axis); | ||||
|             if (mapping.threshold > 0) { | ||||
|                 if (input_value > mapping.threshold) { | ||||
|                     cur_buttons |= mapping.output_mask; | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 if (input_value < mapping.threshold) { | ||||
|                     cur_buttons |= mapping.output_mask; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (const auto& mapping : controller_button_map) { | ||||
|             int input_value = SDL_GameControllerGetButton(controller, mapping.button); | ||||
|             if (input_value) { | ||||
|                 cur_buttons |= mapping.output_mask; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *buttons_out = cur_buttons; | ||||
|     cur_x = std::clamp(cur_x, -1.0f, 1.0f); | ||||
|     cur_y = std::clamp(cur_y, -1.0f, 1.0f); | ||||
|     *x_out = cur_x; | ||||
|     *y_out = cur_y; | ||||
|     recomp::handle_events(); | ||||
| } | ||||
| 
 | ||||
| static SDL_AudioDeviceID audio_device = 0; | ||||
|  | @ -357,7 +184,7 @@ int main(int argc, char** argv) { | |||
|     }; | ||||
| 
 | ||||
|     ultramodern::input_callbacks_t input_callbacks{ | ||||
|         .get_input = get_input, | ||||
|         .get_input = recomp::get_n64_input, | ||||
|     }; | ||||
| 
 | ||||
|     ultramodern::start({}, audio_callbacks, input_callbacks, gfx_callbacks); | ||||
|  |  | |||
|  | @ -101,16 +101,3 @@ extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) { | |||
| extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) { | ||||
|     ; | ||||
| } | ||||
| 
 | ||||
| #include "../patches/input.h" | ||||
| 
 | ||||
| extern "C" void recomp_get_item_inputs(uint8_t* rdram, recomp_context* ctx) { | ||||
|     RecompInputs* inputs = _arg<0, RecompInputs*>(rdram, ctx); | ||||
| 
 | ||||
|     if (input_callbacks.get_input) { | ||||
|         u16 buttons; | ||||
|         input_callbacks.get_input(&buttons, &inputs->x, &inputs->y); | ||||
|         // TODO remap the inputs for items here
 | ||||
|         inputs->buttons = buttons; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -35,6 +35,13 @@ void load_overlay(size_t section_table_index, int32_t ram) { | |||
|     section_addresses[section.index] = ram; | ||||
| } | ||||
| 
 | ||||
| void load_special_overlay(const SectionTableEntry& section, int32_t ram) { | ||||
|     for (size_t function_index = 0; function_index < section.num_funcs; function_index++) { | ||||
|         const FuncEntry& func = section.funcs[function_index]; | ||||
|         func_map[ram + func.offset] = func.func; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| extern "C" { | ||||
| int32_t section_addresses[num_sections]; | ||||
|  | @ -128,6 +135,8 @@ extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void load_patch_functions(); | ||||
| 
 | ||||
| void init_overlays() { | ||||
|     for (size_t section_index = 0; section_index < num_code_sections; section_index++) { | ||||
|         section_addresses[section_table[section_index].index] = section_table[section_index].ram_addr; | ||||
|  | @ -139,6 +148,8 @@ void init_overlays() { | |||
|             return a.rom_addr < b.rom_addr; | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
|     load_patch_functions(); | ||||
| } | ||||
| 
 | ||||
| extern "C" recomp_func_t * get_function(int32_t addr) { | ||||
|  |  | |||
							
								
								
									
										11
									
								
								src/recomp/patch_loading.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/recomp/patch_loading.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #include <unordered_map> | ||||
| #include <algorithm> | ||||
| #include <vector> | ||||
| #include "recomp.h" | ||||
| #include "../RecompiledPatches/recomp_overlays.inl" | ||||
| 
 | ||||
| void load_special_overlay(const SectionTableEntry& section, int32_t ram); | ||||
| 
 | ||||
| void load_patch_functions() { | ||||
| 	load_special_overlay(section_table[0], section_table[0].ram_addr); | ||||
| } | ||||
|  | @ -36,7 +36,7 @@ public: | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| std::unique_ptr<Rml::EventListenerInstancer> make_event_listener_instancer() { | ||||
| std::unique_ptr<Rml::EventListenerInstancer> recomp::make_event_listener_instancer() { | ||||
| 	std::unique_ptr<UiEventListenerInstancer> ret = std::make_unique<UiEventListenerInstancer>(); | ||||
| 
 | ||||
| 	ret->register_event("start_game", | ||||
|  |  | |||
|  | @ -579,7 +579,7 @@ public: | |||
| struct { | ||||
|     struct UIRenderContext render; | ||||
|     class { | ||||
|         std::unordered_map<Menu, Rml::ElementDocument*> documents; | ||||
|         std::unordered_map<recomp::Menu, Rml::ElementDocument*> documents; | ||||
|         Rml::ElementDocument* current_document; | ||||
|     public: | ||||
|         SystemInterface_SDL system_interface; | ||||
|  | @ -591,7 +591,7 @@ struct { | |||
|             render_interface.reset(); | ||||
|         } | ||||
| 
 | ||||
|         void swap_document(Menu menu) { | ||||
|         void swap_document(recomp::Menu menu) { | ||||
|             if (current_document != nullptr) { | ||||
|                 current_document->Hide(); | ||||
|             } | ||||
|  | @ -628,7 +628,7 @@ struct { | |||
|                 Rml::Factory::RegisterEventListenerInstancer(event_listener_instancer.get()); | ||||
|             } | ||||
| 
 | ||||
|             documents.emplace(Menu::Launcher, context->LoadDocument("assets/launcher.rml")); | ||||
|             documents.emplace(recomp::Menu::Launcher, context->LoadDocument("assets/launcher.rml")); | ||||
|         } | ||||
|     } rml; | ||||
| } UIContext; | ||||
|  | @ -645,7 +645,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) { | |||
|     // Setup RML
 | ||||
|     UIContext.rml.system_interface.SetWindow(window); | ||||
|     UIContext.rml.render_interface = std::make_unique<RmlRenderInterface_RT64>(&UIContext.render); | ||||
|     UIContext.rml.event_listener_instancer = make_event_listener_instancer(); | ||||
|     UIContext.rml.event_listener_instancer = recomp::make_event_listener_instancer(); | ||||
| 
 | ||||
|     Rml::SetSystemInterface(&UIContext.rml.system_interface); | ||||
|     Rml::SetRenderInterface(UIContext.rml.render_interface.get()); | ||||
|  | @ -685,15 +685,15 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) { | |||
| 
 | ||||
| moodycamel::ConcurrentQueue<SDL_Event> ui_event_queue{}; | ||||
| 
 | ||||
| void queue_event(const SDL_Event& event) { | ||||
| void recomp::queue_event(const SDL_Event& event) { | ||||
|     ui_event_queue.enqueue(event); | ||||
| } | ||||
| 
 | ||||
| bool try_deque_event(SDL_Event& out) { | ||||
| bool recomp::try_deque_event(SDL_Event& out) { | ||||
|     return ui_event_queue.try_dequeue(out); | ||||
| } | ||||
| 
 | ||||
| std::atomic<Menu> open_menu = Menu::Launcher; | ||||
| std::atomic<recomp::Menu> open_menu = recomp::Menu::Launcher; | ||||
| 
 | ||||
| void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) { | ||||
|     int num_keys; | ||||
|  | @ -704,12 +704,12 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_ | |||
|     bool reload_sheets = is_reload_held && !was_reload_held; | ||||
|     was_reload_held = is_reload_held; | ||||
|      | ||||
|     static Menu prev_menu = Menu::None; | ||||
|     Menu cur_menu = open_menu.load(); | ||||
|     static recomp::Menu prev_menu = recomp::Menu::None; | ||||
|     recomp::Menu cur_menu = open_menu.load(); | ||||
| 
 | ||||
|     if (reload_sheets) { | ||||
|         UIContext.rml.load_documents(); | ||||
|         prev_menu = Menu::None; | ||||
|         prev_menu = recomp::Menu::None; | ||||
|     } | ||||
| 
 | ||||
|     if (cur_menu != prev_menu) { | ||||
|  | @ -720,11 +720,11 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_ | |||
| 
 | ||||
|     SDL_Event cur_event{}; | ||||
| 
 | ||||
|     while (try_deque_event(cur_event)) { | ||||
|     while (recomp::try_deque_event(cur_event)) { | ||||
|         RmlSDL::InputEventHandler(UIContext.rml.context, cur_event); | ||||
|     } | ||||
| 
 | ||||
|     if (cur_menu != Menu::None) { | ||||
|     if (cur_menu != recomp::Menu::None) { | ||||
|         int width, height; | ||||
|         SDL_GetWindowSizeInPixels(window, &width, &height); | ||||
| 
 | ||||
|  | @ -753,11 +753,11 @@ void set_rt64_hooks() { | |||
|     RT64::SetRenderHooks(init_hook, draw_hook, deinit_hook); | ||||
| } | ||||
| 
 | ||||
| void set_current_menu(Menu menu) { | ||||
| void recomp::set_current_menu(Menu menu) { | ||||
|     open_menu.store(menu); | ||||
| } | ||||
| 
 | ||||
| void destroy_ui() { | ||||
| void recomp::destroy_ui() { | ||||
|     Rml::Shutdown(); | ||||
|     UIContext.rml.unload(); | ||||
| } | ||||
|  |  | |||
|  | @ -292,7 +292,7 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read | |||
|             } | ||||
|         } | ||||
|     } | ||||
|     destroy_ui(); | ||||
|     recomp::destroy_ui(); | ||||
|     // TODO restore this call once the RT64 shutdown issue is fixed.
 | ||||
|     // RT64Shutdown();
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Mr-Wiseguy
						Mr-Wiseguy