WinUAE/specialmonitors.cpp
Toni Wilen 65e20bb66f 2420b4
2012-06-03 13:38:28 +03:00

457 lines
12 KiB
C++
Executable File

#include "sysconfig.h"
#include "sysdeps.h"
#include <ctype.h>
#include <assert.h>
#include "options.h"
#include "xwin.h"
#include "custom.h"
static bool automatic;
static int monitor;
extern unsigned int bplcon0;
static uae_u8 graffiti_palette[256 * 4];
STATIC_INLINE bool FR(struct vidbuffer *src, uae_u8 *dataline)
{
if (src->pixbytes == 4)
return (dataline[2] & 0x80) != 0;
else
return ((dataline[1] >> 7) & 1) != 0;
}
STATIC_INLINE bool FG(struct vidbuffer *src, uae_u8 *dataline)
{
if (src->pixbytes == 4)
return (dataline[1] & 0x80) != 0;
else
return ((dataline[1] >> 2) & 1) != 0;
}
STATIC_INLINE bool FB(struct vidbuffer *src, uae_u8 *dataline)
{
if (src->pixbytes == 4)
return (dataline[0] & 0x80) != 0;
else
return ((dataline[0] >> 4) & 1) != 0;
}
STATIC_INLINE bool FI(struct vidbuffer *src, uae_u8 *dataline)
{
if (src->pixbytes == 4)
return (dataline[0] & 0x10) != 0;
else
return ((dataline[0] >> 1) & 1) != 0;
}
STATIC_INLINE void PRGB(struct vidbuffer *dst, uae_u8 *dataline, uae_u8 r, uae_u8 g, uae_u8 b)
{
if (dst->pixbytes == 4) {
dataline[0] = b;
dataline[1] = g;
dataline[2] = r;
} else {
r >>= 3;
g >>= 2;
b >>= 3;
((uae_u16*)dataline)[0] = (r << 11) | (g << 5) | b;
}
}
static void clearmonitor(struct vidbuffer *dst)
{
uae_u8 *p = dst->bufmem;
for (int y = 0; y < dst->height_allocated; y++) {
memset(p, 0, dst->width_allocated * dst->pixbytes);
p += dst->rowbytes;
}
}
static bool graffiti(struct vidbuffer *src, struct vidbuffer *dst)
{
int y, x;
int ystart, yend, isntsc;
int xstart, xend;
uae_u8 *srcbuf, *srcend;
uae_u8 *dstbuf;
bool command, hires, found;
int xadd, xpixadd, extrapix;
int waitline = 0, dbl;
uae_u8 read_mask = 0xff, color = 0, color2 = 0;
if (!(bplcon0 & 0x0100)) // GAUD
return false;
command = true;
found = false;
isntsc = (beamcon0 & 0x20) ? 0 : 1;
if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
isntsc = currprefs.ntscmode ? 1 : 0;
dbl = gfxvidinfo.ychange == 1 ? 2 : 1;
ystart = isntsc ? VBLANK_ENDLINE_NTSC : VBLANK_ENDLINE_PAL;
yend = isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL;
if (src->yoffset >= (ystart << VRES_MAX))
ystart = src->yoffset >> VRES_MAX;
xadd = gfxvidinfo.xchange == 1 ? src->pixbytes * 2 : src->pixbytes;
xpixadd = gfxvidinfo.xchange == 1 ? 4 : 2;
xstart = 0x1c * 2 + 1;
xend = 0xf0 * 2 + 1;
srcbuf = src->bufmem + (((ystart << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes + (((xstart << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * src->pixbytes;
srcend = src->bufmem + (((yend << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes;
extrapix = 0;
dstbuf = dst->bufmem + (((ystart << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * dst->rowbytes + (((xstart << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * dst->pixbytes;
y = 0;
while (srcend > srcbuf && dst->bufmemend > dstbuf) {
uae_u8 *srcp = srcbuf + extrapix;
uae_u8 *dstp = dstbuf;
x = xstart;
while (x < xend) {
uae_u8 mask = 0x80;
uae_u8 chunky[4] = { 0, 0, 0, 0 };
while (mask) {
if (FR(src, srcp)) // R
chunky[3] |= mask;
if (FG(src, srcp)) // G
chunky[2] |= mask;
if (FB(src, srcp)) // B
chunky[1] |= mask;
if (FI(src, srcp)) // I
chunky[0] |= mask;
srcp += xadd;
mask >>= 1;
}
if (command) {
if (chunky[0] || chunky[1] || chunky[2] || chunky[3] || found) {
for (int pix = 0; pix < 2; pix++) {
uae_u8 cmd = chunky[pix * 2 + 0];
uae_u8 parm = chunky[pix * 2 + 1];
#if 0
//if (cmd != 0)
write_log(_T("X=%d Y=%d %02x = %02x (%d %d)\n"), x, y, cmd, parm, color, color2);
#endif
if (automatic && cmd >= 0x40)
return false;
if (cmd != 0)
found = true;
if (cmd & 8) {
command = false;
dbl = 1;
waitline = 2;
if (cmd & 16) {
hires = true;
xadd /= 2;
xpixadd /= 2;
extrapix = -4 * src->pixbytes;
} else {
hires = false;
}
if (xpixadd == 0) // shres needed
return false;
if (monitor != MONITOREMU_GRAFFITI)
clearmonitor(dst);
} else if (cmd & 4) {
if ((cmd & 3) == 1) {
read_mask = parm;
} else if ((cmd & 3) == 2) {
graffiti_palette[color * 4 + color2] = (parm << 2) | (parm & 3);
color2++;
if (color2 == 3) {
color2 = 0;
color++;
}
} else if ((cmd & 3) == 0) {
color = parm;
color2 = 0;
}
}
}
}
memset(dstp, 0, dst->pixbytes * 4 * 2);
dstp += dst->pixbytes * 4 * 2;
} else if (waitline) {
memset(dstp, 0, dst->pixbytes * 4 * 2);
dstp += dst->pixbytes * 4 * 2;
} else {
for (int pix = 0; pix < 4; pix++) {
uae_u8 r, g, b, c;
c = chunky[pix] & read_mask;
r = graffiti_palette[c * 4 + 0];
g = graffiti_palette[c * 4 + 1];
b = graffiti_palette[c * 4 + 2];
PRGB(dst, dstp, r, g, b);
dstp += dst->pixbytes;
PRGB(dst, dstp, r, g, b);
dstp += dst->pixbytes;
if (gfxvidinfo.xchange == 1 && !hires) {
PRGB(dst, dstp, r, g, b);
dstp += dst->pixbytes;
PRGB(dst, dstp, r, g, b);
dstp += dst->pixbytes;
}
}
}
x += xpixadd;
}
y++;
srcbuf += src->rowbytes * dbl;
dstbuf += dst->rowbytes * dbl;
if (waitline > 0)
waitline--;
}
dst->nativepositioning = true;
if (monitor != MONITOREMU_GRAFFITI) {
monitor = MONITOREMU_GRAFFITI;
write_log (_T("GRAFFITI %s mode\n"), hires ? _T("hires") : _T("lores"));
}
return true;
}
/* A2024 information comes from US patent 4851826 */
static bool a2024(struct vidbuffer *src, struct vidbuffer *dst)
{
int y;
uae_u8 *srcbuf, *dstbuf;
uae_u8 *dataline;
int px, py, doff, pxcnt, dbl;
int panel_width, panel_width_draw, panel_height, srcxoffset;
bool f64, interlace, expand, wpb, less16;
uae_u8 enp, dpl;
bool hires, ntsc, found;
int idline;
int total_width, total_height;
dbl = gfxvidinfo.ychange == 1 ? 2 : 1;
doff = (128 * 2 / gfxvidinfo.xchange) * src->pixbytes;
found = false;
for (idline = 21; idline <= 29; idline += 8) {
if (src->yoffset > (idline << VRES_MAX))
continue;
// min 178 max 234
dataline = src->bufmem + (((idline << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes + (((200 << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * src->pixbytes;
#if 0
write_log (_T("%02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x\n"),
dataline[0 * doff + 0], dataline[0 * doff + 1], dataline[0 * doff + 2],
dataline[1 * doff + 0], dataline[1 * doff + 1], dataline[1 * doff + 2],
dataline[2 * doff + 0], dataline[2 * doff + 1], dataline[2 * doff + 2],
dataline[3 * doff + 0], dataline[3 * doff + 1], dataline[3 * doff + 2]);
#endif
if (FB(src, &dataline[0 * doff])) // 0:B = 0
continue;
if (!FI(src, &dataline[0 * doff])) // 0:I = 1
continue;
if (FI(src, &dataline[2 * doff])) // 2:I = 0
continue;
if (!FI(src, &dataline[3 * doff])) // 3:I = 1
continue;
ntsc = idline < 26;
found = true;
break;
}
if (!found)
return false;
px = py = 0;
if (FB(src, &dataline[1 * doff])) // 1:B FN2
px |= 2;
if (FG(src, &dataline[1 * doff])) // 1:G FN1
px |= 1;
if (FR(src, &dataline[1 * doff])) // 1:R FN0
py |= 1;
f64 = FR(src, &dataline[0 * doff]) != 0; // 0:R
interlace = FG(src, &dataline[0 * doff]) != 0; // 0:G (*Always zero)
expand = FI(src, &dataline[1 * doff]) != 0; // 1:I (*Always set)
enp = FR(src, &dataline[2 * doff]) ? 1 : 0; // 2:R (*ENP=3)
enp |= FG(src, &dataline[2 * doff]) ? 2 : 0; // 2:G
wpb = FB(src, &dataline[2 * doff]) != 0; // 2:B (*Always zero)
dpl = FR(src, &dataline[3 * doff]) ? 1 : 0; // 3:R (*DPL=3)
dpl |= FG(src, &dataline[3 * doff]) ? 2 : 0; // 3:G
less16 = FB(src, &dataline[3 * doff]) != 0; // 3:B
/* (*) = AOS A2024 driver static bits. Not yet implemented in emulation. */
if (f64) {
panel_width = 336;
panel_width_draw = px == 2 ? 352 : 336;
pxcnt = 3;
hires = false;
srcxoffset = 113;
if (px > 2)
return false;
total_width = 336 + 336 + 352;
} else {
panel_width = 512;
panel_width_draw = 512;
pxcnt = 2;
hires = true;
srcxoffset = 129;
if (px > 1)
return false;
total_width = 512 + 512;
}
panel_height = ntsc ? 400 : 512;
if (monitor != MONITOREMU_A2024) {
clearmonitor(dst);
}
#if 0
write_log (_T("0 = F6-4:%d INTERLACE:%d\n"), f64, interlace);
write_log (_T("1 = FN:%d EXPAND:%d\n"), py + px *2, expand);
write_log (_T("2 = ENP:%d WPB=%d\n"), enp, wpb);
write_log (_T("3 = DPL:%d LESS16=%d\n"), dpl, less16);
#endif
#if 0
write_log (_T("%02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %dx%d\n"),
dataline[0 * doff + 0], dataline[0 * doff + 1], dataline[0 * doff + 2],
dataline[1 * doff + 0], dataline[1 * doff + 1], dataline[1 * doff + 2],
dataline[2 * doff + 0], dataline[2 * doff + 1], dataline[2 * doff + 2],
dataline[3 * doff + 0], dataline[3 * doff + 1], dataline[3 * doff + 2],
px, py);
#endif
if (less16) {
total_width -= 16;
if (px == pxcnt - 1)
panel_width_draw -= 16;
}
total_height = panel_height * dbl;
srcbuf = src->bufmem + (((44 << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes + (((srcxoffset << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * src->pixbytes;
dstbuf = dst->bufmem + py * (panel_height / gfxvidinfo.ychange) * dst->rowbytes + px * ((panel_width * 2) / gfxvidinfo.xchange) * dst->pixbytes;
for (y = 0; y < (panel_height / (dbl == 1 ? 1 : 2)) / gfxvidinfo.ychange; y++) {
#if 0
memcpy (dstbuf, srcbuf, ((panel_width * 2) / gfxvidinfo.xchange) * dst->pixbytes);
#else
uae_u8 *srcp = srcbuf;
uae_u8 *dstp1 = dstbuf;
uae_u8 *dstp2 = dstbuf + dst->rowbytes;
int x;
for (x = 0; x < (panel_width_draw * 2) / gfxvidinfo.xchange; x++) {
uae_u8 c1 = 0, c2 = 0;
if (FR(src, srcp)) // R
c1 |= 2;
if (FG(src, srcp)) // G
c2 |= 2;
if (FB(src, srcp)) // B
c1 |= 1;
if (FI(src, srcp)) // I
c2 |= 1;
if (dpl == 0) {
c1 = c2 = 0;
} else if (dpl == 1) {
c1 &= 1;
c1 |= c1 << 1;
c2 &= 1;
c2 |= c2 << 1;
} else if (dpl == 2) {
c1 &= 2;
c1 |= c1 >> 1;
c2 &= 2;
c2 |= c2 >> 1;
}
if (dbl == 1) {
c1 = (c1 + c2 + 1) / 2;
c1 = (c1 << 6) | (c1 << 4) | (c1 << 2) | (c1 << 0);
PRGB(dst, dstp1, c1, c1, c1);
} else {
c1 = (c1 << 6) | (c1 << 4) | (c1 << 2) | (c1 << 0);
c2 = (c2 << 6) | (c2 << 4) | (c2 << 2) | (c2 << 0);
PRGB(dst, dstp1, c1, c1, c1);
PRGB(dst, dstp2, c2, c2, c2);
dstp2 += dst->pixbytes;
}
srcp += src->pixbytes;
if (!hires)
srcp += src->pixbytes;
dstp1 += dst->pixbytes;
}
#endif
srcbuf += src->rowbytes * dbl;
dstbuf += dst->rowbytes * dbl;
}
total_width /= 2;
total_width <<= currprefs.gfx_resolution;
dst->outwidth = total_width;
dst->outheight = total_height;
dst->inwidth = total_width;
dst->inheight = total_height;
dst->inwidth2 = total_width;
dst->inheight2 = total_height;
dst->nativepositioning = false;
if (monitor != MONITOREMU_A2024) {
monitor = MONITOREMU_A2024;
write_log (_T("A2024 %dHz %s mode\n"), hires ? 10 : 15, ntsc ? _T("NTSC") : _T("PAL"));
}
return true;
}
static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *dst)
{
if (currprefs.monitoremu == MONITOREMU_AUTO) {
automatic = true;
bool v = a2024(src, dst);
if (!v)
v = graffiti(src, dst);
return v;
} else if (currprefs.monitoremu == MONITOREMU_A2024) {
automatic = false;
return a2024(src, dst);
} else if (currprefs.monitoremu == MONITOREMU_GRAFFITI) {
automatic = false;
return graffiti(src, dst);
}
return false;
}
bool emulate_specialmonitors(struct vidbuffer *src, struct vidbuffer *dst)
{
if (!emulate_specialmonitors2(src, dst)) {
if (monitor) {
clearmonitor(dst);
monitor = 0;
write_log (_T("Native mode\n"));
}
return false;
}
return true;
}