]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Newtronic Technologies Video DAC 18 and Archos AVideo 12 emulation.
authorToni Wilen <twilen@winuae.net>
Sat, 2 May 2015 16:17:07 +0000 (19:17 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 2 May 2015 16:17:07 +0000 (19:17 +0300)
custom.cpp
drawing.cpp
include/custom.h
include/drawing.h
include/specialmonitors.h [new file with mode: 0644]
specialmonitors.cpp

index b3cfa4dd69133f8f91f95ad9b1f066129a94cfa4..91914c6d6e1356c05341e4a53fe5ee907cf716d0 100644 (file)
@@ -45,6 +45,7 @@
 #include "luascript.h"
 #include "devices.h"
 #include "rommgr.h"
+#include "specialmonitors.h"
 
 #define CUSTOM_DEBUG 0
 #define SPRITE_DEBUG 0
@@ -3747,6 +3748,13 @@ void compute_vsynctime (void)
        devices_update_sync(svpos, syncadjust);
 }
 
+void getsyncregisters(uae_u16 *phsstrt, uae_u16 *phsstop, uae_u16 *pvsstrt, uae_u16 *pvsstop)
+{
+       *phsstrt = hsstrt;
+       *phsstop = hsstop;
+       *pvsstrt = vsstrt;
+       *pvsstop = vsstop;
+}
 
 static void dumpsync (void)
 {
@@ -4965,12 +4973,12 @@ static void ADKCON (int hpos, uae_u16 v)
 static void BEAMCON0 (uae_u16 v)
 {
        if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) {
-               if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE))
-                       v &= 0x20;
                if (v != new_beamcon0) {
                        new_beamcon0 = v;
-                       if (v & ~0x20)
+                       if (v & ~0x20) {
                                write_log (_T("warning: %04X written to BEAMCON0 PC=%08X\n"), v, M68K_GETPC);
+                               dumpsync();
+                       }
                }
                calcdiw();
        }
