1use crate::sys::{
2    self,
3    display::DisplayPixelFormat,
4    ge::{GeBreakParam, GeCommand, GeContext, GeListArgs, GeListState},
5    kernel::SceUid,
6    types::{ScePspFMatrix4, ScePspFVector3, ScePspIMatrix4, ScePspIVector4},
7};
8use core::{ffi::c_void, mem, ptr::addr_of_mut, ptr::null_mut};
9use num_enum::TryFromPrimitive;
10
11#[allow(clippy::approx_constant)]
12pub const GU_PI: f32 = 3.141593;
13
14#[repr(u32)]
16#[derive(Copy, Clone, Debug)]
17pub enum GuPrimitive {
18    Points = 0,
20    Lines = 1,
22    LineStrip = 2,
24    Triangles = 3,
26    TriangleStrip = 4,
28    TriangleFan = 5,
30    Sprites = 6,
32}
33
34#[repr(u32)]
36#[derive(Copy, Clone, Debug)]
37pub enum PatchPrimitive {
38    Points = 0,
40    LineStrip = 2,
42    TriangleStrip = 4,
44}
45
46#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive)]
48#[repr(u32)]
49pub enum GuState {
50    AlphaTest = 0,
51    DepthTest = 1,
52    ScissorTest = 2,
53    StencilTest = 3,
54    Blend = 4,
55    CullFace = 5,
56    Dither = 6,
57    Fog = 7,
58    ClipPlanes = 8,
59    Texture2D = 9,
60    Lighting = 10,
61    Light0 = 11,
62    Light1 = 12,
63    Light2 = 13,
64    Light3 = 14,
65    LineSmooth = 15,
66    PatchCullFace = 16,
67    ColorTest = 17,
68    ColorLogicOp = 18,
69    FaceNormalReverse = 19,
70    PatchFace = 20,
71    Fragment2X = 21,
72}
73
74#[repr(u32)]
76#[derive(Copy, Clone, Debug)]
77pub enum MatrixMode {
78    Projection = 0,
79    View = 1,
80    Model = 2,
81    Texture = 3,
82}
83
84bitflags::bitflags! {
85    #[repr(transparent)]
88    pub struct VertexType: i32 {
89        const TEXTURE_8BIT = 1;
91        const TEXTURE_16BIT = 2;
93        const TEXTURE_32BITF = 3;
95
96        const COLOR_5650 = 4 << 2;
98        const COLOR_5551 = 5 << 2;
100        const COLOR_4444 = 6 << 2;
102        const COLOR_8888 = 7 << 2;
104
105        const NORMAL_8BIT = 1 << 5;
107        const NORMAL_16BIT = 2 << 5;
109        const NORMAL_32BITF = 3 << 5;
111
112        const VERTEX_8BIT = 1 << 7;
114        const VERTEX_16BIT = 2 << 7;
116        const VERTEX_32BITF = 3 << 7;
118
119        const WEIGHT_8BIT = 1 << 9;
121        const WEIGHT_16BIT = 2 << 9;
123        const WEIGHT_32BITF = 3 << 9;
125
126        const INDEX_8BIT = 1 << 11;
128        const INDEX_16BIT = 2 << 11;
130
131        const WEIGHTS1 = Self::num_weights(1);
134        const WEIGHTS2 = Self::num_weights(2);
135        const WEIGHTS3 = Self::num_weights(3);
136        const WEIGHTS4 = Self::num_weights(4);
137        const WEIGHTS5 = Self::num_weights(5);
138        const WEIGHTS6 = Self::num_weights(6);
139        const WEIGHTS7 = Self::num_weights(7);
140        const WEIGHTS8 = Self::num_weights(8);
141
142        const VERTICES1 = Self::num_vertices(1);
144        const VERTICES2 = Self::num_vertices(2);
145        const VERTICES3 = Self::num_vertices(3);
146        const VERTICES4 = Self::num_vertices(4);
147        const VERTICES5 = Self::num_vertices(5);
148        const VERTICES6 = Self::num_vertices(6);
149        const VERTICES7 = Self::num_vertices(7);
150        const VERTICES8 = Self::num_vertices(8);
151
152        const TRANSFORM_2D = 1 << 23;
154        const TRANSFORM_3D = 0;
156    }
157}
158
159impl VertexType {
160    const fn num_weights(n: u32) -> i32 {
161        (((n - 1) & 7) << 14) as i32
162    }
163
164    const fn num_vertices(n: u32) -> i32 {
165        (((n - 1) & 7) << 18) as i32
166    }
167}
168
169#[derive(Debug, Clone, Copy)]
172#[repr(u32)]
173pub enum TexturePixelFormat {
174    Psm5650 = 0,
176    Psm5551 = 1,
178    Psm4444 = 2,
180    Psm8888 = 3,
182    PsmT4 = 4,
184    PsmT8 = 5,
186    PsmT16 = 6,
188    PsmT32 = 7,
190    PsmDxt1 = 8,
191    PsmDxt3 = 9,
192    PsmDxt5 = 10,
193}
194
195#[repr(u32)]
197pub enum SplineMode {
198    FillFill = 0,
199    OpenFill = 1,
200    FillOpen = 2,
201    OpenOpen = 3,
202}
203
204#[repr(u32)]
206pub enum ShadingModel {
208    Flat = 0,
209    Smooth = 1,
210}
211
212#[repr(u32)]
214pub enum LogicalOperation {
215    Clear = 0,
216    And = 1,
217    AndReverse = 2,
218    Copy = 3,
219    AndInverted = 4,
220    Noop = 5,
221    Xor = 6,
222    Or = 7,
223    Nor = 8,
224    Equiv = 9,
225    Inverted = 10,
226    OrReverse = 11,
227    CopyInverted = 12,
228    OrInverted = 13,
229    Nand = 14,
230    Set = 15,
231}
232
233#[repr(u32)]
235pub enum TextureFilter {
236    Nearest = 0,
237    Linear = 1,
238    NearestMipmapNearest = 4,
239    LinearMipmapNearest = 5,
240    NearestMipmapLinear = 6,
241    LinearMipmapLinear = 7,
242}
243
244#[derive(Debug, Clone, Copy)]
246#[repr(u32)]
247pub enum TextureMapMode {
248    TextureCoords = 0,
249    TextureMatrix = 1,
250    EnvironmentMap = 2,
251}
252
253#[repr(u32)]
255pub enum TextureLevelMode {
256    Auto = 0,
257    Const = 1,
258    Slope = 2,
259}
260
261#[derive(Debug, Clone, Copy)]
263#[repr(u32)]
264pub enum TextureProjectionMapMode {
265    Position = 0,
266    Uv = 1,
267    NormalizedNormal = 2,
268    Normal = 3,
269}
270
271#[repr(u32)]
273pub enum GuTexWrapMode {
274    Repeat = 0,
276
277    Clamp = 1,
279}
280
281#[repr(u32)]
283pub enum FrontFaceDirection {
284    Clockwise = 0,
285    CounterClockwise = 1,
286}
287
288#[derive(Copy, Clone, Debug)]
290#[repr(u32)]
291pub enum AlphaFunc {
292    Never = 0,
293    Always,
294    Equal,
295    NotEqual,
296    Less,
297    LessOrEqual,
298    Greater,
299    GreaterOrEqual,
300}
301
302#[derive(Copy, Clone, Debug)]
304#[repr(u32)]
305pub enum StencilFunc {
306    Never = 0,
307    Always,
308    Equal,
309    NotEqual,
310    Less,
311    LessOrEqual,
312    Greater,
313    GreaterOrEqual,
314}
315
316#[derive(Copy, Clone, Debug)]
318#[repr(u32)]
319pub enum ColorFunc {
320    Never = 0,
321    Always,
322    Equal,
323    NotEqual,
324}
325
326#[derive(Copy, Clone, Debug)]
328#[repr(u32)]
329pub enum DepthFunc {
330    Never = 0,
332    Always,
334    Equal,
336    NotEqual,
338    Less,
340    LessOrEqual,
342    Greater,
344    GreaterOrEqual,
346}
347
348bitflags::bitflags! {
349    #[repr(transparent)]
351    pub struct ClearBuffer: u32 {
352        const COLOR_BUFFER_BIT = 1;
354        const STENCIL_BUFFER_BIT = 2;
356        const DEPTH_BUFFER_BIT = 4;
358        const FAST_CLEAR_BIT = 16;
361    }
362}
363
364#[derive(Debug, Clone, Copy)]
375#[repr(u32)]
376pub enum TextureEffect {
377    Modulate = 0,
382    Decal = 1,
384    Blend = 2,
386    Replace = 3,
390    Add = 4,
394}
395
396#[derive(Debug, Clone, Copy)]
398#[repr(u32)]
399pub enum TextureColorComponent {
400    Rgb = 0,
402    Rgba = 1,
404}
405
406#[derive(Debug, Clone, Copy)]
408#[repr(u32)]
409pub enum MipmapLevel {
410    None = 0,
411    Level1,
412    Level2,
413    Level3,
414    Level4,
415    Level5,
416    Level6,
417    Level7,
418}
419
420#[repr(u32)]
429pub enum BlendOp {
430    Add = 0,
432    Subtract = 1,
434    ReverseSubtract = 2,
436    Min = 3,
438    Max = 4,
440    Abs = 5,
442}
443
444#[repr(u32)]
446pub enum BlendFactor {
447    Color = 0,
448    OneMinusColor = 1,
449    SrcAlpha = 2,
450    OneMinusSrcAlpha = 3,
451    DstAlpha = 4,
452    OneMinusDstAlpha = 5,
453    Fix = 10,
458}
459
460#[repr(u32)]
462pub enum StencilOperation {
463    Keep = 0,
465    Zero = 1,
467    Replace = 2,
469    Invert = 3,
471    Incr = 4,
473    Decr = 5,
475}
476
477bitflags::bitflags!(
478    #[repr(transparent)]
480    pub struct LightComponent: i32 {
481        const AMBIENT = 1;
482        const DIFFUSE = 2;
483        const SPECULAR = 4;
484
485        const UNKNOWN_LIGHT_COMPONENT = 8;
487    }
488);
489
490#[repr(u32)]
492pub enum LightMode {
493    SingleColor = 0,
494
495    SeparateSpecularColor = 1,
499}
500
501#[repr(u32)]
503pub enum LightType {
504    Directional = 0,
505    Pointlight = 1,
506    Spotlight = 2,
507}
508
509#[repr(u32)]
511#[derive(Copy, Clone, Debug)]
512pub enum GuContextType {
513    Direct = 0,
514    Call = 1,
515    Send = 2,
516}
517
518#[repr(u32)]
520pub enum GuQueueMode {
521    Tail = 0,
523    Head = 1,
525}
526
527#[repr(u32)]
529pub enum GuSyncMode {
530    Finish = 0,
532    Signal = 1,
534    Done = 2,
536    List = 3,
538    Send = 4,
540}
541
542#[repr(u32)]
544pub enum GuSyncBehavior {
545    Wait = 0,
547    NoWait = 1,
549}
550
551#[repr(u32)]
553pub enum GuCallbackId {
554    Signal = 1,
556
557    Finish = 4,
559}
560
561#[repr(u32)]
563pub enum SignalBehavior {
564    Suspend = 1,
566    Continue = 2,
568}
569
570#[inline]
572pub const fn abgr(a: u8, b: u8, g: u8, r: u8) -> u32 {
573    (r as u32) | ((g as u32) << 8) | ((b as u32) << 16) | ((a as u32) << 24)
574}
575
576#[inline]
578pub const fn argb(a: u8, r: u8, g: u8, b: u8) -> u32 {
579    abgr(a, b, g, r)
580}
581
582#[inline]
584pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> u32 {
585    argb(a, r, g, b)
586}
587
588#[inline]
589pub fn color(r: f32, g: f32, b: f32, a: f32) -> u32 {
591    rgba(
592        (r * 255.0) as u8,
593        (g * 255.0) as u8,
594        (b * 255.0) as u8,
595        (a * 255.0) as u8,
596    )
597}
598
599pub type GuCallback = Option<extern "C" fn(id: i32, arg: *mut c_void)>;
600pub type GuSwapBuffersCallback =
601    Option<extern "C" fn(display: *mut *mut c_void, render: *mut *mut c_void)>;
602
603struct Settings {
604    sig: GuCallback,
605    fin: GuCallback,
606    signal_history: [i16; 16],
607    signal_offset: u32,
608    kernel_event_flag: SceUid,
609    ge_callback_id: i32,
610    swap_buffers_callback: GuSwapBuffersCallback,
611    swap_buffers_behaviour: crate::sys::DisplaySetBufSync,
612}
613
614struct GuDisplayList {
615    start: *mut u32,
616    current: *mut u32,
617    parent_context: GuContextType,
618}
619
620struct GuContext {
621    list: GuDisplayList,
622    scissor_enable: i32,
623    scissor_start: [i32; 2],
624    scissor_end: [i32; 2],
625    near_plane: i32,
626    far_plane: i32,
627    depth_offset: i32,
628    fragment_2x: i32,
629    texture_function: i32,
630    texture_proj_map_mode: TextureProjectionMapMode,
631    texture_map_mode: TextureMapMode,
632    sprite_mode: [i32; 4],
633    clear_color: u32,
634    clear_stencil: u32,
635    clear_depth: u32,
636    texture_mode: TexturePixelFormat,
637}
638
639struct GuDrawBuffer {
640    pixel_size: DisplayPixelFormat,
641    frame_width: i32,
642    frame_buffer: *mut c_void,
643    disp_buffer: *mut c_void,
644    depth_buffer: *mut c_void,
645    depth_width: i32,
646    width: i32,
647    height: i32,
648}
649
650struct GuLightSettings {
651    type_: GeCommand,
653    xpos: GeCommand,
655    ypos: GeCommand,
657    zpos: GeCommand,
659    xdir: GeCommand,
661    ydir: GeCommand,
663    zdir: GeCommand,
665
666    ambient: GeCommand,
668    diffuse: GeCommand,
670    specular: GeCommand,
672    constant: GeCommand,
674    linear: GeCommand,
676    quadratic: GeCommand,
678    exponent: GeCommand,
680    cutoff: GeCommand,
682}
683
684static mut CURRENT_FRAME: u32 = 0;
685static mut CONTEXTS: [GuContext; 3] = [
686    GuContext {
687        list: GuDisplayList {
688            start: null_mut(),
689            current: null_mut(),
690            parent_context: GuContextType::Direct,
691        },
692        scissor_enable: 0,
693        scissor_start: [0, 0],
694        scissor_end: [0, 0],
695        near_plane: 0,
696        far_plane: 0,
697        depth_offset: 0,
698        fragment_2x: 0,
699        texture_function: 0,
700        texture_proj_map_mode: TextureProjectionMapMode::Position,
701        texture_map_mode: TextureMapMode::TextureCoords,
702        sprite_mode: [0, 0, 0, 0],
703        clear_color: 0,
704        clear_stencil: 0,
705        clear_depth: 0,
706        texture_mode: TexturePixelFormat::Psm5650,
707    },
708    GuContext {
709        list: GuDisplayList {
710            start: null_mut(),
711            current: null_mut(),
712            parent_context: GuContextType::Direct,
713        },
714        scissor_enable: 0,
715        scissor_start: [0, 0],
716        scissor_end: [0, 0],
717        near_plane: 0,
718        far_plane: 0,
719        depth_offset: 0,
720        fragment_2x: 0,
721        texture_function: 0,
722        texture_proj_map_mode: TextureProjectionMapMode::Position,
723        texture_map_mode: TextureMapMode::TextureCoords,
724        sprite_mode: [0, 0, 0, 0],
725        clear_color: 0,
726        clear_stencil: 0,
727        clear_depth: 0,
728        texture_mode: TexturePixelFormat::Psm5650,
729    },
730    GuContext {
731        list: GuDisplayList {
732            start: null_mut(),
733            current: null_mut(),
734            parent_context: GuContextType::Direct,
735        },
736        scissor_enable: 0,
737        scissor_start: [0, 0],
738        scissor_end: [0, 0],
739        near_plane: 0,
740        far_plane: 0,
741        depth_offset: 0,
742        fragment_2x: 0,
743        texture_function: 0,
744        texture_proj_map_mode: TextureProjectionMapMode::Position,
745        texture_map_mode: TextureMapMode::TextureCoords,
746        sprite_mode: [0, 0, 0, 0],
747        clear_color: 0,
748        clear_stencil: 0,
749        clear_depth: 0,
750        texture_mode: TexturePixelFormat::Psm5650,
751    },
752];
753
754static mut GE_LIST_EXECUTED: [i32; 2] = [0, 0];
755static mut GE_EDRAM_ADDRESS: *mut c_void = null_mut();
756
757static mut SETTINGS: Settings = Settings {
758    sig: None,
759    fin: None,
760    signal_history: [0; 16],
761    signal_offset: 0,
762
763    kernel_event_flag: SceUid(-1),
765
766    ge_callback_id: 0,
767    swap_buffers_behaviour: crate::sys::DisplaySetBufSync::Immediate,
768    swap_buffers_callback: None,
769};
770
771static mut LIST: *mut GuDisplayList = null_mut();
772static mut CURR_CONTEXT: GuContextType = GuContextType::Direct;
773static mut INIT: i32 = 0;
774static mut DISPLAY_ON: bool = false;
775static mut CALL_MODE: i32 = 0;
776static mut STATES: u32 = 0;
777
778static mut DRAW_BUFFER: GuDrawBuffer = GuDrawBuffer {
779    depth_buffer: null_mut(),
780    frame_buffer: null_mut(),
781    disp_buffer: null_mut(),
782    width: 0,
783    height: 0,
784    depth_width: 0,
785    frame_width: 0,
786    pixel_size: DisplayPixelFormat::Psm5650,
787};
788
789static mut OBJECT_STACK: *mut *mut u32 = null_mut();
790static mut OBJECT_STACK_DEPTH: i32 = 0;
791
792const LIGHT_COMMANDS: [GuLightSettings; 4] = [
793    GuLightSettings {
794        type_: GeCommand::LightType0,
795        xpos: GeCommand::Light0X,
796        ypos: GeCommand::Light0Y,
797        zpos: GeCommand::Light0Z,
798        xdir: GeCommand::Light0DirectionX,
799        ydir: GeCommand::Light0DirectionY,
800        zdir: GeCommand::Light0DirectionZ,
801        ambient: GeCommand::Light0Ambient,
802        diffuse: GeCommand::Light0Diffuse,
803        specular: GeCommand::Light0Specular,
804        constant: GeCommand::Light0ConstantAtten,
805        linear: GeCommand::Light0LinearAtten,
806        quadratic: GeCommand::Light0QuadtraticAtten,
807        exponent: GeCommand::Light0ExponentAtten,
808        cutoff: GeCommand::Light0CutoffAtten,
809    },
810    GuLightSettings {
811        type_: GeCommand::LightType1,
812        xpos: GeCommand::Light1X,
813        ypos: GeCommand::Light1Y,
814        zpos: GeCommand::Light1Z,
815        xdir: GeCommand::Light1DirectionX,
816        ydir: GeCommand::Light1DirectionY,
817        zdir: GeCommand::Light1DirectionZ,
818        ambient: GeCommand::Light1Ambient,
819        diffuse: GeCommand::Light1Diffuse,
820        specular: GeCommand::Light1Specular,
821        constant: GeCommand::Light1ConstantAtten,
822        linear: GeCommand::Light1LinearAtten,
823        quadratic: GeCommand::Light1QuadtraticAtten,
824        exponent: GeCommand::Light1ExponentAtten,
825        cutoff: GeCommand::Light1CutoffAtten,
826    },
827    GuLightSettings {
828        type_: GeCommand::LightType2,
829        xpos: GeCommand::Light2X,
830        ypos: GeCommand::Light2Y,
831        zpos: GeCommand::Light2Z,
832        xdir: GeCommand::Light2DirectionX,
833        ydir: GeCommand::Light2DirectionY,
834        zdir: GeCommand::Light2DirectionZ,
835        ambient: GeCommand::Light2Ambient,
836        diffuse: GeCommand::Light2Diffuse,
837        specular: GeCommand::Light2Specular,
838        constant: GeCommand::Light2ConstantAtten,
839        linear: GeCommand::Light2LinearAtten,
840        quadratic: GeCommand::Light2QuadtraticAtten,
841        exponent: GeCommand::Light2ExponentAtten,
842        cutoff: GeCommand::Light2CutoffAtten,
843    },
844    GuLightSettings {
845        type_: GeCommand::LightType3,
846        xpos: GeCommand::Light3X,
847        ypos: GeCommand::Light3Y,
848        zpos: GeCommand::Light3Z,
849        xdir: GeCommand::Light3DirectionX,
850        ydir: GeCommand::Light3DirectionY,
851        zdir: GeCommand::Light3DirectionZ,
852        ambient: GeCommand::Light3Ambient,
853        diffuse: GeCommand::Light3Diffuse,
854        specular: GeCommand::Light3Specular,
855        constant: GeCommand::Light3ConstantAtten,
856        linear: GeCommand::Light3LinearAtten,
857        quadratic: GeCommand::Light3QuadtraticAtten,
858        exponent: GeCommand::Light3ExponentAtten,
859        cutoff: GeCommand::Light3CutoffAtten,
860    },
861];
862
863#[inline]
864unsafe fn send_command_i(cmd: GeCommand, argument: i32) {
865    (*(*LIST).current) = ((cmd as u32) << 24) | (argument as u32 & 0xffffff);
866    (*LIST).current = (*LIST).current.add(1);
867}
868
869#[inline]
870unsafe fn send_command_f(cmd: GeCommand, argument: f32) {
871    send_command_i(cmd, (argument.to_bits() >> 8) as i32);
872}
873
874#[inline]
875unsafe fn send_command_i_stall(cmd: GeCommand, argument: i32) {
876    send_command_i(cmd, argument);
877    if let (GuContextType::Direct, 0) = (CURR_CONTEXT, OBJECT_STACK_DEPTH) {
878        crate::sys::sceGeListUpdateStallAddr(GE_LIST_EXECUTED[0], (*LIST).current as *mut c_void);
879    }
880}
881
882unsafe fn draw_region(x: i32, y: i32, width: i32, height: i32) {
883    send_command_i(GeCommand::Region1, (y << 10) | x);
884    send_command_i(
885        GeCommand::Region2,
886        (((y + height) - 1) << 10) | ((x + width) - 1),
887    );
888}
889
890unsafe fn reset_values() {
891    INIT = 0;
892    STATES = 0;
893    CURRENT_FRAME = 0;
894    OBJECT_STACK_DEPTH = 0;
895    DISPLAY_ON = false;
896    CALL_MODE = 0;
897    DRAW_BUFFER.pixel_size = DisplayPixelFormat::Psm5551;
898    DRAW_BUFFER.frame_width = 0;
899    DRAW_BUFFER.frame_buffer = null_mut();
900    DRAW_BUFFER.disp_buffer = null_mut();
901    DRAW_BUFFER.depth_buffer = null_mut();
902    DRAW_BUFFER.depth_width = 0;
903    DRAW_BUFFER.width = 480;
904    DRAW_BUFFER.height = 272;
905
906    for i in 0..CONTEXTS.len() {
907        let context = addr_of_mut!(CONTEXTS[i]);
908        (*context).scissor_enable = 0;
909        (*context).scissor_start = [0, 0];
910        (*context).scissor_end = [0, 0];
911
912        (*context).near_plane = 0;
913        (*context).far_plane = 1;
914
915        (*context).depth_offset = 0;
916        (*context).fragment_2x = 0;
917        (*context).texture_function = 0;
918        (*context).texture_proj_map_mode = TextureProjectionMapMode::Position;
919        (*context).texture_map_mode = TextureMapMode::TextureCoords;
920        (*context).sprite_mode[0] = 0;
921        (*context).sprite_mode[1] = 0;
922        (*context).sprite_mode[2] = 0;
923        (*context).sprite_mode[3] = 0;
924        (*context).clear_color = 0;
925        (*context).clear_stencil = 0;
926        (*context).clear_depth = 0xffff;
927        (*context).texture_mode = TexturePixelFormat::Psm5650;
928    }
929
930    SETTINGS.sig = None;
931    SETTINGS.fin = None;
932}
933
934extern "C" fn callback_sig(id: i32, arg: *mut c_void) {
935    let settings = arg as *mut Settings;
936
937    unsafe {
938        let idx = ((*settings).signal_offset & 15) as usize;
939        (*settings).signal_history[idx] = (id & 0xffff) as i16;
940        (*settings).signal_offset += 1;
941
942        if (*settings).sig.is_some() {
943            let f = mem::transmute::<_, extern "C" fn(i32)>((*settings).sig);
948
949            f(id & 0xffff);
950        }
951
952        crate::sys::sceKernelSetEventFlag((*settings).kernel_event_flag, 1);
953    }
954}
955
956extern "C" fn callback_fin(id: i32, arg: *mut c_void) {
957    unsafe {
958        let settings = arg as *mut Settings;
959
960        if let Some(fin) = (*settings).fin {
961            let f = core::mem::transmute::<_, extern "C" fn(i32)>(fin);
966
967            f(id & 0xffff)
968        }
969    }
970}
971
972#[allow(non_snake_case)]
979#[no_mangle]
980pub unsafe extern "C" fn sceGuDepthBuffer(zbp: *mut c_void, zbw: i32) {
981    DRAW_BUFFER.depth_buffer = zbp;
982
983    if DRAW_BUFFER.depth_width == 0 || DRAW_BUFFER.depth_width != zbw {
984        DRAW_BUFFER.depth_width = zbw;
985    }
986
987    send_command_i(GeCommand::ZBufPtr, zbp as i32 & 0xffffff);
988    send_command_i(
989        GeCommand::ZBufWidth,
990        (((zbp as u32 & 0xff000000) >> 8) | zbw as u32) as i32,
991    );
992}
993
994#[allow(non_snake_case)]
1003#[no_mangle]
1004pub unsafe extern "C" fn sceGuDispBuffer(
1005    width: i32,
1006    height: i32,
1007    dispbp: *mut c_void,
1008    dispbw: i32,
1009) {
1010    use crate::sys::DisplaySetBufSync;
1011
1012    DRAW_BUFFER.width = width;
1013    DRAW_BUFFER.height = height;
1014    DRAW_BUFFER.disp_buffer = dispbp;
1015
1016    if DRAW_BUFFER.frame_width == 0 || DRAW_BUFFER.frame_width != dispbw {
1017        DRAW_BUFFER.frame_width = dispbw;
1018    }
1019
1020    draw_region(0, 0, DRAW_BUFFER.width, DRAW_BUFFER.height);
1021
1022    crate::sys::sceDisplaySetMode(
1023        crate::sys::DisplayMode::Lcd,
1024        DRAW_BUFFER.width as usize,
1025        DRAW_BUFFER.height as usize,
1026    );
1027
1028    if DISPLAY_ON {
1029        crate::sys::sceDisplaySetFrameBuf(
1030            (GE_EDRAM_ADDRESS as *mut u8).add(DRAW_BUFFER.disp_buffer as usize),
1031            dispbw as usize,
1032            DRAW_BUFFER.pixel_size,
1033            DisplaySetBufSync::NextFrame,
1034        );
1035    }
1036}
1037
1038#[allow(non_snake_case)]
1046#[no_mangle]
1047pub unsafe extern "C" fn sceGuDrawBuffer(psm: DisplayPixelFormat, fbp: *mut c_void, fbw: i32) {
1048    DRAW_BUFFER.pixel_size = psm;
1049    DRAW_BUFFER.frame_width = fbw;
1050    DRAW_BUFFER.frame_buffer = fbp;
1051
1052    if DRAW_BUFFER.depth_buffer.is_null() && DRAW_BUFFER.height != 0 {
1053        DRAW_BUFFER.depth_buffer =
1054            (fbp as u32 + (((DRAW_BUFFER.height * fbw) as u32) << 2u32)) as *mut c_void;
1055    }
1056
1057    if DRAW_BUFFER.depth_width == 0 {
1058        DRAW_BUFFER.depth_width = fbw;
1059    }
1060
1061    send_command_i(GeCommand::FramebufPixFormat, psm as i32);
1062    send_command_i(
1063        GeCommand::FrameBufPtr,
1064        DRAW_BUFFER.frame_buffer as i32 & 0xffffff,
1065    );
1066    send_command_i(
1067        GeCommand::FrameBufWidth,
1068        ((DRAW_BUFFER.frame_buffer as u32 & 0xff000000) >> 8) as i32 | DRAW_BUFFER.frame_width,
1069    );
1070    send_command_i(
1071        GeCommand::ZBufPtr,
1072        DRAW_BUFFER.depth_buffer as i32 & 0xffffff,
1073    );
1074    send_command_i(
1075        GeCommand::ZBufWidth,
1076        ((DRAW_BUFFER.depth_buffer as u32 & 0xff000000) >> 8) as i32 | DRAW_BUFFER.depth_width,
1077    );
1078}
1079
1080#[allow(non_snake_case)]
1088#[no_mangle]
1089pub unsafe extern "C" fn sceGuDrawBufferList(psm: DisplayPixelFormat, fbp: *mut c_void, fbw: i32) {
1090    send_command_i(GeCommand::FramebufPixFormat, psm as i32);
1091    send_command_i(GeCommand::FrameBufPtr, fbp as i32 & 0xffffff);
1092    send_command_i(
1093        GeCommand::FrameBufWidth,
1094        ((fbp as u32 & 0xff000000) >> 8) as i32 | fbw,
1095    );
1096}
1097
1098#[allow(non_snake_case)]
1108#[no_mangle]
1109pub unsafe extern "C" fn sceGuDisplay(state: bool) -> bool {
1110    use crate::sys::DisplaySetBufSync;
1111
1112    if state {
1113        crate::sys::sceDisplaySetFrameBuf(
1114            (GE_EDRAM_ADDRESS as *mut u8).add(DRAW_BUFFER.disp_buffer as usize),
1115            DRAW_BUFFER.frame_width as usize,
1116            DRAW_BUFFER.pixel_size,
1117            DisplaySetBufSync::NextFrame,
1118        );
1119    } else {
1120        crate::sys::sceDisplaySetFrameBuf(
1121            null_mut(),
1122            0,
1123            DisplayPixelFormat::Psm5650,
1124            DisplaySetBufSync::NextFrame,
1125        );
1126    }
1127
1128    DISPLAY_ON = state;
1129    state
1130}
1131
1132#[allow(non_snake_case)]
1138#[no_mangle]
1139pub unsafe extern "C" fn sceGuDepthFunc(function: DepthFunc) {
1140    send_command_i(GeCommand::ZTest, function as i32);
1141}
1142
1143#[allow(non_snake_case)]
1150#[no_mangle]
1151pub unsafe extern "C" fn sceGuDepthMask(mask: i32) {
1152    send_command_i(GeCommand::ZWriteDisable, mask);
1153}
1154
1155#[allow(non_snake_case)]
1156#[no_mangle]
1157pub unsafe extern "C" fn sceGuDepthOffset(offset: i32) {
1158    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
1159    context.depth_offset = offset;
1160    sceGuDepthRange(context.near_plane, context.far_plane);
1161}
1162
1163#[allow(non_snake_case)]
1174#[no_mangle]
1175pub unsafe extern "C" fn sceGuDepthRange(mut near: i32, mut far: i32) {
1176    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
1177    let max = near as u32 + far as u32;
1178    let val = ((max >> 31) + max) as i32;
1179    let z = (val >> 1) as f32;
1180
1181    context.near_plane = near;
1182    context.far_plane = far;
1183
1184    send_command_f(GeCommand::ViewportZScale, z - near as f32);
1185    send_command_f(GeCommand::ViewportZCenter, z + context.depth_offset as f32);
1186
1187    if near > far {
1188        mem::swap(&mut near, &mut far);
1189    }
1190
1191    send_command_i(GeCommand::MinZ, near);
1192    send_command_i(GeCommand::MaxZ, far);
1193}
1194
1195#[allow(non_snake_case)]
1196#[no_mangle]
1197pub unsafe extern "C" fn sceGuFog(near: f32, far: f32, color: u32) {
1198    let mut distance = far - near;
1199
1200    if distance != 0.0 {
1201        distance = 1.0 / distance;
1202    }
1203
1204    send_command_i(GeCommand::FogColor, (color & 0xffffff) as i32);
1205    send_command_f(GeCommand::Fog1, far);
1206    send_command_f(GeCommand::Fog2, distance);
1207}
1208
1209#[allow(non_snake_case)]
1213#[no_mangle]
1214pub unsafe extern "C" fn sceGuInit() {
1215    const INIT_COMMANDS: [GeCommand; 223] = [
1216        GeCommand::Vaddr,
1217        GeCommand::Iaddr,
1218        GeCommand::Base,
1219        GeCommand::VertexType,
1220        GeCommand::OffsetAddr,
1221        GeCommand::Region1,
1222        GeCommand::Region2,
1223        GeCommand::LightingEnable,
1224        GeCommand::LightEnable0,
1225        GeCommand::LightEnable1,
1226        GeCommand::LightEnable2,
1227        GeCommand::LightEnable3,
1228        GeCommand::DepthClampEnable,
1229        GeCommand::CullFaceEnable,
1230        GeCommand::TextureMapEnable,
1231        GeCommand::FogEnable,
1232        GeCommand::DitherEnable,
1233        GeCommand::AlphaBlendEnable,
1234        GeCommand::AlphaTestEnable,
1235        GeCommand::ZTestEnable,
1236        GeCommand::StencilTestEnable,
1237        GeCommand::AntiAliasEnable,
1238        GeCommand::PatchCullEnable,
1239        GeCommand::ColorTestEnable,
1240        GeCommand::LogicOpEnable,
1241        GeCommand::BoneMatrixNumber,
1242        GeCommand::BoneMatrixData,
1243        GeCommand::MorphWeight0,
1244        GeCommand::MorphWeight1,
1245        GeCommand::MorphWeight2,
1246        GeCommand::MorphWeight3,
1247        GeCommand::MorphWeight4,
1248        GeCommand::MorphWeight5,
1249        GeCommand::MorphWeight6,
1250        GeCommand::MorphWeight7,
1251        GeCommand::PatchDivision,
1252        GeCommand::PatchPrimitive,
1253        GeCommand::PatchFacing,
1254        GeCommand::WorldMatrixNumber,
1255        GeCommand::WorldMatrixData,
1256        GeCommand::ViewMatrixNumber,
1257        GeCommand::ViewMatrixData,
1258        GeCommand::ProjMatrixNumber,
1259        GeCommand::ProjMatrixData,
1260        GeCommand::TGenMatrixNumber,
1261        GeCommand::TGenMatrixData,
1262        GeCommand::ViewportXScale,
1263        GeCommand::ViewportYScale,
1264        GeCommand::ViewportZScale,
1265        GeCommand::ViewportXCenter,
1266        GeCommand::ViewportYCenter,
1267        GeCommand::ViewportZCenter,
1268        GeCommand::TexScaleU,
1269        GeCommand::TexScaleV,
1270        GeCommand::TexOffsetU,
1271        GeCommand::TexOffsetV,
1272        GeCommand::OffsetX,
1273        GeCommand::OffsetY,
1274        GeCommand::ShadeMode,
1275        GeCommand::ReverseNormal,
1276        GeCommand::MaterialUpdate,
1277        GeCommand::MaterialEmissive,
1278        GeCommand::MaterialAmbient,
1279        GeCommand::MaterialDiffuse,
1280        GeCommand::MaterialSpecular,
1281        GeCommand::MaterialAlpha,
1282        GeCommand::MaterialSpecularCoef,
1283        GeCommand::AmbientColor,
1284        GeCommand::AmbientAlpha,
1285        GeCommand::LightMode,
1286        GeCommand::LightType0,
1287        GeCommand::LightType1,
1288        GeCommand::LightType2,
1289        GeCommand::LightType3,
1290        GeCommand::Light0X,
1291        GeCommand::Light0Y,
1292        GeCommand::Light0Z,
1293        GeCommand::Light1X,
1294        GeCommand::Light1Y,
1295        GeCommand::Light1Z,
1296        GeCommand::Light2X,
1297        GeCommand::Light2Y,
1298        GeCommand::Light2Z,
1299        GeCommand::Light3X,
1300        GeCommand::Light3Y,
1301        GeCommand::Light3Z,
1302        GeCommand::Light0DirectionX,
1303        GeCommand::Light0DirectionY,
1304        GeCommand::Light0DirectionZ,
1305        GeCommand::Light1DirectionX,
1306        GeCommand::Light1DirectionY,
1307        GeCommand::Light1DirectionZ,
1308        GeCommand::Light2DirectionX,
1309        GeCommand::Light2DirectionY,
1310        GeCommand::Light2DirectionZ,
1311        GeCommand::Light3DirectionX,
1312        GeCommand::Light3DirectionY,
1313        GeCommand::Light3DirectionZ,
1314        GeCommand::Light0ConstantAtten,
1315        GeCommand::Light0LinearAtten,
1316        GeCommand::Light0QuadtraticAtten,
1317        GeCommand::Light1ConstantAtten,
1318        GeCommand::Light1LinearAtten,
1319        GeCommand::Light1QuadtraticAtten,
1320        GeCommand::Light2ConstantAtten,
1321        GeCommand::Light2LinearAtten,
1322        GeCommand::Light2QuadtraticAtten,
1323        GeCommand::Light3ConstantAtten,
1324        GeCommand::Light3LinearAtten,
1325        GeCommand::Light3QuadtraticAtten,
1326        GeCommand::Light0ExponentAtten,
1327        GeCommand::Light1ExponentAtten,
1328        GeCommand::Light2ExponentAtten,
1329        GeCommand::Light3ExponentAtten,
1330        GeCommand::Light0CutoffAtten,
1331        GeCommand::Light1CutoffAtten,
1332        GeCommand::Light2CutoffAtten,
1333        GeCommand::Light3CutoffAtten,
1334        GeCommand::Light0Ambient,
1335        GeCommand::Light0Diffuse,
1336        GeCommand::Light0Specular,
1337        GeCommand::Light1Ambient,
1338        GeCommand::Light1Diffuse,
1339        GeCommand::Light1Specular,
1340        GeCommand::Light2Ambient,
1341        GeCommand::Light2Diffuse,
1342        GeCommand::Light2Specular,
1343        GeCommand::Light3Ambient,
1344        GeCommand::Light3Diffuse,
1345        GeCommand::Light3Specular,
1346        GeCommand::Cull,
1347        GeCommand::FrameBufPtr,
1348        GeCommand::FrameBufWidth,
1349        GeCommand::ZBufPtr,
1350        GeCommand::ZBufWidth,
1351        GeCommand::TexAddr0,
1352        GeCommand::TexAddr1,
1353        GeCommand::TexAddr2,
1354        GeCommand::TexAddr3,
1355        GeCommand::TexAddr4,
1356        GeCommand::TexAddr5,
1357        GeCommand::TexAddr6,
1358        GeCommand::TexAddr7,
1359        GeCommand::TexBufWidth0,
1360        GeCommand::TexBufWidth1,
1361        GeCommand::TexBufWidth2,
1362        GeCommand::TexBufWidth3,
1363        GeCommand::TexBufWidth4,
1364        GeCommand::TexBufWidth5,
1365        GeCommand::TexBufWidth6,
1366        GeCommand::TexBufWidth7,
1367        GeCommand::ClutAddr,
1368        GeCommand::ClutAddrUpper,
1369        GeCommand::TransferSrc,
1370        GeCommand::TransferSrcW,
1371        GeCommand::TransferDst,
1372        GeCommand::TransferDstW,
1373        GeCommand::TexSize0,
1374        GeCommand::TexSize1,
1375        GeCommand::TexSize2,
1376        GeCommand::TexSize3,
1377        GeCommand::TexSize4,
1378        GeCommand::TexSize5,
1379        GeCommand::TexSize6,
1380        GeCommand::TexSize7,
1381        GeCommand::TexMapMode,
1382        GeCommand::TexShadeLs,
1383        GeCommand::TexMode,
1384        GeCommand::TexFormat,
1385        GeCommand::LoadClut,
1386        GeCommand::ClutFormat,
1387        GeCommand::TexFilter,
1388        GeCommand::TexWrap,
1389        GeCommand::TexLevel,
1390        GeCommand::TexFunc,
1391        GeCommand::TexEnvColor,
1392        GeCommand::TexFlush,
1393        GeCommand::TexSync,
1394        GeCommand::Fog1,
1395        GeCommand::Fog2,
1396        GeCommand::FogColor,
1397        GeCommand::TexLodSlope,
1398        GeCommand::FramebufPixFormat,
1399        GeCommand::ClearMode,
1400        GeCommand::Scissor1,
1401        GeCommand::Scissor2,
1402        GeCommand::MinZ,
1403        GeCommand::MaxZ,
1404        GeCommand::ColorTest,
1405        GeCommand::ColorRef,
1406        GeCommand::ColorTestmask,
1407        GeCommand::AlphaTest,
1408        GeCommand::StencilTest,
1409        GeCommand::StencilOp,
1410        GeCommand::ZTest,
1411        GeCommand::BlendMode,
1412        GeCommand::BlendFixedA,
1413        GeCommand::BlendFixedB,
1414        GeCommand::Dith0,
1415        GeCommand::Dith1,
1416        GeCommand::Dith2,
1417        GeCommand::Dith3,
1418        GeCommand::LogicOp,
1419        GeCommand::ZWriteDisable,
1420        GeCommand::MaskRgb,
1421        GeCommand::MaskAlpha,
1422        GeCommand::TransferSrcPos,
1423        GeCommand::TransferDstPos,
1424        GeCommand::TransferSize,
1425        GeCommand::Vscx,
1426        GeCommand::Vscy,
1427        GeCommand::Vscz,
1428        GeCommand::Vtcs,
1429        GeCommand::Vtct,
1430        GeCommand::Vtcq,
1431        GeCommand::Vcv,
1432        GeCommand::Vap,
1433        GeCommand::Vfc,
1434        GeCommand::Vscv,
1435        GeCommand::Finish,
1436        GeCommand::End,
1437        GeCommand::Nop,
1438        GeCommand::Nop,
1439    ];
1440
1441    static INIT_LIST: crate::Align16<[u32; 223]> = crate::Align16({
1442        let mut out = [0; 223];
1443
1444        let mut i = 0;
1445        while i < 223 {
1446            out[i] = (INIT_COMMANDS[i] as u32) << 24;
1447            i += 1;
1448        }
1449
1450        out
1451    });
1452
1453    let mut callback = crate::sys::GeCallbackData {
1454        signal_func: Some(callback_sig),
1455        signal_arg: addr_of_mut!(SETTINGS).cast::<c_void>(),
1456        finish_func: Some(callback_fin),
1457        finish_arg: addr_of_mut!(SETTINGS).cast::<c_void>(),
1458    };
1459
1460    SETTINGS.ge_callback_id = crate::sys::sceGeSetCallback(&mut callback);
1461    SETTINGS.swap_buffers_callback = None;
1462    SETTINGS.swap_buffers_behaviour = super::display::DisplaySetBufSync::Immediate;
1463
1464    GE_EDRAM_ADDRESS = sys::sceGeEdramGetAddr().cast::<c_void>();
1465
1466    GE_LIST_EXECUTED[0] = sys::sceGeListEnQueue(
1467        (&INIT_LIST as *const _ as u32 & 0x1fffffff) as *const _,
1468        core::ptr::null_mut(),
1469        SETTINGS.ge_callback_id,
1470        core::ptr::null_mut(),
1471    );
1472
1473    reset_values();
1474
1475    SETTINGS.kernel_event_flag = super::kernel::sceKernelCreateEventFlag(
1476        b"SceGuSignal\0" as *const u8,
1477        super::kernel::EventFlagAttributes::WAIT_MULTIPLE,
1478        3,
1479        null_mut(),
1480    );
1481
1482    sys::sceGeListSync(GE_LIST_EXECUTED[0], 0);
1483}
1484
1485#[allow(non_snake_case)]
1489#[no_mangle]
1490pub unsafe extern "C" fn sceGuTerm() {
1491    sys::sceKernelDeleteEventFlag(SETTINGS.kernel_event_flag);
1492    sys::sceGeUnsetCallback(SETTINGS.ge_callback_id);
1493}
1494
1495#[allow(non_snake_case)]
1499#[no_mangle]
1500pub unsafe extern "C" fn sceGuBreak(mode: i32) {
1501    static mut UNUSED_BREAK: GeBreakParam = GeBreakParam { buf: [0; 4] };
1502
1503    sys::sceGeBreak(mode, addr_of_mut!(UNUSED_BREAK));
1504}
1505
1506#[allow(non_snake_case)]
1507#[no_mangle]
1508pub unsafe extern "C" fn sceGuContinue() {
1509    sys::sceGeContinue();
1511}
1512
1513#[allow(non_snake_case)]
1525#[no_mangle]
1526pub unsafe extern "C" fn sceGuSetCallback(
1527    signal: GuCallbackId,
1528    callback: GuCallback,
1529) -> GuCallback {
1530    let old_callback;
1531
1532    match signal {
1533        GuCallbackId::Signal => {
1534            old_callback = SETTINGS.sig;
1535            SETTINGS.sig = callback;
1536        }
1537
1538        GuCallbackId::Finish => {
1539            old_callback = SETTINGS.fin;
1540            SETTINGS.fin = callback;
1541        }
1542    }
1543
1544    old_callback
1545}
1546
1547#[allow(non_snake_case)]
1555#[no_mangle]
1556pub unsafe extern "C" fn sceGuSignal(behavior: SignalBehavior, signal: i32) {
1557    send_command_i(
1558        GeCommand::Signal,
1559        ((signal & 0xff) << 16) | (behavior as i32 & 0xffff),
1560    );
1561    send_command_i(GeCommand::End, 0);
1562
1563    if signal == 3 {
1564        send_command_i(GeCommand::Finish, 0);
1565        send_command_i(GeCommand::End, 0);
1566    }
1567
1568    send_command_i_stall(GeCommand::Nop, 0);
1569}
1570
1571#[allow(non_snake_case)]
1580#[no_mangle]
1581pub unsafe extern "C" fn sceGuSendCommandf(cmd: GeCommand, argument: f32) {
1582    send_command_f(cmd, argument);
1583}
1584
1585#[allow(non_snake_case)]
1594#[no_mangle]
1595pub unsafe extern "C" fn sceGuSendCommandi(cmd: GeCommand, argument: i32) {
1596    send_command_i(cmd, argument);
1597}
1598
1599#[allow(non_snake_case)]
1614#[no_mangle]
1615pub unsafe extern "C" fn sceGuGetMemory(mut size: i32) -> *mut c_void {
1616    size += 3;
1618    size += (((size >> 31) as u32) >> 30) as i32;
1619    size = (size >> 2) << 2;
1620
1621    let orig_ptr = (*LIST).current;
1622    let new_ptr = (orig_ptr as usize + size as usize + 8) as *mut u32;
1623
1624    let lo = (8 << 24) | (new_ptr as i32 & 0xffffff);
1625    let hi = ((16 << 24) | ((new_ptr as u32 >> 8) & 0xf0000)) as i32;
1626
1627    *orig_ptr = hi as u32;
1628    *orig_ptr.offset(1) = lo as u32;
1629
1630    (*LIST).current = new_ptr;
1631
1632    if let GuContextType::Direct = CURR_CONTEXT {
1633        crate::sys::sceGeListUpdateStallAddr(GE_LIST_EXECUTED[0], new_ptr.cast::<c_void>());
1634    }
1635
1636    orig_ptr.add(2).cast::<c_void>()
1637}
1638
1639#[allow(non_snake_case)]
1648#[no_mangle]
1649pub unsafe extern "C" fn sceGuStart(context_type: GuContextType, list: *mut c_void) {
1650    let context = &mut CONTEXTS[context_type as usize];
1651    let local_list = ((list as u32) | 0x4000_0000) as *mut u32;
1652
1653    context.list.start = local_list;
1655    context.list.current = local_list;
1656    context.list.parent_context = CURR_CONTEXT;
1657    LIST = &mut context.list;
1658
1659    CURR_CONTEXT = context_type;
1661
1662    if let GuContextType::Direct = context_type {
1663        GE_LIST_EXECUTED[0] = crate::sys::sceGeListEnQueue(
1664            local_list as *mut c_void,
1665            local_list as *mut c_void,
1666            SETTINGS.ge_callback_id,
1667            core::ptr::null_mut(),
1668        );
1669
1670        SETTINGS.signal_offset = 0;
1671    }
1672
1673    if INIT == 0 {
1674        static DITHER_MATRIX: ScePspIMatrix4 = ScePspIMatrix4 {
1675            x: ScePspIVector4 {
1676                x: -4,
1677                y: 0,
1678                z: -3,
1679                w: 1,
1680            },
1681            y: ScePspIVector4 {
1682                x: 2,
1683                y: -2,
1684                z: 3,
1685                w: -1,
1686            },
1687            z: ScePspIVector4 {
1688                x: -3,
1689                y: 1,
1690                z: -4,
1691                w: 0,
1692            },
1693            w: ScePspIVector4 {
1694                x: 3,
1695                y: -1,
1696                z: 2,
1697                w: -2,
1698            },
1699        };
1700
1701        sceGuSetDither(&DITHER_MATRIX);
1702        sceGuPatchDivide(16, 16);
1703        sceGuColorMaterial(
1704            LightComponent::AMBIENT | LightComponent::DIFFUSE | LightComponent::SPECULAR,
1705        );
1706
1707        sceGuSpecular(1.0);
1708        sceGuTexScale(1.0, 1.0);
1709
1710        INIT = 1;
1711    }
1712
1713    if let GuContextType::Direct = CURR_CONTEXT {
1714        if DRAW_BUFFER.frame_width != 0 {
1715            send_command_i(
1716                GeCommand::FrameBufPtr,
1717                DRAW_BUFFER.frame_buffer as i32 & 0xffffff,
1718            );
1719            send_command_i(
1720                GeCommand::FrameBufWidth,
1721                ((DRAW_BUFFER.frame_buffer as u32 & 0xff00_0000) >> 8) as i32
1722                    | DRAW_BUFFER.frame_width,
1723            );
1724        }
1725    }
1726}
1727
1728#[allow(non_snake_case)]
1743#[no_mangle]
1744pub unsafe extern "C" fn sceGuFinish() -> i32 {
1745    match CURR_CONTEXT {
1746        GuContextType::Direct | GuContextType::Send => {
1747            send_command_i(GeCommand::Finish, 0);
1748            send_command_i_stall(GeCommand::End, 0);
1749        }
1750
1751        GuContextType::Call => {
1752            if CALL_MODE == 1 {
1753                send_command_i(GeCommand::Signal, 0x120000);
1754                send_command_i(GeCommand::End, 0);
1755                send_command_i_stall(GeCommand::Nop, 0);
1756            } else {
1757                send_command_i(GeCommand::Ret, 0);
1758            }
1759        }
1760    }
1761
1762    let size = ((*LIST).current as usize) - ((*LIST).start as usize);
1763
1764    CURR_CONTEXT = (*LIST).parent_context;
1766    LIST = &mut CONTEXTS[CURR_CONTEXT as usize].list;
1767    size as i32
1768}
1769
1770#[allow(non_snake_case)]
1785#[no_mangle]
1786pub unsafe extern "C" fn sceGuFinishId(id: u32) -> i32 {
1787    match CURR_CONTEXT {
1788        GuContextType::Direct | GuContextType::Send => {
1789            send_command_i(GeCommand::Finish, (id & 0xffff) as i32);
1790            send_command_i_stall(GeCommand::End, 0);
1791        }
1792
1793        GuContextType::Call => {
1794            if CALL_MODE == 1 {
1795                send_command_i(GeCommand::Signal, 0x120000);
1796                send_command_i(GeCommand::End, 0);
1797                send_command_i_stall(GeCommand::Nop, 0);
1798            } else {
1799                send_command_i(GeCommand::Ret, 0);
1800            }
1801        }
1802    }
1803
1804    let size = ((*LIST).current as usize) - ((*LIST).start as usize);
1805
1806    CURR_CONTEXT = (*LIST).parent_context;
1808    LIST = &mut CONTEXTS[CURR_CONTEXT as usize].list;
1809    size as i32
1810}
1811
1812#[allow(non_snake_case)]
1818#[no_mangle]
1819pub unsafe extern "C" fn sceGuCallList(list: *const c_void) {
1820    let list_addr = list as u32;
1821
1822    if CALL_MODE == 1 {
1823        send_command_i(GeCommand::Signal, (list_addr >> 16) as i32 | 0x110000);
1824        send_command_i(GeCommand::End, list_addr as i32 & 0xffff);
1825        send_command_i_stall(GeCommand::Nop, 0);
1826    } else {
1827        send_command_i(GeCommand::Base, (list_addr >> 8) as i32 & 0xf0000);
1828        send_command_i_stall(GeCommand::Call, list_addr as i32 & 0xffffff);
1829    }
1830}
1831
1832#[allow(non_snake_case)]
1840#[no_mangle]
1841pub unsafe extern "C" fn sceGuCallMode(mode: i32) {
1842    CALL_MODE = mode;
1843}
1844
1845#[allow(non_snake_case)]
1851#[no_mangle]
1852pub unsafe extern "C" fn sceGuCheckList() -> i32 {
1853    (*LIST).current.sub((*LIST).start as usize) as i32
1854}
1855
1856#[allow(non_snake_case)]
1864#[no_mangle]
1865pub unsafe extern "C" fn sceGuSendList(
1866    mode: GuQueueMode,
1867    list: *const c_void,
1868    context: *mut GeContext,
1869) {
1870    SETTINGS.signal_offset = 0;
1871
1872    let mut args = GeListArgs {
1873        size: 8,
1874        context,
1875        ..<_>::default()
1876    };
1877
1878    let callback = SETTINGS.ge_callback_id;
1879
1880    let list_id = match mode {
1881        GuQueueMode::Head => {
1882            crate::sys::sceGeListEnQueueHead(list, null_mut(), callback, &mut args)
1883        }
1884
1885        GuQueueMode::Tail => crate::sys::sceGeListEnQueue(list, null_mut(), callback, &mut args),
1886    };
1887
1888    GE_LIST_EXECUTED[1] = list_id;
1889}
1890
1891#[allow(non_snake_case)]
1897#[no_mangle]
1898pub unsafe extern "C" fn sceGuSwapBuffers() -> *mut c_void {
1899    if let Some(cb) = SETTINGS.swap_buffers_callback {
1900        cb(
1901            addr_of_mut!(DRAW_BUFFER.disp_buffer),
1902            addr_of_mut!(DRAW_BUFFER.frame_buffer),
1903        );
1904    } else {
1905        mem::swap(&mut DRAW_BUFFER.disp_buffer, &mut DRAW_BUFFER.frame_buffer);
1906    }
1907
1908    if DISPLAY_ON {
1909        crate::sys::sceDisplaySetFrameBuf(
1910            GE_EDRAM_ADDRESS.add(DRAW_BUFFER.disp_buffer as usize) as *const u8,
1911            DRAW_BUFFER.frame_width as usize,
1912            DRAW_BUFFER.pixel_size,
1913            SETTINGS.swap_buffers_behaviour,
1914        );
1915    }
1916
1917    CURRENT_FRAME ^= 1;
1919
1920    DRAW_BUFFER.frame_buffer
1921}
1922
1923#[allow(non_snake_case)]
1934#[no_mangle]
1935pub unsafe extern "C" fn sceGuSync(mode: GuSyncMode, behavior: GuSyncBehavior) -> GeListState {
1936    match mode {
1937        GuSyncMode::Finish => crate::sys::sceGeDrawSync(behavior as i32),
1938        GuSyncMode::List => crate::sys::sceGeListSync(GE_LIST_EXECUTED[0], behavior as i32),
1939        GuSyncMode::Send => crate::sys::sceGeListSync(GE_LIST_EXECUTED[1], behavior as i32),
1940        _ => GeListState::Done,
1941    }
1942}
1943
1944#[allow(non_snake_case)]
1967#[no_mangle]
1968pub unsafe extern "C" fn sceGuDrawArray(
1969    prim: GuPrimitive,
1970    vtype: VertexType,
1971    count: i32,
1972    indices: *const c_void,
1973    vertices: *const c_void,
1974) {
1975    if !vtype.is_empty() {
1976        send_command_i(GeCommand::VertexType, vtype.bits());
1977    }
1978
1979    if !indices.is_null() {
1980        send_command_i(GeCommand::Base, (indices as u32 >> 8) as i32 & 0xf0000);
1981        send_command_i(GeCommand::Iaddr, indices as i32 & 0xffffff);
1982    }
1983
1984    if !vertices.is_null() {
1985        send_command_i(GeCommand::Base, (vertices as u32 >> 8) as i32 & 0xf0000);
1986        send_command_i(GeCommand::Vaddr, vertices as i32 & 0xffffff);
1987    }
1988
1989    send_command_i_stall(GeCommand::Prim, ((prim as i32) << 16) | count);
1990}
1991
1992#[allow(non_snake_case)]
2005#[no_mangle]
2006pub unsafe extern "C" fn sceGuBeginObject(
2007    vtype: i32,
2008    count: i32,
2009    indices: *const c_void,
2010    vertices: *const c_void,
2011) {
2012    if vtype != 0 {
2013        send_command_i(GeCommand::VertexType, vtype);
2014    }
2015
2016    if !indices.is_null() {
2017        send_command_i(GeCommand::Base, (indices as u32 >> 8) as i32 & 0xf0000);
2018        send_command_i(GeCommand::Iaddr, indices as i32 & 0xffffff);
2019    }
2020
2021    if !vertices.is_null() {
2022        send_command_i(GeCommand::Base, (vertices as u32 >> 8) as i32 & 0xf0000);
2023        send_command_i(GeCommand::Vaddr, vertices as i32 & 0xffffff);
2024    }
2025
2026    send_command_i(GeCommand::BoundingBox, count);
2027
2028    (*OBJECT_STACK.offset(OBJECT_STACK_DEPTH as isize)) = (*LIST).current;
2030    OBJECT_STACK_DEPTH += 1;
2031
2032    send_command_i(GeCommand::Base, 0);
2034    send_command_i(GeCommand::BJump, 0);
2035}
2036
2037#[allow(non_snake_case)]
2039#[no_mangle]
2040pub unsafe extern "C" fn sceGuEndObject() {
2041    let current = (*LIST).current;
2044    (*LIST).current = *OBJECT_STACK.offset(OBJECT_STACK_DEPTH as isize - 1);
2045
2046    send_command_i(GeCommand::Base, (current as u32 >> 8) as i32 & 0xf0000);
2047    send_command_i(GeCommand::BJump, current as i32 & 0xffffff);
2048    (*LIST).current = current;
2049    OBJECT_STACK_DEPTH -= 1;
2050}
2051
2052#[allow(non_snake_case)]
2062#[no_mangle]
2063pub unsafe extern "C" fn sceGuSetStatus(state: GuState, status: i32) {
2064    if status != 0 {
2065        sceGuEnable(state);
2066    } else {
2067        sceGuDisable(state);
2068    }
2069}
2070
2071#[allow(non_snake_case)]
2081#[no_mangle]
2082pub unsafe extern "C" fn sceGuGetStatus(state: GuState) -> bool {
2083    let state = state as u32;
2084
2085    if state < 22 {
2086        return (STATES >> state) & 1 != 0;
2087    }
2088
2089    false
2090}
2091
2092#[allow(non_snake_case)]
2098#[no_mangle]
2099pub unsafe extern "C" fn sceGuSetAllStatus(status: i32) {
2100    for i in 0..22 {
2101        if (status >> i) & 1 != 0 {
2102            sceGuEnable(mem::transmute(i));
2103        } else {
2104            sceGuDisable(mem::transmute(i));
2105        }
2106    }
2107}
2108
2109#[allow(non_snake_case)]
2115#[no_mangle]
2116pub unsafe extern "C" fn sceGuGetAllStatus() -> i32 {
2117    STATES as i32
2118}
2119
2120#[allow(non_snake_case)]
2126#[no_mangle]
2127pub unsafe extern "C" fn sceGuEnable(state: GuState) {
2128    match state {
2129        GuState::AlphaTest => send_command_i(GeCommand::AlphaTestEnable, 1),
2130        GuState::DepthTest => send_command_i(GeCommand::ZTestEnable, 1),
2131        GuState::ScissorTest => {
2132            let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2133            context.scissor_enable = 1;
2134            send_command_i(
2135                GeCommand::Scissor1,
2136                (context.scissor_start[1] << 10) | context.scissor_start[0],
2137            );
2138            send_command_i(
2139                GeCommand::Scissor2,
2140                (context.scissor_end[1] << 10) | context.scissor_end[0],
2141            );
2142        }
2143        GuState::StencilTest => send_command_i(GeCommand::StencilTestEnable, 1),
2144        GuState::Blend => send_command_i(GeCommand::AlphaBlendEnable, 1),
2145        GuState::CullFace => send_command_i(GeCommand::CullFaceEnable, 1),
2146        GuState::Dither => send_command_i(GeCommand::DitherEnable, 1),
2147        GuState::Fog => send_command_i(GeCommand::FogEnable, 1),
2148        GuState::ClipPlanes => send_command_i(GeCommand::DepthClampEnable, 1),
2149        GuState::Texture2D => send_command_i(GeCommand::TextureMapEnable, 1),
2150        GuState::Lighting => send_command_i(GeCommand::LightingEnable, 1),
2151        GuState::Light0 => send_command_i(GeCommand::LightEnable0, 1),
2152        GuState::Light1 => send_command_i(GeCommand::LightEnable1, 1),
2153        GuState::Light2 => send_command_i(GeCommand::LightEnable2, 1),
2154        GuState::Light3 => send_command_i(GeCommand::LightEnable3, 1),
2155        GuState::LineSmooth => send_command_i(GeCommand::AntiAliasEnable, 1),
2156        GuState::PatchCullFace => send_command_i(GeCommand::PatchCullEnable, 1),
2157        GuState::ColorTest => send_command_i(GeCommand::ColorTestEnable, 1),
2158        GuState::ColorLogicOp => send_command_i(GeCommand::LogicOpEnable, 1),
2159        GuState::FaceNormalReverse => send_command_i(GeCommand::ReverseNormal, 1),
2160        GuState::PatchFace => send_command_i(GeCommand::PatchFacing, 1),
2161        GuState::Fragment2X => {
2162            let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2163            context.fragment_2x = 0x10000;
2164            send_command_i(GeCommand::TexFunc, 0x10000 | context.texture_function);
2165        }
2166    }
2167
2168    if (state as u32) < 22 {
2169        STATES |= 1 << state as u32
2170    }
2171}
2172
2173#[allow(non_snake_case)]
2179#[no_mangle]
2180pub unsafe extern "C" fn sceGuDisable(state: GuState) {
2181    match state {
2182        GuState::AlphaTest => send_command_i(GeCommand::AlphaTestEnable, 0),
2183        GuState::DepthTest => send_command_i(GeCommand::ZTestEnable, 0),
2184        GuState::ScissorTest => {
2185            let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2186            context.scissor_enable = 0;
2187            send_command_i(GeCommand::Scissor1, 0);
2188            send_command_i(
2189                GeCommand::Scissor2,
2190                ((DRAW_BUFFER.height - 1) << 10) | (DRAW_BUFFER.width - 1),
2191            );
2192        }
2193        GuState::StencilTest => send_command_i(GeCommand::StencilTestEnable, 0),
2194        GuState::Blend => send_command_i(GeCommand::AlphaBlendEnable, 0),
2195        GuState::CullFace => send_command_i(GeCommand::CullFaceEnable, 0),
2196        GuState::Dither => send_command_i(GeCommand::DitherEnable, 0),
2197        GuState::Fog => send_command_i(GeCommand::FogEnable, 0),
2198        GuState::ClipPlanes => send_command_i(GeCommand::DepthClampEnable, 0),
2199        GuState::Texture2D => send_command_i(GeCommand::TextureMapEnable, 0),
2200        GuState::Lighting => send_command_i(GeCommand::LightingEnable, 0),
2201        GuState::Light0 => send_command_i(GeCommand::LightEnable0, 0),
2202        GuState::Light1 => send_command_i(GeCommand::LightEnable1, 0),
2203        GuState::Light2 => send_command_i(GeCommand::LightEnable2, 0),
2204        GuState::Light3 => send_command_i(GeCommand::LightEnable3, 0),
2205        GuState::LineSmooth => send_command_i(GeCommand::AntiAliasEnable, 0),
2206        GuState::PatchCullFace => send_command_i(GeCommand::PatchCullEnable, 0),
2207        GuState::ColorTest => send_command_i(GeCommand::ColorTestEnable, 0),
2208        GuState::ColorLogicOp => send_command_i(GeCommand::LogicOpEnable, 0),
2209        GuState::FaceNormalReverse => send_command_i(GeCommand::ReverseNormal, 0),
2210        GuState::PatchFace => send_command_i(GeCommand::PatchFacing, 0),
2211        GuState::Fragment2X => {
2212            let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2213            context.fragment_2x = 0;
2214            send_command_i(GeCommand::TexFunc, context.texture_function);
2215        }
2216    }
2217
2218    if (state as u32) < 22 {
2219        STATES &= !(1 << state as u32)
2220    }
2221}
2222
2223#[allow(non_snake_case)]
2233#[no_mangle]
2234pub unsafe extern "C" fn sceGuLight(
2235    light: i32,
2236    type_: LightType,
2237    components: LightComponent,
2238    position: &ScePspFVector3,
2239) {
2240    let settings = &LIGHT_COMMANDS[light as usize];
2241
2242    send_command_f(settings.xpos, position.x);
2243    send_command_f(settings.ypos, position.y);
2244    send_command_f(settings.zpos, position.z);
2245
2246    let mut kind = 2;
2247    if components.bits() != 8 {
2248        kind = if components.bits() ^ 6 < 1 { 1 } else { 0 };
2249    }
2250
2251    send_command_i(settings.type_, ((type_ as i32 & 0x03) << 8) | kind);
2252}
2253
2254#[allow(non_snake_case)]
2263#[no_mangle]
2264pub unsafe extern "C" fn sceGuLightAtt(light: i32, atten0: f32, atten1: f32, atten2: f32) {
2265    let settings = &LIGHT_COMMANDS[light as usize];
2266    send_command_f(settings.constant, atten0);
2267    send_command_f(settings.linear, atten1);
2268    send_command_f(settings.quadratic, atten2);
2269}
2270
2271#[allow(non_snake_case)]
2279#[no_mangle]
2280pub unsafe extern "C" fn sceGuLightColor(light: i32, component: LightComponent, color: u32) {
2281    let settings = &LIGHT_COMMANDS[light as usize];
2282
2283    if component.intersects(LightComponent::AMBIENT) {
2289        send_command_i(settings.ambient, (color & 0xffffff) as i32);
2290    }
2291
2292    if component.intersects(LightComponent::DIFFUSE) {
2293        send_command_i(settings.diffuse, (color & 0xffffff) as i32);
2294    }
2295
2296    if component.intersects(LightComponent::SPECULAR) {
2297        send_command_i(settings.specular, (color & 0xffffff) as i32);
2298    }
2299}
2300
2301#[allow(non_snake_case)]
2307#[no_mangle]
2308pub unsafe extern "C" fn sceGuLightMode(mode: LightMode) {
2309    send_command_i(GeCommand::LightMode, mode as i32);
2310}
2311
2312#[allow(non_snake_case)]
2321#[no_mangle]
2322pub unsafe extern "C" fn sceGuLightSpot(
2323    light: i32,
2324    direction: &ScePspFVector3,
2325    exponent: f32,
2326    cutoff: f32,
2327) {
2328    let settings = &LIGHT_COMMANDS[light as usize];
2329
2330    send_command_f(settings.exponent, exponent);
2331    send_command_f(settings.cutoff, cutoff);
2332
2333    send_command_f(settings.xdir, direction.x);
2334    send_command_f(settings.ydir, direction.y);
2335    send_command_f(settings.zdir, direction.z);
2336}
2337
2338#[allow(non_snake_case)]
2344#[no_mangle]
2345pub unsafe extern "C" fn sceGuClear(flags: ClearBuffer) {
2346    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2347
2348    struct Vertex {
2349        color: u32,
2350        x: u16,
2351        y: u16,
2352        z: u16,
2353        _pad: u16,
2354    }
2355
2356    let filter: u32 = match DRAW_BUFFER.pixel_size {
2357        DisplayPixelFormat::Psm5650 => context.clear_color & 0xffffff,
2358        DisplayPixelFormat::Psm5551 => {
2359            (context.clear_color & 0xffffff) | (context.clear_stencil << 31)
2360        }
2361        DisplayPixelFormat::Psm4444 => {
2362            (context.clear_color & 0xffffff) | (context.clear_stencil << 28)
2363        }
2364        DisplayPixelFormat::Psm8888 => {
2365            (context.clear_color & 0xffffff) | (context.clear_stencil << 24)
2366        }
2367    };
2368
2369    let vertices;
2370    let count;
2371
2372    if !flags.intersects(ClearBuffer::FAST_CLEAR_BIT) {
2373        vertices = sceGuGetMemory(2 * mem::size_of::<Vertex>() as i32) as *mut Vertex;
2374        count = 2;
2375
2376        (*vertices.offset(0)).color = 0;
2377        (*vertices.offset(0)).x = 0;
2378        (*vertices.offset(0)).y = 0;
2379        (*vertices.offset(0)).z = context.clear_depth as u16;
2380
2381        (*vertices.offset(1)).color = filter;
2382        (*vertices.offset(1)).x = DRAW_BUFFER.width as u16;
2383        (*vertices.offset(1)).y = DRAW_BUFFER.height as u16;
2384        (*vertices.offset(1)).z = context.clear_depth as u16;
2385    } else {
2386        count = ((DRAW_BUFFER.width + 63) / 64) * 2;
2387        vertices = sceGuGetMemory(count * core::mem::size_of::<Vertex>() as i32) as *mut Vertex;
2388
2389        let mut curr = vertices;
2390
2391        for i in 0..count {
2392            let j = i >> 1;
2393            let k = i & 1;
2394
2395            (*curr).color = filter;
2396            (*curr).x = (j + k) as u16 * 64;
2397            (*curr).y = (k * DRAW_BUFFER.height) as u16;
2398            (*curr).z = context.clear_depth as u16;
2399
2400            curr = curr.add(1);
2401        }
2402    }
2403
2404    {
2405        let relevant_flags = flags
2406            & (ClearBuffer::COLOR_BUFFER_BIT
2407                | ClearBuffer::STENCIL_BUFFER_BIT
2408                | ClearBuffer::DEPTH_BUFFER_BIT);
2409
2410        send_command_i(
2411            GeCommand::ClearMode,
2412            (relevant_flags.bits() << 8) as i32 | 0x01,
2413        );
2414    }
2415
2416    sceGuDrawArray(
2417        GuPrimitive::Sprites,
2418        VertexType::COLOR_8888 | VertexType::VERTEX_16BIT | VertexType::TRANSFORM_2D,
2419        count,
2420        null_mut(),
2421        vertices as *mut c_void,
2422    );
2423
2424    send_command_i(GeCommand::ClearMode, 0);
2425}
2426
2427#[allow(non_snake_case)]
2433#[no_mangle]
2434pub unsafe extern "C" fn sceGuClearColor(color: u32) {
2435    CONTEXTS[CURR_CONTEXT as usize].clear_color = color;
2436}
2437
2438#[allow(non_snake_case)]
2445#[no_mangle]
2446pub unsafe extern "C" fn sceGuClearDepth(depth: u32) {
2447    CONTEXTS[CURR_CONTEXT as usize].clear_depth = depth;
2448}
2449
2450#[allow(non_snake_case)]
2457#[no_mangle]
2458pub unsafe extern "C" fn sceGuClearStencil(stencil: u32) {
2459    CONTEXTS[CURR_CONTEXT as usize].clear_stencil = stencil;
2460}
2461
2462#[allow(non_snake_case)]
2468#[no_mangle]
2469pub unsafe extern "C" fn sceGuPixelMask(mask: u32) {
2470    send_command_i(GeCommand::MaskRgb, mask as i32 & 0xffffff);
2471    send_command_i(GeCommand::MaskAlpha, (mask >> 24) as i32);
2472}
2473
2474#[allow(non_snake_case)]
2480#[no_mangle]
2481pub unsafe extern "C" fn sceGuColor(color: u32) {
2482    sceGuMaterial(
2483        LightComponent::AMBIENT | LightComponent::DIFFUSE | LightComponent::SPECULAR,
2484        color,
2485    );
2486}
2487
2488#[allow(non_snake_case)]
2499#[no_mangle]
2500pub unsafe extern "C" fn sceGuColorFunc(func: ColorFunc, color: u32, mask: u32) {
2501    send_command_i(GeCommand::ColorTest, func as i32 & 0x03);
2502    send_command_i(GeCommand::ColorRef, color as i32 & 0xffffff);
2503    send_command_i(GeCommand::ColorTestmask, mask as i32);
2504}
2505
2506#[allow(non_snake_case)]
2512#[no_mangle]
2513pub unsafe extern "C" fn sceGuColorMaterial(components: LightComponent) {
2514    send_command_i(GeCommand::MaterialUpdate, components.bits());
2515}
2516
2517#[allow(non_snake_case)]
2525#[no_mangle]
2526pub unsafe extern "C" fn sceGuAlphaFunc(func: AlphaFunc, value: i32, mask: i32) {
2527    let arg = func as i32 | ((value & 0xff) << 8) | ((mask & 0xff) << 16);
2528    send_command_i(GeCommand::AlphaTest, arg);
2529}
2530
2531#[allow(non_snake_case)]
2532#[no_mangle]
2533pub unsafe extern "C" fn sceGuAmbient(color: u32) {
2534    send_command_i(GeCommand::AmbientColor, color as i32 & 0xffffff);
2535    send_command_i(GeCommand::AmbientAlpha, (color >> 24) as i32);
2536}
2537
2538#[allow(non_snake_case)]
2539#[no_mangle]
2540pub unsafe extern "C" fn sceGuAmbientColor(color: u32) {
2541    send_command_i(GeCommand::MaterialAmbient, color as i32 & 0xffffff);
2542    send_command_i(GeCommand::MaterialAlpha, (color >> 24) as i32);
2543}
2544
2545#[allow(non_snake_case)]
2557#[no_mangle]
2558pub unsafe extern "C" fn sceGuBlendFunc(
2559    op: BlendOp,
2560    src: BlendFactor,
2561    dest: BlendFactor,
2562    src_fix: u32,
2563    dest_fix: u32,
2564) {
2565    send_command_i(
2566        GeCommand::BlendMode,
2567        src as i32 | ((dest as i32) << 4) | ((op as i32) << 8),
2568    );
2569    send_command_i(GeCommand::BlendFixedA, src_fix as i32 & 0xffffff);
2570    send_command_i(GeCommand::BlendFixedB, dest_fix as i32 & 0xffffff);
2571}
2572
2573#[allow(non_snake_case)]
2580#[no_mangle]
2581pub unsafe extern "C" fn sceGuMaterial(components: LightComponent, color: u32) {
2582    if components.intersects(LightComponent::AMBIENT) {
2583        send_command_i(GeCommand::MaterialAmbient, color as i32 & 0xffffff);
2584        send_command_i(GeCommand::MaterialAlpha, (color >> 24) as i32);
2585    }
2586
2587    if components.intersects(LightComponent::DIFFUSE) {
2588        send_command_i(GeCommand::MaterialDiffuse, color as i32 & 0xffffff);
2589    }
2590
2591    if components.intersects(LightComponent::SPECULAR) {
2592        send_command_i(GeCommand::MaterialSpecular, color as i32 & 0xffffff);
2593    }
2594}
2595
2596#[allow(non_snake_case)]
2598#[no_mangle]
2599pub unsafe extern "C" fn sceGuModelColor(emissive: u32, ambient: u32, diffuse: u32, specular: u32) {
2600    send_command_i(GeCommand::MaterialEmissive, emissive as i32 & 0xffffff);
2601    send_command_i(GeCommand::MaterialAmbient, ambient as i32 & 0xffffff);
2602    send_command_i(GeCommand::MaterialDiffuse, diffuse as i32 & 0xffffff);
2603    send_command_i(GeCommand::MaterialSpecular, specular as i32 & 0xffffff);
2604}
2605
2606#[allow(non_snake_case)]
2615#[no_mangle]
2616pub unsafe extern "C" fn sceGuStencilFunc(func: StencilFunc, ref_: i32, mask: i32) {
2617    send_command_i(
2618        GeCommand::StencilTest,
2619        func as i32 | ((ref_ & 0xff) << 8) | ((mask & 0xff) << 16),
2620    );
2621}
2622
2623#[allow(non_snake_case)]
2634#[no_mangle]
2635pub unsafe extern "C" fn sceGuStencilOp(
2636    fail: StencilOperation,
2637    zfail: StencilOperation,
2638    zpass: StencilOperation,
2639) {
2640    send_command_i(
2641        GeCommand::StencilOp,
2642        fail as i32 | ((zfail as i32) << 8) | ((zpass as i32) << 16),
2643    );
2644}
2645
2646#[allow(non_snake_case)]
2652#[no_mangle]
2653pub unsafe extern "C" fn sceGuSpecular(power: f32) {
2654    send_command_f(GeCommand::MaterialSpecularCoef, power);
2655}
2656
2657#[allow(non_snake_case)]
2666#[no_mangle]
2667pub unsafe extern "C" fn sceGuFrontFace(order: FrontFaceDirection) {
2668    match order {
2669        FrontFaceDirection::CounterClockwise => send_command_i(GeCommand::Cull, 0),
2670        FrontFaceDirection::Clockwise => send_command_i(GeCommand::Cull, 1),
2671    }
2672}
2673
2674#[allow(non_snake_case)]
2683#[no_mangle]
2684pub unsafe extern "C" fn sceGuLogicalOp(op: LogicalOperation) {
2685    send_command_i(GeCommand::LogicOp, op as i32 & 0x0f);
2686}
2687
2688#[allow(non_snake_case)]
2697#[no_mangle]
2698pub unsafe extern "C" fn sceGuSetDither(matrix: &ScePspIMatrix4) {
2699    send_command_i(
2700        GeCommand::Dith0,
2701        (matrix.x.x & 0x0f)
2702            | ((matrix.x.y & 0x0f) << 4)
2703            | ((matrix.x.z & 0x0f) << 8)
2704            | ((matrix.x.w & 0x0f) << 12),
2705    );
2706
2707    send_command_i(
2708        GeCommand::Dith1,
2709        (matrix.y.x & 0x0f)
2710            | ((matrix.y.y & 0x0f) << 4)
2711            | ((matrix.y.z & 0x0f) << 8)
2712            | ((matrix.y.w & 0x0f) << 12),
2713    );
2714
2715    send_command_i(
2716        GeCommand::Dith2,
2717        (matrix.z.x & 0x0f)
2718            | ((matrix.z.y & 0x0f) << 4)
2719            | ((matrix.z.z & 0x0f) << 8)
2720            | ((matrix.z.w & 0x0f) << 12),
2721    );
2722
2723    send_command_i(
2724        GeCommand::Dith3,
2725        (matrix.w.x & 0x0f)
2726            | ((matrix.w.y & 0x0f) << 4)
2727            | ((matrix.w.z & 0x0f) << 8)
2728            | ((matrix.w.w & 0x0f) << 12),
2729    );
2730}
2731
2732#[allow(non_snake_case)]
2738#[no_mangle]
2739pub unsafe extern "C" fn sceGuShadeModel(mode: ShadingModel) {
2740    match mode {
2741        ShadingModel::Smooth => send_command_i(GeCommand::ShadeMode, 1),
2742        ShadingModel::Flat => send_command_i(GeCommand::ShadeMode, 0),
2743    }
2744}
2745
2746#[allow(non_snake_case)]
2767#[no_mangle]
2768pub unsafe extern "C" fn sceGuCopyImage(
2769    psm: DisplayPixelFormat,
2770    sx: i32,
2771    sy: i32,
2772    width: i32,
2773    height: i32,
2774    srcw: i32,
2775    src: *mut c_void,
2776    dx: i32,
2777    dy: i32,
2778    destw: i32,
2779    dest: *mut c_void,
2780) {
2781    send_command_i(GeCommand::TransferSrc, (src as i32) & 0xffffff);
2782    send_command_i(
2783        GeCommand::TransferSrcW,
2784        (((src as u32) & 0xff000000) >> 8) as i32 | srcw,
2785    );
2786    send_command_i(GeCommand::TransferSrcPos, (sy << 10) | sx);
2787    send_command_i(GeCommand::TransferDst, (dest as i32) & 0xffffff);
2788    send_command_i(
2789        GeCommand::TransferDstW,
2790        (((dest as u32) & 0xff000000) >> 8) as i32 | destw,
2791    );
2792    send_command_i(GeCommand::TransferDstPos, (dy << 10) | dx);
2793    send_command_i(GeCommand::TransferSize, ((height - 1) << 10) | (width - 1));
2794
2795    let is_32_bit_texel = if let DisplayPixelFormat::Psm8888 = psm {
2796        1
2797    } else {
2798        0
2799    };
2800
2801    send_command_i(GeCommand::TransferStart, is_32_bit_texel);
2802}
2803
2804#[allow(non_snake_case)]
2814#[no_mangle]
2815pub unsafe extern "C" fn sceGuTexEnvColor(color: u32) {
2816    send_command_i(GeCommand::TexEnvColor, color as i32 & 0xffffff);
2817}
2818
2819#[allow(non_snake_case)]
2826#[no_mangle]
2827pub unsafe extern "C" fn sceGuTexFilter(min: TextureFilter, mag: TextureFilter) {
2828    send_command_i(GeCommand::TexFilter, ((mag as i32) << 8) | (min as i32));
2829}
2830
2831#[allow(non_snake_case)]
2836#[no_mangle]
2837pub unsafe extern "C" fn sceGuTexFlush() {
2838    send_command_f(GeCommand::TexFlush, 0.0);
2839}
2840
2841#[allow(non_snake_case)]
2848#[no_mangle]
2849pub unsafe extern "C" fn sceGuTexFunc(tfx: TextureEffect, tcc: TextureColorComponent) {
2850    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2851    context.texture_function = (((tcc as u32) << 8) | (tfx as u32)) as i32;
2852    send_command_i(
2853        GeCommand::TexFunc,
2854        (((tcc as u32) << 8) | (tfx as u32) | context.fragment_2x as u32) as i32,
2855    );
2856}
2857
2858#[allow(non_snake_case)]
2899#[no_mangle]
2900pub unsafe extern "C" fn sceGuTexImage(
2901    mipmap: MipmapLevel,
2902    width: i32,
2903    height: i32,
2904    tbw: i32,
2905    tbp: *const c_void,
2906) {
2907    use core::intrinsics::ctlz;
2908
2909    const TBP_CMD_TBL: [GeCommand; 8] = [
2910        GeCommand::TexAddr0,
2911        GeCommand::TexAddr1,
2912        GeCommand::TexAddr2,
2913        GeCommand::TexAddr3,
2914        GeCommand::TexAddr4,
2915        GeCommand::TexAddr5,
2916        GeCommand::TexAddr6,
2917        GeCommand::TexAddr7,
2918    ];
2919
2920    const TBW_CMD_TBL: [GeCommand; 8] = [
2921        GeCommand::TexBufWidth0,
2922        GeCommand::TexBufWidth1,
2923        GeCommand::TexBufWidth2,
2924        GeCommand::TexBufWidth3,
2925        GeCommand::TexBufWidth4,
2926        GeCommand::TexBufWidth5,
2927        GeCommand::TexBufWidth6,
2928        GeCommand::TexBufWidth7,
2929    ];
2930
2931    const TSIZE_CMD_TBL: [GeCommand; 8] = [
2932        GeCommand::TexSize0,
2933        GeCommand::TexSize1,
2934        GeCommand::TexSize2,
2935        GeCommand::TexSize3,
2936        GeCommand::TexSize4,
2937        GeCommand::TexSize5,
2938        GeCommand::TexSize6,
2939        GeCommand::TexSize7,
2940    ];
2941
2942    send_command_i(TBP_CMD_TBL[mipmap as usize], (tbp as i32) & 0xffffff);
2943    send_command_i(
2944        TBW_CMD_TBL[mipmap as usize],
2945        ((tbp as u32 >> 8) as i32 & 0x0f0000) | tbw,
2946    );
2947    send_command_i(
2948        TSIZE_CMD_TBL[mipmap as usize],
2949        (((31 - ctlz(height & 0x3ff)) << 8) | (31 - ctlz(width & 0x3ff))) as i32,
2950    );
2951    sceGuTexFlush();
2952}
2953
2954#[allow(non_snake_case)]
2961#[no_mangle]
2962pub unsafe extern "C" fn sceGuTexLevelMode(mode: TextureLevelMode, bias: f32) {
2963    #[no_mangle]
2965    #[cfg(target_os = "psp")]
2966    #[allow(deprecated)]
2967    unsafe extern "C" fn truncf(mut x: f32) -> f32 {
2968        core::arch::asm!("cvt.w.s {0}, {0}", inout(freg) x);
2969        x
2970    }
2971
2972    let mut offset = core::intrinsics::truncf32(bias * 16.0) as i32;
2973
2974    if offset >= 128 {
2976        offset = 128
2977    } else if offset < -128 {
2978        offset = -128;
2979    }
2980
2981    send_command_i(GeCommand::TexLevel, ((offset as i32) << 16) | mode as i32);
2982}
2983
2984#[allow(non_snake_case)]
2992#[no_mangle]
2993pub unsafe extern "C" fn sceGuTexMapMode(mode: TextureMapMode, a1: u32, a2: u32) {
2994    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
2995    context.texture_map_mode = mode;
2996    send_command_i(
2997        GeCommand::TexMapMode,
2998        ((context.texture_proj_map_mode as i32) << 8) | mode as i32,
2999    );
3000    send_command_i(GeCommand::TexShadeLs, ((a2 << 8) | (a1 & 0x03)) as i32);
3001}
3002
3003#[allow(non_snake_case)]
3015#[no_mangle]
3016pub unsafe extern "C" fn sceGuTexMode(
3017    tpsm: TexturePixelFormat,
3018    maxmips: i32,
3019    a2: i32,
3020    swizzle: i32,
3021) {
3022    CONTEXTS[CURR_CONTEXT as usize].texture_mode = tpsm;
3023
3024    send_command_i(GeCommand::TexMode, (maxmips << 16) | (a2 << 8) | swizzle);
3025
3026    send_command_i(GeCommand::TexFormat, tpsm as i32);
3027    sceGuTexFlush();
3028}
3029
3030#[allow(non_snake_case)]
3042#[no_mangle]
3043pub unsafe extern "C" fn sceGuTexOffset(u: f32, v: f32) {
3044    send_command_f(GeCommand::TexOffsetU, u);
3045    send_command_f(GeCommand::TexOffsetV, v);
3046}
3047
3048#[allow(non_snake_case)]
3054#[no_mangle]
3055pub unsafe extern "C" fn sceGuTexProjMapMode(mode: TextureProjectionMapMode) {
3056    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
3057    context.texture_proj_map_mode = mode;
3058    send_command_i(
3059        GeCommand::TexMapMode,
3060        ((mode as i32) << 8) | context.texture_map_mode as i32,
3061    );
3062}
3063
3064#[allow(non_snake_case)]
3076#[no_mangle]
3077pub unsafe extern "C" fn sceGuTexScale(u: f32, v: f32) {
3078    send_command_f(GeCommand::TexScaleU, u);
3079    send_command_f(GeCommand::TexScaleV, v);
3080}
3081
3082#[allow(non_snake_case)]
3083#[no_mangle]
3084pub unsafe extern "C" fn sceGuTexSlope(slope: f32) {
3085    send_command_f(GeCommand::TexLodSlope, slope);
3086}
3087
3088#[allow(non_snake_case)]
3093#[no_mangle]
3094pub unsafe extern "C" fn sceGuTexSync() {
3095    send_command_i(GeCommand::TexSync, 0);
3096}
3097
3098#[allow(non_snake_case)]
3107#[no_mangle]
3108pub unsafe extern "C" fn sceGuTexWrap(u: GuTexWrapMode, v: GuTexWrapMode) {
3109    send_command_i(GeCommand::TexWrap, ((v as i32) << 8) | u as i32);
3110}
3111
3112#[allow(non_snake_case)]
3123#[no_mangle]
3124pub unsafe extern "C" fn sceGuClutLoad(num_blocks: i32, cbp: *const c_void) {
3125    send_command_i(GeCommand::ClutAddr, (cbp as i32) & 0xffffff);
3126    send_command_i(
3127        GeCommand::ClutAddrUpper,
3128        ((cbp as u32) >> 8) as i32 & 0xf0000,
3129    );
3130    send_command_i(GeCommand::LoadClut, num_blocks);
3131}
3132
3133#[repr(u32)]
3137pub enum ClutPixelFormat {
3138    Psm5650 = 0,
3140    Psm5551 = 1,
3142    Psm4444 = 2,
3144    Psm8888 = 3,
3146}
3147
3148#[allow(non_snake_case)]
3157#[no_mangle]
3158pub unsafe extern "C" fn sceGuClutMode(cpsm: ClutPixelFormat, shift: u32, mask: u32, a3: u32) {
3159    let arg = ((cpsm as u32) | (shift << 2) | (mask << 8) | (a3 << 16)) as i32;
3160    send_command_i(GeCommand::ClutFormat, arg);
3161}
3162
3163#[allow(non_snake_case)]
3182#[no_mangle]
3183pub unsafe extern "C" fn sceGuOffset(x: u32, y: u32) {
3184    send_command_i(GeCommand::OffsetX, (x << 4) as i32);
3185    send_command_i(GeCommand::OffsetY, (y << 4) as i32);
3186}
3187
3188#[allow(non_snake_case)]
3200#[no_mangle]
3201pub unsafe extern "C" fn sceGuScissor(x: i32, y: i32, w: i32, h: i32) {
3202    let context = &mut CONTEXTS[CURR_CONTEXT as usize];
3203
3204    context.scissor_start = [x, y];
3205    context.scissor_end = [w - 1, h - 1];
3206
3207    if context.scissor_enable != 0 {
3208        send_command_i(
3209            GeCommand::Scissor1,
3210            (context.scissor_start[1] << 10) | context.scissor_start[0],
3211        );
3212        send_command_i(
3213            GeCommand::Scissor2,
3214            (context.scissor_end[1] << 10) | context.scissor_end[0],
3215        );
3216    }
3217}
3218
3219#[allow(non_snake_case)]
3237#[no_mangle]
3238pub unsafe extern "C" fn sceGuViewport(cx: i32, cy: i32, width: i32, height: i32) {
3239    send_command_f(GeCommand::ViewportXScale, (width >> 1) as f32);
3240    send_command_f(GeCommand::ViewportYScale, ((-height) >> 1) as f32);
3241    send_command_f(GeCommand::ViewportXCenter, cx as f32);
3242    send_command_f(GeCommand::ViewportYCenter, cy as f32);
3243}
3244
3245#[allow(non_snake_case)]
3255#[no_mangle]
3256pub unsafe extern "C" fn sceGuDrawBezier(
3257    v_type: VertexType,
3258    u_count: i32,
3259    v_count: i32,
3260    indices: *const c_void,
3261    vertices: *const c_void,
3262) {
3263    if !v_type.is_empty() {
3264        send_command_i(GeCommand::VertexType, v_type.bits());
3265    }
3266
3267    if !indices.is_null() {
3268        send_command_i(GeCommand::Base, ((indices as u32) >> 8) as i32 & 0xf0000);
3269        send_command_i(GeCommand::Iaddr, (indices as i32) & 0xffffff);
3270    }
3271
3272    if !vertices.is_null() {
3273        send_command_i(GeCommand::Base, ((vertices as u32) >> 8) as i32 & 0xf0000);
3274        send_command_i(GeCommand::Vaddr, (vertices as i32) & 0xffffff);
3275    }
3276
3277    send_command_i(GeCommand::Bezier, (v_count << 8) | u_count);
3278}
3279
3280#[allow(non_snake_case)]
3287#[no_mangle]
3288pub unsafe extern "C" fn sceGuPatchDivide(ulevel: u32, vlevel: u32) {
3289    send_command_i(GeCommand::PatchDivision, ((vlevel << 8) | ulevel) as i32);
3290}
3291
3292#[allow(non_snake_case)]
3293#[no_mangle]
3294pub unsafe extern "C" fn sceGuPatchFrontFace(a0: u32) {
3295    send_command_i(GeCommand::PatchFacing, a0 as i32);
3296}
3297
3298#[allow(non_snake_case)]
3304#[no_mangle]
3305pub unsafe extern "C" fn sceGuPatchPrim(prim: PatchPrimitive) {
3306    match prim {
3307        PatchPrimitive::Points => send_command_i(GeCommand::PatchPrimitive, 2),
3308        PatchPrimitive::LineStrip => send_command_i(GeCommand::PatchPrimitive, 1),
3309        PatchPrimitive::TriangleStrip => send_command_i(GeCommand::PatchPrimitive, 0),
3310    }
3311}
3312
3313#[allow(non_snake_case)]
3314#[no_mangle]
3315pub unsafe extern "C" fn sceGuDrawSpline(
3316    v_type: VertexType,
3317    u_count: i32,
3318    v_count: i32,
3319    u_edge: i32,
3320    v_edge: i32,
3321    indices: *const c_void,
3322    vertices: *const c_void,
3323) {
3324    if !v_type.is_empty() {
3325        send_command_i(GeCommand::VertexType, v_type.bits());
3326    }
3327
3328    if !indices.is_null() {
3329        send_command_i(GeCommand::Base, ((indices as u32) >> 8) as i32 & 0xf0000);
3330        send_command_i(GeCommand::Iaddr, (indices as i32) & 0xffffff);
3331    }
3332
3333    if !vertices.is_null() {
3334        send_command_i(GeCommand::Base, ((vertices as u32) >> 8) as i32 & 0xf0000);
3335        send_command_i(GeCommand::Vaddr, (vertices as i32) & 0xffffff);
3336    }
3337
3338    send_command_i(
3339        GeCommand::Spline,
3340        (v_edge << 18) | (u_edge << 16) | (v_count << 8) | u_count,
3341    );
3342}
3343
3344#[allow(non_snake_case)]
3351#[no_mangle]
3352pub unsafe extern "C" fn sceGuSetMatrix(type_: MatrixMode, matrix: &ScePspFMatrix4) {
3353    let fmatrix = matrix as *const _ as *const f32;
3354
3355    match type_ {
3356        MatrixMode::Projection => {
3357            send_command_f(GeCommand::ProjMatrixNumber, 0.0);
3358            for i in 0..16 {
3359                send_command_f(GeCommand::ProjMatrixData, *fmatrix.offset(i));
3360            }
3361        }
3362
3363        MatrixMode::View => {
3364            send_command_f(GeCommand::ViewMatrixNumber, 0.0);
3365            for i in 0..4 {
3366                for j in 0..3 {
3367                    send_command_f(GeCommand::ViewMatrixData, *fmatrix.offset(j + i * 4));
3368                }
3369            }
3370        }
3371
3372        MatrixMode::Model => {
3373            send_command_f(GeCommand::WorldMatrixNumber, 0.0);
3374            for i in 0..4 {
3375                for j in 0..3 {
3376                    send_command_f(GeCommand::WorldMatrixData, *fmatrix.offset(j + i * 4));
3377                }
3378            }
3379        }
3380
3381        MatrixMode::Texture => {
3382            send_command_f(GeCommand::TGenMatrixNumber, 0.0);
3383            for i in 0..4 {
3384                for j in 0..3 {
3385                    send_command_f(GeCommand::TGenMatrixData, *fmatrix.offset(j + i * 4));
3386                }
3387            }
3388        }
3389    }
3390}
3391
3392#[allow(non_snake_case)]
3407#[no_mangle]
3408pub unsafe extern "C" fn sceGuBoneMatrix(index: u32, matrix: &ScePspFMatrix4) {
3409    send_command_i(GeCommand::BoneMatrixNumber, index as i32 * 12); send_command_f(GeCommand::BoneMatrixData, matrix.x.x);
3412    send_command_f(GeCommand::BoneMatrixData, matrix.x.y);
3413    send_command_f(GeCommand::BoneMatrixData, matrix.x.z);
3414
3415    send_command_f(GeCommand::BoneMatrixData, matrix.y.x);
3416    send_command_f(GeCommand::BoneMatrixData, matrix.y.y);
3417    send_command_f(GeCommand::BoneMatrixData, matrix.y.z);
3418
3419    send_command_f(GeCommand::BoneMatrixData, matrix.z.x);
3420    send_command_f(GeCommand::BoneMatrixData, matrix.z.y);
3421    send_command_f(GeCommand::BoneMatrixData, matrix.z.z);
3422
3423    send_command_f(GeCommand::BoneMatrixData, matrix.w.x);
3424    send_command_f(GeCommand::BoneMatrixData, matrix.w.y);
3425    send_command_f(GeCommand::BoneMatrixData, matrix.w.z);
3426}
3427
3428#[allow(non_snake_case)]
3442#[no_mangle]
3443pub unsafe extern "C" fn sceGuMorphWeight(index: i32, weight: f32) {
3444    let cmd = match index {
3445        0 => GeCommand::MorphWeight0,
3446        1 => GeCommand::MorphWeight1,
3447        2 => GeCommand::MorphWeight2,
3448        3 => GeCommand::MorphWeight3,
3449        4 => GeCommand::MorphWeight4,
3450        5 => GeCommand::MorphWeight5,
3451        6 => GeCommand::MorphWeight6,
3452        7 => GeCommand::MorphWeight7,
3453        _ => core::intrinsics::unreachable(),
3454    };
3455
3456    send_command_f(cmd, weight);
3457}
3458
3459#[allow(non_snake_case)]
3460#[no_mangle]
3461pub unsafe extern "C" fn sceGuDrawArrayN(
3462    primitive_type: GuPrimitive,
3463    v_type: VertexType,
3464    count: i32,
3465    a3: i32,
3466    indices: *const c_void,
3467    vertices: *const c_void,
3468) {
3469    if !v_type.is_empty() {
3470        send_command_i(GeCommand::VertexType, v_type.bits());
3471    }
3472
3473    if !indices.is_null() {
3474        send_command_i(GeCommand::Base, ((indices as u32) >> 8) as i32 & 0xf0000);
3475        send_command_i(GeCommand::Iaddr, indices as i32 & 0xffffff);
3476    }
3477
3478    if !vertices.is_null() {
3479        send_command_i(GeCommand::Base, ((vertices as u32) >> 8) as i32 & 0xf0000);
3480        send_command_i(GeCommand::Vaddr, vertices as i32 & 0xffffff);
3481    }
3482
3483    if a3 > 0 {
3484        for _ in 1..a3 {
3486            send_command_i(GeCommand::Prim, ((primitive_type as i32) << 16) | count);
3487        }
3488
3489        send_command_i_stall(GeCommand::Prim, ((primitive_type as i32) << 16) | count);
3490    }
3491}
3492
3493static mut CHAR_BUFFER_USED: u32 = 0;
3494static mut CHAR_BUFFER: [DebugCharStruct; 2048] = [DebugCharStruct {
3495    x: 0,
3496    y: 0,
3497    color: 0,
3498    character: b'\0',
3499    unused: [0, 0, 0],
3500}; 2048];
3501static FONT: [u8; 768] = *include_bytes!("./debugfont.bin");
3502
3503#[repr(C, packed)]
3504#[derive(Copy, Clone)]
3505struct DebugCharStruct {
3506    x: i32,
3507    y: i32,
3508    color: u32,
3509    character: u8,
3510    unused: [u8; 3],
3511}
3512
3513#[allow(non_snake_case)]
3522#[no_mangle]
3523pub unsafe extern "C" fn sceGuDebugPrint(x: i32, mut y: i32, mut color: u32, mut msg: *const u8) {
3524    let mut cur_char: u8;
3525    let mut uVar1: u32;
3526    let iVar2: i32;
3527    let mut cur_x: i32;
3528    let mut char_struct_ptr: *mut DebugCharStruct =
3529        addr_of_mut!(CHAR_BUFFER).cast::<DebugCharStruct>();
3530
3531    let mut i = CHAR_BUFFER_USED;
3532    if i >= 0x3ff {
3533        return;
3534    }
3535    uVar1 = color >> 8 & 0xff;
3536    let uVar3 = color >> 16 & 0xff;
3537    let iVar4 = (uVar3 >> 3) as i32;
3538    cur_x = x;
3539    match DRAW_BUFFER.pixel_size {
3540        DisplayPixelFormat::Psm5650 => {
3541            iVar2 = (uVar1 as i32) >> 2;
3542            uVar1 = (iVar4 as u32) << 0xb;
3543            uVar1 = (uVar1 | iVar2 as u32) << 5;
3544            color = (color & 0xff) >> 3;
3545            color |= uVar1;
3546        }
3547        DisplayPixelFormat::Psm5551 => {
3548            iVar2 = (uVar1 >> 3) as i32;
3549            uVar1 = ((color >> 24) >> 7) << 0xf | (iVar4 as u32) << 10;
3550            uVar1 = (uVar1 | iVar2 as u32) << 5;
3551            color = (color & 0xff) >> 3;
3552            color |= uVar1;
3553        }
3554        DisplayPixelFormat::Psm8888 => {}
3555        DisplayPixelFormat::Psm4444 => {
3556            uVar1 = ((color >> 0x18) >> 4) << 0xc | (uVar3 >> 4) << 8 | (uVar1 >> 4) << 4;
3557            color &= 0xff >> 4;
3558            color |= uVar1;
3559        }
3560    }
3561    cur_char = *msg;
3562    while cur_char != b'\0' {
3563        if cur_char == b'\n' {
3564            y += 8;
3565            cur_x = x;
3566        } else {
3567            (*char_struct_ptr).x = cur_x;
3568            i += 1;
3569            (*char_struct_ptr).character = cur_char - 0x20;
3570            (*char_struct_ptr).y = y;
3571            (*char_struct_ptr).color = color;
3572            char_struct_ptr = (char_struct_ptr as u32 + 16) as *mut DebugCharStruct;
3573            cur_x += 8;
3574        }
3575        msg = msg.add(1);
3576        cur_char = *msg;
3577    }
3578    CHAR_BUFFER_USED = i;
3579}
3580
3581#[allow(non_snake_case)]
3583#[no_mangle]
3584pub unsafe extern "C" fn sceGuDebugFlush() {
3585    let edram_address = GE_EDRAM_ADDRESS;
3586    let mut pixel_size: DisplayPixelFormat;
3587    let mut frame_width: i32;
3588    let mut frame_buffer: *mut c_void;
3589    let draw_buffer_height = DRAW_BUFFER.height;
3590    let mut char_index: i32;
3591    let mut pos: i32;
3592    let mut x_pixel_counter: i32;
3593    let mut glyph_pos: u32 = 0;
3594    let mut color: u32;
3595    let mut font_glyph: u32 = 0;
3596    let mut y_pixel_counter: i32;
3597    let mut x: i32;
3598    let mut char_buffer_used = CHAR_BUFFER_USED;
3599    let mut y: i32;
3600    let mut char_struct_ptr: *mut DebugCharStruct =
3601        addr_of_mut!(CHAR_BUFFER).cast::<DebugCharStruct>();
3602
3603    if char_buffer_used != 0 {
3604        loop {
3605            frame_buffer = DRAW_BUFFER.frame_buffer;
3606            frame_width = DRAW_BUFFER.frame_width;
3607            pixel_size = DRAW_BUFFER.pixel_size;
3608            y = (*char_struct_ptr).y;
3609            x = (*char_struct_ptr).x;
3610            if (y + 7 < draw_buffer_height)
3611                && (((x + 7 < DRAW_BUFFER.width) as i32 & !y >> 0x1f) != 0)
3612                && -1 < x
3613            {
3614                color = (*char_struct_ptr).color;
3615                char_index = ((*char_struct_ptr).character) as i32 * 8;
3616                y_pixel_counter = 0;
3617                loop {
3618                    if y_pixel_counter == 0 {
3619                        font_glyph =
3620                            *(((&FONT as *const _ as u32) + char_index as u32) as *const u32);
3621                        glyph_pos = 1;
3622                    } else if y_pixel_counter == 4 {
3623                        font_glyph =
3624                            *(((&FONT as *const _ as u32) + 4 + char_index as u32) as *const u32);
3625                        glyph_pos = 1
3626                    }
3627                    x_pixel_counter = 7;
3628                    pos = x + (y + y_pixel_counter) * frame_width;
3629                    pos = pos * 4 + edram_address as i32 + frame_buffer as i32;
3630                    loop {
3631                        match pixel_size {
3632                            DisplayPixelFormat::Psm8888 => {
3633                                if font_glyph & glyph_pos != 0 {
3634                                    *((pos as u32 + 0x4000_0000) as *mut u32) = color;
3635                                }
3636                            }
3637                            _ => {
3638                                *((pos as u32 + 0x4000_0002) as *mut u16) = color as u16;
3639                            }
3640                        }
3641                        x_pixel_counter -= 1;
3642                        glyph_pos <<= 1;
3643                        pos += 4;
3644                        if x_pixel_counter <= -1 {
3645                            break;
3646                        }
3647                    }
3648                    y_pixel_counter += 1;
3649                    if 8 <= y_pixel_counter {
3650                        break;
3651                    }
3652                }
3653            }
3654            char_buffer_used -= 1;
3655            char_struct_ptr = ((char_struct_ptr as u32) + 16) as *mut DebugCharStruct;
3656            if char_buffer_used == 0 {
3657                break;
3658            }
3659        }
3660        CHAR_BUFFER_USED = 0;
3661    }
3662}