

/* Xvid.c - basic video window interface routines */

/* 
	modified by RMS 6/8/87

	Added error checking; does intelligent things for non-video displays.
	Although the functions will return -1 if not called on a video
	display, they will still put up windows and write stuff into
	them for debugging purposes. I have included the bitmap() code
	for background pixmaps in this file for convenience in portability.

	IMPORTANT: note that XStartVideo() now only takes 4 parms;
		   the previous 'srcpix' parm (#2) was always 0,
		   so I took it out.
*/

#include <stdio.h>
#include <X10/Xlib.h>

#define SCOPE
#include "XVideo.h"

/* the following are default pixmaps for video windows on non-plx */

/* #include "../bitmaps/still.bitmap" */

#define still_width 16
#define still_height 16
static short still_bits[] = {
   0x0000, 0x3c3c, 0x2424, 0x2424,
   0x3c3c, 0x0000, 0x03c0, 0x0240,
   0x0240, 0x03c0, 0x0000, 0x3c3c,
   0x2424, 0x2424, 0x3c3c, 0x0000};

/* #include "../bitmaps/live.bitmap" */

#define live_width 16
#define live_height 16
static short live_bits[] = {
   0x0000, 0x0603, 0x8f1f, 0xddfb,
   0xfcf1, 0x7800, 0x01c7, 0xcfcf,
   0xfffd, 0x7870, 0x0000, 0x0e0e,
   0x3fbf, 0xf9f3, 0xe1c1, 0x0000};

/* #include "../bitmaps/scale.bitmap" */

#define scale_width 16
#define scale_height 16
static short scale_bits[] = {
   0x0380, 0x07c0, 0x07c0, 0x07c0,
   0x0380, 0x001c, 0x003e, 0x1c7f,
   0x3e7f, 0x3e7f, 0x3e3e, 0x1c1c,
   0x01c0, 0x01c0, 0x01c0, 0x0000};

/* #include "../bitmaps/gray.bitmap" */

#define gray_width 16
#define gray_height 16
static short gray_bits[] = {
   0xaaaa, 0x5555, 0xaaaa, 0x5555,
   0xaaaa, 0x5555, 0xaaaa, 0x5555,
   0xaaaa, 0x5555, 0xaaaa, 0x5555,
   0xaaaa, 0x5555, 0xaaaa, 0x5555};

/* **************************************
 * begin EXTERNAL variables
 */

	int	VideoInitialized = FALSE;
	int	VideoDebug = FALSE;
	int	VideoNoCheck = FALSE;	/* no parameter checking */

/* 
 * end EXTERNAL variables
 * ************************************** */

/* **************************************
 * begin LOCAL variables
 */
	static Bitmap 	nullbm=NULL;
	static Window 	wk;
/* 
 * end LOCAL variables
 * ************************************** */

/* *******************************************************************
 * FUNCTION
 * XSetVideoDisplay();
 *
 * This function sets the appropriate action for subsequent calls to
 * routines which use video windows. If you don't call it first, it
 * will still get called automatically by any functions in the XVideo
 * library. This helps the routines do intelligent things on non-Parallax
 * systems. This is slightly contrary to X conventions for device independence,
 * but then the whole video thing under X10 is a crock anyway.
 */

int
XSetVideoDisplay()

{
Bitmap	gray_bitmap,
	live_bitmap,
	still_bitmap,
	scale_bitmap;

	if( VideoInitialized ) 
		return VideoDevice;

	VideoDevice = DISPLAY_IS_PLX;
	if( !VideoDevice )
	{
		gray_bitmap = 
			XStoreBitmap(gray_width,gray_height,gray_bits);
		vback_pixmap =
			XMakePixmap(gray_bitmap,BlackPixel,WhitePixel);

		live_bitmap = 
			XStoreBitmap(live_width,live_height,live_bits);
		live_pixmap =
			XMakePixmap(live_bitmap,BlackPixel,WhitePixel);

		still_bitmap = 
			XStoreBitmap(still_width,still_height,still_bits);
		still_pixmap =
			XMakePixmap(still_bitmap,BlackPixel,WhitePixel);

		scale_bitmap = 
			XStoreBitmap(scale_width,scale_height,scale_bits);
		scale_pixmap =
			XMakePixmap(scale_bitmap,BlackPixel,WhitePixel);

		XFreeBitmap( gray_bitmap );
		XFreeBitmap( live_bitmap );
		XFreeBitmap( still_bitmap );
		XFreeBitmap( scale_bitmap );

		VideoLabel = NULL;		/* no labels yet */
		VideoInitialized = TRUE;	/* we are ready, Freddy */

		VideoFont = XGetFont(DEF_VID_FONT);
		if( !VideoFont )
			fprintf(stderr,
			"XSetVideoDisplay: can't open label font: %s\n",
			DEF_VID_FONT );
	}
	
	return VideoDevice;
}

