dotzuki-engine 0.1.0

A general-purpose JRPG game engine built from Game Boy tile rendering principles
Documentation
use super::{
    facing_table_index, sprite_tile_base_offset, FACING_END, NUM_SPRITESTATEDATA_STRUCTS,
    OAM_BG_PRIORITY, OAM_COUNT, OAM_X_OFS, OAM_Y_OFS, SPRITE_FACING_TABLE, UNDER_GRASS,
    OamEntry, SpriteTable,
};

const OAM_ENTRIES_PER_SPRITE: usize = 4;
const PRESERVED_OAM_ENTRIES: usize = 4;

pub fn prepare_oam_data(table: &mut SpriteTable, screen_height: u8) {
    let preserve_count = if table.ledge_or_fishing {
        PRESERVED_OAM_ENTRIES
    } else {
        0
    };
    let max_oam = OAM_COUNT - preserve_count;
    let mut oam_idx = 0;

    for sprite_idx in 0..NUM_SPRITESTATEDATA_STRUCTS {
        if oam_idx + OAM_ENTRIES_PER_SPRITE > max_oam {
            break;
        }

        let sd1 = &table.data1[sprite_idx];
        if !sd1.is_active() || !sd1.is_visible() {
            continue;
        }

        let sd2 = &table.data2[sprite_idx];
        let facing_idx = facing_table_index(sd1.image_index);
        if facing_idx >= SPRITE_FACING_TABLE.len() {
            continue;
        }

        let entry = &SPRITE_FACING_TABLE[facing_idx];
        let tile_base = sprite_tile_base_offset(sd1.image_index);
        let grass_attr = if sd2.has_grass_priority() {
            OAM_BG_PRIORITY
        } else {
            0
        };

        write_oam_block(
            &mut table.shadow_oam.entries,
            &mut oam_idx,
            sd1.y_pixels,
            sd1.x_pixels,
            tile_base,
            entry.tile_pattern,
            entry.oam_template,
            grass_attr,
        );
    }

    table.oam_count = oam_idx;

    for i in oam_idx..max_oam {
        table.shadow_oam.entries[i].y = OAM_Y_OFS + screen_height;
    }
}

fn write_oam_block(
    oam: &mut [OamEntry; OAM_COUNT],
    oam_idx: &mut usize,
    sprite_y: u8,
    sprite_x: u8,
    tile_base: u8,
    tile_pattern: &super::SpriteTilePattern,
    oam_template: &[super::OamTemplate; 4],
    grass_attr: u8,
) {
    for i in 0..OAM_ENTRIES_PER_SPRITE {
        let tmpl = &oam_template[i];
        let entry = &mut oam[*oam_idx];

        entry.y = sprite_y.wrapping_add(OAM_Y_OFS).wrapping_add(tmpl.y_offset);
        entry.x = sprite_x.wrapping_add(OAM_X_OFS).wrapping_add(tmpl.x_offset);
        entry.tile_id = tile_base.wrapping_add(tile_pattern.tiles[i]);

        let mut attr = tmpl.attributes;
        if attr & UNDER_GRASS != 0 {
            attr = (attr & !UNDER_GRASS) | grass_attr;
        }
        attr &= !FACING_END;
        entry.attributes = attr;

        *oam_idx += 1;
    }
}