Files
glide/glide2x/cvg/glide/src/gdraw.c

1131 lines
35 KiB
C

/*
** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
**
** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
** THE UNITED STATES.
**
** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
**
** $Header$
** $Log$
** Revision 1.3 2000/01/17 22:18:41 joseph
** A nicer, cleaner fix than the evil hack.
**
** Revision 1.2 2000/01/15 00:08:22 joseph
** Evil nasty hack to fix dispatch code using binutils 2.9.5.
**
** Revision 1.1.1.1 1999/12/07 21:49:10 joseph
** Initial checkin into SourceForge.
**
**
** 98 6/02/98 8:03p Peter
** Mmmmm.... points
**
** 97 6/01/98 6:44p Peter
** snapped/unsnapped points
**
** 96 5/20/98 3:51p Peter
** no fifo glide
**
** 95 5/18/98 12:14p Peter
** better point code
**
** 94 2/20/98 11:00a Peter
** removed glide3 from glid2 tree
**
** 93 2/11/98 5:23p Peter
** workaround for tombraider rgb > 255.0
*
* 92 1/15/98 2:46p Atai
* fixed grDrawPoint and grDrawLine in aa mode
*
* 90 12/17/97 4:45p Peter
* groundwork for CrybabyGlide
*
* 89 12/15/97 5:52p Atai
* disable obsolete glide2 api for glide3
*
* 85 12/08/97 12:06p Atai
* change prototype for grDrawPoint, grDrawLine, grDrawTriangel
*
* 83 11/21/97 6:05p Atai
* use one datalist (tsuDataList) in glide3
*
* 82 11/21/97 3:20p Peter
* direct writes tsu registers
*
* 81 11/19/97 4:33p Atai
* make vSize debug variable
*
* 80 11/18/97 4:36p Peter
* chipfield stuff cleanup and w/ direct writes
*
* 79 11/17/97 4:55p Peter
* watcom warnings/chipfield stuff
*
* 78 11/16/97 2:20p Peter
* cleanup
*
* 77 11/15/97 7:43p Peter
* more comdex silliness
*
**
*/
#include <memory.h>
#include <3dfx.h>
#define FX_DLL_DEFINITION
#include <fxdll.h>
#include <glide.h>
#include "fxglide.h"
#if GLIDE_DISPATCH_SETUP
#include "fxinline.h"
#endif
#define SST_XY_HALF (1 << (SST_XY_FRACBITS - 1))
#define SST_XY_ONE (1 << SST_XY_FRACBITS)
#define OUTBOUNDSX(a) ((a->x < 0.f ? 1 : 0) || (a->x > gc->state.screen_width ? 1 : 0))
#define OUTBOUNDSY(a) ((a->y < 0.f ? 1 : 0) || (a->y > gc->state.screen_height ? 1 : 0))
#define OUTBOUNDS(a) (OUTBOUNDSX(a) || OUTBOUNDSY(a))
/*---------------------------------------------------------------------------
** grDrawPoint
*/
GR_ENTRY(grDrawPoint, void, (const GrVertex *p))
{
#define FN_NAME "grDrawPoint"
FxU32 x, y;
GR_BEGIN_NOFIFOCHECK(FN_NAME, 90);
GDBG_INFO_MORE(gc->myLevel, "(0x%X) : (%f %f)\n", p, p->x, p->y);
GR_FLUSH_STATE();
/* we snap to an integer by adding a large enough number that it
* shoves all fraction bits off the right side of the mantissa.
*
* NB: IEEE rounds to nearest integer by default, but applications
* can change the rounding mode so that it is difficult to get the
* correct truncation/ceiling operation w/ a simple adjustment to
* the bias.
*
* NB: The constant kNumMantissaBits defines how many bits of
* integer precision a coordinate can have. This needs to be atleast
* as large as the maximum hw screen resolution. We later use this
* to compute a logical 1/2 value to fill an entire pixel.
*/
#define kNumMantissaBits 18UL
{
const float bias = (const float)(3UL << kNumMantissaBits);
/* Convert to 32-bit representation */
#define FP_TRUNC_BIAS(__fpVal, __fpBias) \
((__fpVal) < (__fpBias) ? (float)((__fpVal) + (__fpBias)) : (__fpVal))
_GlideRoot.pool.ftemp1 = FP_TRUNC_BIAS(p->x, bias);
_GlideRoot.pool.ftemp2 = FP_TRUNC_BIAS(p->y, bias);
/* Mask off the real fractional bits from the mantissa */
x = ((*(FxU32*)&_GlideRoot.pool.ftemp1 & (0xFFFFFFFFUL << (22UL - kNumMantissaBits))) +
(0x01UL << (22UL - kNumMantissaBits)));
y = ((*(FxU32*)&_GlideRoot.pool.ftemp2 & (0xFFFFFFFFUL << (22UL - kNumMantissaBits))) +
(0x01UL << (22UL - kNumMantissaBits)));
}
/* draw a little triangle, with the lower left corner at pixel center. */
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
/* The approach here is to split the triangle into two packets, one
* that sends just the coordinates of the last two points of the
* triangle w/ no other parameter information, and then the
* centered point w/ all of the parameter information. The first
* packet is has a BDD command, but is incomplete, so nothing
* draws, the next packet has a DDD command so will complete the
* triangle from the first packet sent.
*/
GR_SET_EXPECTED_SIZE((sizeof(FxU32) << 2) + /* Size of Initial coordinate packet */
_GlideRoot.curVertexSize, /* The full coordinate vertex */
2); /* We do two split packets */
TRI_PACKET_BEGIN(kSetupStrip | kSetupCullDisable, 0x00,
0x02, sizeof(FxU32) << 1, SSTCP_PKT3_BDDDDD);
{
/* Lower right corner */
TRI_SET(x);
TRI_SET(y);
/* Upper right corner. */
y -= (0x01UL << (21UL - kNumMantissaBits));
TRI_SET(x);
TRI_SET(y);
/* Upper Left corner */
x -= (0x01UL << (21UL - kNumMantissaBits));
}
TRI_END;
/* Packet w/ actual point coordinate and parameter data */
TRI_PACKET_BEGIN(kSetupStrip | kSetupCullDisable, gc->cmdTransportInfo.paramMask,
1, _GlideRoot.curVertexSize, SSTCP_PKT3_DDDDDD);
{
TRI_SET(x);
TRI_SET(y);
/* Vertex parameters */
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
if ((gc->cmdTransportInfo.paramMask & SSTCP_PKT3_PACKEDCOLOR) != 0) {
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(p, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(p, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(p, (GR_VERTEX_R_OFFSET << 2)), R));
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(p, (GR_VERTEX_A_OFFSET << 2)), A);
dataList++;
}
TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(p, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while(*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(p, *dataList));
dataList++;
}
}
}
TRI_END;
GR_CHECK_SIZE();
_GlideRoot.stats.pointsDrawn++;
#else /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
/* GMT: gross overestimate of fifo requirements */
GR_SET_EXPECTED_SIZE(_GlideRoot.curTriSize, _GlideRoot.curTriSize >> 2);
{
const struct dataList_s* dlp = gc->regDataList;
int i;
#ifdef GLIDE_USE_ALT_REGMAP
hw = SST_WRAP(hw,128); /* use alternate register mapping */
#endif
GR_SET(BROADCAST_ID, hw, FvA.x, x);
GR_SET(BROADCAST_ID, hw, FvA.y, y);
x += (0x01UL << (22UL - kNumMantissaBits));
GR_SET(BROADCAST_ID, hw, FvB.x, x);
GR_SET(BROADCAST_ID, hw, FvB.y, y);
y += (0x01UL << (22UL - kNumMantissaBits));
GR_SET(BROADCAST_ID, hw, FvC.x, x);
GR_SET(BROADCAST_ID, hw, FvC.y, y);
i = _GlideRoot.stats.pointsDrawn++;
_GlideRoot.stats.pointsDrawn = ++i;
dlp = gc->regDataList;
i = dlp->i;
/* we don't care what the slopes are because the pixel center that is drawn */
/* is exactly at vertex A - isn't that wonderful */
while (i) {
GR_SETF_INDEX(BROADCAST_ID, hw, ((FxU32*)dlp->addr - (FxU32*)hw), FARRAY(p,i));
dlp++;
i = dlp->i;
}
GR_SET(BROADCAST_ID, hw, triangleCMD, 1);
}
GR_CHECK_SIZE();
#endif /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
GR_END();
#undef FN_NAME
} /* grDrawPoint */
/*---------------------------------------------------------------------------
** grDrawLine
**
** NOTE: 1. this will not fill the last pixel in line because
** B2 or C is on the right edge and the right edge is not
** drawn.
** (0,0)
**
** A(x1,y1-0.5)+
** | \
** | \ \
** (x1,y1)* \
** | * \
** | *\ \
** B1(x1,y1+0.5)+ * \
** \ \ * +B2(x2,y2-0.5)
** \ * |
** \ \ * |
** \ \ + (x2,y2)
** \ |
** \ |
** +C(x2,y2+0.5)
*/
GR_ENTRY(grDrawLine, void, (const GrVertex *a, const GrVertex *b))
{
#define FN_NAME "grDrawLine"
int i, j;
#define DX _GlideRoot.pool.ftemp1
#define ADY _GlideRoot.pool.ftemp2
GR_BEGIN_NOFIFOCHECK("grDrawLine", 91);
GDBG_INFO_MORE(gc->myLevel, "A: (%f %f) B: (%f %f)\n",
a->x, a->y, b->x, b->y);
GR_FLUSH_STATE();
/*
** compute absolute deltas and draw from low Y to high Y
*/
ADY = b->y - a->y;
i = *(long *)&ADY;
if (i < 0) {
const GrVertex *tv;
tv = a; a = b; b = tv;
i ^= 0x80000000; /* ady = -ady; */
(*(long *)&ADY) = i;
}
DX = b->x - a->x;
j = *(long *)&DX;
if (j < 0) {
j ^= 0x80000000; /* adx = -adx; */
}
/* check for zero-length lines */
if ((j >= i) && (j == 0)) goto all_done;
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
/* One packet w/ 4 vertices */
GR_SET_EXPECTED_SIZE((_GlideRoot.curVertexSize << 2), 1);
{
const float* const fa = (float*)a;
const float* const fb = (float*)b;
/* Draw the triangle pair as a strip of 4 vertices.
* We can skip all of the gradient calculation stuff.
*
* NB: There are two cases, x/y major lines, and each of these
* loops are unrolled to send one set of endpoints of the 'line'
* per iteration since we can use the same bias per iteration.
*/
TRI_PACKET_BEGIN(kSetupCullDisable | kSetupStrip, gc->cmdTransportInfo.paramMask,
0x04UL, _GlideRoot.curVertexSize, SSTCP_PKT3_BDDDDD);
{
float fBias = - _GlideRoot.pool.fHalf;
int vIndex;
/* x macjor */
if (j >= i) {
for(vIndex = 0; vIndex < 2; vIndex++) {
TRI_SETF(fb[GR_VERTEX_X_OFFSET]);
TRI_SETF(fb[GR_VERTEX_Y_OFFSET] + fBias);
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
if ((gc->cmdTransportInfo.paramMask & SSTCP_PKT3_PACKEDCOLOR) != 0) {
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_R_OFFSET << 2)), R));
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_A_OFFSET << 2)), A);
dataList++;
}
TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(fb, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while(*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(fb, *dataList));
dataList++;
}
}
TRI_SETF(fa[GR_VERTEX_X_OFFSET]);
TRI_SETF(fa[GR_VERTEX_Y_OFFSET] + fBias);
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
if ((gc->cmdTransportInfo.paramMask & SSTCP_PKT3_PACKEDCOLOR) != 0) {
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_R_OFFSET << 2)), R));
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_A_OFFSET << 2)), A);
dataList++;
}
TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(fa, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while (*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(fa, *dataList));
dataList++;
}
}
fBias *= -1.0f;
}
} else { /* y major */
for(vIndex = 0; vIndex < 2; vIndex++) {
TRI_SETF(fb[GR_VERTEX_X_OFFSET] + fBias);
TRI_SETF(fb[GR_VERTEX_Y_OFFSET]);
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
if ((gc->cmdTransportInfo.paramMask & SSTCP_PKT3_PACKEDCOLOR) != 0) {
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_R_OFFSET << 2)), R));
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(fb, (GR_VERTEX_A_OFFSET << 2)), A);
dataList++;
}
TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(fb, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while (*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(fb, *dataList));
dataList++;
}
}
TRI_SETF(fa[GR_VERTEX_X_OFFSET] + fBias);
TRI_SETF(fa[GR_VERTEX_Y_OFFSET]);
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
if ((gc->cmdTransportInfo.paramMask & SSTCP_PKT3_PACKEDCOLOR) != 0) {
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_R_OFFSET << 2)), R));
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(fa, (GR_VERTEX_A_OFFSET << 2)), A);
dataList++;
}
TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(fa, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while (*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(fa, *dataList));
dataList++;
}
}
fBias *= -1.0f;
}
}
}
TRI_END;
}
GR_CHECK_SIZE();
#else /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
#ifdef GLIDE_USE_ALT_REGMAP
hw = SST_WRAP(hw,128); /* use alternate register mapping */
#endif
GR_SET_EXPECTED_SIZE(12 + _GlideRoot.curTriSize, (_GlideRoot.curTriSize + 12) >> 2);
{
float m, dp;
struct dataList_s* dlp;
/*
** X major line
*/
if (j >= i) { /* if (adx > ady) */
if (j == 0) goto all_done; /* check for zero-length lines */
/* start up divide and overlap with as much integer stuff as possible*/
m = _GlideRoot.pool.f1 / DX;
dlp = gc->regDataList;
GR_SETF(BROADCAST_ID, hw, FvA.x, a->x);
dp = b->x;
GR_SETF(BROADCAST_ID, hw, FvB.x, dp);
GR_SETF(BROADCAST_ID, hw, FvC.x, dp);
GR_SETF(BROADCAST_ID, hw, FvA.y, a->y - _GlideRoot.pool.fHalf);
dp = b->y;
GR_SETF(BROADCAST_ID, hw, FvB.y, dp - _GlideRoot.pool.fHalf);
i = dlp->i;
GR_SETF(BROADCAST_ID, hw, FvC.y, dp + _GlideRoot.pool.fHalf);
while (i) {
dp = FARRAY(a,i);
GR_SETF_INDEX(BROADCAST_ID, hw,
((FxU32*)dlp->addr - (FxU32*)hw), dp);
dp = FARRAY(b,i) - dp;
GR_SETF_INDEX(BROADCAST_ID, hw,
((FxU32*)&dlp->addr[DPDX_OFFSET >> 2] - (FxU32*)hw), dp * m);
dlp++;
i = dlp->i;
GR_SETF_INDEX(BROADCAST_ID, hw,
((FxU32*)&dlp->addr[DPDY_OFFSET >> 2] - (FxU32*)hw), _GlideRoot.pool.f0);
}
GR_SETF(BROADCAST_ID, hw, FtriangleCMD,_GlideRoot.pool.ftemp1);
GR_SETF(BROADCAST_ID, hw, FvB.x,a->x);
GR_SETF(BROADCAST_ID, hw, FvB.y,a->y + _GlideRoot.pool.fHalf);
GR_SETF(BROADCAST_ID, hw, FtriangleCMD,-_GlideRoot.pool.ftemp1);
}
/*
** Y major line
*/
else {
m = _GlideRoot.pool.f1 / ADY;
dlp = gc->regDataList;
GR_SETF(BROADCAST_ID, hw, FvA.y,a->y);
dp = b->y;
GR_SETF(BROADCAST_ID, hw, FvB.y,dp);
GR_SETF(BROADCAST_ID, hw, FvC.y,dp);
GR_SETF(BROADCAST_ID, hw, FvA.x,a->x - _GlideRoot.pool.fHalf);
dp = b->x;
GR_SETF(BROADCAST_ID, hw, FvB.x,dp - _GlideRoot.pool.fHalf);
i = dlp->i;
GR_SETF(BROADCAST_ID, hw, FvC.x,dp + _GlideRoot.pool.fHalf);
while (i) {
dp = FARRAY(a,i);
GR_SETF_INDEX(BROADCAST_ID, hw, ((FxU32*)dlp->addr - (FxU32*)hw), dp);
dp = FARRAY(b,i) - dp;
GR_SETF_INDEX(BROADCAST_ID, hw,
((FxU32*)&dlp->addr[DPDX_OFFSET >> 2] - (FxU32*)hw), _GlideRoot.pool.f0);
dlp++;
i = dlp->i;
GR_SETF_INDEX(BROADCAST_ID, hw,
((FxU32*)&dlp->addr[DPDY_OFFSET >> 2] - (FxU32*)hw), dp * m);
}
GR_SET(BROADCAST_ID, hw, triangleCMD, 0xFFFFFFFF);
GR_SETF(BROADCAST_ID, hw, FvB.x, a->x + _GlideRoot.pool.fHalf);
GR_SETF(BROADCAST_ID, hw, FvB.y, a->y);
GR_SET(BROADCAST_ID, hw, triangleCMD, 1);
}
}
GR_CHECK_SIZE();
#endif /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
all_done: /* come here on degenerate lines */
_GlideRoot.stats.linesDrawn++;
GR_END();
#undef FN_NAME
} /* grDrawLine */
/*---------------------------------------------------------------------------
** grDrawTriangle
*/
GR_ENTRY(grDrawTriangle, void, (const GrVertex *a, const GrVertex *b, const GrVertex *c))
{
#define FN_NAME grDrawTriangle
#if defined(GLIDE_USE_C_TRISETUP) || defined(__WATCOMC__) || defined(GLIDE_DEBUG)
GR_BEGIN_NOFIFOCHECK("grDrawTriangle",92);
GDBG_INFO_MORE(gc->myLevel,"(0x%x,0x%x,0x%x)\n",a,b,c);
GR_CHECK_F(myName, !a || !b || !c, "NULL pointer passed");
GR_FLUSH_STATE();
/* Silly warning killer */
if (0) goto all_done;
#ifdef GLIDE_DEBUG
if (_GlideRoot.environment.triBoundsCheck) {
if (OUTBOUNDS(a) || OUTBOUNDS(b) || OUTBOUNDS(c)) {
GDBG_PRINTF("Triangle out of bounds:\n");
GDBG_PRINTF("a->x = %3.2f, a->y = %3.2f\n", a->x, a->y);
GDBG_PRINTF("b->x = %3.2f, b->y = %3.2f\n", b->x, b->y);
GDBG_PRINTF("c->x = %3.2f, c->y = %3.2f\n", c->x, c->y);
GDBG_PRINTF("Culling triangle based on these bogus values.\n");
goto all_done;
}
}
#endif /* GLIDE_DEBUG */
/* _trisetup and _trisetup_asm return 0 if culled, 1 if drawn */
#if GLIDE_DEBUG && !GLIDE_USE_C_TRISETUP
/* HackAlert: Nuke the fifo ptr checking stuff here if we're just
* debugging teh asm tri code.
*/
if (TRISETUP(a, b, c) != 0) {
gc->checkPtr = (FxU32)gc->cmdTransportInfo.fifoPtr;
gc->checkCounter = 0;
}
#else
TRISETUP(a, b, c);
#endif
all_done:
GR_END();
#else
#if defined(__MSC__)
{
extern struct _GlideRoot_s _GlideRoot;
_asm {
mov eax, [_GlideRoot + kCurGCOffset];
mov eax, [eax + kTriProcOffset];
jmp eax;
}
}
#endif
#if defined( __linux__ )
/* Here's the basic strategy for this dispatch code:
* We jump to _GlideRoot.curGC->archDispatchProcs.triSetupProc
* which contains code that looks like a function, we leave the
* paramters passed to grDrawTriangle on the stack and the dispatched
* function picks them up. However we have to compensate for
* the compiler pushing anything on the stack. The following describes
* why and when we have to pop.
*
* BIG_OPT: gcc pushes a frame pointer to maintain things, BIG_OPT
* turns on -fomit-frame-pointer so we don't have to pop it.
*
* PIC: When using position independant code gcc stores eip in ebx
* so it saves ebx from the previous call automatically.
* Therefore, once we have the jump address we have to pop ebx
* to restore the stack.
*
* The syntax is further complicated by the fact that gcc can (and will)
* emit code between the asm statements, so they all need to be in a single
* asm statement, wrapped with #ifdef's. This means we have fun with
* deciding if we need to list trashed registers and when we need commas
* between them.
*/
asm (
#if defined(PIC)
"popl %%ebx\n\t"
#endif
#if !defined(BIG_OPT)
"popl %%ebp\n\t"
#endif
"jmp *%0"
: /* no outputs */
: "m" (_GlideRoot.curGC->cmdTransportInfo.triSetupProc)
#if defined (PIC) || !defined (BIG_OPT)
:
#endif
#if defined (PIC)
"ebx"
#endif
#if defined (PIC) && !defined (BIG_OPT)
,
#endif
#if !defined(BIG_OPT)
"ebp"
#endif
);
#endif
#endif
#undef FN_NAME
} /* grDrawTriangle */
/*---------------------------------------------------------------------------
** grDrawPlanarPolygon
**
** Brute force "triangle-fan" implementation of a convex polygon drawer.
*/
GR_ENTRY(grDrawPlanarPolygon,
void,
(int nVerts, const int iList[], const GrVertex vList[]))
{
GR_BEGIN_NOFIFOCHECK("grDrawPlanarPolygon",93);
GDBG_INFO_MORE(gc->myLevel,"(%d,0x%x,0x%x)\n",nVerts,iList,vList);
GR_CHECK_F(myName, !iList || !vList, "NULL pointer passed");
GR_FLUSH_STATE();
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
grDrawPolygon(nVerts, iList, vList);
#else /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
{
int n,i = nVerts-2;
const GrVertex *firstv = &vList[iList[0]];
for (i = 1; i < nVerts - 1; i++) {
n = TRISETUP(firstv, &vList[iList[i]], &vList[iList[i+1]]);
if (n > 0) break; /* stop after 1st non-zero-area triangle */
if (n < 0) goto all_done;
}
/* now all the gradients are loaded into the chip, so we just have to */
/* draw all the rest of the triangles */
for (i = i+1; i < nVerts - 1; i++) {
_trisetup_nogradients(firstv, &vList[iList[i]], &vList[iList[i+1]]);
}
}
all_done:
#endif /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
GR_END();
} /* grDrawPlanarPolygon */
/*---------------------------------------------------------------------------
** grDrawPlanarPolygonVertexList
**
** Brute force "triangle-fan" implementation of a convex polygon drawer.
*/
GR_ENTRY(grDrawPlanarPolygonVertexList, void, (int nVerts, const GrVertex vList[]))
{
GR_BEGIN_NOFIFOCHECK("grDrawPlanarPolygonVertexList",93);
GDBG_INFO_MORE(gc->myLevel,"(%d,0x%x)\n",nVerts,vList);
GR_CHECK_F(myName, !vList, "NULL pointer passed");
GR_FLUSH_STATE();
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
grDrawPolygonVertexList(nVerts, vList);
#else /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
{
int n,i = nVerts-2;
const GrVertex *firstv = &vList[0];
for (i = 1; i < nVerts - 1; i++) {
n = TRISETUP(firstv, &vList[i], &vList[i+1]);
if (n > 0) break; /* stop after 1st non-zero-area triangle */
if (n < 0) goto all_done;
}
/* now all the gradients are loaded into the chip, so we just have to */
/* draw all the rest of the triangles */
for (i = i+1; i < nVerts - 1; i++) {
_trisetup_nogradients(firstv, &vList[i], &vList[i+1]);
}
all_done:
;
}
#endif /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
GR_END();
} /* grDrawPlanarPolygonVertexList */
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
#define kMaxPacket3Vertex 0x0FUL
/* Packet 3 requires at least one vertex, if there isn't enough room
* in the fifo then force a wrap now and write up to the max.
*/
#define FIFO_VERT(__vertSize, __polyVerts) \
((gc->cmdTransportInfo.fifoRoom < (FxI32)(sizeof(FxU32) + (__vertSize))) \
? (__polyVerts) \
: MIN((__polyVerts), ((gc->cmdTransportInfo.fifoRoom - sizeof(FxU32)) / (__vertSize))))
#define FIFO_MAX_VERT(__polyVerts) MIN(kMaxPacket3Vertex, (__polyVerts))
#endif /* GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP */
/*---------------------------------------------------------------------------
** grDrawPolygon
**
** Brute force "triangle-fan" implementation of a convex polygon drawer.
*/
GR_ENTRY(grDrawPolygon, void, (int nVerts, const int iList[], const GrVertex vList[]))
{
#define FN_NAME "grDrawPolygon"
GR_BEGIN_NOFIFOCHECK("grDrawPolygon",93);
GDBG_INFO_MORE(gc->myLevel,"(%d,0x%x,0x%x)\n",nVerts,iList,vList);
GR_CHECK_F(myName, !iList || !vList, "NULL pointer passed");
GR_FLUSH_STATE();
/* Zero length vertex lists are allowed, but we can't send them to
* the hw.
*/
if (nVerts <= 0) goto __exitNoVerts;
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
{
const FxU32 vertexParamOffset = _GlideRoot.curVertexSize;
const int* vertexIndexP = iList;
FxU32 packVertMax = FIFO_MAX_VERT(nVerts); /* Max possible verts for this packet */
FxU32 packVerts = FIFO_VERT(vertexParamOffset, packVertMax); /* # verts for this packet */
FxU32 packType = SSTCP_PKT3_BDDDDD;
__doPolyVertexSend:
{
const FxU32 packSize = packVerts * vertexParamOffset;
FxU32 vertexOffset;
GR_ASSERT((packSize % vertexParamOffset) == 0);
GR_ASSERT(packSize >= vertexParamOffset);
GR_SET_EXPECTED_SIZE(packSize, 1);
TRI_STRIP_BEGIN(kSetupFan,
packSize / vertexParamOffset, vertexParamOffset,
packType);
for(vertexOffset = 0; vertexOffset < packSize; vertexOffset += vertexParamOffset) {
const float* vertex = (const float*)(vList + *vertexIndexP++);
TRI_SETF(vertex[GR_VERTEX_X_OFFSET]);
TRI_SETF(vertex[GR_VERTEX_Y_OFFSET]);
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
{
FxBool doColorP = FXFALSE;
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_R_OFFSET << 2)), R));
doColorP = FXTRUE;
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_A_OFFSET << 2)), A);
doColorP = FXTRUE;
dataList++;
}
if (doColorP) TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(vertex, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while (*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(vertex, *dataList));
dataList++;
}
}
}
TRI_END;
GR_CHECK_SIZE();
}
/* Are there more vertices that need to be sent for this
* polygon? Reset the parameters and do the rest of them.
*/
if (vertexIndexP < iList + nVerts) {
/* Reset the # of verts maxing out the send based on the
* space left in the fifo and the max packet size.
*/
nVerts -= packVerts;
packVertMax = FIFO_MAX_VERT(nVerts); /* Max possible verts for this packet */
packVerts = FIFO_VERT(vertexParamOffset, packVertMax); /* # verts for this packet */
packType = SSTCP_PKT3_DDDDDD;
GDBG_INFO(120, "\tSending continueing polygon data (0x%X : 0x%X)\n", nVerts, packVerts);
goto __doPolyVertexSend;
}
}
#else /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
{
int i;
for (i = 1; i < nVerts - 1; i++) {
grDrawTriangle(&vList[iList[0]], &vList[iList[i]], &vList[iList[i+1]]);
}
}
#endif /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
__exitNoVerts:
GR_END();
#undef FN_NAME
} /* grDrawPolygon */
/*---------------------------------------------------------------------------
** grDrawPolygonVertexList
**
** Brute force "triangle-fan" implementation of a convex polygon drawer.
*/
GR_ENTRY(grDrawPolygonVertexList, void, (int nVerts, const GrVertex vList[]))
{
#define FN_NAME "grDrawPolygonVertexList"
GR_BEGIN_NOFIFOCHECK("grDrawPolygonVertexList", 92);
GDBG_INFO_MORE(gc->myLevel,"(%d,0x%x)\n",nVerts,vList);
GR_CHECK_F(myName, !vList, "NULL pointer passed");
GR_FLUSH_STATE();
/* Zero length vertex lists are allowed, but we can't send them to
* the hw.
*/
if (nVerts <= 0) goto __exitNoVerts;
#if GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP
{
const FxU32 vertexParamOffset = _GlideRoot.curVertexSize;
const GrVertex* vertexListP = vList;
FxU32 packVertMax = FIFO_MAX_VERT(nVerts); /* Max possible verts for this packet */
FxU32 packVerts = FIFO_VERT(vertexParamOffset, packVertMax); /* # verts for this packet */
FxU32 packType = SSTCP_PKT3_BDDDDD;
__doPolyVertexSend:
GR_ASSERT(packVerts > 0);
GR_ASSERT(packVerts <= kMaxPacket3Vertex);
{
const FxU32 packSize = packVerts * vertexParamOffset;
FxU32 vertexOffset;
GR_SET_EXPECTED_SIZE(packSize, 1);
TRI_STRIP_BEGIN(kSetupFan, packVerts, vertexParamOffset, packType);
for(vertexOffset = 0; vertexOffset < packSize; vertexOffset += vertexParamOffset) {
const float* vertex = (const float*)vertexListP++;
TRI_SETF(vertex[GR_VERTEX_X_OFFSET]);
TRI_SETF(vertex[GR_VERTEX_Y_OFFSET]);
{
const int* dataList = gc->tsuDataList;
#if GLIDE_PACKED_RGB
/* dpc - 10 feb 1998 -
* Some apps send color values outside of the range [0..255]
*/
#undef RGBA_COMP
#define RGBA_COMP(__fpVal, __fpBias, __fpShift, __fpMask) \
((_GlideRoot.pool.ftemp1 = (float)((float)(__fpVal) + (float)(__fpBias))), \
((((float)(__fpVal)) > 255.0f) \
? (__fpMask) \
: ((((float)(__fpVal)) < 0.0f) \
? 0x00UL \
: ((*(const FxU32*)&_GlideRoot.pool.ftemp1) & (__fpMask)))) << (__fpShift))
{
FxBool doColorP = FXFALSE;
FxU32 packedColor = 0x00;
if (*dataList == (GR_VERTEX_R_OFFSET << 2)) {
packedColor = (RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_B_OFFSET << 2)), B) |
RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_G_OFFSET << 2)), G) |
RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_R_OFFSET << 2)), R));
doColorP = FXTRUE;
dataList++;
}
if (*dataList == (GR_VERTEX_A_OFFSET << 2)) {
packedColor |= RGBA_COMP_CLAMP(FARRAY(vertex, (GR_VERTEX_A_OFFSET << 2)), A);
doColorP = FXTRUE;
dataList++;
}
if (doColorP) TRI_SET(packedColor);
}
#endif /* GLIDE_PACKED_RGB */
#if GLIDE_FP_CLAMP_TEX
while(*dataList != 0) {
TRI_SETF(FARRAY(vertex, *dataList));
dataList++;
}
dataList++;
#endif /* GLIDE_FP_CLAMP_TEX */
while (*dataList != 0) {
TRI_SETF_CLAMP(FARRAY(vertex, *dataList));
dataList++;
}
}
}
TRI_END;
GR_CHECK_SIZE();
}
/* More verts? */
if (vertexListP < vList + nVerts) {
/* Reset the # of verts maxing out the send based on the
* space left in the fifo and the max packet size.
*/
nVerts -= packVerts;
packVertMax = FIFO_MAX_VERT(nVerts); /* Max possible verts for this packet */
packVerts = FIFO_VERT(vertexParamOffset, packVertMax); /* # verts for this packet */
/* Packet type to continue strip */
packType = SSTCP_PKT3_DDDDDD;
GDBG_INFO(120, "\tSending continueing polygon data (0x%X : 0x%X)\n", packVerts, nVerts);
goto __doPolyVertexSend;
}
}
#else /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
{
int i;
for (i = 1; i < nVerts - 1; i++) {
grDrawTriangle(&vList[0], &vList[i], &vList[i+1]);
}
}
#endif /* !(GLIDE_HW_TRI_SETUP && GLIDE_PACKET3_TRI_SETUP) */
__exitNoVerts:
GR_END();
#undef FN_NAME
} /* grDrawPolygonVertexList */
/*---------------------------------------------------------------------------
** _grColorCombineDelta0Mode
**
** GMT: when we are in delta0 mode, color comes from the RGB iterators
** but the slopes are 0.0. So when we enter delta0 mode we set
** the iterators up and then we leave them alone during primitive
** rendering
*/
GR_DDFUNC(_grColorCombineDelta0Mode, void, (FxBool delta0mode))
{
#define FN_NAME "_grColorCombineDelta0Mode"
GR_BEGIN_NOFIFOCHECK("_grColorCombineDelta0Mode",85);
GDBG_INFO_MORE(gc->myLevel,"(%d)\n",delta0mode);
if (delta0mode) {
GR_SET_EXPECTED_SIZE(9 << 2, 9);
{
GR_SETF(BROADCAST_ID, hw, Fr, gc->state.r);
GR_SETF(BROADCAST_ID, hw, Fg, gc->state.g);
GR_SETF(BROADCAST_ID, hw, Fb, gc->state.b);
GR_SET(BROADCAST_ID, hw, drdx, 0);
GR_SET(BROADCAST_ID, hw, drdy, 0);
GR_SET(BROADCAST_ID, hw, dgdx, 0);
GR_SET(BROADCAST_ID, hw, dgdy, 0);
GR_SET(BROADCAST_ID, hw, dbdx, 0);
GR_SET(BROADCAST_ID, hw, dbdy, 0);
}
GR_CHECK_SIZE();
}
gc->state.cc_delta0mode = delta0mode;
GR_END();
#undef FN_NAME
} /* _grColorCombineDeltaMode */