/*
 *  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.
 */

#ifndef	PURE_C
__asm__(".stabs \"_v_bezon\",5,0,0,_v_bez_on"); /* dept of clean tricks */
#else	PURE_C
int v_bezon (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

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)
 */

#ifndef	PURE_C
__asm__(".stabs \"_v_bezoff\",5,0,0,_v_bez_off"); /* dept of clean tricks */
#else	PURE_C
void
v_bezoff (int handle)
{
    __vdi__(VDI_CONTRL_ENCODE(11, 0, 0, 13), handle);
}
#endif

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
 */

#ifndef	PURE_C
__asm__(".stabs \"_v_bezfill\",5,0,0,_v_bez_fill"); /* dept of clean tricks */
#else	PURE_C
int
v_bezfill(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

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
 */

#ifndef	PURE_C
__asm__(".stabs \"_v_bezqual\",5,0,0,_v_bez_qual"); /* dept of clean tricks */
#else	PURE_C
int
v_bezqual (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

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- */
