2009-05-02 23:03:37 +02:00
|
|
|
/*
|
2009-05-03 00:28:34 +02:00
|
|
|
* Copyright (C) 2002-2007 The DOSBox Team
|
2009-05-02 23:03:37 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2009-05-03 00:02:15 +02:00
|
|
|
* GNU General Public License for more details.
|
2009-05-02 23:03:37 +02:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2009-05-02 23:53:27 +02:00
|
|
|
#include <math.h>
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "dosbox.h"
|
|
|
|
#include "video.h"
|
2009-05-02 23:43:00 +02:00
|
|
|
#include "render.h"
|
2009-05-03 00:18:08 +02:00
|
|
|
#include "../gui/render_scalers.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "vga.h"
|
2009-05-02 23:43:00 +02:00
|
|
|
#include "pic.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
#define VGA_PARTS 4
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
typedef Bit8u * (* VGA_Line_Handler)(Bitu vidstart, Bitu line);
|
2009-05-02 23:53:27 +02:00
|
|
|
|
|
|
|
static VGA_Line_Handler VGA_DrawLine;
|
2009-05-03 00:18:08 +02:00
|
|
|
static Bit8u TempLine[SCALER_MAXWIDTH * 4];
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart, Bitu line) {
|
|
|
|
const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
|
|
|
|
Bit32u *draw = (Bit32u *)TempLine;
|
|
|
|
for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
|
|
|
|
Bitu val = base[(vidstart & (8 * 1024 -1))];
|
2009-05-02 23:53:27 +02:00
|
|
|
*draw++=CGA_2_Table[val >> 4];
|
|
|
|
*draw++=CGA_2_Table[val & 0xf];
|
2009-05-02 23:27:47 +02:00
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
return TempLine;
|
2009-05-02 23:12:18 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_2BPP_Line(Bitu vidstart, Bitu line) {
|
|
|
|
const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
|
|
|
|
Bit32u * draw=(Bit32u *)TempLine;
|
2009-05-02 23:53:27 +02:00
|
|
|
for (Bitu x=0;x<vga.draw.blocks;x++) {
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu val = base[vidstart & vga.tandy.addr_mask];
|
2009-05-03 00:18:08 +02:00
|
|
|
vidstart++;
|
2009-05-02 23:53:27 +02:00
|
|
|
*draw++=CGA_4_Table[val];
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
return TempLine;
|
2009-05-02 23:27:47 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_2BPPHiRes_Line(Bitu vidstart, Bitu line) {
|
|
|
|
const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
|
|
|
|
Bit32u * draw=(Bit32u *)TempLine;
|
2009-05-03 00:18:08 +02:00
|
|
|
for (Bitu x=0;x<vga.draw.blocks;x++) {
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu val1 = base[vidstart & vga.tandy.addr_mask];
|
|
|
|
++vidstart;
|
|
|
|
Bitu val2 = base[vidstart & vga.tandy.addr_mask];
|
|
|
|
++vidstart;
|
2009-05-03 00:18:08 +02:00
|
|
|
*draw++=CGA_4_HiRes_Table[(val1>>4)|(val2&0xf0)];
|
|
|
|
*draw++=CGA_4_HiRes_Table[(val1&0x0f)|((val2&0x0f)<<4)];
|
|
|
|
}
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bitu temp[643]={0};
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) {
|
|
|
|
const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
|
|
|
|
const Bit8u *reader = base + vidstart;
|
2009-05-03 00:02:15 +02:00
|
|
|
Bit32u * draw=(Bit32u *)TempLine;
|
2009-05-03 00:18:08 +02:00
|
|
|
//Generate a temporary bitline to calculate the avarage
|
|
|
|
//over bit-2 bit-1 bit bit+1.
|
|
|
|
//Combine this number with the current colour to get
|
|
|
|
//an unigue index in the pallete. Or it with bit 7 as they are stored
|
|
|
|
//in the upperpart to keep them from interfering the regular cga stuff
|
|
|
|
|
|
|
|
for(Bitu x = 0; x < 640; x++)
|
|
|
|
temp[x+2] = (( reader[(x>>3)] >> (7-(x&7)) )&1) << 4;
|
|
|
|
//shift 4 as that is for the index.
|
|
|
|
Bitu i = 0,temp1,temp2,temp3,temp4;
|
2009-05-02 23:53:27 +02:00
|
|
|
for (Bitu x=0;x<vga.draw.blocks;x++) {
|
2009-05-03 00:18:08 +02:00
|
|
|
Bitu val1 = *reader++;
|
|
|
|
Bitu val2 = val1&0xf;
|
|
|
|
val1 >>= 4;
|
|
|
|
|
|
|
|
temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
|
|
|
|
*draw++ = 0x80808080|(temp1|val1) |
|
|
|
|
((temp2|val1) << 8) |
|
|
|
|
((temp3|val1) <<16) |
|
|
|
|
((temp4|val1) <<24);
|
|
|
|
temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
|
|
|
|
*draw++ = 0x80808080|(temp1|val2) |
|
|
|
|
((temp2|val2) << 8) |
|
|
|
|
((temp3|val2) <<16) |
|
|
|
|
((temp4|val2) <<24);
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
return TempLine;
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) {
|
|
|
|
const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
|
|
|
|
Bit32u * draw=(Bit32u *)TempLine;
|
2009-05-02 23:53:27 +02:00
|
|
|
for (Bitu x=0;x<vga.draw.blocks;x++) {
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu val1 = base[vidstart & vga.tandy.addr_mask];
|
|
|
|
++vidstart;
|
|
|
|
Bitu val2 = base[vidstart & vga.tandy.addr_mask];
|
|
|
|
++vidstart;
|
2009-05-02 23:53:27 +02:00
|
|
|
*draw++=(val1 & 0x0f) << 8 |
|
|
|
|
(val1 & 0xf0) >> 4 |
|
|
|
|
(val2 & 0x0f) << 24 |
|
|
|
|
(val2 & 0xf0) << 12;
|
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
return TempLine;
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart, Bitu line) {
|
|
|
|
const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
|
|
|
|
Bit32u * draw=(Bit32u *)TempLine;
|
2009-05-03 00:02:15 +02:00
|
|
|
for (Bitu x=0;x<vga.draw.blocks;x++) {
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu val = base[vidstart & vga.tandy.addr_mask];
|
|
|
|
++vidstart;
|
2009-05-03 00:18:08 +02:00
|
|
|
*draw++=(val & 0xf0) >> 4 |
|
|
|
|
(val & 0xf0) << 4 |
|
|
|
|
(val & 0x0f) << 16 |
|
|
|
|
(val & 0x0f) << 24;
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
static Bit8u * VGA_Draw_Changes_Line(Bitu vidstart, Bitu line) {
|
|
|
|
Bitu checkMask = vga.changes.checkMask;
|
|
|
|
Bit8u *map = vga.changes.map;
|
|
|
|
Bitu start = (vidstart >> VGA_CHANGE_SHIFT);
|
|
|
|
Bitu end = ((vidstart + vga.draw.line_length ) >> VGA_CHANGE_SHIFT);
|
|
|
|
for (; start <= end;start++) {
|
|
|
|
if ( map[start] & checkMask ) {
|
|
|
|
Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ];
|
|
|
|
#if !defined(C_UNALIGNED_MEMORY)
|
|
|
|
if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
|
|
|
|
memcpy( TempLine, ret, vga.draw.line_length );
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// memset( TempLine, 0x30, vga.changes.lineWidth );
|
|
|
|
// return TempLine;
|
|
|
|
return 0;
|
2009-05-03 00:18:08 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu line) {
|
|
|
|
Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ];
|
|
|
|
#if !defined(C_UNALIGNED_MEMORY)
|
|
|
|
if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
|
|
|
|
memcpy( TempLine, ret, vga.draw.line_length );
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return ret;
|
2009-05-03 00:18:08 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
//Test version, might as well keep it
|
|
|
|
static Bit8u * VGA_Draw_Chain_Line(Bitu vidstart, Bitu line) {
|
|
|
|
Bitu i = 0;
|
|
|
|
for ( i = 0; i < vga.draw.width;i++ ) {
|
|
|
|
Bitu addr = vidstart + i;
|
|
|
|
TempLine[i] = vga.mem.linear[((addr&~3)<<2)+(addr&3)];
|
|
|
|
}
|
|
|
|
return TempLine;
|
2009-05-03 00:18:08 +02:00
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_Draw_VGA_Line_HWMouse( Bitu vidstart, Bitu line) {
|
2009-05-03 00:02:15 +02:00
|
|
|
if(vga.s3.hgc.curmode & 0x1) {
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu lineat = vidstart / vga.draw.width;
|
2009-05-03 00:18:08 +02:00
|
|
|
if((lineat < vga.s3.hgc.originy) || (lineat > (vga.s3.hgc.originy + 63U))) {
|
2009-05-03 00:28:34 +02:00
|
|
|
return &vga.mem.linear[ vidstart ];
|
2009-05-03 00:02:15 +02:00
|
|
|
} else {
|
2009-05-03 00:28:34 +02:00
|
|
|
memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width);
|
2009-05-03 00:02:15 +02:00
|
|
|
/* Draw mouse cursor */
|
|
|
|
Bits moff = ((Bits)lineat - (Bits)vga.s3.hgc.originy) + (Bits)vga.s3.hgc.posy;
|
2009-05-03 00:28:34 +02:00
|
|
|
if(moff>63) return &vga.mem.linear[ vidstart ];
|
2009-05-03 00:02:15 +02:00
|
|
|
if(moff<0) moff+=64;
|
|
|
|
Bitu xat = vga.s3.hgc.originx;
|
2009-05-03 00:18:08 +02:00
|
|
|
Bitu m, mapat;
|
|
|
|
Bits r, z;
|
|
|
|
mapat = 0;
|
|
|
|
|
|
|
|
Bitu mouseaddr = (Bit32u)vga.s3.hgc.startaddr * (Bit32u)1024;
|
|
|
|
mouseaddr+=(moff * 16);
|
2009-05-03 00:02:15 +02:00
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
Bit16u bitsA, bitsB;
|
|
|
|
Bit8u mappoint;
|
|
|
|
for(m=0;m<4;m++) {
|
|
|
|
bitsA = *(Bit16u *)&vga.mem.linear[mouseaddr];
|
|
|
|
mouseaddr+=2;
|
|
|
|
bitsB = *(Bit16u *)&vga.mem.linear[mouseaddr];
|
|
|
|
mouseaddr+=2;
|
|
|
|
z = 7;
|
|
|
|
for(r=15;r>=0;--r) {
|
|
|
|
mappoint = (((bitsA >> z) & 0x1) << 1) | ((bitsB >> z) & 0x1);
|
|
|
|
if(mapat >= vga.s3.hgc.posx) {
|
|
|
|
switch(mappoint) {
|
2009-05-03 00:02:15 +02:00
|
|
|
case 0:
|
|
|
|
TempLine[xat] = vga.s3.hgc.backstack[0];
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
TempLine[xat] = vga.s3.hgc.forestack[0];
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//Transparent
|
|
|
|
break;
|
|
|
|
case 3:
|
2009-05-03 00:18:08 +02:00
|
|
|
// Invert screen data
|
|
|
|
TempLine[xat] = ~TempLine[xat];
|
2009-05-03 00:02:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
xat++;
|
2009-05-03 00:18:08 +02:00
|
|
|
}
|
|
|
|
mapat++;
|
|
|
|
--z;
|
|
|
|
if(z<0) z=15;
|
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* HW Mouse not enabled, use the tried and true call */
|
2009-05-03 00:28:34 +02:00
|
|
|
return &vga.mem.linear[ vidstart ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bit8u * VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart, Bitu line) {
|
|
|
|
if(vga.s3.hgc.curmode & 0x1) {
|
|
|
|
Bitu lineat = (vidstart >> 1) / vga.draw.width;
|
|
|
|
if((lineat < vga.s3.hgc.originy) || (lineat > (vga.s3.hgc.originy + 63U))) {
|
|
|
|
return &vga.mem.linear[ vidstart ];
|
|
|
|
} else {
|
|
|
|
memcpy(TempLine, &vga.mem.linear[ vidstart ], 2*vga.draw.width);
|
|
|
|
/* Draw mouse cursor */
|
|
|
|
Bits moff = ((Bits)lineat - (Bits)vga.s3.hgc.originy) + (Bits)vga.s3.hgc.posy;
|
|
|
|
if(moff>63) return &vga.mem.linear[ vidstart ];
|
|
|
|
if(moff<0) moff+=64;
|
|
|
|
Bitu xat = 2*vga.s3.hgc.originx;
|
|
|
|
Bitu m, mapat;
|
|
|
|
Bits r, z;
|
|
|
|
mapat = 0;
|
|
|
|
|
|
|
|
Bitu mouseaddr = (Bit32u)vga.s3.hgc.startaddr * (Bit32u)1024;
|
|
|
|
mouseaddr+=(moff * 16);
|
|
|
|
|
|
|
|
Bit16u bitsA, bitsB;
|
|
|
|
Bit8u mappoint;
|
|
|
|
for(m=0;m<4;m++) {
|
|
|
|
bitsA = *(Bit16u *)&vga.mem.linear[mouseaddr];
|
|
|
|
mouseaddr+=2;
|
|
|
|
bitsB = *(Bit16u *)&vga.mem.linear[mouseaddr];
|
|
|
|
mouseaddr+=2;
|
|
|
|
z = 7;
|
|
|
|
for(r=15;r>=0;--r) {
|
|
|
|
mappoint = (((bitsA >> z) & 0x1) << 1) | ((bitsB >> z) & 0x1);
|
|
|
|
if(mapat >= vga.s3.hgc.posx) {
|
|
|
|
switch(mappoint) {
|
|
|
|
case 0:
|
|
|
|
TempLine[xat] = vga.s3.hgc.backstack[0];
|
|
|
|
TempLine[xat+1] = vga.s3.hgc.backstack[1];
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
TempLine[xat] = vga.s3.hgc.forestack[0];
|
|
|
|
TempLine[xat+1] = vga.s3.hgc.forestack[1];
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//Transparent
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
// Invert screen data
|
|
|
|
TempLine[xat] = ~TempLine[xat];
|
|
|
|
TempLine[xat+1] = ~TempLine[xat+1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
xat+=2;
|
|
|
|
}
|
|
|
|
mapat++;
|
|
|
|
--z;
|
|
|
|
if(z<0) z=15;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* HW Mouse not enabled, use the tried and true call */
|
|
|
|
return &vga.mem.linear[ vidstart ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bit8u * VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart, Bitu line) {
|
|
|
|
if(vga.s3.hgc.curmode & 0x1) {
|
|
|
|
Bitu lineat = (vidstart >> 2) / vga.draw.width;
|
|
|
|
if((lineat < vga.s3.hgc.originy) || (lineat > (vga.s3.hgc.originy + 63U))) {
|
|
|
|
return &vga.mem.linear[ vidstart ];
|
|
|
|
} else {
|
|
|
|
memcpy(TempLine, &vga.mem.linear[ vidstart ], 4*vga.draw.width);
|
|
|
|
/* Draw mouse cursor */
|
|
|
|
Bits moff = ((Bits)lineat - (Bits)vga.s3.hgc.originy) + (Bits)vga.s3.hgc.posy;
|
|
|
|
if(moff>63) return &vga.mem.linear[ vidstart ];
|
|
|
|
if(moff<0) moff+=64;
|
|
|
|
Bitu xat = 4*vga.s3.hgc.originx;
|
|
|
|
Bitu m, mapat;
|
|
|
|
Bits r, z;
|
|
|
|
mapat = 0;
|
|
|
|
|
|
|
|
Bitu mouseaddr = (Bit32u)vga.s3.hgc.startaddr * (Bit32u)1024;
|
|
|
|
mouseaddr+=(moff * 16);
|
|
|
|
|
|
|
|
Bit16u bitsA, bitsB;
|
|
|
|
Bit8u mappoint;
|
|
|
|
for(m=0;m<4;m++) {
|
|
|
|
bitsA = *(Bit16u *)&vga.mem.linear[mouseaddr];
|
|
|
|
mouseaddr+=2;
|
|
|
|
bitsB = *(Bit16u *)&vga.mem.linear[mouseaddr];
|
|
|
|
mouseaddr+=2;
|
|
|
|
z = 7;
|
|
|
|
for(r=15;r>=0;--r) {
|
|
|
|
mappoint = (((bitsA >> z) & 0x1) << 1) | ((bitsB >> z) & 0x1);
|
|
|
|
if(mapat >= vga.s3.hgc.posx) {
|
|
|
|
switch(mappoint) {
|
|
|
|
case 0:
|
|
|
|
TempLine[xat] = vga.s3.hgc.backstack[0];
|
|
|
|
TempLine[xat+1] = vga.s3.hgc.backstack[1];
|
|
|
|
TempLine[xat+2] = vga.s3.hgc.backstack[2];
|
|
|
|
TempLine[xat+3] = 255;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
TempLine[xat] = vga.s3.hgc.forestack[0];
|
|
|
|
TempLine[xat+1] = vga.s3.hgc.forestack[1];
|
|
|
|
TempLine[xat+2] = vga.s3.hgc.forestack[2];
|
|
|
|
TempLine[xat+3] = 255;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//Transparent
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
// Invert screen data
|
|
|
|
TempLine[xat] = ~TempLine[xat];
|
|
|
|
TempLine[xat+1] = ~TempLine[xat+1];
|
|
|
|
TempLine[xat+2] = ~TempLine[xat+2];
|
|
|
|
TempLine[xat+2] = ~TempLine[xat+3];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
xat+=4;
|
|
|
|
}
|
|
|
|
mapat++;
|
|
|
|
--z;
|
|
|
|
if(z<0) z=15;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TempLine;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* HW Mouse not enabled, use the tried and true call */
|
|
|
|
return &vga.mem.linear[ vidstart ];
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
|
|
|
}
|
2009-05-02 23:53:27 +02:00
|
|
|
|
|
|
|
static Bit32u FontMask[2]={0xffffffff,0x0};
|
2009-05-03 00:28:34 +02:00
|
|
|
static Bit8u * VGA_TEXT_Draw_Line(Bitu vidstart, Bitu line) {
|
2009-05-03 00:37:32 +02:00
|
|
|
Bits font_addr;
|
2009-05-03 00:02:15 +02:00
|
|
|
Bit32u * draw=(Bit32u *)TempLine;
|
2009-05-03 00:28:34 +02:00
|
|
|
const Bit8u *vidmem = &vga.tandy.draw_base[vidstart];
|
2009-05-02 23:53:27 +02:00
|
|
|
for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
|
|
|
|
Bitu chr=vidmem[cx*2];
|
|
|
|
Bitu col=vidmem[cx*2+1];
|
2009-05-03 00:02:15 +02:00
|
|
|
Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
|
|
|
|
Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
|
|
|
|
Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
|
2009-05-02 23:53:27 +02:00
|
|
|
Bit32u fg=TXT_FG_Table[col&0xf];
|
|
|
|
Bit32u bg=TXT_BG_Table[col>>4];
|
|
|
|
*draw++=fg&mask1 | bg&~mask1;
|
|
|
|
*draw++=fg&mask2 | bg&~mask2;
|
|
|
|
}
|
|
|
|
if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
|
2009-05-03 00:18:08 +02:00
|
|
|
font_addr = (vga.draw.cursor.address-vidstart) >> 1;
|
2009-05-03 00:37:32 +02:00
|
|
|
if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
|
2009-05-02 23:53:27 +02:00
|
|
|
if (line<vga.draw.cursor.sline) goto skip_cursor;
|
|
|
|
if (line>vga.draw.cursor.eline) goto skip_cursor;
|
2009-05-03 00:02:15 +02:00
|
|
|
draw=(Bit32u *)&TempLine[font_addr*8];
|
2009-05-03 00:28:34 +02:00
|
|
|
Bit32u att=TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf];
|
2009-05-02 23:53:27 +02:00
|
|
|
*draw++=att;*draw++=att;
|
|
|
|
}
|
|
|
|
skip_cursor:
|
2009-05-03 00:02:15 +02:00
|
|
|
return TempLine;
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
static void VGA_VerticalDisplayEnd(Bitu val) {
|
2009-05-03 00:28:34 +02:00
|
|
|
// vga.config.retrace=true;
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.config.real_start=vga.config.display_start & ((2*1024*1024)-1);
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
static void VGA_HorizontalTimer(void) {
|
|
|
|
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
static INLINE void VGA_ChangesEnd(void ) {
|
|
|
|
if ( vga.changes.active ) {
|
|
|
|
// vga.changes.active = false;
|
|
|
|
Bitu end = vga.draw.address >> VGA_CHANGE_SHIFT;
|
|
|
|
Bitu total = 4 + end - vga.changes.start;
|
|
|
|
Bit32u clearMask = vga.changes.clearMask;
|
|
|
|
total >>= 2;
|
|
|
|
Bit32u *clear = (Bit32u *)&vga.changes.map[ vga.changes.start & ~3 ];
|
|
|
|
while ( total-- ) {
|
|
|
|
clear[0] &= clearMask;
|
|
|
|
clear++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
static void VGA_DrawPart(Bitu lines) {
|
|
|
|
while (lines--) {
|
2009-05-03 00:28:34 +02:00
|
|
|
Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
|
2009-05-02 23:53:27 +02:00
|
|
|
RENDER_DrawLine(data);
|
|
|
|
vga.draw.address_line++;
|
|
|
|
if (vga.draw.address_line>=vga.draw.address_line_total) {
|
|
|
|
vga.draw.address_line=0;
|
|
|
|
vga.draw.address+=vga.draw.address_add;
|
|
|
|
}
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.lines_done++;
|
2009-05-03 00:02:15 +02:00
|
|
|
if (vga.draw.split_line==vga.draw.lines_done) {
|
2009-05-03 00:28:34 +02:00
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
VGA_ChangesEnd( );
|
|
|
|
#endif
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.draw.address=0;
|
2009-05-03 00:28:34 +02:00
|
|
|
if(!(vga.attr.mode_control&0x20))
|
|
|
|
vga.draw.address += vga.config.pel_panning;
|
2009-05-02 23:53:27 +02:00
|
|
|
vga.draw.address_line=0;
|
2009-05-03 00:28:34 +02:00
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
|
|
|
|
#endif
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
if (--vga.draw.parts_left) {
|
2009-05-03 00:28:34 +02:00
|
|
|
PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,
|
2009-05-03 00:02:15 +02:00
|
|
|
(vga.draw.parts_left!=1) ? vga.draw.parts_lines : (vga.draw.lines_total - vga.draw.lines_done));
|
|
|
|
} else {
|
2009-05-03 00:28:34 +02:00
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
VGA_ChangesEnd();
|
|
|
|
#endif
|
|
|
|
RENDER_EndUpdate();
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
void VGA_SetBlinking(Bitu enabled) {
|
|
|
|
Bitu b;
|
|
|
|
LOG(LOG_VGA,LOG_NORMAL)("Blinking %d",enabled);
|
|
|
|
if (enabled) {
|
|
|
|
b=0;vga.draw.blinking=1; //used to -1 but blinking is unsigned
|
|
|
|
vga.attr.mode_control|=0x08;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.tandy.mode_control|=0x20;
|
2009-05-02 23:53:27 +02:00
|
|
|
} else {
|
|
|
|
b=8;vga.draw.blinking=0;
|
|
|
|
vga.attr.mode_control&=~0x08;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.tandy.mode_control&=~0x20;
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
|
|
|
for (Bitu i=0;i<8;i++) TXT_BG_Table[i+8]=(b+i) | ((b+i) << 8)| ((b+i) <<16) | ((b+i) << 24);
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
static void INLINE VGA_ChangesStart( void ) {
|
|
|
|
vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
|
|
|
|
vga.changes.last = vga.changes.start;
|
|
|
|
if ( vga.changes.lastAddress != vga.draw.address ) {
|
|
|
|
// LOG_MSG("Address");
|
|
|
|
VGA_DrawLine = VGA_Draw_Linear_Line;
|
|
|
|
vga.changes.lastAddress = vga.draw.address;
|
|
|
|
} else if ( render.fullFrame ) {
|
|
|
|
// LOG_MSG("Full Frame");
|
|
|
|
VGA_DrawLine = VGA_Draw_Linear_Line;
|
|
|
|
} else {
|
|
|
|
// LOG_MSG("Changes");
|
|
|
|
VGA_DrawLine = VGA_Draw_Changes_Line;
|
|
|
|
}
|
|
|
|
vga.changes.active = true;
|
|
|
|
vga.changes.checkMask = vga.changes.writeMask;
|
|
|
|
vga.changes.clearMask = ~( 0x01010101 << (vga.changes.frame & 7));
|
|
|
|
vga.changes.frame++;
|
|
|
|
vga.changes.writeMask = 1 << (vga.changes.frame & 7);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
static void VGA_VerticalTimer(Bitu val) {
|
2009-05-03 00:28:34 +02:00
|
|
|
double error = vga.draw.delay.framestart;
|
|
|
|
vga.draw.delay.framestart = PIC_FullIndex();
|
|
|
|
error = vga.draw.delay.framestart - error - vga.draw.delay.vtotal;
|
|
|
|
// if (abs(error) > 0.001 )
|
|
|
|
// LOG_MSG("vgaerror: %f",error);
|
|
|
|
PIC_AddEvent( VGA_VerticalTimer, (float)vga.draw.delay.vtotal );
|
|
|
|
PIC_AddEvent( VGA_VerticalDisplayEnd, (float)vga.draw.delay.vrstart );
|
|
|
|
if ( GCC_UNLIKELY( vga.draw.parts_left )) {
|
|
|
|
LOG(LOG_VGAMISC,LOG_NORMAL)( "Parts left: %d", vga.draw.parts_left );
|
|
|
|
PIC_RemoveEvents( &VGA_DrawPart );
|
|
|
|
RENDER_EndUpdate();
|
|
|
|
vga.draw.parts_left = 0;
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
2009-05-03 00:28:34 +02:00
|
|
|
//Check if we can actually render, else skip the rest
|
|
|
|
if (!RENDER_StartUpdate())
|
|
|
|
return;
|
|
|
|
//TODO Maybe check for an active frame on parts_left and clear that first?
|
|
|
|
vga.draw.parts_left = vga.draw.parts_total;
|
|
|
|
vga.draw.lines_done = 0;
|
|
|
|
// vga.draw.address=vga.config.display_start;
|
|
|
|
vga.draw.address = vga.config.real_start;
|
|
|
|
vga.draw.address_line = vga.config.hlines_skip;
|
|
|
|
vga.draw.split_line = (vga.config.line_compare/vga.draw.lines_scaled);
|
2009-05-02 23:53:27 +02:00
|
|
|
switch (vga.mode) {
|
2009-05-03 00:28:34 +02:00
|
|
|
case M_EGA:
|
|
|
|
case M_LIN4:
|
|
|
|
vga.draw.address *= 8;
|
|
|
|
vga.draw.address += vga.config.pel_panning;
|
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
VGA_ChangesStart();
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case M_VGA:
|
|
|
|
if(vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) {
|
|
|
|
vga.draw.linear_base = vga.mem.linear + VGA_CACHE_OFFSET;
|
|
|
|
vga.draw.linear_mask = 0xffff;
|
|
|
|
} else {
|
|
|
|
vga.draw.linear_base = vga.mem.linear;
|
|
|
|
vga.draw.linear_mask = VGA_MEMORY - 1;
|
|
|
|
}
|
|
|
|
case M_LIN8:
|
|
|
|
case M_LIN15:
|
|
|
|
case M_LIN16:
|
|
|
|
case M_LIN32:
|
|
|
|
vga.draw.address *= 4;
|
|
|
|
vga.draw.address += vga.config.pel_panning;
|
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
VGA_ChangesStart();
|
|
|
|
#endif
|
|
|
|
break;
|
2009-05-03 00:02:15 +02:00
|
|
|
case M_TEXT:
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.address = vga.config.display_start * 2;
|
2009-05-03 00:02:15 +02:00
|
|
|
case M_TANDY_TEXT:
|
|
|
|
case M_HERC_TEXT:
|
|
|
|
vga.draw.cursor.address=vga.config.cursor_start*2;
|
2009-05-02 23:53:27 +02:00
|
|
|
vga.draw.cursor.count++;
|
|
|
|
/* check for blinking and blinking change delay */
|
2009-05-03 00:02:15 +02:00
|
|
|
FontMask[1]=(vga.draw.blinking & (vga.draw.cursor.count >> 4)) ?
|
2009-05-02 23:53:27 +02:00
|
|
|
0 : 0xffffffff;
|
|
|
|
break;
|
2009-05-03 00:28:34 +02:00
|
|
|
case M_HERC_GFX:
|
|
|
|
break;
|
|
|
|
case M_CGA4:case M_CGA2:
|
2009-05-02 23:53:27 +02:00
|
|
|
vga.draw.address=(vga.draw.address*2)&0x1fff;
|
|
|
|
break;
|
2009-05-03 00:28:34 +02:00
|
|
|
case M_CGA16:
|
|
|
|
case M_TANDY2:case M_TANDY4:case M_TANDY16:
|
|
|
|
vga.draw.address *= 2;
|
|
|
|
break;
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-03 00:28:34 +02:00
|
|
|
//VGA_DrawPart( vga.draw.parts_lines );
|
2009-05-03 00:37:32 +02:00
|
|
|
PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,vga.draw.parts_lines);
|
|
|
|
// PIC_AddEvent(VGA_DrawPart,(float)(vga.draw.delay.parts/2),vga.draw.parts_lines); //Else tearline in Tyrian and second reality
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
void VGA_CheckScanLength(void) {
|
|
|
|
switch (vga.mode) {
|
2009-05-03 00:18:08 +02:00
|
|
|
case M_EGA:
|
|
|
|
case M_LIN4:
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.address_add=vga.config.scan_len*16;
|
|
|
|
break;
|
|
|
|
case M_VGA:
|
2009-05-03 00:02:15 +02:00
|
|
|
case M_LIN8:
|
2009-05-03 00:18:08 +02:00
|
|
|
case M_LIN15:
|
|
|
|
case M_LIN16:
|
|
|
|
case M_LIN32:
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.address_add=vga.config.scan_len*8;
|
2009-05-03 00:02:15 +02:00
|
|
|
break;
|
|
|
|
case M_TEXT:
|
|
|
|
vga.draw.address_add=vga.config.scan_len*4;
|
|
|
|
break;
|
|
|
|
case M_CGA2:
|
|
|
|
case M_CGA4:
|
|
|
|
case M_CGA16:
|
|
|
|
vga.draw.address_add=80;
|
|
|
|
return;
|
|
|
|
case M_TANDY2:
|
|
|
|
vga.draw.address_add=vga.draw.blocks/4;
|
|
|
|
break;
|
|
|
|
case M_TANDY4:
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.draw.address_add=vga.draw.blocks;
|
2009-05-03 00:02:15 +02:00
|
|
|
break;
|
|
|
|
case M_TANDY16:
|
|
|
|
vga.draw.address_add=vga.draw.blocks;
|
|
|
|
break;
|
|
|
|
case M_TANDY_TEXT:
|
|
|
|
vga.draw.address_add=vga.draw.blocks*2;
|
|
|
|
break;
|
|
|
|
case M_HERC_TEXT:
|
|
|
|
vga.draw.address_add=vga.draw.blocks*2;
|
|
|
|
break;
|
|
|
|
case M_HERC_GFX:
|
|
|
|
vga.draw.address_add=vga.draw.blocks;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
void VGA_ActivateHardwareCursor(void) {
|
|
|
|
if(vga.s3.hgc.curmode & 0x1) {
|
2009-05-03 00:28:34 +02:00
|
|
|
switch(vga.mode) {
|
|
|
|
case M_LIN32:
|
|
|
|
VGA_DrawLine=VGA_Draw_LIN32_Line_HWMouse;
|
|
|
|
break;
|
|
|
|
case M_LIN15:
|
|
|
|
case M_LIN16:
|
|
|
|
VGA_DrawLine=VGA_Draw_LIN16_Line_HWMouse;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse;
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
} else {
|
2009-05-03 00:28:34 +02:00
|
|
|
VGA_DrawLine=VGA_Draw_Linear_Line;
|
2009-05-03 00:18:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
void VGA_SetupDrawing(Bitu val) {
|
|
|
|
if (vga.mode==M_ERROR) {
|
|
|
|
PIC_RemoveEvents(VGA_VerticalTimer);
|
|
|
|
PIC_RemoveEvents(VGA_VerticalDisplayEnd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Calculate the FPS for this screen */
|
2009-05-03 00:44:30 +02:00
|
|
|
float fps; Bitu clock;
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu htotal, hdend, hbstart, hbend, hrstart, hrend;
|
|
|
|
Bitu vtotal, vdend, vbstart, vbend, vrstart, vrend;
|
2009-05-03 00:02:15 +02:00
|
|
|
if (machine==MCH_VGA) {
|
2009-05-03 00:28:34 +02:00
|
|
|
htotal = 5 + vga.crtc.horizontal_total;
|
|
|
|
hdend = 1 + vga.crtc.horizontal_display_end;
|
|
|
|
hbstart = vga.crtc.start_horizontal_blanking;
|
|
|
|
hbend = vga.crtc.end_horizontal_blanking&0x1F |
|
|
|
|
((vga.crtc.end_horizontal_retrace&0x80)>>2);
|
|
|
|
hbend = hbstart + ((hbend - hbstart) & 0x3F);
|
|
|
|
hrstart = vga.crtc.start_horizontal_retrace;
|
|
|
|
hrend = vga.crtc.end_horizontal_retrace & 0x1f;
|
|
|
|
hrend = (hrend - hrstart) & 0x1f;
|
|
|
|
if ( !hrend )
|
|
|
|
hrend = hrstart + 0x1f + 1;
|
|
|
|
else
|
|
|
|
hrend = hrstart + hrend;
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
vtotal=2 + vga.crtc.vertical_total |
|
|
|
|
((vga.crtc.overflow & 1) << 8) | ((vga.crtc.overflow & 0x20) << 4);
|
2009-05-03 00:28:34 +02:00
|
|
|
vdend = 1 + (vga.crtc.vertical_display_end |
|
|
|
|
((vga.crtc.overflow & 2)<<7) |
|
|
|
|
((vga.crtc.overflow & 0x40) << 3) |
|
2009-05-03 00:02:15 +02:00
|
|
|
((vga.s3.ex_ver_overflow & 0x2) << 9));
|
2009-05-03 00:28:34 +02:00
|
|
|
vrstart = vga.crtc.vertical_retrace_start +
|
|
|
|
((vga.crtc.overflow & 0x04) << 6) |
|
2009-05-03 00:02:15 +02:00
|
|
|
((vga.crtc.overflow & 0x80) << 2);
|
2009-05-03 00:28:34 +02:00
|
|
|
vrend = vga.crtc.vertical_retrace_end & 0xF;
|
|
|
|
vrend = ( vrend - vrstart)&0xF;
|
|
|
|
if ( !vrend)
|
|
|
|
vrend = vrstart + 0xf + 1;
|
|
|
|
else
|
|
|
|
vrend = vrstart + vrend;
|
|
|
|
|
|
|
|
vbstart = vga.crtc.start_vertical_blanking |
|
|
|
|
((vga.crtc.overflow & 0x08) << 5) |
|
|
|
|
((vga.crtc.maximum_scan_line & 0x20) << 4);
|
|
|
|
vbend = vga.crtc.end_vertical_blanking & 0x3f;
|
|
|
|
vbend = (vbend - vbstart) & 0x3f;
|
|
|
|
if ( !vbend)
|
|
|
|
vbend = vbstart + 0x3f + 1;
|
|
|
|
else
|
|
|
|
vbend = vbstart + vbend;
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
switch (svgaCard) {
|
|
|
|
case SVGA_S3Trio:
|
|
|
|
clock = SVGA_S3_GetClock();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch ((vga.misc_output >> 2) & 3) {
|
|
|
|
case 0:
|
|
|
|
clock = 25175000;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
clock = 28322000;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-05-03 00:44:30 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
/* Check for 8 for 9 character clock mode */
|
|
|
|
if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9;
|
|
|
|
/* Check for pixel doubling, master clock/2 */
|
|
|
|
if (vga.seq.clocking_mode & 0x8) {
|
|
|
|
htotal*=2;
|
|
|
|
}
|
|
|
|
vga.draw.address_line_total=(vga.crtc.maximum_scan_line&0xf)+1;
|
|
|
|
/* Check for dual transfer whatever thing,master clock/2 */
|
|
|
|
if (vga.s3.pll.cmd & 0x10) clock/=2;
|
|
|
|
vga.draw.double_scan=(vga.crtc.maximum_scan_line&0x80)>0;
|
|
|
|
} else {
|
2009-05-03 00:28:34 +02:00
|
|
|
htotal = vga.other.htotal + 1;
|
|
|
|
hdend = vga.other.hdend;
|
|
|
|
hbstart = hdend;
|
|
|
|
hbend = htotal;
|
|
|
|
hrstart = vga.other.hsyncp;
|
|
|
|
hrend = hrstart + (vga.other.syncw & 0xf) ;
|
|
|
|
|
|
|
|
vga.draw.address_line_total = vga.other.max_scanline + 1;
|
|
|
|
vtotal = vga.draw.address_line_total * (vga.other.vtotal+1)+vga.other.vadjust;
|
|
|
|
vdend = vga.draw.address_line_total * vga.other.vdend;
|
|
|
|
vrstart = vga.draw.address_line_total * vga.other.vsyncp;
|
|
|
|
vrend = (vga.other.syncw >> 4);
|
|
|
|
if (!vrend)
|
|
|
|
vrend = vrstart + 0xf + 1;
|
|
|
|
else
|
|
|
|
vrend = vrstart + vrend;
|
|
|
|
vbstart = vdend;
|
|
|
|
vbend = vtotal;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.draw.double_scan=false;
|
|
|
|
switch (machine) {
|
|
|
|
case MCH_CGA:
|
2009-05-03 00:18:08 +02:00
|
|
|
case TANDY_ARCH_CASE:
|
2009-05-03 00:02:15 +02:00
|
|
|
clock=((vga.tandy.mode_control & 1) ? 14318180 : (14318180/2))/8;
|
|
|
|
break;
|
|
|
|
case MCH_HERC:
|
|
|
|
if (vga.herc.mode_control & 0x2) clock=14318180/16;
|
|
|
|
else clock=14318180/8;
|
|
|
|
break;
|
|
|
|
}
|
2009-05-02 23:53:27 +02:00
|
|
|
}
|
2009-05-03 00:28:34 +02:00
|
|
|
#if C_DEBUG
|
|
|
|
LOG(LOG_VGA,LOG_NORMAL)("h total %d end %d blank (%d/%d) retrace (%d/%d)",
|
|
|
|
htotal, hdend, hbstart, hbend, hrstart, hrend );
|
|
|
|
LOG(LOG_VGA,LOG_NORMAL)("v total %d end %d blank (%d/%d) retrace (%d/%d)",
|
|
|
|
vtotal, vdend, vbstart, vbend, vrstart, vrend );
|
|
|
|
#endif
|
2009-05-03 00:02:15 +02:00
|
|
|
if (!htotal) return;
|
|
|
|
if (!vtotal) return;
|
2009-05-03 00:28:34 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
fps=(float)clock/(vtotal*htotal);
|
2009-05-03 00:28:34 +02:00
|
|
|
// The time a complete video frame takes
|
|
|
|
vga.draw.delay.vtotal = (1000.0 * (double)(vtotal*htotal)) / (double)clock;
|
|
|
|
// Horizontal total (that's how long a line takes with whistles and bells)
|
|
|
|
vga.draw.delay.htotal = htotal*1000.0/clock; //in milliseconds
|
|
|
|
// Start and End of horizontal blanking
|
|
|
|
vga.draw.delay.hblkstart = hbstart*1000.0/clock; //in milliseconds
|
|
|
|
vga.draw.delay.hblkend = hbend*1000.0/clock;
|
|
|
|
vga.draw.delay.hrstart = 0;
|
|
|
|
|
|
|
|
// Start and End of vertical blanking
|
|
|
|
vga.draw.delay.vblkstart = vbstart * vga.draw.delay.htotal;
|
|
|
|
vga.draw.delay.vblkend = vbend * vga.draw.delay.htotal;
|
|
|
|
// Start and End of vertical retrace pulse
|
|
|
|
vga.draw.delay.vrstart = vrstart * vga.draw.delay.htotal;
|
|
|
|
vga.draw.delay.vrend = vrend * vga.draw.delay.htotal;
|
|
|
|
// Display end
|
|
|
|
vga.draw.delay.vdend = vdend * vga.draw.delay.htotal;
|
|
|
|
|
|
|
|
/*
|
|
|
|
// just curious
|
|
|
|
LOG_MSG("H total %d, V Total %d",htotal,vtotal);
|
|
|
|
LOG_MSG("H D End %d, V D End %d",hdispend,vdispend);
|
|
|
|
LOG_MSG("vrstart: %d, vrend: %d\n",vrstart,vrend);
|
|
|
|
LOG_MSG("htotal: %2.6f, vtotal: %2.6f,\n"\
|
|
|
|
"hblkstart: %2.6f, hblkend: %2.6f,\n"\
|
|
|
|
"vblkstart: %2.6f, vblkend: %2.6f,\n"\
|
|
|
|
"vrstart: %2.6f, vrend: %2.6f,\n"\
|
|
|
|
"vdispend: %2.6f",
|
|
|
|
vga.draw.delay.htotal, vga.draw.delay.vtotal,
|
|
|
|
vga.draw.delay.hblkstart, vga.draw.delay.hblkend,
|
|
|
|
vga.draw.delay.vblkstart, vga.draw.delay.vblkend,
|
|
|
|
vga.draw.delay.vrstart, vga.draw.delay.vrend,
|
|
|
|
vga.draw.delay.vend);
|
|
|
|
*/
|
2009-05-02 23:53:27 +02:00
|
|
|
vga.draw.parts_total=VGA_PARTS;
|
2009-05-03 00:44:30 +02:00
|
|
|
/*
|
|
|
|
6 Horizontal Sync Polarity. Negative if set
|
|
|
|
7 Vertical Sync Polarity. Negative if set
|
|
|
|
Bit 6-7 indicates the number of lines on the display:
|
|
|
|
1: 400, 2: 350, 3: 480
|
|
|
|
*/
|
|
|
|
//Try to determine the pixel size, aspect correct is based around square pixels
|
|
|
|
|
|
|
|
//Base pixel width around 100 clocks horizontal
|
|
|
|
//For 9 pixel text modes this should be changed, but we don't support that anyway :)
|
|
|
|
//Seems regular vga only listens to the 9 char pixel mode with character mode enabled
|
|
|
|
double pwidth = 100.0 / htotal;
|
|
|
|
//Base pixel height around vertical totals of modes that have 100 clocks horizontal
|
|
|
|
//Different sync values gives different scaling of the whole vertical range
|
|
|
|
//VGA monitor just seems to thighten or widen the whole vertical range
|
|
|
|
double pheight;
|
|
|
|
Bitu sync = vga.misc_output >> 6;
|
|
|
|
switch ( sync ) {
|
|
|
|
case 0: // This is not defined in vga specs,
|
|
|
|
// Kiet, seems to be slightly less than 350 on my monitor
|
|
|
|
//340 line mode, filled with 449 total
|
|
|
|
pheight = (480.0 / 340.0) * ( 449.0 / vtotal );
|
|
|
|
break;
|
|
|
|
case 1: //400 line mode, filled with 449 total
|
|
|
|
pheight = (480.0 / 400.0) * ( 449.0 / vtotal );
|
|
|
|
break;
|
|
|
|
case 2: //350 line mode, filled with 449 total
|
|
|
|
//This mode seems to get regular 640x400 timing and goes for a loong retrace
|
|
|
|
//Depends on the monitor to stretch the screen
|
|
|
|
pheight = (480.0 / 350.0) * ( 449.0 / vtotal );
|
|
|
|
break;
|
|
|
|
case 3: //480 line mode, filled with 525 total
|
|
|
|
pheight = (480.0 / 480.0) * ( 525.0 / vtotal );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
double aspect_ratio = pheight / pwidth;
|
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.delay.parts = vga.draw.delay.vdend/vga.draw.parts_total;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.draw.resizing=false;
|
2009-05-03 00:28:34 +02:00
|
|
|
|
|
|
|
//Check to prevent useless black areas
|
|
|
|
if (hbstart<hdend) hdend=hbstart;
|
|
|
|
if (vbstart<vdend) vdend=vbstart;
|
|
|
|
|
|
|
|
Bitu width=hdend;
|
|
|
|
Bitu height=vdend;
|
2009-05-03 00:02:15 +02:00
|
|
|
bool doubleheight=false;
|
|
|
|
bool doublewidth=false;
|
2009-05-03 00:28:34 +02:00
|
|
|
|
|
|
|
//Set the bpp
|
|
|
|
Bitu bpp;
|
2009-05-02 23:43:00 +02:00
|
|
|
switch (vga.mode) {
|
2009-05-03 00:18:08 +02:00
|
|
|
case M_LIN15:
|
|
|
|
bpp = 15;
|
|
|
|
break;
|
|
|
|
case M_LIN16:
|
|
|
|
bpp = 16;
|
|
|
|
break;
|
|
|
|
case M_LIN32:
|
|
|
|
bpp = 32;
|
2009-05-03 00:28:34 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bpp = 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
vga.draw.linear_base = vga.mem.linear;
|
|
|
|
vga.draw.linear_mask = VGA_MEMORY - 1;
|
|
|
|
switch (vga.mode) {
|
|
|
|
case M_VGA:
|
|
|
|
doublewidth=true;
|
|
|
|
width<<=2;
|
|
|
|
VGA_DrawLine = VGA_Draw_Linear_Line;
|
|
|
|
break;
|
|
|
|
case M_LIN8:
|
|
|
|
case M_LIN15:
|
|
|
|
case M_LIN16:
|
|
|
|
case M_LIN32:
|
2009-05-03 00:18:08 +02:00
|
|
|
width<<=3;
|
|
|
|
if (vga.crtc.mode_control & 0x8) {
|
|
|
|
doublewidth = true;
|
|
|
|
width >>= 1;
|
|
|
|
}
|
2009-05-03 00:28:34 +02:00
|
|
|
/* Use HW mouse cursor drawer if enabled */
|
|
|
|
VGA_ActivateHardwareCursor();
|
2009-05-03 00:18:08 +02:00
|
|
|
break;
|
|
|
|
case M_LIN4:
|
|
|
|
doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
|
|
|
|
vga.draw.blocks = width;
|
|
|
|
width<<=3;
|
2009-05-03 00:28:34 +02:00
|
|
|
VGA_DrawLine=VGA_Draw_Linear_Line;
|
|
|
|
vga.draw.linear_base = vga.mem.linear + VGA_CACHE_OFFSET;
|
|
|
|
vga.draw.linear_mask = 1024 * 1024 - 1;
|
2009-05-02 23:43:00 +02:00
|
|
|
break;
|
2009-05-03 00:18:08 +02:00
|
|
|
case M_EGA:
|
2009-05-03 00:02:15 +02:00
|
|
|
doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.draw.blocks = width;
|
2009-05-02 23:43:00 +02:00
|
|
|
width<<=3;
|
2009-05-03 00:28:34 +02:00
|
|
|
VGA_DrawLine=VGA_Draw_Linear_Line;
|
|
|
|
vga.draw.linear_base = vga.mem.linear + VGA_CACHE_OFFSET;
|
|
|
|
vga.draw.linear_mask = 512 * 1024 - 1;
|
2009-05-03 00:02:15 +02:00
|
|
|
break;
|
|
|
|
case M_CGA16:
|
|
|
|
doubleheight=true;
|
|
|
|
vga.draw.blocks=width*2;
|
2009-05-03 00:18:08 +02:00
|
|
|
width<<=4;
|
2009-05-03 00:02:15 +02:00
|
|
|
VGA_DrawLine=VGA_Draw_CGA16_Line;
|
2009-05-02 23:43:00 +02:00
|
|
|
break;
|
|
|
|
case M_CGA4:
|
2009-05-03 00:02:15 +02:00
|
|
|
doublewidth=true;
|
|
|
|
vga.draw.blocks=width*2;
|
|
|
|
width<<=3;
|
|
|
|
VGA_DrawLine=VGA_Draw_2BPP_Line;
|
2009-05-02 23:43:00 +02:00
|
|
|
break;
|
|
|
|
case M_CGA2:
|
2009-05-03 00:02:15 +02:00
|
|
|
doubleheight=true;
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.draw.blocks=2*width;
|
|
|
|
width<<=3;
|
2009-05-03 00:02:15 +02:00
|
|
|
VGA_DrawLine=VGA_Draw_1BPP_Line;
|
2009-05-02 23:53:27 +02:00
|
|
|
break;
|
2009-05-03 00:02:15 +02:00
|
|
|
case M_TEXT:
|
|
|
|
aspect_ratio=1.0;
|
|
|
|
vga.draw.blocks=width;
|
|
|
|
doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
|
|
|
|
width<<=3; /* 8 bit wide text font */
|
|
|
|
VGA_DrawLine=VGA_TEXT_Draw_Line;
|
|
|
|
break;
|
|
|
|
case M_HERC_GFX:
|
2009-05-02 23:53:27 +02:00
|
|
|
aspect_ratio=1.5;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.draw.blocks=width*2;
|
|
|
|
width*=16;
|
|
|
|
VGA_DrawLine=VGA_Draw_1BPP_Line;
|
|
|
|
break;
|
|
|
|
case M_TANDY2:
|
|
|
|
aspect_ratio=1.2;
|
|
|
|
doubleheight=true;
|
2009-05-03 00:18:08 +02:00
|
|
|
if (machine==MCH_PCJR) doublewidth=(vga.tandy.gfx_control & 0x8)==0x00;
|
|
|
|
else doublewidth=(vga.tandy.mode_control & 0x10)==0;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.draw.blocks=width * (doublewidth ? 4:8);
|
|
|
|
width=vga.draw.blocks*2;
|
|
|
|
VGA_DrawLine=VGA_Draw_1BPP_Line;
|
|
|
|
break;
|
|
|
|
case M_TANDY4:
|
|
|
|
aspect_ratio=1.2;
|
|
|
|
doubleheight=true;
|
2009-05-03 00:18:08 +02:00
|
|
|
if (machine==MCH_TANDY) doublewidth=(vga.tandy.mode_control & 0x10)==0;
|
|
|
|
else doublewidth=(vga.tandy.mode_control & 0x01)==0x00;
|
|
|
|
vga.draw.blocks=width * 2;
|
|
|
|
width=vga.draw.blocks*4;
|
|
|
|
if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) ||
|
2009-05-03 00:28:34 +02:00
|
|
|
(machine==MCH_PCJR && (vga.tandy.mode_control==0x0b)))
|
|
|
|
VGA_DrawLine=VGA_Draw_2BPPHiRes_Line;
|
2009-05-03 00:18:08 +02:00
|
|
|
else VGA_DrawLine=VGA_Draw_2BPP_Line;
|
2009-05-02 23:43:00 +02:00
|
|
|
break;
|
|
|
|
case M_TANDY16:
|
2009-05-03 00:02:15 +02:00
|
|
|
aspect_ratio=1.2;
|
|
|
|
doubleheight=true;
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.draw.blocks=width*2;
|
|
|
|
if (vga.tandy.mode_control & 0x1) {
|
2009-05-03 00:28:34 +02:00
|
|
|
if (( machine==MCH_TANDY ) && ( vga.tandy.mode_control & 0x10 )) {
|
|
|
|
doublewidth = false;
|
|
|
|
vga.draw.blocks*=2;
|
|
|
|
width=vga.draw.blocks*2;
|
|
|
|
} else {
|
|
|
|
doublewidth = true;
|
|
|
|
width=vga.draw.blocks*2;
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
VGA_DrawLine=VGA_Draw_4BPP_Line;
|
|
|
|
} else {
|
2009-05-03 00:28:34 +02:00
|
|
|
doublewidth=true;
|
2009-05-03 00:18:08 +02:00
|
|
|
width=vga.draw.blocks*4;
|
|
|
|
VGA_DrawLine=VGA_Draw_4BPP_Line_Double;
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
break;
|
2009-05-03 00:02:15 +02:00
|
|
|
case M_TANDY_TEXT:
|
|
|
|
doublewidth=(vga.tandy.mode_control & 0x1)==0;
|
|
|
|
case M_HERC_TEXT:
|
|
|
|
aspect_ratio=1;
|
|
|
|
doubleheight=(vga.mode!=M_HERC_TEXT);
|
2009-05-02 23:53:27 +02:00
|
|
|
vga.draw.blocks=width;
|
2009-05-03 00:02:15 +02:00
|
|
|
width<<=3;
|
2009-05-02 23:53:27 +02:00
|
|
|
VGA_DrawLine=VGA_TEXT_Draw_Line;
|
2009-05-02 23:43:00 +02:00
|
|
|
break;
|
|
|
|
default:
|
2009-05-03 00:02:15 +02:00
|
|
|
LOG(LOG_VGA,LOG_ERROR)("Unhandled VGA mode %d while checking for resolution",vga.mode);
|
2009-05-02 23:43:00 +02:00
|
|
|
};
|
2009-05-03 00:02:15 +02:00
|
|
|
VGA_CheckScanLength();
|
|
|
|
if (vga.draw.double_scan) {
|
|
|
|
height/=2;
|
|
|
|
doubleheight=true;
|
|
|
|
}
|
|
|
|
//Only check for exra double heigh in vga modes
|
|
|
|
if (!doubleheight && (vga.mode<M_TEXT) && !(vga.draw.address_line_total & 1)) {
|
|
|
|
vga.draw.address_line_total/=2;
|
|
|
|
doubleheight=true;
|
|
|
|
height/=2;
|
|
|
|
}
|
2009-05-02 23:53:27 +02:00
|
|
|
vga.draw.lines_total=height;
|
2009-05-03 00:02:15 +02:00
|
|
|
vga.draw.parts_lines=vga.draw.lines_total/vga.draw.parts_total;
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.line_length = width * ((bpp + 1) / 8);
|
|
|
|
#ifdef VGA_KEEP_CHANGES
|
|
|
|
vga.changes.active = false;
|
|
|
|
vga.changes.frame = 0;
|
|
|
|
vga.changes.writeMask = 1;
|
|
|
|
#endif
|
2009-05-03 00:44:30 +02:00
|
|
|
/*
|
|
|
|
Cheap hack to just make all > 640x480 modes have 4:3 aspect ratio
|
|
|
|
*/
|
|
|
|
if ( width >= 640 && height >= 480 ) {
|
|
|
|
aspect_ratio = ((float)width / (float)height) * ( 3.0 / 4.0);
|
|
|
|
}
|
|
|
|
// LOG_MSG("ht %d vt %d ratio %f", htotal, vtotal, aspect_ratio );
|
|
|
|
|
|
|
|
if (( width != vga.draw.width) || (height != vga.draw.height) ||
|
|
|
|
(aspect_ratio != vga.draw.aspect_ratio) ||
|
|
|
|
(vga.mode != vga.lastmode)) {
|
2009-05-03 00:18:08 +02:00
|
|
|
vga.lastmode = vga.mode;
|
2009-05-02 23:53:27 +02:00
|
|
|
PIC_RemoveEvents(VGA_VerticalTimer);
|
|
|
|
PIC_RemoveEvents(VGA_VerticalDisplayEnd);
|
2009-05-03 00:02:15 +02:00
|
|
|
PIC_RemoveEvents(VGA_DrawPart);
|
2009-05-03 00:44:30 +02:00
|
|
|
vga.draw.width = width;
|
|
|
|
vga.draw.height = height;
|
|
|
|
vga.draw.doublewidth = doublewidth;
|
|
|
|
vga.draw.doubleheight = doubleheight;
|
|
|
|
vga.draw.aspect_ratio = aspect_ratio;
|
2009-05-03 00:02:15 +02:00
|
|
|
if (doubleheight) vga.draw.lines_scaled=2;
|
|
|
|
else vga.draw.lines_scaled=1;
|
|
|
|
#if C_DEBUG
|
2009-05-02 23:53:27 +02:00
|
|
|
LOG(LOG_VGA,LOG_NORMAL)("Width %d, Height %d, fps %f",width,height,fps);
|
2009-05-03 00:02:15 +02:00
|
|
|
LOG(LOG_VGA,LOG_NORMAL)("%s width, %s height aspect %f",
|
|
|
|
doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio);
|
|
|
|
#endif
|
2009-05-03 00:18:08 +02:00
|
|
|
RENDER_SetSize(width,height,bpp,fps,aspect_ratio,doublewidth,doubleheight);
|
2009-05-03 00:28:34 +02:00
|
|
|
vga.draw.delay.framestart = PIC_FullIndex();
|
2009-05-03 00:37:32 +02:00
|
|
|
PIC_AddEvent( VGA_VerticalTimer , (float)vga.draw.delay.vtotal );
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
};
|
2009-05-03 00:18:08 +02:00
|
|
|
|
|
|
|
void VGA_KillDrawing(void) {
|
|
|
|
PIC_RemoveEvents(VGA_DrawPart);
|
|
|
|
}
|