/*
 *	vdibez.c
 *
 *	Bindings for Bezier curves.
 *
 *	  ++jrb   bammi@cadence.com
 *	  and Michal Jaegermann, ntomczak@vm.ucs.ulberta.ca
 *
 *	Some function have alias names in order to maintain a common
 *	set of symbols with compilers which need symbols unique in the
 *	first seven characters.  Besides this resolution is required
 *	by "The Standard" :-)
 *
 *	++jrb sync up with SpeedoGDOS docs
 *
 */
#include "common.h"
#ifndef _COMPILER_H
# include <compiler.h>
#endif
#include <types.h>


__EXTERN void vdi __PROTO((void));

#ifdef __DEF_ALL__

#define L_v_set_ap
#define L_v_bez_co
#define L_v_bez_on
#define L_v_bez_of
#define L_v_bez
#define L_v_bez_fi
#define L_v_bez_qu

#endif /* __DEF_ALL__ */


#ifdef L_v_set_ap

/*
 * Inform GDOS about  location and size of a buffer which  GDOS
 * can use for creation of Bezier curves.
 *	  buf_p  is a pointer to an address of a buffer
 *	  size	 its a buffer size in 16-bytes paragraphs
 *
 * If buf_p is NULL, then space for a buffer will be allocated
 * by GDOS - using Malloc (who knows where to look for this space?)
 *
 * "Hand coding" required - function opcode does not fit into 0-255 range
 */
void
v_set_app_buff (void *buf_p, int size)
{
	short *wptr = _intin;

	*wptr++ = (short) buf_p;		   /* low word of an address */
	*wptr++ = (short)((long)buf_p >> 16);  /* high word of an address */
	*wptr =   (short) size; 		   /* size of buffer in paragraphs */
										   /* para == 16 bytes */
	 wptr = (short *)_contrl;
	*wptr++ = -1;	/* 0  - opcode */
	*wptr++ = 0;	/* 1 */
	 wptr++;		/* 2 */
	*wptr++ = 3;	/* 3  - # of entries in _intin */
	 wptr++;		/* 4 */
	*wptr++ = 6;	/* 5 - id */
	*wptr	= 0;	/* 6 - dummy handle - really needed? */
	vdi();		/* call vdi */
}
#endif /* L_v_set_ap */

#ifdef L_v_bez_co

/*
 * If onoff is 1 then enable Bezier capabilities and
 * find a number of segments per Bezier curve.
 * Returns logarithm in a base of 2 from that number
 *
 * If onoff is 0 then disable Bezier capabilities and
 * release memory allocated in v_set_app_buff call.
 * Returns NOTHING!
 */

int
v_bez_con(int handle, int onoff)
{
	__vdi__(VDI_CONTRL_ENCODE(11, (unsigned short)(onoff), 0, 13), handle);
	return(_intout[0]);
}
#endif /* L_v_bez_co */

#ifdef L_v_bez_on

/*
 * v_bez_on (alias v_bezon)
 * Enable Bezier capabilities.
 * Returns maximum Bezier depth (a measure of smoothness). The return
 * value can range from 0-7, and is the exponent of 2, giving the
 * number of line segments that make up the curve.
 * 0 == 2**0 == 1 == straight line and
 * 7 == 2**7 == 128 line segments.
 */

__asm__(".stabs \"_v_bezon\",5,0,0,_v_bez_on"); /* dept of clean tricks */
int
v_bez_on (int handle)
{
	_contrl[4] = 4;    /* dont know why, but atari docs say so! */
	__vdi__(VDI_CONTRL_ENCODE(11, 1, 0, 13), handle);
	_contrl[4] = 0;    /* clear it back */
	return *_intout;
}
#endif /* L_v_bez_on */

#ifdef L_v_bez_of

/*
 * v_bez_off (alias v_bezoff)
 * Disable Bezier capabilities.
 * Free space allocated by GDOS for Bezier curves.
 * (see v_set_app_buff for memory alloc info)
 */
__asm__(".stabs \"_v_bezoff\",5,0,0,_v_bez_off"); /* dept of clean tricks */
void
v_bez_off (int handle)
{
	__vdi__(VDI_CONTRL_ENCODE(11, 0, 0, 13), handle);
}
#endif /* L_v_bez_of */

#ifdef L_v_bez
/*
 * Draw an unfilled Bezier curve
 *	  xyarr   - an array of 'count' pairs of control vertices
 *	  bezarr  - an array of flags specifying which control points
 *		are jump points
 *				bit 0  off - start of a polyline if not continuation
 *				bit 0  on  - start of a Bezier segment
 *				bit 1  on  - jump point (move to the next one without draw)
 *
 * Returns - a number of points in a Bezier curve
 */

