1use bitflags::bitflags;
2use num_enum::TryFromPrimitive;
3use pigment64::color::Color;
4
5pub mod color_combiner;
6pub use color_combiner::*;
7pub mod render_mode;
8pub use render_mode::*;
9
10pub mod f3d;
11pub mod f3dex2;
12
13pub const G_MAXZ: u32 = 0x03ff;
14
15#[repr(C)]
16#[derive(Clone, Copy)]
17pub struct GfxWords {
18 pub w0: usize,
19 pub w1: usize,
20}
21
22#[repr(C)]
23#[derive(Clone, Copy)]
24pub union GfxCommand {
25 pub words: GfxWords,
26 force_structure_alignment: i64,
27}
28
29impl GfxCommand {
30 pub fn new(w0: usize, w1: usize) -> Self {
31 Self {
32 words: GfxWords { w0, w1 },
33 }
34 }
35
36 pub fn w0(&self, position: u32, width: u32) -> usize {
38 unsafe { (self.words.w0 >> position) & ((1 << width) - 1) }
39 }
40
41 pub fn w1(&self, position: u32, width: u32) -> usize {
43 unsafe { (self.words.w1 >> position) & ((1 << width) - 1) }
44 }
45}
46
47#[repr(C)]
48#[derive(Clone, Copy)]
49pub union Matrix {
50 pub m: [[u32; 4]; 4],
51 force_structure_alignment: i64,
52}
53
54#[repr(C)]
55#[derive(Clone, Copy)]
56pub union Vertex {
57 pub color: ColorVertex,
58 pub normal: NormalVertex,
59 force_structure_alignment: i64,
60}
61
62#[repr(C)]
63#[derive(Clone, Copy, Debug)]
64pub struct ColorVertex {
65 #[cfg(feature = "gbifloats")]
66 pub position: [f32; 3], #[cfg(not(feature = "gbifloats"))]
68 pub position: [i16; 3], flag: u16, pub texture_coords: [i16; 2],
71 pub color: Color,
72}
73
74impl ColorVertex {
75 pub const fn new(
76 #[cfg(feature = "gbifloats")] position: [f32; 3],
77 #[cfg(not(feature = "gbifloats"))] position: [i16; 3],
78 texture_coords: [i16; 2],
79 color: Color,
80 ) -> Self {
81 Self {
82 position,
83 flag: 0,
84 texture_coords,
85 color,
86 }
87 }
88}
89
90#[repr(C)]
91#[derive(Clone, Copy, Debug)]
92pub struct NormalVertex {
93 #[cfg(feature = "gbifloats")]
94 pub position: [f32; 3], #[cfg(not(feature = "gbifloats"))]
96 pub position: [i16; 3], flag: u16, pub texture_coords: [i16; 2],
99 pub normal: [i8; 3],
100 pub alpha: u8,
101}
102
103#[repr(C)]
104#[derive(Clone, Copy, Debug)]
105pub struct Viewport {
106 pub vscale: [i16; 4], pub vtrans: [i16; 4], _padding: [u8; 8], }
110
111impl Viewport {
112 pub const fn new(vscale: [i16; 4], vtrans: [i16; 4]) -> Self {
113 Self {
114 vscale,
115 vtrans,
116 _padding: [0; 8],
117 }
118 }
119}
120
121#[repr(C)]
122#[derive(Clone, Copy)]
123pub struct RawLight {
124 pub words: [u32; 4],
125}
126
127#[repr(C)]
128#[derive(Clone, Copy)]
129pub union Light {
130 pub raw: RawLight,
131 pub pos: PosLight,
132 pub dir: DirLight,
133}
134
135#[repr(C)]
136#[derive(Clone, Copy)]
137pub struct DirLight {
138 pub col: [u8; 3], pad1: i8,
140 pub color_copy: [u8; 3], pad2: i8,
142 pub dir: [i8; 3], pad3: i8,
144}
145
146#[repr(C)]
147#[derive(Clone, Copy)]
148pub struct PosLight {
149 pub kc: u8,
150 pub col: [u8; 3],
151 pub kl: u8,
152 pub color_copy: [u8; 3],
153 pub pos: [i16; 2],
154 pub reserved1: u8,
155 pub kq: u8,
156 pub posz: i16,
157}
158
159impl Light {
160 pub const ZERO: Self = Self {
161 raw: RawLight {
162 words: [0, 0, 0, 0],
163 },
164 };
165}
166
167pub struct LookAt {
168 pub x: [f32; 3],
169 pub y: [f32; 3],
170}
171
172impl LookAt {
173 pub const fn new(x: [f32; 3], y: [f32; 3]) -> Self {
174 Self { x, y }
175 }
176}
177
178bitflags! {
179 pub struct OpCode: u8 {
180 const NOOP = 0x00;
181
182 const SET_COLORIMG = 0xff;
183 const SET_DEPTHIMG = 0xfe;
184 const SET_TEXIMG = 0xfd;
185 const SET_COMBINE = 0xfc;
186 const SET_ENVCOLOR = 0xfb;
187 const SET_PRIMCOLOR = 0xfa;
188 const SET_BLENDCOLOR = 0xf9;
189 const SET_FOGCOLOR = 0xf8;
190 const SET_FILLCOLOR = 0xf7;
191 const SET_TILE = 0xf5;
192 const SET_TILESIZE = 0xf2;
193 const SET_PRIMDEPTH = 0xee;
194 const SET_SCISSOR = 0xed;
195 const SET_CONVERT = 0xec;
196 const SET_KEYR = 0xeb;
197 const SET_KEYGB = 0xea;
198
199 const LOAD_BLOCK = 0xf3;
200 const LOAD_TILE = 0xf4;
201 const LOAD_TLUT = 0xf0;
202
203 const TEXRECT = 0xe4;
204 const TEXRECTFLIP = 0xe5;
205 const FILLRECT = 0xf6;
206
207 const RDPFULLSYNC = 0xe9;
208 const RDPTILESYNC = 0xe8;
209 const RDPPIPESYNC = 0xe7;
210 const RDPLOADSYNC = 0xe6;
211 const RDPSETOTHERMODE = 0xef;
212 }
213}
214
215#[allow(non_snake_case)]
216pub mod OtherModeH {
217 use bitflags::bitflags;
218
219 bitflags! {
220 pub struct Shift: u32 {
221 const BLEND_MASK = 0x00000000;
223 const ALPHA_DITHER = 0x00000004;
224 const RGB_DITHER = 0x00000006;
225 const COMB_KEY = 0x00000008;
226 const TEXT_CONV = 0x00000009;
227 const TEXT_FILT = 0x0000000c;
228 const TEXT_LUT = 0x0000000e;
229 const TEXT_LOD = 0x00000010;
230 const TEXT_DETAIL = 0x00000011;
231 const TEXT_PERSP = 0x00000013;
232 const CYCLE_TYPE = 0x00000014;
233 const COLOR_DITHER = 0x00000016;
235 const PIPELINE = 0x00000017;
236 }
237 }
238
239 impl Default for Shift {
240 fn default() -> Self {
241 Self::empty()
242 }
243 }
244}
245
246#[allow(non_snake_case)]
247pub mod OtherModeL {
248 use bitflags::bitflags;
249
250 bitflags! {
251 pub struct Shift: u32 {
252 const ALPHA_COMPARE = 0;
253 const DEPTH_SOURCE = 2;
254 const RENDER_MODE = 3;
255 const BLENDER = 16;
256 }
257 }
258
259 impl Default for Shift {
260 fn default() -> Self {
261 Self::empty()
262 }
263 }
264}
265
266bitflags! {
267 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
268 pub struct GeometryModes: u32 {
269 const ZBUFFER = 0x00000001;
270 const SHADE = 0x00000004;
271 const FOG = 0x00010000;
272 const LIGHTING = 0x00020000;
273 const TEXTURE_GEN = 0x00040000;
274 const TEXTURE_GEN_LINEAR = 0x00080000;
275 const LOD = 0x00100000;
276 const CLIPPING = 0x00800000;
277 }
278}
279
280bitflags! {
281 pub struct MoveWordIndex: u8 {
282 const MATRIX = 0x00; const NUMLIGHT = 0x02;
284 const CLIP = 0x04;
285 const SEGMENT = 0x06;
286 const FOG = 0x08;
287 const LIGHTCOL = 0x0A;
288 const PERSPNORM = 0x0E;
289 }
290}
291
292bitflags! {
293 pub struct TextureTile: u8 {
294 const LOADTILE = 0x07;
295 const RENDERTILE = 0x00;
296 }
297}
298
299bitflags! {
300 pub struct TextureMask: u8 {
301 const NOMASK = 0x00;
302 }
303}
304
305bitflags! {
306 pub struct TextureShift: u8 {
307 const NOLOD = 0x00;
308 }
309}
310
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
312#[repr(u8)]
313pub enum DisplayListMode {
314 Display = 0,
315 Branch = 1,
316}
317
318impl Default for DisplayListMode {
319 fn default() -> Self {
320 Self::Display
321 }
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
325#[repr(u8)]
326pub enum TextureFilter {
327 Point = 0,
328 Average = 3,
329 Bilerp = 2,
330}
331
332impl Default for TextureFilter {
333 fn default() -> Self {
334 Self::Point
335 }
336}
337
338impl TextureFilter {
339 pub const fn raw_gbi_value(&self) -> u32 {
340 const G_MDSFT_TEXTFILT: u32 = 12;
341 match self {
342 Self::Point => 0 << G_MDSFT_TEXTFILT,
343 Self::Average => 3 << G_MDSFT_TEXTFILT,
344 Self::Bilerp => 2 << G_MDSFT_TEXTFILT,
345 }
346 }
347}
348
349#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
350#[repr(u8)]
351pub enum TextureLUT {
352 None = 0,
353 Rgba16 = 2,
354 Ia16 = 3,
355}
356
357impl Default for TextureLUT {
358 fn default() -> Self {
359 Self::None
360 }
361}
362
363impl TextureLUT {
364 pub const fn raw_gbi_value(&self) -> u32 {
365 const G_MDSFT_TEXTLUT: u32 = 14;
366 match self {
367 Self::None => 0,
368 Self::Rgba16 => 2 << G_MDSFT_TEXTLUT,
369 Self::Ia16 => 3 << G_MDSFT_TEXTLUT,
370 }
371 }
372}
373
374#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
375#[repr(u8)]
376pub enum TextureLOD {
377 Tile = 0,
378 Lod = 1,
379}
380
381impl Default for TextureLOD {
382 fn default() -> Self {
383 Self::Tile
384 }
385}
386
387impl TextureLOD {
388 pub const fn raw_gbi_value(&self) -> u32 {
389 const G_MDSFT_TEXTLOD: u32 = 16;
390 match self {
391 Self::Tile => 0,
392 Self::Lod => 1 << G_MDSFT_TEXTLOD,
393 }
394 }
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
398#[repr(u8)]
399pub enum TextureDetail {
400 Clamp = 0,
401 Sharpen = 1,
402 Detail = 2,
403}
404
405impl Default for TextureDetail {
406 fn default() -> Self {
407 Self::Clamp
408 }
409}
410
411impl TextureDetail {
412 pub const fn raw_gbi_value(&self) -> u32 {
413 const G_MDSFT_TEXTDETAIL: u32 = 17;
414 match self {
415 Self::Clamp => 0,
416 Self::Sharpen => 1 << G_MDSFT_TEXTDETAIL,
417 Self::Detail => 2 << G_MDSFT_TEXTDETAIL,
418 }
419 }
420}
421
422#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
423#[repr(u8)]
424pub enum TextureConvert {
425 Conv = 0,
426 FiltConv = 5,
427 Filt = 6,
428}
429
430impl Default for TextureConvert {
431 fn default() -> Self {
432 Self::Conv
433 }
434}
435
436impl TextureConvert {
437 pub const fn raw_gbi_value(&self) -> u32 {
438 const G_MDSFT_TEXTCONV: u32 = 9;
439 match self {
440 Self::Conv => 0 << G_MDSFT_TEXTCONV,
441 Self::FiltConv => 5 << G_MDSFT_TEXTCONV,
442 Self::Filt => 6 << G_MDSFT_TEXTCONV,
443 }
444 }
445}
446
447#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
448#[repr(u8)]
449pub enum ColorDither {
450 MagicSq = 0,
451 Bayer = 1,
452 Noise = 2,
453 Disable = 3,
454}
455
456impl Default for ColorDither {
457 fn default() -> Self {
458 Self::Disable
459 }
460}
461
462impl ColorDither {
463 #[cfg(not(feature = "hardware_version_1"))]
464 pub const fn raw_gbi_value(&self) -> u32 {
465 const G_MDSFT_RGBDITHER: u32 = 19;
466 match self {
467 Self::MagicSq => 0 << G_MDSFT_RGBDITHER,
468 Self::Bayer => 1 << G_MDSFT_RGBDITHER,
469 Self::Noise => 2 << G_MDSFT_RGBDITHER,
470 Self::Disable => 3 << G_MDSFT_RGBDITHER,
471 }
472 }
473}
474
475#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
476#[repr(u8)]
477pub enum ImageFormat {
478 Rgba = 0,
479 Yuv = 1,
480 Ci = 2,
481 Ia = 3,
482 I = 4,
483}
484
485#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
486#[repr(u8)]
487pub enum ComponentSize {
488 Bits4 = 0,
489 Bits8 = 1,
490 Bits16 = 2,
491 Bits32 = 3,
492 DD = 5,
493}
494
495impl Default for ComponentSize {
496 fn default() -> Self {
497 Self::Bits4
498 }
499}
500
501#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
502#[repr(u8)]
503pub enum CycleType {
504 OneCycle = 0,
505 TwoCycle = 1,
506 Copy = 2,
507 Fill = 3,
508}
509
510impl Default for CycleType {
511 fn default() -> Self {
512 Self::OneCycle
513 }
514}
515
516impl CycleType {
517 pub const fn raw_gbi_value(&self) -> u32 {
518 const G_MDSFT_CYCLETYPE: u32 = 20;
519 match self {
520 CycleType::OneCycle => 0 << G_MDSFT_CYCLETYPE,
521 CycleType::TwoCycle => 1 << G_MDSFT_CYCLETYPE,
522 CycleType::Copy => 2 << G_MDSFT_CYCLETYPE,
523 CycleType::Fill => 3 << G_MDSFT_CYCLETYPE,
524 }
525 }
526}
527
528#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
529#[repr(u8)]
530pub enum PipelineMode {
531 OnePrimitive = 1,
532 NPrimitive = 0,
533}
534
535impl Default for PipelineMode {
536 fn default() -> Self {
537 Self::NPrimitive
538 }
539}
540
541impl PipelineMode {
542 pub const fn raw_gbi_value(&self) -> u32 {
543 const G_MDSFT_PIPELINE: u32 = 23;
544 match self {
545 PipelineMode::OnePrimitive => 1 << G_MDSFT_PIPELINE,
546 PipelineMode::NPrimitive => 0 << G_MDSFT_PIPELINE,
547 }
548 }
549}
550
551#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
552#[repr(u8)]
553#[allow(clippy::enum_variant_names)]
554pub enum ScissorMode {
555 NonInterlace = 0,
556 OddInterlace = 3,
557 EvenInterlace = 2,
558}
559
560impl Default for ScissorMode {
561 fn default() -> Self {
562 Self::NonInterlace
563 }
564}
565
566#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
567#[repr(u8)]
568pub enum AlphaCompare {
569 None = 0,
570 Threshold = 1,
571 Dither = 3,
572}
573
574impl Default for AlphaCompare {
575 fn default() -> Self {
576 Self::None
577 }
578}
579
580impl AlphaCompare {
581 pub const fn raw_gbi_value(&self) -> u32 {
582 const G_MDSFT_ALPHACOMPARE: u32 = 0;
583 match self {
584 AlphaCompare::None => 0 << G_MDSFT_ALPHACOMPARE,
585 AlphaCompare::Threshold => 1 << G_MDSFT_ALPHACOMPARE,
586 AlphaCompare::Dither => 3 << G_MDSFT_ALPHACOMPARE,
587 }
588 }
589}
590
591#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
592#[repr(u8)]
593pub enum WrapMode {
594 Clamp,
595 Repeat,
596 MirrorRepeat,
597}
598
599impl Default for WrapMode {
600 fn default() -> Self {
601 Self::Repeat
602 }
603}
604
605impl From<u8> for WrapMode {
606 fn from(v: u8) -> Self {
607 let mirror = v & 0x1 != 0;
608 let clamp = v & 0x2 != 0;
609
610 if clamp {
611 WrapMode::Clamp
612 } else if mirror {
613 WrapMode::MirrorRepeat
614 } else {
615 WrapMode::Repeat
616 }
617 }
618}