diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 449d5b2..d54946d 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -26,7 +26,7 @@ jobs: runs-on: macos-latest strategy: matrix: - renderer: [opengl, wgpu] + renderer: [opengl-renderer, wgpu-renderer] steps: - uses: actions/checkout@v2 - name: Test @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - renderer: [opengl, wgpu] + renderer: [opengl-renderer, wgpu-renderer] steps: - uses: actions/checkout@v2 - name: Update apt @@ -50,7 +50,7 @@ jobs: runs-on: windows-latest strategy: matrix: - renderer: [opengl, wgpu] + renderer: [opengl-renderer, wgpu-renderer] steps: - uses: actions/checkout@v2 - name: Test diff --git a/Cargo.toml b/Cargo.toml index 93b837b..db0c603 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,18 +8,18 @@ name = "helix" crate-type = ["lib", "staticlib"] [features] -default = ["f3dex2", "opengl"] +default = ["f3dex2", "opengl_renderer"] # Graphics Features -f3dex2 = [] -f3dex2e = ["gbifloats", "f3dex2"] -f3dzex2 = ["f3dex2"] +f3dex2 = ["fast3d/f3dex2"] +f3dex2e = ["gbifloats", "f3dex2", "fast3d/f3dex2e"] +f3dzex2 = ["f3dex2", "fast3d/f3dzex2"] -gbifloats = [] +gbifloats = ["fast3d/gbifloats"] # Renderer Backend -wgpu = ["imgui-wgpu"] -opengl = ["glium", "glutin", "imgui-glium-renderer"] +wgpu_renderer = ["wgpu", "imgui-wgpu", "fast3d-wgpu-renderer"] +opengl_renderer = ["glium", "glutin", "imgui-glium-renderer", "fast3d-glium-renderer"] # Additional Features speech = ["dep:tts"] @@ -27,11 +27,8 @@ network = ["dep:tokio"] [dependencies] anyhow = "1.0.70" -approx = "0.5.1" env_logger = "0.10.0" -farbe = "0.2.0" gilrs = { version = "0.10.2", features = ["serde", "serde-serialize"] } -glam = { git = "https://github.com/bitshifter/glam-rs.git", branch = "neon", features = ["approx", "bytemuck"] } glium = { version = "0.32.1", optional = true } imgui = { version = "0.11.0", features = ["docking"] } imgui-wgpu = { git = "https://github.com/retrofoundry/imgui-wgpu-rs.git", branch = "helix", optional = true } @@ -44,10 +41,14 @@ pollster = "0.3.0" tokio = { version = "1.26.0", features = ["full"], optional = true } tts = { version = "0.25.0", optional = true } glutin = { version = "0.29.1", optional = true } -wgpu = "0.16" +wgpu = { version = "0.16", optional = true } spin_sleep = "1.1.1" -bytemuck = { version = "1.13.1", features = ["derive"] } arie = "0.2.0" +fast3d = { version = "0.1.0", default-features = false } +fast3d-glium-renderer = { git = "https://github.com/retrofoundry/fast3d-rs", optional = true } +fast3d-wgpu-renderer = { version = "0.1.0", optional = true } [patch.crates-io] glium = { git = "https://github.com/retrofoundry/glium", branch = "helix" } +fast3d = { git = "https://github.com/retrofoundry/fast3d-rs" } # remove once we have our glium fix upstreamed +fast3d-wgpu-renderer = { git = "https://github.com/retrofoundry/fast3d-rs" } # remove once we have our glium fix upstreamed diff --git a/src/extensions.rs b/src/extensions.rs deleted file mode 100644 index 3bb3506..0000000 --- a/src/extensions.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod matrix; diff --git a/src/extensions/matrix.rs b/src/extensions/matrix.rs deleted file mode 100644 index 492fe33..0000000 --- a/src/extensions/matrix.rs +++ /dev/null @@ -1,54 +0,0 @@ -use glam::{Mat4, Vec3A, Vec4Swizzles}; - -pub trait MatrixFrom { - fn from_fixed_point(addr: &[i32]) -> Self; - fn from_floats(addr: &[f32]) -> Self; -} - -impl MatrixFrom for Mat4 { - fn from_fixed_point(addr: &[i32]) -> Self { - let mut f_mtx = Mat4::ZERO; - for i in 0..4 { - for j in (0..4).step_by(2) { - let int_part = addr[i * 2 + j / 2]; - let frac_part = addr[8 + i * 2 + j / 2] as u32; - - let a = (int_part as u32 & 0xFFFF0000) as i32; - let b = (frac_part >> 16) as i32; - let c = int_part << 16; - let d = frac_part as i32 & 0xFFFF; - - f_mtx.col_mut(j)[i] = (a | b) as f32 / 65536.0; - f_mtx.col_mut(j + 1)[i] = (c | d) as f32 / 65536.0; - } - } - - f_mtx - } - - fn from_floats(addr: &[f32]) -> Self { - Mat4::from_cols_array(&[ - addr[0], addr[4], addr[8], addr[12], addr[1], addr[5], addr[9], addr[13], addr[2], - addr[6], addr[10], addr[14], addr[3], addr[7], addr[11], addr[15], - ]) - } -} - -pub trait Vec3AMul { - fn mul_mat4(&self, matrix: &Mat4) -> Self; -} - -impl Vec3AMul for Vec3A { - #[inline] - fn mul_mat4(&self, matrix: &Mat4) -> Self { - Self::new( - self.dot(matrix.row(0).xyz().into()), - self.dot(matrix.row(1).xyz().into()), - self.dot(matrix.row(2).xyz().into()), - ) - } -} - -pub fn calculate_normal_dir(vector: &Vec3A, matrix: &Mat4, output: &mut Vec3A) { - *output = vector.mul_mat4(matrix).normalize_or_zero(); -} diff --git a/src/fast3d.rs b/src/fast3d.rs deleted file mode 100644 index 1a7b9b7..0000000 --- a/src/fast3d.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod gbi; -pub mod graphics; -pub mod rcp; -pub mod rdp; -mod rsp; -pub mod utils; diff --git a/src/fast3d/gbi.rs b/src/fast3d/gbi.rs deleted file mode 100644 index e201976..0000000 --- a/src/fast3d/gbi.rs +++ /dev/null @@ -1,84 +0,0 @@ -use self::defines::{Gfx, G_RDPFULLSYNC, G_RDPLOADSYNC, G_RDPPIPESYNC, G_RDPTILESYNC}; - -use super::{graphics::GraphicsIntermediateDevice, rdp::RDP, rsp::RSP}; -use std::collections::HashMap; - -pub mod defines; -mod f3d; -mod f3dex2; -mod f3dex2e; -mod f3dzex2; -pub mod utils; - -pub enum GBIResult { - Return, - Recurse(usize), - Unknown(usize), - Continue, -} - -pub type GBICommand = fn( - dp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, -) -> GBIResult; - -trait GBIDefinition { - fn setup(gbi: &mut GBI); -} - -pub struct GBI { - pub gbi_opcode_table: HashMap, -} - -impl Default for GBI { - fn default() -> Self { - Self::new() - } -} - -impl GBI { - pub fn new() -> Self { - Self { - gbi_opcode_table: HashMap::new(), - } - } - - pub fn setup(&mut self) { - self.register(G_RDPLOADSYNC as usize, |_, _, _, _| GBIResult::Continue); - self.register(G_RDPPIPESYNC as usize, |_, _, _, _| GBIResult::Continue); - self.register(G_RDPTILESYNC as usize, |_, _, _, _| GBIResult::Continue); - self.register(G_RDPFULLSYNC as usize, |_, _, _, _| GBIResult::Continue); - - if cfg!(feature = "f3dzex2") { - f3dzex2::F3DZEX2::setup(self); - } else if cfg!(feature = "f3dex2e") { - f3dex2e::F3DEX2E::setup(self); - } else if cfg!(feature = "f3dex2") { - f3dex2::F3DEX2::setup(self); - } - } - - pub fn register(&mut self, opcode: usize, cmd: GBICommand) { - self.gbi_opcode_table.insert(opcode, cmd); - } - - pub fn handle_command( - &self, - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - - let opcode = w0 >> 24; - let cmd = self.gbi_opcode_table.get(&opcode); - - match cmd { - Some(cmd) => cmd(rdp, rsp, gfx_device, command), - None => GBIResult::Unknown(opcode), - } - } -} diff --git a/src/fast3d/gbi/defines.rs b/src/fast3d/gbi/defines.rs deleted file mode 100644 index 471fa3f..0000000 --- a/src/fast3d/gbi/defines.rs +++ /dev/null @@ -1,197 +0,0 @@ -#[repr(C)] -#[derive(Clone, Copy)] -pub struct GWords { - pub w0: usize, - pub w1: usize, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub union Gfx { - pub words: GWords, - pub force_structure_alignment: i64, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct Viewport { - pub vscale: [i16; 4], // scale, 2 bits fraction - pub vtrans: [i16; 4], // translate, 2 bits fraction - _padding: [u8; 8], // padding to 64-bit boundary -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct RawLight { - pub words: [u32; 4], -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub union Light { - pub raw: RawLight, - pub pos: PosLight, - pub dir: DirLight, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct DirLight { - pub col: [u8; 3], // diffuse light value (rgba) - pad1: i8, - pub colc: [u8; 3], // copy of diffuse light value (rgba) - pad2: i8, - pub dir: [i8; 3], // direction of light (normalized) - pad3: i8, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct PosLight { - pub kc: u8, - pub col: [u8; 3], - pub kl: u8, - pub colc: [u8; 3], - pub pos: [i16; 2], - pub reserved1: u8, - pub kq: u8, - pub posz: i16, -} - -impl Light { - pub const ZERO: Self = Self { - raw: RawLight { - words: [0, 0, 0, 0], - }, - }; -} - -pub struct LookAt { - pub x: [f32; 3], - pub y: [f32; 3], -} - -impl LookAt { - pub const fn new(x: [f32; 3], y: [f32; 3]) -> Self { - Self { x, y } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Color_t { - pub r: u8, - pub g: u8, - pub b: u8, - pub a: u8, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub union Vtx { - pub vertex: Vtx_t, - pub normal: Vtx_tn, - force_structure_alignment: i64, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct Vtx_t { - #[cfg(feature = "gbifloats")] - pub position: [f32; 3], // in object space - #[cfg(not(feature = "gbifloats"))] - pub position: [i16; 3], // in object space - flag: u16, // unused - pub texture_coords: [i16; 2], - pub color: Color_t, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct Vtx_tn { - #[cfg(feature = "gbifloats")] - pub position: [f32; 3], // in object space - #[cfg(not(feature = "gbifloats"))] - pub position: [i16; 3], // in object space - flag: u16, // unused - pub texture_coords: [i16; 2], - pub normal: [i8; 3], - pub alpha: u8, -} - -#[cfg(feature = "f3dex2")] -pub struct G_MTX; -#[cfg(feature = "f3dex2")] -impl G_MTX { - pub const NOPUSH: u8 = 0x00; - pub const PUSH: u8 = 0x01; - pub const MUL: u8 = 0x00; - pub const LOAD: u8 = 0x02; - pub const MODELVIEW: u8 = 0x00; - pub const PROJECTION: u8 = 0x04; -} - -pub struct G_SET; -impl G_SET { - pub const COLORIMG: u8 = 0xff; - pub const DEPTHIMG: u8 = 0xfe; - pub const TEXIMG: u8 = 0xfd; - pub const COMBINE: u8 = 0xfc; - pub const ENVCOLOR: u8 = 0xfb; - pub const PRIMCOLOR: u8 = 0xfa; - pub const BLENDCOLOR: u8 = 0xf9; - pub const FOGCOLOR: u8 = 0xf8; - pub const FILLCOLOR: u8 = 0xf7; - pub const TILE: u8 = 0xf5; - pub const TILESIZE: u8 = 0xf2; - pub const PRIMDEPTH: u8 = 0xee; - pub const SCISSOR: u8 = 0xed; - pub const CONVERT: u8 = 0xec; - pub const KEYR: u8 = 0xeb; - pub const KEYGB: u8 = 0xea; -} - -pub struct G_LOAD; -impl G_LOAD { - pub const BLOCK: u8 = 0xf3; - pub const TILE: u8 = 0xf4; - pub const TLUT: u8 = 0xf0; -} - -pub struct G_MW; -impl G_MW { - pub const MATRIX: u8 = 0x00; /* NOTE: also used by movemem */ - pub const NUMLIGHT: u8 = 0x02; - pub const CLIP: u8 = 0x04; - pub const SEGMENT: u8 = 0x06; - pub const FOG: u8 = 0x08; - pub const LIGHTCOL: u8 = 0x0A; - #[cfg(feature = "f3dex2")] - pub const FORCEMTX: u8 = 0x0C; - #[cfg(not(feature = "f3dex2"))] - pub const POINTS: u8 = 0x0C; - pub const PERSPNORM: u8 = 0x0E; -} - -pub struct G_TX; -impl G_TX { - pub const LOADTILE: u8 = 7; - pub const RENDERTILE: u8 = 0; - pub const NOMIRROR: u8 = 0; - pub const WRAP: u8 = 0; - pub const MIRROR: u8 = 1; - pub const CLAMP: u8 = 2; - pub const NOMASK: u8 = 0; - pub const NOLOD: u8 = 0; -} - -// lose defines - -pub const G_TEXRECT: u8 = 0xe4; -pub const G_TEXRECTFLIP: u8 = 0xe5; -pub const G_FILLRECT: u8 = 0xf6; - -pub const G_RDPFULLSYNC: u8 = 0xe9; -pub const G_RDPTILESYNC: u8 = 0xe8; -pub const G_RDPPIPESYNC: u8 = 0xe7; -pub const G_RDPLOADSYNC: u8 = 0xe6; diff --git a/src/fast3d/gbi/f3d.rs b/src/fast3d/gbi/f3d.rs deleted file mode 100644 index 8a9d9d7..0000000 --- a/src/fast3d/gbi/f3d.rs +++ /dev/null @@ -1,55 +0,0 @@ -pub struct F3D; - -impl F3D { - pub const G_MW_POINTS: u8 = 0x0c; - pub const G_MWO_aLIGHT_2: u8 = 0x20; - pub const G_MWO_bLIGHT_2: u8 = 0x24; - pub const G_MWO_aLIGHT_3: u8 = 0x40; - pub const G_MWO_bLIGHT_3: u8 = 0x44; - pub const G_MWO_aLIGHT_4: u8 = 0x60; - pub const G_MWO_bLIGHT_4: u8 = 0x64; - pub const G_MWO_aLIGHT_5: u8 = 0x80; - pub const G_MWO_bLIGHT_5: u8 = 0x84; - pub const G_MWO_aLIGHT_6: u8 = 0xa0; - pub const G_MWO_bLIGHT_6: u8 = 0xa4; - pub const G_MWO_aLIGHT_7: u8 = 0xc0; - pub const G_MWO_bLIGHT_7: u8 = 0xc4; - pub const G_MWO_aLIGHT_8: u8 = 0xe0; - pub const G_MWO_bLIGHT_8: u8 = 0xe4; - pub const G_NOOP: u8 = 0xc0; - pub const G_SETOTHERMODE_H: u8 = 0xBA; - pub const G_SETOTHERMODE_L: u8 = 0xB9; - pub const G_RDPHALF_1: u8 = 0xB4; - pub const G_RDPHALF_2: u8 = 0xB3; - pub const G_SPNOOP: u8 = 0x00; - pub const G_ENDDL: u8 = 0xB8; - pub const G_DL: u8 = 0x06; - pub const G_MOVEMEM: u8 = 0x03; - pub const G_MOVEWORD: u8 = 0xBC; - pub const G_MTX: u8 = 0x01; - pub const G_POPMTX: u8 = 0xBD; - pub const G_TEXTURE: u8 = 0xBB; - pub const G_VTX: u8 = 0x04; - pub const G_CULLDL: u8 = 0xBE; - pub const G_TRI1: u8 = 0xBF; - pub const G_QUAD: u8 = 0xB5; - pub const G_SPRITE2D_BASE: u8 = 0x09; - pub const G_SETGEOMETRYMODE: u8 = 0xB7; - pub const G_CLEARGEOMETRYMODE: u8 = 0xB6; - pub const G_MV_VIEWPORT: u8 = 0x80; - pub const G_MV_LOOKATY: u8 = 0x82; - pub const G_MV_LOOKATX: u8 = 0x84; - pub const G_MV_L0: u8 = 0x86; - pub const G_MV_L1: u8 = 0x88; - pub const G_MV_L2: u8 = 0x8a; - pub const G_MV_L3: u8 = 0x8c; - pub const G_MV_L4: u8 = 0x8e; - pub const G_MV_L5: u8 = 0x90; - pub const G_MV_L6: u8 = 0x92; - pub const G_MV_L7: u8 = 0x94; - pub const G_MV_TXTATT: u8 = 0x96; - pub const G_MV_MATRIX_1: u8 = 0x9e; - pub const G_MV_MATRIX_2: u8 = 0x98; - pub const G_MV_MATRIX_3: u8 = 0x9a; - pub const G_MV_MATRIX_4: u8 = 0x9c; -} diff --git a/src/fast3d/gbi/f3dex.rs b/src/fast3d/gbi/f3dex.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/fast3d/gbi/f3dex2.rs b/src/fast3d/gbi/f3dex2.rs deleted file mode 100644 index 5dfdeee..0000000 --- a/src/fast3d/gbi/f3dex2.rs +++ /dev/null @@ -1,1500 +0,0 @@ -use std::slice; - -use glam::{Mat4, Vec2, Vec3A, Vec4}; - -use log::trace; - -use super::defines::{Gfx, Light, Viewport, Vtx, G_FILLRECT, G_MTX, G_TEXRECT, G_TEXRECTFLIP}; -use super::utils::{ - geometry_mode_uses_fog, get_cmd, get_cycle_type_from_other_mode_h, - get_textfilter_from_other_mode_h, -}; -use super::{ - super::{ - rdp::RDP, - rsp::{RSPGeometry, MATRIX_STACK_SIZE, RSP}, - }, - defines::{G_LOAD, G_MW, G_SET}, -}; -use super::{GBIDefinition, GBIResult, GBI}; -use crate::extensions::matrix::MatrixFrom; -use crate::fast3d::gbi::defines::G_TX; -use crate::fast3d::graphics::GraphicsIntermediateDevice; -use crate::fast3d::rdp::MAX_BUFFERED; -use crate::{ - extensions::matrix::calculate_normal_dir, - fast3d::{ - rdp::{ - OtherModeHCycleType, OtherModeH_Layout, Rect, TMEMMapEntry, SCREEN_HEIGHT, SCREEN_WIDTH, - }, - rsp::MAX_VERTICES, - utils::{ - color::R5G5B5A1, - color_combiner::{CombineParams, ACMUX, CCMUX}, - texture::{ImageSize, TextFilt, TextureImageState, TextureState}, - }, - }, -}; - -pub struct F3DEX2; - -impl F3DEX2 { - /* - * MOVEWORD indices - * - * Each of these indexes an entry in a dmem table - * which points to a word in dmem in dmem where - * an immediate word will be stored. - * - */ - pub const G_MWO_aLIGHT_2: u8 = 0x18; - pub const G_MWO_bLIGHT_2: u8 = 0x1c; - pub const G_MWO_aLIGHT_3: u8 = 0x30; - pub const G_MWO_bLIGHT_3: u8 = 0x34; - pub const G_MWO_aLIGHT_4: u8 = 0x48; - pub const G_MWO_bLIGHT_4: u8 = 0x4c; - pub const G_MWO_aLIGHT_5: u8 = 0x60; - pub const G_MWO_bLIGHT_5: u8 = 0x64; - pub const G_MWO_aLIGHT_6: u8 = 0x78; - pub const G_MWO_bLIGHT_6: u8 = 0x7c; - pub const G_MWO_aLIGHT_7: u8 = 0x90; - pub const G_MWO_bLIGHT_7: u8 = 0x94; - pub const G_MWO_aLIGHT_8: u8 = 0xa8; - pub const G_MWO_bLIGHT_8: u8 = 0xac; - - pub const G_NOOP: u8 = 0x00; - - // RDP - pub const G_SETOTHERMODE_H: u8 = 0xe3; - pub const G_SETOTHERMODE_L: u8 = 0xe2; - pub const G_RDPHALF_1: u8 = 0xe1; - pub const G_RDPHALF_2: u8 = 0xf1; - - pub const G_SPNOOP: u8 = 0xe0; - - // RSP - pub const G_ENDDL: u8 = 0xdf; - pub const G_DL: u8 = 0xde; - pub const G_LOAD_UCODE: u8 = 0xdd; - pub const G_MOVEMEM: u8 = 0xdc; - pub const G_MOVEWORD: u8 = 0xdb; - pub const G_MTX: u8 = 0xda; - pub const G_GEOMETRYMODE: u8 = 0xd9; - pub const G_POPMTX: u8 = 0xd8; - pub const G_TEXTURE: u8 = 0xd7; - - // DMA - pub const G_VTX: u8 = 0x01; - pub const G_MODIFYVTX: u8 = 0x02; - pub const G_CULLDL: u8 = 0x03; - pub const G_BRANCH_Z: u8 = 0x04; - pub const G_TRI1: u8 = 0x05; - pub const G_TRI2: u8 = 0x06; - pub const G_QUAD: u8 = 0x07; - pub const G_LINE3D: u8 = 0x08; - pub const G_DMA_IO: u8 = 0xD6; - - pub const G_SPECIAL_1: u8 = 0xD5; - - /* - * MOVEMEM indices - * - * Each of these indexes an entry in a dmem table - * which points to a 1-4 word block of dmem in - * which to store a 1-4 word DMA. - * - */ - pub const G_MV_MMTX: u8 = 2; - pub const G_MV_PMTX: u8 = 6; - pub const G_MV_VIEWPORT: u8 = 8; - pub const G_MV_LIGHT: u8 = 10; - pub const G_MV_POINT: u8 = 12; - pub const G_MV_MATRIX: u8 = 14; - pub const G_MVO_LOOKATX: u8 = 0; // (0 * 24); - pub const G_MVO_LOOKATY: u8 = 24; - pub const G_MVO_L0: u8 = (2 * 24); - pub const G_MVO_L1: u8 = (3 * 24); - pub const G_MVO_L2: u8 = (4 * 24); - pub const G_MVO_L3: u8 = (5 * 24); - pub const G_MVO_L4: u8 = (6 * 24); - pub const G_MVO_L5: u8 = (7 * 24); - pub const G_MVO_L6: u8 = (8 * 24); - pub const G_MVO_L7: u8 = (9 * 24); -} - -impl GBIDefinition for F3DEX2 { - fn setup(gbi: &mut GBI) { - gbi.register(F3DEX2::G_MTX as usize, F3DEX2::gsp_matrix); - gbi.register(F3DEX2::G_POPMTX as usize, F3DEX2::gsp_pop_matrix); - gbi.register(F3DEX2::G_MOVEMEM as usize, F3DEX2::gsp_movemem); - gbi.register(F3DEX2::G_MOVEWORD as usize, F3DEX2::gsp_moveword); - gbi.register(F3DEX2::G_TEXTURE as usize, F3DEX2::gsp_texture); - gbi.register(F3DEX2::G_VTX as usize, F3DEX2::gsp_vertex); - gbi.register(F3DEX2::G_DL as usize, F3DEX2::sub_dl); - gbi.register(F3DEX2::G_GEOMETRYMODE as usize, F3DEX2::gsp_geometry_mode); - gbi.register(F3DEX2::G_TRI1 as usize, F3DEX2::gsp_tri1); - gbi.register(F3DEX2::G_TRI2 as usize, F3DEX2::gsp_tri2); - gbi.register(F3DEX2::G_ENDDL as usize, |_, _, _, _| GBIResult::Return); - - gbi.register( - F3DEX2::G_SETOTHERMODE_L as usize, - F3DEX2::gdp_set_other_mode_l, - ); - gbi.register( - F3DEX2::G_SETOTHERMODE_H as usize, - F3DEX2::gdp_set_other_mode_h, - ); - gbi.register(G_SET::TEXIMG as usize, F3DEX2::gdp_set_texture_image); - gbi.register(G_LOAD::BLOCK as usize, F3DEX2::gdp_load_block); - gbi.register(G_LOAD::TILE as usize, F3DEX2::gdp_load_tile); - gbi.register(G_LOAD::TLUT as usize, F3DEX2::gdp_load_tlut); - gbi.register(G_SET::TILE as usize, F3DEX2::gdp_set_tile); - gbi.register(G_SET::TILESIZE as usize, F3DEX2::gdp_set_tile_size); - gbi.register(G_SET::SCISSOR as usize, F3DEX2::gdp_set_scissor); - gbi.register(G_SET::CONVERT as usize, F3DEX2::gdp_set_convert); - gbi.register(G_SET::KEYR as usize, F3DEX2::gdp_set_key_r); - gbi.register(G_SET::KEYGB as usize, F3DEX2::gdp_set_key_gb); - gbi.register(G_SET::COMBINE as usize, F3DEX2::gdp_set_combine); - gbi.register(G_SET::ENVCOLOR as usize, F3DEX2::gdp_set_env_color); - gbi.register(G_SET::PRIMCOLOR as usize, F3DEX2::gdp_set_prim_color); - gbi.register(G_SET::BLENDCOLOR as usize, F3DEX2::gdp_set_blend_color); - gbi.register(G_SET::FOGCOLOR as usize, F3DEX2::gdp_set_fog_color); - gbi.register(G_SET::FILLCOLOR as usize, F3DEX2::gdp_set_fill_color); - gbi.register(G_SET::DEPTHIMG as usize, F3DEX2::gdp_set_depth_image); - gbi.register(G_SET::COLORIMG as usize, F3DEX2::gdp_set_color_image); - gbi.register(G_TEXRECT as usize, F3DEX2::gdp_texture_rectangle); - gbi.register(G_TEXRECTFLIP as usize, F3DEX2::gdp_texture_rectangle); - gbi.register(G_FILLRECT as usize, F3DEX2::gdp_fill_rectangle); - } -} - -impl F3DEX2 { - pub fn gsp_matrix( - _rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let params = get_cmd(w0, 0, 8) as u8 ^ G_MTX::PUSH; - - let matrix = if cfg!(feature = "gbifloats") { - let addr = rsp.from_segmented(w1) as *const f32; - let slice = unsafe { slice::from_raw_parts(addr, 16) }; - Mat4::from_floats(slice) - } else { - let addr = rsp.from_segmented(w1) as *const i32; - let slice = unsafe { slice::from_raw_parts(addr, 16) }; - Mat4::from_fixed_point(slice) - }; - - if params & G_MTX::PROJECTION != 0 { - if (params & G_MTX::LOAD) != 0 { - // Load the input matrix into the projection matrix - // rsp.projection_matrix.copy_from_slice(&matrix); - rsp.projection_matrix = matrix; - } else { - // Multiply the current projection matrix with the input matrix - rsp.projection_matrix = matrix * rsp.projection_matrix; - } - } else { - // Modelview matrix - if params & G_MTX::PUSH != 0 && rsp.matrix_stack_pointer < MATRIX_STACK_SIZE { - // Push a copy of the current matrix onto the stack - rsp.matrix_stack_pointer += 1; - - let src_index = rsp.matrix_stack_pointer - 2; - let dst_index = rsp.matrix_stack_pointer - 1; - let (left, right) = rsp.matrix_stack.split_at_mut(dst_index); - right[0] = left[src_index]; - } - - if params & G_MTX::LOAD != 0 { - // Load the input matrix into the current matrix - rsp.matrix_stack[rsp.matrix_stack_pointer - 1] = matrix; - } else { - // Multiply the current matrix with the input matrix - let result = matrix * rsp.matrix_stack[rsp.matrix_stack_pointer - 1]; - rsp.matrix_stack[rsp.matrix_stack_pointer - 1] = result; - } - - // Clear the lights_valid flag - rsp.lights_valid = false; - } - - rsp.modelview_projection_matrix_changed = true; - - GBIResult::Continue - } - - pub fn gsp_pop_matrix( - _rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - let num_matrices_to_pop = w1 / 64; - - // If no matrices to pop, return - if num_matrices_to_pop == 0 || rsp.matrix_stack_pointer == 0 { - return GBIResult::Continue; - } - - // Pop the specified number of matrices - for _ in 0..num_matrices_to_pop { - // Check if there are matrices left to pop - if rsp.matrix_stack_pointer > 0 { - // Decrement the matrix stack index - rsp.matrix_stack_pointer -= 1; - } - } - - // Recalculate the modelview projection matrix - rsp.recompute_mvp_matrix(); - - GBIResult::Continue - } - - pub fn gsp_movemem( - rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let index: u8 = get_cmd(w0, 0, 8) as u8; - let offset = get_cmd(w0, 8, 8) * 8; - let data = rsp.from_segmented(w1); - - match index { - index if index == F3DEX2::G_MV_VIEWPORT => { - let viewport_ptr = data as *const Viewport; - let viewport = unsafe { &*viewport_ptr }; - rdp.calculate_and_set_viewport(*viewport); - } - index if index == F3DEX2::G_MV_MATRIX => { - panic!("Unimplemented move matrix"); - // unsafe { *command = (*command).add(1) }; - } - index if index == F3DEX2::G_MV_LIGHT => { - let index = offset / 24; - if index >= 2 { - rsp.set_light(index - 2, w1); - } else { - rsp.set_look_at(index, w1); - } - } - _ => panic!("Unimplemented move_mem command"), - } - - GBIResult::Continue - } - - pub fn gsp_moveword( - _rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let m_type = get_cmd(w0, 16, 8) as u8; - - match m_type { - m_type if m_type == G_MW::FORCEMTX => rsp.modelview_projection_matrix_changed = w1 == 0, - m_type if m_type == G_MW::NUMLIGHT => rsp.set_num_lights(w1 as u8 / 24), - m_type if m_type == G_MW::CLIP => { - rsp.set_clip_ratio(w1); - } - m_type if m_type == G_MW::SEGMENT => { - let segment = get_cmd(w0, 2, 4); - rsp.set_segment(segment, w1 & 0x00FFFFFF) - } - m_type if m_type == G_MW::FOG => { - let multiplier = get_cmd(w1, 16, 16) as i16; - let offset = get_cmd(w1, 0, 16) as i16; - rsp.set_fog(multiplier, offset); - rsp.fog_changed = true; - } - m_type if m_type == G_MW::LIGHTCOL => { - let index = get_cmd(w0, 0, 16) / 24; - rsp.set_light_color(index, w1 as u32); - } - m_type if m_type == G_MW::PERSPNORM => { - rsp.set_persp_norm(w1); - } - // TODO: G_MW_MATRIX - _ => { - // panic!("Unknown moveword type: {}", m_type); - } - } - - GBIResult::Continue - } - - pub fn gsp_texture( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let scale_s = get_cmd(w1, 16, 16) as u16; - let scale_t = get_cmd(w1, 0, 16) as u16; - let level = get_cmd(w0, 11, 3) as u8; - let tile = get_cmd(w0, 8, 3) as u8; - let on = get_cmd(w0, 1, 7) as u8; - - if rdp.texture_state.tile != tile { - rdp.textures_changed[0] = true; - rdp.textures_changed[1] = true; - } - - rdp.texture_state = TextureState::new(on != 0, tile, level, scale_s, scale_t); - - GBIResult::Continue - } - - pub fn gsp_vertex( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - if rsp.modelview_projection_matrix_changed { - rdp.flush(gfx_device); - rsp.recompute_mvp_matrix(); - gfx_device.set_projection_matrix(rsp.modelview_projection_matrix); - rsp.modelview_projection_matrix_changed = false; - } - - let vertex_count = get_cmd(w0, 12, 8) as u8; - let mut write_index = get_cmd(w0, 1, 7) as u8 - get_cmd(w0, 12, 8) as u8; - let vertices = rsp.from_segmented(w1) as *const Vtx; - - for i in 0..vertex_count { - let vertex = unsafe { &(*vertices.offset(i as isize)).vertex }; - let vertex_normal = unsafe { &(*vertices.offset(i as isize)).normal }; - let staging_vertex = &mut rsp.vertex_table[write_index as usize]; - - let mut U = (((vertex.texture_coords[0] as i32) * (rdp.texture_state.scale_s as i32)) - >> 16) as i16; - let mut V = (((vertex.texture_coords[1] as i32) * (rdp.texture_state.scale_t as i32)) - >> 16) as i16; - - if rsp.geometry_mode & RSPGeometry::G_LIGHTING as u32 > 0 { - if !rsp.lights_valid { - for i in 0..(rsp.num_lights + 1) { - let light: &Light = &rsp.lights[i as usize]; - let normalized_light_vector = Vec3A::new( - unsafe { light.dir.dir[0] as f32 / 127.0 }, - unsafe { light.dir.dir[1] as f32 / 127.0 }, - unsafe { light.dir.dir[2] as f32 / 127.0 }, - ); - - calculate_normal_dir( - &normalized_light_vector, - &rsp.matrix_stack[rsp.matrix_stack_pointer - 1], - &mut rsp.lights_coeffs[i as usize], - ); - } - - calculate_normal_dir( - &rsp.lookat[0], - &rsp.matrix_stack[rsp.matrix_stack_pointer - 1], - &mut rsp.lookat_coeffs[0], - ); - - calculate_normal_dir( - &rsp.lookat[1], - &rsp.matrix_stack[rsp.matrix_stack_pointer - 1], - &mut rsp.lookat_coeffs[1], - ); - - rsp.lights_valid = true - } - - let mut r = unsafe { rsp.lights[rsp.num_lights as usize].dir.col[0] as f32 }; - let mut g = unsafe { rsp.lights[rsp.num_lights as usize].dir.col[1] as f32 }; - let mut b = unsafe { rsp.lights[rsp.num_lights as usize].dir.col[2] as f32 }; - - for i in 0..rsp.num_lights { - let mut intensity = vertex_normal.normal[0] as f32 - * rsp.lights_coeffs[i as usize][0] - + vertex_normal.normal[1] as f32 * rsp.lights_coeffs[i as usize][1] - + vertex_normal.normal[2] as f32 * rsp.lights_coeffs[i as usize][2]; - - intensity /= 127.0; - - if intensity > 0.0 { - unsafe { - r += intensity * rsp.lights[i as usize].dir.col[0] as f32; - } - unsafe { - g += intensity * rsp.lights[i as usize].dir.col[1] as f32; - } - unsafe { - b += intensity * rsp.lights[i as usize].dir.col[2] as f32; - } - } - } - - staging_vertex.color.r = if r > 255.0 { 255.0 } else { r } / 255.0; - staging_vertex.color.g = if g > 255.0 { 255.0 } else { g } / 255.0; - staging_vertex.color.b = if b > 255.0 { 255.0 } else { b } / 255.0; - - if rsp.geometry_mode & RSPGeometry::G_TEXTURE_GEN as u32 > 0 { - let dotx = vertex_normal.normal[0] as f32 * rsp.lookat_coeffs[0][0] - + vertex_normal.normal[1] as f32 * rsp.lookat_coeffs[0][1] - + vertex_normal.normal[2] as f32 * rsp.lookat_coeffs[0][2]; - - let doty = vertex_normal.normal[0] as f32 * rsp.lookat_coeffs[1][0] - + vertex_normal.normal[1] as f32 * rsp.lookat_coeffs[1][1] - + vertex_normal.normal[2] as f32 * rsp.lookat_coeffs[1][2]; - - U = ((dotx / 127.0 + 1.0) / 4.0) as i16 * rdp.texture_state.scale_s as i16; - V = ((doty / 127.0 + 1.0) / 4.0) as i16 * rdp.texture_state.scale_t as i16; - } - } else { - staging_vertex.color.r = vertex.color.r as f32 / 255.0; - staging_vertex.color.g = vertex.color.g as f32 / 255.0; - staging_vertex.color.b = vertex.color.b as f32 / 255.0; - } - - // if geometry_mode_uses_lighting(rsp.geometry_mode) { - // if !rsp.lights_valid { - // warn!("Lights not valid - recomputing normals"); - // rsp.lights_valid = true; - // } - - // if rsp.geometry_mode & RSPGeometry::G_TEXTURE_GEN as u32 > 0 { - // let dotx = vertex_normal.normal[0] as f32 * rsp.lookat_coeffs[0][0] - // + vertex_normal.normal[1] as f32 * rsp.lookat_coeffs[0][1] - // + vertex_normal.normal[2] as f32 * rsp.lookat_coeffs[0][2]; - - // let doty = vertex_normal.normal[0] as f32 * rsp.lookat_coeffs[1][0] - // + vertex_normal.normal[1] as f32 * rsp.lookat_coeffs[1][1] - // + vertex_normal.normal[2] as f32 * rsp.lookat_coeffs[1][2]; - - // U = ((dotx / 127.0 + 1.0) / 4.0) as i16 * rdp.texture_state.scale_s as i16; - // V = ((doty / 127.0 + 1.0) / 4.0) as i16 * rdp.texture_state.scale_t as i16; - // } - - // staging_vertex.color.r = - // unsafe { rsp.lights[rsp.num_lights as usize].dir.col[0] as f32 / 255.0 }; - // staging_vertex.color.g = - // unsafe { rsp.lights[rsp.num_lights as usize].dir.col[1] as f32 / 255.0 }; - // staging_vertex.color.b = - // unsafe { rsp.lights[rsp.num_lights as usize].dir.col[2] as f32 / 255.0 }; - // } else { - // staging_vertex.color.r = vertex.color.r as f32 / 255.0; - // staging_vertex.color.g = vertex.color.g as f32 / 255.0; - // staging_vertex.color.b = vertex.color.b as f32 / 255.0; - // } - - staging_vertex.uv[0] = U as f32; - staging_vertex.uv[1] = V as f32; - - staging_vertex.position.x = vertex.position[0] as f32; - staging_vertex.position.y = vertex.position[1] as f32; - staging_vertex.position.z = vertex.position[2] as f32; - staging_vertex.position.w = 1.0; - - if geometry_mode_uses_fog(rsp.geometry_mode) && rsp.fog_changed { - rdp.flush(gfx_device); - gfx_device.set_fog(rsp.fog_multiplier, rsp.fog_offset); - } - - staging_vertex.color.a = vertex.color.a as f32 / 255.0; - - write_index += 1; - } - - GBIResult::Continue - } - - pub fn gsp_geometry_mode( - rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let clear_bits = get_cmd(w0, 0, 24); - let set_bits = w1; - - rsp.geometry_mode &= clear_bits as u32; - rsp.geometry_mode |= set_bits as u32; - rdp.shader_config_changed = true; - - GBIResult::Continue - } - - pub fn gsp_tri1_raw( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - vertex_id1: usize, - vertex_id2: usize, - vertex_id3: usize, - is_drawing_rect: bool, - ) -> GBIResult { - let vertex1 = &rsp.vertex_table[vertex_id1]; - let vertex2 = &rsp.vertex_table[vertex_id2]; - let vertex3 = &rsp.vertex_table[vertex_id3]; - let vertex_array = [vertex1, vertex2, vertex3]; - - // Don't draw anything if both tris are being culled. - if (rsp.geometry_mode & RSPGeometry::G_CULL_BOTH as u32) == RSPGeometry::G_CULL_BOTH as u32 - { - return GBIResult::Continue; - } - - rdp.update_render_state(gfx_device, rsp.geometry_mode); - - // let shader_hash = rdp.shader_program_hash(rsp.geometry_mode); - // if shader_hash != rdp.rendering_state.shader_program_hash { - if rdp.shader_config_changed { - rdp.flush(gfx_device); - - gfx_device.set_program_params( - rdp.other_mode_h, - rdp.other_mode_l, - rdp.combine, - rdp.tile_descriptors, - ); - - rdp.rendering_state.shader_program_hash = rdp.shader_program_hash(rsp.geometry_mode); - rdp.shader_config_changed = false; - } - - rdp.flush_textures(gfx_device); - - gfx_device.set_uniforms( - rdp.fog_color, - rdp.blend_color, - rdp.prim_color, - rdp.env_color, - rdp.key_center, - rdp.key_scale, - rdp.prim_lod, - rdp.convert_k, - ); - - let current_tile = rdp.tile_descriptors[rdp.texture_state.tile as usize]; - let tex_width = current_tile.get_width(); - let tex_height = current_tile.get_height(); - let use_texture = rdp.combine.uses_texture0() || rdp.combine.uses_texture1(); - - for vertex in &vertex_array { - rdp.add_to_buf_vbo(vertex.position.x); - rdp.add_to_buf_vbo(vertex.position.y); - rdp.add_to_buf_vbo(vertex.position.z); - rdp.add_to_buf_vbo(if is_drawing_rect { - 0.0 - } else { - vertex.position.w - }); - - rdp.add_to_buf_vbo(vertex.color.r); - rdp.add_to_buf_vbo(vertex.color.g); - rdp.add_to_buf_vbo(vertex.color.b); - rdp.add_to_buf_vbo(vertex.color.a); - - if use_texture { - let mut u = (vertex.uv[0] - (current_tile.uls as f32) * 8.0) / 32.0; - let mut v = (vertex.uv[1] - (current_tile.ult as f32) * 8.0) / 32.0; - - if get_textfilter_from_other_mode_h(rdp.other_mode_h) != TextFilt::G_TF_POINT { - u += 0.5; - v += 0.5; - } - - rdp.add_to_buf_vbo(u / tex_width as f32); - rdp.add_to_buf_vbo(v / tex_height as f32); - } - } - - rdp.buf_vbo_num_tris += 1; - if rdp.buf_vbo_num_tris == MAX_BUFFERED { - rdp.flush(gfx_device); - } - - GBIResult::Continue - } - - pub fn gsp_tri1( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - - let vertex_id1 = get_cmd(w0, 16, 8) / 2; - let vertex_id2 = get_cmd(w0, 8, 8) / 2; - let vertex_id3 = get_cmd(w0, 0, 8) / 2; - - F3DEX2::gsp_tri1_raw( - rdp, rsp, gfx_device, vertex_id1, vertex_id2, vertex_id3, false, - ) - } - - pub fn gsp_tri2( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let vertex_id1 = get_cmd(w0, 16, 8) / 2; - let vertex_id2 = get_cmd(w0, 8, 8) / 2; - let vertex_id3 = get_cmd(w0, 0, 8) / 2; - - F3DEX2::gsp_tri1_raw( - rdp, rsp, gfx_device, vertex_id1, vertex_id2, vertex_id3, false, - ); - - let vertex_id1 = get_cmd(w1, 16, 8) / 2; - let vertex_id2 = get_cmd(w1, 8, 8) / 2; - let vertex_id3 = get_cmd(w1, 0, 8) / 2; - F3DEX2::gsp_tri1_raw( - rdp, rsp, gfx_device, vertex_id1, vertex_id2, vertex_id3, false, - ) - } - - pub fn sub_dl( - _rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - if get_cmd(w0, 16, 1) == 0 { - // Push return address - let new_addr = rsp.from_segmented(w1); - GBIResult::Recurse(new_addr) - } else { - let new_addr = rsp.from_segmented(w1); - let cmd = new_addr as *mut Gfx; - unsafe { - *command = cmd.sub(1); - } - GBIResult::Continue - } - } - - pub fn gdp_set_other_mode_l( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let shift = 31 - get_cmd(w0, 8, 8) - get_cmd(w0, 0, 8); - let mask = get_cmd(w0, 0, 8) + 1; - let mode = w1; - - F3DEX2::gdp_other_mode(rdp, shift, mask, mode as u64) - } - - pub fn gdp_set_other_mode_h( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let shift = 63 - get_cmd(w0, 8, 8) - get_cmd(w0, 0, 8); - let mask = get_cmd(w0, 0, 8) + 1; - let mode = (w1 as u64) << 32; - - F3DEX2::gdp_other_mode(rdp, shift, mask, mode) - } - - pub fn gdp_other_mode(rdp: &mut RDP, shift: usize, mask: usize, mode: u64) -> GBIResult { - let mask = ((1_u64 << (mask as u64)) - 1) << shift as u64; - let mut om = rdp.other_mode_l as u64 | ((rdp.other_mode_h as u64) << 32); - om = (om & !mask) | mode; - - rdp.other_mode_l = om as u32; - rdp.other_mode_h = (om >> 32) as u32; - rdp.shader_config_changed = true; - - GBIResult::Continue - } - - pub fn gdp_set_scissor( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let _mode = get_cmd(w1, 24, 2); - let ulx = get_cmd(w0, 12, 12); - let uly = get_cmd(w0, 0, 12); - let lrx = get_cmd(w1, 12, 12); - let lry = get_cmd(w1, 0, 12); - - let x = ulx as f32 / 4.0 * rdp.scaled_x(); - let y = (SCREEN_HEIGHT - lry as f32 / 4.0) * rdp.scaled_y(); - let width = (lrx as f32 - ulx as f32) / 4.0 * rdp.scaled_x(); - let height = (lry as f32 - uly as f32) / 4.0 * rdp.scaled_y(); - - rdp.scissor.x = x as u16; - rdp.scissor.y = y as u16; - rdp.scissor.width = width as u16; - rdp.scissor.height = height as u16; - - rdp.viewport_or_scissor_changed = true; - GBIResult::Continue - } - - pub fn gdp_set_convert( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let k0 = get_cmd(w0, 13, 9); - let k1 = get_cmd(w0, 4, 9); - let k2 = (get_cmd(w0, 0, 4) << 5) | get_cmd(w1, 27, 5); - let k3 = get_cmd(w1, 18, 9); - let k4 = get_cmd(w1, 9, 9); - let k5 = get_cmd(w1, 0, 9); - - rdp.set_convert( - k0 as i32, k1 as i32, k2 as i32, k3 as i32, k4 as i32, k5 as i32, - ); - - GBIResult::Continue - } - - pub fn gdp_set_key_r( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - let cr = get_cmd(w1, 8, 8); - let sr = get_cmd(w1, 0, 8); - let wr = get_cmd(w1, 16, 2); - - rdp.set_key_r(cr as u32, sr as u32, wr as u32); - - GBIResult::Continue - } - - pub fn gdp_set_key_gb( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let cg = get_cmd(w1, 24, 8); - let sg = get_cmd(w1, 16, 8); - let wg = get_cmd(w0, 12, 12); - let cb = get_cmd(w1, 8, 8); - let sb = get_cmd(w1, 0, 8); - let wb = get_cmd(w0, 0, 12); - - rdp.set_key_gb( - cg as u32, sg as u32, wg as u32, cb as u32, sb as u32, wb as u32, - ); - - GBIResult::Continue - } - - pub fn gdp_set_combine( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - rdp.combine = CombineParams::decode(w0, w1); - rdp.shader_config_changed = true; - - GBIResult::Continue - } - - pub fn gdp_set_tile( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let format = get_cmd(w0, 21, 3) as u8; - let size = get_cmd(w0, 19, 2) as u8; - let line = get_cmd(w0, 9, 9) as u16; - let tmem = get_cmd(w0, 0, 9) as u16; - let tile = get_cmd(w1, 24, 3) as u8; - let palette = get_cmd(w1, 20, 4) as u8; - let cm_t: u8 = get_cmd(w1, 18, 2) as u8; - let mask_t: u8 = get_cmd(w1, 14, 4) as u8; - let shift_t: u8 = get_cmd(w1, 10, 4) as u8; - let cm_s: u8 = get_cmd(w1, 8, 2) as u8; - let mask_s: u8 = get_cmd(w1, 4, 4) as u8; - let shift_s: u8 = get_cmd(w1, 0, 4) as u8; - - let tile = &mut rdp.tile_descriptors[tile as usize]; - tile.set_format(format); - tile.set_size(size); - tile.line = line; - tile.tmem = tmem; - tile.palette = palette; - tile.cm_t = cm_t; - tile.mask_t = mask_t; - tile.shift_t = shift_t; - tile.cm_s = cm_s; - tile.mask_s = mask_s; - tile.shift_s = shift_s; - - rdp.textures_changed[0] = true; - rdp.textures_changed[1] = true; - - GBIResult::Continue - } - - pub fn gdp_set_tile_size( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let tile = get_cmd(w1, 24, 3) as u8; - let uls = get_cmd(w0, 12, 12) as u16; - let ult = get_cmd(w0, 0, 12) as u16; - let lrs = get_cmd(w1, 12, 12) as u16; - let lrt = get_cmd(w1, 0, 12) as u16; - - let tile = &mut rdp.tile_descriptors[tile as usize]; - tile.uls = uls; - tile.ult = ult; - tile.lrs = lrs; - tile.lrt = lrt; - - rdp.textures_changed[0] = true; - rdp.textures_changed[1] = true; - - GBIResult::Continue - } - - pub fn gdp_set_texture_image( - rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let format = get_cmd(w0, 21, 3) as u8; - let size = get_cmd(w0, 19, 2) as u8; - let width = get_cmd(w0, 0, 10) as u16; - let address = rsp.from_segmented(w1); - - rdp.texture_image_state = TextureImageState { - format, - size, - width, - address, - }; - - GBIResult::Continue - } - - pub fn gdp_load_tlut( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - let tile = get_cmd(w1, 24, 3) as u8; - let high_index = get_cmd(w1, 14, 10) as u16; - - assert!(tile == G_TX::LOADTILE); - assert!(rdp.texture_image_state.size == ImageSize::G_IM_SIZ_16b as u8); // TLUTs are always 16-bit (so far) - assert!( - rdp.tile_descriptors[tile as usize].tmem == 256 - && (high_index <= 127 || high_index == 255) - || rdp.tile_descriptors[tile as usize].tmem == 384 && high_index == 127 - ); - - trace!("gdp_load_tlut(tile: {}, high_index: {})", tile, high_index); - - let tile = &mut rdp.tile_descriptors[tile as usize]; - rdp.tmem_map.insert( - tile.tmem, - TMEMMapEntry::new(rdp.texture_image_state.address), - ); - - GBIResult::Continue - } - - pub fn gdp_load_block( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let tile = get_cmd(w1, 24, 3) as u8; - let uls = get_cmd(w0, 12, 12); - let ult = get_cmd(w0, 0, 12); - let _texels = get_cmd(w1, 12, 12) as u16; - let _dxt = get_cmd(w1, 0, 12); - - // First, verify that we're loading the whole texture. - assert!(uls == 0 && ult == 0); - // Verify that we're loading into LOADTILE. - assert!(tile == G_TX::LOADTILE); - - let tile = &mut rdp.tile_descriptors[tile as usize]; - rdp.tmem_map.insert( - tile.tmem, - TMEMMapEntry::new(rdp.texture_image_state.address), - ); - - let tmem_index = if tile.tmem != 0 { 1 } else { 0 }; - rdp.textures_changed[tmem_index as usize] = true; - - GBIResult::Continue - } - - pub fn gdp_load_tile( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let tile = get_cmd(w1, 24, 3) as u8; - let uls = get_cmd(w0, 12, 12) as u16; - let ult = get_cmd(w0, 0, 12) as u16; - let lrs = get_cmd(w1, 12, 12) as u16; - let lrt = get_cmd(w1, 0, 12) as u16; - - // First, verify that we're loading the whole texture. - assert!(uls == 0 && ult == 0); - // Verify that we're loading into LOADTILE. - assert!(tile == G_TX::LOADTILE); - - let tile = &mut rdp.tile_descriptors[tile as usize]; - rdp.tmem_map.insert( - tile.tmem, - TMEMMapEntry::new(rdp.texture_image_state.address), - ); - - // TODO: Really necessary? - tile.uls = uls; - tile.ult = ult; - tile.lrs = lrs; - tile.lrt = lrt; - - trace!("texture {} is being marked as has changed", tile.tmem / 256); - let tmem_index = if tile.tmem != 0 { 1 } else { 0 }; - rdp.textures_changed[tmem_index as usize] = true; - - GBIResult::Continue - } - - pub fn gdp_set_env_color( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - let r = get_cmd(w1, 24, 8) as u8; - let g = get_cmd(w1, 16, 8) as u8; - let b = get_cmd(w1, 8, 8) as u8; - let a = get_cmd(w1, 0, 8) as u8; - - rdp.env_color = Vec4::new( - r as f32 / 255.0, - g as f32 / 255.0, - b as f32 / 255.0, - a as f32 / 255.0, - ); - GBIResult::Continue - } - - pub fn gdp_set_prim_color( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let lod_frac = get_cmd(w0, 0, 8) as u8; - let lod_min = get_cmd(w0, 8, 5) as u8; - - let r = get_cmd(w1, 24, 8) as u8; - let g = get_cmd(w1, 16, 8) as u8; - let b = get_cmd(w1, 8, 8) as u8; - let a = get_cmd(w1, 0, 8) as u8; - - rdp.prim_lod = Vec2::new(lod_frac as f32 / 256.0, lod_min as f32 / 32.0); - rdp.prim_color = Vec4::new( - r as f32 / 255.0, - g as f32 / 255.0, - b as f32 / 255.0, - a as f32 / 255.0, - ); - - GBIResult::Continue - } - - pub fn gdp_set_blend_color( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - let r = get_cmd(w1, 24, 8) as u8; - let g = get_cmd(w1, 16, 8) as u8; - let b = get_cmd(w1, 8, 8) as u8; - let a = get_cmd(w1, 0, 8) as u8; - - rdp.blend_color = Vec4::new( - r as f32 / 255.0, - g as f32 / 255.0, - b as f32 / 255.0, - a as f32 / 255.0, - ); - - GBIResult::Continue - } - - pub fn gdp_set_fog_color( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - let r = get_cmd(w1, 24, 8) as u8; - let g = get_cmd(w1, 16, 8) as u8; - let b = get_cmd(w1, 8, 8) as u8; - let a = get_cmd(w1, 0, 8) as u8; - - rdp.fog_color = Vec4::new( - r as f32 / 255.0, - g as f32 / 255.0, - b as f32 / 255.0, - a as f32 / 255.0, - ); - - GBIResult::Continue - } - - pub fn gdp_set_fill_color( - rdp: &mut RDP, - _rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - let packed_color = w1 as u16; - rdp.fill_color = R5G5B5A1::to_rgba(packed_color); - - GBIResult::Continue - } - - pub fn gdp_set_depth_image( - rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w1 = unsafe { (*(*command)).words.w1 }; - - rdp.depth_image = rsp.from_segmented(w1); - GBIResult::Continue - } - - pub fn gdp_set_color_image( - rdp: &mut RDP, - rsp: &mut RSP, - _gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let _format = get_cmd(w0, 21, 3); - let _size = get_cmd(w0, 19, 2); - let _width = get_cmd(w0, 0, 11); - - rdp.color_image = rsp.from_segmented(w1); - GBIResult::Continue - } - - pub fn draw_rectangle( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - ulx: i32, - uly: i32, - lrx: i32, - lry: i32, - ) { - let saved_other_mode_h = rdp.other_mode_h; - let cycle_type = get_cycle_type_from_other_mode_h(rdp.other_mode_h); - - if cycle_type == OtherModeHCycleType::G_CYC_COPY { - rdp.other_mode_h = (rdp.other_mode_h - & !(3 << OtherModeH_Layout::G_MDSFT_TEXTFILT as u32)) - | (TextFilt::G_TF_POINT as u32); - rdp.shader_config_changed = true; - } - - // U10.2 coordinates - let mut ulxf = ulx as f32 / (4.0 * (SCREEN_WIDTH / 2.0)) - 1.0; - let ulyf = -(uly as f32 / (4.0 * (SCREEN_HEIGHT / 2.0))) + 1.0; - let mut lrxf = lrx as f32 / (4.0 * (SCREEN_WIDTH / 2.0)) - 1.0; - let lryf = -(lry as f32 / (4.0 * (SCREEN_HEIGHT / 2.0))) + 1.0; - - ulxf = rdp.adjust_x_for_viewport(ulxf); - lrxf = rdp.adjust_x_for_viewport(lrxf); - - { - let ul = &mut rsp.vertex_table[MAX_VERTICES]; - ul.position.x = ulxf; - ul.position.y = ulyf; - ul.position.z = -1.0; - ul.position.w = 1.0; - } - - { - let ll = &mut rsp.vertex_table[MAX_VERTICES + 1]; - ll.position.x = ulxf; - ll.position.y = lryf; - ll.position.z = -1.0; - ll.position.w = 1.0; - } - - { - let lr = &mut rsp.vertex_table[MAX_VERTICES + 2]; - lr.position.x = lrxf; - lr.position.y = lryf; - lr.position.z = -1.0; - lr.position.w = 1.0; - } - - { - let ur = &mut rsp.vertex_table[MAX_VERTICES + 3]; - ur.position.x = lrxf; - ur.position.y = ulyf; - ur.position.z = -1.0; - ur.position.w = 1.0; - } - - // The coordinates for texture rectangle shall bypass the viewport setting - let default_viewport = Rect::new( - 0, - 0, - rdp.output_dimensions.width as u16, - rdp.output_dimensions.height as u16, - ); - let viewport_saved = rdp.viewport; - let geometry_mode_saved = rsp.geometry_mode; - - rdp.viewport = default_viewport; - rdp.viewport_or_scissor_changed = true; - rsp.geometry_mode = 0; - rdp.shader_config_changed = true; - - F3DEX2::gsp_tri1_raw( - rdp, - rsp, - gfx_device, - MAX_VERTICES, - MAX_VERTICES + 1, - MAX_VERTICES + 3, - true, - ); - F3DEX2::gsp_tri1_raw( - rdp, - rsp, - gfx_device, - MAX_VERTICES + 1, - MAX_VERTICES + 2, - MAX_VERTICES + 3, - true, - ); - - rsp.geometry_mode = geometry_mode_saved; - rdp.shader_config_changed = true; - rdp.viewport = viewport_saved; - rdp.viewport_or_scissor_changed = true; - - if cycle_type == OtherModeHCycleType::G_CYC_COPY { - rdp.other_mode_h = saved_other_mode_h; - rdp.shader_config_changed = true; - } - } - - pub fn gdp_texture_rectangle_raw( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - ulx: i32, - uly: i32, - mut lrx: i32, - mut lry: i32, - _tile: u8, - uls: i16, - ult: i16, - mut dsdx: i16, - mut dtdy: i16, - flipped: bool, - ) -> GBIResult { - let saved_combine_mode = rdp.combine; - if (rdp.other_mode_h >> OtherModeH_Layout::G_MDSFT_CYCLETYPE as u32) & 0x03 - == OtherModeHCycleType::G_CYC_COPY as u32 - { - // Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels - // Divide by 4 to get 1 instead - dsdx >>= 2; - - // Color combiner is turned off in copy mode - let rhs = - (CCMUX::TEXEL0 as usize & 0b111) << 15 | (ACMUX::TEXEL0 as usize & 0b111) << 9; - rdp.combine = CombineParams::decode(0, rhs); - rdp.shader_config_changed = true; - - // Per documentation one extra pixel is added in this modes to each edge - lrx += 1 << 2; - lry += 1 << 2; - } - - // uls and ult are S10.5 - // dsdx and dtdy are S5.10 - // lrx, lry, ulx, uly are U10.2 - // lrs, lrt are S10.5 - if flipped { - dsdx = -dsdx; - dtdy = -dtdy; - } - - let width = if !flipped { lrx - ulx } else { lry - uly } as i64; - let height = if !flipped { lry - uly } else { lrx - ulx } as i64; - let lrs: i64 = ((uls << 7) as i64 + (dsdx as i64) * width) >> 7; - let lrt: i64 = ((ult << 7) as i64 + (dtdy as i64) * height) >> 7; - - let ul = &mut rsp.vertex_table[MAX_VERTICES]; - ul.uv[0] = uls as f32; - ul.uv[1] = ult as f32; - - let lr = &mut rsp.vertex_table[MAX_VERTICES + 2]; - lr.uv[0] = lrs as f32; - lr.uv[1] = lrt as f32; - - let ll = &mut rsp.vertex_table[MAX_VERTICES + 1]; - ll.uv[0] = if !flipped { uls as f32 } else { lrs as f32 }; - ll.uv[1] = if !flipped { lrt as f32 } else { ult as f32 }; - - let ur = &mut rsp.vertex_table[MAX_VERTICES + 3]; - ur.uv[0] = if !flipped { lrs as f32 } else { uls as f32 }; - ur.uv[1] = if !flipped { ult as f32 } else { lrt as f32 }; - - F3DEX2::draw_rectangle(rdp, rsp, gfx_device, ulx, uly, lrx, lry); - rdp.combine = saved_combine_mode; - rdp.shader_config_changed = true; - - GBIResult::Continue - } - - pub fn gdp_texture_rectangle( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let opcode = w0 >> 24; - - let lrx = get_cmd(w0, 12, 12); - let lry = get_cmd(w0, 0, 12); - let tile = get_cmd(w1, 24, 3); - let ulx = get_cmd(w1, 12, 12); - let uly = get_cmd(w1, 0, 12); - - unsafe { - *command = (*command).add(1); - } - let w1 = unsafe { (*(*command)).words.w1 }; - - let uls = get_cmd(w1, 16, 16); - let ult = get_cmd(w1, 0, 16); - - unsafe { - *command = (*command).add(1); - } - let w1 = unsafe { (*(*command)).words.w1 }; - - let dsdx = get_cmd(w1, 16, 16); - let dtdy = get_cmd(w1, 0, 16); - - F3DEX2::gdp_texture_rectangle_raw( - rdp, - rsp, - gfx_device, - ulx as i32, - uly as i32, - lrx as i32, - lry as i32, - tile as u8, - uls as i16, - ult as i16, - dsdx as i16, - dtdy as i16, - opcode == G_TEXRECTFLIP as usize, - ) - } - - pub fn gdp_fill_rectangle_raw( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - ulx: i32, - uly: i32, - mut lrx: i32, - mut lry: i32, - ) -> GBIResult { - if rdp.color_image == rdp.depth_image { - // used to clear depth buffer, not necessary in modern pipelines - return GBIResult::Continue; - } - - let cycle_type = get_cycle_type_from_other_mode_h(rdp.other_mode_h); - if cycle_type == OtherModeHCycleType::G_CYC_COPY - || cycle_type == OtherModeHCycleType::G_CYC_FILL - { - // Per documentation one extra pixel is added in this modes to each edge - lrx += 1 << 2; - lry += 1 << 2; - } - - for i in MAX_VERTICES..MAX_VERTICES + 4 { - let v = &mut rsp.vertex_table[i]; - v.color = rdp.fill_color; - } - - let saved_combine_mode = rdp.combine; - let rhs = (CCMUX::SHADE as usize & 0b111) << 15 | (ACMUX::SHADE as usize & 0b111) << 9; - rdp.combine = CombineParams::decode(0, rhs); - rdp.shader_config_changed = true; - F3DEX2::draw_rectangle(rdp, rsp, gfx_device, ulx, uly, lrx, lry); - rdp.combine = saved_combine_mode; - rdp.shader_config_changed = true; - - GBIResult::Continue - } - - pub fn gdp_fill_rectangle( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let ulx = get_cmd(w1, 12, 12); - let uly = get_cmd(w1, 0, 12); - let lrx = get_cmd(w0, 12, 12); - let lry = get_cmd(w0, 0, 12); - - F3DEX2::gdp_fill_rectangle_raw( - rdp, rsp, gfx_device, ulx as i32, uly as i32, lrx as i32, lry as i32, - ) - } -} - -#[cfg(test)] -mod tests { - - #[test] - fn test_moveword() { - // // NUM_LIGHT - // let w0: usize = 3674341376; - // let w1: usize = 24; - - // let mut rsp = RSP::new(); - // let mut rdp = RDP::new(); - - // let dummy_gfx_context = GraphicsContext::new(Box::new(DummyGraphicsDevice {})); - // F3DEX2::gsp_moveword(&mut rdp, &mut rsp, &dummy_gfx_context, w0, w1); - // assert!(rsp.num_lights == 2); - - // // FOG - // let w0: usize = 3674734592; - // let w1: usize = 279638102; - - // let mut rsp = RSP::new(); - // let mut rdp = RDP::new(); - - // let dummy_gfx_context = GraphicsContext::new(Box::new(DummyGraphicsDevice {})); - // F3DEX2::gsp_moveword(&mut rdp, &mut rsp, &dummy_gfx_context, w0, w1); - // assert!(rsp.fog_multiplier == 4266); - // assert!(rsp.fog_offset == -4010); - } -} diff --git a/src/fast3d/gbi/f3dex2e.rs b/src/fast3d/gbi/f3dex2e.rs deleted file mode 100644 index 2d4c131..0000000 --- a/src/fast3d/gbi/f3dex2e.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::fast3d::{graphics::GraphicsIntermediateDevice, rdp::RDP, rsp::RSP}; - -use super::{ - defines::{Gfx, G_FILLRECT, G_TEXRECT, G_TEXRECTFLIP}, - f3dex2::F3DEX2, - utils::get_cmd, - GBIDefinition, GBIResult, GBI, -}; - -pub struct F3DEX2E; - -impl GBIDefinition for F3DEX2E { - fn setup(gbi: &mut GBI) { - F3DEX2::setup(gbi); - gbi.register(G_TEXRECT as usize, F3DEX2E::gdp_texture_rectangle); - gbi.register(G_TEXRECTFLIP as usize, F3DEX2E::gdp_texture_rectangle); - gbi.register(G_FILLRECT as usize, F3DEX2E::gdp_fill_rectangle); - } -} - -impl F3DEX2E { - pub fn gdp_texture_rectangle( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let opcode = w0 >> 24; - - let lrx = get_cmd(w0, 0, 24) << 8 >> 8; - let lry = get_cmd(w1, 0, 24) << 8 >> 8; - let tile = get_cmd(w1, 24, 3); - - unsafe { - *command = (*command).add(1); - } - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let ulx = get_cmd(w0, 0, 24) << 8 >> 8; - let uls = get_cmd(w1, 16, 16); - let ult = get_cmd(w1, 0, 16); - - unsafe { - *command = (*command).add(1); - } - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let uly = get_cmd(w0, 0, 24) << 8 >> 8; - let dsdx = get_cmd(w1, 16, 16); - let dtdy = get_cmd(w1, 0, 16); - - F3DEX2::gdp_texture_rectangle_raw( - rdp, - rsp, - gfx_device, - ulx as i32, - uly as i32, - lrx as i32, - lry as i32, - tile as u8, - uls as i16, - ult as i16, - dsdx as i16, - dtdy as i16, - opcode == G_TEXRECTFLIP as usize, - ) - } - - pub fn gdp_fill_rectangle( - rdp: &mut RDP, - rsp: &mut RSP, - gfx_device: &mut GraphicsIntermediateDevice, - command: &mut *mut Gfx, - ) -> GBIResult { - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let lrx = get_cmd(w0, 0, 24) << 8 >> 8; - let lry = get_cmd(w1, 0, 24) << 8 >> 8; - - unsafe { - *command = (*command).add(1); - } - let w0 = unsafe { (*(*command)).words.w0 }; - let w1 = unsafe { (*(*command)).words.w1 }; - - let ulx = get_cmd(w0, 0, 24) << 8 >> 8; - let uly = get_cmd(w1, 0, 24) << 8 >> 8; - - F3DEX2::gdp_fill_rectangle_raw( - rdp, rsp, gfx_device, ulx as i32, uly as i32, lrx as i32, lry as i32, - ) - } -} diff --git a/src/fast3d/gbi/f3dzex2.rs b/src/fast3d/gbi/f3dzex2.rs deleted file mode 100644 index 8b5d622..0000000 --- a/src/fast3d/gbi/f3dzex2.rs +++ /dev/null @@ -1,9 +0,0 @@ -use super::{f3dex2::F3DEX2, GBIDefinition, GBI}; - -pub enum F3DZEX2 {} - -impl GBIDefinition for F3DZEX2 { - fn setup(gbi: &mut GBI) { - F3DEX2::setup(gbi); - } -} diff --git a/src/fast3d/gbi/utils.rs b/src/fast3d/gbi/utils.rs deleted file mode 100644 index ec945fe..0000000 --- a/src/fast3d/gbi/utils.rs +++ /dev/null @@ -1,123 +0,0 @@ -use wgpu::BlendFactor; - -use crate::fast3d::{ - rdp::{ - AlphaCompare, BlendParamB, BlendParamPMColor, OtherModeHCycleType, OtherModeH_Layout, - OtherModeLayoutL, - }, - rsp::RSPGeometry, - utils::texture::TextFilt, -}; - -pub fn get_cmd(val: usize, start_bit: u32, num_bits: u32) -> usize { - (val >> start_bit) & ((1 << num_bits) - 1) -} - -pub fn geometry_mode_uses_lighting(geometry_mode: u32) -> bool { - geometry_mode & RSPGeometry::G_LIGHTING as u32 > 0 -} - -pub fn geometry_mode_uses_fog(geometry_mode: u32) -> bool { - geometry_mode & RSPGeometry::G_FOG as u32 > 0 -} - -pub fn other_mode_l_uses_texture_edge(other_mode_l: u32) -> bool { - other_mode_l >> (OtherModeLayoutL::CVG_X_ALPHA as u32) & 0x01 == 0x01 -} - -pub fn other_mode_l_uses_alpha(other_mode_l: u32) -> bool { - other_mode_l & ((BlendParamB::G_BL_A_MEM as u32) << (OtherModeLayoutL::B_1 as u32)) == 0 -} - -pub fn other_mode_l_alpha_compare_threshold(other_mode_l: u32) -> bool { - other_mode_l & AlphaCompare::G_AC_THRESHOLD as u32 == AlphaCompare::G_AC_THRESHOLD as u32 -} - -pub fn other_mode_l_uses_fog(other_mode_l: u32) -> bool { - (other_mode_l >> OtherModeLayoutL::P_1 as u32) == BlendParamPMColor::G_BL_CLR_FOG as u32 -} - -pub fn other_mode_l_alpha_compare_dither(other_mode_l: u32) -> bool { - other_mode_l & AlphaCompare::G_AC_DITHER as u32 == AlphaCompare::G_AC_DITHER as u32 -} - -pub fn get_cycle_type_from_other_mode_h(mode_h: u32) -> OtherModeHCycleType { - match (mode_h >> OtherModeH_Layout::G_MDSFT_CYCLETYPE as u32) & 0x03 { - x if x == OtherModeHCycleType::G_CYC_1CYCLE as u32 => OtherModeHCycleType::G_CYC_1CYCLE, - x if x == OtherModeHCycleType::G_CYC_2CYCLE as u32 => OtherModeHCycleType::G_CYC_2CYCLE, - x if x == OtherModeHCycleType::G_CYC_COPY as u32 => OtherModeHCycleType::G_CYC_COPY, - x if x == OtherModeHCycleType::G_CYC_FILL as u32 => OtherModeHCycleType::G_CYC_FILL, - _ => panic!("Invalid cycle type"), - } -} - -pub fn get_textfilter_from_other_mode_h(mode_h: u32) -> TextFilt { - match (mode_h >> OtherModeH_Layout::G_MDSFT_TEXTFILT as u32) & 0x3 { - x if x == TextFilt::G_TF_POINT as u32 => TextFilt::G_TF_POINT, - x if x == TextFilt::G_TF_AVERAGE as u32 => TextFilt::G_TF_AVERAGE, - x if x == TextFilt::G_TF_BILERP as u32 => TextFilt::G_TF_BILERP, - _ => panic!("Invalid text filter"), - } -} - -pub fn translate_blend_param_b(param: u32, src: BlendFactor) -> BlendFactor { - match param { - x if x == BlendParamB::G_BL_1MA as u32 => { - if src == BlendFactor::SrcAlpha { - BlendFactor::OneMinusSrcAlpha - } else if src == BlendFactor::One { - BlendFactor::Zero - } else { - BlendFactor::One - } - } - x if x == BlendParamB::G_BL_A_MEM as u32 => BlendFactor::DstAlpha, - x if x == BlendParamB::G_BL_1 as u32 => BlendFactor::One, - x if x == BlendParamB::G_BL_0 as u32 => BlendFactor::Zero, - _ => panic!("Unknown Blend Param B: {}", param), - } -} - -pub fn translate_cull_mode(geometry_mode: u32) -> Option { - let cull_front = (geometry_mode & RSPGeometry::G_CULL_FRONT as u32) != 0; - let cull_back = (geometry_mode & RSPGeometry::G_CULL_BACK as u32) != 0; - - if cull_front && cull_back { - panic!("Culling both front and back faces is not supported"); - } else if cull_front { - Some(wgpu::Face::Front) - } else if cull_back { - Some(wgpu::Face::Back) - } else { - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - - pub trait I32MathExt { - fn ushr(self, n: u32) -> u32; - } - - impl I32MathExt for i32 { - fn ushr(self, n: u32) -> u32 { - ((self >> n) & ((1 << (32 - n)) - 1)) as u32 - } - } - - #[test] - fn test_get_cmd() { - let word: usize = 84939284; - let a = get_cmd(word, 16, 8) / 2; - let b = get_cmd(word, 8, 8) / 2; - let c = get_cmd(word, 0, 8) / 2; - - assert_eq!(a, 8); - assert_eq!(b, 9); - assert_eq!(c, 10); - - assert_eq!(a, ((((word as i32).ushr(16)) & 0xFF) / 2) as usize); - } -} diff --git a/src/fast3d/graphics.rs b/src/fast3d/graphics.rs deleted file mode 100644 index 01dca5a..0000000 --- a/src/fast3d/graphics.rs +++ /dev/null @@ -1,380 +0,0 @@ -use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, -}; - -use super::{ - rdp::NUM_TILE_DESCRIPTORS, - utils::{ - color_combiner::CombineParams, - texture::{ImageFormat, ImageSize}, - texture_cache::TextureCache, - tile_descriptor::TileDescriptor, - }, -}; - -const TEXTURE_CACHE_MAX_SIZE: usize = 500; - -pub struct GraphicsIntermediateTexture { - pub game_address: usize, - pub format: ImageFormat, - pub size: ImageSize, - pub width: u32, - pub height: u32, - pub data: Vec, - - // when a texture has been created in a gfx backend, this field will be Some - pub device_id: Option, -} - -impl GraphicsIntermediateTexture { - pub fn new( - game_address: usize, - format: ImageFormat, - size: ImageSize, - width: u32, - height: u32, - data: Vec, - ) -> Self { - Self { - game_address, - format, - size, - width, - height, - data, - device_id: None, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct GraphicsIntermediateSampler { - pub tile: usize, - pub linear_filter: bool, - pub clamp_s: u32, - pub clamp_t: u32, -} - -#[derive(Debug, Clone, Copy)] -pub struct GraphicsIntermediateStencil { - pub depth_write_enabled: bool, - pub depth_compare: wgpu::CompareFunction, - pub polygon_offset: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct GraphicsIntermediateUniformsBlend { - pub fog_color: glam::Vec4, - pub blend_color: glam::Vec4, -} - -impl GraphicsIntermediateUniformsBlend { - pub const EMPTY: Self = GraphicsIntermediateUniformsBlend { - fog_color: glam::Vec4::ZERO, - blend_color: glam::Vec4::ZERO, - }; -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct GraphicsIntermediateUniformsCombine { - pub prim_color: glam::Vec4, - pub env_color: glam::Vec4, - pub key_center: glam::Vec3, - pub key_scale: glam::Vec3, - pub prim_lod: glam::Vec2, - pub convert_k4: f32, - pub convert_k5: f32, -} - -impl GraphicsIntermediateUniformsCombine { - pub const EMPTY: Self = GraphicsIntermediateUniformsCombine { - prim_color: glam::Vec4::ZERO, - env_color: glam::Vec4::ZERO, - key_center: glam::Vec3::ZERO, - key_scale: glam::Vec3::ZERO, - prim_lod: glam::Vec2::ZERO, - convert_k4: 0.0, - convert_k5: 0.0, - }; -} - -#[derive(Debug, Clone, Copy)] -pub struct GraphicsIntermediateUniforms { - pub blend: GraphicsIntermediateUniformsBlend, - pub combine: GraphicsIntermediateUniformsCombine, -} - -impl GraphicsIntermediateUniforms { - pub const EMPTY: Self = GraphicsIntermediateUniforms { - blend: GraphicsIntermediateUniformsBlend::EMPTY, - combine: GraphicsIntermediateUniformsCombine::EMPTY, - }; -} - -#[derive(Debug, Clone)] -pub struct GraphicsIntermediateVBO { - pub vbo: Vec, - pub num_tris: usize, -} - -impl GraphicsIntermediateVBO { - pub const EMPTY: Self = GraphicsIntermediateVBO { - vbo: Vec::new(), - num_tris: 0, - }; -} - -#[derive(Debug, Clone)] -pub struct GraphicsIntermediateFogParams { - pub multiplier: i16, - pub offset: i16, -} - -impl GraphicsIntermediateFogParams { - pub const EMPTY: Self = GraphicsIntermediateFogParams { - multiplier: 0, - offset: 0, - }; -} - -#[derive(Debug, Clone)] -pub struct GraphicsDrawCall { - // Shader Configuration - pub other_mode_h: u32, - pub other_mode_l: u32, - pub geometry_mode: u32, - pub combine: CombineParams, - pub tile_descriptors: [TileDescriptor; NUM_TILE_DESCRIPTORS], - pub shader_hash: u64, - - // Textures - pub textures: [Option; 2], - - // Samplers - pub samplers: [Option; 2], - - // Stencil - pub stencil: Option, - - // Viewport - pub viewport: glam::Vec4, - - // Scissor - pub scissor: [u32; 4], - - // Blend State - pub blend_state: Option, - - // Cull Mode - pub cull_mode: Option, - - // Uniforms - pub uniforms: GraphicsIntermediateUniforms, - - // Triangle Data - pub vbo: GraphicsIntermediateVBO, - - // Projection Matrix - pub projection_matrix: glam::Mat4, - - // Fog Params - pub fog: GraphicsIntermediateFogParams, -} - -impl GraphicsDrawCall { - pub const EMPTY: Self = GraphicsDrawCall { - other_mode_h: 0, - other_mode_l: 0, - geometry_mode: 0, - combine: CombineParams::ZERO, - tile_descriptors: [TileDescriptor::EMPTY; NUM_TILE_DESCRIPTORS], - shader_hash: 0, - textures: [None; 2], - samplers: [None; 2], - stencil: None, - viewport: glam::Vec4::ZERO, - scissor: [0; 4], - blend_state: None, - cull_mode: None, - uniforms: GraphicsIntermediateUniforms::EMPTY, - vbo: GraphicsIntermediateVBO::EMPTY, - projection_matrix: glam::Mat4::ZERO, - fog: GraphicsIntermediateFogParams::EMPTY, - }; - - pub fn finalize(&mut self) { - // compute the shader hash and store it - let mut hasher = DefaultHasher::new(); - - self.other_mode_h.hash(&mut hasher); - self.other_mode_l.hash(&mut hasher); - self.geometry_mode.hash(&mut hasher); - self.combine.hash(&mut hasher); - - self.shader_hash = hasher.finish(); - } -} - -pub struct GraphicsIntermediateDevice { - pub texture_cache: TextureCache, - pub draw_calls: Vec, -} - -impl Default for GraphicsIntermediateDevice { - fn default() -> Self { - Self::new() - } -} - -impl GraphicsIntermediateDevice { - pub fn new() -> Self { - GraphicsIntermediateDevice { - texture_cache: TextureCache::new(TEXTURE_CACHE_MAX_SIZE), - // start draw calls with a default draw call - draw_calls: vec![GraphicsDrawCall::EMPTY], - } - } - - fn current_draw_call(&mut self) -> &mut GraphicsDrawCall { - self.draw_calls.last_mut().unwrap() - } - - fn new_draw_call(&mut self) { - let draw_call = self.current_draw_call(); - let draw_call = draw_call.clone(); - self.draw_calls.push(draw_call); - } - - // Public API - - pub fn clear_draw_calls(&mut self) { - let draw_call = self.current_draw_call(); - let draw_call = draw_call.clone(); - self.draw_calls = vec![draw_call]; - } - - pub fn clear_textures(&mut self, index: usize) { - let draw_call = self.current_draw_call(); - draw_call.textures[index] = None; - } - - pub fn set_program_params( - &mut self, - other_mode_h: u32, - other_mode_l: u32, - combine: CombineParams, - tile_descriptors: [TileDescriptor; NUM_TILE_DESCRIPTORS], - ) { - let draw_call = self.current_draw_call(); - draw_call.other_mode_h = other_mode_h; - draw_call.other_mode_l = other_mode_l; - draw_call.combine = combine; - draw_call.tile_descriptors = tile_descriptors; - } - - pub fn set_texture(&mut self, tile: usize, hash: u64) { - let draw_call = self.current_draw_call(); - draw_call.textures[tile] = Some(hash); - } - - pub fn set_sampler_parameters( - &mut self, - tile: usize, - linear_filter: bool, - clamp_s: u32, - clamp_t: u32, - ) { - let draw_call = self.current_draw_call(); - draw_call.samplers[tile] = Some(GraphicsIntermediateSampler { - tile, - linear_filter, - clamp_s, - clamp_t, - }); - } - - pub fn set_depth_stencil_params( - &mut self, - _depth_test_enabled: bool, - depth_write_enabled: bool, - depth_compare: wgpu::CompareFunction, - polygon_offset: bool, - ) { - let draw_call = self.current_draw_call(); - draw_call.stencil = Some(GraphicsIntermediateStencil { - depth_write_enabled, - depth_compare, - polygon_offset, - }); - } - - pub fn set_projection_matrix(&mut self, matrix: glam::Mat4) { - let draw_call = self.current_draw_call(); - draw_call.projection_matrix = matrix; - } - - pub fn set_fog(&mut self, multiplier: i16, offset: i16) { - let draw_call = self.current_draw_call(); - draw_call.fog = GraphicsIntermediateFogParams { multiplier, offset }; - } - - pub fn set_viewport(&mut self, x: f32, y: f32, width: f32, height: f32) { - let draw_call = self.current_draw_call(); - draw_call.viewport = glam::Vec4::new(x, y, width, height); - } - - pub fn set_scissor(&mut self, x: u32, y: u32, width: u32, height: u32) { - let draw_call = self.current_draw_call(); - draw_call.scissor = [x, y, width, height]; - } - - pub fn set_blend_state(&mut self, blend_state: Option) { - let draw_call = self.current_draw_call(); - draw_call.blend_state = blend_state; - } - - pub fn set_cull_mode(&mut self, cull_mode: Option) { - let draw_call = self.current_draw_call(); - draw_call.cull_mode = cull_mode; - } - - pub fn set_uniforms( - &mut self, - fog_color: glam::Vec4, - blend_color: glam::Vec4, - prim_color: glam::Vec4, - env_color: glam::Vec4, - key_center: glam::Vec3, - key_scale: glam::Vec3, - prim_lod: glam::Vec2, - convert_k: [i32; 6], - ) { - let draw_call = self.current_draw_call(); - draw_call.uniforms = GraphicsIntermediateUniforms { - blend: GraphicsIntermediateUniformsBlend { - fog_color, - blend_color, - }, - combine: GraphicsIntermediateUniformsCombine { - prim_color, - env_color, - key_center, - key_scale, - prim_lod, - convert_k4: convert_k[4] as f32 / 255.0, - convert_k5: convert_k[5] as f32 / 255.0, - }, - }; - } - - pub fn set_vbo(&mut self, vbo: Vec, num_tris: usize) { - let draw_call = self.current_draw_call(); - draw_call.vbo = GraphicsIntermediateVBO { vbo, num_tris }; - draw_call.finalize(); - - // start a new draw call that's a copy of the current one - // we do this cause atm we only set properties on changes - self.new_draw_call(); - } -} diff --git a/src/fast3d/rcp.rs b/src/fast3d/rcp.rs deleted file mode 100644 index 31e5eff..0000000 --- a/src/fast3d/rcp.rs +++ /dev/null @@ -1,68 +0,0 @@ -use log::trace; - -use super::{ - gbi::{defines::Gfx, GBIResult, GBI}, - graphics::GraphicsIntermediateDevice, - rdp::RDP, - rsp::RSP, -}; - -pub struct RCP { - gbi: GBI, - pub rdp: RDP, - pub rsp: RSP, -} - -impl Default for RCP { - fn default() -> Self { - Self::new() - } -} - -impl RCP { - pub fn new() -> Self { - let mut gbi = GBI::default(); - gbi.setup(); - - RCP { - gbi, - rdp: RDP::default(), - rsp: RSP::default(), - } - } - - pub fn reset(&mut self) { - self.rdp.reset(); - self.rsp.reset(); - } - - /// This funtion is called to process a work buffer. - /// It takes in a pointer to the start of the work buffer and will - /// process until it hits a `G_ENDDL` inidicating the end. - pub fn run(&mut self, gfx_device: &mut GraphicsIntermediateDevice, commands: usize) { - self.reset(); - - self.run_dl(gfx_device, commands); - self.rdp.flush(gfx_device); - } - - fn run_dl(&mut self, gfx_device: &mut GraphicsIntermediateDevice, commands: usize) { - let mut command = commands as *mut Gfx; - - loop { - match self - .gbi - .handle_command(&mut self.rdp, &mut self.rsp, gfx_device, &mut command) - { - GBIResult::Recurse(new_command) => self.run_dl(gfx_device, new_command), - GBIResult::Unknown(opcode) => { - trace!("Unknown GBI command: {:#x}", opcode) - } - GBIResult::Return => return, - GBIResult::Continue => {} - } - - unsafe { command = command.add(1) }; - } - } -} diff --git a/src/fast3d/rdp.rs b/src/fast3d/rdp.rs deleted file mode 100644 index 6d8bc18..0000000 --- a/src/fast3d/rdp.rs +++ /dev/null @@ -1,669 +0,0 @@ -use std::collections::hash_map::DefaultHasher; -use std::collections::HashMap; -use std::hash::{Hash, Hasher}; - -use glam::{Vec2, Vec3, Vec4}; -use log::trace; -use wgpu::{BlendState, CompareFunction}; - -use crate::fast3d::gbi::utils::{other_mode_l_uses_alpha, other_mode_l_uses_texture_edge}; - -use super::graphics::GraphicsIntermediateDevice; -use super::utils::color::Color; -use super::utils::texture::RenderingStateTexture; -use super::{ - gbi::{ - defines::Viewport, - utils::{ - get_cycle_type_from_other_mode_h, get_textfilter_from_other_mode_h, translate_cull_mode, - }, - }, - rsp::RSPGeometry, - utils::{ - color_combiner::CombineParams, - texture::{ - translate_tile_ci4, translate_tile_ci8, translate_tile_i4, translate_tile_i8, - translate_tile_ia16, translate_tile_ia4, translate_tile_ia8, translate_tile_rgba16, - translate_tile_rgba32, translate_tlut, ImageFormat, ImageSize, TextFilt, - TextureImageState, TextureLUT, TextureState, - }, - tile_descriptor::TileDescriptor, - }, -}; - -use farbe::image::n64::ImageSize as FarbeImageSize; - -pub const SCREEN_WIDTH: f32 = 320.0; -pub const SCREEN_HEIGHT: f32 = 240.0; -const MAX_VBO_SIZE: usize = 256; -const MAX_TEXTURE_SIZE: usize = 4096; -pub const NUM_TILE_DESCRIPTORS: usize = 8; -pub const MAX_BUFFERED: usize = 256 * 4; - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Rect { - pub x: u16, - pub y: u16, - pub width: u16, - pub height: u16, -} - -impl Rect { - pub const ZERO: Self = Self { - x: 0, - y: 0, - width: 0, - height: 0, - }; - - pub fn new(x: u16, y: u16, width: u16, height: u16) -> Self { - Self { - x, - y, - width, - height, - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct OutputDimensions { - pub width: u32, - pub height: u32, - pub aspect_ratio: f32, -} - -impl OutputDimensions { - pub const ZERO: Self = Self { - width: 0, - height: 0, - aspect_ratio: 0.0, - }; -} - -pub struct RenderingState { - pub depth_compare: CompareFunction, - pub depth_test: bool, - pub depth_write: bool, - pub polygon_offset: bool, - pub blend_enabled: bool, - pub blend_state: BlendState, - pub viewport: Rect, - pub scissor: Rect, - pub shader_program_hash: u64, - pub textures: [RenderingStateTexture; 2], - pub cull_mode: Option, - pub blend_color: Color, -} - -impl RenderingState { - pub const EMPTY: Self = Self { - depth_compare: CompareFunction::Always, - depth_test: false, - depth_write: false, - polygon_offset: false, - blend_enabled: false, - blend_state: BlendState::REPLACE, - viewport: Rect::ZERO, - scissor: Rect::ZERO, - shader_program_hash: 0, - textures: [RenderingStateTexture::EMPTY; 2], - cull_mode: None, - blend_color: Color::TRANSPARENT, - }; -} - -pub enum OtherModeLayoutL { - // non-render-mode fields - G_MDSFT_ALPHACOMPARE = 0, - G_MDSFT_ZSRCSEL = 2, - // cycle-independent render-mode bits - AA_EN = 3, - Z_CMP = 4, - Z_UPD = 5, - IM_RD = 6, - CLR_ON_CVG = 7, - CVG_DST = 8, - ZMODE = 10, - CVG_X_ALPHA = 12, - ALPHA_CVG_SEL = 13, - FORCE_BL = 14, - // bit 15 unused, was "TEX_EDGE" - // cycle-dependent render-mode bits - B_2 = 16, - B_1 = 18, - M_2 = 20, - M_1 = 22, - A_2 = 24, - A_1 = 26, - P_2 = 28, - P_1 = 30, -} - -pub enum OtherModeH_Layout { - G_MDSFT_BLENDMASK = 0, - G_MDSFT_ALPHADITHER = 4, - G_MDSFT_RGBDITHER = 6, - G_MDSFT_COMBKEY = 8, - G_MDSFT_TEXTCONV = 9, - G_MDSFT_TEXTFILT = 12, - G_MDSFT_TEXTLUT = 14, - G_MDSFT_TEXTLOD = 16, - G_MDSFT_TEXTDETAIL = 17, - G_MDSFT_TEXTPERSP = 19, - G_MDSFT_CYCLETYPE = 20, - G_MDSFT_COLORDITHER = 22, - G_MDSFT_PIPELINE = 23, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum OtherModeHCycleType { - G_CYC_1CYCLE = 0, - G_CYC_2CYCLE = 1, - G_CYC_COPY = 2, - G_CYC_FILL = 3, -} - -enum ZMode { - ZMODE_OPA = 0, - ZMODE_INTER = 1, - ZMODE_XLU = 2, // translucent - ZMODE_DEC = 3, -} - -pub enum BlendParamPMColor { - G_BL_CLR_IN = 0, - G_BL_CLR_MEM = 1, - G_BL_CLR_BL = 2, - G_BL_CLR_FOG = 3, -} - -enum BlendParamA { - G_BL_A_IN = 0, - G_BL_A_FOG = 1, - G_BL_A_SHADE = 2, - G_BL_0 = 3, -} - -pub enum BlendParamB { - G_BL_1MA = 0, - G_BL_A_MEM = 1, - G_BL_1 = 2, - G_BL_0 = 3, -} - -pub enum AlphaCompare { - G_AC_NONE = 0, - G_AC_THRESHOLD = 1, - G_AC_DITHER = 3, -} - -pub struct TMEMMapEntry { - pub address: usize, -} - -impl TMEMMapEntry { - pub fn new(address: usize) -> Self { - Self { address } - } -} - -pub struct RDP { - pub output_dimensions: OutputDimensions, - pub rendering_state: RenderingState, - - pub texture_state: TextureState, - pub texture_image_state: TextureImageState, // coming via GBI (texture to load) - pub tile_descriptors: [TileDescriptor; NUM_TILE_DESCRIPTORS], - pub tmem_map: HashMap, // tmem address -> texture image state address - pub textures_changed: [bool; 2], - - pub viewport: Rect, - pub scissor: Rect, - pub viewport_or_scissor_changed: bool, - - pub combine: CombineParams, - pub other_mode_l: u32, - pub other_mode_h: u32, - pub shader_config_changed: bool, - - pub buf_vbo: [f32; MAX_VBO_SIZE * (26 * 3)], // 3 vertices in a triangle and 26 floats per vtx - pub buf_vbo_len: usize, - pub buf_vbo_num_tris: usize, - - pub env_color: Vec4, - pub fog_color: Vec4, - pub prim_color: Vec4, - pub blend_color: Vec4, - pub fill_color: Color, - - pub prim_lod: Vec2, - - pub convert_k: [i32; 6], - pub key_center: Vec3, - pub key_scale: Vec3, - - pub depth_image: usize, - pub color_image: usize, -} - -impl Default for RDP { - fn default() -> Self { - Self::new() - } -} - -impl RDP { - pub fn new() -> Self { - RDP { - output_dimensions: OutputDimensions::ZERO, - rendering_state: RenderingState::EMPTY, - - texture_state: TextureState::EMPTY, - texture_image_state: TextureImageState::EMPTY, - tile_descriptors: [TileDescriptor::EMPTY; 8], - tmem_map: HashMap::new(), - textures_changed: [false; 2], - - viewport: Rect::ZERO, - scissor: Rect::ZERO, - viewport_or_scissor_changed: false, - - combine: CombineParams::ZERO, - other_mode_l: 0, - other_mode_h: 0, - shader_config_changed: false, - - buf_vbo: [0.0; MAX_VBO_SIZE * (26 * 3)], - buf_vbo_len: 0, - buf_vbo_num_tris: 0, - - env_color: Vec4::ZERO, - fog_color: Vec4::ZERO, - prim_color: Vec4::ZERO, - blend_color: Vec4::ZERO, - fill_color: Color::TRANSPARENT, - - prim_lod: Vec2::ZERO, - - convert_k: [0; 6], - key_center: Vec3::ZERO, - key_scale: Vec3::ZERO, - - depth_image: 0, - color_image: 0, - } - } - - pub fn reset(&mut self) { - self.combine = CombineParams::ZERO; - self.other_mode_l = 0; - self.other_mode_h = 0; - self.env_color = Vec4::ZERO; - self.fog_color = Vec4::ZERO; - self.prim_color = Vec4::ZERO; - self.blend_color = Vec4::ZERO; - self.fill_color = Color::TRANSPARENT; - self.prim_lod = Vec2::ZERO; - self.key_center = Vec3::ZERO; - self.key_scale = Vec3::ZERO; - self.convert_k = [0; 6]; - } - - // Viewport - - pub fn calculate_and_set_viewport(&mut self, viewport: Viewport) { - let mut width = 2.0 * viewport.vscale[0] as f32 / 4.0; - let mut height = 2.0 * viewport.vscale[1] as f32 / 4.0; - let mut x = viewport.vtrans[0] as f32 / 4.0 - width / 2.0; - let mut y = SCREEN_HEIGHT - ((viewport.vtrans[1] as f32 / 4.0) + height / 2.0); - - width *= self.scaled_x(); - height *= self.scaled_y(); - x *= self.scaled_x(); - y *= self.scaled_y(); - - self.viewport.x = x as u16; - self.viewport.y = y as u16; - self.viewport.width = width as u16; - self.viewport.height = height as u16; - - self.viewport_or_scissor_changed = true; - } - - pub fn adjust_x_for_viewport(&self, x: f32) -> f32 { - x * (4.0 / 3.0) - / (self.output_dimensions.width as f32 / self.output_dimensions.height as f32) - } - - // Textures - - pub fn import_tile_texture( - &mut self, - gfx_device: &mut GraphicsIntermediateDevice, - tmem_index: usize, - ) { - let tile = self.tile_descriptors[self.texture_state.tile as usize]; - let format = tile.format as u32; - let size = tile.size as u32; - let width = tile.get_width() as u32; - let height = tile.get_height() as u32; - - let tmap_entry = self.tmem_map.get(&tile.tmem).unwrap(); - let texture_address = tmap_entry.address; - - if let Some(hash) = - gfx_device - .texture_cache - .contains(texture_address, tile.format, tile.size) - { - gfx_device.set_texture(tmem_index, hash); - return; - } - - // TODO: figure out how to find the size of bytes in the texture - let texture_data = unsafe { - std::slice::from_raw_parts(texture_address as *const u8, MAX_TEXTURE_SIZE * 4) - }; - - let texture = match (format << 4) | size { - x if x - == ((ImageFormat::G_IM_FMT_RGBA as u32) << 4 | ImageSize::G_IM_SIZ_16b as u32) => - { - translate_tile_rgba16(texture_data, width, height) - } - x if x - == ((ImageFormat::G_IM_FMT_RGBA as u32) << 4 | ImageSize::G_IM_SIZ_32b as u32) => - { - translate_tile_rgba32(texture_data, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_IA as u32) << 4 | ImageSize::G_IM_SIZ_4b as u32) => { - translate_tile_ia4(texture_data, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_IA as u32) << 4 | ImageSize::G_IM_SIZ_8b as u32) => { - translate_tile_ia8(texture_data, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_IA as u32) << 4 | ImageSize::G_IM_SIZ_16b as u32) => { - translate_tile_ia16(texture_data, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_I as u32) << 4 | ImageSize::G_IM_SIZ_4b as u32) => { - translate_tile_i4(texture_data, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_I as u32) << 4 | ImageSize::G_IM_SIZ_8b as u32) => { - translate_tile_i8(texture_data, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_CI as u32) << 4 | ImageSize::G_IM_SIZ_4b as u32) => { - let pal_addr = self - .tmem_map - .get(&(u16::MAX - tmem_index as u16)) - .unwrap() - .address; - let texlut: TextureLUT = TextureLUT::from_u32((self.other_mode_h >> 14) & 0x3); - let palette = translate_tlut(pal_addr, FarbeImageSize::S4B, &texlut); - translate_tile_ci4(texture_data, &palette, width, height) - } - x if x == ((ImageFormat::G_IM_FMT_CI as u32) << 4 | ImageSize::G_IM_SIZ_8b as u32) => { - let pal_addr = self - .tmem_map - .get(&(u16::MAX - tmem_index as u16)) - .unwrap() - .address; - let texlut: TextureLUT = TextureLUT::from_u32((self.other_mode_h >> 14) & 0x3); - let palette = translate_tlut(pal_addr, FarbeImageSize::S8B, &texlut); - translate_tile_ci8(texture_data, &palette, width, height) - } - _ => { - // TODO: Create an empty texture? - panic!("Unsupported texture format: {:?} {:?}", format, size); - } - }; - - let hash = gfx_device.texture_cache.insert( - texture_address, - tile.format, - tile.size, - width, - height, - texture, - ); - gfx_device.set_texture(tmem_index, hash); - } - - pub fn uses_texture1(&self) -> bool { - get_cycle_type_from_other_mode_h(self.other_mode_h) == OtherModeHCycleType::G_CYC_2CYCLE - && self.combine.uses_texture1() - } - - pub fn flush_textures(&mut self, gfx_device: &mut GraphicsIntermediateDevice) { - // if textures are not on, then we have no textures to flush - // if !self.texture_state.on { - // return; - // } - - let lod_en = (self.other_mode_h >> 16 & 0x1) != 0; - if lod_en { - // TODO: Support mip-mapping - trace!("Mip-mapping is enabled, but not supported yet"); - assert!(false); - } else { - // we're in TILE mode. Let's check if we're in two-cycle mode. - // let cycle_type = RDP::get_cycle_type_from_other_mode_h(self.other_mode_h); - // assert!( - // cycle_type == OtherModeHCycleType::G_CYC_1CYCLE - // || cycle_type == OtherModeHCycleType::G_CYC_2CYCLE - // ); - - for i in 0..2 { - if i == 0 || self.uses_texture1() { - if self.textures_changed[i as usize] { - self.flush(gfx_device); - gfx_device.clear_textures(i as usize); - - self.import_tile_texture(gfx_device, i as usize); - self.textures_changed[i as usize] = false; - } - - let tile_descriptor = - self.tile_descriptors[(self.texture_state.tile + i) as usize]; - let linear_filter = - get_textfilter_from_other_mode_h(self.other_mode_h) != TextFilt::G_TF_POINT; - let texture = self.rendering_state.textures[i as usize]; - if linear_filter != texture.linear_filter - || tile_descriptor.cm_s != texture.cms - || tile_descriptor.cm_t != texture.cmt - { - gfx_device.set_sampler_parameters( - i as usize, - linear_filter, - tile_descriptor.cm_s as u32, - tile_descriptor.cm_t as u32, - ); - self.rendering_state.textures[i as usize].linear_filter = linear_filter; - self.rendering_state.textures[i as usize].cms = tile_descriptor.cm_s; - self.rendering_state.textures[i as usize].cmt = tile_descriptor.cm_t; - } - } - } - } - } - - pub fn flush(&mut self, gfx_device: &mut GraphicsIntermediateDevice) { - if self.buf_vbo_len > 0 { - let vbo = bytemuck::cast_slice(&self.buf_vbo[..self.buf_vbo_len]); - gfx_device.set_vbo(vbo.to_vec(), self.buf_vbo_num_tris); - self.buf_vbo_len = 0; - self.buf_vbo_num_tris = 0; - } - } - - // MARK: - Shader Programs - - pub fn shader_program_hash(&mut self, geometry_mode: u32) -> u64 { - let mut hasher = DefaultHasher::new(); - - self.other_mode_h.hash(&mut hasher); - self.other_mode_l.hash(&mut hasher); - geometry_mode.hash(&mut hasher); - self.combine.hash(&mut hasher); - - hasher.finish() - } - - // MARK: - Blend - - fn process_depth_params( - &mut self, - gfx_device: &mut GraphicsIntermediateDevice, - geometry_mode: u32, - render_mode: u32, - ) { - let depth_test = geometry_mode & RSPGeometry::G_ZBUFFER as u32 != 0; - if depth_test != self.rendering_state.depth_test { - self.flush(gfx_device); - self.rendering_state.depth_test = depth_test; - } - - let zmode: u32 = self.other_mode_l >> (OtherModeLayoutL::ZMODE as u32) & 0x03; - - // handle depth compare - let depth_compare = if self.other_mode_l & (1 << OtherModeLayoutL::Z_CMP as u32) != 0 { - let depth_compare = match zmode { - x if x == ZMode::ZMODE_OPA as u32 => CompareFunction::Less, - x if x == ZMode::ZMODE_INTER as u32 => CompareFunction::Less, // TODO: Understand this - x if x == ZMode::ZMODE_XLU as u32 => CompareFunction::Less, - x if x == ZMode::ZMODE_DEC as u32 => CompareFunction::LessEqual, - _ => panic!("Unknown ZMode"), - }; - - if depth_compare != self.rendering_state.depth_compare { - self.flush(gfx_device); - self.rendering_state.depth_compare = depth_compare; - } - - depth_compare - } else { - if self.rendering_state.depth_compare != CompareFunction::Always { - self.flush(gfx_device); - self.rendering_state.depth_compare = CompareFunction::Always; - } - - CompareFunction::Always - }; - - // handle depth write - let depth_write = render_mode & (1 << OtherModeLayoutL::Z_UPD as u32) != 0; - if depth_write != self.rendering_state.depth_write { - self.flush(gfx_device); - self.rendering_state.depth_write = depth_write; - } - - // handle polygon offset (slope scale depth bias) - let polygon_offset = zmode == ZMode::ZMODE_DEC as u32; - if polygon_offset != self.rendering_state.polygon_offset { - self.flush(gfx_device); - self.rendering_state.polygon_offset = polygon_offset; - } - - gfx_device.set_depth_stencil_params(depth_test, depth_write, depth_compare, polygon_offset); - } - - pub fn update_render_state( - &mut self, - gfx_device: &mut GraphicsIntermediateDevice, - geometry_mode: u32, - ) { - let cull_mode = translate_cull_mode(geometry_mode); - if cull_mode != self.rendering_state.cull_mode { - self.flush(gfx_device); - gfx_device.set_cull_mode(cull_mode); - self.rendering_state.cull_mode = cull_mode; - } - - self.process_depth_params(gfx_device, geometry_mode, self.other_mode_l); - - // handle alpha blending - let do_blend = other_mode_l_uses_alpha(self.other_mode_l) - || other_mode_l_uses_texture_edge(self.other_mode_l); - - if do_blend != self.rendering_state.blend_enabled { - let blend_state = if do_blend { - Some(BlendState::ALPHA_BLENDING) - } else { - None - }; - - self.flush(gfx_device); - gfx_device.set_blend_state(blend_state); - self.rendering_state.blend_enabled = do_blend; - } - - // handle viewport and scissor - if self.viewport_or_scissor_changed { - let viewport = self.viewport; - if viewport != self.rendering_state.viewport { - self.flush(gfx_device); - gfx_device.set_viewport( - viewport.x as f32, - viewport.y as f32, - viewport.width as f32, - viewport.height as f32, - ); - self.rendering_state.viewport = viewport; - } - let scissor = self.scissor; - if scissor != self.rendering_state.scissor { - self.flush(gfx_device); - gfx_device.set_scissor( - scissor.x as u32, - scissor.y as u32, - scissor.width as u32, - scissor.height as u32, - ); - self.rendering_state.scissor = scissor; - } - self.viewport_or_scissor_changed = false; - } - } - - // MARK: - Setters - - pub fn set_convert(&mut self, k0: i32, k1: i32, k2: i32, k3: i32, k4: i32, k5: i32) { - self.convert_k[0] = k0; - self.convert_k[1] = k1; - self.convert_k[2] = k2; - self.convert_k[3] = k3; - self.convert_k[4] = k4; - self.convert_k[5] = k5; - } - - pub fn set_key_r(&mut self, cr: u32, sr: u32, _wr: u32) { - // TODO: Figure out how to use width - self.key_center.x = cr as f32 / 255.0; - self.key_scale.x = sr as f32 / 255.0; - } - - pub fn set_key_gb(&mut self, cg: u32, sg: u32, _wg: u32, cb: u32, sb: u32, _wb: u32) { - // TODO: Figure out how to use width - self.key_center.y = cg as f32 / 255.0; - self.key_center.z = cb as f32 / 255.0; - self.key_scale.y = sg as f32 / 255.0; - self.key_scale.z = sb as f32 / 255.0; - } - - // MARK: - Helpers - - pub fn scaled_x(&self) -> f32 { - self.output_dimensions.width as f32 / SCREEN_WIDTH - } - - pub fn scaled_y(&self) -> f32 { - self.output_dimensions.height as f32 / SCREEN_HEIGHT - } - - pub fn add_to_buf_vbo(&mut self, data: f32) { - self.buf_vbo[self.buf_vbo_len] = data; - self.buf_vbo_len += 1; - } -} diff --git a/src/fast3d/rsp.rs b/src/fast3d/rsp.rs deleted file mode 100644 index 8975473..0000000 --- a/src/fast3d/rsp.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::fast3d::gbi::defines::DirLight; - -use super::{gbi::defines::Light, utils::color::Color}; -use glam::{Mat4, Vec2, Vec3A}; - -pub const MATRIX_STACK_SIZE: usize = 32; -pub const MAX_VERTICES: usize = 256; -pub const MAX_LIGHTS: usize = 7; -pub const MAX_SEGMENTS: usize = 16; - -#[repr(C)] -pub struct Position { - pub x: f32, - pub y: f32, - pub z: f32, - pub w: f32, -} - -impl Position { - pub const ZERO: Self = Self { - x: 0.0, - y: 0.0, - z: 0.0, - w: 0.0, - }; -} - -#[repr(C)] -pub struct StagingVertex { - pub position: Position, - pub uv: Vec2, - pub color: Color, - pub clip_reject: u8, -} - -impl StagingVertex { - pub const ZERO: Self = Self { - position: Position::ZERO, - uv: Vec2::ZERO, - color: Color::TRANSPARENT, - clip_reject: 0, - }; -} - -#[cfg(feature = "f3dex2")] -pub enum RSPGeometry { - G_ZBUFFER = 1 << 0, - G_SHADE = 1 << 2, - G_TEXTURE_ENABLE = 0, - G_SHADING_SMOOTH = 1 << 21, - G_CULL_FRONT = 1 << 9, - G_CULL_BACK = 1 << 10, - G_CULL_BOTH = Self::G_CULL_FRONT as isize | Self::G_CULL_BACK as isize, - G_FOG = 1 << 16, - G_LIGHTING = 1 << 17, - G_TEXTURE_GEN = 1 << 18, - G_TEXTURE_GEN_LINEAR = 1 << 19, - G_LOD = 1 << 20, /* NOT IMPLEMENTED */ - G_CLIPPING = 1 << 23, -} - -pub struct RSP { - pub geometry_mode: u32, - pub projection_matrix: Mat4, - - pub matrix_stack: [Mat4; MATRIX_STACK_SIZE], - pub matrix_stack_pointer: usize, - - pub modelview_projection_matrix: Mat4, - pub modelview_projection_matrix_changed: bool, - - pub lights_valid: bool, - pub num_lights: u8, - pub lights: [Light; MAX_LIGHTS + 1], - pub lookat: [Vec3A; 2], // lookat_x, lookat_y - - pub fog_multiplier: i16, - pub fog_offset: i16, - pub fog_changed: bool, - - pub vertex_table: [StagingVertex; MAX_VERTICES + 4], - - pub lights_coeffs: [Vec3A; MAX_LIGHTS], - pub lookat_coeffs: [Vec3A; 2], // lookat_x, lookat_y - - pub segments: [usize; MAX_SEGMENTS], -} - -impl Default for RSP { - fn default() -> Self { - Self::new() - } -} - -impl RSP { - pub fn new() -> Self { - RSP { - geometry_mode: 0, - projection_matrix: Mat4::ZERO, - - matrix_stack: [Mat4::ZERO; MATRIX_STACK_SIZE], - matrix_stack_pointer: 0, - - modelview_projection_matrix: Mat4::ZERO, - modelview_projection_matrix_changed: false, - - lights_valid: true, - num_lights: 0, - lights: [Light::ZERO; MAX_LIGHTS + 1], - lookat: [Vec3A::ZERO; 2], - - fog_multiplier: 0, - fog_offset: 0, - fog_changed: false, - - vertex_table: [StagingVertex::ZERO; MAX_VERTICES + 4], - - lights_coeffs: [Vec3A::ZERO; MAX_LIGHTS], - lookat_coeffs: [Vec3A::ZERO; 2], - - segments: [0; MAX_SEGMENTS], - } - } - - pub fn reset(&mut self) { - self.matrix_stack_pointer = 1; - self.set_num_lights(1); - } - - pub fn recompute_mvp_matrix(&mut self) { - self.modelview_projection_matrix = - self.matrix_stack[self.matrix_stack_pointer - 1] * self.projection_matrix; - } - - pub fn set_num_lights(&mut self, num_lights: u8) { - self.num_lights = num_lights; - self.lights_valid = false; - } - - pub fn set_segment(&mut self, segment: usize, address: usize) { - assert!(segment < MAX_SEGMENTS); - self.segments[segment] = address; - } - - pub fn set_fog(&mut self, multiplier: i16, offset: i16) { - self.fog_multiplier = multiplier; - self.fog_offset = offset; - } - - pub fn set_light_color(&mut self, index: usize, value: u32) { - assert!(index <= MAX_LIGHTS); - - let light = &mut self.lights[index]; - unsafe { - light.raw.words[0] = value; - } - unsafe { - light.raw.words[1] = value; - } - self.lights_valid = false; - } - - pub fn from_segmented(&self, address: usize) -> usize { - let segment = (address >> 24) & 0x0F; - let offset = address & 0x00FFFFFF; - - if self.segments[segment] != 0 { - self.segments[segment] + offset - } else { - address - } - } - - pub fn set_clip_ratio(&mut self, _ratio: usize) { - // TODO: implement - } - - pub fn set_persp_norm(&mut self, _norm: usize) { - // TODO: implement - } - - pub fn set_light(&mut self, index: usize, address: usize) { - assert!(index <= MAX_LIGHTS); - - let data = self.from_segmented(address); - let light_ptr = data as *const Light; - let light = unsafe { &*light_ptr }; - - self.lights[index] = *light; - - self.lights_valid = false; - } - - pub fn set_look_at(&mut self, index: usize, address: usize) { - assert!(index < 2); - let data = self.from_segmented(address); - let dir_light_ptr = data as *const DirLight; - let dir_light = unsafe { &*dir_light_ptr }; - - let lookat = if index == 0 { - &mut self.lookat[0] - } else { - &mut self.lookat[1] - }; - if dir_light.dir[0] != 0 || dir_light.dir[1] != 0 || dir_light.dir[2] != 0 { - *lookat = Vec3A::new( - dir_light.dir[0] as f32, - dir_light.dir[1] as f32, - dir_light.dir[2] as f32, - ) - .normalize(); - } else { - *lookat = Vec3A::ZERO; - } - } -} diff --git a/src/fast3d/utils.rs b/src/fast3d/utils.rs deleted file mode 100644 index 3d35194..0000000 --- a/src/fast3d/utils.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod color; -pub mod color_combiner; -pub mod texture; -pub mod texture_cache; -pub mod tile_descriptor; diff --git a/src/fast3d/utils/color.rs b/src/fast3d/utils/color.rs deleted file mode 100644 index 2f35964..0000000 --- a/src/fast3d/utils/color.rs +++ /dev/null @@ -1,43 +0,0 @@ -use glam::Vec4; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Color { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} - -impl Color { - pub const TRANSPARENT: Color = Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 0.0, - }; - - #[inline] - pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color { - Color { r, g, b, a } - } -} - -impl From for Vec4 { - fn from(c: Color) -> Self { - Self::new(c.r, c.g, c.b, c.a) - } -} - -pub struct R5G5B5A1 {} - -impl R5G5B5A1 { - #[inline] - pub fn to_rgba(pixel: u16) -> Color { - let r = ((pixel & 0xF800) >> 11) as u8; - let g = ((pixel & 0x07C0) >> 6) as u8; - let b = ((pixel & 0x003E) >> 1) as u8; - let a = (pixel & 0x01) as u8; - - Color::new(r as f32 / 31.0, g as f32 / 31.0, b as f32 / 31.0, a as f32) - } -} diff --git a/src/fast3d/utils/color_combiner.rs b/src/fast3d/utils/color_combiner.rs deleted file mode 100644 index c171e40..0000000 --- a/src/fast3d/utils/color_combiner.rs +++ /dev/null @@ -1,293 +0,0 @@ -use crate::fast3d::gbi::utils::get_cmd; - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ColorCombinePass { - pub a: CCMUX, - pub b: CCMUX, - pub c: CCMUX, - pub d: CCMUX, -} - -impl ColorCombinePass { - // grab property by index - pub fn get(&self, index: usize) -> CCMUX { - match index { - 0 => self.a, - 1 => self.b, - 2 => self.c, - 3 => self.d, - _ => panic!("Invalid index"), - } - } - - pub fn uses_texture0(&self) -> bool { - self.a == CCMUX::TEXEL0 - || self.a == CCMUX::TEXEL0_ALPHA - || self.b == CCMUX::TEXEL0 - || self.b == CCMUX::TEXEL0_ALPHA - || self.c == CCMUX::TEXEL0 - || self.c == CCMUX::TEXEL0_ALPHA - || self.d == CCMUX::TEXEL0 - || self.d == CCMUX::TEXEL0_ALPHA - } - - pub fn uses_texture1(&self) -> bool { - self.a == CCMUX::TEXEL1 - || self.a == CCMUX::TEXEL1_ALPHA - || self.b == CCMUX::TEXEL1 - || self.b == CCMUX::TEXEL1_ALPHA - || self.c == CCMUX::TEXEL1 - || self.c == CCMUX::TEXEL1_ALPHA - || self.d == CCMUX::TEXEL1 - || self.d == CCMUX::TEXEL1_ALPHA - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AlphaCombinePass { - pub a: ACMUX, - pub b: ACMUX, - pub c: ACMUX, - pub d: ACMUX, -} - -impl AlphaCombinePass { - // grab property by index - pub fn get(&self, index: usize) -> ACMUX { - match index { - 0 => self.a, - 1 => self.b, - 2 => self.c, - 3 => self.d, - _ => panic!("Invalid index"), - } - } - - pub fn uses_texture0(&self) -> bool { - self.a == ACMUX::TEXEL0 - || self.b == ACMUX::TEXEL0 - || self.c == ACMUX::TEXEL0 - || self.d == ACMUX::TEXEL0 - } - - pub fn uses_texture1(&self) -> bool { - self.a == ACMUX::TEXEL1 - || self.b == ACMUX::TEXEL1 - || self.c == ACMUX::TEXEL1 - || self.d == ACMUX::TEXEL1 - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CombineParams { - pub c0: ColorCombinePass, - pub a0: AlphaCombinePass, - pub c1: ColorCombinePass, - pub a1: AlphaCombinePass, -} - -impl CombineParams { - pub const ZERO: Self = Self { - c0: ColorCombinePass { - a: CCMUX::COMBINED, - b: CCMUX::TEXEL0, - c: CCMUX::PRIMITIVE, - d: CCMUX::COMBINED, - }, - a0: AlphaCombinePass { - a: ACMUX::COMBINED__LOD_FRAC, - b: ACMUX::TEXEL0, - c: ACMUX::PRIMITIVE, - d: ACMUX::COMBINED__LOD_FRAC, - }, - c1: ColorCombinePass { - a: CCMUX::COMBINED, - b: CCMUX::TEXEL0, - c: CCMUX::PRIMITIVE, - d: CCMUX::COMBINED, - }, - a1: AlphaCombinePass { - a: ACMUX::COMBINED__LOD_FRAC, - b: ACMUX::TEXEL0, - c: ACMUX::PRIMITIVE, - d: ACMUX::COMBINED__LOD_FRAC, - }, - }; - - pub fn decode(w0: usize, w1: usize) -> Self { - let a0 = (get_cmd(w0, 20, 4) & 0xF) as u8; - let b0 = (get_cmd(w1, 28, 4) & 0xF) as u8; - let c0 = (get_cmd(w0, 15, 5) & 0x1F) as u8; - let d0 = (get_cmd(w1, 15, 3) & 0x7) as u8; - - let aa0 = (get_cmd(w0, 12, 3) & 0x7) as u8; - let ab0 = (get_cmd(w1, 12, 3) & 0x7) as u8; - let ac0 = (get_cmd(w0, 9, 3) & 0x7) as u8; - let ad0 = (get_cmd(w1, 9, 3) & 0x7) as u8; - - let a1 = (get_cmd(w0, 5, 4) & 0xF) as u8; - let b1 = (get_cmd(w1, 24, 4) & 0xF) as u8; - let c1 = (get_cmd(w0, 0, 5) & 0x1F) as u8; - let d1 = (get_cmd(w1, 6, 3) & 0x7) as u8; - - let aa1 = (get_cmd(w1, 21, 3) & 0x7) as u8; - let ab1 = (get_cmd(w1, 3, 3) & 0x7) as u8; - let ac1 = (get_cmd(w1, 18, 3) & 0x7) as u8; - let ad1 = (get_cmd(w1, 0, 3) & 0x7) as u8; - - Self { - c0: ColorCombinePass { - a: CCMUX::from(a0), - b: CCMUX::from(b0), - c: CCMUX::from(c0), - d: CCMUX::from(d0), - }, - a0: AlphaCombinePass { - a: ACMUX::from(aa0), - b: ACMUX::from(ab0), - c: ACMUX::from(ac0), - d: ACMUX::from(ad0), - }, - c1: ColorCombinePass { - a: CCMUX::from(a1), - b: CCMUX::from(b1), - c: CCMUX::from(c1), - d: CCMUX::from(d1), - }, - a1: AlphaCombinePass { - a: ACMUX::from(aa1), - b: ACMUX::from(ab1), - c: ACMUX::from(ac1), - d: ACMUX::from(ad1), - }, - } - } - - pub fn get_cc(&self, index: usize) -> ColorCombinePass { - match index { - 0 => self.c0, - 1 => self.c1, - _ => panic!("Invalid index"), - } - } - - pub fn get_ac(&self, index: usize) -> AlphaCombinePass { - match index { - 0 => self.a0, - 1 => self.a1, - _ => panic!("Invalid index"), - } - } - - pub fn cc_ac_same(&self, index: usize) -> bool { - match index { - 0 => { - self.c0.a as u8 == self.a0.a as u8 - && self.c0.b as u8 == self.a0.b as u8 - && self.c0.c as u8 == self.a0.c as u8 - && self.c0.d as u8 == self.a0.d as u8 - } - 1 => { - self.c1.a as u8 == self.a1.a as u8 - && self.c1.b as u8 == self.a1.b as u8 - && self.c1.c as u8 == self.a1.c as u8 - && self.c1.d as u8 == self.a1.d as u8 - } - _ => panic!("Invalid index"), - } - } - - pub fn uses_texture0(&self) -> bool { - self.c0.uses_texture0() - || self.c1.uses_texture0() - || self.a0.uses_texture0() - || self.a1.uses_texture0() - } - - pub fn uses_texture1(&self) -> bool { - self.c0.uses_texture1() - || self.c1.uses_texture1() - || self.a0.uses_texture1() - || self.a1.uses_texture1() - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Hash)] -pub enum CCMUX { - COMBINED = 0, - TEXEL0 = 1, - TEXEL1 = 2, - PRIMITIVE = 3, - SHADE = 4, - ENVIRONMENT = 5, - CENTER__SCALE__ONE = 6, - // param C only - COMBINED_ALPHA__NOISE__K4 = 7, // COMBINE_A only for C (ADD_ZERO?) - TEXEL0_ALPHA = 8, - TEXEL1_ALPHA = 9, - PRIMITIVE_ALPHA = 10, - SHADE_ALPHA = 11, - ENV_ALPHA = 12, - LOD_FRACTION = 13, - PRIM_LOD_FRACTION = 14, - K5 = 15, // MUL_ZERO? - ZERO = 31, -} - -impl CCMUX { - pub fn from(val: u8) -> Self { - match val { - 0 => CCMUX::COMBINED, - 1 => CCMUX::TEXEL0, - 2 => CCMUX::TEXEL1, - 3 => CCMUX::PRIMITIVE, - 4 => CCMUX::SHADE, - 5 => CCMUX::ENVIRONMENT, - 6 => CCMUX::CENTER__SCALE__ONE, - 7 => CCMUX::COMBINED_ALPHA__NOISE__K4, - 8 => CCMUX::TEXEL0_ALPHA, - 9 => CCMUX::TEXEL1_ALPHA, - 10 => CCMUX::PRIMITIVE_ALPHA, - 11 => CCMUX::SHADE_ALPHA, - 12 => CCMUX::ENV_ALPHA, - 13 => CCMUX::LOD_FRACTION, - 14 => CCMUX::PRIM_LOD_FRACTION, - 15 => CCMUX::K5, - 31 => CCMUX::ZERO, - _ => panic!("Invalid CCMUX value: {}", val), - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Hash)] -pub enum ACMUX { - COMBINED__LOD_FRAC = 0, // ADD? - TEXEL0 = 1, - TEXEL1 = 2, - PRIMITIVE = 3, - SHADE = 4, - ENVIRONMENT = 5, - PRIM_LOD_FRAC__ONE = 6, - ZERO = 7, -} - -impl ACMUX { - pub fn from(val: u8) -> Self { - match val { - 0 => ACMUX::COMBINED__LOD_FRAC, - 1 => ACMUX::TEXEL0, - 2 => ACMUX::TEXEL1, - 3 => ACMUX::PRIMITIVE, - 4 => ACMUX::SHADE, - 5 => ACMUX::ENVIRONMENT, - 6 => ACMUX::PRIM_LOD_FRAC__ONE, - 7 => ACMUX::ZERO, - _ => panic!("Invalid ACMUX value: {}", val), - } - } -} diff --git a/src/fast3d/utils/texture.rs b/src/fast3d/utils/texture.rs deleted file mode 100644 index 9747398..0000000 --- a/src/fast3d/utils/texture.rs +++ /dev/null @@ -1,234 +0,0 @@ -use farbe::image::n64::{ - ImageFormat as FarbeImageFormat, ImageSize as FarbeImageSize, NativeImage, TLUT, -}; -use log::trace; - -pub fn translate_tile_rgba16(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::RGBA16, tile_width, tile_height).unwrap(); - trace!("Decoding RGBA16 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded RGBA16 image"); - - decoded -} - -pub fn translate_tile_rgba32(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::RGBA32, tile_width, tile_height).unwrap(); - trace!("Decoding RGBA32 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded RGBA32 image"); - - decoded -} - -pub fn translate_tile_ia4(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::IA4, tile_width, tile_height).unwrap(); - trace!("Decoding IA4 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded IA4 image"); - - decoded -} - -pub fn translate_tile_ia8(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::IA8, tile_width, tile_height).unwrap(); - trace!("Decoding IA8 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded IA8 image"); - - decoded -} - -pub fn translate_tile_ia16(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::IA16, tile_width, tile_height).unwrap(); - trace!("Decoding IA16 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded IA16 image"); - - decoded -} - -pub fn translate_tile_i4(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::I4, tile_width, tile_height).unwrap(); - trace!("Decoding I4 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded I4 image"); - - decoded -} - -pub fn translate_tile_i8(tmem: &[u8], tile_width: u32, tile_height: u32) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::I8, tile_width, tile_height).unwrap(); - trace!("Decoding I8 image"); - let decoded = image.decode(None).unwrap(); - trace!("Decoded I8 image"); - - decoded -} - -pub fn translate_tile_ci4( - tmem: &[u8], - palette: &[u8], - tile_width: u32, - tile_height: u32, -) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::I8, tile_width, tile_height).unwrap(); - trace!("Decoding CI4 image"); - let decoded = image.decode(Some(palette)).unwrap(); - trace!("Decoded CI4 image"); - - decoded -} - -pub fn translate_tile_ci8( - tmem: &[u8], - palette: &[u8], - tile_width: u32, - tile_height: u32, -) -> Vec { - let image = NativeImage::read(tmem, FarbeImageFormat::I8, tile_width, tile_height).unwrap(); - trace!("Decoding CI8 image"); - let decoded = image.decode(Some(palette)).unwrap(); - trace!("Decoded CI8 image"); - - decoded -} - -pub fn translate_tlut( - pal_dram_addr: usize, - image_size: FarbeImageSize, - texlut: &TextureLUT, -) -> Vec { - // TODO: handle non-rgba16 palettes - assert!(texlut == &TextureLUT::G_TT_RGBA16); - - let tlut_size = image_size.tlut_size_in_bytes(); - let palette_data = unsafe { std::slice::from_raw_parts(pal_dram_addr as *const u8, tlut_size) }; - - let tlut = TLUT::read(palette_data, image_size).unwrap(); - trace!("Decoding TLUT"); - let decoded = tlut.decode().unwrap(); - trace!("Decoded TLUT"); - - decoded -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum ImageFormat { - G_IM_FMT_RGBA = 0x00, - G_IM_FMT_YUV = 0x01, - G_IM_FMT_CI = 0x02, - G_IM_FMT_IA = 0x03, - G_IM_FMT_I = 0x04, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum ImageSize { - G_IM_SIZ_4b = 0x00, - G_IM_SIZ_8b = 0x01, - G_IM_SIZ_16b = 0x02, - G_IM_SIZ_32b = 0x03, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum TextureLUT { - G_TT_NONE = 0x00, - G_TT_RGBA16 = 0x02, - G_TT_IA16 = 0x03, -} - -impl TextureLUT { - pub fn from_u32(value: u32) -> Self { - match value { - x if x == TextureLUT::G_TT_NONE as u32 => TextureLUT::G_TT_NONE, - x if x == TextureLUT::G_TT_RGBA16 as u32 => TextureLUT::G_TT_RGBA16, - x if x == TextureLUT::G_TT_IA16 as u32 => TextureLUT::G_TT_IA16, - _ => panic!("Invalid TextureLUT"), - } - } -} - -pub enum TexCM { - WRAP = 0x00, - MIRROR = 0x01, - CLAMP = 0x02, - MIRROR_CLAMP = 0x03, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TextFilt { - G_TF_POINT = 0x00, - G_TF_AVERAGE = 0x03, - G_TF_BILERP = 0x02, -} - -pub struct TextureState { - pub on: bool, - /// Index of parameter-setting tile descriptor (3bit precision, 0 - 7) - pub tile: u8, - pub level: u8, - pub scale_s: u16, - pub scale_t: u16, -} - -impl TextureState { - pub const EMPTY: Self = Self { - on: false, - tile: 0, - level: 0, - scale_s: 0, - scale_t: 0, - }; - - pub fn new(on: bool, tile: u8, level: u8, scale_s: u16, scale_t: u16) -> Self { - Self { - on, - tile, - level, - scale_s, - scale_t, - } - } -} - -pub struct TextureImageState { - pub format: u8, - pub size: u8, - pub width: u16, - pub address: usize, -} - -impl TextureImageState { - pub const EMPTY: Self = Self { - format: 0, - size: 0, - width: 0, - address: 0, - }; - - pub fn new(format: u8, size: u8, width: u16, address: usize) -> Self { - Self { - format, - size, - width, - address, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct RenderingStateTexture { - pub cms: u8, - pub cmt: u8, - - pub linear_filter: bool, -} - -impl RenderingStateTexture { - pub const EMPTY: Self = Self { - cms: 0, - cmt: 0, - - linear_filter: false, - }; -} diff --git a/src/fast3d/utils/texture_cache.rs b/src/fast3d/utils/texture_cache.rs deleted file mode 100644 index 39ce170..0000000 --- a/src/fast3d/utils/texture_cache.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::{ - collections::{hash_map::DefaultHasher, HashMap, VecDeque}, - hash::{Hash, Hasher}, -}; - -use crate::fast3d::graphics::GraphicsIntermediateTexture; - -use super::texture::{ImageFormat, ImageSize}; - -pub struct TextureCache { - pub map: HashMap, - pub lru: VecDeque, - pub capacity: usize, -} - -impl TextureCache { - pub fn new(capacity: usize) -> Self { - Self { - map: HashMap::new(), - lru: VecDeque::new(), - capacity, - } - } - - pub fn contains( - &self, - game_address: usize, - format: ImageFormat, - size: ImageSize, - ) -> Option { - let mut hasher = DefaultHasher::new(); - game_address.hash(&mut hasher); - format.hash(&mut hasher); - size.hash(&mut hasher); - let hash = hasher.finish(); - - if self.map.contains_key(&hash) { - // trace!("Texture found in decoding cache"); - return Some(hash); - } - - None - } - - pub fn get(&mut self, hash: u64) -> Option<&GraphicsIntermediateTexture> { - if let Some(texture) = self.map.get(&hash) { - self.lru.push_back(hash); - return Some(texture); - } - - None - } - - pub fn get_mut(&mut self, hash: u64) -> Option<&mut GraphicsIntermediateTexture> { - if let Some(texture) = self.map.get_mut(&hash) { - self.lru.push_back(hash); - return Some(texture); - } - - None - } - - pub fn insert( - &mut self, - game_address: usize, - format: ImageFormat, - size: ImageSize, - width: u32, - height: u32, - data: Vec, - ) -> u64 { - if self.map.len() >= self.capacity { - if let Some(key) = self.lru.pop_front() { - self.map.remove(&key); - // TODO: Keep track of removed textures so they can be deleted from the GPU - } - } - - let texture = - GraphicsIntermediateTexture::new(game_address, format, size, width, height, data); - - let mut hasher = DefaultHasher::new(); - game_address.hash(&mut hasher); - format.hash(&mut hasher); - size.hash(&mut hasher); - let hash = hasher.finish(); - - self.map.insert(hash, texture); - - hash - } -} diff --git a/src/fast3d/utils/tile_descriptor.rs b/src/fast3d/utils/tile_descriptor.rs deleted file mode 100644 index b9d3316..0000000 --- a/src/fast3d/utils/tile_descriptor.rs +++ /dev/null @@ -1,82 +0,0 @@ -use super::texture::{ImageFormat, ImageSize}; - -#[derive(Debug, Clone, Copy, Hash)] -pub struct TileDescriptor { - pub uls: u16, - pub ult: u16, - pub lrs: u16, - pub lrt: u16, - // Set by G_SETTILE - pub format: ImageFormat, - pub size: ImageSize, - /// Size of 1 line (s-axis) of texture tile (9bit precision, 0 - 511) - pub line: u16, - /// Address of texture tile origin (9bit precision, 0 - 511) - pub tmem: u16, - /// slot in tmem (usually 0 or 1)? - pub tmem_index: u8, - /// Position of palette for 4bit color index textures (4bit precision, 0 - 15) - pub palette: u8, - /// s-axis mirror, wrap, clamp flags - pub cm_s: u8, - /// s-axis mask (4bit precision, 0 - 15) - pub mask_s: u8, - /// s-coordinate shift value - pub shift_s: u8, - /// t-axis mirror, wrap, clamp flags - pub cm_t: u8, - /// t-axis mask (4bit precision, 0 - 15) - pub mask_t: u8, - /// t-coordinate shift value - pub shift_t: u8, -} - -impl TileDescriptor { - pub const EMPTY: Self = Self { - uls: 0, - ult: 0, - lrs: 0, - lrt: 0, - format: ImageFormat::G_IM_FMT_YUV, - size: ImageSize::G_IM_SIZ_4b, - line: 0, - tmem: 0, - tmem_index: 0, - palette: 0, - cm_s: 0, - mask_s: 0, - shift_s: 0, - cm_t: 0, - mask_t: 0, - shift_t: 0, - }; - - pub fn set_format(&mut self, format: u8) { - match format { - 0 => self.format = ImageFormat::G_IM_FMT_RGBA, - 1 => self.format = ImageFormat::G_IM_FMT_YUV, - 2 => self.format = ImageFormat::G_IM_FMT_CI, - 3 => self.format = ImageFormat::G_IM_FMT_IA, - 4 => self.format = ImageFormat::G_IM_FMT_I, - _ => panic!("Invalid format: {}", format), - } - } - - pub fn set_size(&mut self, size: u8) { - match size { - 0 => self.size = ImageSize::G_IM_SIZ_4b, - 1 => self.size = ImageSize::G_IM_SIZ_8b, - 2 => self.size = ImageSize::G_IM_SIZ_16b, - 3 => self.size = ImageSize::G_IM_SIZ_32b, - _ => panic!("Invalid size: {}", size), - } - } - - pub fn get_width(&self) -> u16 { - ((self.lrs - self.uls) + 4) / 4 - } - - pub fn get_height(&self) -> u16 { - ((self.lrt - self.ult) + 4) / 4 - } -} diff --git a/src/gui.rs b/src/gui.rs index 72ddbd3..2dad455 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,8 +1,7 @@ -#[cfg(feature = "wgpu")] +#[cfg(feature = "wgpu_renderer")] pub mod gui_wgpu; -#[cfg(feature = "opengl")] +#[cfg(feature = "opengl_renderer")] pub mod gui_glium; -pub mod renderer; pub mod windows; diff --git a/src/gui/gui_glium.rs b/src/gui/gui_glium.rs index 7768ac0..d45320f 100644 --- a/src/gui/gui_glium.rs +++ b/src/gui/gui_glium.rs @@ -12,12 +12,12 @@ use std::time::Duration; use std::{ffi::CStr, result::Result::Ok, time::Instant}; use winit::platform::run_return::EventLoopExtRunReturn; -use crate::fast3d::graphics::GraphicsIntermediateDevice; -use crate::fast3d::rcp::RCP; -use crate::fast3d::rdp::OutputDimensions; use crate::gamepad::manager::GamepadManager; +use fast3d::graphics::GraphicsIntermediateDevice; +use fast3d::rcp::RCP; +use fast3d::rdp::OutputDimensions; -use super::renderer::glium_device::GliumGraphicsDevice; +use fast3d_glium_renderer::glium_device::GliumGraphicsDevice; pub struct Gui<'a> { // window diff --git a/src/gui/renderer.rs b/src/gui/renderer.rs deleted file mode 100644 index 6379275..0000000 --- a/src/gui/renderer.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[cfg(feature = "opengl")] -pub mod glium_device; - -#[cfg(feature = "opengl")] -mod opengl_program; - -#[cfg(feature = "wgpu")] -pub mod wgpu_device; -#[cfg(feature = "wgpu")] -mod wgpu_program; diff --git a/src/gui/renderer/glium_device.rs b/src/gui/renderer/glium_device.rs deleted file mode 100644 index e256126..0000000 --- a/src/gui/renderer/glium_device.rs +++ /dev/null @@ -1,461 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use glam::Vec4Swizzles; -use glium::{ - draw_parameters::{DepthClamp, PolygonOffset}, - index::{NoIndices, PrimitiveType}, - program::ProgramCreationInput, - texture::{RawImage2d, Texture2d}, - uniforms::{ - MagnifySamplerFilter, MinifySamplerFilter, SamplerBehavior, SamplerWrapFunction, - UniformValue, Uniforms, - }, - vertex::{AttributeType, VertexBufferAny}, - BackfaceCullingMode, BlendingFunction, DepthTest, Display, DrawParameters, Frame, - LinearBlendingFactor, Program, Surface, -}; - -use crate::fast3d::{ - gbi::defines::G_TX, - graphics::{ - GraphicsIntermediateFogParams, GraphicsIntermediateSampler, GraphicsIntermediateStencil, - GraphicsIntermediateTexture, GraphicsIntermediateUniforms, - }, - utils::color_combiner::CombineParams, -}; - -use super::opengl_program::OpenGLProgram; - -struct TextureData { - texture: Texture2d, - sampler: Option, -} - -impl TextureData { - pub fn new(texture: Texture2d) -> Self { - Self { - texture, - sampler: None, - } - } -} - -#[derive(Default)] -struct UniformVec<'a, 'b> { - pub uniforms: Vec<(&'a str, UniformValue<'b>)>, -} - -impl Uniforms for UniformVec<'_, '_> { - fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut func: F) { - for uniform in &self.uniforms { - func(uniform.0, uniform.1); - } - } -} - -pub struct GliumGraphicsDevice<'draw> { - pub shader_cache: HashMap>, - current_shader: u64, - - textures: Vec, - active_texture: usize, - current_texture_ids: [usize; 2], - - frame_count: i32, - current_height: i32, - - draw_params: DrawParameters<'draw>, -} - -fn blend_component_to_glium(component: wgpu::BlendComponent) -> BlendingFunction { - match component.operation { - wgpu::BlendOperation::Add => BlendingFunction::Addition { - source: blend_factor_to_glium(component.src_factor), - destination: blend_factor_to_glium(component.dst_factor), - }, - wgpu::BlendOperation::Subtract => BlendingFunction::Subtraction { - source: blend_factor_to_glium(component.src_factor), - destination: blend_factor_to_glium(component.dst_factor), - }, - wgpu::BlendOperation::ReverseSubtract => BlendingFunction::ReverseSubtraction { - source: blend_factor_to_glium(component.src_factor), - destination: blend_factor_to_glium(component.dst_factor), - }, - wgpu::BlendOperation::Min => BlendingFunction::Min, - wgpu::BlendOperation::Max => BlendingFunction::Max, - } -} - -fn blend_factor_to_glium(factor: wgpu::BlendFactor) -> LinearBlendingFactor { - match factor { - wgpu::BlendFactor::Zero => LinearBlendingFactor::Zero, - wgpu::BlendFactor::One => LinearBlendingFactor::One, - wgpu::BlendFactor::Src => LinearBlendingFactor::SourceColor, - wgpu::BlendFactor::OneMinusSrc => LinearBlendingFactor::OneMinusSourceColor, - wgpu::BlendFactor::SrcAlpha => LinearBlendingFactor::SourceAlpha, - wgpu::BlendFactor::OneMinusSrcAlpha => LinearBlendingFactor::OneMinusSourceAlpha, - wgpu::BlendFactor::Dst => LinearBlendingFactor::DestinationColor, - wgpu::BlendFactor::OneMinusDst => LinearBlendingFactor::OneMinusDestinationColor, - wgpu::BlendFactor::DstAlpha => LinearBlendingFactor::DestinationAlpha, - wgpu::BlendFactor::OneMinusDstAlpha => LinearBlendingFactor::OneMinusDestinationAlpha, - wgpu::BlendFactor::SrcAlphaSaturated => LinearBlendingFactor::SourceAlphaSaturate, - wgpu::BlendFactor::Constant => LinearBlendingFactor::ConstantColor, - wgpu::BlendFactor::OneMinusConstant => LinearBlendingFactor::OneMinusConstantColor, - } -} - -fn clamp_to_glium(clamp: u32) -> SamplerWrapFunction { - if clamp & G_TX::CLAMP as u32 != 0 { - return SamplerWrapFunction::Clamp; - } - - if clamp & G_TX::MIRROR as u32 != 0 { - return SamplerWrapFunction::Mirror; - } - - SamplerWrapFunction::Repeat -} - -impl<'draw> Default for GliumGraphicsDevice<'draw> { - fn default() -> Self { - Self::new() - } -} - -impl<'draw> GliumGraphicsDevice<'draw> { - pub fn new() -> Self { - Self { - shader_cache: HashMap::new(), - current_shader: 0, - - textures: Vec::new(), - active_texture: 0, - current_texture_ids: [0; 2], - - frame_count: 0, - current_height: 0, - - draw_params: DrawParameters { - ..Default::default() - }, - } - } - - pub fn start_frame(&mut self, target: &mut Frame) { - self.frame_count += 1; - - target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0); - - self.draw_params = DrawParameters { - ..Default::default() - }; - } - - pub fn end_frame(&self) {} - - pub fn set_cull_mode(&mut self, cull_mode: Option) { - self.draw_params.backface_culling = match cull_mode { - Some(wgpu::Face::Front) => BackfaceCullingMode::CullCounterClockwise, - Some(wgpu::Face::Back) => BackfaceCullingMode::CullClockwise, - None => BackfaceCullingMode::CullingDisabled, - } - } - - pub fn set_depth_stencil_params(&mut self, params: Option) { - self.draw_params.depth = if let Some(params) = params { - glium::Depth { - test: match params.depth_compare { - wgpu::CompareFunction::Never => DepthTest::Ignore, - wgpu::CompareFunction::Less => DepthTest::IfLess, - wgpu::CompareFunction::Equal => DepthTest::IfEqual, - wgpu::CompareFunction::LessEqual => DepthTest::IfLessOrEqual, - wgpu::CompareFunction::Greater => DepthTest::IfMore, - wgpu::CompareFunction::NotEqual => DepthTest::IfNotEqual, - wgpu::CompareFunction::GreaterEqual => DepthTest::IfMoreOrEqual, - wgpu::CompareFunction::Always => DepthTest::Overwrite, - }, - write: params.depth_write_enabled, - clamp: DepthClamp::Clamp, - ..Default::default() - } - } else { - glium::Depth { - clamp: DepthClamp::Clamp, - ..Default::default() - } - }; - - self.draw_params.polygon_offset = if let Some(params) = params { - PolygonOffset { - factor: if params.polygon_offset { -2.0 } else { 0.0 }, - units: if params.polygon_offset { 2.0 } else { 0.0 }, - fill: true, - ..Default::default() - } - } else { - PolygonOffset { - ..Default::default() - } - }; - } - - pub fn set_blend_state(&mut self, blend_state: Option) { - self.draw_params.blend = if let Some(blend_state) = blend_state { - glium::Blend { - color: blend_component_to_glium(blend_state.color), - alpha: blend_component_to_glium(blend_state.alpha), - ..Default::default() - } - } else { - glium::Blend { - ..Default::default() - } - }; - } - - pub fn set_viewport(&mut self, viewport: &glam::Vec4) { - self.draw_params.viewport = Some(glium::Rect { - left: viewport.x as u32, - bottom: viewport.y as u32, - width: viewport.z as u32, - height: viewport.w as u32, - }); - - self.current_height = viewport.w as i32; - } - - pub fn set_scissor(&mut self, scissor: [u32; 4]) { - self.draw_params.scissor = Some(glium::Rect { - left: scissor[0], - bottom: scissor[1], - width: scissor[2], - height: scissor[3], - }); - } - - pub fn load_program( - &mut self, - display: &Display, - shader_hash: u64, - other_mode_h: u32, - other_mode_l: u32, - geometry_mode: u32, - combine: CombineParams, - ) { - // check if the shader is already loaded - if self.current_shader == shader_hash { - return; - } - - // unload the current shader - if self.current_shader != 0 { - self.current_shader = 0; - } - - // check if the shader is in the cache - if self.shader_cache.contains_key(&shader_hash) { - self.current_shader = shader_hash; - return; - } - - // create the shader and add it to the cache - let mut program = OpenGLProgram::new(other_mode_h, other_mode_l, geometry_mode, combine); - program.init(); - program.preprocess(); - - let source = ProgramCreationInput::SourceCode { - vertex_shader: &program.preprocessed_vertex, - fragment_shader: &program.preprocessed_frag, - geometry_shader: None, - tessellation_control_shader: None, - tessellation_evaluation_shader: None, - transform_feedback_varyings: None, - outputs_srgb: true, // workaround to avoid glium doing gamma correction - uses_point_size: false, - }; - - program.compiled_program = Some(Program::new(display, source).unwrap()); - - self.current_shader = shader_hash; - self.shader_cache.insert(shader_hash, program); - } - - pub fn bind_texture( - &mut self, - display: &Display, - tile: usize, - texture: &mut GraphicsIntermediateTexture, - ) { - // check if we've already uploaded this texture to the GPU - if let Some(texture_id) = texture.device_id { - // trace!("Texture found in GPU cache"); - self.active_texture = tile; - self.current_texture_ids[tile] = texture_id as usize; - - return; - } - - // Create the texture - let raw_texture = - RawImage2d::from_raw_rgba(texture.data.clone(), (texture.width, texture.height)); - let native_texture = Texture2d::new(display, raw_texture).unwrap(); - - self.active_texture = tile; - self.current_texture_ids[tile] = self.textures.len(); - texture.device_id = Some(self.textures.len() as u32); - - self.textures.push(TextureData::new(native_texture)); - } - - pub fn bind_sampler(&mut self, tile: usize, sampler: &GraphicsIntermediateSampler) { - if let Some(texture_data) = self.textures.get_mut(self.current_texture_ids[tile]) { - let wrap_s = clamp_to_glium(sampler.clamp_s); - let wrap_t = clamp_to_glium(sampler.clamp_t); - - let native_sampler = SamplerBehavior { - minify_filter: if sampler.linear_filter { - MinifySamplerFilter::Linear - } else { - MinifySamplerFilter::Nearest - }, - magnify_filter: if sampler.linear_filter { - MagnifySamplerFilter::Linear - } else { - MagnifySamplerFilter::Nearest - }, - wrap_function: (wrap_s, wrap_t, SamplerWrapFunction::Repeat), - ..Default::default() - }; - - texture_data.sampler = Some(native_sampler); - } - } - - pub fn draw_triangles( - &self, - display: &Display, - target: &mut Frame, - projection_matrix: glam::Mat4, - fog: &GraphicsIntermediateFogParams, - vbo: &[u8], - uniforms: &GraphicsIntermediateUniforms, - ) { - // Grab current program - let program = self.shader_cache.get(&self.current_shader).unwrap(); - - // Setup vertex buffer - let mut num_floats = 8; - let mut vertex_format_data = vec![ - ( - Cow::Borrowed("aVtxPos"), - 0, - -1, - AttributeType::F32F32F32F32, - false, - ), - ( - Cow::Borrowed("aVtxColor"), - 4 * ::std::mem::size_of::(), - -1, - AttributeType::F32F32F32F32, - false, - ), - ]; - - if program.get_define_bool("USE_TEXTURE0") || program.get_define_bool("USE_TEXTURE1") { - num_floats += 2; - vertex_format_data.push(( - Cow::Borrowed("aTexCoord"), - 8 * ::std::mem::size_of::(), - -1, - AttributeType::F32F32, - false, - )); - } - - let vertex_buffer = unsafe { - VertexBufferAny::new_raw( - display, - vbo, - Cow::Owned(vertex_format_data), - num_floats * ::std::mem::size_of::(), - ) - } - .unwrap(); - - // Setup uniforms - let mut shader_uniforms = vec![ - ( - "uProjection", - UniformValue::Mat4(projection_matrix.to_cols_array_2d()), - ), - ( - "uBlendColor", - UniformValue::Vec4(uniforms.blend.blend_color.to_array()), - ), - ( - "uPrimColor", - UniformValue::Vec4(uniforms.combine.prim_color.to_array()), - ), - ( - "uEnvColor", - UniformValue::Vec4(uniforms.combine.env_color.to_array()), - ), - ( - "uKeyCenter", - UniformValue::Vec3(uniforms.combine.key_center.to_array()), - ), - ( - "uKeyScale", - UniformValue::Vec3(uniforms.combine.key_scale.to_array()), - ), - ("uPrimLOD", UniformValue::Float(uniforms.combine.prim_lod.x)), - ("uK4", UniformValue::Float(uniforms.combine.convert_k4)), - ("uK5", UniformValue::Float(uniforms.combine.convert_k5)), - ]; - - if program.get_define_bool("USE_FOG") { - shader_uniforms.push(( - "uFogColor", - UniformValue::Vec3(uniforms.blend.fog_color.xyz().to_array()), - )); - - shader_uniforms.push(("uFogMultiplier", UniformValue::Float(fog.multiplier as f32))); - shader_uniforms.push(("uFogOffset", UniformValue::Float(fog.offset as f32))); - } - - if program.get_define_bool("USE_TEXTURE0") { - let texture = self.textures.get(self.current_texture_ids[0]).unwrap(); - shader_uniforms.push(( - "uTex0", - UniformValue::Texture2d(&texture.texture, texture.sampler), - )); - } - - if program.get_define_bool("USE_TEXTURE1") { - let texture = self.textures.get(self.current_texture_ids[1]).unwrap(); - shader_uniforms.push(( - "uTex1", - UniformValue::Texture2d(&texture.texture, texture.sampler), - )); - } - - if program.get_define_bool("USE_ALPHA") && program.get_define_bool("ALPHA_COMPARE_DITHER") { - shader_uniforms.push(("uFrameCount", UniformValue::SignedInt(self.frame_count))); - shader_uniforms.push(("uFrameHeight", UniformValue::SignedInt(self.current_height))); - } - - // Draw triangles - target - .draw( - &vertex_buffer, - NoIndices(PrimitiveType::TrianglesList), - program.compiled_program.as_ref().unwrap(), - &UniformVec { - uniforms: shader_uniforms, - }, - &self.draw_params, - ) - .unwrap(); - } -} diff --git a/src/gui/renderer/opengl_program.rs b/src/gui/renderer/opengl_program.rs deleted file mode 100644 index cd585e8..0000000 --- a/src/gui/renderer/opengl_program.rs +++ /dev/null @@ -1,523 +0,0 @@ -use crate::fast3d::gbi::utils::{ - geometry_mode_uses_lighting, get_cycle_type_from_other_mode_h, - get_textfilter_from_other_mode_h, other_mode_l_alpha_compare_dither, - other_mode_l_alpha_compare_threshold, other_mode_l_uses_alpha, other_mode_l_uses_fog, - other_mode_l_uses_texture_edge, -}; - -use crate::fast3d::utils::{ - color_combiner::{CombineParams, ACMUX, CCMUX}, - texture::TextFilt, -}; - -use crate::fast3d::rdp::OtherModeHCycleType; -use std::collections::HashMap; - -#[derive(PartialEq, Eq)] -pub enum ShaderType { - Vertex, - Fragment, -} - -#[derive(Debug, Clone)] -pub struct OpenGLProgram { - // Compiled program. - pub preprocessed_vertex: String, - pub preprocessed_frag: String, - pub compiled_program: Option, - - // inputs - pub both: String, - pub vertex: String, - pub fragment: String, - pub defines: HashMap, - - // configurators - other_mode_h: u32, - other_mode_l: u32, - geometry_mode: u32, - combine: CombineParams, - - pub num_floats: usize, -} - -impl OpenGLProgram { - // MARK: - Defines - pub fn defines_changed(&mut self) { - self.preprocessed_vertex = "".to_string(); - self.preprocessed_frag = "".to_string(); - } - - pub fn set_define_string(&mut self, name: String, v: Option) -> bool { - if let Some(v) = v { - if self.defines.get(&name) == Some(&v) { - return false; - } - self.defines.insert(name, v); - } else { - if !self.defines.contains_key(&name) { - return false; - } - self.defines.remove(&name); - } - - self.defines_changed(); - true - } - - pub fn set_define_bool(&mut self, name: String, v: bool) -> bool { - self.set_define_string(name, if v { Some("1".to_string()) } else { None }) - } - - pub fn get_define_string(&self, name: &str) -> Option<&String> { - self.defines.get(name) - } - - pub fn get_define_bool(&self, name: &str) -> bool { - let str = self.get_define_string(name); - - if let Some(str) = str { - assert_eq!(str, "1"); - } - - str.is_some() - } - - // MARK: - Preprocessing - - pub fn preprocess(&mut self) { - if !self.preprocessed_vertex.is_empty() { - return; - } - - self.preprocessed_vertex = - self.preprocess_shader(ShaderType::Vertex, &format!("{}{}", self.both, self.vertex)); - self.preprocessed_frag = self.preprocess_shader( - ShaderType::Fragment, - &format!("{}{}", self.both, self.fragment), - ); - } - - pub fn preprocess_shader(&mut self, _shader_type: ShaderType, shader: &str) -> String { - let defines_string = self - .defines - .iter() - .map(|(k, v)| format!("#define {} {}\n", k, v)) - .collect::>() - .join(""); - - format!( - r#" - #version 140 - {} - {} - "#, - defines_string, shader - ) - } - - // MARK: - Defaults - - pub fn new( - other_mode_h: u32, - other_mode_l: u32, - geometry_mode: u32, - combine: CombineParams, - ) -> Self { - Self { - preprocessed_vertex: "".to_string(), - preprocessed_frag: "".to_string(), - compiled_program: None, - - both: "".to_string(), - vertex: "".to_string(), - fragment: "".to_string(), - defines: HashMap::new(), - - other_mode_h, - other_mode_l, - geometry_mode, - combine, - - num_floats: 0, - } - } - - pub fn init(&mut self) { - // for debugging - self.set_define_bool("USE_ALPHA_VISUALIZER".to_string(), false); - self.set_define_bool("ONLY_VERTEX_COLOR".to_string(), false); - - self.set_define_bool( - "TWO_CYCLE".to_string(), - get_cycle_type_from_other_mode_h(self.other_mode_h) - == OtherModeHCycleType::G_CYC_2CYCLE, - ); - self.set_define_bool( - "LIGHTING".to_string(), - geometry_mode_uses_lighting(self.geometry_mode), - ); - self.set_define_bool("USE_TEXTURE0".to_string(), self.combine.uses_texture0()); - self.set_define_bool("USE_TEXTURE1".to_string(), self.combine.uses_texture1()); - self.set_define_bool( - "TEXTURE_EDGE".to_string(), - other_mode_l_uses_texture_edge(self.other_mode_l), - ); - - self.set_define_bool( - "USE_FOG".to_string(), - other_mode_l_uses_fog(self.other_mode_l), - ); - self.set_define_bool( - "USE_ALPHA".to_string(), - other_mode_l_uses_alpha(self.other_mode_l) - || other_mode_l_uses_texture_edge(self.other_mode_l), - ); - self.set_define_bool( - "ALPHA_COMPARE_DITHER".to_string(), - other_mode_l_alpha_compare_dither(self.other_mode_l), - ); - - self.set_define_bool( - "ALPHA_COMPARE_THRESHOLD".to_string(), - other_mode_l_alpha_compare_threshold(self.other_mode_l), - ); - - self.set_define_bool("COLOR_ALPHA_SAME".to_string(), self.combine.cc_ac_same(0)); - - self.num_floats = 8; - - if self.get_define_bool("USE_TEXTURE0") || self.get_define_bool("USE_TEXTURE1") { - self.num_floats += 2; - } - - self.both = r#" - const vec4 tZero = vec4(0.0); - const vec4 tHalf = vec4(0.5); - const vec4 tOne = vec4(1.0); - - const int DRAWING_RECT = 0; - "# - .to_string(); - - self.vertex = r#" - in vec4 aVtxPos; - - in vec4 aVtxColor; - out vec4 vVtxColor; - - #if defined(USE_TEXTURE0) || defined(USE_TEXTURE1) - in vec2 aTexCoord; - out vec2 vTexCoord; - #endif - - uniform mat4 uProjection; - #ifdef USE_FOG - uniform float uFogMultiplier; - uniform float uFogOffset; - #endif - - // Convert from 0...1 UNORM range to SNORM range - vec3 ConvertToSignedInt(vec3 t_Input) { - ivec3 t_Num = ivec3(t_Input * 255.0); - // Sign extend - t_Num = t_Num << 24 >> 24; - return vec3(t_Num) / 127.0; - } - - void main() { - if (aVtxPos.w == DRAWING_RECT) { - gl_Position = vec4(aVtxPos.xyz, 1.0); - } else { - gl_Position = aVtxPos * uProjection; - } - - #ifdef USE_FOG - float fogValue = (max(gl_Position.z, 0.0) / gl_Position.w) * uFogMultiplier + uFogOffset; - fogValue = clamp(fogValue, 0.0, 255.0); - vVtxColor = vec4(aVtxColor.rgb, fogValue / 255.0); - #else - vVtxColor = aVtxColor; - #endif - - #ifdef LIGHTING - // convert (unsigned) colors to normal vector components - vec4 t_Normal = vec4(ConvertToSignedInt(aVtxColor.rgb), 0.0); - // t_Normal = normalize(Mul(_Mat4x4(u_BoneMatrix[t_BoneIndex]), t_Normal)); - #endif - - #if defined(USE_TEXTURE0) || defined(USE_TEXTURE1) - vTexCoord = aTexCoord; - #endif - } - "# - .to_string(); - - self.fragment = self.generate_frag(); - } - - fn generate_frag(&mut self) -> String { - let tex_filter = match get_textfilter_from_other_mode_h(self.other_mode_h) { - TextFilt::G_TF_POINT => "Point", - TextFilt::G_TF_AVERAGE => "Average", - TextFilt::G_TF_BILERP => "Bilerp", - }; - - let color_input_common = |input| match input { - CCMUX::COMBINED => "tCombColor.rgb", - CCMUX::TEXEL0 => "texVal0.rgb", - CCMUX::TEXEL1 => "texVal1.rgb", - CCMUX::PRIMITIVE => "uPrimColor.rgb", - CCMUX::SHADE => "vVtxColor.rgb", - CCMUX::ENVIRONMENT => "uEnvColor.rgb", - _ => panic!("Should be unreachable"), - }; - - let color_input_a = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "tOne.rgb", // matching against ONE - CCMUX::COMBINED_ALPHA__NOISE__K4 => "vec3(RAND_NOISE, RAND_NOISE, RAND_NOISE)", // matching against NOISE - _ => "tZero.rgb", - } - } - }; - - let color_input_b = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "uKeyCenter", // matching against CENTER - CCMUX::COMBINED_ALPHA__NOISE__K4 => "vec3(uK4, uK4, uK4)", // matching against K4 - _ => "tZero.rgb", - } - } - }; - - let color_input_c = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "uKeyScale", // matching against SCALE - CCMUX::COMBINED_ALPHA__NOISE__K4 => "tCombColor.aaa", // matching against COMBINED_ALPHA - CCMUX::TEXEL0_ALPHA => "texVal0.aaa", - CCMUX::TEXEL1_ALPHA => "texVal1.aaa", - CCMUX::PRIMITIVE_ALPHA => "uPrimColor.aaa", - CCMUX::SHADE_ALPHA => "vVtxColor.aaa", - CCMUX::ENV_ALPHA => "uEnvColor.aaa", - CCMUX::LOD_FRACTION => "tZero.rgb", // TODO: LOD FRACTION - CCMUX::PRIM_LOD_FRACTION => "vec3(uPrimLodFrac, uPrimLodFrac, uPrimLodFrac)", - CCMUX::K5 => "vec3(uK5, uK5, uK5)", - _ => "tZero.rgb", - } - } - }; - - let color_input_d = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "tOne.rgb", // matching against ONE - _ => "tZero.rgb", - } - } - }; - - let alpha_input_abd = |input| { - match input { - ACMUX::COMBINED__LOD_FRAC => "tCombColor.a", // matching against COMBINED - ACMUX::TEXEL0 => "texVal0.a", - ACMUX::TEXEL1 => "texVal1.a", - ACMUX::PRIMITIVE => "uPrimColor.a", - ACMUX::SHADE => { - if self.get_define_bool("USE_FOG") { - "tOne.a" - } else { - "vVtxColor.a" - } - } - ACMUX::ENVIRONMENT => "uEnvColor.a", - ACMUX::PRIM_LOD_FRAC__ONE => "tOne.a", // matching against ONE - _ => "tZero.a", - } - }; - - let alpha_input_c = |input| { - match input { - ACMUX::COMBINED__LOD_FRAC => "tZero.a", // TODO: LOD_FRAC - ACMUX::TEXEL0 => "texVal0.a", - ACMUX::TEXEL1 => "texVal1.a", - ACMUX::PRIMITIVE => "uPrimColor.a", - ACMUX::SHADE => "vVtxColor.a", - ACMUX::ENVIRONMENT => "uEnvColor.a", - ACMUX::PRIM_LOD_FRAC__ONE => "uPrimLodFrac", - _ => "tZero.a", - } - }; - - format!( - r#" - in vec4 vVtxColor; - - #if defined(USE_TEXTURE0) || defined(USE_TEXTURE1) - in vec2 vTexCoord; - #endif - - #ifdef USE_FOG - uniform vec3 uFogColor; - #endif - - // blend parameters - uniform vec4 uBlendColor; - - // combine parameters - // TODO: use a uniform block? - uniform vec4 uPrimColor; - uniform vec4 uEnvColor; - uniform vec3 uKeyCenter; - uniform vec3 uKeyScale; - uniform float uPrimLodFrac; - uniform float uK4; - uniform float uK5; - - #ifdef USE_TEXTURE0 - uniform sampler2D uTex0; - #endif - #ifdef USE_TEXTURE1 - uniform sampler2D uTex1; - #endif - - #if defined(USE_ALPHA) - #if defined(ALPHA_COMPARE_DITHER) - uniform int uFrameCount; - uniform int uFrameHeight; - - float random(in vec3 value) {{ - float random = dot(sin(value), vec3(12.9898, 78.233, 37.719)); - return fract(sin(random) * 143758.5453); - }} - #endif - #endif - - out vec4 outColor; - - #define TEX_OFFSET(offset) texture(tex, texCoord - (offset) / texSize) - #define RAND_NOISE "((random(vec3(floor(gl_FragCoord.xy * (240.0 / float(uFrameHeight)), float(uFrameCount))) + 1.0) / 2.0)" - - vec4 Texture2D_N64_Point(in sampler2D tex, in vec2 texCoord) {{ - return texture(tex, texCoord); - }} - - vec4 Texture2D_N64_Average(in sampler2D tex, in vec2 texCoord) {{ - // Unimplemented. - return texture(tex, texCoord); - }} - - // Implements N64-style "triangle bilienar filtering" with three taps. - // Based on ArthurCarvalho's implementation, modified for use here. - vec4 Texture2D_N64_Bilerp(in sampler2D tex, in vec2 texCoord) {{ - vec2 texSize = vec2(textureSize(tex, 0)); - vec2 offset = fract(texCoord * texSize - vec2(0.5)); - offset -= step(1.0, offset.x + offset.y); - vec4 s0 = TEX_OFFSET(offset); - vec4 s1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y)); - vec4 s2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y))); - return s0 + abs(offset.x) * (s1 - s0) + abs(offset.y) * (s2 - s0); - }} - - #define Texture2D_N64 Texture2D_N64_{} - - vec3 CombineColorCycle0(vec4 tCombColor, vec4 texVal0, vec4 texVal1) {{ - return ({} - {}) * {} + {}; - }} - - float CombineAlphaCycle0(vec4 tCombColor, vec4 texVal0, vec4 texVal1) {{ - return ({} - {}) * {} + {}; - }} - - vec3 CombineColorCycle1(vec4 tCombColor, vec4 texVal0, vec4 texVal1) {{ - return ({} - {}) * {} + {}; - }} - - float CombineAlphaCycle1(vec4 tCombColor, vec4 texVal0, vec4 texVal1) {{ - return ({} - {}) * {} + {}; - }} - - void main() {{ - vec4 texVal0 = tOne, texVal1 = tOne; - - #ifdef USE_TEXTURE0 - texVal0 = Texture2D_N64(uTex0, vTexCoord); - #endif - #ifdef USE_TEXTURE1 - texVal1 = Texture2D_N64(uTex1, vTexCoord); - #endif - - #ifdef ONLY_VERTEX_COLOR - vec4 texel = vVtxColor; - #else - vec4 texel = vec4( - CombineColorCycle0(tHalf, texVal0, texVal1), - CombineAlphaCycle0(tHalf, texVal0, texVal1) - ); - - #ifdef TWO_CYCLE - // Note that in the second cycle, Tex0 and Tex1 are swapped - texel = vec4( - CombineColorCycle1(texel, texVal1, texVal0), - CombineAlphaCycle1(texel, texVal1, texVal0) - ); - #endif - #endif - - #if defined(USE_ALPHA) - #if defined(ALPHA_COMPARE_DITHER) - if (texel.a < floor(random(vec3(floor(gl_FragCoord.xy * (240.0 / float(uFrameHeight))), float(uFrameCount))) + 0.5)) discard; - #endif - - #if defined(ALPHA_COMPARE_THRESHOLD) - if (texel.a < uBlendColor.a) discard; - #endif - - #if defined(TEXTURE_EDGE) - if (texel.a < 0.125) discard; - #endif - - #if defined(USE_ALPHA_VISUALIZER) - texel = mix(texel, vec4(1.0f, 0.0f, 1.0f, 1.0f), 0.5f); - #endif - #endif - - // TODO: Blender - #ifdef USE_FOG - texel = vec4(mix(texel.rgb, uFogColor.rgb, vVtxColor.a), texel.a); - #endif - - outColor = texel; - }} - "#, - tex_filter, - color_input_a(self.combine.c0.a), - color_input_b(self.combine.c0.b), - color_input_c(self.combine.c0.c), - color_input_d(self.combine.c0.d), - alpha_input_abd(self.combine.a0.a), - alpha_input_abd(self.combine.a0.b), - alpha_input_c(self.combine.a0.c), - alpha_input_abd(self.combine.a0.d), - color_input_a(self.combine.c1.a), - color_input_b(self.combine.c1.b), - color_input_c(self.combine.c1.c), - color_input_d(self.combine.c1.d), - alpha_input_abd(self.combine.a1.a), - alpha_input_abd(self.combine.a1.b), - alpha_input_c(self.combine.a1.c), - alpha_input_abd(self.combine.a1.d), - ) - } -} diff --git a/src/gui/renderer/wgpu_device.rs b/src/gui/renderer/wgpu_device.rs deleted file mode 100644 index 3e59888..0000000 --- a/src/gui/renderer/wgpu_device.rs +++ /dev/null @@ -1,787 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use bytemuck::{Pod, Zeroable}; - -use wgpu::util::{align_to, DeviceExt}; - -use crate::fast3d::{ - gbi::defines::G_TX, - graphics::{ - GraphicsIntermediateFogParams, GraphicsIntermediateSampler, GraphicsIntermediateStencil, - GraphicsIntermediateTexture, GraphicsIntermediateUniforms, - }, - utils::color_combiner::CombineParams, -}; - -use super::wgpu_program::WgpuProgram; - -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] -struct VertexUniforms { - projection_matrix: [[f32; 4]; 4], - _pad: [f32; 4], -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] -struct VertexWithFogUniforms { - projection_matrix: [[f32; 4]; 4], - fog_multiplier: f32, - fog_offset: f32, - _pad: [f32; 2], -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] -struct FragmentBlendUniforms { - blend_color: [f32; 4], - fog_color: [f32; 4], -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] -struct FragmentCombineUniforms { - prim_color: [f32; 4], - env_color: [f32; 4], - key_center: [f32; 3], - // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here - _pad: u32, - key_scale: [f32; 3], - // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here - __pad: u32, - prim_lod_frac: f32, - convert_k4: f32, - convert_k5: f32, - ___pad: u32, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] -struct FragmentFrameUniforms { - count: u32, - height: u32, -} - -struct TextureData { - texture_view: wgpu::TextureView, - sampler: Option, -} - -impl TextureData { - pub fn new(texture_view: wgpu::TextureView) -> Self { - Self { - texture_view, - sampler: None, - } - } -} - -pub struct WgpuGraphicsDevice { - depth_texture: wgpu::TextureView, - - vertex_buf: wgpu::Buffer, - - vertex_uniform_buf: wgpu::Buffer, - vertex_bind_group_layout: wgpu::BindGroupLayout, - vertex_bind_group: wgpu::BindGroup, - - blend_uniform_buf: wgpu::Buffer, - combine_uniform_buf: wgpu::Buffer, - frame_uniform_buf: wgpu::Buffer, - fragment_uniform_bind_group_layout: wgpu::BindGroupLayout, - fragment_uniform_bind_group: wgpu::BindGroup, - - pub shader_cache: HashMap, - current_shader: u64, - - textures: Vec, - active_texture: usize, - current_texture_ids: [usize; 2], - - frame_count: i32, - current_height: i32, -} - -impl WgpuGraphicsDevice { - const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - - fn create_depth_texture( - config: &wgpu::SurfaceConfiguration, - device: &wgpu::Device, - ) -> wgpu::TextureView { - let depth_texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: config.width, - height: config.height, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - label: None, - view_formats: &[], - }); - - depth_texture.create_view(&wgpu::TextureViewDescriptor::default()) - } - - fn create_vertex_uniforms(device: &wgpu::Device) -> wgpu::Buffer { - // Handle vertex uniform size ohne fog - let vertex_uniform_size = std::mem::size_of::() as wgpu::BufferAddress; - let vertex_uniform_alignment = { - let alignment = - device.limits().min_uniform_buffer_offset_alignment as wgpu::BufferAddress; - align_to(vertex_uniform_size, alignment) - }; - - device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Vertex Uniform Buffer"), - size: vertex_uniform_alignment, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }) - } - - fn create_fragment_uniforms( - device: &wgpu::Device, - ) -> (wgpu::Buffer, wgpu::Buffer, wgpu::Buffer) { - // Handle blend uniform - let blend_uniform_size = - std::mem::size_of::() as wgpu::BufferAddress; - let blend_uniform_alignment = { - let alignment = - device.limits().min_uniform_buffer_offset_alignment as wgpu::BufferAddress; - align_to(blend_uniform_size, alignment) - }; - let blend_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Blend Uniform Buffer"), - size: blend_uniform_alignment, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - // Handle combine uniform - let combine_uniform_size = - std::mem::size_of::() as wgpu::BufferAddress; - let combine_uniform_alignment = { - let alignment = - device.limits().min_uniform_buffer_offset_alignment as wgpu::BufferAddress; - align_to(combine_uniform_size, alignment) - }; - let combine_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Combine Uniform Buffer"), - size: combine_uniform_alignment, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - // Handle frame uniform - let frame_uniform_size = - std::mem::size_of::() as wgpu::BufferAddress; - let frame_uniform_alignment = { - let alignment = - device.limits().min_uniform_buffer_offset_alignment as wgpu::BufferAddress; - align_to(frame_uniform_size, alignment) - }; - let frame_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Frame Uniform Buffer"), - size: frame_uniform_alignment, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - (blend_uniform_buf, combine_uniform_buf, frame_uniform_buf) - } - - fn create_vertex_bind_groups( - device: &wgpu::Device, - vertex_uniform_buf: &wgpu::Buffer, - ) -> (wgpu::BindGroupLayout, wgpu::BindGroup) { - let vertex_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Vertex Bind Group Layout"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: wgpu::BufferSize::new( - std::mem::size_of::() as wgpu::BufferAddress, - ), - }, - count: None, - }], - }); - - let vertex_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Vertex Bind Group"), - layout: &vertex_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { - buffer: vertex_uniform_buf, - offset: 0, - size: wgpu::BufferSize::new( - std::mem::size_of::() as wgpu::BufferAddress - ), - }), - }], - }); - - (vertex_bind_group_layout, vertex_bind_group) - } - - fn create_fragment_bind_groups( - device: &wgpu::Device, - blend_uniform_buf: &wgpu::Buffer, - combine_uniform_buf: &wgpu::Buffer, - frame_uniform_buf: &wgpu::Buffer, - ) -> (wgpu::BindGroupLayout, wgpu::BindGroup) { - let fragment_uniform_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Fragment Uniform Group Layout"), - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: wgpu::BufferSize::new(std::mem::size_of::< - FragmentBlendUniforms, - >() - as wgpu::BufferAddress), - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: wgpu::BufferSize::new(std::mem::size_of::< - FragmentCombineUniforms, - >() - as wgpu::BufferAddress), - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: wgpu::BufferSize::new(std::mem::size_of::< - FragmentFrameUniforms, - >() - as wgpu::BufferAddress), - }, - count: None, - }, - ], - }); - - let fragment_uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Fragment Uniform Group"), - layout: &fragment_uniform_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { - buffer: blend_uniform_buf, - offset: 0, - size: wgpu::BufferSize::new( - std::mem::size_of::() as wgpu::BufferAddress - ), - }), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { - buffer: combine_uniform_buf, - offset: 0, - size: wgpu::BufferSize::new( - std::mem::size_of::() as wgpu::BufferAddress - ), - }), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { - buffer: frame_uniform_buf, - offset: 0, - size: wgpu::BufferSize::new( - std::mem::size_of::() as wgpu::BufferAddress - ), - }), - }, - ], - }); - - ( - fragment_uniform_bind_group_layout, - fragment_uniform_bind_group, - ) - } - - fn create_textures_bind_group( - &self, - device: &wgpu::Device, - program: &WgpuProgram, - texture_bind_group_layout: &wgpu::BindGroupLayout, - ) -> wgpu::BindGroup { - let mut texture_bind_group_entries: Vec = Vec::new(); - - for i in 0..2 { - let texture_index = format!("USE_TEXTURE{}", i); - if program.get_define_bool(&texture_index) { - texture_bind_group_entries.push(wgpu::BindGroupEntry { - binding: i * 2, - resource: wgpu::BindingResource::TextureView( - &self.textures[self.current_texture_ids[i as usize]].texture_view, - ), - }); - - texture_bind_group_entries.push(wgpu::BindGroupEntry { - binding: (i * 2 + 1), - resource: wgpu::BindingResource::Sampler( - self.textures[self.current_texture_ids[i as usize]] - .sampler - .as_ref() - .unwrap(), - ), - }); - } - } - - device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: texture_bind_group_layout, - entries: &texture_bind_group_entries, - label: None, - }) - } - - fn gfx_cm_to_wgpu(val: u32) -> wgpu::AddressMode { - if val & G_TX::CLAMP as u32 != 0 { - return wgpu::AddressMode::ClampToEdge; - } - - if val & G_TX::MIRROR as u32 != 0 { - return wgpu::AddressMode::MirrorRepeat; - } - - wgpu::AddressMode::Repeat - } -} - -impl WgpuGraphicsDevice { - pub fn new(config: &wgpu::SurfaceConfiguration, device: &wgpu::Device) -> Self { - // Create the depth texture - let depth_texture = Self::create_depth_texture(config, device); - - // Create vertex buffer - let vertex_buf = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Vertex Buffer"), - size: 256 * 32 * 3 * ::std::mem::size_of::() as u64 * 50, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - // Create the uniform buffers - let vertex_uniform_buf = Self::create_vertex_uniforms(device); - let (blend_uniform_buf, combine_uniform_buf, frame_uniform_buf) = - Self::create_fragment_uniforms(device); - - // Create the bind groups - let (vertex_bind_group_layout, vertex_bind_group) = - Self::create_vertex_bind_groups(device, &vertex_uniform_buf); - let (fragment_uniform_bind_group_layout, fragment_uniform_bind_group) = - Self::create_fragment_bind_groups( - device, - &blend_uniform_buf, - &combine_uniform_buf, - &frame_uniform_buf, - ); - - Self { - depth_texture, - - vertex_buf, - - vertex_uniform_buf, - vertex_bind_group_layout, - vertex_bind_group, - - blend_uniform_buf, - combine_uniform_buf, - frame_uniform_buf, - fragment_uniform_bind_group_layout, - fragment_uniform_bind_group, - - shader_cache: HashMap::new(), - current_shader: 0, - - textures: Vec::new(), - active_texture: 0, - current_texture_ids: [0; 2], - - frame_count: 0, - current_height: 0, - } - } - - pub fn resize(&mut self, config: &wgpu::SurfaceConfiguration, device: &wgpu::Device) { - self.depth_texture = Self::create_depth_texture(config, device); - } - - pub fn update_frame_count(&mut self) { - self.frame_count += 1; - } - - pub fn update_current_height(&mut self, height: i32) { - self.current_height = height; - } - - pub fn select_program( - &mut self, - device: &wgpu::Device, - shader_hash: u64, - other_mode_h: u32, - other_mode_l: u32, - geometry_mode: u32, - combine: CombineParams, - ) { - // check if the shader is already loaded - if self.current_shader == shader_hash { - return; - } - - // unload the current shader - if self.current_shader != 0 { - self.current_shader = 0; - } - - // check if the shader is in the cache - if self.shader_cache.contains_key(&shader_hash) { - self.current_shader = shader_hash; - return; - } - - // create the shader and add it to the cache - let mut program = WgpuProgram::new(other_mode_h, other_mode_l, geometry_mode, combine); - program.init(); - program.preprocess(); - - program.compiled_program = - Some(device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: None, - source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&program.processed_shader)), - })); - - self.current_shader = shader_hash; - self.shader_cache.insert(shader_hash, program); - } - - pub fn bind_texture( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - tile: usize, - texture: &mut GraphicsIntermediateTexture, - ) { - // check if we've already uploaded this texture to the GPU - if let Some(texture_id) = texture.device_id { - self.active_texture = tile; - self.current_texture_ids[tile] = texture_id as usize; - - return; - } - - // Create device texture - let texture_extent = wgpu::Extent3d { - width: texture.width, - height: texture.height, - depth_or_array_layers: 1, - }; - - let device_texture = device.create_texture(&wgpu::TextureDescriptor { - label: None, - size: texture_extent, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8Unorm, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - view_formats: &[], - }); - - // Write data to the device texture - let bytes_per_pixel = 4; - let bytes_per_row = bytes_per_pixel * texture.width; - - queue.write_texture( - device_texture.as_image_copy(), - &texture.data, - wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: Some(bytes_per_row), - rows_per_image: None, - }, - texture_extent, - ); - - // Create the texture - let texture_view = device_texture.create_view(&wgpu::TextureViewDescriptor::default()); - - self.active_texture = tile; - self.current_texture_ids[tile] = self.textures.len(); - texture.device_id = Some(self.textures.len() as u32); - - self.textures.push(TextureData::new(texture_view)); - } - - pub fn bind_sampler( - &mut self, - device: &wgpu::Device, - tile: usize, - sampler: &GraphicsIntermediateSampler, - ) { - if let Some(texture_data) = self.textures.get_mut(self.current_texture_ids[tile]) { - texture_data.sampler = Some(device.create_sampler(&wgpu::SamplerDescriptor { - label: None, - address_mode_u: Self::gfx_cm_to_wgpu(sampler.clamp_s), - address_mode_v: Self::gfx_cm_to_wgpu(sampler.clamp_t), - address_mode_w: wgpu::AddressMode::Repeat, - mag_filter: if sampler.linear_filter { - wgpu::FilterMode::Linear - } else { - wgpu::FilterMode::Nearest - }, - min_filter: if sampler.linear_filter { - wgpu::FilterMode::Linear - } else { - wgpu::FilterMode::Nearest - }, - ..Default::default() - })); - } - } - - pub fn update_uniforms( - &mut self, - queue: &wgpu::Queue, - projection_matrix: glam::Mat4, - fog: &GraphicsIntermediateFogParams, - uniforms: &GraphicsIntermediateUniforms, - ) { - // Grab current program - let program = self.shader_cache.get_mut(&self.current_shader).unwrap(); - - // Update the vertex uniforms - if program.get_define_bool("USE_FOG") { - let uniform = VertexWithFogUniforms { - projection_matrix: projection_matrix.transpose().to_cols_array_2d(), - fog_multiplier: fog.multiplier as f32, - fog_offset: fog.offset as f32, - _pad: [0.0; 2], - }; - - queue.write_buffer(&self.vertex_uniform_buf, 0, bytemuck::bytes_of(&uniform)); - } else { - let uniform = VertexUniforms { - projection_matrix: projection_matrix.transpose().to_cols_array_2d(), - _pad: [0.0; 4], - }; - - queue.write_buffer(&self.vertex_uniform_buf, 0, bytemuck::bytes_of(&uniform)); - } - - // Update the blend uniforms - let uniform = FragmentBlendUniforms { - blend_color: uniforms.blend.blend_color.to_array(), - fog_color: uniforms.blend.fog_color.to_array(), - }; - - queue.write_buffer(&self.blend_uniform_buf, 0, bytemuck::bytes_of(&uniform)); - - // Update the combine uniforms - let uniform = FragmentCombineUniforms { - prim_color: uniforms.combine.prim_color.to_array(), - env_color: uniforms.combine.env_color.to_array(), - key_center: uniforms.combine.key_center.to_array(), - _pad: 0, - key_scale: uniforms.combine.key_scale.to_array(), - __pad: 0, - prim_lod_frac: uniforms.combine.prim_lod.x, - convert_k4: uniforms.combine.convert_k4, - convert_k5: uniforms.combine.convert_k5, - ___pad: 0, - }; - - queue.write_buffer(&self.combine_uniform_buf, 0, bytemuck::bytes_of(&uniform)); - - // Update the frame uniforms - let uniform = FragmentFrameUniforms { - count: self.frame_count as u32, - height: self.current_height as u32, - }; - - queue.write_buffer(&self.frame_uniform_buf, 0, bytemuck::bytes_of(&uniform)); - } - - pub fn create_pipeline( - &mut self, - device: &wgpu::Device, - surface_texture_format: wgpu::TextureFormat, - blend_state: Option, - cull_mode: Option, - depth_stencil: Option, - ) -> (wgpu::BindGroupLayout, wgpu::RenderPipeline) { - // Grab current program - let program = self.shader_cache.get_mut(&self.current_shader).unwrap(); - - // Create the texture bind group layout - let texture_bind_group_layout = program.create_texture_bind_group_layout(device); - - // Create the pipeline layout - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Pipeline Layout"), - bind_group_layouts: &[ - &self.vertex_bind_group_layout, - &self.fragment_uniform_bind_group_layout, - &texture_bind_group_layout, - ], - push_constant_ranges: &[], - }); - - // Create color target state - let color_target_states = wgpu::ColorTargetState { - format: surface_texture_format, - blend: blend_state, - write_mask: wgpu::ColorWrites::ALL, - }; - - // Depth stencil state - let depth_stencil = depth_stencil.map(|ds| wgpu::DepthStencilState { - format: Self::DEPTH_FORMAT, - depth_write_enabled: ds.depth_write_enabled, - depth_compare: ds.depth_compare, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState { - constant: 0, - slope_scale: if ds.polygon_offset { -2.0 } else { 0.0 }, - clamp: 0.0, - }, - }); - - // Create pipeline descriptor - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Render Pipeline"), - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: program.compiled_program.as_ref().unwrap(), - entry_point: "vs_main", - buffers: &[program.vertex_description()], - }, - fragment: Some(wgpu::FragmentState { - module: program.compiled_program.as_ref().unwrap(), - entry_point: "fs_main", - targets: &[Some(color_target_states)], - }), - primitive: wgpu::PrimitiveState { - cull_mode, - ..Default::default() - }, - depth_stencil, - multisample: wgpu::MultisampleState::default(), - multiview: None, - }); - - (texture_bind_group_layout, pipeline) - } - - pub fn draw_triangles( - &mut self, - draw_call_index: usize, - view: &wgpu::TextureView, - device: &wgpu::Device, - _queue: &wgpu::Queue, - encoder: &mut wgpu::CommandEncoder, - pipeline: &wgpu::RenderPipeline, - texture_bind_group_layout: &wgpu::BindGroupLayout, - viewport: &glam::Vec4, - scissor: [u32; 4], - buf_vbo: &[u8], - num_tris: usize, - ) { - // Grab current program - let program = self.shader_cache.get(&self.current_shader).unwrap(); - - // Render the triangles - encoder.push_debug_group(&format!("draw triangle pass: {}", draw_call_index)); - - { - // Create the texture bind groups - let textures_bind_group = - self.create_textures_bind_group(device, program, texture_bind_group_layout); - - // Copy the vertex data to the buffer - let staging_vertex_buffer = - device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Vertex Staging Buffer"), - contents: buf_vbo, - usage: wgpu::BufferUsages::COPY_SRC, - }); - - encoder.copy_buffer_to_buffer( - &staging_vertex_buffer, - 0, - &self.vertex_buf, - 0, - buf_vbo.len() as u64, - ); - - // queue.write_buffer(&self.vertex_buf, 0, buf_vbo); - - // Create the render pass - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some(&format!("Game Render Pass: {}", draw_call_index)), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - })], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }), - stencil_ops: None, - }), - }); - - pass.push_debug_group("Prepare data for draw."); - pass.set_pipeline(pipeline); - pass.set_bind_group(0, &self.vertex_bind_group, &[]); - pass.set_bind_group(1, &self.fragment_uniform_bind_group, &[]); - pass.set_bind_group(2, &textures_bind_group, &[]); - pass.set_vertex_buffer(0, self.vertex_buf.slice(..)); - pass.set_viewport(viewport.x, viewport.y, viewport.z, viewport.w, 0.0, 1.0); - pass.set_scissor_rect(scissor[0], scissor[1], scissor[2], scissor[3]); - pass.pop_debug_group(); - pass.insert_debug_marker("Draw!"); - pass.draw(0..(num_tris * 3) as u32, 0..1); - } - - encoder.pop_debug_group(); - } -} diff --git a/src/gui/renderer/wgpu_program.rs b/src/gui/renderer/wgpu_program.rs deleted file mode 100644 index 301ee5e..0000000 --- a/src/gui/renderer/wgpu_program.rs +++ /dev/null @@ -1,652 +0,0 @@ -use std::collections::HashMap; - -use wgpu::{ - BindGroupLayout, ShaderModule, VertexAttribute, VertexBufferLayout, VertexFormat, - VertexStepMode, -}; - -use crate::fast3d::{ - gbi::utils::{ - get_cycle_type_from_other_mode_h, get_textfilter_from_other_mode_h, - other_mode_l_alpha_compare_dither, other_mode_l_alpha_compare_threshold, - other_mode_l_uses_alpha, other_mode_l_uses_fog, other_mode_l_uses_texture_edge, - }, - rdp::OtherModeHCycleType, - utils::{ - color_combiner::{CombineParams, ACMUX, CCMUX}, - texture::TextFilt, - }, -}; - -pub struct WgpuProgram { - // Compiled program. - pub processed_shader: String, - pub compiled_program: Option, - - // inputs - pub both: String, - pub vertex: String, - pub fragment: String, - pub defines: HashMap, - - // configurators - other_mode_h: u32, - other_mode_l: u32, - geometry_mode: u32, - combine: CombineParams, - - pub num_floats: usize, -} - -impl WgpuProgram { - // MARK: - Defines - pub fn defines_changed(&mut self) { - self.processed_shader = "".to_string(); - } - - pub fn set_define_string(&mut self, name: String, v: Option) -> bool { - if let Some(v) = v { - if self.defines.get(&name) == Some(&v) { - return false; - } - self.defines.insert(name, v); - } else { - if !self.defines.contains_key(&name) { - return false; - } - self.defines.remove(&name); - } - - self.defines_changed(); - true - } - - pub fn set_define_bool(&mut self, name: String, v: bool) -> bool { - self.set_define_string(name, if v { Some("1".to_string()) } else { None }) - } - - pub fn get_define_string(&self, name: &str) -> Option<&String> { - self.defines.get(name) - } - - pub fn get_define_bool(&self, name: &str) -> bool { - let str = self.get_define_string(name); - - if let Some(str) = str { - assert_eq!(str, "1"); - } - - str.is_some() - } - - // MARK: - Preprocessing - - pub fn preprocess(&mut self) { - if !self.processed_shader.is_empty() { - return; - } - - self.processed_shader = format!( - "{both}{vertex}{fragment}", - both = self.both, - vertex = self.vertex, - fragment = self.fragment, - ); - } - - // MARK: - Defaults - - pub fn new( - other_mode_h: u32, - other_mode_l: u32, - geometry_mode: u32, - combine: CombineParams, - ) -> Self { - Self { - processed_shader: "".to_string(), - compiled_program: None, - - both: "".to_string(), - vertex: "".to_string(), - fragment: "".to_string(), - defines: HashMap::new(), - - other_mode_h, - other_mode_l, - geometry_mode, - combine, - - num_floats: 0, - } - } - - pub fn init(&mut self) { - // for debugging - self.set_define_bool("USE_ALPHA_VISUALIZER".to_string(), false); - self.set_define_bool("ONLY_VERTEX_COLOR".to_string(), false); - - self.set_define_bool( - "TWO_CYCLE".to_string(), - get_cycle_type_from_other_mode_h(self.other_mode_h) - == OtherModeHCycleType::G_CYC_2CYCLE, - ); - self.set_define_bool("USE_TEXTURE0".to_string(), self.combine.uses_texture0()); - self.set_define_bool("USE_TEXTURE1".to_string(), self.combine.uses_texture1()); - self.set_define_bool( - "TEXTURE_EDGE".to_string(), - other_mode_l_uses_texture_edge(self.other_mode_l), - ); - - self.set_define_bool( - "USE_FOG".to_string(), - other_mode_l_uses_fog(self.other_mode_l), - ); - self.set_define_bool( - "USE_ALPHA".to_string(), - other_mode_l_uses_alpha(self.other_mode_l) - || other_mode_l_uses_texture_edge(self.other_mode_l), - ); - self.set_define_bool( - "ALPHA_COMPARE_DITHER".to_string(), - other_mode_l_alpha_compare_dither(self.other_mode_l), - ); - - self.set_define_bool( - "ALPHA_COMPARE_THRESHOLD".to_string(), - other_mode_l_alpha_compare_threshold(self.other_mode_l), - ); - - self.set_define_bool("COLOR_ALPHA_SAME".to_string(), self.combine.cc_ac_same(0)); - - self.num_floats = 8; - - if self.get_define_bool("USE_TEXTURE0") || self.get_define_bool("USE_TEXTURE1") { - self.num_floats += 2; - } - - self.both = format!( - r#" - const tZero = vec4(0.0, 0.0, 0.0, 0.0); - const tHalf = vec4(0.5 ,0.5, 0.5, 0.5); - const tOne = vec4(1.0 ,1.0, 1.0, 1.0); - - const DRAWING_RECT: f32 = 0.0; - - struct VertexInput {{ - @location(0) position: vec4, - @location(1) color: vec4, - {uv_input} - }}; - - struct VertexOutput {{ - @location(0) color: vec4, - {uv_output} - @builtin(position) position: vec4, - }}; - - "#, - uv_input = self.on_defined( - &["USE_TEXTURE0", "USE_TEXTURE1"], - "@location(2) uv: vec2," - ), - uv_output = self.on_defined( - &["USE_TEXTURE0", "USE_TEXTURE1"], - "@location(1) uv: vec2," - ), - ); - - self.vertex = self.generate_vertex(); - - self.fragment = self.generate_fragment(); - } - - fn generate_vertex(&mut self) -> String { - let compute_uniform_fields = || { - if self.get_define_bool("USE_FOG") { - return r#" - fog_multiplier: f32, - fog_offset: f32, - "# - .to_string(); - } - - "_pad: vec2,".to_string() - }; - - let compute_color = || { - if self.get_define_bool("USE_FOG") { - return r#" - var fog_value = (max(0.0, out.position.z) - out.position.w) * uniforms.fog_multiplier + uniforms.fog_offset; - fog_value = clamp(fog_value, 0.0, 255.0); - out.color = vec4(in.color.xyz, fog_value); - "#.to_string(); - } - - "out.color = in.color;".to_string() - }; - - format!( - r#" - struct Uniforms {{ - projection_matrix: mat4x4, - {fog_params} - }} - - @group(0) @binding(0) - var uniforms: Uniforms; - - @vertex - fn vs_main(in: VertexInput) -> VertexOutput {{ - var out: VertexOutput; - - if (in.position.w == DRAWING_RECT) {{ - out.position = uniforms.projection_matrix * vec4(in.position.xyz, 1.0); - }} else {{ - out.position = uniforms.projection_matrix * in.position; - }} - - // map z to [0, 1] - out.position.z = (out.position.z + out.position.w) / (2.0 * out.position.w); - - {color} - - {uv} - - return out; - }} - "#, - uv = self.on_defined(&["USE_TEXTURE0", "USE_TEXTURE1"], "out.uv = in.uv;"), - fog_params = compute_uniform_fields(), - color = compute_color(), - ) - } - - fn generate_fragment(&mut self) -> String { - let tex_filter = match get_textfilter_from_other_mode_h(self.other_mode_h) { - TextFilt::G_TF_POINT => "Point", - TextFilt::G_TF_AVERAGE => "Average", - TextFilt::G_TF_BILERP => "Bilerp", - }; - - let color_input_common = |input| match input { - CCMUX::COMBINED => "comb_color.rgb", - CCMUX::TEXEL0 => "tex0.rgb", - CCMUX::TEXEL1 => "tex1.rgb", - CCMUX::PRIMITIVE => "combine_uniforms.prim_color.rgb", - CCMUX::SHADE => "shade_color.rgb", - CCMUX::ENVIRONMENT => "combine_uniforms.env_color.rgb", - _ => panic!("Should be unreachable"), - }; - - let color_input_a = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "tOne.rgb", // matching against ONE - CCMUX::COMBINED_ALPHA__NOISE__K4 => "vec3(noise, noise, noise)", // matching against NOISE - _ => "tZero.rgb", - } - } - }; - - let color_input_b = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "combine_uniforms.key_center", // matching against CENTER - CCMUX::COMBINED_ALPHA__NOISE__K4 => "vec3(combine_uniforms.convert_k4, combine_uniforms.convert_k4, combine_uniforms.convert_k4)", // matching against K4 - _ => "tZero.rgb", - } - } - }; - - let color_input_c = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "combine_uniforms.key_scale", // matching against SCALE - CCMUX::COMBINED_ALPHA__NOISE__K4 => "comb_color.aaa", // matching against COMBINED_ALPHA - CCMUX::TEXEL0_ALPHA => "tex0.aaa", - CCMUX::TEXEL1_ALPHA => "tex1.aaa", - CCMUX::PRIMITIVE_ALPHA => "combine_uniforms.prim_color.aaa", - CCMUX::SHADE_ALPHA => "shade_color.aaa", - CCMUX::ENV_ALPHA => "combine_uniforms.env_color.aaa", - CCMUX::LOD_FRACTION => "tZero.rgb", // TODO: LOD FRACTION - CCMUX::PRIM_LOD_FRACTION => "vec3(combine_uniforms.prim_lod_frac, combine_uniforms.prim_lod_frac, combine_uniforms.prim_lod_frac)", - CCMUX::K5 => "vec3(combine_uniforms.convert_k5, combine_uniforms.convert_k5, combine_uniforms.convert_k5)", - _ => "tZero.rgb", - } - } - }; - - let color_input_d = |input| { - if input <= CCMUX::ENVIRONMENT { - color_input_common(input) - } else { - match input { - CCMUX::CENTER__SCALE__ONE => "tOne.rgb", // matching against ONE - _ => "tZero.rgb", - } - } - }; - - let alpha_input_abd = |input| { - match input { - ACMUX::COMBINED__LOD_FRAC => "comb_color.a", // matching against COMBINED - ACMUX::TEXEL0 => "tex0.a", - ACMUX::TEXEL1 => "tex1.a", - ACMUX::PRIMITIVE => "combine_uniforms.prim_color.a", - ACMUX::SHADE => { - if self.get_define_bool("USE_FOG") { - "tOne.a" - } else { - "shade_color.a" - } - } - ACMUX::ENVIRONMENT => "combine_uniforms.env_color.a", - ACMUX::PRIM_LOD_FRAC__ONE => "tOne.a", // matching against ONE - _ => "tZero.a", - } - }; - - let alpha_input_c = |input| { - match input { - ACMUX::COMBINED__LOD_FRAC => "tZero.a", // TODO: LOD_FRAC - ACMUX::TEXEL0 => "tex0.a", - ACMUX::TEXEL1 => "tex1.a", - ACMUX::PRIMITIVE => "combine_uniforms.prim_color.a", - ACMUX::SHADE => "shade_color.a", - ACMUX::ENVIRONMENT => "combine_uniforms.env_color.a", - ACMUX::PRIM_LOD_FRAC__ONE => "combine_uniforms.prim_lod_frac", - _ => "tZero.a", - } - }; - - format!( - r#" - struct BlendParamsUniforms {{ - blend_color: vec4, - fog_color: vec4, - }}; - - struct CombineParamsUniforms {{ - prim_color: vec4, - env_color: vec4, - key_center: vec3, - key_scale: vec3, - prim_lod_frac: f32, - convert_k4: f32, - convert_k5: f32, - }}; - - struct FrameUniforms {{ - count: u32, - height: u32, - }}; - - @group(1) @binding(0) - var blend_uniforms: BlendParamsUniforms; - @group(1) @binding(1) - var combine_uniforms: CombineParamsUniforms; - @group(1) @binding(2) - var frame_uniforms: FrameUniforms; - - {tex0_bindings} - - {tex1_bindings} - - fn random(value: vec3) -> f32 {{ - var random = dot(sin(value), vec3(12.9898, 78.233, 37.719)); - return fract(sin(random) * 143758.5453); - }} - - fn textureSampleN64Point(tex: texture_2d, samplr: sampler, uv: vec2) -> vec4 {{ - return textureSample(tex, samplr, uv); - }} - - fn textureSampleN64Average(tex: texture_2d, samplr: sampler, uv: vec2) -> vec4 {{ - // Unimplemented. - return textureSample(tex, samplr, uv); - }} - - fn textureSampleN64Bilerp(tex: texture_2d, samplr: sampler, uv: vec2) -> vec4 {{ - var tex_size = vec2(textureDimensions(tex, 0)); - var offset = fract(uv * tex_size - 0.5); - - var offset_sign = sign(offset); - var offset_abs = abs(offset); - - var s0 = textureSample(tex, samplr, uv - offset / tex_size); - var s1 = textureSample(tex, samplr, uv - offset_sign * vec2(1.0, 0.0) / tex_size); - var s2 = textureSample(tex, samplr, uv - offset_sign * vec2(0.0, 1.0) / tex_size); - - return s0 + offset_abs.x * (s1 - s0) + offset_abs.y * (s2 - s0); - }} - - fn combineColorCycle0(comb_color: vec4, shade_color: vec4, tex0: vec4, tex1: vec4, noise: f32) -> vec3 {{ - return ({c0a} - {c0b}) * {c0c} + {c0d}; - }} - - fn combineAlphaCycle0(comb_color: vec4, shade_color: vec4, tex0: vec4, tex1: vec4, noise: f32) -> f32 {{ - return ({a0a} - {a0b}) * {a0c} + {a0d}; - }} - - fn combineColorCycle1(comb_color: vec4, shade_color: vec4, tex0: vec4, tex1: vec4, noise: f32) -> vec3 {{ - return ({c1a} - {c1b}) * {c1c} + {c1d}; - }} - - fn combineAlphaCycle1(comb_color: vec4, shade_color: vec4, tex0: vec4, tex1: vec4, noise: f32) -> f32 {{ - return ({a1a} - {a1b}) * {a1c} + {a1d}; - }} - - @fragment - fn fs_main(in: VertexOutput) -> @location(0) vec4 {{ - var tex_val0 = tOne; - var tex_val1 = tOne; - - {sample_texture0} - {sample_texture1} - - var noise = (random(vec3(floor(in.position.xy * (240.0 / f32(frame_uniforms.height))), f32(frame_uniforms.count))) + 1.0) / 2.0; - - var texel = vec4( - combineColorCycle0(tHalf, in.color, tex_val0, tex_val1, noise), - combineAlphaCycle0(tHalf, in.color, tex_val0, tex_val1, noise) - ); - - {second_pass_combine} - - {alpha_compare_dither} - {alpha_compare_threshold} - - {texture_edge} - - {alpha_visualizer} - - {blend_fog} - - return texel; - }} - "#, - tex0_bindings = self.on_defined( - &["USE_TEXTURE0"], - r#" - @group(2) @binding(0) - var texture0: texture_2d; - @group(2) @binding(1) - var sampler0: sampler; - "# - ), - tex1_bindings = self.on_defined( - &["USE_TEXTURE1"], - r#" - @group(2) @binding(2) - var texture1: texture_2d; - @group(2) @binding(3) - var sampler1: sampler; - "# - ), - c0a = color_input_a(self.combine.c0.a), - c0b = color_input_b(self.combine.c0.b), - c0c = color_input_c(self.combine.c0.c), - c0d = color_input_d(self.combine.c0.d), - a0a = alpha_input_abd(self.combine.a0.a), - a0b = alpha_input_abd(self.combine.a0.b), - a0c = alpha_input_c(self.combine.a0.c), - a0d = alpha_input_abd(self.combine.a0.d), - c1a = color_input_a(self.combine.c1.a), - c1b = color_input_b(self.combine.c1.b), - c1c = color_input_c(self.combine.c1.c), - c1d = color_input_d(self.combine.c1.d), - a1a = alpha_input_abd(self.combine.a1.a), - a1b = alpha_input_abd(self.combine.a1.b), - a1c = alpha_input_c(self.combine.a1.c), - a1d = alpha_input_abd(self.combine.a1.d), - sample_texture0 = self.on_defined_str( - &["USE_TEXTURE0"], - format!("tex_val0 = textureSampleN64{tex_filter}(texture0, sampler0, in.uv);") - ), - sample_texture1 = self.on_defined_str( - &["USE_TEXTURE1"], - format!("tex_val1 = textureSampleN64{tex_filter}(texture1, sampler1, in.uv);") - ), - second_pass_combine = self.on_defined( - &["TWO_CYCLE"], - r#" - // Note that in the second cycle, Tex0 and Tex1 are swapped - texel = vec4( - combineColorCycle1(texel, in.color tex_val1, tex_val0, noise), - combineAlphaCycle1(texel, in.color, tex_val1, tex_val0, noise) - ); - "#, - ), - alpha_compare_dither = self.on_defined( - &["USE_ALPHA", "ALPHA_COMPARE_DITHER"], - r#" - var random_alpha = floor(random(vec3(floor(in.position.xy * (240.0 / f32(frame_uniforms.height))), f32(frame_uniforms.count))) + 0.5); - if texel.a < random_alpha { discard; } - "#, - ), - alpha_compare_threshold = self.on_defined( - &["USE_ALPHA", "ALPHA_COMPARE_THRESHOLD"], - "if texel.a < blend_uniforms.blend_color.a { discard; }" - ), - texture_edge = self.on_defined( - &["USE_ALPHA", "TEXTURE_EDGE"], - "if texel.a < 0.125 { discard; }" - ), - alpha_visualizer = self.on_defined( - &["USE_ALPHA", "USE_ALPHA_VISUALIZER"], - "texel = mix(texel, vec4(1.0, 0.0, 1.0, 1.0), 0.5);" - ), - blend_fog = self.on_defined( - &["USE_FOG"], - "texel = vec4(mix(texel.rgb, blend_uniforms.fog_color.rgb, in.color.a), texel.a);" - ), - ) - } - - // MARK: - Pipeline Helpers - - pub fn vertex_description(&self) -> VertexBufferLayout<'static> { - VertexBufferLayout { - array_stride: (self.num_floats * ::std::mem::size_of::()) as u64, - step_mode: VertexStepMode::Vertex, - // TODO: Is there a better way to construct this? - attributes: if self.get_define_bool("USE_TEXTURE0") - || self.get_define_bool("USE_TEXTURE1") - { - &[ - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 0, // position - shader_location: 0, - }, - VertexAttribute { - format: VertexFormat::Float32x4, - offset: std::mem::size_of::<[f32; 4]>() as u64, // color - shader_location: 1, - }, - wgpu::VertexAttribute { - format: VertexFormat::Float32x2, - offset: std::mem::size_of::<[f32; 8]>() as u64, // texcoord - shader_location: 2, - }, - ] - } else { - &[ - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 0, // position - shader_location: 0, - }, - VertexAttribute { - format: VertexFormat::Float32x4, - offset: std::mem::size_of::<[f32; 4]>() as u64, // color - shader_location: 1, - }, - ] - }, - } - } - - pub fn create_texture_bind_group_layout(&self, device: &wgpu::Device) -> BindGroupLayout { - { - let mut group_layout_entries: Vec = Vec::new(); - - for i in 0..2 { - let texture_index = format!("USE_TEXTURE{}", i); - if self.get_define_bool(&texture_index) { - group_layout_entries.push(wgpu::BindGroupLayoutEntry { - binding: i * 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - }, - count: None, - }); - - group_layout_entries.push(wgpu::BindGroupLayoutEntry { - binding: (i * 2 + 1), - visibility: wgpu::ShaderStages::FRAGMENT, - // TODO: Is this the appropriate setting? - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }); - } - } - - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Textures/Samplers Group Layout"), - entries: &group_layout_entries, - }) - } - } - - // MARK: - Helpers - - fn on_defined(&self, def: &[&str], output: &'static str) -> &str { - if let Some(d) = def.iter().next() { - if self.get_define_bool(d) { - return output; - } - } - - "" - } - - fn on_defined_str(&self, def: &[&str], output: String) -> String { - if let Some(d) = def.iter().next() { - if self.get_define_bool(d) { - return output; - } - } - - "".to_string() - } -} diff --git a/src/gui/windows.rs b/src/gui/windows.rs index 66dd29a..5560a25 100644 --- a/src/gui/windows.rs +++ b/src/gui/windows.rs @@ -1,11 +1,11 @@ use imgui::{CollapsingHeader, TreeNode, Ui}; -use crate::fast3d::gbi::utils::{geometry_mode_uses_fog, geometry_mode_uses_lighting}; +use fast3d::gbi::utils::{geometry_mode_uses_fog, geometry_mode_uses_lighting}; -#[cfg(feature = "glium")] +#[cfg(feature = "opengl_renderer")] use super::gui_glium::Gui; -#[cfg(feature = "wgpu")] +#[cfg(feature = "wgpu_renderer")] use super::gui_wgpu::Gui; pub trait HelixWindows { diff --git a/src/lib.rs b/src/lib.rs index 97d4d1a..dcc0e2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,4 @@ use env_logger::Builder; -mod extensions; -pub mod fast3d; pub mod gamepad; pub mod gui; #[cfg(feature = "network")]