#include #include #include "mem.h" const u8 apple_font[] = { 0x00, 0x70, 0x88, 0xa8, 0xe8, 0x68, 0x08, 0xf0, 0x00, 0x20, 0x50, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x78, 0x88, 0x88, 0x78, 0x88, 0x88, 0x78, 0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x78, 0x00, 0xf8, 0x08, 0x08, 0x78, 0x08, 0x08, 0xf8, 0x00, 0xf8, 0x08, 0x08, 0x78, 0x08, 0x08, 0x08, 0x00, 0xf0, 0x08, 0x08, 0x08, 0xc8, 0x88, 0xf0, 0x00, 0x88, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x88, 0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x70, 0x00, 0x88, 0x48, 0x28, 0x18, 0x28, 0x48, 0x88, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x88, 0xd8, 0xa8, 0xa8, 0x88, 0x88, 0x88, 0x00, 0x88, 0x88, 0x98, 0xa8, 0xc8, 0x88, 0x88, 0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x78, 0x88, 0x88, 0x78, 0x08, 0x08, 0x08, 0x00, 0x70, 0x88, 0x88, 0x88, 0xa8, 0x48, 0xb0, 0x00, 0x78, 0x88, 0x88, 0x78, 0x28, 0x48, 0x88, 0x00, 0x70, 0x88, 0x08, 0x70, 0x80, 0x88, 0x70, 0x00, 0xf8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, 0x88, 0x88, 0x88, 0xa8, 0xa8, 0xd8, 0x88, 0x00, 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00, 0xf8, 0x80, 0x40, 0x20, 0x10, 0x08, 0xf8, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0xf8, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf8, 0x00, 0x00, 0x00, 0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0xf8, 0x50, 0xf8, 0x50, 0x50, 0x00, 0x20, 0xf0, 0x28, 0x70, 0xa0, 0x78, 0x20, 0x00, 0x18, 0x98, 0x40, 0x20, 0x10, 0xc8, 0xc0, 0x00, 0x10, 0x28, 0x28, 0x10, 0xa8, 0x48, 0xb0, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x20, 0x40, 0x80, 0x80, 0x80, 0x40, 0x20, 0x00, 0x20, 0xa8, 0x70, 0x20, 0x70, 0xa8, 0x20, 0x00, 0x00, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x70, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x70, 0x00, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x70, 0x88, 0x80, 0x60, 0x10, 0x08, 0xf8, 0x00, 0xf8, 0x80, 0x40, 0x60, 0x80, 0x88, 0x70, 0x00, 0x40, 0x60, 0x50, 0x48, 0xf8, 0x40, 0x40, 0x00, 0xf8, 0x08, 0x78, 0x80, 0x80, 0x88, 0x70, 0x00, 0xe0, 0x10, 0x08, 0x78, 0x88, 0x88, 0x70, 0x00, 0xf8, 0x80, 0x40, 0x20, 0x10, 0x10, 0x10, 0x00, 0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00, 0x70, 0x88, 0x88, 0xf0, 0x80, 0x40, 0x38, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x20, 0x10, 0x00, 0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00, 0x70, 0x88, 0x40, 0x20, 0x20, 0x00, 0x20 }; static const u16 video_addr[] DTCM_DATA = { 0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8, 0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0 }; static const u16 palette[] = { RGB15(0, 0, 0), RGB15(28, 4, 12), RGB15(12, 9, 23), RGB15(31, 8, 31), RGB15(0, 20, 12), RGB15(19, 19, 19), RGB15(2, 25, 31), RGB15(25, 24, 31), RGB15(12, 14, 0), RGB15(31, 13, 7), RGB15(19, 19, 19), RGB15(31, 19, 25), RGB15(2, 30, 7), RGB15(25, 27, 17), RGB15(14, 31, 25), RGB15(31, 31, 31), }; static int text_bg; static int gfx_bg; static int text_mode; static int mixed_mode; static int sel_page; static int hires; void video_set_mode (); void video_save (FILE *f) { fwrite(&text_mode, 1, 4, f); fwrite(&mixed_mode, 1, 4, f); fwrite(&sel_page, 1, 4, f); fwrite(&hires, 1, 4, f); } void video_load (FILE *f) { fread(&text_mode, 1, 4, f); fread(&mixed_mode, 1, 4, f); fread(&sel_page, 1, 4, f); fread(&hires, 1, 4, f); video_set_mode(); } void video_set_mode () { if (mixed_mode) { bgShow(gfx_bg); bgShow(text_bg); REG_DISPCNT |= DISPLAY_WIN0_ON; } else { bgShow(text_mode ? text_bg : gfx_bg); bgHide(text_mode ? gfx_bg : text_bg); REG_DISPCNT &= ~DISPLAY_WIN0_ON; } } u8 video_io_read (u16 addr) ITCM_CODE; u8 video_io_read (u16 addr) { switch (addr&0xf) { case 0x0: text_mode = 0; break; case 0x1: text_mode = 1; break; case 0x2: mixed_mode = 0; break; case 0x3: mixed_mode = 1; break; case 0x4: sel_page = 1; break; case 0x5: sel_page = 2; break; case 0x6: hires = 0; break; case 0x7: hires = 1; break; // Annunciators case 0x8: case 0xa: case 0xc: case 0xe: break; } video_set_mode(); // Duh, some scrollers wont work if we don't return 0x80 // http://rich12345.tripod.com/aiivideo/vbl.html return 0x80; } void draw_lores_scr (u16 *map) ITCM_CODE; void draw_lores_scr (u16 *map) { int last_line; int i, j; u8 *ptr; if (!page_dirty[sel_page]) return; last_line = mixed_mode ? 168 : 192; for (i = 0; i < last_line; i++) { ptr = (u8 *)(mainram + (sel_page << 10) + video_addr[i/8]); for (j = 0; j < 40/2; j++) { const u8 col_a = ((i&0x7)>=4) ? (*ptr>>4) : (*ptr&0xf); ptr++; const u8 col_b = ((i&0x7)>=4) ? (*ptr>>4) : (*ptr&0xf); ptr++; *map++ = col_a << 8 | col_a; *map++ = col_a << 8 | col_a; *map++ = col_a << 8 | col_a; *map++ = col_b << 8 | col_a; *map++ = col_b << 8 | col_b; *map++ = col_b << 8 | col_b; *map++ = col_b << 8 | col_b; } map += 232/2; } } /*odd_color = (b1&0x80) ? 6 : 3;*/ /*even_color = (b1&0x80) ? 9 : 12;*/ void draw_hires_scr_1 (u16 *map) { int last_line; int i, j, k; u8 *ptr, tmp; static u8 tmp_line[0x200]; static const u8 color_lut[] DTCM_DATA = { 0, 12, 0, 15, 0, 9, 0, 15, 0, 3, 0, 15, 0, 6, 0, 15 }; last_line = mixed_mode ? 168 : 192; for (i = 0; i < last_line; i++, map += 0x100) { if (!page_dirty[8 + (i&7)]) continue; ptr = mainram + (sel_page << 13) + ((i&7) * 0x400) + video_addr[i>>3]; for (j = 0, tmp = 0; j < 280; j += 7) { const u8 b1 = *ptr++; tmp = (b1&0x7f) << 1 | tmp; // embb // e = even / odd // m = msb // b = data for (k = 0; k <= 7; k++) tmp_line[j+k] = color_lut[(((j+k)&1) ? 0x8 : 0x0) + ((b1&0x80)>>5) + ((tmp>>k)&3)]; tmp >>= 7; } dmaCopyAsynch(tmp_line, map, 0x200); } } void draw_hires_scr (u16 *map) ITCM_CODE; void draw_hires_scr (u16 *map) { int last_line; int i, j, k, x; u8 *xptr, *ptr, tmp; u16 *omap; static u8 tmp_line[0x200]; static const u8 color_lut[] DTCM_DATA = { 0, 12, 0, 15, 0, 9, 0, 15, 0, 3, 0, 15, 0, 6, 0, 15 }; last_line = mixed_mode ? 168/8 : 192/8; for(x = 0; x < 8; x++, map += 0x100) { if (!page_dirty[8+x]) continue; xptr = mainram + (sel_page << 13) + (x << 10); for(omap = map, i = 0; i < last_line; i++, omap += 0x800) { ptr = xptr + video_addr[i]; for (j = 0, tmp = 0; j < 280; j += 7) { const u8 b1 = *ptr++; tmp = (b1&0x7f) << 1 | tmp; const u8 *lut_b = color_lut + ((b1&0x80)>>5); for (k = 0; k < 7; k+=2) { tmp_line[j+k+0] = lut_b[((j&1) << 3) + (tmp&3)]; tmp >>= 1; if(k == 6) break; tmp_line[j+k+1] = lut_b[((~j&1) << 3) + (tmp&3)]; tmp >>= 1; } } dmaCopyAsynch(tmp_line, omap, 0x200); /*memcpy(omap, tmp_line, 0x200);*/ } page_dirty[8+x] = 0; } } void draw_text_scr (u16 *map) ITCM_CODE; void draw_text_scr (u16 *map) { int start_line; int i, j; u16 *ptr; if (!page_dirty[sel_page]) return; if ((start_line = mixed_mode ? 21 : 0)) map += 32 * start_line; for (i = start_line; i < 24; i++) { ptr = (u16 *)(mainram + (sel_page << 10) + video_addr[i]); for (j = 0; j < 5; j++) { *map++ = (*ptr++)&0x3f3f; *map++ = (*ptr++)&0x3f3f; *map++ = (*ptr++)&0x3f3f; *map++ = (*ptr++)&0x3f3f; } map += 12; } } void video_draw () ITCM_CODE; void video_draw () { u16 *text_ptr = (u16 *)0x6002000; u16 *gfx_ptr = (u16 *)0x6020000; if (mixed_mode) { draw_text_scr(text_ptr); (hires) ? draw_hires_scr(gfx_ptr) : draw_lores_scr(gfx_ptr); } else { if (text_mode) draw_text_scr(text_ptr); else if (hires) draw_hires_scr(gfx_ptr); else draw_lores_scr(gfx_ptr); } // Clear this here otherwise we won't be able to render a lores // screen after the text one page_dirty[sel_page] = 0; } int video_set_scale (int mode) { int scale_x; int scale_y; switch (mode) { default: case 0: scale_x = floatToFixed(1., 8); scale_y = floatToFixed(1., 8); break; case 1: // 280 / 256 = 1.09 scale_x = floatToFixed(1.09, 8); scale_y = floatToFixed(1., 8); break; } bgSetScale(gfx_bg, scale_x, scale_y); bgSetScale(text_bg, scale_x, scale_y); return 1; } void video_init () { videoSetMode(MODE_4_2D); vramSetBankA(VRAM_A_MAIN_BG_0x06000000); vramSetBankB(VRAM_B_MAIN_BG_0x06020000); // http://mtheall.com/vram.html#T2=3&NT2=128&MB2=4&TB2=0&S2=2&T3=5&NT3=32&MB3=8&TB3=1&S3=3 text_bg = bgInit(2, BgType_Rotation, BgSize_R_512x512, 4, 0); gfx_bg = bgInit(3, BgType_Bmp8, BgSize_B8_512x256, 8, 0); REG_DISPCNT &= ~DISPLAY_WIN0_ON; // Setup the window used for mixed mode WIN0_X0 = 0; WIN0_X1 = 255; WIN0_Y0 = 0; WIN0_Y1 = 160; // BG3 inside WIN_IN = 0x8; // BG2 outside WIN_OUT = 0x4; memcpy(BG_PALETTE, palette, sizeof(palette)); struct UnpackStruct unpack_bit; unpack_bit.dataOffset = 14; unpack_bit.destWidth = 8; unpack_bit.sourceSize = 64*8; unpack_bit.sourceWidth = 1; swiUnpackBits((u8 *)&apple_font, (u32 *)bgGetGfxPtr(text_bg), &unpack_bit); }