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