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

// This example shows how to scroll a background that has a map that is too big
// for the hardware and, in addition, it has more tiles than you can fit in
// VRAM.
//
// As you scroll the background, the engine:
//
// - Loads and unloads tiles dynamically from RAM to VRAM.
// - Loads the parts of the map that appear on the screen from RAM to VRAM.
//
// The map used in this example uses a custom format with no tile flip bits and
// with a 16 bit tile index. This is achieved with "-mB16:i16".
//
// The engine is prepared to load enough tiles to VRAM to fit the whole screen.
// This is possible because the maximum number of tiles for a background is
// 1024, and the maximum number of tiles we may need on the screen at any point
// is smaller than 900 (even if you consider a margin of 2 tiles added to the
// 32x24 tiles you need for one screen).
//
// Most images will have tiles that repeat, so the VRAM usage will never get to
// the maximum possible. However, if you want to stress test the engine, open
// the ".grit" file in the "graphics" folder and disable tile reduction as
// mentioned in the comment: "-mR!"
//
// Note: The debug mode must be used to debug the engine with emulators. Its
// only purpose is to clear VRAM when tiles become unused or when a part of the
// map leaves the screen. This can easily be seen with the debugger no$gba if
// you open the map or tileset windows and leave them next to the main window
// while you move around the map.

#include <nds.h>

#include "debug.h"
#include "map.h"
#include "vram_alloc.h"

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

#define ARKANOS_WIDTH   1280
#define ARKANOS_HEIGHT  1280

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

    videoSetMode(MODE_0_2D);

    vramSetBankA(VRAM_A_MAIN_BG);

    printf("PAD:    Scroll background\n");
    printf("SELECT: Jump to random position\n");
    printf("A:      Enable debug mode\n");
    printf("B:      Disable debug mode\n");
    printf("\n");
    printf("START:  Exit to loader\n");

    map_load(0,    // Background layer
             0, 1, // Map base, tile base
             arkanosMap,                    // Map data
             ARKANOS_WIDTH, ARKANOS_HEIGHT, // Map dimensions in pixels
             arkanosTiles, arkanosTilesLen, // Tile data and size
             arkanosPal, arkanosPalLen);    // Palette data and size

    // Start at an arbitrary position to show that it's a possibility
    map_set_position(30, 15);

    while (1)
    {
        swiWaitForVBlank();

        map_refresh_scroll();

        bgUpdate();

        consoleSetCursor(NULL, 0, 8);
        printf("Tiles allocated: %3d / %3d",
               vram_tiles_get_count_used(), vram_tiles_get_count_max());

        scanKeys();

        u16 keys_held = keysHeld();
        u16 keys_down = keysDown();

        // Do player scroll
        if (keys_held & KEY_UP)
            map_scroll_y(-3);
        else if (keys_held & KEY_DOWN)
            map_scroll_y(3);

        if (keys_held & KEY_LEFT)
            map_scroll_x(-3);
        else if (keys_held & KEY_RIGHT)
            map_scroll_x(3);

        if (keys_down & KEY_SELECT)
        {
            int x = rand() % map_get_max_scroll_x();
            int y = rand() % map_get_max_scroll_y();
            map_set_position(x, y);
        }

        if (keys_held & KEY_A)
            debug_mode_enable(true);
        else if (keys_held & KEY_B)
            debug_mode_enable(false);

        if (keys_held & KEY_START)
            break;
    }

    return 0;
}
