Files
BaS_gcc/video/vdi_fill.c
2017-12-25 10:21:08 +01:00

1113 lines
30 KiB
C

/*
*
*
* Copyright 1982 by Digital Research Inc. All rights reserved.
* Copyright 1999 by Caldera, Inc. and Authors:
* Copyright 2002-2013 The EmuTOS development team
*
* This file is distributed under the GPL, version 2 or at your
* option any later version. See doc/license.txt for details.
*/
#include "config.h"
#include "portab.h"
#include "vdi_defs.h"
#include "tosvars.h"
#include "lineavars.h"
#define EMPTY 0xffff
#define DOWN_FLAG 0x8000
#define QSIZE 200
#define QMAX QSIZE-1
#define ABS(v) (v & 0x7FFF)
/* prototypes */
static void crunch_queue(void);
static BOOL clipbox(Vwk * vwk, Rect * rect);
/* Global variables */
static UWORD search_color; /* the color of the border */
/* some kind of stack for the segments to fill */
static WORD queue[QSIZE]; /* storage for the seed points */
static WORD qbottom; /* the bottom of the queue (zero) */
static WORD qtop; /* points top seed +3 */
static WORD qptr; /* points to the active point */
static WORD qtmp;
static WORD qhole; /* an empty space in the queue */
/* the storage for the used defined fill pattern */
const UWORD ROM_UD_PATRN[16] = {
0x07E0, 0x0FF0, 0x1FD8, 0x1808, 0x1808, 0x1008, 0x1E78, 0x1348,
0x1108, 0x0810, 0x0B70, 0x0650, 0x07A0, 0x1E20, 0x1BC0, 0x1800
};
static const UWORD OEMMSKPAT = 7;
static const UWORD OEMPAT[128] = {
/* Brick */
0xFFFF, 0x8080, 0x8080, 0x8080, 0xFFFF, 0x0808, 0x0808, 0x0808,
/* Diagonal Bricks */
0x2020, 0x4040, 0x8080, 0x4141, 0x2222, 0x1414, 0x0808, 0x1010,
/* Grass */
0x0000, 0x0000, 0x1010, 0x2828, 0x0000, 0x0000, 0x0101, 0x8282,
/* Trees */
0x0202, 0x0202, 0xAAAA, 0x5050, 0x2020, 0x2020, 0xAAAA, 0x0505,
/* Dashed x's */
0x4040, 0x8080, 0x0000, 0x0808, 0x0404, 0x0202, 0x0000, 0x2020,
/* Cobble Stones */
0x6606, 0xC6C6, 0xD8D8, 0x1818, 0x8181, 0x8DB1, 0x0C33, 0x6000,
/* Sand */
0x0000, 0x0000, 0x0400, 0x0000, 0x0010, 0x0000, 0x8000, 0x0000,
/* Rough Weave */
0xF8F8, 0x6C6C, 0xC6C6, 0x8F8F, 0x1F1F, 0x3636, 0x6363, 0xF1F1,
/* Quilt */
0xAAAA, 0x0000, 0x8888, 0x1414, 0x2222, 0x4141, 0x8888, 0x0000,
/* Paterned Cross */
0x0808, 0x0000, 0xAAAA, 0x0000, 0x0808, 0x0000, 0x8888, 0x0000,
/* Balls */
0x7777, 0x9898, 0xF8F8, 0xF8F8, 0x7777, 0x8989, 0x8F8F, 0x8F8F,
/* Verticle Scales */
0x8080, 0x8080, 0x4141, 0x3E3E, 0x0808, 0x0808, 0x1414, 0xE3E3,
/* Diagonal scales */
0x8181, 0x4242, 0x2424, 0x1818, 0x0606, 0x0101, 0x8080, 0x8080,
/* Checker Board */
0xF0F0, 0xF0F0, 0xF0F0, 0xF0F0, 0x0F0F, 0x0F0F, 0x0F0F, 0x0F0F,
/* Filled Diamond */
0x0808, 0x1C1C, 0x3E3E, 0x7F7F, 0xFFFF, 0x7F7F, 0x3E3E, 0x1C1C,
/* Herringbone */
0x1111, 0x2222, 0x4444, 0xFFFF, 0x8888, 0x4444, 0x2222, 0xFFFF
};
static const UWORD DITHRMSK = 3; /* mask off all but four scans */
static const UWORD DITHER[32] = {
0x0000, 0x4444, 0x0000, 0x1111, /* intensity level 2 */
0x0000, 0x5555, 0x0000, 0x5555, /* intensity level 4 */
0x8888, 0x5555, 0x2222, 0x5555, /* intensity level 6 */
0xAAAA, 0x5555, 0xAAAA, 0x5555, /* intensity level 8 */
0xAAAA, 0xDDDD, 0xAAAA, 0x7777, /* intensity level 10 */
0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF, /* intensity level 12 */
0xEEEE, 0xFFFF, 0xBBBB, 0xFFFF, /* intensity level 14 */
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF /* intensity level 16 */
};
static const UWORD HAT_0_MSK = 7;
static const UWORD HATCH0[48] = {
/* narrow spaced + 45 */
0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
/* medium spaced thick 45 deg */
0x6060, 0xC0C0, 0x8181, 0x0303, 0x0606, 0x0C0C, 0x1818, 0x3030,
/* medium +-45 deg */
0x4242, 0x8181, 0x8181, 0x4242, 0x2424, 0x1818, 0x1818, 0x2424,
/* medium spaced vertical */
0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080,
/* medium spaced horizontal */
0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* medium spaced cross */
0xFFFF, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080
};
static const UWORD HAT_1_MSK = 0xF;
static const UWORD HATCH1[96] = {
/* wide +45 deg */
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
/* widely spaced thick 45 deg */
0x8003, 0x0007, 0x000E, 0x001C, 0x0038, 0x0070, 0x00E0, 0x01C0,
0x0380, 0x0700, 0x0E00, 0x1C00, 0x3800, 0x7000, 0x0E000, 0x0C001,
/* widely +- 45 deg */
0x8001, 0x4002, 0x2004, 0x1008, 0x0810, 0x0420, 0x0240, 0x0180,
0x0180, 0x0240, 0x0420, 0x0810, 0x1008, 0x2004, 0x4002, 0x8001,
/* widely spaced vertical */
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
/* widely spaced horizontal */
0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* widely spaced horizontal/vert cross */
0xFFFF, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080,
0xFFFF, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080,
};
const UWORD HOLLOW = 0;
const UWORD SOLID = 0xFFFF;
/*
* dsf_udpat - Update pattern
*/
void
dsf_udpat(Vwk * vwk)
{
WORD *sp, *dp, i, count;
count = CONTRL[3];
if (count == 16)
vwk->multifill = 0; /* Single Plane Pattern */
else if (count == (INQ_TAB[4] * 16))
vwk->multifill = 1; /* Valid Multi-plane pattern */
else
return; /* Invalid pattern, return */
sp = INTIN;
dp = &vwk->ud_patrn[0];
for (i = 0; i < count; i++)
*dp++ = *sp++;
}
/*
* _vsf_interior - Set fill style
*/
void
_vsf_interior(Vwk * vwk)
{
WORD fs;
CONTRL[4] = 1;
fs = *INTIN;
if ((fs > MX_FIL_STYLE) || (fs < 0))
fs = 0;
*INTOUT = vwk->fill_style = fs;
st_fl_ptr(vwk);
}
/* S_FILL_INDEX: */
void
_vsf_style(Vwk * vwk)
{
WORD fi;
CONTRL[4] = 1;
fi = *INTIN;
if (vwk->fill_style == 2) {
if ((fi > MX_FIL_PAT_INDEX) || (fi < 1))
fi = 1;
} else {
if ((fi > MX_FIL_HAT_INDEX) || (fi < 1))
fi = 1;
}
vwk->fill_index = (*INTOUT = fi) - 1;
st_fl_ptr(vwk);
}
/* S_FILL_COLOR: */
void
_vsf_color(Vwk * vwk)
{
WORD fc;
*(CONTRL + 4) = 1;
fc = *INTIN;
if ((fc >= DEV_TAB[13]) || (fc < 0))
fc = 1;
*INTOUT = fc;
vwk->fill_color = MAP_COL[fc];
}
/* ST_FILLPERIMETER: */
void
_vsf_perimeter(Vwk * vwk)
{
WORD *int_out;
int_out = INTOUT;
if (*INTIN == 0) {
*int_out = 0;
vwk->fill_per = FALSE;
} else {
*(int_out) = 1;
vwk->fill_per = TRUE;
}
CONTRL[4] = 1;
}
/*
* dr_recfl - draw filled rectangle
*/
void
dr_recfl(Vwk * vwk)
{
Rect * rect = (Rect*)PTSIN;
if (vwk->clip)
if (!clipbox(vwk, rect))
return;
/* do the real work... */
draw_rect(vwk, rect, vwk->fill_color);
}
/*
* _v_cellarray - Draw a square of sqares (just color devices)
*/
void
_v_cellarray(Vwk * vwk)
{
/* not implemented */
}
/*
* _vq_cellarray -
*/
void
_vq_cellarray(Vwk * vwk)
{
/* not implemented */
}
/*
* vql_attr - Inquire current fill area attributes
*/
void
vqf_attr(Vwk * vwk)
{
WORD *pointer;
pointer = INTOUT;
*pointer++ = vwk->fill_style;
*pointer++ = REV_MAP_COL[vwk->fill_color];
*pointer++ = vwk->fill_index + 1;
*pointer++ = vwk->wrt_mode + 1;
*pointer = vwk->fill_per;
CONTRL[4] = 5;
}
/*
* st_fl_ptr - set fill pattern?
*/
void
st_fl_ptr(Vwk * vwk)
{
WORD fi, pm;
const UWORD *pp = NULL;
fi = vwk->fill_index;
pm = 0;
switch (vwk->fill_style) {
case 0:
pp = &HOLLOW;
break;
case 1:
pp = &SOLID;
break;
case 2:
if (fi < 8) {
pm = DITHRMSK;
pp = &DITHER[fi * (pm + 1)];
} else {
pm = OEMMSKPAT;
pp = &OEMPAT[(fi - 8) * (pm + 1)];
}
break;
case 3:
if (fi < 6) {
pm = HAT_0_MSK;
pp = &HATCH0[fi * (pm + 1)];
} else {
pm = HAT_1_MSK;
pp = &HATCH1[(fi - 6) * (pm + 1)];
}
break;
case 4:
pm = 0x000f;
pp = (UWORD *)&vwk->ud_patrn[0];
break;
}
vwk->patptr = (UWORD *)pp;
vwk->patmsk = pm;
}
/*
* bub_sort - sorts an array of words
*
* This routine bubble-sorts an array of words into ascending order.
*
* input:
* buf - ptr to start of array.
* count - number of words in array.
*/
static void
bub_sort (WORD * buf, WORD count)
{
int i, j;
for (i = count-1; i > 0; i--) {
WORD * ptr = buf; /* reset pointer to the array */
for (j = 0; j < i; j++) {
WORD val = *ptr++; /* word */ /* get next value */
if ( val > *ptr ) { /* yes - do nothing */
*(ptr-1) = *ptr; /* word */ /* nope - swap them */
*ptr = val; /* word */
}
}
}
}
/*
* clc_flit - draw a filled polygon
*
* (Sutherland and Hodgman Polygon Clipping Algorithm)
*
* For each non-horizontal scanline crossing poly, do:
* - find intersection points of scan line with poly edges.
* - Sort intersections left to right
* - Draw pixels between each pair of points (x coords) on the scan line
*/
/*
* the buffer used by clc_flit() has been temporarily moved from the
* stack to a local static area. this avoids some cases of stack
* overflow when the VDI is called from the AES (and the stack is the
* small one located in the UDA). this fix allows GemAmigo to run.
*
* this change restores the situation that existed in the original
* DRI code, when clc_flit() was written in assembler; the buffer
* was moved to the stack when clc_flit() was re-implemented in C.
*/
#define MAX_INTERSECTIONS 256
static WORD fill_buffer[MAX_INTERSECTIONS];
void
clc_flit (const VwkAttrib * attr, const VwkClip * clipper, const Point * point, WORD y, int vectors)
{
// WORD fill_buffer[256]; /* must be 256 words or it will fail */
WORD * bufptr; /* point to array of x-values. */
int intersections; /* count of intersections */
int i;
/* Initialize the pointers and counters. */
intersections = 0; /* reset counter */
bufptr = fill_buffer;
/* find intersection points of scan line with poly edges. */
for (i = vectors - 1; i >= 0; i--) {
WORD x1, x2, y1, y2, dy;
x1 = point->x; /* fetch x-value of 1st endpoint. */
y1 = point->y; /* fetch y-value of 1st endpoint. */
point++;
x2 = point->x; /* fetch x-value of 2nd endpoint. */
y2 = point->y; /* fetch y-value of 2nd endpoint. */
/* if the current vector is horizontal, ignore it. */
dy = y2 - y1;
if ( dy ) {
LONG dy1, dy2;
/* fetch scan-line y. */
dy1 = y - y1; /* d4 - delta y1. */
dy2 = y - y2; /* d3 - delta y2. */
/*
* Determine whether the current vector intersects with the scan
* line we wish to draw. This test is performed by computing the
* y-deltas of the two endpoints from the scan line.
* If both deltas have the same sign, then the line does
* not intersect and can be ignored. The origin for this
* test is found in Newman and Sproull.
*/
if ((dy1 < 0) != (dy2 < 0)) {
int dx = (x2 - x1) << 1; /* so we can round by adding 1 below */
if (++intersections > MAX_INTERSECTIONS)
break;
/* fill edge buffer with x-values */
if ( dx < 0 ) {
*bufptr++ = ((dy2 * dx / dy + 1) >> 1) + x2;
}
else {
*bufptr++ = ((dy1 * dx / dy + 1) >> 1) + x1;
}
}
}
}
/*
* All of the points of intersection have now been found. If there
* were none then there is nothing more to do. Otherwise, sort the
* list of points of intersection in ascending order.
* (The list contains only the x-coordinates of the points.)
*/
/* anything to do? */
if (intersections == 0)
return;
/* bubblesort the intersections, if it makes sense */
if ( intersections > 1 )
bub_sort(fill_buffer, intersections);
if (attr->clip) {
/* Clipping is in force. Once the endpoints of the line segment have */
/* been adjusted for the border, clip them to the left and right sides */
/* of the clipping rectangle. */
/* The x-coordinates of each line segment are adjusted so that the */
/* border of the figure will not be drawn with the fill pattern. */
/* loop through buffered points */
WORD * ptr = fill_buffer;
for (i = intersections / 2 - 1; i >= 0; i--) {
WORD x1, x2;
Rect rect;
/* grab a pair of adjusted intersections */
x1 = *ptr++ + 1;
x2 = *ptr++ - 1;
/* do nothing, if starting point greater than ending point */
if ( x1 > x2 )
continue;
if ( x1 < clipper->xmn_clip ) {
if ( x2 < clipper->xmn_clip )
continue; /* entire segment clipped left */
x1 = clipper->xmn_clip; /* clip left end of line */
}
if ( x2 > clipper->xmx_clip ) {
if ( x1 > clipper->xmx_clip )
continue; /* entire segment clippped */
x2 = clipper->xmx_clip; /* clip right end of line */
}
rect.x1 = x1;
rect.y1 = y;
rect.x2 = x2;
rect.y2 = y;
/* rectangle fill routine draws horizontal line */
draw_rect_common(attr, &rect);
}
}
else {
/* Clipping is not in force. Draw from point to point. */
/* This code has been modified from the version in the screen driver. */
/* The x-coordinates of each line segment are adjusted so that the */
/* border of the figure will not be drawn with the fill pattern. If */
/* the starting point is greater than the ending point then nothing is */
/* done. */
/* loop through buffered points */
WORD * ptr = fill_buffer;
for (i = intersections / 2 - 1; i >= 0; i--) {
WORD x1, x2;
Rect rect;
/* grab a pair of adjusted endpoints */
x1 = *ptr++ + 1 ; /* word */
x2 = *ptr++ - 1 ; /* word */
/* If starting point greater than ending point, nothing is done. */ /* is start still to left of end? */
if ( x1 <= x2 ) {
rect.x1 = x1;
rect.y1 = y;
rect.x2 = x2;
rect.y2 = y;
/* rectangle fill routine draws horizontal line */
draw_rect_common(attr, &rect);
}
}
}
}
/*
* polygon - draw a filled polygon
*/
void
polygon(Vwk * vwk, Point * ptsin, int count)
{
WORD i, k, y;
WORD fill_maxy, fill_miny;
Point * point, * ptsget, * ptsput;
VwkClip *clipper;
VwkAttrib attr;
LSTLIN = FALSE;
/* find out the total min and max y values */
point = ptsin;
fill_maxy = fill_miny = point->y;
for (i = count - 1; i > 0; i--) {
point++;
k = point->y;
if (k < fill_miny)
fill_miny = k;
else
if (k > fill_maxy)
fill_maxy = k;
}
if (vwk->clip) {
if (fill_miny < vwk->ymn_clip) {
if (fill_maxy >= vwk->ymn_clip) {
/* polygon starts before clip */
fill_miny = vwk->ymn_clip - 1; /* polygon partial overlap */
if (fill_miny < 1)
fill_miny = 1;
} else
return; /* polygon entirely before clip */
}
if (fill_maxy > vwk->ymx_clip) {
if (fill_miny <= vwk->ymx_clip) /* polygon ends after clip */
fill_maxy = vwk->ymx_clip; /* polygon partial overlap */
else
return; /* polygon entirely after clip */
}
}
/* close the polygon, connect last and first point */
ptsget = ptsin;
ptsput = ptsin + count;
ptsput->x = ptsget->x;
ptsput->y = ptsget->y;
/* cast structure needed by clc_flit */
clipper = VDI_CLIP(vwk);
/* copy data needed by clc_flit -> draw_rect_common */
Vwk2Attrib(vwk, &attr, vwk->fill_color);
/* really draw it */
for (y = fill_maxy; y > fill_miny; y--) {
clc_flit(&attr, clipper, ptsin, y, count);
}
if (vwk->fill_per == TRUE) {
LN_MASK = 0xffff;
polyline(vwk, ptsin, count+1, vwk->fill_color);
}
}
/*
* _v_fillarea - Fill an area
*/
void
_v_fillarea(Vwk * vwk)
{
Point * point = (Point*)PTSIN;
int count = CONTRL[1];
#if 0
#if HAVE_BEZIER
/* check, if we want to draw a filled bezier curve */
if (CONTRL[5] == 13 && vwk->bez_qual )
v_bez_fill(vwk, point, count);
else
#endif
#endif
polygon(vwk, point, count);
}
/*
* clipbox - Just clips and copies the inputs for use by "rectfill"
*
* input:
* X1 = x coord of upper left corner.
* Y1 = y coord of upper left corner.
* X2 = x coord of lower right corner.
* Y2 = y coord of lower right corner.
* vwk->clip = clipping flag. (0 => no clipping.)
* vwk->xmn_clip = x clipping minimum.
* vwk->xmx_clip = x clipping maximum.
* vwk->ymn_clip = y clipping minimum.
* vwk->ymx_clip = y clipping maximum.
*
* output:
* X1 = x coord of upper left corner.
* Y1 = y coord of upper left corner.
* X2 = x coord of lower right corner.
* Y2 = y coord of lower right corner.
*/
static BOOL
clipbox(Vwk * vwk, Rect * rect)
{
WORD x1, y1, x2, y2;
x1 = rect->x1;
y1 = rect->y1;
x2 = rect->x2;
y2 = rect->y2;
/* clip x coordinates */
if ( x1 < vwk->xmn_clip) {
if (x2 < vwk->xmn_clip) {
return(FALSE); /* clipped box is null */
}
rect->x1 = vwk->xmn_clip;
}
if ( x2 > vwk->xmx_clip) {
if (x1 > vwk->xmx_clip) {
return(FALSE); /* clipped box is null */
}
rect->x2 = vwk->xmx_clip;
}
/* clip y coordinates */
if ( y1 < vwk->ymn_clip) {
if (y2 < vwk->ymn_clip) {
return(FALSE); /* clipped box is null */
}
rect->y1 = vwk->ymn_clip;
}
if ( y2 > vwk->ymx_clip) {
if (y1 > vwk->ymx_clip) {
return(FALSE); /* clipped box is null */
}
rect->y2 = vwk->ymx_clip;
}
return (TRUE);
}
/*
* get_color - Get color value of requested pixel.
*/
static UWORD
get_color (UWORD mask, UWORD * addr)
{
UWORD color = 0; /* clear the pixel value accumulator. */
WORD plane = v_planes;
while(1) {
/* test the bit. */
if ( *--addr & mask )
color |= 1; /* if 1, set color accumulator bit. */
if ( --plane == 0 )
break;
color <<= 1; /* shift accumulator for next bit_plane. */
}
return color; /* this is the color we are searching for */
}
/*
* pixelread - gets a pixel's color index value
*
* input:
* PTSIN(0) = x coordinate.
* PTSIN(1) = y coordinate.
* output:
* pixel value
*/
static UWORD
pixelread(const WORD x, const WORD y)
{
UWORD *addr;
UWORD mask;
/* convert x,y to start adress and bit mask */
addr = get_start_addr(x, y);
addr += v_planes; /* start at highest-order bit_plane */
mask = 0x8000 >> (x&0xf); /* initial bit position in WORD */
return get_color(mask, addr); /* return the composed color value */
}
static UWORD
search_to_right (Vwk * vwk, WORD x, UWORD mask, const UWORD search_col, UWORD * addr)
{
/* is x coord < x resolution ? */
while( x++ < vwk->xmx_clip ) {
UWORD color;
/* need to jump over interleaved bit_plane? */
mask = mask >> 1 | mask << 15; /* roll right */
if ( mask & 0x8000 )
addr += v_planes;
/* search, while pixel color != search color */
color = get_color(mask, addr);
if ( search_col != color ) {
break;
}
}
return x - 1; /* output x coord -1 to endxright. */
}
static UWORD
search_to_left (Vwk * vwk, WORD x, UWORD mask, const UWORD search_col, UWORD * addr)
{
/* Now, search to the left. */
while (x-- > vwk->xmn_clip) {
UWORD color;
/* need to jump over interleaved bit_plane? */
mask = mask >> 15 | mask << 1; /* roll left */
if ( mask & 0x0001 )
addr -= v_planes;
/* search, while pixel color != search color */
color = get_color(mask, addr);
if ( search_col != color )
break;
}
return x + 1; /* output x coord + 1 to endxleft. */
}
/*
* end_pts - find the endpoints of a section of solid color
*
* (for the _seed_fill routine.)
*
* input: 4(sp) = xstart.
* 6(sp) = ystart.
* 8(sp) = ptr to endxleft.
* C(sp) = ptr to endxright.
*
* output: endxleft := left endpoint of solid color.
* endxright := right endpoint of solid color.
* d0 := success flag.
* 0 => no endpoints or xstart on edge.
* 1 => endpoints found.
* seed_type indicates the type of fill
*/
static WORD
end_pts(Vwk * vwk, WORD x, WORD y, WORD *xleftout, WORD *xrightout,
BOOL seed_type)
{
UWORD color;
UWORD * addr;
UWORD mask;
/* see, if we are in the y clipping range */
if ( y < vwk->ymn_clip || y > vwk->ymx_clip)
return 0;
/* convert x,y to start adress and bit mask */
addr = get_start_addr(x, y);
addr += v_planes; /* start at highest-order bit_plane */
mask = 0x8000 >> (x & 0x000f); /* fetch the pixel mask. */
/* get search color and the left and right end */
color = get_color (mask, addr);
*xrightout = search_to_right (vwk, x, mask, color, addr);
*xleftout = search_to_left (vwk, x, mask, color, addr);
/* see, if the whole found segment is of search color? */
if ( color != search_color ) {
return seed_type ^ 1; /* return segment not of search color */
}
return seed_type ^ 0; /* return segment is of search color */
}
/* Prototypes local to this module */
static WORD
get_seed(Vwk * vwk, WORD xin, WORD yin, WORD *xleftout, WORD *xrightout,
BOOL seed_type);
void
d_contourfill(Vwk * vwk)
{
WORD newxleft; /* ends of line at oldy + */
WORD newxright; /* the current direction */
WORD oldxleft; /* left end of line at oldy */
WORD oldxright; /* right end */
WORD oldy; /* the previous scan line */
WORD xleft; /* temporary endpoints */
WORD xright; /* */
WORD direction; /* is next scan line up or down */
BOOL notdone; /* does seedpoint==search_color */
BOOL gotseed; /* a seed was put in the Q */
BOOL seed_type; /* indicates the type of fill */
xleft = PTSIN[0];
oldy = PTSIN[1];
if (xleft < vwk->xmn_clip || xleft > vwk->xmx_clip ||
oldy < vwk->ymn_clip || oldy > vwk->ymx_clip)
return;
search_color = INTIN[0];
if ((WORD)search_color < 0) {
search_color = pixelread(xleft,oldy);
seed_type = 1;
} else {
const WORD plane_mask[] = { 1, 3, 7, 15 };
/* Range check the color and convert the index to a pixel value */
if (search_color >= DEV_TAB[13])
return;
/*
* We mandate that white is all bits on. Since this yields 15
* in rom, we must limit it to how many planes there really are.
* Anding with the mask is only necessary when the driver supports
* move than one resolution.
*/
search_color =
(MAP_COL[search_color] & plane_mask[INQ_TAB[4] - 1]);
seed_type = 0;
}
/* Initialize the line drawing parameters */
LSTLIN = FALSE;
notdone = end_pts(vwk, xleft, oldy, &oldxleft, &oldxright, seed_type);
qptr = qbottom = 0;
qtop = 3; /* one above highest seed point */
queue[0] = (oldy | DOWN_FLAG);
queue[1] = oldxleft;
queue[2] = oldxright; /* stuff a point going down into the Q */
if (notdone) {
/* couldn't get point out of Q or draw it */
while (1) {
Rect rect;
direction = (oldy & DOWN_FLAG) ? 1 : -1;
gotseed = get_seed(vwk, oldxleft, (oldy + direction),
&newxleft, &newxright, seed_type);
if ((newxleft < (oldxleft - 1)) && gotseed) {
xleft = oldxleft;
while (xleft > newxleft) {
--xleft;
get_seed(vwk, xleft, oldy ^ DOWN_FLAG,
&xleft, &xright, seed_type);
}
}
while (newxright < oldxright) {
++newxright;
gotseed = get_seed(vwk, newxright, oldy + direction,
&xleft, &newxright, seed_type);
}
if ((newxright > (oldxright + 1)) && gotseed) {
xright = oldxright;
while (xright < newxright) {
++xright;
get_seed(vwk, xright, oldy ^ DOWN_FLAG,
&xleft, &xright, seed_type);
}
}
/* Eventually jump out here */
if (qtop == qbottom)
break;
while (queue[qptr] == EMPTY) {
qptr += 3;
if (qptr == qtop)
qptr = qbottom;
}
oldy = queue[qptr];
queue[qptr++] = EMPTY;
oldxleft = queue[qptr++];
oldxright = queue[qptr++];
if (qptr == qtop)
crunch_queue();
rect.x1 = oldxleft;
rect.y1 = ABS(oldy);
rect.x2 = oldxright;
rect.y2 = ABS(oldy);
/* rectangle fill routine draws horizontal line */
draw_rect(vwk, &rect, vwk->fill_color);
}
}
} /* end of fill() */
/*
* crunch_queue - move qtop down to remove unused seeds
*/
static void
crunch_queue(void)
{
while ((queue[qtop - 3] == EMPTY) && (qtop > qbottom))
qtop -= 3;
if (qptr >= qtop)
qptr = qbottom;
}
/*
* get_seed - put seeds into Q, if (xin,yin) is not of search_color
*/
static WORD
get_seed(Vwk * vwk, WORD xin, WORD yin, WORD *xleftout, WORD *xrightout,
BOOL seed_type)
{
if (end_pts(vwk, xin, ABS(yin), xleftout, xrightout, seed_type)) {
/* false if of search_color */
for (qtmp = qbottom, qhole = EMPTY; qtmp < qtop; qtmp += 3) {
/* see, if we ran into another seed */
if ( ((queue[qtmp] ^ DOWN_FLAG) == yin) && (queue[qtmp] != EMPTY) &&
(queue[qtmp + 1] == *xleftout) )
{
/* we ran into another seed so remove it and fill the line */
Rect rect;
rect.x1 = *xleftout;
rect.y1 = ABS(yin);
rect.x2 = *xrightout;
rect.y2 = ABS(yin);
/* rectangle fill routine draws horizontal line */
draw_rect(vwk, &rect, vwk->fill_color);
queue[qtmp] = EMPTY;
if ((qtmp + 3) == qtop)
crunch_queue();
return 0;
}
if ((queue[qtmp] == EMPTY) && (qhole == EMPTY))
qhole = qtmp;
}
if (qhole == EMPTY) {
if ((qtop += 3) > QMAX) {
qtmp = qbottom;
qtop -= 3;
}
} else
qtmp = qhole;
queue[qtmp++] = yin; /* put the y and endpoints in the Q */
queue[qtmp++] = *xleftout;
queue[qtmp] = *xrightout;
return 1; /* we put a seed in the Q */
}
return 0; /* we didnt put a seed in the Q */
}
void
_v_get_pixel(Vwk * vwk)
{
WORD pel;
WORD *int_out;
const WORD x = PTSIN[0]; /* fetch x coord. */
const WORD y = PTSIN[1]; /* fetch y coord. */
/* Get the requested pixel */
pel = (WORD)pixelread(x,y);
int_out = INTOUT;
*int_out++ = pel;
*int_out = REV_MAP_COL[pel];
CONTRL[4] = 2;
}
/*
* get_pix - gets a pixel (just for linea!)
*
* input:
* PTSIN(0) = x coordinate.
* PTSIN(1) = y coordinate.
* output:
* pixel value
*/
WORD
get_pix(void)
{
/* return the composed color value */
return pixelread(PTSIN[0], PTSIN[1]);
}
/*
* put_pix - plot a pixel (just for linea!)
*
* input:
* INTIN(0) = pixel value.
* PTSIN(0) = x coordinate.
* PTSIN(1) = y coordinate.
*/
void
put_pix(void)
{
UWORD *addr;
UWORD color;
UWORD mask;
int plane;
const WORD x = PTSIN[0];
const WORD y = PTSIN[1];
/* convert x,y to start adress */
addr = get_start_addr(x, y);
/* co-ordinates can wrap, but cannot write outside screen,
* alternatively this could check against v_bas_ad+vram_size()
*/
if (addr < (UWORD*)v_bas_ad || addr >= get_start_addr(v_hz_rez, v_vt_rez)) {
return;
}
color = INTIN[0]; /* device dependent encoded color bits */
mask = 0x8000 >> (x&0xf); /* initial bit position in WORD */
for (plane = v_planes-1; plane >= 0; plane-- ) {
color = color >> 1| color << 15; /* rotate color bits */
if (color&0x8000)
*addr++ |= mask;
else
*addr++ &= ~mask;
}
}