fast3d/
output.rs

1use crate::output::models::{
2    OutputFogParams, OutputSampler, OutputStencil, OutputUniforms, OutputUniformsBlend,
3    OutputUniformsCombine, OutputVBO,
4};
5use crate::output::texture_cache::TextureCacheId;
6use fast3d_gbi::defines::color_combiner::CombineParams;
7use fast3d_gbi::defines::{GeometryModes, WrapMode};
8use std::hash::Hash;
9use texture_cache::TextureCache;
10
11use self::gfx::{BlendState, CompareFunction, Face};
12
13pub mod gfx;
14pub mod models;
15pub mod texture_cache;
16
17const TEXTURE_CACHE_MAX_SIZE: usize = 500;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub struct ShaderId(pub ShaderConfig);
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub struct ShaderConfig {
24    pub other_mode_h: u32,
25    pub other_mode_l: u32,
26    pub geometry_mode: GeometryModes,
27    pub combine: CombineParams,
28}
29
30impl ShaderConfig {
31    pub const EMPTY: Self = {
32        Self {
33            other_mode_h: 0,
34            other_mode_l: 0,
35            geometry_mode: GeometryModes::empty(),
36            combine: CombineParams::ZERO,
37        }
38    };
39}
40
41#[derive(Debug, Clone)]
42pub struct IntermediateDrawCall {
43    // Shader Configuration
44    pub shader_id: ShaderId,
45    pub shader_config: ShaderConfig,
46
47    // Textures
48    pub texture_indices: [Option<TextureCacheId>; 2],
49
50    // Samplers
51    pub samplers: [Option<OutputSampler>; 2],
52
53    // Stencil
54    pub stencil: Option<OutputStencil>,
55
56    // Viewport
57    pub viewport: glam::Vec4,
58
59    // Scissor
60    pub scissor: [u32; 4],
61
62    // Blend State
63    pub blend_state: Option<BlendState>,
64
65    // Cull Mode
66    pub cull_mode: Option<Face>,
67
68    // Uniforms
69    pub uniforms: OutputUniforms,
70
71    // Triangle Data
72    pub vbo: OutputVBO,
73
74    // Projection Matrix
75    pub projection_matrix: glam::Mat4,
76
77    // Fog Params
78    pub fog: OutputFogParams,
79}
80
81impl IntermediateDrawCall {
82    pub const EMPTY: Self = IntermediateDrawCall {
83        shader_id: ShaderId(ShaderConfig::EMPTY),
84        shader_config: ShaderConfig::EMPTY,
85        texture_indices: [None; 2],
86        samplers: [None; 2],
87        stencil: None,
88        viewport: glam::Vec4::ZERO,
89        scissor: [0; 4],
90        blend_state: None,
91        cull_mode: None,
92        uniforms: OutputUniforms::EMPTY,
93        vbo: OutputVBO::EMPTY,
94        projection_matrix: glam::Mat4::ZERO,
95        fog: OutputFogParams::EMPTY,
96    };
97}
98
99pub struct RenderData {
100    pub texture_cache: TextureCache,
101    pub draw_calls: Vec<IntermediateDrawCall>,
102}
103
104impl Default for RenderData {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110impl RenderData {
111    pub fn new() -> Self {
112        RenderData {
113            texture_cache: TextureCache::new(TEXTURE_CACHE_MAX_SIZE),
114            // start draw calls with a default draw call
115            draw_calls: vec![IntermediateDrawCall::EMPTY],
116        }
117    }
118
119    fn current_draw_call(&mut self) -> &mut IntermediateDrawCall {
120        self.draw_calls.last_mut().unwrap()
121    }
122
123    fn new_draw_call(&mut self) {
124        let draw_call = self.current_draw_call();
125        let draw_call = draw_call.clone();
126        self.draw_calls.push(draw_call);
127    }
128
129    // Public API
130
131    pub fn clear_draw_calls(&mut self) {
132        let draw_call = self.current_draw_call();
133        let draw_call = draw_call.clone();
134        self.draw_calls = vec![draw_call];
135    }
136
137    pub fn clear_textures(&mut self, index: usize) {
138        let draw_call = self.current_draw_call();
139        draw_call.texture_indices[index] = None;
140    }
141
142    pub fn set_program_params(
143        &mut self,
144        other_mode_h: u32,
145        other_mode_l: u32,
146        geometry_mode: GeometryModes,
147        combine: CombineParams,
148    ) {
149        let draw_call = self.current_draw_call();
150        let shader_config = ShaderConfig {
151            other_mode_h,
152            other_mode_l,
153            geometry_mode,
154            combine,
155        };
156
157        draw_call.shader_id = ShaderId(shader_config);
158        draw_call.shader_config = shader_config;
159    }
160
161    pub fn set_texture(&mut self, tile: usize, cache_id: TextureCacheId) {
162        let draw_call = self.current_draw_call();
163        draw_call.texture_indices[tile] = Some(cache_id);
164    }
165
166    pub fn set_sampler_parameters(
167        &mut self,
168        tile: usize,
169        linear_filter: bool,
170        clamp_s: WrapMode,
171        clamp_t: WrapMode,
172    ) {
173        let draw_call = self.current_draw_call();
174        draw_call.samplers[tile] = Some(OutputSampler {
175            tile,
176            linear_filter,
177            clamp_s,
178            clamp_t,
179        });
180    }
181
182    pub fn set_depth_stencil_params(
183        &mut self,
184        _depth_test_enabled: bool,
185        depth_write_enabled: bool,
186        depth_compare: CompareFunction,
187        polygon_offset: bool,
188    ) {
189        let draw_call = self.current_draw_call();
190        draw_call.stencil = Some(OutputStencil {
191            depth_write_enabled,
192            depth_compare,
193            polygon_offset,
194        });
195    }
196
197    pub fn set_projection_matrix(&mut self, matrix: glam::Mat4) {
198        let draw_call = self.current_draw_call();
199        draw_call.projection_matrix = matrix;
200    }
201
202    pub fn set_fog(&mut self, multiplier: i16, offset: i16) {
203        let draw_call = self.current_draw_call();
204        draw_call.fog = OutputFogParams { multiplier, offset };
205    }
206
207    pub fn set_viewport(&mut self, x: f32, y: f32, width: f32, height: f32) {
208        let draw_call = self.current_draw_call();
209        draw_call.viewport = glam::Vec4::new(x, y, width, height);
210    }
211
212    pub fn set_scissor(&mut self, x: u32, y: u32, width: u32, height: u32) {
213        let draw_call = self.current_draw_call();
214        draw_call.scissor = [x, y, width, height];
215    }
216
217    pub fn set_blend_state(&mut self, blend_state: Option<BlendState>) {
218        let draw_call = self.current_draw_call();
219        draw_call.blend_state = blend_state;
220    }
221
222    pub fn set_cull_mode(&mut self, cull_mode: Option<Face>) {
223        let draw_call = self.current_draw_call();
224        draw_call.cull_mode = cull_mode;
225    }
226
227    #[allow(clippy::too_many_arguments)]
228    pub fn set_uniforms(
229        &mut self,
230        fog_color: glam::Vec4,
231        blend_color: glam::Vec4,
232        prim_color: glam::Vec4,
233        env_color: glam::Vec4,
234        key_center: glam::Vec3,
235        key_scale: glam::Vec3,
236        prim_lod: glam::Vec2,
237        convert_k: [i32; 6],
238    ) {
239        let draw_call = self.current_draw_call();
240        draw_call.uniforms = OutputUniforms {
241            blend: OutputUniformsBlend {
242                fog_color,
243                blend_color,
244            },
245            combine: OutputUniformsCombine {
246                prim_color,
247                env_color,
248                key_center,
249                key_scale,
250                prim_lod,
251                convert_k4: convert_k[4] as f32 / 255.0,
252                convert_k5: convert_k[5] as f32 / 255.0,
253            },
254        };
255    }
256
257    pub fn set_vbo(&mut self, vbo: Vec<u8>, num_tris: usize) {
258        let draw_call = self.current_draw_call();
259        draw_call.vbo = OutputVBO { vbo, num_tris };
260
261        // start a new draw call that's a copy of the current one
262        // we do this cause atm we only set properties on changes
263        self.new_draw_call();
264    }
265}