]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
screenshot/avioutput genlock alpha.
authorToni Wilen <twilen@winuae.net>
Sat, 15 Oct 2016 16:30:31 +0000 (19:30 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 15 Oct 2016 16:30:31 +0000 (19:30 +0300)
drawing.cpp
include/keyboard.h
include/specialmonitors.h
include/videograb.h
inputdevice.cpp
inputevents.def
od-win32/avioutput.cpp
od-win32/avioutput.h
od-win32/screenshot.cpp
od-win32/win32_videograb.cpp
specialmonitors.cpp

index 092d2a4d2db5a305b3785496a5f5122c7fc310f1..5bfbae7e3945caac6ed110946b5418c9b33fbd52 100644 (file)
@@ -104,7 +104,8 @@ int detected_screen_resolution;
 static int can_use_lores = 0, frame_res, frame_res_lace;
 static int resolution_count[RES_MAX + 1], lines_count;
 static bool center_reset;
-static bool need_genlock_data, init_genlock_data;
+static bool init_genlock_data;
+bool need_genlock_data;
 
 /* Lookup tables for dual playfields.  The dblpf_*1 versions are for the case
 that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has
@@ -510,6 +511,11 @@ void set_custom_limits (int w, int h, int dx, int dy)
        int vts = visible_top_start;
        int vbs = visible_bottom_stop;
 
+       if (specialmonitor_uses_control_lines()) {
+               w = -1;
+               h = -1;
+       }
+
        if (w <= 0 || dx < 0) {
                visible_left_start = 0;
                visible_right_stop = MAX_STOP;
index 63eb2e07bba4e431426a0a660ecf8d86befa8727..da39da8982d8ec2d6c6a3a08b73616d6d7615bab 100644 (file)
@@ -177,6 +177,7 @@ enum aks { AKS_ENTERGUI = 0x200,
        AKS_RTG_C, AKS_RTG_0, AKS_RTG_1, AKS_RTG_2, AKS_RTG_3,
        AKS_CDTV_FRONT_PANEL_STOP, AKS_CDTV_FRONT_PANEL_PLAYPAUSE, AKS_CDTV_FRONT_PANEL_PREV,
        AKS_CDTV_FRONT_PANEL_NEXT, AKS_CDTV_FRONT_PANEL_REW, AKS_CDTV_FRONT_PANEL_FF,
+       AKS_VIDEOGRAB_RESTART, AKS_VIDEOGRAB_PAUSE, AKS_VIDEOGRAB_PREV, AKS_VIDEOGRAB_NEXT,
        AKS_QUALIFIER1, AKS_QUALIFIER2, AKS_QUALIFIER3, AKS_QUALIFIER4,
        AKS_QUALIFIER5, AKS_QUALIFIER6, AKS_QUALIFIER7, AKS_QUALIFIER8,
        AKS_QUALIFIER_SPECIAL, AKS_QUALIFIER_SHIFT, AKS_QUALIFIER_CONTROL,
index 96ba90a6a34e92d6214ed58fb193b6978e88a604..c735a14f1d917851699c5f437b47d51972ae9b4d 100644 (file)
@@ -4,11 +4,14 @@
 #include "memory.h"
 
 bool emulate_specialmonitors(struct vidbuffer *src, struct vidbuffer *dst);
+bool emulate_specialmonitors_line(struct vidbuffer *src, struct vidbuffer *dst, int line);
 void specialmonitor_store_fmode(int vpos, int hpos, uae_u16 fmode);
 void specialmonitor_reset(void);
 bool specialmonitor_need_genlock(void);
+bool specialmonitor_uses_control_lines(void);
 bool specialmonitor_autoconfig_init(struct autoconfig_info*);
 bool emulate_genlock(struct vidbuffer*, struct vidbuffer*);
 bool emulate_grayscale(struct vidbuffer*, struct vidbuffer*);
+bool specialmonitor_linebased(void);
 
 #endif /* UAE_SPECIALMONITORS_H */
index f38e52ff502ccdd8d4bb65597278d547a2142979..9ca681e09c4ed06ae9284c4735ec83ad57f7aee4 100644 (file)
@@ -2,4 +2,5 @@
 bool initvideograb(const TCHAR *filename);
 void uninitvideograb(void);
 bool getvideograb(long **buffer, int *width, int *height);
-void pausevideograb(bool pause);
\ No newline at end of file
+void pausevideograb(int pause);
+uae_s64 getsetpositionvideograb(uae_s64 framepos);
\ No newline at end of file
index 3b6b41d55122915870d9bc0cd49089dd56aac8e4..c62a58c133552f8dff02a32904bc6d3317130fb0 100644 (file)
@@ -59,6 +59,7 @@
 #include "tabletlibrary.h"
 #include "statusline.h"
 #include "native2amiga_api.h"
+#include "videograb.h"
 
 #if SIZEOF_TCHAR != 1
 /* FIXME: replace strcasecmp with _tcsicmp in source code instead */
@@ -4117,6 +4118,31 @@ static bool inputdevice_handle_inputcode2 (int code, int state)
        case AKS_RTG_3:
                toggle_rtg(code - AKS_RTG_C);
                break;
+       case AKS_VIDEOGRAB_RESTART:
+               getsetpositionvideograb(0);
+               pausevideograb(0);
+               break;
+       case AKS_VIDEOGRAB_PAUSE:
+               pausevideograb(-1);
+               break;
+       case AKS_VIDEOGRAB_PREV:
+       {
+               pausevideograb(1);
+               uae_s64 pos = getsetpositionvideograb(-1);
+               pos--;
+               if (pos >= 0)
+                       getsetpositionvideograb(pos);
+               break;
+       }
+       case AKS_VIDEOGRAB_NEXT:
+       {
+               pausevideograb(1);
+               uae_s64 pos = getsetpositionvideograb(-1);
+               pos++;
+               getsetpositionvideograb(pos);
+               break;
+       }
+
 #ifdef CDTV
        case AKS_CDTV_FRONT_PANEL_STOP:
        case AKS_CDTV_FRONT_PANEL_PLAYPAUSE:
index 5349ffad9fef2d99efc7c16d420ef59ff7d82d57..cd2a3156495c0019cae4b0c60dea6a62eefcf315 100644 (file)
@@ -414,4 +414,9 @@ DEFEVENT(SPC_CDTV_FRONT_PANEL_NEXT,_T("CDTV Front Panel Next"),AM_K,0,0,AKS_CDTV
 DEFEVENT(SPC_CDTV_FRONT_PANEL_REW,_T("CDTV Front Panel Rewind"),AM_K,0,0,AKS_CDTV_FRONT_PANEL_REW)
 DEFEVENT(SPC_CDTV_FRONT_PANEL_FF,_T("CDTV Front Panel Fast Forward"),AM_K,0,0,AKS_CDTV_FRONT_PANEL_FF)
 
+DEFEVENT(SPC_VIDEOGRAB_RESTART,_T("VideoGrab Restart"),AM_K,0,0,AKS_VIDEOGRAB_RESTART)
+DEFEVENT(SPC_VIDEOGRAB_PAUSE,_T("VideoGrab Pause"),AM_K,0,0,AKS_VIDEOGRAB_PAUSE)
+DEFEVENT(SPC_VIDEOGRAB_PREV,_T("VideoGrab Previous Frame"),AM_K,0,0,AKS_VIDEOGRAB_PREV)
+DEFEVENT(SPC_VIDEOGRAB_NEXT,_T("VideoGrab Next Frame"),AM_K,0,0,AKS_VIDEOGRAB_NEXT)
+
 DEFEVENT(SPC_LAST, _T(""), AM_DUMMY, 0,0,0)
index 5995e285717d51239101673317cb15a866b34ddd..5b3a9c92506b1506f3438447e70d0282c9d85137 100644 (file)
@@ -128,6 +128,13 @@ static AVICOMPRESSOPTIONS FAR * aOptions[] = { &videoOptions }; // array of poin
 static LPBITMAPINFOHEADER lpbi;
 static PCOMPVARS pcompvars;
 
+extern bool need_genlock_data;
+extern uae_u8 **row_map_genlock;
+
+static bool usealpha(void)
+{
+       return need_genlock_data != 0 && row_map_genlock && currprefs.genlock_image && currprefs.genlock_alpha;
+}
 
 void avi_message (const TCHAR *format,...)
 {
@@ -568,6 +575,8 @@ static int AVIOutput_AllocateVideo (void)
                avioutput_bits = 24;
        if (avioutput_bits > 24)
                avioutput_bits = 24;
+       if (usealpha() && avioutput_bits == 24)
+               avioutput_bits = 32;
        lpbi = (LPBITMAPINFOHEADER)xcalloc (uae_u8, lpbisize ());
        lpbi->biSize = sizeof (BITMAPINFOHEADER);
        lpbi->biWidth = aviout_width_out;
@@ -951,7 +960,12 @@ static int getFromRenderTarget(struct avientry *avie)
                                                d[0] = v >> 0;
                                                d[1] = v >> 8;
                                                d[2] = v >> 16;
-                                               d += 3;
+                                               if (avioutput_bits == 32) {
+                                                       d[3] = v >> 24;
+                                                       d += 4;
+                                               } else {
+                                                       d += 3;
+                                               }
                                        }
                                }
                        } else if (bits == 16 || bits == 15) {
@@ -1014,7 +1028,7 @@ static int getFromDC (struct avientry *avie)
 
 static int rgb_type;
 
-void AVIOutput_RGBinfo (int rb, int gb, int bb, int rs, int gs, int bs)
+void AVIOutput_RGBinfo (int rb, int gb, int bb, int ab, int rs, int gs, int bs, int as)
 {
        if (bs == 0 && gs == 5 && rs == 11)
                rgb_type = 1;
index a5a9c9b89fff0fe315f4349edbecf8e206bc881f..885239105b57d6b220e4f8cffc1e8098e42b02a1 100644 (file)
@@ -32,11 +32,11 @@ extern void AVIOutput_End (void);
 extern void AVIOutput_Begin (void);
 extern void AVIOutput_Release (void);
 extern void AVIOutput_Initialize (void);
-extern void AVIOutput_RGBinfo (int,int,int,int,int,int);
+extern void AVIOutput_RGBinfo (int,int,int,int,int,int,int,int);
 extern void AVIOutput_GetSettings (void);
 extern void AVIOutput_SetSettings (void);
 
-extern void Screenshot_RGBinfo (int,int,int,int,int,int);
+extern void Screenshot_RGBinfo (int,int,int,int,int,int,int,int);
 
 #define AVIAUDIO_AVI 1
 #define AVIAUDIO_WAV 2
index 8f75730fbccc4045022d07e48415200b68c221b3..2f6e18d6f2cf385fc1718fd290abef02372d2527 100644 (file)
@@ -28,6 +28,14 @@ int screenshot_originalsize = 0;
 int screenshot_clipmode = 0;
 int screenshot_multi = 0;
 
+extern bool need_genlock_data;
+extern uae_u8 **row_map_genlock;
+
+static bool usealpha(void)
+{
+       return need_genlock_data != 0 && row_map_genlock && currprefs.genlock_image && currprefs.genlock_alpha;
+}
+
 static void namesplit (TCHAR *s)
 {
        int l;
@@ -96,13 +104,14 @@ void screenshot_free (void)
        screenshot_prepared = FALSE;
 }
 
-static int rgb_rb, rgb_gb, rgb_bb, rgb_rs, rgb_gs, rgb_bs;
+static int rgb_rb, rgb_gb, rgb_bb, rgb_rs, rgb_gs, rgb_bs, rgb_ab, rgb_as;
 
 static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
 {
        int width, height;
        HGDIOBJ hgdiobj;
        int bits;
+       int depth = usealpha() ? 32 : 24;
 
        screenshot_free ();
 
@@ -116,8 +125,8 @@ static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
                uae_u8 *src, *dst, *mem;
                bool needfree = false;
                uae_u8 *palette = NULL;
-               int rgb_bb2, rgb_gb2, rgb_rb2;
-               int rgb_bs2, rgb_gs2, rgb_rs2;
+               int rgb_bb2, rgb_gb2, rgb_rb2, rgb_ab2;
+               int rgb_bs2, rgb_gs2, rgb_rs2, rgb_as2;
                uae_u8 pal[256 * 3];
                int screenshot_width = 0, screenshot_height = 0;
                int screenshot_xoffset = -1, screenshot_yoffset = -1;
@@ -128,9 +137,11 @@ static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
                        rgb_bb2 = 8;
                        rgb_gb2 = 8;
                        rgb_rb2 = 8;
+                       rgb_ab2 = 8;
                        rgb_bs2 = 0;
                        rgb_gs2 = 8;
                        rgb_rs2 = 16;
+                       rgb_as2 = 24;
                } else if (vb) {
                        width = vb->outwidth;
                        height = vb->outheight;
@@ -140,18 +151,22 @@ static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
                        rgb_bb2 = rgb_bb;
                        rgb_gb2 = rgb_gb;
                        rgb_rb2 = rgb_rb;
+                       rgb_ab2 = rgb_ab;
                        rgb_bs2 = rgb_bs;
                        rgb_gs2 = rgb_gs;
                        rgb_rs2 = rgb_rs;
+                       rgb_as2 = rgb_as;
                } else {
                        src = mem = getfilterbuffer (&width, &height, &spitch, &bits);
                        needfree = true;
                        rgb_bb2 = rgb_bb;
                        rgb_gb2 = rgb_gb;
                        rgb_rb2 = rgb_rb;
+                       rgb_ab2 = rgb_ab;
                        rgb_bs2 = rgb_bs;
                        rgb_gs2 = rgb_gs;
                        rgb_rs2 = rgb_rs;
+                       rgb_as2 = rgb_as;
                }
                if (src == NULL)
                        goto donormal;
@@ -237,7 +252,7 @@ static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
                bi->bmiHeader.biWidth = screenshot_width * screenshot_xmult;
                bi->bmiHeader.biHeight = screenshot_height * screenshot_ymult;
                bi->bmiHeader.biPlanes = 1;
-               bi->bmiHeader.biBitCount = bits <= 8 ? 8 : 24;
+               bi->bmiHeader.biBitCount = bits <= 8 ? 8 : depth;
                bi->bmiHeader.biCompression = BI_RGB;
                dpitch = ((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8;
                bi->bmiHeader.biSizeImage = dpitch * bi->bmiHeader.biHeight;
@@ -314,7 +329,7 @@ static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
                                } else {
                                        int shift;
                                        uae_u32 v = 0;
-                                       uae_u32 v2, v2a, v2b, v2c;
+                                       uae_u32 v2, v2a, v2b, v2c, v2d;
 
                                        if (bits == 16)
                                                v = ((uae_u16*)s)[x];
@@ -342,12 +357,28 @@ static int screenshot_prepare (int imagemode, struct vidbuffer *vb)
                                                v2 |= (v2 >> shift) & ((1 < shift) - 1);
                                        v2c = v2;
 
+                                       if (depth == 32) {
+                                               shift = 8 - rgb_ab2;
+                                               v2 = (v >> rgb_as2) & ((1 << rgb_ab2) - 1);
+                                               v2 <<= (8 - rgb_ab2);
+                                               if (rgb_ab < 8)
+                                                       v2 |= (v2 >> shift) & ((1 < shift) - 1);
+                                               v2d = v2;
+                                       }
+
                                        uae_u8 *d2 = d;
                                        for (int y2 = 0; y2 < ymult; y2++) {
                                                for (int x2 = 0; x2 < xmult; x2++) {
-                                                       d2[(xx + x2) * 3 + 0] = v2a;
-                                                       d2[(xx + x2) * 3 + 1] = v2b;
-                                                       d2[(xx + x2) * 3 + 2] = v2c;
+                                                       if (depth == 32) {
+                                                               d2[(xx + x2) * 4 + 0] = v2a;
+                                                               d2[(xx + x2) * 4 + 1] = v2b;
+                                                               d2[(xx + x2) * 4 + 2] = v2c;
+                                                               d2[(xx + x2) * 4 + 3] = v2d;
+                                                       } else {
+                                                               d2[(xx + x2) * 3 + 0] = v2a;
+                                                               d2[(xx + x2) * 3 + 1] = v2b;
+                                                               d2[(xx + x2) * 3 + 2] = v2c;
+                                                       }
                                                }
                                                d2 += dpitch2;
                                        }
@@ -378,7 +409,7 @@ donormal:
                        if (s) {
                                hr = s->LockRect(&l, NULL, D3DLOCK_READONLY);
                                if (SUCCEEDED(hr)) {
-                                       int dpitch = (((w * 24 + 31) & ~31) / 8);
+                                       int dpitch = (((w * depth + 31) & ~31) / 8);
                                        lpvBits = xmalloc(uae_u8, dpitch * h); 
 
                                        ZeroMemory(bi, sizeof(bi));
@@ -386,7 +417,7 @@ donormal:
                                        bi->bmiHeader.biWidth = w;
                                        bi->bmiHeader.biHeight = h;
                                        bi->bmiHeader.biPlanes = 1;
-                                       bi->bmiHeader.biBitCount = 24;
+                                       bi->bmiHeader.biBitCount = depth;
                                        bi->bmiHeader.biCompression = BI_RGB;
                                        bi->bmiHeader.biSizeImage = dpitch * bi->bmiHeader.biHeight;
                                        bi->bmiHeader.biXPelsPerMeter = 0;
@@ -404,7 +435,12 @@ donormal:
                                                                        d[0] = v >> 0;
                                                                        d[1] = v >> 8;
                                                                        d[2] = v >> 16;
-                                                                       d += 3;
+                                                                       if (depth == 32) {
+                                                                               d[3] = v >> 24;
+                                                                               d += 4;
+                                                                       } else {
+                                                                               d += 3;
+                                                                       }
                                                                }
                                                        }
                                                } else if (bits == 16 || bits == 15) {
@@ -507,16 +543,18 @@ int screenshot_prepare (void)
        return screenshot_prepare (-1);
 }
 
-void Screenshot_RGBinfo (int rb, int gb, int bb, int rs, int gs, int bs)
+void Screenshot_RGBinfo (int rb, int gb, int bb, int ab, int rs, int gs, int bs, int as)
 {
        if (!bi)
                bi = xcalloc (BITMAPINFO, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
        rgb_rb = rb;
        rgb_gb = gb;
        rgb_bb = rb;
+       rgb_ab = ab;
        rgb_rs = rs;
        rgb_gs = gs;
        rgb_bs = bs;
+       rgb_as = as;
 }
 
 #if PNG_SCREENSHOTS > 0
@@ -532,7 +570,7 @@ static void _cdecl pngtest_blah (png_structp png_ptr, png_const_charp message)
 #endif
 }
 
-static int savepng (FILE *fp)
+static int savepng(FILE *fp, bool alpha)
 {
        png_structp png_ptr;
        png_infop info_ptr;
@@ -559,7 +597,7 @@ static int savepng (FILE *fp)
        png_init_io (png_ptr, fp);
        png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
        png_set_IHDR (png_ptr, info_ptr,
-               w, h, 8, d <= 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
+               w, h, 8, d <= 8 ? PNG_COLOR_TYPE_PALETTE : (alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB),
                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
        if (d <= 8) {
                for (i = 0; i < (1 << d); i++) {
@@ -572,7 +610,7 @@ static int savepng (FILE *fp)
        row_pointers = xmalloc (png_bytep, h);
        for (i = 0; i < h; i++) {
                int j = h - i - 1;
-               row_pointers[i] = (uae_u8*)lpvBits + j * (((w * (d <= 8 ? 8 : 24) + 31) & ~31) / 8);
+               row_pointers[i] = (uae_u8*)lpvBits + j * (((w * (d <= 8 ? 8 : (alpha ? 32 : 24)) + 31) & ~31) / 8);
        }
        png_set_rows (png_ptr, info_ptr, row_pointers);
        png_write_png (png_ptr,info_ptr, PNG_TRANSFORM_BGR, NULL);
@@ -582,7 +620,7 @@ static int savepng (FILE *fp)
 }
 #endif
 
-static int savebmp (FILE *fp)
+static int savebmp (FILE *fp, bool alpha)
 {
        BITMAPFILEHEADER bfh;
        // write the file header, bitmap information and pixel data
@@ -622,6 +660,7 @@ int screenshotf (const TCHAR *spath, int mode, int doprepare, int imagemode, str
        int failed = 0;
        int screenshot_max = 1000; // limit 999 iterations / screenshots
        TCHAR *format = _T("%s%s%s%03d.%s");
+       bool alpha = usealpha();
 
        HBITMAP offscreen_bitmap = NULL; // bitmap that is converted to a DIB
        HDC offscreen_dc = NULL; // offscreen DC that we can select offscreen bitmap into
@@ -652,10 +691,10 @@ int screenshotf (const TCHAR *spath, int mode, int doprepare, int imagemode, str
                        if (fp) {
 #if PNG_SCREENSHOTS > 0
                                if (screenshotmode)
-                                       failed = savepng (fp);
+                                       failed = savepng (fp, alpha);
                                else
 #endif
-                                       failed = savebmp (fp);
+                                       failed = savebmp (fp, alpha);
                                fclose(fp);
                                fp = NULL;
                                if (failed)
@@ -710,10 +749,10 @@ int screenshotf (const TCHAR *spath, int mode, int doprepare, int imagemode, str
                                }
 #if PNG_SCREENSHOTS > 0
                                if (screenshotmode)
-                                       nok = savepng (fp);
+                                       nok = savepng (fp, alpha);
                                else
 #endif
-                                       nok = savebmp (fp);
+                                       nok = savebmp (fp, alpha);
                                fclose(fp);
                                if (nok && fp) {
                                        _tunlink(filename);
@@ -780,4 +819,4 @@ void screenshot (int mode, int doprepare)
        screenshotf (_T("c:\\temp\\1.bmp"), 1, 1, 1, &vb);
        freevidbuffer (&vb);
 #endif
-}
\ No newline at end of file
+}
index fd66000352d79274a613b8f53acc27d18a0c9074..f996c79c687d37894779ffb0d15ee3edb162d2e0 100644 (file)
@@ -47,7 +47,9 @@ static CComPtr<ICaptureGraphBuilder2> graphBuilder;
 static CComPtr<IFilterGraph2> filterGraph;
 static CComPtr<ISampleGrabber> sampleGrabber;
 static CComPtr<IMediaControl> mediaControl;
+static CComPtr<IMediaSeeking> mediaSeeking;
 static bool videoInitialized;
+static bool videoPaused;
 static long *frameBuffer;
 static long bufferSize;
 static int videoWidth, videoHeight;
@@ -57,8 +59,10 @@ void uninitvideograb(void)
        write_log(_T("uninitvideograb\n"));
 
        videoInitialized = false;
+       videoPaused = false;
 
        sampleGrabber.Release();
+       mediaSeeking.Release();
        if (mediaControl) {
                mediaControl->Stop();
        }
@@ -242,6 +246,8 @@ bool initvideograb(const TCHAR *filename)
                return false;
        }
 
+       hr = filterGraph->QueryInterface(IID_IMediaSeeking, (void**)&mediaSeeking);
+
        hr = filterGraph->QueryInterface(IID_IMediaControl, (void**)&mediaControl);
        if (FAILED(hr)) {
                uninitvideograb();
@@ -249,6 +255,7 @@ bool initvideograb(const TCHAR *filename)
        }
        if (SUCCEEDED(mediaControl->Run())) {
                videoInitialized = true;
+               write_log(_T("Playing '%s'\n"), filename ? filename : _T("<capture>"));
                return true;
        } else {
                uninitvideograb();
@@ -256,14 +263,46 @@ bool initvideograb(const TCHAR *filename)
        }
 }
 
-void pausevideograb(bool pause)
+uae_s64 getsetpositionvideograb(uae_s64 framepos)
 {
+       if (!videoInitialized || !mediaSeeking)
+               return 0;
+       LONGLONG pos;
+       HRESULT hr = mediaSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);
+       if (FAILED(hr))
+               write_log(_T("SetTimeFormat format %08x\n"), hr);
+       if (framepos < 0) {
+               LONGLONG stoppos;
+               hr = mediaSeeking->GetPositions(&pos, &stoppos);
+               if (FAILED(hr)) {
+                       write_log(_T("GetPositions failed %08x\n"), hr);
+                       pos = 0;
+               }
+               return pos;
+       } else {
+               LONGLONG pos = framepos;
+               hr = mediaSeeking->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
+               if (FAILED(hr)) {
+                       write_log(_T("SetPositions %lld failed %08x\n"), framepos, hr);
+               }
+               return 0;
+       }
+}
+
+void pausevideograb(int pause)
+{
+       HRESULT hr;
        if (!videoInitialized)
                return;
-       if (pause) {
-               mediaControl->Pause();
-       } else {
-               mediaControl->Run();
+       if (pause < 0) {
+               pause = videoPaused ? 0 : 1;
+       }
+       if (pause > 0) {
+               hr = mediaControl->Pause();
+               videoPaused = true;
+       } else if (pause == 0) {
+               hr = mediaControl->Run();
+               videoPaused = false;
        }
 }
 
index 2744d091d0db06969f8a8a84443d60bd328b52da..a65dbc2ee4b4b440bacb6d97a2a7ea11056997a7 100755 (executable)
@@ -136,6 +136,22 @@ STATIC_INLINE void PRGB(struct vidbuffer *dst, uae_u8 *dataline, uae_u8 r, uae_u
        }
 }
 
+STATIC_INLINE void PRGBA(struct vidbuffer *dst, uae_u8 *dataline, uae_u8 r, uae_u8 g, uae_u8 b, uae_u8 a)
+{
+       if (dst->pixbytes == 4) {
+               dataline[0] = b;
+               dataline[1] = g;
+               dataline[2] = r;
+               dataline[3] = a;
+       } else {
+               r >>= 3;
+               g >>= 2;
+               b >>= 3;
+               ((uae_u16*)dataline)[0] = (r << 11) | (g << 5) | b;
+       }
+}
+
+
 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)
@@ -158,6 +174,28 @@ STATIC_INLINE void PUT_PRGB(uae_u8 *d, uae_u8 *d2, struct vidbuffer *dst, uae_u8
        }
 }
 
+STATIC_INLINE void PUT_PRGBA(uae_u8 *d, uae_u8 *d2, struct vidbuffer *dst, uae_u8 r, uae_u8 g, uae_u8 b, uae_u8 a, int xadd, int doublelines, bool hdouble)
+{
+       if (hdouble)
+               PRGBA(dst, d - dst->pixbytes, r, g, b, a);
+       PRGBA(dst, d, r, g, b, a);
+       if (xadd >= 2) {
+               PRGBA(dst, d + 1 * dst->pixbytes, r, g, b, a);
+               if (hdouble)
+                       PRGBA(dst, d + 2 * dst->pixbytes, r, g, b, a);
+       }
+       if (doublelines) {
+               if (hdouble)
+                       PRGBA(dst, d2 - dst->pixbytes, r, g, b, a);
+               PRGBA(dst, d2, r, g, b, a);
+               if (xadd >= 2) {
+                       PRGBA(dst, d2 + 1 * dst->pixbytes, r, g, b, a);
+                       if (hdouble)
+                               PRGBA(dst, d2 + 2 * dst->pixbytes, r, g, b, a);
+               }
+       }
+}
+
 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) {
@@ -182,6 +220,30 @@ STATIC_INLINE void PUT_AMIGARGB(uae_u8 *d, uae_u8 *s, uae_u8 *d2, uae_u8 *s2, st
        }
 }
 
+STATIC_INLINE void PUT_AMIGARGBA(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]) | 0xff000000;
+               ((uae_u32*)d)[0] = (((uae_u32*)s)[0]) | 0xff000000;
+       } else {
+               if (hdouble)
+                       ((uae_u16*)d)[-1] = (((uae_u16*)s)[-1]) | 0xff000000;
+               ((uae_u16*)d)[0] = (((uae_u16*)s)[0]) | 0xff000000;
+       }
+       if (doublelines) {
+               if (dst->pixbytes == 4) {
+                       if (hdouble)
+                               ((uae_u32*)d2)[-1] = (((uae_u32*)s2)[-1]) | 0xff000000;
+                       ((uae_u32*)d2)[0] = (((uae_u32*)s2)[0]) | 0xff000000;
+               } else {
+                       if (hdouble)
+                               ((uae_u16*)d2)[-1] = (((uae_u16*)s2)[-1]) | 0xff000000;
+                       ((uae_u16*)d2)[0] = (((uae_u16*)s2)[0]) | 0xff000000;
+               }
+       }
+}
+
 static void clearmonitor(struct vidbuffer *dst)
 {
        uae_u8 *p = dst->bufmem;
@@ -2414,8 +2476,10 @@ static bool do_genlock(struct vidbuffer *src, struct vidbuffer *dst, bool double
                mix1 = 256 - currprefs.genlock_mix;
                mix2 = currprefs.genlock_mix;
        }
+       uae_u8 amix1 = 255 - (currprefs.genlock_mix > 255 ? 255 : 0);
+       uae_u8 amix2 = 255 - amix1;
 
-       uae_u8 r = 0, g = 0, b = 0;
+       uae_u8 r = 0, g = 0, b = 0, a = 0;
        for (y = ystart; y < yend; y++) {
                int yoff = (((y * 2 + oddlines) - src->yoffset) >> vdbl);
                if (yoff < 0)
@@ -2430,7 +2494,8 @@ static bool do_genlock(struct vidbuffer *src, struct vidbuffer *dst, bool double
                if (genlock_image_upsidedown)
                        gy = (genlock_image_height - 1) - gy;
                uae_u8 *image_genlock = genlock_image + gy * genlock_image_pitch;
-               r = g = b = 0;
+               r = g = b;
+               a = amix1;
                noise_add = (quickrand() & 15) | 1;
                for (x = 0; x < src->inwidth; x++) {
                        uae_u8 *s = line + x * src->pixbytes;
@@ -2440,6 +2505,7 @@ static bool do_genlock(struct vidbuffer *src, struct vidbuffer *dst, bool double
                        uae_u8 *d2 = d + dst->rowbytes;
 
                        if (is_transparent(*s_genlock)) {
+                               a = amix2;
                                if (genlock_error) {
                                        r = 0x00;
                                        g = 0x00;
@@ -2462,9 +2528,9 @@ static bool do_genlock(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                        g = (mix1 * g + mix2 * FVG(src, s)) / 256;
                                        b = (mix1 * b + mix2 * FVB(src, s)) / 256;
                                }
-                               PUT_PRGB(d, d2, dst, r, g, b, 0, doublelines, false);
+                               PUT_PRGBA(d, d2, dst, r, g, b, a, 0, doublelines, false);
                        } else {
-                               PUT_AMIGARGB(d, s, d2, s2, dst, 0, doublelines, false);
+                               PUT_AMIGARGBA(d, s, d2, s2, dst, 0, doublelines, false);
                        }
                }
        }
@@ -2669,6 +2735,19 @@ struct opals {
        int address_load;
        int rowbytes;
        uae_u8 control_line[OPAL_CONTROL_LINE_LENGTH];
+
+       int palcoprocnt;
+       bool copro_hires;
+       int copro_bank_offset[2];
+       int copro_vdm;
+       bool copro_prior_mode;
+       bool copro_priority;
+       bool copro_dual_disp;
+       int address_load_sync;
+       int vram_write_offset;
+       int vram_read_offset;
+       int control_y;
+       bool detected;
 };
 static struct opals *opal;
 
@@ -2726,9 +2805,9 @@ static void opal_pixel(struct opals *opal, uae_u8 *d, uae_u8 *d2, uae_u8 *s, uae
        }
 }
 
-#define OPAL_SWAP_BANK (opal->dual_play && pf && !copro_hires) || (opal->v2 && opal->opal && opal->dual_play && copro_hires && s_genlock && is_transparent(*s_genlock))
+#define OPAL_SWAP_BANK (opal->dual_play && pf && !opal->copro_hires) || (opal->v2 && opal->opal && opal->dual_play && opal->copro_hires && s_genlock && is_transparent(*s_genlock))
 
-static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, int oddlines, bool isopal)
+static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool doublelines, int oddlines, int yline, bool isopal)
 {
        int y, x, vdbl, hdbl;
        int isntsc;
@@ -2759,20 +2838,27 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
        int yimgstart = ystart + 6;
        int yend = (isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL) + 1;
 
-       int palcoprocnt = 0;
-
-       bool copro_hires = false;
-       int copro_bank_offset[2] = { 0, 0 };
-       int copro_vdm = 0;
-       bool copro_prior_mode = false;
-       bool copro_priority = false;
-       bool copro_dual_disp = false;
-       int address_load_sync = -1;
-       int vram_write_offset = 0;
-       int vram_read_offset = 0;
-       int control_y = 0;
+       if (yline < 0 || yline == ystart) {
+               opal->address_load_sync = -1;
+               opal->vram_write_offset = 0;
+               opal->vram_read_offset = 0;
+               opal->control_y = 0;
+               opal->copro_prior_mode = false;
+               opal->copro_priority = false;
+               opal->copro_dual_disp = false;
+               opal->copro_vdm = 0;
+               opal->copro_hires = 0;
+               opal->palcoprocnt = 0;
+               opal->detected = opal->latched;
+       }
+
+       if (yline < 0) {
+               y = ystart;
+       } else {
+               y = yline;
+       }
 
-       for (y = ystart; y < yend; y++) {
+       for (; y < yend; y++) {
 
                uae_u8 *line = NULL;
                uae_u8 *line_genlock = NULL;
@@ -2791,27 +2877,27 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
 
                uae_u8 copro = opal->copro[y - ystart];
                if (opal->opal) {
-                       copro_prior_mode = (copro & 0x40) != 0;
-                       copro_priority = (copro & 0x20) != 0;
-                       copro_dual_disp = (copro & 0x10) != 0;
-                       copro_hires = (copro & 8) != 0;
-                       copro_bank_offset[0] = (copro & 4) ? 6 * OPAL_SEGMENT_SIZE : 0;
-                       copro_bank_offset[1] = (copro & 4) ? 0 : 6 * OPAL_SEGMENT_SIZE;
-                       copro_vdm = copro & 3;
+                       opal->copro_prior_mode = (copro & 0x40) != 0;
+                       opal->copro_priority = (copro & 0x20) != 0;
+                       opal->copro_dual_disp = (copro & 0x10) != 0;
+                       opal->copro_hires = (copro & 8) != 0;
+                       opal->copro_bank_offset[0] = (copro & 4) ? 6 * OPAL_SEGMENT_SIZE : 0;
+                       opal->copro_bank_offset[1] = (copro & 4) ? 0 : 6 * OPAL_SEGMENT_SIZE;
+                       opal->copro_vdm = copro & 3;
                } else {
-                       copro_vdm = (((copro >> 6) & 1) << 1) | opal->control_line[7];
-                       copro_hires = (copro & 0x20) != 0;
-                       copro_prior_mode = (copro & 0x10) != 0;
-                       copro_priority = (copro & 8) != 0;
-                       copro_dual_disp = (copro & 4) != 0;
+                       opal->copro_vdm = (((copro >> 6) & 1) << 1) | opal->control_line[7];
+                       opal->copro_hires = (copro & 0x20) != 0;
+                       opal->copro_prior_mode = (copro & 0x10) != 0;
+                       opal->copro_priority = (copro & 8) != 0;
+                       opal->copro_dual_disp = (copro & 4) != 0;
                        opal->dual_play = (copro & 2) != 0;
-                       copro_bank_offset[0] = (copro & 1) ? 6 * OPAL_SEGMENT_SIZE : 0;
-                       copro_bank_offset[1] = (copro & 1) ? 0 : 6 * OPAL_SEGMENT_SIZE;
+                       opal->copro_bank_offset[0] = (copro & 1) ? 6 * OPAL_SEGMENT_SIZE : 0;
+                       opal->copro_bank_offset[1] = (copro & 1) ? 0 : 6 * OPAL_SEGMENT_SIZE;
                }
-               opal->priority_stencil_mode = (copro_prior_mode ? 2 : 0) | (copro_priority ? 4 : 0) | (copro_dual_disp ? 8 : 0);
+               opal->priority_stencil_mode = (opal->copro_prior_mode ? 2 : 0) | (opal->copro_priority ? 4 : 0) | (opal->copro_dual_disp ? 8 : 0);
                if (!(copro & 0x80)) {
                        // Add_Load
-                       vram_read_offset = opal->address_load;
+                       opal->vram_read_offset = opal->address_load;
                }
 
 
@@ -2827,8 +2913,8 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                if (!line)
                        continue;
 
-               int vram_write_pixel_offset = vram_write_offset;
-               int vram_read_pixel_offset = vram_read_offset;
+               int vram_write_pixel_offset = opal->vram_write_offset;
+               int vram_read_pixel_offset = opal->vram_read_offset;
 
                // behavior not fully known
                if ((!opal->auto_field && opal->bank_field) || (opal->auto_field && oddlines)) {
@@ -2859,67 +2945,67 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                uae_u8 pf, pr;
                                int bidx;
 
-                               if (copro_vdm == 0) {
+                               if (opal->copro_vdm == 0) {
                                        // 24-bit truecolor (palette)
                                        uae_u8 m = opal->pixel_read_mask;
 
-                                       r = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 0 * OPAL_SEGMENT_SIZE] & m) + 0];
-                                       g = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE] & m) + 1];
-                                       b = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & m) + 2];
+                                       r = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 0 * OPAL_SEGMENT_SIZE] & m) + 0];
+                                       g = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE] & m) + 1];
+                                       b = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & m) + 2];
                                        pf = g & 1;
                                        pr = b & 1;
                                        if (OPAL_SWAP_BANK) {
-                                               r = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 0 * OPAL_SEGMENT_SIZE] & m) + 0];
-                                               g = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 1 * OPAL_SEGMENT_SIZE] & m) + 1];
-                                               b = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 2 * OPAL_SEGMENT_SIZE] & m) + 2];
+                                               r = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 0 * OPAL_SEGMENT_SIZE] & m) + 0];
+                                               g = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 1 * OPAL_SEGMENT_SIZE] & m) + 1];
+                                               b = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 2 * OPAL_SEGMENT_SIZE] & m) + 2];
                                                bidx = 0;
                                        } else {
                                                bidx = 1;
                                        }
