mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Implemented RmlUi hack to replace color parsing so it uses 0-1 alpha instead of 0-255
This commit is contained in:
		
							parent
							
								
									8e3c163594
								
							
						
					
					
						commit
						8510bb9109
					
				
					 4 changed files with 173 additions and 0 deletions
				
			
		|  | @ -116,6 +116,7 @@ set (SOURCES | |||
|     ${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/ui/ui_launcher.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/ui/ui_config.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/src/ui/ui_color_hack.cpp | ||||
|      | ||||
|     ${CMAKE_SOURCE_DIR}/rsp/aspMain.cpp | ||||
|     ${CMAKE_SOURCE_DIR}/rsp/njpgdspMain.cpp | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ namespace recomp { | |||
| 
 | ||||
| 	void set_current_menu(Menu menu); | ||||
| 	void destroy_ui(); | ||||
| 	void apply_color_hack(); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										168
									
								
								src/ui/ui_color_hack.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/ui/ui_color_hack.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,168 @@ | |||
| 
 | ||||
| #include "RmlUi/Core.h" | ||||
| #include "RmlUi/../../Source/Core/PropertyParserColour.h" | ||||
| #include "recomp_ui.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| namespace recomp { | ||||
| 	class PropertyParserColorHack : public Rml::PropertyParser { | ||||
| 	public: | ||||
| 		PropertyParserColorHack(); | ||||
| 		virtual ~PropertyParserColorHack(); | ||||
| 		bool ParseValue(Rml::Property& property, const Rml::String& value, const Rml::ParameterMap& /*parameters*/) const override; | ||||
| 	private: | ||||
| 		using ColourMap = Rml::UnorderedMap<Rml::String, Rml::Colourb>; | ||||
| 		ColourMap html_colours; | ||||
| 	}; | ||||
| 	static_assert(sizeof(PropertyParserColorHack) == sizeof(Rml::PropertyParserColour)); | ||||
| 	PropertyParserColorHack::PropertyParserColorHack() { | ||||
| 		html_colours["black"] = Rml::Colourb(0, 0, 0); | ||||
| 		html_colours["silver"] = Rml::Colourb(192, 192, 192); | ||||
| 		html_colours["gray"] = Rml::Colourb(128, 128, 128); | ||||
| 		html_colours["grey"] = Rml::Colourb(128, 128, 128); | ||||
| 		html_colours["white"] = Rml::Colourb(255, 255, 255); | ||||
| 		html_colours["maroon"] = Rml::Colourb(128, 0, 0); | ||||
| 		html_colours["red"] = Rml::Colourb(255, 0, 0); | ||||
| 		html_colours["orange"] = Rml::Colourb(255, 165, 0); | ||||
| 		html_colours["purple"] = Rml::Colourb(128, 0, 128); | ||||
| 		html_colours["fuchsia"] = Rml::Colourb(255, 0, 255); | ||||
| 		html_colours["green"] = Rml::Colourb(0, 128, 0); | ||||
| 		html_colours["lime"] = Rml::Colourb(0, 255, 0); | ||||
| 		html_colours["olive"] = Rml::Colourb(128, 128, 0); | ||||
| 		html_colours["yellow"] = Rml::Colourb(255, 255, 0); | ||||
| 		html_colours["navy"] = Rml::Colourb(0, 0, 128); | ||||
| 		html_colours["blue"] = Rml::Colourb(0, 0, 255); | ||||
| 		html_colours["teal"] = Rml::Colourb(0, 128, 128); | ||||
| 		html_colours["aqua"] = Rml::Colourb(0, 255, 255); | ||||
| 		html_colours["transparent"] = Rml::Colourb(0, 0, 0, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	PropertyParserColorHack::~PropertyParserColorHack() {} | ||||
| 
 | ||||
| 	bool PropertyParserColorHack::ParseValue(Rml::Property& property, const Rml::String& value, const Rml::ParameterMap& /*parameters*/) const { | ||||
| 		if (value.empty()) | ||||
| 			return false; | ||||
| 
 | ||||
| 		Rml::Colourb colour; | ||||
| 
 | ||||
| 		// Check for a hex colour.
 | ||||
| 		if (value[0] == '#') | ||||
| 		{ | ||||
| 			char hex_values[4][2] = { {'f', 'f'}, {'f', 'f'}, {'f', 'f'}, {'f', 'f'} }; | ||||
| 
 | ||||
| 			switch (value.size()) | ||||
| 			{ | ||||
| 				// Single hex digit per channel, RGB and alpha.
 | ||||
| 			case 5: | ||||
| 				hex_values[3][0] = hex_values[3][1] = value[4]; | ||||
| 				//-fallthrough
 | ||||
| 			// Single hex digit per channel, RGB only.
 | ||||
| 			case 4: | ||||
| 				hex_values[0][0] = hex_values[0][1] = value[1]; | ||||
| 				hex_values[1][0] = hex_values[1][1] = value[2]; | ||||
| 				hex_values[2][0] = hex_values[2][1] = value[3]; | ||||
| 				break; | ||||
| 
 | ||||
| 				// Two hex digits per channel, RGB and alpha.
 | ||||
| 			case 9: | ||||
| 				hex_values[3][0] = value[7]; | ||||
| 				hex_values[3][1] = value[8]; | ||||
| 				//-fallthrough
 | ||||
| 			// Two hex digits per channel, RGB only.
 | ||||
| 			case 7: memcpy(hex_values, &value.c_str()[1], sizeof(char) * 6); break; | ||||
| 
 | ||||
| 			default: return false; | ||||
| 			} | ||||
| 
 | ||||
| 			// Parse each of the colour elements.
 | ||||
| 			for (int i = 0; i < 4; i++) | ||||
| 			{ | ||||
| 				int tens = Rml::Math::HexToDecimal(hex_values[i][0]); | ||||
| 				int ones = Rml::Math::HexToDecimal(hex_values[i][1]); | ||||
| 				if (tens == -1 || ones == -1) | ||||
| 					return false; | ||||
| 
 | ||||
| 				colour[i] = (Rml::byte)(tens * 16 + ones); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (value.substr(0, 3) == "rgb") | ||||
| 		{ | ||||
| 			Rml::StringList values; | ||||
| 			values.reserve(4); | ||||
| 
 | ||||
| 			size_t find = value.find('('); | ||||
| 			if (find == Rml::String::npos) | ||||
| 				return false; | ||||
| 
 | ||||
| 			size_t begin_values = find + 1; | ||||
| 
 | ||||
| 			Rml::StringUtilities::ExpandString(values, value.substr(begin_values, value.rfind(')') - begin_values), ','); | ||||
| 
 | ||||
| 			// Check if we're parsing an 'rgba' or 'rgb' colour declaration.
 | ||||
| 			if (value.size() > 3 && value[3] == 'a') | ||||
| 			{ | ||||
| 				if (values.size() != 4) | ||||
| 					return false; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (values.size() != 3) | ||||
| 					return false; | ||||
| 
 | ||||
| 				values.push_back("255"); | ||||
| 			} | ||||
| 
 | ||||
| 			// Parse the three RGB values.
 | ||||
| 			for (int i = 0; i < 3; ++i) | ||||
| 			{ | ||||
| 				int component; | ||||
| 
 | ||||
| 				// We're parsing a percentage value.
 | ||||
| 				if (values[i].size() > 0 && values[i][values[i].size() - 1] == '%') | ||||
| 					component = int((float)atof(values[i].substr(0, values[i].size() - 1).c_str()) * (255.0f / 100.0f)); | ||||
| 				// We're parsing a 0 -> 255 integer value.
 | ||||
| 				else | ||||
| 					component = atoi(values[i].c_str()); | ||||
| 
 | ||||
| 				colour[i] = (Rml::byte)(Rml::Math::Clamp(component, 0, 255)); | ||||
| 			} | ||||
| 			// Parse the alpha value. Modified from the original RmlUi implementation to use 0-1 instead of 0-255.
 | ||||
| 			{ | ||||
| 				int component; | ||||
| 
 | ||||
| 				// We're parsing a percentage value.
 | ||||
| 				if (values[3].size() > 0 && values[3][values[3].size() - 1] == '%') | ||||
| 					component = ((float)atof(values[3].substr(0, values[3].size() - 1).c_str()) * (255.0f / 100.0f)); | ||||
| 				// We're parsing a 0 -> 1 float value.
 | ||||
| 				else | ||||
| 					component = atof(values[3].c_str()) * 255.0f; | ||||
| 
 | ||||
| 				colour[3] = (Rml::byte)(Rml::Math::Clamp(component, 0, 255)); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// Check for the specification of an HTML colour.
 | ||||
| 			ColourMap::const_iterator iterator = html_colours.find(Rml::StringUtilities::ToLower(value)); | ||||
| 			if (iterator == html_colours.end()) | ||||
| 				return false; | ||||
| 			else | ||||
| 				colour = (*iterator).second; | ||||
| 		} | ||||
| 
 | ||||
| 		property.value = Rml::Variant(colour); | ||||
| 		property.unit = Rml::Unit::COLOUR; | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	// This hack overwrites the contents of a property parser pointer for "color" (which is known to point to a valid Rml::PropertyParserColour) with the contents of a PropertyParserColorHack.
 | ||||
| 	// This overwrites the object's vtable, allowing us to override color parsing behavior to use 0-1 alpha instead of 0-255.
 | ||||
| 	// Ideally we'd just replace the pointer itself, but RmlUi doesn't provide a way to do that currently.
 | ||||
| 	void apply_color_hack() { | ||||
| 		// Allocate and leak a parser to act as a vtable source.
 | ||||
| 		PropertyParserColorHack* new_parser = new PropertyParserColorHack(); | ||||
| 		// Copy the allocated object into the color parser pointer to overwrite its vtable.
 | ||||
| 		memcpy((void*)Rml::StyleSheetSpecification::GetParser("color"), (void*)new_parser, sizeof(*new_parser)); | ||||
| 	} | ||||
| } | ||||
|  | @ -758,6 +758,9 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) { | |||
| 
 | ||||
|     Rml::Initialise(); | ||||
| 
 | ||||
|     // Apply the hack to replace RmlUi's default color parser with one that conforms to HTML5 alpha parsing for SASS compatibility
 | ||||
|     recomp::apply_color_hack(); | ||||
| 
 | ||||
|     int width, height; | ||||
|     SDL_GetWindowSizeInPixels(window, &width, &height); | ||||
|      | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Mr-Wiseguy
						Mr-Wiseguy