fast3d/gbi/
common.rs

1use crate::gbi::macros::gbi_command;
2use crate::gbi::utils::get_cmd;
3use crate::gbi::{GBICommandParams, GBICommandRegistry, GBIResult};
4use fast3d_gbi::defines::{CombineParams, OpCode, WrapMode};
5
6use crate::models::texture::TextureImageState;
7
8use crate::rdp::SCREEN_HEIGHT;
9use crate::rsp::RSP;
10
11pub struct Common;
12impl Common {
13    pub fn setup(gbi: &mut GBICommandRegistry, _rsp: &mut RSP) {
14        gbi.register(OpCode::NOOP.bits(), RDPNoOp);
15        gbi.register(OpCode::TEXRECT.bits(), RDPTextureRectangle);
16        gbi.register(OpCode::TEXRECTFLIP.bits(), RDPTextureRectangle);
17        gbi.register(OpCode::FILLRECT.bits(), RDPFillRectangle);
18        gbi.register(OpCode::SET_COLORIMG.bits(), RDPSetColorImage);
19        gbi.register(OpCode::SET_DEPTHIMG.bits(), RDPSetDepthImage);
20        gbi.register(OpCode::SET_TEXIMG.bits(), RDPSetTextureImage);
21        gbi.register(OpCode::SET_COMBINE.bits(), RDPSetCombine);
22        gbi.register(OpCode::SET_TILE.bits(), RDPSetTile);
23        gbi.register(OpCode::SET_TILESIZE.bits(), RDPSetTileSize);
24        gbi.register(OpCode::SET_ENVCOLOR.bits(), RDPSetEnvColor);
25        gbi.register(OpCode::SET_PRIMCOLOR.bits(), RDPSetPrimColor);
26        gbi.register(OpCode::SET_BLENDCOLOR.bits(), RDPSetBlendColor);
27        gbi.register(OpCode::SET_FOGCOLOR.bits(), RDPSetFogColor);
28        gbi.register(OpCode::SET_FILLCOLOR.bits(), RDPSetFillColor);
29        // TODO: PRIM_DEPTH
30        gbi.register(OpCode::SET_SCISSOR.bits(), RDPSetScissor);
31        gbi.register(OpCode::SET_CONVERT.bits(), RDPSetConvert);
32        gbi.register(OpCode::SET_KEYR.bits(), RDPSetKeyR);
33        gbi.register(OpCode::SET_KEYGB.bits(), RDPSetKeyGB);
34        gbi.register(OpCode::LOAD_TILE.bits(), RDPLoadTile);
35        gbi.register(OpCode::LOAD_BLOCK.bits(), RDPLoadBlock);
36        gbi.register(OpCode::LOAD_TLUT.bits(), RDPLoadTLUT);
37        gbi.register(OpCode::RDPLOADSYNC.bits(), RDPLoadSync);
38        gbi.register(OpCode::RDPPIPESYNC.bits(), RDPPipeSync);
39        gbi.register(OpCode::RDPTILESYNC.bits(), RDPTileSync);
40        gbi.register(OpCode::RDPFULLSYNC.bits(), RDPFullSync);
41        gbi.register(OpCode::RDPSETOTHERMODE.bits(), RDPSetOtherMode);
42    }
43}
44
45gbi_command!(RDPNoOp, |_| { GBIResult::Continue });
46gbi_command!(RDPLoadSync, |_| { GBIResult::Continue });
47gbi_command!(RDPPipeSync, |_| { GBIResult::Continue });
48gbi_command!(RDPTileSync, |_| { GBIResult::Continue });
49gbi_command!(RDPFullSync, |_| { GBIResult::Continue });
50
51gbi_command!(RDPSetColorImage, |params: &mut GBICommandParams| {
52    let w0 = unsafe { (*(*params.command)).words.w0 };
53    let w1 = unsafe { (*(*params.command)).words.w1 };
54
55    let _format = get_cmd(w0, 21, 3);
56    let _size = get_cmd(w0, 19, 2);
57    let _width = get_cmd(w0, 0, 12) + 1;
58
59    params.rdp.color_image = params.rsp.get_segment(w1);
60    GBIResult::Continue
61});
62
63gbi_command!(RDPSetDepthImage, |params: &mut GBICommandParams| {
64    let w1 = unsafe { (*(*params.command)).words.w1 };
65
66    params.rdp.depth_image = params.rsp.get_segment(w1);
67    GBIResult::Continue
68});
69
70gbi_command!(RDPSetTextureImage, |params: &mut GBICommandParams| {
71    let w0 = unsafe { (*(*params.command)).words.w0 };
72    let w1 = unsafe { (*(*params.command)).words.w1 };
73
74    let format = get_cmd(w0, 21, 3) as u8;
75    let size = get_cmd(w0, 19, 2) as u8;
76    let width = get_cmd(w0, 0, 12) as u16 + 1;
77    let address = params.rsp.get_segment(w1);
78
79    params.rdp.texture_image_state = TextureImageState {
80        format,
81        size,
82        width,
83        address,
84    };
85
86    GBIResult::Continue
87});
88
89gbi_command!(RDPSetCombine, |params: &mut GBICommandParams| {
90    let w0 = unsafe { (*(*params.command)).words.w0 };
91    let w1 = unsafe { (*(*params.command)).words.w1 };
92    params.rdp.set_combine(CombineParams::decode(w0, w1));
93
94    GBIResult::Continue
95});
96
97gbi_command!(RDPSetTile, |params: &mut GBICommandParams| {
98    let w0 = unsafe { (*(*params.command)).words.w0 };
99    let w1 = unsafe { (*(*params.command)).words.w1 };
100
101    let format = get_cmd(w0, 21, 3) as u8;
102    let size = get_cmd(w0, 19, 2) as u8;
103    let line = get_cmd(w0, 9, 9) as u16;
104    let tmem = get_cmd(w0, 0, 9) as u16;
105    let tile = get_cmd(w1, 24, 3) as u8;
106    let palette = get_cmd(w1, 20, 4) as u8;
107    let cm_t: WrapMode = ((get_cmd(w1, 18, 2) & 0x3) as u8).into();
108    let mask_t: u8 = get_cmd(w1, 14, 4) as u8;
109    let shift_t: u8 = get_cmd(w1, 10, 4) as u8;
110    let cm_s: WrapMode = ((get_cmd(w1, 8, 2) & 0x3) as u8).into();
111    let mask_s: u8 = get_cmd(w1, 4, 4) as u8;
112    let shift_s: u8 = get_cmd(w1, 0, 4) as u8;
113
114    params.rdp.set_tile(
115        tile, format, size, line, tmem, palette, cm_t, cm_s, mask_t, mask_s, shift_t, shift_s,
116    );
117
118    GBIResult::Continue
119});
120
121gbi_command!(RDPSetTileSize, |params: &mut GBICommandParams| {
122    let w0 = unsafe { (*(*params.command)).words.w0 };
123    let w1 = unsafe { (*(*params.command)).words.w1 };
124
125    let tile = get_cmd(w1, 24, 3) as u8;
126    let uls = get_cmd(w0, 12, 12) as u16;
127    let ult = get_cmd(w0, 0, 12) as u16;
128    let lrs = get_cmd(w1, 12, 12) as u16;
129    let lrt = get_cmd(w1, 0, 12) as u16;
130
131    params.rdp.set_tile_size(tile, ult, uls, lrt, lrs);
132
133    GBIResult::Continue
134});
135
136gbi_command!(RDPLoadTile, |params: &mut GBICommandParams| {
137    let w0 = unsafe { (*(*params.command)).words.w0 };
138    let w1 = unsafe { (*(*params.command)).words.w1 };
139
140    let tile = get_cmd(w1, 24, 3) as u8;
141    let uls = get_cmd(w0, 12, 12) as u16;
142    let ult = get_cmd(w0, 0, 12) as u16;
143    let lrs = get_cmd(w1, 12, 12) as u16;
144    let lrt = get_cmd(w1, 0, 12) as u16;
145
146    params.rdp.load_tile(tile, ult, uls, lrt, lrs);
147
148    GBIResult::Continue
149});
150
151gbi_command!(RDPLoadBlock, |params: &mut GBICommandParams| {
152    let w0 = unsafe { (*(*params.command)).words.w0 };
153    let w1 = unsafe { (*(*params.command)).words.w1 };
154
155    let tile = get_cmd(w1, 24, 3) as u8;
156    let uls = get_cmd(w0, 12, 12) as u16;
157    let ult = get_cmd(w0, 0, 12) as u16;
158    let texels = get_cmd(w1, 12, 12) as u16;
159    let dxt = get_cmd(w1, 0, 12) as u16;
160
161    params.rdp.load_block(tile, ult, uls, texels, dxt);
162
163    GBIResult::Continue
164});
165
166gbi_command!(RDPLoadTLUT, |params: &mut GBICommandParams| {
167    let w1 = unsafe { (*(*params.command)).words.w1 };
168
169    let tile = get_cmd(w1, 24, 3) as u8;
170    let high_index = get_cmd(w1, 14, 10) as u16;
171
172    params.rdp.load_tlut(tile, high_index);
173
174    GBIResult::Continue
175});
176
177gbi_command!(RDPSetEnvColor, |params: &mut GBICommandParams| {
178    let w1 = unsafe { (*(*params.command)).words.w1 };
179    params.rdp.set_env_color(w1);
180
181    GBIResult::Continue
182});
183
184gbi_command!(RDPSetPrimColor, |params: &mut GBICommandParams| {
185    let w0 = unsafe { (*(*params.command)).words.w0 };
186    let w1 = unsafe { (*(*params.command)).words.w1 };
187
188    let lod_frac = get_cmd(w0, 0, 8) as u8;
189    let lod_min = get_cmd(w0, 8, 5) as u8;
190    params.rdp.set_prim_color(lod_frac, lod_min, w1);
191
192    GBIResult::Continue
193});
194
195gbi_command!(RDPSetBlendColor, |params: &mut GBICommandParams| {
196    let w1 = unsafe { (*(*params.command)).words.w1 };
197    params.rdp.set_blend_color(w1);
198
199    GBIResult::Continue
200});
201
202gbi_command!(RDPSetFogColor, |params: &mut GBICommandParams| {
203    let w1 = unsafe { (*(*params.command)).words.w1 };
204    params.rdp.set_fog_color(w1);
205
206    GBIResult::Continue
207});
208
209gbi_command!(RDPSetFillColor, |params: &mut GBICommandParams| {
210    let w1 = unsafe { (*(*params.command)).words.w1 };
211    params.rdp.set_fill_color(w1);
212
213    GBIResult::Continue
214});
215
216gbi_command!(RDPSetOtherMode, |params: &mut GBICommandParams| {
217    let w0 = unsafe { (*(*params.command)).words.w0 };
218    let w1 = unsafe { (*(*params.command)).words.w1 };
219
220    let high = get_cmd(w0, 0, 24);
221    let low = w1;
222    params.rdp.set_other_mode(high as u32, low as u32);
223
224    GBIResult::Continue
225});
226
227gbi_command!(RDPSetScissor, |params: &mut GBICommandParams| {
228    let w0 = unsafe { (*(*params.command)).words.w0 };
229    let w1 = unsafe { (*(*params.command)).words.w1 };
230
231    let _mode = get_cmd(w1, 24, 2);
232    let ulx = get_cmd(w0, 12, 12);
233    let uly = get_cmd(w0, 0, 12);
234    let lrx = get_cmd(w1, 12, 12);
235    let lry = get_cmd(w1, 0, 12);
236
237    let x = ulx as f32 / 4.0 * params.rdp.scaled_x();
238    let y = (SCREEN_HEIGHT - lry as f32 / 4.0) * params.rdp.scaled_y();
239    let width = (lrx as f32 - ulx as f32) / 4.0 * params.rdp.scaled_x();
240    let height = (lry as f32 - uly as f32) / 4.0 * params.rdp.scaled_y();
241
242    params.rdp.scissor.x = x as u16;
243    params.rdp.scissor.y = y as u16;
244    params.rdp.scissor.width = width as u16;
245    params.rdp.scissor.height = height as u16;
246
247    params.rdp.shader_config_changed = true;
248    GBIResult::Continue
249});
250
251gbi_command!(RDPSetConvert, |params: &mut GBICommandParams| {
252    let w0 = unsafe { (*(*params.command)).words.w0 };
253    let w1 = unsafe { (*(*params.command)).words.w1 };
254
255    let k0 = get_cmd(w0, 13, 9);
256    let k1 = get_cmd(w0, 4, 9);
257    let k2 = (get_cmd(w0, 0, 4) << 5) | get_cmd(w1, 27, 5);
258    let k3 = get_cmd(w1, 18, 9);
259    let k4 = get_cmd(w1, 9, 9);
260    let k5 = get_cmd(w1, 0, 9);
261
262    params.rdp.set_convert(
263        k0 as i32, k1 as i32, k2 as i32, k3 as i32, k4 as i32, k5 as i32,
264    );
265
266    GBIResult::Continue
267});
268
269gbi_command!(RDPSetKeyR, |params: &mut GBICommandParams| {
270    let w1 = unsafe { (*(*params.command)).words.w1 };
271
272    let cr = get_cmd(w1, 8, 8);
273    let sr = get_cmd(w1, 0, 8);
274    let wr = get_cmd(w1, 16, 2);
275
276    params.rdp.set_key_r(cr as u32, sr as u32, wr as u32);
277
278    GBIResult::Continue
279});
280
281gbi_command!(RDPSetKeyGB, |params: &mut GBICommandParams| {
282    let w0 = unsafe { (*(*params.command)).words.w0 };
283    let w1 = unsafe { (*(*params.command)).words.w1 };
284
285    let cg = get_cmd(w1, 24, 8);
286    let sg = get_cmd(w1, 16, 8);
287    let wg = get_cmd(w0, 12, 12);
288    let cb = get_cmd(w1, 8, 8);
289    let sb = get_cmd(w1, 0, 8);
290    let wb = get_cmd(w0, 0, 12);
291
292    params.rdp.set_key_gb(
293        cg as u32, sg as u32, wg as u32, cb as u32, sb as u32, wb as u32,
294    );
295
296    GBIResult::Continue
297});
298
299gbi_command!(RDPTextureRectangle, |params: &mut GBICommandParams| {
300    let w0 = unsafe { (*(*params.command)).words.w0 };
301    let w1 = unsafe { (*(*params.command)).words.w1 };
302
303    let opcode = (w0 >> 24) as u8;
304
305    let lrx = get_cmd(w0, 12, 12);
306    let lry = get_cmd(w0, 0, 12);
307    let tile = get_cmd(w1, 24, 3);
308    let ulx = get_cmd(w1, 12, 12);
309    let uly = get_cmd(w1, 0, 12);
310
311    unsafe {
312        *params.command = (*params.command).add(1);
313    }
314    let w1 = unsafe { (*(*params.command)).words.w1 };
315
316    let uls = get_cmd(w1, 16, 16);
317    let ult = get_cmd(w1, 0, 16);
318
319    unsafe {
320        *params.command = (*params.command).add(1);
321    }
322    let w1 = unsafe { (*(*params.command)).words.w1 };
323
324    let dsdx = get_cmd(w1, 16, 16);
325    let dtdy = get_cmd(w1, 0, 16);
326
327    params.rdp.draw_texture_rectangle(
328        params.rsp,
329        params.output,
330        ulx as i32,
331        uly as i32,
332        lrx as i32,
333        lry as i32,
334        tile as u8,
335        uls as i16,
336        ult as i16,
337        dsdx as i16,
338        dtdy as i16,
339        opcode == OpCode::TEXRECTFLIP.bits(),
340    );
341
342    GBIResult::Continue
343});
344
345gbi_command!(RDPFillRectangle, |params: &mut GBICommandParams| {
346    let w0 = unsafe { (*(*params.command)).words.w0 };
347    let w1 = unsafe { (*(*params.command)).words.w1 };
348
349    let ulx = get_cmd(w1, 12, 12);
350    let uly = get_cmd(w1, 0, 12);
351    let lrx = get_cmd(w0, 12, 12);
352    let lry = get_cmd(w0, 0, 12);
353
354    params.rdp.fill_rect(
355        params.rsp,
356        params.output,
357        ulx as i32,
358        uly as i32,
359        lrx as i32,
360        lry as i32,
361    );
362
363    GBIResult::Continue
364});