-                                       opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !copro_hires, false);
+                                       opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !opal->copro_hires, false);
 
-                                       if (copro_hires) {
-                                               r = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 0 * OPAL_SEGMENT_SIZE] & m) + 0];
-                                               g = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 1 * OPAL_SEGMENT_SIZE] & m) + 1];
-                                               b = opal->palette[4 * (opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE] & m) + 2];
+                                       if (opal->copro_hires) {
+                                               r = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 0 * OPAL_SEGMENT_SIZE] & m) + 0];
+                                               g = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 1 * OPAL_SEGMENT_SIZE] & m) + 1];
+                                               b = opal->palette[4 * (opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE] & m) + 2];
                                                pr = b & 1;
                                                opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, false, true);
                                        }
 
-                               } else if (copro_vdm == 1) {
+                               } else if (opal->copro_vdm == 1) {
                                        // 24-bit truecolor (bypass palette)
 
-                                       r = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 0 * OPAL_SEGMENT_SIZE];
-                                       g = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE];
-                                       b = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE];
+                                       r = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 0 * OPAL_SEGMENT_SIZE];
+                                       g = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE];
+                                       b = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE];
                                        pf = g & 1;
                                        pr = b & 1;
                                        if (OPAL_SWAP_BANK) {
-                                               r = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 0 * OPAL_SEGMENT_SIZE];
-                                               g = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 1 * OPAL_SEGMENT_SIZE];
-                                               b = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 2 * OPAL_SEGMENT_SIZE];
+                                               r = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 0 * OPAL_SEGMENT_SIZE];
+                                               g = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 1 * OPAL_SEGMENT_SIZE];
+                                               b = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 2 * OPAL_SEGMENT_SIZE];
                                                bidx = 0;
                                        } else {
                                                bidx = 1;
                                        }
