/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:vector.c 12.0$ */
/* $ACIS:vector.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/lib/pmp/RCS/vector.c,v $ */

#ifndef lint
static char *rcsid = "$Header:vector.c 12.0$";
#endif

#include <stdio.h>
#include <utils.h>
#include <pmp_commands.h>
#include <vector.h>
#include <char.h>
#include <font.h>
#include <creg.h>
#include <rp.h>
#include <vp.h>

/***============================================================***/

#define WHERE_AM_I	"vector.c"
#define V_NYBBLE	PMPARG_VEC_NYBBLES
#define V_BYTE		PMPARG_VEC_BYTES
#define V_WORD		PMPARG_VEC_WORDS


/*

*/

/***============================================================***/
/***			     POINTS				***/
/***============================================================***/

	int 	v_p_debug;

typedef struct PT	{
			    int		v_p_x;
			    int		v_p_y;
			    struct PT	*v_p_next;
			} v_point;

#define x(v)		(v->v_p_x)
#define y(v)		(v->v_p_y)
#define next_pt(v)	(v->v_p_next)

/*** v_p_free - head of free list maintained by _v_p_new        ***/
/***		and _v_p_free.					***/

static	v_point	*v_p_free;	

/***============================================================***/
/***								***/
/***	_v_p_new - allocate a new point				***/
/***								***/
/***	arguments:						***/
/***		px, py - coordinates of new point		***/
/***	returns:						***/
/***		pointer to new point				***/
/***								***/
/***	Allocates from a free list as long as there are 	***/
/***	previously freed points available, else allocates	***/
/***	new storage.						***/
/***								***/
/***============================================================***/

static v_point *
_v_p_new(px,py)
register2 int	px;
register3 int	py;
{
register1 v_point	*vec;

    D_ENTRY(v_p_debug,"_v_p_new()\n");
    if (v_p_free) { 
	vec=		v_p_free;
	v_p_free=	next_pt(v_p_free);
    }
    else {
	vec= (v_point *)u_malloc(sizeof(v_point));
    }
    x(vec)=		px;
    y(vec)=		py;
    next_pt(vec)=	NULL;
    RETURN(vec);
}

/***============================================================***/
/***								***/
/***	_v_p_free - free a list of points			***/
/***								***/
/***	arguments:						***/
/***		vec - head of list to free			***/
/***	returns:						***/
/***		NULL						***/
/***								***/
/***	Adds the list of points to the head of the free list.	***/
/***								***/
/***============================================================***/

static int
_v_p_free(vec)
register1 v_point	*vec;
{
register2 v_point	*vtmp;

    D_ENTRY1(v_p_debug,"_v_p_free(0x%x)\n",vec);
    vtmp=	vec;
    while (next_pt(vtmp)) {
	vtmp=	next_pt(vtmp);
    }
    next_pt(vtmp)=	v_p_free;
    v_p_free=	vec;
    RETURN(NULL);
}

/***============================================================***/
/***								***/
/***	_v_p_size - return size of space required to represent	***/
/***		a vector					***/
/***								***/
/***	arguments:						***/
/***		vec - pointer to a vector			***/
/***	returns:						***/
/***		V_NYBBLE, V_BYTE, or V_WORD			***/
/***								***/
/***============================================================***/

static int
_v_p_size(vec)
register1 v_point	*vec;
{

    D_ENTRY1(v_debug,"_v_p_size(0x%x)\n",vec);
    if ((x(vec)>127)||(y(vec)>127)||(x(vec)<-128)||(y(vec)<-128)) 
	RETURN(V_WORD);
    if ((x(vec)>7)||(y(vec)>7)||(x(vec)<-8)||(y(vec)<-8)) 
	RETURN(V_BYTE);
/*RETURN(V_BYTE);*/
    RETURN(V_NYBBLE);
}

/*

*/

/***============================================================***/
/***			VECTOR FILL INFO			***/
/***============================================================***/