/* *******************************************************************
 * FUNCTION
 * success = XStartVideo(	Window	w,
 *				int	video_source_x,
 *				int	video_source_y,
 *				int	video_priority	);
 * int success;
 *
 * Assumes that you have already created a window with valid parameters.
 * Video windows must have widths and x-coords that are multiples of 16.
 * The priority is generally in the range 1-3, and represents the number
 * of frames of incoming video that can be missed while performing graphics
 * instructions. A value of 0 will really slow things to a crawl. This
 * function fills the window with live motion video. Output is clipped to
 * the window boundaries. Returns 0 if okay, -1 if (!VideoDisplay).
 */

int
XStartVideo(w,sx,sy,prio)

	Window	w;
	int sx,sy, prio;
{
static char *funcname = "XStartVideo";
static int srcpix = 0;
WindowInfo	wi;

	if( !VideoInitialized ) XSetVideoDisplay();

	if (!nullbm )
		nullbm = XStoreBitmap(1,1,&sx);
	
	if( sx%16 && !VideoNoCheck ) {
		if( VideoDebug )
		{
			fprintf(stderr,"%s: x-coord not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: x-coord changed from %d to %d.\n",
				funcname, sx, ROUND_16(sx) );
		}
		sx = ROUND_16(sx);
	}

	if( VideoDevice ) 
	{
		XPixFill(w,0,0,2048|sx,2048|sy,0,nullbm,1,1);
		XPixFill(w,0,0,2048|prio,2048,srcpix,nullbm,0,1);
		XSync(FALSE);
		return SUCCESS;
	}
	else 
	{	/* do something intelligent (we hope) */
		XQueryWindow(w,&wi);
		XTileSet(w,0,0,wi.width,wi.height,live_pixmap);
		set_vidlabel(w,0,0);
		XSync(FALSE);
		return FAILURE;		/* because we aren't a video device */
	}
}

/* *******************************************************************
 * FUNCTION
 * XStillVideo(	Window	w,
 *		int	video_source_x,
 *		int	video_source_y,
 *		int	destination_x,
 *		int	destination_y,
 *		int	destination_width,
 *		int	destination_height	);
 *
 * Assumes that you have already created a window with valid parameters.
 * Video windows must have widths and x-coords that are multiples of 16.
 * Puts a still video image from the source at offset (x,y) into the
 * destination box.
 */

int
XStillVideo(w,sx,sy,dstx,dsty,wid,h)

	Window w;
	int	sx,sy,dstx,dsty,wid,h;
{
static char *funcname = "XStillVideo";

	if( !VideoInitialized ) 
		XSetVideoDisplay();

	if (!nullbm)
		nullbm = XStoreBitmap(1,1,&sx);

	if( sx%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: source x-coord not multiple of 16.\n",funcname);
			fprintf(stderr,"%s: source x-coord changed from %d to %d\n",
				funcname, sx, ROUND_16(sx) );
		}
		sx = ROUND_16(sx);
	}

	if( dstx%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: dest x-coord not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: dest x-coord changed from %d to %d\n",
				funcname, dstx, ROUND_16(dstx) );
		}
		dstx = ROUND_16(dstx);
	}

	if( wid > VIDEO_WIDTH ) 
		wid = VIDEO_WIDTH;

	if( wid%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: width not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: width changed from %d to %d\n",
				funcname, wid, UP_TO_16(wid) );
		}
		wid = ROUND_16(wid);
	}

	if( VideoDevice ) 
	{
		XPixFill(w,0,0,2048|sx,2048|sy,0,nullbm,1,1);
		XPixFill(w,dstx,dsty,wid,h,0,nullbm,3,1);
		XSync(FALSE);
		return SUCCESS;
	}
	else 
	{	/* do something intelligent (we hope) */
		XTileSet(w,dstx,dsty,wid,h,still_pixmap);
		set_vidlabel(w,dstx,dsty);
		XSync(FALSE);
		return FAILURE;		/* because we aren't a video device */
	}
}

