From e9191a17407ab736f197672b9cd8c0544bf2ac39 Mon Sep 17 00:00:00 2001 From: kelpsyberry <138107494+kelpsyberry@users.noreply.github.com> Date: Thu, 9 May 2024 21:54:55 +0200 Subject: [PATCH] Emulate texture color bug (documented by Jakly) --- render/soft-3d/src/lib.rs | 39 ++++++++++++++---------- render/soft-3d/src/utils.rs | 9 +++++- render/wgpu-3d/src/lib.rs | 44 ++++++++++++++++------------ render/wgpu-3d/src/render/texture.rs | 4 +-- render/wgpu-3d/src/utils.rs | 12 ++++++++ 5 files changed, 71 insertions(+), 37 deletions(-) diff --git a/render/soft-3d/src/lib.rs b/render/soft-3d/src/lib.rs index 70dfe9b..3eb3f6e 100644 --- a/render/soft-3d/src/lib.rs +++ b/render/soft-3d/src/lib.rs @@ -18,7 +18,7 @@ use dust_core::{ }; use utils::{ clip_x_range, dec_poly_vert_index, decode_rgb5, expand_depth, inc_poly_vert_index, - rgb5_to_rgb6, DummyEdge, Edge, Edges, InterpLineData, + rgb5_to_rgb6, rgb5_to_rgb6_shift, DummyEdge, Edge, Edges, InterpLineData, }; type DepthTestFn = fn(u32, u32, PixelAttrs) -> bool; @@ -142,24 +142,24 @@ fn process_pixel( let i = v << (tex_width_shift + 3) | u; - let tex_color = rgb5_to_rgb6(match FORMAT { + let tex_color = match FORMAT { 1 => { let pixel = rendering_data.texture[(tex_base + i) & 0x7_FFFF]; let color_index = pixel as usize & 0x1F; let raw_alpha = pixel >> 5; - decode_rgb5( + rgb5_to_rgb6(decode_rgb5( rendering_data .tex_pal .read_le::((pal_base + (color_index << 1)) & 0x1_FFFF), (raw_alpha << 2 | raw_alpha >> 1) as u16, - ) + )) } 2 => { let color_index = rendering_data.texture[(tex_base + (i >> 2)) & 0x7_FFFF] .wrapping_shr((i << 1) as u32) as usize & 3; - decode_rgb5( + rgb5_to_rgb6(decode_rgb5( rendering_data .tex_pal .read_le::(pal_base | color_index << 1), @@ -168,14 +168,14 @@ fn process_pixel( } else { 0x1F }, - ) + )) } 3 => { let color_index = rendering_data.texture[(tex_base + (i >> 1)) & 0x7_FFFF] .wrapping_shr((i << 2) as u32) as usize & 0xF; - decode_rgb5( + rgb5_to_rgb6(decode_rgb5( rendering_data .tex_pal .read_le::((pal_base + (color_index << 1)) & 0x1_FFFF), @@ -184,12 +184,12 @@ fn process_pixel( } else { 0x1F }, - ) + )) } 4 => { let color_index = rendering_data.texture[(tex_base + i) & 0x7_FFFF] as usize; - decode_rgb5( + rgb5_to_rgb6(decode_rgb5( rendering_data .tex_pal .read_le::((pal_base + (color_index << 1)) & 0x1_FFFF), @@ -198,7 +198,7 @@ fn process_pixel( } else { 0x1F }, - ) + )) } 5 => { @@ -226,7 +226,7 @@ fn process_pixel( }; } - match texel_value { + let color = match texel_value { 0 => color!(0), 1 => color!(1), @@ -258,6 +258,12 @@ fn process_pixel( (color_0 * InterpColor::splat(3) + color_1 * InterpColor::splat(5)) >> 3 } }, + }; + + if mode & 1 != 0 { + rgb5_to_rgb6_shift(color) + } else { + rgb5_to_rgb6(color) } } @@ -265,21 +271,24 @@ fn process_pixel( let pixel = rendering_data.texture[(tex_base + i) & 0x7_FFFF]; let color_index = pixel as usize & 7; let alpha = pixel >> 3; - decode_rgb5( + rgb5_to_rgb6(decode_rgb5( rendering_data .tex_pal .read_le::((pal_base | color_index << 1) & 0x1_FFFF), alpha as u16, - ) + )) } _ => { let color = rendering_data .texture .read_le::((tex_base + (i << 1)) & 0x7_FFFE); - decode_rgb5(color, if color & 1 << 15 != 0 { 0x1F } else { 0 }) + rgb5_to_rgb6(decode_rgb5( + color, + if color & 1 << 15 != 0 { 0x1F } else { 0 }, + )) } - }); + }; match MODE { 1 => match tex_color[3] { diff --git a/render/soft-3d/src/utils.rs b/render/soft-3d/src/utils.rs index e4b6b1f..72dafa1 100644 --- a/render/soft-3d/src/utils.rs +++ b/render/soft-3d/src/utils.rs @@ -32,10 +32,17 @@ pub fn decode_rgb5(color: u16, alpha: u16) -> InterpColor { ]) } +#[inline] +pub fn rgb5_to_rgb6_shift(color: InterpColor) -> InterpColor { + let mut result = color << 1; + result[3] = color[3]; + result +} + #[inline] pub fn rgb5_to_rgb6(color: InterpColor) -> InterpColor { let mut result = (color << 1) - color.simd_ne(InterpColor::splat(0)).to_int().cast::(); - result[3] >>= 1; + result[3] = color[3]; result } diff --git a/render/wgpu-3d/src/lib.rs b/render/wgpu-3d/src/lib.rs index 326a4c4..7392186 100644 --- a/render/wgpu-3d/src/lib.rs +++ b/render/wgpu-3d/src/lib.rs @@ -26,7 +26,10 @@ use dust_core::{ utils::mem_prelude::*, }; use std::sync::Arc; -use utils::{color_to_wgpu_f64, decode_rgb5, expand_depth, round_up_to_alignment}; +use utils::{ + color_to_wgpu_f64, decode_rgb5, expand_depth, rgb5_to_rgb6, rgb5_to_rgb6_shift, + round_up_to_alignment, +}; use wgpu::util::DeviceExt; proc_bitfield::bitfield! { @@ -369,7 +372,10 @@ fn create_texture( let pixel = unsafe { *frame.rendering.texture.get_unchecked(i) }; let color_index = pixel as usize & 0x1F; let raw_alpha = pixel >> 5; - decode_buffer.push(read_palette!(color_index, raw_alpha << 2 | raw_alpha >> 1)); + decode_buffer.push(rgb5_to_rgb6(read_palette!( + color_index, + raw_alpha << 2 | raw_alpha >> 1 + ))); i = (i + 1) & 0x7_FFFF; } } @@ -382,14 +388,14 @@ fn create_texture( let mut pixels = unsafe { *frame.rendering.texture.get_unchecked(i) }; for _ in 0..4 { let color_index = pixels as usize & 3; - decode_buffer.push(read_palette!( + decode_buffer.push(rgb5_to_rgb6(read_palette!( color_index, if texture_key.color_0_is_transparent() && color_index == 0 { 0 } else { 0x1F } - )); + ))); pixels >>= 2; } i = (i + 1) & 0x7_FFFF; @@ -404,14 +410,14 @@ fn create_texture( let mut pixels = unsafe { *frame.rendering.texture.get_unchecked(i) }; for _ in 0..2 { let color_index = pixels as usize & 0xF; - decode_buffer.push(read_palette!( + decode_buffer.push(rgb5_to_rgb6(read_palette!( color_index, if texture_key.color_0_is_transparent() && color_index == 0 { 0 } else { 0x1F } - )); + ))); pixels >>= 4; } i = (i + 1) & 0x7_FFFF; @@ -424,14 +430,14 @@ fn create_texture( let mut i = range.0; while i != range.1 || decode_buffer.len() != len { let color_index = unsafe { *frame.rendering.texture.get_unchecked(i) } as usize; - decode_buffer.push(read_palette!( + decode_buffer.push(rgb5_to_rgb6(read_palette!( color_index, if texture_key.color_0_is_transparent() && color_index == 0 { 0 } else { 0x1F } - )); + ))); i = (i + 1) & 0x7_FFFF; } } @@ -498,36 +504,36 @@ fn create_texture( match mode { 0 => process!(|texel| { - match texel { + rgb5_to_rgb6(match texel { 0 => color_0, 1 => color_1, 2 => color!(2), _ => 0, - } + }) }), 1 => process!(|texel| { - match texel { + rgb5_to_rgb6_shift(match texel { 0 => color_0, 1 => color_1, 2 => (color_0 + color_1) >> 1 & 0x1F1F_1F1F, _ => 0, - } + }) }), 2 => process!(|texel| { - match texel { + rgb5_to_rgb6(match texel { 0 => color_0, 1 => color_1, 2 => color!(2), _ => color!(3), - } + }) }), _ => process!(|texel| { - match texel { + rgb5_to_rgb6_shift(match texel { 0 => color_0, 1 => color_1, 2 => (color_0 * 5 + color_1 * 3) >> 3 & 0x1F1F_1F1F, _ => (color_0 * 3 + color_1 * 5) >> 3 & 0x1F1F_1F1F, - } + }) }), }; } @@ -553,7 +559,7 @@ fn create_texture( let pixel = unsafe { *frame.rendering.texture.get_unchecked(i) }; let color_index = pixel as usize & 7; let raw_alpha = pixel >> 3; - decode_buffer.push(read_palette!(color_index, raw_alpha)); + decode_buffer.push(rgb5_to_rgb6(read_palette!(color_index, raw_alpha))); i = (i + 1) & 0x7_FFFF; } } @@ -564,10 +570,10 @@ fn create_texture( let mut i = range.0; while i != range.1 || decode_buffer.len() != len { let color = unsafe { frame.rendering.texture.read_le_aligned_unchecked::(i) }; - decode_buffer.push(decode_rgb5( + decode_buffer.push(rgb5_to_rgb6(decode_rgb5( color, if color & 0x8000 != 0 { 0x1F } else { 0 }, - )); + ))); i = (i + 2) & 0x7_FFFF; } } diff --git a/render/wgpu-3d/src/render/texture.rs b/render/wgpu-3d/src/render/texture.rs index 48b72e7..356aa8f 100644 --- a/render/wgpu-3d/src/render/texture.rs +++ b/render/wgpu-3d/src/render/texture.rs @@ -24,8 +24,8 @@ impl TextureCode { texture_frag_inputs: "@location(1) uv: vec2,", texture_get_color: "let t_color = textureSample(t_texture, s_texture, uv / \ - vec2(textureDimensions(t_texture))) * vec4(255.0 / \ - 31.0);", + vec2(textureDimensions(t_texture))) * \ + vec4(vec3(255.0 / 63.0), 255.0 / 31.0);", } } } diff --git a/render/wgpu-3d/src/utils.rs b/render/wgpu-3d/src/utils.rs index 9089607..c737b27 100644 --- a/render/wgpu-3d/src/utils.rs +++ b/render/wgpu-3d/src/utils.rs @@ -20,6 +20,18 @@ pub fn decode_rgb5(color: u16, alpha: u8) -> u32 { (alpha as u32) << 24 | (b as u32) << 16 | (g as u32) << 8 | r as u32 } +#[inline] +pub fn rgb5_to_rgb6_shift(color: u32) -> u32 { + (color & 0xFF00_0000) | (color << 1 & 0x00FF_FFFF) +} + +#[inline] +pub fn rgb5_to_rgb6(color: u32) -> u32 { + (color & 0xFF00_0000) + | (color << 1 & 0x00FF_FFFF) + | ((color >> 4 | color >> 3 | color >> 2 | color >> 1 | color) & 0x010101) +} + #[inline] pub fn color_to_wgpu_f64(color: Color) -> wgpu::Color { let [r, g, b, a] = (color.cast::() * f64x4::splat(1.0 / 31.0)).to_array();