Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
318 lines
9.0 KiB
C
318 lines
9.0 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// VDP command sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
|
|
//=============================================================================
|
|
// INCLUDES
|
|
//=============================================================================
|
|
#include "msxgl.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Library's logo
|
|
#define MSX_GL6 "\x01\x02\x03\x04\x05\x06"
|
|
#define MSX_GL8 "\x02\x03\x04\x05"
|
|
// #define GET_OP(a) (g_Operator == 0xFF) ? a : g_Operator
|
|
#define HEIGHT 212
|
|
|
|
// Screen setting
|
|
struct ScreenSetting
|
|
{
|
|
// Setup
|
|
const c8* Name;
|
|
u8 Mode;
|
|
u16 Width;
|
|
u8 BPC;
|
|
// Colors
|
|
u8 Text;
|
|
u8 Background;
|
|
u8 Red;
|
|
u8 White;
|
|
u8 Gray;
|
|
u8 Black;
|
|
// Data
|
|
const u8* Font;
|
|
const u8* Data;
|
|
const u8* DataLMMC;
|
|
const u16* Palette;
|
|
};
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
// Screen mode setting index
|
|
u8 g_SrcModeIndex;
|
|
u8 g_VBlank = 0;
|
|
u8 g_Frame = 0;
|
|
u16 SX0, SY0;
|
|
u16 SX, SY;
|
|
u8 g_Operator = 0xFF; // default
|
|
bool g_bMoving;
|
|
|
|
// Memory buffer to unpack compressed data
|
|
u8 g_LMMC2b_2[32*16*6];
|
|
u8 g_LMMC4b[16*16*6];
|
|
u8 g_LMMC4b_2[32*16*6];
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Fonts
|
|
extern const u8 g_Font_MGL_Sample6[];
|
|
extern const u8 g_Font_MGL_Sample8[];
|
|
|
|
// Bitmaps by GrafxKid (https://opengameart.org/content/super-random-sprites)
|
|
extern const u8 g_DataBmp2b[];
|
|
extern const u8 g_DataBmp4b[];
|
|
extern const u8 g_DataBmp8b[];
|
|
|
|
// Screen mode settings
|
|
const struct ScreenSetting g_Settings[] =
|
|
{ // Name Mode Width BPC Txt BG Red White Gray Black Font Data DataLMMC Palette
|
|
{ MSX_GL6 " SOFTWARE SPRITE SAMPLE (S5/G4)", VDP_MODE_SCREEN5, 256, 4, 0xFF, 0xCC, 0x22, 0x33, 0x11, 0x11, g_Font_MGL_Sample6, g_DataBmp4b, g_LMMC4b, NULL }, // 0
|
|
{ MSX_GL8 " SOFTWARE SPRITE SAMPLE (S6/G5)", VDP_MODE_SCREEN6, 512, 2, 0xFF, 0x00, 0x55, 0xAA, 0xAA, 0x55, g_Font_MGL_Sample8, g_DataBmp2b, g_LMMC2b_2, NULL }, // 1
|
|
{ MSX_GL8 " SOFTWARE SPRITE SAMPLE (S7/G6)", VDP_MODE_SCREEN7, 512, 4, 0xFF, 0xCC, 0x22, 0x33, 0x11, 0x11, g_Font_MGL_Sample8, g_DataBmp4b, g_LMMC4b_2, NULL }, // 2
|
|
{ MSX_GL6 " SOFTWARE SPRITE SAMPLE (S8/G7)", VDP_MODE_SCREEN8, 256, 8, 0xFF, COLOR8_DARKGREEN, COLOR8_GREEN, COLOR8_LIGHTGREEN, 0x6D, 0x00, g_Font_MGL_Sample6, g_DataBmp8b, g_DataBmp8b, NULL }, // 3
|
|
};
|
|
|
|
// Sign-of-life animation
|
|
const u8 chrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
//=============================================================================
|
|
// HELPER FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void BackupBackground()
|
|
{
|
|
const struct ScreenSetting* src = &g_Settings[g_SrcModeIndex];
|
|
u8 pixelWidth = src->Width / 256;
|
|
u8 sprtWidth = pixelWidth * 16;
|
|
|
|
// Backup
|
|
VDP_CommandHMMM(SX * pixelWidth - 2, SY, 0, HEIGHT + 16, sprtWidth + 4, 16);
|
|
|
|
SX0 = SX;
|
|
SY0 = SY;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void InitScreen()
|
|
{
|
|
const struct ScreenSetting* src = &g_Settings[g_SrcModeIndex];
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Setup variables
|
|
u16 blockWidth = src->Width / 16;
|
|
u16 blockBytes = 16 / 8 * src->BPC;
|
|
u16 lineBytes = src->Width / 8 * src->BPC;
|
|
u8 scale = 8 / src->BPC;
|
|
u8 pixelWidth = src->Width / 256;
|
|
u8 sprtWidth = pixelWidth * 16;
|
|
|
|
// Initialize VDP
|
|
VDP_SetMode(src->Mode);
|
|
VDP_SetColor(src->Background);
|
|
VDP_EnableSprite(FALSE);
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Initialize background
|
|
if (src->BPC == 2)
|
|
{
|
|
VDP_SetPaletteEntry(0, RGB16(1, 3, 1));
|
|
VDP_SetPaletteEntry(1, RGB16(1, 5, 1));
|
|
VDP_SetPaletteEntry(2, RGB16(0, 0, 0));
|
|
VDP_SetPaletteEntry(3, RGB16(7, 7, 7));
|
|
}
|
|
else if (src->BPC == 4)
|
|
{
|
|
VDP_SetPaletteEntry(0, COLOR16_DEFAULT_0);
|
|
VDP_SetPaletteEntry(1, COLOR16_DEFAULT_1);
|
|
VDP_SetPaletteEntry(2, COLOR16_DEFAULT_2);
|
|
VDP_SetPaletteEntry(3, COLOR16_DEFAULT_3);
|
|
VDP_SetPaletteEntry(5, RGB16(4, 4, 4));
|
|
}
|
|
VDP_CommandHMMV(0, 0, src->Width, HEIGHT, src->Background);
|
|
for (u8 i = 0; i < 255; ++i)
|
|
{
|
|
u16 x = Math_GetRandom16() % src->Width;
|
|
u16 y = Math_GetRandom16() % (HEIGHT - 24) + 16;
|
|
VDP_CommandLMMV(x, y, pixelWidth, 1, src->Red, VDP_OP_IMP);
|
|
x = Math_GetRandom16() % src->Width;
|
|
y = Math_GetRandom16() % (HEIGHT - 24) + 16;
|
|
VDP_CommandLMMV(x, y, pixelWidth, 1, src->White, VDP_OP_IMP);
|
|
}
|
|
|
|
// Initialize sprite
|
|
VDP_CommandHMMV(0, HEIGHT, sprtWidth * 6, 16, 0);
|
|
for (u8 i = 0; i < 6; ++i)
|
|
{
|
|
VDP_CommandLMMC(src->DataLMMC + i * (16 * 16 * pixelWidth), i * sprtWidth, HEIGHT, sprtWidth, 16, VDP_OP_TIMP);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Initialize font
|
|
Print_SetBitmapFont(src->Font);
|
|
Print_SetColor(src->Text, src->Background);
|
|
|
|
// Display header
|
|
Print_SetPosition(0, 2);
|
|
Print_DrawText(src->Name);
|
|
Draw_LineH(0, src->Width - 1, 12, src->Text, 0);
|
|
|
|
// Display footer
|
|
Print_SetPosition(0, 204);
|
|
Print_DrawText("\x81\x82\x80:Move \x83:Change mode");
|
|
|
|
BackupBackground();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void DisplaySprite()
|
|
{
|
|
const struct ScreenSetting* src = &g_Settings[g_SrcModeIndex];
|
|
u8 pixelWidth = src->Width / 256;
|
|
u8 sprtWidth = pixelWidth * 16;
|
|
|
|
// Restore background at the previous place
|
|
VDP_CommandHMMM(0, HEIGHT + 16, SX0 * pixelWidth - 2, SY0, sprtWidth + 4, 16);
|
|
|
|
// Backup background at the new place
|
|
VDP_CommandHMMM(SX * pixelWidth - 2, SY, 0, HEIGHT + 16, sprtWidth + 4, 16);
|
|
|
|
// Draw the sprite
|
|
u8 frame = g_bMoving ? ((g_Frame / 4) % 6) : 4;
|
|
VDP_CommandLMMM(sprtWidth * frame, HEIGHT, SX * pixelWidth, SY, sprtWidth, 16, VDP_OP_TIMP);
|
|
|
|
SX0 = SX;
|
|
SY0 = SY;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// VBlank interrupt
|
|
void VDP_InterruptHandler()
|
|
{
|
|
g_VBlank = 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Wait for V-Blank period
|
|
void WaitVBlank()
|
|
{
|
|
while (g_VBlank == 0) {}
|
|
g_VBlank = 0;
|
|
g_Frame++;
|
|
}
|
|
|
|
//=============================================================================
|
|
// MAIN LOOP
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
void main()
|
|
{
|
|
// Precalc
|
|
for (u16 i = 0; i < 16*16*6; ++i)
|
|
{
|
|
u8 c, b = g_DataBmp4b[i >> 1];
|
|
if ((i & 0x1) == 0)
|
|
c = b >> 4;
|
|
else // if ((i & 0x1) == 1)
|
|
c = b & 0x0F;
|
|
if (c == 3)
|
|
c = 13;
|
|
g_LMMC4b[i] = c;
|
|
g_LMMC4b_2[2*i+0] = c;
|
|
g_LMMC4b_2[2*i+1] = c;
|
|
}
|
|
for (u16 i = 0; i < 16*16*6; ++i)
|
|
{
|
|
u8 c, b = g_DataBmp2b[i >> 2];
|
|
if ((i & 0x3) == 0)
|
|
c = b >> 6;
|
|
else if ((i & 0x3) == 1)
|
|
c = b >> 4;
|
|
else if ((i & 0x3) == 2)
|
|
c = b >> 2;
|
|
else // if ((i & 0x3) == 3)
|
|
c = b;
|
|
g_LMMC2b_2[2*i+0] = c & 0x03;
|
|
g_LMMC2b_2[2*i+1] = c & 0x03;
|
|
}
|
|
|
|
// Init
|
|
g_SrcModeIndex = 3;
|
|
|
|
SX = 64;
|
|
SY = 64;
|
|
InitScreen();
|
|
|
|
bool bContinue = TRUE;
|
|
while (bContinue)
|
|
{
|
|
WaitVBlank();
|
|
DisplaySprite();
|
|
|
|
const struct ScreenSetting* src = &g_Settings[g_SrcModeIndex];
|
|
Print_SetPosition(src->Width - 8, 2);
|
|
Print_DrawChar(chrAnim[g_Frame & 0x03]);
|
|
|
|
u8 row = Keyboard_Read(KEY_ROW(KEY_DOWN));
|
|
if ((row & KEY_FLAG(KEY_SPACE)) == 0)
|
|
{
|
|
if (g_SrcModeIndex < numberof(g_Settings) - 1)
|
|
g_SrcModeIndex++;
|
|
else
|
|
g_SrcModeIndex = 0;
|
|
InitScreen();
|
|
}
|
|
g_bMoving = FALSE;
|
|
if ((row & KEY_FLAG(KEY_LEFT)) == 0)
|
|
{
|
|
if (SX > 2)
|
|
{
|
|
SX--;
|
|
g_bMoving = TRUE;
|
|
}
|
|
}
|
|
else if ((row & KEY_FLAG(KEY_RIGHT)) == 0)
|
|
{
|
|
if (SX < 256-16-2)
|
|
{
|
|
SX++;
|
|
g_bMoving = TRUE;
|
|
}
|
|
}
|
|
if ((row & KEY_FLAG(KEY_UP)) == 0)
|
|
{
|
|
if (SY > 2)
|
|
{
|
|
SY--;
|
|
g_bMoving = TRUE;
|
|
}
|
|
}
|
|
else if ((row & KEY_FLAG(KEY_DOWN)) == 0)
|
|
{
|
|
if (SY < HEIGHT-16-2)
|
|
{
|
|
SY++;
|
|
g_bMoving = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Keyboard_IsKeyPressed(KEY_ESC))
|
|
bContinue = FALSE;
|
|
}
|
|
} |