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

// This example shows how to use 256-color sprites that use different palettes
// thanks to extended palettes.

#include <nds.h>

// This is autogenerated from ruin.png, ruin.grit, statue.png and statue.grit
#include "ruin.h"
#include "statue.h"

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

    // VRAM_C is used by consoleDemoInit()
    vramSetPrimaryBanks(VRAM_A_MAIN_SPRITE, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_SUB_SPRITE);

    consoleDemoInit();

    // Initialize sprites with extended palettes active
    oamInit(&oamMain, SpriteMapping_Bmp_1D_128, true);
    oamInit(&oamSub, SpriteMapping_Bmp_1D_128, true);

    // Allocate space for the tiles and copy them there
    u16 *gfx256ExtMainStatue = oamAllocateGfx(&oamMain, SpriteSize_64x64, SpriteColorFormat_256Color);
    memcpy(gfx256ExtMainStatue, statueTiles, statueTilesLen);

    u16 *gfx256ExtMainRuin = oamAllocateGfx(&oamMain, SpriteSize_64x64, SpriteColorFormat_256Color);
    memcpy(gfx256ExtMainRuin, ruinTiles, ruinTilesLen);

    u16 *gfx256ExtSubStatue = oamAllocateGfx(&oamSub, SpriteSize_64x64, SpriteColorFormat_256Color);
    memcpy(gfx256ExtSubStatue, statueTiles, statueTilesLen);

    u16 *gfx256ExtSubRuin = oamAllocateGfx(&oamSub, SpriteSize_64x64, SpriteColorFormat_256Color);
    memcpy(gfx256ExtSubRuin, ruinTiles, ruinTilesLen);

    const int spr_pal_main_statue = 3;
    const int spr_pal_main_ruin = 7;

    const int spr_pal_sub_statue = 4;
    const int spr_pal_sub_ruin = 5;

    // Map VRAM as LCD because it can't be accessed by the CPU while it is
    // mapped as extended palette VRAM.
    vramSetBankF(VRAM_F_LCD);
    vramSetBankI(VRAM_I_LCD);

    // Copy palettes
    memcpy(VRAM_F_EXT_SPR_PALETTE[spr_pal_main_statue], statuePal, statuePalLen);
    memcpy(VRAM_F_EXT_SPR_PALETTE[spr_pal_main_ruin], ruinPal, ruinPalLen);

    memcpy(VRAM_I_EXT_SPR_PALETTE[spr_pal_sub_statue], statuePal, statuePalLen);
    memcpy(VRAM_I_EXT_SPR_PALETTE[spr_pal_sub_ruin], ruinPal, ruinPalLen);

    // Map some VRAM to be used as extended palettes
    vramSetBankF(VRAM_F_SPRITE_EXT_PALETTE);
    vramSetBankI(VRAM_I_SUB_SPRITE_EXT_PALETTE);

    oamSet(&oamMain, 0,
           150, 70, // X, Y
           0, // Priority
           spr_pal_main_statue, // Palette index
           SpriteSize_64x64, SpriteColorFormat_256Color, // Size, format
           gfx256ExtMainStatue, // Graphics offset
           -1, // Affine index
           false, // Double size
           false, // Hide
           false, false, // H flip, V flip
           false); // Mosaic

    oamSet(&oamMain, 1,
           10, 20, // X, Y
           0, // Priority
           spr_pal_main_ruin, // Palette index
           SpriteSize_64x64, SpriteColorFormat_256Color, // Size, format
           gfx256ExtMainRuin, // Graphics offset
           -1, // Affine index
           false, // Double size
           false, // Hide
           false, false, // H flip, V flip
           false); // Mosaic

    oamSet(&oamSub, 0,
           10, 70, // X, Y
           0, // Priority
           spr_pal_sub_statue, // Palette index
           SpriteSize_64x64, SpriteColorFormat_256Color, // Size, format
           gfx256ExtSubStatue, // Graphics offset
           -1, // Affine index
           false, // Double size
           false, // Hide
           false, false, // H flip, V flip
           false); // Mosaic

    oamSet(&oamSub, 1,
           100, 70, // X, Y
           0, // Priority
           spr_pal_sub_ruin, // Palette index
           SpriteSize_64x64, SpriteColorFormat_256Color, // Size, format
           gfx256ExtSubRuin, // Graphics offset
           -1, // Affine index
           false, // Double size
           false, // Hide
           false, false, // H flip, V flip
           false); // Mosaic

    printf("PAD:   Move sprite\n");
    printf("START: Exit to loader\n");

    int x = 150, y = 70;

    while (1)
    {
        swiWaitForVBlank();

        oamSetXY(&oamMain, 0, x, y);

        oamUpdate(&oamMain);
        oamUpdate(&oamSub);

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

    oamFreeGfx(&oamMain, gfx256ExtMainStatue);
    oamFreeGfx(&oamMain, gfx256ExtMainRuin);

    oamFreeGfx(&oamSub, gfx256ExtSubStatue);
    oamFreeGfx(&oamSub, gfx256ExtSubRuin);

    return 0;
}
