DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_draw.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <string.h>
00021 #include <math.h>
00022 #include <stdio.h>
00023 #include "dosbox.h"
00024 #if defined (WIN32)
00025 #include <d3d9.h>
00026 #endif
00027 #include "timer.h"
00028 #include "setup.h"
00029 #include "support.h"
00030 #include "video.h"
00031 #include "render.h"
00032 #include "../gui/render_scalers.h"
00033 #include "vga.h"
00034 #include "pic.h"
00035 #include "menu.h"
00036 #include "timer.h"
00037 #include "config.h"
00038 #include "control.h"
00039 #include "pc98_cg.h"
00040 #include "pc98_gdc.h"
00041 #include "pc98_gdc_const.h"
00042 
00043 const char* const mode_texts[M_MAX] = {
00044     "M_CGA2",           // 0
00045     "M_CGA4",
00046     "M_EGA",
00047     "M_VGA",
00048     "M_LIN4",
00049     "M_LIN8",           // 5
00050     "M_LIN15",
00051     "M_LIN16",
00052     "M_LIN24",
00053     "M_LIN32",
00054     "M_TEXT",           // 10
00055     "M_HERC_GFX",
00056     "M_HERC_TEXT",
00057     "M_CGA16",
00058     "M_TANDY2",
00059     "M_TANDY4",         // 15
00060     "M_TANDY16",
00061     "M_TANDY_TEXT",
00062     "M_AMSTRAD",
00063     "M_PC98",
00064     "M_FM_TOWNS",       // 20 STUB
00065     "M_ERROR"
00066 };
00067 
00068 #if defined(_MSC_VER)
00069 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00070 # pragma warning(disable:4305) /* truncation from double to float */
00071 #endif
00072 
00073 //#undef C_DEBUG
00074 //#define C_DEBUG 1
00075 //#define LOG(X,Y) LOG_MSG
00076 
00077 bool et4k_highcolor_half_pixel_rate();
00078 
00079 double vga_fps = 70;
00080 double vga_mode_time_base = -1;
00081 int vga_mode_frames_since_time_base = 0;
00082 
00083 extern bool vga_3da_polled;
00084 extern bool vga_page_flip_occurred;
00085 extern bool vga_enable_hpel_effects;
00086 extern bool vga_enable_hretrace_effects;
00087 extern unsigned int vga_display_start_hretrace;
00088 extern float hretrace_fx_avg_weight;
00089 extern bool ignore_vblank_wraparound;
00090 extern bool vga_double_buffered_line_compare;
00091 
00092 extern bool pc98_31khz_mode;
00093 
00094 void memxor(void *_d,unsigned int byte,size_t count) {
00095     unsigned char *d = (unsigned char*)_d;
00096     while (count-- > 0) *d++ ^= byte;
00097 }
00098 
00099 void memxor_greendotted_16bpp(uint16_t *d,unsigned int count,unsigned int line) {
00100     static const uint16_t greenptrn[2] = { (0x3F << 5), 0 };
00101     line &= 1;
00102     count >>= 1;
00103     while (count-- > 0) {
00104         *d++ ^= greenptrn[line];
00105         *d++ ^= greenptrn[line^1];
00106     }
00107 }
00108 
00109 typedef Bit8u * (* VGA_Line_Handler)(Bitu vidstart, Bitu line);
00110 
00111 static VGA_Line_Handler VGA_DrawLine;
00112 static Bit8u TempLine[SCALER_MAXWIDTH * 4 + 256];
00113 static float hretrace_fx_avg = 0;
00114 
00115 static Bit8u * VGA_Draw_AMS_4BPP_Line(Bitu vidstart, Bitu line) {
00116     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00117     const Bit8u *lbase;
00118     Bit32u *draw = (Bit32u *)TempLine;
00119     for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
00120         lbase = &base[ (vidstart & (8 * 1024 -1)) ];
00121         Bitu val0 = lbase[ 0 ];
00122         Bitu val1 = lbase[ 16384 ];
00123         Bitu val2 = lbase[ 32768 ];
00124         Bitu val3 = lbase[ 49152 ];
00125         
00126         *draw++=( ( CGA_2_Table[ val0 >> 4 ] << 0 ) | 
00127             ( CGA_2_Table[ val1 >> 4 ] << 1 ) |
00128             ( CGA_2_Table[ val2 >> 4 ] << 2 ) |
00129             ( CGA_2_Table[ val3 >> 4 ] << 3 ) ) & vga.amstrad.mask_plane;
00130         *draw++=( ( CGA_2_Table[ val0 & 0x0F ] << 0 ) | 
00131             ( CGA_2_Table[ val1 & 0x0F ] << 1 ) |
00132             ( CGA_2_Table[ val2 & 0x0F ] << 2 ) |
00133             ( CGA_2_Table[ val3 & 0x0F ] << 3 ) ) & vga.amstrad.mask_plane;
00134     }
00135     return TempLine;
00136 }
00137 
00138 struct vsync_state vsync;
00139 
00140 float uservsyncjolt=0.0f;
00141 
00142 VGA_Vsync vsyncmode_current = VS_Off;
00143 
00144 void VGA_VsyncUpdateMode(VGA_Vsync vsyncmode) {
00145     vsyncmode_current = vsyncmode;
00146 
00147     mainMenu.get_item("vsync_off").check(vsyncmode_current == VS_Off).refresh_item(mainMenu);
00148     mainMenu.get_item("vsync_on").check(vsyncmode_current == VS_On).refresh_item(mainMenu);
00149     mainMenu.get_item("vsync_force").check(vsyncmode_current == VS_Force).refresh_item(mainMenu);
00150     mainMenu.get_item("vsync_host").check(vsyncmode_current == VS_Host).refresh_item(mainMenu);
00151 
00152     switch(vsyncmode) {
00153     case VS_Off:
00154         vsync.manual    = false;
00155         vsync.persistent= false;
00156         vsync.faithful  = false;
00157         break;
00158     case VS_On:
00159         vsync.manual    = true;
00160         vsync.persistent= true;
00161         vsync.faithful  = true;
00162         break;
00163     case VS_Force:
00164     case VS_Host:
00165         vsync.manual    = true;
00166         vsync.persistent= true;
00167         vsync.faithful  = false;
00168         break;
00169     default:
00170         LOG_MSG("VGA_VsyncUpdateMode: Invalid mode, using defaults.");
00171         vsync.manual    = false;
00172         vsync.persistent= false;
00173         vsync.faithful  = false;
00174         break;
00175     }
00176 }
00177 
00178 void VGA_TweakUserVsyncOffset(float val) { uservsyncjolt = val; }
00179 
00180 static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart, Bitu line) {
00181     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00182     Bit32u *draw = (Bit32u *)TempLine;
00183     for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
00184         Bitu val = base[(vidstart & (8 * 1024 -1))];
00185         *draw++=CGA_2_Table[val >> 4];
00186         *draw++=CGA_2_Table[val & 0xf];
00187     }
00188     return TempLine;
00189 }
00190 
00191 static Bit8u * VGA_Draw_1BPP_Blend_Line(Bitu vidstart, Bitu line) {
00192     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00193     Bit32u *draw = (Bit32u *)TempLine;
00194     Bitu carry = 0;
00195     for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
00196         Bitu val1 = base[(vidstart & (8 * 1024 -1))];
00197         Bitu val2 = (val1 >> 1) + carry;
00198         carry = (val1 & 1) << 7;
00199         *draw++=CGA_2_Table[val1 >> 4] + CGA_2_Table[val2 >> 4];
00200         *draw++=CGA_2_Table[val1 & 0xf] + CGA_2_Table[val2 & 0xf];
00201     }
00202     return TempLine;
00203 }
00204 
00205 static Bit8u * EGA_Draw_2BPP_Line_as_EGA(Bitu vidstart, Bitu line) {
00206     const Bit32u *base = (Bit32u*)vga.draw.linear_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00207     Bit8u * draw=(Bit8u *)TempLine;
00208     VGA_Latch pixels;
00209     Bitu val,i;
00210 
00211     for (Bitu x=0;x<vga.draw.blocks;x++) {
00212         pixels.d = base[vidstart & vga.tandy.addr_mask];
00213         vidstart += 1u<<vga.config.addr_shift;
00214 
00215         /* CGA odd/even mode, first plane */
00216         val=pixels.b[0];
00217         for (i=0;i < 4;i++,val <<= 2)
00218             *draw++ = vga.attr.palette[(val>>6)&3];
00219 
00220         /* CGA odd/even mode, second plane */
00221         val=pixels.b[1];
00222         for (i=0;i < 4;i++,val <<= 2)
00223             *draw++ = vga.attr.palette[(val>>6)&3];
00224     }
00225     return TempLine;
00226 }
00227 
00228 static Bit8u * VGA_Draw_2BPP_Line_as_VGA(Bitu vidstart, Bitu line) {
00229     const Bit32u *base = (Bit32u*)vga.draw.linear_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00230     Bit32u * draw=(Bit32u *)TempLine;
00231     VGA_Latch pixels;
00232     Bitu val,i;
00233 
00234     for (Bitu x=0;x<vga.draw.blocks;x++) {
00235         pixels.d = base[vidstart & vga.tandy.addr_mask];
00236         vidstart += 1u<<vga.config.addr_shift;
00237 
00238         /* CGA odd/even mode, first plane */
00239         val=pixels.b[0];
00240         for (i=0;i < 4;i++,val <<= 2)
00241             *draw++ = vga.dac.xlat32[(val>>6)&3];
00242 
00243         /* CGA odd/even mode, second plane */
00244         val=pixels.b[1];
00245         for (i=0;i < 4;i++,val <<= 2)
00246             *draw++ = vga.dac.xlat32[(val>>6)&3];
00247     }
00248     return TempLine;
00249 }
00250 
00251 static Bit8u * EGA_Draw_1BPP_Line_as_EGA(Bitu vidstart, Bitu line) {
00252     const Bit32u *base = (Bit32u*)vga.draw.linear_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00253     Bit8u * draw=(Bit8u *)TempLine;
00254     VGA_Latch pixels;
00255     Bitu val,i;
00256 
00257     for (Bitu x=0;x<vga.draw.blocks;x++) {
00258         pixels.d = base[vidstart & vga.tandy.addr_mask];
00259         vidstart += 1u<<vga.config.addr_shift;
00260 
00261         val=pixels.b[0];
00262         for (i=0;i < 8;i++,val <<= 1)
00263             *draw++ = vga.attr.palette[(val>>7)&1];
00264     }
00265     return TempLine;
00266 }
00267 
00268 static Bit8u * VGA_Draw_1BPP_Line_as_VGA(Bitu vidstart, Bitu line) {
00269     const Bit32u *base = (Bit32u*)vga.draw.linear_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00270     Bit32u * draw=(Bit32u *)TempLine;
00271     VGA_Latch pixels;
00272     Bitu val,i;
00273 
00274     for (Bitu x=0;x<vga.draw.blocks;x++) {
00275         pixels.d = base[vidstart & vga.tandy.addr_mask];
00276         vidstart += 1u<<vga.config.addr_shift;
00277 
00278         val=pixels.b[0];
00279         for (i=0;i < 8;i++,val <<= 1)
00280             *draw++ = vga.dac.xlat32[(val>>7)&1];
00281     }
00282     return TempLine;
00283 }
00284 
00285 static Bit8u * VGA_Draw_2BPP_Line(Bitu vidstart, Bitu line) {
00286     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00287     Bit32u * draw=(Bit32u *)TempLine;
00288     for (Bitu x=0;x<vga.draw.blocks;x++) {
00289         Bitu val = base[vidstart & vga.tandy.addr_mask];
00290         vidstart++;
00291         *draw++=CGA_4_Table[val];
00292     }
00293     return TempLine;
00294 }
00295 
00296 static Bit8u * VGA_Draw_2BPPHiRes_Line(Bitu vidstart, Bitu line) {
00297     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00298     Bit32u * draw=(Bit32u *)TempLine;
00299     for (Bitu x=0;x<vga.draw.blocks;x++) {
00300         Bitu val1 = base[vidstart & vga.tandy.addr_mask];
00301         ++vidstart;
00302         Bitu val2 = base[vidstart & vga.tandy.addr_mask];
00303         ++vidstart;
00304         *draw++=CGA_4_HiRes_Table[(val1>>4)|(val2&0xf0)];
00305         *draw++=CGA_4_HiRes_Table[(val1&0x0f)|((val2&0x0f)<<4)];
00306     }
00307     return TempLine;
00308 }
00309 
00310 static Bitu temp[643]={0};
00311 
00312 static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) {
00313     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00314 #define CGA16_READER(OFF) (base[(vidstart +(OFF))& (8*1024 -1)])
00315     Bit32u * draw=(Bit32u *)TempLine;
00316     //There are 640 hdots in each line of the screen.
00317     //The color of an even hdot always depends on only 4 bits of video RAM.
00318     //The color of an odd hdot depends on 4 bits of video RAM in
00319     //1-hdot-per-pixel modes and 6 bits of video RAM in 2-hdot-per-pixel
00320     //modes. We always assume 6 and use duplicate palette entries in
00321     //1-hdot-per-pixel modes so that we can use the same routine for all
00322     //composite modes.
00323   temp[1] = (CGA16_READER(0) >> 6) & 3;
00324     for(Bitu x = 2; x < 640; x+=2) {
00325         temp[x] = (temp[x-1] & 0xf);
00326         temp[x+1] = (temp[x] << 2) | ((( CGA16_READER(x>>3)) >> (6-(x&6)) )&3);
00327     }
00328     temp[640] = temp[639] & 0xf;
00329     temp[641] = temp[640] << 2;
00330     temp[642] = temp[641] & 0xf;
00331 
00332     Bitu i = 2;
00333     for (Bitu x=0;x<vga.draw.blocks;x++) {
00334         *draw++ = 0xc0708030 | temp[i] | (temp[i+1] << 8) | (temp[i+2] << 16) | (temp[i+3] << 24);
00335         i += 4;
00336         *draw++ = 0xc0708030 | temp[i] | (temp[i+1] << 8) | (temp[i+2] << 16) | (temp[i+3] << 24);
00337         i += 4;
00338     }
00339     return TempLine;
00340 #undef CGA16_READER
00341 }
00342 
00343 static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) {
00344     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00345     Bit8u* draw=TempLine;
00346     Bitu end = vga.draw.blocks*2;
00347     while(end) {
00348         Bit8u byte = base[vidstart & vga.tandy.addr_mask];
00349         *draw++=vga.attr.palette[byte >> 4];
00350         *draw++=vga.attr.palette[byte & 0x0f];
00351         vidstart++;
00352         end--;
00353     }
00354     return TempLine;
00355 }
00356 
00357 static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart, Bitu line) {
00358     const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
00359     Bit8u* draw=TempLine;
00360     Bitu end = vga.draw.blocks;
00361     while(end) {
00362         Bit8u byte = base[vidstart & vga.tandy.addr_mask];
00363         Bit8u data = vga.attr.palette[byte >> 4];
00364         *draw++ = data; *draw++ = data;
00365         data = vga.attr.palette[byte & 0x0f];
00366         *draw++ = data; *draw++ = data;
00367         vidstart++;
00368         end--;
00369     }
00370     return TempLine;
00371 }
00372 
00373 #if SDL_BYTEORDER == SDL_LIL_ENDIAN && defined(MACOSX) /* Mac OS X Intel builds use a weird RGBA order (alpha in the low 8 bits) */
00374 static inline Bit32u guest_bgr_to_macosx_rgba(const Bit32u x) {
00375     /* guest: XRGB      X   R   G   B
00376      * host:  RGBX      B   G   R   X */
00377     return      ((x & 0x000000FFU) << 24U) +      /* BBxxxxxx */
00378                 ((x & 0x0000FF00U) <<  8U) +      /* xxGGxxxx */
00379                 ((x & 0x00FF0000U) >>  8U);       /* xxxxRRxx */
00380 }
00381 #endif
00382 
00383 static Bit8u * VGA_Draw_Linear_Line_24_to_32(Bitu vidstart, Bitu /*line*/) {
00384     Bitu offset = vidstart & vga.draw.linear_mask;
00385     Bitu i;
00386 
00387     /* DOSBox's render/scalar code can't handle 24bpp natively, so we have
00388      * to convert 24bpp -> 32bpp.
00389      *
00390      * WARNING: My clever trick might crash on processors that don't support
00391      *          unaligned memory addressing. To explain what it's doing, is
00392      *          it's using a DWORD read to fetch the 24bpp pixel (plus an
00393      *          extra byte), then overwrites the extra byte with 0xFF to
00394      *          produce a valid RGBA 8:8:8:8 value with the original pixel's
00395      *          RGB plus alpha channel value of 0xFF. */
00396 #if SDL_BYTEORDER == SDL_LIL_ENDIAN && defined(MACOSX) /* Mac OS X Intel builds use a weird RGBA order (alpha in the low 8 bits) */
00397     for (i=0;i < vga.draw.width;i++)
00398         ((uint32_t*)TempLine)[i] = guest_bgr_to_macosx_rgba(*((uint32_t*)(vga.draw.linear_base+offset+(i*3)))) | 0x000000FF;
00399 #else
00400     for (i=0;i < vga.draw.width;i++)
00401         ((uint32_t*)TempLine)[i] = *((uint32_t*)(vga.draw.linear_base+offset+(i*3))) | 0xFF000000;
00402 #endif
00403 
00404     return TempLine;
00405 }
00406 
00407 static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu /*line*/) {
00408     Bitu offset = vidstart & vga.draw.linear_mask;
00409     Bit8u* ret = &vga.draw.linear_base[offset];
00410     
00411     // in case (vga.draw.line_length + offset) has bits set that
00412     // are not set in the mask: ((x|y)!=y) equals (x&~y)
00413     if (GCC_UNLIKELY(((vga.draw.line_length + offset) & (~vga.draw.linear_mask)) != 0u)) {
00414         // this happens, if at all, only once per frame (1 of 480 lines)
00415         // in some obscure games
00416         Bitu end = (Bitu)((Bitu)offset + (Bitu)vga.draw.line_length) & (Bitu)vga.draw.linear_mask;
00417         
00418         // assuming lines not longer than 4096 pixels
00419         Bitu wrapped_len = end & 0xFFF;
00420         Bitu unwrapped_len = vga.draw.line_length-wrapped_len;
00421         
00422         // unwrapped chunk: to top of memory block
00423         memcpy(TempLine, &vga.draw.linear_base[offset], unwrapped_len);
00424         // wrapped chunk: from base of memory block
00425         memcpy(&TempLine[unwrapped_len], vga.draw.linear_base, wrapped_len);
00426 
00427         ret = TempLine;
00428     }
00429 
00430 #if !defined(C_UNALIGNED_MEMORY)
00431     if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
00432         memcpy( TempLine, ret, vga.draw.line_length );
00433         return TempLine;
00434     }
00435 #endif
00436     return ret;
00437 }
00438 
00439 /* WARNING: This routine assumes (vidstart&3) == 0 */
00440 static Bit8u * VGA_Draw_Xlat32_VGA_CRTC_bmode_Line(Bitu vidstart, Bitu /*line*/) {
00441     Bit32u* temps = (Bit32u*) TempLine;
00442     unsigned int poff = 0;
00443     Bitu skip; /* how much to skip after drawing 4 pixels */
00444 
00445     skip = 4u << vga.config.addr_shift;
00446 
00447     /* *sigh* it looks like DOSBox's VGA scanline code will pass nonzero bits 0-1 in vidstart */
00448     poff += vidstart & 3u;
00449     vidstart &= ~3ul;
00450 
00451     /* hack for Surprise! productions "copper" demo.
00452      * when the demo talks about making the picture waver, what it's doing is diddling
00453      * with the Start Horizontal Retrace register of the CRTC once per scanline.
00454      * ...yeah, really. It's a wonder in retrospect the programmer didn't burn out his
00455      * VGA monitor, and I bet this makes the demo effect unwatchable on LCD flat panels or
00456      * scan converters that rely on the pulses to detect VGA mode changes! */
00457     if (vga_enable_hretrace_effects) {
00458         /* NTS: This is NOT BACKWARDS. It makes sense if you think about it: the monitor
00459          *      begins swinging the electron beam back on horizontal retract, so if the
00460          *      retrace starts sooner, then the blanking on the left side appears to last
00461          *      longer because there are more clocks until active display.
00462          *
00463          *      Also don't forget horizontal total/blank/retrace etc. registers are in
00464          *      character clocks not pixels. In 320x200x256 mode, one character clock is
00465          *      4 pixels.
00466          *
00467          *      Finally, we average it with "weight" because CRTs have "inertia" */
00468         float a = 1.0 / (hretrace_fx_avg_weight + 1);
00469 
00470         hretrace_fx_avg *= 1.0 - a;
00471         hretrace_fx_avg += a * 4 * ((int)vga_display_start_hretrace - (int)vga.crtc.start_horizontal_retrace);
00472         int x = (int)floor(hretrace_fx_avg + 0.5);
00473 
00474         vidstart += (Bitu)((int)skip * (x >> 2));
00475         poff += x & 3;
00476     }
00477 
00478     for(Bitu i = 0; i < ((vga.draw.line_length>>(2/*32bpp*/+2/*4 pixels*/))+((poff+3)>>2)); i++) {
00479         Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ];
00480 
00481         /* one group of 4 */
00482         *temps++ = vga.dac.xlat32[*ret++];
00483         *temps++ = vga.dac.xlat32[*ret++];
00484         *temps++ = vga.dac.xlat32[*ret++];
00485         *temps++ = vga.dac.xlat32[*ret++];
00486         /* and skip */
00487         vidstart += skip;
00488     }
00489 
00490     return TempLine + (poff * 4);
00491 }
00492 
00493 static Bit8u * VGA_Draw_Xlat32_Linear_Line(Bitu vidstart, Bitu /*line*/) {
00494     Bit32u* temps = (Bit32u*) TempLine;
00495 
00496     /* hack for Surprise! productions "copper" demo.
00497      * when the demo talks about making the picture waver, what it's doing is diddling
00498      * with the Start Horizontal Retrace register of the CRTC once per scanline.
00499      * ...yeah, really. It's a wonder in retrospect the programmer didn't burn out his
00500      * VGA monitor, and I bet this makes the demo effect unwatchable on LCD flat panels or
00501      * scan converters that rely on the pulses to detect VGA mode changes! */
00502     if (vga_enable_hretrace_effects) {
00503         /* NTS: This is NOT BACKWARDS. It makes sense if you think about it: the monitor
00504          *      begins swinging the electron beam back on horizontal retract, so if the
00505          *      retrace starts sooner, then the blanking on the left side appears to last
00506          *      longer because there are more clocks until active display.
00507          *
00508          *      Also don't forget horizontal total/blank/retrace etc. registers are in
00509          *      character clocks not pixels. In 320x200x256 mode, one character clock is
00510          *      4 pixels.
00511          *
00512          *      Finally, we average it with "weight" because CRTs have "inertia" */
00513         float a = 1.0 / (hretrace_fx_avg_weight + 1);
00514 
00515         hretrace_fx_avg *= 1.0 - a;
00516         hretrace_fx_avg += a * 4 * ((int)vga_display_start_hretrace - (int)vga.crtc.start_horizontal_retrace);
00517         int x = (int)floor(hretrace_fx_avg + 0.5);
00518 
00519         vidstart += (Bitu)((int)x);
00520     }
00521 
00522     for(Bitu i = 0; i < (vga.draw.line_length>>2); i++)
00523         temps[i]=vga.dac.xlat32[vga.draw.linear_base[(vidstart+i)&vga.draw.linear_mask]];
00524 
00525     return TempLine;
00526 }
00527 
00528 extern Bit32u Expand16Table[4][16];
00529 
00530 static Bit8u * EGA_Draw_VGA_Planar_Xlat8_Line(Bitu vidstart, Bitu /*line*/) {
00531     Bit8u* temps = (Bit8u*) TempLine;
00532     Bit32u t1,t2,tmp;
00533 
00534     if (vga.seq.clocking_mode&4) { /* odd/even mode serialization */
00535         for (Bitu i = 0; i < ((vga.draw.line_length)+vga.draw.panning);) {
00536             if (vidstart > vga.draw.linear_mask)
00537                 vidstart = (vidstart + 4u) & vga.draw.linear_mask;
00538 
00539             t1 = t2 = *((Bit32u*)(&vga.draw.linear_base[ vidstart & vga.draw.linear_mask ]));
00540             t1 = (t1 >> 4) & 0x0f0f0f0f;
00541             t2 &= 0x0f0f0f0f;
00542             vidstart += 4 * 2;
00543 
00544             for (Bitu w = 0;w < 2;w++,t1>>=8,t2>>=8,i+=8) {
00545                 tmp =   Expand16Table[0][(t1>>0)&0xFF] |
00546                     Expand16Table[2][(t1>>16)&0xFF];
00547                 temps[i+0] = vga.attr.palette[(tmp>>0)&0xFF];
00548                 temps[i+1] = vga.attr.palette[(tmp>>8)&0xFF];
00549                 temps[i+2] = vga.attr.palette[(tmp>>16)&0xFF];
00550                 temps[i+3] = vga.attr.palette[(tmp>>24)&0xFF];
00551 
00552                 tmp =   Expand16Table[0][(t2>>0)&0xFF] |
00553                     Expand16Table[2][(t2>>16)&0xFF];
00554                 temps[i+4] = vga.attr.palette[(tmp>>0)&0xFF];
00555                 temps[i+5] = vga.attr.palette[(tmp>>8)&0xFF];
00556                 temps[i+6] = vga.attr.palette[(tmp>>16)&0xFF];
00557                 temps[i+7] = vga.attr.palette[(tmp>>24)&0xFF];
00558             }
00559         }
00560     }
00561     else {
00562         for (Bitu i = 0; i < ((vga.draw.line_length)+vga.draw.panning); i += 8) {
00563             t1 = t2 = *((Bit32u*)(&vga.draw.linear_base[ vidstart & vga.draw.linear_mask ]));
00564             t1 = (t1 >> 4) & 0x0f0f0f0f;
00565             t2 &= 0x0f0f0f0f;
00566             vidstart += 4;
00567 
00568             tmp =   Expand16Table[0][(t1>>0)&0xFF] |
00569                 Expand16Table[1][(t1>>8)&0xFF] |
00570                 Expand16Table[2][(t1>>16)&0xFF] |
00571                 Expand16Table[3][(t1>>24)&0xFF];
00572             temps[i+0] = vga.attr.palette[(tmp>>0)&0xFF];
00573             temps[i+1] = vga.attr.palette[(tmp>>8)&0xFF];
00574             temps[i+2] = vga.attr.palette[(tmp>>16)&0xFF];
00575             temps[i+3] = vga.attr.palette[(tmp>>24)&0xFF];
00576 
00577             tmp =   Expand16Table[0][(t2>>0)&0xFF] |
00578                 Expand16Table[1][(t2>>8)&0xFF] |
00579                 Expand16Table[2][(t2>>16)&0xFF] |
00580                 Expand16Table[3][(t2>>24)&0xFF];
00581             temps[i+4] = vga.attr.palette[(tmp>>0)&0xFF];
00582             temps[i+5] = vga.attr.palette[(tmp>>8)&0xFF];
00583             temps[i+6] = vga.attr.palette[(tmp>>16)&0xFF];
00584             temps[i+7] = vga.attr.palette[(tmp>>24)&0xFF];
00585         }
00586     }
00587 
00588     return TempLine + (vga.draw.panning);
00589 }
00590 
00591 static Bit8u * VGA_Draw_VGA_Planar_Xlat32_Line(Bitu vidstart, Bitu /*line*/) {
00592     Bit32u* temps = (Bit32u*) TempLine;
00593     Bit32u t1,t2,tmp;
00594 
00595     for (Bitu i = 0; i < ((vga.draw.line_length>>2)+vga.draw.panning); i += 8) {
00596         t1 = t2 = *((Bit32u*)(&vga.draw.linear_base[ vidstart & vga.draw.linear_mask ]));
00597         t1 = (t1 >> 4) & 0x0f0f0f0f;
00598         t2 &= 0x0f0f0f0f;
00599         vidstart += 4;
00600 
00601         tmp =   Expand16Table[0][(t1>>0)&0xFF] |
00602             Expand16Table[1][(t1>>8)&0xFF] |
00603             Expand16Table[2][(t1>>16)&0xFF] |
00604             Expand16Table[3][(t1>>24)&0xFF];
00605         temps[i+0] = vga.dac.xlat32[(tmp>>0)&0xFF];
00606         temps[i+1] = vga.dac.xlat32[(tmp>>8)&0xFF];
00607         temps[i+2] = vga.dac.xlat32[(tmp>>16)&0xFF];
00608         temps[i+3] = vga.dac.xlat32[(tmp>>24)&0xFF];
00609 
00610         tmp =   Expand16Table[0][(t2>>0)&0xFF] |
00611             Expand16Table[1][(t2>>8)&0xFF] |
00612             Expand16Table[2][(t2>>16)&0xFF] |
00613             Expand16Table[3][(t2>>24)&0xFF];
00614         temps[i+4] = vga.dac.xlat32[(tmp>>0)&0xFF];
00615         temps[i+5] = vga.dac.xlat32[(tmp>>8)&0xFF];
00616         temps[i+6] = vga.dac.xlat32[(tmp>>16)&0xFF];
00617         temps[i+7] = vga.dac.xlat32[(tmp>>24)&0xFF];
00618     }
00619 
00620     return TempLine + (vga.draw.panning*4);
00621 }
00622 
00623 //Test version, might as well keep it
00624 /* static Bit8u * VGA_Draw_Chain_Line(Bitu vidstart, Bitu line) {
00625     Bitu i = 0;
00626     for ( i = 0; i < vga.draw.width;i++ ) {
00627         Bitu addr = vidstart + i;
00628         TempLine[i] = vga.mem.linear[((addr&~3)<<2)+(addr&3)];
00629     }
00630     return TempLine;
00631 } */
00632 
00633 static Bit8u * VGA_Draw_VGA_Line_Xlat32_HWMouse( Bitu vidstart, Bitu /*line*/) {
00634     if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
00635         // HW Mouse not enabled, use the tried and true call
00636         return VGA_Draw_Xlat32_Linear_Line(vidstart, 0);
00637 
00638     Bitu lineat = (vidstart-(vga.config.real_start<<2)) / vga.draw.width;
00639     if ((vga.s3.hgc.posx >= vga.draw.width) ||
00640         (lineat < vga.s3.hgc.originy) ||
00641         (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
00642         // the mouse cursor *pattern* is not on this line
00643         return VGA_Draw_Xlat32_Linear_Line(vidstart, 0);
00644     } else {
00645         // Draw mouse cursor: cursor is a 64x64 pattern which is shifted (inside the
00646         // 64x64 mouse cursor space) to the right by posx pixels and up by posy pixels.
00647         // This is used when the mouse cursor partially leaves the screen.
00648         // It is arranged as bitmap of 16bits of bitA followed by 16bits of bitB, each
00649         // AB bits corresponding to a cursor pixel. The whole map is 8kB in size.
00650         Bit32u* temp = (Bit32u*)VGA_Draw_Xlat32_Linear_Line(vidstart, 0);
00651         //memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width);
00652 
00653         // the index of the bit inside the cursor bitmap we start at:
00654         Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
00655         // convert to video memory addr and bit index
00656         // start adjusted to the pattern structure (thus shift address by 2 instead of 3)
00657         // Need to get rid of the third bit, so "/8 *2" becomes ">> 2 & ~1"
00658         Bitu cursorMemStart = ((sourceStartBit >> 2ul) & ~1ul) + (((Bit32u)vga.s3.hgc.startaddr) << 10ul);
00659         Bitu cursorStartBit = sourceStartBit & 0x7u;
00660         // stay at the right position in the pattern
00661         if (cursorMemStart & 0x2) cursorMemStart--;
00662         Bitu cursorMemEnd = cursorMemStart + (Bitu)((64 - vga.s3.hgc.posx) >> 2);
00663         Bit32u* xat = &temp[vga.s3.hgc.originx]; // mouse data start pos. in scanline
00664         for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
00665             // for each byte of cursor data
00666             Bit8u bitsA = vga.mem.linear[m];
00667             Bit8u bitsB = vga.mem.linear[m+2];
00668             for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
00669                 // for each bit
00670                 cursorStartBit=0; // only the first byte has some bits cut off
00671                 if (bitsA&bit) {
00672                     if (bitsB&bit) *xat ^= 0xFFFFFFFF; // Invert screen data
00673                     //else Transparent
00674                 } else if (bitsB&bit) {
00675                     *xat = vga.dac.xlat32[vga.s3.hgc.forestack[0]]; // foreground color
00676                 } else {
00677                     *xat = vga.dac.xlat32[vga.s3.hgc.backstack[0]];
00678                 }
00679                 xat++;
00680             }
00681         }
00682         return (Bit8u*)temp;
00683     }
00684 }
00685 
00686 static Bit8u * VGA_Draw_VGA_Line_HWMouse( Bitu vidstart, Bitu /*line*/) {
00687     if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
00688         // HW Mouse not enabled, use the tried and true call
00689         return &vga.mem.linear[vidstart];
00690 
00691     Bitu lineat = (vidstart-(vga.config.real_start<<2)) / vga.draw.width;
00692     if ((vga.s3.hgc.posx >= vga.draw.width) ||
00693         (lineat < vga.s3.hgc.originy) || 
00694         (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
00695         // the mouse cursor *pattern* is not on this line
00696         return &vga.mem.linear[ vidstart ];
00697     } else {
00698         // Draw mouse cursor: cursor is a 64x64 pattern which is shifted (inside the
00699         // 64x64 mouse cursor space) to the right by posx pixels and up by posy pixels.
00700         // This is used when the mouse cursor partially leaves the screen.
00701         // It is arranged as bitmap of 16bits of bitA followed by 16bits of bitB, each
00702         // AB bits corresponding to a cursor pixel. The whole map is 8kB in size.
00703         memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width);
00704         // the index of the bit inside the cursor bitmap we start at:
00705         Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx; 
00706         // convert to video memory addr and bit index
00707         // start adjusted to the pattern structure (thus shift address by 2 instead of 3)
00708         // Need to get rid of the third bit, so "/8 *2" becomes ">> 2 & ~1"
00709         Bitu cursorMemStart = ((sourceStartBit >> 2) & ~1ul) + (((Bit32u)vga.s3.hgc.startaddr) << 10ul);
00710         Bitu cursorStartBit = sourceStartBit & 0x7u;
00711         // stay at the right position in the pattern
00712         if (cursorMemStart & 0x2) cursorMemStart--;
00713         Bitu cursorMemEnd = cursorMemStart + (Bitu)((64 - vga.s3.hgc.posx) >> 2);
00714         Bit8u* xat = &TempLine[vga.s3.hgc.originx]; // mouse data start pos. in scanline
00715         for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
00716             // for each byte of cursor data
00717             Bit8u bitsA = vga.mem.linear[m];
00718             Bit8u bitsB = vga.mem.linear[m+2];
00719             for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
00720                 // for each bit
00721                 cursorStartBit=0; // only the first byte has some bits cut off
00722                 if (bitsA&bit) {
00723                     if (bitsB&bit) *xat ^= 0xFF; // Invert screen data
00724                     //else Transparent
00725                 } else if (bitsB&bit) {
00726                     *xat = vga.s3.hgc.forestack[0]; // foreground color
00727                 } else {
00728                     *xat = vga.s3.hgc.backstack[0];
00729                 }
00730                 xat++;
00731             }
00732         }
00733         return TempLine;
00734     }
00735 }
00736 
00737 /* render 16bpp line DOUBLED horizontally */
00738 static Bit8u * VGA_Draw_LIN16_Line_2x(Bitu vidstart, Bitu /*line*/) {
00739     Bit16u *s = (Bit16u*)(&vga.mem.linear[vidstart]);
00740     Bit16u *d = (Bit16u*)TempLine;
00741 
00742     for (Bitu i = 0; i < (vga.draw.line_length>>2); i++) {
00743         d[0] = d[1] = *s++;
00744         d += 2;
00745     }
00746 
00747     return TempLine;
00748 }
00749 
00750 static Bit8u * VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
00751     if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
00752         return &vga.mem.linear[vidstart];
00753 
00754     Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 1) / vga.draw.width;
00755     if ((vga.s3.hgc.posx >= vga.draw.width) ||
00756         (lineat < vga.s3.hgc.originy) || 
00757         (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
00758         return &vga.mem.linear[vidstart];
00759     } else {
00760         memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*2);
00761         Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx; 
00762         Bitu cursorMemStart = ((sourceStartBit >> 2) & ~1ul) + (((Bit32u)vga.s3.hgc.startaddr) << 10ul);
00763         Bitu cursorStartBit = sourceStartBit & 0x7u;
00764         if (cursorMemStart & 0x2) cursorMemStart--;
00765         Bitu cursorMemEnd = cursorMemStart + (Bitu)((64 - vga.s3.hgc.posx) >> 2);
00766         Bit16u* xat = &((Bit16u*)TempLine)[vga.s3.hgc.originx];
00767         for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
00768             // for each byte of cursor data
00769             Bit8u bitsA = vga.mem.linear[m];
00770             Bit8u bitsB = vga.mem.linear[m+2];
00771             for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
00772                 // for each bit
00773                 cursorStartBit=0;
00774                 if (bitsA&bit) {
00775                     // byte order doesn't matter here as all bits get flipped
00776                     if (bitsB&bit) *xat ^= ~0U;
00777                     //else Transparent
00778                 } else if (bitsB&bit) {
00779                     // Source as well as destination are Bit8u arrays, 
00780                     // so this should work out endian-wise?
00781                     *xat = *(Bit16u*)vga.s3.hgc.forestack;
00782                 } else {
00783                     *xat = *(Bit16u*)vga.s3.hgc.backstack;
00784                 }
00785                 xat++;
00786             }
00787         }
00788         return TempLine;
00789     }
00790 }
00791 
00792 static Bit8u * VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
00793 #if SDL_BYTEORDER == SDL_LIL_ENDIAN && defined(MACOSX) /* Mac OS X Intel builds use a weird RGBA order (alpha in the low 8 bits) */
00794     Bitu offset = vidstart & vga.draw.linear_mask;
00795     Bitu i;
00796 
00797     for (i=0;i < vga.draw.width;i++)
00798         ((uint32_t*)TempLine)[i] = guest_bgr_to_macosx_rgba((((uint32_t*)(vga.draw.linear_base+offset))[i]));
00799 
00800     return TempLine;
00801 #else
00802     if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
00803         return &vga.mem.linear[vidstart];
00804 
00805     Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 2) / vga.draw.width;
00806     if ((vga.s3.hgc.posx >= vga.draw.width) ||
00807         (lineat < vga.s3.hgc.originy) || 
00808         (lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
00809         return &vga.mem.linear[ vidstart ];
00810     } else {
00811         memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*4);
00812         Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx; 
00813         Bitu cursorMemStart = ((sourceStartBit >> 2) & ~1ul) + (((Bit32u)vga.s3.hgc.startaddr) << 10ul);
00814         Bitu cursorStartBit = sourceStartBit & 0x7u;
00815         if (cursorMemStart & 0x2) cursorMemStart--;
00816         Bitu cursorMemEnd = cursorMemStart + (Bitu)((64 - vga.s3.hgc.posx) >> 2);
00817         Bit32u* xat = &((Bit32u*)TempLine)[vga.s3.hgc.originx];
00818         for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
00819             // for each byte of cursor data
00820             Bit8u bitsA = vga.mem.linear[m];
00821             Bit8u bitsB = vga.mem.linear[m+2];
00822             for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) { // for each bit
00823                 cursorStartBit=0;
00824                 if (bitsA&bit) {
00825                     if (bitsB&bit) *xat ^= ~0U;
00826                     //else Transparent
00827                 } else if (bitsB&bit) {
00828                     *xat = *(Bit32u*)vga.s3.hgc.forestack;
00829                 } else {
00830                     *xat = *(Bit32u*)vga.s3.hgc.backstack;
00831                 }
00832                 xat++;
00833             }
00834         }
00835         return TempLine;
00836     }
00837 #endif
00838 }
00839 
00840 static const Bit32u* VGA_Planar_Memwrap(Bitu vidstart) {
00841     vidstart &= vga.draw.planar_mask;
00842     return (Bit32u*)(&vga.mem.linear[vidstart << 2]);
00843 }
00844 
00845 static const Bit8u* VGA_Text_Memwrap(Bitu vidstart) {
00846     vidstart &= vga.draw.linear_mask;
00847     Bitu line_end = 2 * vga.draw.blocks;
00848     if (GCC_UNLIKELY((vidstart + line_end) > vga.draw.linear_mask)) {
00849         // wrapping in this line
00850         Bitu break_pos = (vga.draw.linear_mask - vidstart) + 1;
00851         // need a temporary storage - TempLine/2 is ok for a bit more than 132 columns
00852         memcpy(&TempLine[sizeof(TempLine)/2], &vga.tandy.draw_base[vidstart], break_pos);
00853         memcpy(&TempLine[sizeof(TempLine)/2 + break_pos],&vga.tandy.draw_base[0], line_end - break_pos);
00854         return &TempLine[sizeof(TempLine)/2];
00855     } else return &vga.tandy.draw_base[vidstart];
00856 }
00857 
00858 static Bit32u FontMask[2]={0xffffffff,0x0};
00859 static Bit32u CGA_PRND = 1;
00860 
00861 static Bit8u * VGA_CGASNOW_TEXT_Draw_Line(Bitu vidstart, Bitu line) {
00862     Bits font_addr;
00863     Bit32u * draw=(Bit32u *)TempLine;
00864     const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
00865 
00866     /* HACK: our code does not have render control during VBLANK, zero our
00867      *       noise bits on the first scanline */
00868     if (line == 0)
00869         memset(vga.draw.cga_snow,0,sizeof(vga.draw.cga_snow));
00870 
00871     for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
00872         Bitu chr,col;
00873         chr=vidmem[cx*2];
00874         col=vidmem[cx*2+1];
00875         if ((cx&1) == 0 && cx <= 78) {
00876             /* Trixter's "CGA test" program and reference video seems to suggest
00877              * to me that the CGA "snow" might contain the value written by the CPU. */
00878             if (vga.draw.cga_snow[cx] != 0)
00879                 chr = vga.draw.cga_snow[cx];
00880             if (vga.draw.cga_snow[cx+1] != 0)
00881                 col = vga.draw.cga_snow[cx+1];
00882 
00883             CGA_PRND = ((CGA_PRND+1)*9421)&0xFFFF;
00884         }
00885 
00886         Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
00887         Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
00888         Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
00889         Bit32u fg=TXT_FG_Table[col&0xf];
00890         Bit32u bg=TXT_BG_Table[col>>4];
00891         *draw++=(fg&mask1) | (bg&~mask1);
00892         *draw++=(fg&mask2) | (bg&~mask2);
00893     }
00894     memset(vga.draw.cga_snow,0,sizeof(vga.draw.cga_snow));
00895     if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
00896     font_addr = ((Bits)vga.draw.cursor.address - (Bits)vidstart) >> 1ll;
00897     if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
00898         if (line<vga.draw.cursor.sline) goto skip_cursor;
00899         if (line>vga.draw.cursor.eline) goto skip_cursor;
00900         draw=(Bit32u *)&TempLine[(unsigned long)font_addr*8ul];
00901         Bit32u att=TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1ul]&0xfu];
00902         *draw++=att;*draw++=att;
00903     }
00904 skip_cursor:
00905     return TempLine;
00906 }
00907 
00908 static Bit8u * VGA_TEXT_Draw_Line(Bitu vidstart, Bitu line) {
00909     Bits font_addr;
00910     Bit32u * draw=(Bit32u *)TempLine;
00911     const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
00912     //assert(FontMask[0] == 0xffffffff);
00913     if (FontMask[1] == 0) {
00914         for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
00915             Bitu chr=vidmem[cx*2];
00916             Bitu col=vidmem[cx*2+1];
00917             Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
00918             Bit32u font_mask = (Bit32u)((((Bit32s)col) << 24) >> 31);
00919             font_mask = ~font_mask;
00920             Bit32u mask1=TXT_Font_Table[font>>4ul] & font_mask;
00921             Bit32u mask2=TXT_Font_Table[font&0xful] & font_mask;
00922             Bit32u fg=TXT_FG_Table[col&0xful];
00923             Bit32u bg=TXT_BG_Table[col>>4ul];
00924             *draw++=(fg&mask1) | (bg&~mask1);
00925             *draw++=(fg&mask2) | (bg&~mask2);
00926         }
00927     } else {
00928         //assert(FontMask[1] == 0xffffffff);
00929         for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
00930             Bitu chr=vidmem[cx*2];
00931             Bitu col=vidmem[cx*2+1];
00932             Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
00933             Bit32u mask1=TXT_Font_Table[font>>4];
00934             Bit32u mask2=TXT_Font_Table[font&0xf];
00935             Bit32u fg=TXT_FG_Table[col&0xf];
00936             Bit32u bg=TXT_BG_Table[col>>4];
00937             *draw++=(fg&mask1) | (bg&~mask1);
00938             *draw++=(fg&mask2) | (bg&~mask2);
00939         }
00940     }
00941     if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
00942     font_addr = ((Bits)vga.draw.cursor.address-(Bits)vidstart) >> 1ll;
00943     if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
00944         if (line<vga.draw.cursor.sline) goto skip_cursor;
00945         if (line>vga.draw.cursor.eline) goto skip_cursor;
00946         draw=(Bit32u *)&TempLine[(unsigned long)font_addr*8ul];
00947         Bit32u att=TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf];
00948         *draw++=att;*draw++=att;
00949     }
00950 skip_cursor:
00951     return TempLine;
00952 }
00953 
00954 static Bit8u * VGA_TEXT_Herc_Draw_Line(Bitu vidstart, Bitu line) {
00955     Bits font_addr;
00956     Bit32u * draw=(Bit32u *)TempLine;
00957     const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
00958 
00959     for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
00960         Bitu chr=vidmem[cx*2];
00961         Bitu attrib=vidmem[cx*2+1];
00962         if (!(attrib&0x77)) {
00963             // 00h, 80h, 08h, 88h produce black space
00964             *draw++=0;
00965             *draw++=0;
00966         } else {
00967             Bit32u bg, fg;
00968             bool underline=false;
00969             if ((attrib&0x77)==0x70) {
00970                 bg = TXT_BG_Table[0x7];
00971                 if (attrib&0x8) fg = TXT_FG_Table[0xf];
00972                 else fg = TXT_FG_Table[0x0];
00973             } else {
00974                 if (((Bitu)(vga.crtc.underline_location&0x1f)==line) && ((attrib&0x77)==0x1)) underline=true;
00975                 bg = TXT_BG_Table[0x0];
00976                 if (attrib&0x8) fg = TXT_FG_Table[0xf];
00977                 else fg = TXT_FG_Table[0x7];
00978             }
00979             Bit32u mask1, mask2;
00980             if (GCC_UNLIKELY(underline)) mask1 = mask2 = FontMask[attrib >> 7];
00981             else {
00982                 Bitu font=vga.draw.font_tables[0][chr*32+line];
00983                 mask1=TXT_Font_Table[font>>4] & FontMask[attrib >> 7]; // blinking
00984                 mask2=TXT_Font_Table[font&0xf] & FontMask[attrib >> 7];
00985             }
00986             *draw++=(fg&mask1) | (bg&~mask1);
00987             *draw++=(fg&mask2) | (bg&~mask2);
00988         }
00989     }
00990     if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
00991     font_addr = ((Bits)vga.draw.cursor.address - (Bits)vidstart) >> 1ll;
00992     if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
00993         if (line<vga.draw.cursor.sline) goto skip_cursor;
00994         if (line>vga.draw.cursor.eline) goto skip_cursor;
00995         draw=(Bit32u *)&TempLine[(unsigned long)font_addr*8ul];
00996         Bit8u attr = vga.tandy.draw_base[vga.draw.cursor.address+1];
00997         Bit32u cg;
00998         if (attr&0x8) {
00999             cg = TXT_FG_Table[0xf];
01000         } else if ((attr&0x77)==0x70) {
01001             cg = TXT_FG_Table[0x0];
01002         } else {
01003             cg = TXT_FG_Table[0x7];
01004         }
01005         *draw++=cg;*draw++=cg;
01006     }
01007 skip_cursor:
01008     return TempLine;
01009 }
01010 
01011 // combined 8/9-dot wide text mode 16bpp line drawing function
01012 static Bit8u* EGA_TEXT_Xlat8_Draw_Line(Bitu vidstart, Bitu line) {
01013     // keep it aligned:
01014     Bit8u* draw = ((Bit8u*)TempLine) + 16 - vga.draw.panning;
01015     const Bit32u* vidmem = VGA_Planar_Memwrap(vidstart); // pointer to chars+attribs
01016     Bitu blocks = vga.draw.blocks;
01017     if (vga.draw.panning) blocks++; // if the text is panned part of an 
01018                                     // additional character becomes visible
01019     while (blocks--) { // for each character in the line
01020         VGA_Latch pixels;
01021 
01022         pixels.d = *vidmem;
01023         vidmem += (uintptr_t)1U << (uintptr_t)vga.config.addr_shift;
01024 
01025         Bitu chr = pixels.b[0];
01026         Bitu attr = pixels.b[1];
01027         // the font pattern
01028         Bitu font = vga.draw.font_tables[(attr >> 3)&1][(chr<<5)+line];
01029         
01030         Bitu background = attr >> 4u;
01031         // if blinking is enabled bit7 is not mapped to attributes
01032         if (vga.draw.blinking) background &= ~0x8u;
01033         // choose foreground color if blinking not set for this cell or blink on
01034         Bitu foreground = (vga.draw.blink || (!(attr&0x80)))?
01035             (attr&0xf):background;
01036         // underline: all foreground [freevga: 0x77, previous 0x7]
01037         if (GCC_UNLIKELY(((attr&0x77) == 0x01) &&
01038             (vga.crtc.underline_location&0x1f)==line))
01039                 background = foreground;
01040         if (vga.draw.char9dot) {
01041             font <<=1; // 9 pixels
01042             // extend to the 9th pixel if needed
01043             if ((font&0x2) && (vga.attr.mode_control&0x04) &&
01044                 (chr>=0xc0) && (chr<=0xdf)) font |= 1;
01045             for (Bitu n = 0; n < 9; n++) {
01046                 *draw++ = vga.attr.palette[(font&0x100)? foreground:background];
01047                 font <<= 1;
01048             }
01049         } else {
01050             for (Bitu n = 0; n < 8; n++) {
01051                 *draw++ = vga.attr.palette[(font&0x80)? foreground:background];
01052                 font <<= 1;
01053             }
01054         }
01055     }
01056     // draw the text mode cursor if needed
01057     if ((vga.draw.cursor.count&0x8) && (line >= vga.draw.cursor.sline) &&
01058         (line <= vga.draw.cursor.eline) && vga.draw.cursor.enabled) {
01059         // the adress of the attribute that makes up the cell the cursor is in
01060         Bits attr_addr = ((Bits)vga.draw.cursor.address - (Bits)vidstart) >> (Bits)vga.config.addr_shift; /* <- FIXME: This right? */
01061         if (attr_addr >= 0 && attr_addr < (Bits)vga.draw.blocks) {
01062             Bitu index = (Bitu)attr_addr * (vga.draw.char9dot ? 9u : 8u);
01063             draw = (Bit8u*)(&TempLine[index]) + 16 - vga.draw.panning;
01064             
01065             Bitu foreground = vga.tandy.draw_base[(vga.draw.cursor.address<<2ul)+1] & 0xf;
01066             for (Bitu i = 0; i < 8; i++) {
01067                 *draw++ = vga.attr.palette[foreground];
01068             }
01069         }
01070     }
01071     return TempLine+(16);
01072 }
01073 
01074 // combined 8/9-dot wide text mode 16bpp line drawing function
01075 static Bit8u* VGA_TEXT_Xlat32_Draw_Line(Bitu vidstart, Bitu line) {
01076     // keep it aligned:
01077     Bit32u* draw = ((Bit32u*)TempLine) + 16 - vga.draw.panning;
01078     const Bit32u* vidmem = VGA_Planar_Memwrap(vidstart); // pointer to chars+attribs
01079     Bitu blocks = vga.draw.blocks;
01080     if (vga.draw.panning) blocks++; // if the text is panned part of an 
01081                                     // additional character becomes visible
01082     while (blocks--) { // for each character in the line
01083         VGA_Latch pixels;
01084 
01085         pixels.d = *vidmem;
01086         vidmem += (uintptr_t)1U << (uintptr_t)vga.config.addr_shift;
01087 
01088         Bitu chr = pixels.b[0];
01089         Bitu attr = pixels.b[1];
01090         // the font pattern
01091         Bitu font = vga.draw.font_tables[(attr >> 3u)&1u][(chr<<5u)+line];
01092         
01093         Bitu background = attr >> 4u;
01094         // if blinking is enabled bit7 is not mapped to attributes
01095         if (vga.draw.blinking) background &= ~0x8u;
01096         // choose foreground color if blinking not set for this cell or blink on
01097         Bitu foreground = (vga.draw.blink || (!(attr&0x80)))?
01098             (attr&0xf):background;
01099         // underline: all foreground [freevga: 0x77, previous 0x7]
01100         if (GCC_UNLIKELY(((attr&0x77) == 0x01) &&
01101             (vga.crtc.underline_location&0x1f)==line))
01102                 background = foreground;
01103         if (vga.draw.char9dot) {
01104             font <<=1; // 9 pixels
01105             // extend to the 9th pixel if needed
01106             if ((font&0x2) && (vga.attr.mode_control&0x04) &&
01107                 (chr>=0xc0) && (chr<=0xdf)) font |= 1;
01108             for (Bitu n = 0; n < 9; n++) {
01109                 *draw++ = vga.dac.xlat32[(font&0x100)? foreground:background];
01110                 font <<= 1;
01111             }
01112         } else {
01113             for (Bitu n = 0; n < 8; n++) {
01114                 *draw++ = vga.dac.xlat32[(font&0x80)? foreground:background];
01115                 font <<= 1;
01116             }
01117         }
01118     }
01119     // draw the text mode cursor if needed
01120     if ((vga.draw.cursor.count&0x8) && (line >= vga.draw.cursor.sline) &&
01121         (line <= vga.draw.cursor.eline) && vga.draw.cursor.enabled) {
01122         // the adress of the attribute that makes up the cell the cursor is in
01123         Bits attr_addr = ((Bits)vga.draw.cursor.address - (Bits)vidstart) >> (Bits)vga.config.addr_shift; /* <- FIXME: This right? */
01124         if (attr_addr >= 0 && attr_addr < (Bits)vga.draw.blocks) {
01125             Bitu index = (Bitu)attr_addr * (vga.draw.char9dot?9u:8u) * 4u;
01126             draw = (Bit32u*)(&TempLine[index]) + 16 - vga.draw.panning;
01127             
01128             Bitu foreground = vga.tandy.draw_base[(vga.draw.cursor.address<<2)+1] & 0xf;
01129             for (Bitu i = 0; i < 8; i++) {
01130                 *draw++ = vga.dac.xlat32[foreground];
01131             }
01132         }
01133     }
01134     return TempLine+(16*4);
01135 }
01136 
01137 extern bool pc98_attr4_graphic;
01138 extern uint8_t GDC_display_plane;
01139 extern uint8_t GDC_display_plane_pending;
01140 extern bool pc98_graphics_hide_odd_raster_200line;
01141 extern bool pc98_allow_scanline_effect;
01142 extern bool gdc_analog;
01143 
01144 static Bit8u* VGA_PC98_Xlat32_Draw_Line(Bitu vidstart, Bitu line) {
01145     // keep it aligned:
01146     Bit32u* draw = ((Bit32u*)TempLine);
01147     Bitu blocks = vga.draw.blocks;
01148     Bit32u vidmem = vidstart;
01149     Bit16u chr = 0,attr = 0;
01150     Bit16u lineoverlay = 0; // vertical + underline overlay over the character cell, but apparently with a 4-pixel delay
01151     bool doublewide = false;
01152     unsigned char font,foreground;
01153     unsigned char fline;
01154     bool ok_raster = true;
01155 
01156     // 200-line modes: The BIOS or DOS game can elect to hide odd raster lines
01157     if (pc98_gdc[GDC_SLAVE].doublescan && pc98_graphics_hide_odd_raster_200line && pc98_allow_scanline_effect)
01158         ok_raster = (vga.draw.lines_done & 1) == 0;
01159 
01160     // Graphic RAM layer (or blank)
01161     // Think of it as a 3-plane GRB color graphics mode, each plane is 1 bit per pixel.
01162     // G-RAM is addressed 16 bits per RAM cycle.
01163     if (pc98_gdc[GDC_SLAVE].display_enable && ok_raster) {
01164         unsigned int disp_base;
01165         Bit8u g8,r8,b8,e8;
01166 
01167         draw = ((Bit32u*)TempLine);
01168         blocks = vga.draw.blocks;
01169         vidmem = (unsigned int)pc98_gdc[GDC_SLAVE].scan_address << 1u;
01170         disp_base = GDC_display_plane ? 0x20000U : 0x00000U;
01171 
01172         while (blocks--) {
01173             // NTS: Testing on real hardware shows that, when you switch the GDC back to 8-color mode,
01174             //      the 4th bitplane is no longer rendered.
01175             if (gdc_analog)
01176                 e8 = vga.mem.linear[(vidmem & 0x7FFFU) + 0x20000U + disp_base]; /* E0000-E7FFF */
01177             else
01178                 e8 = 0x00;
01179 
01180             g8 = vga.mem.linear[(vidmem & 0x7FFFU) + 0x18000U + disp_base]; /* B8000-BFFFF */
01181             r8 = vga.mem.linear[(vidmem & 0x7FFFU) + 0x10000U + disp_base]; /* B0000-B7FFF */
01182             b8 = vga.mem.linear[(vidmem & 0x7FFFU) + 0x08000U + disp_base]; /* A8000-AFFFF */
01183 
01184             for (unsigned char i=0;i < 8;i++) {
01185                 foreground  = (e8 & 0x80) ? 8 : 0;
01186                 foreground += (g8 & 0x80) ? 4 : 0;
01187                 foreground += (r8 & 0x80) ? 2 : 0;
01188                 foreground += (b8 & 0x80) ? 1 : 0;
01189 
01190                 e8 <<= 1;
01191                 g8 <<= 1;
01192                 r8 <<= 1;
01193                 b8 <<= 1;
01194 
01195                 *draw++ = vga.dac.xlat32[foreground];
01196             }
01197 
01198             vidmem++;
01199         }
01200     }
01201     else {
01202         memset(TempLine,0,4 * 8 * blocks);
01203     }
01204 
01205     // Text RAM layer
01206     if (pc98_gdc[GDC_MASTER].display_enable) {
01207         draw = ((Bit32u*)TempLine);
01208         blocks = vga.draw.blocks;
01209         vidmem = pc98_gdc[GDC_MASTER].scan_address;
01210         while (blocks--) { // for each character in the line
01211             /* NTS: On real hardware, in 20-line mode, either the hardware or the BIOS sets
01212              *      up the text mode in such a way that the text is centered vertically
01213              *      against the cursor, and the cursor fills all 20 lines */
01214             fline = pc98_gdc[GDC_MASTER].row_line;
01215             if (pc98_gdc[GDC_MASTER].row_height > 16) /* 20-line */
01216                 fline -= 2; /* vertically center */
01217 
01218             /* Amusing question: How does it handle the "simple graphics" in 20-line mode? */
01219 
01220             if (!doublewide) {
01221 interrupted_char_begin:
01222                 chr = ((Bit16u*)vga.mem.linear)[(vidmem & 0xFFFU) + 0x0000U];
01223                 attr = ((Bit16u*)vga.mem.linear)[(vidmem & 0xFFFU) + 0x1000U];
01224 
01225                 if (pc98_attr4_graphic && (attr & 0x10)) {
01226                     /* the "vertical line" attribute (bit 4) can be redefined as a signal
01227                      * to interpret the character as a low res bitmap instead compatible with
01228                      * "simple graphics" of the PC-8001 (ref. Carat) */
01229                     /* Contrary to what you normally expect of a "bitmap", the pixels are
01230                      * in column order.
01231                      *     0 1
01232                      *     col
01233                      *     0 4  r 0
01234                      *     1 5  o 1
01235                      *     2 6  w 2
01236                      *     3 7    3
01237                      */
01238                     /* The only way a direct bitmap can be encoded in 8 bits is if one character
01239                      * cell were 2 pixels wide 4 pixels high, and each pixel was repeated 4 times.
01240                      * In case you're wondering, the high byte doesn't appear to be used in this mode.
01241                      *
01242                      * Setting the high byte seems to blank the cell entirely */
01243                     if ((chr & 0xFF00) == 0x00) {
01244                         unsigned char bits2 = (chr >> (pc98_gdc[GDC_MASTER].row_line >> 2)) & 0x11;
01245 
01246                         font =  ((bits2 & 0x01) ? 0xF0 : 0x00) +
01247                                 ((bits2 & 0x10) ? 0x0F : 0x00);
01248                     }
01249                     else {
01250                         font = 0;
01251                     }
01252                 }
01253                 else {
01254                     // NTS: The display handles single-wide vs double-wide by whether or not the 8 bits are nonzero.
01255                     //      If zero, the char is one cell wide.
01256                     //      If nonzero, the char is two cells wide (doublewide) and the current character is rendered
01257                     //      into both cells (the character code in the next cell is ignored). The attribute (as far
01258                     //      as I know) repeats for both.
01259                     //
01260                     //      NTS: It seems different character ROM is used between single and double wide chars.
01261                     //           Contrary to what this suggests, (chr & 0xFF00) == 0x8000 is doublewide but not the
01262                     //           same as single-wide (chr & 0xFF00) == 0x0000.
01263                     //
01264                     //      Specific ranges that would be fullwidth where bits[6:0] are 0x08 to 0x0B inclusive are
01265                     //      apparently not fullwidth (the halfwidth char repeats) if both cells filled in.
01266                     if ((chr & 0xFF00) != 0 && (chr & 0x7CU) != 0x08) {
01267                         // left half of doublewide char. it appears only bits[14:8] and bits[6:0] have any real effect on which char is displayed.
01268                         doublewide = true;
01269                     }
01270 
01271                     /* the hardware appears to blank the lines beyond the 16-line cell */
01272                     if (fline < 0x10)
01273                         font = pc98_font_char_read(chr,fline,0);
01274                     else
01275                         font = 0;
01276                 }
01277             }
01278             else {
01279                 // right half of doublewide char.
01280                 //
01281                 // NTS: Strange idiosyncratic behavior observed on real hardware shows that MOST fullwidth codes
01282                 //      fill two cells and ignore the other cell, EXCEPT, that specific ranges require you to
01283                 //      enter the same fullwidth code in both cells.
01284                 doublewide = false;
01285 
01286                 // It seems that for any fullwidth char, you need the same code in both cells for bit[6:0] values
01287                 // from 0x08 to 0x0F inclusive. 0x08 to 0x0B inclusive are not fullwidth, apparently.
01288                 // Same applies 0x56 to 0x5F.
01289                 //
01290                 // Real hardware seems to show that this code will show the other half of the character IF the
01291                 // character code matches. If it does not match, then it will show the first half of the new code.
01292                 //
01293                 // This fix is needed for Touhou Project to show some level titles correctly. The reason this fix
01294                 // affects it, is that the text RAM covering the playfield is not space or any traditionally empty
01295                 // cell but a custom character code that is generally empty, but the character cell bitmap is animated
01296                 // (changed per frame) when doing fade/wipe transitions between levels. Some of the level titles
01297                 // are displayed starting at an odd column cell number, which means that the Kanji intended for
01298                 // display "interrupts" the blank custom character cell code. TH02 ~idnight bug fix.
01299                 if ((chr&0x78U) == 0x08 || (chr&0x7FU) >= 0x56) {
01300                     uint16_t n_chr;
01301 
01302                     n_chr = ((Bit16u*)vga.mem.linear)[(vidmem & 0xFFFU) + 0x0000U];
01303                     attr = ((Bit16u*)vga.mem.linear)[(vidmem & 0xFFFU) + 0x1000U];
01304 
01305                     if ((chr&0x7F7F) != (n_chr&0x7F7F))
01306                         goto interrupted_char_begin;
01307                 }
01308 
01309                 /* the hardware appears to blank the lines beyond the 16-line cell */
01310                 if (fline < 0x10)
01311                     font = pc98_font_char_read(chr,fline,1);
01312                 else
01313                     font = 0;
01314             }
01315 
01316             lineoverlay <<= 8;
01317 
01318             /* the character is not rendered if "~secret" (bit 0) is not set */
01319             if (!(attr & 1)) font = 0;
01320 
01321             /* "blink" seems to count at the same speed as the cursor blink rate,
01322              * through a 4-cycle pattern in which the character is invisible only
01323              * at the first count. */
01324             if ((attr & 0x02/*blink*/) && pc98_gdc[GDC_MASTER].cursor_blink_state == 0) font = 0;
01325 
01326             /* reverse attribute. seems to take effect BEFORE vertical & underline attributes */
01327             if (attr & 0x04/*reverse*/) font ^= 0xFF;
01328 
01329             /* based on real hardware, the cursor seems to act like a reverse attribute */
01330             if (vidmem == vga.draw.cursor.address &&
01331                 pc98_gdc[GDC_MASTER].cursor_enable &&
01332                 ((!pc98_gdc[GDC_MASTER].cursor_blink) || (pc98_gdc[GDC_MASTER].cursor_blink_state&1)) &&
01333                 (line >= vga.draw.cursor.sline) &&
01334                 (line <= vga.draw.cursor.eline)) {
01335                 font ^= 0xFF;
01336             }
01337 
01338             /* "vertical line" bit puts a vertical line on the 4th pixel of the cell */
01339             if (!pc98_attr4_graphic && (attr & 0x10)) lineoverlay |= 1U << 7U;
01340 
01341             /* underline fills the row to underline the text */
01342             if ((attr & 0x08) && line == (vga.crtc.maximum_scan_line & 0x1FU)) lineoverlay |= 0xFFU;
01343 
01344             /* lineoverlay overlays font with 4-pixel delay */
01345             font |= (unsigned char)(((unsigned int)lineoverlay >> 4u) & 0xFFU);
01346 
01347             /* color? */
01348             foreground = ((unsigned int)attr >> 5u) & 7u; /* bits[7:5] are GRB foreground color */
01349 
01350             /* draw it!
01351              * NTS: Based on real hardware (and this is probably why there's no provisions for both fore and background color)
01352              *      any bit in the font overlays the graphic output (after reverse, etc) or else does not output anything. */
01353             /* NTS: Apparently (correct me if I'm wrong) the analog color palette applies to the graphics layer, NOT the text layer. */
01354             for (Bitu n = 0; n < 8; n++) {
01355                 if (font & 0x80)
01356                     *draw++ = pc98_text_palette[foreground];
01357                 else
01358                     draw++;
01359 
01360                 font <<= 1u;
01361             }
01362 
01363             vidmem++;
01364         }
01365     }
01366 
01367     return TempLine;
01368 }
01369 
01370 static void VGA_ProcessSplit() {
01371     vga.draw.has_split = true;
01372     if (vga.attr.mode_control&0x20) {
01373         vga.draw.address=0;
01374         // reset panning to 0 here so we don't have to check for 
01375         // it in the character draw functions. It will be set back
01376         // to its proper value in v-retrace
01377         vga.draw.panning=0; 
01378     } else {
01379         // In text mode only the characters are shifted by panning, not the address;
01380         // this is done in the text line draw function. EGA/VGA planar is handled the same way.
01381         vga.draw.address = vga.draw.byte_panning_shift*vga.draw.bytes_skip;
01382         if (machine != MCH_EGA) {
01383             switch (vga.mode) {
01384                 case M_PC98:
01385                 case M_TEXT:
01386                 case M_EGA:
01387                 case M_LIN4:
01388                     /* ignore */
01389                     break;
01390                 default:
01391                     vga.draw.address += vga.draw.panning;
01392                     break;
01393             }
01394         }
01395     }
01396     vga.draw.address_line=0;
01397 }
01398 
01399 static Bit8u bg_color_index = 0; // screen-off black index
01400 static Bit8u VGA_GetBlankedIndex() {
01401     if (vga.dac.xlat16[bg_color_index] != 0) {
01402         for(Bitu i = 0; i < 256; i++)
01403             if (vga.dac.xlat16[i] == 0) {
01404                 bg_color_index = i;
01405                 break;
01406             }
01407     }
01408     return bg_color_index;
01409 }
01410 
01411 /* this is now called PER LINE because most VGA cards do not double-buffer the value.
01412  * a few demos rely on line compare schenanigans to play with the raster, as does my own VGA test program --J.C. */
01413 void VGA_Update_SplitLineCompare() {
01414     vga.draw.split_line = (vga.config.line_compare + 1) / vga.draw.render_max;
01415     if (svgaCard==SVGA_S3Trio) {
01416         /* FIXME: Is this really necessary? Is this what S3 chipsets do?
01417          *        What is supposed to happen is that line_compare == 0 on normal VGA will cause the first
01418          *        scanline to repeat twice. Do S3 chipsets NOT reproduce that quirk?
01419          *
01420          *        The other theory I have about whoever wrote this code is that they wanted to multiply
01421          *        the scan line by two but had to compensate for the line_compare+1 assignment above.
01422          *        Rather than end up with a splitscreen too far down, they did that.
01423          *
01424          *        I think the proper code to put here would be:
01425          *
01426          *        if (vga.s3.reg_42 & 0x20) {
01427          *            vga.draw.split_line--;
01428          *            vga.draw.split_line *= 2;
01429          *            vga.draw.split_line++;
01430          *        }
01431          *
01432          *        Is that right?
01433          *
01434          *        This behavior is the reason for Issue #40 "Flash productions "monstra" extra white line at top of screen"
01435          *        because it causes line compare to miss and the first scanline of the white bar appears on scanline 2,
01436          *        when the demo coder obviously intended for line_compare == 0 to repeat the first scanline twice so that
01437          *        on line 3, it can begin updating line compare to continue repeating the first scanline.
01438          *
01439          * TODO: Pull out some S3 graphics cards and check split line behavior when line_compare == 0 */
01440         if (vga.config.line_compare==0) vga.draw.split_line=0;
01441         if (vga.s3.reg_42 & 0x20) { // interlaced mode
01442             vga.draw.split_line *= 2;
01443         }
01444     }
01445     vga.draw.split_line -= vga.draw.vblank_skip;
01446 }
01447 
01448 static void VGA_DrawSingleLine(Bitu /*blah*/) {
01449     bool skiprender;
01450 
01451     if (vga.draw.render_step == 0)
01452         skiprender = false;
01453     else
01454         skiprender = true;
01455 
01456     if ((++vga.draw.render_step) >= vga.draw.render_max)
01457         vga.draw.render_step = 0;
01458 
01459     if (!skiprender) {
01460         if (GCC_UNLIKELY(vga.attr.disabled)) {
01461             switch(machine) {
01462                 case MCH_PCJR:
01463                     // Displays the border color when screen is disabled
01464                     bg_color_index = vga.tandy.border_color;
01465                     break;
01466                 case MCH_TANDY:
01467                     // Either the PCJr way or the CGA way
01468                     if (vga.tandy.gfx_control& 0x4) { 
01469                         bg_color_index = vga.tandy.border_color;
01470                     } else if (vga.mode==M_TANDY4) 
01471                         bg_color_index = vga.attr.palette[0];
01472                     else bg_color_index = 0;
01473                     break;
01474                 case MCH_CGA:
01475                     // the background color
01476                     bg_color_index = vga.attr.overscan_color;
01477                     break;
01478                 case MCH_EGA:
01479                 case MCH_VGA:
01480                 case MCH_PC98:
01481                     // DoWhackaDo, Alien Carnage, TV sports Football
01482                     // when disabled by attribute index bit 5:
01483                     //  ET3000, ET4000, Paradise display the border color
01484                     //  S3 displays the content of the currently selected attribute register
01485                     // when disabled by sequencer the screen is black "257th color"
01486 
01487                     // the DAC table may not match the bits of the overscan register
01488                     // so use black for this case too...
01489                     //if (vga.attr.disabled& 2) {
01490                     VGA_GetBlankedIndex();
01491                     //} else 
01492                     //    bg_color_index = vga.attr.overscan_color;
01493                     break;
01494                 default:
01495                     bg_color_index = 0;
01496                     break;
01497             }
01498             if (vga.draw.bpp==8) {
01499                 memset(TempLine, bg_color_index, sizeof(TempLine));
01500             } else if (vga.draw.bpp==16) {
01501                 Bit16u* wptr = (Bit16u*) TempLine;
01502                 Bit16u value = vga.dac.xlat16[bg_color_index];
01503                 for (Bitu i = 0; i < sizeof(TempLine)/2; i++) {
01504                     wptr[i] = value;
01505                 }
01506             } else if (vga.draw.bpp==32) {
01507                 Bit32u* wptr = (Bit32u*) TempLine;
01508                 Bit32u value = vga.dac.xlat32[bg_color_index];
01509                 for (Bitu i = 0; i < sizeof(TempLine)/4; i++) {
01510                     wptr[i] = value;
01511                 }
01512             }
01513 
01514             if (vga_page_flip_occurred) {
01515                 memxor(TempLine,0xFF,vga.draw.width*(vga.draw.bpp>>3));
01516                 vga_page_flip_occurred = false;
01517             }
01518             if (vga_3da_polled) {
01519                 memxor_greendotted_16bpp((uint16_t*)TempLine,(vga.draw.width>>1)*(vga.draw.bpp>>3),vga.draw.lines_done);
01520                 vga_3da_polled = false;
01521             }
01522             RENDER_DrawLine(TempLine);
01523         } else {
01524             Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
01525             if (vga_page_flip_occurred) {
01526                 memxor(data,0xFF,vga.draw.width*(vga.draw.bpp>>3));
01527                 vga_page_flip_occurred = false;
01528             }
01529             if (vga_3da_polled) {
01530                 memxor_greendotted_16bpp((uint16_t*)TempLine,(vga.draw.width>>1)*(vga.draw.bpp>>3),vga.draw.lines_done);
01531                 vga_3da_polled = false;
01532             }
01533             RENDER_DrawLine(data);
01534         }
01535     }
01536 
01537     vga.draw.address_line++;
01538     if (vga.draw.address_line>=vga.draw.address_line_total) {
01539         vga.draw.address_line=0;
01540         vga.draw.address+=vga.draw.address_add;
01541     }
01542 
01543     if (!skiprender) {
01544         vga.draw.lines_done++;
01545         if (vga.draw.split_line==vga.draw.lines_done) VGA_ProcessSplit();
01546     }
01547 
01548     if (vga.draw.lines_done < vga.draw.lines_total) {
01549         PIC_AddEvent(VGA_DrawSingleLine,(float)vga.draw.delay.singleline_delay);
01550     } else {
01551         vga_mode_frames_since_time_base++;
01552         RENDER_EndUpdate(false);
01553     }
01554 
01555     if (IS_PC98_ARCH) {
01556         for (unsigned int i=0;i < 2;i++)
01557             pc98_gdc[i].next_line();
01558     }
01559 
01560     /* some VGA cards (ATI chipsets especially) do not double-buffer the
01561      * horizontal panning register. some DOS demos take advantage of that
01562      * to make the picture "waver".
01563      *
01564      * We stop doing this though if the attribute controller is setup to set hpel=0 at splitscreen. */
01565     if (IS_VGA_ARCH && vga_enable_hpel_effects) {
01566         /* Attribute Mode Controller: If bit 5 (Pixel Panning Mode) is set, then upon line compare the bottom portion is displayed as if Pixel Shift Count and Byte Panning are set to 0.
01567          * This ensures some demos like Future Crew "Yo" display correctly instead of the bottom non-scroller half jittering because the top half is scrolling. */
01568         if (vga.draw.has_split && (vga.attr.mode_control&0x20))
01569             vga.draw.panning = 0;
01570         else
01571             vga.draw.panning = vga.config.pel_panning;
01572     }
01573 
01574     if (IS_EGAVGA_ARCH && !vga_double_buffered_line_compare) VGA_Update_SplitLineCompare();
01575 }
01576 
01577 static void VGA_DrawEGASingleLine(Bitu /*blah*/) {
01578     bool skiprender;
01579 
01580     if (vga.draw.render_step == 0)
01581         skiprender = false;
01582     else
01583         skiprender = true;
01584 
01585     if ((++vga.draw.render_step) >= vga.draw.render_max)
01586         vga.draw.render_step = 0;
01587 
01588     if (!skiprender) {
01589         if (GCC_UNLIKELY(vga.attr.disabled)) {
01590             memset(TempLine, 0, sizeof(TempLine));
01591             RENDER_DrawLine(TempLine);
01592         } else {
01593             Bitu address = vga.draw.address;
01594             if (machine != MCH_EGA) {
01595                 switch (vga.mode) {
01596                     case M_PC98:
01597                     case M_TEXT:
01598                     case M_EGA:
01599                     case M_LIN4:
01600                         /* ignore */
01601                         break;
01602                     default:
01603                         vga.draw.address += vga.draw.panning;
01604                         break;
01605                 }
01606             }
01607             Bit8u * data=VGA_DrawLine(address, vga.draw.address_line ); 
01608             RENDER_DrawLine(data);
01609         }
01610     }
01611 
01612     vga.draw.address_line++;
01613     if (vga.draw.address_line>=vga.draw.address_line_total) {
01614         vga.draw.address_line=0;
01615         vga.draw.address+=vga.draw.address_add;
01616     }
01617 
01618     if (!skiprender) {
01619         vga.draw.lines_done++;
01620         if (vga.draw.split_line==vga.draw.lines_done) VGA_ProcessSplit();
01621     }
01622 
01623     if (vga.draw.lines_done < vga.draw.lines_total) {
01624         PIC_AddEvent(VGA_DrawEGASingleLine,(float)vga.draw.delay.singleline_delay);
01625     } else {
01626         vga_mode_frames_since_time_base++;
01627         RENDER_EndUpdate(false);
01628     }
01629 }
01630 
01631 void VGA_SetBlinking(Bitu enabled) {
01632     Bitu b;
01633     LOG(LOG_VGA,LOG_NORMAL)("Blinking %d",(int)enabled);
01634     if (enabled) {
01635         b=0;vga.draw.blinking=1; //used to -1 but blinking is unsigned
01636         vga.attr.mode_control|=0x08;
01637         vga.tandy.mode_control|=0x20;
01638     } else {
01639         b=8;vga.draw.blinking=0;
01640         vga.attr.mode_control&=~0x08;
01641         vga.tandy.mode_control&=~0x20;
01642     }
01643     for (Bitu i=0;i<8;i++) TXT_BG_Table[i+8]=(b+i) | ((b+i) << 8)| ((b+i) <<16) | ((b+i) << 24);
01644 }
01645 
01646 extern bool                        GDC_vsync_interrupt;
01647 
01648 static void VGA_VertInterrupt(Bitu /*val*/) {
01649     if (IS_PC98_ARCH) {
01650         if (GDC_vsync_interrupt) {
01651             GDC_vsync_interrupt = false;
01652             PIC_ActivateIRQ(2);
01653         }
01654     }
01655     else {
01656         if ((!vga.draw.vret_triggered) && ((vga.crtc.vertical_retrace_end&0x30)==0x10)) {
01657             vga.draw.vret_triggered=true;
01658             if (GCC_UNLIKELY(machine==MCH_EGA)) PIC_ActivateIRQ(9);
01659         }
01660     }
01661 }
01662 
01663 static void VGA_Other_VertInterrupt(Bitu val) {
01664     if (val) PIC_ActivateIRQ(5);
01665     else PIC_DeActivateIRQ(5);
01666 }
01667 
01668 static void VGA_DisplayStartLatch(Bitu /*val*/) {
01669     /* hretrace fx support: store the hretrace value at start of picture so we have
01670      * a point of reference how far to displace the scanline when wavy effects are
01671      * made */
01672     vga_display_start_hretrace = vga.crtc.start_horizontal_retrace;
01673     vga.config.real_start=vga.config.display_start & vga.mem.memmask;
01674     vga.draw.bytes_skip = vga.config.bytes_skip;
01675 }
01676  
01677 static void VGA_PanningLatch(Bitu /*val*/) {
01678     vga.draw.panning = vga.config.pel_panning;
01679 
01680     if (IS_PC98_ARCH) {
01681         for (unsigned int i=0;i < 2;i++)
01682             pc98_gdc[i].begin_frame();
01683     }
01684 }
01685 
01686 static void VGA_VerticalTimer(Bitu /*val*/) {
01687     double current_time = PIC_FullIndex();
01688 
01689     GDC_display_plane = GDC_display_plane_pending;
01690 
01691     vga.draw.delay.framestart = current_time; /* FIXME: Anyone use this?? If not, remove it */
01692     vga_page_flip_occurred = false;
01693     vga.draw.has_split = false;
01694     vga_3da_polled = false;
01695 
01696     // FIXME: While this code is quite good at keeping time, I'm seeing drift "reset" back to
01697     //        14-30ms every video mode change. Is our INT 10h code that slow?
01698     /* compensate for floating point drift, make sure we're keeping the frame rate.
01699      * be very gentle about it. generally the drift is very small, and large adjustments can cause
01700      * DOS games dependent on vsync to fail/hang. */
01701     double shouldbe = (((double)vga_mode_frames_since_time_base * 1000.0) / vga_fps) + vga_mode_time_base;
01702     double vsync_err = shouldbe - current_time; /* < 0 too slow     > 0 too fast */
01703     double vsync_adj = (vsync_err < 0 ? -1 : 1) * vsync_err * vsync_err * 0.05;
01704     if (vsync_adj < -0.1) vsync_adj = -0.1;
01705     else if (vsync_adj > 0.1) vsync_adj = 0.1;
01706 
01707 //  LOG_MSG("Vsync err %.6fms adj=%.6fms",vsync_err,vsync_adj);
01708 
01709     float vsynctimerval;
01710     float vdisplayendtimerval;
01711     if( vsync.manual ) {
01712         static float hack_memory = 0.0f;
01713         if( hack_memory > 0.0f ) {
01714             uservsyncjolt+=hack_memory;
01715             hack_memory = 0.0f;
01716         }
01717 
01718         float faithful_framerate_adjustment_delay = 0.0f;
01719         if( vsync.faithful ) {
01720             static float counter = 0.0f;
01721             const float gfxmode_vsyncrate   = 1000.0f/vga.draw.delay.vtotal;
01722             const float user_vsyncrate      = 1000.0f/vsync.period;
01723             const float framerate_diff      = user_vsyncrate - gfxmode_vsyncrate;
01724             if( framerate_diff >= 0 ) {
01725                 // User vsync rate is greater than the target vsync rate
01726                 const float adjustment_deadline = gfxmode_vsyncrate / framerate_diff;
01727                 counter += 1.0f;
01728                 if(counter >= adjustment_deadline) {
01729                     // double vsync duration this frame to resynchronize with the target vsync timing
01730                     faithful_framerate_adjustment_delay = vsync.period;
01731                     counter -= adjustment_deadline;
01732                 }
01733             } else {
01734                 // User vsync rate is less than the target vsync rate
01735 
01736                 // I don't have a good solution for this right now.
01737                 // I also don't have access to a 60Hz display for proper testing.
01738                 // Making an instant vsync is more difficult than making a long vsync.. because
01739                 // the emulated app's retrace loop must be able to detect that the retrace has both
01740                 // begun and ended.  So it's not as easy as adjusting timer durations.
01741                 // I think adding a hack to cause port 3da's code to temporarily force the
01742                 // vertical retrace bit to cycle could work.. Even then, it's possible that
01743                 // some shearing could be seen when the app draws two new frames during a single
01744                 // host refresh.
01745                 // Anyway, this could be worth dealing with for console ports since they'll be
01746                 // running at either 60 or 50Hz (below 70Hz).
01747                 /*
01748                 const float adjustment_deadline = -(gfxmode_vsyncrate / framerate_diff);
01749                 counter += 1.0f;
01750                 if(counter >= adjustment_deadline) {
01751                     // nullify vsync duration this frame to resynchronize with the target vsync timing
01752                     // TODO(AUG): proper low user vsync rate synchronization
01753                     faithful_framerate_adjustment_delay = -uservsyncperiod + 1.2f;
01754                     vsync_hackval = 10;
01755                     hack_memory = -1.2f;
01756                     counter -= adjustment_deadline;
01757                 }
01758                 */
01759             }
01760         }
01761 
01762         const Bitu persistent_sync_update_interval = 100;
01763         static Bitu persistent_sync_counter = persistent_sync_update_interval;
01764         Bits current_tick = GetTicks();
01765         static Bitu jolt_tick = 0;
01766         if( uservsyncjolt > 0.0f ) {
01767             jolt_tick = (Bitu)current_tick;
01768 
01769             // set the update counter to a low value so that the user will almost
01770             // immediately see the effects of an auto-correction.  This gives the
01771             // user a chance to compensate for it.
01772             persistent_sync_counter = 50;
01773         }
01774 
01775         float real_diff = 0.0f;
01776         if( vsync.persistent ) {
01777             if( persistent_sync_counter == 0 ) {
01778                 float ticks_since_jolt = (signed long)current_tick - (signed long)jolt_tick;
01779                 double num_host_syncs_in_those_ticks = floor(ticks_since_jolt / vsync.period);
01780                 float diff_thing = ticks_since_jolt - (num_host_syncs_in_those_ticks * (double)vsync.period);
01781 
01782                 if( diff_thing > (vsync.period / 2.0f) ) real_diff = diff_thing - vsync.period;
01783                 else real_diff = diff_thing;
01784 
01785 //              LOG_MSG("diff is %f",real_diff);
01786 
01787                 if( ((real_diff > 0.0f) && (real_diff < 1.5f)) || ((real_diff < 0.0f) && (real_diff > -1.5f)) )
01788                     real_diff = 0.0f;
01789 
01790                 persistent_sync_counter = persistent_sync_update_interval;
01791             } else --persistent_sync_counter;
01792         }
01793 
01794 //      vsynctimerval       = uservsyncperiod + faithful_framerate_adjustment_delay + uservsyncjolt;
01795         vsynctimerval       = vsync.period - (real_diff/1.0f);  // formerly /2.0f
01796         vsynctimerval       += faithful_framerate_adjustment_delay + uservsyncjolt;
01797 
01798         // be sure to provide delay between end of one refresh, and start of the next
01799 //      vdisplayendtimerval = vsynctimerval - 1.18f;
01800 
01801         // be sure to provide delay between end of one refresh, and start of the next
01802         vdisplayendtimerval = vsynctimerval - (vga.draw.delay.vtotal - vga.draw.delay.vrstart);
01803 
01804         // in case some calculations above cause this.  this really shouldn't happen though.
01805         if( vdisplayendtimerval < 0.0f ) vdisplayendtimerval = 0.0f;
01806 
01807         uservsyncjolt = 0.0f;
01808     } else {
01809         // Standard vsync behaviour
01810         vsynctimerval       = (float)vga.draw.delay.vtotal;
01811         vdisplayendtimerval = (float)vga.draw.delay.vrstart;
01812     }
01813 
01814     {
01815         double fv;
01816 
01817         fv = vsynctimerval + vsync_adj;
01818         if (fv < 1) fv = 1;
01819         PIC_AddEvent(VGA_VerticalTimer,fv);
01820 
01821         fv = vdisplayendtimerval + vsync_adj;
01822         if (fv < 1) fv = 1;
01823         PIC_AddEvent(VGA_DisplayStartLatch,fv);
01824     }
01825     
01826     switch(machine) {
01827     case MCH_PCJR:
01828     case MCH_TANDY:
01829         // PCJr: Vsync is directly connected to the IRQ controller
01830         // Some earlier Tandy models are said to have a vsync interrupt too
01831         PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrstart, 1);
01832         PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrend, 0);
01833         // fall-through
01834     case MCH_AMSTRAD:
01835     case MCH_CGA:
01836     case MCH_HERC:
01837         // MC6845-powered graphics: Loading the display start latch happens somewhere
01838         // after vsync off and before first visible scanline, so probably here
01839         VGA_DisplayStartLatch(0);
01840         break;
01841     case MCH_VGA:
01842     case MCH_PC98:
01843         PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrstart);
01844         PIC_AddEvent(VGA_PanningLatch, (float)vga.draw.delay.vrend);
01845         // EGA: 82c435 datasheet: interrupt happens at display end
01846         // VGA: checked with scope; however disabled by default by jumper on VGA boards
01847         // add a little amount of time to make sure the last drawpart has already fired
01848         PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005));
01849         break;
01850     case MCH_EGA:
01851         PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrend);
01852         PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005));
01853         break;
01854     default:
01855         //E_Exit("This new machine needs implementation in VGA_VerticalTimer too.");
01856         PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrstart);
01857         PIC_AddEvent(VGA_PanningLatch, (float)vga.draw.delay.vrend);
01858         PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005));
01859         break;
01860     }
01861     // for same blinking frequency with higher frameskip
01862     vga.draw.cursor.count++;
01863 
01864     if (IS_PC98_ARCH) {
01865         for (unsigned int i=0;i < 2;i++)
01866             pc98_gdc[i].cursor_advance();
01867     }
01868 
01869     //Check if we can actually render, else skip the rest
01870     if (vga.draw.vga_override || !RENDER_StartUpdate()) return;
01871 
01872     vga.draw.address_line = vga.config.hlines_skip;
01873     if (IS_EGAVGA_ARCH) VGA_Update_SplitLineCompare();
01874     vga.draw.address = vga.config.real_start;
01875     vga.draw.byte_panning_shift = 0;
01876 
01877     switch (vga.mode) {
01878     case M_EGA:
01879         if (vga.mem.memmask >= 0x1FFFFu) {
01880             if (!(vga.crtc.mode_control&0x1u)) vga.draw.linear_mask &= ~0x10000u;
01881             else vga.draw.linear_mask |= 0x10000u;
01882         }
01883         /* fall through */
01884     case M_LIN4:
01885         vga.draw.byte_panning_shift = 4u;
01886         vga.draw.address += vga.draw.bytes_skip;
01887         vga.draw.address *= vga.draw.byte_panning_shift;
01888         break;
01889     case M_VGA:
01890         /* TODO: Various SVGA chipsets have a bit to enable/disable 256KB wrapping */
01891         vga.draw.linear_mask = 0x3ffffu;
01892         if (svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K) {
01893             if (vga.config.addr_shift == 1) /* NTS: Remember the ET4K steps by 4 pixels, one per byteplane, treats BYTE and DWORD modes the same */
01894                 vga.draw.address *= 2u;
01895         }
01896         else {
01897             vga.draw.address *= 1u<<vga.config.addr_shift; /* NTS: Remember the bizarre 4 x 4 mode most SVGA chipsets do */
01898         }
01899         /* fall through */
01900     case M_LIN8:
01901     case M_LIN15:
01902     case M_LIN16:
01903     case M_LIN24:
01904     case M_LIN32:
01905         vga.draw.byte_panning_shift = 4;
01906         vga.draw.address += vga.draw.bytes_skip;
01907         vga.draw.address *= vga.draw.byte_panning_shift;
01908         vga.draw.address += vga.draw.panning;
01909         break;
01910     case M_PC98:
01911         vga.draw.linear_mask = 0xfff; // 1 page
01912         vga.draw.byte_panning_shift = 2;
01913         vga.draw.address += vga.draw.bytes_skip;
01914         vga.draw.cursor.address = vga.config.cursor_start;
01915         break;
01916     case M_TEXT:
01917         vga.draw.byte_panning_shift = 2;
01918         vga.draw.address += vga.draw.bytes_skip;
01919         // fall-through
01920     case M_TANDY_TEXT:
01921     case M_HERC_TEXT:
01922         if (machine==MCH_HERC) vga.draw.linear_mask = 0xfff; // 1 page
01923         else if (IS_EGAVGA_ARCH) vga.draw.linear_mask = 0x7fff; // 8 pages
01924         else vga.draw.linear_mask = 0x3fff; // CGA, Tandy 4 pages
01925         if (IS_EGAVGA_ARCH)
01926             vga.draw.cursor.address=vga.config.cursor_start<<vga.config.addr_shift;
01927         else
01928             vga.draw.cursor.address=vga.config.cursor_start*2;
01929         vga.draw.address *= 2;
01930 
01931         /* check for blinking and blinking change delay */
01932         FontMask[1]=(vga.draw.blinking & (unsigned int)(vga.draw.cursor.count >> 4u)) ?
01933             0 : 0xffffffff;
01934         /* if blinking is enabled, 'blink' will toggle between true
01935          * and false. Otherwise it's true */
01936         vga.draw.blink = ((vga.draw.blinking & (unsigned int)(vga.draw.cursor.count >> 4u))
01937             || !vga.draw.blinking) ? true:false;
01938         break;
01939     case M_HERC_GFX:
01940     case M_CGA4:
01941     case M_CGA2:
01942         vga.draw.address=(vga.draw.address*2u)&0x1fffu;
01943         break;
01944     case M_AMSTRAD: // Base address: No difference?
01945         vga.draw.address=(vga.draw.address*2u)&0xffffu;
01946         break;
01947     case M_CGA16:
01948     case M_TANDY2:case M_TANDY4:case M_TANDY16:
01949         vga.draw.address *= 2u;
01950         break;
01951     default:
01952         break;
01953     }
01954 
01955     /* ET4000 High Sierra DAC programs can change SVGA mode */
01956     if ((vga.mode == M_LIN15 || vga.mode == M_LIN16) && (svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K)) {
01957         if (et4k_highcolor_half_pixel_rate())
01958             VGA_DrawLine=VGA_Draw_LIN16_Line_2x;
01959         else
01960             VGA_DrawLine=VGA_Draw_LIN16_Line_HWMouse;
01961     }
01962 
01963     // check if some lines at the top off the screen are blanked
01964     float draw_skip = 0.0;
01965     if (GCC_UNLIKELY(vga.draw.vblank_skip > 0)) {
01966         draw_skip = (float)(vga.draw.delay.htotal * vga.draw.vblank_skip);
01967         vga.draw.address_line += (vga.draw.vblank_skip % vga.draw.address_line_total);
01968         vga.draw.address += vga.draw.address_add * (vga.draw.vblank_skip / vga.draw.address_line_total);
01969     }
01970 
01971     /* do VGA split now if line compare <= 0. NTS: vga.draw.split_line is defined as Bitu (unsigned integer) so we need the typecast. */
01972     if (GCC_UNLIKELY((Bits)vga.draw.split_line <= 0)) {
01973         VGA_ProcessSplit();
01974 
01975         /* if vblank_skip != 0, line compare can become a negative value! Fixes "Warlock" 1992 demo by Warlock */
01976         if (GCC_UNLIKELY((Bits)vga.draw.split_line < 0)) {
01977             vga.draw.address_line += (Bitu)(-((Bits)vga.draw.split_line) % (Bits)vga.draw.address_line_total);
01978             vga.draw.address += vga.draw.address_add * (Bitu)(-((Bits)vga.draw.split_line) / (Bits)vga.draw.address_line_total);
01979         }
01980     }
01981 
01982     // add the draw event
01983     switch (vga.draw.mode) {
01984     case LINE:
01985     case EGALINE:
01986         if (GCC_UNLIKELY(vga.draw.lines_done < vga.draw.lines_total)) {
01987             LOG(LOG_VGAMISC,LOG_NORMAL)( "Lines left: %d", 
01988                 (int)(vga.draw.lines_total-vga.draw.lines_done));
01989             if (vga.draw.mode==EGALINE) PIC_RemoveEvents(VGA_DrawEGASingleLine);
01990             else PIC_RemoveEvents(VGA_DrawSingleLine);
01991             vga_mode_frames_since_time_base++;
01992             RENDER_EndUpdate(true);
01993         }
01994         vga.draw.lines_done = 0;
01995         if (vga.draw.mode==EGALINE)
01996             PIC_AddEvent(VGA_DrawEGASingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip));
01997         else PIC_AddEvent(VGA_DrawSingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip));
01998         break;
01999     }
02000 }
02001 
02002 void VGA_CheckScanLength(void) {
02003     switch (vga.mode) {
02004     case M_EGA:
02005     case M_LIN4:
02006         if ((machine==MCH_EGA)&&(vga.crtc.mode_control&0x8))
02007             vga.draw.address_add=vga.config.scan_len*16;
02008         else
02009             vga.draw.address_add=vga.config.scan_len*8;
02010 
02011         if (IS_EGA_ARCH && (vga.seq.clocking_mode&4))
02012             vga.draw.address_add*=2;
02013         break;
02014     case M_VGA:
02015     case M_LIN8:
02016     case M_LIN15:
02017     case M_LIN16:
02018     case M_LIN24:
02019     case M_LIN32:
02020         if (vga.mode == M_VGA) {
02021             if (svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K) {
02022                 /* Observed ET4000AX behavior:
02023                  *    byte mode OR dword mode scans 256-color 4-pixel groups byte by byte from
02024                  *    planar RAM. word mode scans every other byte (skips by two).
02025                  *    We can just scan the buffer normally as linear because of the address
02026                  *    translation carried out by the ET4000 in chained mode:
02027                  *
02028                  *    plane = (addr & 3)   addr = (addr >> 2)
02029                  *
02030                  *    TODO: Validate that this is correct. */
02031                 vga.draw.address_add=vga.config.scan_len*((vga.config.addr_shift == 1)?16:8);
02032             }
02033             else {
02034                 /* Most (almost ALL) VGA clones render chained modes as 4 8-bit planes one DWORD apart.
02035                  * They all act as if writes to chained VGA memory are translated as:
02036                  * addr = ((addr & ~3) << 2) + (addr & 3) */
02037                 vga.draw.address_add=(unsigned int)vga.config.scan_len*((unsigned int)(2*4)<<(unsigned int)vga.config.addr_shift);
02038             }
02039         }
02040         else {
02041             /* the rest (SVGA modes) can be rendered with sanity */
02042             vga.draw.address_add=vga.config.scan_len*(unsigned int)(2u<<vga.config.addr_shift);
02043         }
02044         break;
02045     case M_PC98:
02046         vga.draw.address_add=vga.draw.blocks;
02047         break;
02048     case M_TEXT:
02049     case M_CGA2:
02050     case M_CGA4:
02051     case M_CGA16:
02052     case M_AMSTRAD: // Next line.
02053         if (IS_EGAVGA_ARCH || IS_PC98_ARCH)
02054             vga.draw.address_add=vga.config.scan_len*(unsigned int)(2u<<vga.config.addr_shift);
02055         else
02056             vga.draw.address_add=vga.draw.blocks;
02057         break;
02058     case M_TANDY2:
02059         vga.draw.address_add=vga.draw.blocks/4u;
02060         break;
02061     case M_TANDY4:
02062         vga.draw.address_add=vga.draw.blocks;
02063         break;
02064     case M_TANDY16:
02065         vga.draw.address_add=vga.draw.blocks;
02066         break;
02067     case M_TANDY_TEXT:
02068         vga.draw.address_add=vga.draw.blocks*2;
02069         break;
02070     case M_HERC_TEXT:
02071         vga.draw.address_add=vga.draw.blocks*2;
02072         break;
02073     case M_HERC_GFX:
02074         vga.draw.address_add=vga.draw.blocks;
02075         break;
02076     default:
02077         vga.draw.address_add=vga.draw.blocks*8;
02078         break;
02079     }
02080 }
02081 
02082 void VGA_ActivateHardwareCursor(void) {
02083     bool hwcursor_active=false;
02084     if (svga.hardware_cursor_active) {
02085         if (svga.hardware_cursor_active()) hwcursor_active=true;
02086     }
02087     if (hwcursor_active && vga.mode != M_LIN24) {
02088         switch(vga.mode) {
02089         case M_LIN32:
02090             VGA_DrawLine=VGA_Draw_LIN32_Line_HWMouse;
02091             break;
02092         case M_LIN15:
02093         case M_LIN16:
02094             if ((svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K) && et4k_highcolor_half_pixel_rate())
02095                 VGA_DrawLine=VGA_Draw_LIN16_Line_2x;
02096             else
02097                 VGA_DrawLine=VGA_Draw_LIN16_Line_HWMouse;
02098             break;
02099         case M_LIN8:
02100             VGA_DrawLine=VGA_Draw_VGA_Line_Xlat32_HWMouse;
02101             break;
02102         default:
02103             VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse;
02104             break;
02105         }
02106     } else {
02107         switch(vga.mode) {
02108         case M_LIN8:
02109             VGA_DrawLine=VGA_Draw_Xlat32_Linear_Line;
02110             break;
02111         case M_LIN24:
02112             VGA_DrawLine=VGA_Draw_Linear_Line_24_to_32;
02113             break;
02114 #if SDL_BYTEORDER == SDL_LIL_ENDIAN && defined(MACOSX) /* Mac OS X Intel builds use a weird RGBA order (alpha in the low 8 bits) */
02115         case M_LIN32:
02116             VGA_DrawLine=VGA_Draw_LIN32_Line_HWMouse;
02117             break;
02118 #endif
02119         default:
02120             VGA_DrawLine=VGA_Draw_Linear_Line;
02121             break;
02122         }
02123     }
02124 }
02125 
02126 void VGA_SetupDrawing(Bitu /*val*/) {
02127     if (vga.mode==M_ERROR) {
02128         PIC_RemoveEvents(VGA_VerticalTimer);
02129         PIC_RemoveEvents(VGA_PanningLatch);
02130         PIC_RemoveEvents(VGA_DisplayStartLatch);
02131         return;
02132     }
02133     // user choosable special trick support
02134     // multiscan -- zooming effects - only makes sense if linewise is enabled
02135     // linewise -- scan display line by line instead of 4 blocks
02136     // keep compatibility with other builds of DOSBox for vgaonly.
02137     vga.draw.doublescan_effect = true;
02138     vga.draw.render_step = 0;
02139     vga.draw.render_max = 1;
02140 
02141     // set the drawing mode
02142     switch (machine) {
02143     case MCH_CGA:
02144     case MCH_PCJR:
02145     case MCH_TANDY:
02146         vga.draw.mode = LINE;
02147         break;
02148     case MCH_EGA:
02149         // Note: The Paradise SVGA uses the same panning mechanism as EGA
02150         vga.draw.mode = EGALINE;
02151         break;
02152     case MCH_VGA:
02153     case MCH_PC98:
02154         if (svgaCard==SVGA_None) {
02155             vga.draw.mode = LINE;
02156             break;
02157         }
02158         // fall-through
02159     default:
02160         vga.draw.mode = LINE;
02161         break;
02162     }
02163     
02164     /* Calculate the FPS for this screen */
02165     Bitu oscclock = 0, clock;
02166     Bitu htotal, hdend, hbstart, hbend, hrstart, hrend;
02167     Bitu vtotal, vdend, vbstart, vbend, vrstart, vrend;
02168     Bitu hbend_mask, vbend_mask;
02169     Bitu vblank_skip;
02170 
02171     /* NTS: PC-98 emulation re-uses VGA state FOR NOW.
02172      *      This will slowly change to accomodate PC-98 display controller over time
02173      *      and IS_PC98_ARCH will become it's own case statement. */
02174 
02175     if (IS_PC98_ARCH) {
02176         hdend = pc98_gdc[GDC_MASTER].active_display_words_per_line;
02177         hbstart = hdend;
02178         hrstart = hdend + pc98_gdc[GDC_MASTER].horizontal_front_porch_width;
02179         hrend = hrstart + pc98_gdc[GDC_MASTER].horizontal_sync_width;
02180         htotal = hrend + pc98_gdc[GDC_MASTER].horizontal_back_porch_width;
02181         hbend = htotal;
02182 
02183         vdend = pc98_gdc[GDC_MASTER].active_display_lines;
02184         vbstart = vdend;
02185         vrstart = vdend + pc98_gdc[GDC_MASTER].vertical_front_porch_width;
02186         vrend = vrstart + pc98_gdc[GDC_MASTER].vertical_sync_width;
02187         vtotal = vrend + pc98_gdc[GDC_MASTER].vertical_back_porch_width;
02188         vbend = vtotal;
02189 
02190         // perhaps if the game makes a custom mode, it might choose different active display regions
02191         // for text and graphics. allow that here.
02192         // NTS: Remember that the graphics (slave) GDC is programmed in "words" which in graphics mode
02193         //      means 16-pixel wide units.
02194         if (hdend < (pc98_gdc[GDC_SLAVE].active_display_words_per_line * 2U))
02195             hdend = (pc98_gdc[GDC_SLAVE].active_display_words_per_line * 2U);
02196         if (vdend < (pc98_gdc[GDC_SLAVE].active_display_lines))
02197             vdend = (pc98_gdc[GDC_SLAVE].active_display_lines);
02198 
02199         // TODO: The GDC rendering should allow different active display regions to render
02200         //       properly over one another.
02201 
02202         // TODO: Found a monitor document that lists two different scan rates for PC-98:
02203         //
02204         //       640x400  25.175MHz dot clock  70.15Hz refresh  31.5KHz horizontal refresh (basically, VGA)
02205         //       640x400  21.05MHz dot clock   56.42Hz refresh  24.83Hz horizontal refresh (original spec?)
02206 
02207         if (false/*future 15KHz hsync*/) {
02208             oscclock = 14318180;
02209         }
02210         else if (!pc98_31khz_mode/*24KHz hsync*/) {
02211             oscclock = 21052600;
02212         }
02213         else {/*31KHz VGA-like hsync*/
02214             oscclock = 25175000;
02215         }
02216 
02217         clock = oscclock / 8;
02218     }
02219     else if (IS_EGAVGA_ARCH) {
02220         htotal = vga.crtc.horizontal_total;
02221         hdend = vga.crtc.horizontal_display_end;
02222         hbend = vga.crtc.end_horizontal_blanking&0x1F;
02223         hbstart = vga.crtc.start_horizontal_blanking;
02224         hrstart = vga.crtc.start_horizontal_retrace;
02225 
02226         vtotal= vga.crtc.vertical_total | ((vga.crtc.overflow & 1u) << 8u);
02227         vdend = vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2u) << 7u);
02228         vbstart = vga.crtc.start_vertical_blanking | ((vga.crtc.overflow & 0x08u) << 5u);
02229         vrstart = vga.crtc.vertical_retrace_start + ((vga.crtc.overflow & 0x04u) << 6u);
02230         
02231         if (IS_VGA_ARCH || IS_PC98_ARCH) {
02232             // additional bits only present on vga cards
02233             htotal |= (vga.s3.ex_hor_overflow & 0x1u) << 8u;
02234             htotal += 3u;
02235             hdend |= (vga.s3.ex_hor_overflow & 0x2u) << 7u;
02236             hbend |= (vga.crtc.end_horizontal_retrace&0x80u) >> 2u;
02237             hbstart |= (vga.s3.ex_hor_overflow & 0x4u) << 6u;
02238             hrstart |= (vga.s3.ex_hor_overflow & 0x10u) << 4u;
02239             hbend_mask = 0x3fu;
02240             
02241             vtotal |= (vga.crtc.overflow & 0x20u) << 4u;
02242             vtotal |= (vga.s3.ex_ver_overflow & 0x1u) << 10u;
02243             vdend |= (vga.crtc.overflow & 0x40u) << 3u; 
02244             vdend |= (vga.s3.ex_ver_overflow & 0x2u) << 9u;
02245             vbstart |= (vga.crtc.maximum_scan_line & 0x20u) << 4u;
02246             vbstart |= (vga.s3.ex_ver_overflow & 0x4u) << 8u;
02247             vrstart |= ((vga.crtc.overflow & 0x80u) << 2u);
02248             vrstart |= (vga.s3.ex_ver_overflow & 0x10u) << 6u;
02249             vbend_mask = 0xffu;
02250         } else { // EGA
02251             hbend_mask = 0x1fu;
02252             vbend_mask = 0x1fu;
02253         }
02254         htotal += 2;
02255         vtotal += 2;
02256         hdend += 1;
02257         vdend += 1;
02258 
02259         // horitzontal blanking
02260         if (hbend <= (hbstart & hbend_mask)) hbend += hbend_mask + 1;
02261         hbend += hbstart - (hbstart & hbend_mask);
02262         
02263         // horizontal retrace
02264         hrend = vga.crtc.end_horizontal_retrace & 0x1f;
02265         if (hrend <= (hrstart&0x1f)) hrend += 32;
02266         hrend += hrstart - (hrstart&0x1f);
02267         if (hrend > hbend) hrend = hbend; // S3 BIOS (???)
02268         
02269         // vertical retrace
02270         vrend = vga.crtc.vertical_retrace_end & 0xf;
02271         if (vrend <= (vrstart&0xf)) vrend += 16;
02272         vrend += vrstart - (vrstart&0xf);
02273 
02274         // vertical blanking
02275         vbend = vga.crtc.end_vertical_blanking & vbend_mask;
02276         if (vbstart != 0) {
02277         // Special case vbstart==0:
02278         // Most graphics cards agree that lines zero to vbend are
02279         // blanked. ET4000 doesn't blank at all if vbstart==vbend.
02280         // ET3000 blanks lines 1 to vbend (255/6 lines).
02281             vbstart += 1;
02282             if (vbend <= (vbstart & vbend_mask)) vbend += vbend_mask + 1;
02283             vbend += vbstart - (vbstart & vbend_mask);
02284         }
02285         vbend++;
02286 
02287         // TODO: Found a monitor document that lists two different scan rates for PC-98:
02288         //
02289         //       640x400  25.175MHz dot clock  70.15Hz refresh  31.5KHz horizontal refresh (basically, VGA)
02290         //       640x400  21.05MHz dot clock   56.42Hz refresh  24.83Hz horizontal refresh (original spec?)
02291 
02292         if (svga.get_clock) {
02293             oscclock = svga.get_clock();
02294         } else if (vga.mode == M_PC98) {
02295             if (false/*future 15KHz hsync*/) {
02296                 oscclock = 14318180;
02297             }
02298             else if (!pc98_31khz_mode/*24KHz hsync*/) {
02299                 oscclock = 21052600;
02300             }
02301             else {/*31KHz VGA-like hsync*/
02302                 oscclock = 25175000;
02303             }
02304         } else {
02305             switch ((vga.misc_output >> 2) & 3) {
02306             case 0: 
02307                 oscclock = (machine==MCH_EGA) ? (PIT_TICK_RATE*12) : 25175000;
02308                 break;
02309             case 1:
02310             default:
02311                 oscclock = (machine==MCH_EGA) ? 16257000 : 28322000;
02312                 break;
02313             }
02314         }
02315 
02316         /* Check for 8 or 9 character clock mode */
02317         if (vga.seq.clocking_mode & 1 ) clock = oscclock/8; else clock = oscclock/9;
02318         if (vga.mode==M_LIN15 || vga.mode==M_LIN16) clock *= 2;
02319         /* Check for pixel doubling, master clock/2 */
02320         if (vga.seq.clocking_mode & 0x8) clock /=2;
02321 
02322         if (svgaCard==SVGA_S3Trio) {
02323             // support for interlacing used by the S3 BIOS and possibly other drivers
02324             if (vga.s3.reg_42 & 0x20) {
02325                 vtotal *= 2;    vdend *= 2;
02326                 vbstart *= 2;   vbend *= 2;
02327                 vrstart *= 2;   vrend *= 2;
02328                 //clock /= 2;
02329         }
02330         }
02331 
02332         /* FIXME: This is based on correcting the hicolor mode for MFX/Transgression 2.
02333          *        I am not able to test against the Windows drivers at this time. */
02334         if ((svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K) && et4k_highcolor_half_pixel_rate())
02335             clock /= 2;
02336     } else {
02337         // not EGAVGA_ARCH
02338         vga.draw.split_line = 0x10000;  // don't care
02339 
02340         htotal = vga.other.htotal + 1u;
02341         hdend = vga.other.hdend;
02342         hbstart = hdend;
02343         hbend = htotal;
02344         hrstart = vga.other.hsyncp;
02345         hrend = hrstart + (vga.other.hsyncw) ;
02346 
02347         vga.draw.address_line_total = vga.other.max_scanline + 1u;
02348         vtotal = vga.draw.address_line_total * (vga.other.vtotal+1u)+vga.other.vadjust;
02349         vdend = vga.draw.address_line_total * vga.other.vdend;
02350         vrstart = vga.draw.address_line_total * vga.other.vsyncp;
02351         vrend = vrstart + 16; // vsync width is fixed to 16 lines on the MC6845 TODO Tandy
02352         vbstart = vdend;
02353         vbend = vtotal;
02354 
02355         switch (machine) {
02356         case MCH_AMSTRAD:
02357             clock=(16000000/2)/8;
02358             break;
02359         case MCH_CGA:
02360         case TANDY_ARCH_CASE:
02361             clock = (PIT_TICK_RATE*12)/8;
02362             if (!(vga.tandy.mode_control & 1)) clock /= 2;
02363             break;
02364         case MCH_HERC:
02365             clock=16000000/8;
02366             if (vga.herc.mode_control & 0x2) clock/=2;
02367 
02368             break;
02369         default:
02370             clock = (PIT_TICK_RATE*12);
02371             break;
02372         }
02373         vga.draw.delay.hdend = hdend*1000.0/clock; //in milliseconds
02374     }
02375 #if C_DEBUG
02376     LOG(LOG_VGA,LOG_NORMAL)("h total %3d end %3d blank (%3d/%3d) retrace (%3d/%3d)",
02377         (int)htotal, (int)hdend, (int)hbstart, (int)hbend, (int)hrstart, (int)hrend );
02378     LOG(LOG_VGA,LOG_NORMAL)("v total %3d end %3d blank (%3d/%3d) retrace (%3d/%3d)",
02379         (int)vtotal, (int)vdend, (int)vbstart, (int)vbend, (int)vrstart, (int)vrend );
02380 #endif
02381     if (!htotal) return;
02382     if (!vtotal) return;
02383     
02384     // The screen refresh frequency
02385     double fps;
02386     extern double vga_force_refresh_rate;
02387     if (vga_force_refresh_rate > 0) {
02388         /* force the VGA refresh rate by setting fps and bending the clock to our will */
02389         LOG(LOG_VGA,LOG_NORMAL)("VGA forced refresh rate in effect, %.3f",vga_force_refresh_rate);
02390         fps=vga_force_refresh_rate;
02391         clock=((double)(vtotal*htotal))*fps;
02392     }
02393     else {
02394         // The screen refresh frequency
02395         fps=(double)clock/(vtotal*htotal);
02396         LOG(LOG_VGA,LOG_NORMAL)("VGA refresh rate is now, %.3f",fps);
02397     }
02398 
02399     /* clip display end to stay within vtotal ("Monolith" demo part 4 320x570 mode fix) */
02400     if (vdend > vtotal) {
02401         LOG(LOG_VGA,LOG_WARN)("VGA display end greater than vtotal!");
02402         vdend = vtotal;
02403     }
02404 
02405     // Horizontal total (that's how long a line takes with whistles and bells)
02406     vga.draw.delay.htotal = htotal*1000.0/clock; //in milliseconds
02407     // Start and End of horizontal blanking
02408     vga.draw.delay.hblkstart = hbstart*1000.0/clock; //in milliseconds
02409     vga.draw.delay.hblkend = hbend*1000.0/clock; 
02410     // Start and End of horizontal retrace
02411     vga.draw.delay.hrstart = hrstart*1000.0/clock;
02412     vga.draw.delay.hrend = hrend*1000.0/clock;
02413     // Start and End of vertical blanking
02414     vga.draw.delay.vblkstart = vbstart * vga.draw.delay.htotal;
02415     vga.draw.delay.vblkend = vbend * vga.draw.delay.htotal;
02416     // Start and End of vertical retrace pulse
02417     vga.draw.delay.vrstart = vrstart * vga.draw.delay.htotal;
02418     vga.draw.delay.vrend = vrend * vga.draw.delay.htotal;
02419 
02420     // Vertical blanking tricks
02421     vblank_skip = 0;
02422     if ((IS_VGA_ARCH || IS_PC98_ARCH) && !ignore_vblank_wraparound) { // others need more investigation
02423         if (vbstart < vtotal) { // There will be no blanking at all otherwise
02424             if (vbend > vtotal) {
02425                 // blanking wraps to the start of the screen
02426                 vblank_skip = vbend&0x7f;
02427                 
02428                 // on blanking wrap to 0, the first line is not blanked
02429                 // this is used by the S3 BIOS and other S3 drivers in some SVGA modes
02430                 if ((vbend&0x7f)==1) vblank_skip = 0;
02431                 
02432                 // it might also cut some lines off the bottom
02433                 if (vbstart < vdend) {
02434                     vdend = vbstart;
02435                 }
02436                 LOG(LOG_VGA,LOG_WARN)("Blanking wrap to line %d", (int)vblank_skip);
02437             } else if (vbstart<=1) {
02438                 // blanking is used to cut lines at the start of the screen
02439                 vblank_skip = vbend;
02440                 LOG(LOG_VGA,LOG_WARN)("Upper %d lines of the screen blanked", (int)vblank_skip);
02441             } else if (vbstart < vdend) {
02442                 if (vbend < vdend) {
02443                     // the game wants a black bar somewhere on the screen
02444                     LOG(LOG_VGA,LOG_WARN)("Unsupported blanking: line %d-%d",(int)vbstart,(int)vbend);
02445                 } else {
02446                     // blanking is used to cut off some lines from the bottom
02447                     vdend = vbstart;
02448                 }
02449             }
02450             vdend -= vblank_skip;
02451         }
02452     }
02453     vga.draw.vblank_skip = vblank_skip;
02454 
02455     // Display end
02456     vga.draw.delay.vdend = vdend * vga.draw.delay.htotal;
02457 
02458     // EGA frequency dependent monitor palette
02459     if (machine == MCH_EGA) {
02460         if (vga.misc_output & 1) {
02461             // EGA card is in color mode
02462             if ((1.0f/vga.draw.delay.htotal) > 19.0f) {
02463                 // 64 color EGA mode
02464                 VGA_ATTR_SetEGAMonitorPalette(EGA);
02465             } else {
02466                 // 16 color CGA mode compatibility
02467                 VGA_ATTR_SetEGAMonitorPalette(CGA);
02468             }
02469         } else {
02470             // EGA card in monochrome mode
02471             // It is not meant to be autodetected that way, you either
02472             // have a monochrome or color monitor connected and
02473             // the EGA switches configured appropriately.
02474             // But this would only be a problem if a program sets 
02475             // the adapter to monochrome mode and still expects color output.
02476             // Such a program should be shot to the moon...
02477             VGA_ATTR_SetEGAMonitorPalette(MONO);
02478         }
02479     }
02480 
02481     /*
02482       6  Horizontal Sync Polarity. Negative if set
02483       7  Vertical Sync Polarity. Negative if set
02484          Bit 6-7 indicates the number of lines on the display:
02485             1:  400, 2: 350, 3: 480
02486     */
02487     //Try to determine the pixel size, aspect correct is based around square pixels
02488 
02489     //Base pixel width around 100 clocks horizontal
02490     //For 9 pixel text modes this should be changed, but we don't support that anyway :)
02491     //Seems regular vga only listens to the 9 char pixel mode with character mode enabled
02492     //Base pixel height around vertical totals of modes that have 100 clocks horizontal
02493     //Different sync values gives different scaling of the whole vertical range
02494     //VGA monitor just seems to thighten or widen the whole vertical range
02495 
02496     vga.draw.resizing=false;
02497     vga.draw.has_split=false;
02498     vga.draw.vret_triggered=false;
02499 
02500     //Check to prevent useless black areas
02501     if (hbstart<hdend) hdend=hbstart;
02502     if ((!(IS_VGA_ARCH || IS_PC98_ARCH)) && (vbstart<vdend)) vdend=vbstart;
02503 
02504     Bitu width=hdend;
02505     Bitu height=vdend;
02506 
02507     if (IS_EGAVGA_ARCH || IS_PC98_ARCH) {
02508         vga.draw.address_line_total=(vga.crtc.maximum_scan_line&0x1fu)+1u;
02509         switch(vga.mode) {
02510         case M_CGA16:
02511         case M_CGA2:
02512         case M_CGA4:
02513         case M_PC98:
02514         case M_TEXT:
02515             // these use line_total internal
02516             // doublescanning needs to be emulated by renderer doubleheight
02517             // EGA has no doublescanning bit at 0x80
02518             if (vga.crtc.maximum_scan_line&0x80) {
02519                 // vga_draw only needs to draw every second line
02520                 height /= 2;
02521             }
02522             break;
02523         default:
02524             vga.draw.doublescan_effect = vga.draw.doublescan_set;
02525 
02526             if (vga.crtc.maximum_scan_line & 0x80)
02527                 vga.draw.address_line_total *= 2;
02528 
02529             /* if doublescan=false and line_total is even, then halve the height.
02530              * the VGA raster scan will skip every other line to accomodate that. */
02531             if ((!vga.draw.doublescan_effect) && (vga.draw.address_line_total & 1) == 0)
02532                 height /= 2;
02533             else
02534                 vga.draw.doublescan_effect = true;
02535 
02536             break;
02537         }
02538     }
02539 
02540     if (!vga.draw.doublescan_effect)
02541         vga.draw.render_max = 2; /* count all lines but render only every other line */
02542 
02543     //Set the bpp
02544     Bitu bpp;
02545     switch (vga.mode) {
02546     case M_LIN15:
02547         bpp = 15;
02548         break;
02549     case M_LIN16:
02550         bpp = 16;
02551         break;
02552     case M_LIN24:
02553     case M_LIN32:
02554         bpp = 32;
02555         break;
02556     default:
02557         bpp = 8;
02558         break;
02559     }
02560     vga.draw.linear_base = vga.mem.linear;
02561     vga.draw.linear_mask = vga.mem.memmask;
02562     vga.draw.planar_mask = vga.draw.linear_mask >> 2;
02563     Bitu pix_per_char = 8;
02564     switch (vga.mode) {
02565     case M_VGA:
02566         // hack for tgr2 -hc high color mode demo
02567         if (vga.dac.reg02==0x80) {
02568             bpp=16;
02569             vga.mode=M_LIN16;
02570             VGA_SetupHandlers();
02571             VGA_DrawLine=VGA_Draw_LIN16_Line_2x;
02572             pix_per_char = 4;
02573             break;
02574         }
02575         bpp = 32;
02576         pix_per_char = 4;
02577         if (vga.mode == M_VGA && (svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K)) {
02578             /* ET4000 chipsets handle the chained mode (in my opinion) with sanity and we can scan linearly for it.
02579              * Chained VGA mode maps planar byte addr = (addr >> 2) and plane = (addr & 3) */
02580             VGA_DrawLine = VGA_Draw_Xlat32_Linear_Line;
02581         }
02582         else {
02583             /* other SVGA chipsets appear to handle chained mode by writing 4 pixels to 4 planes, and showing
02584              * only every 4th byte, which is why when you switch the CRTC to byte or word mode on these chipsets,
02585              * you see 16-pixel groups with 4 pixels from the chained display you expect followed by 12 pixels
02586              * of whatever contents of memory remain. but when you unchain the bitplanes the card will allow
02587              * "planar" writing to all 16 pixels properly. Chained VGA maps like planar byte = (addr & ~3) and
02588              * plane = (addr & 3) */
02589             VGA_DrawLine = VGA_Draw_Xlat32_VGA_CRTC_bmode_Line;
02590         }
02591         break;
02592     case M_LIN8:
02593         bpp = 32;
02594         VGA_DrawLine = VGA_Draw_Xlat32_Linear_Line;
02595 
02596         if ((vga.s3.reg_3a & 0x10)||(svgaCard!=SVGA_S3Trio))
02597             pix_per_char = 8; // TODO fiddle out the bits for other svga cards
02598         else
02599             pix_per_char = 4;
02600 
02601         VGA_ActivateHardwareCursor();
02602         break;
02603     case M_LIN24:
02604     case M_LIN32:
02605         VGA_ActivateHardwareCursor();
02606         break;
02607     case M_LIN15:
02608     case M_LIN16:
02609         pix_per_char = 4; // 15/16 bpp modes double the horizontal values
02610         VGA_ActivateHardwareCursor();
02611         break;
02612     case M_LIN4:
02613     case M_EGA:
02614         vga.draw.blocks = width;
02615 
02616         if (IS_EGA_ARCH) {
02617             VGA_DrawLine = EGA_Draw_VGA_Planar_Xlat8_Line;
02618             bpp = 8;
02619         }
02620         else {
02621             VGA_DrawLine = VGA_Draw_VGA_Planar_Xlat32_Line;
02622             bpp = 32;
02623         }
02624         break;
02625     case M_CGA16:
02626         vga.draw.blocks=width*2;
02627         pix_per_char = 16;
02628         VGA_DrawLine=VGA_Draw_CGA16_Line;
02629         break;
02630     case M_CGA4:
02631         if (IS_EGA_ARCH) {
02632             vga.draw.blocks=width;
02633             VGA_DrawLine=EGA_Draw_2BPP_Line_as_EGA;
02634             bpp = 8;
02635         }
02636         else if (IS_EGAVGA_ARCH || IS_PC98_ARCH) {
02637             vga.draw.blocks=width;
02638             VGA_DrawLine=VGA_Draw_2BPP_Line_as_VGA;
02639             bpp = 32;
02640         }
02641         else {
02642             vga.draw.blocks=width*2;
02643             VGA_DrawLine=VGA_Draw_2BPP_Line;
02644         }
02645         break;
02646     case M_CGA2:
02647         if (IS_EGA_ARCH) {
02648             vga.draw.blocks=width;
02649             VGA_DrawLine=EGA_Draw_1BPP_Line_as_EGA;
02650             bpp = 8;
02651         }
02652         else if (IS_EGAVGA_ARCH || IS_PC98_ARCH) {
02653             vga.draw.blocks=width;
02654             VGA_DrawLine=VGA_Draw_1BPP_Line_as_VGA;
02655             bpp = 32;
02656         }
02657         else {
02658             vga.draw.blocks=width*2;
02659             VGA_DrawLine=VGA_Draw_1BPP_Line;
02660         }
02661         break;
02662     case M_PC98:
02663         vga.draw.blocks=width;
02664         vga.draw.char9dot = false;
02665         VGA_DrawLine=VGA_PC98_Xlat32_Draw_Line;
02666         bpp = 32;
02667         break;
02668     case M_TEXT:
02669         vga.draw.blocks=width;
02670         // if char9_set is true, allow 9-pixel wide fonts
02671         if ((vga.seq.clocking_mode&0x01) || !vga.draw.char9_set) {
02672             // 8-pixel wide
02673             pix_per_char = 8;
02674             vga.draw.char9dot = false;
02675         } else {
02676             // 9-pixel wide
02677             pix_per_char = 9;
02678             vga.draw.char9dot = true;
02679         }
02680 
02681         if (IS_EGA_ARCH) {
02682             VGA_DrawLine = EGA_TEXT_Xlat8_Draw_Line;
02683             bpp = 8;
02684         }
02685         else {
02686             VGA_DrawLine = VGA_TEXT_Xlat32_Draw_Line;
02687             bpp = 32;
02688         }
02689         break;
02690     case M_HERC_GFX:
02691         vga.draw.blocks=width*2;
02692         pix_per_char = 16;
02693         if (vga.herc.blend) VGA_DrawLine=VGA_Draw_1BPP_Blend_Line;
02694         else VGA_DrawLine=VGA_Draw_1BPP_Line;
02695         break;
02696     case M_TANDY2:
02697         if (((machine==MCH_PCJR)&&(vga.tandy.gfx_control & 0x8)) ||
02698             (vga.tandy.mode_control & 0x10)) {
02699             vga.draw.blocks=width * 8;
02700             pix_per_char = 16;
02701         } else {
02702             vga.draw.blocks=width * 4;
02703             pix_per_char = 8;
02704         }
02705         VGA_DrawLine=VGA_Draw_1BPP_Line;
02706         break;
02707     case M_TANDY4:
02708         vga.draw.blocks=width * 2;
02709         pix_per_char = 8;
02710         if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) ||
02711             (machine==MCH_PCJR && (vga.tandy.mode_control==0x0b)))
02712             VGA_DrawLine=VGA_Draw_2BPPHiRes_Line;
02713         else VGA_DrawLine=VGA_Draw_2BPP_Line;
02714         break;
02715     case M_TANDY16:
02716         if (vga.tandy.mode_control & 0x1) {
02717             if (( machine==MCH_TANDY ) && ( vga.tandy.mode_control & 0x10 )) {
02718                 vga.draw.blocks=width*4;
02719                 pix_per_char = 8;
02720             } else {
02721                 vga.draw.blocks=width*2;
02722                 pix_per_char = 4;
02723             }
02724             VGA_DrawLine=VGA_Draw_4BPP_Line;
02725         } else {
02726             vga.draw.blocks=width*2;
02727             pix_per_char = 8;
02728             VGA_DrawLine=VGA_Draw_4BPP_Line_Double;
02729         }
02730         break;
02731     case M_TANDY_TEXT: /* Also CGA */
02732         vga.draw.blocks=width;
02733         if (machine==MCH_CGA /*&& !doublewidth*/ && enableCGASnow && (vga.tandy.mode_control & 1)/*80-column mode*/)
02734             VGA_DrawLine=VGA_CGASNOW_TEXT_Draw_Line; /* Alternate version that emulates CGA snow */
02735         else
02736             VGA_DrawLine=VGA_TEXT_Draw_Line;
02737         break;
02738     case M_HERC_TEXT:
02739         vga.draw.blocks=width;
02740         VGA_DrawLine=VGA_TEXT_Herc_Draw_Line;
02741         break;
02742     case M_AMSTRAD: // Probably OK?
02743         pix_per_char = 16;
02744         vga.draw.blocks=width*2;
02745         VGA_DrawLine=VGA_Draw_AMS_4BPP_Line;
02746 //      VGA_DrawLine=VGA_Draw_4BPP_Line;
02747 /*      doubleheight=true;
02748         vga.draw.blocks = 2*width; width<<=4;
02749         vga.draw.linear_base = vga.mem.linear + VGA_CACHE_OFFSET;
02750         vga.draw.linear_mask = 512 * 1024 - 1; */
02751         break;
02752     default:
02753         LOG(LOG_VGA,LOG_ERROR)("Unhandled VGA mode %d while checking for resolution",vga.mode);
02754         break;
02755     }
02756     width *= pix_per_char;
02757     VGA_CheckScanLength();
02758 
02759     vga.draw.lines_total=height;
02760     vga.draw.line_length = width * ((bpp + 1) / 8);
02761     vga.draw.clock = clock;
02762 
02763     double vratio = ((double)width)/(double)height; // ratio if pixels were square
02764 
02765     // the picture ratio factor
02766     double scanratio =  ((double)hdend/(double)(htotal-(hrend-hrstart)))/
02767                         ((double)vdend/(double)(vtotal-(vrend-vrstart)));
02768     double scanfield_ratio = 4.0/3.0;
02769     switch(machine) {
02770         case MCH_CGA:
02771         case MCH_PCJR:
02772         case MCH_TANDY:
02773             scanfield_ratio = 1.382;
02774             break;
02775         case MCH_HERC:
02776             scanfield_ratio = 1.535;
02777             break;
02778         case MCH_EGA:
02779             switch (vga.misc_output >> 6) {
02780             case 0: // 200 lines:
02781                 scanfield_ratio = 1.085; // DOSBugs
02782                 //scanfield_ratio = 1.375; // IBM EGA BIOS
02783                 break;
02784             case 2: // 350 lines
02785                 // TODO monitors seem to display this with a bit of black borders on top and bottom
02786                 scanfield_ratio = 1.45;
02787                 break;
02788             default:
02789                 // other cases are undefined for EGA - scale them to 4:3
02790                 scanfield_ratio = (4.0/3.0) / scanratio;
02791                 break;
02792             }
02793             break;
02794 
02795         default: // VGA
02796             switch (vga.misc_output >> 6) {
02797             case 0: // VESA: "OTHER" scanline amount
02798                 scanfield_ratio = (4.0/3.0) / scanratio;
02799                 break;
02800             case 1: // 400 lines
02801                 scanfield_ratio = 1.312;
02802                 break;
02803             case 2: // 350 lines
02804                 scanfield_ratio = 1.249;
02805                 break;
02806             case 3: // 480 lines
02807                 scanfield_ratio = 1.345;
02808                 break;
02809             }
02810             break;
02811     }
02812     // calculate screen ratio
02813     double screenratio = scanratio * scanfield_ratio;
02814 
02815     // override screenratio for certain cases:
02816     if (vratio == 1.6) screenratio = 4.0 / 3.0;
02817     else if (vratio == 0.8) screenratio = 4.0 / 3.0;
02818     else if (vratio == 3.2) screenratio = 4.0 / 3.0;
02819     else if (vratio == (4.0/3.0)) screenratio = 4.0 / 3.0;
02820     else if (vratio == (2.0/3.0)) screenratio = 4.0 / 3.0;
02821     else if ((width >= 800)&&(height>=600)) screenratio = 4.0 / 3.0;
02822 
02823 #if C_DEBUG
02824             LOG(LOG_VGA,LOG_NORMAL)("screen: %1.3f, scanfield: %1.3f, scan: %1.3f, vratio: %1.3f",
02825                 screenratio, scanfield_ratio, scanratio, vratio);
02826 #endif
02827 
02828     bool fps_changed = false;
02829 
02830 #if C_DEBUG
02831     LOG(LOG_VGA,LOG_NORMAL)("h total %2.5f (%3.2fkHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
02832         vga.draw.delay.htotal,(1.0/vga.draw.delay.htotal),
02833         vga.draw.delay.hblkstart,vga.draw.delay.hblkend,
02834         vga.draw.delay.hrstart,vga.draw.delay.hrend);
02835     LOG(LOG_VGA,LOG_NORMAL)("v total %2.5f (%3.2fHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
02836         vga.draw.delay.vtotal,(1000.0/vga.draw.delay.vtotal),
02837         vga.draw.delay.vblkstart,vga.draw.delay.vblkend,
02838         vga.draw.delay.vrstart,vga.draw.delay.vrend);
02839 
02840     LOG(LOG_VGA,LOG_NORMAL)("video clock: %3.2fMHz mode %s",
02841         oscclock/1000000.0, mode_texts[vga.mode]);
02842 #endif
02843 
02844     // need to change the vertical timing?
02845     if (vga_mode_time_base < 0 || fabs(vga.draw.delay.vtotal - 1000.0 / fps) > 0.0001)
02846         fps_changed = true;
02847 
02848     // need to resize the output window?
02849     if ((width != vga.draw.width) ||
02850         (height != vga.draw.height) ||
02851         (fabs(screenratio - vga.draw.screen_ratio) > 0.0001) ||
02852         (vga.draw.bpp != bpp) || fps_changed) {
02853 
02854         VGA_KillDrawing();
02855 
02856         vga.draw.width = width;
02857         vga.draw.height = height;
02858         vga.draw.screen_ratio = screenratio;
02859         vga.draw.bpp = bpp;
02860 #if C_DEBUG
02861         LOG(LOG_VGA,LOG_NORMAL)("%dx%d, %3.2fHz, %dbpp, screen %1.3f",(int)width,(int)height,fps,(int)bpp,screenratio);
02862 #endif
02863         if (!vga.draw.vga_override)
02864             RENDER_SetSize(width,height,bpp,(float)fps,screenratio);
02865 
02866         if (fps_changed) {
02867             vga_mode_time_base = PIC_FullIndex();
02868             vga_mode_frames_since_time_base = 0;
02869             PIC_RemoveEvents(VGA_Other_VertInterrupt);
02870             PIC_RemoveEvents(VGA_VerticalTimer);
02871             PIC_RemoveEvents(VGA_PanningLatch);
02872             PIC_RemoveEvents(VGA_DisplayStartLatch);
02873             vga.draw.delay.vtotal = 1000.0 / fps;
02874             vga.draw.lines_done = vga.draw.lines_total;
02875             vga_fps = fps;
02876             VGA_VerticalTimer(0);
02877         }
02878     }
02879     vga.draw.delay.singleline_delay = (float)vga.draw.delay.htotal;
02880 
02881     /* FIXME: Why is this required to prevent VGA palette errors with Crystal Dream II?
02882      *        What is this code doing to change the palette prior to this point? */
02883     VGA_DAC_UpdateColorPalette();
02884 }
02885 
02886 void VGA_KillDrawing(void) {
02887     PIC_RemoveEvents(VGA_DrawSingleLine);
02888     PIC_RemoveEvents(VGA_DrawEGASingleLine);
02889 }
02890 
02891 void VGA_SetOverride(bool vga_override) {
02892     if (vga.draw.vga_override!=vga_override) {
02893         
02894         if (vga_override) {
02895             VGA_KillDrawing();
02896             vga.draw.vga_override=true;
02897         } else {
02898             vga.draw.vga_override=false;
02899             vga.draw.width=0; // change it so the output window gets updated
02900             VGA_SetupDrawing(0);
02901         }
02902     }
02903 }
02904