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