// #define DEBUG #define VCAI_ENABLED #define DIVE_ENABLED #define VCAI_MONITOR #define INCL_DOS #define INCL_DOSERRORS #define INCL_GPI #define INCL_WIN #define INCL_32 #include #include #include #include #define _MEERROR_H_ #include /* It is from MMPM toolkit */ #include #include #include #include #include "dive.h" #include "pmtv2rem.h" #define WIDTH (300) #define HEIGHT (240) HWND HwndNBFrame; // Notebook frame handle BOOL NotebookOpen = FALSE; // Notebook not open void remote_open (MOUSEPOS mousepos); PWINDATA DiveSetup (char *name, USHORT instance, USHORT connector); int DiveRegister (HAB hab); int DiveStop (void); static void msg_box (UCHAR *txt, UCHAR *title, ULONG options); static WINDATA WTV_data; static DIVE_CAPS DiveCaps = {0}; // DIVE capabilities of system static FOURCC fccFormats[100] = {0}; // Color format code static SETUP_BLITTER SetupBlitter; // structure for blitter ops. /* This function will display a TV in the window using DIVE. The basic * * theory is that the WinCast board will be continually capturing into the * * buffer and DIVE will blit the image onto the screen. The blitter is * * setup in the main thread of the program where window details are known. */ VOID APIENTRY DiveTV (ULONG data_addr) { PWINDATA win_data = NULL; /* Structure holding window information */ UCHAR *tv_image = NULL; /* Capture buffer for TV image */ size_t tv_size = 0; /* Size of capture buffer */ ULONG rc = 0; /* DIVE error return code */ ULONG dive_srcbuf_no = 0; /* DIVE source buffer number */ ULONG line_len = 0; ULONG scanline_bytes = 0; ULONG scanlines = 0; PBYTE dive_buf_addr = 0; RECTL dive_rect; /* Set the window information and check it's valid. */ if ((win_data = (PWINDATA)data_addr) == NULL) { DosExit (EXIT_PROCESS, 1); return; } /* Wait until we are permitted to proceed */ while (win_data->win_blit_halt) DosSleep (100); /* Allocate a capture buffer for the image and declare it to DIVE */ tv_size = (size_t)(win_data->win_dive_width * win_data->win_dive_height * 4); rc = DosAllocMem ((PPVOID)&tv_image, tv_size, (PAG_COMMIT | PAG_WRITE)); if (rc != NO_ERROR) { DosExit (EXIT_PROCESS, 1); return; } #ifdef DIVE_ENABLED line_len = (win_data->win_dive_width << 1); line_len = (line_len - (line_len % 4)); rc = DiveAllocImageBuffer (win_data->win_dive_handle, &dive_srcbuf_no, FOURCC_Y422, win_data->win_dive_width, win_data->win_dive_height, 0, // DIVE sets line len (PBYTE)tv_image); if (rc) { DosExit (EXIT_PROCESS, 1); return; } dive_rect.xLeft = 0; dive_rect.yTop = 0; dive_rect.xRight = win_data->win_dive_width; dive_rect.yBottom = win_data->win_dive_height; #endif #ifdef VCAI_ENABLED // Connect to the capture board and start the capture. VcaiVideoRectValidate (0, 0, win_data->win_dive_width, win_data->win_dive_height, 0, 0, win_data->win_dive_width, win_data->win_dive_height); #ifdef VCAI_MONITOR VcaiWCastMonitor (win_data->win_dive_width, win_data->win_dive_height, (ULONG)tv_image); // VcaiVideoRectValidate (0, 0, // win_data->win_dive_width, win_data->win_dive_height, // 0, 0, // win_data->win_dive_width, win_data->win_dive_height); VcaiOverlay (TRUE); #endif #endif win_data->win_bliting = TRUE; while (!win_data->win_blit_halt) { #ifdef DIVE_ENABLED DosSleep (30); /* Blit the image to the screen. There may be a need for the DIVE * * buffer (dive_srcbuf_no) to be DiveBeginImageBufferAccess'ed * * before the blit is made. */ DiveBlitImage (win_data->win_dive_handle, dive_srcbuf_no, DIVE_BUFFER_SCREEN); #endif } #ifdef VCAI_ENABLED #ifdef VCAI_MONITOR VcaiOverlay (FALSE); // This call will stop displaying the image and free the memory that is // stuck in the PC RAM VcaiWCastMonitor (0, 0, 0L); #endif VcaiVideoInputSet (4); VcaiDeviceClose (win_data->win_vcai_handle); #endif /* Free any buffers and undeclare any of the DIVE buffers used */ #ifdef DIVE_ENABLED DiveFreeImageBuffer (win_data->win_dive_handle, dive_srcbuf_no); #endif DosFreeMem (tv_image); /* Inform the main thread that all has finished okay. */ win_data->win_bliting = FALSE; } MRESULT EXPENTRY TVWindowProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { static PWINDATA win_data = NULL; /* Pointer to window data */ HPS hps; /* Presentation Space handle */ HRGN hrgn; /* Region handle */ RGNRECT rgnCtl; /* Processing control structure */ RECTL rcl; /* Current widow rectangle */ POINTL pointl; /* Point to offset from Desktop */ ULONG rc; ULONG width; /* Width of the current rectangle */ MOUSEPOS mousepos; /* Position of mouse in window */ /* Get the pointer to window data */ if (win_data == NULL) { if ((win_data = (PWINDATA)WinQueryWindowULong (hwnd, 0)) == NULL) return WinDefWindowProc (hwnd, msg, mp1, mp2); } /* Handle messages to this window */ switch (msg) { case WM_COMMAND: switch (SHORT1FROMMP (mp1)) { case ID_FILE_EXIT: win_data->win_blit_halt = TRUE; DiveSetupBlitter (win_data->win_dive_handle, 0); WinPostMsg (hwnd, WM_QUIT, 0L, 0L); break; case ID_TV_SETUP: if (NotebookOpen) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, (PSZ)"Settings notebook already open", (PSZ)WTV_NAME, 0, MB_OK | MB_INFORMATION); break; } HwndNBFrame = WinLoadSecondaryWindow (HWND_DESKTOP, HWND_DESKTOP, (PFNWP)NotebookDlgProc, (HMODULE)NULLHANDLE, IDD_NOTE, NULL); break; case ID_TV_CON1: case ID_TV_CON2: case ID_TV_RF: case ID_TV_SVHS: case ID_TV_TEST: if (win_data->win_vcai_handle == 0) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, (PSZ)"Connector not initialised", (PSZ)WTV_NAME, 0, MB_OK | MB_INFORMATION); break; } #ifdef VCAI_ENABLED /* Now, alter the connector to the appropriate one */ VcaiVideoInputSet (SHORT1FROMMP(mp1)-BASE_CONNECTOR); #endif break; default: /* Let PM handle this message. */ return WinDefWindowProc (hwnd, msg, mp1, mp2); } break; case WM_BUTTON1CLICK : WinQueryWindowRect (hwnd, &rcl); WinMapWindowPoints (hwnd, HWND_DESKTOP, (PPOINTL)&rcl, 2); mousepos.mp_x = MOUSEMSG (&msg)->x + rcl.xLeft; mousepos.mp_y = MOUSEMSG (&msg)->y + rcl.yBottom; remote_open (mousepos); break; case WM_VRNDISABLED: #ifdef DIVE_ENABLED /* Stop the blitter */ DiveSetupBlitter (win_data->win_dive_handle, 0); #endif break; case WM_VRNENABLED: if ((hps = WinGetPS (hwnd)) == 0) break; if ((hrgn = GpiCreateRegion (hps, 0L, NULL)) == RGN_ERROR) { WinReleasePS( hps ); break; } /* NOTE: If mp1 is zero, then this was just a move message. * * Illustrate the visible region on a WM_VRNENABLE. */ WinQueryVisibleRegion (hwnd, hrgn); rgnCtl.ircStart = 0; rgnCtl.crc = 50; rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT; /* Get the all ORed rectangles */ rc = (ULONG)GpiQueryRegionRects (hps, hrgn, NULL, &rgnCtl, win_data->win_rcls); if (rc == FALSE) { #ifdef DIVE_ENABLED /* Reset the blitter and close */ DiveSetupBlitter (win_data->win_dive_handle, 0); #endif GpiDestroyRegion (hps, hrgn); WinReleasePS (hps); break; } win_data->win_rcl_cnt = rgnCtl.crcReturned; /* Now find the window position and size, relative 2 parent * * Convert the point to offset from desktop lower left. */ WinQueryWindowPos (win_data->win_hwnd_client, &win_data->win_swp); pointl.x = win_data->win_swp.x; pointl.y = win_data->win_swp.y; WinMapWindowPoints (win_data->win_hwnd_frame, HWND_DESKTOP, &pointl, 1); /* Tell DIVE about the new settings. */ SetupBlitter.lScreenPosX = pointl.x; SetupBlitter.lScreenPosY = pointl.y; SetupBlitter.ulDstWidth = win_data->win_swp.cx; SetupBlitter.ulDstHeight = win_data->win_swp.cy; SetupBlitter.ulNumDstRects = win_data->win_rcl_cnt; SetupBlitter.pVisDstRects = win_data->win_rcls; #ifdef DIVE_ENABLED DiveSetupBlitter (win_data->win_dive_handle, &SetupBlitter); #endif win_data->win_blit_halt = FALSE; GpiDestroyRegion (hps, hrgn); WinReleasePS (hps); break; case WM_REALIZEPALETTE: #ifdef DIVE_ENABLED /* This tells DIVE that the physical palette may have changed. */ DiveSetDestinationPalette (win_data->win_dive_handle, 0, 0, 0); #endif break; case WM_CLOSE: /* Post to quit the dispatch message loop. */ win_data->win_blit_halt = TRUE; DiveSetupBlitter (win_data->win_dive_handle, 0); WinPostMsg (hwnd, WM_QUIT, 0L, 0L); break; default: /* Let PM handle this message. */ return WinDefWindowProc (hwnd, msg, mp1, mp2); } return ( FALSE ); } PWINDATA DiveSetup (char *name, USHORT instance, USHORT connector) { DRIVERHANDLE vhandle; char txt[400]; WTV_data.win_vcai_connector = connector; strcpy (WTV_data.win_vcai_name, name); WTV_data.win_vcai_no = instance; vhandle = VcaiDeviceOpen (name, instance); if (vhandle <= 0) { sprintf (txt, "Cannot Open Device %s %u !", name, instance); WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, txt, (PSZ)WTV_NAME, 0, MB_OK | MB_INFORMATION); return FALSE; } WTV_data.win_vcai_handle = vhandle; VcaiDeviceConnect (vhandle); VcaiVideoInputSet (connector); #ifdef DIVE_ENABLED // Get the DIVE capabilities and if the system is 16 coloured then exit DiveCaps.pFormatData = fccFormats; DiveCaps.ulFormatLength = 120; DiveCaps.ulStructLen = sizeof (DIVE_CAPS); if (DiveQueryCaps (&DiveCaps, DIVE_BUFFER_SCREEN)) { msg_box ("Unable to query the Dive environment", "Error", MB_OK | MB_ERROR); return FALSE; } if (DiveCaps.ulDepth < 8) { msg_box ("Unable to execute in a 16-colour environment", "Error", MB_OK | MB_ERROR); return FALSE; } // Calculate the bytes per pixel WTV_data.win_sizebytes = DiveCaps.ulScanLineBytes / DiveCaps.ulHorizontalResolution; // Open the DIVE device and the VCAI capture device if (DiveOpen (&(WTV_data.win_dive_handle), FALSE, 0)) { msg_box ("Unable to open the DIVE device", "Error", MB_OK | MB_ERROR); return FALSE; } #endif // Set the window size WTV_data.win_width = WIDTH; // 640 400 WTV_data.win_height = HEIGHT; // 320 300 #if 0 WTV_data.win_dive_width = WTV_data.win_width - 4; WTV_data.win_dive_height = (3 * WTV_data.win_height) >> 2; #else WTV_data.win_dive_width = WIDTH; // 636 WTV_data.win_dive_height = HEIGHT; // 320 #endif return &WTV_data; } int DiveRegister (HAB hab) { ULONG flCreate; // Window creation control flags ULONG rc; // Register a window class, and create a standard window. WinRegisterClass (hab, (PSZ)"WTVWindow", TVWindowProc, 0, sizeof (ULONG)); flCreate = FCF_TASKLIST | FCF_SYSMENU | FCF_TITLEBAR | FCF_ICON | FCF_SIZEBORDER | FCF_MINMAX | FCF_MENU | FCF_SHELLPOSITION; // Window WTV_data.win_hwnd_frame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE, &flCreate, (PSZ)"WTVWindow", (PSZ)"DIVE Window", WS_SYNCPAINT | WS_VISIBLE, 0, ID_MAINWND, &(WTV_data.win_hwnd_client)); WinSetWindowULong (WTV_data.win_hwnd_client, 0, (ULONG)&WTV_data); // Query some information about the window, i.e. size and position WTV_data.win_cxWidthBorder = (LONG)WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER); WTV_data.win_cyWidthBorder = (LONG)WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER); WTV_data.win_cyTitleBar = (LONG)WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR); WTV_data.win_cyMenu = (LONG)WinQuerySysValue (HWND_DESKTOP, SV_CYMENU); // WTV_data.win_cxWidthWindow = (WTV_data.win_width / 2) + WTV_data.win_cxWidthWindow = WTV_data.win_width + (WTV_data.win_cxWidthBorder * 2); WTV_data.win_cyHeightWindow = (WTV_data.win_cyWidthBorder * 2) + WTV_data.win_cyTitleBar + WTV_data.win_cyMenu + WTV_data.win_height; WTV_data.win_cxWindowPos = ((LONG)WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) - WTV_data.win_cxWidthWindow ) / 2; WTV_data.win_cyWindowPos = ((LONG)WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) - WTV_data.win_cyHeightWindow ) / 2; // Set the window position and size. WinSetWindowPos (WTV_data.win_hwnd_frame, HWND_TOP, WTV_data.win_cxWindowPos, WTV_data.win_cyWindowPos, WTV_data.win_cxWidthWindow, WTV_data.win_cyHeightWindow, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); // Turn on visible region notification. WinSetVisibleRegionNotify (WTV_data.win_hwnd_client, TRUE); // Send an invlaidation message to the client. SetupBlitter.ulStructLen = sizeof (SETUP_BLITTER); SetupBlitter.fccSrcColorFormat = FOURCC_Y422; // SetupBlitter.ulSrcWidth = (WTV_data.win_dive_width / 2); SetupBlitter.ulSrcWidth = WTV_data.win_dive_width; SetupBlitter.ulSrcHeight = WTV_data.win_dive_height; SetupBlitter.ulSrcPosX = 0; SetupBlitter.ulSrcPosY = 0; SetupBlitter.ulDitherType = 1; // Dither please! SetupBlitter.fInvert = FALSE; SetupBlitter.lDstPosX = 0; SetupBlitter.lDstPosY = 0; SetupBlitter.fccDstColorFormat = FOURCC_SCRN; WinPostMsg (WTV_data.win_hwnd_frame, WM_VRNENABLED, 0L, 0L); // Start up the blitting thread. WTV_data.win_bliting = FALSE; WTV_data.win_blit_halt = TRUE; rc = DosCreateThread (&(WTV_data.win_blit_tid), (PFNTHREAD)DiveTV, (ULONG)&WTV_data, 0L, 8192L); if (rc) { WinSetVisibleRegionNotify (WTV_data.win_hwnd_client, FALSE); #ifdef DIVE_ENABLED DiveClose (WTV_data.win_dive_handle); #endif WinDestroyWindow (WTV_data.win_hwnd_frame); return FALSE; } // Set the proiroty of the blitting thread DosSetPriority (PRTYS_THREAD, PRTYC_IDLETIME, 0, WTV_data.win_blit_tid); WTV_data.win_blit_halt = FALSE; return TRUE; } int DiveStop () { #ifdef DIVE_ENABLED // Set the variable to end the running thread, and wait for it to end. WTV_data.win_blit_halt = TRUE; DosWaitThread (&(WTV_data.win_blit_tid), DCWW_WAIT); #endif #ifdef DEBUG msg_box ("DiveTV thread has been closed okay", "Info", MB_OK | MB_INFORMATION); #endif // Turn off visible region notificationm tidy up, and terminate DIVE WinSetVisibleRegionNotify (WTV_data.win_hwnd_client, FALSE); #ifdef DIVE_ENABLED DiveClose (WTV_data.win_dive_handle); #endif // Process for termination WinDestroyWindow (WTV_data.win_hwnd_frame); return TRUE; } static void msg_box (UCHAR *txt, UCHAR *title, ULONG options) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, txt, title, 0, options); }