mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3597 lines
112 KiB
3597 lines
112 KiB
/*+
|
|
* Copyright (C) 1993, 1995 by
|
|
* DIGITAL EQUIPMENT CORPORATION, Maynard, MA.
|
|
*
|
|
* This software is furnished under a license and may be used and copied
|
|
* only in accordance with the terms of such license and with the inclusion
|
|
* of the above copyright notice. This software or any other copies there-
|
|
* of may not be provided or otherwise made available to any other person.
|
|
* No title to and ownership of the software is hereby transferred.
|
|
*
|
|
* The information in this software is subject to change without notice
|
|
* and should not be construed as a commitment by DIGITAL EQUIPMENT COR-
|
|
* PORATION.s
|
|
*
|
|
* DIGITAL assumes no responsibility for the use or reliability of its
|
|
* software on equipment which is not supplied by DIGITAL.
|
|
*
|
|
* Module Name: stroke.c
|
|
*
|
|
* DrvStrokePath for TGA driver
|
|
*
|
|
* Define TEST_ENV to use code with the software model
|
|
* Define CONT_ALIAS to use BRESENHAM CONTINUE REGISTER aliases
|
|
* Define PASS_ONE and CONT_ALIAS to use workaround for contiune alias
|
|
* this bug fixed in TGA pass two
|
|
*
|
|
* History
|
|
*
|
|
* 10-Nov-1993 Barry Tannenbaum
|
|
* Added punt_stroke_path to localize handling of punting.
|
|
* Added check of ppdev->bInPuntRoutine to check whether we have to
|
|
* restore TGA to simple mode before we exit
|
|
*
|
|
* 12-NOV-1993 Bill Wernsing
|
|
* Added updated version to handle unclipped and clipped lines
|
|
*
|
|
* 2-Jan-1994 Barry Tannenbaum
|
|
* - Added support for sparse space to punt routine.
|
|
* - Put braces around calls to set the slope register since this was
|
|
* annoying the compiler in sparse space version.
|
|
*
|
|
* 1-Feb-1994 Barry Tannenbaum
|
|
* Implemented styled lines
|
|
*
|
|
* 4-Feb-1994 Barry Tannenbaum
|
|
* Fixed bug in calculating first line mask for styled lines
|
|
*
|
|
* 6-Feb-1994 Barry Tannenbaum
|
|
* Save style state, init PATHOBJ enumeration
|
|
*
|
|
* 21-Feb-1994 Bill Wernsing
|
|
* Don't punt lines because of ROP; force unknown ROP to value of COPY
|
|
*
|
|
* 23-Feb-1994 Bill Wernsing
|
|
* Add code to use Bresenham Continue Register aliases
|
|
*
|
|
* 28-Feb-1994 Bill Wernsing
|
|
* Modified code for calculation of start address of line
|
|
* to be relative to the base address of the frame buffer
|
|
* The incorrect start address was causing lines to be drawn
|
|
* at the wrong locations in sparse-space memory.
|
|
*
|
|
* 3-Mar-1994 Bill Wernsing
|
|
* Modified code for Bresenham Continue Register alias to
|
|
* start alias at AltROM + 512K. Also added continue alias
|
|
* fix for TGA pass one. Modified clipped line code to handle
|
|
* offset for line starting outside display area.
|
|
*
|
|
* 25-Mar-1994 Barry Tannenbaum
|
|
* Implemented Bob McNamara's workaround for the fact that TGA is
|
|
* choosing the wrong pixels to light when exactly between two pixels.
|
|
* The fix is to negate the Breshenham width and select the slope
|
|
* register for the octant mirrored across the X axis. In effect, this
|
|
* mirror's the line across the origin.
|
|
*
|
|
* 4-May-1994 Barry Tannenbaum
|
|
* Reset style state when we see PD_RESETSTYLE.
|
|
*
|
|
* 23-May-1994 Kathleen Langone
|
|
* Add algorithm to do better GIQ end point rounding and correct
|
|
* calculation of the e term
|
|
*
|
|
* 24-May-1994 Kathleen Langone
|
|
* Fixed bug in calculating values for floating point logic and
|
|
* moved float<->int conversions to improve performance
|
|
*
|
|
* 26-May-1994 Kathleen Langone
|
|
* Changed slope register addresses for floating point case to
|
|
* align with changes for the bres. width register
|
|
*
|
|
* 6-Jun-1994 Barry Tannenbaum
|
|
* Creating the aligned copy of the style mask was writing off the
|
|
* end of the fixed-sized array. Instead of creating an entire
|
|
* aligned copy, the style_mask array now has a complete longword's
|
|
* worth of data and we shift is right as needed, on the fly.
|
|
*
|
|
* 9-Jun-1994 Kathleen Langone
|
|
* In routine TGAStrokePath, a field in the structure "pla" needed
|
|
* to be set when calling TGAStyledLines for the clipped case. This
|
|
* was causing clipped/styled lines not to draw properly.
|
|
*
|
|
* 16-Jun-1994 Kathleen Langone
|
|
* 1) Changing logic for clipped floating point cosmetic line
|
|
* to be use full floating point logic, this fixed a bug with
|
|
* clipped lines w/ WINBEZ
|
|
* 2) Taking out "return" logic when line_length = 0,
|
|
* added "if" logic to continue polyline if length != 0,
|
|
* otherwise complete polyline is not drawn, changed in TGALines
|
|
* and TGAStyledLines
|
|
* 3) Obtaining error term from convert_to_giq logic, works better
|
|
* than our old method, passes GUIMAN by "almost" 100%
|
|
* 4) For return values from TGAClipper, put new clipped values
|
|
* into ppt structures and not use "float" values, possibly change
|
|
* this logic later
|
|
*
|
|
* 16-Jun-1994 Kathleen Langone
|
|
* Changed logic so that all line cases have check for zero-length line
|
|
*
|
|
* 16-Jun-1994 Kathleen Langone/Bob Seitsinger
|
|
* Adding fix for clipping bug when line length exceeds clipped
|
|
* mask array size, fixes in TGALines and TGAStyledLines.
|
|
*
|
|
* 20-Jun-1994 Barry Tannenbaum
|
|
* Rewrote support for clipped lines.
|
|
*
|
|
* 22-Jun-1994 Barry Tannenbaum
|
|
* Fixed intialization error.
|
|
*
|
|
* 24-Jun-1994 Kathleen Langone
|
|
* Adding logic to TGAStyledLines to handle floating point lines
|
|
*
|
|
* 15-Jul-1994 Kathleen Langone
|
|
* Changed integer clipping logic to not use mask array and obtain
|
|
* start x,y and length from convert_to_clip for each clip segment
|
|
*
|
|
* 22-Jul-1994 Kathleen Langone
|
|
* Fixed slope calculation for clipped integer lines by creating
|
|
* a flag to indicate if Dx has been negated. If this flag is set,
|
|
* Dy needs to be negated also.
|
|
*
|
|
* 26-Jul-1994 Barry Tannenbaum
|
|
* New code for styled lines. We no longer need the wretched mask
|
|
* array.
|
|
*
|
|
* 29-Jul-1994 Barry Tannenbaum
|
|
* Corrected calculation of slope
|
|
*
|
|
* 8-Aug-1994 Barry Tannenbaum
|
|
* Added support for pass-3 TGA boards - don't need workaround
|
|
*
|
|
* 9-Aug-1994 Barry Tannenbaum
|
|
* Setup for 24 plane support:
|
|
* - TGAMODE and TGAROP now take simple ULONGs instead of structures
|
|
* - Use default values from ppdev->ulModeTemplate & ppdev->ulRopTemplate
|
|
*
|
|
* 15-Aug-1994 Barry Tannenbaum
|
|
* Updated address calculation for 24 plane
|
|
*
|
|
* 16-Aug-1994 Kathleen Langone
|
|
* Changed clipped integer line logic to "goto" clipped floating
|
|
* point logic if line is not vertical or horizontal
|
|
*
|
|
* 17-Aug-1994 Kathleen Langone
|
|
* Fixed the un-initialized warnings for "b" and "slope"
|
|
*
|
|
* 31-Aug-1994 Barry Tannenbaum
|
|
* Mask high byte off of color in 24 plane mode
|
|
*
|
|
* 28-Sep-1994 Kathleen Langone
|
|
* Add line fixes from the 8 Plane stream which included:
|
|
* - clipping
|
|
* - styled lines
|
|
* - fix for line address in TGAStyledLines
|
|
* - new function build_line_mask for use in TGALines
|
|
*
|
|
* 30-Sep-1994 Kathleen Langone
|
|
* - Formated and simplified the code in TGALines and TGAStyledLines
|
|
* - Added the routine "select_slope_register", written by Barry,
|
|
* to the above routines. This routine takes into account the
|
|
* slope register selection differences between pass1/pass2/pass3
|
|
* TGA boards
|
|
*
|
|
* 04-Oct-1994 Kathleen Langone
|
|
* - Put in needed changes from TGAStrokePath from the 8-plane code
|
|
* - Setting of style state for clipped, non-styled lines
|
|
* - Return from TGALines and TGAStyledLine if their boolean
|
|
* return is False
|
|
* - fixed a bug found by Barry dealing with plane mask setting
|
|
* when not a "copy rop"
|
|
* - For clipped/float lines in TGALines, changed input to
|
|
* build_line_mask to just line_length
|
|
*
|
|
* 07-Oct-1994 Kathleen Langone
|
|
* - Put in temporary fix to initialize slope & b for logic not
|
|
* currently used in TGALines
|
|
* - Took out unused variables in TGALines and TGAStyledLines
|
|
*
|
|
* 10-Oct-1994 Kathleen Langone
|
|
* - Condensing logic in TGAStrokePath so that same logic is used for
|
|
* styled and regular lines
|
|
* - Fixed code in "clipped integer" so that logic only goes to
|
|
* "convert_to_clip" when lines are vert/horiz and not alternate
|
|
*
|
|
* 14-Oct-1994 Kathleen Langone
|
|
* - Changed "if" for goto Clip_Float from "&&" to "||",
|
|
* lines that weren't vert/horiz were using convert_to_clip
|
|
*
|
|
* 16-Oct-1994 Barry Tannenbaum
|
|
* Fixed value used for Dy in slope calculation for solid, clipped, integer
|
|
* lines
|
|
*
|
|
* 25-Oct-1994 Bob Seitsinger
|
|
* Write plane mask with ppdev->ulPlanemaskTemplate all the
|
|
* time.
|
|
*
|
|
* For 24 plane boards we don't want to blow away the
|
|
* windows ids for 3d windows. The GL driver removes the
|
|
* window ids when it relinquishes a rectangular area.
|
|
*
|
|
* 03-Nov-1994 Tim Dziechowski
|
|
* Stats support
|
|
*
|
|
* 08-Nov-1994 Kathleen Langone
|
|
* - Fixed bug in style_init(used by TGAStyledLines), that occurs
|
|
* only when cstyle=1, and the index into the style array
|
|
* exceeds the length of element in pstyle
|
|
* - Also took out incorrect logic in TGAStyledLines where there
|
|
* was a goto to clip_float when arun != 0
|
|
*
|
|
* 2-Mar-1995 Barry Tannenbaum
|
|
* EV5 changes
|
|
*
|
|
* 27-Mar-1995 Kathleen Langone
|
|
* Added check for pre-Pass3 boards in TGALines that would cause
|
|
* all solid lines to be done with floating point software/hardware
|
|
* to avoid not passing the HCT's tests(path01 and path02) at
|
|
* 1280x1024 resolution.
|
|
*
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include "driver.h"
|
|
#include "tga.h"
|
|
#include "debug.h"
|
|
#include "lines.h"
|
|
#include "tgastats.h"
|
|
|
|
#define STYLE_DENSITY 3 // Should really be defined in driver.h
|
|
#define RUN_MAX 20
|
|
#define SUBPIXELBITS 4
|
|
|
|
|
|
#define UInt64Div32To32(a, b) \
|
|
((((DWORDLONG)(a)) > ULONG_MAX) ? \
|
|
(ULONG)((DWORDLONG)(a) / (ULONG)(b)) : \
|
|
(ULONG)((ULONG)(a) / (ULONG)(b)))
|
|
|
|
#define UInt64Mod32To32(a, b) \
|
|
((((DWORDLONG)(a)) > ULONG_MAX) ? \
|
|
(ULONG)((DWORDLONG)(a) % (ULONG)(b)) : \
|
|
(ULONG)((ULONG)(a) % (ULONG)(b)))
|
|
|
|
#define SWAPL(x,y,t) {t = x; x = y; y = t;}
|
|
|
|
FLONG gaflRound[] = {
|
|
FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // no flips
|
|
FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // FL_FLIP_D
|
|
FL_H_ROUND_DOWN, // FL_FLIP_V
|
|
FL_V_ROUND_DOWN, // FL_FLIP_V | FL_FLIP_D
|
|
FL_V_ROUND_DOWN, // FL_FLIP_SLOPE_ONE
|
|
0xbaadf00d, // FL_FLIP_SLOPE_ONE | FL_FLIP_D
|
|
FL_H_ROUND_DOWN, // FL_FLIP_SLOPE_ONE | FL_FLIP_V<
|
|
0xbaadf00d // FL_FLIP_SLOPE_ONE | FL_FLIP_V | FL_FL
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
BOOL set; // Flags whether we're setting bits
|
|
ULONG i; // Index for current style array entry
|
|
ULONG i_max; // Number of style array entries
|
|
ULONG len; // Remaining length in current style array entry
|
|
LINEATTRS *pla; // Pointer to line attributes
|
|
} style_t;
|
|
|
|
typedef struct
|
|
{
|
|
BOOL set; // Flags whether we're setting bits
|
|
INT i; // Run index
|
|
ULONG len; // Length of current run segment
|
|
ULONG start; // Offset for current run portion
|
|
INT i_max; // Maximum index
|
|
RUN *runs; // Run array
|
|
} mask_t;
|
|
|
|
// prototype for which function to call
|
|
typedef BOOL (*DRAWFUNC) (SURFOBJ *pso,
|
|
POINTFIX *ppta,
|
|
POINTFIX *pptb,
|
|
ULONG count,
|
|
RUN *arun,
|
|
ULONG run_count,
|
|
LINEATTRS *pla,
|
|
ULONG *continue_alias);
|
|
|
|
typedef union
|
|
{
|
|
BYTE a[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
|
|
CLIPLINE cl;
|
|
} CL;
|
|
|
|
#define MIN(_a, _b) ((_a < _b) ? _a : _b)
|
|
|
|
static
|
|
ULONG word_bits[17] = // Masks used to clip off right hand
|
|
{ // portion of style mask. Also used
|
|
0xffff, // 1111111111111111 0 // to generate style masks.
|
|
0x0001, // 0000000000000001 1
|
|
0x0003, // 0000000000000011 2
|
|
0x0007, // 0000000000000111 3
|
|
0x000f, // 0000000000001111 4
|
|
0x001f, // 0000000000011111 5
|
|
0x003f, // 0000000000111111 6
|
|
0x007f, // 0000000001111111 7
|
|
0x00ff, // 0000000011111111 8
|
|
0x01ff, // 0000000111111111 9
|
|
0x03ff, // 0000001111111111 10
|
|
0x07ff, // 0000011111111111 11
|
|
0x0fff, // 0000111111111111 12
|
|
0x1fff, // 0001111111111111 13
|
|
0x3fff, // 0011111111111111 14
|
|
0x7fff, // 0111111111111111 15
|
|
0xffff // 1111111111111111 16
|
|
};
|
|
|
|
static
|
|
ULONG clip_bits[16] = // Masks used to clip off unused bits on
|
|
{ // the left side of the style mask
|
|
0xffff, // 1111111111111111 0
|
|
0xfffe, // 1111111111111110 1
|
|
0xfffc, // 1111111111111100 2
|
|
0xfff8, // 1111111111111000 3
|
|
0xfff0, // 1111111111110000 4
|
|
0xffe0, // 1111111111100000 5
|
|
0xffc0, // 1111111111000000 6
|
|
0xff80, // 1111111110000000 7
|
|
0xff00, // 1111111100000000 8
|
|
0xfe00, // 1111111000000000 9
|
|
0xfc00, // 1111110000000000 10
|
|
0xf800, // 1111100000000000 11
|
|
0xf000, // 1111000000000000 12
|
|
0xe000, // 1110000000000000 13
|
|
0xc000, // 1100000000000000 14
|
|
0x8000 // 1000000000000000 15
|
|
};
|
|
|
|
static
|
|
long mix_to_rop[17] = // Table to convert a ROP2 to a TGA ROP
|
|
{
|
|
0, // Not Used - saves subtracting 1 from ROP2 code
|
|
TGA_ROP_CLEAR, // 1 - R2_BLACK
|
|
TGA_ROP_NOR, // 2 - R2_NOTMERGEPEN
|
|
TGA_ROP_AND_INVERTED, // 3 - R2_MASKNOTPEN
|
|
TGA_ROP_COPY_INVERTED, // 4 - R2_NOTCOPYPEN
|
|
TGA_ROP_AND_REVERSE, // 5 - R2_MASKPENNOT
|
|
TGA_ROP_INVERT, // 6 - R2_NOT
|
|
TGA_ROP_XOR, // 7 - R2_XORPEN
|
|
TGA_ROP_NAND, // 8 - R2_NOTMASKPEN
|
|
TGA_ROP_AND, // 9 - R2_MASKPEN
|
|
TGA_ROP_EQUIV, // 10 - R2_NOTXORPEN
|
|
TGA_ROP_NOP, // 11 - R2_NOP
|
|
TGA_ROP_OR_INVERTED, // 12 - R2_MERGENOTPEN
|
|
TGA_ROP_COPY, // 13 - R2_COPYPEN
|
|
TGA_ROP_OR_REVERSE, // 14 - R2_MERGEPENNOT
|
|
TGA_ROP_OR, // 15 - R2_MERGEPEN
|
|
TGA_ROP_SET // 16 - R2_WHITE
|
|
};
|
|
|
|
/*************************************************************************\
|
|
* Module Name: intline.c
|
|
*
|
|
* Copyright (c) 1993-1994 Microsoft Corporation
|
|
* Copyright (c) 1992 Digital Equipment Corporation
|
|
\**************************************************************************/
|
|
|
|
#define DEFAULT_DRAW_CMD DRAW_LINE | \
|
|
DRAW | \
|
|
DIR_TYPE_XY | \
|
|
MULTIPLE_PIXELS | \
|
|
WRITE | \
|
|
LAST_PIXEL_OFF
|
|
|
|
/******************************************************************************
|
|
* bIntegerLine
|
|
*
|
|
* This routine attempts to draw a line segment between two points. It
|
|
* will only draw if both end points are whole integers: it does not support
|
|
* fractional endpoints.
|
|
*
|
|
* Returns:
|
|
* TRUE if the line segment is drawn
|
|
* FALSE otherwise
|
|
*****************************************************************************/
|
|
static __inline
|
|
BOOL
|
|
bIntegerLine (
|
|
PDEV* ppdev,
|
|
ULONG X1,
|
|
ULONG Y1,
|
|
ULONG X2,
|
|
ULONG Y2
|
|
)
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bHardwareLine(ppdev, pptfxStart, pptfxEnd)
|
|
*
|
|
* This routine is useful for folks who have line drawing hardware where
|
|
* they can explicitly set the Bresenham terms -- they can use this routine
|
|
* to draw fractional coordinate GIQ lines with the hardware.
|
|
*
|
|
* Fractional coordinate lines require an extra 4 bits of precision in the
|
|
* Bresenham terms. For example, if your hardware has 13 bits of precision
|
|
* for the terms, you can only draw GIQ lines up to 255 pels long using this
|
|
* routine.
|
|
*
|
|
* Input:
|
|
* pptfxStart - Points to GIQ coordinate of start of line
|
|
* pptfxEnd - Points to GIQ coordinate of end of line
|
|
* NUM_DDA_BITS- The number of bits of precision your hardware can support.
|
|
*
|
|
* Output:
|
|
* returns - TRUE if the line was drawn.
|
|
* FALSE if the line is too long, and the strips code must be
|
|
* used.
|
|
*
|
|
* DDALINE:
|
|
* iDir - Direction of the line, as an octant numbered as follows:
|
|
*
|
|
* \ 5 | 6 /
|
|
* \ | /
|
|
* 4 \ | / 7
|
|
* \ /
|
|
* -----+-----
|
|
* /|\
|
|
* 3 / | \ 0
|
|
* / | \
|
|
* / 2 | 1 \
|
|
*
|
|
* ptlStart - Start pixel of line.
|
|
* cPels - # of pels in line. *NOTE* You must check if this is <= 0!
|
|
* dMajor - Major axis delta.
|
|
* dMinor - Minor axis delta.
|
|
* lErrorTerm - Error term.
|
|
*
|
|
* What you do with the last 3 terms may be a little tricky. They are
|
|
* actually the terms for the formula of the normalized line
|
|
*
|
|
* dMinor * x + (lErrorTerm + dMajor)
|
|
* y(x) = floor( ---------------------------------- )
|
|
* dMajor
|
|
*
|
|
* where y(x) is the y coordinate of the pixel to be lit as a function of
|
|
* the x-coordinate.
|
|
*
|
|
* Every time the line advances one in the major direction 'x', dMinor
|
|
* gets added to the current error term. If the resulting value is >= 0,
|
|
* we know we have to move one pixel in the minor direction 'y', and
|
|
* dMajor must be subtracted from the current error term.
|
|
*
|
|
* If you're trying to figure out what this means for your hardware, you can
|
|
* think of the DDALINE terms as having been computed equivalently as
|
|
* follows:
|
|
*
|
|
* dMinor = 2 * (minor axis delta)
|
|
* dMajor = 2 * (major axis delta)
|
|
* lErrorTerm = - (major axis delta) - fixup
|
|
*
|
|
* That is, if your documentation tells you that for integer lines, a
|
|
* register is supposed to be initialized with the value
|
|
* '2 * (minor axis delta)', you'll actually use dMinor.
|
|
*
|
|
* Example: Setting up the 8514
|
|
*
|
|
* AXSTPSIGN is supposed to be the axial step constant register, defined
|
|
* as 2 * (minor axis delta). You set:
|
|
*
|
|
* AXSTPSIGN = dMinor
|
|
*
|
|
* DGSTPSIGN is supposed to be the diagonal step constant register,
|
|
* defined as 2 * (minor axis delta) - 2 * (major axis delta). You set:
|
|
*
|
|
* DGSTPSIGN = dMinor - dMajor
|
|
*
|
|
* ERR_TERM is supposed to be the adjusted error term, defined as
|
|
* 2 * (minor axis delta) - (major axis delta) - fixup. You set:
|
|
*
|
|
* ERR_TERM = lErrorTerm + dMinor
|
|
*
|
|
* Implementation:
|
|
*
|
|
* You'll want to special case integer lines before calling this routine
|
|
* (since they're very common, take less time to the computation of line
|
|
* terms, and can handle longer lines than this routine because 4 bits
|
|
* aren't being given to the fraction).
|
|
*
|
|
* If a GIQ line is too long to be handled by this routine, you can just
|
|
* use the slower strip routines for that line. Note that you cannot
|
|
* just fail the call -- you must be able to accurately draw any line
|
|
* in the 28.4 device space when it intersects the viewport.
|
|
*
|
|
* Testing:
|
|
*
|
|
* Use Guiman, or some other test that draws random fractional coordinate
|
|
* lines and compares them to what GDI itself draws to a bitmap.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static __inline
|
|
BOOL bHardwareLine(
|
|
PDEV* ppdev,
|
|
POINTFIX* pptfxStart, // Start of line
|
|
POINTFIX* pptfxEnd) // End of line
|
|
{
|
|
FLONG fl; // Various flags
|
|
ULONG M0; // Normalized fractional unit x start coordinate (0 <= M0 < F)
|
|
ULONG N0; // Normalized fractional unit y start coordinate (0 <= N0 < F)
|
|
ULONG M1; // Normalized fractional unit x end coordinate (0 <= M1 < F)
|
|
ULONG N1; // Normalized fractional unit x end coordinate (0 <= N1 < F)
|
|
ULONG dM; // Normalized fractional unit x-delta (0 <= dM)
|
|
ULONG dN; // Normalized fractional unit y-delta (0 <= dN <= dM)
|
|
LONG x; // Normalized x coordinate of origin
|
|
LONG y; // Normalized y coordinate of origin
|
|
LONG x0; // Normalized x offset from origin to start pixel (inclusive)
|
|
LONG y0; // Normalized y offset from origin to start pixel (inclusive)
|
|
LONG x1; // Normalized x offset from origin to end pixel (inclusive)
|
|
LONG lGamma;// Bresenham error term at origin
|
|
LONG cPels; // Number of pixels in line
|
|
|
|
/***********************************************************************\
|
|
* Normalize line to the first octant.
|
|
\***********************************************************************/
|
|
|
|
fl = 0;
|
|
|
|
M0 = pptfxStart->x;
|
|
dM = pptfxEnd->x;
|
|
|
|
if ((LONG) dM < (LONG) M0)
|
|
{
|
|
// Line runs from right to left, so flip across x = 0:
|
|
|
|
M0 = -(LONG) M0;
|
|
dM = -(LONG) dM;
|
|
fl |= HW_FLIP_H;
|
|
}
|
|
|
|
// Compute the delta. The DDI says we can never have a valid delta
|
|
// with a magnitude more than 2^31 - 1, but the engine never actually
|
|
// checks its transforms. To ensure that we'll never puke on our shoes,
|
|
// we check for that case and simply refuse to draw the line:
|
|
|
|
dM -= M0;
|
|
if ((LONG) dM < 0)
|
|
return(FALSE);
|
|
|
|
N0 = pptfxStart->y;
|
|
dN = pptfxEnd->y;
|
|
|
|
if ((LONG) dN < (LONG) N0)
|
|
{
|
|
// Line runs from bottom to top, so flip across y = 0:
|
|
|
|
N0 = -(LONG) N0;
|
|
dN = -(LONG) dN;
|
|
fl |= HW_FLIP_V;
|
|
}
|
|
|
|
// Compute another delta:
|
|
|
|
dN -= N0;
|
|
if ((LONG) dN < 0)
|
|
return(FALSE);
|
|
|
|
if (dN >= dM)
|
|
{
|
|
if (dN == dM)
|
|
{
|
|
// Have to special case slopes of one:
|
|
|
|
fl |= HW_FLIP_SLOPE_ONE;
|
|
}
|
|
else
|
|
{
|
|
// Since line has slope greater than 1, flip across x = y:
|
|
|
|
register ULONG ulTmp;
|
|
ulTmp = dM; dM = dN; dN = ulTmp;
|
|
ulTmp = M0; M0 = N0; N0 = ulTmp;
|
|
fl |= HW_FLIP_D;
|
|
}
|
|
}
|
|
|
|
// Figure out if we can do the line in hardware, given that we have a
|
|
// limited number of bits of precision for the Bresenham terms.
|
|
//
|
|
// Remember that one bit has to be kept as a sign bit:
|
|
// 13 = NUM_DDA_BITS
|
|
if ((LONG) dM >= (1L << (13 - 1)))
|
|
return(FALSE);
|
|
|
|
fl |= gaflHardwareRound[fl];
|
|
|
|
/***********************************************************************\
|
|
* Calculate the error term at pixel 0.
|
|
\***********************************************************************/
|
|
|
|
x = LFLOOR((LONG) M0);
|
|
y = LFLOOR((LONG) N0);
|
|
|
|
M0 = FXFRAC(M0);
|
|
N0 = FXFRAC(N0);
|
|
|
|
// NOTE NOTE NOTE: If this routine were to handle any line in the 28.4
|
|
// space, it will overflow its math (the following part requires 36 bits
|
|
// of precision)! But we get here for lines that the hardware can handle
|
|
// (see the expression (dM >= (1L << (NUM_DDA_BITS - 1))) above?), so if
|
|
// cBits is less than 28, we're safe.
|
|
//
|
|
// If you're going to use this routine to handle all lines in the 28.4
|
|
// device space, you will HAVE to make sure the math doesn't overflow,
|
|
// otherwise you won't be NT compliant! (See lines.cxx for an example
|
|
// how to do that. You don't have to worry about this if you simply
|
|
// default to the strips code for long lines, because those routines
|
|
// already do the math correctly.)
|
|
|
|
// Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]. Note
|
|
// that M0 and N0 have at most 4 bits of significance (and if the
|
|
// arguments are properly ordered, on a 486 each multiply would be no
|
|
// more than 13 cycles):
|
|
|
|
lGamma = (N0 + F/2) * dM - M0 * dN;
|
|
|
|
if (fl & HW_Y_ROUND_DOWN)
|
|
lGamma--;
|
|
|
|
lGamma >>= FLOG2;
|
|
|
|
/***********************************************************************\
|
|
* Figure out which pixels are at the ends of the line.
|
|
\***********************************************************************/
|
|
|
|
// The toughest part of GIQ is determining the start and end pels.
|
|
//
|
|
// Our approach here is to calculate x0 and x1 (the inclusive start
|
|
// and end columns of the line respectively, relative to our normalized
|
|
// origin). Then x1 - x0 + 1 is the number of pels in the line. The
|
|
// start point is easily calculated by plugging x0 into our line equation
|
|
// (which takes care of whether y = 1/2 rounds up or down in value)
|
|
// getting y0, and then undoing the normalizing flips to get back
|
|
// into device space.
|
|
//
|
|
// We look at the fractional parts of the coordinates of the start and
|
|
// end points, and call them (M0, N0) and (M1, N1) respectively, where
|
|
// 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid
|
|
// to determine x0:
|
|
//
|
|
// +-----------------------> +x
|
|
// |
|
|
// | 0 1
|
|
// | 0123456789abcdef
|
|
// |
|
|
// | 0 ........?xxxxxxx
|
|
// | 1 ..........xxxxxx
|
|
// | 2 ...........xxxxx
|
|
// | 3 ............xxxx
|
|
// | 4 .............xxx
|
|
// | 5 ..............xx
|
|
// | 6 ...............x
|
|
// | 7 ................
|
|
// | 8 ................
|
|
// | 9 ......**........
|
|
// | a ........****...x
|
|
// | b ............****
|
|
// | c .............xxx****
|
|
// | d ............xxxx ****
|
|
// | e ...........xxxxx ****
|
|
// | f ..........xxxxxx
|
|
// |
|
|
// | 2 3
|
|
// v
|
|
//
|
|
// +y
|
|
//
|
|
// This grid accounts for the appropriate rounding of GIQ and last-pel
|
|
// exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands
|
|
// on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// For the end point, if (M1, N1) lands on an 'x', x1 =
|
|
// floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 =
|
|
// floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// Lines of exactly slope one require a special case for both the start
|
|
// and end. For example, if the line ends such that (M1, N1) is (9, 1),
|
|
// the line has gone exactly through (8, 0) -- which may be considered
|
|
// to be part of 'x' because of rounding! So slopes of exactly slope
|
|
// one going through (8, 0) must also be considered as belonging in 'x'
|
|
// when an x value of 1/2 is supposed to round up in value.
|
|
|
|
// Calculate x0, x1:
|
|
|
|
N1 = FXFRAC(N0 + dN);
|
|
M1 = FXFRAC(M0 + dM);
|
|
|
|
x1 = LFLOOR(M0 + dM);
|
|
|
|
// Line runs left-to-right:
|
|
|
|
// Compute x1:
|
|
|
|
x1--;
|
|
if (M1 > 0)
|
|
{
|
|
if (N1 == 0)
|
|
{
|
|
if (LROUND(M1, fl & HW_X_ROUND_DOWN))
|
|
x1++;
|
|
}
|
|
else if (abs((LONG) (N1 - F/2)) <= (LONG) M1)
|
|
{
|
|
x1++;
|
|
}
|
|
}
|
|
|
|
if ((fl & (HW_FLIP_SLOPE_ONE | HW_X_ROUND_DOWN))
|
|
== (HW_FLIP_SLOPE_ONE | HW_X_ROUND_DOWN))
|
|
{
|
|
// Have to special-case diagonal lines going through our
|
|
// the point exactly equidistant between two horizontal
|
|
// pixels, if we're supposed to round x=1/2 down:
|
|
|
|
if ((M1 > 0) && (N1 == M1 + 8))
|
|
x1--;
|
|
|
|
if ((M0 > 0) && (N0 == M0 + 8))
|
|
{
|
|
x0 = 0;
|
|
goto left_to_right_compute_y0;
|
|
}
|
|
}
|
|
|
|
// Compute x0:
|
|
|
|
x0 = 0;
|
|
if (M0 > 0)
|
|
{
|
|
if (N0 == 0)
|
|
{
|
|
if (LROUND(M0, fl & HW_X_ROUND_DOWN))
|
|
x0 = 1;
|
|
}
|
|
else if (abs((LONG) (N0 - F/2)) <= (LONG) M0)
|
|
{
|
|
x0 = 1;
|
|
}
|
|
}
|
|
|
|
left_to_right_compute_y0:
|
|
|
|
/***********************************************************************\
|
|
* Calculate the start pixel.
|
|
\***********************************************************************/
|
|
|
|
// We now compute y0 and adjust the error term. We know x0, and we know
|
|
// the current formula for the pixels to be lit on the line:
|
|
//
|
|
// dN * x + lGamma
|
|
// y(x) = floor( --------------- )
|
|
// dM
|
|
//
|
|
// The remainder of this expression is the new error term at (x0, y0).
|
|
// Since x0 is going to be either 0 or 1, we don't actually have to do a
|
|
// multiply or divide to compute y0. Finally, we subtract dM from the
|
|
// new error term so that it is in the range [-dM, 0).
|
|
|
|
y0 = 0;
|
|
lGamma += (dN & (-x0));
|
|
lGamma -= dM;
|
|
if (lGamma >= 0)
|
|
{
|
|
y0 = 1;
|
|
lGamma -= dM;
|
|
}
|
|
|
|
// Undo our flips to get the start coordinate:
|
|
|
|
x += x0;
|
|
y += y0;
|
|
|
|
if (fl & HW_FLIP_D)
|
|
{
|
|
register LONG lTmp;
|
|
lTmp = x; x = y; y = lTmp;
|
|
}
|
|
|
|
if (fl & HW_FLIP_V)
|
|
{
|
|
y = -y;
|
|
}
|
|
|
|
if (fl & HW_FLIP_H)
|
|
{
|
|
x = -x;
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* Return the Bresenham terms:
|
|
\***********************************************************************/
|
|
|
|
// iDir = gaiDir[fl & HW_FLIP_MASK];
|
|
// ptlStart.x = x;
|
|
// ptlStart.y = y;
|
|
// cPels = x1 - x0 + 1; // NOTE: You'll have to check if cPels <= 0!
|
|
// dMajor = dM;
|
|
// dMinor = dN;
|
|
// lErrorTerm = lGamma;
|
|
|
|
/***********************************************************************\
|
|
* Draw the line. S3 specific code follows:
|
|
\***********************************************************************/
|
|
|
|
cPels = x1 - x0 + 1;
|
|
|
|
}
|
|
|
|
/*
|
|
* Conversion of x1, y1 to GIQ conventions end points and
|
|
* calculation of major length for line drawing with fixed
|
|
* point lines
|
|
*/
|
|
|
|
static __inline
|
|
void convert_to_clip ( PDEV* ppdev,
|
|
POINTFIX *point1,
|
|
POINTFIX *point2,
|
|
RUN* prun, // Pointer to runs if doing
|
|
//complex clipping
|
|
ULONG cptfx, // Number of points in
|
|
// pptfxBuf or number of runs
|
|
// in prun
|
|
LINESTATE* pls, // Colour and style info
|
|
RECTL* prclClip, // Pointer to clip rectangle if doing simple clipping
|
|
FLONG flStart, // Flags for each line
|
|
int *firstx,
|
|
int *firsty,
|
|
int *length,
|
|
int *error_term
|
|
)
|
|
|
|
{
|
|
|
|
ULONG M0;
|
|
ULONG dM;
|
|
ULONG N0;
|
|
ULONG dN;
|
|
ULONG dN_Original;
|
|
FLONG fl;
|
|
LONG x;
|
|
LONG y;
|
|
LONGLONG llBeta;
|
|
LONGLONG llGamma;
|
|
LONGLONG dl;
|
|
LONGLONG ll;
|
|
ULONG ulDelta;
|
|
ULONG x0;
|
|
ULONG y0;
|
|
ULONG x1;
|
|
ULONG cStylePels; // Major length of line in pixels for styling
|
|
ULONG xStart;
|
|
POINTL ptlStart;
|
|
LONG cPels;
|
|
|
|
POINTFIX* pptfxBufEnd = point2 + cptfx; // Last point in path record
|
|
STYLEPOS spThis; // Style pos for this line
|
|
|
|
/***********************************************************************\
|
|
* Start the DDA calculations. *
|
|
\***********************************************************************/
|
|
|
|
|
|
// Initialize length to zero
|
|
|
|
*length = 0;
|
|
|
|
M0 = (LONG) point1->x;
|
|
dM = (LONG) point2->x;
|
|
|
|
N0 = (LONG) point1->y;
|
|
dN = (LONG) point2->y;
|
|
|
|
fl = flStart;
|
|
|
|
// Check for non-clipped, non-styled integer endpoint lines
|
|
|
|
if ((fl & (FL_CLIP | FL_STYLED)) == 0)
|
|
{
|
|
// Special-case integer end-point lines:
|
|
|
|
if (((M0 | dM | N0 | dN) & (F - 1)) == 0)
|
|
{
|
|
}
|
|
|
|
// Check for fractional endpoint lines that are small enough
|
|
// to use the hardware DDA:
|
|
|
|
else if (bHardwareLine(ppdev, point1, point2))
|
|
{
|
|
//goto Next_Line;
|
|
}
|
|
}
|
|
|
|
if ((LONG) M0 > (LONG) dM)
|
|
{
|
|
// Ensure that we run left-to-right:
|
|
|
|
register ULONG ulTmp;
|
|
SWAPL(M0, dM, ulTmp);
|
|
SWAPL(N0, dN, ulTmp);
|
|
fl |= FL_FLIP_H;
|
|
}
|
|
|
|
// Compute the deltas:
|
|
|
|
dM -= M0;
|
|
dN -= N0;
|
|
|
|
// We now have a line running left-to-right from (M0, N0) to
|
|
// (M0 + dM, N0 + dN):
|
|
|
|
if ((LONG) dN < 0)
|
|
{
|
|
// Line runs from bottom to top, so flip across y = 0:
|
|
|
|
N0 = -(LONG) N0;
|
|
dN = -(LONG) dN;
|
|
fl |= FL_FLIP_V;
|
|
}
|
|
|
|
if (dN >= dM)
|
|
{
|
|
if (dN == dM)
|
|
{
|
|
// Have to special case slopes of one:
|
|
|
|
fl |= FL_FLIP_SLOPE_ONE;
|
|
}
|
|
else
|
|
{
|
|
// Since line has slope greater than 1, flip across x = y:
|
|
|
|
register ULONG ulTmp;
|
|
SWAPL(dM, dN, ulTmp);
|
|
SWAPL(M0, N0, ulTmp);
|
|
fl |= FL_FLIP_D;
|
|
}
|
|
}
|
|
|
|
fl |= gaflRound[(fl & FL_ROUND_MASK) >> FL_ROUND_SHIFT];
|
|
|
|
x = LFLOOR((LONG) M0);
|
|
y = LFLOOR((LONG) N0);
|
|
|
|
M0 = FXFRAC(M0);
|
|
N0 = FXFRAC(N0);
|
|
|
|
// Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]:
|
|
|
|
llGamma = Int32x32To64(dM, N0 + F/2) - Int32x32To64(M0, dN);
|
|
if (fl & FL_V_ROUND_DOWN) // Adjust so y = 1/2 rounds down
|
|
{
|
|
llGamma--;
|
|
}
|
|
|
|
llGamma >>= FLOG2;
|
|
llBeta = ~llGamma;
|
|
|
|
/***********************************************************************\
|
|
* Figure out which pixels are at the ends of the line. *
|
|
\***********************************************************************/
|
|
|
|
// The toughest part of GIQ is determining the start and end pels.
|
|
//
|
|
// Our approach here is to calculate x0 and x1 (the inclusive start
|
|
// and end columns of the line respectively, relative to our normalized
|
|
// origin). Then x1 - x0 + 1 is the number of pels in the line. The
|
|
// start point is easily calculated by plugging x0 into our line equation
|
|
// (which takes care of whether y = 1/2 rounds up or down in value)
|
|
// getting y0, and then undoing the normalizing flips to get back
|
|
// into device space.
|
|
//
|
|
// We look at the fractional parts of the coordinates of the start and
|
|
// end points, and call them (M0, N0) and (M1, N1) respectively, where
|
|
// 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid
|
|
// to determine x0:
|
|
//
|
|
// +-----------------------> +x
|
|
// |
|
|
// | 0 1
|
|
// | 0123456789abcdef
|
|
// |
|
|
// | 0 ........?xxxxxxx
|
|
// | 1 ..........xxxxxx
|
|
// | 2 ...........xxxxx
|
|
// | 3 ............xxxx
|
|
// | 4 .............xxx
|
|
// | 5 ..............xx
|
|
// | 6 ...............x
|
|
// | 7 ................
|
|
// | 8 ................
|
|
// | 9 ......**........
|
|
// | a ........****...x
|
|
// | b ............****
|
|
// | c .............xxx****
|
|
// | d ............xxxx ****
|
|
// | e ...........xxxxx ****
|
|
// | f ..........xxxxxx
|
|
// |
|
|
// | 2 3
|
|
// v
|
|
//
|
|
// +y
|
|
//
|
|
// This grid accounts for the appropriate rounding of GIQ and last-pel
|
|
// exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands
|
|
// on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// For the end point, if (M1, N1) lands on an 'x', x1 =
|
|
// floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 =
|
|
// floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// Lines of exactly slope one require a special case for both the start
|
|
// and end. For example, if the line ends such that (M1, N1) is (9, 1),
|
|
// the line has gone exactly through (8, 0) -- which may be considered
|
|
// to be part of 'x' because of rounding! So slopes of exactly slope
|
|
// one going through (8, 0) must also be considered as belonging in 'x'.
|
|
//
|
|
// For lines that go left-to-right, we have the following grid:
|
|
//
|
|
// +-----------------------> +x
|
|
// |
|
|
// | 0 1
|
|
// | 0123456789abcdef
|
|
// |
|
|
// | 0 xxxxxxxx?.......
|
|
// | 1 xxxxxxx.........
|
|
// | 2 xxxxxx..........
|
|
// | 3 xxxxx...........
|
|
// | 4 xxxx............
|
|
// | 5 xxx.............
|
|
// | 6 xx..............
|
|
// | 7 x...............
|
|
// | 8 x...............
|
|
// | 9 x.....**........
|
|
// | a xx......****....
|
|
// | b xxx.........****
|
|
// | c xxxx............****
|
|
// | d xxxxx........... ****
|
|
// | e xxxxxx.......... ****
|
|
// | f xxxxxxx.........
|
|
// |
|
|
// | 2 3
|
|
// v
|
|
//
|
|
// +y
|
|
//
|
|
// This grid accounts for the appropriate rounding of GIQ and last-pel
|
|
// exclusion. If (M0, N0) lands on an 'x', x0 = 0. If (M0, N0) lands
|
|
// on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// For the end point, if (M1, N1) lands on an 'x', x1 =
|
|
// floor((M0 + dM) / 16) - 1. If (M1, N1) lands on a '.', x1 =
|
|
// floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// Lines of exactly slope one must be handled similarly to the right-to-
|
|
// left case.
|
|
|
|
{
|
|
|
|
// Calculate x0, x1
|
|
|
|
ULONG N1 = FXFRAC(N0 + dN);
|
|
ULONG M1 = FXFRAC(M0 + dM);
|
|
|
|
x1 = LFLOOR(M0 + dM);
|
|
|
|
if (fl & FL_FLIP_H)
|
|
{
|
|
// ---------------------------------------------------------------
|
|
// Line runs right-to-left: <----
|
|
|
|
// Compute x1:
|
|
|
|
if (N1 == 0)
|
|
{
|
|
if (LROUND(M1, fl & FL_H_ROUND_DOWN))
|
|
{
|
|
x1++;
|
|
}
|
|
}
|
|
else if (abs((LONG) (N1 - F/2)) + M1 > F)
|
|
{
|
|
x1++;
|
|
}
|
|
|
|
if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
|
|
== (FL_FLIP_SLOPE_ONE))
|
|
{
|
|
// Have to special-case diagonal lines going through our
|
|
// the point exactly equidistant between two horizontal
|
|
// pixels, if we're supposed to round x=1/2 down:
|
|
|
|
if ((N1 > 0) && (M1 == N1 + 8))
|
|
x1++;
|
|
|
|
// Don't you love special cases? Is this a rhetorical question?
|
|
|
|
if ((N0 > 0) && (M0 == N0 + 8))
|
|
{
|
|
x0 = 2;
|
|
ulDelta = dN;
|
|
goto right_to_left_compute_y0;
|
|
}
|
|
}
|
|
|
|
// Compute x0:
|
|
|
|
x0 = 1;
|
|
ulDelta = 0;
|
|
if (N0 == 0)
|
|
{
|
|
if (LROUND(M0, fl & FL_H_ROUND_DOWN))
|
|
{
|
|
x0 = 2;
|
|
ulDelta = dN;
|
|
}
|
|
}
|
|
else if (abs((LONG) (N0 - F/2)) + M0 > F)
|
|
{
|
|
x0 = 2;
|
|
ulDelta = dN;
|
|
}
|
|
|
|
// Compute y0:
|
|
|
|
right_to_left_compute_y0:
|
|
|
|
y0 = 0;
|
|
ll = llGamma + (LONGLONG) ulDelta;
|
|
|
|
if (ll >= (LONGLONG) (2 * dM - dN))
|
|
y0 = 2;
|
|
else if (ll >= (LONGLONG) (dM - dN))
|
|
y0 = 1;
|
|
}
|
|
else
|
|
{
|
|
// ---------------------------------------------------------------
|
|
// Line runs left-to-right: ---->
|
|
|
|
// Compute x1:
|
|
|
|
x1--;
|
|
|
|
if (M1 > 0)
|
|
{
|
|
if (N1 == 0)
|
|
{
|
|
if (LROUND(M1, fl & FL_H_ROUND_DOWN))
|
|
x1++;
|
|
}
|
|
else if (abs((LONG) (N1 - F/2)) <= (LONG) M1)
|
|
{
|
|
x1++;
|
|
}
|
|
}
|
|
|
|
if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
|
|
== (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
|
|
{
|
|
// Have to special-case diagonal lines going through our
|
|
// the point exactly equidistant between two horizontal
|
|
// pixels, if we're supposed to round x=1/2 down:
|
|
|
|
if ((M1 > 0) && (N1 == M1 + 8))
|
|
x1--;
|
|
|
|
if ((M0 > 0) && (N0 == M0 + 8))
|
|
{
|
|
x0 = 0;
|
|
goto left_to_right_compute_y0;
|
|
}
|
|
}
|
|
|
|
// Compute x0:
|
|
|
|
x0 = 0;
|
|
if (M0 > 0)
|
|
{
|
|
if (N0 == 0)
|
|
{
|
|
if (LROUND(M0, fl & FL_H_ROUND_DOWN))
|
|
x0 = 1;
|
|
}
|
|
else if (abs((LONG) (N0 - F/2)) <= (LONG) M0)
|
|
{
|
|
x0 = 1;
|
|
}
|
|
}
|
|
|
|
// Compute y0:
|
|
|
|
left_to_right_compute_y0:
|
|
|
|
y0 = 0;
|
|
if (llGamma >= (LONGLONG) (dM - (dN & (-(LONG) x0))))
|
|
{
|
|
y0 = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
cStylePels = x1 - x0 + 1;
|
|
if ((LONG) cStylePels <= 0)
|
|
goto Next_Line;
|
|
|
|
xStart = x0;
|
|
|
|
/***********************************************************************\
|
|
* Complex clipping. *
|
|
\***********************************************************************/
|
|
|
|
if (fl & FL_COMPLEX_CLIP)
|
|
{
|
|
dN_Original = dN;
|
|
|
|
if (fl & FL_FLIP_H)
|
|
{
|
|
// Line runs right-to-left <-----
|
|
|
|
x0 = xStart + cStylePels - prun->iStop - 1;
|
|
x1 = xStart + cStylePels - prun->iStart - 1;
|
|
}
|
|
else
|
|
{
|
|
// Line runs left-to-right ----->
|
|
|
|
x0 = xStart + prun->iStart;
|
|
x1 = xStart + prun->iStop;
|
|
}
|
|
|
|
prun++;
|
|
|
|
// Reset some variables we'll nuke a little later:
|
|
|
|
dN = dN_Original;
|
|
pls->spNext = pls->spComplex;
|
|
|
|
// No overflow since large integer math is used. Both values
|
|
// will be positive:
|
|
|
|
dl = Int32x32To64(x0, dN) + llGamma;
|
|
|
|
// y0 = dl / dM:
|
|
|
|
y0 = UInt64Div32To32(dl, dM);
|
|
|
|
ASSERT_TGA((LONG) y0 >= 0, "y0 weird: Goofed up end pel calc?");
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* Simple rectangular clipping. *
|
|
\***********************************************************************/
|
|
|
|
if (fl & FL_SIMPLE_CLIP)
|
|
{
|
|
ULONG y1;
|
|
LONG xRight;
|
|
LONG xLeft;
|
|
LONG yBottom;
|
|
LONG yTop;
|
|
|
|
// Note that y0 and y1 are actually the lower and upper bounds,
|
|
// respectively, of the y coordinates of the line (the line may
|
|
// have actually shrunk due to first/last pel clipping).
|
|
//
|
|
// Also note that x0, y0 are not necessarily zero.
|
|
|
|
RECTL* prcl = &prclClip[(fl & FL_RECTLCLIP_MASK) >>
|
|
FL_RECTLCLIP_SHIFT];
|
|
|
|
// Normalize to the same point we've normalized for the DDA
|
|
// calculations:
|
|
|
|
xRight = prcl->right - x;
|
|
xLeft = prcl->left - x;
|
|
yBottom = prcl->bottom - y;
|
|
yTop = prcl->top - y;
|
|
|
|
if (yBottom <= (LONG) y0 ||
|
|
xRight <= (LONG) x0 ||
|
|
xLeft > (LONG) x1)
|
|
{
|
|
Totally_Clipped:
|
|
// check this logic out...
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
pls->spNext += cStylePels;
|
|
if (pls->spNext >= pls->spTotal2)
|
|
pls->spNext %= pls->spTotal2;
|
|
}
|
|
|
|
goto Next_Line;
|
|
}
|
|
|
|
if ((LONG) x1 >= xRight)
|
|
x1 = xRight - 1;
|
|
|
|
// We have to know the correct y1, which we haven't bothered to
|
|
// calculate up until now. This multiply and divide is quite
|
|
// expensive; we could replace it with code similar to that which
|
|
// we used for computing y0.
|
|
//
|
|
// The reason why we need the actual value, and not an upper
|
|
// bounds guess like y1 = LFLOOR(dM) + 2 is that we have to be
|
|
// careful when calculating x(y) that y0 <= y <= y1, otherwise
|
|
// we can overflow on the divide (which, needless to say, is very
|
|
// bad).
|
|
|
|
dl = Int32x32To64(x1, dN) + llGamma;
|
|
|
|
// y1 = dl / dM:
|
|
|
|
y1 = UInt64Div32To32(dl, dM);
|
|
|
|
if (yTop > (LONG) y1)
|
|
goto Totally_Clipped;
|
|
|
|
if (yBottom <= (LONG) y1)
|
|
{
|
|
y1 = yBottom;
|
|
dl = Int32x32To64(y1, dM) + llBeta;
|
|
|
|
// x1 = dl / dN:
|
|
|
|
x1 = UInt64Div32To32(dl, dN);
|
|
}
|
|
|
|
// At this point, we've taken care of calculating the intercepts
|
|
// with the right and bottom edges. Now we work on the left and
|
|
// top edges:
|
|
|
|
if (xLeft > (LONG) x0)
|
|
{
|
|
x0 = xLeft;
|
|
dl = Int32x32To64(x0, dN) + llGamma;
|
|
|
|
// y0 = dl / dM;
|
|
|
|
y0 = UInt64Div32To32(dl, dM);
|
|
|
|
if (yBottom <= (LONG) y0)
|
|
goto Totally_Clipped;
|
|
}
|
|
|
|
if (yTop > (LONG) y0)
|
|
{
|
|
y0 = yTop;
|
|
dl = Int32x32To64(y0, dM) + llBeta;
|
|
|
|
// x0 = dl / dN + 1;
|
|
|
|
x0 = UInt64Div32To32(dl, dN) + 1;
|
|
|
|
if (xRight <= (LONG) x0)
|
|
goto Totally_Clipped;
|
|
}
|
|
|
|
ASSERT_TGA(x0 <= x1, "Improper rectangle clip");
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* Done clipping. Unflip if necessary. *
|
|
\***********************************************************************/
|
|
|
|
ptlStart.x = x + x0;
|
|
ptlStart.y = y + y0;
|
|
|
|
if (fl & FL_FLIP_D)
|
|
{
|
|
register LONG lTmp;
|
|
SWAPL(ptlStart.x, ptlStart.y, lTmp);
|
|
}
|
|
|
|
|
|
if (fl & FL_FLIP_V)
|
|
{
|
|
ptlStart.y = -ptlStart.y;
|
|
}
|
|
|
|
cPels = x1 - x0 + 1;
|
|
|
|
*firstx = ptlStart.x;
|
|
*firsty = ptlStart.y;
|
|
*length = cPels;
|
|
// *error_term = ;
|
|
|
|
|
|
/***********************************************************************\
|
|
* Style calculations. *
|
|
\***********************************************************************/
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
STYLEPOS sp;
|
|
|
|
spThis = pls->spNext;
|
|
pls->spNext += cStylePels;
|
|
|
|
{
|
|
if (pls->spNext >= pls->spTotal2)
|
|
pls->spNext %= pls->spTotal2;
|
|
|
|
if (fl & FL_FLIP_H)
|
|
sp = pls->spNext - x0 + xStart;
|
|
else
|
|
sp = spThis + x0 - xStart;
|
|
|
|
ASSERT_TGA(fl & FL_ARBITRARYSTYLED, "Oops");
|
|
|
|
// Normalize our target style position:
|
|
|
|
if ((sp < 0) || (sp >= pls->spTotal2))
|
|
{
|
|
sp %= pls->spTotal2;
|
|
|
|
// The modulus of a negative number is not well-defined
|
|
// in C -- if it's negative we'll adjust it so that it's
|
|
// back in the range [0, spTotal2):
|
|
|
|
if (sp < 0)
|
|
sp += pls->spTotal2;
|
|
}
|
|
|
|
// Since we always draw the line left-to-right, but styling is
|
|
// always done in the direction of the original line, we have
|
|
// to figure out where we are in the style array for the left
|
|
// edge of this line.
|
|
|
|
if (fl & FL_FLIP_H)
|
|
{
|
|
// Line originally ran right-to-left:
|
|
|
|
sp = -sp;
|
|
if (sp < 0)
|
|
sp += pls->spTotal2;
|
|
|
|
pls->ulStyleMask = ~pls->ulStartMask;
|
|
pls->pspStart = &pls->aspRtoL[0];
|
|
pls->pspEnd = &pls->aspRtoL[pls->cStyle - 1];
|
|
}
|
|
else
|
|
{
|
|
// Line originally ran left-to-right:
|
|
|
|
pls->ulStyleMask = pls->ulStartMask;
|
|
pls->pspStart = &pls->aspLtoR[0];
|
|
pls->pspEnd = &pls->aspLtoR[pls->cStyle - 1];
|
|
}
|
|
|
|
if (sp >= pls->spTotal)
|
|
{
|
|
sp -= pls->spTotal;
|
|
if (pls->cStyle & 1)
|
|
pls->ulStyleMask = ~pls->ulStyleMask;
|
|
}
|
|
|
|
pls->psp = pls->pspStart;
|
|
while (sp >= *pls->psp)
|
|
sp -= *pls->psp++;
|
|
|
|
ASSERT_TGA(pls->psp <= pls->pspEnd,
|
|
"Flew off into NeverNeverLand");
|
|
|
|
pls->spRemaining = *pls->psp - sp;
|
|
if ((pls->psp - pls->pspStart) & 1)
|
|
pls->ulStyleMask = ~pls->ulStyleMask;
|
|
}
|
|
} // Styled line
|
|
|
|
|
|
if (2 * dN > dM &&
|
|
!(fl & FL_STYLED) &&
|
|
!(fl & FL_DONT_DO_HALF_FLIP))
|
|
{
|
|
// Do a half flip! Remember that we may doing this on the
|
|
// same line multiple times for complex clipping (meaning the
|
|
// affected variables should be reset for every clip run):
|
|
|
|
fl |= FL_FLIP_HALF;
|
|
|
|
llBeta = llGamma - (LONGLONG) ((LONG) dM);
|
|
dN = dM - dN;
|
|
y0 = x0 - y0; // Note this may overflow, but that's okay
|
|
}
|
|
|
|
Next_Line:
|
|
|
|
{
|
|
int dummy;
|
|
dummy = 1;
|
|
}
|
|
|
|
} // End convert_to_clip
|
|
|
|
static __inline
|
|
void convert_to_giq ( POINTFIX *point1,
|
|
POINTFIX *point2,
|
|
int *firstx,
|
|
int *firsty,
|
|
int *length,
|
|
int *error_term
|
|
)
|
|
{
|
|
LONG cBits = 32; // Precision of machine
|
|
FLONG fl; // Various flags
|
|
ULONG M0; // Normalized fractional unit x start coordinate (0 <= M0 < F)
|
|
ULONG N0; // Normalized fractional unit y start coordinate (0 <= N0 < F)
|
|
ULONG M1; // Normalized fractional unit x end coordinate (0 <= M1 < F)
|
|
ULONG N1; // Normalized fractional unit x end coordinate (0 <= N1 < F)
|
|
ULONG dM; // Normalized fractional unit x-delta (0 <= dM)
|
|
ULONG dN; // Normalized fractional unit y-delta (0 <= dN <= dM)
|
|
LONG x; // Normalized x coordinate of origin
|
|
LONG y; // Normalized y coordinate of origin
|
|
LONG x0; // Normalized x offset from origin to start pixel (inclusive)
|
|
LONG y0; // Normalized y offset from origin to start pixel (inclusive)
|
|
LONG x1; // Normalized x offset from origin to end pixel (inclusive)
|
|
LONG lGamma;// Bresenham error term at origin
|
|
|
|
/***********************************************************************\
|
|
* Normalize line to the first octant.
|
|
\***********************************************************************/
|
|
|
|
fl = 0;
|
|
|
|
M0 = point1->x;
|
|
dM = point2->x;
|
|
|
|
if ((LONG) dM < (LONG) M0)
|
|
{
|
|
// Line runs from right to left, so flip across x = 0:
|
|
|
|
M0 = -(LONG) M0;
|
|
dM = -(LONG) dM;
|
|
fl |= HW_FLIP_H;
|
|
}
|
|
|
|
// Compute the delta. The DDI says we can never have a valid delta
|
|
// with a magnitude more than 2^31 - 1, but the engine never actually
|
|
// checks its transforms. To ensure that we'll never puke on our shoes,
|
|
// we check for that case and simply refuse to draw the line:
|
|
|
|
dM -= M0;
|
|
// if ((LONG) dM < 0)
|
|
// return(FALSE);
|
|
|
|
N0 = point1->y;
|
|
dN = point2->y;
|
|
|
|
if ((LONG) dN < (LONG) N0)
|
|
{
|
|
// Line runs from bottom to top, so flip across y = 0:
|
|
|
|
N0 = -(LONG) N0;
|
|
dN = -(LONG) dN;
|
|
fl |= HW_FLIP_V;
|
|
}
|
|
|
|
// Compute another delta:
|
|
|
|
dN -= N0;
|
|
// if ((LONG) dN < 0)
|
|
// return(FALSE);
|
|
|
|
if (dN >= dM)
|
|
{
|
|
if (dN == dM)
|
|
{
|
|
// Have to special case slopes of one:
|
|
|
|
fl |= HW_FLIP_SLOPE_ONE;
|
|
}
|
|
else
|
|
{
|
|
// Since line has slope greater than 1, flip across x = y:
|
|
|
|
register ULONG ulTmp;
|
|
ulTmp = dM; dM = dN; dN = ulTmp;
|
|
ulTmp = M0; M0 = N0; N0 = ulTmp;
|
|
fl |= HW_FLIP_D;
|
|
}
|
|
}
|
|
|
|
// Figure out if we can do the line in hardware, given that we have a
|
|
// limited number of bits of precision for the Bresenham terms.
|
|
//
|
|
// Remember that one bit has to be kept as a sign bit:
|
|
|
|
/* if ((LONG) dM >= (1L << (cBits - 1)))
|
|
return(FALSE);
|
|
*/
|
|
fl |= gaflHardwareRound[fl];
|
|
|
|
/***********************************************************************\
|
|
* Calculate the error term at pixel 0.
|
|
\***********************************************************************/
|
|
|
|
x = LFLOOR((LONG) M0);
|
|
y = LFLOOR((LONG) N0);
|
|
|
|
M0 = FXFRAC(M0);
|
|
N0 = FXFRAC(N0);
|
|
|
|
// NOTE NOTE NOTE: If this routine were to handle any line in the 28.4
|
|
// space, it will overflow its math (the following part requires 36 bits
|
|
// of precision)! But we get here for lines that the hardware can handle
|
|
// (see the expression (dM >= (1L << (cBits - 1))) above?), so if cBits
|
|
// is less than 28, we're safe.
|
|
//
|
|
// If you're going to use this routine to handle all lines in the 28.4
|
|
// device space, you will HAVE to make sure the math doesn't overflow,
|
|
// otherwise you won't be NT compliant! (See lines.cxx for an example
|
|
// how to do that. You don't have to worry about this if you simply
|
|
// default to the strips code for long lines, because those routines
|
|
// already do the math correctly.)
|
|
|
|
// Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]. Note
|
|
// that M0 and N0 have at most 4 bits of significance (and if the
|
|
// arguments are properly ordered, on a 486 each multiply would be no
|
|
// more than 13 cycles):
|
|
|
|
lGamma = (N0 + F/2) * dM - M0 * dN;
|
|
|
|
if (fl & HW_Y_ROUND_DOWN)
|
|
lGamma--;
|
|
|
|
lGamma >>= FLOG2;
|
|
|
|
/***********************************************************************\
|
|
* Figure out which pixels are at the ends of the line.
|
|
\***********************************************************************/
|
|
|
|
// The toughest part of GIQ is determining the start and end pels.
|
|
//
|
|
// Our approach here is to calculate x0 and x1 (the inclusive start
|
|
// and end columns of the line respectively, relative to our normalized
|
|
// origin). Then x1 - x0 + 1 is the number of pels in the line. The
|
|
// start point is easily calculated by plugging x0 into our line equation
|
|
// (which takes care of whether y = 1/2 rounds up or down in value)
|
|
// getting y0, and then undoing the normalizing flips to get back
|
|
// into device space.
|
|
//
|
|
// We look at the fractional parts of the coordinates of the start and
|
|
// end points, and call them (M0, N0) and (M1, N1) respectively, where
|
|
// 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid
|
|
// to determine x0:
|
|
//
|
|
// +-----------------------> +x
|
|
// |
|
|
// | 0 1
|
|
// | 0123456789abcdef
|
|
// |
|
|
// | 0 ........?xxxxxxx
|
|
// | 1 ..........xxxxxx
|
|
// | 2 ...........xxxxx
|
|
// | 3 ............xxxx
|
|
// | 4 .............xxx
|
|
// | 5 ..............xx
|
|
// | 6 ...............x
|
|
// | 7 ................
|
|
// | 8 ................
|
|
// | 9 ......**........
|
|
// | a ........****...x
|
|
// | b ............****
|
|
// | c .............xxx****
|
|
// | d ............xxxx ****
|
|
// | e ...........xxxxx ****
|
|
// | f ..........xxxxxx
|
|
// |
|
|
// | 2 3
|
|
// v
|
|
//
|
|
// +y
|
|
//
|
|
// This grid accounts for the appropriate rounding of GIQ and last-pel
|
|
// exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands
|
|
// on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// For the end point, if (M1, N1) lands on an 'x', x1 =
|
|
// floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 =
|
|
// floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// Lines of exactly slope one require a special case for both the start
|
|
// and end. For example, if the line ends such that (M1, N1) is (9, 1),
|
|
// the line has gone exactly through (8, 0) -- which may be considered
|
|
// to be part of 'x' because of rounding! So slopes of exactly slope
|
|
// one going through (8, 0) must also be considered as belonging in 'x'
|
|
// when an x value of 1/2 is supposed to round up in value.
|
|
|
|
// Calculate x0, x1:
|
|
|
|
N1 = FXFRAC(N0 + dN);
|
|
M1 = FXFRAC(M0 + dM);
|
|
|
|
x1 = LFLOOR(M0 + dM);
|
|
|
|
// Line runs left-to-right:
|
|
|
|
// Compute x1:
|
|
|
|
x1--;
|
|
if (M1 > 0)
|
|
{
|
|
if (N1 == 0)
|
|
{
|
|
if (LROUND(M1, fl & HW_X_ROUND_DOWN))
|
|
x1++;
|
|
}
|
|
else if (ABS((LONG) (N1 - F/2)) <= (LONG) M1)
|
|
{
|
|
x1++;
|
|
}
|
|
}
|
|
|
|
if ((fl & (HW_FLIP_SLOPE_ONE | HW_X_ROUND_DOWN))
|
|
== (HW_FLIP_SLOPE_ONE | HW_X_ROUND_DOWN))
|
|
{
|
|
// Have to special-case diagonal lines going through our
|
|
// the point exactly equidistant between two horizontal
|
|
// pixels, if we're supposed to round x=1/2 down:
|
|
|
|
if ((M1 > 0) && (N1 == M1 + 8))
|
|
x1--;
|
|
|
|
if ((M0 > 0) && (N0 == M0 + 8))
|
|
{
|
|
x0 = 0;
|
|
goto left_to_right_compute_y0;
|
|
}
|
|
}
|
|
|
|
// Compute x0:
|
|
|
|
x0 = 0;
|
|
if (M0 > 0)
|
|
{
|
|
if (N0 == 0)
|
|
{
|
|
if (LROUND(M0, fl & HW_X_ROUND_DOWN))
|
|
x0 = 1;
|
|
}
|
|
else if (ABS((LONG) (N0 - F/2)) <= (LONG) M0)
|
|
{
|
|
x0 = 1;
|
|
}
|
|
}
|
|
|
|
left_to_right_compute_y0:
|
|
|
|
/***********************************************************************\
|
|
* Calculate the start pixel.
|
|
\***********************************************************************/
|
|
|
|
// We now compute y0 and adjust the error term. We know x0, and we know
|
|
// the current formula for the pixels to be lit on the line:
|
|
//
|
|
// dN * x + lGamma
|
|
// y(x) = floor( --------------- )
|
|
// dM
|
|
//
|
|
// The remainder of this expression is the new error term at (x0, y0).
|
|
// Since x0 is going to be either 0 or 1, we don't actually have to do a
|
|
// multiply or divide to compute y0. Finally, we subtract dM from the
|
|
// new error term so that it is in the range [-dM, 0).
|
|
|
|
y0 = 0;
|
|
lGamma += (dN & (-x0));
|
|
lGamma -= dM;
|
|
if (lGamma >= 0)
|
|
{
|
|
y0 = 1;
|
|
lGamma -= dM;
|
|
}
|
|
|
|
// Undo our flips to get the start coordinate:
|
|
|
|
x += x0;
|
|
y += y0;
|
|
|
|
if (fl & HW_FLIP_D)
|
|
{
|
|
register LONG lTmp;
|
|
lTmp = x; x = y; y = lTmp;
|
|
}
|
|
|
|
if (fl & HW_FLIP_V)
|
|
{
|
|
y = -y;
|
|
}
|
|
|
|
if (fl & HW_FLIP_H)
|
|
{
|
|
x = -x;
|
|
}
|
|
|
|
*firstx = x;
|
|
*firsty = y;
|
|
|
|
*length = x1 - x0 + 1;
|
|
|
|
*error_term = lGamma + dN;
|
|
|
|
}
|
|
|
|
/*
|
|
* select_slope_register
|
|
*
|
|
* This routine is called to choose a slope register
|
|
*
|
|
* The logic will determine the octant the line is in and
|
|
* write to appropriate slope register to intiate drawing
|
|
* There is a slope register corresponding to each octant
|
|
* of the cartesian coordinate system
|
|
*
|
|
*/
|
|
|
|
static __inline
|
|
void select_slope_register (BOOL invert,
|
|
PPDEV ppdev,
|
|
CommandWord *base,
|
|
LONG Dx,
|
|
LONG Dy)
|
|
{
|
|
CommandWord *slp_reg_addr = base;
|
|
|
|
if (Dx < 0)
|
|
{
|
|
Dx = -Dx;
|
|
slp_reg_addr -= 2;
|
|
}
|
|
|
|
if (Dy < 0)
|
|
{
|
|
Dy = -Dy;
|
|
slp_reg_addr -= 1;
|
|
}
|
|
|
|
// At this point in the code Dx = Abs(Dx) and Dy = Abs(Dy)
|
|
|
|
|
|
// If a "verticalish" line
|
|
if ( Dx < Dy )
|
|
slp_reg_addr -= 4;
|
|
|
|
// Workaround for pass 2 bug. XOR with 4 to invert through Y origin
|
|
|
|
if (invert)
|
|
slp_reg_addr = (ULONG *)((ULONG)slp_reg_addr ^ 4);
|
|
|
|
TGAWRITE (ppdev, slp_reg_addr, ((Dy << 16) | Dx) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* PuntStrokePath - This routine is called when the TGA display driver
|
|
* can't accelerate the line drawing.
|
|
*/
|
|
|
|
BOOL PuntStrokePath (SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
LINEATTRS *pla,
|
|
MIX mix)
|
|
{
|
|
#ifdef TEST_ENV
|
|
DISPDBG ((0, "StrokePath punted.\n"));
|
|
return FALSE;
|
|
#else
|
|
BOOL status;
|
|
BOOL old_bInPuntRoutine;
|
|
PPDEV ppdev = (PPDEV)pso->dhpdev;
|
|
|
|
DISPDBG ((2, "PuntStrokePath - Entry\n"));
|
|
|
|
BUMP_TGA_STAT(pStats->linepunts);
|
|
|
|
// Force back to simple mode and wait for memory to flush
|
|
|
|
if (! ppdev->bSimpleMode)
|
|
vSetSimpleMode (ppdev);
|
|
|
|
// Copy the rectangle into the punt bitmap if we're using sparse space
|
|
|
|
PUNT_GET_BITS (ppdev, CHOOSE_RECT (ppdev, pco));
|
|
|
|
old_bInPuntRoutine = ppdev->bInPuntRoutine;
|
|
ppdev->bInPuntRoutine = TRUE;
|
|
|
|
// Let NT update the punt bitmap
|
|
|
|
DISPDBG ((2, "EngStrokePath\n"));
|
|
if (!(status = EngStrokePath (ppdev->pPuntSurf, ppo, pco, pxo, pbo,
|
|
pptlBrushOrg, pla, mix)))
|
|
BUMP_TGA_STAT(pStats->linepunts_engine);
|
|
|
|
ppdev->bInPuntRoutine = old_bInPuntRoutine;
|
|
|
|
// Copy the rectangle from the punt bitmap if we're using sparse space
|
|
|
|
PUNT_PUT_BITS (status, ppdev, CHOOSE_RECT (ppdev, pco));
|
|
|
|
DISPDBG ((2, "PuntStrokePath - Exit\n"));
|
|
|
|
return status;
|
|
|
|
#endif // TEST_ENV
|
|
|
|
} // End of function PuntStrokePath
|
|
|
|
|
|
/*
|
|
* clip_init
|
|
*
|
|
* This routine initializes the mask data structure.
|
|
*/
|
|
|
|
VOID clip_init (mask_t *mask_data, RUN *runs, INT num_runs)
|
|
{
|
|
mask_data->i = 0;
|
|
mask_data->i_max = num_runs;
|
|
mask_data->runs = runs;
|
|
|
|
if (0 == runs[0].iStart)
|
|
{
|
|
mask_data->set = TRUE;
|
|
mask_data->len = runs[0].iStop + 1;
|
|
mask_data->start = runs[0].iStop + 1;
|
|
}
|
|
else
|
|
{
|
|
mask_data->set = FALSE;
|
|
mask_data->len = runs[0].iStart;
|
|
mask_data->start = runs[0].iStart;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* clipped_mask
|
|
*
|
|
* This routine returns a mask of bits which indicate which portions of the
|
|
* line may be drawn. The mask is based upon the array of runs specified
|
|
* in the mask data. Each time this routine is called, it will advance
|
|
* "mask_len" pixels through the run array. The maximum allowable value for
|
|
* "mask_len" is 16.
|
|
*/
|
|
|
|
ULONG clipped_mask (ULONG mask_len, mask_t *mask_data)
|
|
{
|
|
ULONG mask;
|
|
ULONG offset;
|
|
RUN *runs;
|
|
|
|
// Check for beyond end of runs
|
|
|
|
if (mask_data->i >= mask_data->i_max)
|
|
return 0;
|
|
|
|
// Check for easy cases (all 1's or 0's)
|
|
|
|
runs = mask_data->runs;
|
|
if (mask_len <= mask_data->len)
|
|
{
|
|
mask_data->len -= mask_len;
|
|
if (mask_data->set)
|
|
mask = word_bits[mask_len];
|
|
else
|
|
mask = 0x00000000;
|
|
|
|
if (0 == mask_data->len)
|
|
{
|
|
if (mask_data->set)
|
|
{
|
|
mask_data->set = FALSE;
|
|
if (++mask_data->i >= mask_data->i_max)
|
|
mask_data->len = 0;
|
|
else
|
|
mask_data->len = (runs[mask_data->i].iStart -
|
|
mask_data->start);
|
|
mask_data->start = runs[mask_data->i].iStart;
|
|
|
|
}
|
|
else
|
|
{
|
|
mask_data->set = TRUE;
|
|
mask_data->len = (runs[mask_data->i].iStop -
|
|
mask_data->start) + 1;
|
|
mask_data->start = runs[mask_data->i].iStop + 1;
|
|
}
|
|
}
|
|
return mask;
|
|
}
|
|
// Rats. We have to work for this one
|
|
|
|
mask = 0;
|
|
offset = 0;
|
|
|
|
while (offset < mask_len)
|
|
{
|
|
if (! mask_data->set)
|
|
{
|
|
if (mask_data->len > mask_len - offset)
|
|
{
|
|
mask_data->len -= mask_len - offset;
|
|
return mask;
|
|
}
|
|
|
|
offset += mask_data->len;
|
|
mask_data->set = TRUE;
|
|
mask_data->len = (runs[mask_data->i].iStop - mask_data->start) + 1;
|
|
mask_data->start = runs[mask_data->i].iStop + 1;
|
|
}
|
|
else
|
|
{
|
|
if (mask_data->len > mask_len - offset)
|
|
{
|
|
mask_data->len -= mask_len - offset;
|
|
|
|
mask |= (0x0000ffff << offset) & 0x0000ffff;
|
|
return mask;
|
|
}
|
|
|
|
mask |= (word_bits[mask_data->len] << offset);
|
|
|
|
offset += mask_data->len;
|
|
mask_data->set = FALSE;
|
|
if (++mask_data->i >= mask_data->i_max)
|
|
{
|
|
mask_data->len = 0;
|
|
mask_data->start = 0;
|
|
return mask;
|
|
}
|
|
mask_data->len = (runs[mask_data->i].iStart - mask_data->start);
|
|
mask_data->start = runs[mask_data->i].iStart;
|
|
}
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
/*
|
|
* build_line_mask
|
|
*
|
|
* This routine determines the line mask to be used, based on the line
|
|
* attributes
|
|
*/
|
|
|
|
ULONG build_line_mask (LINEATTRS *pla, int line_length)
|
|
{
|
|
BOOL odd_style_state;
|
|
BOOL hi_word;
|
|
|
|
// Is this a simple (solid) case?
|
|
|
|
if (! (pla->fl & LA_ALTERNATE))
|
|
return 0x0000ffff;
|
|
|
|
// Update the style state to account for the line length
|
|
|
|
odd_style_state = (0x10000 == (pla->elStyleState.l & 0x010000));
|
|
|
|
hi_word = ( pla->elStyleState.l >> 16);
|
|
hi_word += line_length;
|
|
|
|
pla->elStyleState.l = (hi_word << 16);
|
|
|
|
// We've got an "alternate" style, every other bit on/off
|
|
|
|
if (pla->fl & LA_STARTGAP)
|
|
{
|
|
if (odd_style_state)
|
|
return 0x00005555;
|
|
else
|
|
return 0x0000aaaa;
|
|
}
|
|
else
|
|
{
|
|
if (odd_style_state)
|
|
return 0x0000aaaa;
|
|
else
|
|
return 0x00005555;
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(_ALPHA_)
|
|
|
|
|
|
|
|
|
|
BOOL TGALines (SURFOBJ *pso,
|
|
POINTFIX *ppta, // First point in polyline (28.4 fixed pt)
|
|
POINTFIX *pptb, // Second through last points in polyline
|
|
ULONG count, // Number of points in polyline
|
|
RUN *arun, // Unclipped sections of polyline
|
|
ULONG run_count, // Number of unclipped sections of polyline
|
|
LINEATTRS *pla, // Line attributes of polyline
|
|
ULONG *continue_alias)
|
|
{
|
|
PPDEV ppdev = (PPDEV) pso->dhpdev;
|
|
ULONG start_address; // starting address of first pixel in line
|
|
ULONG base_address; // Base address of frame buffer
|
|
ULONG stride; // Bytes/scanline
|
|
ULONG bytes_per_pixel; // Bytes per pixel
|
|
ULONG AbsDx; // Absolute value of delta X
|
|
ULONG AbsDy; // Absolute value of delta Y
|
|
int line_length; // Number of pixels along major axis of line
|
|
int line_offset; // Number of pixels drawn in first segment (<16)
|
|
LONG Dx; // Delta X of line (in pixels)
|
|
LONG Dy; // Delta Y of line (in pixels)
|
|
ULONG line_mask; // which pixels of 16-pixel segment to draw
|
|
int x1, y1, x2, y2; // integer endpoints of the line
|
|
ULONG line_no; // counter for number of lines in polyline
|
|
ULONG run_no; // counter for number of runs in line
|
|
ULONG bres3;
|
|
int e; // initial Bresenham error term
|
|
double slope, b; // terms needed for clipped integer lines
|
|
BOOL dx_neg = FALSE;
|
|
ULONG first_length;
|
|
ULONG line_template;
|
|
mask_t mask_data;
|
|
BOOL temp;
|
|
|
|
DISPDBG ((2, "TGALines - Entry\n"));
|
|
|
|
// Initialize the information about the frame buffer
|
|
|
|
base_address = SURFOBJ_base_address (pso) - ppdev->pjVideoMemory;
|
|
bytes_per_pixel = SURFOBJ_bytes_per_pixel (pso);
|
|
stride = SURFOBJ_stride (pso);
|
|
|
|
// Draw each line of a polyline
|
|
|
|
for (line_no = 0; line_no < count-1; line_no++)
|
|
{
|
|
|
|
// TGA only handles lines with integer endpoints
|
|
// so real numbers must be rounded and the Bresenham
|
|
// error term modified accordingly
|
|
|
|
if (line_no == 0)
|
|
{
|
|
CYCLE_REGS (ppdev);
|
|
}
|
|
|
|
// !!!! Test Boards earlier than Pass3 - Critical bug was
|
|
// found with the Pass2A boards that caused a failure with
|
|
// The HCT tests(GUIMAN tests Path01 and Path02)
|
|
|
|
if (ppdev->ulTgaVersion < TGA_PASS_3)
|
|
goto Float_Code;
|
|
|
|
// Test for Integer or Floating Point Line
|
|
|
|
if (! ((ppta->x | ppta->y | pptb->x | pptb->y) & 0xF) )
|
|
// Integer Line
|
|
{
|
|
|
|
// Shift out lower 4 bits(which are zero for integer lines)
|
|
x1 = (int) (ppta->x >> 4);
|
|
y1 = (int) (ppta->y >> 4);
|
|
x2 = (int) (pptb->x >> 4);
|
|
y2 = (int) (pptb->y >> 4);
|
|
|
|
Dx = x2 - x1;
|
|
Dy = y2 - y1;
|
|
AbsDx = (Dx < 0) ? -Dx : Dx;
|
|
AbsDy = (Dy < 0) ? -Dy : Dy;
|
|
|
|
// Do out of limits check, and let GDI punt
|
|
if ( (AbsDx > 0xFFFF) || (AbsDy > 0xFFFF) )
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_limitcheck);
|
|
return (FALSE);
|
|
}
|
|
|
|
line_length =
|
|
(AbsDx > AbsDy) ? AbsDx : AbsDy; // number of pixels in the line
|
|
|
|
DISPDBG ((3, "Line(rounded) %d, length=%d, (%d, %d), (%d, %d)\n",
|
|
line_no, line_length, x1, y1, x2, y2));
|
|
|
|
// Don't draw a line which is a single point
|
|
// Results are undefined if the AbsDx and AbsDy values are both zero
|
|
if (line_length == 0)
|
|
goto Next_Segment;
|
|
|
|
|
|
if (arun == NULL)
|
|
{
|
|
// Unclipped line
|
|
|
|
// Set the Address Register to the starting address of the line
|
|
|
|
start_address = base_address +
|
|
(y1 * stride) +
|
|
(x1 * bytes_per_pixel);
|
|
|
|
TGAADDRESS (ppdev, start_address);
|
|
|
|
line_mask = build_line_mask (pla, line_length);
|
|
TGADATA (ppdev, line_mask);
|
|
|
|
// Set the slope register given the TGA card version and Dx,Dy
|
|
// and draw first segment of line
|
|
|
|
select_slope_register ((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->slope_dx_gt_dy,
|
|
Dx, Dy);
|
|
|
|
// Adjust line for pixels drawn by call to
|
|
// select_slope_register)
|
|
|
|
if ((pla->fl & LA_ALTERNATE) && (line_length & 0x1))
|
|
line_mask = ~line_mask;
|
|
|
|
line_offset = line_length & 0x0f; // line_length % 16
|
|
if (0 == line_offset)
|
|
line_length -= 16;
|
|
else
|
|
line_length -= line_offset;
|
|
|
|
// Draw second through last segment (16 pixels) of line
|
|
if (line_length > 0)
|
|
{
|
|
do
|
|
{
|
|
// Write all pixels
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
line_length -= 16;
|
|
} while (line_length > 0);
|
|
} // line_length > 0
|
|
}
|
|
else
|
|
{
|
|
// Clipped line
|
|
|
|
// Old logic: If line is not vertical or horizontal
|
|
//if ( Dx != 0 || Dy != 0)
|
|
// goto Clip_Float;
|
|
|
|
// For now, always goto Clip_Float, may try to fix
|
|
// S3 clipping routine "convert_to_clip" for
|
|
// faster logic
|
|
if ( (pla->fl & LA_ALTERNATE) || (Dx != 0 && Dy != 0) )
|
|
goto Clip_Float;
|
|
|
|
if (0 != Dx)
|
|
{
|
|
slope = (float)Dy / (float)Dx;
|
|
b = ((float)ppta->y / 16.0) -
|
|
((float)ppta->x / 16.0) * slope;
|
|
}
|
|
else
|
|
slope = b = 0.0;
|
|
|
|
// All lines are drawn left to right, with Dx = positive
|
|
if (Dx < 0)
|
|
{
|
|
Dx = -Dx;
|
|
dx_neg = TRUE;
|
|
}
|
|
|
|
for (run_no = 0; run_no < run_count; run_no++)
|
|
{
|
|
|
|
// this call will return start x,y and line length
|
|
{
|
|
FLONG fl = 0;
|
|
int tmp = 1;
|
|
LINESTATE pls;
|
|
|
|
fl |= FL_COMPLEX_CLIP;
|
|
|
|
convert_to_clip (ppdev,
|
|
ppta,
|
|
pptb,
|
|
&arun[run_no],
|
|
tmp,
|
|
&pls,
|
|
(RECTL *)NULL,
|
|
fl,
|
|
&x1, &y1, &line_length, &e);
|
|
}
|
|
|
|
// Set the Address Register to the starting address
|
|
// of the line
|
|
|
|
start_address = base_address +
|
|
(y1 * stride) +
|
|
(x1 * bytes_per_pixel);
|
|
|
|
TGAADDRESS (ppdev, start_address);
|
|
|
|
line_mask = build_line_mask (pla, line_length);
|
|
TGADATA (ppdev, line_mask);
|
|
|
|
// Draw first segment (16 pixels) of line
|
|
|
|
if (AbsDx < AbsDy)
|
|
{
|
|
int lDy;
|
|
|
|
if (dx_neg)
|
|
lDy = -Dy;
|
|
else
|
|
lDy = Dy;
|
|
|
|
AbsDy = arun[run_no].iStop - arun[run_no].iStart + 1;
|
|
if (lDy < 0)
|
|
lDy = - (int)AbsDy;
|
|
else
|
|
lDy = AbsDy;
|
|
|
|
if (AbsDx != 0)
|
|
{
|
|
if (lDy < 0)
|
|
{
|
|
x2 = (int)( ((y1 - AbsDy) - b )/slope );
|
|
Dx = x2 - x1;
|
|
AbsDx = (Dx < 0) ? -Dx : Dx;
|
|
}
|
|
else
|
|
{
|
|
x2 = (int)( ((y1 + AbsDy) - b )/slope );
|
|
Dx = x2 - x1;
|
|
AbsDx = (Dx < 0) ? -Dx : Dx;
|
|
}
|
|
}
|
|
select_slope_register((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->slope_dx_gt_dy,
|
|
Dx, lDy);
|
|
}
|
|
else // (AbsDx >= AbsDy)
|
|
{
|
|
AbsDx = arun[run_no].iStop - arun[run_no].iStart + 1;
|
|
if (AbsDy != 0)
|
|
{
|
|
// Don't need the (Dx < 0) case, because
|
|
// Dx is always > 0
|
|
|
|
y2 = (int)( slope*(x1 + AbsDx) + b );
|
|
Dy = y2 - y1;
|
|
AbsDy = (Dy < 0) ? -Dy : Dy;
|
|
}
|
|
else if ( Dx == Dy )
|
|
{
|
|
AbsDy = AbsDx;
|
|
}
|
|
select_slope_register((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->slope_dx_gt_dy,
|
|
AbsDx, AbsDy);
|
|
}
|
|
|
|
// Adjust line for pixels drawn by call
|
|
// to select_slope_register
|
|
|
|
if ((pla->fl & LA_ALTERNATE) && (line_length & 0x1))
|
|
line_mask = ~line_mask;
|
|
|
|
// The fractional part of line is drawn first if line's not
|
|
// a multiple of 16, this is according to TGA
|
|
|
|
line_offset = line_length & 0x0f; // line_length % 16
|
|
if (0 == line_offset)
|
|
line_length -= 16;
|
|
else
|
|
line_length -= line_offset;
|
|
|
|
// Draw second through last segment
|
|
// (16 pixels per segment) of line
|
|
if (line_length > 0)
|
|
{
|
|
do
|
|
{
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
line_length -= 16;
|
|
} while ( line_length > 0 );
|
|
}
|
|
|
|
CYCLE_REGS (ppdev);
|
|
} // for run_no
|
|
|
|
} // clipped integer line
|
|
|
|
} // integer line
|
|
|
|
else // non-integer(floating point) line
|
|
{
|
|
|
|
Float_Code:
|
|
|
|
Dx = pptb->x - ppta->x;
|
|
Dy = pptb->y - ppta->y;
|
|
|
|
AbsDx = (Dx < 0) ? -Dx : Dx;
|
|
AbsDy = (Dy < 0) ? -Dy : Dy;
|
|
|
|
// Do out of limits check, and let GDI punt
|
|
if ( (AbsDx > 0xFFFF) || (AbsDy > 0xFFFF) )
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_limitcheck);
|
|
return (FALSE);
|
|
}
|
|
|
|
// Is it a unclipped line
|
|
if (arun == NULL)
|
|
{
|
|
// Unclipped line
|
|
|
|
|
|
CYCLE_REGS (ppdev);
|
|
|
|
// Convert to GIQ start points and get line length
|
|
|
|
convert_to_giq( ppta, pptb, &x1, &y1, &line_length, &e );
|
|
|
|
// Put the Line Mask into the Data Register
|
|
line_mask = build_line_mask (pla, line_length);
|
|
TGADATA (ppdev, line_mask);
|
|
|
|
// Set the slope register given the card version and Dx,Dy
|
|
|
|
select_slope_register ((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->sng_dx_gt_dy,
|
|
Dx, Dy);
|
|
|
|
// Exit loop if zero-length line
|
|
if ( line_length == 0)
|
|
goto Next_Segment;
|
|
|
|
//DISPDBG ((3, "Line(rounded) %d, length = %d, (%d, %d),
|
|
//(%d, %d), line_no, line_length, x1, y1, x2, y2));
|
|
|
|
CYCLE_REGS (ppdev);
|
|
|
|
// Set the Address Register to the starting address of the line
|
|
|
|
start_address = base_address +
|
|
(y1 * stride) +
|
|
(x1 * bytes_per_pixel);
|
|
|
|
TGAADDRESS (ppdev, start_address);
|
|
|
|
bres3 = (e << 15) | line_length;
|
|
TGABRES3 (ppdev, bres3);
|
|
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
|
|
// Adjust line for pixels drawn
|
|
|
|
// if odd number of alternating pixels drawn in first segment
|
|
// the line mask must be bitwise NOTTED for next segment.
|
|
|
|
if ((pla->fl & LA_ALTERNATE) && (line_length & 0x1))
|
|
line_mask = ~line_mask;
|
|
|
|
// don't need to know exact length, just number of segments here
|
|
// TGA takes care of details, this statement is more efficient
|
|
line_length -= 16;
|
|
|
|
// Draw second through last segment (16 pixels) of line
|
|
for (; line_length > 0; line_length -= 16)
|
|
{
|
|
// Write all pixels
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
}
|
|
} // non-clipped floating point line
|
|
|
|
else
|
|
{
|
|
|
|
Clip_Float:
|
|
|
|
// Clipped floating point line, note this case may not
|
|
// be needed
|
|
|
|
Dx = pptb->x - ppta->x;
|
|
Dy = pptb->y - ppta->y;
|
|
|
|
// Set the slope register given the card version and Dx,Dy
|
|
|
|
select_slope_register ((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->sng_dx_gt_dy,
|
|
Dx, Dy);
|
|
|
|
// Do we need this cycle reg?
|
|
|
|
CYCLE_REGS (ppdev);
|
|
|
|
// Convert to GIQ start points and get line length
|
|
|
|
convert_to_giq (ppta, pptb, &x1, &y1, &line_length, &e);
|
|
|
|
first_length = line_length & 0x0f;
|
|
if (0 == first_length)
|
|
first_length = 16;
|
|
|
|
if (line_length == 0)
|
|
goto Next_Segment;
|
|
|
|
// Set the Address Register to the starting address of the line
|
|
|
|
start_address = base_address +
|
|
(y1 * stride) +
|
|
(x1 * bytes_per_pixel);
|
|
|
|
TGAADDRESS (ppdev, start_address);
|
|
|
|
// Initialize the clipping information
|
|
|
|
clip_init (&mask_data, arun, run_count);
|
|
|
|
// Load the error term and line length
|
|
|
|
bres3 = (e << 15) | line_length;
|
|
TGABRES3 (ppdev, bres3);
|
|
|
|
// Set line mask for first 16 pixels of line and draw first seg.
|
|
|
|
line_template =
|
|
build_line_mask (pla, line_length);
|
|
line_mask =
|
|
line_template & clipped_mask (first_length, &mask_data);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
|
|
// Adjust line for pixels drawn by call to CONTINUE register.
|
|
// For the first call, this will be 1 to 16 pixels. Subtract
|
|
// 16 from the line length, since we really don't care if we
|
|
// get to exactly 0.
|
|
|
|
if ((pla->fl & LA_ALTERNATE) && (line_length & 0x1))
|
|
line_template = ~line_template;
|
|
|
|
line_length -= 16;
|
|
|
|
// Draw second through last segment (16 pixels per segment)
|
|
// of line
|
|
if (line_length > 0)
|
|
{
|
|
|
|
while (line_length > 0)
|
|
{
|
|
line_mask =
|
|
line_template & clipped_mask (16, &mask_data);
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
line_length -= 16;
|
|
}
|
|
}
|
|
|
|
} // end clipped floating point
|
|
|
|
} // end floating point
|
|
|
|
Next_Segment:
|
|
|
|
// Update pointers to next line
|
|
ppta = pptb;
|
|
pptb++;
|
|
|
|
|
|
} // End for each line
|
|
|
|
// End TGALines
|
|
|
|
return TRUE;
|
|
|
|
} // End of function TGALines
|
|
|
|
|
|
/*
|
|
* style_init
|
|
*
|
|
* This routine initializes the style information kept for a line
|
|
*/
|
|
|
|
VOID style_init (style_t *style_data, LINEATTRS *pla)
|
|
{
|
|
ULONG i, style_len;
|
|
LONG style_index;
|
|
int boundary_flag = 0;
|
|
|
|
// Determine how many STYLE_DENSITY units are in the style array
|
|
|
|
style_len = 0;
|
|
for (i = 0; i < pla->cstyle; i++)
|
|
style_len += pla->pstyle[i].l;
|
|
|
|
// Figure out which entry we're in
|
|
|
|
i = 0;
|
|
style_index = HIWORD (pla->elStyleState.l) % style_len;
|
|
|
|
if ((HIWORD (pla->elStyleState.l) >= style_len) && (pla->cstyle == 1))
|
|
{
|
|
boundary_flag = HIWORD(pla->elStyleState.l) / style_len;
|
|
}
|
|
|
|
while (style_index > 0)
|
|
style_index -= pla->pstyle[i++].l;
|
|
|
|
// If index is < 0, current position is pla->pstyle[0]
|
|
// else it is the same as i
|
|
|
|
if (style_index < 0)
|
|
{
|
|
style_data->i = i - 1;
|
|
style_index += pla->pstyle[style_data->i].l;
|
|
}
|
|
else
|
|
style_data->i = i;
|
|
|
|
style_data->i_max = pla->cstyle;
|
|
style_data->pla = pla;
|
|
|
|
if (boundary_flag == 0)
|
|
{
|
|
// If !LA_STARTGAP, toggle "set" for on bits
|
|
style_data->set = style_data->i & 0x01;
|
|
if (! (pla->fl & LA_STARTGAP))
|
|
style_data->set = !style_data->set;
|
|
}
|
|
else
|
|
{
|
|
style_data->set = !(boundary_flag & 0x01);
|
|
}
|
|
|
|
// style_data->len = length of bits in the current on/off pattern
|
|
// that have not been used
|
|
style_data->len = ((pla->pstyle[style_data->i].l - style_index) *
|
|
STYLE_DENSITY) -
|
|
LOWORD (pla->elStyleState.l);
|
|
}
|
|
|
|
/*
|
|
* style_mask
|
|
*
|
|
* This routine builds a line mask from the style information passed to
|
|
* style_init. Each call will advance the mask "len" bits through the
|
|
* style array
|
|
*/
|
|
|
|
ULONG style_mask (style_t *style_data, ULONG len)
|
|
{
|
|
ULONG mask;
|
|
ULONG offset;
|
|
ULONG *style_array = (ULONG *)style_data->pla->pstyle;
|
|
|
|
// Check for easy cases (all 1's or 0's)
|
|
|
|
if (len < style_data->len)
|
|
{
|
|
style_data->len -= len;
|
|
if (style_data->set)
|
|
mask = word_bits[len];
|
|
else
|
|
mask = 0;
|
|
if (0 == style_data->len)
|
|
{
|
|
style_data->set = !style_data->set;
|
|
if (++style_data->i >= style_data->i_max)
|
|
style_data->i = 0;
|
|
style_data->len = style_array[style_data->i] * STYLE_DENSITY;
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
// Rats! We have to work for this one...
|
|
|
|
mask = 0;
|
|
offset = 0;
|
|
|
|
while (offset < len)
|
|
{
|
|
if (! style_data->set)
|
|
{
|
|
if (style_data->len > len - offset)
|
|
{
|
|
style_data->len -= len - offset;
|
|
return mask & 0x0000ffff;
|
|
}
|
|
|
|
offset += style_data->len;
|
|
style_data->set = TRUE;
|
|
if (++style_data->i >= style_data->i_max)
|
|
style_data->i = 0;
|
|
style_data->len = style_array[style_data->i] * STYLE_DENSITY;
|
|
}
|
|
else
|
|
{
|
|
if (style_data->len > len - offset)
|
|
{
|
|
style_data->len -= len - offset;
|
|
mask |= 0x0000ffff << offset;
|
|
return mask & 0x0000ffff;
|
|
}
|
|
|
|
mask |= word_bits[style_data->len] << offset;
|
|
|
|
offset += style_data->len;
|
|
style_data->set = FALSE;
|
|
if (++style_data->i >= style_data->i_max)
|
|
style_data->i = 0;
|
|
style_data->len = style_array[style_data->i] * STYLE_DENSITY;
|
|
}
|
|
}
|
|
|
|
return mask & 0x0000ffff;
|
|
}
|
|
|
|
/*
|
|
* style_state
|
|
*
|
|
*/
|
|
|
|
ULONG style_state (style_t *style_data)
|
|
{
|
|
ULONG i, whole, fraction;
|
|
ULONG *style_array = (ULONG *)style_data->pla->pstyle;
|
|
|
|
whole = 0;
|
|
for (i = 0; i < style_data->i; i++)
|
|
whole += style_array[i];
|
|
|
|
fraction = (style_array[style_data->i] * STYLE_DENSITY) - style_data->len;
|
|
|
|
return MAKELONG (fraction, whole);
|
|
}
|
|
|
|
|
|
BOOL TGAStyledLines (SURFOBJ *pso,
|
|
POINTFIX *ppta,
|
|
POINTFIX *pptb,
|
|
ULONG count,
|
|
RUN *arun,
|
|
ULONG run_count,
|
|
LINEATTRS *pla,
|
|
ULONG *continue_alias)
|
|
{
|
|
PPDEV ppdev = (PPDEV) pso->dhpdev;
|
|
ULONG start_address; // starting address of 1st pixel in line
|
|
ULONG bytes_per_pixel; // Bytes per pixel
|
|
ULONG base_address; // Base address of frame buffer
|
|
ULONG stride; // Bytes/scanline
|
|
ULONG AbsDx; // Absolute value of delta X
|
|
ULONG AbsDy; // Absolute value of delta Y
|
|
int line_length; // number of pixels along major axis of line
|
|
LONG Dx; // Delta X of line
|
|
LONG Dy; // Delta Y of line
|
|
ULONG line_mask; // which pixels of segment to draw
|
|
int line_offset; // Pixels drawn by initial write
|
|
int x1, y1, x2, y2; // integer endpoints of the line
|
|
ULONG line_no; // line number in polyline
|
|
style_t style_data; // Style state information for the line
|
|
ULONG bres3;
|
|
int e; // initial Bresenham error term
|
|
|
|
DISPDBG ((2, "TGAStyledLines - Entry\n"));
|
|
|
|
// Initialize the information about the frame buffer
|
|
|
|
base_address = SURFOBJ_base_address (pso) - ppdev->pjVideoMemory;
|
|
bytes_per_pixel = SURFOBJ_bytes_per_pixel (pso);
|
|
stride = SURFOBJ_stride (pso);
|
|
|
|
// Initialize the style state we keep
|
|
|
|
style_init (&style_data, pla);
|
|
|
|
// Draw each line of a polyline
|
|
|
|
for (line_no = 0; line_no < count-1; line_no++)
|
|
{
|
|
|
|
// Test for Integer or Floating Point Line
|
|
|
|
if (! ((ppta->x | ppta->y | pptb->x | pptb->y) & 0xF) )
|
|
// Integer Line
|
|
|
|
{
|
|
x1 = (int) (ppta->x >> 4);
|
|
y1 = (int) (ppta->y >> 4);
|
|
x2 = (int) (pptb->x >> 4);
|
|
y2 = (int) (pptb->y >> 4);
|
|
|
|
Dx = x2 - x1;
|
|
Dy = y2 - y1;
|
|
|
|
AbsDx = (Dx < 0) ? -Dx : Dx;
|
|
AbsDy = (Dy < 0) ? -Dy : Dy;
|
|
|
|
// Do out of limits check, and let GDI punt
|
|
if ((AbsDx > 0xFFFF) || (AbsDy > 0xFFFF))
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_limitcheck);
|
|
return (FALSE);
|
|
}
|
|
|
|
// number of pixels in the line
|
|
line_length = (AbsDx > AbsDy) ? AbsDx : AbsDy;
|
|
|
|
// Don't draw a line which is a single point
|
|
// Results are undefined if the AbsDx and AbsDy values are both zero
|
|
|
|
if (line_length == 0)
|
|
goto Next_Segment;
|
|
|
|
line_offset = line_length & 0x0f; // line_length % 16
|
|
if (0 == line_offset)
|
|
line_offset = 16;
|
|
|
|
// Build the initial line mask
|
|
|
|
line_mask = style_mask (&style_data, line_offset);
|
|
|
|
if (line_no == 0)
|
|
CYCLE_REGS (ppdev);
|
|
|
|
// Set the Address Register to the starting address of line
|
|
|
|
start_address = base_address +
|
|
(y1 * stride) +
|
|
(x1 * bytes_per_pixel);
|
|
TGAADDRESS (ppdev, start_address);
|
|
|
|
// Draw first segment of line
|
|
|
|
if (arun == NULL)
|
|
{
|
|
|
|
// Unclipped line
|
|
DISPDBG ((3, "TGAStyledLines - Unclipped Line\n"));
|
|
|
|
// Put the Line Mask into the Data Register
|
|
TGADATA (ppdev, line_mask);
|
|
|
|
// Set the slope register given the TGA card version and Dx,Dy
|
|
|
|
select_slope_register ((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->slope_dx_gt_dy,
|
|
Dx, Dy);
|
|
|
|
// Adjust line for pixels drawn by call to
|
|
// select_slope_register
|
|
|
|
line_length -= line_offset;
|
|
|
|
// Draw second through last segment (16 pixels) of line
|
|
|
|
for (; line_length > 0; line_length -= 16)
|
|
{
|
|
line_mask = style_mask (&style_data, 16);
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
mask_t mask_data;
|
|
|
|
// Clipped line
|
|
|
|
DISPDBG ((3, "TGAStyledLines - Clipped Line\n"));
|
|
|
|
// Initialize clipped line information
|
|
|
|
clip_init (&mask_data, arun, run_count);
|
|
|
|
// Set line mask for first line_offset pixels of line
|
|
// and draw the first segment (1-16 pixels) of the line
|
|
|
|
line_mask &= clipped_mask (line_offset, &mask_data);
|
|
TGADATA (ppdev, line_mask);
|
|
|
|
// Draw first segment (1-16 pixels) of line
|
|
|
|
// Set the slope register given the TGA card version and Dx,Dy
|
|
|
|
select_slope_register ((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->slope_dx_gt_dy,
|
|
Dx, Dy);
|
|
|
|
// Adjust line for pixels drawn by call to
|
|
// select_slope_register
|
|
|
|
line_length -= line_offset;
|
|
|
|
// Draw second through last segment (16 pixels per segment)
|
|
// of line
|
|
|
|
for (; line_length > 0; line_length -= 16)
|
|
{
|
|
line_mask = style_mask (&style_data, 16);
|
|
line_mask &= clipped_mask (16, &mask_data);
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
}
|
|
|
|
} // arun != NULL
|
|
|
|
} // integer line
|
|
else
|
|
{
|
|
// non-integer (Floating point) line
|
|
|
|
// Compute slope register number
|
|
|
|
Dx = pptb->x - ppta->x;
|
|
Dy = pptb->y - ppta->y;
|
|
|
|
AbsDx = (Dx < 0) ? -Dx : Dx;
|
|
AbsDy = (Dy < 0) ? -Dy : Dy;
|
|
|
|
// Do out of limits check, and let GDI punt
|
|
if ((AbsDx > 0xFFFF) || (AbsDy > 0xFFFF))
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_limitcheck);
|
|
return (FALSE);
|
|
}
|
|
|
|
// Set the slope register given the card version and Dx,Dy
|
|
|
|
select_slope_register ((TGA_PASS_2 == ppdev->ulTgaVersion),
|
|
ppdev,
|
|
&ppdev->TGAReg->sng_dx_gt_dy,
|
|
Dx, Dy);
|
|
|
|
// Convert to GIQ start points and get line length
|
|
convert_to_giq( ppta, pptb, &x1, &y1, &line_length, &e );
|
|
|
|
|
|
// Don't draw a line which is a single point
|
|
// Results are undefined if the AbsDx and AbsDy values are both zero
|
|
if (line_length == 0)
|
|
goto Next_Segment;
|
|
|
|
line_offset = line_length & 0x0f; // line_length % 16
|
|
if (0 == line_offset)
|
|
line_offset = 16;
|
|
|
|
// Build the initial line mask
|
|
|
|
line_mask = style_mask (&style_data, line_offset);
|
|
|
|
CYCLE_REGS (ppdev);
|
|
|
|
|
|
// Set the Address Register to the starting address of line
|
|
|
|
start_address = base_address +
|
|
(y1 * stride) +
|
|
(x1 * bytes_per_pixel);
|
|
TGAADDRESS (ppdev, start_address);
|
|
|
|
|
|
// Draw first segment of line
|
|
// Determine the octant the line is in and
|
|
// write to appropriate slope register to intiate drawing
|
|
// There is a slope register corresponding to each octant
|
|
// of the cartesian coordinate system
|
|
|
|
if (arun == NULL)
|
|
{
|
|
|
|
// Unclipped line
|
|
DISPDBG ((3, "TGAStyledLines - Float - Unclipped Line\n"));
|
|
|
|
// Put the Line Mask into the Data Register
|
|
|
|
bres3 = (e << 15) | line_length;
|
|
TGABRES3 (ppdev, bres3);
|
|
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
|
|
|
|
// Adjust line for pixels drawn by call to
|
|
// select_slope_register
|
|
|
|
line_length -= line_offset;
|
|
|
|
for (; line_length > 0; line_length -= 16)
|
|
{
|
|
line_mask = style_mask (&style_data, 16);
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
mask_t mask_data;
|
|
|
|
// Clipped line
|
|
|
|
DISPDBG ((3, "TGAStyledLines - Float - Clipped Line\n"));
|
|
|
|
// Initialize clipped line information
|
|
|
|
clip_init (&mask_data, arun, run_count);
|
|
|
|
// Draw first segment (1-16 pixels) of line
|
|
|
|
line_mask &= clipped_mask (line_offset, &mask_data);
|
|
|
|
bres3 = (e << 15) | line_length;
|
|
TGABRES3 (ppdev, bres3);
|
|
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
|
|
// Adjust line for pixels drawn by call to select_slope_register
|
|
|
|
line_length -= line_offset; // only draws fraction segment
|
|
|
|
// Draw second through last segment (16 pixels per segment)
|
|
// of line
|
|
|
|
for (; line_length > 0; line_length -= 16)
|
|
{
|
|
line_mask = style_mask (&style_data, 16);
|
|
line_mask &= clipped_mask (16, &mask_data);
|
|
CYCLE_REGS (ppdev);
|
|
TGABRESCONTINUE (ppdev, line_mask);
|
|
}
|
|
|
|
} // arun != NULL
|
|
|
|
} // floating point line
|
|
|
|
Next_Segment:
|
|
|
|
// Update pointers to next line
|
|
|
|
ppta = pptb;
|
|
pptb++;
|
|
|
|
} // End for each line
|
|
|
|
// Update the style state that Windows keeps
|
|
|
|
pla->elStyleState.l = style_state (&style_data);
|
|
|
|
DISPDBG ((2, "TGAStyledLines - Exit\n"));
|
|
|
|
return TRUE;
|
|
|
|
} // End of function TGAStyledLines
|
|
|
|
|
|
/*
|
|
* dump_stroke
|
|
*
|
|
* This routine dumps information about a DrvStrokePath call
|
|
* so we can analyze cases of strokePath that we don't handle
|
|
*
|
|
*/
|
|
VOID dump_stroke (SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
LINEATTRS *pla,
|
|
MIX mix)
|
|
{
|
|
#ifndef TEST_ENV
|
|
DISPDBG ((0, "Clip Object: \n"));
|
|
DumpCLIPOBJ (pco);
|
|
DISPDBG ((0, "Brush: \n"));
|
|
DumpBRUSHOBJ (pbo);
|
|
DISPDBG ((0, "Brush Origin: \n"));
|
|
DumpPOINTL (pptlBrushOrg);
|
|
DISPDBG ((0, "Line Attributes: \n"));
|
|
DumpLINEATTRS (pla);
|
|
DISPDBG ((0, "Mix: %8x\n", mix));
|
|
DumpPATHOBJ (ppo);
|
|
#endif
|
|
} // End routine dump_stroke
|
|
|
|
// For lines use transparent-line mode and set line mask to pattern,
|
|
// background and pixel mask registers are not used for transparent lines
|
|
|
|
BOOL TGAStrokePath (SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
LINEATTRS *pla,
|
|
MIX mix)
|
|
{
|
|
ULONG rasterop; // TGA raster operation register
|
|
ULONG mode; // TGA mode register
|
|
LONG bwidth; // TGA Bresenham width register
|
|
BOOL morePts; // More path data records
|
|
PATHDATA pd; // path data record
|
|
ULONG color; // color index
|
|
POINTFIX firstpt; // first point in subpath
|
|
POINTFIX lastpt; // last point in previous path data record
|
|
PPDEV ppdev = (PPDEV) pso->dhpdev;
|
|
CL cl; // Clip line + some number of runs
|
|
ULONG fg_mix; // Holds the foreground mix value
|
|
static ULONG *continue_alias;
|
|
DRAWFUNC linetypeFunc; // which line type call
|
|
|
|
DISPDBG ((2, "TGAStrokePath - Entry\n"));
|
|
|
|
WBFLUSH(ppdev);
|
|
|
|
#ifdef CONT_ALIAS
|
|
// first word in AltROMSpace plus 512K is the start of the
|
|
// contiguous Bresenham Continuation Register aliases
|
|
continue_alias = (ULONG *)((BYTE *)(ppdev->TGAReg) -
|
|
TGA_REGISTER_OFFSET + 0x80000);
|
|
#else
|
|
continue_alias = NULL;
|
|
#endif
|
|
|
|
// Set the foreground register. We already checked to make sure that
|
|
// this is a solid color
|
|
|
|
color = pbo->iSolidColor;
|
|
if (BMF_8BPP == SURFOBJ_format (pso))
|
|
{
|
|
color |= color << 8;
|
|
color |= color << 16;
|
|
}
|
|
else
|
|
color &= 0x00ffffff;
|
|
TGAFOREGROUND (ppdev, color);
|
|
|
|
// Set the plane mask to write to all planes
|
|
// This should only need to be set once but removing it caused problems,
|
|
// take out at your own risk!
|
|
|
|
fg_mix = mix & 0x00ff;
|
|
if ((fg_mix < 1) || (fg_mix > R2_LAST))
|
|
fg_mix = R2_COPYPEN;
|
|
|
|
TGAPLANEMASK (ppdev, ppdev->ulPlanemaskTemplate);
|
|
|
|
// Set mode to transparent-line mode. For some reason, only 8 bit source
|
|
// works on 24 plane boards.
|
|
|
|
ppdev->bSimpleMode = FALSE;
|
|
|
|
mode = TGA_MODE_TRANSPARENT_LINE |
|
|
TGA_MODE_VISUAL_8_PACKED |
|
|
TGA_MODE_ROTATE_0_BYTES |
|
|
TGA_MODE_WIN32_ENVIRONMENT |
|
|
TGA_MODE_Z_24BITS |
|
|
TGA_MODE_CAPENDS_DISABLE;
|
|
TGAMODE (ppdev, mode);
|
|
|
|
// Set the raster operation. We only worry about the forground
|
|
// portion of the MIX.
|
|
|
|
rasterop = ppdev->ulRopTemplate | mix_to_rop [fg_mix];
|
|
TGAROP (ppdev, rasterop);
|
|
|
|
// Set the Breshenham Width register. This must the the screen width
|
|
|
|
bwidth = SURFOBJ_stride (pso) / SURFOBJ_bytes_per_pixel (pso);
|
|
if (TGA_PASS_2 == ppdev->ulTgaVersion)
|
|
bwidth = - bwidth;
|
|
bwidth &= 0x0000ffff;
|
|
TGABRESWIDTH (ppdev, bwidth);
|
|
|
|
// Setup the function prototype for regular or styled line
|
|
|
|
if (NULL == pla->pstyle)
|
|
linetypeFunc = TGALines;
|
|
else
|
|
linetypeFunc = TGAStyledLines;
|
|
|
|
if (pco->iDComplexity == DC_TRIVIAL)
|
|
{
|
|
// Unclipped polyline
|
|
PATHOBJ_vEnumStart (ppo);
|
|
do
|
|
{
|
|
morePts = PATHOBJ_bEnum(ppo, &pd); // Get a path-data record
|
|
|
|
if (pd.count <= 0)
|
|
continue;
|
|
|
|
if (pd.flags & PD_BEGINSUBPATH)
|
|
{
|
|
// the first point in the array begins a new subpath
|
|
firstpt = *pd.pptfx;
|
|
|
|
if (pd.flags & PD_RESETSTYLE)
|
|
{
|
|
// reset line style state (only set on begin_subpath)
|
|
DISPDBG ((3, " Reset \n"));
|
|
pla->elStyleState.l = 0;
|
|
}
|
|
|
|
// Draw the polyline
|
|
|
|
if (! (*linetypeFunc) (pso, pd.pptfx, pd.pptfx+1, pd.count,
|
|
(RUN*) NULL, 0, pla, continue_alias))
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// The last point from the previous record connects to the
|
|
// first point in this record
|
|
// Draw the polyline
|
|
|
|
if (! (*linetypeFunc) (pso, &lastpt, pd.pptfx, pd.count+1,
|
|
(RUN*) NULL, 0, pla, continue_alias))
|
|
return FALSE;
|
|
}
|
|
|
|
// Save last point in data record since it may
|
|
// connect to the next data record
|
|
lastpt = pd.pptfx[pd.count-1];
|
|
|
|
// does the last point in the array end the subpath and
|
|
// close the figure
|
|
if ((pd.flags & PD_ENDSUBPATH) && (pd.flags & PD_CLOSEFIGURE))
|
|
{
|
|
if (! (*linetypeFunc) (pso, &lastpt, &firstpt, 2,
|
|
(RUN*) NULL, 0, pla, continue_alias))
|
|
return FALSE;
|
|
}
|
|
} while (morePts);
|
|
} // End of if (unclipped polyline)
|
|
|
|
// This case may be used later for a timing improvement
|
|
|
|
//else (if pco-iDComplexity == DC_RECT)
|
|
//{
|
|
//}
|
|
else
|
|
{
|
|
// Clipped polyline
|
|
// (pco->iDComplexity == DC_COMPLEX))
|
|
// Clip to a single rectangle or clip region must be enumerated
|
|
|
|
PATHOBJ_vEnumStartClipLines (ppo, pco, pso, pla);
|
|
|
|
// Draw the clipped polyine
|
|
do
|
|
{
|
|
morePts = PATHOBJ_bEnumClipLines (ppo, sizeof(cl), &cl.cl);
|
|
if (cl.cl.c <= 0) // number of runs
|
|
continue;
|
|
|
|
// Set the StyleState field to value returned from
|
|
// PATHOBJ_bEnumClipLines, use pla structure because
|
|
// it's already begin passed to TGALines/StyledLines.
|
|
|
|
pla->elStyleState.l = cl.cl.lStyleState;
|
|
|
|
// Draw the line
|
|
|
|
if (! (*linetypeFunc) (pso, &cl.cl.ptfxA, &cl.cl.ptfxB, 2,
|
|
&cl.cl.arun[0], cl.cl.c,pla, continue_alias))
|
|
return FALSE;
|
|
} while (morePts);
|
|
|
|
} // End of clipped polyline
|
|
|
|
DISPDBG ((2, "TGAStrokePath - Exit\n"));
|
|
|
|
return TRUE;
|
|
|
|
} // End of function TGAStrokePath
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
* DrvStrokePath - This routine is called by GDI to draw lines
|
|
*/
|
|
|
|
BOOL DrvStrokePath (SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
LINEATTRS *pla,
|
|
MIX mix)
|
|
{
|
|
BOOL status;
|
|
#ifndef TEST_ENV
|
|
PPDEV ppdev = (PPDEV) pso->dhpdev;
|
|
#endif // TEST_ENV
|
|
|
|
DISPDBG ((1, "DrvStrokePath - Entry\n"));
|
|
|
|
BUMP_TGA_STAT(pStats->lines);
|
|
|
|
#if 0
|
|
if (DebugLevel)
|
|
dump_stroke (pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix);
|
|
#endif
|
|
|
|
// If the line attributes are abnormal punt the line drawing back to GDI
|
|
|
|
#ifdef TGA_STATS
|
|
if (pla->elWidth.l != 1)
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_width_ne_1);
|
|
}
|
|
else if (pla->fl & LA_GEOMETRIC)
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_la_geometric);
|
|
}
|
|
else if (pbo->iSolidColor == 0xffffffff)
|
|
{
|
|
BUMP_TGA_STAT(pStats->linepunts_solidcolor);
|
|
}
|
|
#endif
|
|
|
|
if ((pla->elWidth.l != 1) ||
|
|
(pla->fl & LA_GEOMETRIC) ||
|
|
// (pbo->iSolidColor == 0) || // Debugging hack for GDI Demo lines
|
|
(pbo->iSolidColor == 0xffffffff))
|
|
|
|
// GDI handles the line drawing
|
|
status = PuntStrokePath (pso, ppo, pco, pxo, pbo, pptlBrushOrg,
|
|
pla, mix);
|
|
else
|
|
{
|
|
#if defined(_ALPHA_)
|
|
|
|
// TGA handles the line drawing
|
|
status = TGAStrokePath (pso, ppo, pco, pxo, pbo, pptlBrushOrg,
|
|
pla, mix);
|
|
if (! status)
|
|
#endif
|
|
status = PuntStrokePath (pso, ppo, pco, pxo, pbo, pptlBrushOrg,
|
|
pla, mix);
|
|
}
|
|
|
|
// Check whether or not we have to leave TGA in simple mode
|
|
|
|
#ifndef TEST_ENV
|
|
if (ppdev->bInPuntRoutine)
|
|
vSetSimpleMode (ppdev);
|
|
#endif // TEST_ENV
|
|
|
|
DISPDBG ((1, "DrvStrokePath - Exit\n"));
|
|
|
|
return status;
|
|
|
|
} // End of function DrvStrokePath
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
/*
|
|
* This routine sets the outcode for a specified 2D point and clip-box.
|
|
* The Cohen-Sutherland clipping algorithm is used here.
|
|
*/
|
|
void outcodes (float x1, float y1,
|
|
float xmin, float xmax, float ymin, float ymax,
|
|
BOOL *outcode)
|
|
{
|
|
outcode[0] = y1 < ymin; // point is above clip-box
|
|
outcode[1] = y1 > ymax; // point is below clip-box
|
|
outcode[2] = x1 > xmax; // point is right of clip-box
|
|
outcode[3] = x1 < xmin; // point is left of clip-box
|
|
|
|
} /* end of routine outcodes */
|
|
|
|
#endif
|
|
|
|
/*
|
|
* This routine returns TRUE if line is completely outside the clip-box
|
|
*/
|
|
BOOL reject_check (BOOL *outcode1, BOOL *outcode2)
|
|
{
|
|
return ((outcode1[0] && outcode2[0]) || // line is above clip-box
|
|
(outcode1[1] && outcode2[1]) || // line is below clip-box
|
|
(outcode1[2] && outcode2[2]) || // line is right of clip-box
|
|
(outcode1[3] && outcode2[3])); // line is left of clip-box
|
|
|
|
} /* end of routine reject_check */
|
|
|
|
|
|
/*
|
|
* This routine returns TRUE if the line is completely within clip box
|
|
*/
|
|
BOOL accept_check (BOOL *outcode1, BOOL *outcode2)
|
|
{
|
|
return !(outcode1[0] || outcode2[0] || // start or end point above clip-box
|
|
outcode1[1] || outcode2[1] || // start or end point below clip-box
|
|
outcode1[2] || outcode2[2] || // start or end point right of clip-box
|
|
outcode1[3] || outcode2[3]); // start or end point left of clip-box
|
|
|
|
} /* end of routine accept_check */
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
/*
|
|
* This routine clips a 2D point to be within the limits of TGA;
|
|
* unsigned 16-bit integers (0x0 - 0xFFFF)
|
|
* The Cohen-Sutherland clipping algorithm is used.
|
|
*/
|
|
BOOL TGAclipper (float *px1, float *py1, float *px2, float *py2,
|
|
float *clip_offset)
|
|
{
|
|
float xmin = 0.0F; // 0x0 - smallest point TGA can handle
|
|
float xmax = 65535.0F; // 0xFFFF - largest point TGA can handle
|
|
float ymin = 0.0F; // 0x0 - smallest point TGA can handle
|
|
float ymax = 65535.0F; // 0xFFFF - largest point TGA can handle
|
|
BOOL accept = FALSE; // line is completely inside clip-box
|
|
BOOL reject = FALSE; // line is completely outside clip-box
|
|
BOOL done = FALSE;
|
|
BOOL outcode1[4]; // above, below, right, left codes for start pt
|
|
BOOL outcode2[4]; //above, below, right, left codes for end point
|
|
float x1;
|
|
float y1;
|
|
float x2;
|
|
float y2;
|
|
BOOL clip_adjust = FALSE;
|
|
float clip_offset_x;
|
|
float clip_offset_y;
|
|
|
|
DISPDBG ((2, "TGAClipper - Entry \n"));
|
|
|
|
x1 = *px1;
|
|
y1 = *py1;
|
|
x2 = *px2;
|
|
y2 = *py2;
|
|
|
|
do
|
|
{
|
|
outcodes (x1, y1, xmin, xmax, ymin, ymax, outcode1);
|
|
outcodes (x2, y2, xmin, xmax, ymin, ymax, outcode2);
|
|
|
|
reject = reject_check (outcode1, outcode2);
|
|
|
|
if (reject)
|
|
/* line is outside clip-box */
|
|
done = TRUE;
|
|
else
|
|
{ /* possible accept */
|
|
accept = accept_check (outcode1, outcode2);
|
|
if (accept)
|
|
done = TRUE;
|
|
else
|
|
{ /* subdivide line since at most one endpoint is inside */
|
|
if (outcode1[0] || outcode1[1] || outcode1[2] || outcode1[3])
|
|
{
|
|
/* Now perform a subdivision, move P1 to the intersection point */
|
|
/* use the formulas: */
|
|
/* y = y1 + slope * (x - x1) */
|
|
/* x = x1 + (1/slope) * (y - y1) */
|
|
if (outcode1[0])
|
|
{ /* divide line at top of window */
|
|
x1 += (x2 - x1) * (ymin - y1) / (y2 - y1);
|
|
y1 = ymin;
|
|
}
|
|
else if (outcode1[1])
|
|
{ /* divide line at bottom of window */
|
|
x1 += (x2 - x1) * (ymax - y1) / (y2 - y1);
|
|
y1 = ymax;
|
|
}
|
|
else if (outcode1[2])
|
|
{ /* divide line at right of window */
|
|
y1 += (y2 - y1) * (xmax - x1) / (x2 - x1);
|
|
x1 = xmax;
|
|
}
|
|
else if (outcode1[3])
|
|
{ /* divide line at left of window */
|
|
y1 += (y2 - y1) * (xmin - x1) / (x2 - x1);
|
|
x1 = xmin;
|
|
}
|
|
clip_adjust = TRUE;
|
|
}
|
|
else
|
|
{ /* SWAP */
|
|
/* Now perform a subdivision, move P2 to the intersection point */
|
|
/* use the formulas: */
|
|
/* y = y2 + slope * (x - x2) */
|
|
/* x = x2 + (1/slope) * (y - y2) */
|
|
if (outcode2[0])
|
|
{ /* divide line at top of window */
|
|
x2 += (x1 - x2) * (ymin - y2) / (y1 - y2);
|
|
y2 = ymin;
|
|
}
|
|
else if (outcode2[1])
|
|
{ /* divide line at bottom of window */
|
|
x2 += (x1 - x2) * (ymax - y2) / (y1 - y2);
|
|
y2 = ymax;
|
|
}
|
|
else if (outcode2[2])
|
|
{ /* divide line at right of window */
|
|
y2 += (y1 - y2) * (xmax - x2) / (x1 - x2);
|
|
x2 = xmax;
|
|
}
|
|
else if (outcode2[3])
|
|
{ /* divide line at left of window */
|
|
y2 += (y1 - y2) * (xmin - x2) / (x1 - x2);
|
|
x2 = xmin;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (!done);
|
|
|
|
if (clip_adjust)
|
|
{
|
|
clip_offset_x = *px1 - x1;
|
|
if (clip_offset_x < 0)
|
|
clip_offset_x = -clip_offset_x;
|
|
clip_offset_y = *py1 - y1;
|
|
if (clip_offset_y < 0)
|
|
clip_offset_y = -clip_offset_y;
|
|
if (clip_offset_x >= clip_offset_y)
|
|
*clip_offset = clip_offset_x;
|
|
else
|
|
*clip_offset = clip_offset_y;
|
|
}
|
|
else
|
|
*clip_offset = 0.0F;
|
|
|
|
*px1 = x1;
|
|
*py1 = y1;
|
|
*px2 = x2;
|
|
*py2 = y2;
|
|
|
|
DISPDBG ((2, "TGAClipper - Exit \n"));
|
|
|
|
return accept;
|
|
|
|
} // End of routine TGAclipper
|
|
|
|
#endif
|