typedef struct VFIL	{
			     int	 v_f_font;
			     int	 v_f_char;
			     int	 v_f_ref_x;
			     int	 v_f_ref_y;
			} v_fill_info;

int	v_f_debug;

#define fillfont(f)	((f)->v_f_font)
#define fillchar(f)	((f)->v_f_char)
#define fill_x(f)	((f)->v_f_ref_x)
#define fill_y(f)	((f)->v_f_ref_y)
#define _v_f_copy(f)	_v_f_new(fillfont(f),fillchar(f),fill_x(f),\
								fill_y(f))

/***============================================================***/
/***								***/
/***	_v_f_new - allocate a new vector fill structure		***/
/***								***/
/***	arguments:						***/
/***		font - font to get fill char from		***/
/***		ch - fill character				***/
/***		ref_x, ref_y - coordinates of reference point	***/
/***								***/
/***	returns:						***/
/***		address of structure				***/
/***								***/
/***============================================================***/

static v_fill_info *
_v_f_new(font,ch,ref_x,ref_y)
register2 int	 font;
register3 int	 ch;
register4 int	 ref_x;
register5 int	 ref_y;
{
register1 v_fill_info	*vftmp;

    D_ENTRY4(v_f_debug,"_v_f_new(%d,%d,%d,%d)\n",font,ch,ref_x,ref_y);
    vftmp= (v_fill_info *)u_malloc(sizeof(v_fill_info));
    fillfont(vftmp)=	font;
    fillchar(vftmp)= 	ch;
    fill_x(vftmp)=	ref_x;
    fill_y(vftmp)=	ref_y;
    RETURN(vftmp);
}

/***============================================================***/
/***								***/
/***	_v_f_free - free a vector fill structure		***/
/***								***/
/***	arguments:						***/
/***		fill_info - pointer to structure		***/
/***	returns:						***/
/***		TRUE						***/
/***								***/
/***============================================================***/

static int
_v_f_free(fill_info)
register1 v_fill_info	*fill_info;
{
    D_ENTRY1(v_f_debug,"_v_f_free(0x%x)\n",fill_info);
    if (fill_info) {
	u_free(fill_info);
	RETURN(TRUE);
    }
    RETURN(FALSE);
}

/***============================================================***/
/***								***/
/***	_v_f_match - determine if two vector fill structures	***/
/***		are the same					***/
/***								***/
/***	arguments:						***/
/***		fill1, fill2 - pointers to the structures	***/
/***	returns:						***/
/***		TRUE or FALSE					***/
/***								***/
/***	True if pointer point to the same structure or the	***/
/***	structures are identical.				***/
/***								***/
/***============================================================***/

static int
_v_f_match(fill1,fill2)
register1 v_fill_info	*fill1;
register2 v_fill_info	*fill2;
{
    D_ENTRY2(v_f_debug,"_v_f_match(0x%x,0x%x)\n",fill1,fill2);
    if (fill1==fill2)				RETURN(TRUE);
    if (!((fill1)&&(fill2)))			RETURN(FALSE);
    if (fillfont(fill1)!=fillfont(fill2))	RETURN(FALSE);
    if (fillchar(fill1)!=fillchar(fill2))	RETURN(FALSE);
    if (fill_x(fill1)!=fill_x(fill2))		RETURN(FALSE);
    if (fill_y(fill1)!=fill_y(fill2))		RETURN(FALSE);
    RETURN(TRUE);
}

/*

*/

/***============================================================***/
/***			LISTS OF VECTORS			***/
/***============================================================***/

typedef struct VEC	{
    			     unsigned		 v_flags;
			     unsigned		 v_length;
			     v_point		*v_start;
			     v_point		*v_end;
			     v_fill_info	*v_fill;
			     struct VEC	*v_next;
			} v_list;

#define V_ROUND		PMPARG_VEC_ROUND_ENDS
#define V_MODEMASK	PMPMASK_VEC_MODE
#define V_WIDTHMASK	PMPMASK_VEC_WIDTH

#define V_MOVEMENT	0x8000
#define V_FREE		0x4000

