1 /*
2 * Copyright (C) 2002-2010 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* $Id: vga_draw.cpp,v 1.112 2009-11-03 21:06:59 h-a-l-9000 Exp $ */
20
21 #include <string.h>
22 #include <math.h>
23 #include "dosbox.h"
24 #include "video.h"
25 #include "render.h"
26 #include "../gui/render_scalers.h"
27 #include "vga.h"
28 #include "pic.h"
29
30 //#undef C_DEBUG
31 //#define C_DEBUG 1
32 //#define LOG(X,Y) LOG_MSG
33
34 #define VGA_PARTS 4
35
36 typedef Bit8u * (* VGA_Line_Handler)(Bitu vidstart, Bitu line);
37
38 static VGA_Line_Handler VGA_DrawLine;
39 static Bit8u TempLine[SCALER_MAXWIDTH * 4];
40
VGA_Draw_1BPP_Line(Bitu vidstart,Bitu line)41 static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart, Bitu line) {
42 const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
43 Bit32u *draw = (Bit32u *)TempLine;
44 for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
45 Bitu val = base[(vidstart & (8 * 1024 -1))];
46 *draw++=CGA_2_Table[val >> 4];
47 *draw++=CGA_2_Table[val & 0xf];
48 }
49 return TempLine;
50 }
51
VGA_Draw_2BPP_Line(Bitu vidstart,Bitu line)52 static Bit8u * VGA_Draw_2BPP_Line(Bitu vidstart, Bitu line) {
53 const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
54 Bit32u * draw=(Bit32u *)TempLine;
55 for (Bitu x=0;x<vga.draw.blocks;x++) {
56 Bitu val = base[vidstart & vga.tandy.addr_mask];
57 vidstart++;
58 *draw++=CGA_4_Table[val];
59 }
60 return TempLine;
61 }
62
VGA_Draw_2BPPHiRes_Line(Bitu vidstart,Bitu line)63 static Bit8u * VGA_Draw_2BPPHiRes_Line(Bitu vidstart, Bitu line) {
64 const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
65 Bit32u * draw=(Bit32u *)TempLine;
66 for (Bitu x=0;x<vga.draw.blocks;x++) {
67 Bitu val1 = base[vidstart & vga.tandy.addr_mask];
68 ++vidstart;
69 Bitu val2 = base[vidstart & vga.tandy.addr_mask];
70 ++vidstart;
71 *draw++=CGA_4_HiRes_Table[(val1>>4)|(val2&0xf0)];
72 *draw++=CGA_4_HiRes_Table[(val1&0x0f)|((val2&0x0f)<<4)];
73 }
74 return TempLine;
75 }
76
77 static Bitu temp[643]={0};
78
VGA_Draw_CGA16_Line(Bitu vidstart,Bitu line)79 static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) {
80 const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
81 const Bit8u *reader = base + vidstart;
82 Bit32u * draw=(Bit32u *)TempLine;
83 //Generate a temporary bitline to calculate the avarage
84 //over bit-2 bit-1 bit bit+1.
85 //Combine this number with the current colour to get
86 //an unigue index in the pallete. Or it with bit 7 as they are stored
87 //in the upperpart to keep them from interfering the regular cga stuff
88
89 for(Bitu x = 0; x < 640; x++)
90 temp[x+2] = (( reader[(x>>3)] >> (7-(x&7)) )&1) << 4;
91 //shift 4 as that is for the index.
92 Bitu i = 0,temp1,temp2,temp3,temp4;
93 for (Bitu x=0;x<vga.draw.blocks;x++) {
94 Bitu val1 = *reader++;
95 Bitu val2 = val1&0xf;
96 val1 >>= 4;
97
98 temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
99 temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
100 temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
101 temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
102
103 *draw++ = 0x80808080|(temp1|val1) |
104 ((temp2|val1) << 8) |
105 ((temp3|val1) <<16) |
106 ((temp4|val1) <<24);
107 temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
108 temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
109 temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
110 temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
111 *draw++ = 0x80808080|(temp1|val2) |
112 ((temp2|val2) << 8) |
113 ((temp3|val2) <<16) |
114 ((temp4|val2) <<24);
115 }
116 return TempLine;
117 }
118
VGA_Draw_4BPP_Line(Bitu vidstart,Bitu line)119 static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) {
120 const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
121 Bit32u * draw=(Bit32u *)TempLine;
122 for (Bitu x=0;x<vga.draw.blocks;x++) {
123 Bitu val1 = base[vidstart & vga.tandy.addr_mask];
124 ++vidstart;
125 Bitu val2 = base[vidstart & vga.tandy.addr_mask];
126 ++vidstart;
127 *draw++=(val1 & 0x0f) << 8 |
128 (val1 & 0xf0) >> 4 |
129 (val2 & 0x0f) << 24 |
130 (val2 & 0xf0) << 12;
131 }
132 return TempLine;
133 }
134
VGA_Draw_4BPP_Line_Double(Bitu vidstart,Bitu line)135 static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart, Bitu line) {
136 const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
137 Bit32u * draw=(Bit32u *)TempLine;
138 for (Bitu x=0;x<vga.draw.blocks;x++) {
139 Bitu val = base[vidstart & vga.tandy.addr_mask];
140 ++vidstart;
141 *draw++=(val & 0xf0) >> 4 |
142 (val & 0xf0) << 4 |
143 (val & 0x0f) << 16 |
144 (val & 0x0f) << 24;
145 }
146 return TempLine;
147 }
148
149 #ifdef VGA_KEEP_CHANGES
VGA_Draw_Changes_Line(Bitu vidstart,Bitu line)150 static Bit8u * VGA_Draw_Changes_Line(Bitu vidstart, Bitu line) {
151 Bitu checkMask = vga.changes.checkMask;
152 Bit8u *map = vga.changes.map;
153 Bitu start = (vidstart >> VGA_CHANGE_SHIFT);
154 Bitu end = ((vidstart + vga.draw.line_length ) >> VGA_CHANGE_SHIFT);
155 for (; start <= end;start++) {
156 if ( map[start] & checkMask ) {
157 Bitu offset = vidstart & vga.draw.linear_mask;
158 if(vga.draw.linear_mask-offset < vga.draw.line_length)
159 memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length);
160 Bit8u *ret = &vga.draw.linear_base[ offset ];
161 #if !defined(C_UNALIGNED_MEMORY)
162 if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
163 memcpy( TempLine, ret, vga.draw.line_length );
164 return TempLine;
165 }
166 #endif
167 return ret;
168 }
169 }
170 // memset( TempLine, 0x30, vga.changes.lineWidth );
171 // return TempLine;
172 return 0;
173 }
174
175 #endif
176
VGA_Draw_Linear_Line(Bitu vidstart,Bitu)177 static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu /*line*/) {
178 // There is guaranteed extra memory past the wrap boundary. So, instead of using temporary
179 // storage just copy appropriate chunk from the beginning to the wrap boundary when needed.
180 Bitu offset = vidstart & vga.draw.linear_mask;
181 if (vga.draw.linear_mask-offset < vga.draw.line_length)
182 memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length);
183 Bit8u *ret = &vga.draw.linear_base[ offset ];
184 #if !defined(C_UNALIGNED_MEMORY)
185 if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
186 memcpy( TempLine, ret, vga.draw.line_length );
187 return TempLine;
188 }
189 #endif
190 return ret;
191 }
192
VGA_Draw_Xlat16_Linear_Line(Bitu vidstart,Bitu)193 static Bit8u * VGA_Draw_Xlat16_Linear_Line(Bitu vidstart, Bitu /*line*/) {
194 Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ];
195 Bit16u* temps = (Bit16u*) TempLine;
196 for(Bitu i = 0; i < vga.draw.line_length; i++) {
197 temps[i]=vga.dac.xlat16[ret[i]];
198 }
199 return TempLine;
200 /*
201 #if !defined(C_UNALIGNED_MEMORY)
202 if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
203 memcpy( TempLine, ret, vga.draw.line_length );
204 return TempLine;
205 }
206 #endif
207 return ret;*/
208 }
209
210 //Test version, might as well keep it
211 /* static Bit8u * VGA_Draw_Chain_Line(Bitu vidstart, Bitu line) {
212 Bitu i = 0;
213 for ( i = 0; i < vga.draw.width;i++ ) {
214 Bitu addr = vidstart + i;
215 TempLine[i] = vga.mem.linear[((addr&~3)<<2)+(addr&3)];
216 }
217 return TempLine;
218 } */
219
VGA_Draw_VGA_Line_HWMouse(Bitu vidstart,Bitu)220 static Bit8u * VGA_Draw_VGA_Line_HWMouse( Bitu vidstart, Bitu /*line*/) {
221 if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
222 // HW Mouse not enabled, use the tried and true call
223 return &vga.mem.linear[vidstart];
224
225 Bitu lineat = (vidstart-(vga.config.real_start<<2)) / vga.draw.width;
226 if ((vga.s3.hgc.posx >= vga.draw.width) ||
227 (lineat < vga.s3.hgc.originy) ||
228 (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
229 // the mouse cursor *pattern* is not on this line
230 return &vga.mem.linear[ vidstart ];
231 } else {
232 // Draw mouse cursor: cursor is a 64x64 pattern which is shifted (inside the
233 // 64x64 mouse cursor space) to the right by posx pixels and up by posy pixels.
234 // This is used when the mouse cursor partially leaves the screen.
235 // It is arranged as bitmap of 16bits of bitA followed by 16bits of bitB, each
236 // AB bits corresponding to a cursor pixel. The whole map is 8kB in size.
237 memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width);
238 // the index of the bit inside the cursor bitmap we start at:
239 Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
240 // convert to video memory addr and bit index
241 // start adjusted to the pattern structure (thus shift address by 2 instead of 3)
242 // Need to get rid of the third bit, so "/8 *2" becomes ">> 2 & ~1"
243 Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
244 Bitu cursorStartBit = sourceStartBit & 0x7;
245 // stay at the right position in the pattern
246 if (cursorMemStart & 0x2) cursorMemStart--;
247 Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
248 Bit8u* xat = &TempLine[vga.s3.hgc.originx]; // mouse data start pos. in scanline
249 for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
250 // for each byte of cursor data
251 Bit8u bitsA = vga.mem.linear[m];
252 Bit8u bitsB = vga.mem.linear[m+2];
253 for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
254 // for each bit
255 cursorStartBit=0; // only the first byte has some bits cut off
256 if (bitsA&bit) {
257 if (bitsB&bit) *xat ^= 0xFF; // Invert screen data
258 //else Transparent
259 } else if (bitsB&bit) {
260 *xat = vga.s3.hgc.forestack[0]; // foreground color
261 } else {
262 *xat = vga.s3.hgc.backstack[0];
263 }
264 xat++;
265 }
266 }
267 return TempLine;
268 }
269 }
270
VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart,Bitu)271 static Bit8u * VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
272 if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
273 return &vga.mem.linear[vidstart];
274
275 Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 1) / vga.draw.width;
276 if ((vga.s3.hgc.posx >= vga.draw.width) ||
277 (lineat < vga.s3.hgc.originy) ||
278 (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
279 return &vga.mem.linear[vidstart];
280 } else {
281 memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*2);
282 Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
283 Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
284 Bitu cursorStartBit = sourceStartBit & 0x7;
285 if (cursorMemStart & 0x2) cursorMemStart--;
286 Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
287 Bit16u* xat = &((Bit16u*)TempLine)[vga.s3.hgc.originx];
288 for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
289 // for each byte of cursor data
290 Bit8u bitsA = vga.mem.linear[m];
291 Bit8u bitsB = vga.mem.linear[m+2];
292 for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
293 // for each bit
294 cursorStartBit=0;
295 if (bitsA&bit) {
296 // byte order doesn't matter here as all bits get flipped
297 if (bitsB&bit) *xat ^= ~0U;
298 //else Transparent
299 } else if (bitsB&bit) {
300 // Source as well as destination are Bit8u arrays,
301 // so this should work out endian-wise?
302 *xat = *(Bit16u*)vga.s3.hgc.forestack;
303 } else {
304 *xat = *(Bit16u*)vga.s3.hgc.backstack;
305 }
306 xat++;
307 }
308 }
309 return TempLine;
310 }
311 }
312
VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart,Bitu)313 static Bit8u * VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
314 if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
315 return &vga.mem.linear[vidstart];
316
317 Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 2) / vga.draw.width;
318 if ((vga.s3.hgc.posx >= vga.draw.width) ||
319 (lineat < vga.s3.hgc.originy) ||
320 (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
321 return &vga.mem.linear[ vidstart ];
322 } else {
323 memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*4);
324 Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
325 Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
326 Bitu cursorStartBit = sourceStartBit & 0x7;
327 if (cursorMemStart & 0x2) cursorMemStart--;
328 Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
329 Bit32u* xat = &((Bit32u*)TempLine)[vga.s3.hgc.originx];
330 for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
331 // for each byte of cursor data
332 Bit8u bitsA = vga.mem.linear[m];
333 Bit8u bitsB = vga.mem.linear[m+2];
334 for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) { // for each bit
335 cursorStartBit=0;
336 if (bitsA&bit) {
337 if (bitsB&bit) *xat ^= ~0U;
338 //else Transparent
339 } else if (bitsB&bit) {
340 *xat = *(Bit32u*)vga.s3.hgc.forestack;
341 } else {
342 *xat = *(Bit32u*)vga.s3.hgc.backstack;
343 }
344 xat++;
345 }
346 }
347 return TempLine;
348 }
349 }
350
VGA_Text_Memwrap(Bitu vidstart)351 static const Bit8u* VGA_Text_Memwrap(Bitu vidstart) {
352 vidstart &= vga.draw.linear_mask;
353 Bitu line_end = 2 * vga.draw.blocks;
354 if (GCC_UNLIKELY((vidstart + line_end) > vga.draw.linear_mask)) {
355 // wrapping in this line
356 Bitu break_pos = (vga.draw.linear_mask - vidstart) + 1;
357 // need a temporary storage - TempLine/2 is ok for a bit more than 132 columns
358 memcpy(&TempLine[sizeof(TempLine)/2], &vga.tandy.draw_base[vidstart], break_pos);
359 memcpy(&TempLine[sizeof(TempLine)/2 + break_pos],&vga.tandy.draw_base[0], line_end - break_pos);
360 return &TempLine[sizeof(TempLine)/2];
361 } else return &vga.tandy.draw_base[vidstart];
362 }
363
364 static Bit32u FontMask[2]={0xffffffff,0x0};
VGA_TEXT_Draw_Line(Bitu vidstart,Bitu line)365 static Bit8u * VGA_TEXT_Draw_Line(Bitu vidstart, Bitu line) {
366 Bits font_addr;
367 Bit32u * draw=(Bit32u *)TempLine;
368 const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
369 for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
370 Bitu chr=vidmem[cx*2];
371 Bitu col=vidmem[cx*2+1];
372 Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
373 Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
374 Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
375 Bit32u fg=TXT_FG_Table[col&0xf];
376 Bit32u bg=TXT_BG_Table[col>>4];
377 *draw++=(fg&mask1) | (bg&~mask1);
378 *draw++=(fg&mask2) | (bg&~mask2);
379 }
380 if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
381 font_addr = (vga.draw.cursor.address-vidstart) >> 1;
382 if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
383 if (line<vga.draw.cursor.sline) goto skip_cursor;
384 if (line>vga.draw.cursor.eline) goto skip_cursor;
385 draw=(Bit32u *)&TempLine[font_addr*8];
386 Bit32u att=TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf];
387 *draw++=att;*draw++=att;
388 }
389 skip_cursor:
390 return TempLine;
391 }
392
VGA_TEXT_Herc_Draw_Line(Bitu vidstart,Bitu line)393 static Bit8u * VGA_TEXT_Herc_Draw_Line(Bitu vidstart, Bitu line) {
394 Bits font_addr;
395 Bit32u * draw=(Bit32u *)TempLine;
396 const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
397
398 for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
399 Bitu chr=vidmem[cx*2];
400 Bitu attrib=vidmem[cx*2+1];
401 if (!(attrib&0x77)) {
402 // 00h, 80h, 08h, 88h produce black space
403 *draw++=0;
404 *draw++=0;
405 } else {
406 Bit32u bg, fg;
407 bool underline=false;
408 if ((attrib&0x77)==0x70) {
409 bg = TXT_BG_Table[0x7];
410 if (attrib&0x8) fg = TXT_FG_Table[0xf];
411 else fg = TXT_FG_Table[0x0];
412 } else {
413 if (((Bitu)(vga.crtc.underline_location&0x1f)==line) && ((attrib&0x77)==0x1)) underline=true;
414 bg = TXT_BG_Table[0x0];
415 if (attrib&0x8) fg = TXT_FG_Table[0xf];
416 else fg = TXT_FG_Table[0x7];
417 }
418 Bit32u mask1, mask2;
419 if (GCC_UNLIKELY(underline)) mask1 = mask2 = FontMask[attrib >> 7];
420 else {
421 Bitu font=vga.draw.font_tables[0][chr*32+line];
422 mask1=TXT_Font_Table[font>>4] & FontMask[attrib >> 7]; // blinking
423 mask2=TXT_Font_Table[font&0xf] & FontMask[attrib >> 7];
424 }
425 *draw++=(fg&mask1) | (bg&~mask1);
426 *draw++=(fg&mask2) | (bg&~mask2);
427 }
428 }
429 if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
430 font_addr = (vga.draw.cursor.address-vidstart) >> 1;
431 if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
432 if (line<vga.draw.cursor.sline) goto skip_cursor;
433 if (line>vga.draw.cursor.eline) goto skip_cursor;
434 draw=(Bit32u *)&TempLine[font_addr*8];
435 Bit8u attr = vga.tandy.draw_base[vga.draw.cursor.address+1];
436 Bit32u cg;
437 if (attr&0x8) {
438 cg = TXT_FG_Table[0xf];
439 } else if ((attr&0x77)==0x70) {
440 cg = TXT_FG_Table[0x0];
441 } else {
442 cg = TXT_FG_Table[0x7];
443 }
444 *draw++=cg;*draw++=cg;
445 }
446 skip_cursor:
447 return TempLine;
448 }
449
VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart,Bitu line)450 static Bit8u * VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart, Bitu line) {
451 Bits font_addr;
452 Bit16u * draw=(Bit16u *)TempLine;
453 const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
454 for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
455 Bitu chr=vidmem[cx*2];
456 Bitu col=vidmem[cx*2+1];
457 Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
458 Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
459 Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
460 Bit32u fg=TXT_FG_Table[col&0xf];
461 Bit32u bg=TXT_BG_Table[col>>4];
462
463 mask1=(fg&mask1) | (bg&~mask1);
464 mask2=(fg&mask2) | (bg&~mask2);
465
466 for(int i = 0; i < 4; i++) {
467 *draw++ = vga.dac.xlat16[(mask1>>8*i)&0xff];
468 }
469 for(int i = 0; i < 4; i++) {
470 *draw++ = vga.dac.xlat16[(mask2>>8*i)&0xff];
471 }
472 }
473 if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
474 font_addr = (vga.draw.cursor.address-vidstart) >> 1;
475 if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
476 if (line<vga.draw.cursor.sline) goto skip_cursor;
477 if (line>vga.draw.cursor.eline) goto skip_cursor;
478 draw=(Bit16u *)&TempLine[font_addr*16];
479 Bit8u att=(Bit8u)(TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf]&0xff);
480 for(int i = 0; i < 8; i++) {
481 *draw++ = vga.dac.xlat16[att];
482 }
483 }
484 skip_cursor:
485 return TempLine;
486 }
487
488 /*
489 static Bit8u * VGA_TEXT_Draw_Line_9(Bitu vidstart, Bitu line) {
490 Bits font_addr;
491 Bit8u * draw=(Bit8u *)TempLine;
492 bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line;
493 Bit8u pel_pan=(Bit8u)vga.draw.panning;
494 if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0;
495 const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
496 Bit8u chr=vidmem[0];
497 Bit8u col=vidmem[1];
498 Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
499 if (underline && ((col&0x07) == 0x01)) font=0xff;
500 Bit8u fg=col&0xf;
501 Bit8u bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
502 Bitu draw_blocks=vga.draw.blocks;
503 draw_blocks++;
504 for (Bitu cx=1;cx<draw_blocks;cx++) {
505 if (pel_pan) {
506 chr=vidmem[cx*2];
507 col=vidmem[cx*2+1];
508 if (underline && ((col&0x07) == 0x01)) font|=0xff>>(8-pel_pan);
509 else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan);
510 fg=col&0xf;
511 bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
512 } else {
513 chr=vidmem[(cx-1)*2];
514 col=vidmem[(cx-1)*2+1];
515 if (underline && ((col&0x07) == 0x01)) font=0xff;
516 else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
517 fg=col&0xf;
518 bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
519 }
520 if (FontMask[col>>7]==0) font=0;
521 *draw++=(font&0x80)?fg:bg; *draw++=(font&0x40)?fg:bg;
522 *draw++=(font&0x20)?fg:bg; *draw++=(font&0x10)?fg:bg;
523 *draw++=(font&0x08)?fg:bg; *draw++=(font&0x04)?fg:bg;
524 *draw++=(font&0x02)?fg:bg;
525 Bit8u last=(font&0x01)?fg:bg;
526 *draw++=last;
527 *draw++=((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) ? bg : last;
528 if (pel_pan) {
529 if (underline && ((col&0x07) == 0x01)) font=0xff;
530 else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
531 }
532 }
533 if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
534 font_addr = (vga.draw.cursor.address-vidstart) >> 1;
535 if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
536 if (line<vga.draw.cursor.sline) goto skip_cursor;
537 if (line>vga.draw.cursor.eline) goto skip_cursor;
538 draw=&TempLine[font_addr*9];
539 Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf;
540 *draw++=fg; *draw++=fg; *draw++=fg; *draw++=fg;
541 *draw++=fg; *draw++=fg; *draw++=fg; *draw++=fg;
542 }
543 skip_cursor:
544 return TempLine;
545 }
546 */
547
VGA_TEXT_Xlat16_Draw_Line_9(Bitu vidstart,Bitu line)548 static Bit8u * VGA_TEXT_Xlat16_Draw_Line_9(Bitu vidstart, Bitu line) {
549 Bits font_addr;
550 Bit16u * draw=(Bit16u *)TempLine;
551 bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line;
552 Bit8u pel_pan=(Bit8u)vga.draw.panning;
553 if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0;
554 const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
555 Bit8u chr=vidmem[0];
556 Bit8u col=vidmem[1];
557 Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
558 if (underline && ((col&0x07) == 0x01)) font=0xff;
559 Bit8u fg=col&0xf;
560 Bit8u bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
561 Bitu draw_blocks=vga.draw.blocks;
562 draw_blocks++;
563 for (Bitu cx=1;cx<draw_blocks;cx++) {
564 if (pel_pan) {
565 chr=vidmem[cx*2];
566 col=vidmem[cx*2+1];
567 if (underline && ((col&0x07) == 0x01)) font|=0xff>>(8-pel_pan);
568 else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan);
569 fg=col&0xf;
570 bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
571 } else {
572 chr=vidmem[(cx-1)*2];
573 col=vidmem[(cx-1)*2+1];
574 if (underline && ((col&0x07) == 0x01)) font=0xff;
575 else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
576 fg=col&0xf;
577 bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
578 }
579 if (FontMask[col>>7]==0) font=0;
580 Bit8u mask=0x80;
581 for (int i = 0; i < 7; i++) {
582 *draw++=vga.dac.xlat16[font&mask?fg:bg];
583 mask>>=1;
584 }
585 Bit16u lastval=vga.dac.xlat16[font&mask?fg:bg];
586 *draw++=lastval;
587 *draw++=(((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) &&
588 !(underline && ((col&0x07) == 0x01))) ?
589 (vga.dac.xlat16[bg]) : lastval;
590 if (pel_pan) {
591 if (underline && ((col&0x07) == 0x01)) font=0xff;
592 else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
593 }
594 }
595 if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
596 font_addr = (vga.draw.cursor.address-vidstart) >> 1;
597 if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
598 if (line<vga.draw.cursor.sline) goto skip_cursor;
599 if (line>vga.draw.cursor.eline) goto skip_cursor;
600 draw=(Bit16u*)&TempLine[font_addr*18];
601 Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf;
602 for(int i = 0; i < 8; i++) {
603 *draw++ = vga.dac.xlat16[fg];
604 }
605 //if(underline && ((col&0x07) == 0x01))
606 // *draw = vga.dac.xlat16[fg];
607 }
608 skip_cursor:
609 return TempLine;
610 }
611
612 #ifdef VGA_KEEP_CHANGES
VGA_ChangesEnd(void)613 static INLINE void VGA_ChangesEnd(void ) {
614 if ( vga.changes.active ) {
615 // vga.changes.active = false;
616 Bitu end = vga.draw.address >> VGA_CHANGE_SHIFT;
617 Bitu total = 4 + end - vga.changes.start;
618 Bit32u clearMask = vga.changes.clearMask;
619 total >>= 2;
620 Bit32u *clear = (Bit32u *)&vga.changes.map[ vga.changes.start & ~3 ];
621 while ( total-- ) {
622 clear[0] &= clearMask;
623 clear++;
624 }
625 }
626 }
627 #endif
628
629
VGA_ProcessSplit()630 static void VGA_ProcessSplit() {
631 // On the EGA the address is always reset to 0.
632 if ((vga.attr.mode_control&0x20) || (machine==MCH_EGA)) {
633 vga.draw.address=0;
634 } else {
635 // In text mode only the characters are shifted by panning, not the address;
636 // this is done in the text line draw function.
637 vga.draw.address = vga.draw.byte_panning_shift*vga.draw.bytes_skip;
638 if (!(vga.mode==M_TEXT)) vga.draw.address += vga.draw.panning;
639 }
640 vga.draw.address_line=0;
641 }
642
VGA_DrawSingleLine(Bitu)643 static void VGA_DrawSingleLine(Bitu /*blah*/) {
644 if (GCC_UNLIKELY(vga.attr.disabled)) {
645 // draw blanked line (DoWhackaDo, Alien Carnage, TV sports Football)
646 memset(TempLine, 0, sizeof(TempLine));
647 RENDER_DrawLine(TempLine);
648 } else {
649 Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
650 RENDER_DrawLine(data);
651 }
652
653 vga.draw.address_line++;
654 if (vga.draw.address_line>=vga.draw.address_line_total) {
655 vga.draw.address_line=0;
656 vga.draw.address+=vga.draw.address_add;
657 }
658 vga.draw.lines_done++;
659 if (vga.draw.split_line==vga.draw.lines_done) VGA_ProcessSplit();
660 if (vga.draw.lines_done < vga.draw.lines_total) {
661 PIC_AddEvent(VGA_DrawSingleLine,(float)vga.draw.delay.htotal);
662 } else RENDER_EndUpdate(false);
663 }
664
VGA_DrawPart(Bitu lines)665 static void VGA_DrawPart(Bitu lines) {
666 while (lines--) {
667 Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
668 RENDER_DrawLine(data);
669 vga.draw.address_line++;
670 if (vga.draw.address_line>=vga.draw.address_line_total) {
671 vga.draw.address_line=0;
672 vga.draw.address+=vga.draw.address_add;
673 }
674 vga.draw.lines_done++;
675 if (vga.draw.split_line==vga.draw.lines_done) {
676 #ifdef VGA_KEEP_CHANGES
677 VGA_ChangesEnd( );
678 #endif
679 VGA_ProcessSplit();
680 #ifdef VGA_KEEP_CHANGES
681 vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
682 #endif
683 }
684 }
685 if (--vga.draw.parts_left) {
686 PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,
687 (vga.draw.parts_left!=1) ? vga.draw.parts_lines : (vga.draw.lines_total - vga.draw.lines_done));
688 } else {
689 #ifdef VGA_KEEP_CHANGES
690 VGA_ChangesEnd();
691 #endif
692 RENDER_EndUpdate(false);
693 }
694 }
695
VGA_SetBlinking(Bitu enabled)696 void VGA_SetBlinking(Bitu enabled) {
697 Bitu b;
698 LOG(LOG_VGA,LOG_NORMAL)("Blinking %d",enabled);
699 if (enabled) {
700 b=0;vga.draw.blinking=1; //used to -1 but blinking is unsigned
701 vga.attr.mode_control|=0x08;
702 vga.tandy.mode_control|=0x20;
703 } else {
704 b=8;vga.draw.blinking=0;
705 vga.attr.mode_control&=~0x08;
706 vga.tandy.mode_control&=~0x20;
707 }
708 for (Bitu i=0;i<8;i++) TXT_BG_Table[i+8]=(b+i) | ((b+i) << 8)| ((b+i) <<16) | ((b+i) << 24);
709 }
710
711 #ifdef VGA_KEEP_CHANGES
VGA_ChangesStart(void)712 static void INLINE VGA_ChangesStart( void ) {
713 vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
714 vga.changes.last = vga.changes.start;
715 if ( vga.changes.lastAddress != vga.draw.address ) {
716 // LOG_MSG("Address");
717 VGA_DrawLine = VGA_Draw_Linear_Line;
718 vga.changes.lastAddress = vga.draw.address;
719 } else if ( render.fullFrame ) {
720 // LOG_MSG("Full Frame");
721 VGA_DrawLine = VGA_Draw_Linear_Line;
722 } else {
723 // LOG_MSG("Changes");
724 VGA_DrawLine = VGA_Draw_Changes_Line;
725 }
726 vga.changes.active = true;
727 vga.changes.checkMask = vga.changes.writeMask;
728 vga.changes.clearMask = ~( 0x01010101 << (vga.changes.frame & 7));
729 vga.changes.frame++;
730 vga.changes.writeMask = 1 << (vga.changes.frame & 7);
731 }
732 #endif
733
VGA_VertInterrupt(Bitu)734 static void VGA_VertInterrupt(Bitu /*val*/) {
735 if ((!vga.draw.vret_triggered) && ((vga.crtc.vertical_retrace_end&0x30)==0x10)) {
736 vga.draw.vret_triggered=true;
737 if (GCC_UNLIKELY(machine==MCH_EGA)) PIC_ActivateIRQ(9);
738 }
739 }
740
VGA_Other_VertInterrupt(Bitu val)741 static void VGA_Other_VertInterrupt(Bitu val) {
742 if (val) PIC_ActivateIRQ(5);
743 else PIC_DeActivateIRQ(5);
744 }
745
VGA_DisplayStartLatch(Bitu)746 static void VGA_DisplayStartLatch(Bitu /*val*/) {
747 vga.config.real_start=vga.config.display_start & (vga.vmemwrap-1);
748 vga.draw.bytes_skip = vga.config.bytes_skip;
749 }
750
VGA_PanningLatch(Bitu)751 static void VGA_PanningLatch(Bitu /*val*/) {
752 vga.draw.panning = vga.config.pel_panning;
753 }
754
VGA_VerticalTimer(Bitu)755 static void VGA_VerticalTimer(Bitu /*val*/) {
756 vga.draw.delay.framestart = PIC_FullIndex();
757 PIC_AddEvent( VGA_VerticalTimer, (float)vga.draw.delay.vtotal );
758
759 switch(machine) {
760 case MCH_PCJR:
761 case MCH_TANDY:
762 // PCJr: Vsync is directly connected to the IRQ controller
763 // Some earlier Tandy models are said to have a vsync interrupt too
764 PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrstart, 1);
765 PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrend, 0);
766 // fall-through
767 case MCH_CGA:
768 case MCH_HERC:
769 // MC6845-powered graphics: Loading the display start latch happens somewhere
770 // after vsync off and before first visible scanline, so probably here
771 VGA_DisplayStartLatch(0);
772 break;
773 case MCH_VGA:
774 case MCH_EGA:
775 PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrstart);
776 PIC_AddEvent(VGA_PanningLatch, (float)vga.draw.delay.vrend);
777 // EGA: 82c435 datasheet: interrupt happens at display end
778 // VGA: checked with scope; however disabled by default by jumper on VGA boards
779 // add a little amount of time to make sure the last drawpart has already fired
780 PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005));
781 break;
782 default:
783 E_Exit("This new machine needs implementation in VGA_VerticalTimer too.");
784 break;
785 }
786 //Check if we can actually render, else skip the rest (frameskip)
787 if (!RENDER_StartUpdate())
788 return;
789
790 vga.draw.address_line = vga.config.hlines_skip;
791 if (IS_EGAVGA_ARCH) {
792 vga.draw.split_line = (Bitu)((vga.config.line_compare+1)/vga.draw.lines_scaled);
793 if ((svgaCard==SVGA_S3Trio) && (vga.config.line_compare==0)) vga.draw.split_line=0;
794 vga.draw.split_line -= vga.draw.vblank_skip;
795 } else {
796 vga.draw.split_line = 0x10000; // don't care
797 }
798 vga.draw.address = vga.config.real_start;
799 vga.draw.byte_panning_shift = 0;
800 // go figure...
801 if (machine==MCH_EGA) vga.draw.split_line*=2;
802 // if (machine==MCH_EGA) vga.draw.split_line = ((((vga.config.line_compare&0x5ff)+1)*2-1)/vga.draw.lines_scaled);
803 #ifdef VGA_KEEP_CHANGES
804 bool startaddr_changed=false;
805 #endif
806 switch (vga.mode) {
807 case M_EGA:
808 if (!(vga.crtc.mode_control&0x1)) vga.draw.linear_mask &= ~0x10000;
809 else vga.draw.linear_mask |= 0x10000;
810 case M_LIN4:
811 vga.draw.byte_panning_shift = 8;
812 vga.draw.address += vga.draw.bytes_skip;
813 vga.draw.address *= vga.draw.byte_panning_shift;
814 vga.draw.address += vga.draw.panning;
815 #ifdef VGA_KEEP_CHANGES
816 startaddr_changed=true;
817 #endif
818 break;
819 case M_VGA:
820 if(vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) {
821 vga.draw.linear_base = vga.fastmem;
822 vga.draw.linear_mask = 0xffff;
823 } else {
824 vga.draw.linear_base = vga.mem.linear;
825 vga.draw.linear_mask = vga.vmemwrap - 1;
826 }
827 case M_LIN8:
828 case M_LIN15:
829 case M_LIN16:
830 case M_LIN32:
831 vga.draw.byte_panning_shift = 4;
832 vga.draw.address += vga.draw.bytes_skip;
833 vga.draw.address *= vga.draw.byte_panning_shift;
834 vga.draw.address += vga.draw.panning;
835 #ifdef VGA_KEEP_CHANGES
836 startaddr_changed=true;
837 #endif
838 break;
839 case M_TEXT:
840 vga.draw.byte_panning_shift = 2;
841 vga.draw.address += vga.draw.bytes_skip;
842 // fall-through
843 case M_TANDY_TEXT:
844 case M_HERC_TEXT:
845 if (machine==MCH_HERC) vga.draw.linear_mask = 0xfff; // 1 page
846 else if (IS_EGAVGA_ARCH) vga.draw.linear_mask = 0x7fff; // 8 pages
847 else vga.draw.linear_mask = 0x3fff; // CGA, Tandy 4 pages
848 vga.draw.cursor.address=vga.config.cursor_start*2;
849 vga.draw.address *= 2;
850 vga.draw.cursor.count++;
851 /* check for blinking and blinking change delay */
852 FontMask[1]=(vga.draw.blinking & (vga.draw.cursor.count >> 4)) ?
853 0 : 0xffffffff;
854 break;
855 case M_HERC_GFX:
856 break;
857 case M_CGA4:case M_CGA2:
858 vga.draw.address=(vga.draw.address*2)&0x1fff;
859 break;
860 case M_CGA16:
861 case M_TANDY2:case M_TANDY4:case M_TANDY16:
862 vga.draw.address *= 2;
863 break;
864 default:
865 break;
866 }
867 if (GCC_UNLIKELY(vga.draw.split_line==0)) VGA_ProcessSplit();
868 #ifdef VGA_KEEP_CHANGES
869 if (startaddr_changed) VGA_ChangesStart();
870 #endif
871
872 // check if some lines at the top off the screen are blanked
873 float draw_skip = 0.0;
874 if (GCC_UNLIKELY(vga.draw.vblank_skip)) {
875 draw_skip = (float)(vga.draw.delay.htotal * vga.draw.vblank_skip);
876 vga.draw.address += vga.draw.address_add * (vga.draw.vblank_skip/(vga.draw.address_line_total));
877 }
878
879 // add the draw event
880 switch (vga.draw.mode) {
881 case PART:
882 if (GCC_UNLIKELY(vga.draw.parts_left)) {
883 LOG(LOG_VGAMISC,LOG_NORMAL)( "Parts left: %d", vga.draw.parts_left );
884 PIC_RemoveEvents(VGA_DrawPart);
885 RENDER_EndUpdate(true);
886 }
887 vga.draw.lines_done = 0;
888 vga.draw.parts_left = vga.draw.parts_total;
889 PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts + draw_skip,vga.draw.parts_lines);
890 break;
891 case DRAWLINE:
892 if (GCC_UNLIKELY(vga.draw.lines_done < vga.draw.lines_total)) {
893 LOG(LOG_VGAMISC,LOG_NORMAL)( "Lines left: %d",
894 vga.draw.lines_total-vga.draw.lines_done);
895 PIC_RemoveEvents(VGA_DrawSingleLine);
896 RENDER_EndUpdate(true);
897 }
898 vga.draw.lines_done = 0;
899 PIC_AddEvent(VGA_DrawSingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip));
900 break;
901 //case EGALINE:
902 }
903 }
904
VGA_CheckScanLength(void)905 void VGA_CheckScanLength(void) {
906 switch (vga.mode) {
907 case M_EGA:
908 case M_LIN4:
909 vga.draw.address_add=vga.config.scan_len*16;
910 break;
911 case M_VGA:
912 case M_LIN8:
913 case M_LIN15:
914 case M_LIN16:
915 case M_LIN32:
916 vga.draw.address_add=vga.config.scan_len*8;
917 break;
918 case M_TEXT:
919 vga.draw.address_add=vga.config.scan_len*4;
920 break;
921 case M_CGA2:
922 case M_CGA4:
923 case M_CGA16:
924 vga.draw.address_add=80;
925 return;
926 case M_TANDY2:
927 vga.draw.address_add=vga.draw.blocks/4;
928 break;
929 case M_TANDY4:
930 vga.draw.address_add=vga.draw.blocks;
931 break;
932 case M_TANDY16:
933 vga.draw.address_add=vga.draw.blocks;
934 break;
935 case M_TANDY_TEXT:
936 vga.draw.address_add=vga.draw.blocks*2;
937 break;
938 case M_HERC_TEXT:
939 vga.draw.address_add=vga.draw.blocks*2;
940 break;
941 case M_HERC_GFX:
942 vga.draw.address_add=vga.draw.blocks;
943 break;
944 default:
945 vga.draw.address_add=vga.draw.blocks*8;
946 break;
947 }
948 }
949
VGA_ActivateHardwareCursor(void)950 void VGA_ActivateHardwareCursor(void) {
951 bool hwcursor_active=false;
952 if (svga.hardware_cursor_active) {
953 if (svga.hardware_cursor_active()) hwcursor_active=true;
954 }
955 if (hwcursor_active) {
956 switch(vga.mode) {
957 case M_LIN32:
958 VGA_DrawLine=VGA_Draw_LIN32_Line_HWMouse;
959 break;
960 case M_LIN15:
961 case M_LIN16:
962 VGA_DrawLine=VGA_Draw_LIN16_Line_HWMouse;
963 break;
964 default:
965 VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse;
966 }
967 } else {
968 VGA_DrawLine=VGA_Draw_Linear_Line;
969 }
970 }
971
VGA_SetupDrawing(Bitu)972 void VGA_SetupDrawing(Bitu /*val*/) {
973 if (vga.mode==M_ERROR) {
974 PIC_RemoveEvents(VGA_VerticalTimer);
975 PIC_RemoveEvents(VGA_PanningLatch);
976 PIC_RemoveEvents(VGA_DisplayStartLatch);
977 return;
978 }
979 // set the drawing mode
980 switch (machine) {
981 case MCH_CGA:
982 case MCH_PCJR:
983 vga.draw.mode = DRAWLINE;
984 break;
985 case MCH_VGA:
986 if (svgaCard==SVGA_None) {
987 vga.draw.mode = DRAWLINE;
988 break;
989 }
990 // fall-through
991 default:
992 vga.draw.mode = PART;
993 break;
994 }
995
996 /* Calculate the FPS for this screen */
997 double fps; Bitu clock;
998 Bitu htotal, hdend, hbstart, hbend, hrstart, hrend;
999 Bitu vtotal, vdend, vbstart, vbend, vrstart, vrend;
1000 Bitu vblank_skip;
1001 if (IS_EGAVGA_ARCH) {
1002 htotal = vga.crtc.horizontal_total;
1003 hdend = vga.crtc.horizontal_display_end;
1004 hbend = vga.crtc.end_horizontal_blanking&0x1F;
1005 hbstart = vga.crtc.start_horizontal_blanking;
1006 hrstart = vga.crtc.start_horizontal_retrace;
1007
1008 vtotal= vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8);
1009 vdend = vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7);
1010 vbstart = vga.crtc.start_vertical_blanking | ((vga.crtc.overflow & 0x08) << 5);
1011 vrstart = vga.crtc.vertical_retrace_start + ((vga.crtc.overflow & 0x04) << 6);
1012
1013 if (IS_VGA_ARCH) {
1014 // additional bits only present on vga cards
1015 htotal |= (vga.s3.ex_hor_overflow & 0x1) << 8;
1016 htotal += 3;
1017 hdend |= (vga.s3.ex_hor_overflow & 0x2) << 7;
1018 hbend |= (vga.crtc.end_horizontal_retrace&0x80) >> 2;
1019 hbstart |= (vga.s3.ex_hor_overflow & 0x4) << 6;
1020 hrstart |= (vga.s3.ex_hor_overflow & 0x10) << 4;
1021
1022 vtotal |= (vga.crtc.overflow & 0x20) << 4;
1023 vtotal |= (vga.s3.ex_ver_overflow & 0x1) << 10;
1024 vdend |= (vga.crtc.overflow & 0x40) << 3;
1025 vdend |= (vga.s3.ex_ver_overflow & 0x2) << 9;
1026 vbstart |= (vga.crtc.maximum_scan_line & 0x20) << 4;
1027 vbstart |= (vga.s3.ex_ver_overflow & 0x4) << 8;
1028 vrstart |= ((vga.crtc.overflow & 0x80) << 2);
1029 vrstart |= (vga.s3.ex_ver_overflow & 0x10) << 6;
1030 vbend = vga.crtc.end_vertical_blanking & 0x7f;
1031 } else { // EGA
1032 vbend = vga.crtc.end_vertical_blanking & 0x1f;
1033 }
1034 htotal += 2;
1035 vtotal += 2;
1036 hdend += 1;
1037 vdend += 1;
1038 vbstart += 1;
1039
1040 hbend = hbstart + ((hbend - hbstart) & 0x3F);
1041 hrend = vga.crtc.end_horizontal_retrace & 0x1f;
1042 hrend = (hrend - hrstart) & 0x1f;
1043
1044 if ( !hrend ) hrend = hrstart + 0x1f + 1;
1045 else hrend = hrstart + hrend;
1046
1047 vrend = vga.crtc.vertical_retrace_end & 0xF;
1048 vrend = ( vrend - vrstart)&0xF;
1049
1050 if ( !vrend) vrend = vrstart + 0xf + 1;
1051 else vrend = vrstart + vrend;
1052
1053 vbend = (vbend - vbstart) & 0x7f;
1054 if ( !vbend) vbend = vbstart + 0x7f + 1;
1055 else vbend = vbstart + vbend;
1056
1057 vbend++;
1058
1059 if (svga.get_clock) {
1060 clock = svga.get_clock();
1061 } else {
1062 switch ((vga.misc_output >> 2) & 3) {
1063 case 0:
1064 clock = (machine==MCH_EGA) ? 14318180 : 25175000;
1065 break;
1066 case 1:
1067 default:
1068 clock = (machine==MCH_EGA) ? 16257000 : 28322000;
1069 break;
1070 }
1071 }
1072
1073 /* Check for 8 for 9 character clock mode */
1074 if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9;
1075 /* Check for pixel doubling, master clock/2 */
1076 if (vga.seq.clocking_mode & 0x8) {
1077 htotal*=2;
1078 }
1079 vga.draw.address_line_total=(vga.crtc.maximum_scan_line&0x1f)+1;
1080 if(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA)) {
1081 // vgaonly; can't use with CGA because these use address_line for their
1082 // own purposes.
1083 // Set the low resolution modes to have as many lines as are scanned -
1084 // Quite a few demos change the max_scanline register at display time
1085 // to get SFX: Majic12 show, Magic circle, Copper, GBU, Party91
1086 if( vga.crtc.maximum_scan_line&0x80) vga.draw.address_line_total*=2;
1087 vga.draw.double_scan=false;
1088 }
1089 else if (IS_VGA_ARCH) vga.draw.double_scan=(vga.crtc.maximum_scan_line&0x80)>0;
1090 else vga.draw.double_scan=(vtotal==262);
1091 } else {
1092 htotal = vga.other.htotal + 1;
1093 hdend = vga.other.hdend;
1094 hbstart = hdend;
1095 hbend = htotal;
1096 hrstart = vga.other.hsyncp;
1097 hrend = hrstart + vga.other.hsyncw;
1098
1099 vga.draw.address_line_total = vga.other.max_scanline + 1;
1100 vtotal = vga.draw.address_line_total * (vga.other.vtotal+1)+vga.other.vadjust;
1101 vdend = vga.draw.address_line_total * vga.other.vdend;
1102 vrstart = vga.draw.address_line_total * vga.other.vsyncp;
1103 vrend = vrstart + 16; // vsync width is fixed to 16 lines on the MC6845 TODO Tandy
1104 vbstart = vdend;
1105 vbend = vtotal;
1106 vga.draw.double_scan=false;
1107 switch (machine) {
1108 case MCH_CGA:
1109 case TANDY_ARCH_CASE:
1110 clock=((vga.tandy.mode_control & 1) ? 14318180 : (14318180/2))/8;
1111 break;
1112 case MCH_HERC:
1113 if (vga.herc.mode_control & 0x2) clock=16000000/16;
1114 else clock=16000000/8;
1115 break;
1116 default:
1117 clock = 14318180;
1118 break;
1119 }
1120 vga.draw.delay.hdend = hdend*1000.0/clock; //in milliseconds
1121 }
1122 #if C_DEBUG
1123 LOG(LOG_VGA,LOG_NORMAL)("h total %d end %d blank (%d/%d) retrace (%d/%d)",
1124 htotal, hdend, hbstart, hbend, hrstart, hrend );
1125 LOG(LOG_VGA,LOG_NORMAL)("v total %d end %d blank (%d/%d) retrace (%d/%d)",
1126 vtotal, vdend, vbstart, vbend, vrstart, vrend );
1127 #endif
1128 if (!htotal) return;
1129 if (!vtotal) return;
1130
1131 // The screen refresh frequency
1132 fps=(double)clock/(vtotal*htotal);
1133 // Horizontal total (that's how long a line takes with whistles and bells)
1134 vga.draw.delay.htotal = htotal*1000.0/clock; //in milliseconds
1135 // Start and End of horizontal blanking
1136 vga.draw.delay.hblkstart = hbstart*1000.0/clock; //in milliseconds
1137 vga.draw.delay.hblkend = hbend*1000.0/clock;
1138 // Start and End of horizontal retrace
1139 vga.draw.delay.hrstart = hrstart*1000.0/clock;
1140 vga.draw.delay.hrend = hrend*1000.0/clock;
1141 // Start and End of vertical blanking
1142 vga.draw.delay.vblkstart = vbstart * vga.draw.delay.htotal;
1143 vga.draw.delay.vblkend = vbend * vga.draw.delay.htotal;
1144 // Start and End of vertical retrace pulse
1145 vga.draw.delay.vrstart = vrstart * vga.draw.delay.htotal;
1146 vga.draw.delay.vrend = vrend * vga.draw.delay.htotal;
1147
1148 // Vertical blanking tricks
1149 vblank_skip = 0;
1150 if (IS_VGA_ARCH) { // others need more investigation
1151 if (vbend > vtotal) {
1152 // blanking wraps to the start of the screen
1153 vblank_skip = vbend&0x7f;
1154
1155 // on blanking wrap to 0, the first line is not blanked
1156 // this is used by the S3 BIOS and other S3 drivers in some SVGA modes
1157 if((vbend&0x7f)==1) vblank_skip = 0;
1158
1159 // it might also cut some lines off the bottom
1160 if(vbstart < vdend) {
1161 vdend = vbstart;
1162 }
1163 LOG(LOG_VGA,LOG_WARN)("Blanking wrap to line %d", vblank_skip);
1164 } else if (vbstart==1) {
1165 // blanking is used to cut lines at the start of the screen
1166 vblank_skip = vbend;
1167 LOG(LOG_VGA,LOG_WARN)("Upper %d lines of the screen blanked", vblank_skip);
1168 } else if (vbstart < vdend) {
1169 if(vbend < vdend) {
1170 // the game wants a black bar somewhere on the screen
1171 LOG(LOG_VGA,LOG_WARN)("Unsupported blanking: line %d-%d",vbstart,vbend);
1172 } else {
1173 // blanking is used to cut off some lines from the bottom
1174 vdend = vbstart;
1175 }
1176 }
1177 vdend -= vblank_skip;
1178 }
1179 // Display end
1180 vga.draw.delay.vdend = vdend * vga.draw.delay.htotal;
1181
1182 vga.draw.parts_total=VGA_PARTS;
1183 /*
1184 6 Horizontal Sync Polarity. Negative if set
1185 7 Vertical Sync Polarity. Negative if set
1186 Bit 6-7 indicates the number of lines on the display:
1187 1: 400, 2: 350, 3: 480
1188 */
1189 //Try to determine the pixel size, aspect correct is based around square pixels
1190
1191 //Base pixel width around 100 clocks horizontal
1192 //For 9 pixel text modes this should be changed, but we don't support that anyway :)
1193 //Seems regular vga only listens to the 9 char pixel mode with character mode enabled
1194 double pwidth = (machine==MCH_EGA) ? (114.0 / htotal) : (100.0 / htotal);
1195 //Base pixel height around vertical totals of modes that have 100 clocks horizontal
1196 //Different sync values gives different scaling of the whole vertical range
1197 //VGA monitor just seems to thighten or widen the whole vertical range
1198 double pheight;
1199 double target_total = (machine==MCH_EGA) ? 262.0 : 449.0;
1200 Bitu sync = vga.misc_output >> 6;
1201 switch ( sync ) {
1202 case 0: // This is not defined in vga specs,
1203 // Kiet, seems to be slightly less than 350 on my monitor
1204 //340 line mode, filled with 449 total
1205 pheight = (480.0 / 340.0) * ( target_total / vtotal );
1206 break;
1207 case 1: //400 line mode, filled with 449 total
1208 pheight = (480.0 / 400.0) * ( target_total / vtotal );
1209 break;
1210 case 2: //350 line mode, filled with 449 total
1211 //This mode seems to get regular 640x400 timing and goes for a loong retrace
1212 //Depends on the monitor to stretch the screen
1213 pheight = (480.0 / 350.0) * ( target_total / vtotal );
1214 break;
1215 case 3: //480 line mode, filled with 525 total
1216 default:
1217 pheight = (480.0 / 480.0) * ( 525.0 / vtotal );
1218 break;
1219 }
1220
1221 double aspect_ratio = pheight / pwidth;
1222
1223 vga.draw.delay.parts = vga.draw.delay.vdend/vga.draw.parts_total;
1224 vga.draw.resizing=false;
1225 vga.draw.vret_triggered=false;
1226
1227 //Check to prevent useless black areas
1228 if (hbstart<hdend) hdend=hbstart;
1229 if ((!IS_VGA_ARCH) && (vbstart<vdend)) vdend=vbstart;
1230
1231
1232 Bitu width=hdend;
1233 Bitu height=vdend;
1234 bool doubleheight=false;
1235 bool doublewidth=false;
1236
1237 //Set the bpp
1238 Bitu bpp;
1239 switch (vga.mode) {
1240 case M_LIN15:
1241 bpp = 15;
1242 break;
1243 case M_LIN16:
1244 bpp = 16;
1245 break;
1246 case M_LIN32:
1247 bpp = 32;
1248 break;
1249 default:
1250 bpp = 8;
1251 break;
1252 }
1253 vga.draw.linear_base = vga.mem.linear;
1254 vga.draw.linear_mask = vga.vmemwrap - 1;
1255 switch (vga.mode) {
1256 case M_VGA:
1257 doublewidth=true;
1258 width<<=2;
1259 if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
1260 bpp=16;
1261 VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line;
1262 } else VGA_DrawLine = VGA_Draw_Linear_Line;
1263 break;
1264 case M_LIN8:
1265 if (vga.crtc.mode_control & 0x8)
1266 width >>=1;
1267 else if(svgaCard == SVGA_S3Trio && !(vga.s3.reg_3a&0x10)) {
1268 doublewidth=true;
1269 width >>=1;
1270 }
1271 // fall-through
1272 case M_LIN32:
1273 width<<=3;
1274 if (vga.crtc.mode_control & 0x8)
1275 doublewidth = true;
1276 /* Use HW mouse cursor drawer if enabled */
1277 VGA_ActivateHardwareCursor();
1278 break;
1279 case M_LIN15:
1280 case M_LIN16:
1281 // 15/16 bpp modes double the horizontal values
1282 width<<=2;
1283 if ((vga.crtc.mode_control & 0x8) || (svgaCard == SVGA_S3Trio && (vga.s3.pll.cmd & 0x10)))
1284 doublewidth = true;
1285 /* Use HW mouse cursor drawer if enabled */
1286 VGA_ActivateHardwareCursor();
1287 break;
1288 case M_LIN4:
1289 doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
1290 vga.draw.blocks = width;
1291 width<<=3;
1292 VGA_DrawLine=VGA_Draw_Linear_Line;
1293 vga.draw.linear_base = vga.fastmem;
1294 vga.draw.linear_mask = (vga.vmemwrap<<1) - 1;
1295 break;
1296 case M_EGA:
1297 doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
1298 vga.draw.blocks = width;
1299 width<<=3;
1300 if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
1301 bpp=16;
1302 VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line;
1303 } else VGA_DrawLine=VGA_Draw_Linear_Line;
1304
1305 vga.draw.linear_base = vga.fastmem;
1306 vga.draw.linear_mask = (vga.vmemwrap<<1) - 1;
1307 break;
1308 case M_CGA16:
1309 doubleheight=true;
1310 vga.draw.blocks=width*2;
1311 width<<=4;
1312 VGA_DrawLine=VGA_Draw_CGA16_Line;
1313 break;
1314 case M_CGA4:
1315 doublewidth=true;
1316 vga.draw.blocks=width*2;
1317 width<<=3;
1318 VGA_DrawLine=VGA_Draw_2BPP_Line;
1319 break;
1320 case M_CGA2:
1321 doubleheight=true;
1322 vga.draw.blocks=2*width;
1323 width<<=3;
1324 VGA_DrawLine=VGA_Draw_1BPP_Line;
1325 break;
1326 case M_TEXT:
1327 aspect_ratio=1.0;
1328 vga.draw.blocks=width;
1329 doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
1330 if ((IS_VGA_ARCH) && (svgaCard==SVGA_None) && !(vga.seq.clocking_mode&0x01)) {
1331 width*=9; /* 9 bit wide text font */
1332 VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line_9;
1333 bpp=16;
1334 // VGA_DrawLine=VGA_TEXT_Draw_Line_9;
1335 } else {
1336 width<<=3; /* 8 bit wide text font */
1337 if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
1338 VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line;
1339 bpp=16;
1340 } else VGA_DrawLine=VGA_TEXT_Draw_Line;
1341 }
1342 break;
1343 case M_HERC_GFX:
1344 aspect_ratio=1.5;
1345 vga.draw.blocks=width*2;
1346 width*=16;
1347 VGA_DrawLine=VGA_Draw_1BPP_Line;
1348 break;
1349 case M_TANDY2:
1350 aspect_ratio=1.2;
1351 doubleheight=true;
1352 if (machine==MCH_PCJR) doublewidth=(vga.tandy.gfx_control & 0x8)==0x00;
1353 else doublewidth=(vga.tandy.mode_control & 0x10)==0;
1354 vga.draw.blocks=width * (doublewidth ? 4:8);
1355 width=vga.draw.blocks*2;
1356 VGA_DrawLine=VGA_Draw_1BPP_Line;
1357 break;
1358 case M_TANDY4:
1359 aspect_ratio=1.2;
1360 doubleheight=true;
1361 if (machine==MCH_TANDY) doublewidth=(vga.tandy.mode_control & 0x10)==0;
1362 else doublewidth=(vga.tandy.mode_control & 0x01)==0x00;
1363 vga.draw.blocks=width * 2;
1364 width=vga.draw.blocks*4;
1365 if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) ||
1366 (machine==MCH_PCJR && (vga.tandy.mode_control==0x0b)))
1367 VGA_DrawLine=VGA_Draw_2BPPHiRes_Line;
1368 else VGA_DrawLine=VGA_Draw_2BPP_Line;
1369 break;
1370 case M_TANDY16:
1371 aspect_ratio=1.2;
1372 doubleheight=true;
1373 vga.draw.blocks=width*2;
1374 if (vga.tandy.mode_control & 0x1) {
1375 if (( machine==MCH_TANDY ) && ( vga.tandy.mode_control & 0x10 )) {
1376 doublewidth = false;
1377 vga.draw.blocks*=2;
1378 width=vga.draw.blocks*2;
1379 } else {
1380 doublewidth = true;
1381 width=vga.draw.blocks*2;
1382 }
1383 VGA_DrawLine=VGA_Draw_4BPP_Line;
1384 } else {
1385 doublewidth=true;
1386 width=vga.draw.blocks*4;
1387 VGA_DrawLine=VGA_Draw_4BPP_Line_Double;
1388 }
1389 break;
1390 case M_TANDY_TEXT:
1391 doublewidth=(vga.tandy.mode_control & 0x1)==0;
1392 aspect_ratio=1;
1393 doubleheight=true;
1394 vga.draw.blocks=width;
1395 width<<=3;
1396 VGA_DrawLine=VGA_TEXT_Draw_Line;
1397 break;
1398 case M_HERC_TEXT:
1399 aspect_ratio=1;
1400 vga.draw.blocks=width;
1401 width<<=3;
1402 VGA_DrawLine=VGA_TEXT_Herc_Draw_Line;
1403 break;
1404 default:
1405 LOG(LOG_VGA,LOG_ERROR)("Unhandled VGA mode %d while checking for resolution",vga.mode);
1406 break;
1407 }
1408 VGA_CheckScanLength();
1409 if (vga.draw.double_scan) {
1410 if (IS_VGA_ARCH) {
1411 vga.draw.vblank_skip /= 2;
1412 height/=2;
1413 }
1414 doubleheight=true;
1415 }
1416 vga.draw.vblank_skip = vblank_skip;
1417
1418 if(!(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA))) {
1419 //Only check for extra double height in vga modes
1420 //(line multiplying by address_line_total)
1421 if (!doubleheight && (vga.mode<M_TEXT) && !(vga.draw.address_line_total & 1)) {
1422 vga.draw.address_line_total/=2;
1423 doubleheight=true;
1424 height/=2;
1425 }
1426 }
1427 vga.draw.lines_total=height;
1428 vga.draw.parts_lines=vga.draw.lines_total/vga.draw.parts_total;
1429 vga.draw.line_length = width * ((bpp + 1) / 8);
1430 #ifdef VGA_KEEP_CHANGES
1431 vga.changes.active = false;
1432 vga.changes.frame = 0;
1433 vga.changes.writeMask = 1;
1434 #endif
1435 /*
1436 Cheap hack to just make all > 640x480 modes have 4:3 aspect ratio
1437 */
1438 if ( width >= 640 && height >= 480 ) {
1439 aspect_ratio = ((float)width / (float)height) * ( 3.0 / 4.0);
1440 }
1441 // LOG_MSG("ht %d vt %d ratio %f", htotal, vtotal, aspect_ratio );
1442
1443 bool fps_changed = false;
1444 // need to change the vertical timing?
1445 if (fabs(vga.draw.delay.vtotal - 1000.0 / fps) > 0.0001) {
1446 fps_changed = true;
1447 vga.draw.delay.vtotal = 1000.0 / fps;
1448 VGA_KillDrawing();
1449 PIC_RemoveEvents(VGA_Other_VertInterrupt);
1450 PIC_RemoveEvents(VGA_VerticalTimer);
1451 PIC_RemoveEvents(VGA_PanningLatch);
1452 PIC_RemoveEvents(VGA_DisplayStartLatch);
1453 VGA_VerticalTimer(0);
1454 }
1455
1456 #if C_DEBUG
1457 LOG(LOG_VGA,LOG_NORMAL)("h total %2.5f (%3.2fkHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
1458 vga.draw.delay.htotal,(1.0/vga.draw.delay.htotal),
1459 vga.draw.delay.hblkstart,vga.draw.delay.hblkend,
1460 vga.draw.delay.hrstart,vga.draw.delay.hrend);
1461 LOG(LOG_VGA,LOG_NORMAL)("v total %2.5f (%3.2fHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
1462 vga.draw.delay.vtotal,(1000.0/vga.draw.delay.vtotal),
1463 vga.draw.delay.vblkstart,vga.draw.delay.vblkend,
1464 vga.draw.delay.vrstart,vga.draw.delay.vrend);
1465 #endif
1466
1467 // need to resize the output window?
1468 if ((width != vga.draw.width) ||
1469 (height != vga.draw.height) ||
1470 (vga.draw.doublewidth != doublewidth) ||
1471 (vga.draw.doubleheight != doubleheight) ||
1472 (fabs(aspect_ratio - vga.draw.aspect_ratio) > 0.0001) ||
1473 (vga.draw.bpp != bpp) || fps_changed) {
1474
1475 VGA_KillDrawing();
1476
1477 vga.draw.width = width;
1478 vga.draw.height = height;
1479 vga.draw.doublewidth = doublewidth;
1480 vga.draw.doubleheight = doubleheight;
1481 vga.draw.aspect_ratio = aspect_ratio;
1482 vga.draw.bpp = bpp;
1483 if (doubleheight) vga.draw.lines_scaled=2;
1484 else vga.draw.lines_scaled=1;
1485 #if C_DEBUG
1486 LOG(LOG_VGA,LOG_NORMAL)("Width %d, Height %d, fps %f",width,height,fps);
1487 LOG(LOG_VGA,LOG_NORMAL)("%s width, %s height aspect %f",
1488 doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio);
1489 #endif
1490 RENDER_SetSize(width,height,bpp,(float)fps,aspect_ratio,doublewidth,doubleheight);
1491 }
1492 }
1493
VGA_KillDrawing(void)1494 void VGA_KillDrawing(void) {
1495 PIC_RemoveEvents(VGA_DrawPart);
1496 PIC_RemoveEvents(VGA_DrawSingleLine);
1497 vga.draw.parts_left = 0;
1498 vga.draw.lines_done = ~0;
1499 RENDER_EndUpdate(true);
1500 }
1501