int
v_bez(	   int	 handle,   /* Device handle we're drawing to */
		   int	 count,    /* Number of points total... */
	   int	*xyarr,    /* The points in x1,y1,x2,y2 format */
	   char *bezarr,   /* Flag array, so that we can set start, jump pts */
	   int	*extent,   /* "bounding box coordinates */
	   int	*totpts,   /* number of resulting polygon points */
	   int	*totmoves) /* number of resulting moves  */
{
	short *end;
	char *pbd = bezarr;
	char *opbd = (char *)_intin;
#ifndef __MSHORT__
	short *optr;
	int *iptr = xyarr;
#endif

	int cntrl0 = 6;

	/* copy entries from bezarr to _intin packing and swaping bytes ???! */
	/* this requirement for byte swapping  is not documented - if you	 */
	/* discount some old code example, but things seem to work this way  */
	end  = (short *) (pbd + count);
	while (pbd < (char *)end) {
	*(opbd + 1) = *pbd++;
	if (pbd >= (char *)end)
		break;
	*opbd = *pbd++;
	opbd += 2;
	}
#ifdef __MSHORT__
	_vdiparams[2] = (void *) xyarr;
	_vdiparams[4] = (void *) extent;
#else
	/* copy xyarr into an array of shorts */

	optr = _ptsin;
	end  = optr + count + count;
	while (optr < end)
		*optr++ = *xyarr++;
#endif

	_contrl[2] = 2; /* dont know why, the atari docs say so without */
	_contrl[4] = 6; /* any	explaination */

	__vdi__(VDI_CONTRL_ENCODE(cntrl0, count, ((count + 1) >> 1), 13), handle);

	_contrl[2] = 0;
	_contrl[4] = 0;

#ifdef __MSHORT__
	/* restore standard parameter block */
	_vdiparams[2] = (void *) _ptsin;
	_vdiparams[4] = (void *) _ptsout;
#else
	optr = _ptsout;
	iptr = extent;
	*iptr++ = *optr++;
	*iptr++ = *optr++;
	*iptr++ = *optr++;
	*iptr	= *optr;
#endif
	*totmoves = _intout[1];
	return(*totpts = _intout[0]);	/* number of points in Bezier */
}

#endif /* L_v_bez */


#ifdef L_v_bez_fi

/*
 * v_bez_fill (alias _v_bezfill)
 * Draw a filled Bezier curve
 *	  xyarr   - an array of 'count' pairs of control vertices
 *	  bezarr  - an array of flags specifying which control points
 *		are jump points
 *				bit 0  off - start of a polyline if not continuation
 *				bit 0  on  - start of a Bezier segment
 *				bit 1  on  - jump point (move to the next one without draw)
 * Returns - a number of points in a filled Bezier curve
 */

__asm__(".stabs \"_v_bezfill\",5,0,0,_v_bez_fill"); /* dept of clean tricks */
int
v_bez_fill(int handle,	   /* Device handle we're drawing to */
		   int	 count,    /* Number of points total... */
	   int	*xyarr,    /* The points in x1,y1,x2,y2 format */
	   char *bezarr,   /* Flag array, so that we can set start, jump pts */
	   int	*extent,   /* "bounding box coordinates */
	   int	*totpts,   /* number of resulting polygon points */
	   int	*totmoves) /* number of resulting moves  */
{
	short *end;
	char *pbd = bezarr;
	char *opbd = (char *)_intin;
#ifndef __MSHORT__
	short *optr;
	int *iptr = xyarr;
#endif

	int cntrl0 = 9;

	/* copy entries from bezarr to _intin packing and swaping bytes ???! */
	/* this requirement for byte swapping  is not documented - if you	 */
	/* discount some old code example, but things seem to work this way  */
	end  = (short *) (pbd + count);
	while (pbd < (char *)end) {
	*(opbd + 1) = *pbd++;
	if (pbd >= (char *)end)
		break;
	*opbd = *pbd++;
	opbd += 2;
	}
#ifdef __MSHORT__
	_vdiparams[2] = (void *) xyarr;
	_vdiparams[4] = (void *) extent;
#else
	/* copy xyarr into an array of shorts */

	optr = _ptsin;
	end  = optr + count + count;
	while (optr < end)
		*optr++ = *xyarr++;
#endif
	_contrl[2] = 2; /* dont know why, the atari docs say so without */
	_contrl[4] = 6; /* any	explaination */

	__vdi__(VDI_CONTRL_ENCODE(cntrl0, count, ((count + 1) >> 1), 13), handle);

	_contrl[2] = 0;
	_contrl[4] = 0;

#ifdef __MSHORT__
	/* restore standard parameter block */
	_vdiparams[2] = (void *) _ptsin;
	_vdiparams[4] = (void *) _ptsout;
#else
	optr = _ptsout;
	iptr = extent;
	*iptr++ = *optr++;
	*iptr++ = *optr++;
	*iptr++ = *optr++;
	*iptr	= *optr;
#endif
	*totmoves = _intout[1];
	return(*totpts = _intout[0]);	/* number of points in Bezier */
}
#endif /* L_v_bez_fi */

#ifdef L_v_bez_qu

/*
 * v_bez_qual (alias v_bezqual)
 * Set the quality / speed tradeoff when drawing Beizier curve
 * quality is given in percents
 *
 * Returns an actual quality set.
 *
 * This function requires "hand coding" since subcode 99 does
 * not fit into 5 bits required by VDI_CONTRL_ENCODE
 */
__asm__(".stabs \"_v_bezqual\",5,0,0,_v_bez_qual"); /* dept of clean tricks */
int
v_bez_qual (int handle, int percent, int *actual)
{
	short *wptr = _intin;

	*wptr++ = 32;
	*wptr++ = 1;
	*wptr  = percent;

	 wptr = (short *)_contrl;
	*wptr++ = 5;	/* 0  - opcode */
	*wptr++ = 0;	/* 1 */
	 wptr++;		/* 2 */
	*wptr++ = 3;	/* 3  - # of entries in _intin */
	*wptr++ = 1;	/* 4 - atari doesnt say why! */
	*wptr++ = 99;	/* 5 - id */
	*wptr	= handle;	/* 6 - handle */
	vdi();		/* call vdi */
	_contrl[4] = 0; 	/* clear it back */

	return (*actual = *_intout);
}
#endif /* L_v_bez_qu */

/* -eof- */
