/****************************************************************************** * * PROGRAM: TomsGOV.c * * AUTHOR: Tom Bouril (October 1997) * * DESCRIPTION: Displays live video in a window and GOV (Graphics Over Video). * To DRAW graphics on video, press the LEFT mouse button. * To ERASE graphics on video, press the RIGHT mouse button. * * PARALLAX BUG OVERRIDE: There is a bug in the Parallax library that causes * some X graphics primitives to not draw or erase * properly. This bug and program sample applies * only to systems running the Solaris OS. * * The following X graphics function calls do not draw or * erase properly when used with Parallax video. To * override this bug, the XCreateGC() function must be * called with its 3rd parameter set to "GCLineWidth." * The 4th parameter of XCreateGC() (a pointer to struct * XGCValues) must have its "line_width" member variable * set to the value shown below, corresponding to graphics * function that is called. For further details, see the * source code below. * * X FUNCTION CALL | XGCValues.line_width = * ===================================================== * XDrawArc() | ANY VALUE -- No bug. * XDrawLine() | 1 * XDrawLines() | 1 * XDrawPoints() | ANY VALUE -- No bug. * XDrawRectangle() | 1 * XDrawString() | 0 * XFillArc() | 0 * XFillPolygon() | ANY VALUE -- No bug. * XFillRectangle() | ANY VALUE -- No bug. * * * * NOTE: This program only uses Xlib calls, no Xt Widgets are used. If you * use Parallax XT widget calls, the GCs must still be created with * the GCLineWidth parameter shown above. * ******************************************************************************/ #include #include #include #include /****************************************************************************** * * FUNCTION: main() * * DESCRIPTION: Perform initializations and then pop up a window that displays * live video. Graphics are drawn/erased over video by pressing * the left/right mouse buttons. * ******************************************************************************/ void main(int argc, char **argv) { Window win; Display *display; char *progname = argv[0], *TextString = "This text printed by XDrawString()."; int InputWire, screen, mask, videowidth, videoheight; GC gcGraphics, gcVideo; plx_signal *plxsignal = NULL; plx_IO *plxio = NULL; XGCValues values; XEvent event; XPoint Points[9]; XSetWindowAttributes attr; XVisualInfo *visualInfo; // Open X display server. display = XOpenDisplay(getenv("DISPLAY")); if (display == NULL) { printf("%s: Can't connect to X Server Display: %s\n", progname, XDisplayName(getenv("DISPLAY"))); exit (0); } // Get default screen. screen = (int) XDefaultScreen(display); // Obtain information about the video display. visualInfo = XPlxGetVideoVisual(screen, display); if (TrueColor == visualInfo->class) { // Parallax card has a frame buffer. // Create a colormap for this window. attr.colormap = XCreateColormap(display, XRootWindow(display, screen), visualInfo->visual, AllocNone); } else { // Parallax card is an overlay card. Get colormap used // by the frame buffer. attr.colormap = XDefaultColormap(display, screen); } // Set up colormap so it will work when window depth is different // than root depth. This is done by setting Border Pixel and // Background Pixel. mask = CWBackPixel | CWColormap | CWBorderPixel; attr.background_pixel = BlackPixel(display, DefaultScreen(display)); attr.border_pixel = WhitePixel(display, DefaultScreen(display)); // Create tiny window for Parallax video. Resize it later to // fit exact size of Parallax video. win = XCreateWindow(display, RootWindow(display, screen), 0, 0, 1, 1, 1, (int) visualInfo->depth, InputOutput, visualInfo->visual, mask, &attr); // Create a graphics CG and a video GC. To override bug in Parallax // library, change line width of both GCs to 1. values.line_width = 1; gcVideo = XCreateGC(display, win, GCLineWidth, &values); gcGraphics = XCreateGC(display, win, GCLineWidth, &values); XFlush(display); // Send all buffered requests to the XServer. // Query Parallax card for hardware config. parameters. plxio = XPlxQueryConfig(display, win, gcVideo); // Select wire to be used for video input. 0 = Composite-In No. 1, // 1 = Composite-In No. 2. InputWire = 0; // Select Parallax video input parameters. XPlxVideoInputSelect(display, win, gcVideo, PLX_INPUT_0, PLX_NTSC, (InputWire << 16) | PLX_COMP, PLX_RGB24); // Determine if channel selected by XPlxVideoInputSelect() // contains a valid sync signal. plxsignal = XPlxQueryVideo(display, win, gcVideo); while (!plxsignal->sync_ok) { // Loop until XPlxQueryVideo() finds a valid sync signal. puts("Sync Absent - Hook up a video input source."); XPlxSleep(500000); // Wait 0.5 seconds plxsignal = XPlxQueryVideo(display, win, gcVideo); } // Obtain video screen's width and height from value returned // by XPlxQueryVideo(). videowidth = plxsignal->w; videoheight = plxsignal->h - plxsignal->b; // Set the video tags for graphics and video GCs. XPlxVideoTag(display, win, gcVideo, PLX_VIDEO); XPlxVideoTag(display, win, gcGraphics, PLX_GRAPHICS_24); // Select event type(s) sent to the video window. ExposureMask enables // Expose events, which occur when any part of the window becomes visible. XSelectInput(display, win, ExposureMask | ButtonPressMask); // Resize window to fit video image. XResizeWindow(display, win, videowidth, videoheight); // Display the window just created. XMapWindow(display, win); // EVENT LOOP. while (1) { // Get next event in event queue, XNextEvent(display, &event); // Trap event(s) here, if necessary. switch(event.type) { case Expose: // Previously invisible part of window becomes visible. // Put live video onto window. XPlxVideoLive(display, win, gcVideo, 0, plxsignal->b, 0, 0, videowidth, videoheight); break; case ButtonPress: if (event.xbutton.button == 1) { // Left mouse button pressed. // DRAW GOV (Graphics Over Video) // Initiialize XPoint array for XDrawPoints(). Points[0].x = 10; Points[0].y = 120; Points[1].x = 55; Points[1].y = 120; Points[2].x = 100; Points[2].y = 120; Points[3].x = 10; Points[3].y = 170; Points[4].x = 55; Points[4].y = 170; Points[5].x = 100; Points[5].y = 170; Points[6].x = 10; Points[6].y = 220; Points[7].x = 55; Points[7].y = 220; Points[8].x = 100; Points[8].y = 220; XDrawPoints(display, win, gcGraphics, Points, 9, CoordModeOrigin); XDrawLine(display, win, gcGraphics, 10, 10, 100, 100); XFillRectangle(display, win, gcGraphics, 120, 10, 100, 100); XDrawRectangle(display, win, gcGraphics, 120, 120, 100, 100); XDrawArc(display, win, gcGraphics, 230, 120, 50, 50, 0, 360*64); // Initiialize XPoint array for XFillPolygon(). Points[0].x = 300; Points[0].y = 10; Points[1].x = 380; Points[1].y = 30; Points[2].x = 420; Points[2].y = 90; Points[3].x = 350; Points[3].y = 50; Points[4].x = 320; Points[4].y = 85; XFillPolygon(display, win, gcGraphics, Points, 5, NULL, CoordModeOrigin); // Inititalize XPoint array for XDrawLines(). Points[0].y = 120; Points[1].y = 140; Points[2].y = 200; Points[3].y = 160; Points[4].y = 195; Points[5].x = Points[0].x; Points[5].y = Points[0].y; XDrawLines(display, win, gcGraphics, Points, 6, CoordModeOrigin); // To override bug in Parallax library, change the gcGraphics // line width to 0 for calls to XDrawString() and XFillArc(). values.line_width = 0; XChangeGC(display, gcGraphics, GCLineWidth, &values); XDrawString(display, win, gcGraphics, 10, 240, TextString, strlen(TextString)); XFillArc(display, win, gcGraphics, 230, 10, 50, 50, 0, 360*64); // Set gcGraphics line width back to 1 for other X calls. values.line_width = 1; XChangeGC(display, gcGraphics, GCLineWidth, &values); } else if (event.xbutton.button == 2) { // Middle mouse button pressed. } else if (event.xbutton.button == 3) { // Right mouse buttton pressed. // ERASE the GOV. // Initiialize XPoint array for XDrawPoints(). Points[0].x = 10; Points[0].y = 120; Points[1].x = 55; Points[1].y = 120; Points[2].x = 100; Points[2].y = 120; Points[3].x = 10; Points[3].y = 170; Points[4].x = 55; Points[4].y = 170; Points[5].x = 100; Points[5].y = 170; Points[6].x = 10; Points[6].y = 220; Points[7].x = 55; Points[7].y = 220; Points[8].x = 100; Points[8].y = 220; XDrawPoints(display, win, gcVideo, Points, 9, CoordModeOrigin); XDrawLine(display, win, gcVideo, 10, 10, 100, 100); XFillRectangle(display, win, gcVideo, 120, 10, 100, 100); XDrawRectangle(display, win, gcVideo, 120, 120, 100, 100); XDrawArc(display, win, gcVideo, 230, 120, 50, 50, 0, 360*64); // Initiialize XPoint array for XFillPolygon(). Points[0].x = 300; Points[0].y = 10; Points[1].x = 380; Points[1].y = 30; Points[2].x = 420; Points[2].y = 90; Points[3].x = 350; Points[3].y = 50; Points[4].x = 320; Points[4].y = 85; XFillPolygon(display, win, gcVideo, Points, 5, NULL, CoordModeOrigin); // Inititalize XPoint array for XDrawLines(). Points[0].y = 120; Points[1].y = 140; Points[2].y = 200; Points[3].y = 160; Points[4].y = 195; Points[5].x = Points[0].x; Points[5].y = Points[0].y; XDrawLines(display, win, gcVideo, Points, 6, CoordModeOrigin); // To override bug in Parallax library, change the gcVideo // line width to 0 for calls to XDrawString() and XFillArc(). values.line_width = 0; XChangeGC(display, gcVideo, GCLineWidth, &values); XDrawString(display, win, gcVideo, 10, 240, TextString, strlen(TextString)); XFillArc(display, win, gcVideo, 230, 10, 50, 50, 0, 360*64); // Set gcVideo line width back to 1 for other X calls. values.line_width = 1; XChangeGC(display, gcVideo, GCLineWidth, &values); } break; default: break; } } // End: while(1) loop. return; }