-//\r
-// Apple 2 video support\r
-//\r
-// All the video modes that a real Apple 2 supports are handled here\r
-//\r
-// by James L. Hammons\r
-// (c) 2005 Underground Software\r
-//\r
-// JLH = James L. Hammons <jlhamm@acm.org>\r
-//\r
-// WHO WHEN WHAT\r
-// --- ---------- ------------------------------------------------------------\r
-// JLH 12/01/2005 Added color TV/monochrome emulation to hi-res code\r
-// JLH 12/09/2005 Cleaned up color TV emulation code\r
-// JLH 12/09/2005 Fixed lo-res color TV/mono emulation modes\r
-//\r
-// STILL TO DO:\r
-//\r
-// - Fix LoRes mode green mono to skip every other scanline instead of fill\r
-// like white mono does\r
-// - Double HiRes\r
-// - 80 column text\r
-// - Fix OSD text display so that it's visible no matter what background is there [DONE]\r
-//\r
-\r
-// Display routines seem MUCH slower now... !!! INVESTIGATE !!!\r
-\r
-#include "applevideo.h"\r
-\r
-#include <string.h> // for memset()\r
-#include <stdarg.h> // for va_* stuff\r
-#include <string> // for vsprintf()\r
-#include "apple2.h"\r
-#include "video.h"\r
-#include "charset.h"\r
-#include "font14pt.h"\r
-\r
-/* Reference: Technote tn-iigs-063 "Master Color Values"\r
-\r
- Color Color Register LR HR DHR Master Color R,G,B\r
- Name Value # # # Value\r
- ----------------------------------------------------\r
- Black 0 0 0,4 0 $0000 (0,0,0)\r
-(Magenta) Deep Red 1 1 1 $0D03 (D,0,3)\r
- Dark Blue 2 2 8 $0009 (0,0,9)\r
- (Violet) Purple 3 3 2 9 $0D2D (D,2,D)\r
- Dark Green 4 4 4 $0072 (0,7,2)\r
- (Gray 1) Dark Gray 5 5 5 $0555 (5,5,5)\r
- (Blue) Medium Blue 6 6 6 C $022F (2,2,F)\r
- (Cyan) Light Blue 7 7 D $06AF (6,A,F)\r
- Brown 8 8 2 $0850 (8,5,0)\r
- Orange 9 9 5 3 $0F60 (F,6,0)\r
- (Gray 2) Light Gray A A A $0AAA (A,A,A)\r
- Pink B B B $0F98 (F,9,8)\r
- (Green) Light Green C C 1 6 $01D0 (1,D,0)\r
- Yellow D D 7 $0FF0 (F,F,0)\r
- (Aqua) Aquamarine E E E $04F9 (4,F,9)\r
- White F F 3,7 F $0FFF (F,F,F)\r
-\r
- LR: Lo-Res HR: Hi-Res DHR: Double Hi-Res */\r
-\r
-// Global variables\r
-\r
-bool flash;\r
-bool textMode;\r
-bool mixedMode;\r
-bool displayPage2;\r
-bool hiRes;\r
-bool alternateCharset;\r
-//void SpawnMessage(const char * text, ...);\r
-\r
-// Local variables\r
-\r
-// We set up the colors this way so that they'll be endian safe\r
-// when we cast them to a uint32.\r
-\r
-// "Master Color Values" palette\r
-\r
-static uint8 colors[16 * 4] = {\r
- 0x00, 0x00, 0x00, 0xFF, // Black\r
- 0xDD, 0x00, 0x33, 0xFF, // Deep Red (Magenta)\r
- 0x00, 0x00, 0x99, 0xFF, // Dark Blue\r
- 0xDD, 0x22, 0xDD, 0xFF, // Purple (Violet)\r
- 0x00, 0x77, 0x22, 0xFF, // Dark Green\r
- 0x55, 0x55, 0x55, 0xFF, // Dark Gray (Gray 1)\r
- 0x22, 0x22, 0xFF, 0xFF, // Medium Blue (Blue)\r
- 0x66, 0xAA, 0xFF, 0xFF, // Light Blue (Cyan)\r
- 0x88, 0x55, 0x00, 0xFF, // Brown\r
- 0xFF, 0x66, 0x00, 0xFF, // Orange\r
- 0xAA, 0xAA, 0xAA, 0xFF, // Light Gray (Gray 2)\r
- 0xFF, 0x99, 0x88, 0xFF, // Pink\r
- 0x11, 0xDD, 0x00, 0xFF, // Light Green (Green)\r
- 0xFF, 0xFF, 0x00, 0xFF, // Yellow\r
- 0x44, 0xFF, 0x99, 0xFF, // Aquamarine (Aqua)\r
- 0xFF, 0xFF, 0xFF, 0xFF // White\r
-};\r
-\r
-// This palette comes from ApplePC's colors (more realistic to my eye ;-)\r
-\r
-static uint8 altColors[16 * 4] = {\r
- 0x00, 0x00, 0x00, 0xFF,\r
- 0x7D, 0x20, 0x41, 0xFF,\r
- 0x41, 0x30, 0x7D, 0xFF,\r
- 0xBE, 0x51, 0xBE, 0xFF,\r
- 0x00, 0x5D, 0x3C, 0xFF,\r
- 0x7D, 0x7D, 0x7D, 0xFF,\r
- 0x41, 0x8E, 0xBA, 0xFF,\r
- 0xBE, 0xAE, 0xFB, 0xFF,\r
- 0x3C, 0x4D, 0x00, 0xFF,\r
- 0xBA, 0x6D, 0x41, 0xFF,\r
- 0x7D, 0x7D, 0x7D, 0xFF,\r
- 0xFB, 0x9E, 0xBE, 0xFF,\r
- 0x3C, 0xAA, 0x3C, 0xFF,\r
- 0xBA, 0xCB, 0x7D, 0xFF,\r
- 0x7D, 0xDB, 0xBA, 0xFF,\r
- 0xFB, 0xFB, 0xFB, 0xFF };\r
-\r
-// Lo-res starting line addresses\r
-\r
-static uint16 lineAddrLoRes[24] = {\r
- 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780,\r
- 0x0428, 0x04A8, 0x0528, 0x05A8, 0x0628, 0x06A8, 0x0728, 0x07A8,\r
- 0x0450, 0x04D0, 0x0550, 0x05D0, 0x0650, 0x06D0, 0x0750, 0x07D0 };\r
-\r
-// Hi-res starting line addresses\r
-\r
-static uint16 lineAddrHiRes[192] = {\r
- 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,\r
- 0x2080, 0x2480, 0x2880, 0x2C80, 0x3080, 0x3480, 0x3880, 0x3C80,\r
- 0x2100, 0x2500, 0x2900, 0x2D00, 0x3100, 0x3500, 0x3900, 0x3D00,\r
- 0x2180, 0x2580, 0x2980, 0x2D80, 0x3180, 0x3580, 0x3980, 0x3D80,\r
-\r
- 0x2200, 0x2600, 0x2A00, 0x2E00, 0x3200, 0x3600, 0x3A00, 0x3E00,\r
- 0x2280, 0x2680, 0x2A80, 0x2E80, 0x3280, 0x3680, 0x3A80, 0x3E80,\r
- 0x2300, 0x2700, 0x2B00, 0x2F00, 0x3300, 0x3700, 0x3B00, 0x3F00,\r
- 0x2380, 0x2780, 0x2B80, 0x2F80, 0x3380, 0x3780, 0x3B80, 0x3F80,\r
-\r
- 0x2028, 0x2428, 0x2828, 0x2C28, 0x3028, 0x3428, 0x3828, 0x3C28,\r
- 0x20A8, 0x24A8, 0x28A8, 0x2CA8, 0x30A8, 0x34A8, 0x38A8, 0x3CA8,\r
- 0x2128, 0x2528, 0x2928, 0x2D28, 0x3128, 0x3528, 0x3928, 0x3D28,\r
- 0x21A8, 0x25A8, 0x29A8, 0x2DA8, 0x31A8, 0x35A8, 0x39A8, 0x3DA8,\r
-\r
- 0x2228, 0x2628, 0x2A28, 0x2E28, 0x3228, 0x3628, 0x3A28, 0x3E28,\r
- 0x22A8, 0x26A8, 0x2AA8, 0x2EA8, 0x32A8, 0x36A8, 0x3AA8, 0x3EA8,\r
- 0x2328, 0x2728, 0x2B28, 0x2F28, 0x3328, 0x3728, 0x3B28, 0x3F28,\r
- 0x23A8, 0x27A8, 0x2BA8, 0x2FA8, 0x33A8, 0x37A8, 0x3BA8, 0x3FA8,\r
-\r
- 0x2050, 0x2450, 0x2850, 0x2C50, 0x3050, 0x3450, 0x3850, 0x3C50,\r
- 0x20D0, 0x24D0, 0x28D0, 0x2CD0, 0x30D0, 0x34D0, 0x38D0, 0x3CD0,\r
- 0x2150, 0x2550, 0x2950, 0x2D50, 0x3150, 0x3550, 0x3950, 0x3D50,\r
- 0x21D0, 0x25D0, 0x29D0, 0x2DD0, 0x31D0, 0x35D0, 0x39D0, 0x3DD0,\r
-\r
- 0x2250, 0x2650, 0x2A50, 0x2E50, 0x3250, 0x3650, 0x3A50, 0x3E50,\r
- 0x22D0, 0x26D0, 0x2AD0, 0x2ED0, 0x32D0, 0x36D0, 0x3AD0, 0x3ED0,\r
- 0x2350, 0x2750, 0x2B50, 0x2F50, 0x3350, 0x3750, 0x3B50, 0x3F50,\r
- 0x23D0, 0x27D0, 0x2BD0, 0x2FD0, 0x33D0, 0x37D0, 0x3BD0, 0x3FD0 };\r
-\r
-uint16 appleHiresToMono[0x200] = {\r
- 0x0000, 0x3000, 0x0C00, 0x3C00, 0x0300, 0x3300, 0x0F00, 0x3F00,\r
- 0x00C0, 0x30C0, 0x0CC0, 0x3CC0, 0x03C0, 0x33C0, 0x0FC0, 0x3FC0, // $0x\r
- 0x0030, 0x3030, 0x0C30, 0x3C30, 0x0330, 0x3330, 0x0F30, 0x3F30,\r
- 0x00F0, 0x30F0, 0x0CF0, 0x3CF0, 0x03F0, 0x33F0, 0x0FF0, 0x3FF0, // $1x\r
- 0x000C, 0x300C, 0x0C0C, 0x3C0C, 0x030C, 0x330C, 0x0F0C, 0x3F0C,\r
- 0x00CC, 0x30CC, 0x0CCC, 0x3CCC, 0x03CC, 0x33CC, 0x0FCC, 0x3FCC, // $2x\r
- 0x003C, 0x303C, 0x0C3C, 0x3C3C, 0x033C, 0x333C, 0x0F3C, 0x3F3C,\r
- 0x00FC, 0x30FC, 0x0CFC, 0x3CFC, 0x03FC, 0x33FC, 0x0FFC, 0x3FFC, // $3x\r
- 0x0003, 0x3003, 0x0C03, 0x3C03, 0x0303, 0x3303, 0x0F03, 0x3F03,\r
- 0x00C3, 0x30C3, 0x0CC3, 0x3CC3, 0x03C3, 0x33C3, 0x0FC3, 0x3FC3, // $4x\r
- 0x0033, 0x3033, 0x0C33, 0x3C33, 0x0333, 0x3333, 0x0F33, 0x3F33,\r
- 0x00F3, 0x30F3, 0x0CF3, 0x3CF3, 0x03F3, 0x33F3, 0x0FF3, 0x3FF3, // $5x\r
- 0x000F, 0x300F, 0x0C0F, 0x3C0F, 0x030F, 0x330F, 0x0F0F, 0x3F0F,\r
- 0x00CF, 0x30CF, 0x0CCF, 0x3CCF, 0x03CF, 0x33CF, 0x0FCF, 0x3FCF, // $6x\r
- 0x003F, 0x303F, 0x0C3F, 0x3C3F, 0x033F, 0x333F, 0x0F3F, 0x3F3F,\r
- 0x00FF, 0x30FF, 0x0CFF, 0x3CFF, 0x03FF, 0x33FF, 0x0FFF, 0x3FFF, // $7x\r
- 0x0000, 0x1800, 0x0600, 0x1E00, 0x0180, 0x1980, 0x0780, 0x1F80,\r
- 0x0060, 0x1860, 0x0660, 0x1E60, 0x01E0, 0x19E0, 0x07E0, 0x1FE0, // $8x\r
- 0x0018, 0x1818, 0x0618, 0x1E18, 0x0198, 0x1998, 0x0798, 0x1F98,\r
- 0x0078, 0x1878, 0x0678, 0x1E78, 0x01F8, 0x19F8, 0x07F8, 0x1FF8, // $9x\r
- 0x0006, 0x1806, 0x0606, 0x1E06, 0x0186, 0x1986, 0x0786, 0x1F86,\r
- 0x0066, 0x1866, 0x0666, 0x1E66, 0x01E6, 0x19E6, 0x07E6, 0x1FE6, // $Ax\r
- 0x001E, 0x181E, 0x061E, 0x1E1E, 0x019E, 0x199E, 0x079E, 0x1F9E,\r
- 0x007E, 0x187E, 0x067E, 0x1E7E, 0x01FE, 0x19FE, 0x07FE, 0x1FFE, // $Bx\r
- 0x0001, 0x1801, 0x0601, 0x1E01, 0x0181, 0x1981, 0x0781, 0x1F81,\r
- 0x0061, 0x1861, 0x0661, 0x1E61, 0x01E1, 0x19E1, 0x07E1, 0x1FE1, // $Cx\r
- 0x0019, 0x1819, 0x0619, 0x1E19, 0x0199, 0x1999, 0x0799, 0x1F99,\r
- 0x0079, 0x1879, 0x0679, 0x1E79, 0x01F9, 0x19F9, 0x07F9, 0x1FF9, // $Dx\r
- 0x0007, 0x1807, 0x0607, 0x1E07, 0x0187, 0x1987, 0x0787, 0x1F87,\r
- 0x0067, 0x1867, 0x0667, 0x1E67, 0x01E7, 0x19E7, 0x07E7, 0x1FE7, // $Ex\r
- 0x001F, 0x181F, 0x061F, 0x1E1F, 0x019F, 0x199F, 0x079F, 0x1F9F,\r
- 0x007F, 0x187F, 0x067F, 0x1E7F, 0x01FF, 0x19FF, 0x07FF, 0x1FFF, // $Fx\r
-\r
- // Second half adds in the previous byte's lo pixel\r
-\r
- 0x0000, 0x3000, 0x0C00, 0x3C00, 0x0300, 0x3300, 0x0F00, 0x3F00,\r
- 0x00C0, 0x30C0, 0x0CC0, 0x3CC0, 0x03C0, 0x33C0, 0x0FC0, 0x3FC0, // $0x\r
- 0x0030, 0x3030, 0x0C30, 0x3C30, 0x0330, 0x3330, 0x0F30, 0x3F30,\r
- 0x00F0, 0x30F0, 0x0CF0, 0x3CF0, 0x03F0, 0x33F0, 0x0FF0, 0x3FF0, // $1x\r
- 0x000C, 0x300C, 0x0C0C, 0x3C0C, 0x030C, 0x330C, 0x0F0C, 0x3F0C,\r
- 0x00CC, 0x30CC, 0x0CCC, 0x3CCC, 0x03CC, 0x33CC, 0x0FCC, 0x3FCC, // $2x\r
- 0x003C, 0x303C, 0x0C3C, 0x3C3C, 0x033C, 0x333C, 0x0F3C, 0x3F3C,\r
- 0x00FC, 0x30FC, 0x0CFC, 0x3CFC, 0x03FC, 0x33FC, 0x0FFC, 0x3FFC, // $3x\r
- 0x0003, 0x3003, 0x0C03, 0x3C03, 0x0303, 0x3303, 0x0F03, 0x3F03,\r
- 0x00C3, 0x30C3, 0x0CC3, 0x3CC3, 0x03C3, 0x33C3, 0x0FC3, 0x3FC3, // $4x\r
- 0x0033, 0x3033, 0x0C33, 0x3C33, 0x0333, 0x3333, 0x0F33, 0x3F33,\r
- 0x00F3, 0x30F3, 0x0CF3, 0x3CF3, 0x03F3, 0x33F3, 0x0FF3, 0x3FF3, // $5x\r
- 0x000F, 0x300F, 0x0C0F, 0x3C0F, 0x030F, 0x330F, 0x0F0F, 0x3F0F,\r
- 0x00CF, 0x30CF, 0x0CCF, 0x3CCF, 0x03CF, 0x33CF, 0x0FCF, 0x3FCF, // $6x\r
- 0x003F, 0x303F, 0x0C3F, 0x3C3F, 0x033F, 0x333F, 0x0F3F, 0x3F3F,\r
- 0x00FF, 0x30FF, 0x0CFF, 0x3CFF, 0x03FF, 0x33FF, 0x0FFF, 0x3FFF, // $7x\r
- 0x2000, 0x3800, 0x2600, 0x3E00, 0x2180, 0x3980, 0x2780, 0x3F80,\r
- 0x2060, 0x3860, 0x2660, 0x3E60, 0x21E0, 0x39E0, 0x27E0, 0x3FE0, // $8x\r
- 0x2018, 0x3818, 0x2618, 0x3E18, 0x2198, 0x3998, 0x2798, 0x3F98,\r
- 0x2078, 0x3878, 0x2678, 0x3E78, 0x21F8, 0x39F8, 0x27F8, 0x3FF8, // $9x\r
- 0x2006, 0x3806, 0x2606, 0x3E06, 0x2186, 0x3986, 0x2786, 0x3F86,\r
- 0x2066, 0x3866, 0x2666, 0x3E66, 0x21E6, 0x39E6, 0x27E6, 0x3FE6, // $Ax\r
- 0x201E, 0x381E, 0x261E, 0x3E1E, 0x219E, 0x399E, 0x279E, 0x3F9E,\r
- 0x207E, 0x387E, 0x267E, 0x3E7E, 0x21FE, 0x39FE, 0x27FE, 0x3FFE, // $Bx\r
- 0x2001, 0x3801, 0x2601, 0x3E01, 0x2181, 0x3981, 0x2781, 0x3F81,\r
- 0x2061, 0x3861, 0x2661, 0x3E61, 0x21E1, 0x39E1, 0x27E1, 0x3FE1, // $Cx\r
- 0x2019, 0x3819, 0x2619, 0x3E19, 0x2199, 0x3999, 0x2799, 0x3F99,\r
- 0x2079, 0x3879, 0x2679, 0x3E79, 0x21F9, 0x39F9, 0x27F9, 0x3FF9, // $Dx\r
- 0x2007, 0x3807, 0x2607, 0x3E07, 0x2187, 0x3987, 0x2787, 0x3F87,\r
- 0x2067, 0x3867, 0x2667, 0x3E67, 0x21E7, 0x39E7, 0x27E7, 0x3FE7, // $Ex\r
- 0x201F, 0x381F, 0x261F, 0x3E1F, 0x219F, 0x399F, 0x279F, 0x3F9F,\r
- 0x207F, 0x387F, 0x267F, 0x3E7F, 0x21FF, 0x39FF, 0x27FF, 0x3FFF // $Fx\r
-};\r
-\r
-static uint8 blurTable[0x800][8]; // Color TV blur table\r
-static uint32 * palette = (uint32 *)altColors;\r
-enum { ST_FIRST_ENTRY = 0, ST_COLOR_TV = 0, ST_WHITE_MONO, ST_GREEN_MONO, ST_LAST_ENTRY };\r
-static uint8 screenType = ST_COLOR_TV;\r
-\r
-// Local functions\r
-\r
-static void Render40ColumnTextLine(uint8 line);\r
-static void Render40ColumnText(void);\r
-static void RenderLoRes(uint16 toLine = 24);\r
-static void RenderHiRes(uint16 toLine = 192);\r
-\r
-\r
-void SetupBlurTable(void)\r
-{\r
- // NOTE: This table only needs to be 7 bits wide instead of 11, since the\r
- // last four bits are copies of the previous four...\r
-\r
- for(uint16 bitPat=0; bitPat<0x800; bitPat++)\r
- {\r
- uint16 w3 = bitPat & 0x888;\r
- uint16 w2 = bitPat & 0x444;\r
- uint16 w1 = bitPat & 0x222;\r
- uint16 w0 = bitPat & 0x111;\r
-\r
- uint16 blurred3 = (w3 | (w3 >> 1) | (w3 >> 2) | (w3 >> 3)) & 0x00FF;\r
- uint16 blurred2 = (w2 | (w2 >> 1) | (w2 >> 2) | (w2 >> 3)) & 0x00FF;\r
- uint16 blurred1 = (w1 | (w1 >> 1) | (w1 >> 2) | (w1 >> 3)) & 0x00FF;\r
- uint16 blurred0 = (w0 | (w0 >> 1) | (w0 >> 2) | (w0 >> 3)) & 0x00FF;\r
-\r
- for(int8 i=7; i>=0; i--)\r
- {\r
- uint8 color = (((blurred0 >> i) & 0x01) << 3)\r
- | (((blurred1 >> i) & 0x01) << 2)\r
- | (((blurred2 >> i) & 0x01) << 1)\r
- | ((blurred3 >> i) & 0x01);\r
- blurTable[bitPat][7 - i] = color;\r
- }\r
- }\r
-}\r
-\r
-void TogglePalette(void)\r
-{\r
- if (palette == (uint32 *)colors)\r
- {\r
- palette = (uint32 *)altColors;\r
- SpawnMessage("Color TV palette");\r
- }\r
- else\r
- {\r
- palette = (uint32 *)colors;\r
- SpawnMessage("\"Master Color Values\" palette");\r
- }\r
-}\r
-\r
-void CycleScreenTypes(void)\r
-{\r
- char scrTypeStr[3][40] = { "Color TV", "White monochrome", "Green monochrome" };\r
-\r
- screenType++;\r
-\r
- if (screenType == ST_LAST_ENTRY)\r
- screenType = ST_FIRST_ENTRY;\r
-\r
- SpawnMessage("%s", scrTypeStr[screenType]);\r
-}\r
-\r
-static uint32 msgTicks = 0;\r
-static char message[4096];\r
-\r
-void SpawnMessage(const char * text, ...)\r
-{\r
- va_list arg;\r
-\r
- va_start(arg, text);\r
- vsprintf(message, text, arg);\r
- va_end(arg);\r
-\r
- msgTicks = 120;\r
-}\r
-\r
-static void DrawString2(uint32 x, uint32 y, uint32 color);\r
-static void DrawString(void)\r
-{\r
-//This approach works, and seems to be fast enough... Though it probably would\r
-//be better to make the oversized font to match this one...\r
- for(uint32 x=7; x<=9; x++)\r
- for(uint32 y=7; y<=9; y++)\r
- DrawString2(x, y, 0x00000000);\r
-\r
- DrawString2(8, 8, 0x0020FF20);\r
-}\r
-\r
-static void DrawString2(uint32 x, uint32 y, uint32 color)\r
-{\r
-//uint32 x = 8, y = 8;\r
- uint32 length = strlen(message), address = x + (y * VIRTUAL_SCREEN_WIDTH);\r
-// uint32 color = 0x0020FF20;\r
-//This could be done ahead of time, instead of on each pixel...\r
-//(Now it is!)\r
- uint8 nBlue = (color >> 16) & 0xFF, nGreen = (color >> 8) & 0xFF, nRed = color & 0xFF;\r
-\r
- for(uint32 i=0; i<length; i++)\r
- {\r
- uint8 c = message[i];\r
- c = (c < 32 ? 0 : c - 32);\r
- uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;\r
-\r
- for(uint32 yy=0; yy<FONT_HEIGHT; yy++)\r
- {\r
- for(uint32 xx=0; xx<FONT_WIDTH; xx++)\r
- {\r
-/* uint8 fontTrans = font1[fontAddr++];\r
-// uint32 newTrans = (fontTrans * transparency / 255) << 24;\r
- uint32 newTrans = fontTrans << 24;\r
- uint32 pixel = newTrans | color;\r
-\r
- *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = pixel;//*/\r
-\r
- uint8 trans = font1[fontAddr++];\r
-\r
- if (trans)\r
- {\r
- uint32 existingColor = *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH));\r
-\r
- uint8 eBlue = (existingColor >> 16) & 0xFF,\r
- eGreen = (existingColor >> 8) & 0xFF,\r
- eRed = existingColor & 0xFF;\r
-\r
-//This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)\r
-//Here we've modified it to have 33 levels of transparency (could have any # we want!)\r
-//because dividing by 32 is faster than dividing by 31...!\r
- uint8 invTrans = 255 - trans;\r
-\r
- uint32 bRed = (eRed * invTrans + nRed * trans) / 255;\r
- uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;\r
- uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;\r
-\r
-//THIS IS NOT ENDIAN SAFE\r
- *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;\r
- }\r
- }\r
- }\r
-\r
- address += FONT_WIDTH;\r
- }\r
-}\r
-\r
-static void Render40ColumnTextLine(uint8 line)\r
-{\r
- uint32 pixelOn = (screenType == ST_GREEN_MONO ? 0xFF61FF61 : 0xFFFFFFFF);\r
-\r
- for(int x=0; x<40; x++)\r
- {\r
- uint8 chr = ram[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x];\r
-\r
- // Render character at (x, y)\r
-\r
- for(int cy=0; cy<8; cy++)\r
- {\r
- for(int cx=0; cx<7; cx++)\r
- {\r
- uint32 pixel = 0xFF000000;\r
-\r
- if (!alternateCharset)\r
- {\r
- if (textChar[((chr & 0x3F) * 56) + cx + (cy * 7)])\r
-// pixel = 0xFFFFFFFF;\r
- pixel = pixelOn;\r
-\r
- if (chr < 0x80)\r
- pixel = pixel ^ (screenType == ST_GREEN_MONO ? 0x0061FF61 : 0x00FFFFFF);\r
-\r
- if ((chr & 0xC0) == 0x40 && flash)\r
- pixel = 0xFF000000;\r
- }\r
- else\r
- {\r
- if (textChar2e[(chr * 56) + cx + (cy * 7)])\r
-// pixel = 0xFFFFFFFF;\r
- pixel = pixelOn;\r
- }\r
-\r
-// scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;\r
-// scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;\r
- scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;\r
- scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;\r
-\r
- if (screenType == ST_GREEN_MONO)\r
- pixel = 0xFF000000;\r
-\r
- {\r
- scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;\r
- scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-static void Render40ColumnText(void)\r
-{\r
- for(uint8 line=0; line<24; line++)\r
- Render40ColumnTextLine(line);\r
-}\r
-\r
-static void RenderLoRes(uint16 toLine/*= 24*/)\r
-{\r
-// NOTE: The green mono rendering doesn't skip every other line... !!! FIX !!!\r
-/*\r
-Note that these colors correspond to the bit patterns generated by the numbers 0-F in order:\r
-Color #s correspond to the bit patterns in reverse... Interesting!\r
-\r
-00 00 00 -> 0 [0000] -> 0 (lores color #)\r
-3c 4d 00 -> 8 [0001] -> 8? BROWN\r
-00 5d 3c -> 4 [0010] -> 4? DARK GREEN\r
-3c aa 3c -> 12 [0011] -> 12? LIGHT GREEN (GREEN)\r
-41 30 7d -> 2 [0100] -> 2? DARK BLUE\r
-7d 7d 7d -> 10 [0101] -> 10? LIGHT GRAY\r
-41 8e ba -> 6 [0110] -> 6? MEDIUM BLUE (BLUE)\r
-7d db ba -> 14 [0111] -> 14? AQUAMARINE (AQUA)\r
-7d 20 41 -> 1 [1000] -> 1? DEEP RED (MAGENTA)\r
-ba 6d 41 -> 9 [1001] -> 9? ORANGE\r
-7d 7d 7d -> 5 [1010] -> 5? DARK GRAY\r
-ba cb 7d -> 13 [1011] -> 13? YELLOW\r
-be 51 be -> 3 [1100] -> 3 PURPLE (VIOLET)\r
-fb 9e be -> 11 [1101] -> 11? PINK\r
-be ae fb -> 7 [1110] -> 7? LIGHT BLUE (CYAN)\r
-fb fb fb -> 15 [1111] -> 15 WHITE\r
-*/\r
- uint8 mirrorNybble[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };\r
-\r
-//This is the old "perfect monitor" rendering code...\r
-/* if (screenType != ST_COLOR_TV) // Not correct, but for now...\r
-//if (1)\r
- {\r
- for(uint16 y=0; y<toLine; y++)\r
- {\r
- for(uint16 x=0; x<40; x++)\r
- {\r
- uint8 scrByte = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x];\r
- uint32 pixel = palette[scrByte & 0x0F];\r
- \r
- for(int cy=0; cy<4; cy++)\r
- for(int cx=0; cx<14; cx++)\r
- scrBuffer[((x * 14) + cx) + (((y * 8) + cy) * VIRTUAL_SCREEN_WIDTH)] = pixel;\r
- \r
- pixel = palette[scrByte >> 4];\r
- \r
- for(int cy=4; cy<8; cy++)\r
- for(int cx=0; cx<14; cx++)\r
- scrBuffer[(x * 14) + (y * VIRTUAL_SCREEN_WIDTH * 8) + cx + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;\r
- }\r
- }\r
- }\r
- else//*/\r
-\r
- uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);\r
-\r
- for(uint16 y=0; y<toLine; y++)\r
- {\r
- // Do top half of lores screen bytes...\r
-\r
- uint32 previous3Bits = 0;\r
-\r
- for(uint16 x=0; x<40; x+=2)\r
- {\r
- uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] & 0x0F;\r
- uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] & 0x0F;\r
- scrByte1 = mirrorNybble[scrByte1];\r
- scrByte2 = mirrorNybble[scrByte2];\r
- // This is just a guess, but it'll have to do for now...\r
- uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)\r
- | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)\r
- | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;\r
-\r
- // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF\r
- // 0ppp 1111 1111 1111 11|11 1111 1111 1111\r
- // 31 27 23 19 15 11 7 3 0\r
-\r
- if (screenType == ST_COLOR_TV)\r
- {\r
- for(uint8 i=0; i<7; i++)\r
- {\r
- uint16 bitPat = (pixels & 0x7F000000) >> 20;\r
- pixels <<= 4;\r
-\r
- for(uint8 j=0; j<4; j++)\r
- {\r
- uint8 color = blurTable[bitPat][j];\r
-\r
- for(uint32 cy=0; cy<8; cy++)\r
- {\r
- scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
-// scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
- }\r
- }\r
- }\r
-\r
- previous3Bits = pixels & 0x70000000;\r
- }\r
- else\r
- {\r
- for(int j=0; j<28; j++)\r
- {\r
- for(uint32 cy=0; cy<8; cy++)\r
- {\r
- scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);\r
-// scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);\r
- }\r
-\r
- pixels <<= 1;\r
- }\r
- }\r
- }\r
-\r
- // Now do bottom half...\r
-\r
- previous3Bits = 0;\r
-\r
- for(uint16 x=0; x<40; x+=2)\r
- {\r
- uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] >> 4;\r
- uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] >> 4;\r
- scrByte1 = mirrorNybble[scrByte1];\r
- scrByte2 = mirrorNybble[scrByte2];\r
- // This is just a guess, but it'll have to do for now...\r
- uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)\r
- | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)\r
- | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;\r
-\r
- // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF\r
- // 0ppp 1111 1111 1111 11|11 1111 1111 1111\r
- // 31 27 23 19 15 11 7 3 0\r
-\r
- if (screenType == ST_COLOR_TV)\r
- {\r
- for(uint8 i=0; i<7; i++)\r
- {\r
- uint16 bitPat = (pixels & 0x7F000000) >> 20;\r
- pixels <<= 4;\r
-\r
- for(uint8 j=0; j<4; j++)\r
- {\r
- uint8 color = blurTable[bitPat][j];\r
-\r
- for(uint32 cy=8; cy<16; cy++)\r
- {\r
- scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
-// scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
- }\r
- }\r
- }\r
-\r
- previous3Bits = pixels & 0x70000000;\r
- }\r
- else\r
- {\r
- for(int j=0; j<28; j++)\r
- {\r
- for(uint32 cy=8; cy<16; cy++)\r
- {\r
- scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);\r
-// scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);\r
- }\r
-\r
- pixels <<= 1;\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-static void RenderHiRes(uint16 toLine/*= 192*/)\r
-{\r
- uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);\r
-\r
- for(uint16 y=0; y<toLine; y++)\r
- {\r
- uint16 previousLoPixel = 0;\r
- uint32 previous3bits = 0;\r
-\r
- for(uint16 x=0; x<40; x+=2)\r
- {\r
- uint8 screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x];\r
- uint32 pixels = appleHiresToMono[previousLoPixel | screenByte];\r
- previousLoPixel = (screenByte << 2) & 0x0100;\r
-\r
- screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x + 1];\r
- uint32 pixels2 = appleHiresToMono[previousLoPixel | screenByte];\r
- previousLoPixel = (screenByte << 2) & 0x0100;\r
-\r
- pixels = previous3bits | (pixels << 14) | pixels2;\r
-\r
- // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF\r
- // 0ppp 1111 1111 1111 1111 1111 1111 1111\r
- // 31 27 23 19 15 11 7 3 0\r
-\r
- if (screenType == ST_COLOR_TV)\r
- {\r
- for(uint8 i=0; i<7; i++)\r
- {\r
- uint16 bitPat = (pixels & 0x7F000000) >> 20;\r
- pixels <<= 4;\r
-\r
- for(uint8 j=0; j<4; j++)\r
- {\r
- uint8 color = blurTable[bitPat][j];\r
-#if 0\r
-//This doesn't seem to make things go any faster...\r
-//It's the OpenGL render that's faster... Hmm...\r
- scrBuffer[(x * 14) + (i * 4) + j + (y * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
-#else\r
- scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
- scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = palette[color];\r
-#endif\r
- }\r
- }\r
-\r
- previous3bits = pixels & 0x70000000;\r
- }\r
- else\r
- {\r
- for(int j=0; j<28; j++)\r
- {\r
- scrBuffer[(x * 14) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);\r
-\r
- if (screenType == ST_GREEN_MONO)\r
- pixels &= 0x07FFFFFF;\r
-\r
- scrBuffer[(x * 14) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);\r
- pixels <<= 1;\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void RenderVideoFrame(void)\r
-{\r
-//temp...\r
-/*RenderLoRes();\r
-RenderScreenBuffer();\r
-return;//*/\r
-\r
- if (textMode)\r
- {\r
- // There's prolly more to it than this (like 80 column text), but this'll have to do for now...\r
- Render40ColumnText();\r
- }\r
- else\r
- {\r
- if (mixedMode)\r
- {\r
- if (hiRes)\r
- {\r
- RenderHiRes(160);\r
- Render40ColumnTextLine(20);\r
- Render40ColumnTextLine(21);\r
- Render40ColumnTextLine(22);\r
- Render40ColumnTextLine(23);\r
- }\r
- else\r
- {\r
- RenderLoRes(20);\r
- Render40ColumnTextLine(20);\r
- Render40ColumnTextLine(21);\r
- Render40ColumnTextLine(22);\r
- Render40ColumnTextLine(23);\r
- }\r
- }\r
- else\r
- {\r
- if (hiRes)\r
- RenderHiRes();\r
- else\r
- RenderLoRes();\r
- }\r
- }\r
-\r
- if (msgTicks)\r
- {\r
- DrawString();\r
- msgTicks--;\r
- }\r
-\r
- RenderScreenBuffer();\r
-}\r
+//
+// Apple 2 video support
+//
+// All the video modes that a real Apple 2 supports are handled here
+//
+// by James L. Hammons
+// (c) 2005 Underground Software
+//
+// JLH = James L. Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 12/01/2005 Added color TV/monochrome emulation to hi-res code
+// JLH 12/09/2005 Cleaned up color TV emulation code
+// JLH 12/09/2005 Fixed lo-res color TV/mono emulation modes
+//
+// STILL TO DO:
+//
+// - Fix LoRes mode green mono to skip every other scanline instead of fill
+// like white mono does
+// - Double HiRes
+// - 80 column text
+// - Fix OSD text display so that it's visible no matter what background is there [DONE]
+//
+
+// Display routines seem MUCH slower now... !!! INVESTIGATE !!!
+
+#include "applevideo.h"
+
+#include <string.h> // for memset()
+#include <stdarg.h> // for va_* stuff
+#include <string> // for vsprintf()
+#include "apple2.h"
+#include "video.h"
+#include "charset.h"
+#include "font14pt.h"
+
+/* Reference: Technote tn-iigs-063 "Master Color Values"
+
+ Color Color Register LR HR DHR Master Color R,G,B
+ Name Value # # # Value
+ ----------------------------------------------------
+ Black 0 0 0,4 0 $0000 (0,0,0)
+(Magenta) Deep Red 1 1 1 $0D03 (D,0,3)
+ Dark Blue 2 2 8 $0009 (0,0,9)
+ (Violet) Purple 3 3 2 9 $0D2D (D,2,D)
+ Dark Green 4 4 4 $0072 (0,7,2)
+ (Gray 1) Dark Gray 5 5 5 $0555 (5,5,5)
+ (Blue) Medium Blue 6 6 6 C $022F (2,2,F)
+ (Cyan) Light Blue 7 7 D $06AF (6,A,F)
+ Brown 8 8 2 $0850 (8,5,0)
+ Orange 9 9 5 3 $0F60 (F,6,0)
+ (Gray 2) Light Gray A A A $0AAA (A,A,A)
+ Pink B B B $0F98 (F,9,8)
+ (Green) Light Green C C 1 6 $01D0 (1,D,0)
+ Yellow D D 7 $0FF0 (F,F,0)
+ (Aqua) Aquamarine E E E $04F9 (4,F,9)
+ White F F 3,7 F $0FFF (F,F,F)
+
+ LR: Lo-Res HR: Hi-Res DHR: Double Hi-Res */
+
+// Global variables
+
+bool flash;
+bool textMode;
+bool mixedMode;
+bool displayPage2;
+bool hiRes;
+bool alternateCharset;
+//void SpawnMessage(const char * text, ...);
+
+// Local variables
+
+// We set up the colors this way so that they'll be endian safe
+// when we cast them to a uint32.
+
+// "Master Color Values" palette
+
+static uint8 colors[16 * 4] = {
+ 0x00, 0x00, 0x00, 0xFF, // Black
+ 0xDD, 0x00, 0x33, 0xFF, // Deep Red (Magenta)
+ 0x00, 0x00, 0x99, 0xFF, // Dark Blue
+ 0xDD, 0x22, 0xDD, 0xFF, // Purple (Violet)
+ 0x00, 0x77, 0x22, 0xFF, // Dark Green
+ 0x55, 0x55, 0x55, 0xFF, // Dark Gray (Gray 1)
+ 0x22, 0x22, 0xFF, 0xFF, // Medium Blue (Blue)
+ 0x66, 0xAA, 0xFF, 0xFF, // Light Blue (Cyan)
+ 0x88, 0x55, 0x00, 0xFF, // Brown
+ 0xFF, 0x66, 0x00, 0xFF, // Orange
+ 0xAA, 0xAA, 0xAA, 0xFF, // Light Gray (Gray 2)
+ 0xFF, 0x99, 0x88, 0xFF, // Pink
+ 0x11, 0xDD, 0x00, 0xFF, // Light Green (Green)
+ 0xFF, 0xFF, 0x00, 0xFF, // Yellow
+ 0x44, 0xFF, 0x99, 0xFF, // Aquamarine (Aqua)
+ 0xFF, 0xFF, 0xFF, 0xFF // White
+};
+
+// This palette comes from ApplePC's colors (more realistic to my eye ;-)
+
+static uint8 altColors[16 * 4] = {
+ 0x00, 0x00, 0x00, 0xFF,
+ 0x7D, 0x20, 0x41, 0xFF,
+ 0x41, 0x30, 0x7D, 0xFF,
+ 0xBE, 0x51, 0xBE, 0xFF,
+ 0x00, 0x5D, 0x3C, 0xFF,
+ 0x7D, 0x7D, 0x7D, 0xFF,
+ 0x41, 0x8E, 0xBA, 0xFF,
+ 0xBE, 0xAE, 0xFB, 0xFF,
+ 0x3C, 0x4D, 0x00, 0xFF,
+ 0xBA, 0x6D, 0x41, 0xFF,
+ 0x7D, 0x7D, 0x7D, 0xFF,
+ 0xFB, 0x9E, 0xBE, 0xFF,
+ 0x3C, 0xAA, 0x3C, 0xFF,
+ 0xBA, 0xCB, 0x7D, 0xFF,
+ 0x7D, 0xDB, 0xBA, 0xFF,
+ 0xFB, 0xFB, 0xFB, 0xFF };
+
+// Lo-res starting line addresses
+
+static uint16 lineAddrLoRes[24] = {
+ 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780,
+ 0x0428, 0x04A8, 0x0528, 0x05A8, 0x0628, 0x06A8, 0x0728, 0x07A8,
+ 0x0450, 0x04D0, 0x0550, 0x05D0, 0x0650, 0x06D0, 0x0750, 0x07D0 };
+
+// Hi-res starting line addresses
+
+static uint16 lineAddrHiRes[192] = {
+ 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,
+ 0x2080, 0x2480, 0x2880, 0x2C80, 0x3080, 0x3480, 0x3880, 0x3C80,
+ 0x2100, 0x2500, 0x2900, 0x2D00, 0x3100, 0x3500, 0x3900, 0x3D00,
+ 0x2180, 0x2580, 0x2980, 0x2D80, 0x3180, 0x3580, 0x3980, 0x3D80,
+
+ 0x2200, 0x2600, 0x2A00, 0x2E00, 0x3200, 0x3600, 0x3A00, 0x3E00,
+ 0x2280, 0x2680, 0x2A80, 0x2E80, 0x3280, 0x3680, 0x3A80, 0x3E80,
+ 0x2300, 0x2700, 0x2B00, 0x2F00, 0x3300, 0x3700, 0x3B00, 0x3F00,
+ 0x2380, 0x2780, 0x2B80, 0x2F80, 0x3380, 0x3780, 0x3B80, 0x3F80,
+
+ 0x2028, 0x2428, 0x2828, 0x2C28, 0x3028, 0x3428, 0x3828, 0x3C28,
+ 0x20A8, 0x24A8, 0x28A8, 0x2CA8, 0x30A8, 0x34A8, 0x38A8, 0x3CA8,
+ 0x2128, 0x2528, 0x2928, 0x2D28, 0x3128, 0x3528, 0x3928, 0x3D28,
+ 0x21A8, 0x25A8, 0x29A8, 0x2DA8, 0x31A8, 0x35A8, 0x39A8, 0x3DA8,
+
+ 0x2228, 0x2628, 0x2A28, 0x2E28, 0x3228, 0x3628, 0x3A28, 0x3E28,
+ 0x22A8, 0x26A8, 0x2AA8, 0x2EA8, 0x32A8, 0x36A8, 0x3AA8, 0x3EA8,
+ 0x2328, 0x2728, 0x2B28, 0x2F28, 0x3328, 0x3728, 0x3B28, 0x3F28,
+ 0x23A8, 0x27A8, 0x2BA8, 0x2FA8, 0x33A8, 0x37A8, 0x3BA8, 0x3FA8,
+
+ 0x2050, 0x2450, 0x2850, 0x2C50, 0x3050, 0x3450, 0x3850, 0x3C50,
+ 0x20D0, 0x24D0, 0x28D0, 0x2CD0, 0x30D0, 0x34D0, 0x38D0, 0x3CD0,
+ 0x2150, 0x2550, 0x2950, 0x2D50, 0x3150, 0x3550, 0x3950, 0x3D50,
+ 0x21D0, 0x25D0, 0x29D0, 0x2DD0, 0x31D0, 0x35D0, 0x39D0, 0x3DD0,
+
+ 0x2250, 0x2650, 0x2A50, 0x2E50, 0x3250, 0x3650, 0x3A50, 0x3E50,
+ 0x22D0, 0x26D0, 0x2AD0, 0x2ED0, 0x32D0, 0x36D0, 0x3AD0, 0x3ED0,
+ 0x2350, 0x2750, 0x2B50, 0x2F50, 0x3350, 0x3750, 0x3B50, 0x3F50,
+ 0x23D0, 0x27D0, 0x2BD0, 0x2FD0, 0x33D0, 0x37D0, 0x3BD0, 0x3FD0 };
+
+uint16 appleHiresToMono[0x200] = {
+ 0x0000, 0x3000, 0x0C00, 0x3C00, 0x0300, 0x3300, 0x0F00, 0x3F00,
+ 0x00C0, 0x30C0, 0x0CC0, 0x3CC0, 0x03C0, 0x33C0, 0x0FC0, 0x3FC0, // $0x
+ 0x0030, 0x3030, 0x0C30, 0x3C30, 0x0330, 0x3330, 0x0F30, 0x3F30,
+ 0x00F0, 0x30F0, 0x0CF0, 0x3CF0, 0x03F0, 0x33F0, 0x0FF0, 0x3FF0, // $1x
+ 0x000C, 0x300C, 0x0C0C, 0x3C0C, 0x030C, 0x330C, 0x0F0C, 0x3F0C,
+ 0x00CC, 0x30CC, 0x0CCC, 0x3CCC, 0x03CC, 0x33CC, 0x0FCC, 0x3FCC, // $2x
+ 0x003C, 0x303C, 0x0C3C, 0x3C3C, 0x033C, 0x333C, 0x0F3C, 0x3F3C,
+ 0x00FC, 0x30FC, 0x0CFC, 0x3CFC, 0x03FC, 0x33FC, 0x0FFC, 0x3FFC, // $3x
+ 0x0003, 0x3003, 0x0C03, 0x3C03, 0x0303, 0x3303, 0x0F03, 0x3F03,
+ 0x00C3, 0x30C3, 0x0CC3, 0x3CC3, 0x03C3, 0x33C3, 0x0FC3, 0x3FC3, // $4x
+ 0x0033, 0x3033, 0x0C33, 0x3C33, 0x0333, 0x3333, 0x0F33, 0x3F33,
+ 0x00F3, 0x30F3, 0x0CF3, 0x3CF3, 0x03F3, 0x33F3, 0x0FF3, 0x3FF3, // $5x
+ 0x000F, 0x300F, 0x0C0F, 0x3C0F, 0x030F, 0x330F, 0x0F0F, 0x3F0F,
+ 0x00CF, 0x30CF, 0x0CCF, 0x3CCF, 0x03CF, 0x33CF, 0x0FCF, 0x3FCF, // $6x
+ 0x003F, 0x303F, 0x0C3F, 0x3C3F, 0x033F, 0x333F, 0x0F3F, 0x3F3F,
+ 0x00FF, 0x30FF, 0x0CFF, 0x3CFF, 0x03FF, 0x33FF, 0x0FFF, 0x3FFF, // $7x
+ 0x0000, 0x1800, 0x0600, 0x1E00, 0x0180, 0x1980, 0x0780, 0x1F80,
+ 0x0060, 0x1860, 0x0660, 0x1E60, 0x01E0, 0x19E0, 0x07E0, 0x1FE0, // $8x
+ 0x0018, 0x1818, 0x0618, 0x1E18, 0x0198, 0x1998, 0x0798, 0x1F98,
+ 0x0078, 0x1878, 0x0678, 0x1E78, 0x01F8, 0x19F8, 0x07F8, 0x1FF8, // $9x
+ 0x0006, 0x1806, 0x0606, 0x1E06, 0x0186, 0x1986, 0x0786, 0x1F86,
+ 0x0066, 0x1866, 0x0666, 0x1E66, 0x01E6, 0x19E6, 0x07E6, 0x1FE6, // $Ax
+ 0x001E, 0x181E, 0x061E, 0x1E1E, 0x019E, 0x199E, 0x079E, 0x1F9E,
+ 0x007E, 0x187E, 0x067E, 0x1E7E, 0x01FE, 0x19FE, 0x07FE, 0x1FFE, // $Bx
+ 0x0001, 0x1801, 0x0601, 0x1E01, 0x0181, 0x1981, 0x0781, 0x1F81,
+ 0x0061, 0x1861, 0x0661, 0x1E61, 0x01E1, 0x19E1, 0x07E1, 0x1FE1, // $Cx
+ 0x0019, 0x1819, 0x0619, 0x1E19, 0x0199, 0x1999, 0x0799, 0x1F99,
+ 0x0079, 0x1879, 0x0679, 0x1E79, 0x01F9, 0x19F9, 0x07F9, 0x1FF9, // $Dx
+ 0x0007, 0x1807, 0x0607, 0x1E07, 0x0187, 0x1987, 0x0787, 0x1F87,
+ 0x0067, 0x1867, 0x0667, 0x1E67, 0x01E7, 0x19E7, 0x07E7, 0x1FE7, // $Ex
+ 0x001F, 0x181F, 0x061F, 0x1E1F, 0x019F, 0x199F, 0x079F, 0x1F9F,
+ 0x007F, 0x187F, 0x067F, 0x1E7F, 0x01FF, 0x19FF, 0x07FF, 0x1FFF, // $Fx
+
+ // Second half adds in the previous byte's lo pixel
+
+ 0x0000, 0x3000, 0x0C00, 0x3C00, 0x0300, 0x3300, 0x0F00, 0x3F00,
+ 0x00C0, 0x30C0, 0x0CC0, 0x3CC0, 0x03C0, 0x33C0, 0x0FC0, 0x3FC0, // $0x
+ 0x0030, 0x3030, 0x0C30, 0x3C30, 0x0330, 0x3330, 0x0F30, 0x3F30,
+ 0x00F0, 0x30F0, 0x0CF0, 0x3CF0, 0x03F0, 0x33F0, 0x0FF0, 0x3FF0, // $1x
+ 0x000C, 0x300C, 0x0C0C, 0x3C0C, 0x030C, 0x330C, 0x0F0C, 0x3F0C,
+ 0x00CC, 0x30CC, 0x0CCC, 0x3CCC, 0x03CC, 0x33CC, 0x0FCC, 0x3FCC, // $2x
+ 0x003C, 0x303C, 0x0C3C, 0x3C3C, 0x033C, 0x333C, 0x0F3C, 0x3F3C,
+ 0x00FC, 0x30FC, 0x0CFC, 0x3CFC, 0x03FC, 0x33FC, 0x0FFC, 0x3FFC, // $3x
+ 0x0003, 0x3003, 0x0C03, 0x3C03, 0x0303, 0x3303, 0x0F03, 0x3F03,
+ 0x00C3, 0x30C3, 0x0CC3, 0x3CC3, 0x03C3, 0x33C3, 0x0FC3, 0x3FC3, // $4x
+ 0x0033, 0x3033, 0x0C33, 0x3C33, 0x0333, 0x3333, 0x0F33, 0x3F33,
+ 0x00F3, 0x30F3, 0x0CF3, 0x3CF3, 0x03F3, 0x33F3, 0x0FF3, 0x3FF3, // $5x
+ 0x000F, 0x300F, 0x0C0F, 0x3C0F, 0x030F, 0x330F, 0x0F0F, 0x3F0F,
+ 0x00CF, 0x30CF, 0x0CCF, 0x3CCF, 0x03CF, 0x33CF, 0x0FCF, 0x3FCF, // $6x
+ 0x003F, 0x303F, 0x0C3F, 0x3C3F, 0x033F, 0x333F, 0x0F3F, 0x3F3F,
+ 0x00FF, 0x30FF, 0x0CFF, 0x3CFF, 0x03FF, 0x33FF, 0x0FFF, 0x3FFF, // $7x
+ 0x2000, 0x3800, 0x2600, 0x3E00, 0x2180, 0x3980, 0x2780, 0x3F80,
+ 0x2060, 0x3860, 0x2660, 0x3E60, 0x21E0, 0x39E0, 0x27E0, 0x3FE0, // $8x
+ 0x2018, 0x3818, 0x2618, 0x3E18, 0x2198, 0x3998, 0x2798, 0x3F98,
+ 0x2078, 0x3878, 0x2678, 0x3E78, 0x21F8, 0x39F8, 0x27F8, 0x3FF8, // $9x
+ 0x2006, 0x3806, 0x2606, 0x3E06, 0x2186, 0x3986, 0x2786, 0x3F86,
+ 0x2066, 0x3866, 0x2666, 0x3E66, 0x21E6, 0x39E6, 0x27E6, 0x3FE6, // $Ax
+ 0x201E, 0x381E, 0x261E, 0x3E1E, 0x219E, 0x399E, 0x279E, 0x3F9E,
+ 0x207E, 0x387E, 0x267E, 0x3E7E, 0x21FE, 0x39FE, 0x27FE, 0x3FFE, // $Bx
+ 0x2001, 0x3801, 0x2601, 0x3E01, 0x2181, 0x3981, 0x2781, 0x3F81,
+ 0x2061, 0x3861, 0x2661, 0x3E61, 0x21E1, 0x39E1, 0x27E1, 0x3FE1, // $Cx
+ 0x2019, 0x3819, 0x2619, 0x3E19, 0x2199, 0x3999, 0x2799, 0x3F99,
+ 0x2079, 0x3879, 0x2679, 0x3E79, 0x21F9, 0x39F9, 0x27F9, 0x3FF9, // $Dx
+ 0x2007, 0x3807, 0x2607, 0x3E07, 0x2187, 0x3987, 0x2787, 0x3F87,
+ 0x2067, 0x3867, 0x2667, 0x3E67, 0x21E7, 0x39E7, 0x27E7, 0x3FE7, // $Ex
+ 0x201F, 0x381F, 0x261F, 0x3E1F, 0x219F, 0x399F, 0x279F, 0x3F9F,
+ 0x207F, 0x387F, 0x267F, 0x3E7F, 0x21FF, 0x39FF, 0x27FF, 0x3FFF // $Fx
+};
+
+static uint8 blurTable[0x800][8]; // Color TV blur table
+static uint32 * palette = (uint32 *)altColors;
+enum { ST_FIRST_ENTRY = 0, ST_COLOR_TV = 0, ST_WHITE_MONO, ST_GREEN_MONO, ST_LAST_ENTRY };
+static uint8 screenType = ST_COLOR_TV;
+
+// Local functions
+
+static void Render40ColumnTextLine(uint8 line);
+static void Render40ColumnText(void);
+static void RenderLoRes(uint16 toLine = 24);
+static void RenderHiRes(uint16 toLine = 192);
+
+
+void SetupBlurTable(void)
+{
+ // NOTE: This table only needs to be 7 bits wide instead of 11, since the
+ // last four bits are copies of the previous four...
+
+ for(uint16 bitPat=0; bitPat<0x800; bitPat++)
+ {
+ uint16 w3 = bitPat & 0x888;
+ uint16 w2 = bitPat & 0x444;
+ uint16 w1 = bitPat & 0x222;
+ uint16 w0 = bitPat & 0x111;
+
+ uint16 blurred3 = (w3 | (w3 >> 1) | (w3 >> 2) | (w3 >> 3)) & 0x00FF;
+ uint16 blurred2 = (w2 | (w2 >> 1) | (w2 >> 2) | (w2 >> 3)) & 0x00FF;
+ uint16 blurred1 = (w1 | (w1 >> 1) | (w1 >> 2) | (w1 >> 3)) & 0x00FF;
+ uint16 blurred0 = (w0 | (w0 >> 1) | (w0 >> 2) | (w0 >> 3)) & 0x00FF;
+
+ for(int8 i=7; i>=0; i--)
+ {
+ uint8 color = (((blurred0 >> i) & 0x01) << 3)
+ | (((blurred1 >> i) & 0x01) << 2)
+ | (((blurred2 >> i) & 0x01) << 1)
+ | ((blurred3 >> i) & 0x01);
+ blurTable[bitPat][7 - i] = color;
+ }
+ }
+}
+
+void TogglePalette(void)
+{
+ if (palette == (uint32 *)colors)
+ {
+ palette = (uint32 *)altColors;
+ SpawnMessage("Color TV palette");
+ }
+ else
+ {
+ palette = (uint32 *)colors;
+ SpawnMessage("\"Master Color Values\" palette");
+ }
+}
+
+void CycleScreenTypes(void)
+{
+ char scrTypeStr[3][40] = { "Color TV", "White monochrome", "Green monochrome" };
+
+ screenType++;
+
+ if (screenType == ST_LAST_ENTRY)
+ screenType = ST_FIRST_ENTRY;
+
+ SpawnMessage("%s", scrTypeStr[screenType]);
+}
+
+static uint32 msgTicks = 0;
+static char message[4096];
+
+void SpawnMessage(const char * text, ...)
+{
+ va_list arg;
+
+ va_start(arg, text);
+ vsprintf(message, text, arg);
+ va_end(arg);
+
+ msgTicks = 120;
+}
+
+static void DrawString2(uint32 x, uint32 y, uint32 color);
+static void DrawString(void)
+{
+//This approach works, and seems to be fast enough... Though it probably would
+//be better to make the oversized font to match this one...
+ for(uint32 x=7; x<=9; x++)
+ for(uint32 y=7; y<=9; y++)
+ DrawString2(x, y, 0x00000000);
+
+ DrawString2(8, 8, 0x0020FF20);
+}
+
+static void DrawString2(uint32 x, uint32 y, uint32 color)
+{
+//uint32 x = 8, y = 8;
+ uint32 length = strlen(message), address = x + (y * VIRTUAL_SCREEN_WIDTH);
+// uint32 color = 0x0020FF20;
+//This could be done ahead of time, instead of on each pixel...
+//(Now it is!)
+ uint8 nBlue = (color >> 16) & 0xFF, nGreen = (color >> 8) & 0xFF, nRed = color & 0xFF;
+
+ for(uint32 i=0; i<length; i++)
+ {
+ uint8 c = message[i];
+ c = (c < 32 ? 0 : c - 32);
+ uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
+
+ for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
+ {
+ for(uint32 xx=0; xx<FONT_WIDTH; xx++)
+ {
+/* uint8 fontTrans = font1[fontAddr++];
+// uint32 newTrans = (fontTrans * transparency / 255) << 24;
+ uint32 newTrans = fontTrans << 24;
+ uint32 pixel = newTrans | color;
+
+ *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = pixel;//*/
+
+ uint8 trans = font1[fontAddr++];
+
+ if (trans)
+ {
+ uint32 existingColor = *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH));
+
+ uint8 eBlue = (existingColor >> 16) & 0xFF,
+ eGreen = (existingColor >> 8) & 0xFF,
+ eRed = existingColor & 0xFF;
+
+//This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
+//Here we've modified it to have 33 levels of transparency (could have any # we want!)
+//because dividing by 32 is faster than dividing by 31...!
+ uint8 invTrans = 255 - trans;
+
+ uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
+ uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
+ uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
+
+//THIS IS NOT ENDIAN SAFE
+ *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
+ }
+ }
+ }
+
+ address += FONT_WIDTH;
+ }
+}
+
+static void Render40ColumnTextLine(uint8 line)
+{
+ uint32 pixelOn = (screenType == ST_GREEN_MONO ? 0xFF61FF61 : 0xFFFFFFFF);
+
+ for(int x=0; x<40; x++)
+ {
+ uint8 chr = ram[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x];
+
+ // Render character at (x, y)
+
+ for(int cy=0; cy<8; cy++)
+ {
+ for(int cx=0; cx<7; cx++)
+ {
+ uint32 pixel = 0xFF000000;
+
+ if (!alternateCharset)
+ {
+ if (textChar[((chr & 0x3F) * 56) + cx + (cy * 7)])
+// pixel = 0xFFFFFFFF;
+ pixel = pixelOn;
+
+ if (chr < 0x80)
+ pixel = pixel ^ (screenType == ST_GREEN_MONO ? 0x0061FF61 : 0x00FFFFFF);
+
+ if ((chr & 0xC0) == 0x40 && flash)
+ pixel = 0xFF000000;
+ }
+ else
+ {
+ if (textChar2e[(chr * 56) + cx + (cy * 7)])
+// pixel = 0xFFFFFFFF;
+ pixel = pixelOn;
+ }
+
+// scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
+// scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
+ scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;
+ scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;
+
+ if (screenType == ST_GREEN_MONO)
+ pixel = 0xFF000000;
+
+ {
+ scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;
+ scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;
+ }
+ }
+ }
+ }
+}
+
+static void Render40ColumnText(void)
+{
+ for(uint8 line=0; line<24; line++)
+ Render40ColumnTextLine(line);
+}
+
+static void RenderLoRes(uint16 toLine/*= 24*/)
+{
+// NOTE: The green mono rendering doesn't skip every other line... !!! FIX !!!
+/*
+Note that these colors correspond to the bit patterns generated by the numbers 0-F in order:
+Color #s correspond to the bit patterns in reverse... Interesting!
+
+00 00 00 -> 0 [0000] -> 0 (lores color #)
+3c 4d 00 -> 8 [0001] -> 8? BROWN
+00 5d 3c -> 4 [0010] -> 4? DARK GREEN
+3c aa 3c -> 12 [0011] -> 12? LIGHT GREEN (GREEN)
+41 30 7d -> 2 [0100] -> 2? DARK BLUE
+7d 7d 7d -> 10 [0101] -> 10? LIGHT GRAY
+41 8e ba -> 6 [0110] -> 6? MEDIUM BLUE (BLUE)
+7d db ba -> 14 [0111] -> 14? AQUAMARINE (AQUA)
+7d 20 41 -> 1 [1000] -> 1? DEEP RED (MAGENTA)
+ba 6d 41 -> 9 [1001] -> 9? ORANGE
+7d 7d 7d -> 5 [1010] -> 5? DARK GRAY
+ba cb 7d -> 13 [1011] -> 13? YELLOW
+be 51 be -> 3 [1100] -> 3 PURPLE (VIOLET)
+fb 9e be -> 11 [1101] -> 11? PINK
+be ae fb -> 7 [1110] -> 7? LIGHT BLUE (CYAN)
+fb fb fb -> 15 [1111] -> 15 WHITE
+*/
+ uint8 mirrorNybble[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+
+//This is the old "perfect monitor" rendering code...
+/* if (screenType != ST_COLOR_TV) // Not correct, but for now...
+//if (1)
+ {
+ for(uint16 y=0; y<toLine; y++)
+ {
+ for(uint16 x=0; x<40; x++)
+ {
+ uint8 scrByte = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x];
+ uint32 pixel = palette[scrByte & 0x0F];
+
+ for(int cy=0; cy<4; cy++)
+ for(int cx=0; cx<14; cx++)
+ scrBuffer[((x * 14) + cx) + (((y * 8) + cy) * VIRTUAL_SCREEN_WIDTH)] = pixel;
+
+ pixel = palette[scrByte >> 4];
+
+ for(int cy=4; cy<8; cy++)
+ for(int cx=0; cx<14; cx++)
+ scrBuffer[(x * 14) + (y * VIRTUAL_SCREEN_WIDTH * 8) + cx + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
+ }
+ }
+ }
+ else//*/
+
+ uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
+
+ for(uint16 y=0; y<toLine; y++)
+ {
+ // Do top half of lores screen bytes...
+
+ uint32 previous3Bits = 0;
+
+ for(uint16 x=0; x<40; x+=2)
+ {
+ uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] & 0x0F;
+ uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] & 0x0F;
+ scrByte1 = mirrorNybble[scrByte1];
+ scrByte2 = mirrorNybble[scrByte2];
+ // This is just a guess, but it'll have to do for now...
+ uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
+ | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
+ | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
+
+ // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
+ // 0ppp 1111 1111 1111 11|11 1111 1111 1111
+ // 31 27 23 19 15 11 7 3 0
+
+ if (screenType == ST_COLOR_TV)
+ {
+ for(uint8 i=0; i<7; i++)
+ {
+ uint16 bitPat = (pixels & 0x7F000000) >> 20;
+ pixels <<= 4;
+
+ for(uint8 j=0; j<4; j++)
+ {
+ uint8 color = blurTable[bitPat][j];
+
+ for(uint32 cy=0; cy<8; cy++)
+ {
+ scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+// scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+ }
+ }
+ }
+
+ previous3Bits = pixels & 0x70000000;
+ }
+ else
+ {
+ for(int j=0; j<28; j++)
+ {
+ for(uint32 cy=0; cy<8; cy++)
+ {
+ scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+// scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+ }
+
+ pixels <<= 1;
+ }
+ }
+ }
+
+ // Now do bottom half...
+
+ previous3Bits = 0;
+
+ for(uint16 x=0; x<40; x+=2)
+ {
+ uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] >> 4;
+ uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] >> 4;
+ scrByte1 = mirrorNybble[scrByte1];
+ scrByte2 = mirrorNybble[scrByte2];
+ // This is just a guess, but it'll have to do for now...
+ uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
+ | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
+ | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
+
+ // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
+ // 0ppp 1111 1111 1111 11|11 1111 1111 1111
+ // 31 27 23 19 15 11 7 3 0
+
+ if (screenType == ST_COLOR_TV)
+ {
+ for(uint8 i=0; i<7; i++)
+ {
+ uint16 bitPat = (pixels & 0x7F000000) >> 20;
+ pixels <<= 4;
+
+ for(uint8 j=0; j<4; j++)
+ {
+ uint8 color = blurTable[bitPat][j];
+
+ for(uint32 cy=8; cy<16; cy++)
+ {
+ scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+// scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+ }
+ }
+ }
+
+ previous3Bits = pixels & 0x70000000;
+ }
+ else
+ {
+ for(int j=0; j<28; j++)
+ {
+ for(uint32 cy=8; cy<16; cy++)
+ {
+ scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+// scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+ }
+
+ pixels <<= 1;
+ }
+ }
+ }
+ }
+}
+
+static void RenderHiRes(uint16 toLine/*= 192*/)
+{
+ uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
+
+ for(uint16 y=0; y<toLine; y++)
+ {
+ uint16 previousLoPixel = 0;
+ uint32 previous3bits = 0;
+
+ for(uint16 x=0; x<40; x+=2)
+ {
+ uint8 screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x];
+ uint32 pixels = appleHiresToMono[previousLoPixel | screenByte];
+ previousLoPixel = (screenByte << 2) & 0x0100;
+
+ screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x + 1];
+ uint32 pixels2 = appleHiresToMono[previousLoPixel | screenByte];
+ previousLoPixel = (screenByte << 2) & 0x0100;
+
+ pixels = previous3bits | (pixels << 14) | pixels2;
+
+ // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
+ // 0ppp 1111 1111 1111 1111 1111 1111 1111
+ // 31 27 23 19 15 11 7 3 0
+
+ if (screenType == ST_COLOR_TV)
+ {
+ for(uint8 i=0; i<7; i++)
+ {
+ uint16 bitPat = (pixels & 0x7F000000) >> 20;
+ pixels <<= 4;
+
+ for(uint8 j=0; j<4; j++)
+ {
+ uint8 color = blurTable[bitPat][j];
+#if 0
+//This doesn't seem to make things go any faster...
+//It's the OpenGL render that's faster... Hmm...
+ scrBuffer[(x * 14) + (i * 4) + j + (y * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+#else
+ scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+ scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+#endif
+ }
+ }
+
+ previous3bits = pixels & 0x70000000;
+ }
+ else
+ {
+ for(int j=0; j<28; j++)
+ {
+ scrBuffer[(x * 14) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+
+ if (screenType == ST_GREEN_MONO)
+ pixels &= 0x07FFFFFF;
+
+ scrBuffer[(x * 14) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+ pixels <<= 1;
+ }
+ }
+ }
+ }
+}
+
+void RenderVideoFrame(void)
+{
+//temp...
+/*RenderLoRes();
+RenderScreenBuffer();
+return;//*/
+
+ if (textMode)
+ {
+ // There's prolly more to it than this (like 80 column text), but this'll have to do for now...
+ Render40ColumnText();
+ }
+ else
+ {
+ if (mixedMode)
+ {
+ if (hiRes)
+ {
+ RenderHiRes(160);
+ Render40ColumnTextLine(20);
+ Render40ColumnTextLine(21);
+ Render40ColumnTextLine(22);
+ Render40ColumnTextLine(23);
+ }
+ else
+ {
+ RenderLoRes(20);
+ Render40ColumnTextLine(20);
+ Render40ColumnTextLine(21);
+ Render40ColumnTextLine(22);
+ Render40ColumnTextLine(23);
+ }
+ }
+ else
+ {
+ if (hiRes)
+ RenderHiRes();
+ else
+ RenderLoRes();
+ }
+ }
+
+ if (msgTicks)
+ {
+ DrawString();
+ msgTicks--;
+ }
+
+ RenderScreenBuffer();
+}