mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Hooked up graphics option menu to RT64, updated RT64
This commit is contained in:
		
							parent
							
								
									ac131c7835
								
							
						
					
					
						commit
						09bacbe82c
					
				
					 12 changed files with 354 additions and 135 deletions
				
			
		|  | @ -127,7 +127,9 @@ target_include_directories(MMRecomp PRIVATE | |||
|     ${CMAKE_SOURCE_DIR}/lib/concurrentqueue | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RmlUi/Include | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RmlUi/Backends | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RT64-HLE/src/contrib | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RT64-HLE/src/contrib/mupen64plus-win32-deps/SDL2-2.26.3/include | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RT64-HLE/src/contrib/hlslpp/include | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RT64-HLE/src | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RT64-HLE/src/rhi | ||||
|     ${CMAKE_SOURCE_DIR}/lib/RT64-HLE/src/render | ||||
|  |  | |||
|  | @ -33,55 +33,55 @@ | |||
| 			<div style="flex:1 1 auto"> | ||||
| 				<tabset> | ||||
| 					<tab id="tab_graphics" autofocus>Graphics</tab> | ||||
| 					<panel> | ||||
| 					<panel data-model="graphics_model"> | ||||
| 						<form> | ||||
| 							<div class="option_container"> | ||||
| 								<div class="option_row"> | ||||
| 									<div class="option"> | ||||
| 										<label style="padding:4dp;">Resolution</label><br/> | ||||
| 										<label class="option_title">Resolution</label><br/> | ||||
| 										<hr/> | ||||
| 										<div class="option_list"> | ||||
| 											<input type="radio" name="resolution" id="res_original"/> | ||||
| 											<input type="radio" name="resolution" data-checked="res_option" value="Original" id="res_original"/> | ||||
| 											<label for="res_original">Original</label> | ||||
| 											<input type="radio" name="resolution" id="res_2x" style="nav-down:#ar_expand"/> | ||||
| 											<input type="radio" name="resolution" data-checked="res_option" value="Original2x" id="res_2x" style="nav-down:#ar_expand"/> | ||||
| 											<label for="res_2x">Original 2x</label> | ||||
| 											<input type="radio" name="resolution" id="res_auto" style="nav-down:#ar_expand" checked="checked"/> | ||||
| 											<input type="radio" name="resolution" data-checked="res_option" value="Auto" id="res_auto" style="nav-down:#ar_expand"/> | ||||
| 											<label for="res_auto">Auto</label> | ||||
| 										</div> | ||||
| 									</div> | ||||
| 									<div class="option"> | ||||
| 										<label style="padding:4dp;">Window Mode</label><br/> | ||||
| 										<label class="option_title">Window Mode</label><br/> | ||||
| 										<hr/> | ||||
| 										<div class="option_list"> | ||||
| 											<input type="radio" name="windowmode" id="wm_windowed" style="nav-down:#msaa_none" checked="checked"/> | ||||
| 											<input type="radio" name="windowmode" data-checked="wm_option" value="Windowed" id="wm_windowed" style="nav-down:#msaa_none"/> | ||||
| 											<label for="wm_windowed">Windowed</label> | ||||
| 											<input type="radio" name="windowmode" id="wm_fullscreen" style="nav-right:none"/> | ||||
| 											<input type="radio" name="windowmode" data-checked="wm_option" value="Fullscreen" id="wm_fullscreen" style="nav-right:none"/> | ||||
| 											<label for="wm_fullscreen">Fullscreen</label> | ||||
| 										</div> | ||||
| 									</div> | ||||
| 								</div> | ||||
| 								<div class="option_row"> | ||||
| 									<div class="option"> | ||||
| 										<label style="padding:4dp;">Aspect Ratio</label><br/> | ||||
| 										<label class="option_title">Aspect Ratio</label><br/> | ||||
| 										<hr/> | ||||
| 										<div class="option_list"> | ||||
| 											<input type="radio" name="aspectratio" id="ar_original" style="nav-left:none"/> | ||||
| 											<input type="radio" name="aspectratio" data-checked="ar_option" value="Original" id="ar_original" style="nav-left:none"/> | ||||
| 											<label for="ar_original">Original</label> | ||||
| 											<input type="radio" name="aspectratio" id="ar_expand" style="nav-up:#res_2x" checked="checked"/> | ||||
| 											<input type="radio" name="aspectratio" data-checked="ar_option" value="Expand" id="ar_expand" style="nav-up:#res_2x"/> | ||||
| 											<label for="ar_expand">Expand</label> | ||||
| 										</div> | ||||
| 									</div> | ||||
| 									<div class="option"> | ||||
| 										<label style="padding:4dp;">MS Anti-Aliasing</label><br/> | ||||
| 										<label class="option_title">MS Anti-Aliasing</label><br/> | ||||
| 										<hr/> | ||||
| 										<div class="option_list"> | ||||
| 											<input type="radio" name="antialiasing" id="msaa_none" checked="checked" style="nav-up:#wm_windowed;nav-left:none"/> | ||||
| 											<input type="radio" name="antialiasing" data-checked="msaa_option" value="None" id="msaa_none" style="nav-up:#wm_windowed;nav-down:#rr_manual"/> | ||||
| 											<label for="msaa_none">None</label> | ||||
| 											<input type="radio" name="antialiasing" id="msaa_2x"/> | ||||
| 											<input type="radio" name="antialiasing" data-checked="msaa_option" value="MSAA2X" id="msaa_2x" style="nav-down:#rr_manual"/> | ||||
| 											<label for="msaa_2x">2x</label> | ||||
| 											<input type="radio" name="antialiasing" id="msaa_4x"/> | ||||
| 											<input type="radio" name="antialiasing" data-checked="msaa_option" value="MSAA4X" id="msaa_4x" style="nav-down:#rr_manual"/> | ||||
| 											<label for="msaa_4x">4x</label> | ||||
| 											<input type="radio" name="antialiasing" id="msaa_8x" style="nav-right:none"/> | ||||
| 											<input type="radio" name="antialiasing" data-checked="msaa_option" value="MSAA8X" id="msaa_8x" style="nav-right:none;nav-down:#rr_manual"/> | ||||
| 											<label for="msaa_8x">8x</label> | ||||
| 										</div> | ||||
| 									</div> | ||||
|  | @ -89,20 +89,24 @@ | |||
| 								 | ||||
| 								<div class="option_row"> | ||||
| 									<div class="option"> | ||||
| 										<label style="padding:4dp;">Refresh Rate</label><br/> | ||||
| 										<label class="option_title">Framerate</label><br/> | ||||
| 										<hr/> | ||||
| 										<div class="option_list" style="flex-wrap: wrap;"> | ||||
| 											<input type="radio" name="refreshrate" id="rr_original" style="nav-up:#ar_expand"/> | ||||
| 										<div class="option_list"> | ||||
| 											<input type="radio" name="refreshrate" data-checked="rr_option" value="Original" id="rr_original" style="nav-up:#ar_expand"/> | ||||
| 											<label for="rr_original">Original</label> | ||||
| 											<input type="radio" name="refreshrate" id="rr_display" style="nav-up:#ar_expand"/> | ||||
| 											<input type="radio" name="refreshrate" data-checked="rr_option" value="Display" id="rr_display" style="nav-up:#ar_expand"/> | ||||
| 											<label for="rr_display">Display</label> | ||||
| 											<input type="radio" name="refreshrate" id="rr_manual" checked="checked" style="nav-up:#msaa_none;nav-right:none"/> | ||||
| 											<input type="radio" name="refreshrate" data-checked="rr_option" value="Manual" id="rr_manual" style="nav-up:#msaa_none;nav-right:none"/> | ||||
| 											<label for="rr_manual">Manual</label> | ||||
| 											<div style="flex-basis:100%;height:0"/> | ||||
| 											<input id="rr_manual_input" type="range" min="60" max="1000" style="font:normal;flex:1;nav-up:auto;nav-down:auto;width:100%" value="60"/> | ||||
| 										</div> | ||||
| 										<div data-if="rr_option=='Manual'" class="option_list" style="padding:10dp"> | ||||
| 											<input id="rr_manual_input" type="range" min="20" max="1000" style="flex:1;margin-left:30dp;margin-right:30dp;nav-up:auto;nav-down:auto;" data-value="rr_manual_value"/> | ||||
| 											<label style="flex:0 0 50dp">{{rr_manual_value}}</label> | ||||
| 										</div> | ||||
| 									</div> | ||||
| 								</div> | ||||
| 
 | ||||
| 								<button nav-return="rr_manual" style="margin-top:10dp;margin-left:auto;margin-right:auto;width:100dp" data-attrif-disabled="!options_changed" onclick="apply_options">Apply</button> | ||||
| 							</div> | ||||
| 						</form> | ||||
| 					</panel> | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ div.option_container { | |||
|     margin-left:auto; | ||||
|     margin-right:auto; | ||||
|     font-effect: outline(2dp black); | ||||
|     font-size:24dp; | ||||
|     font-size:20dp; | ||||
|     background:rgba(50,50,50,200); | ||||
| } | ||||
| 
 | ||||
|  | @ -55,6 +55,11 @@ div.option_list { | |||
|     justify-content:center; | ||||
| } | ||||
| 
 | ||||
| label.option_title { | ||||
|     padding:4dp; | ||||
|     font-size:24dp; | ||||
| } | ||||
| 
 | ||||
| div#title_bar { | ||||
|     z-index: 1; | ||||
|     position: absolute; | ||||
|  | @ -137,17 +142,18 @@ input.submit { | |||
|     /* vertical-align: center; */ | ||||
|     height: auto; | ||||
|     width: 100%; | ||||
|     focus:auto; | ||||
|     tab-index:auto; | ||||
|     nav-up:auto; | ||||
|     nav-down:auto; | ||||
|     nav-right:auto; | ||||
|     nav-left:auto; | ||||
| } | ||||
| 
 | ||||
| button:focus, | ||||
| input.submit:focus { | ||||
|     font-effect: blur(3dp #fff); | ||||
|     background-color: rgb(120, 120, 120); | ||||
| } | ||||
| 
 | ||||
| button:hover, | ||||
| input.submit:hover { | ||||
|     background-color: rgb(150, 150, 150); | ||||
|     /* font-effect: blur(3dp #fff); */ | ||||
|     color: #329696; | ||||
| } | ||||
| 
 | ||||
| button:active, | ||||
|  | @ -161,6 +167,34 @@ input.submit:disabled { | |||
|     cursor: unavailable | ||||
| } | ||||
| 
 | ||||
| button[disabled] { | ||||
|     /* decorator: image(button); */ | ||||
|     /* image-color: #329696; */ | ||||
|     /* color:black; */ | ||||
|     color:rgb(100,100,100); | ||||
|     background-color: rgb(50, 50, 50); | ||||
|     /* focus:none; | ||||
|     tab-index:none; | ||||
|     nav-up:none; | ||||
|     nav-down:none; | ||||
|     nav-right:none; | ||||
|     nav-left:none; */ | ||||
| } | ||||
| 
 | ||||
| button:focus[disabled] { | ||||
|     /* decorator: image(button); */ | ||||
|     /* image-color: #329696; */ | ||||
|     /* color:black; */ | ||||
|     color:#329696; | ||||
|     background-color: rgb(50, 50, 50); | ||||
|     /* focus:none; | ||||
|     tab-index:none; | ||||
|     nav-up:none; | ||||
|     nav-down:none; | ||||
|     nav-right:none; | ||||
|     nav-left:none; */ | ||||
| } | ||||
| 
 | ||||
| input.text, | ||||
| input.password { | ||||
|     box-sizing: border-box; | ||||
|  | @ -316,14 +350,6 @@ input.radio + label { | |||
|     /* decorator: image(radio) */ | ||||
| } | ||||
| 
 | ||||
| #rr_manual:not(:checked) ~ #rr_manual_input { | ||||
|     /* background: rgb(120,120,120); */ | ||||
|     /* font-effect: outline(2dp black); */ | ||||
|     display:none; | ||||
|     /* display:none; */ | ||||
|     /* decorator: image(radio) */ | ||||
| } | ||||
| 
 | ||||
| input.radio:checked + label { | ||||
|     /* background: rgb(72, 102, 255); */ | ||||
|     color: white; | ||||
|  | @ -403,12 +429,6 @@ input.checkbox:checked:active { | |||
|     decorator: image(checkbox-checked-active) | ||||
| } */ | ||||
| 
 | ||||
| input.range { | ||||
|     height: 32dp; | ||||
|     margin:auto; | ||||
|     width:80%; | ||||
| } | ||||
| 
 | ||||
| input.range slidertrack { | ||||
|     margin-top: 7dp; | ||||
|     height: 6dp; | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| namespace Rml { | ||||
| 	class ElementDocument; | ||||
| 	class EventListenerInstancer; | ||||
| 	class Context; | ||||
| } | ||||
| 
 | ||||
| namespace recomp { | ||||
|  | @ -16,6 +17,7 @@ namespace recomp { | |||
| 	bool try_deque_event(SDL_Event& out); | ||||
| 
 | ||||
| 	std::unique_ptr<Rml::EventListenerInstancer> make_event_listener_instancer(); | ||||
| 	void make_ui_bindings(Rml::Context* context); | ||||
| 
 | ||||
| 	enum class Menu { | ||||
| 		Launcher, | ||||
|  |  | |||
|  | @ -2,81 +2,22 @@ | |||
| #define __RT64_LAYER_H__ | ||||
| 
 | ||||
| #include "../ultramodern/ultramodern.hpp" | ||||
| #include "../ultramodern/config.hpp" | ||||
| 
 | ||||
| typedef struct { | ||||
|     // void* hWnd;
 | ||||
|     // void* hStatusBar;
 | ||||
| namespace RT64 { | ||||
|     struct Application; | ||||
| } | ||||
| 
 | ||||
|     // int Reserved;
 | ||||
| namespace ultramodern { | ||||
|     struct WindowHandle; | ||||
| } | ||||
| 
 | ||||
|     unsigned char* HEADER;  /* This is the rom header (first 40h bytes of the rom) */ | ||||
|     unsigned char* RDRAM; | ||||
|     unsigned char* DMEM; | ||||
|     unsigned char* IMEM; | ||||
| 
 | ||||
|     unsigned int* MI_INTR_REG; | ||||
| 
 | ||||
|     unsigned int* DPC_START_REG; | ||||
|     unsigned int* DPC_END_REG; | ||||
|     unsigned int* DPC_CURRENT_REG; | ||||
|     unsigned int* DPC_STATUS_REG; | ||||
|     unsigned int* DPC_CLOCK_REG; | ||||
|     unsigned int* DPC_BUFBUSY_REG; | ||||
|     unsigned int* DPC_PIPEBUSY_REG; | ||||
|     unsigned int* DPC_TMEM_REG; | ||||
| 
 | ||||
|     unsigned int* VI_STATUS_REG; | ||||
|     unsigned int* VI_ORIGIN_REG; | ||||
|     unsigned int* VI_WIDTH_REG; | ||||
|     unsigned int* VI_INTR_REG; | ||||
|     unsigned int* VI_V_CURRENT_LINE_REG; | ||||
|     unsigned int* VI_TIMING_REG; | ||||
|     unsigned int* VI_V_SYNC_REG; | ||||
|     unsigned int* VI_H_SYNC_REG; | ||||
|     unsigned int* VI_LEAP_REG; | ||||
|     unsigned int* VI_H_START_REG; | ||||
|     unsigned int* VI_V_START_REG; | ||||
|     unsigned int* VI_V_BURST_REG; | ||||
|     unsigned int* VI_X_SCALE_REG; | ||||
|     unsigned int* VI_Y_SCALE_REG; | ||||
| 
 | ||||
|     void (*CheckInterrupts)(void); | ||||
| 
 | ||||
|     unsigned int version; | ||||
|     unsigned int* SP_STATUS_REG; | ||||
|     const unsigned int* RDRAM_SIZE; | ||||
| } GFX_INFO; | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #define DLLEXPORT extern "C" __declspec(dllexport)   | ||||
| #define DLLIMPORT extern "C" __declspec(dllimport) | ||||
| #define CALL   __cdecl | ||||
| #else | ||||
| #define DLLEXPORT extern "C" __attribute__((visibility("default"))) | ||||
| #define DLLIMPORT extern "C" | ||||
| #endif | ||||
| 
 | ||||
| // Dynamic loading
 | ||||
| //DLLEXPORT int (CALL *InitiateGFX)(GFX_INFO Gfx_Info) = nullptr;
 | ||||
| //DLLEXPORT void (CALL *ProcessRDPList)(void) = nullptr;
 | ||||
| //DLLEXPORT void (CALL *ProcessDList)(void) = nullptr;
 | ||||
| //DLLEXPORT void (CALL *UpdateScreen)(void) = nullptr;
 | ||||
| //DLLEXPORT void (CALL *PumpEvents)(void) = nullptr;
 | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
| extern "C" int InitiateGFXWindows(GFX_INFO Gfx_Info, HWND hwnd, DWORD threadId); | ||||
| #elif defined(__ANDROID__) | ||||
| static_assert(false && "Unimplemented"); | ||||
| #elif defined(__linux__) | ||||
| extern "C" int InitiateGFXLinux(GFX_INFO Gfx_Info, Window window, Display *display); | ||||
| #else | ||||
| static_assert(false && "Unimplemented"); | ||||
| #endif | ||||
| DLLIMPORT void ProcessRDPList(void); | ||||
| DLLIMPORT void ProcessDList(void); | ||||
| DLLIMPORT void UpdateScreen(void); | ||||
| DLLIMPORT void ChangeWindow(void); | ||||
| DLLIMPORT void PluginShutdown(void); | ||||
| RT64::Application* RT64Init(uint8_t* rom, uint8_t* rdram, ultramodern::WindowHandle window_handle); | ||||
| void RT64UpdateConfig(RT64::Application* application, const ultramodern::GraphicsConfig& old_config, const ultramodern::GraphicsConfig& new_config); | ||||
| void RT64SendDL(uint8_t* rdram, const OSTask* task); | ||||
| void RT64UpdateScreen(uint32_t vi_origin); | ||||
| void RT64ChangeWindow(); | ||||
| void RT64Shutdown(); | ||||
| 
 | ||||
| void set_rt64_hooks(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| Subproject commit 12bf0efad21fb7cc1f27a630ae6dbcb90ddd1433 | ||||
| Subproject commit f57eeec44a49cf4fb3ffe6c22d9f0c3d5410fb72 | ||||
|  | @ -2,10 +2,80 @@ | |||
| #include <cstring> | ||||
| // #include <Windows.h>
 | ||||
| 
 | ||||
| #include "../ultramodern/ultramodern.hpp" | ||||
| #define HLSL_CPU | ||||
| #include "hle/rt64_application.h" | ||||
| #include "rt64_layer.h" | ||||
| #include "rt64_render_hooks.h" | ||||
| 
 | ||||
| typedef struct { | ||||
|     // void* hWnd;
 | ||||
|     // void* hStatusBar;
 | ||||
| 
 | ||||
|     // int Reserved;
 | ||||
| 
 | ||||
|     unsigned char* HEADER;  /* This is the rom header (first 40h bytes of the rom) */ | ||||
|     unsigned char* RDRAM; | ||||
|     unsigned char* DMEM; | ||||
|     unsigned char* IMEM; | ||||
| 
 | ||||
|     unsigned int* MI_INTR_REG; | ||||
| 
 | ||||
|     unsigned int* DPC_START_REG; | ||||
|     unsigned int* DPC_END_REG; | ||||
|     unsigned int* DPC_CURRENT_REG; | ||||
|     unsigned int* DPC_STATUS_REG; | ||||
|     unsigned int* DPC_CLOCK_REG; | ||||
|     unsigned int* DPC_BUFBUSY_REG; | ||||
|     unsigned int* DPC_PIPEBUSY_REG; | ||||
|     unsigned int* DPC_TMEM_REG; | ||||
| 
 | ||||
|     unsigned int* VI_STATUS_REG; | ||||
|     unsigned int* VI_ORIGIN_REG; | ||||
|     unsigned int* VI_WIDTH_REG; | ||||
|     unsigned int* VI_INTR_REG; | ||||
|     unsigned int* VI_V_CURRENT_LINE_REG; | ||||
|     unsigned int* VI_TIMING_REG; | ||||
|     unsigned int* VI_V_SYNC_REG; | ||||
|     unsigned int* VI_H_SYNC_REG; | ||||
|     unsigned int* VI_LEAP_REG; | ||||
|     unsigned int* VI_H_START_REG; | ||||
|     unsigned int* VI_V_START_REG; | ||||
|     unsigned int* VI_V_BURST_REG; | ||||
|     unsigned int* VI_X_SCALE_REG; | ||||
|     unsigned int* VI_Y_SCALE_REG; | ||||
| 
 | ||||
|     void (*CheckInterrupts)(void); | ||||
| 
 | ||||
|     unsigned int version; | ||||
|     unsigned int* SP_STATUS_REG; | ||||
|     const unsigned int* RDRAM_SIZE; | ||||
| } GFX_INFO; | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #define DLLEXPORT extern "C" __declspec(dllexport)   | ||||
| #define DLLIMPORT extern "C" __declspec(dllimport) | ||||
| #define CALL   __cdecl | ||||
| #else | ||||
| #define DLLEXPORT extern "C" __attribute__((visibility("default"))) | ||||
| #define DLLIMPORT extern "C" | ||||
| #endif | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
| extern "C" RT64::Application* InitiateGFXWindows(GFX_INFO Gfx_Info, HWND hwnd, DWORD threadId); | ||||
| #elif defined(__ANDROID__) | ||||
| static_assert(false && "Unimplemented"); | ||||
| #elif defined(__linux__) | ||||
| extern "C" RT64::Application* InitiateGFXLinux(GFX_INFO Gfx_Info, Window window, Display *display); | ||||
| #else | ||||
| static_assert(false && "Unimplemented"); | ||||
| #endif | ||||
| 
 | ||||
| DLLIMPORT void ProcessRDPList(void); | ||||
| DLLIMPORT void ProcessDList(void); | ||||
| DLLIMPORT void UpdateScreen(void); | ||||
| DLLIMPORT void ChangeWindow(void); | ||||
| DLLIMPORT void PluginShutdown(void); | ||||
| 
 | ||||
| static uint8_t DMEM[0x1000]; | ||||
| static uint8_t IMEM[0x1000]; | ||||
| 
 | ||||
|  | @ -45,7 +115,7 @@ void dummy_check_interrupts() { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool RT64Init(uint8_t* rom, uint8_t* rdram, ultramodern::WindowHandle window_handle) { | ||||
| RT64::Application* RT64Init(uint8_t* rom, uint8_t* rdram, ultramodern::WindowHandle window_handle) { | ||||
|     set_rt64_hooks(); | ||||
|     // Dynamic loading
 | ||||
|     //auto RT64 = LoadLibrary("RT64.dll");
 | ||||
|  | @ -134,3 +204,34 @@ void RT64ChangeWindow() { | |||
| void RT64Shutdown() { | ||||
|     PluginShutdown(); | ||||
| } | ||||
| 
 | ||||
| void RT64UpdateConfig(RT64::Application* application, const ultramodern::GraphicsConfig& old_config, const ultramodern::GraphicsConfig& new_config) { | ||||
|     if (new_config.wm_option != old_config.wm_option) { | ||||
|         application->setFullScreen(new_config.wm_option == ultramodern::WindowMode::Fullscreen); | ||||
|     } | ||||
| 
 | ||||
|     switch (new_config.res_option) { | ||||
|         default: | ||||
|         case ultramodern::Resolution::Auto: | ||||
|             application->userConfig.resolution = RT64::UserConfiguration::Resolution::WindowIntegerScale; | ||||
|             break; | ||||
|         case ultramodern::Resolution::Original: | ||||
|             application->userConfig.resolution = RT64::UserConfiguration::Resolution::Original; | ||||
|             break; | ||||
|         case ultramodern::Resolution::Original2x: | ||||
|             application->userConfig.resolution = RT64::UserConfiguration::Resolution::Manual; | ||||
|             application->userConfig.resolutionMultiplier = 2.0; | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     application->userConfig.aspectRatio = new_config.ar_option; | ||||
|     application->userConfig.antialiasing = new_config.msaa_option; | ||||
|     application->userConfig.refreshRate = new_config.rr_option; | ||||
|     application->userConfig.refreshRateTarget = new_config.rr_manual_value; | ||||
| 
 | ||||
|     application->updateUserConfig(true); | ||||
| 
 | ||||
|     if (new_config.msaa_option != old_config.msaa_option) { | ||||
|         application->updateMultisampling(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| 
 | ||||
| #include "recomp_ui.h" | ||||
| #include "../../ultramodern/ultramodern.hpp" | ||||
| #include "../../ultramodern/config.hpp" | ||||
| #include "common/rt64_user_configuration.h" | ||||
| 
 | ||||
| #include "nfd.h" | ||||
| #include "RmlUi/Core.h" | ||||
|  | @ -36,15 +38,97 @@ public: | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::Resolution, { | ||||
| 	{ultramodern::Resolution::Original, "Original"}, | ||||
| 	{ultramodern::Resolution::Original2x, "Original2x"}, | ||||
| 	{ultramodern::Resolution::Auto, "Auto"}, | ||||
| }); | ||||
| 
 | ||||
| NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::WindowMode, { | ||||
| 	{ultramodern::WindowMode::Windowed, "Windowed"}, | ||||
| 	{ultramodern::WindowMode::Fullscreen, "Fullscreen"} | ||||
| }); | ||||
| 
 | ||||
| ultramodern::GraphicsConfig cur_options; | ||||
| ultramodern::GraphicsConfig new_options; | ||||
| Rml::DataModelHandle options_handle; | ||||
| 
 | ||||
| template <typename T> | ||||
| void get_option(const T& input, Rml::Variant& output) { | ||||
| 	std::string value = ""; | ||||
| 	to_json(value, input); | ||||
| 
 | ||||
| 	if (value.empty()) { | ||||
| 		throw std::runtime_error("Invalid value :" + std::to_string(int(input))); | ||||
| 	} | ||||
| 
 | ||||
| 	output = value; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void set_option(T& output, const Rml::Variant& input) { | ||||
| 	T value = T::OptionCount; | ||||
| 	from_json(input.Get<std::string>(), value); | ||||
| 
 | ||||
| 	if (value == T::OptionCount) { | ||||
| 		throw std::runtime_error("Invalid value :" + input.Get<std::string>()); | ||||
| 	} | ||||
| 
 | ||||
| 	output = value; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void bind_option(Rml::DataModelConstructor& constructor, const std::string& name, T* option) { | ||||
| 	constructor.BindFunc(name, | ||||
| 		[option](Rml::Variant& out) { get_option(*option, out); }, | ||||
| 		[option](const Rml::Variant& in) { set_option(*option, in); options_handle.DirtyVariable("options_changed"); } | ||||
| 	); | ||||
| }; | ||||
| 
 | ||||
| void recomp::make_ui_bindings(Rml::Context* context) { | ||||
| 	Rml::DataModelConstructor constructor = context->CreateDataModel("graphics_model"); | ||||
| 	if (!constructor) { | ||||
| 		throw std::runtime_error("Failed to make RmlUi data model constructor"); | ||||
| 	} | ||||
| 
 | ||||
| 	bind_option(constructor, "res_option", &new_options.res_option); | ||||
| 	bind_option(constructor, "wm_option", &new_options.wm_option); | ||||
| 	bind_option(constructor, "ar_option", &new_options.ar_option); | ||||
| 	bind_option(constructor, "msaa_option", &new_options.msaa_option); | ||||
| 	bind_option(constructor, "rr_option", &new_options.rr_option); | ||||
| 	constructor.BindFunc("rr_manual_value", | ||||
| 		[](Rml::Variant& out) { | ||||
| 			out = new_options.rr_manual_value; | ||||
| 		}, | ||||
| 		[](const Rml::Variant& in) { | ||||
| 			new_options.rr_manual_value = in.Get<int>(); | ||||
| 			options_handle.DirtyVariable("options_changed"); | ||||
| 		}); | ||||
| 
 | ||||
| 	constructor.BindFunc("options_changed", | ||||
| 		[](Rml::Variant& out) { | ||||
| 			out = (cur_options != new_options); | ||||
| 		}); | ||||
| 
 | ||||
| 	options_handle = constructor.GetModelHandle(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Rml::EventListenerInstancer> recomp::make_event_listener_instancer() { | ||||
| 	std::unique_ptr<UiEventListenerInstancer> ret = std::make_unique<UiEventListenerInstancer>(); | ||||
| 
 | ||||
| 	ret->register_event("start_game", | ||||
| 		[](Rml::Event& event) { | ||||
| 			ultramodern::start_game(0); | ||||
| 			set_current_menu(Menu::None); | ||||
| 			set_current_menu(Menu::Config); | ||||
| 		} | ||||
| 	); | ||||
| 
 | ||||
| 	ret->register_event("apply_options", | ||||
| 		[](Rml::Event& event) { | ||||
| 			cur_options = new_options; | ||||
| 			options_handle.DirtyVariable("options_changed"); | ||||
| 			update_graphics_config(new_options); | ||||
| 		}); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  |  | |||
|  | @ -565,7 +565,7 @@ public: | |||
| }; | ||||
| 
 | ||||
| bool can_focus(Rml::Element* element) { | ||||
|     return element->GetProperty(Rml::PropertyId::TabIndex)->Get<Rml::Style::TabIndex>() != Rml::Property(Rml::Style::TabIndex::None); | ||||
|     return element->GetOwnerDocument() != nullptr && element->GetProperty(Rml::PropertyId::TabIndex)->Get<Rml::Style::TabIndex>() != Rml::Property(Rml::Style::TabIndex::None); | ||||
| } | ||||
| 
 | ||||
| Rml::Element* get_target(Rml::ElementDocument* document, Rml::Element* element) { | ||||
|  | @ -660,7 +660,20 @@ struct { | |||
|             // Revert focus to the previous element if focused on anything without a tab index.
 | ||||
|             // This should prevent the user from losing focus on something that has no navigation.
 | ||||
|             if (focused && !can_focus(focused)) { | ||||
|                 prev_focused->Focus(); | ||||
|                 // If the previously focused element is still accepting focus, return focus to it.
 | ||||
|                 if (prev_focused && can_focus(prev_focused)) { | ||||
|                     prev_focused->Focus(); | ||||
|                 } | ||||
|                 // Otherwise, check if the currently focused element has a "nav-return" attribute and focus that attribute's value if so.
 | ||||
|                 else { | ||||
|                     Rml::Variant* nav_return = focused->GetAttribute("nav-return"); | ||||
|                     if (nav_return && nav_return->GetType() == Rml::Variant::STRING) { | ||||
|                         Rml::Element* return_element = current_document->GetElementById(nav_return->Get<std::string>()); | ||||
|                         if (return_element) { | ||||
|                             return_element->Focus(); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 prev_focused = current_document->GetFocusLeafNode(); | ||||
|  | @ -693,6 +706,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) { | |||
|     SDL_GetWindowSizeInPixels(window, &width, &height); | ||||
|      | ||||
|     UIContext.rml.context = Rml::CreateContext("main", Rml::Vector2i(width, height)); | ||||
|     recomp::make_ui_bindings(UIContext.rml.context); | ||||
| 
 | ||||
|     Rml::Debugger::Initialise(UIContext.rml.context); | ||||
| 
 | ||||
|  | @ -730,7 +744,7 @@ bool recomp::try_deque_event(SDL_Event& out) { | |||
|     return ui_event_queue.try_dequeue(out); | ||||
| } | ||||
| 
 | ||||
| std::atomic<recomp::Menu> open_menu = recomp::Menu::Config;//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; | ||||
|  | @ -778,6 +792,9 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_ | |||
|         int width, height; | ||||
|         SDL_GetWindowSizeInPixels(window, &width, &height); | ||||
| 
 | ||||
|         // Scale the UI based on the window size with 720 vertical resolution as the reference point.
 | ||||
|         UIContext.rml.context->SetDensityIndependentPixelRatio(height / 720.0f); | ||||
| 
 | ||||
|         UIContext.rml.render_interface->start(command_list, width, height); | ||||
| 
 | ||||
|         static int prev_width = 0; | ||||
|  |  | |||
							
								
								
									
										33
									
								
								ultramodern/config.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ultramodern/config.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| #ifndef __CONFIG_HPP__ | ||||
| #define __CONFIG_HPP__ | ||||
| 
 | ||||
| #include "common/rt64_user_configuration.h" | ||||
| 
 | ||||
| namespace ultramodern { | ||||
| 	enum class Resolution { | ||||
| 		Original, | ||||
| 		Original2x, | ||||
| 		Auto, | ||||
| 		OptionCount | ||||
| 	}; | ||||
| 	enum class WindowMode { | ||||
| 		Windowed, | ||||
| 		Fullscreen, | ||||
| 		OptionCount | ||||
| 	}; | ||||
| 
 | ||||
| 	struct GraphicsConfig { | ||||
| 		Resolution res_option; | ||||
| 		WindowMode wm_option; | ||||
| 		RT64::UserConfiguration::AspectRatio ar_option; | ||||
| 		RT64::UserConfiguration::Antialiasing msaa_option; | ||||
| 		RT64::UserConfiguration::RefreshRate rr_option; | ||||
| 		int rr_manual_value; | ||||
| 
 | ||||
| 		auto operator<=>(const GraphicsConfig& rhs) const = default; | ||||
| 	}; | ||||
| 
 | ||||
| 	void update_graphics_config(const GraphicsConfig& config); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -13,6 +13,8 @@ | |||
| 
 | ||||
| #include "ultra64.h" | ||||
| #include "ultramodern.hpp" | ||||
| #include "config.hpp" | ||||
| #include "rt64_layer.h" | ||||
| #include "recomp.h" | ||||
| #include "recomp_ui.h" | ||||
| #include "rsp.h" | ||||
|  | @ -25,7 +27,11 @@ struct SwapBuffersAction { | |||
|     uint32_t origin; | ||||
| }; | ||||
| 
 | ||||
| using Action = std::variant<SpTaskAction, SwapBuffersAction>; | ||||
| struct UpdateConfigAction { | ||||
|     ultramodern::GraphicsConfig config; | ||||
| }; | ||||
| 
 | ||||
| using Action = std::variant<SpTaskAction, SwapBuffersAction, UpdateConfigAction>; | ||||
| 
 | ||||
| static struct { | ||||
|     struct { | ||||
|  | @ -174,12 +180,6 @@ void dp_complete() { | |||
|     osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK); | ||||
| } | ||||
| 
 | ||||
| bool RT64Init(uint8_t* rom, uint8_t* rdram, ultramodern::WindowHandle window_handle); | ||||
| void RT64SendDL(uint8_t* rdram, const OSTask* task); | ||||
| void RT64UpdateScreen(uint32_t vi_origin); | ||||
| void RT64ChangeWindow(); | ||||
| void RT64Shutdown(); | ||||
| 
 | ||||
| uint8_t dmem[0x1000]; | ||||
| uint16_t rspReciprocals[512]; | ||||
| uint16_t rspInverseSquareRoots[512]; | ||||
|  | @ -257,13 +257,21 @@ void task_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_rea | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void ultramodern::update_graphics_config(const ultramodern::GraphicsConfig& config) { | ||||
|     events_context.action_queue.enqueue(UpdateConfigAction{ config }); | ||||
| } | ||||
| 
 | ||||
| void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready, ultramodern::WindowHandle window_handle) { | ||||
|     using namespace std::chrono_literals; | ||||
| 
 | ||||
|     ultramodern::set_native_thread_name("Gfx Thread"); | ||||
|     ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Normal); | ||||
| 
 | ||||
|     if (!RT64Init(rom, rdram, window_handle)) { | ||||
|     ultramodern::GraphicsConfig cur_config{}; | ||||
| 
 | ||||
|     RT64::Application* application = RT64Init(rom, rdram, window_handle); | ||||
| 
 | ||||
|     if (application == nullptr) { | ||||
|         throw std::runtime_error("Failed to initialize RT64!"); | ||||
|     } | ||||
|      | ||||
|  | @ -286,10 +294,17 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read | |||
|                 sp_complete(); | ||||
|                 RT64SendDL(rdram, &task_action->task); | ||||
|                 dp_complete(); | ||||
|             } else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) { | ||||
|             } | ||||
|             else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) { | ||||
|                 events_context.vi.current_buffer = events_context.vi.next_buffer; | ||||
|                 RT64UpdateScreen(swap_action->origin); | ||||
|             } | ||||
|             else if (const auto* config_action = std::get_if<UpdateConfigAction>(&action)) { | ||||
|                 if (cur_config != config_action->config) { | ||||
|                     RT64UpdateConfig(application, cur_config, config_action->config); | ||||
|                     cur_config = config_action->config; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     recomp::destroy_ui(); | ||||
|  |  | |||
|  | @ -136,10 +136,10 @@ typedef struct { | |||
| 
 | ||||
|     PTR(u64) yield_data_ptr; | ||||
|     u32	yield_data_size; | ||||
| } OSTask_t; | ||||
| } OSTask_s; | ||||
| 
 | ||||
| typedef union { | ||||
|     OSTask_t t; | ||||
|     OSTask_s t; | ||||
|     int64_t force_structure_alignment; | ||||
| } OSTask; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Mr-Wiseguy
						Mr-Wiseguy