// ____________________________ // ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄ // ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███ // █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄ // ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀ // 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" enum SCREEN_MODE { SCREEN_MODE_5 = 0, SCREEN_MODE_6, SCREEN_MODE_7, SCREEN_MODE_8, }; // 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; }; void DisplayPageMain(); void DisplayPageHMMC(); void DisplayPageHMMM(); void DisplayPageLMMC(); //============================================================================= // MEMORY DATA //============================================================================= // Screen mode setting index u8 g_CmdModeIndex = 0; u8 g_SrcModeIndex = SCREEN_MODE_8; u8 g_VBlank = 0; u8 g_Frame = 0; u16 SX, SY; const struct ScreenSetting* src; u8* buffer; u16 blockWidth; u16 blockBytes; u16 lineBytes; u8 scale; // Memory buffer to unpack compressed data u8 g_LMMC2b[16*16]; u8 g_LMMC4b[16*16]; //============================================================================= // READ-ONLY DATA //============================================================================= // Fonts #include "font/font_mgl_sample6.h" #include "font/font_mgl_sample8.h" // Cursor const u8 g_CursorForm[] = { // Sprite[0] (offset:0) 0xF0, /* ######## */ 0x80, /* #....... */ 0x80, /* #....... */ 0x80, /* #....... */ 0x00, /* #....... */ 0x00, /* #....... */ 0x00, /* #....... */ 0x00, /* #....... */ // Sprite[1] (offset:8) 0x00, /* #....... */ 0x00, /* #....... */ 0x00, /* #....... */ 0x00, /* #....... */ 0x80, /* #....... */ 0x80, /* #....... */ 0x80, /* #....... */ 0xF0, /* ######## */ // Sprite[2] (offset:16) 0x0F, /* ######## */ 0x01, /* .......# */ 0x01, /* .......# */ 0x01, /* .......# */ 0x00, /* .......# */ 0x00, /* .......# */ 0x00, /* .......# */ 0x00, /* .......# */ // Sprite[3] (offset:24) 0x00, /* .......# */ 0x00, /* .......# */ 0x00, /* .......# */ 0x00, /* .......# */ 0x01, /* .......# */ 0x01, /* .......# */ 0x01, /* .......# */ 0x0F, /* ######## */ }; // Bitmaps by GrafxKid (https://opengameart.org/content/super-random-sprites) #include "content/data_bmp_2b.h" #include "content/data_bmp_4b.h" #include "content/data_bmp_8b.h" // Screen mode settings const struct ScreenSetting g_Settings[] = { // Name Mode Width BPC Txt BG Red White Gray Black Font Data DataLMMC Palette { MSX_GL6 " VDP COMMAND SAMPLE (S5/G4)", VDP_MODE_SCREEN5, 256, 4, 0xFF, 0x44, 0x88, 0xFF, 0x11, 0x11, g_Font_MGL_Sample6, g_DataBmp4b, g_LMMC4b, NULL }, // 0 { MSX_GL8 " VDP COMMAND SAMPLE (S6/G5)", VDP_MODE_SCREEN6, 512, 2, 0xFF, 0x00, 0x55, 0xFF, 0xAA, 0x55, g_Font_MGL_Sample8, g_DataBmp2b, g_LMMC2b, NULL }, // 1 { MSX_GL8 " VDP COMMAND SAMPLE (S7/G6)", VDP_MODE_SCREEN7, 512, 4, 0xFF, 0x44, 0x88, 0xFF, 0x11, 0x11, g_Font_MGL_Sample8, g_DataBmp4b, g_LMMC4b, NULL }, // 2 { MSX_GL6 " VDP COMMAND SAMPLE (S8/G7)", VDP_MODE_SCREEN8, 256, 8, 0xFF, 0x47, 0x1C, 0xFF, 0x6D, 0x00, g_Font_MGL_Sample6, g_DataBmp8b, g_DataBmp8b, NULL }, // 3 }; // Character animation const u8 chrAnim[] = { '|', '\\', '-', '/' }; // const callback g_Page[] = { DisplayPageMain, DisplayPageHMMC, DisplayPageHMMM, DisplayPageLMMC, }; //============================================================================= // HELPER FUNCTIONS //============================================================================= //----------------------------------------------------------------------------- // void DisplayPage() { src = &g_Settings[g_SrcModeIndex]; buffer = Mem_HeapAlloc(256); blockWidth = src->Width / 16; blockBytes = 16 / 8 * src->BPC; lineBytes = src->Width / 8 * src->BPC; scale = 8 / src->BPC; //------------------------------------------------------------------------- // Init VDP_SetMode(src->Mode); VDP_SetColor(src->Background); VDP_CommandHMMV(0, 0, src->Width, 212, src->Background); VDP_EnableDisplay(FALSE); switch (g_SrcModeIndex) { case SCREEN_MODE_5: case SCREEN_MODE_7: VDP_SetPaletteEntry(1, RGB16(0, 0, 0)); VDP_SetPaletteEntry(5, RGB16(4, 4, 4)); VDP_SetPaletteEntry(14, RGB16(6, 6, 6)); break; case SCREEN_MODE_6: VDP_SetPaletteEntry(0, RGB16(1, 1, 7)); VDP_SetPaletteEntry(1, RGB16(0, 0, 4)); VDP_SetPaletteEntry(2, RGB16(0, 0, 0)); VDP_SetPaletteEntry(3, RGB16(7, 7, 7)); break; }; Print_SetBitmapFont(src->Font); Print_SetColor(src->Text, src->Background); //------------------------------------------------------------------------- // Header Print_SetPosition(4, 2); Print_DrawText(src->Name); Draw_LineH(0, src->Width - 1, 8+4, src->Text, 0); //------------------------------------------------------------------------- g_Page[g_CmdModeIndex](); //------------------------------------------------------------------------- // Footer Draw_LineH(0, src->Width - 1, (u8)(200-4), src->Text, 0); Print_SetPosition(4, 200); Print_DrawText("\x82:Mode \x81\x80:Cmd \x83+\x81\x82\x80:Cursor"); // Init sprite VDP_EnableSprite(TRUE); VDP_SetSpritePatternTable(0x0E000); VDP_SetSpriteAttributeTable(0x0EA00); VDP_SetSpriteFlag(VDP_SPRITE_SIZE_16); // Load and setup sprite VDP_LoadSpritePattern(g_CursorForm, 0, 4); VDP_SetSpriteExUniColor(0, SX, SY, 0, 0xF); VDP_DisableSpritesFrom(1); VDP_EnableDisplay(TRUE); } //----------------------------------------------------------------------------- // void DisplayPageMain() { u16 X, Y; //------------------------------------------------------------------------- // WriteVRAM(src, destLow, destHigh, count) - Write data from RAM to VRAM X = blockWidth / 2; Y = 24; Print_SetPosition(X, Y); Print_DrawText("Write"); for (u16 i = 0; i < 16; ++i) VDP_WriteVRAM(src->Data + (blockBytes * i), (Y + 8 + i) * lineBytes + (X / scale), 0, blockBytes); // HMMC(addr, dx, dy, nx, ny) - High speed move CPU to VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("HMMC"); VDP_CommandHMMC(src->Data, X, Y + 8, 16, 16); // YMMM(sy, dx, dy, ny, dir) - High speed move VRAM to VRAM, Y coordinate only Y += 32; Print_SetPosition(X, Y); Print_DrawText("YMMM"); VDP_CommandYMMM(SY, X, Y + 8, 16, 0); // HMMM(sx, sy, dx, dy, nx, ny) - High speed move VRAM to VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("HMMM"); VDP_CommandHMMM(SX, SY, X, Y + 8, 16, 16); // HMMV(dx, dy, nx, ny, col) - High speed move VDP to VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("HMMV"); VDP_CommandHMMV(X, Y + 8, blockWidth, 16, src->Red); //----------------------------------------------------------------------------- // ReadVRAM(srcLow, srcHigh, dest, count) - Read data from VRAM to RAM X += src->Width / 3; Y = 24; Print_SetPosition(X, Y); Print_DrawText("Read>W"); for (u16 i = 0; i < 16; ++i) { VDP_ReadVRAM((SY + i) * lineBytes + (SX / scale), 0, buffer + (blockBytes * i), blockBytes); // Read from page 0 VDP_WriteVRAM(buffer + (blockBytes * i), (Y + 8 + i) * lineBytes + (X / scale), 0, blockBytes); // Write to page 0 // Page 1 write VDP_WriteVRAM(buffer + (blockBytes * i), (Y + 8 + i) * lineBytes + (X / scale), 1, blockBytes); // Write to page 1 VDP_ReadVRAM((Y + 8 + i) * lineBytes + (X / scale), 1, buffer + (blockBytes * i), blockBytes); // Read from page 1 VDP_WriteVRAM(buffer + (blockBytes * i), (Y + 8 + i) * lineBytes + (X / scale) + 32, 1, blockBytes); // Write to page 1 } // LMMC(addr, dx, dy, nx, ny, op) - Logical move CPU to VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("LMMC(TI)"); VDP_CommandLMMC(src->DataLMMC, X, Y + 8, 16, 16, VDP_OP_TIMP); // LMCM() - Logical move VRAM to CPU Y += 32; Print_SetPosition(X, Y); Print_DrawText("LMCM(TI)"); Print_SetPosition(X, Y + 8); Print_DrawText("xxx"); // LMMM(sx, sy, dx, dy, nx, ny, op) - Logical move VRAM to VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("LMMM(TI)"); VDP_CommandLMMM(SX, SY, X, Y + 8, 16, 16, VDP_OP_TIMP); // LMMV(dx, dy, nx, ny, col, op) - Logical move VDP to VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("LMMV(OR)"); VDP_CommandLMMV(X - blockWidth/4, Y + 8 + 4, blockWidth + blockWidth/2, 16 - 8, src->Red, VDP_OP_IMP); VDP_CommandLMMV(X, Y + 8, blockWidth, 16, src->Gray, VDP_OP_OR); //----------------------------------------------------------------------------- // FillVRAM(value, destLow, destHigh, count) - Fill VRAM area with a given value X += src->Width / 3; Y = 24; Print_SetPosition(X, Y); Print_DrawText("Fill"); for (u16 i = 0; i < 16; ++i) VDP_FillVRAM(src->Red, (Y + 8 + i) * lineBytes + (X / scale), 0, blockBytes * blockWidth/16); // LINE - Draw straight line in VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("LINE(OR)"); VDP_CommandHMMV(X - blockWidth/4, Y + 8 + 4, blockWidth + blockWidth/2, 8, src->Red); VDP_CommandLINE(X, Y + 8, blockWidth, 16, src->Gray, VDP_ARG_DIY_DOWN + VDP_ARG_DIX_RIGHT, VDP_OP_OR); VDP_CommandLINE(X, Y + 16 + 8, blockWidth, 16, src->Gray, VDP_ARG_DIY_UP + VDP_ARG_DIX_RIGHT, VDP_OP_OR); VDP_CommandLINE(X, Y + 8 + 8, blockWidth, 0, src->Gray, VDP_ARG_DIY_DOWN + VDP_ARG_DIX_RIGHT, VDP_OP_OR); VDP_CommandLINE(X + blockWidth/2, Y + 8, 16, 0, src->Gray, VDP_ARG_DIY_DOWN + VDP_ARG_MAJ_V, VDP_OP_OR); // SRCH - Search for the specific color in VRAM to the right or left of the starting point Y += 32; Print_SetPosition(X, Y); Print_DrawText("SRCH"); Print_SetPosition(X, Y + 8); Print_DrawText("xxx"); // PSET - Draw a dot in VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("PSET(I)"); for (u16 i = 0; i < 32; ++i) { u16 rnd = Math_GetRandom16(); VDP_CommandPSET(X + rnd % blockWidth, Y + 8 + (rnd >> 4) % 16, (rnd >> 8), VDP_OP_IMP); } // POINT(sx, sy) - Read the color of the specified dot located in VRAM Y += 32; Print_SetPosition(X, Y); Print_DrawText("POINT(I)"); u8 clr = VDP_CommandPOINT(SX, SY); VDP_CommandLMMV(X, Y + 8, blockWidth, 16, clr, VDP_OP_IMP); } //----------------------------------------------------------------------------- // void DisplayPageHMMC() { Print_SetPosition(0, 24); Print_DrawText("HMMC"); VDP_CommandHMMC(src->Data, 0, 40, 16, 16); VDP_CommandHMMC(src->Data, src->Width-1-15, 16+17*0, 16, 16); VDP_CommandHMMC(src->Data, src->Width-1-14, 16+17*1, 16, 16); VDP_CommandHMMC(src->Data, src->Width-1-8, 16+17*2, 16, 16); VDP_CommandHMMC(src->Data, src->Width-1-7, 16+17*3, 16, 16); VDP_CommandHMMC(src->Data, src->Width-1, 16+17*4, 16, 16); VDP_CommandHMMC_Arg(src->Data, 0+15, 100+17*0, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMC_Arg(src->Data, 0+14, 100+17*1, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMC_Arg(src->Data, 0+8, 100+17*2, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMC_Arg(src->Data, 0+7, 100+17*3, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMC_Arg(src->Data, 0, 100+17*4, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMC_Arg(src->Data, src->Width/2+1, 100+1, 16, 16, 0); VDP_CommandHMMC_Arg(src->Data, src->Width/2-1, 100+1, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMC_Arg(src->Data, src->Width/2+1, 100-1, 16, 16, VDP_ARG_DIY_UP); VDP_CommandHMMC_Arg(src->Data, src->Width/2-1, 100-1, 16, 16, VDP_ARG_DIX_LEFT+VDP_ARG_DIY_UP); } //----------------------------------------------------------------------------- // void DisplayPageHMMM() { Print_SetPosition(0, 24); Print_DrawText("HMMM"); VDP_CommandHMMC(src->Data, 0, 40, 16, 16); VDP_CommandHMMM(0, 40, src->Width-1-15, 16+17*0, 16, 16); VDP_CommandHMMM(0, 40, src->Width-1-14, 16+17*1, 16, 16); VDP_CommandHMMM(0, 40, src->Width-1-8, 16+17*2, 16, 16); VDP_CommandHMMM(0, 40, src->Width-1-7, 16+17*3, 16, 16); VDP_CommandHMMM(0, 40, src->Width-1, 16+17*4, 16, 16); VDP_CommandHMMM_Arg(15, 40, 0+15, 100+17*0, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMM_Arg(15, 40, 0+14, 100+17*1, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMM_Arg(15, 40, 0+8, 100+17*2, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMM_Arg(15, 40, 0+7, 100+17*3, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMM_Arg(15, 40, 0, 100+17*4, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMM_Arg(0, 40, src->Width/2+1, 100+1, 16, 16, 0); VDP_CommandHMMM_Arg(15, 40, src->Width/2-1, 100+1, 16, 16, VDP_ARG_DIX_LEFT); VDP_CommandHMMM_Arg(0, 40+15, src->Width/2+1, 100-1, 16, 16, VDP_ARG_DIY_UP); VDP_CommandHMMM_Arg(15, 40+15, src->Width/2-1, 100-1, 16, 16, VDP_ARG_DIX_LEFT+VDP_ARG_DIY_UP); } //----------------------------------------------------------------------------- // void DisplayPageLMMC() { Print_SetPosition(0, 24); Print_DrawText("LMMC"); VDP_CommandLMMC(src->DataLMMC, 0, 40, 16, 16, VDP_OP_TIMP); VDP_CommandLMMC(src->DataLMMC, src->Width-1-15, 16+17*0, 16, 16, VDP_OP_TIMP); VDP_CommandLMMC(src->DataLMMC, src->Width-1-14, 16+17*1, 16, 16, VDP_OP_TIMP); VDP_CommandLMMC(src->DataLMMC, src->Width-1-8, 16+17*2, 16, 16, VDP_OP_TIMP); VDP_CommandLMMC(src->DataLMMC, src->Width-1-7, 16+17*3, 16, 16, VDP_OP_TIMP); VDP_CommandLMMC(src->DataLMMC, src->Width-1, 16+17*4, 16, 16, VDP_OP_TIMP); VDP_CommandLMMC_Arg(src->DataLMMC, 0+15, 100+17*0, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT); VDP_CommandLMMC_Arg(src->DataLMMC, 0+14, 100+17*1, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT); VDP_CommandLMMC_Arg(src->DataLMMC, 0+8, 100+17*2, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT); VDP_CommandLMMC_Arg(src->DataLMMC, 0+7, 100+17*3, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT); VDP_CommandLMMC_Arg(src->DataLMMC, 0, 100+17*4, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT); VDP_CommandLMMC_Arg(src->DataLMMC, src->Width/2+1, 100+1, 16, 16, VDP_OP_TIMP, 0); VDP_CommandLMMC_Arg(src->DataLMMC, src->Width/2-1, 100+1, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT); VDP_CommandLMMC_Arg(src->DataLMMC, src->Width/2+1, 100-1, 16, 16, VDP_OP_TIMP, VDP_ARG_DIY_UP); VDP_CommandLMMC_Arg(src->DataLMMC, src->Width/2-1, 100-1, 16, 16, VDP_OP_TIMP, VDP_ARG_DIX_LEFT+VDP_ARG_DIY_UP); } //----------------------------------------------------------------------------- // H_TIMI interrupt hook void VBlankHook() { 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 < 256; ++i) { u8 c, b = g_DataBmp4b[i >> 1]; if ((i & 0x1) == 0) c = b >> 4; else // if ((i & 0x1) == 1) c = b; g_LMMC4b[i] = c & 0x0F; } for (u16 i = 0; i < 256; ++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[i] = c & 0x03; } // Init BIOS_SetHookCallback(H_TIMI, VBlankHook); SX = 8; SY = 32; DisplayPage(); bool bContinue = TRUE; bool bEditing = FALSE; while (bContinue) { const struct ScreenSetting* src = &g_Settings[g_SrcModeIndex]; Print_SetPosition(src->Width - 8, 2); Print_DrawChar(chrAnim[g_Frame & 0x03]); u8 row8 = Keyboard_Read(KEY_ROW(KEY_DOWN)); if ((row8 & KEY_FLAG(KEY_SPACE)) == 0) { // Move cursor bEditing = TRUE; if ((row8 & KEY_FLAG(KEY_UP)) == 0) { if (SY > 0) --SY; } if ((row8 & KEY_FLAG(KEY_DOWN)) == 0) { if (SY < 212) ++SY; } if ((row8 & KEY_FLAG(KEY_LEFT)) == 0) { if (SX > 0) --SX; } if ((row8 & KEY_FLAG(KEY_RIGHT)) == 0) { ++SX; if (SX >= src->Width) SX = src->Width - 1; } } else { // Change screen mode if ((row8 & KEY_FLAG(KEY_UP)) == 0) { if (g_SrcModeIndex > 0) g_SrcModeIndex--; else g_SrcModeIndex = numberof(g_Settings) - 1; DisplayPage(); } else if ((row8 & KEY_FLAG(KEY_DOWN)) == 0) { if (g_SrcModeIndex < numberof(g_Settings) - 1) g_SrcModeIndex++; else g_SrcModeIndex = 0; DisplayPage(); } // Change page if ((row8 & KEY_FLAG(KEY_LEFT)) == 0) { if (g_CmdModeIndex > 0) g_CmdModeIndex--; else g_CmdModeIndex = numberof(g_Page) - 1; DisplayPage(); } else if ((row8 & KEY_FLAG(KEY_RIGHT)) == 0) { if (g_CmdModeIndex < numberof(g_Page) - 1) g_CmdModeIndex++; else g_CmdModeIndex = 0; DisplayPage(); } if (bEditing) { DisplayPage(); bEditing = FALSE; } if (Keyboard_IsKeyPressed(KEY_ESC)) bContinue = FALSE; u8 row0 = Keyboard_Read(KEY_ROW(KEY_0)); if ((row0 & KEY_FLAG(KEY_1)) == 0) VDP_SetPage(1); else if ((row0 & KEY_FLAG(KEY_2)) == 0) VDP_SetPage(2); else if ((row0 & KEY_FLAG(KEY_3)) == 0) VDP_SetPage(3); else VDP_SetPage(0); } if (bEditing) VDP_SetSpriteExUniColor(0, SX, SY-1, 0, 0x8); else VDP_SetSpriteExUniColor(0, SX, (((g_Frame >> 3) & 1) == 0) ? SY-1 : 212, 0, 0xF); WaitVBlank(); } BIOS_ClearHook(H_TIMI); BIOS_Exit(0); }