1use crate::output::gfx::Face;
2use crate::rsp::RSPConstants;
3#[allow(unused_imports)]
4use bitflags::Flags;
5use fast3d_gbi::defines::render_mode::{
6 BlendAlpha2, BlendColor, RenderMode, RenderModeFlags, ZMode,
7};
8use fast3d_gbi::defines::{AlphaCompare, CycleType, GeometryModes, OtherModeH, TextureFilter};
9
10pub fn get_cmd(val: usize, start_bit: u32, num_bits: u32) -> usize {
12 (val >> start_bit) & ((1 << num_bits) - 1)
13}
14
15pub fn get_render_mode_from_other_mode_l(other_mode_l: u32) -> RenderMode {
16 RenderMode::try_from(other_mode_l).unwrap()
17}
18
19pub fn other_mode_l_uses_texture_edge(other_mode_l: u32) -> bool {
20 let render_mode = get_render_mode_from_other_mode_l(other_mode_l);
21 render_mode.flags.contains(RenderModeFlags::CVG_X_ALPHA)
22}
23
24pub fn other_mode_l_uses_alpha(other_mode_l: u32) -> bool {
25 let render_mode = get_render_mode_from_other_mode_l(other_mode_l);
26 render_mode.blend_cycle1.alpha2 == BlendAlpha2::OneMinusAlpha
27 }
30
31pub fn other_mode_l_alpha_compare_threshold(other_mode_l: u32) -> bool {
32 other_mode_l & AlphaCompare::Threshold as u32 == AlphaCompare::Threshold as u32
33}
34
35pub fn other_mode_l_uses_fog(other_mode_l: u32) -> bool {
36 let render_mode = get_render_mode_from_other_mode_l(other_mode_l);
37 render_mode.blend_cycle1.color1 == BlendColor::Fog
38}
39
40pub fn get_zmode_from_other_mode_l(other_mode_l: u32) -> ZMode {
41 get_render_mode_from_other_mode_l(other_mode_l).z_mode
42}
43
44pub fn other_mode_l_alpha_compare_dither(other_mode_l: u32) -> bool {
45 other_mode_l & AlphaCompare::Dither as u32 == AlphaCompare::Dither as u32
46}
47
48pub fn get_cycle_type_from_other_mode_h(mode_h: u32) -> CycleType {
49 (((mode_h >> OtherModeH::Shift::CYCLE_TYPE.bits()) & 0x03) as u8)
50 .try_into()
51 .unwrap()
52}
53
54pub fn get_texture_filter_from_other_mode_h(mode_h: u32) -> TextureFilter {
55 (((mode_h >> OtherModeH::Shift::TEXT_FILT.bits()) & 0x3) as u8)
56 .try_into()
57 .unwrap()
58}
59
60pub fn translate_cull_mode(
61 geometry_mode: GeometryModes,
62 rsp_constants: &RSPConstants,
63) -> Option<Face> {
64 let cull_front = geometry_mode.contains(GeometryModes::from_bits_retain(
67 rsp_constants.geomode_cull_front_val,
68 ));
69 let cull_back = geometry_mode.contains(GeometryModes::from_bits_retain(
70 rsp_constants.geomode_cull_back_val,
71 ));
72
73 if cull_front && cull_back {
74 panic!("Culling both front and back faces is not supported");
75 } else if cull_front {
76 Some(Face::Front)
77 } else if cull_back {
78 Some(Face::Back)
79 } else {
80 None
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 pub trait I32MathExt {
89 fn ushr(self, n: u32) -> u32;
90 }
91
92 impl I32MathExt for i32 {
93 fn ushr(self, n: u32) -> u32 {
94 ((self >> n) & ((1 << (32 - n)) - 1)) as u32
95 }
96 }
97
98 #[test]
99 fn test_get_cmd() {
100 let word: usize = 84939284;
101 let a = get_cmd(word, 16, 8) / 2;
102 let b = get_cmd(word, 8, 8) / 2;
103 let c = get_cmd(word, 0, 8) / 2;
104
105 assert_eq!(a, 8);
106 assert_eq!(b, 9);
107 assert_eq!(c, 10);
108
109 assert_eq!(a, ((((word as i32).ushr(16)) & 0xFF) / 2) as usize);
110 }
111}