// SPDX-License-Identifier: CC0-1.0
//
// SPDX-FileContributor: Antonio Niño Díaz, 2024-2026

#include <nds.h>

// This is autogenerated from forest.png and forest.grit
#include "forest.h"

int main(int argc, char *argv[])
{
    videoSetMode(MODE_0_2D);

    vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD);

    // Setup background layer

    int bg = bgInitHidden(0, BgType_Text4bpp, BgSize_T_256x256, 0, 1);

    memcpy(bgGetGfxPtr(bg), forestTiles, forestTilesLen);
    memcpy(BG_PALETTE, forestPal, forestPalLen);

    // Load map

    u16 *vram_map = bgGetMapPtr(bg);

    const u32 metatile_width = 2;
    const u32 metatile_height = 2;
    const u32 metatile_size = metatile_width * metatile_height;

    const u32 metamap_width = 16;
    __attribute__((unused)) const u32 metamap_height = 16;

    // The original map size is 32x32 tiles.
    //
    // The metamap size is 16x16 metatiles, each metatile size is 2x2 tiles.
    //
    // forestMetaMap[] is a 16x16 map in which each entry is a metatile index.
    //
    // forestMetaTiles[] is an array of metatiles. There are 2x2 tiles in each
    // metatile. If you want to access the 4 tiles of a specific metatile you
    // need to access the 4 bytes starting at "index * 4".

    for (u32 ty = 0; ty < 32; ty++)
    {
        for (u32 tx = 0; tx < 32; tx++)
        {
            // (tx, ty) = Tile in VRAM to modify

            u32 mx = tx / metatile_width;
            u32 my = ty / metatile_height;

            // (mx, my) = Metatile of the map we need to read

            u16 meta_map_entry = forestMetaMap[my * metamap_width + mx];

            // meta_map_entry is the metatile index

            const u16 *meta_tile = &forestMetaTiles[meta_map_entry * metatile_size];

            // meta_tile points to the 4 tiles that form that metatile

            u32 mtx = tx % metatile_width;
            u32 mty = ty % metatile_height;

            // (mtx, mty) = Position inside the metatile

            u16 tile = meta_tile[mty * metatile_width + mtx];

            vram_map[ty * 32 + tx] = tile;
        }
    }

    // Display background when all of its data is ready

    bgShow(bg);

    consoleDemoInit();

    printf("PAD:   Scroll background\n");
    printf("START: Exit to loader\n");

    int x = 0, y = 0;

    while (1)
    {
        swiWaitForVBlank();

        bgSetScroll(bg, x, y);

        bgUpdate();

        scanKeys();

        u16 keys_held = keysHeld();

        if (keys_held & KEY_UP)
            y--;
        else if (keys_held & KEY_DOWN)
            y++;

        if (keys_held & KEY_LEFT)
            x--;
        else if (keys_held & KEY_RIGHT)
            x++;

        if (keys_held & KEY_START)
            break;
    }

    return 0;
}
