view python/src/glide/gr.rs @ 772:7492d384d122 default tip

Rust: Add a Glide renderer (2D only for now) This is an experiment for a Rust renderer, iterating over the Python data using pyo3. It requires --feature=glide to be passed to cargo build, doesn’t support NPOT textures, text rendering, the background, or even msg faces, some of that may come in a future changeset.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Mon, 05 Sep 2022 17:53:36 +0200
parents
children
line wrap: on
line source

use core::ptr::null;

#[link(name = "glide2x")]
extern "C" {
    fn grGlideInit();
    fn grGlideShutdown();
    fn grSstSelect(sst: u32);
    fn grSstWinOpen(hwnd: u32, resolution: u32, refresh: u32, color_format: u32, origin_location: u32, num_buf: i32, num_aux_buf: i32);
    fn grBufferSwap(interval: i32);
    fn grBufferClear(color: u32, alpha: u8, depth: u16);
    fn grTexCalcMemRequired(min: Lod, max: Lod, aspect: AspectRatio, format: TextureFormat) -> u32;
    fn grTexDownloadMipMap(tmu: u32, start: u32, even_odd: EvenOdd, info: *const TexInfo);
    fn grTexSource(tmu: u32, start: u32, even_odd: EvenOdd, info: &TexInfo);
    fn grTexMinAddress(tmu: u32) -> u32;
    fn grTexMaxAddress(tmu: u32) -> u32;
    fn guAlphaSource(mode: AlphaSource) -> u32;
    fn guColorCombineFunction(function: ColorCombineFnc) -> u32;
    fn grTexCombineFunction(tmu: u32, function: TextureCombineFnc) -> u32;
    fn grDrawTriangle(a: *const Vertex, b: *const Vertex, c: *const Vertex);
    fn grAlphaBlendFunction(a: Blend, b: Blend, c: Blend, d: Blend);
}

#[repr(i32)]
#[derive(Clone, Copy)]
pub enum Lod {
    L256x256 = 0,
    L128x128 = 1,
    L64x64 = 2,
    L32x32 = 3,
    L16x16 = 4,
    L8x8 = 5,
    L4x4 = 6,
    L2x2 = 7,
    L1x1 = 8,
}

#[repr(i32)]
#[derive(Clone, Copy)]
pub enum AspectRatio {
    A8x1 = 0,
    A4x1 = 1,
    A2x1 = 2,
    A1x1 = 3,
    A1x2 = 4,
    A1x4 = 5,
    A1x8 = 6,
}

fn lod_aspect_from_dimensions(dimensions: (u32, u32)) -> (Lod, AspectRatio) {
    match dimensions {
        (256, 256) => (Lod::L256x256, AspectRatio::A1x1),
        (128, 128) => (Lod::L128x128, AspectRatio::A1x1),
        (64, 64) => (Lod::L64x64, AspectRatio::A1x1),
        (32, 32) => (Lod::L32x32, AspectRatio::A1x1),
        (16, 16) => (Lod::L16x16, AspectRatio::A1x1),
        (8, 8) => (Lod::L8x8, AspectRatio::A1x1),
        (4, 4) => (Lod::L4x4, AspectRatio::A1x1),
        (2, 2) => (Lod::L2x2, AspectRatio::A1x1),
        (1, 1) => (Lod::L1x1, AspectRatio::A1x1),
        (width, height) => todo!("NPOT texture size {width}×{height}"),
    }
}

#[repr(i32)]
#[derive(Clone, Copy, Debug)]
pub enum TextureFormat {
    Rgb332 = 0,
    Yiq422 = 1,
    Alpha8 = 2,
    Intensity8 = 3,
    AlphaIntensity44 = 4,
    P8 = 5,
    Argb8332 = 8,
    Ayiq8422 = 9,
    Rgb565 = 10,
    Argb1555 = 11,
    Argb4444 = 12,
    AlphaIntensity88 = 13,
    Ap88 = 14,
}

#[repr(C)]
pub struct TexInfo {
    pub small_lod: Lod,
    pub large_lod: Lod,
    pub aspect: AspectRatio,
    pub format: TextureFormat,
    data: *const u8,
}

impl TexInfo {
    pub fn new(width: u32, height: u32, format: TextureFormat) -> TexInfo {
        let (lod, aspect) = lod_aspect_from_dimensions((width, height));
        TexInfo {
            small_lod: lod,
            large_lod: lod,
            aspect,
            format,
            data: null(),
        }
    }

    pub fn with_data(width: u32, height: u32, format: TextureFormat, data: &[u8]) -> TexInfo {
        let (lod, aspect) = lod_aspect_from_dimensions((width, height));
        TexInfo {
            small_lod: lod,
            large_lod: lod,
            aspect,
            format,
            data: data.as_ptr(),
        }
    }
}

#[repr(C)]
pub struct Vertex {
    x: f32,
    y: f32,
    z: f32,
    r: f32,
    g: f32,
    b: f32,
    ooz: f32,
    a: f32,
    oow: f32,
    sow0: f32,
    tow0: f32,
    oow0: f32,
    sow1: f32,
    tow1: f32,
    oow1: f32,
}