#define mode(f)		((f)&V_MODEMASK)
#define setmode(f,m)	((f)=((f)&(~V_MODEMASK))|((m)&V_MODEMASK))

#define width(f)	((f)&V_WIDTHMASK)
#define setwidth(f,w)	((f)=((f)&(~V_WIDTHMASK))|((w)&V_WIDTHMASK))

#define round(f)	((f)&V_ROUND)
#define setround(f,r)	((r)?(f)|=(V_ROUND):(f)&=(~V_ROUND))

#define isfree(fl)	((fl)&V_FREE)
#define setfree(fl,fr)	((fr)?(fl)|=(V_FREE):(fl)&=(~V_FREE))

#define move(f)		((f)&V_MOVEMENT)
#define setmove(f,m)	((m)?(f)|=(V_MOVEMENT):(f)&=(~V_MOVEMENT))

#define pmpflags(f)	((f)&0xFF)

#define sameflags(f1,f2)	((f1)==(f2))

#define next(v)		((v)->v_next)
#define start(v)	((v)->v_start)
#define end(v)		((v)->v_end)
#define length(v)	((v)->v_length)
#define fill(v)		((v)->v_fill)
#define flags(v)	((v)->v_flags)

	int		 v_l_debug;

/*** v_l_free - head of free list used by _v_l_new and _v_l_free***/

static	v_list		*v_l_free;

/***============================================================***/
/***								***/
/***	_v_l_new - allocate a new vector list structure		***/
/***								***/
/***	arguments:						***/
/***		control - control flags for this list           ***/
/***			of vectors				***/
/***		fill_info - fill structure, or NULL if no fill	***/
/***	returns:						***/
/***		pointer to new structure			***/
/***								***/
/***	Allocates from a free list as long as there are 	***/
/***	previously freed nodes available, otherwise allocate	***/
/***	memory for a new structure.				***/
/***								***/
/***	There is one of these for each group of vectors with	***/
/***	the same attributes in a vector stream.			***/
/***								***/
/***============================================================***/

static v_list *
_v_l_new(control,fill_info)
register2 int		 control;
register3 v_fill_info	*fill_info;
{
register1 v_list	*vtmp;

    D_ENTRY2(v_l_debug,"_v_l_new(0x%x,0x%x)\n",control,fill_info);
    if (v_l_free) {
	vtmp=	v_l_free;
	v_l_free=	next(vtmp);
    }
    else {
	vtmp=	(v_list *)u_malloc(sizeof(v_list));
    }
    flags(vtmp)=	control;
    length(vtmp)=	0;
    start(vtmp)=	NULL;
    end(vtmp)=		NULL;
    if (fill_info) 
		fill(vtmp)=	_v_f_copy(fill_info);
    else 	fill(vtmp)=	NULL;
    next(vtmp)=		NULL;
    RETURN(vtmp);
}

/***============================================================***/
/***								***/
/***	_v_l_free - free a list of vector lists			***/
/***								***/
/***	arguments:						***/
/***		vl - pointer to the first vector list structure	***/
/***	returns:						***/
/***		TRUE						***/
/***								***/
/***	Frees fill structure, vector list, then adds the	***/
/***	structure itself to the free list, for each vector	***/
/***	list in the chain.					***/
/***								***/
/***============================================================***/

static int
_v_l_free(vl)
register1 v_list	*vl;
{
register2 v_list	*vtmp;

    D_ENTRY1(v_debug,"_v_l_free(0x%x)\n",vl);
    if (isfree(flags(vl))) 
	RETURN(FALSE);
    vtmp=	vl;
    while (vtmp) {
	if (start(vtmp)) {
	    _v_p_free(start(vtmp));
	    start(vtmp)=	NULL;
	}
	if (fill(vtmp)) {
	    _v_f_free(fill(vtmp));
	    fill(vtmp)= 	NULL;
	}
	setfree(flags(vtmp),TRUE);
	if (next(vtmp)) 
	    vtmp=	next(vtmp);
	else {
	    next(vtmp)=		v_l_free;
	    vtmp=	NULL;
	}
    }
    v_l_free= vl;
    RETURN(TRUE);
}

