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