-                                       opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !copro_hires, false);
+                                       opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !opal->copro_hires, false);
 
-                                       if (copro_hires) {
-                                               r = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 0 * OPAL_SEGMENT_SIZE];
-                                               g = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 1 * OPAL_SEGMENT_SIZE];
-                                               b = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE];
+                                       if (opal->copro_hires) {
+                                               r = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 0 * OPAL_SEGMENT_SIZE];
+                                               g = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 1 * OPAL_SEGMENT_SIZE];
+                                               b = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE];
                                                pr = b & 1;
                                                opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, false, true);
                                        }
 
-                               } else if (copro_vdm == 2) {
+                               } else if (opal->copro_vdm == 2) {
                                        // 8-bit palette
 
-                                       uae_u8 v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + opal->color_offset] & opal->pixel_read_mask;
-                                       pf = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE] & 1;
-                                       pr = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & 1;
+                                       uae_u8 v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + opal->color_offset] & opal->pixel_read_mask;
+                                       pf = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE] & 1;
+                                       pr = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & 1;
                                        if (OPAL_SWAP_BANK) {
-                                               v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + opal->color_offset] & opal->pixel_read_mask;
+                                               v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + opal->color_offset] & opal->pixel_read_mask;
                                                bidx = 0;
                                        } else {
                                                bidx = 1;
@@ -2927,40 +3013,40 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                        r = opal->palette[v0 * 4 + 0];
                                        g = opal->palette[v0 * 4 + 1];
                                        b = opal->palette[v0 * 4 + 2];
-                                       opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !copro_hires, false);
+                                       opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !opal->copro_hires, false);
 
