Mercurial > touhou
diff 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 diff
new file mode 100644 --- /dev/null +++ b/python/src/glide/gr.rs @@ -0,0 +1,312 @@ +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) }; +}