/***============================================================***/
/***			    VECTOR STREAM			***/
/***============================================================***/

typedef struct VS	{
				unsigned	 v_current_flags;
				v_fill_info	*v_current_fill;
				v_list		*v_first;
				v_list		*v_current;
				int		 v_x_offset;
				int		 v_y_offset;
			} v_stream;

	int		 v_debug;

/***============================================================***/
/***								***/
/***	v_new - create a new vector stream			***/
/***								***/
/***	returns - pointer to vector stream			***/
/***								***/
/***============================================================***/

static	unsigned	 _v_dflt_flags= V_ROUND_ENDS|5;
static	v_fill_info	*_v_dflt_fill=  NULL;

vectors *
v_new()
{
register1 v_stream	*vs;

    D_ENTRY(v_debug,"v_new()\n");
    vs= (v_stream *)u_malloc(sizeof(v_stream));
    vs->v_current_fill=		_v_dflt_fill;
    vs->v_current_flags=	_v_dflt_flags;
    vs->v_first=		NULL;
    vs->v_current=		NULL;
    vs->v_x_offset=		0;
    vs->v_y_offset=		0;
    RETURN((vectors *)vs);
}

/***============================================================***/
/***								***/
/***	v_free - free a vector stream structure			***/
/***								***/
/***	arguments:						***/
/***		vs - pointer to a vector stream			***/
/***	returns:						***/
/***		TRUE						***/
/***								***/
/***	Frees the vector lists, the current fill structure,	***/
/***	then the stream structure.				***/
/***								***/
/***============================================================***/