@@ -5357,6 +5365,8 @@ static void DDFSTOP (int hpos, uae_u16 v)
 
 static void FMODE (int hpos, uae_u16 v)
 {
+       if (currprefs.monitoremu)
+               specialmonitor_store_fmode(vpos, hpos, v);
        if (! (currprefs.chipset_mask & CSMASK_AGA))
                v = 0;
        v &= 0xC00F;
@@ -7422,7 +7432,7 @@ static void vsync_handler_post (void)
 
        devices_vsync_post();
 
-       if (varsync_changed || (beamcon0 & (0x20 | 0x80)) != (new_beamcon0 & (0x20 | 0x80))) {
+       if (varsync_changed || (beamcon0 & (0x10 | 0x20 | 0x80 | 0x100 | 0x200)) != (new_beamcon0 & (0x10 | 0x20 | 0x80 | 0x100 | 0x200))) {
                init_hz ();
        } else if (vpos_count > 0 && abs (vpos_count - vpos_count_diff) > 1 && vposw_change < 4) {
                init_hz ();
@@ -7763,8 +7773,14 @@ static void hsync_handler_post (bool onvsync)
        bool ciavsyncs = !(bplcon0 & 2) || ((bplcon0 & 2) && currprefs.genlock && genlockvtoggle);
 
        CIA_hsync_posthandler (ciahsyncs);
-       if (ciahsyncs)
-               CIAB_tod_handler ((beamcon0 & 0x80) ? hsstop : 18);
+       if (ciahsyncs) {
+               if (beamcon0 & (0x80 | 0x100)) {
+                       if (hsstop < (maxhpos & ~1) && hsstrt < maxhpos)
+                               CIAB_tod_handler(hsstop);
+               } else {
+                       CIAB_tod_handler(18);
+               }
+       }
        if (currprefs.cs_ciaatod > 0) {
 #if 0
                static uae_s32 oldtick;
@@ -7791,8 +7807,8 @@ static void hsync_handler_post (bool onvsync)
 #endif
        } else if (currprefs.cs_ciaatod == 0 && ciavsyncs) {
                // CIA-A TOD counter increases when vsync pulse ends
-               if (beamcon0 & 0x80) {
-                       if (vpos == vsstop)
+               if (beamcon0 & (0x80 | 0x200)) {
+                       if (vpos == vsstop && vsstrt <= maxvpos)
                                CIAA_tod_inc (lof_store ? hsstop : hsstop + hcenter);
                } else {
                        if (vpos == (currprefs.ntscmode ? VSYNC_ENDLINE_NTSC : VSYNC_ENDLINE_PAL)) {
index efa1687270849fdd3a43591f726515feeeb8bffa..e73c725451758fbcbd450bc7c1758838e875e8a7 100644 (file)
@@ -50,8 +50,7 @@ happening, all ports should restrict window widths to be multiples of 16 pixels.
 #include "inputdevice.h"
 #include "debug.h"
 #include "cd32_fmv.h"
-
-extern bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*);
+#include "specialmonitors.h"
 
 extern int sprite_buffer_res;
 int lores_factor, lores_shift;
@@ -2788,6 +2787,9 @@ static void init_drawing_frame (void)
        int i, maxline;
        static int frame_res_old;
 
+       if (currprefs.gfx_resolution != changed_prefs.gfx_resolution)
+               return;
+
        if (lines_count > 0) {
                int largest_count = 0;
                int largest_count_res = 0;
@@ -2819,10 +2821,16 @@ static void init_drawing_frame (void)
                                autoswitch_old_resolution = RES_HIRES;
                                write_log(_T("Programmed mode autores = %d -> %d (%d)\n"), changed_prefs.gfx_resolution, newres, largest_res);
                                changed_prefs.gfx_resolution = newres;
+                               set_config_changed();
+                               return;
                        }
-               } else if (autoswitch_old_resolution == 1) {
-                       changed_prefs.gfx_resolution = RES_HIRES;
+               } else if (autoswitch_old_resolution == RES_HIRES) {
                        autoswitch_old_resolution = 0;
+                       if (changed_prefs.gfx_resolution != RES_HIRES) {
+                               changed_prefs.gfx_resolution = RES_HIRES;
+                               set_config_changed();
+                               return;
+                       }
                }
 
                if (currprefs.gfx_autoresolution) {
index d3d8a9d35767bcb6eea1d210a2cdbf9618490851..4ab060353cbab28160c5a6016a0aff34191b3eb6 100644 (file)
@@ -237,5 +237,6 @@ extern bool isvga (void);
 extern int current_maxvpos (void);
 extern struct chipset_refresh *get_chipset_refresh (void);
 extern void compute_framesync (void);
+extern void getsyncregisters(uae_u16 *phsstrt, uae_u16 *phsstop, uae_u16 *pvsstrt, uae_u16 *pvsstop);
 
 #endif /* CUSTOM_H */
index 319f86cafe8700cfec4b58e24f2362ede01d240d..847551f70ec782a35c6cd07ef30af6844814019a 100644 (file)
@@ -45,6 +45,7 @@ before it appears on-screen. (TW: display emulation now does this automatically)
 
 extern int lores_factor, lores_shift, interlace_seen;
 extern bool aga_mode, direct_rgb;
+extern int visible_left_border, visible_right_border;
 
 STATIC_INLINE int coord_hw_to_window_x (int x)
 {
diff --git a/include/specialmonitors.h b/include/specialmonitors.h
new file mode 100644 (file)
index 0000000..a21e433
--- /dev/null
@@ -0,0 +1,3 @@
+
+bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*);
+void specialmonitor_store_fmode(int vpos, int hpos, uae_u16 fmode);
index cc9ad213ea9eb7824b5fc16f696ae1fc20c28d99..310a9b569bc341411435013180c6d42ca81668ac 100755 (executable)
@@ -7,15 +7,38 @@
 #include "options.h"
 #include "xwin.h"
 #include "custom.h"
+#include "drawing.h"
+#include "specialmonitors.h"
 
 static bool automatic;
 static int monitor;
 
 extern unsigned int bplcon0;
-extern int interlace_seen;
 
 static uae_u8 graffiti_palette[256 * 4];
 
+STATIC_INLINE uae_u8 FVR(struct vidbuffer *src, uae_u8 *dataline)
+{
+       if (src->pixbytes == 4)
+               return dataline[2];
+       else
+               return ((((uae_u16*)dataline)[0] >> 11) & 31) << 3;
+}
+STATIC_INLINE uae_u8 FVG(struct vidbuffer *src, uae_u8 *dataline)
+{
+       if (src->pixbytes == 4)
+               return dataline[1];
+       else
+               return ((((uae_u16*)dataline)[0] >> 5) & 63) << 2;
+}
+STATIC_INLINE uae_u8 FVB(struct vidbuffer *src, uae_u8 *dataline)
+{
+       if (src->pixbytes == 4)
+               return dataline[0];
+       else
+               return ((((uae_u16*)dataline)[0] >> 0) & 31) << 2;
+}
+
 STATIC_INLINE bool FR(struct vidbuffer *src, uae_u8 *dataline)
 {
        if (src->pixbytes == 4)
@@ -70,7 +93,6 @@ STATIC_INLINE uae_u8 FIRGB(struct vidbuffer *src, uae_u8 *dataline)
        return v;
 }
 
-
 STATIC_INLINE void PRGB(struct vidbuffer *dst, uae_u8 *dataline, uae_u8 r, uae_u8 g, uae_u8 b)
 {
        if (dst->pixbytes == 4) {
@@ -85,6 +107,52 @@ STATIC_INLINE void PRGB(struct vidbuffer *dst, uae_u8 *dataline, uae_u8 r, uae_u
        }
 }
 
+STATIC_INLINE void PUT_PRGB(uae_u8 *d, uae_u8 *d2, struct vidbuffer *dst, uae_u8 r, uae_u8 g, uae_u8 b, int xadd, int doublelines, bool hdouble)
+{
+       if (hdouble)
+               PRGB(dst, d - dst->pixbytes, r, g, b);
+       PRGB(dst, d, r, g, b);
+       if (xadd > 4) {
+               PRGB(dst, d + 1 * dst->pixbytes, r, g, b);
+               if (hdouble)
+                       PRGB(dst, d + 2 * dst->pixbytes, r, g, b);
+       }
+       if (doublelines) {
+               if (hdouble)
+                       PRGB(dst, d2 - dst->pixbytes, r, g, b);
+               PRGB(dst, d2, r, g, b);
+               if (xadd > 4) {
+                       PRGB(dst, d2 + 1 * dst->pixbytes, r, g, b);
+                       if (hdouble)
+                               PRGB(dst, d2 + 2 * dst->pixbytes, r, g, b);
+               }
+       }
+}
+
+STATIC_INLINE void PUT_AMIGARGB(uae_u8 *d, uae_u8 *s, uae_u8 *d2, uae_u8 *s2, struct vidbuffer *dst, int xadd, int doublelines, bool hdouble)
+{
+       if (dst->pixbytes == 4) {
+               if (hdouble)
+                       ((uae_u32*)d)[-1] = ((uae_u32*)s)[-1];
+               ((uae_u32*)d)[0] = ((uae_u32*)s)[0];
+       } else {
+               if (hdouble)
+                       ((uae_u16*)d)[-1] = ((uae_u16*)s)[-1];
+               ((uae_u16*)d)[0] = ((uae_u16*)s)[0];
+       }
+       if (doublelines) {
+               if (dst->pixbytes == 4) {
+                       if (hdouble)
+                               ((uae_u32*)d2)[-1] = ((uae_u32*)s2)[-1];
+                       ((uae_u32*)d2)[0] = ((uae_u32*)s2)[0];
+               } else {
+                       if (hdouble)
+                               ((uae_u16*)d2)[-1] = ((uae_u16*)s2)[-1];
+                       ((uae_u16*)d2)[0] = ((uae_u16*)s2)[0];
+               }
+       }
+}
+
 static void clearmonitor(struct vidbuffer *dst)
 {
        uae_u8 *p = dst->bufmem;
@@ -161,6 +229,304 @@ static bool dctv(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines,
        return true;
 }
 
+static uae_u16 avideo_previous_fmode[2];
+
+static uae_u8 *avideo_buffer;
+static int av24_offset;
+#define AVIDEO_VRAM_WIDTH 800
+#define AVIDEO_VRAM_HEIGHT 800
+#define AVIDEO_VRAM_BYTES 4
+
+static bool avideo(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, int oddlines)
+{
+       int y, x, vdbl, hdbl;
+       int ystart, yend, isntsc;
+       int xadd;
+       int mode;
+       int offset = -1;
+       bool writetovram;
+       bool av24 = currprefs.monitoremu == MONITOREMU_AVIDEO24;
+       bool lownybble = false;
+       bool doublebuffer = false;
+       uae_u16 fmode;
+       
+       fmode = avideo_previous_fmode[oddlines];
+
+       if (currprefs.chipset_mask & CSMASK_AGA)
+               return false;
+
+       if (av24) {
+               if (fmode & 0x40)
+                       mode = 6;
+               else
+                       mode = 0;
+               writetovram = (fmode  & (0x08 | 0x10 | 0x20)) != 0;
+       } else {
+               mode = fmode & 7;
+               if (mode == 1)
+                       offset = 0;
+               else if (mode == 3)
+                       offset = 1;
+               else if (mode == 2)
+                       offset = 2;
+               writetovram = offset >= 0;
+       }
+
+       if (!mode)
+               return false;
+
+       if (!avideo_buffer) {
+               avideo_buffer = xcalloc(uae_u8, AVIDEO_VRAM_WIDTH * AVIDEO_VRAM_HEIGHT * AVIDEO_VRAM_BYTES);
+       }
+
+       //write_log(_T("%04x %d %d %d\n"), avideo_previous_fmode[oddlines], mode, offset, writetovram);
+
+       isntsc = (beamcon0 & 0x20) ? 0 : 1;
+       if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+               isntsc = currprefs.ntscmode ? 1 : 0;
+
+       vdbl = gfxvidinfo.ychange;
+       hdbl = gfxvidinfo.xchange;
+
+       xadd = ((1 << 1) / hdbl) * src->pixbytes;
+
+       ystart = isntsc ? VBLANK_ENDLINE_NTSC : VBLANK_ENDLINE_PAL;
+       yend = isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL;
+
+       for (y = ystart; y < yend; y++) {
+               int oddeven = 0;
+               uae_u8 prev = 0;
+               int yoff = (((y * 2 + oddlines) - src->yoffset) / vdbl);
+               if (yoff < 0)
+                       continue;
+               if (yoff >= src->inheight)
+                       continue;
+               uae_u8 *line = src->bufmem + yoff * src->rowbytes;
+               uae_u8 *dstline = dst->bufmem + (((y * 2 + oddlines) - dst->yoffset) / vdbl) * dst->rowbytes;
+               uae_u8 *vramline = avideo_buffer + y * 2 * AVIDEO_VRAM_WIDTH * AVIDEO_VRAM_BYTES;
+
+               if (av24) {
+                       vramline += av24_offset;
+               } else {
+                       if (fmode & 0x10)
+                               vramline += AVIDEO_VRAM_WIDTH * AVIDEO_VRAM_BYTES;
+               }
+
+               for (x = 0; x < src->inwidth; x++) {
+                       uae_u8 *s = line + ((x << 1) / hdbl) * src->pixbytes;
+                       uae_u8 *d = dstline + ((x << 1) / hdbl) * dst->pixbytes;
+                       uae_u8 *vramptr = vramline + ((x << 1) / hdbl) * AVIDEO_VRAM_BYTES;
+                       uae_u8 *s2 = s + src->rowbytes;
+                       uae_u8 *d2 = d + dst->rowbytes;
+                       if (writetovram) {
+                               uae_u8 val[3];
+                               val[0] = FVR(src, s) >> 4;
+                               val[1] = FVG(src, s) >> 4;
+                               val[2] = FVB(src, s) >> 4;
+                               if (av24) {  // 021 012 102 120 210 201
+                                       uae_u8 v;
+
+                                       if (fmode & 0x08) {
+                                               v = (((val[0] >> 0) & 1) << 3) | (((val[0] >> 1) & 1) << 0);
+                                               vramptr[0] &= ~(0x08 | 0x01);
+                                               vramptr[0] |= v;
+                                               v = (((val[1] >> 0) & 1) << 2);
+                                               vramptr[1] &= ~(0x04);
+                                               vramptr[1] |= v;
+                                               v = (((val[2] >> 0) & 1) << 1);
+                                               vramptr[2] &= ~(0x02);
+                                               vramptr[2] |= v;
+                                       }
+
+                                       if (fmode & 0x10) {
+                                               v = (((val[1] >> 1) & 1) << 3) | (((val[1] >> 2) & 1) << 0);
+                                               vramptr[1] &= ~(0x08 | 0x01);
+                                               vramptr[1] |= v;
+                                               v = (((val[2] >> 1) & 1) << 2);
+                                               vramptr[2] &= ~(0x04);
+                                               vramptr[2] |= v;
+                                               v = (((val[0] >> 2) & 1) << 1);
+                                               vramptr[0] &= ~(0x02);
+                                               vramptr[0] |= v;
+                                       }
+
+                                       if (fmode & 0x20) {
+                                               v = (((val[2] >> 2) & 1) << 3) | (((val[2] >> 3) & 1) << 0);
+                                               vramptr[2] &= ~(0x08 | 0x01);
+                                               vramptr[2] |= v;
+                                               v = (((val[0] >> 3) & 1) << 2);
+                                               vramptr[0] &= ~(0x04);
+                                               vramptr[0] |= v;
+                                               v = (((val[2] >> 3) & 1) << 1);
+                                               vramptr[1] &= ~(0x02);
+                                               vramptr[1] |= v;
+                                       }
+
+                               } else {
+
+                                       uae_u8 v = val[offset];
+                                       vramptr[offset] = (v << 4) | (v & 15);
+
+                               }
+                       }
+                       if (writetovram || mode == 7 || (mode == 6 && FVR(src, s) == 0 && FVG(src, s) == 0 && FVB(src, s) == 0)) {
+                               uae_u8 r, g, b;
+                               if (av24) {
+                                       r = vramptr[0] << 4;
+                                       g = vramptr[1] << 4;
+                                       b = vramptr[2] << 4;
+                               } else {
+                                       r = vramptr[0];
+                                       g = vramptr[1];
+                                       b = vramptr[2];
+                               }
+                               if (doublebuffer) {
+                                       r = (r << 4) | (r & 15);
+                                       g = (g << 4) | (g & 15);
+                                       b = (b << 4) | (b & 15);
+                               }
+                               PUT_PRGB(d, d2, dst, r, g, b, xadd, doublelines, false);
+                       } else {
+                               PUT_AMIGARGB(d, s, d2, s2, dst, xadd, doublelines, false);
+                       }
+               }
+       }
+
+       dst->nativepositioning = true;
+       if (monitor != MONITOREMU_AVIDEO12 && monitor != MONITOREMU_AVIDEO24) {
+               monitor = av24 ? MONITOREMU_AVIDEO24 : MONITOREMU_AVIDEO12;
+               write_log (_T("AVIDEO mode\n"));
+       }
+
+       return true;
+}
+
+void specialmonitor_store_fmode(int vpos, int hpos, uae_u16 fmode)
+{
+       write_log(_T("%04x\n"), fmode);
+       fmode &= 0xff;
+       if (fmode == 0x91)
+               av24_offset = AVIDEO_VRAM_WIDTH * AVIDEO_VRAM_BYTES;
+       else if (fmode == 0x92)
+               av24_offset = 0;
+        avideo_previous_fmode[lof_store ? 0 : 1] = fmode;
+}
+
+static bool do_avideo(struct vidbuffer *src, struct vidbuffer *dst)
+{
+       bool v;
+       if (interlace_seen) {
+               if (currprefs.gfx_iscanlines) {
+                       v = avideo(src, dst, false, lof_store ? 0 : 1);
+               } else {
+                       v = avideo(src, dst, false, 0);
+                       v |= avideo(src, dst, false, 1);
+               }
+       } else {
+               v = avideo(src, dst, true, 0);
+       }
+       return v;
+}
+
+
+static bool videodac18(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, int oddlines)
+{
+       int y, x, vdbl, hdbl;
+       int ystart, yend, isntsc;
+       int xadd;
+       uae_u16 hsstrt, hsstop, vsstrt, vsstop;
+       int xstart, xstop;
+
+       if ((beamcon0 & (0x80 | 0x100 | 0x200 | 0x10)) != 0x300)
+               return false;
+       getsyncregisters(&hsstrt, &hsstop, &vsstrt, &vsstop);
+
+       if (hsstop >= (maxhpos & ~1))
+               hsstrt = 0;
+       xstart = ((hsstrt * 2) << RES_MAX) - src->xoffset;
+       xstop = ((hsstop * 2) << RES_MAX) - src->xoffset;
+
+       isntsc = (beamcon0 & 0x20) ? 0 : 1;
+       if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+               isntsc = currprefs.ntscmode ? 1 : 0;
+
+       vdbl = gfxvidinfo.ychange;
+       hdbl = gfxvidinfo.xchange;
+
+       xadd = ((1 << 1) / hdbl) * src->pixbytes;
+
+       ystart = isntsc ? VBLANK_ENDLINE_NTSC : VBLANK_ENDLINE_PAL;
+       yend = isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL;
+
+       uae_u8 r = 0, g = 0, b = 0;
+       for (y = ystart; y < yend; y++) {
+               int oddeven = 0;
+               uae_u8 prev = 0;
+               int yoff = (((y * 2 + oddlines) - src->yoffset) / vdbl);
+               if (yoff < 0)
+                       continue;
+               if (yoff >= src->inheight)
+                       continue;
+               uae_u8 *line = src->bufmem + yoff * src->rowbytes;
+               uae_u8 *dstline = dst->bufmem + (((y * 2 + oddlines) - dst->yoffset) / vdbl) * dst->rowbytes;
+               r = g = b = 0;
+               for (x = 0; x < src->inwidth; x++) {
+                       uae_u8 *s = line + ((x << 1) / hdbl) * src->pixbytes;
+                       uae_u8 *d = dstline + ((x << 1) / hdbl) * dst->pixbytes;
+                       uae_u8 *s2 = s + src->rowbytes;
+                       uae_u8 *d2 = d + dst->rowbytes;
+                       uae_u8 newval = FIRGB(src, s);
+                       uae_u8 val = prev | (newval << 4);
+                       if (oddeven) {
+                               int mode = val >> 6;
+                               int data = (val & 63) << 2;
+                               if (mode == 0) {
+                                       r = data;
+                                       g = data;
+                                       b = data;
+                               } else if (mode == 1) {
+                                       b = data;
+                               } else if (mode == 2) {
+                                       r = data;
+                               } else {
+                                       g = data;
+                               }
+                               if (y >= vsstrt && y < vsstop && x >= xstart && y < xstop) {
+                                       PUT_PRGB(d, d2, dst, r, g, b, xadd, doublelines, true);
+                               } else {
+                                       PUT_AMIGARGB(d, s, d2, s2, dst, xadd, doublelines, true);
+                               }
+                       }
+                       oddeven = oddeven ? 0 : 1;
+                       prev = val >> 4;
+               }
+       }
+
+       dst->nativepositioning = true;
+       if (monitor != MONITOREMU_VIDEODAC18) {
+               monitor = MONITOREMU_VIDEODAC18;
+               write_log (_T("Video DAC 18 mode\n"));
+       }
+
+       return true;
+}
+
+static bool do_videodac18(struct vidbuffer *src, struct vidbuffer *dst)
+{
+       bool v;
+       if (interlace_seen) {
+               if (currprefs.gfx_iscanlines) {
+                       v = videodac18(src, dst, false, lof_store ? 0 : 1);
+               } else {
+                       v = videodac18(src, dst, false, 0);
+                       v |= videodac18(src, dst, false, 1);
+               }
+       } else {
+               v = videodac18(src, dst, true, 0);
+       }
+       return v;
+}
+
 static const uae_u8 ham_e_magic_cookie[] = { 0xa2, 0xf5, 0x84, 0xdc, 0x6d, 0xb0, 0x7f  };
 static const uae_u8 ham_e_magic_cookie_reg = 0x14;
 static const uae_u8 ham_e_magic_cookie_ham = 0x18;
@@ -283,17 +649,11 @@ static bool ham_e(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines
                                        if (hameplus) {
                                                uae_u8 ar, ag, ab;
 
-                                               if (abs(r - or) < 64 && abs(g - og) < 64 && abs(b - ob) < 64) {
-                                                       ar = (r + or) / 2;
-                                                       ag = (g + og) / 2;
-                                                       ab = (b + ob) / 2;
-                                               } else {
-                                                       ar = r;
-                                                       ag = g;
-                                                       ab = b;
-                                               }
+                                               ar = (r + or) / 2;
+                                               ag = (g + og) / 2;
+                                               ab = (b + ob) / 2;
 
-                                               if (xadd > 2) {
+                                               if (xadd > 4) {
                                                        PRGB(dst, d - dst->pixbytes, ar, ag, ab);
                                                        PRGB(dst, d, ar, ag, ab);
                                                        PRGB(dst, d + 1 * dst->pixbytes, r, g, b);
@@ -316,38 +676,10 @@ static bool ham_e(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines
                                                og = g;
                                                ob = b;
                                        } else {
-                                               PRGB(dst, d - dst->pixbytes, r, g, b);
-                                               PRGB(dst, d, r, g, b);
-                                               if (xadd > 2) {
-                                                       PRGB(dst, d + 1 * dst->pixbytes, r, g, b);
-                                                       PRGB(dst, d + 2 * dst->pixbytes, r, g, b);
-                                               }
-                                               if (doublelines) {
-                                                       PRGB(dst, d2 - dst->pixbytes, r, g, b);
-                                                       PRGB(dst, d2, r, g, b);
-                                                       if (xadd > 2) {
-                                                               PRGB(dst, d2 + 1 * dst->pixbytes, r, g, b);
-                                                               PRGB(dst, d2 + 2 * dst->pixbytes, r, g, b);
-                                                       }
-                                               }
+                                               PUT_PRGB(d, d2, dst, r, g, b, xadd, doublelines, true);
                                        }
                                } else {
-                                       if (dst->pixbytes == 4) {
-                                               ((uae_u32*)d)[-1] = ((uae_u32*)s)[-1];
-                                               ((uae_u32*)d)[0] = ((uae_u32*)s)[0];
-                                       } else {
-                                               ((uae_u16*)d)[-1] = ((uae_u16*)s)[-1];
-                                               ((uae_u16*)d)[0] = ((uae_u16*)s)[0];
-                                       }
-                                       if (doublelines) {
-                                               if (dst->pixbytes == 4) {
-                                                       ((uae_u32*)d2)[-1] = ((uae_u32*)s2)[-1];
-                                                       ((uae_u32*)d2)[0] = ((uae_u32*)s2)[0];
-                                               } else {
-                                                       ((uae_u16*)d2)[-1] = ((uae_u16*)s2)[-1];
-                                                       ((uae_u16*)d2)[0] = ((uae_u16*)s2)[0];
-                                               }
-                                       }
+                                       PUT_AMIGARGB(d, s, d2, s2, dst, xadd, doublelines, true);
                                }
                        }
 
@@ -746,31 +1078,38 @@ static bool a2024(struct vidbuffer *src, struct vidbuffer *dst)
 
 static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *dst)
 {
+       automatic = false;
        if (currprefs.monitoremu == MONITOREMU_AUTO) {
                automatic = true;
                bool v = a2024(src, dst);
                if (!v)
                        v = graffiti(src, dst);
+               if (!v)
+                       v = do_videodac18(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);
        } else if (currprefs.monitoremu == MONITOREMU_DCTV) {
-               automatic = false;
                return dctv(src, dst, false, 0);
        } else if (currprefs.monitoremu == MONITOREMU_HAM_E || currprefs.monitoremu == MONITOREMU_HAM_E_PLUS) {
                bool v;
-               automatic = false;
                if (interlace_seen) {
-                       v = ham_e(src, dst, false, 0);
-                       v |= ham_e(src, dst, false, 1);
+                       if (currprefs.gfx_iscanlines) {
+                               v = ham_e(src, dst, false, lof_store ? 0 : 1);
+                       } else {
+                               v = ham_e(src, dst, false, 0);
+                               v |= ham_e(src, dst, false, 1);
+                       }
                } else {
                        v = ham_e(src, dst, true, 0);
                }
                return v;
+       } else if (currprefs.monitoremu == MONITOREMU_VIDEODAC18) {
+               return do_videodac18(src, dst);
+       } else if (currprefs.monitoremu == MONITOREMU_AVIDEO12 || currprefs.monitoremu == MONITOREMU_AVIDEO24) {
+               return do_avideo(src, dst);
        }
        return false;
 }