2021-10-11 18:37:13 -03:00

532 lines
16 KiB
C

#ifndef lint
static char sccsid[] = "@(#)polyline.c 1.1 94/10/31 Copyr 1985-9 Sun Micro";
#endif lint
/*
* Copyright (c) 1985, 1986, 1987, 1988, 1989 by Sun Microsystems, Inc.
* Permission to use, copy, modify, and distribute this software for any
* purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both that copyright
* notice and this permission notice are retained, and that the name
* of Sun Microsystems, Inc., not be used in advertising or publicity
* pertaining to this software without specific, written prior permission.
* Sun Microsystems, Inc., makes no representations about the suitability
* of this software or the interface defined in this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
/*
* CGI Polyline functions
*/
/*
polyline
cgipw_polyline
_cgi_polyline
disjoint_polyline
cgipw_disjoint_polyline
rectangle
cgipw_rectangle
_cgi_rectangle
_cgi_pattern_rect
_cgi_arr_dev_xform
*/
#include "cgipriv.h" /* defines types used in this file */
#include <pixrect/gp1cmds.h>
View_surface *_cgi_vws; /* current view surface */
Outatt *_cgi_att; /* structure containing current attributes */
int _cgi_pix_mode; /* pixrect equivalent of drawing mode */
u_char *_cgi_disjoint_mvlist;
Cpixrect *_cgi_pattern();
#define gp_lock(pw, rect, vws) \
(void) _cgi_gp1_pw_lock(pw, rect, vws->sunview.gp_att)
#define gp_unlock(pw) pw_unlock(pw)
/****************************************************************************/
/* */
/* FUNCTION: polyline */
/* */
/* Polyline draws non-closed polyline. Elements of polyline */
/* are drawn by the textured line algorithm in pw_polyline */
/****************************************************************************/
Cerror polyline(polycoors)
Ccoorlist *polycoors; /* list of points */
{
int ivw;
Cerror err; /* error */
err = _cgi_err_check_4();
if (!err)
{
ivw = 0;
while (_cgi_bump_vws(&ivw))
err = _cgi_polyline(_cgi_vws, polycoors->n, polycoors->ptlist,
POLY_DONTCLOSE, XFORM);
}
return (_cgi_errhand(err));
}
/****************************************************************************/
/* */
/* FUNCTION: cgipw_polyline */
/* */
/* Polyline draws non-closed polyline. Elements of polyline */
/* are drawn by the textured line algorithm in _cgi_polyline */
/****************************************************************************/
Cerror cgipw_polyline(desc, polycoors)
Ccgiwin *desc;
Ccoorlist *polycoors; /* list of points */
{
SETUP_CGIWIN(desc);
return (_cgi_polyline(desc->vws, polycoors->n, polycoors->ptlist,
POLY_DONTCLOSE, XFORM));
}
/****************************************************************************/
/* */
/* FUNCTION: _cgi_polyline */
/* */
/* Draws closed or non-closed polyline. */
/* Actual work is done by pw_polyline or _cgi_gp1_polyline. */
/****************************************************************************/
Cerror _cgi_polyline(vws, npts, coorlist, mvlist, xformflg)
View_surface *vws;
register int npts; /* number of points in coorlist */
Ccoor *coorlist; /* list of points */
u_char *mvlist; /* draw/move flags for each segment */
Cxformflg xformflg; /* if TRUE, transform coordinates */
{
register Outatt *attP = vws->att;
register View_surface *vwsP = vws;
register Gp1_attr *gpattP = vws->sunview.gp_att;
struct pr_pos conv_ptlist[MAXPTS];
Pr_texture tex, *texP;
Pr_brush brush;
extern Pr_texture *_cgi_line_setup();
struct pr_pos *point;
int err = NO_ERROR; /* error */
int usegp;
int op;
int dx, dy;
if (npts >= 2)
{
if (npts <= MAXPTS)
{
texP = _cgi_line_setup(&tex, &brush, npts);
op = PIX_COLOR(attP->line.color) | _cgi_pix_mode;
/*
* If we have untransformed points, give them directly to the GP,
* otherwise let pw_polyline take care of it.
*/
if (xformflg == XFORM && vwsP->sunview.gp_att != (Gp1_attr *) 0)
{
/*
* See if we need textured or wide line capability, which is
* not available pre-3.2.
*/
if (attP->line.style != SOLID || vwsP->conv.line_width != 1)
{
/*
* Can't do it if GP1_CGI_LINE command not available, or
* textured lines if GP1_SET_LINE_WIDTH not available, or
* wide lines if GP1_SET_LINE_TEX not available.
*/
if (gpattP->cmdver[GP1_CGI_LINE >> 8] == 0
|| (attP->line.style != SOLID
&& gpattP->cmdver[(GP1_SET_LINE_TEX >> 8)] == 0)
|| (vwsP->conv.line_width != 1
&& gpattP->cmdver[(GP1_SET_LINE_WIDTH >> 8)] == 0))
{
usegp = 0;
}
else
{
usegp = 1;
}
}
else if (gpattP->cmdver[GP1_CGIVEC >> 8] != 0)
/* Ok if at least GP1_CGIVEC is available */
usegp = 1;
else
usegp = 0;
}
else
usegp = 0;
if (usegp)
{
gpattP = vwsP->sunview.gp_att;
_cgi_gp1_set_op(_cgi_pix_mode, gpattP);
_cgi_gp1_set_color(attP->line.color, gpattP);
_cgi_gp1_set_linewidth(vwsP->conv.line_width, gpattP);
_cgi_gp1_set_linetexture(texP, gpattP);
gp_lock(vwsP->sunview.pw, &vwsP->sunview.lock_rect, vwsP);
_cgi_gp1_pw_polyline(vwsP->sunview.pw, gpattP, npts,
coorlist, mvlist);
gp_unlock(vwsP->sunview.pw);
if (vwsP->sunview.pw->pw_prretained)
{
if (X_DEVSCALE_NEEDED(vwsP) || Y_DEVSCALE_NEEDED(vwsP))
{
_cgi_arr_dev_xform(vwsP, (unsigned) npts, coorlist,
conv_ptlist);
dx = 0;
dy = 0;
point = conv_ptlist;
}
else
{
dx = vwsP->xform.off.x;
dy = vwsP->xform.off.y;
point = (struct pr_pos *) coorlist;
}
if (mvlist == POLY_DISJOINT)
mvlist = _cgi_disjoint_mvlist;
(void) pr_polyline(vwsP->sunview.pw->pw_prretained, dx, dy,
npts, point, mvlist, &brush, texP, op);
}
}
else
{
if (mvlist == POLY_DISJOINT)
mvlist = _cgi_disjoint_mvlist;
switch (xformflg)
{
case XFORM:
if (X_DEVSCALE_NEEDED(vwsP) || Y_DEVSCALE_NEEDED(vwsP))
{
_cgi_arr_dev_xform(vwsP, (unsigned) npts, coorlist,
conv_ptlist);
dx = 0;
dy = 0;
point = conv_ptlist;
break;
}
/* if scaling not needed, fall through to OFFSET_ONLY */
case OFFSET_ONLY:
dx = vwsP->xform.off.x;
dy = vwsP->xform.off.y;
point = (struct pr_pos *) coorlist;
break;
case DONT_XFORM:
dx = 0;
dy = 0;
point = (struct pr_pos *) coorlist;
break;
}
pw_polyline(vwsP->sunview.pw, dx, dy, npts,
point, mvlist, &brush, texP, op);
}
}
else
err = ENMPTSTL;
}
else
err = EPLMTWPT;
return (err);
}
/****************************************************************************/
/* */
/* FUNCTION: disjoint_polyline */
/* */
/* Disjoint_polyline draws a non-closed polyline. Only */
/* alternate elements of the polyline */
/* are drawn by the textured line algorithm. */
/****************************************************************************/
Cerror disjoint_polyline(polycoors)
Ccoorlist *polycoors; /* list of points */
{
int ivw, err; /* error */
err = _cgi_err_check_4();
if (!err)
{
ivw = 0;
while (_cgi_bump_vws(&ivw))
{
err = _cgi_polyline(_cgi_vws, polycoors->n, polycoors->ptlist,
POLY_DISJOINT, XFORM);
}
}
return (_cgi_errhand(err));
}
/****************************************************************************/
/* */
/* FUNCTION: cgipw_disjoint_polyline */
/* */
/* Disjoint_polyline draws a non-closed polyline. */
/* Only alternate elements of the polyline */
/* are drawn by the textured line algorithm. */
/****************************************************************************/
Cerror cgipw_disjoint_polyline(desc, polycoors)
Ccgiwin *desc;
Ccoorlist *polycoors; /* list of points */
{
int err; /* error */
SETUP_CGIWIN(desc);
err = _cgi_polyline(desc->vws, polycoors->n, polycoors->ptlist,
POLY_DISJOINT, XFORM);
return (err);
}
/****************************************************************************/
/* */
/* FUNCTION: rectangle */
/* */
/* draws filled box from coordinate rbc (right-hand bottom */
/* corner) to ltc (left-hand top corner). */
/****************************************************************************/
Cerror rectangle(rbc, ltc)
Ccoor *rbc, *ltc; /* corners defining rectangle */
{
int ivw;
Cerror err; /* error */
err = _cgi_err_check_4();
if (!err)
{
ivw = 0;
while (_cgi_bump_vws(&ivw) && !err)
{
err = _cgi_rectangle(_cgi_vws, rbc, ltc);
}
}
return (_cgi_errhand(err));
}
/****************************************************************************/
/* */
/* FUNCTION: cgipw_rectangle */
/* */
/* draws filled box from coordinate rbc (right-hand bottom */
/* corner) to ltc (left-hand top corner). */
/****************************************************************************/
int cgipw_rectangle(desc, rbc, ltc)
Ccgiwin *desc;
Ccoor *rbc, *ltc; /* corners defining rectangle */
{
Cerror err;
SETUP_CGIWIN(desc);
err = _cgi_rectangle(desc->vws, rbc, ltc);
return (err);
}
/****************************************************************************/
/* */
/* FUNCTION: _cgi_rectangle */
/* */
/* draws filled box from coordinate rbc (right-hand bottom */
/* corner) to ltc (left-hand top corner). */
/****************************************************************************/
int _cgi_rectangle(vws, rbc, ltc)
register View_surface *vws;
Ccoor *rbc, *ltc; /* corners defining rectangle */
{
register Outatt *attP = vws->att;
int d1, d2, xa, x1, y1, x2, y2, color;
Cerror err = NO_ERROR;
/* get device coordinates of inner rectangle */
_cgi_devscale(rbc->x, rbc->y, x2, y1); /* Exchange coords: put mins in
* 1s */
_cgi_devscale(ltc->x, ltc->y, x1, y2); /* put maximums in x2 and y2. */
color = PIX_COLOR(attP->fill.color) | _cgi_pix_mode;
d1 = x2 - x1;
if (d1 < 0)
{
xa = x1;
x1 = x2;
x2 = xa;
d1 = -d1;
} /* now, x1 < x2 */
d2 = y2 - y1;
if (d2 < 0)
{
xa = y1;
y1 = y2;
y2 = xa;
d2 = -d2;
} /* now, y1 < y2 */
pw_lock(vws->sunview.pw, &vws->sunview.lock_rect);
/* fill interior of rectangle */
switch (attP->fill.style)
{
case SOLIDI:
{
pw_write(vws->sunview.pw, x1, y1, d1 + 1, d2 + 1,
color, 0, 0, 0);
break;
}
case HOLLOW:
{
break;
}
case PATTERN:
{
_cgi_pattern_rect(vws, x1, y1, d1 + 1, d2 + 1,
attP->fill.pattern_index, 1);
break;
}
case HATCH:
{
_cgi_pattern_rect(vws, x1, y1, d1 + 1, d2 + 1,
attP->fill.hatch_index, 0);
break;
}
}
/* draw perimeter of rectangle */
if (attP->fill.visible == ON)
{
Ccoor corners[8]; /* DC coordinates */
Clintype s_style;
Cint s_width;
Cint s_color;
int width, xw, hw;
/*
* Push out the corners so the filled interior and the border share no
* pixels.
*/
x1--;
y1--;
x2++;
y2++;
s_style = attP->line.style;
s_width = vws->conv.line_width;
s_color = attP->line.color;
attP->line.style = attP->fill.pstyle;
vws->conv.line_width = vws->conv.perimeter_width;
attP->line.color = attP->fill.pcolor;
/*
* This assumes excess width is displayed left and up by pw_polyline,
* and normalizes so that all width is displayed out (away from center
* of rectangle).
*/
width = vws->conv.perimeter_width;
hw = (width - 1) >> 1;
xw = (width & 1) ^ 1;
/* Top horizontal line */
corners[0].x = x1 - (width - 1);
corners[0].y = y1 - hw;
corners[1].x = x2 + (width - 1);
corners[1].y = y1 - hw;
/* Right vertical */
corners[2].x = x2 + (hw + xw);;
corners[2].y = y1 + 1;
corners[3].x = x2 + (hw + xw);;
corners[3].y = y2 - 1;
/* Bottom horizontal */
corners[4].x = x2 + (width - 1);
corners[4].y = y2 + (hw + xw);
corners[5].x = x1 - (width - 1);
corners[5].y = y2 + (hw + xw);
/* Left vertical */
corners[6].x = x1 - hw;
corners[6].y = y2 - 1;
corners[7].x = x1 - hw;
corners[7].y = y1 + 1;
err = _cgi_polyline(vws, 8, &corners[0], POLY_DISJOINT, DONT_XFORM);
attP->line.style = s_style;
vws->conv.line_width = s_width;
attP->line.color = s_color;
}
pw_unlock(vws->sunview.pw);
return (err);
}
/****************************************************************************/
/* */
/* FUNCTION: _cgi_pattern_rect */
/* */
/* draws pattern/hatch rectangle */
/* with coors in screen space */
/****************************************************************************/
int _cgi_pattern_rect(vws, x0, y0, d1, d2, index, flag)
View_surface *vws;
int x0, y0, d1, d2, index, flag;
{
Cpixrect *patrect;
patrect = _cgi_pattern(index, flag);
pw_replrop(vws->sunview.pw, x0, y0, d1, d2, _cgi_pix_mode, patrect, x0, y0);
(void) pr_destroy(patrect);
}
/****************************************************************************/
/* */
/* FUNCTION: _cgi_arr_dev_xform */
/* */
/* transform VDC coordinate list to DEVICE coordinates */
/* This is faster than looping over _cgi_devscale() */
/****************************************************************************/
_cgi_arr_dev_xform(vws, npoints, vdc_coord_ptr, dev_coord_ptr)
View_surface *vws;
register unsigned npoints; /* count down to 0 */
register Ccoor *vdc_coord_ptr;
register struct pr_pos *dev_coord_ptr;
{
register View_surface *vws_ptr = vws;
if ((X_DEVSCALE_NEEDED(vws_ptr)) || (Y_DEVSCALE_NEEDED(vws_ptr)))
{
if (X_DEVSCALE_NEEDED(vws_ptr))
{
if (Y_DEVSCALE_NEEDED(vws_ptr)) /* Typical non-cgipw case */
while (npoints--)
{
DEV_XFORM_X(vdc_coord_ptr, dev_coord_ptr,, vws_ptr);
DEV_XFORM_Y(vdc_coord_ptr, dev_coord_ptr, ++, vws_ptr);
}
else /* X scale needed, not Y */
while (npoints--)
{
DEV_XFORM_X(vdc_coord_ptr, dev_coord_ptr,, vws_ptr);
DEV_OFF_Y(vdc_coord_ptr, dev_coord_ptr, ++);
}
}
else /* Y scale needed, not X */
{
while (npoints--)
{
DEV_OFF_X(vdc_coord_ptr, dev_coord_ptr,);
DEV_XFORM_Y(vdc_coord_ptr, dev_coord_ptr, ++, vws_ptr);
}
}
}
else /* Neither X nor Y needs scaling (typical cgipw
* case) */
{
while (npoints--)
{
DEV_OFF_X(vdc_coord_ptr, dev_coord_ptr,);
DEV_OFF_Y(vdc_coord_ptr, dev_coord_ptr, ++);
}
}
}