-                                       if (copro_hires) {
-                                               uae_u8 v1 = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + opal->color_offset] & opal->pixel_read_mask;
+                                       if (opal->copro_hires) {
+                                               uae_u8 v1 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + opal->color_offset] & opal->pixel_read_mask;
                                                r = opal->palette[v1 * 4 + 0];
                                                g = opal->palette[v1 * 4 + 1];
                                                b = opal->palette[v1 * 4 + 2];
                                                opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, false, true);
                                        }
 
-                               } else if (copro_vdm == 3) {
+                               } else if (opal->copro_vdm == 3) {
 
                                        if (((opal->video_command >> 6) & 3) == 3) {
                                                // 15 bit true color
-                                               uae_u8 v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 0 * OPAL_SEGMENT_SIZE];
-                                               uae_u8 v1 = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE];
+                                               uae_u8 v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 0 * OPAL_SEGMENT_SIZE];
+                                               uae_u8 v1 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE];
                                                r = ((v0 >> 2) & 31) << (8 - 5);
                                                g = (((v0 & 3) << 3) | ((v1 >> 5) &7)) << (8 - 5);
                                                b = ((v1 & 31)) << (8 - 5);
                                                pf = v1 & 1;
-                                               pr = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & 1;
+                                               pr = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & 1;
                                                if (OPAL_SWAP_BANK) {
-                                                       v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 0 * OPAL_SEGMENT_SIZE];
-                                                       v1 = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + 1 * OPAL_SEGMENT_SIZE];
+                                                       v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 0 * OPAL_SEGMENT_SIZE];
+                                                       v1 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + 1 * OPAL_SEGMENT_SIZE];
                                                        bidx = 0;
                                                } else {
                                                        bidx = 1;
                                                }
