]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
2400b1
authorToni Wilen <twilen@winuae.net>
Sat, 26 Nov 2011 12:18:54 +0000 (14:18 +0200)
committerToni Wilen <twilen@winuae.net>
Sat, 26 Nov 2011 12:18:54 +0000 (14:18 +0200)
specialmonitors.cpp [new file with mode: 0755]

diff --git a/specialmonitors.cpp b/specialmonitors.cpp
new file mode 100755 (executable)
index 0000000..1533e37
--- /dev/null
@@ -0,0 +1,391 @@
+#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 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) {
+               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 (srcp[2] & 0x80) // R
+                                       chunky[3] |= mask;
+                               if (srcp[1] & 0x80) // G
+                                       chunky[2] |= mask;
+                               if (srcp[0] & 0x80) // B
+                                       chunky[1] |= mask;
+                               if (srcp[0] & 0x10) // 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(L"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;
+                                                       }
+                                               } 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];
+                                       dstp[2] = r;
+                                       dstp[1] = g;
+                                       dstp[0] = b;
+                                       dstp += dst->pixbytes;
+                                       dstp[2] = r;
+                                       dstp[1] = g;
+                                       dstp[0] = b;
+                                       dstp += dst->pixbytes;
+                                       
+                                       if (gfxvidinfo.xchange == 1 && !hires) {
+                                               dstp[2] = r;
+                                               dstp[1] = g;
+                                               dstp[0] = b;
+                                               dstp += dst->pixbytes;
+                                               dstp[2] = r;
+                                               dstp[1] = g;
+                                               dstp[0] = 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 (L"GRAFFITI %s mode\n", hires ? L"hires" : L"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;
+       int idline;
+       int total_width, total_height;
+       
+       idline = currprefs.ntscmode ? 21 : 29;
+
+       if (src->yoffset > (idline << VRES_MAX))
+               return false;
+
+       dbl = gfxvidinfo.ychange == 1 ? 2 : 1;
+       doff = (128 * 2 / gfxvidinfo.xchange) * src->pixbytes;
+       // 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 (L"%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
+
+       px = py = 0;
+       if (dataline[1 * doff + 0] & 0x80) // 1:B FN2
+               px |= 2;
+       if (dataline[1 * doff + 1] & 0x80) // 1:G FN1
+               px |= 1;
+       if (dataline[1 * doff + 2] & 0x80) // 1:R FN0
+               py |= 1;
+
+       f64 = (dataline[0 * doff + 2] & 0x80) != 0;                     // 0:R
+       interlace = (dataline[0 * doff + 1] & 0x80) != 0;       // 0:G (*Always zero)
+       if ((dataline[0 * doff + 0] & 0x80) != 0)                       // 0:B = 0
+               return false;
+       if ((dataline[0 * doff + 0] & 0x10) == 0)                       // 0:I = 1
+               return false;
+       expand = (dataline[1 * doff + 0] & 0x10) != 0;          // 1:I (*Always set)
+       enp = (dataline[2 * doff + 2] & 0x80) ? 1 : 0;          // 2:R (*ENP=3)
+       enp |= (dataline[2 * doff + 1] & 0x80) ? 2 : 0;         // 2:G
+       wpb = (dataline[2 * doff + 0] & 0x80) != 0;                     // 2:B (*Always zero)
+       if ((dataline[2 * doff + 0] & 0x10) != 0)                       // 2:I = 0
+               return false;
+       dpl = (dataline[3 * doff + 2] & 0x80) ? 1 : 0;          // 3:R (*DPL=3)
+       dpl |= (dataline[3 * doff + 1] & 0x80) ? 2 : 0;         // 3:G
+       less16 = (dataline[3 * doff + 0] & 0x80) != 0;          // 3:B
+       if ((dataline[3 * doff + 0] & 0x10) == 0)                       // 3:I = 1
+               return false;
+
+       /* (*) = AOS A2024 driver static bits. Not yet implemented in emulation. */
+
+       if (f64) {
+               panel_width = 336;
+               panel_width_draw = 352;
+               pxcnt = 3;
+               hires = false;
+               srcxoffset = 113;
+               if (px > 2)
+                       return false;
+       } else {
+               panel_width = 512;
+               panel_width_draw = 512;
+               pxcnt = 2;
+               hires = true;
+               srcxoffset = 129;
+               if (px > 1)
+                       return false;
+       }
+       panel_height = currprefs.ntscmode ? 400 : 512;
+
+
+#if 0
+       write_log (L"0 = F6-4:%d INTERLACE:%d\n", f64, interlace);
+       write_log (L"1 = FN:%d EXPAND:%d\n", py + px *2, expand);
+       write_log (L"2 = ENP:%d WPB=%d\n", enp, wpb);
+       write_log (L"3 = DPL:%d LESS16=%d\n", dpl, less16);
+#endif
+#if 0
+       write_log (L"%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
+
+       total_width = panel_width * (pxcnt - 1) + panel_width_draw;
+       if (total_width > 1024)
+               total_width = 1024;
+       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 (srcp[2] & 0x80) // R
+                               c1 |= 2;
+                       if (srcp[1] & 0x80) // G
+                               c2 |= 2;
+                       if (srcp[0] & 0x80) // B
+                               c1 |= 1;
+                       if (srcp[0] & 0x10) // I
+                               c2 |= 1;
+                       if (dbl == 1) {
+                               c1 = (c1 + c2 + 1) / 2;
+                               c1 = (c1 << 6) | (c1 << 4) | (c1 << 2);
+                               dstp1[0] = c1;
+                               dstp1[1] = c1;
+                               dstp1[2] = c1;
+                       } else {
+                               c1 = (c1 << 6) | (c1 << 4) | (c1 << 2);
+                               c2 = (c2 << 6) | (c2 << 4) | (c2 << 2);
+                               dstp1[0] = c1;
+                               dstp1[1] = c1;
+                               dstp1[2] = c1;
+                               dstp2[0] = c2;
+                               dstp2[1] = c2;
+                               dstp2[2] = 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 (L"A2024 %dHz mode\n", hires ? 10 : 15);
+       }
+
+       return true;
+}
+
+static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *dst)
+{
+       if (src->pixbytes != 4)
+               return false;
+
+       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) {
+                       monitor = 0;
+                       write_log (L"Native mode\n");
+               }
+               return false;
+       }
+       return true;
+}