int
v_free(vs)
register1 v_stream	*vs;
{
    D_ENTRY1(v_debug,"v_free(0x%x)\n",vs);
    if (vs) {
	if (vs->v_first) {
	    _v_l_free(vs->v_first);
	}
	if (vs->v_current_fill) 
	    _v_f_free(vs->v_current_fill);
	u_free(vs);
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_reset - reset a vector stream				***/
/***								***/
/***	arguments:						***/
/***		vs - pointer to vector stream			***/
/***	returns:						***/
/***		TRUE						***/
/***								***/
/***	Frees the vector lists and sets first and current	***/
/***	vector lists to NULL.					***/
/***								***/
/***============================================================***/

int
v_reset(vs)
register1 v_stream	*vs;
{
    D_ENTRY1(v_debug,"v_reset(0x%x)\n",vs);
    if (vs) {
	if (vs->v_first) {
	    _v_l_free(vs->v_first);
	}
	vs->v_first= vs->v_current= NULL;
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_draw - adds a vector to a vector stream		***/
/***								***/
/***	arguments:						***/
/***		vs - vector stream to add to			***/
/***		d_x, d_y - components of the vector		***/
/***	returns:						***/
/***		FALSE - for zero vector				***/
/***		TRUE - otherwise				***/
/***								***/
/***	Allocates new point, creates new vector list if needed, ***/
/***	then adds point to vector list.				***/
/***								***/
/***============================================================***/

int
v_draw(vs,d_x,d_y)
register5 v_stream	*vs;
register7 int		 d_x;
	  int		 d_y;
{
register1 v_list	*current;
register2 v_point	*vp;
register3 int		size;
register4 unsigned	control;
register6 v_fill_info	*fill_info;

    D_ENTRY3(v_debug,"v_draw(0x%x,%d,%d)\n",vs,d_x,d_y);
    if ((!d_x)&&(!d_y))
	RETURN(FALSE);
    vs->v_x_offset+= d_x;
    vs->v_y_offset+= d_y;
    control= 	vs->v_current_flags;
    fill_info=	vs->v_current_fill;
    vp=	_v_p_new(d_x,d_y);
    size= _v_p_size(vp);
    setmode(control,size);
    current= vs->v_current;

				/* no current v_list, or flags have changed */
    if ((!current)||(!sameflags(control,flags(current)))||
				(!_v_f_match(fill_info,fill(current)))) {
 	register8 v_list *vl;

	vl= _v_l_new(control&(~V_MODEMASK),fill_info);
	if (current) 
	    next(current)=	vl;
	current= vs->v_current=	vl;
	if (!vs->v_first) 
	    vs->v_first=	current;
    }

    if (!start(current)) {
	start(current)=		vp;
	end(current)=		vp;
	length(current)=	1;
 	setmode(flags(current),size);
    }
    else {
	next_pt(end(current))=	vp;
	end(current)=		vp;
	length(current)+=	1;
    }
/*** Remove optimizations from here, to them later on (and better!)
 ***	if ((x(end(current))==d_x)&&(y(end(current))==d_y)) {
 ***	    x(end(current))+= x(vp);
 ***	    y(end(current))+= y(vp);
 ***	    size= _v_p_size(end(current));
 ***	}
 ***	else {
 ***	    next_pt(end(current))=	vp;
 ***	    end(current)=		vp;
 ***	    length(current)+=		1;
 ***	}
 ***	if (size>mode(flags(current))) 
 ***	    setmode(flags(current),size); 
 ***}
 ***/
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_move - add a movement to a vector stream		***/
/***								***/
/***	arguments:						***/
/***		vs - vector stream to add to			***/
/***	returns:						***/
/***		FALSE - for zero movement			***/
/***		TRUE - otherwise				***/
/***								***/
/***	If there was not a vertor list, or there has not been	***/
/***	movement immediately before this then allocate a new	***/
/***	vector list.  If there is previous movement on this	***/
/***	list then add to it, otherwise create a new vector.	***/
/***								***/
/***============================================================***/

int
v_move(vs,d_x,d_y)
register2 v_stream	*vs;
register3 int		 d_x;
register4 int		 d_y;
{
register1 v_list	*current;

    D_ENTRY3(v_debug,"v_move(0x%x,%d,%d)\n",vs,d_x,d_y);
    vs->v_x_offset+= d_x;
    vs->v_y_offset+= d_y;
    if ((!d_x)&&(!d_y))
	RETURN(FALSE);

    current= vs->v_current;
				/* no current v_list, or flags have changed */
    if ((!current)||(!move(flags(current)))) {
 	register5 v_list *vl;

	vl= _v_l_new(V_MOVEMENT,NULL);
	if (current) 
	    next(current)=	vl;
	vs->v_current= current=	vl;
	if (!vs->v_first)
	    vs->v_first= current;
    }

    if (!start(current)) {
	end(current)= 		start(current)= _v_p_new(d_x,d_y);
	length(current)=	1;
    }
    else {
	x(start(current))+=	d_x;
	y(start(current))+=	d_y;
    }
    setmode(flags(current),_v_p_size(start(current)));
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_flush - write out the vector stream			***/
/***								***/
/***	arguments:						***/
/***		vs - the vector stream				***/
/***	returns:						***/
/***		TRUE						***/
/***								***/
/***============================================================***/

v_flush(vs)
register7 v_stream	*vs;
{
register1 v_list	*vl;
register2 v_point	*vp;
register3 unsigned	 flgs;
register4 unsigned	 size;

    D_ENTRY1(v_debug,"v_flush(0x%x,0x%x,0x%x)\n",vs);
    vl= vs->v_first;
    while (vl) {
	flgs=	flags(vl);
	vp= 	start(vl);
	if (!vp) 
	    continue;
	if (move(flgs)) {
	    rp_mvrelative(x(vp),y(vp));
	}
	else {
	    if (fill(vl)) {
		register5 v_fill_info	*vfill;
		register6 v_point	*fillpt;

		vfill=	fill(vl);
		_rp_parmcmd(PMP_SAVE_CURSOR,2);
		rp_mvabsolute(fill_x(vfill),fill_y(vfill));
		_rp_parmcmd(PMP_SAVE_CURSOR,1);
		_rp_parmcmd(PMP_RESTORE_CURSOR,2);
		_rp_drw_command(PMP_GENERATE_FILLED_VECTORS);
		_rp_byte(fillfont(vfill));
		_rp_byte(fillchar(vfill));
		_rp_byte(1);
	    }
	    else  
		_rp_command(PMP_GENERATE_VECTORS);
	    size= mode(flgs);
	    if		(size==V_NYBBLE)	_rp_word(1+length(vl));
	    else if	(size==V_BYTE)		_rp_word(1+(length(vl)*2));
	    else				_rp_word(1+(length(vl)*4));
	    _rp_byte(pmpflags(flgs));
	    while (vp)  {
		if (size==V_NYBBLE) {
		    register5 unsigned outvec;

	    	    outvec=	(y(vp)&0xf)<<4;
		    outvec|=	(x(vp)&0xf);
		    _rp_byte(outvec);
		}
		else if (size==V_BYTE) {
		    _rp_byte(y(vp));
		    _rp_byte(x(vp));
		}
		else {
		    _rp_word(y(vp));
		    _rp_word(x(vp));
		}
		vp= next_pt(vp);
	    }
	}
	vl= next(vl);
    }
    rp_x+= vs->v_x_offset;
    rp_y+= vs->v_y_offset;
    RETURN(TRUE);
}

/***====================================================================***/
/***									***/
/***	v_testflush - print debugging info about vector stream		***/
/***									***/
/***	arguments:							***/
/***		vs - the vector stream					***/
/***	returns:							***/
/***		TRUE							***/
/***									***/
/***	Prints all vector stream info.					***/
/***									***/
/***====================================================================***/

v_textflush(vs)
register3 v_stream	*vs;
{
register1 v_list	*vl;
register2 v_point	*vp;

    vl= vs->v_first;
    DEBUG(v_debug,1,"flushing vector stream\n");
    while (vl) {
	DEBUG1(v_debug,1,"flags=	0x%x\n",flags(vl));
	DEBUG1(v_debug,1,"length=	%d\n",length(vl));
	if (!fill(vl))
	    DEBUG(v_debug,1,"not filled\n");
	else {
	    DEBUG1(v_debug,1,"fill font=	%d\n",fillfont(fill(vl)));
	    DEBUG1(v_debug,1,"fill char=	%d\n",fillchar(fill(vl)));
	    DEBUG2(v_debug,1,"fill point=	(%d,%d)\n",
						fill_x(fill(vl)),
						fill_y(fill(vl)));
	}
	vp= start(vl);
	if (!vp) {
	    DEBUG(v_debug,1,"   no points\n");
	}
	else {
	    while (vp) {
		DEBUG2(v_debug,1,"   (%d,%d)\n",x(vp),y(vp));
		vp= next_pt(vp);
	    }
	}
	vl= next(vl);
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_join - join two vector streams			***/
/***								***/
/***	arguments:						***/
/***		vs1, vs2 - the vector streams			***/
/***		how - how to join them, can be:			***/
/***			V_TAIL_TO_TAIL or V_HEAD_TO_TAIL	***/
/***	returns:						***/
/***		FALSE - for bad how, or empty streams		***/
/***		TRUE - otherwise				***/
/***								***/
/***============================================================***/

int
v_join(vs1,vs2,how)
register1 v_stream	*vs1;
register2 v_stream	*vs2;
register3 int		 how;
{
    D_ENTRY3(v_debug,"v_join(0x%x,0x%x,0x%x)\n",vs1,vs2,how);
    if ((!vs1)||(!vs2)||(!vs1->v_current)||(!vs2->v_current)) {
	RETURN(FALSE);
    }
    if ((how!=V_TAIL_TO_TAIL)&&(how!=V_HEAD_TO_TAIL)) {
	RETURN(FALSE);
    }

    if (how==V_TAIL_TO_TAIL) {
	v_move(vs1,vs1->v_x_offset,vs1->v_y_offset);
    }
/* could do some optimization here */
    next(vs1->v_current)=	vs2->v_first;
    vs1->v_current=		vs2->v_current;
    vs2->v_first= vs2->v_current= NULL;
	RETURN(TRUE);
}
    
/***============================================================***/
/***								***/
/***	v_nofill - sets no fill mode for a vector stream	***/
/***								***/
/***	arguments:						***/
/***		vs - the vector stream				***/
/***	returns:						***/
/***		TRUE						***/
/***								***/
/***	Also frees the current fill structure			***/
/***								***/
/***============================================================***/

int
v_nofill(vs)
register1 v_stream *vs;
{
    D_ENTRY1(v_debug,"v_nofill(0x%x)\n",vs);
    if (vs->v_current_fill) {
	_v_f_free(vs->v_current_fill);
	vs->v_current_fill=	NULL;
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_fill - set fill mode for a vector stream		***/
/***								***/
/***	arguments:						***/
/***		vs - the vector stream				***/
/***		font - the font that the fill character is from ***/
/***		ch - the fill character				***/
/***		ref_x, ref_y - coordinates of the reference pt. ***/
/***	results:						***/
/***		TRUE						***/
/***								***/
/***	Allocates a new fill structure if necessary		***/
/***								***/
/***============================================================***/

int
v_fill(vs,font,ch,ref_x,ref_y)
register1 v_stream	*vs;
register2 int	 	 font;
register3 int	 	 ch;
register4 int	 	 ref_x,ref_y;
{

    D_ENTRY5(v_debug,"v_fill(0x%x,%d,%d,%d,%d)\n",vs,font,ch,ref_x,ref_y);
    if (vs->v_current_fill) {
	fillfont(vs->v_current_fill)=	font;
	fillchar(vs->v_current_fill)=	ch;
	fill_x(vs->v_current_fill)=	ref_x;
	fill_y(vs->v_current_fill)=		ref_y;
    }
    else {
	vs->v_current_fill= _v_f_new(font,ch,ref_x,ref_y);
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_no_dflt_fill - if there is a default fill, remove it	***/
/***								***/
/***	arguments:						***/
/***		none						***/
/***	results:						***/
/***		TRUE						***/
/***								***/
/***============================================================***/

v_no_dflt_fill()
{
    D_ENTRY(v_debug,"v_no_dflt_fill()\n");
    if (_v_dflt_fill) {
	_v_f_free(_v_dflt_fill);
	_v_dflt_fill= NULL;
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_set_dflt_fill - set the default fill			***/
/***								***/
/***	arguments:						***/
/***		font - the font that the fill character is from ***/
/***		ch - the fill character				***/
/***		ref_x, ref_y - coordinates of the reference pt. ***/
/***	results:						***/
/***		TRUE						***/
/***								***/
/***============================================================***/


v_set_dflt_fill(font,ch,ref_x,ref_y)
register1 int	 	 font;
register2 int	 	 ch;
register3 int	 	 ref_x,ref_y;
{

    D_ENTRY4(v_debug,"v_set_dflt_fill(%d,%d,%d,%d)\n",font,ch,ref_x,ref_y);
    if (_v_dflt_fill) {
	fillfont(_v_dflt_fill)=	font;
	fillchar(_v_dflt_fill)=	ch;
	fill_x(_v_dflt_fill)=	ref_x;
	fill_y(_v_dflt_fill)=	ref_y;
    }
    else {
	_v_dflt_fill= _v_f_new(font,ch,ref_x,ref_y);
    }
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_set_width - set the width for a vector stream		***/
/***								***/
/***	arguments:						***/
/***		vs - the vector stream				***/
/***		wid - the new width				***/
/***	results:						***/
/***		TRUE						***/
/***								***/
/***============================================================***/


v_set_width(vs,wid)
register1 v_stream	*vs;
register2 unsigned	 wid;
{
    D_ENTRY2(v_debug,"v_set_width(0x%x,%d)\n",vs,wid);
    if ((wid<V_MIN_WIDTH)||(wid>V_MAX_WIDTH)) 
	RETURN(FALSE);
    setwidth(vs->v_current_flags,wid);
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_set_dflt_width - set the default width		***/
/***								***/
/***	arguments:						***/
/***		wid - the new default width			***/
/***	results:						***/
/***		FALSE - if bad width				***/
/***		old default width - otherwise			***/
/***								***/
/***============================================================***/


v_set_dflt_width(wid)
register1 int	wid;
{
register2 int	old;

    D_ENTRY1(v_debug,"v_set_dflt_width(%d)\n",wid);
    if ((wid<V_MIN_WIDTH)||(wid>V_MAX_WIDTH))
	RETURN(FALSE);
    old= width(_v_dflt_flags);
    setwidth(_v_dflt_flags,wid);
    RETURN(old);
}

/***============================================================***/
/***								***/
/***	v_dflt_width - return the default width			***/
/***								***/
/***	arguments:						***/
/***		none						***/
/***	results:						***/
/***		the default width				***/
/***								***/
/***============================================================***/


v_dflt_width()
{
    D_ENTRY(v_debug,"v_dflt_width()\n");
    RETURN(width(_v_dflt_flags));
}

/***============================================================***/
/***								***/
/***	_v_endstr - return the string for end types		***/
/***								***/
/***	arguments:						***/
/***		ends - V_ROUND_ENDS or V_SQUARE_ENDS		***/
/***	results:						***/
/***		the appropriate string				***/
/***								***/
/***============================================================***/


static char *
_v_endstr(ends)
register1 int	ends;
{
    if 		(ends==V_ROUND_ENDS)	return("round_ends");
    else if	(ends==V_SQUARE_ENDS)	return("square_ends");
    else				return("***ILLEGAL***");
}

/***============================================================***/
/***								***/
/***	v_set_ends - set vector end type for a vector stream	***/
/***								***/
/***	arguments:						***/
/***		vs - the vector stream				***/
/***		ends - the type of end				***/
/***	results:						***/
/***		FALSE - if bad end type				***/
/***		TRUE - otherwise				***/
/***								***/
/***============================================================***/

v_set_ends(vs,ends)
register1 v_stream	*vs;
register2 int		 ends;
{
    D_ENTRY2(v_debug,"v_set_ends(0x%x,%s)\n",vs,_v_endstr(ends));
    if 		(ends==V_ROUND_ENDS)	setround(vs->v_current_flags,TRUE);
    else if 	(ends==V_SQUARE_ENDS)	setround(vs->v_current_flags,FALSE);
    else				RETURN(FALSE);
    RETURN(TRUE);
}

/***============================================================***/
/***								***/
/***	v_set_dflt_ends - set the default end type		***/
/***								***/
/***	arguments:						***/
/***		ends - the new default end type			***/
/***	results:						***/
/***		previous default end type			***/
/***								***/
/***============================================================***/

v_set_dflt_ends(ends)
register1 int	ends;
{
register2 int	rnd;

    D_ENTRY1(v_debug,"v_set_dflt_ends(%s)\n",_v_endstr(ends));
    rnd= round(_v_dflt_flags);
    if 		(ends==V_ROUND_ENDS)	setround(_v_dflt_flags,TRUE);
    else if 	(ends==V_SQUARE_ENDS)	setround(_v_dflt_flags,FALSE);
    else				RETURN(FALSE);
    if (rnd)	RETURN(V_ROUND_ENDS);
    else	RETURN(V_SQUARE_ENDS);
}
    
/***============================================================***/
/***								***/
/***	v_dflt_ends - return the default end type		***/
/***								***/
/***	arguments:						***/
/***		none						***/
/***	results:						***/
/***		the default end type				***/
/***								***/
/***============================================================***/


v_dflt_ends()
{
    D_ENTRY(v_debug,"v_dflt_ends()\n");
    if (round(_v_dflt_flags))	RETURN(V_ROUND_ENDS);
    else			RETURN(V_SQUARE_ENDS);
}