-                                               opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !copro_hires, false);
+                                               opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !opal->copro_hires, false);
 
-                                               if (copro_hires) {
-                                                       v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 0 * OPAL_SEGMENT_SIZE];
-                                                       v1 = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 1 * OPAL_SEGMENT_SIZE];
-                                                       pr = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE] & 1;
+                                               if (opal->copro_hires) {
+                                                       v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 0 * OPAL_SEGMENT_SIZE];
+                                                       v1 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 1 * OPAL_SEGMENT_SIZE];
+                                                       pr = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE] & 1;
                                                        r = ((v0 >> 2) & 31) << (8 - 5);
                                                        g = (((v0 & 3) << 3) | ((v1 >> 5) & 7)) << (8 - 5);
                                                        b = ((v1 & 31)) << (8 - 5);
@@ -2969,26 +3055,26 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
 
                                        } else {
                                                // 8-bit true color
-                                               uae_u8 v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + opal->color_offset];
+                                               uae_u8 v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + opal->color_offset];
                                                r = ((v0 >> 5) & 7) << (8 - 3);
                                                g = ((v0 >> 2) & 7) << (8 - 3);
                                                b = ((v0 >> 0) & 3) << (8 - 2);
-                                               pf = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE] & 1;
-                                               pr = opal->vram[vram_read_pixel_offset + copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & 1;
+                                               pf = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 1 * OPAL_SEGMENT_SIZE] & 1;
+                                               pr = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[0] + 2 * OPAL_SEGMENT_SIZE] & 1;
                                                if (OPAL_SWAP_BANK) {
-                                                       v0 = opal->vram[vram_read_pixel_offset + copro_bank_offset[1] + opal->color_offset];
+                                                       v0 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[1] + opal->color_offset];
                                                        bidx = 0;
                                                } else {
                                                        bidx = 1;
                                                }
