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

// This example shows how to set the global tileset and tilemap base steps in
// the DISPCNT register. It configures the character (tileset) base step to 1
// and the screen (tilemap) step to 2. Then it configures a background to use
// map base 0 and tile base 0. Normally they would overlap and cause graphics
// corruption, but the steps make it so that they affect different memory.
//
// Check the following link:
//
//     https://mtheall.com/vram.html#MS=1&TS=2&T0=1&NT0=1024&MB0=0&TB0=0&S0=1
//
// Note that this only affects tilesets and tilemaps. Backgrounds in bitmap mode
// aren't affected by the settings.

#include <nds.h>

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

int main(int argc, char *argv[])
{
    // Make sure to set the two bases before using any other background-related
    // functions like bgGetGfxPtr() or bgGetMapPtr(). They calculate the address
    // by reading DISPCNT internally, so you need to set it to its final setup
    // yourself first.
    videoSetMode(MODE_0_2D | DISPLAY_CHAR_BASE(1) | DISPLAY_SCREEN_BASE(2));

    vramSetPrimaryBanks(VRAM_A_MAIN_BG_0x06000000,
                        VRAM_B_MAIN_BG_0x06020000,
                        VRAM_C_LCD, VRAM_D_LCD);

    // We're going to use 0 as map and tile bases. Normally this would make them
    // overlap and cause the graphics to be corrupted, but we have used
    // different global steps, so they are actually in different places.
    int bg = bgInitHidden(0, BgType_Text8bpp, BgSize_T_512x256,
                          0,  // Map base
                          0); // Tile base

    memcpy(bgGetGfxPtr(bg), forest_townTiles, forest_townTilesLen);
    memcpy(bgGetMapPtr(bg), forest_townMap, forest_townMapLen);
    memcpy(BG_PALETTE, forest_townPal, forest_townPalLen);

    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;
}
