2 // Apple 2 video support
4 // All the video modes that a real Apple 2 supports are handled here
7 // (c) 2005 Underground Software
9 // JLH = James L. Hammons <jlhamm@acm.org>
12 // --- ---------- ------------------------------------------------------------
13 // JLH 12/01/2005 Added color TV/monochrome emulation to hi-res code
14 // JLH 12/09/2005 Cleaned up color TV emulation code
15 // JLH 12/09/2005 Fixed lo-res color TV/mono emulation modes
19 // - Fix LoRes mode green mono to skip every other scanline instead of fill
20 // like white mono does
23 // - Fix OSD text display so that it's visible no matter what background is there [DONE]
26 // Display routines seem MUCH slower now... !!! INVESTIGATE !!!
28 #include "applevideo.h"
30 #include <string.h> // for memset()
31 #include <stdarg.h> // for va_* stuff
32 #include <string> // for vsprintf()
38 /* Reference: Technote tn-iigs-063 "Master Color Values"
40 Color Color Register LR HR DHR Master Color R,G,B
41 Name Value # # # Value
42 ----------------------------------------------------
43 Black 0 0 0,4 0 $0000 (0,0,0)
44 (Magenta) Deep Red 1 1 1 $0D03 (D,0,3)
45 Dark Blue 2 2 8 $0009 (0,0,9)
46 (Violet) Purple 3 3 2 9 $0D2D (D,2,D)
47 Dark Green 4 4 4 $0072 (0,7,2)
48 (Gray 1) Dark Gray 5 5 5 $0555 (5,5,5)
49 (Blue) Medium Blue 6 6 6 C $022F (2,2,F)
50 (Cyan) Light Blue 7 7 D $06AF (6,A,F)
51 Brown 8 8 2 $0850 (8,5,0)
52 Orange 9 9 5 3 $0F60 (F,6,0)
53 (Gray 2) Light Gray A A A $0AAA (A,A,A)
54 Pink B B B $0F98 (F,9,8)
55 (Green) Light Green C C 1 6 $01D0 (1,D,0)
56 Yellow D D 7 $0FF0 (F,F,0)
57 (Aqua) Aquamarine E E E $04F9 (4,F,9)
58 White F F 3,7 F $0FFF (F,F,F)
60 LR: Lo-Res HR: Hi-Res DHR: Double Hi-Res */
69 bool alternateCharset;
70 //void SpawnMessage(const char * text, ...);
74 // We set up the colors this way so that they'll be endian safe
75 // when we cast them to a uint32.
77 // "Master Color Values" palette
79 static uint8 colors[16 * 4] = {
80 0x00, 0x00, 0x00, 0xFF, // Black
81 0xDD, 0x00, 0x33, 0xFF, // Deep Red (Magenta)
82 0x00, 0x00, 0x99, 0xFF, // Dark Blue
83 0xDD, 0x22, 0xDD, 0xFF, // Purple (Violet)
84 0x00, 0x77, 0x22, 0xFF, // Dark Green
85 0x55, 0x55, 0x55, 0xFF, // Dark Gray (Gray 1)
86 0x22, 0x22, 0xFF, 0xFF, // Medium Blue (Blue)
87 0x66, 0xAA, 0xFF, 0xFF, // Light Blue (Cyan)
88 0x88, 0x55, 0x00, 0xFF, // Brown
89 0xFF, 0x66, 0x00, 0xFF, // Orange
90 0xAA, 0xAA, 0xAA, 0xFF, // Light Gray (Gray 2)
91 0xFF, 0x99, 0x88, 0xFF, // Pink
92 0x11, 0xDD, 0x00, 0xFF, // Light Green (Green)
93 0xFF, 0xFF, 0x00, 0xFF, // Yellow
94 0x44, 0xFF, 0x99, 0xFF, // Aquamarine (Aqua)
95 0xFF, 0xFF, 0xFF, 0xFF // White
98 // This palette comes from ApplePC's colors (more realistic to my eye ;-)
100 static uint8 altColors[16 * 4] = {
101 0x00, 0x00, 0x00, 0xFF,
102 0x7D, 0x20, 0x41, 0xFF,
103 0x41, 0x30, 0x7D, 0xFF,
104 0xBE, 0x51, 0xBE, 0xFF,
105 0x00, 0x5D, 0x3C, 0xFF,
106 0x7D, 0x7D, 0x7D, 0xFF,
107 0x41, 0x8E, 0xBA, 0xFF,
108 0xBE, 0xAE, 0xFB, 0xFF,
109 0x3C, 0x4D, 0x00, 0xFF,
110 0xBA, 0x6D, 0x41, 0xFF,
111 0x7D, 0x7D, 0x7D, 0xFF,
112 0xFB, 0x9E, 0xBE, 0xFF,
113 0x3C, 0xAA, 0x3C, 0xFF,
114 0xBA, 0xCB, 0x7D, 0xFF,
115 0x7D, 0xDB, 0xBA, 0xFF,
116 0xFB, 0xFB, 0xFB, 0xFF };
118 // Lo-res starting line addresses
120 static uint16 lineAddrLoRes[24] = {
121 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780,
122 0x0428, 0x04A8, 0x0528, 0x05A8, 0x0628, 0x06A8, 0x0728, 0x07A8,
123 0x0450, 0x04D0, 0x0550, 0x05D0, 0x0650, 0x06D0, 0x0750, 0x07D0 };
125 // Hi-res starting line addresses
127 static uint16 lineAddrHiRes[192] = {
128 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,
129 0x2080, 0x2480, 0x2880, 0x2C80, 0x3080, 0x3480, 0x3880, 0x3C80,
130 0x2100, 0x2500, 0x2900, 0x2D00, 0x3100, 0x3500, 0x3900, 0x3D00,
131 0x2180, 0x2580, 0x2980, 0x2D80, 0x3180, 0x3580, 0x3980, 0x3D80,
133 0x2200, 0x2600, 0x2A00, 0x2E00, 0x3200, 0x3600, 0x3A00, 0x3E00,
134 0x2280, 0x2680, 0x2A80, 0x2E80, 0x3280, 0x3680, 0x3A80, 0x3E80,
135 0x2300, 0x2700, 0x2B00, 0x2F00, 0x3300, 0x3700, 0x3B00, 0x3F00,
136 0x2380, 0x2780, 0x2B80, 0x2F80, 0x3380, 0x3780, 0x3B80, 0x3F80,
138 0x2028, 0x2428, 0x2828, 0x2C28, 0x3028, 0x3428, 0x3828, 0x3C28,
139 0x20A8, 0x24A8, 0x28A8, 0x2CA8, 0x30A8, 0x34A8, 0x38A8, 0x3CA8,
140 0x2128, 0x2528, 0x2928, 0x2D28, 0x3128, 0x3528, 0x3928, 0x3D28,
141 0x21A8, 0x25A8, 0x29A8, 0x2DA8, 0x31A8, 0x35A8, 0x39A8, 0x3DA8,
143 0x2228, 0x2628, 0x2A28, 0x2E28, 0x3228, 0x3628, 0x3A28, 0x3E28,
144 0x22A8, 0x26A8, 0x2AA8, 0x2EA8, 0x32A8, 0x36A8, 0x3AA8, 0x3EA8,
145 0x2328, 0x2728, 0x2B28, 0x2F28, 0x3328, 0x3728, 0x3B28, 0x3F28,
146 0x23A8, 0x27A8, 0x2BA8, 0x2FA8, 0x33A8, 0x37A8, 0x3BA8, 0x3FA8,
148 0x2050, 0x2450, 0x2850, 0x2C50, 0x3050, 0x3450, 0x3850, 0x3C50,
149 0x20D0, 0x24D0, 0x28D0, 0x2CD0, 0x30D0, 0x34D0, 0x38D0, 0x3CD0,
150 0x2150, 0x2550, 0x2950, 0x2D50, 0x3150, 0x3550, 0x3950, 0x3D50,
151 0x21D0, 0x25D0, 0x29D0, 0x2DD0, 0x31D0, 0x35D0, 0x39D0, 0x3DD0,
153 0x2250, 0x2650, 0x2A50, 0x2E50, 0x3250, 0x3650, 0x3A50, 0x3E50,
154 0x22D0, 0x26D0, 0x2AD0, 0x2ED0, 0x32D0, 0x36D0, 0x3AD0, 0x3ED0,
155 0x2350, 0x2750, 0x2B50, 0x2F50, 0x3350, 0x3750, 0x3B50, 0x3F50,
156 0x23D0, 0x27D0, 0x2BD0, 0x2FD0, 0x33D0, 0x37D0, 0x3BD0, 0x3FD0 };
158 uint16 appleHiresToMono[0x200] = {
159 0x0000, 0x3000, 0x0C00, 0x3C00, 0x0300, 0x3300, 0x0F00, 0x3F00,
160 0x00C0, 0x30C0, 0x0CC0, 0x3CC0, 0x03C0, 0x33C0, 0x0FC0, 0x3FC0, // $0x
161 0x0030, 0x3030, 0x0C30, 0x3C30, 0x0330, 0x3330, 0x0F30, 0x3F30,
162 0x00F0, 0x30F0, 0x0CF0, 0x3CF0, 0x03F0, 0x33F0, 0x0FF0, 0x3FF0, // $1x
163 0x000C, 0x300C, 0x0C0C, 0x3C0C, 0x030C, 0x330C, 0x0F0C, 0x3F0C,
164 0x00CC, 0x30CC, 0x0CCC, 0x3CCC, 0x03CC, 0x33CC, 0x0FCC, 0x3FCC, // $2x
165 0x003C, 0x303C, 0x0C3C, 0x3C3C, 0x033C, 0x333C, 0x0F3C, 0x3F3C,
166 0x00FC, 0x30FC, 0x0CFC, 0x3CFC, 0x03FC, 0x33FC, 0x0FFC, 0x3FFC, // $3x
167 0x0003, 0x3003, 0x0C03, 0x3C03, 0x0303, 0x3303, 0x0F03, 0x3F03,
168 0x00C3, 0x30C3, 0x0CC3, 0x3CC3, 0x03C3, 0x33C3, 0x0FC3, 0x3FC3, // $4x
169 0x0033, 0x3033, 0x0C33, 0x3C33, 0x0333, 0x3333, 0x0F33, 0x3F33,
170 0x00F3, 0x30F3, 0x0CF3, 0x3CF3, 0x03F3, 0x33F3, 0x0FF3, 0x3FF3, // $5x
171 0x000F, 0x300F, 0x0C0F, 0x3C0F, 0x030F, 0x330F, 0x0F0F, 0x3F0F,
172 0x00CF, 0x30CF, 0x0CCF, 0x3CCF, 0x03CF, 0x33CF, 0x0FCF, 0x3FCF, // $6x
173 0x003F, 0x303F, 0x0C3F, 0x3C3F, 0x033F, 0x333F, 0x0F3F, 0x3F3F,
174 0x00FF, 0x30FF, 0x0CFF, 0x3CFF, 0x03FF, 0x33FF, 0x0FFF, 0x3FFF, // $7x
175 0x0000, 0x1800, 0x0600, 0x1E00, 0x0180, 0x1980, 0x0780, 0x1F80,
176 0x0060, 0x1860, 0x0660, 0x1E60, 0x01E0, 0x19E0, 0x07E0, 0x1FE0, // $8x
177 0x0018, 0x1818, 0x0618, 0x1E18, 0x0198, 0x1998, 0x0798, 0x1F98,
178 0x0078, 0x1878, 0x0678, 0x1E78, 0x01F8, 0x19F8, 0x07F8, 0x1FF8, // $9x
179 0x0006, 0x1806, 0x0606, 0x1E06, 0x0186, 0x1986, 0x0786, 0x1F86,
180 0x0066, 0x1866, 0x0666, 0x1E66, 0x01E6, 0x19E6, 0x07E6, 0x1FE6, // $Ax
181 0x001E, 0x181E, 0x061E, 0x1E1E, 0x019E, 0x199E, 0x079E, 0x1F9E,
182 0x007E, 0x187E, 0x067E, 0x1E7E, 0x01FE, 0x19FE, 0x07FE, 0x1FFE, // $Bx
183 0x0001, 0x1801, 0x0601, 0x1E01, 0x0181, 0x1981, 0x0781, 0x1F81,
184 0x0061, 0x1861, 0x0661, 0x1E61, 0x01E1, 0x19E1, 0x07E1, 0x1FE1, // $Cx
185 0x0019, 0x1819, 0x0619, 0x1E19, 0x0199, 0x1999, 0x0799, 0x1F99,
186 0x0079, 0x1879, 0x0679, 0x1E79, 0x01F9, 0x19F9, 0x07F9, 0x1FF9, // $Dx
187 0x0007, 0x1807, 0x0607, 0x1E07, 0x0187, 0x1987, 0x0787, 0x1F87,
188 0x0067, 0x1867, 0x0667, 0x1E67, 0x01E7, 0x19E7, 0x07E7, 0x1FE7, // $Ex
189 0x001F, 0x181F, 0x061F, 0x1E1F, 0x019F, 0x199F, 0x079F, 0x1F9F,
190 0x007F, 0x187F, 0x067F, 0x1E7F, 0x01FF, 0x19FF, 0x07FF, 0x1FFF, // $Fx
192 // Second half adds in the previous byte's lo pixel
194 0x0000, 0x3000, 0x0C00, 0x3C00, 0x0300, 0x3300, 0x0F00, 0x3F00,
195 0x00C0, 0x30C0, 0x0CC0, 0x3CC0, 0x03C0, 0x33C0, 0x0FC0, 0x3FC0, // $0x
196 0x0030, 0x3030, 0x0C30, 0x3C30, 0x0330, 0x3330, 0x0F30, 0x3F30,
197 0x00F0, 0x30F0, 0x0CF0, 0x3CF0, 0x03F0, 0x33F0, 0x0FF0, 0x3FF0, // $1x
198 0x000C, 0x300C, 0x0C0C, 0x3C0C, 0x030C, 0x330C, 0x0F0C, 0x3F0C,
199 0x00CC, 0x30CC, 0x0CCC, 0x3CCC, 0x03CC, 0x33CC, 0x0FCC, 0x3FCC, // $2x
200 0x003C, 0x303C, 0x0C3C, 0x3C3C, 0x033C, 0x333C, 0x0F3C, 0x3F3C,
201 0x00FC, 0x30FC, 0x0CFC, 0x3CFC, 0x03FC, 0x33FC, 0x0FFC, 0x3FFC, // $3x
202 0x0003, 0x3003, 0x0C03, 0x3C03, 0x0303, 0x3303, 0x0F03, 0x3F03,
203 0x00C3, 0x30C3, 0x0CC3, 0x3CC3, 0x03C3, 0x33C3, 0x0FC3, 0x3FC3, // $4x
204 0x0033, 0x3033, 0x0C33, 0x3C33, 0x0333, 0x3333, 0x0F33, 0x3F33,
205 0x00F3, 0x30F3, 0x0CF3, 0x3CF3, 0x03F3, 0x33F3, 0x0FF3, 0x3FF3, // $5x
206 0x000F, 0x300F, 0x0C0F, 0x3C0F, 0x030F, 0x330F, 0x0F0F, 0x3F0F,
207 0x00CF, 0x30CF, 0x0CCF, 0x3CCF, 0x03CF, 0x33CF, 0x0FCF, 0x3FCF, // $6x
208 0x003F, 0x303F, 0x0C3F, 0x3C3F, 0x033F, 0x333F, 0x0F3F, 0x3F3F,
209 0x00FF, 0x30FF, 0x0CFF, 0x3CFF, 0x03FF, 0x33FF, 0x0FFF, 0x3FFF, // $7x
210 0x2000, 0x3800, 0x2600, 0x3E00, 0x2180, 0x3980, 0x2780, 0x3F80,
211 0x2060, 0x3860, 0x2660, 0x3E60, 0x21E0, 0x39E0, 0x27E0, 0x3FE0, // $8x
212 0x2018, 0x3818, 0x2618, 0x3E18, 0x2198, 0x3998, 0x2798, 0x3F98,
213 0x2078, 0x3878, 0x2678, 0x3E78, 0x21F8, 0x39F8, 0x27F8, 0x3FF8, // $9x
214 0x2006, 0x3806, 0x2606, 0x3E06, 0x2186, 0x3986, 0x2786, 0x3F86,
215 0x2066, 0x3866, 0x2666, 0x3E66, 0x21E6, 0x39E6, 0x27E6, 0x3FE6, // $Ax
216 0x201E, 0x381E, 0x261E, 0x3E1E, 0x219E, 0x399E, 0x279E, 0x3F9E,
217 0x207E, 0x387E, 0x267E, 0x3E7E, 0x21FE, 0x39FE, 0x27FE, 0x3FFE, // $Bx
218 0x2001, 0x3801, 0x2601, 0x3E01, 0x2181, 0x3981, 0x2781, 0x3F81,
219 0x2061, 0x3861, 0x2661, 0x3E61, 0x21E1, 0x39E1, 0x27E1, 0x3FE1, // $Cx
220 0x2019, 0x3819, 0x2619, 0x3E19, 0x2199, 0x3999, 0x2799, 0x3F99,
221 0x2079, 0x3879, 0x2679, 0x3E79, 0x21F9, 0x39F9, 0x27F9, 0x3FF9, // $Dx
222 0x2007, 0x3807, 0x2607, 0x3E07, 0x2187, 0x3987, 0x2787, 0x3F87,
223 0x2067, 0x3867, 0x2667, 0x3E67, 0x21E7, 0x39E7, 0x27E7, 0x3FE7, // $Ex
224 0x201F, 0x381F, 0x261F, 0x3E1F, 0x219F, 0x399F, 0x279F, 0x3F9F,
225 0x207F, 0x387F, 0x267F, 0x3E7F, 0x21FF, 0x39FF, 0x27FF, 0x3FFF // $Fx
228 static uint8 blurTable[0x800][8]; // Color TV blur table
229 static uint32 * palette = (uint32 *)altColors;
230 enum { ST_FIRST_ENTRY = 0, ST_COLOR_TV = 0, ST_WHITE_MONO, ST_GREEN_MONO, ST_LAST_ENTRY };
231 static uint8 screenType = ST_COLOR_TV;
235 static void Render40ColumnTextLine(uint8 line);
236 static void Render40ColumnText(void);
237 static void RenderLoRes(uint16 toLine = 24);
238 static void RenderHiRes(uint16 toLine = 192);
241 void SetupBlurTable(void)
243 // NOTE: This table only needs to be 7 bits wide instead of 11, since the
244 // last four bits are copies of the previous four...
246 for(uint16 bitPat=0; bitPat<0x800; bitPat++)
248 uint16 w3 = bitPat & 0x888;
249 uint16 w2 = bitPat & 0x444;
250 uint16 w1 = bitPat & 0x222;
251 uint16 w0 = bitPat & 0x111;
253 uint16 blurred3 = (w3 | (w3 >> 1) | (w3 >> 2) | (w3 >> 3)) & 0x00FF;
254 uint16 blurred2 = (w2 | (w2 >> 1) | (w2 >> 2) | (w2 >> 3)) & 0x00FF;
255 uint16 blurred1 = (w1 | (w1 >> 1) | (w1 >> 2) | (w1 >> 3)) & 0x00FF;
256 uint16 blurred0 = (w0 | (w0 >> 1) | (w0 >> 2) | (w0 >> 3)) & 0x00FF;
258 for(int8 i=7; i>=0; i--)
260 uint8 color = (((blurred0 >> i) & 0x01) << 3)
261 | (((blurred1 >> i) & 0x01) << 2)
262 | (((blurred2 >> i) & 0x01) << 1)
263 | ((blurred3 >> i) & 0x01);
264 blurTable[bitPat][7 - i] = color;
269 void TogglePalette(void)
271 if (palette == (uint32 *)colors)
273 palette = (uint32 *)altColors;
274 SpawnMessage("Color TV palette");
278 palette = (uint32 *)colors;
279 SpawnMessage("\"Master Color Values\" palette");
283 void CycleScreenTypes(void)
285 char scrTypeStr[3][40] = { "Color TV", "White monochrome", "Green monochrome" };
289 if (screenType == ST_LAST_ENTRY)
290 screenType = ST_FIRST_ENTRY;
292 SpawnMessage("%s", scrTypeStr[screenType]);
295 static uint32 msgTicks = 0;
296 static char message[4096];
298 void SpawnMessage(const char * text, ...)
303 vsprintf(message, text, arg);
309 static void DrawString2(uint32 x, uint32 y, uint32 color);
310 static void DrawString(void)
312 //This approach works, and seems to be fast enough... Though it probably would
313 //be better to make the oversized font to match this one...
314 for(uint32 x=7; x<=9; x++)
315 for(uint32 y=7; y<=9; y++)
316 DrawString2(x, y, 0x00000000);
318 DrawString2(8, 8, 0x0020FF20);
321 static void DrawString2(uint32 x, uint32 y, uint32 color)
323 //uint32 x = 8, y = 8;
324 uint32 length = strlen(message), address = x + (y * VIRTUAL_SCREEN_WIDTH);
325 // uint32 color = 0x0020FF20;
326 //This could be done ahead of time, instead of on each pixel...
328 uint8 nBlue = (color >> 16) & 0xFF, nGreen = (color >> 8) & 0xFF, nRed = color & 0xFF;
330 for(uint32 i=0; i<length; i++)
332 uint8 c = message[i];
333 c = (c < 32 ? 0 : c - 32);
334 uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
336 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
338 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
340 /* uint8 fontTrans = font1[fontAddr++];
341 // uint32 newTrans = (fontTrans * transparency / 255) << 24;
342 uint32 newTrans = fontTrans << 24;
343 uint32 pixel = newTrans | color;
345 *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = pixel;//*/
347 uint8 trans = font1[fontAddr++];
351 uint32 existingColor = *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH));
353 uint8 eBlue = (existingColor >> 16) & 0xFF,
354 eGreen = (existingColor >> 8) & 0xFF,
355 eRed = existingColor & 0xFF;
357 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
358 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
359 //because dividing by 32 is faster than dividing by 31...!
360 uint8 invTrans = 255 - trans;
362 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
363 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
364 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
366 //THIS IS NOT ENDIAN SAFE
367 *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
372 address += FONT_WIDTH;
376 static void Render40ColumnTextLine(uint8 line)
378 uint32 pixelOn = (screenType == ST_GREEN_MONO ? 0xFF61FF61 : 0xFFFFFFFF);
380 for(int x=0; x<40; x++)
382 uint8 chr = ram[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x];
384 // Render character at (x, y)
386 for(int cy=0; cy<8; cy++)
388 for(int cx=0; cx<7; cx++)
390 uint32 pixel = 0xFF000000;
392 if (!alternateCharset)
394 if (textChar[((chr & 0x3F) * 56) + cx + (cy * 7)])
395 // pixel = 0xFFFFFFFF;
399 pixel = pixel ^ (screenType == ST_GREEN_MONO ? 0x0061FF61 : 0x00FFFFFF);
401 if ((chr & 0xC0) == 0x40 && flash)
406 if (textChar2e[(chr * 56) + cx + (cy * 7)])
407 // pixel = 0xFFFFFFFF;
411 // scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
412 // scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
413 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;
414 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;
416 if (screenType == ST_GREEN_MONO)
420 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;
421 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;
428 static void Render40ColumnText(void)
430 for(uint8 line=0; line<24; line++)
431 Render40ColumnTextLine(line);
434 static void RenderLoRes(uint16 toLine/*= 24*/)
436 // NOTE: The green mono rendering doesn't skip every other line... !!! FIX !!!
438 Note that these colors correspond to the bit patterns generated by the numbers 0-F in order:
439 Color #s correspond to the bit patterns in reverse... Interesting!
441 00 00 00 -> 0 [0000] -> 0 (lores color #)
442 3c 4d 00 -> 8 [0001] -> 8? BROWN
443 00 5d 3c -> 4 [0010] -> 4? DARK GREEN
444 3c aa 3c -> 12 [0011] -> 12? LIGHT GREEN (GREEN)
445 41 30 7d -> 2 [0100] -> 2? DARK BLUE
446 7d 7d 7d -> 10 [0101] -> 10? LIGHT GRAY
447 41 8e ba -> 6 [0110] -> 6? MEDIUM BLUE (BLUE)
448 7d db ba -> 14 [0111] -> 14? AQUAMARINE (AQUA)
449 7d 20 41 -> 1 [1000] -> 1? DEEP RED (MAGENTA)
450 ba 6d 41 -> 9 [1001] -> 9? ORANGE
451 7d 7d 7d -> 5 [1010] -> 5? DARK GRAY
452 ba cb 7d -> 13 [1011] -> 13? YELLOW
453 be 51 be -> 3 [1100] -> 3 PURPLE (VIOLET)
454 fb 9e be -> 11 [1101] -> 11? PINK
455 be ae fb -> 7 [1110] -> 7? LIGHT BLUE (CYAN)
456 fb fb fb -> 15 [1111] -> 15 WHITE
458 uint8 mirrorNybble[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
460 //This is the old "perfect monitor" rendering code...
461 /* if (screenType != ST_COLOR_TV) // Not correct, but for now...
464 for(uint16 y=0; y<toLine; y++)
466 for(uint16 x=0; x<40; x++)
468 uint8 scrByte = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x];
469 uint32 pixel = palette[scrByte & 0x0F];
471 for(int cy=0; cy<4; cy++)
472 for(int cx=0; cx<14; cx++)
473 scrBuffer[((x * 14) + cx) + (((y * 8) + cy) * VIRTUAL_SCREEN_WIDTH)] = pixel;
475 pixel = palette[scrByte >> 4];
477 for(int cy=4; cy<8; cy++)
478 for(int cx=0; cx<14; cx++)
479 scrBuffer[(x * 14) + (y * VIRTUAL_SCREEN_WIDTH * 8) + cx + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
485 uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
487 for(uint16 y=0; y<toLine; y++)
489 // Do top half of lores screen bytes...
491 uint32 previous3Bits = 0;
493 for(uint16 x=0; x<40; x+=2)
495 uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] & 0x0F;
496 uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] & 0x0F;
497 scrByte1 = mirrorNybble[scrByte1];
498 scrByte2 = mirrorNybble[scrByte2];
499 // This is just a guess, but it'll have to do for now...
500 uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
501 | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
502 | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
504 // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
505 // 0ppp 1111 1111 1111 11|11 1111 1111 1111
506 // 31 27 23 19 15 11 7 3 0
508 if (screenType == ST_COLOR_TV)
510 for(uint8 i=0; i<7; i++)
512 uint16 bitPat = (pixels & 0x7F000000) >> 20;
515 for(uint8 j=0; j<4; j++)
517 uint8 color = blurTable[bitPat][j];
519 for(uint32 cy=0; cy<8; cy++)
521 scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
522 // scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
527 previous3Bits = pixels & 0x70000000;
531 for(int j=0; j<28; j++)
533 for(uint32 cy=0; cy<8; cy++)
535 scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
536 // scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
544 // Now do bottom half...
548 for(uint16 x=0; x<40; x+=2)
550 uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] >> 4;
551 uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] >> 4;
552 scrByte1 = mirrorNybble[scrByte1];
553 scrByte2 = mirrorNybble[scrByte2];
554 // This is just a guess, but it'll have to do for now...
555 uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
556 | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
557 | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
559 // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
560 // 0ppp 1111 1111 1111 11|11 1111 1111 1111
561 // 31 27 23 19 15 11 7 3 0
563 if (screenType == ST_COLOR_TV)
565 for(uint8 i=0; i<7; i++)
567 uint16 bitPat = (pixels & 0x7F000000) >> 20;
570 for(uint8 j=0; j<4; j++)
572 uint8 color = blurTable[bitPat][j];
574 for(uint32 cy=8; cy<16; cy++)
576 scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
577 // scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
582 previous3Bits = pixels & 0x70000000;
586 for(int j=0; j<28; j++)
588 for(uint32 cy=8; cy<16; cy++)
590 scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
591 // scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
601 static void RenderHiRes(uint16 toLine/*= 192*/)
603 uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
605 for(uint16 y=0; y<toLine; y++)
607 uint16 previousLoPixel = 0;
608 uint32 previous3bits = 0;
610 for(uint16 x=0; x<40; x+=2)
612 uint8 screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x];
613 uint32 pixels = appleHiresToMono[previousLoPixel | screenByte];
614 previousLoPixel = (screenByte << 2) & 0x0100;
616 screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x + 1];
617 uint32 pixels2 = appleHiresToMono[previousLoPixel | screenByte];
618 previousLoPixel = (screenByte << 2) & 0x0100;
620 pixels = previous3bits | (pixels << 14) | pixels2;
622 // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
623 // 0ppp 1111 1111 1111 1111 1111 1111 1111
624 // 31 27 23 19 15 11 7 3 0
626 if (screenType == ST_COLOR_TV)
628 for(uint8 i=0; i<7; i++)
630 uint16 bitPat = (pixels & 0x7F000000) >> 20;
633 for(uint8 j=0; j<4; j++)
635 uint8 color = blurTable[bitPat][j];
637 //This doesn't seem to make things go any faster...
638 //It's the OpenGL render that's faster... Hmm...
639 scrBuffer[(x * 14) + (i * 4) + j + (y * VIRTUAL_SCREEN_WIDTH)] = palette[color];
641 scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
642 scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
647 previous3bits = pixels & 0x70000000;
651 for(int j=0; j<28; j++)
653 scrBuffer[(x * 14) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
655 if (screenType == ST_GREEN_MONO)
656 pixels &= 0x07FFFFFF;
658 scrBuffer[(x * 14) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
666 void RenderVideoFrame(void)
670 RenderScreenBuffer();
675 // There's prolly more to it than this (like 80 column text), but this'll have to do for now...
676 Render40ColumnText();
685 Render40ColumnTextLine(20);
686 Render40ColumnTextLine(21);
687 Render40ColumnTextLine(22);
688 Render40ColumnTextLine(23);
693 Render40ColumnTextLine(20);
694 Render40ColumnTextLine(21);
695 Render40ColumnTextLine(22);
696 Render40ColumnTextLine(23);
714 RenderScreenBuffer();