gsa 0.2.1

Game development library modelled after an imaginary console
Documentation
use crate::{
    Background, Gsa, Rgb, BACKGROUND_MAX_SIZE, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS,
    SCREEN_HEIGHT, SCREEN_WIDTH, TILESET_SIZE, TILE_SIZE, TRANSPARENT,
};
use glam::IVec2;
use softbuffer::Buffer;

fn draw_tile(target: &mut [u8], pos: IVec2, tile: u16, tileset: &[u8], half: bool) {
    let tilesize = if half { HALF_TILE_SIZE } else { TILE_SIZE };
    let tx = tile as usize % 0x100 * tilesize;
    let ty = tile as usize / 0x100 * tilesize;
    let startx = pos.x.max(0).min(SCREEN_WIDTH as i32);
    let starty = pos.y.max(0).min(SCREEN_HEIGHT as i32);
    let endx = (pos.x + tilesize as i32).max(0).min(SCREEN_WIDTH as i32);
    let endy = (pos.y + tilesize as i32).max(0).min(SCREEN_HEIGHT as i32);
    for y in (starty - pos.y)..(endy - pos.y) {
        for x in (startx - pos.x)..(endx - pos.x) {
            let p = tileset[(x as usize + tx) + (y as usize + ty) * (TILESET_SIZE * TILE_SIZE)];
            if p != TRANSPARENT {
                target[(x as usize + pos.x as usize)
                    + (y as usize + pos.y as usize) * SCREEN_WIDTH] = p;
            }
        }
    }
}

fn render_map(target: &mut [u8], map: &Background, tileset: &[u8]) {
    let tcmult = if map.half_tile { 2 } else { 1 };
    let tilesize = if map.half_tile {
        HALF_TILE_SIZE
    } else {
        TILE_SIZE
    } as i32;
    let mut startx = map.scroll.x / tilesize;
    let mut starty = map.scroll.y / tilesize;
    let endx = (BACKGROUND_MAX_SIZE as i32).min(startx + 20 * tcmult);
    let endy = (BACKGROUND_MAX_SIZE as i32).min(starty + 12 * tcmult);
    startx = 0.max(startx);
    starty = 0.max(starty);
    for x in startx..endx {
        for y in starty..endy {
            let tile = map.tiles[x as usize][y as usize];
            if tile != EMPTY_TILE {
                draw_tile(
                    target,
                    IVec2 {
                        x: x * tilesize - map.scroll.x,
                        y: y * tilesize - map.scroll.y,
                    },
                    tile,
                    tileset,
                    map.half_tile,
                );
            }
        }
    }
}

pub(crate) fn render_to_screen(target: &mut [u8], gsa: &Gsa, tileset: &[u8]) {
    for i in 0..MAX_BACKGROUNDS {
        render_map(target, &gsa.bgs[i], tileset);
        for sprite in &gsa.sprites {
            if sprite.tile != EMPTY_TILE && sprite.priority == i as u8 {
                draw_tile(target, sprite.pos, sprite.tile, tileset, false);
            }
        }
    }
}

pub(crate) fn render_to_window(
    target: &mut Buffer,
    src: &mut [u8],
    palette: &[Rgb; 256],
    window_size: IVec2,
    scale: usize,
    off_x: usize,
    off_y: usize,
) {
    let start = window_size.x as usize * off_y;
    let end = start + window_size.x as usize * SCREEN_HEIGHT * scale;
    for (y, row) in target[start..end]
        .chunks_exact_mut(window_size.x as usize * scale)
        .enumerate()
    {
        let y = y as i32;
        for x in 0..SCREEN_WIDTH {
            let p = src[x + y as usize * SCREEN_WIDTH];

            for scaley in 0..scale {
                for scalex in 0..scale {
                    let sx = x * scale + scalex;
                    row[sx + off_x + scaley * window_size.x as usize] =
                        palette[p as usize].to_u32();
                }
            }

            //unrolled is faster benchmarked... <_<
            /*
            let ww = window_size.x as usize;
            match scale {
                1 => {
                    row[x + off_x] = palette[p as usize].to_u32();
                }
                2 => {
                    row[x * 2 + off_x] = palette[p as usize].to_u32();
                    row[x * 2 + off_x + 1] = palette[p as usize].to_u32();
                    row[x * 2 + off_x + ww] = palette[p as usize].to_u32();
                    row[x * 2 + off_x + ww + 1] = palette[p as usize].to_u32();
                }
                6 => {
                    row[x * 6 + off_x + ww * 0] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 0 + 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 0 + 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 0 + 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 0 + 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 0 + 5] = palette[p as usize].to_u32();

                    row[x * 6 + off_x + ww * 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 1 + 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 1 + 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 1 + 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 1 + 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 1 + 5] = palette[p as usize].to_u32();

                    row[x * 6 + off_x + ww * 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 2 + 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 2 + 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 2 + 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 2 + 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 2 + 5] = palette[p as usize].to_u32();

                    row[x * 6 + off_x + ww * 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 3 + 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 3 + 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 3 + 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 3 + 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 3 + 5] = palette[p as usize].to_u32();

                    row[x * 6 + off_x + ww * 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 4 + 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 4 + 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 4 + 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 4 + 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 4 + 5] = palette[p as usize].to_u32();

                    row[x * 6 + off_x + ww * 5] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 5 + 1] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 5 + 2] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 5 + 3] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 5 + 4] = palette[p as usize].to_u32();
                    row[x * 6 + off_x + ww * 5 + 5] = palette[p as usize].to_u32();
                }
                _ => {}
            }
            */
        }
    }
}