use crate::sys::{
self,
display::DisplayPixelFormat,
ge::{GeBreakParam, GeCommand, GeContext, GeListArgs, GeListState},
kernel::SceUid,
types::{ScePspFMatrix4, ScePspFVector3, ScePspIMatrix4, ScePspIVector4},
};
use core::{ffi::c_void, mem, ptr::addr_of_mut, ptr::null_mut};
use num_enum::TryFromPrimitive;
#[allow(clippy::approx_constant)]
pub const GU_PI: f32 = 3.141593;
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum GuPrimitive {
Points = 0,
Lines = 1,
LineStrip = 2,
Triangles = 3,
TriangleStrip = 4,
TriangleFan = 5,
Sprites = 6,
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum PatchPrimitive {
Points = 0,
LineStrip = 2,
TriangleStrip = 4,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum GuState {
AlphaTest = 0,
DepthTest = 1,
ScissorTest = 2,
StencilTest = 3,
Blend = 4,
CullFace = 5,
Dither = 6,
Fog = 7,
ClipPlanes = 8,
Texture2D = 9,
Lighting = 10,
Light0 = 11,
Light1 = 12,
Light2 = 13,
Light3 = 14,
LineSmooth = 15,
PatchCullFace = 16,
ColorTest = 17,
ColorLogicOp = 18,
FaceNormalReverse = 19,
PatchFace = 20,
Fragment2X = 21,
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum MatrixMode {
Projection = 0,
View = 1,
Model = 2,
Texture = 3,
}
bitflags::bitflags! {
#[repr(transparent)]
pub struct VertexType: i32 {
const TEXTURE_8BIT = 1;
const TEXTURE_16BIT = 2;
const TEXTURE_32BITF = 3;
const COLOR_5650 = 4 << 2;
const COLOR_5551 = 5 << 2;
const COLOR_4444 = 6 << 2;
const COLOR_8888 = 7 << 2;
const NORMAL_8BIT = 1 << 5;
const NORMAL_16BIT = 2 << 5;
const NORMAL_32BITF = 3 << 5;
const VERTEX_8BIT = 1 << 7;
const VERTEX_16BIT = 2 << 7;
const VERTEX_32BITF = 3 << 7;
const WEIGHT_8BIT = 1 << 9;
const WEIGHT_16BIT = 2 << 9;
const WEIGHT_32BITF = 3 << 9;
const INDEX_8BIT = 1 << 11;
const INDEX_16BIT = 2 << 11;
const WEIGHTS1 = Self::num_weights(1);
const WEIGHTS2 = Self::num_weights(2);
const WEIGHTS3 = Self::num_weights(3);
const WEIGHTS4 = Self::num_weights(4);
const WEIGHTS5 = Self::num_weights(5);
const WEIGHTS6 = Self::num_weights(6);
const WEIGHTS7 = Self::num_weights(7);
const WEIGHTS8 = Self::num_weights(8);
const VERTICES1 = Self::num_vertices(1);
const VERTICES2 = Self::num_vertices(2);
const VERTICES3 = Self::num_vertices(3);
const VERTICES4 = Self::num_vertices(4);
const VERTICES5 = Self::num_vertices(5);
const VERTICES6 = Self::num_vertices(6);
const VERTICES7 = Self::num_vertices(7);
const VERTICES8 = Self::num_vertices(8);
const TRANSFORM_2D = 1 << 23;
const TRANSFORM_3D = 0;
}
}
impl VertexType {
const fn num_weights(n: u32) -> i32 {
(((n - 1) & 7) << 14) as i32
}
const fn num_vertices(n: u32) -> i32 {
(((n - 1) & 7) << 18) as i32
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum TexturePixelFormat {
Psm5650 = 0,
Psm5551 = 1,
Psm4444 = 2,
Psm8888 = 3,
PsmT4 = 4,
PsmT8 = 5,
PsmT16 = 6,
PsmT32 = 7,
PsmDxt1 = 8,
PsmDxt3 = 9,
PsmDxt5 = 10,
}
#[repr(u32)]
pub enum SplineMode {
FillFill = 0,
OpenFill = 1,
FillOpen = 2,
OpenOpen = 3,
}
#[repr(u32)]
pub enum ShadingModel {
Flat = 0,
Smooth = 1,
}
#[repr(u32)]
pub enum LogicalOperation {
Clear = 0,
And = 1,
AndReverse = 2,
Copy = 3,
AndInverted = 4,
Noop = 5,
Xor = 6,
Or = 7,
Nor = 8,
Equiv = 9,
Inverted = 10,
OrReverse = 11,
CopyInverted = 12,
OrInverted = 13,
Nand = 14,
Set = 15,
}
#[repr(u32)]
pub enum TextureFilter {
Nearest = 0,
Linear = 1,
NearestMipmapNearest = 4,
LinearMipmapNearest = 5,
NearestMipmapLinear = 6,
LinearMipmapLinear = 7,
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum TextureMapMode {
TextureCoords = 0,
TextureMatrix = 1,
EnvironmentMap = 2,
}
#[repr(u32)]
pub enum TextureLevelMode {
Auto = 0,
Const = 1,
Slope = 2,
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum TextureProjectionMapMode {
Position = 0,
Uv = 1,
NormalizedNormal = 2,
Normal = 3,
}
#[repr(u32)]
pub enum GuTexWrapMode {
Repeat = 0,
Clamp = 1,
}
#[repr(u32)]
pub enum FrontFaceDirection {
Clockwise = 0,
CounterClockwise = 1,
}
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum AlphaFunc {
Never = 0,
Always,
Equal,
NotEqual,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
}
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum StencilFunc {
Never = 0,
Always,
Equal,
NotEqual,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
}
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum ColorFunc {
Never = 0,
Always,
Equal,
NotEqual,
}
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum DepthFunc {
Never = 0,
Always,
Equal,
NotEqual,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
}
bitflags::bitflags! {
#[repr(transparent)]
pub struct ClearBuffer: u32 {
const COLOR_BUFFER_BIT = 1;
const STENCIL_BUFFER_BIT = 2;
const DEPTH_BUFFER_BIT = 4;
const FAST_CLEAR_BIT = 16;
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum TextureEffect {
Modulate = 0,
Decal = 1,
Blend = 2,
Replace = 3,
Add = 4,
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum TextureColorComponent {
Rgb = 0,
Rgba = 1,
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum MipmapLevel {
None = 0,
Level1,
Level2,
Level3,
Level4,
Level5,
Level6,
Level7,
}
#[repr(u32)]
pub enum BlendOp {
Add = 0,
Subtract = 1,
ReverseSubtract = 2,
Min = 3,
Max = 4,
Abs = 5,
}
#[repr(u32)]
pub enum BlendFactor {
Color = 0,
OneMinusColor = 1,
SrcAlpha = 2,
OneMinusSrcAlpha = 3,
DstAlpha = 4,
OneMinusDstAlpha = 5,
Fix = 10,
}
#[repr(u32)]
pub enum StencilOperation {
Keep = 0,
Zero = 1,
Replace = 2,
Invert = 3,
Incr = 4,
Decr = 5,
}
bitflags::bitflags!(
#[repr(transparent)]
pub struct LightComponent: i32 {
const AMBIENT = 1;
const DIFFUSE = 2;
const SPECULAR = 4;
const UNKNOWN_LIGHT_COMPONENT = 8;
}
);
#[repr(u32)]
pub enum LightMode {
SingleColor = 0,
SeparateSpecularColor = 1,
}
#[repr(u32)]
pub enum LightType {
Directional = 0,
Pointlight = 1,
Spotlight = 2,
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum GuContextType {
Direct = 0,
Call = 1,
Send = 2,
}
#[repr(u32)]
pub enum GuQueueMode {
Tail = 0,
Head = 1,
}
#[repr(u32)]
pub enum GuSyncMode {
Finish = 0,
Signal = 1,
Done = 2,
List = 3,
Send = 4,
}
#[repr(u32)]
pub enum GuSyncBehavior {
Wait = 0,
NoWait = 1,
}
#[repr(u32)]
pub enum GuCallbackId {
Signal = 1,
Finish = 4,
}
#[repr(u32)]
pub enum SignalBehavior {
Suspend = 1,
Continue = 2,
}
#[inline]
pub const fn abgr(a: u8, b: u8, g: u8, r: u8) -> u32 {
(r as u32) | ((g as u32) << 8) | ((b as u32) << 16) | ((a as u32) << 24)
}
#[inline]
pub const fn argb(a: u8, r: u8, g: u8, b: u8) -> u32 {
abgr(a, b, g, r)
}
#[inline]
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> u32 {
argb(a, r, g, b)
}
#[inline]
pub fn color(r: f32, g: f32, b: f32, a: f32) -> u32 {
rgba(
(r * 255.0) as u8,
(g * 255.0) as u8,
(b * 255.0) as u8,
(a * 255.0) as u8,
)
}
pub type GuCallback = Option<extern "C" fn(id: i32, arg: *mut c_void)>;
pub type GuSwapBuffersCallback =
Option<extern "C" fn(display: *mut *mut c_void, render: *mut *mut c_void)>;
struct Settings {
sig: GuCallback,
fin: GuCallback,
signal_history: [i16; 16],
signal_offset: u32,
kernel_event_flag: SceUid,
ge_callback_id: i32,
swap_buffers_callback: GuSwapBuffersCallback,
swap_buffers_behaviour: crate::sys::DisplaySetBufSync,
}
struct GuDisplayList {
start: *mut u32,
current: *mut u32,
parent_context: GuContextType,
}
struct GuContext {
list: GuDisplayList,
scissor_enable: i32,
scissor_start: [i32; 2],
scissor_end: [i32; 2],
near_plane: i32,
far_plane: i32,
depth_offset: i32,
fragment_2x: i32,
texture_function: i32,
texture_proj_map_mode: TextureProjectionMapMode,
texture_map_mode: TextureMapMode,
sprite_mode: [i32; 4],
clear_color: u32,
clear_stencil: u32,
clear_depth: u32,
texture_mode: TexturePixelFormat,
}
struct GuDrawBuffer {
pixel_size: DisplayPixelFormat,
frame_width: i32,
frame_buffer: *mut c_void,
disp_buffer: *mut c_void,
depth_buffer: *mut c_void,
depth_width: i32,
width: i32,
height: i32,
}
struct GuLightSettings {
type_: GeCommand,
xpos: GeCommand,
ypos: GeCommand,
zpos: GeCommand,
xdir: GeCommand,
ydir: GeCommand,
zdir: GeCommand,
ambient: GeCommand,
diffuse: GeCommand,
specular: GeCommand,
constant: GeCommand,
linear: GeCommand,
quadratic: GeCommand,
exponent: GeCommand,
cutoff: GeCommand,
}
static mut CURRENT_FRAME: u32 = 0;
static mut CONTEXTS: [GuContext; 3] = [
GuContext {
list: GuDisplayList {
start: null_mut(),
current: null_mut(),
parent_context: GuContextType::Direct,
},
scissor_enable: 0,
scissor_start: [0, 0],
scissor_end: [0, 0],
near_plane: 0,
far_plane: 0,
depth_offset: 0,
fragment_2x: 0,
texture_function: 0,
texture_proj_map_mode: TextureProjectionMapMode::Position,
texture_map_mode: TextureMapMode::TextureCoords,
sprite_mode: [0, 0, 0, 0],
clear_color: 0,
clear_stencil: 0,
clear_depth: 0,
texture_mode: TexturePixelFormat::Psm5650,
},
GuContext {
list: GuDisplayList {
start: null_mut(),
current: null_mut(),
parent_context: GuContextType::Direct,
},
scissor_enable: 0,
scissor_start: [0, 0],
scissor_end: [0, 0],
near_plane: 0,
far_plane: 0,
depth_offset: 0,
fragment_2x: 0,
texture_function: 0,
texture_proj_map_mode: TextureProjectionMapMode::Position,
texture_map_mode: TextureMapMode::TextureCoords,
sprite_mode: [0, 0, 0, 0],
clear_color: 0,
clear_stencil: 0,
clear_depth: 0,
texture_mode: TexturePixelFormat::Psm5650,
},
GuContext {
list: GuDisplayList {
start: null_mut(),
current: null_mut(),
parent_context: GuContextType::Direct,
},
scissor_enable: 0,
scissor_start: [0, 0],
scissor_end: [0, 0],
near_plane: 0,
far_plane: 0,
depth_offset: 0,
fragment_2x: 0,
texture_function: 0,
texture_proj_map_mode: TextureProjectionMapMode::Position,
texture_map_mode: TextureMapMode::TextureCoords,
sprite_mode: [0, 0, 0, 0],
clear_color: 0,
clear_stencil: 0,
clear_depth: 0,
texture_mode: TexturePixelFormat::Psm5650,
},
];
static mut GE_LIST_EXECUTED: [i32; 2] = [0, 0];
static mut GE_EDRAM_ADDRESS: *mut c_void = null_mut();
static mut SETTINGS: Settings = Settings {
sig: None,
fin: None,
signal_history: [0; 16],
signal_offset: 0,
kernel_event_flag: SceUid(-1),
ge_callback_id: 0,
swap_buffers_behaviour: crate::sys::DisplaySetBufSync::Immediate,
swap_buffers_callback: None,
};
static mut LIST: *mut GuDisplayList = null_mut();
static mut CURR_CONTEXT: GuContextType = GuContextType::Direct;
static mut INIT: i32 = 0;
static mut DISPLAY_ON: bool = false;
static mut CALL_MODE: i32 = 0;
static mut STATES: u32 = 0;
static mut DRAW_BUFFER: GuDrawBuffer = GuDrawBuffer {
depth_buffer: null_mut(),
frame_buffer: null_mut(),
disp_buffer: null_mut(),
width: 0,
height: 0,
depth_width: 0,
frame_width: 0,
pixel_size: DisplayPixelFormat::Psm5650,
};
static mut OBJECT_STACK: *mut *mut u32 = null_mut();
static mut OBJECT_STACK_DEPTH: i32 = 0;
const LIGHT_COMMANDS: [GuLightSettings; 4] = [
GuLightSettings {
type_: GeCommand::LightType0,
xpos: GeCommand::Light0X,
ypos: GeCommand::Light0Y,
zpos: GeCommand::Light0Z,
xdir: GeCommand::Light0DirectionX,
ydir: GeCommand::Light0DirectionY,
zdir: GeCommand::Light0DirectionZ,
ambient: GeCommand::Light0Ambient,
diffuse: GeCommand::Light0Diffuse,
specular: GeCommand::Light0Specular,
constant: GeCommand::Light0ConstantAtten,
linear: GeCommand::Light0LinearAtten,
quadratic: GeCommand::Light0QuadtraticAtten,
exponent: GeCommand::Light0ExponentAtten,
cutoff: GeCommand::Light0CutoffAtten,
},
GuLightSettings {
type_: GeCommand::LightType1,
xpos: GeCommand::Light1X,
ypos: GeCommand::Light1Y,
zpos: GeCommand::Light1Z,
xdir: GeCommand::Light1DirectionX,
ydir: GeCommand::Light1DirectionY,
zdir: GeCommand::Light1DirectionZ,
ambient: GeCommand::Light1Ambient,
diffuse: GeCommand::Light1Diffuse,
specular: GeCommand::Light1Specular,
constant: GeCommand::Light1ConstantAtten,
linear: GeCommand::Light1LinearAtten,
quadratic: GeCommand::Light1QuadtraticAtten,
exponent: GeCommand::Light1ExponentAtten,
cutoff: GeCommand::Light1CutoffAtten,
},
GuLightSettings {
type_: GeCommand::LightType2,
xpos: GeCommand::Light2X,
ypos: GeCommand::Light2Y,
zpos: GeCommand::Light2Z,
xdir: GeCommand::Light2DirectionX,
ydir: GeCommand::Light2DirectionY,
zdir: GeCommand::Light2DirectionZ,
ambient: GeCommand::Light2Ambient,
diffuse: GeCommand::Light2Diffuse,
specular: GeCommand::Light2Specular,
constant: GeCommand::Light2ConstantAtten,
linear: GeCommand::Light2LinearAtten,
quadratic: GeCommand::Light2QuadtraticAtten,
exponent: GeCommand::Light2ExponentAtten,
cutoff: GeCommand::Light2CutoffAtten,
},
GuLightSettings {
type_: GeCommand::LightType3,
xpos: GeCommand::Light3X,
ypos: GeCommand::Light3Y,
zpos: GeCommand::Light3Z,
xdir: GeCommand::Light3DirectionX,
ydir: GeCommand::Light3DirectionY,
zdir: GeCommand::Light3DirectionZ,
ambient: GeCommand::Light3Ambient,
diffuse: GeCommand::Light3Diffuse,
specular: GeCommand::Light3Specular,
constant: GeCommand::Light3ConstantAtten,
linear: GeCommand::Light3LinearAtten,
quadratic: GeCommand::Light3QuadtraticAtten,
exponent: GeCommand::Light3ExponentAtten,
cutoff: GeCommand::Light3CutoffAtten,
},
];
#[inline]
unsafe fn send_command_i(cmd: GeCommand, argument: i32) {
(*(*LIST).current) = ((cmd as u32) << 24) | (argument as u32 & 0xffffff);
(*LIST).current = (*LIST).current.add(1);
}
#[inline]
unsafe fn send_command_f(cmd: GeCommand, argument: f32) {
send_command_i(cmd, (argument.to_bits() >> 8) as i32);
}
#[inline]
unsafe fn send_command_i_stall(cmd: GeCommand, argument: i32) {
send_command_i(cmd, argument);
if let (GuContextType::Direct, 0) = (CURR_CONTEXT, OBJECT_STACK_DEPTH) {
crate::sys::sceGeListUpdateStallAddr(GE_LIST_EXECUTED[0], (*LIST).current as *mut c_void);
}
}
unsafe fn draw_region(x: i32, y: i32, width: i32, height: i32) {
send_command_i(GeCommand::Region1, (y << 10) | x);
send_command_i(
GeCommand::Region2,
(((y + height) - 1) << 10) | ((x + width) - 1),
);
}
unsafe fn reset_values() {
INIT = 0;
STATES = 0;
CURRENT_FRAME = 0;
OBJECT_STACK_DEPTH = 0;
DISPLAY_ON = false;
CALL_MODE = 0;
DRAW_BUFFER.pixel_size = DisplayPixelFormat::Psm5551;
DRAW_BUFFER.frame_width = 0;
DRAW_BUFFER.frame_buffer = null_mut();
DRAW_BUFFER.disp_buffer = null_mut();
DRAW_BUFFER.depth_buffer = null_mut();
DRAW_BUFFER.depth_width = 0;
DRAW_BUFFER.width = 480;
DRAW_BUFFER.height = 272;
for i in 0..CONTEXTS.len() {
let context = addr_of_mut!(CONTEXTS[i]);
(*context).scissor_enable = 0;
(*context).scissor_start = [0, 0];
(*context).scissor_end = [0, 0];
(*context).near_plane = 0;
(*context).far_plane = 1;
(*context).depth_offset = 0;
(*context).fragment_2x = 0;
(*context).texture_function = 0;
(*context).texture_proj_map_mode = TextureProjectionMapMode::Position;
(*context).texture_map_mode = TextureMapMode::TextureCoords;
(*context).sprite_mode[0] = 0;
(*context).sprite_mode[1] = 0;
(*context).sprite_mode[2] = 0;
(*context).sprite_mode[3] = 0;
(*context).clear_color = 0;
(*context).clear_stencil = 0;
(*context).clear_depth = 0xffff;
(*context).texture_mode = TexturePixelFormat::Psm5650;
}
SETTINGS.sig = None;
SETTINGS.fin = None;
}
extern "C" fn callback_sig(id: i32, arg: *mut c_void) {
let settings = arg as *mut Settings;
unsafe {
let idx = ((*settings).signal_offset & 15) as usize;
(*settings).signal_history[idx] = (id & 0xffff) as i16;
(*settings).signal_offset += 1;
if (*settings).sig.is_some() {
let f = mem::transmute::<_, extern "C" fn(i32)>((*settings).sig);
f(id & 0xffff);
}
crate::sys::sceKernelSetEventFlag((*settings).kernel_event_flag, 1);
}
}
extern "C" fn callback_fin(id: i32, arg: *mut c_void) {
unsafe {
let settings = arg as *mut Settings;
if let Some(fin) = (*settings).fin {
let f = core::mem::transmute::<_, extern "C" fn(i32)>(fin);
f(id & 0xffff)
}
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDepthBuffer(zbp: *mut c_void, zbw: i32) {
DRAW_BUFFER.depth_buffer = zbp;
if DRAW_BUFFER.depth_width == 0 || DRAW_BUFFER.depth_width != zbw {
DRAW_BUFFER.depth_width = zbw;
}
send_command_i(GeCommand::ZBufPtr, zbp as i32 & 0xffffff);
send_command_i(
GeCommand::ZBufWidth,
(((zbp as u32 & 0xff000000) >> 8) | zbw as u32) as i32,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDispBuffer(
width: i32,
height: i32,
dispbp: *mut c_void,
dispbw: i32,
) {
use crate::sys::DisplaySetBufSync;
DRAW_BUFFER.width = width;
DRAW_BUFFER.height = height;
DRAW_BUFFER.disp_buffer = dispbp;
if DRAW_BUFFER.frame_width == 0 || DRAW_BUFFER.frame_width != dispbw {
DRAW_BUFFER.frame_width = dispbw;
}
draw_region(0, 0, DRAW_BUFFER.width, DRAW_BUFFER.height);
crate::sys::sceDisplaySetMode(
crate::sys::DisplayMode::Lcd,
DRAW_BUFFER.width as usize,
DRAW_BUFFER.height as usize,
);
if DISPLAY_ON {
crate::sys::sceDisplaySetFrameBuf(
(GE_EDRAM_ADDRESS as *mut u8).add(DRAW_BUFFER.disp_buffer as usize),
dispbw as usize,
DRAW_BUFFER.pixel_size,
DisplaySetBufSync::NextFrame,
);
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDrawBuffer(psm: DisplayPixelFormat, fbp: *mut c_void, fbw: i32) {
DRAW_BUFFER.pixel_size = psm;
DRAW_BUFFER.frame_width = fbw;
DRAW_BUFFER.frame_buffer = fbp;
if DRAW_BUFFER.depth_buffer.is_null() && DRAW_BUFFER.height != 0 {
DRAW_BUFFER.depth_buffer =
(fbp as u32 + (((DRAW_BUFFER.height * fbw) as u32) << 2u32)) as *mut c_void;
}
if DRAW_BUFFER.depth_width == 0 {
DRAW_BUFFER.depth_width = fbw;
}
send_command_i(GeCommand::FramebufPixFormat, psm as i32);
send_command_i(
GeCommand::FrameBufPtr,
DRAW_BUFFER.frame_buffer as i32 & 0xffffff,
);
send_command_i(
GeCommand::FrameBufWidth,
((DRAW_BUFFER.frame_buffer as u32 & 0xff000000) >> 8) as i32 | DRAW_BUFFER.frame_width,
);
send_command_i(
GeCommand::ZBufPtr,
DRAW_BUFFER.depth_buffer as i32 & 0xffffff,
);
send_command_i(
GeCommand::ZBufWidth,
((DRAW_BUFFER.depth_buffer as u32 & 0xff000000) >> 8) as i32 | DRAW_BUFFER.depth_width,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDrawBufferList(psm: DisplayPixelFormat, fbp: *mut c_void, fbw: i32) {
send_command_i(GeCommand::FramebufPixFormat, psm as i32);
send_command_i(GeCommand::FrameBufPtr, fbp as i32 & 0xffffff);
send_command_i(
GeCommand::FrameBufWidth,
((fbp as u32 & 0xff000000) >> 8) as i32 | fbw,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDisplay(state: bool) -> bool {
use crate::sys::DisplaySetBufSync;
if state {
crate::sys::sceDisplaySetFrameBuf(
(GE_EDRAM_ADDRESS as *mut u8).add(DRAW_BUFFER.disp_buffer as usize),
DRAW_BUFFER.frame_width as usize,
DRAW_BUFFER.pixel_size,
DisplaySetBufSync::NextFrame,
);
} else {
crate::sys::sceDisplaySetFrameBuf(
null_mut(),
0,
DisplayPixelFormat::Psm5650,
DisplaySetBufSync::NextFrame,
);
}
DISPLAY_ON = state;
state
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDepthFunc(function: DepthFunc) {
send_command_i(GeCommand::ZTest, function as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDepthMask(mask: i32) {
send_command_i(GeCommand::ZWriteDisable, mask);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDepthOffset(offset: i32) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.depth_offset = offset;
sceGuDepthRange(context.near_plane, context.far_plane);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDepthRange(mut near: i32, mut far: i32) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
let max = near as u32 + far as u32;
let val = ((max >> 31) + max) as i32;
let z = (val >> 1) as f32;
context.near_plane = near;
context.far_plane = far;
send_command_f(GeCommand::ViewportZScale, z - near as f32);
send_command_f(GeCommand::ViewportZCenter, z + context.depth_offset as f32);
if near > far {
mem::swap(&mut near, &mut far);
}
send_command_i(GeCommand::MinZ, near);
send_command_i(GeCommand::MaxZ, far);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuFog(near: f32, far: f32, color: u32) {
let mut distance = far - near;
if distance != 0.0 {
distance = 1.0 / distance;
}
send_command_i(GeCommand::FogColor, (color & 0xffffff) as i32);
send_command_f(GeCommand::Fog1, far);
send_command_f(GeCommand::Fog2, distance);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuInit() {
const INIT_COMMANDS: [GeCommand; 223] = [
GeCommand::Vaddr,
GeCommand::Iaddr,
GeCommand::Base,
GeCommand::VertexType,
GeCommand::OffsetAddr,
GeCommand::Region1,
GeCommand::Region2,
GeCommand::LightingEnable,
GeCommand::LightEnable0,
GeCommand::LightEnable1,
GeCommand::LightEnable2,
GeCommand::LightEnable3,
GeCommand::DepthClampEnable,
GeCommand::CullFaceEnable,
GeCommand::TextureMapEnable,
GeCommand::FogEnable,
GeCommand::DitherEnable,
GeCommand::AlphaBlendEnable,
GeCommand::AlphaTestEnable,
GeCommand::ZTestEnable,
GeCommand::StencilTestEnable,
GeCommand::AntiAliasEnable,
GeCommand::PatchCullEnable,
GeCommand::ColorTestEnable,
GeCommand::LogicOpEnable,
GeCommand::BoneMatrixNumber,
GeCommand::BoneMatrixData,
GeCommand::MorphWeight0,
GeCommand::MorphWeight1,
GeCommand::MorphWeight2,
GeCommand::MorphWeight3,
GeCommand::MorphWeight4,
GeCommand::MorphWeight5,
GeCommand::MorphWeight6,
GeCommand::MorphWeight7,
GeCommand::PatchDivision,
GeCommand::PatchPrimitive,
GeCommand::PatchFacing,
GeCommand::WorldMatrixNumber,
GeCommand::WorldMatrixData,
GeCommand::ViewMatrixNumber,
GeCommand::ViewMatrixData,
GeCommand::ProjMatrixNumber,
GeCommand::ProjMatrixData,
GeCommand::TGenMatrixNumber,
GeCommand::TGenMatrixData,
GeCommand::ViewportXScale,
GeCommand::ViewportYScale,
GeCommand::ViewportZScale,
GeCommand::ViewportXCenter,
GeCommand::ViewportYCenter,
GeCommand::ViewportZCenter,
GeCommand::TexScaleU,
GeCommand::TexScaleV,
GeCommand::TexOffsetU,
GeCommand::TexOffsetV,
GeCommand::OffsetX,
GeCommand::OffsetY,
GeCommand::ShadeMode,
GeCommand::ReverseNormal,
GeCommand::MaterialUpdate,
GeCommand::MaterialEmissive,
GeCommand::MaterialAmbient,
GeCommand::MaterialDiffuse,
GeCommand::MaterialSpecular,
GeCommand::MaterialAlpha,
GeCommand::MaterialSpecularCoef,
GeCommand::AmbientColor,
GeCommand::AmbientAlpha,
GeCommand::LightMode,
GeCommand::LightType0,
GeCommand::LightType1,
GeCommand::LightType2,
GeCommand::LightType3,
GeCommand::Light0X,
GeCommand::Light0Y,
GeCommand::Light0Z,
GeCommand::Light1X,
GeCommand::Light1Y,
GeCommand::Light1Z,
GeCommand::Light2X,
GeCommand::Light2Y,
GeCommand::Light2Z,
GeCommand::Light3X,
GeCommand::Light3Y,
GeCommand::Light3Z,
GeCommand::Light0DirectionX,
GeCommand::Light0DirectionY,
GeCommand::Light0DirectionZ,
GeCommand::Light1DirectionX,
GeCommand::Light1DirectionY,
GeCommand::Light1DirectionZ,
GeCommand::Light2DirectionX,
GeCommand::Light2DirectionY,
GeCommand::Light2DirectionZ,
GeCommand::Light3DirectionX,
GeCommand::Light3DirectionY,
GeCommand::Light3DirectionZ,
GeCommand::Light0ConstantAtten,
GeCommand::Light0LinearAtten,
GeCommand::Light0QuadtraticAtten,
GeCommand::Light1ConstantAtten,
GeCommand::Light1LinearAtten,
GeCommand::Light1QuadtraticAtten,
GeCommand::Light2ConstantAtten,
GeCommand::Light2LinearAtten,
GeCommand::Light2QuadtraticAtten,
GeCommand::Light3ConstantAtten,
GeCommand::Light3LinearAtten,
GeCommand::Light3QuadtraticAtten,
GeCommand::Light0ExponentAtten,
GeCommand::Light1ExponentAtten,
GeCommand::Light2ExponentAtten,
GeCommand::Light3ExponentAtten,
GeCommand::Light0CutoffAtten,
GeCommand::Light1CutoffAtten,
GeCommand::Light2CutoffAtten,
GeCommand::Light3CutoffAtten,
GeCommand::Light0Ambient,
GeCommand::Light0Diffuse,
GeCommand::Light0Specular,
GeCommand::Light1Ambient,
GeCommand::Light1Diffuse,
GeCommand::Light1Specular,
GeCommand::Light2Ambient,
GeCommand::Light2Diffuse,
GeCommand::Light2Specular,
GeCommand::Light3Ambient,
GeCommand::Light3Diffuse,
GeCommand::Light3Specular,
GeCommand::Cull,
GeCommand::FrameBufPtr,
GeCommand::FrameBufWidth,
GeCommand::ZBufPtr,
GeCommand::ZBufWidth,
GeCommand::TexAddr0,
GeCommand::TexAddr1,
GeCommand::TexAddr2,
GeCommand::TexAddr3,
GeCommand::TexAddr4,
GeCommand::TexAddr5,
GeCommand::TexAddr6,
GeCommand::TexAddr7,
GeCommand::TexBufWidth0,
GeCommand::TexBufWidth1,
GeCommand::TexBufWidth2,
GeCommand::TexBufWidth3,
GeCommand::TexBufWidth4,
GeCommand::TexBufWidth5,
GeCommand::TexBufWidth6,
GeCommand::TexBufWidth7,
GeCommand::ClutAddr,
GeCommand::ClutAddrUpper,
GeCommand::TransferSrc,
GeCommand::TransferSrcW,
GeCommand::TransferDst,
GeCommand::TransferDstW,
GeCommand::TexSize0,
GeCommand::TexSize1,
GeCommand::TexSize2,
GeCommand::TexSize3,
GeCommand::TexSize4,
GeCommand::TexSize5,
GeCommand::TexSize6,
GeCommand::TexSize7,
GeCommand::TexMapMode,
GeCommand::TexShadeLs,
GeCommand::TexMode,
GeCommand::TexFormat,
GeCommand::LoadClut,
GeCommand::ClutFormat,
GeCommand::TexFilter,
GeCommand::TexWrap,
GeCommand::TexLevel,
GeCommand::TexFunc,
GeCommand::TexEnvColor,
GeCommand::TexFlush,
GeCommand::TexSync,
GeCommand::Fog1,
GeCommand::Fog2,
GeCommand::FogColor,
GeCommand::TexLodSlope,
GeCommand::FramebufPixFormat,
GeCommand::ClearMode,
GeCommand::Scissor1,
GeCommand::Scissor2,
GeCommand::MinZ,
GeCommand::MaxZ,
GeCommand::ColorTest,
GeCommand::ColorRef,
GeCommand::ColorTestmask,
GeCommand::AlphaTest,
GeCommand::StencilTest,
GeCommand::StencilOp,
GeCommand::ZTest,
GeCommand::BlendMode,
GeCommand::BlendFixedA,
GeCommand::BlendFixedB,
GeCommand::Dith0,
GeCommand::Dith1,
GeCommand::Dith2,
GeCommand::Dith3,
GeCommand::LogicOp,
GeCommand::ZWriteDisable,
GeCommand::MaskRgb,
GeCommand::MaskAlpha,
GeCommand::TransferSrcPos,
GeCommand::TransferDstPos,
GeCommand::TransferSize,
GeCommand::Vscx,
GeCommand::Vscy,
GeCommand::Vscz,
GeCommand::Vtcs,
GeCommand::Vtct,
GeCommand::Vtcq,
GeCommand::Vcv,
GeCommand::Vap,
GeCommand::Vfc,
GeCommand::Vscv,
GeCommand::Finish,
GeCommand::End,
GeCommand::Nop,
GeCommand::Nop,
];
static INIT_LIST: crate::Align16<[u32; 223]> = crate::Align16({
let mut out = [0; 223];
let mut i = 0;
while i < 223 {
out[i] = (INIT_COMMANDS[i] as u32) << 24;
i += 1;
}
out
});
let mut callback = crate::sys::GeCallbackData {
signal_func: Some(callback_sig),
signal_arg: addr_of_mut!(SETTINGS).cast::<c_void>(),
finish_func: Some(callback_fin),
finish_arg: addr_of_mut!(SETTINGS).cast::<c_void>(),
};
SETTINGS.ge_callback_id = crate::sys::sceGeSetCallback(&mut callback);
SETTINGS.swap_buffers_callback = None;
SETTINGS.swap_buffers_behaviour = super::display::DisplaySetBufSync::Immediate;
GE_EDRAM_ADDRESS = sys::sceGeEdramGetAddr().cast::<c_void>();
GE_LIST_EXECUTED[0] = sys::sceGeListEnQueue(
(&INIT_LIST as *const _ as u32 & 0x1fffffff) as *const _,
core::ptr::null_mut(),
SETTINGS.ge_callback_id,
core::ptr::null_mut(),
);
reset_values();
SETTINGS.kernel_event_flag = super::kernel::sceKernelCreateEventFlag(
b"SceGuSignal\0" as *const u8,
super::kernel::EventFlagAttributes::WAIT_MULTIPLE,
3,
null_mut(),
);
sys::sceGeListSync(GE_LIST_EXECUTED[0], 0);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTerm() {
sys::sceKernelDeleteEventFlag(SETTINGS.kernel_event_flag);
sys::sceGeUnsetCallback(SETTINGS.ge_callback_id);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuBreak(mode: i32) {
static mut UNUSED_BREAK: GeBreakParam = GeBreakParam { buf: [0; 4] };
sys::sceGeBreak(mode, addr_of_mut!(UNUSED_BREAK));
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuContinue() {
sys::sceGeContinue();
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSetCallback(
signal: GuCallbackId,
callback: GuCallback,
) -> GuCallback {
let old_callback;
match signal {
GuCallbackId::Signal => {
old_callback = SETTINGS.sig;
SETTINGS.sig = callback;
}
GuCallbackId::Finish => {
old_callback = SETTINGS.fin;
SETTINGS.fin = callback;
}
}
old_callback
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSignal(behavior: SignalBehavior, signal: i32) {
send_command_i(
GeCommand::Signal,
((signal & 0xff) << 16) | (behavior as i32 & 0xffff),
);
send_command_i(GeCommand::End, 0);
if signal == 3 {
send_command_i(GeCommand::Finish, 0);
send_command_i(GeCommand::End, 0);
}
send_command_i_stall(GeCommand::Nop, 0);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSendCommandf(cmd: GeCommand, argument: f32) {
send_command_f(cmd, argument);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSendCommandi(cmd: GeCommand, argument: i32) {
send_command_i(cmd, argument);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuGetMemory(mut size: i32) -> *mut c_void {
size += 3;
size += (((size >> 31) as u32) >> 30) as i32;
size = (size >> 2) << 2;
let orig_ptr = (*LIST).current;
let new_ptr = (orig_ptr as usize + size as usize + 8) as *mut u32;
let lo = (8 << 24) | (new_ptr as i32 & 0xffffff);
let hi = ((16 << 24) | ((new_ptr as u32 >> 8) & 0xf0000)) as i32;
*orig_ptr = hi as u32;
*orig_ptr.offset(1) = lo as u32;
(*LIST).current = new_ptr;
if let GuContextType::Direct = CURR_CONTEXT {
crate::sys::sceGeListUpdateStallAddr(GE_LIST_EXECUTED[0], new_ptr.cast::<c_void>());
}
orig_ptr.add(2).cast::<c_void>()
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuStart(context_type: GuContextType, list: *mut c_void) {
let context = &mut CONTEXTS[context_type as usize];
let local_list = ((list as u32) | 0x4000_0000) as *mut u32;
context.list.start = local_list;
context.list.current = local_list;
context.list.parent_context = CURR_CONTEXT;
LIST = &mut context.list;
CURR_CONTEXT = context_type;
if let GuContextType::Direct = context_type {
GE_LIST_EXECUTED[0] = crate::sys::sceGeListEnQueue(
local_list as *mut c_void,
local_list as *mut c_void,
SETTINGS.ge_callback_id,
core::ptr::null_mut(),
);
SETTINGS.signal_offset = 0;
}
if INIT == 0 {
static DITHER_MATRIX: ScePspIMatrix4 = ScePspIMatrix4 {
x: ScePspIVector4 {
x: -4,
y: 0,
z: -3,
w: 1,
},
y: ScePspIVector4 {
x: 2,
y: -2,
z: 3,
w: -1,
},
z: ScePspIVector4 {
x: -3,
y: 1,
z: -4,
w: 0,
},
w: ScePspIVector4 {
x: 3,
y: -1,
z: 2,
w: -2,
},
};
sceGuSetDither(&DITHER_MATRIX);
sceGuPatchDivide(16, 16);
sceGuColorMaterial(
LightComponent::AMBIENT | LightComponent::DIFFUSE | LightComponent::SPECULAR,
);
sceGuSpecular(1.0);
sceGuTexScale(1.0, 1.0);
INIT = 1;
}
if let GuContextType::Direct = CURR_CONTEXT {
if DRAW_BUFFER.frame_width != 0 {
send_command_i(
GeCommand::FrameBufPtr,
DRAW_BUFFER.frame_buffer as i32 & 0xffffff,
);
send_command_i(
GeCommand::FrameBufWidth,
((DRAW_BUFFER.frame_buffer as u32 & 0xff00_0000) >> 8) as i32
| DRAW_BUFFER.frame_width,
);
}
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuFinish() -> i32 {
match CURR_CONTEXT {
GuContextType::Direct | GuContextType::Send => {
send_command_i(GeCommand::Finish, 0);
send_command_i_stall(GeCommand::End, 0);
}
GuContextType::Call => {
if CALL_MODE == 1 {
send_command_i(GeCommand::Signal, 0x120000);
send_command_i(GeCommand::End, 0);
send_command_i_stall(GeCommand::Nop, 0);
} else {
send_command_i(GeCommand::Ret, 0);
}
}
}
let size = ((*LIST).current as usize) - ((*LIST).start as usize);
CURR_CONTEXT = (*LIST).parent_context;
LIST = &mut CONTEXTS[CURR_CONTEXT as usize].list;
size as i32
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuFinishId(id: u32) -> i32 {
match CURR_CONTEXT {
GuContextType::Direct | GuContextType::Send => {
send_command_i(GeCommand::Finish, (id & 0xffff) as i32);
send_command_i_stall(GeCommand::End, 0);
}
GuContextType::Call => {
if CALL_MODE == 1 {
send_command_i(GeCommand::Signal, 0x120000);
send_command_i(GeCommand::End, 0);
send_command_i_stall(GeCommand::Nop, 0);
} else {
send_command_i(GeCommand::Ret, 0);
}
}
}
let size = ((*LIST).current as usize) - ((*LIST).start as usize);
CURR_CONTEXT = (*LIST).parent_context;
LIST = &mut CONTEXTS[CURR_CONTEXT as usize].list;
size as i32
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuCallList(list: *const c_void) {
let list_addr = list as u32;
if CALL_MODE == 1 {
send_command_i(GeCommand::Signal, (list_addr >> 16) as i32 | 0x110000);
send_command_i(GeCommand::End, list_addr as i32 & 0xffff);
send_command_i_stall(GeCommand::Nop, 0);
} else {
send_command_i(GeCommand::Base, (list_addr >> 8) as i32 & 0xf0000);
send_command_i_stall(GeCommand::Call, list_addr as i32 & 0xffffff);
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuCallMode(mode: i32) {
CALL_MODE = mode;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuCheckList() -> i32 {
(*LIST).current.sub((*LIST).start as usize) as i32
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSendList(
mode: GuQueueMode,
list: *const c_void,
context: *mut GeContext,
) {
SETTINGS.signal_offset = 0;
let mut args = GeListArgs {
size: 8,
context,
..<_>::default()
};
let callback = SETTINGS.ge_callback_id;
let list_id = match mode {
GuQueueMode::Head => {
crate::sys::sceGeListEnQueueHead(list, null_mut(), callback, &mut args)
}
GuQueueMode::Tail => crate::sys::sceGeListEnQueue(list, null_mut(), callback, &mut args),
};
GE_LIST_EXECUTED[1] = list_id;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSwapBuffers() -> *mut c_void {
if let Some(cb) = SETTINGS.swap_buffers_callback {
cb(
addr_of_mut!(DRAW_BUFFER.disp_buffer),
addr_of_mut!(DRAW_BUFFER.frame_buffer),
);
} else {
mem::swap(&mut DRAW_BUFFER.disp_buffer, &mut DRAW_BUFFER.frame_buffer);
}
if DISPLAY_ON {
crate::sys::sceDisplaySetFrameBuf(
GE_EDRAM_ADDRESS.add(DRAW_BUFFER.disp_buffer as usize) as *const u8,
DRAW_BUFFER.frame_width as usize,
DRAW_BUFFER.pixel_size,
SETTINGS.swap_buffers_behaviour,
);
}
CURRENT_FRAME ^= 1;
DRAW_BUFFER.frame_buffer
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSync(mode: GuSyncMode, behavior: GuSyncBehavior) -> GeListState {
match mode {
GuSyncMode::Finish => crate::sys::sceGeDrawSync(behavior as i32),
GuSyncMode::List => crate::sys::sceGeListSync(GE_LIST_EXECUTED[0], behavior as i32),
GuSyncMode::Send => crate::sys::sceGeListSync(GE_LIST_EXECUTED[1], behavior as i32),
_ => GeListState::Done,
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDrawArray(
prim: GuPrimitive,
vtype: VertexType,
count: i32,
indices: *const c_void,
vertices: *const c_void,
) {
if !vtype.is_empty() {
send_command_i(GeCommand::VertexType, vtype.bits());
}
if !indices.is_null() {
send_command_i(GeCommand::Base, (indices as u32 >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Iaddr, indices as i32 & 0xffffff);
}
if !vertices.is_null() {
send_command_i(GeCommand::Base, (vertices as u32 >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Vaddr, vertices as i32 & 0xffffff);
}
send_command_i_stall(GeCommand::Prim, ((prim as i32) << 16) | count);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuBeginObject(
vtype: i32,
count: i32,
indices: *const c_void,
vertices: *const c_void,
) {
if vtype != 0 {
send_command_i(GeCommand::VertexType, vtype);
}
if !indices.is_null() {
send_command_i(GeCommand::Base, (indices as u32 >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Iaddr, indices as i32 & 0xffffff);
}
if !vertices.is_null() {
send_command_i(GeCommand::Base, (vertices as u32 >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Vaddr, vertices as i32 & 0xffffff);
}
send_command_i(GeCommand::BoundingBox, count);
(*OBJECT_STACK.offset(OBJECT_STACK_DEPTH as isize)) = (*LIST).current;
OBJECT_STACK_DEPTH += 1;
send_command_i(GeCommand::Base, 0);
send_command_i(GeCommand::BJump, 0);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuEndObject() {
let current = (*LIST).current;
(*LIST).current = *OBJECT_STACK.offset(OBJECT_STACK_DEPTH as isize - 1);
send_command_i(GeCommand::Base, (current as u32 >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::BJump, current as i32 & 0xffffff);
(*LIST).current = current;
OBJECT_STACK_DEPTH -= 1;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSetStatus(state: GuState, status: i32) {
if status != 0 {
sceGuEnable(state);
} else {
sceGuDisable(state);
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuGetStatus(state: GuState) -> bool {
let state = state as u32;
if state < 22 {
return (STATES >> state) & 1 != 0;
}
false
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSetAllStatus(status: i32) {
for i in 0..22 {
if (status >> i) & 1 != 0 {
sceGuEnable(mem::transmute(i));
} else {
sceGuDisable(mem::transmute(i));
}
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuGetAllStatus() -> i32 {
STATES as i32
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuEnable(state: GuState) {
match state {
GuState::AlphaTest => send_command_i(GeCommand::AlphaTestEnable, 1),
GuState::DepthTest => send_command_i(GeCommand::ZTestEnable, 1),
GuState::ScissorTest => {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.scissor_enable = 1;
send_command_i(
GeCommand::Scissor1,
(context.scissor_start[1] << 10) | context.scissor_start[0],
);
send_command_i(
GeCommand::Scissor2,
(context.scissor_end[1] << 10) | context.scissor_end[0],
);
}
GuState::StencilTest => send_command_i(GeCommand::StencilTestEnable, 1),
GuState::Blend => send_command_i(GeCommand::AlphaBlendEnable, 1),
GuState::CullFace => send_command_i(GeCommand::CullFaceEnable, 1),
GuState::Dither => send_command_i(GeCommand::DitherEnable, 1),
GuState::Fog => send_command_i(GeCommand::FogEnable, 1),
GuState::ClipPlanes => send_command_i(GeCommand::DepthClampEnable, 1),
GuState::Texture2D => send_command_i(GeCommand::TextureMapEnable, 1),
GuState::Lighting => send_command_i(GeCommand::LightingEnable, 1),
GuState::Light0 => send_command_i(GeCommand::LightEnable0, 1),
GuState::Light1 => send_command_i(GeCommand::LightEnable1, 1),
GuState::Light2 => send_command_i(GeCommand::LightEnable2, 1),
GuState::Light3 => send_command_i(GeCommand::LightEnable3, 1),
GuState::LineSmooth => send_command_i(GeCommand::AntiAliasEnable, 1),
GuState::PatchCullFace => send_command_i(GeCommand::PatchCullEnable, 1),
GuState::ColorTest => send_command_i(GeCommand::ColorTestEnable, 1),
GuState::ColorLogicOp => send_command_i(GeCommand::LogicOpEnable, 1),
GuState::FaceNormalReverse => send_command_i(GeCommand::ReverseNormal, 1),
GuState::PatchFace => send_command_i(GeCommand::PatchFacing, 1),
GuState::Fragment2X => {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.fragment_2x = 0x10000;
send_command_i(GeCommand::TexFunc, 0x10000 | context.texture_function);
}
}
if (state as u32) < 22 {
STATES |= 1 << state as u32
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDisable(state: GuState) {
match state {
GuState::AlphaTest => send_command_i(GeCommand::AlphaTestEnable, 0),
GuState::DepthTest => send_command_i(GeCommand::ZTestEnable, 0),
GuState::ScissorTest => {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.scissor_enable = 0;
send_command_i(GeCommand::Scissor1, 0);
send_command_i(
GeCommand::Scissor2,
((DRAW_BUFFER.height - 1) << 10) | (DRAW_BUFFER.width - 1),
);
}
GuState::StencilTest => send_command_i(GeCommand::StencilTestEnable, 0),
GuState::Blend => send_command_i(GeCommand::AlphaBlendEnable, 0),
GuState::CullFace => send_command_i(GeCommand::CullFaceEnable, 0),
GuState::Dither => send_command_i(GeCommand::DitherEnable, 0),
GuState::Fog => send_command_i(GeCommand::FogEnable, 0),
GuState::ClipPlanes => send_command_i(GeCommand::DepthClampEnable, 0),
GuState::Texture2D => send_command_i(GeCommand::TextureMapEnable, 0),
GuState::Lighting => send_command_i(GeCommand::LightingEnable, 0),
GuState::Light0 => send_command_i(GeCommand::LightEnable0, 0),
GuState::Light1 => send_command_i(GeCommand::LightEnable1, 0),
GuState::Light2 => send_command_i(GeCommand::LightEnable2, 0),
GuState::Light3 => send_command_i(GeCommand::LightEnable3, 0),
GuState::LineSmooth => send_command_i(GeCommand::AntiAliasEnable, 0),
GuState::PatchCullFace => send_command_i(GeCommand::PatchCullEnable, 0),
GuState::ColorTest => send_command_i(GeCommand::ColorTestEnable, 0),
GuState::ColorLogicOp => send_command_i(GeCommand::LogicOpEnable, 0),
GuState::FaceNormalReverse => send_command_i(GeCommand::ReverseNormal, 0),
GuState::PatchFace => send_command_i(GeCommand::PatchFacing, 0),
GuState::Fragment2X => {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.fragment_2x = 0;
send_command_i(GeCommand::TexFunc, context.texture_function);
}
}
if (state as u32) < 22 {
STATES &= !(1 << state as u32)
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuLight(
light: i32,
type_: LightType,
components: LightComponent,
position: &ScePspFVector3,
) {
let settings = &LIGHT_COMMANDS[light as usize];
send_command_f(settings.xpos, position.x);
send_command_f(settings.ypos, position.y);
send_command_f(settings.zpos, position.z);
let mut kind = 2;
if components.bits() != 8 {
kind = if components.bits() ^ 6 < 1 { 1 } else { 0 };
}
send_command_i(settings.type_, ((type_ as i32 & 0x03) << 8) | kind);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuLightAtt(light: i32, atten0: f32, atten1: f32, atten2: f32) {
let settings = &LIGHT_COMMANDS[light as usize];
send_command_f(settings.constant, atten0);
send_command_f(settings.linear, atten1);
send_command_f(settings.quadratic, atten2);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuLightColor(light: i32, component: LightComponent, color: u32) {
let settings = &LIGHT_COMMANDS[light as usize];
if component.intersects(LightComponent::AMBIENT) {
send_command_i(settings.ambient, (color & 0xffffff) as i32);
}
if component.intersects(LightComponent::DIFFUSE) {
send_command_i(settings.diffuse, (color & 0xffffff) as i32);
}
if component.intersects(LightComponent::SPECULAR) {
send_command_i(settings.specular, (color & 0xffffff) as i32);
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuLightMode(mode: LightMode) {
send_command_i(GeCommand::LightMode, mode as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuLightSpot(
light: i32,
direction: &ScePspFVector3,
exponent: f32,
cutoff: f32,
) {
let settings = &LIGHT_COMMANDS[light as usize];
send_command_f(settings.exponent, exponent);
send_command_f(settings.cutoff, cutoff);
send_command_f(settings.xdir, direction.x);
send_command_f(settings.ydir, direction.y);
send_command_f(settings.zdir, direction.z);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuClear(flags: ClearBuffer) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
struct Vertex {
color: u32,
x: u16,
y: u16,
z: u16,
_pad: u16,
}
let filter: u32 = match DRAW_BUFFER.pixel_size {
DisplayPixelFormat::Psm5650 => context.clear_color & 0xffffff,
DisplayPixelFormat::Psm5551 => {
(context.clear_color & 0xffffff) | (context.clear_stencil << 31)
}
DisplayPixelFormat::Psm4444 => {
(context.clear_color & 0xffffff) | (context.clear_stencil << 28)
}
DisplayPixelFormat::Psm8888 => {
(context.clear_color & 0xffffff) | (context.clear_stencil << 24)
}
};
let vertices;
let count;
if !flags.intersects(ClearBuffer::FAST_CLEAR_BIT) {
vertices = sceGuGetMemory(2 * mem::size_of::<Vertex>() as i32) as *mut Vertex;
count = 2;
(*vertices.offset(0)).color = 0;
(*vertices.offset(0)).x = 0;
(*vertices.offset(0)).y = 0;
(*vertices.offset(0)).z = context.clear_depth as u16;
(*vertices.offset(1)).color = filter;
(*vertices.offset(1)).x = DRAW_BUFFER.width as u16;
(*vertices.offset(1)).y = DRAW_BUFFER.height as u16;
(*vertices.offset(1)).z = context.clear_depth as u16;
} else {
count = ((DRAW_BUFFER.width + 63) / 64) * 2;
vertices = sceGuGetMemory(count * core::mem::size_of::<Vertex>() as i32) as *mut Vertex;
let mut curr = vertices;
for i in 0..count {
let j = i >> 1;
let k = i & 1;
(*curr).color = filter;
(*curr).x = (j + k) as u16 * 64;
(*curr).y = (k * DRAW_BUFFER.height) as u16;
(*curr).z = context.clear_depth as u16;
curr = curr.add(1);
}
}
{
let relevant_flags = flags
& (ClearBuffer::COLOR_BUFFER_BIT
| ClearBuffer::STENCIL_BUFFER_BIT
| ClearBuffer::DEPTH_BUFFER_BIT);
send_command_i(
GeCommand::ClearMode,
(relevant_flags.bits() << 8) as i32 | 0x01,
);
}
sceGuDrawArray(
GuPrimitive::Sprites,
VertexType::COLOR_8888 | VertexType::VERTEX_16BIT | VertexType::TRANSFORM_2D,
count,
null_mut(),
vertices as *mut c_void,
);
send_command_i(GeCommand::ClearMode, 0);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuClearColor(color: u32) {
CONTEXTS[CURR_CONTEXT as usize].clear_color = color;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuClearDepth(depth: u32) {
CONTEXTS[CURR_CONTEXT as usize].clear_depth = depth;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuClearStencil(stencil: u32) {
CONTEXTS[CURR_CONTEXT as usize].clear_stencil = stencil;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuPixelMask(mask: u32) {
send_command_i(GeCommand::MaskRgb, mask as i32 & 0xffffff);
send_command_i(GeCommand::MaskAlpha, (mask >> 24) as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuColor(color: u32) {
sceGuMaterial(
LightComponent::AMBIENT | LightComponent::DIFFUSE | LightComponent::SPECULAR,
color,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuColorFunc(func: ColorFunc, color: u32, mask: u32) {
send_command_i(GeCommand::ColorTest, func as i32 & 0x03);
send_command_i(GeCommand::ColorRef, color as i32 & 0xffffff);
send_command_i(GeCommand::ColorTestmask, mask as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuColorMaterial(components: LightComponent) {
send_command_i(GeCommand::MaterialUpdate, components.bits());
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuAlphaFunc(func: AlphaFunc, value: i32, mask: i32) {
let arg = func as i32 | ((value & 0xff) << 8) | ((mask & 0xff) << 16);
send_command_i(GeCommand::AlphaTest, arg);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuAmbient(color: u32) {
send_command_i(GeCommand::AmbientColor, color as i32 & 0xffffff);
send_command_i(GeCommand::AmbientAlpha, (color >> 24) as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuAmbientColor(color: u32) {
send_command_i(GeCommand::MaterialAmbient, color as i32 & 0xffffff);
send_command_i(GeCommand::MaterialAlpha, (color >> 24) as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuBlendFunc(
op: BlendOp,
src: BlendFactor,
dest: BlendFactor,
src_fix: u32,
dest_fix: u32,
) {
send_command_i(
GeCommand::BlendMode,
src as i32 | ((dest as i32) << 4) | ((op as i32) << 8),
);
send_command_i(GeCommand::BlendFixedA, src_fix as i32 & 0xffffff);
send_command_i(GeCommand::BlendFixedB, dest_fix as i32 & 0xffffff);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuMaterial(components: LightComponent, color: u32) {
if components.intersects(LightComponent::AMBIENT) {
send_command_i(GeCommand::MaterialAmbient, color as i32 & 0xffffff);
send_command_i(GeCommand::MaterialAlpha, (color >> 24) as i32);
}
if components.intersects(LightComponent::DIFFUSE) {
send_command_i(GeCommand::MaterialDiffuse, color as i32 & 0xffffff);
}
if components.intersects(LightComponent::SPECULAR) {
send_command_i(GeCommand::MaterialSpecular, color as i32 & 0xffffff);
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuModelColor(emissive: u32, ambient: u32, diffuse: u32, specular: u32) {
send_command_i(GeCommand::MaterialEmissive, emissive as i32 & 0xffffff);
send_command_i(GeCommand::MaterialAmbient, ambient as i32 & 0xffffff);
send_command_i(GeCommand::MaterialDiffuse, diffuse as i32 & 0xffffff);
send_command_i(GeCommand::MaterialSpecular, specular as i32 & 0xffffff);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuStencilFunc(func: StencilFunc, ref_: i32, mask: i32) {
send_command_i(
GeCommand::StencilTest,
func as i32 | ((ref_ & 0xff) << 8) | ((mask & 0xff) << 16),
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuStencilOp(
fail: StencilOperation,
zfail: StencilOperation,
zpass: StencilOperation,
) {
send_command_i(
GeCommand::StencilOp,
fail as i32 | ((zfail as i32) << 8) | ((zpass as i32) << 16),
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSpecular(power: f32) {
send_command_f(GeCommand::MaterialSpecularCoef, power);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuFrontFace(order: FrontFaceDirection) {
match order {
FrontFaceDirection::CounterClockwise => send_command_i(GeCommand::Cull, 0),
FrontFaceDirection::Clockwise => send_command_i(GeCommand::Cull, 1),
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuLogicalOp(op: LogicalOperation) {
send_command_i(GeCommand::LogicOp, op as i32 & 0x0f);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSetDither(matrix: &ScePspIMatrix4) {
send_command_i(
GeCommand::Dith0,
(matrix.x.x & 0x0f)
| ((matrix.x.y & 0x0f) << 4)
| ((matrix.x.z & 0x0f) << 8)
| ((matrix.x.w & 0x0f) << 12),
);
send_command_i(
GeCommand::Dith1,
(matrix.y.x & 0x0f)
| ((matrix.y.y & 0x0f) << 4)
| ((matrix.y.z & 0x0f) << 8)
| ((matrix.y.w & 0x0f) << 12),
);
send_command_i(
GeCommand::Dith2,
(matrix.z.x & 0x0f)
| ((matrix.z.y & 0x0f) << 4)
| ((matrix.z.z & 0x0f) << 8)
| ((matrix.z.w & 0x0f) << 12),
);
send_command_i(
GeCommand::Dith3,
(matrix.w.x & 0x0f)
| ((matrix.w.y & 0x0f) << 4)
| ((matrix.w.z & 0x0f) << 8)
| ((matrix.w.w & 0x0f) << 12),
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuShadeModel(mode: ShadingModel) {
match mode {
ShadingModel::Smooth => send_command_i(GeCommand::ShadeMode, 1),
ShadingModel::Flat => send_command_i(GeCommand::ShadeMode, 0),
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuCopyImage(
psm: DisplayPixelFormat,
sx: i32,
sy: i32,
width: i32,
height: i32,
srcw: i32,
src: *mut c_void,
dx: i32,
dy: i32,
destw: i32,
dest: *mut c_void,
) {
send_command_i(GeCommand::TransferSrc, (src as i32) & 0xffffff);
send_command_i(
GeCommand::TransferSrcW,
(((src as u32) & 0xff000000) >> 8) as i32 | srcw,
);
send_command_i(GeCommand::TransferSrcPos, (sy << 10) | sx);
send_command_i(GeCommand::TransferDst, (dest as i32) & 0xffffff);
send_command_i(
GeCommand::TransferDstW,
(((dest as u32) & 0xff000000) >> 8) as i32 | destw,
);
send_command_i(GeCommand::TransferDstPos, (dy << 10) | dx);
send_command_i(GeCommand::TransferSize, ((height - 1) << 10) | (width - 1));
let is_32_bit_texel = if let DisplayPixelFormat::Psm8888 = psm {
1
} else {
0
};
send_command_i(GeCommand::TransferStart, is_32_bit_texel);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexEnvColor(color: u32) {
send_command_i(GeCommand::TexEnvColor, color as i32 & 0xffffff);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexFilter(min: TextureFilter, mag: TextureFilter) {
send_command_i(GeCommand::TexFilter, ((mag as i32) << 8) | (min as i32));
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexFlush() {
send_command_f(GeCommand::TexFlush, 0.0);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexFunc(tfx: TextureEffect, tcc: TextureColorComponent) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.texture_function = (((tcc as u32) << 8) | (tfx as u32)) as i32;
send_command_i(
GeCommand::TexFunc,
(((tcc as u32) << 8) | (tfx as u32) | context.fragment_2x as u32) as i32,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexImage(
mipmap: MipmapLevel,
width: i32,
height: i32,
tbw: i32,
tbp: *const c_void,
) {
use core::intrinsics::ctlz;
const TBP_CMD_TBL: [GeCommand; 8] = [
GeCommand::TexAddr0,
GeCommand::TexAddr1,
GeCommand::TexAddr2,
GeCommand::TexAddr3,
GeCommand::TexAddr4,
GeCommand::TexAddr5,
GeCommand::TexAddr6,
GeCommand::TexAddr7,
];
const TBW_CMD_TBL: [GeCommand; 8] = [
GeCommand::TexBufWidth0,
GeCommand::TexBufWidth1,
GeCommand::TexBufWidth2,
GeCommand::TexBufWidth3,
GeCommand::TexBufWidth4,
GeCommand::TexBufWidth5,
GeCommand::TexBufWidth6,
GeCommand::TexBufWidth7,
];
const TSIZE_CMD_TBL: [GeCommand; 8] = [
GeCommand::TexSize0,
GeCommand::TexSize1,
GeCommand::TexSize2,
GeCommand::TexSize3,
GeCommand::TexSize4,
GeCommand::TexSize5,
GeCommand::TexSize6,
GeCommand::TexSize7,
];
send_command_i(TBP_CMD_TBL[mipmap as usize], (tbp as i32) & 0xffffff);
send_command_i(
TBW_CMD_TBL[mipmap as usize],
((tbp as u32 >> 8) as i32 & 0x0f0000) | tbw,
);
send_command_i(
TSIZE_CMD_TBL[mipmap as usize],
(((31 - ctlz(height & 0x3ff)) << 8) | (31 - ctlz(width & 0x3ff))) as i32,
);
sceGuTexFlush();
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexLevelMode(mode: TextureLevelMode, bias: f32) {
#[no_mangle]
#[cfg(target_os = "psp")]
#[allow(deprecated)]
unsafe extern "C" fn truncf(mut x: f32) -> f32 {
core::arch::asm!("cvt.w.s {0}, {0}", inout(freg) x);
x
}
let mut offset = core::intrinsics::truncf32(bias * 16.0) as i32;
if offset >= 128 {
offset = 128
} else if offset < -128 {
offset = -128;
}
send_command_i(GeCommand::TexLevel, ((offset as i32) << 16) | mode as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexMapMode(mode: TextureMapMode, a1: u32, a2: u32) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.texture_map_mode = mode;
send_command_i(
GeCommand::TexMapMode,
((context.texture_proj_map_mode as i32) << 8) | mode as i32,
);
send_command_i(GeCommand::TexShadeLs, ((a2 << 8) | (a1 & 0x03)) as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexMode(
tpsm: TexturePixelFormat,
maxmips: i32,
a2: i32,
swizzle: i32,
) {
CONTEXTS[CURR_CONTEXT as usize].texture_mode = tpsm;
send_command_i(GeCommand::TexMode, (maxmips << 16) | (a2 << 8) | swizzle);
send_command_i(GeCommand::TexFormat, tpsm as i32);
sceGuTexFlush();
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexOffset(u: f32, v: f32) {
send_command_f(GeCommand::TexOffsetU, u);
send_command_f(GeCommand::TexOffsetV, v);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexProjMapMode(mode: TextureProjectionMapMode) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.texture_proj_map_mode = mode;
send_command_i(
GeCommand::TexMapMode,
((mode as i32) << 8) | context.texture_map_mode as i32,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexScale(u: f32, v: f32) {
send_command_f(GeCommand::TexScaleU, u);
send_command_f(GeCommand::TexScaleV, v);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexSlope(slope: f32) {
send_command_f(GeCommand::TexLodSlope, slope);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexSync() {
send_command_i(GeCommand::TexSync, 0);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuTexWrap(u: GuTexWrapMode, v: GuTexWrapMode) {
send_command_i(GeCommand::TexWrap, ((v as i32) << 8) | u as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuClutLoad(num_blocks: i32, cbp: *const c_void) {
send_command_i(GeCommand::ClutAddr, (cbp as i32) & 0xffffff);
send_command_i(
GeCommand::ClutAddrUpper,
((cbp as u32) >> 8) as i32 & 0xf0000,
);
send_command_i(GeCommand::LoadClut, num_blocks);
}
#[repr(u32)]
pub enum ClutPixelFormat {
Psm5650 = 0,
Psm5551 = 1,
Psm4444 = 2,
Psm8888 = 3,
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuClutMode(cpsm: ClutPixelFormat, shift: u32, mask: u32, a3: u32) {
let arg = ((cpsm as u32) | (shift << 2) | (mask << 8) | (a3 << 16)) as i32;
send_command_i(GeCommand::ClutFormat, arg);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuOffset(x: u32, y: u32) {
send_command_i(GeCommand::OffsetX, (x << 4) as i32);
send_command_i(GeCommand::OffsetY, (y << 4) as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuScissor(x: i32, y: i32, w: i32, h: i32) {
let context = &mut CONTEXTS[CURR_CONTEXT as usize];
context.scissor_start = [x, y];
context.scissor_end = [w - 1, h - 1];
if context.scissor_enable != 0 {
send_command_i(
GeCommand::Scissor1,
(context.scissor_start[1] << 10) | context.scissor_start[0],
);
send_command_i(
GeCommand::Scissor2,
(context.scissor_end[1] << 10) | context.scissor_end[0],
);
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuViewport(cx: i32, cy: i32, width: i32, height: i32) {
send_command_f(GeCommand::ViewportXScale, (width >> 1) as f32);
send_command_f(GeCommand::ViewportYScale, ((-height) >> 1) as f32);
send_command_f(GeCommand::ViewportXCenter, cx as f32);
send_command_f(GeCommand::ViewportYCenter, cy as f32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDrawBezier(
v_type: VertexType,
u_count: i32,
v_count: i32,
indices: *const c_void,
vertices: *const c_void,
) {
if !v_type.is_empty() {
send_command_i(GeCommand::VertexType, v_type.bits());
}
if !indices.is_null() {
send_command_i(GeCommand::Base, ((indices as u32) >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Iaddr, (indices as i32) & 0xffffff);
}
if !vertices.is_null() {
send_command_i(GeCommand::Base, ((vertices as u32) >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Vaddr, (vertices as i32) & 0xffffff);
}
send_command_i(GeCommand::Bezier, (v_count << 8) | u_count);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuPatchDivide(ulevel: u32, vlevel: u32) {
send_command_i(GeCommand::PatchDivision, ((vlevel << 8) | ulevel) as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuPatchFrontFace(a0: u32) {
send_command_i(GeCommand::PatchFacing, a0 as i32);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuPatchPrim(prim: PatchPrimitive) {
match prim {
PatchPrimitive::Points => send_command_i(GeCommand::PatchPrimitive, 2),
PatchPrimitive::LineStrip => send_command_i(GeCommand::PatchPrimitive, 1),
PatchPrimitive::TriangleStrip => send_command_i(GeCommand::PatchPrimitive, 0),
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDrawSpline(
v_type: VertexType,
u_count: i32,
v_count: i32,
u_edge: i32,
v_edge: i32,
indices: *const c_void,
vertices: *const c_void,
) {
if !v_type.is_empty() {
send_command_i(GeCommand::VertexType, v_type.bits());
}
if !indices.is_null() {
send_command_i(GeCommand::Base, ((indices as u32) >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Iaddr, (indices as i32) & 0xffffff);
}
if !vertices.is_null() {
send_command_i(GeCommand::Base, ((vertices as u32) >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Vaddr, (vertices as i32) & 0xffffff);
}
send_command_i(
GeCommand::Spline,
(v_edge << 18) | (u_edge << 16) | (v_count << 8) | u_count,
);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuSetMatrix(type_: MatrixMode, matrix: &ScePspFMatrix4) {
let fmatrix = matrix as *const _ as *const f32;
match type_ {
MatrixMode::Projection => {
send_command_f(GeCommand::ProjMatrixNumber, 0.0);
for i in 0..16 {
send_command_f(GeCommand::ProjMatrixData, *fmatrix.offset(i));
}
}
MatrixMode::View => {
send_command_f(GeCommand::ViewMatrixNumber, 0.0);
for i in 0..4 {
for j in 0..3 {
send_command_f(GeCommand::ViewMatrixData, *fmatrix.offset(j + i * 4));
}
}
}
MatrixMode::Model => {
send_command_f(GeCommand::WorldMatrixNumber, 0.0);
for i in 0..4 {
for j in 0..3 {
send_command_f(GeCommand::WorldMatrixData, *fmatrix.offset(j + i * 4));
}
}
}
MatrixMode::Texture => {
send_command_f(GeCommand::TGenMatrixNumber, 0.0);
for i in 0..4 {
for j in 0..3 {
send_command_f(GeCommand::TGenMatrixData, *fmatrix.offset(j + i * 4));
}
}
}
}
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuBoneMatrix(index: u32, matrix: &ScePspFMatrix4) {
send_command_i(GeCommand::BoneMatrixNumber, index as i32 * 12); send_command_f(GeCommand::BoneMatrixData, matrix.x.x);
send_command_f(GeCommand::BoneMatrixData, matrix.x.y);
send_command_f(GeCommand::BoneMatrixData, matrix.x.z);
send_command_f(GeCommand::BoneMatrixData, matrix.y.x);
send_command_f(GeCommand::BoneMatrixData, matrix.y.y);
send_command_f(GeCommand::BoneMatrixData, matrix.y.z);
send_command_f(GeCommand::BoneMatrixData, matrix.z.x);
send_command_f(GeCommand::BoneMatrixData, matrix.z.y);
send_command_f(GeCommand::BoneMatrixData, matrix.z.z);
send_command_f(GeCommand::BoneMatrixData, matrix.w.x);
send_command_f(GeCommand::BoneMatrixData, matrix.w.y);
send_command_f(GeCommand::BoneMatrixData, matrix.w.z);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuMorphWeight(index: i32, weight: f32) {
let cmd = match index {
0 => GeCommand::MorphWeight0,
1 => GeCommand::MorphWeight1,
2 => GeCommand::MorphWeight2,
3 => GeCommand::MorphWeight3,
4 => GeCommand::MorphWeight4,
5 => GeCommand::MorphWeight5,
6 => GeCommand::MorphWeight6,
7 => GeCommand::MorphWeight7,
_ => core::intrinsics::unreachable(),
};
send_command_f(cmd, weight);
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDrawArrayN(
primitive_type: GuPrimitive,
v_type: VertexType,
count: i32,
a3: i32,
indices: *const c_void,
vertices: *const c_void,
) {
if !v_type.is_empty() {
send_command_i(GeCommand::VertexType, v_type.bits());
}
if !indices.is_null() {
send_command_i(GeCommand::Base, ((indices as u32) >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Iaddr, indices as i32 & 0xffffff);
}
if !vertices.is_null() {
send_command_i(GeCommand::Base, ((vertices as u32) >> 8) as i32 & 0xf0000);
send_command_i(GeCommand::Vaddr, vertices as i32 & 0xffffff);
}
if a3 > 0 {
for _ in 1..a3 {
send_command_i(GeCommand::Prim, ((primitive_type as i32) << 16) | count);
}
send_command_i_stall(GeCommand::Prim, ((primitive_type as i32) << 16) | count);
}
}
static mut CHAR_BUFFER_USED: u32 = 0;
static mut CHAR_BUFFER: [DebugCharStruct; 2048] = [DebugCharStruct {
x: 0,
y: 0,
color: 0,
character: b'\0',
unused: [0, 0, 0],
}; 2048];
static FONT: [u8; 768] = *include_bytes!("./debugfont.bin");
#[repr(C, packed)]
#[derive(Copy, Clone)]
struct DebugCharStruct {
x: i32,
y: i32,
color: u32,
character: u8,
unused: [u8; 3],
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDebugPrint(x: i32, mut y: i32, mut color: u32, mut msg: *const u8) {
let mut cur_char: u8;
let mut uVar1: u32;
let iVar2: i32;
let mut cur_x: i32;
let mut char_struct_ptr: *mut DebugCharStruct =
addr_of_mut!(CHAR_BUFFER).cast::<DebugCharStruct>();
let mut i = CHAR_BUFFER_USED;
if i >= 0x3ff {
return;
}
uVar1 = color >> 8 & 0xff;
let uVar3 = color >> 16 & 0xff;
let iVar4 = (uVar3 >> 3) as i32;
cur_x = x;
match DRAW_BUFFER.pixel_size {
DisplayPixelFormat::Psm5650 => {
iVar2 = (uVar1 as i32) >> 2;
uVar1 = (iVar4 as u32) << 0xb;
uVar1 = (uVar1 | iVar2 as u32) << 5;
color = (color & 0xff) >> 3;
color |= uVar1;
}
DisplayPixelFormat::Psm5551 => {
iVar2 = (uVar1 >> 3) as i32;
uVar1 = ((color >> 24) >> 7) << 0xf | (iVar4 as u32) << 10;
uVar1 = (uVar1 | iVar2 as u32) << 5;
color = (color & 0xff) >> 3;
color |= uVar1;
}
DisplayPixelFormat::Psm8888 => {}
DisplayPixelFormat::Psm4444 => {
uVar1 = ((color >> 0x18) >> 4) << 0xc | (uVar3 >> 4) << 8 | (uVar1 >> 4) << 4;
color &= 0xff >> 4;
color |= uVar1;
}
}
cur_char = *msg;
while cur_char != b'\0' {
if cur_char == b'\n' {
y += 8;
cur_x = x;
} else {
(*char_struct_ptr).x = cur_x;
i += 1;
(*char_struct_ptr).character = cur_char - 0x20;
(*char_struct_ptr).y = y;
(*char_struct_ptr).color = color;
char_struct_ptr = (char_struct_ptr as u32 + 16) as *mut DebugCharStruct;
cur_x += 8;
}
msg = msg.add(1);
cur_char = *msg;
}
CHAR_BUFFER_USED = i;
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn sceGuDebugFlush() {
let edram_address = GE_EDRAM_ADDRESS;
let mut pixel_size: DisplayPixelFormat;
let mut frame_width: i32;
let mut frame_buffer: *mut c_void;
let draw_buffer_height = DRAW_BUFFER.height;
let mut char_index: i32;
let mut pos: i32;
let mut x_pixel_counter: i32;
let mut glyph_pos: u32 = 0;
let mut color: u32;
let mut font_glyph: u32 = 0;
let mut y_pixel_counter: i32;
let mut x: i32;
let mut char_buffer_used = CHAR_BUFFER_USED;
let mut y: i32;
let mut char_struct_ptr: *mut DebugCharStruct =
addr_of_mut!(CHAR_BUFFER).cast::<DebugCharStruct>();
if char_buffer_used != 0 {
loop {
frame_buffer = DRAW_BUFFER.frame_buffer;
frame_width = DRAW_BUFFER.frame_width;
pixel_size = DRAW_BUFFER.pixel_size;
y = (*char_struct_ptr).y;
x = (*char_struct_ptr).x;
if (y + 7 < draw_buffer_height)
&& (((x + 7 < DRAW_BUFFER.width) as i32 & !y >> 0x1f) != 0)
&& -1 < x
{
color = (*char_struct_ptr).color;
char_index = ((*char_struct_ptr).character) as i32 * 8;
y_pixel_counter = 0;
loop {
if y_pixel_counter == 0 {
font_glyph =
*(((&FONT as *const _ as u32) + char_index as u32) as *const u32);
glyph_pos = 1;
} else if y_pixel_counter == 4 {
font_glyph =
*(((&FONT as *const _ as u32) + 4 + char_index as u32) as *const u32);
glyph_pos = 1
}
x_pixel_counter = 7;
pos = x + (y + y_pixel_counter) * frame_width;
pos = pos * 4 + edram_address as i32 + frame_buffer as i32;
loop {
match pixel_size {
DisplayPixelFormat::Psm8888 => {
if font_glyph & glyph_pos != 0 {
*((pos as u32 + 0x4000_0000) as *mut u32) = color;
}
}
_ => {
*((pos as u32 + 0x4000_0002) as *mut u16) = color as u16;
}
}
x_pixel_counter -= 1;
glyph_pos <<= 1;
pos += 4;
if x_pixel_counter <= -1 {
break;
}
}
y_pixel_counter += 1;
if 8 <= y_pixel_counter {
break;
}
}
}
char_buffer_used -= 1;
char_struct_ptr = ((char_struct_ptr as u32) + 16) as *mut DebugCharStruct;
if char_buffer_used == 0 {
break;
}
}
CHAR_BUFFER_USED = 0;
}
}