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