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 pub shader_id: ShaderId,
45 pub shader_config: ShaderConfig,
46
47 pub texture_indices: [Option<TextureCacheId>; 2],
49
50 pub samplers: [Option<OutputSampler>; 2],
52
53 pub stencil: Option<OutputStencil>,
55
56 pub viewport: glam::Vec4,
58
59 pub scissor: [u32; 4],
61
62 pub blend_state: Option<BlendState>,
64
65 pub cull_mode: Option<Face>,
67
68 pub uniforms: OutputUniforms,
70
71 pub vbo: OutputVBO,
73
74 pub projection_matrix: glam::Mat4,
76
77 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 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 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 self.new_draw_call();
264 }
265}