Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
293 lines
8.8 KiB
C
293 lines
8.8 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// Multi-directionnal scrolling sample
|
|
//
|
|
// Scrolling parameters (source data format, output window and used fetaures)
|
|
// are defined in msxgl_config.h for optimization purpose (the 'scroll' module
|
|
// is optimized at compile time to useonly necessary features).
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
#include "msxgl.h"
|
|
#include "math.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x02\x03\x04\x05"
|
|
|
|
#define SPLIT_LINE (106 - 5)
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Fonts
|
|
#include "font/font_mgl_sample8.h"
|
|
// Tiles
|
|
#include "content/tile/data_tile_gm2.h"
|
|
#include "content/tile/data_map_gm2.h"
|
|
// Sprites by GrafxKid (https://opengameart.org/content/super-random-sprites)
|
|
#include "content/data_sprt_layer.h"
|
|
|
|
// Ball sprite data
|
|
const u8 g_BallColor[8] = { COLOR_WHITE, COLOR_LIGHT_GREEN, COLOR_LIGHT_RED, COLOR_LIGHT_YELLOW, COLOR_LIGHT_BLUE, COLOR_MEDIUM_GREEN, COLOR_MEDIUM_RED, COLOR_MAGENTA };
|
|
const u8 g_BallPattern[] =
|
|
{
|
|
// ======== Frame[0]
|
|
// ---- Layer[0] (16x16 0,0 1,1 inc 2)
|
|
// Sprite[0] (offset:0)
|
|
0x07, /* .....### */
|
|
0x1F, /* ...##### */
|
|
0x3F, /* ..###### */
|
|
0x7F, /* .####### */
|
|
0x7F, /* .####### */
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
// Sprite[1] (offset:8)
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
0x7F, /* .####### */
|
|
0x7F, /* .####### */
|
|
0x3F, /* ..###### */
|
|
0x1F, /* ...##### */
|
|
0x07, /* .....### */
|
|
// Sprite[2] (offset:16)
|
|
0xE0, /* ###..... */
|
|
0xF8, /* #####... */
|
|
0xFC, /* ######.. */
|
|
0xFE, /* #######. */
|
|
0xFE, /* #######. */
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
// Sprite[3] (offset:24)
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
0xFF, /* ######## */
|
|
0xFE, /* #######. */
|
|
0xFE, /* #######. */
|
|
0xFC, /* ######.. */
|
|
0xF8, /* #####... */
|
|
0xE0, /* ###..... */
|
|
};
|
|
|
|
// SAT double buffer address
|
|
const u16 g_SATAddr[] = { 0x5200, 0x5600 };
|
|
|
|
// Bank data
|
|
const c8 g_FillChar[] = { 10, 185, 156, 142 };
|
|
const c8 g_FillColor[] = { 0x3C, 0x74, 0x96, 0xFE };
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
struct VDP_Sprite g_SpriteData[29*2];
|
|
|
|
// Screen mode setting index
|
|
u8 g_VBlank = 0;
|
|
u8 g_Frame = 0;
|
|
|
|
//=============================================================================
|
|
// HELPER FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// V-blank interruption handler (called from the ISR)
|
|
void VDP_InterruptHandler()
|
|
{
|
|
g_VBlank = 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Wait for V-Blank period
|
|
void WaitVBlank()
|
|
{
|
|
while (g_VBlank == 0) {} // Wait for ISR to be executed
|
|
|
|
g_VBlank = 0;
|
|
g_Frame++;
|
|
VDP_SetSpriteAttributeTable(g_SATAddr[0]);
|
|
VDP_SetColor(COLOR_DARK_BLUE);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// H-blank interruption handler (called from the ISR)
|
|
void VDP_HBlankHandler()
|
|
{
|
|
VDP_SetSpriteAttributeTable(g_SATAddr[1]);
|
|
VDP_SetColor(COLOR_LIGHT_BLUE);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set screen mode
|
|
void SetScreenMode(u8 mode)
|
|
{
|
|
VDP_SetMode(mode); // Screen mode 4 (G3) with mirrored pattern/color table
|
|
VDP_SetLineCount(VDP_LINE_212);
|
|
VDP_SetPatternTable(0x0000);
|
|
VDP_SetColorTable(0x2000);
|
|
VDP_SetLayoutTable(0x4000);
|
|
VDP_SetSpritePatternTable(0x4800);
|
|
VDP_SetSpriteAttributeTable(g_SATAddr[0]);
|
|
}
|
|
|
|
//=============================================================================
|
|
// MAIN LOOP
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
void main()
|
|
{
|
|
BIOS_SetKeyClick(FALSE);
|
|
|
|
// Initialize video
|
|
SetScreenMode(VDP_MODE_GRAPHIC3_MIRROR); // Screen mode 4 (G3) with full mirrored pattern/color table
|
|
VDP_SetColor(0xF5);
|
|
VDP_ClearVRAM();
|
|
|
|
// Generate tiles data
|
|
u16 addr = VDP_GetColorTable();
|
|
for (u8 bank = 0; bank < 4; ++bank)
|
|
{
|
|
VDP_LoadBankPattern_GM2(g_Font_MGL_Sample8 + 4 + 8 * g_FillChar[bank], 1, bank, 1); // Load 1 character at index 1
|
|
VDP_FillVRAM(g_FillColor[bank], addr, 0, 256 * 8); // Fill bank color
|
|
addr += 256 * 8;
|
|
}
|
|
|
|
// Generate layout
|
|
addr = VDP_GetLayoutTable();
|
|
for (u16 i = 0; i < 32*32; ++i)
|
|
{
|
|
if ((i >= 32 * 3) && !(i & 0x20))
|
|
VDP_Poke(i & 0x01, addr, 0);
|
|
addr++;
|
|
}
|
|
|
|
// Initialize text
|
|
g_PrintData.PatternOffset = 32;
|
|
Print_SetFontEx(8, 8, 1, 1, 32, 127, g_Font_MGL_Sample8 + 32 * 8 + 4);
|
|
Print_Initialize();
|
|
Print_SetMode(PRINT_MODE_TEXT);
|
|
VDP_LoadBankPattern_GM2(g_PrintData.FontPatterns, g_PrintData.CharCount, 0, 32); // Load data to VRAM
|
|
// Print header
|
|
Print_DrawTextAt(0, 0, "MSXgl - GM3 SAMPLE");
|
|
Print_DrawTextAt(0, 1, " [1]:Mirror 0 [2]:Mirror 01");
|
|
Print_DrawTextAt(0, 2, " [3]:Mirror 02 [4]:No mirror");
|
|
|
|
// Initialize sprite
|
|
u8 X = 100, Y = 100;
|
|
VDP_EnableSprite(TRUE);
|
|
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_16);
|
|
VDP_LoadSpritePattern(g_BallPattern, 0, 4);
|
|
VDP_LoadSpritePattern(g_DataSprtLayer, 8*4, 13*4*4);
|
|
|
|
loop (s, 2)
|
|
{
|
|
g_SpriteAttributeLow = g_SATAddr[s];
|
|
g_SpriteAttributeHigh = 0;
|
|
g_SpriteColorLow = g_SpriteAttributeLow - 0x200;
|
|
g_SpriteColorHigh = 0;
|
|
|
|
VDP_SetSpriteExUniColor(0, X, Y, 32, COLOR_BLACK);
|
|
VDP_SetSpriteExUniColor(1, X, Y, 36, COLOR_WHITE);
|
|
VDP_SetSpriteExUniColor(2, X, Y, 40, COLOR_LIGHT_RED);
|
|
|
|
for (u8 i = 3; i < 32; ++i)
|
|
{
|
|
u8 idx = i - 3 + (s * 29);
|
|
struct VDP_Sprite* sprt = &g_SpriteData[idx];
|
|
sprt->X = Math_GetRandom8();
|
|
sprt->Y = (106 - 16) * (i - 3) / 29 /*Math_GetRandom8() % (106 - 16)*/ + (s * 106);
|
|
sprt->Pattern = 0;
|
|
sprt->Color = g_BallColor[Math_GetRandom8() % 8];
|
|
VDP_SetSpriteExUniColor(i, sprt->X, sprt->Y, sprt->Pattern, sprt->Color);
|
|
}
|
|
}
|
|
|
|
// Interruption
|
|
VDP_EnableVBlank(TRUE);
|
|
VDP_EnableHBlank(TRUE);
|
|
|
|
u8 shape = 6;
|
|
u8 prevRow8 = 0xFF;
|
|
while (1)
|
|
{
|
|
// Wait for v-synch
|
|
WaitVBlank();
|
|
VDP_SetHBlankLine(SPLIT_LINE + g_Frame);
|
|
VDP_SetVerticalOffset(g_Frame);
|
|
|
|
loop (s, 2)
|
|
{
|
|
// Update SAT address
|
|
g_SpriteAttributeLow = g_SATAddr[s];
|
|
g_SpriteAttributeHigh = 0;
|
|
g_SpriteColorLow = g_SpriteAttributeLow - 0x200;
|
|
g_SpriteColorHigh = 0;
|
|
|
|
// Update player sprites
|
|
u8 y = Y + g_Frame;
|
|
if (y == 216)
|
|
y++;
|
|
VDP_SetSprite(0, X, y, 32 + shape * 16);
|
|
VDP_SetSprite(1, X, y, 36 + shape * 16);
|
|
VDP_SetSprite(2, X, y, 40 + shape * 16);
|
|
|
|
// Update balloon sprites
|
|
for (u8 i = 3; i < 32; ++i)
|
|
{
|
|
u8 idx = i - 3;
|
|
if (s)
|
|
idx += 29;
|
|
struct VDP_Sprite* sprt = &g_SpriteData[idx];
|
|
u8 y = sprt->Y + g_Frame;
|
|
if (y == 216)
|
|
y++;
|
|
VDP_SetSpritePositionY(i, y);
|
|
}
|
|
}
|
|
|
|
u8 row0 = Keyboard_Read(0);
|
|
if (IS_KEY_PRESSED(row0, KEY_1))
|
|
SetScreenMode(VDP_MODE_GRAPHIC3_MIRROR_0);
|
|
if (IS_KEY_PRESSED(row0, KEY_2))
|
|
SetScreenMode(VDP_MODE_GRAPHIC3_MIRROR_01);
|
|
if (IS_KEY_PRESSED(row0, KEY_3))
|
|
SetScreenMode(VDP_MODE_GRAPHIC3_MIRROR_02);
|
|
if (IS_KEY_PRESSED(row0, KEY_4))
|
|
SetScreenMode(VDP_MODE_GRAPHIC3);
|
|
|
|
shape = 6;
|
|
u8 row8 = Keyboard_Read(8);
|
|
// Update horizontal scrolling offset
|
|
if (IS_KEY_PRESSED(row8, KEY_RIGHT))
|
|
{
|
|
X++;
|
|
shape = (g_Frame >> 2) % 6;
|
|
}
|
|
else if (IS_KEY_PRESSED(row8, KEY_LEFT))
|
|
{
|
|
X--;
|
|
shape = (g_Frame >> 2) % 6;
|
|
}
|
|
if (IS_KEY_PRESSED(row8, KEY_DOWN))
|
|
{
|
|
Y++;
|
|
shape = (g_Frame >> 2) % 6;
|
|
}
|
|
else if (IS_KEY_PRESSED(row8, KEY_UP))
|
|
{
|
|
Y--;
|
|
shape = (g_Frame >> 2) % 6;
|
|
}
|
|
prevRow8 = row8;
|
|
}
|
|
} |