/* *******************************************************************
 * FUNCTION
 * XScaleVideo(	Window	w,
 *		int	video_source_x,
 *		int	video_source_y,
 *		int	video_source_width,
 *		int	video_source_height,
 *		int	destination_x,
 *		int	destination_y,
 *		int	destination_width,
 *		int	destination_height	);
 *
 * Assumes that you have already created a window with valid parameters.
 * Video windows must have widths and x-coords that are multiples of 16.
 * Does a dynamic scale/expand from source to destination video box.
 */

int
XScaleVideo(w,sx,sy,sw,sh,dstx,dsty,wid,h)

	Window w;
	int	sx,sy,sw,sh,dstx,dsty,wid,h;
{
static char *funcname = "XScaleVideo";

	if( !VideoInitialized ) 
		XSetVideoDisplay();

	if (!nullbm)
		nullbm = XStoreBitmap(1,1,&sx);

	if( sx%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: source x-coord not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: source x-coord changed from %d to %d\n",
				funcname, sx, ROUND_16(sx) );
		}
		sx = ROUND_16(sx);
	}

	if( dstx%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: dest x-coord not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: dest x-coord changed from %d to %d\n",
				funcname, dstx, ROUND_16(dstx) );
		}
		dstx = ROUND_16(dstx);
	}

	if( sw > VIDEO_WIDTH ) 
		sw = VIDEO_WIDTH;

	if( sw%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: source width not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: source width changed from %d to %d\n",
				funcname, sw, ROUND_16(sw) );
		}
		sw = UP_TO_16(sw);
	}

	if( wid%16 && !VideoNoCheck ) 
	{
		if( VideoDebug )
		{
			fprintf(stderr,"%s: width not multiple of 16.\n",
				funcname);
			fprintf(stderr,"%s: width changed from %d to %d\n",
				funcname, wid, UP_TO_16(wid) );
		}
		wid = ROUND_16(wid);
	}

	if( VideoDevice ) 
	{
		XPixFill(w,0,0,2048|sx,2048|sy,0,nullbm,1,1);
		XPixFill(w,0,0,2048|sw,2048|sh,0,nullbm,2,1);
		XPixFill(w,dstx,dsty,wid,h,0,nullbm,4,1);
		XSync(FALSE);
		return SUCCESS;
	}
	else 
	{	/* do something intelligent (we hope) */
		XTileSet(w,dstx,dsty,wid,h,scale_pixmap);
		set_vidlabel(w,dstx,dsty);
		XSync(FALSE);
		return FAILURE;		/* because we aren't a video device */
	}
}

/* *******************************************************************
 * FUNCTION
 * XSetVideoColor(	int	color_index,
 *			int	red_component,
 *			int	green_component,
 *			int	blue_component	);
 *
 * This takes as input an ODD pseudo-color index less than 64, and a
 * color definition with each component in 8-bit rgb format. Thereafter,
 * graphics operations over video can be requested by giving the index of 
 * one of these reserved colors, and a plane mask of 0x3f (or less).
 */

int
XSetVideoColor(c,red,g,b)

	int	c,red,g,b;
{
static char *funcname = "XSetVideoColor";

	if( !VideoInitialized ) 
		XSetVideoDisplay();

	if (!nullbm)
		nullbm = XStoreBitmap(1,1,&c);
	
	if( !ODD(c) && !VideoNoCheck ) 
	{
		fprintf(stderr,
			"%s: requested color index %d is not odd.\n",
			funcname,c);
		return FAILURE;		/* because it won't work, Jack */
	}

	if( VideoDevice ) 
	{
		XPixFill(RootWindow,0,0,2048|(red&0xff),2048,0,nullbm,6,~0);
		XPixFill(RootWindow,
			0,0,2048|(g&0xff),2048|(b&0xff),c,nullbm,7,~0);
		XSync(FALSE);
		return SUCCESS;
	}
	else 
		return FAILURE;	/* because we aren't a video device */
}

/* ********************************************************************	*/
/* set_vidlabel(	Window	w,
/*			int	x,y	);
/* 
/* This routine attaches the current label to the current video window.
 */

static
set_vidlabel(w,x,y)

	Window	w;
	int	x,y;
{
int	len;
char	*str;

	if( VideoDevice || (VideoLabel == NULL) || !VideoFont || !w ) 
		return;		/* can't (or shouldn't) do anything */

	/* append space at the end of label for readability */

	len = strlen(VideoLabel);
	if( len < 1 )
		return;

	str = calloc( 1, len+1 );
	strcpy( str, VideoLabel );
	strcat( str, " " );
	
	XText( w, x,y, str, len+1, VideoFont, WhitePixel, BlackPixel );
	XSync(0);

	free( (char *) str );
}