-                                               opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !copro_hires, false);
+                                               opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, !opal->copro_hires, false);
 
-                                               if (copro_hires) {
-                                                       uae_u8 v1 = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + opal->color_offset] & opal->pixel_read_mask;
+                                               if (opal->copro_hires) {
+                                                       uae_u8 v1 = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + opal->color_offset] & opal->pixel_read_mask;
                                                        r = ((v0 >> 5) & 7) << (8 - 3);
                                                        g = ((v0 >> 2) & 7) << (8 - 3);
                                                        b = ((v0 >> 0) & 3) << (8 - 2);
-                                                       pr = opal->vram[vram_read_pixel_offset + copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE] & 1;
+                                                       pr = opal->vram[vram_read_pixel_offset + opal->copro_bank_offset[bidx] + 2 * OPAL_SEGMENT_SIZE] & 1;
                                                        opal_pixel(opal, d, d2, s, s2, s_genlock, src, dst, r, g, b, pr, doublelines, false, true);
                                                }
                                        }
@@ -3068,7 +3154,7 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                        }
                                }
 
-                               if (control_y && y >= control_y) {
+                               if (opal->control_y && y >= opal->control_y) {
                                
                                        if (opal_debug & 2)
                                                write_log(_T("%02x."), val);
@@ -3076,7 +3162,7 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                        if (pixcnt >= 1 && pixcnt < 4) {
 
                                                if (val != 0x00)
-                                                       control_y = 0;
+                                                       opal->control_y = 0;
 
                                        } else if (pixcnt > 0) {
 
@@ -3088,21 +3174,21 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                                } else  if (opal->colcopro) {
 
                                                        if ((pixcnt & 3) != 0) {
-                                                               if (palcoprocnt < OPAL_MAXLINES) {
+                                                               if (opal->palcoprocnt < OPAL_MAXLINES) {
                                                                        if (opal->wren)
-                                                                               opal->copro[palcoprocnt] = val;
-                                                               } else if (palcoprocnt == OPAL_MAXLINES + 7) {
+                                                                               opal->copro[opal->palcoprocnt] = val;
+                                                               } else if (opal->palcoprocnt == OPAL_MAXLINES + 7) {
                                                                        opal->video_command = val;
                                                                        command_update = true;
                                                                } else if (val != 0x00) {
-                                                                       write_log(_T("COPRO %d = %02x\n"), palcoprocnt, val);
+                                                                       write_log(_T("COPRO %d = %02x\n"), opal->palcoprocnt, val);
                                                                }
-                                                               palcoprocnt++;
+                                                               opal->palcoprocnt++;
                                                        }
 
                                                } else {
 
-                                                       if (y == control_y) {
+                                                       if (y == opal->control_y) {
        
                                                                if (pixcnt == 5) {
                                                                        opal->palette_load = val;
@@ -3117,29 +3203,29 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                                                                        command_update = true;
                                                                }
                                                        }
-                                                       if ((((y == control_y && pixcnt > 8) || (y > control_y)) && palcoprocnt < 4 * 256) && opal->wren) {
+                                                       if ((((y == opal->control_y && pixcnt > 8) || (y > opal->control_y)) && opal->palcoprocnt < 4 * 256) && opal->wren) {
                                                                if (!(opal->video_command & 0x10)) {
                                                                        // 6-bit palette (2 low bits are simply cleared)
                                                                        val <<= 2;
                                                                }
-                                                               opal->palette[(palcoprocnt + (opal->palette_load * 4)) & 1023] = val;
-                                                               palcoprocnt++;
+                                                               opal->palette[(opal->palcoprocnt + (opal->palette_load * 4)) & 1023] = val;
+                                                               opal->palcoprocnt++;
                                                        }
                                                }
 
-                                       } else if (pixcnt < 0 && y == control_y + 2) {
+                                       } else if (pixcnt < 0 && y == opal->control_y + 2) {
 
-                                               if (address_load_sync < 0 && val == 0xff)
-                                                       address_load_sync = 0;
-                                               if (address_load_sync > 0 && address_load_sync < 4) {
-                                                       if (address_load_sync == 1 && (val & 0xfe))
+                                               if (opal->address_load_sync < 0 && val == 0xff)
+                                                       opal->address_load_sync = 0;
+                                               if (opal->address_load_sync > 0 && opal->address_load_sync < 4) {
+                                                       if (opal->address_load_sync == 1 && (val & 0xfe))
                                                                write_log(_T("Address load %02x\n"), val);
                                                        opal->address_load <<= 8;
                                                        opal->address_load |= val;
                                                        opal->address_load &= (OPAL_SEGMENT_SIZE - 1);
                                                }
-                                               if (address_load_sync >= 0)
-                                                       address_load_sync++;
+                                               if (opal->address_load_sync >= 0)
+                                                       opal->address_load_sync++;
                                        }
                                        if (pixcnt >= 0)
                                                pixcnt++;
@@ -3153,13 +3239,13 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                        opal->color_offset = ((opal->video_command >> 6) & 3) * OPAL_SEGMENT_SIZE;
                }
 
-               vram_write_offset += opal->rowbytes;
-               vram_write_offset &= (OPAL_SEGMENT_SIZE - 1);
+               opal->vram_write_offset += opal->rowbytes;
+               opal->vram_write_offset &= (OPAL_SEGMENT_SIZE - 1);
 
-               vram_read_offset += opal->rowbytes;
-               vram_read_offset &= (OPAL_SEGMENT_SIZE - 1);
+               opal->vram_read_offset += opal->rowbytes;
+               opal->vram_read_offset &= (OPAL_SEGMENT_SIZE - 1);
 
-               if (control_y && y >= control_y && (opal_debug & 2)) {
+               if (opal->control_y && y >= opal->control_y && (opal_debug & 2)) {
                        write_log(_T("\n"));
                }
 
@@ -3167,16 +3253,17 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                        write_log(_T("\n"));
                }
 
-               if (y == control_y + 3) {
-                       control_y = 0;
+               if (y == opal->control_y + 3) {
+                       opal->control_y = 0;
                }
 
                if (opal->opal && controlcnt >= OPAL_CONTROL_LINE_LENGTH) {
                        memcpy(opal->control_line, control_line_tmp, OPAL_CONTROL_LINE_LENGTH);
                        detected = opal->control_line[0] && opal->control_line[2] && !opal->control_line[1] && !opal->control_line[3];
+                       opal->detected |= detected;
                        if (detected) {
-                               palcoprocnt = 0;
-                               control_y = y + 1;
+                               opal->palcoprocnt = 0;
+                               opal->control_y = y + 1;
                                uae_u8 *c = opal->control_line;
                                if (opal_debug & 1) {
                                        write_log(_T("WREN=%d COPRO=%d AUTO=%d DP=%d FIELD=%d FM=%d Latch=%d FGrab=%d\n"),
@@ -3202,9 +3289,10 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                } else if (!opal->opal && controlcnt >= COLORBURST_CONTROL_LINE_LENGTH) {
                        memcpy(opal->control_line, control_line_tmp, COLORBURST_CONTROL_LINE_LENGTH);
                        detected = !opal->control_line[0] && !opal->control_line[2] && opal->control_line[1] && opal->control_line[3];
+                       opal->detected |= detected;
                        if (detected) {
-                               palcoprocnt = 0;
-                               control_y = y + 1;
+                               opal->palcoprocnt = 0;
+                               opal->control_y = y + 1;
                                uae_u8 *c = opal->control_line;
                                if (opal_debug & 1) {
                                        write_log(_T("WREN=%d COPRO=%d AUTO=%d S0=%d\n"),
@@ -3227,11 +3315,17 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
                        }
                }
 
+               if (yline >= 0)
+                       break;
+
                if (y >= yimgstart && !detected)
                        return false;
 
        }
 
+       if (!opal->detected && y == yend)
+               return false;
+
        if (opal->opal && monitor != MONITOREMU_OPALVISION) {
                monitor = MONITOREMU_OPALVISION;
                write_log(_T("Opalvision control line detected\n"));
@@ -3244,26 +3338,26 @@ static bool opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool double
        return true;
 }
 
-static bool do_opalvision(struct vidbuffer *src, struct vidbuffer *dst, bool opal)
+static bool do_opalvision(struct vidbuffer *src, struct vidbuffer *dst, int line, bool opal)
 {
        bool v;
        if (interlace_seen) {
                if (currprefs.gfx_iscanlines) {
-                       v = opalvision(src, dst, false, lof_store ? 0 : 1, opal);
+                       v = opalvision(src, dst, false, lof_store ? 0 : 1, line, opal);
                        if (v && currprefs.gfx_iscanlines > 1)
                                blank_generic(src, dst, lof_store ? 1 : 0);
                } else {
-                       v = opalvision(src, dst, false, 0, opal);
-                       v |= opalvision(src, dst, false, 1, opal);
+                       v = opalvision(src, dst, false, 0, line, opal);
+                       v |= opalvision(src, dst, false, 1, line, opal);
                }
        } else {
-               v = opalvision(src, dst, true, 0, opal);
+               v = opalvision(src, dst, true, 0, line, opal);
        }
        return v;
 }
 
 
-static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *dst)
+static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *dst, int line)
 {
        automatic = false;
        if (currprefs.monitoremu == MONITOREMU_AUTO) {
@@ -3278,9 +3372,9 @@ static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *ds
                                v = do_avideo(src, dst);
                }
                if (!v)
-                       v = do_opalvision(src, dst, true);
+                       v = do_opalvision(src, dst, line, true);
                if (!v)
-                       v = do_opalvision(src, dst, false);
+                       v = do_opalvision(src, dst, line, false);
                return v;
        } else if (currprefs.monitoremu == MONITOREMU_A2024) {
                return a2024(src, dst);
@@ -3298,9 +3392,9 @@ static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *ds
        } else if (currprefs.monitoremu == MONITOREMU_FIRECRACKER24) {
                return do_firecracker24(src, dst);
        } else if (currprefs.monitoremu == MONITOREMU_OPALVISION) {
-               return do_opalvision(src, dst, true);
+               return do_opalvision(src, dst, line, true);
        } else if (currprefs.monitoremu == MONITOREMU_COLORBURST) {
-               return do_opalvision(src, dst, false);
+               return do_opalvision(src, dst, line, false);
        }
        return false;
 }
@@ -3308,7 +3402,7 @@ static bool emulate_specialmonitors2(struct vidbuffer *src, struct vidbuffer *ds
 
 bool emulate_specialmonitors(struct vidbuffer *src, struct vidbuffer *dst)
 {
-       if (!emulate_specialmonitors2(src, dst)) {
+       if (!emulate_specialmonitors2(src, dst, -1)) {
                if (monitor) {
                        clearmonitor(dst);
                        monitor = 0;
@@ -3319,6 +3413,11 @@ bool emulate_specialmonitors(struct vidbuffer *src, struct vidbuffer *dst)
        return true;
 }
 
+bool emulate_specialmonitors_line(struct vidbuffer *src, struct vidbuffer *dst, int line)
+{
+       return emulate_specialmonitors2(src, dst, line);
+}
+
 void specialmonitor_reset(void)
 {
        if (!currprefs.monitoremu)
@@ -3343,3 +3442,26 @@ bool specialmonitor_need_genlock(void)
                return true;
        return false;
 }
+
+bool specialmonitor_uses_control_lines(void)
+{
+       switch (currprefs.monitoremu) {
+               case MONITOREMU_GRAFFITI:
+               case MONITOREMU_HAM_E:
+               case MONITOREMU_HAM_E_PLUS:
+               case MONITOREMU_OPALVISION:
+               case MONITOREMU_COLORBURST:
+               return true;
+       }
+       return false;
+}
+
+bool specialmonitor_linebased(void)
+{
+       switch (currprefs.monitoremu) {
+               case MONITOREMU_OPALVISION:
+               case MONITOREMU_COLORBURST:
+               return true;
+       }
+       return false;
+}