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 uint8 blurTable[0x80][8]; // Color TV blur table
230 static uint32 * palette = (uint32 *)altColors;
231 enum { ST_FIRST_ENTRY = 0, ST_COLOR_TV = 0, ST_WHITE_MONO, ST_GREEN_MONO, ST_LAST_ENTRY };
232 static uint8 screenType = ST_COLOR_TV;
236 static void Render40ColumnTextLine(uint8 line);
237 static void Render40ColumnText(void);
238 static void RenderLoRes(uint16 toLine = 24);
239 static void RenderHiRes(uint16 toLine = 192);
242 void SetupBlurTable(void)
244 // NOTE: This table only needs to be 7 bits wide instead of 11, since the
245 // last four bits are copies of the previous four...
247 // for(uint16 bitPat=0; bitPat<0x800; bitPat++)
248 for(uint16 bitPat=0; bitPat<0x80; bitPat++)
250 /* uint16 w3 = bitPat & 0x888;
251 uint16 w2 = bitPat & 0x444;
252 uint16 w1 = bitPat & 0x222;
253 uint16 w0 = bitPat & 0x111;*/
254 uint16 w3 = bitPat & 0x88;
255 uint16 w2 = bitPat & 0x44;
256 uint16 w1 = bitPat & 0x22;
257 uint16 w0 = bitPat & 0x11;
259 uint16 blurred3 = (w3 | (w3 >> 1) | (w3 >> 2) | (w3 >> 3)) & 0x00FF;
260 uint16 blurred2 = (w2 | (w2 >> 1) | (w2 >> 2) | (w2 >> 3)) & 0x00FF;
261 uint16 blurred1 = (w1 | (w1 >> 1) | (w1 >> 2) | (w1 >> 3)) & 0x00FF;
262 uint16 blurred0 = (w0 | (w0 >> 1) | (w0 >> 2) | (w0 >> 3)) & 0x00FF;
264 for(int8 i=7; i>=0; i--)
266 uint8 color = (((blurred0 >> i) & 0x01) << 3)
267 | (((blurred1 >> i) & 0x01) << 2)
268 | (((blurred2 >> i) & 0x01) << 1)
269 | ((blurred3 >> i) & 0x01);
270 blurTable[bitPat][7 - i] = color;
275 void TogglePalette(void)
277 if (palette == (uint32 *)colors)
279 palette = (uint32 *)altColors;
280 SpawnMessage("Color TV palette");
284 palette = (uint32 *)colors;
285 SpawnMessage("\"Master Color Values\" palette");
289 void CycleScreenTypes(void)
291 char scrTypeStr[3][40] = { "Color TV", "White monochrome", "Green monochrome" };
295 if (screenType == ST_LAST_ENTRY)
296 screenType = ST_FIRST_ENTRY;
298 SpawnMessage("%s", scrTypeStr[screenType]);
301 static uint32 msgTicks = 0;
302 static char message[4096];
304 void SpawnMessage(const char * text, ...)
309 vsprintf(message, text, arg);
315 static void DrawString2(uint32 x, uint32 y, uint32 color);
316 static void DrawString(void)
318 //This approach works, and seems to be fast enough... Though it probably would
319 //be better to make the oversized font to match this one...
320 for(uint32 x=7; x<=9; x++)
321 for(uint32 y=7; y<=9; y++)
322 DrawString2(x, y, 0x00000000);
324 DrawString2(8, 8, 0x0020FF20);
327 static void DrawString2(uint32 x, uint32 y, uint32 color)
329 //uint32 x = 8, y = 8;
330 uint32 length = strlen(message), address = x + (y * VIRTUAL_SCREEN_WIDTH);
331 // uint32 color = 0x0020FF20;
332 //This could be done ahead of time, instead of on each pixel...
334 uint8 nBlue = (color >> 16) & 0xFF, nGreen = (color >> 8) & 0xFF, nRed = color & 0xFF;
336 for(uint32 i=0; i<length; i++)
338 uint8 c = message[i];
339 c = (c < 32 ? 0 : c - 32);
340 uint32 fontAddr = (uint32)c * FONT_WIDTH * FONT_HEIGHT;
342 for(uint32 yy=0; yy<FONT_HEIGHT; yy++)
344 for(uint32 xx=0; xx<FONT_WIDTH; xx++)
346 /* uint8 fontTrans = font1[fontAddr++];
347 // uint32 newTrans = (fontTrans * transparency / 255) << 24;
348 uint32 newTrans = fontTrans << 24;
349 uint32 pixel = newTrans | color;
351 *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = pixel;//*/
353 uint8 trans = font1[fontAddr++];
357 uint32 existingColor = *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH));
359 uint8 eBlue = (existingColor >> 16) & 0xFF,
360 eGreen = (existingColor >> 8) & 0xFF,
361 eRed = existingColor & 0xFF;
363 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
364 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
365 //because dividing by 32 is faster than dividing by 31...!
366 uint8 invTrans = 255 - trans;
368 uint32 bRed = (eRed * invTrans + nRed * trans) / 255;
369 uint32 bGreen = (eGreen * invTrans + nGreen * trans) / 255;
370 uint32 bBlue = (eBlue * invTrans + nBlue * trans) / 255;
372 //THIS IS NOT ENDIAN SAFE
373 *(scrBuffer + address + xx + (yy * VIRTUAL_SCREEN_WIDTH)) = 0xFF000000 | (bBlue << 16) | (bGreen << 8) | bRed;
378 address += FONT_WIDTH;
382 static void Render40ColumnTextLine(uint8 line)
384 uint32 pixelOn = (screenType == ST_GREEN_MONO ? 0xFF61FF61 : 0xFFFFFFFF);
386 for(int x=0; x<40; x++)
388 uint8 chr = ram[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x];
390 // Render character at (x, y)
392 for(int cy=0; cy<8; cy++)
394 for(int cx=0; cx<7; cx++)
396 uint32 pixel = 0xFF000000;
398 if (!alternateCharset)
400 if (textChar[((chr & 0x3F) * 56) + cx + (cy * 7)])
401 // pixel = 0xFFFFFFFF;
405 pixel = pixel ^ (screenType == ST_GREEN_MONO ? 0x0061FF61 : 0x00FFFFFF);
407 if ((chr & 0xC0) == 0x40 && flash)
412 if (textChar2e[(chr * 56) + cx + (cy * 7)])
413 // pixel = 0xFFFFFFFF;
417 // scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
418 // scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
419 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;
420 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel;
422 if (screenType == ST_GREEN_MONO)
426 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;
427 scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel;
434 static void Render40ColumnText(void)
436 for(uint8 line=0; line<24; line++)
437 Render40ColumnTextLine(line);
440 static void RenderLoRes(uint16 toLine/*= 24*/)
442 // NOTE: The green mono rendering doesn't skip every other line... !!! FIX !!!
443 // Also, we could set up three different Render functions depending on which
444 // render type was set and call it with a function pointer. Would be faster
445 // then the nested ifs we have now.
447 Note that these colors correspond to the bit patterns generated by the numbers 0-F in order:
448 Color #s correspond to the bit patterns in reverse... Interesting!
450 00 00 00 -> 0 [0000] -> 0 (lores color #)
451 3c 4d 00 -> 8 [0001] -> 8? BROWN
452 00 5d 3c -> 4 [0010] -> 4? DARK GREEN
453 3c aa 3c -> 12 [0011] -> 12? LIGHT GREEN (GREEN)
454 41 30 7d -> 2 [0100] -> 2? DARK BLUE
455 7d 7d 7d -> 10 [0101] -> 10? LIGHT GRAY
456 41 8e ba -> 6 [0110] -> 6? MEDIUM BLUE (BLUE)
457 7d db ba -> 14 [0111] -> 14? AQUAMARINE (AQUA)
458 7d 20 41 -> 1 [1000] -> 1? DEEP RED (MAGENTA)
459 ba 6d 41 -> 9 [1001] -> 9? ORANGE
460 7d 7d 7d -> 5 [1010] -> 5? DARK GRAY
461 ba cb 7d -> 13 [1011] -> 13? YELLOW
462 be 51 be -> 3 [1100] -> 3 PURPLE (VIOLET)
463 fb 9e be -> 11 [1101] -> 11? PINK
464 be ae fb -> 7 [1110] -> 7? LIGHT BLUE (CYAN)
465 fb fb fb -> 15 [1111] -> 15 WHITE
467 uint8 mirrorNybble[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
469 //This is the old "perfect monitor" rendering code...
470 /* if (screenType != ST_COLOR_TV) // Not correct, but for now...
473 for(uint16 y=0; y<toLine; y++)
475 for(uint16 x=0; x<40; x++)
477 uint8 scrByte = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x];
478 uint32 pixel = palette[scrByte & 0x0F];
480 for(int cy=0; cy<4; cy++)
481 for(int cx=0; cx<14; cx++)
482 scrBuffer[((x * 14) + cx) + (((y * 8) + cy) * VIRTUAL_SCREEN_WIDTH)] = pixel;
484 pixel = palette[scrByte >> 4];
486 for(int cy=4; cy<8; cy++)
487 for(int cx=0; cx<14; cx++)
488 scrBuffer[(x * 14) + (y * VIRTUAL_SCREEN_WIDTH * 8) + cx + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel;
494 uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
496 for(uint16 y=0; y<toLine; y++)
498 // Do top half of lores screen bytes...
500 uint32 previous3Bits = 0;
502 for(uint16 x=0; x<40; x+=2)
504 uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] & 0x0F;
505 uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] & 0x0F;
506 scrByte1 = mirrorNybble[scrByte1];
507 scrByte2 = mirrorNybble[scrByte2];
508 // This is just a guess, but it'll have to do for now...
509 uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
510 | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
511 | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
513 // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
514 // 0ppp 1111 1111 1111 11|11 1111 1111 1111
515 // 31 27 23 19 15 11 7 3 0
517 if (screenType == ST_COLOR_TV)
519 for(uint8 i=0; i<7; i++)
521 uint16 bitPat = (pixels & 0x7F000000) >> 20;
524 for(uint8 j=0; j<4; j++)
526 uint8 color = blurTable[bitPat][j];
528 for(uint32 cy=0; cy<8; cy++)
530 scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
531 // scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
536 previous3Bits = pixels & 0x70000000;
540 for(int j=0; j<28; j++)
542 for(uint32 cy=0; cy<8; cy++)
544 scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
545 // scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
553 // Now do bottom half...
557 for(uint16 x=0; x<40; x+=2)
559 uint8 scrByte1 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 0] >> 4;
560 uint8 scrByte2 = ram[lineAddrLoRes[y] + (displayPage2 ? 0x0400 : 0x0000) + x + 1] >> 4;
561 scrByte1 = mirrorNybble[scrByte1];
562 scrByte2 = mirrorNybble[scrByte2];
563 // This is just a guess, but it'll have to do for now...
564 uint32 pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
565 | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
566 | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
568 // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
569 // 0ppp 1111 1111 1111 11|11 1111 1111 1111
570 // 31 27 23 19 15 11 7 3 0
572 if (screenType == ST_COLOR_TV)
574 for(uint8 i=0; i<7; i++)
576 uint16 bitPat = (pixels & 0x7F000000) >> 20;
579 for(uint8 j=0; j<4; j++)
581 uint8 color = blurTable[bitPat][j];
583 for(uint32 cy=8; cy<16; cy++)
585 scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
586 // scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
591 previous3Bits = pixels & 0x70000000;
595 for(int j=0; j<28; j++)
597 for(uint32 cy=8; cy<16; cy++)
599 scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
600 // scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
610 static void RenderHiRes(uint16 toLine/*= 192*/)
612 // NOTE: Not endian safe. !!! FIX !!!
613 uint32 pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
615 for(uint16 y=0; y<toLine; y++)
617 uint16 previousLoPixel = 0;
618 uint32 previous3bits = 0;
620 for(uint16 x=0; x<40; x+=2)
622 uint8 screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x];
623 uint32 pixels = appleHiresToMono[previousLoPixel | screenByte];
624 previousLoPixel = (screenByte << 2) & 0x0100;
626 screenByte = ram[lineAddrHiRes[y] + (displayPage2 ? 0x2000 : 0x0000) + x + 1];
627 uint32 pixels2 = appleHiresToMono[previousLoPixel | screenByte];
628 previousLoPixel = (screenByte << 2) & 0x0100;
630 pixels = previous3bits | (pixels << 14) | pixels2;
632 // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
633 // 0ppp 1111 1111 1111 1111 1111 1111 1111
634 // 31 27 23 19 15 11 7 3 0
636 if (screenType == ST_COLOR_TV)
638 for(uint8 i=0; i<7; i++)
640 uint16 bitPat = (pixels & 0x7F000000) >> 20;
643 for(uint8 j=0; j<4; j++)
645 uint8 color = blurTable[bitPat][j];
647 //This doesn't seem to make things go any faster...
648 //It's the OpenGL render that's faster... Hmm...
649 scrBuffer[(x * 14) + (i * 4) + j + (y * VIRTUAL_SCREEN_WIDTH)] = palette[color];
651 scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
652 scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
657 previous3bits = pixels & 0x70000000;
661 for(int j=0; j<28; j++)
663 scrBuffer[(x * 14) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
665 if (screenType == ST_GREEN_MONO)
666 pixels &= 0x07FFFFFF;
668 scrBuffer[(x * 14) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
676 void RenderVideoFrame(void)
680 RenderScreenBuffer();
685 // There's prolly more to it than this (like 80 column text), but this'll have to do for now...
686 Render40ColumnText();
695 Render40ColumnTextLine(20);
696 Render40ColumnTextLine(21);
697 Render40ColumnTextLine(22);
698 Render40ColumnTextLine(23);
703 Render40ColumnTextLine(20);
704 Render40ColumnTextLine(21);
705 Render40ColumnTextLine(22);
706 Render40ColumnTextLine(23);
724 RenderScreenBuffer();