Files
mazegame/projects/samples/s_v9990.c
T

1005 lines
25 KiB
C

// ____________________________
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
// Hello world sample
//─────────────────────────────────────────────────────────────────────────────
#include "msxgl.h"
#include "v9990.h"
#include "math.h"
#include "memory.h"
//=============================================================================
// DEFINES
//=============================================================================
#define CUSTOM_ISR 0
// Library's logo
#define MSX_GL "\x01\x02\x03\x04\x05\x06"
// Display constants
#define V9_GROUND_Y 20
#define V9_HORIZON_Y 14
#define BMP_TILES_Y 256
#define BG_COLOR 14
// Bits per pixel
#define BPP_2 0x02
#define BPP_4 0x04
#define BPP_8 0x08
#define BPP_16 0x10
// Screen mode index (match the g_ScreenMode table)
enum
{
#if (V9_USE_MODE_P1)
MODE_P1,
#endif
#if (V9_USE_MODE_P2)
MODE_P2,
#endif
#if ((V9_USE_MODE_B0) || (V9_USE_MODE_B1) || (V9_USE_MODE_B2) || (V9_USE_MODE_B3) || (V9_USE_MODE_B4) || (V9_USE_MODE_B5) || (V9_USE_MODE_B6) || (V9_USE_MODE_B7))
MODE_B0,
MODE_B1,
MODE_B2,
MODE_B3,
MODE_B4,
MODE_B5,
MODE_B6,
MODE_B7,
#endif
MODE_MAX,
};
// Screen mode structure
struct ScreenMode
{
const c8* Name;
u8 Mode;
callback Init;
callback Tick;
callback Hblank;
u8 BPP;
u16 Width;
u16 Height;
};
// Color mode structure
struct ColorMode
{
const c8* Name;
u8 Mode;
u8 BPP;
u16 ScaneLine;
};
// Function prototypes
void InitP1(); void TickP1(); void HblankP1();
void InitP2(); void TickP2(); void HblankP2();
void InitBmp(); void TickBmp(); void HblankBmp();
//=============================================================================
// READ-ONLY DATA
//=============================================================================
// 1-bit font (VDP)
#include "font/font_mgl_sample6.h"
// 4-bits font (V9990)
#include "content/v9990/data_v9_font.h"
// Sprite
#include "content/v9990/data_v9_chr.h"
// Tiles
#include "content/v9990/data_v9_bg.h"
// Trigo table
#include "mathtable/mt_sin_64.inc"
// Animation characters
const u8 g_ChrAnim[4] = { '|', '\\', '-', '/' };
// Black color
const u8 g_ColorBlack[] = { 0, 0, 0 };
const u8 g_ColorBG[] = { 0x07, 0x12, 0x1C };
// Screen mode configuration
const struct ScreenMode g_ScreenMode[MODE_MAX] =
{
#if (V9_USE_MODE_P1)
{ "P1", V9_MODE_P1, InitP1, TickP1, HblankP1, BPP_4, 256, 212 },
#endif
#if (V9_USE_MODE_P2)
{ "P2", V9_MODE_P2, InitP2, TickP2, HblankP2, BPP_4, 512, 212 },
#endif
#if ((V9_USE_MODE_B0) || (V9_USE_MODE_B1) || (V9_USE_MODE_B2) || (V9_USE_MODE_B3) || (V9_USE_MODE_B4) || (V9_USE_MODE_B5) || (V9_USE_MODE_B6) || (V9_USE_MODE_B7))
{ "B0", V9_MODE_B0, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4|BPP_8|BPP_16, 192, 240 },
{ "B1", V9_MODE_B1, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4|BPP_8|BPP_16, 256, 212 },
{ "B2", V9_MODE_B2, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4|BPP_8|BPP_16, 384, 240 },
{ "B3", V9_MODE_B3, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4|BPP_8|BPP_16, 512, 212 },
{ "B4", V9_MODE_B4, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4, 768, 240 },
{ "B5", V9_MODE_B5, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4, 640, 400 },
{ "B6", V9_MODE_B6, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4, 640, 480 },
{ "B7", V9_MODE_B7, InitBmp, TickBmp, HblankBmp, BPP_2|BPP_4, 1024, 212 },
#endif
};
// Color mode configuration for bitmap modes
const struct ColorMode g_ColorMode[V9_COLOR_BMP_MAX] =
{
{ "BP2", V9_COLOR_BP2, BPP_2, 256 }, // Color palette (4 colors out of 32768 colors)
{ "BP4", V9_COLOR_BP4, BPP_4, 512 }, // Color palette (16 colors out of 32768 colors)
{ "BP6", V9_COLOR_BP6, BPP_8, 1024 }, // Color palette (64 colors out of 32768 colors)
{ "BD8", V9_COLOR_BD8, BPP_8, 1024 }, // Direct RGB [G:3|R:3|B:2] (256 colors)
{ "BYJK", V9_COLOR_BYJK, BPP_8, 1024 }, // YJK Decoder (19268 colors)
{ "BYJKP", V9_COLOR_BYJKP, BPP_8, 1024 }, // YJK Decoder + Color palette (12599 colors + 16 colors out of 32768 colors)
{ "BYUV", V9_COLOR_BYUV, BPP_8, 1024 }, // YUV Decoder (19268 colors)
{ "BYUVP", V9_COLOR_BYUVP, BPP_8, 1024 }, // YUV Decoder + Color palette (12599 colors + 16 colors out of 32768 colors)
{ "BD16", V9_COLOR_BD16, BPP_16, 2048 }, // Direct RGB [YS|G:5|R:2][R:3|B:5] (32768 colors)
};
//=============================================================================
// MEMORY DATA
//=============================================================================
u8 g_CurrentScreen = MODE_P1; // Current screen mode index in the g_ScreenMode table
u8 g_CurrentColor = V9_COLOR_BP4; // Current color mode index in the g_ColorMode table
u16 g_Frame = 0;
bool g_Interlaced = false;
u16 g_TextX;
u16 g_TextY;
bool g_HideSprite = FALSE;
bool g_KeyPressed[256];
//=============================================================================
// CODE
//=============================================================================
void InitPalette()
{
switch (g_ScreenMode[g_CurrentScreen].Mode)
{
case V9_MODE_P1:
case V9_MODE_P2:
V9_SetPaletteEntry(0, g_ColorBlack);
V9_SetPalette(1, 15, g_DataV9BG_palette);
V9_SetPaletteEntry(16, g_ColorBlack);
V9_SetPalette(17, 15, g_DataV9Chr_palette);
V9_SetPaletteEntry(32, g_ColorBlack);
V9_SetPalette(33, 15, g_DataV9Font_palette);
break;
case V9_MODE_B0:
case V9_MODE_B1:
case V9_MODE_B2:
case V9_MODE_B3:
V9_SetPaletteEntry(0, g_ColorBlack);
V9_SetPalette(1, 15, g_DataV9BG_palette);
V9_SetPaletteEntry(16, g_ColorBlack);
V9_SetPalette(17, 15, g_DataV9Font_palette);
V9_SetPaletteEntry(16 + 6, g_ColorBG);
break;
case V9_MODE_B4:
case V9_MODE_B5:
case V9_MODE_B6:
case V9_MODE_B7:
loop (i, 2)
{
V9_SetPaletteEntry(i * 32 + 0, g_ColorBlack);
V9_SetPalette(i * 32 + 1, 15, g_DataV9BG_palette);
V9_SetPaletteEntry(i * 32 + 16, g_ColorBlack);
V9_SetPalette(i * 32 + 17, 15, g_DataV9Font_palette);
V9_SetPaletteEntry(i * 32 + 16 + 6, g_ColorBG);
}
break;
}
}
//-----------------------------------------------------------------------------
// P1 MODE (256x212, 2 layers)
//-----------------------------------------------------------------------------
#if (V9_USE_MODE_P1)
void V9_Print(u32 addr, const c8* str)
{
while (*str != 0)
V9_Poke16(addr += 2, 512 + *(str++) - ' ');
}
//
void InitP1()
{
// Initialize screen mode
V9_SetScreenMode(V9_MODE_P1);
V9_SetDisplayEnable(FALSE);
V9_SetInterrupt(V9_INT_NONE);
V9_SetBackgroundColor(BG_COLOR);
V9_SetSpriteEnable(TRUE);
InitPalette();
// Pattern generator table
V9_WriteVRAM(V9_P1_PGT_A, g_DataV9BG, sizeof(g_DataV9BG));
V9_WriteVRAM(V9_P1_PGT_A + 0x04000, g_DataV9Font, sizeof(g_DataV9Font));
V9_WriteVRAM(V9_P1_PGT_B, g_DataV9BG, sizeof(g_DataV9BG));
// Pattern name table
V9_FillVRAM16(V9_P1_PNT_A, 0x0000, 64*64); // Init layer A
V9_Print(V9_P1_PNT_A, "MSXgl V9990 - P1 Mode (PP)"); // Draw title
for (u8 i = 0; i < 8; ++i) // Draw plateform
{
u8 x = i * 8;
u8 y = Math_GetRandom8() % 8 + 10;
for (u8 j = y; j < V9_GROUND_Y; j++)
{
u8 cell;
if (j == y)
cell = 32;
else if (((j - y) & 1))
cell = 64;
else
cell = 96;
u32 addr = V9_CellAddrP1A(x, j);
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++);
}
}
for (u16 i = 0; i < 64; ++i) // Draw ground
{
for (u8 j = V9_GROUND_Y; j < 27; j++)
{
u8 cell;
if (j == V9_GROUND_Y)
cell = 33;
else
cell = (j & 1) ? 65 : 97;
V9_Poke16(V9_CellAddrP1A(0, j) + i*2, cell + i%2);
}
}
V9_FillVRAM16(V9_P1_PNT_B, 160, 64*27); // Init layer B
for (u16 i = 0; i < 64; ++i) // Draw horizon
V9_Poke16(V9_CellAddrP1B(0, V9_HORIZON_Y) + i*2, 128 + i%4);
V9_FillVRAM16(V9_P1_PNT_B, 135, 64*V9_HORIZON_Y); // Draw sky
for (u8 i = 0; i < 6; ++i) // Draw big cloud
{
u8 x = Math_GetRandom8() % 8 + (i * 10);
u8 y = (i == 0) ? 0 : Math_GetRandom8() % 8;
u32 addr = V9_CellAddrP1B(x, y);
V9_Poke16(addr, 132); addr += 2;
V9_Poke16(addr, 133); addr += 2;
V9_Poke16(addr, 134); addr += 2;
V9_Poke16(addr, 135);
addr = V9_CellAddrP1B(x, y +1);
V9_Poke16(addr, 164); addr += 2;
V9_Poke16(addr, 165); addr += 2;
V9_Poke16(addr, 166); addr += 2;
V9_Poke16(addr, 167);
}
for (u8 i = 0; i < 6; ++i) // Draw small cloud
{
u8 x = Math_GetRandom8() % 8 + (i * 10);
u8 y = Math_GetRandom8() % 4 + 9;
u32 addr = V9_CellAddrP1B(x, y);
V9_Poke16(addr, 136); addr += 2;
V9_Poke16(addr, 137);
addr = V9_CellAddrP1B(x, y +1);
V9_Poke16(addr, 168); addr += 2;
V9_Poke16(addr, 169);
}
// Sprite pattern generator table
V9_SetSpritePatternAddr(V9_P1_SGT_08000);
V9_WriteVRAM(0x08000, g_DataV9Chr, sizeof(g_DataV9Chr));
// Sprite attribute table
struct V9_Sprite attr;
for (u16 i = 0; i < 125; ++i)
{
attr.Y = (i / 13) * 20 + 12;
attr.Pattern = 0;
attr.X = (i % 13) * 20;
attr.P = 0;
attr.D = 0;
attr.SC = 1;
V9_SetSpriteP1(i, &attr);
}
V9_SetInterrupt(V9_INT_VBLANK | V9_INT_HBLANK);
V9_SetInterruptLine(71);
V9_SetDisplayEnable(TRUE);
}
//
void TickP1()
{
V9_SelectPaletteP1(2, 0);
V9_SetScrollingX(0);
V9_SetScrollingBX(g_Frame >> 1);
u8 frame = (g_Frame >> 2) % 6;
for (u16 i = 0; i < 125; ++i)
V9_SetSpritePatternP1(i, frame);
g_Frame++;
}
//
void HblankP1()
{
V9_SelectPaletteP1(0, 0);
V9_SetScrollingX(g_Frame >> 0);
V9_SetScrollingBX(g_Frame >> 2);
}
#endif // (V9_USE_MODE_P1)
//-----------------------------------------------------------------------------
// P1 MODE (512x212, 1 layer)
//-----------------------------------------------------------------------------
#if (V9_USE_MODE_P2)
void V9_WriteVRAM_256to512(u32 addr, const u8* src, u8 line)
{
for (u8 i = 0; i < line; ++i)
{
u8 line = i % 8;
u8 row = i / 2 / 8 * 8;
u8 odd = (i / 8) & 1;
V9_WriteVRAM(addr + (256 * (row + line)) + (128 * odd), src + (128 * i), 128);
}
}
//
void InitP2()
{
// Initialize screen mode
V9_SetScreenMode(V9_MODE_P2);
V9_SetDisplayEnable(FALSE);
V9_SetInterrupt(V9_INT_NONE);
V9_SetBackgroundColor(BG_COLOR);
V9_SetSpriteEnable(TRUE);
InitPalette();
// Pattern generator table
V9_WriteVRAM_256to512(V9_P2_PGT + 0x00000, g_DataV9BG, 48);
V9_WriteVRAM_256to512(V9_P2_PGT + 0x04000, g_DataV9Font, 24);
// Pattern name table
// for (u16 i = 0; i < 64*27; ++i)
// {
// u16 addr = (((i / 64) * 128) + (i % 64)) * 2;
// V9_Poke16(V9_P2_PNT + addr, i);
// addr += 2;
// }
V9_FillVRAM16(V9_P2_PNT, 0, 128*2);
V9_Print(V9_P2_PNT, "MSXgl V9990 - P2 Mode (PP)"); // Draw title
V9_FillVRAM16(V9_P2_PNT + 512, 135, 128*V9_HORIZON_Y); // Draw sky
for (u16 i = 0; i < 128; ++i) // Draw horizon
V9_Poke16(V9_CellAddrP2(0, V9_HORIZON_Y) + i*2, 128 + i%4);
V9_FillVRAM16(V9_CellAddrP2(0, V9_HORIZON_Y+1), 160, (27-V9_HORIZON_Y)*128); // Draw sea
for (u8 i = 0; i < 12; ++i) // Draw big cloud
{
u8 x = Math_GetRandom8() % 8 + (i * 10);
u8 y = Math_GetRandom8() % 4 + 4;
u32 addr = V9_CellAddrP2(x, y);
V9_Poke16(addr, 132); addr += 2;
V9_Poke16(addr, 133); addr += 2;
V9_Poke16(addr, 134); addr += 2;
V9_Poke16(addr, 135);
addr = V9_CellAddrP2(x, y +1);
V9_Poke16(addr, 164); addr += 2;
V9_Poke16(addr, 165); addr += 2;
V9_Poke16(addr, 166); addr += 2;
V9_Poke16(addr, 167);
}
for (u8 i = 0; i < 12; ++i) // Draw small cloud
{
u8 x = Math_GetRandom8() % 8 + (i * 10);
u8 y = Math_GetRandom8() % 4 + 9;
u32 addr = V9_CellAddrP2(x, y);
V9_Poke16(addr, 136); addr += 2;
V9_Poke16(addr, 137);
addr = V9_CellAddrP2(x, y +1);
V9_Poke16(addr, 168); addr += 2;
V9_Poke16(addr, 169);
}
for (u8 i = 0; i < 8; ++i) // Draw plateform
{
u8 x = i * 16;
u8 y = Math_GetRandom8() % 8 + 10;
for (u8 j = y; j < V9_GROUND_Y; j++)
{
u8 cell;
if (j == y)
cell = 32;
else if (((j - y) & 1))
cell = 64;
else
cell = 96;
u32 addr = V9_CellAddrP2(x, j);
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++); cell -= 2;
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++); cell -= 2;
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++);
V9_Poke16(addr += 2, cell++);
}
}
for (u16 i = 0; i < 128; ++i) // Draw ground
{
for (u8 j = V9_GROUND_Y; j < 27; j++)
{
u8 cell;
if (j == V9_GROUND_Y)
cell = 33;
else
cell = (j & 1) ? 65 : 97;
V9_Poke16(V9_CellAddrP2(0, j) + i*2, cell + i%2);
}
}
// Sprite pattern generator table
V9_SetSpritePatternAddr(V9_P2_SGT_08000);
for (u8 i = 0; i < 16; ++i)
V9_WriteVRAM(V9_P2_PGT + 0x08000 + (256 * i), g_DataV9Chr + (128 * i), 128);
// Sprite attribute table
struct V9_Sprite attr;
for (u8 i = 0; i < 125; ++i)
{
attr.Y = (i / 13) * 20 + 12;
attr.Pattern = 0;
attr.X = (i % 13) * 40 + 8;
attr.P = 0;
attr.D = 0;
attr.SC = 1;
V9_SetSpriteP2(i, &attr);
}
V9_SetInterrupt(V9_INT_VBLANK | V9_INT_HBLANK);
V9_SetInterruptLine(6);
V9_SetDisplayEnable(TRUE);
}
//
void TickP2()
{
V9_SelectPaletteP2(2);
V9_SetScrollingX(0);
u8 frame = (g_Frame >> 2) % 6;
for (u16 i = 0; i < 125; ++i)
V9_SetSpritePatternP2(i, frame);
g_Frame++;
}
//
void HblankP2()
{
V9_SelectPaletteP2(0);
V9_SetScrollingX(g_Frame >> 0);
V9_SetScrollingBX(g_Frame >> 2);
}
#endif // (V9_USE_MODE_P1)
//-----------------------------------------------------------------------------
// BITMAP MODE
//-----------------------------------------------------------------------------
#if ((V9_USE_MODE_B0) || (V9_USE_MODE_B1) || (V9_USE_MODE_B2) || (V9_USE_MODE_B3) || (V9_USE_MODE_B4) || (V9_USE_MODE_B5) || (V9_USE_MODE_B6) || (V9_USE_MODE_B7))
//
void V9_SetPrintPositionBmp(u16 x, u16 y)
{
g_TextX = x;
g_TextY = y;
}
//
void V9_PrintBmpChar(c8 chr)
{
u8 idx = chr - ' ';
V9_WaitCmdEnd();
V9_CommandLMMM(idx % 32 * 8, BMP_TILES_Y + 48 + (idx / 32) * 8, g_TextX, g_TextY, 8, 8, 0);
g_TextX += 8;
}
//
void V9_PrintBmpString(const c8* str)
{
while (*str)
V9_PrintBmpChar(*str++);
}
//
void V9_PrintBmpStringAt(u16 x, u16 y, const c8* str)
{
V9_SetPrintPositionBmp(x, y);
V9_PrintBmpString(str);
}
//
void V9_DrawTileBmp(u8 x, u8 y, u8 tile)
{
V9_WaitCmdEnd();
V9_CommandLMMM((tile % 32) * 8, BMP_TILES_Y + (tile / 32) * 8, x * 8, y * 8, 8, 8, 0);
}
const u8 g_BP6_Palette[] =
{
0x00, 0x00, 0x00, // [ 1] Black
0x0A, 0x0A, 0x0A, // [ 2] Dark gray
0x16, 0x16, 0x16, // [ 3] Light gray
0x1F, 0x1F, 0x1F, // [ 4] White
};
// 15-bit RGB => 8-bit GRB
const u8 g_BD8_PaletteBG[] =
{
0b00000000, // [ 0] #000000
0b00000000, // [ 1] #000000
0b01000110, // [ 2] #3953AB : 010'001'10
0b11001111, // [ 3] #71DCE9 : 110'011'11
0b00110001, // [ 4] #903F43 : 001'100'01
0b00000100, // [ 5] #2E142E : 000'001'00
0b10000111, // [ 6] #3B95E2 : 100'001'11
0b10111101, // [ 7] #EDB774 : 101'111'01
0b10101110, // [ 8] #79A790 : 101'011'10
0b11111111, // [ 9] #F6F3F3 : 111'111'11
0b10010110, // [10] #A89E99 : 100'101'10
0b00101001, // [11] #542F54 : 001'010'01
0b01101111, // [12] #6D60E7 : 011'011'11
0b01101001, // [13] #4E636B : 011'010'01
0b11011011, // [14] #CEC9CC : 110'110'11
0b01111001, // [15] #D86E61 : 011'110'01
};
//
void InitBmp()
{
// Initialize screen mode
V9_SetScreenMode(g_ScreenMode[g_CurrentScreen].Mode);
V9_SetDisplayEnable(FALSE);
V9_SetInterrupt(V9_INT_NONE);
V9_SetImageSpaceWidth(V9_R06_WIDH_1024);
V9_SetColorMode(g_ColorMode[g_CurrentColor].Mode);
V9_SetBackgroundColor(BG_COLOR);
V9_SetScrollingX(0);
u16 bgColor = 0;
if (g_CurrentColor == V9_COLOR_BP2)
{
bgColor = 0x5555;
V9_SetPalette(0, 4, g_BP6_Palette);
V9_SelectPaletteBP2(0);
// Load graphics data to VRAM
// for (u8 i = 0; i < 48; ++i)
// V9_WriteVRAM((u32)(0 + (u32)(512 * (u32)(512 + 0 + i))), g_DataV9BG + (128 * i), 128);
// for (u8 i = 0; i < 24; ++i)
// V9_WriteVRAM((u32)(0 + (u32)(512 * (u32)(512 + 48 + i))), g_DataV9Font + (128 * i), 128);
// loop (i, 48+24)
// loop (j, 64)
// V9_Poke((u32)(0 + (u32)(512 * (u32)(256 + 0 + i)) + j), (j & 1) ? 0b11100100 : 0b00011011);
V9_FillVRAM(BMP_TILES_Y * 256, 0b00000000, 256 * 72);
}
else if (g_CurrentColor == V9_COLOR_BP4)
{
bgColor = 0xEEEE;
InitPalette();
V9_SelectPaletteBP4(0);
// Load graphics data to VRAM
for (u8 i = 0; i < 48; ++i)
V9_WriteVRAM((u32)(0 + (u32)(512 * (u32)(BMP_TILES_Y + 0 + i))), g_DataV9BG + (128 * i), 128);
for (u8 i = 0; i < 24; ++i)
{
u8* buf = (u8*)Mem_GetHeapAddress();
loop (j, 128)
{
u8 v = *(const u8*)(g_DataV9Font + (128 * i) + j);
if ((v & 0xF0) == 0x00)
v |= 0x60;
else if ((v & 0xF0) == 0x60)
v &= 0x0F;
if ((v & 0x0F) == 0x00)
v |= 0x06;
else if ((v & 0x0F) == 0x06)
v &= 0xF0;
buf[j] = v;
}
V9_WriteVRAM((u32)(0 + (u32)(512 * (u32)(BMP_TILES_Y + 48 + i))), buf, 128);
}
}
else if (g_CurrentColor == V9_COLOR_BD8)
{
bgColor = 0x8787;
// Load graphics data to VRAM
const u8* data = g_DataV9BG;
loop (i, 48)
{
u32 addr = BMP_TILES_Y * 1024 + i * 1024;
loop (j, 128)
{
V9_Poke(addr++, g_BD8_PaletteBG[*data >> 4]);
V9_Poke(addr++, g_BD8_PaletteBG[*data & 0x0F]);
data++;
}
}
}
// Initialize background color
V9_SetCommandLogicalOp(V9_R45_LOP_SET);//| V9_R45_TP);
V9_SetCommandWriteMask(0xFFFF);
V9_WaitCmdEnd();
V9_CommandLMMV(0, 0, 1024, 256, 0, bgColor);
for (u16 i = 0; i < 128; ++i) // Draw ground
{
for (u16 j = V9_HORIZON_Y; j < 32; j++)
{
u8 cell;
if (j == V9_HORIZON_Y)
cell = 128 + i % 4;
else if (j < V9_GROUND_Y)
cell = 160;
else if (j == V9_GROUND_Y)
cell = 33 + i % 2;
else
{
cell = (j & 1) ? 65 : 97;
cell += i % 2;
}
V9_DrawTileBmp(i, j, cell);
}
}
for (u8 i = 0; i < 16; ++i) // Draw plateform
{
u16 x = i * 8;
u8 y = Math_GetRandom8() % 8 + 10;
for (u8 j = y; j < V9_GROUND_Y; j++)
{
u8 cell;
if (j == y)
cell = 32;
else if (((j - y) & 1))
cell = 64;
else
cell = 96;
V9_DrawTileBmp(x, j, cell++);
V9_DrawTileBmp(x + 1, j, cell++);
V9_DrawTileBmp(x + 2, j, cell++);
V9_DrawTileBmp(x + 3, j, cell++);
}
}
// Draw title
V9_PrintBmpStringAt(g_CurrentScreen > MODE_B1 ? 16 : 8, 1, "MSXgl V9990 - ");
V9_PrintBmpString(g_ScreenMode[g_CurrentScreen].Name);
V9_PrintBmpString(" (");
V9_PrintBmpString(g_ColorMode[g_CurrentColor].Name);
V9_PrintBmpString(")");
// Setup cursors
V9_SetCursorEnable(true);
V9_SetCursorPalette(2); // entry 8
u8* buf = (u8*)Mem_GetHeapAddress();
loop (i, 128)
{
buf[i] = i & 0x04 ? 0xAA : 0x55; // Initialize 'check' pattern
}
loop (i, 2)
V9_SetCursorPattern(i, buf);
V9_SetInterrupt(V9_INT_VBLANK | V9_INT_HBLANK);
V9_SetInterruptLine(9);
V9_SetDisplayEnable(TRUE);
}
//
void TickBmp()
{
if (g_CurrentColor == V9_COLOR_BP4)
V9_SelectPaletteBP4(1);
V9_SetScrollingX(0);
if (Keyboard_IsKeyPressed(KEY_H))
{
if (g_CurrentColor == V9_COLOR_BP4)
V9_SelectPaletteBP4(0);
V9_SetScrollingX(0);
V9_SetScrollingY(BMP_TILES_Y);
V9_SetInterrupt(V9_INT_VBLANK);
}
else
{
V9_SetScrollingY(0);
V9_SetInterrupt(V9_INT_VBLANK | V9_INT_HBLANK);
}
loop (i, 2)
{
u8 idx = ((g_Frame >> 2) + (i * 32)) % 64;
V9_SetCursorAttribute(i, 64 + i * 96, 64 + ((i16)g_Sinus64[idx] / 8), i + 1);
}
g_Frame++;
}
//
void HblankBmp()
{
if (g_CurrentColor == V9_COLOR_BP4)
V9_SelectPaletteBP4(0);
V9_SetScrollingX(g_Frame >> 0);
}
#endif // ((V9_USE_MODE_B0) || (V9_USE_MODE_B1) || (V9_USE_MODE_B2) || (V9_USE_MODE_B3) || (V9_USE_MODE_B4) || (V9_USE_MODE_B5) || (V9_USE_MODE_B6) || (V9_USE_MODE_B7))
//-----------------------------------------------------------------------------
// Helper function
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
void DisplayMSX()
{
Print_SetTextFont(g_Font_MGL_Sample6, 1); // Initialize font
Print_SetColor(0xF, 0x0);
Print_DrawText(MSX_GL " V9990 SAMPLE");
Print_DrawLineH(0, 1, 40);
const c8* str = "V9990 not found!";
if (V9_Detect())
str = "V9990 found!";
Print_SetPosition(0, 3);
Print_DrawText(str);
Print_SetPosition(0, 5);
Print_DrawText("Ports:\n\n 0-7\n 8-F");
for (u8 i = 0; i < 16; ++i)
{
u8 val = V9_GetPort(V9_P00 + i);
u8 x = 9 + (i % 8) * 3;
u8 y = 7 + (i / 8);
Print_SetPosition(x, y);
Print_DrawHex8(val);
}
Print_SetPosition(0, 10);
Print_DrawText("Registers:\n\n 00-07\n 08-0F\n 10-17\n 18-1F\n 20-27\n 28-2F\n 30-37\n 38-3F");
for (u8 i = 0; i < 64; ++i)
{
u8 val = V9_GetRegister(i);
u8 x = 9 + (i % 8) * 3;
u8 y = 12 + (i / 8);
Print_SetPosition(x, y);
Print_DrawHex8(val);
}
Print_DrawLineH(0, 22, 40);
Print_SetPosition(0, 23);
Print_DrawText("R:Refresh C:Color");
}
bool g_VSynch = FALSE;
#if (CUSTOM_ISR == 0)
//-----------------------------------------------------------------------------
//
void InterruptHook()
{
__asm
// Flush VDP interruption signal
in a, (P_VDP_STAT)
// Call VDP interruption handler
in a, (V9_P06)
out (V9_P06), a
// V-Blank interruption
rra
call c, _V9_InterruptVBlank
// H-Blank interruption
rra
call c, _V9_InterruptHBlank
// Command end interruption
rra
call c, _V9_InterruptCommand
__endasm;
}
#endif
//-----------------------------------------------------------------------------
//
void V9_InterruptVBlank()
{
g_VSynch = TRUE;
}
//-----------------------------------------------------------------------------
//
void V9_InterruptHBlank()
{
g_ScreenMode[g_CurrentScreen].Hblank();
}
//-----------------------------------------------------------------------------
//
void V9_InterruptCommand()
{
}
//-----------------------------------------------------------------------------
//
void VDP_InterruptVBlank()
{
}
//-----------------------------------------------------------------------------
// Set current screen mode
void SetScreenMode(u8 mode)
{
g_CurrentScreen = mode;
g_ScreenMode[g_CurrentScreen].Init();
}
//-----------------------------------------------------------------------------
// Set current bitmap color mode
void SetColorMode(u8 mode)
{
#if (V9_USE_MODE_P1)
if (g_CurrentScreen == MODE_P1)
return;
#endif
#if (V9_USE_MODE_P2)
if (g_CurrentScreen == MODE_P2)
return;
#endif
g_CurrentColor = mode;
g_ScreenMode[g_CurrentScreen].Init();
}
//-----------------------------------------------------------------------------
// Program entry point
void main()
{
V9_SetPort(V9_P15, 0); // Disactivate Video9000 if present (recommanded)
// Initialize screen mode 0 (text)
VDP_SetMode(VDP_MODE_SCREEN0);
VDP_EnableVBlank(FALSE);
VDP_ClearVRAM();
DisplayMSX();
#if (CUSTOM_ISR == 0)
BIOS_SetHookDirectCallback(H_KEYI, InterruptHook);
BIOS_ClearHook(H_TIMI);
#endif
//---- CURRENT SCREEN MODE INIT ----
g_ScreenMode[g_CurrentScreen].Init();
loop (i, 80)
g_KeyPressed[i] = FALSE;
u16 count = 0;
u8 clr = 0;
while (1)
{
// V9_SetRegister(15, 2);
while (g_VSynch == FALSE) {}
// V9_SetRegister(15, 1);
g_VSynch = FALSE;
//---- CURRENT SCREEN MODE UPDATE ----
g_ScreenMode[g_CurrentScreen].Tick();
// Sign of life
Print_SetPosition(39, 0);
Print_DrawChar(g_ChrAnim[count++ & 0x03]);
// Handle inputs
u8 row0 = Keyboard_Read(0);
u8 row1 = Keyboard_Read(1);
u8 row8 = Keyboard_Read(8);
// Select next/previous screen mode
if (IS_KEY_PRESSED(row8, KEY_RIGHT))
{
if (g_CurrentScreen < numberof(g_ScreenMode) - 1)
SetScreenMode(g_CurrentScreen + 1);
}
else if (IS_KEY_PRESSED(row8, KEY_LEFT))
{
if (g_CurrentScreen > 0)
SetScreenMode(g_CurrentScreen - 1);
}
// Direction selection of a screen mode
#if ((V9_USE_MODE_B0) || (V9_USE_MODE_B1) || (V9_USE_MODE_B2) || (V9_USE_MODE_B3) || (V9_USE_MODE_B4) || (V9_USE_MODE_B5) || (V9_USE_MODE_B6) || (V9_USE_MODE_B7))
if (IS_KEY_PRESSED(row0, KEY_0))
SetScreenMode(MODE_B0);
else if (IS_KEY_PRESSED(row0, KEY_1))
SetScreenMode(MODE_B1);
else if (IS_KEY_PRESSED(row0, KEY_2))
SetScreenMode(MODE_B2);
else if (IS_KEY_PRESSED(row0, KEY_3))
SetScreenMode(MODE_B3);
else if (IS_KEY_PRESSED(row0, KEY_4))
SetScreenMode(MODE_B4);
else if (IS_KEY_PRESSED(row0, KEY_5))
SetScreenMode(MODE_B5);
else if (IS_KEY_PRESSED(row0, KEY_6))
SetScreenMode(MODE_B6);
else if (IS_KEY_PRESSED(row0, KEY_7))
SetScreenMode(MODE_B7);
#endif
#if (V9_USE_MODE_P1)
if (IS_KEY_PRESSED(row1, KEY_8))
SetScreenMode(MODE_P1);
#endif
#if (V9_USE_MODE_P2)
if (IS_KEY_PRESSED(row1, KEY_9))
SetScreenMode(MODE_P2);
#endif
// Select color mode
if (IS_KEY_PRESSED(row8, KEY_DOWN))
{
if (g_CurrentColor < numberof(g_ColorMode) - 1)
SetColorMode(g_CurrentColor + 1);
}
else if (IS_KEY_PRESSED(row8, KEY_UP))
{
if (g_CurrentColor > 0)
SetColorMode(g_CurrentColor - 1);
}
// Hide/display sprite/cursor
if (Keyboard_IsKeyPressed(KEY_G))
{
if (!g_KeyPressed[KEY_G])
{
g_KeyPressed[KEY_G] = TRUE;
g_HideSprite = !g_HideSprite;
if (g_HideSprite)
V9_SetFlag(8, V9_R08_SPD_OFF, V9_R08_SPD_OFF);
else
V9_SetFlag(8, V9_R08_SPD_OFF, 0);
}
}
else
g_KeyPressed[KEY_G] = FALSE;
// Refresh MSX display
if (Keyboard_IsKeyPressed(KEY_R))
DisplayMSX();
}
V9_SetPort(V9_P15, 0x10); // Reactivate Video9000 if present (recommanded)
}