impl Vertex {
    pub fn new(x: f32, y: f32, sow: f32, tow: f32, color: u32) -> Vertex {
        let z = 1.0;
        let r = ((color >> 24) & 0xff) as f32;
        let g = ((color >> 16) & 0xff) as f32;
        let b = ((color >> 8) & 0xff) as f32;
        let a = (color & 0xff) as f32;
        let ooz = 1.0;
        let oow = 1.0;
        let sow0 = sow;
        let tow0 = tow;
        let oow0 = 1.0;
        let sow1 = sow;
        let tow1 = tow;
        let oow1 = 1.0;
        Vertex {
            x, y, z,
            r, g, b,
            ooz,
            a,
            oow,
            sow0, tow0, oow0,
            sow1, tow1, oow1,
        }
    }
}

pub fn glide_init() {
    unsafe { grGlideInit() };
}

pub fn glide_shutdown() {
    unsafe { grGlideShutdown() };
}

pub fn sst_select(sst: u32) {
    unsafe { grSstSelect(sst) };
}

pub fn sst_win_open(width: u32, height: u32, refresh: u32) {
    let resolution = match (width, height) {
        (320, 200) => 0,
        (320, 240) => 1,
        (400, 256) => 2,
        (512, 384) => 3,
        (640, 200) => 4,
        (640, 350) => 5,
        (640, 400) => 6,
        (640, 480) => 7,
        _ => unreachable!("Unknown screen resolution {width}×{height}."),
    };
    let refresh = match refresh {
        60 => 0,
        70 => 1,
        72 => 2,
        75 => 3,
        80 => 4,
        90 => 5,
        100 => 6,
        85 => 7,
        120 => 8,
        _ => unreachable!("Unknown refresh rate {refresh} Hz."),
    };
    let color_format = 2; // RGBA
    let origin_location = 0; // Upper Left
    unsafe { grSstWinOpen(0, resolution, refresh, color_format, origin_location, 2, 0) };
}

pub fn buffer_swap(interval: i32) {
    unsafe { grBufferSwap(interval) };
}

pub fn buffer_clear(color: u32, alpha: u8, depth: u16) {
    unsafe { grBufferClear(color, alpha, depth) };
}

pub fn tex_calc_mem_required(small_lod: Lod, large_lod: Lod, aspect: AspectRatio, format: TextureFormat) -> u32 {
    unsafe { grTexCalcMemRequired(small_lod, large_lod, aspect, format) }
}

pub fn tex_download_mip_map(tmu: u32, start: u32, even_odd: EvenOdd, info: &TexInfo) {
    unsafe { grTexDownloadMipMap(tmu, start, even_odd, info) };
}

pub fn tex_source(tmu: u32, start: u32, even_odd: EvenOdd, info: &TexInfo) {
    unsafe { grTexSource(tmu, start, even_odd, info) };
}

pub fn tex_min_address(tmu: u32) -> u32 {
    unsafe { grTexMinAddress(tmu) }
}

pub fn tex_max_address(tmu: u32) -> u32 {
    unsafe { grTexMaxAddress(tmu) }
}

pub fn alpha_source(mode: AlphaSource) {
    unsafe { guAlphaSource(mode) };
}

pub fn color_combine_function(function: ColorCombineFnc) {
    unsafe { guColorCombineFunction(function) };
}

pub fn tex_combine_function(tmu: u32, function: TextureCombineFnc) {
    unsafe { grTexCombineFunction(tmu, function) };
}

pub fn alpha_blend_function(a: Blend, b: Blend, c: Blend, d: Blend) {
    unsafe { grAlphaBlendFunction(a, b, c, d) };
}

#[repr(i32)]
pub enum EvenOdd {
    Even = 0,
    Odd = 1,
    Both = 2,
}

#[repr(i32)]
pub enum Blend {
    Zero = 0,
    SrcAlpha = 1,
    SrcColor = 2,
    DstAlpha = 3,
    One = 4,
    OneMinusSrcAlpha = 5,
    OneMinusSrcColor = 6,
    OneMinusDstAlpha = 7,
    AlphaSaturate = 15,
}

#[repr(i32)]
pub enum AlphaSource {
    CcAlpha = 0,
    IteratedAlpha = 1,
    TextureAlpha = 2,
    TextureAlphaTimesIteratedAlpha = 3,
}

#[repr(i32)]
pub enum ColorCombineFnc {
    Zero = 0,
    Ccrgb = 1,
    Itrgb = 2,
    ItrgbDelta0 = 3,
    DecalTexture = 4,
    TextureTimesCcrgb = 5,
    TextureTimesItrgb = 6,
    TextureTimesItrgbDelta0 = 7,
    TextureTimesItrgbAddAlpha = 8,
    TextureTimesAlpha = 9,
    TextureTimesAlphaAddItrgb = 10,
    TextureAddItrgb = 11,
    TextureSubItrgb = 12,
    CcrgbBlendItrgbOnTexalpha = 13,
    DiffSpecA = 14,
    DiffSpecB = 15,
    One = 16,
}

#[repr(i32)]
pub enum TextureCombineFnc {
    Zero = 0,
    Decal = 1,
    Other = 2,
    Add = 3,
    Multiply = 4,
    Subtract = 5,
    Detail = 6,
    DetailOther = 7,
    TrilinearOdd = 8,
    TrilinearEven = 9,
    One = 10,
}

pub fn draw_triangle(a: &Vertex, b: &Vertex, c: &Vertex) {
    unsafe { grDrawTriangle(a, b, c) };
}