Skip to content

Commit

Permalink
Emulate texture color bug (documented by Jakly)
Browse files Browse the repository at this point in the history
  • Loading branch information
kelpsyberry committed May 9, 2024
1 parent 70234b3 commit e9191a1
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 37 deletions.
39 changes: 24 additions & 15 deletions render/soft-3d/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -142,24 +142,24 @@ fn process_pixel<const FORMAT: u8, const MODE: u8>(

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::<u16>((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::<u16>(pal_base | color_index << 1),
Expand All @@ -168,14 +168,14 @@ fn process_pixel<const FORMAT: u8, const MODE: u8>(
} 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::<u16>((pal_base + (color_index << 1)) & 0x1_FFFF),
Expand All @@ -184,12 +184,12 @@ fn process_pixel<const FORMAT: u8, const MODE: u8>(
} 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::<u16>((pal_base + (color_index << 1)) & 0x1_FFFF),
Expand All @@ -198,7 +198,7 @@ fn process_pixel<const FORMAT: u8, const MODE: u8>(
} else {
0x1F
},
)
))
}

5 => {
Expand Down Expand Up @@ -226,7 +226,7 @@ fn process_pixel<const FORMAT: u8, const MODE: u8>(
};
}

match texel_value {
let color = match texel_value {
0 => color!(0),

1 => color!(1),
Expand Down Expand Up @@ -258,28 +258,37 @@ fn process_pixel<const FORMAT: u8, const MODE: u8>(
(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)
}
}

6 => {
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::<u16>((pal_base | color_index << 1) & 0x1_FFFF),
alpha as u16,
)
))
}

_ => {
let color = rendering_data
.texture
.read_le::<u16>((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] {
Expand Down
9 changes: 8 additions & 1 deletion render/soft-3d/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u16>();
result[3] >>= 1;
result[3] = color[3];
result
}

Expand Down
44 changes: 25 additions & 19 deletions render/wgpu-3d/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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,
}
})
}),
};
}
Expand All @@ -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;
}
}
Expand All @@ -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::<u16>(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;
}
}
Expand Down
4 changes: 2 additions & 2 deletions render/wgpu-3d/src/render/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ impl TextureCode {

texture_frag_inputs: "@location(1) uv: vec2<f32>,",
texture_get_color: "let t_color = textureSample(t_texture, s_texture, uv / \
vec2<f32>(textureDimensions(t_texture))) * vec4<f32>(255.0 / \
31.0);",
vec2<f32>(textureDimensions(t_texture))) * \
vec4<f32>(vec3<f32>(255.0 / 63.0), 255.0 / 31.0);",
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions render/wgpu-3d/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>() * f64x4::splat(1.0 / 31.0)).to_array();
Expand Down

0 comments on commit e9191a1

Please sign in to comment.