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.
938 lines
37 KiB
938 lines
37 KiB
/******************************module*header*******************************\
|
|
* Module Name: mcdtri.c
|
|
*
|
|
* Contains the low-level (rasterization) triangle-rendering routines for the
|
|
* Cirrus Logic 546X MCD driver.
|
|
*
|
|
* Copyright (c) 1997 Cirrus Logic, Inc.
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "mcdhw.h"
|
|
#include "mcdutil.h"
|
|
#include "mcdmath.h"
|
|
|
|
#define QUAKEEDGE_FIX
|
|
#define FASTER_RECIP_ORTHO
|
|
|
|
|
|
#define HALF 0x08000
|
|
#define ONE 0x10000
|
|
|
|
#define MCDTRI_PRINT
|
|
|
|
//#define MAX_W_RATIO (float)1.45
|
|
#define MAX_W_RATIO (float)1.80
|
|
#define W_RATIO_PERSP_EQ_LINEAR (float)1.03
|
|
|
|
#define EDGE_SUBDIVIDE_TEST(start,end,WRAMAX,WRBMAX,SPLIT) \
|
|
SPLIT = ((start->windowCoord.w > WRAMAX) || (end->windowCoord.w > WRBMAX)) ? 1 : 0;
|
|
|
|
|
|
#define FIND_MIDPOINT(start, end, mid) { \
|
|
float recip; \
|
|
mid->windowCoord.x = (start->windowCoord.x + end->windowCoord.x) * (float)0.5; \
|
|
mid->windowCoord.y = (start->windowCoord.y + end->windowCoord.y) * (float)0.5; \
|
|
mid->windowCoord.z = (start->windowCoord.z + end->windowCoord.z) * (float)0.5; \
|
|
mid->colors[0].r = (start->colors[0].r + end->colors[0].r) * (float)0.5; \
|
|
mid->colors[0].g = (start->colors[0].g + end->colors[0].g) * (float)0.5; \
|
|
mid->colors[0].b = (start->colors[0].b + end->colors[0].b) * (float)0.5; \
|
|
mid->colors[0].a = (start->colors[0].a + end->colors[0].a) * (float)0.5; \
|
|
mid->fog = (start->fog + end->fog) * (float)0.5; \
|
|
mid->windowCoord.w = (start->windowCoord.w + end->windowCoord.w) * (float)0.5; \
|
|
recip = (float)0.5/mid->windowCoord.w; /* pre-mult by .5 for use below */ \
|
|
mid->texCoord.x = recip * (start->texCoord.x * start->windowCoord.w + \
|
|
end->texCoord.x * end->windowCoord.w); \
|
|
mid->texCoord.y = recip * (start->texCoord.y * start->windowCoord.w + \
|
|
end->texCoord.y * end->windowCoord.w); \
|
|
}
|
|
|
|
|
|
VOID FASTCALL __MCDSubdivideTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c,
|
|
int split12, int split23, int split31, int subdiv_levels)
|
|
{
|
|
|
|
MCDVERTEX Vmid12,Vmid23,Vmid31; // 3 possible midpoints
|
|
|
|
subdiv_levels++;
|
|
|
|
// find midpoint of edges if they need to be split
|
|
if (split12) FIND_MIDPOINT(a,b,((MCDVERTEX *)&Vmid12));
|
|
if (split23) FIND_MIDPOINT(b,c,((MCDVERTEX *)&Vmid23));
|
|
if (split31) FIND_MIDPOINT(c,a,((MCDVERTEX *)&Vmid31));
|
|
|
|
#define SPLIT12 0x4
|
|
#define SPLIT23 0x2
|
|
#define SPLIT31 0x1
|
|
|
|
// from original vertices and any midpoints found above, create a batch of triangles
|
|
switch ((split12<<2) | (split23<<1) | split31)
|
|
{
|
|
case SPLIT12:
|
|
// 2 triangles, 1->2 edge was divided
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid12, c, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, b, &Vmid12, c, subdiv_levels);
|
|
break;
|
|
|
|
case SPLIT23:
|
|
// 2 triangles, 2->3 edge was divided
|
|
__MCDPerspTxtTriangle(pRc, b, &Vmid23, a, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, c, &Vmid23, a, subdiv_levels);
|
|
break;
|
|
|
|
case SPLIT31:
|
|
// 2 triangles, 3->1 edge was divided
|
|
__MCDPerspTxtTriangle(pRc, c, &Vmid31, b, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid31, b, subdiv_levels);
|
|
break;
|
|
|
|
case (SPLIT12|SPLIT23):
|
|
// 3 triangles, 1->2 and 2->3 edges were divided
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid23, c, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid23, &Vmid12, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, &Vmid12, &Vmid23, b, subdiv_levels);
|
|
break;
|
|
|
|
case (SPLIT23|SPLIT31):
|
|
// 3 triangles, 2->3 and 3->1 edges were divided
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid31, b, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, b, &Vmid31, &Vmid23, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, &Vmid23, &Vmid31, c, subdiv_levels);
|
|
break;
|
|
|
|
case (SPLIT12|SPLIT31):
|
|
// 3 triangles, 1->2 and 3->1 edges were divided
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid31, &Vmid12, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, b, &Vmid31, &Vmid12, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, b, &Vmid31, c, subdiv_levels);
|
|
break;
|
|
|
|
case (SPLIT12|SPLIT23|SPLIT31):
|
|
// 4 triangles, all 3 edges were divided
|
|
__MCDPerspTxtTriangle(pRc, a, &Vmid31, &Vmid12, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, b, &Vmid23, &Vmid12, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, c, &Vmid31, &Vmid23, subdiv_levels);
|
|
__MCDPerspTxtTriangle(pRc, &Vmid12, &Vmid23, &Vmid31, subdiv_levels);
|
|
break;
|
|
|
|
default:
|
|
// original triangle - no subdivisions
|
|
// this routine should never be called for this case, but here's insurance
|
|
__MCDPerspTxtTriangle(pRc, a, b, c, subdiv_levels);
|
|
break;
|
|
|
|
} // endswitch
|
|
|
|
}
|
|
|
|
|
|
#define EXCHANGE(i,j) \
|
|
{ \
|
|
ptemp=i; \
|
|
i=j; j=ptemp; \
|
|
}
|
|
#define ROTATE_L(i,j,k) \
|
|
{ \
|
|
ptemp=j; \
|
|
j=k;k=i;i=ptemp; \
|
|
}
|
|
|
|
|
|
#define SORT_Y_ORDER(a,b,c) \
|
|
{ \
|
|
void *ptemp; \
|
|
if( a->windowCoord.y > b->windowCoord.y ) \
|
|
if( c->windowCoord.y < b->windowCoord.y ) \
|
|
EXCHANGE(a,c) \
|
|
else \
|
|
if( c->windowCoord.y < a->windowCoord.y ) \
|
|
ROTATE_L(a,b,c) \
|
|
else \
|
|
EXCHANGE(a,b) \
|
|
else \
|
|
if( c->windowCoord.y < a->windowCoord.y ) \
|
|
ROTATE_L(c,b,a) \
|
|
else \
|
|
if( c->windowCoord.y < b->windowCoord.y ) \
|
|
EXCHANGE(b,c) \
|
|
}
|
|
|
|
|
|
VOID FASTCALL __MCDPerspTxtTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c, int subdiv_levels)
|
|
{
|
|
int split12, split23, split31;
|
|
float w1_times_max = a->windowCoord.w * W_RATIO_PERSP_EQ_LINEAR;
|
|
float w2_times_max = b->windowCoord.w * W_RATIO_PERSP_EQ_LINEAR;
|
|
float w3_times_max = c->windowCoord.w * W_RATIO_PERSP_EQ_LINEAR;
|
|
|
|
if ((a->windowCoord.w < w2_times_max) && (b->windowCoord.w < w1_times_max) &&
|
|
(b->windowCoord.w < w3_times_max) && (c->windowCoord.w < w2_times_max) &&
|
|
(c->windowCoord.w < w1_times_max) && (a->windowCoord.w < w3_times_max))
|
|
{
|
|
if (subdiv_levels > 1)
|
|
{
|
|
// this triangle result of subdivision -> must sort in y
|
|
SORT_Y_ORDER(a,b,c)
|
|
}
|
|
|
|
__MCDFillTriangle(pRc, a, b, c, TRUE); // ready to render - linear ok
|
|
}
|
|
else
|
|
{
|
|
w1_times_max = a->windowCoord.w * MAX_W_RATIO;
|
|
w2_times_max = b->windowCoord.w * MAX_W_RATIO;
|
|
w3_times_max = c->windowCoord.w * MAX_W_RATIO;
|
|
|
|
// determine from w ratios which (if any) edges must be subdivided
|
|
EDGE_SUBDIVIDE_TEST(a,b,w2_times_max,w1_times_max,split12)
|
|
EDGE_SUBDIVIDE_TEST(b,c,w3_times_max,w2_times_max,split23)
|
|
EDGE_SUBDIVIDE_TEST(c,a,w1_times_max,w3_times_max,split31)
|
|
|
|
// if we need to subdivide, and we're not already too many levels deep, do it
|
|
// (since subdivision recursive, must limit it to prevent stack overflow in kernel mode)
|
|
if ((split12 | split23 | split31) && (subdiv_levels < 4))
|
|
__MCDSubdivideTriangle(pRc, a, b, c, split12, split23, split31, subdiv_levels);
|
|
else
|
|
{
|
|
if (subdiv_levels > 1)
|
|
{
|
|
// this triangle result of subdivision -> must sort in y
|
|
SORT_Y_ORDER(a,b,c)
|
|
}
|
|
__MCDFillTriangle(pRc, a, b, c, FALSE); // ready to render - linear NOT ok
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#define FLT_TYPE (float)
|
|
|
|
#define FLOAT_TO_1616 FLT_TYPE 65536.0
|
|
#define FIXED_X_ROUND_FACTOR 0x7fff
|
|
|
|
//#define INTPR(FLOATVAL) FTOL((FLOATVAL) * FLT_TYPE 1000.0)
|
|
#define INTPR(FLOATVAL) 0
|
|
|
|
/*********************************************************************
|
|
* Local Functions
|
|
**********************************************************************/
|
|
#define RIGHT_TO_LEFT_DIR 0x80000000
|
|
#define LEFT_TO_RIGHT_DIR 0
|
|
|
|
#define EDGE_DISABLE_RIGHT_X 0x20000000
|
|
#define EDGE_DISABLE_LEFT_X 0x40000000
|
|
#define EDGE_DISABLE_BOTTOM_Y 0x20000000
|
|
#define EDGE_DISABLE_TOP_Y 0x40000000
|
|
|
|
#define EDGE_DISABLE_X EDGE_DISABLE_RIGHT_X
|
|
#define EDGE_DISABLE_Y 0
|
|
|
|
|
|
// macros to convert float to precision equivalent to 16.16 representation
|
|
|
|
#define PREC_FLOAT FLOAT_TO_1616
|
|
|
|
// rounding done by adding 1/2 of 1/65536, since 1/65536 is 16.16 step size
|
|
#define PREC_ROUND ((FLT_TYPE 0.5) / PREC_FLOAT)
|
|
|
|
#define PREC_1616(inval,outval) { \
|
|
float bias = (inval>=0) ? PREC_ROUND : -PREC_ROUND; \
|
|
outval=(float)(FTOL((inval+bias)*PREC_FLOAT)) * ((FLT_TYPE 1.0) / PREC_FLOAT); \
|
|
}
|
|
|
|
// for positive values that will be used as negative, unconditionally bias it smaller
|
|
// unless it's already too small
|
|
#define NEG_PREC_1616(inval,outval) { \
|
|
float bias = (inval>0) ? -PREC_ROUND : 0; \
|
|
outval=(float)(FTOL((inval+bias)*PREC_FLOAT)) * ((FLT_TYPE 1.0) / PREC_FLOAT); \
|
|
}
|
|
|
|
// convert from float to 16.16 long
|
|
#define fix_ieee( val ) FTOL((val) * (float)65536.0)
|
|
|
|
// convert from float to 8.24 long
|
|
#define fix824_ieee( val ) FTOL((val) * (float)16777216.0)
|
|
|
|
typedef struct {
|
|
float a1, a2;
|
|
float b1, b2;
|
|
} QUADRATIC;
|
|
|
|
VOID FASTCALL __MCDFillTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c, int linear_ok)
|
|
{
|
|
PDEV *ppdev;
|
|
unsigned int *pdwNext;
|
|
|
|
// output queue stuff...
|
|
DWORD *pSrc;
|
|
DWORD *pDest;
|
|
DWORD *pdwStart;
|
|
|
|
DWORD *pdwOrig;
|
|
DWORD *pdwColor;
|
|
DWORD dwOpcode;
|
|
int count1, count2;
|
|
float frecip_main, frecip_ortho;
|
|
float fdx_main;
|
|
float ftemp;
|
|
float v1red,v1grn,v1blu;
|
|
float fv2x,fv2y,fv3x,fv3y,fv32y;
|
|
|
|
float aroundy, broundy;
|
|
|
|
float fmain_adj, fwidth, fxincrement, finitwidth1, finitwidth2;
|
|
float fdwidth1,fdwidth2;
|
|
|
|
float awinx, awiny, bwinx, bwiny, cwinx, cwiny;
|
|
int int_awiny, int_bwiny, int_cwiny;
|
|
float fadjust;
|
|
|
|
int xflags;
|
|
|
|
// window coords are float values, and need to have
|
|
// viewportadjust (MCDVIEWPORT) values subtracted to get to real screen space
|
|
|
|
// color values are 0->1 floats and must be multiplied by scale values (MCDRCINFO)
|
|
// to get to nbits range (scale = 0xff for 8 bit, 0x7 for 3 bit, etc.)
|
|
|
|
// Z values are 0->1 floats and must be multiplied by zscale values (MCDRCINFO)
|
|
|
|
// Caller has already sorted vertices so that a.y <= b.y <= c.y
|
|
|
|
|
|
// Force flat-top/ flat-bottom right triangles to draw toward the center.
|
|
// if Main is vertical edge, much better chance of alignment at diagonal
|
|
if( a->windowCoord.y == b->windowCoord.y ) { // Flat top
|
|
if( b->windowCoord.x == c->windowCoord.x ) {
|
|
void *ptemp;
|
|
EXCHANGE(a, b);
|
|
}
|
|
} else
|
|
if( b->windowCoord.y == c->windowCoord.y ) { // Flat bottom
|
|
if( a->windowCoord.x == b->windowCoord.x ) {
|
|
void *ptemp;
|
|
EXCHANGE(b, c);
|
|
}
|
|
}
|
|
|
|
MCDTRI_PRINT("v1 = %d %d %d c1=%d %d %d",INTPR(a->windowCoord.x),INTPR(a->windowCoord.y),INTPR(a->windowCoord.z),INTPR(a->colors[0].r),INTPR(a->colors[0].g),INTPR(a->colors[0].b));
|
|
MCDTRI_PRINT("v2 = %d %d %d c2=%d %d %d",INTPR(b->windowCoord.x),INTPR(b->windowCoord.y),INTPR(b->windowCoord.z),INTPR(b->colors[0].r),INTPR(b->colors[0].g),INTPR(b->colors[0].b));
|
|
MCDTRI_PRINT("v3 = %d %d %d c3=%d %d %d",INTPR(c->windowCoord.x),INTPR(c->windowCoord.y),INTPR(c->windowCoord.z),INTPR(c->colors[0].r),INTPR(c->colors[0].g),INTPR(c->colors[0].b));
|
|
|
|
awinx = a->windowCoord.x + pRc->fxOffset;
|
|
awiny = a->windowCoord.y + pRc->fyOffset;
|
|
bwinx = b->windowCoord.x + pRc->fxOffset;
|
|
bwiny = b->windowCoord.y + pRc->fyOffset;
|
|
cwinx = c->windowCoord.x + pRc->fxOffset;
|
|
cwiny = c->windowCoord.y + pRc->fyOffset;
|
|
|
|
// round y's (don't ever need rounded version of c's y)
|
|
aroundy = FLT_TYPE FTOL(awiny + FLT_TYPE 0.5);
|
|
broundy = FLT_TYPE FTOL(bwiny + FLT_TYPE 0.5);
|
|
|
|
#if 0
|
|
// Someday, may want to convert floats to 16.16 equivalent precision
|
|
// I didn't find it necessary, but it's the first thing to try if
|
|
// a case comes up with holes....
|
|
PREC_1616(awinx,awinx);
|
|
PREC_1616(awiny,awiny);
|
|
PREC_1616(bwinx,bwinx);
|
|
PREC_1616(bwiny,bwiny);
|
|
PREC_1616(cwinx,cwinx);
|
|
PREC_1616(cwiny,cwiny);
|
|
#endif
|
|
|
|
MCDTRI_PRINT("v1 = %d %d ",INTPR(awinx),INTPR(awiny));
|
|
MCDTRI_PRINT("v2 = %d %d ",INTPR(bwinx),INTPR(bwiny));
|
|
MCDTRI_PRINT("v3 = %d %d ",INTPR(cwinx),INTPR(cwiny));
|
|
|
|
fv2x = bwinx - awinx;
|
|
fv2y = bwiny - awiny;
|
|
fv3x = cwinx - awinx;
|
|
fv3y = cwiny - awiny;
|
|
fv32y= cwiny - bwiny;
|
|
|
|
// counts are total number of scan lines traversed
|
|
|
|
// PERFORMANCE OPTIMIZATION - start divide now for main slope
|
|
__MCD_FLOAT_BEGIN_DIVIDE(__MCDONE, fv3y, &frecip_main);
|
|
|
|
// integer operations "free" since within fdiv latency
|
|
ppdev = pRc->ppdev;
|
|
pdwNext = ppdev->LL_State.pDL->pdwNext;
|
|
pdwOrig = pdwNext;
|
|
|
|
int_cwiny = FTOL(cwiny);
|
|
int_bwiny = FTOL(bwiny);
|
|
int_awiny = FTOL(awiny);
|
|
count1 = int_bwiny - int_awiny;
|
|
count2 = int_cwiny - int_bwiny;
|
|
|
|
__MCD_FLOAT_SIMPLE_END_DIVIDE(frecip_main);
|
|
|
|
if ((awiny - int_awiny) == FLT_TYPE 0.0)
|
|
{
|
|
// start is on whole y - so bump count to include that scanline
|
|
// unless identical to b's y
|
|
if (bwiny != awiny) count1++;
|
|
}
|
|
|
|
// check for case of adjusted A and real B being on same scan line (flat top)
|
|
// even though count not 0
|
|
// ex. a.y = 79.60, b.y = 80.00 -> a will be rounded to 80.0, so really
|
|
// this is a flat top triangle. In such case, set count1 = 0.
|
|
// b will be counted below. Failure to do this results in scanline that
|
|
// has B being part of top and bottom, so width delta's applied when
|
|
// hardware steps make for some interesting artifacts (see p. 205 of MCD notes)
|
|
if (count1 == 1)
|
|
{
|
|
if ((bwiny - int_bwiny) == FLT_TYPE 0.0)
|
|
{
|
|
// convert to flat top
|
|
count1 = 0;
|
|
}
|
|
}
|
|
|
|
// similarly for almost flat bottom triangles...
|
|
// If b.y=124.90 and c.y=125.000, we don't want to draw the scan line at
|
|
// y=125 since any pixels drawn will be outside the triangle,
|
|
// so if c on exact y and count2=1, set count2=0
|
|
if (count2 == 1)
|
|
{
|
|
if ((cwiny - int_cwiny) == FLT_TYPE 0.0)
|
|
{
|
|
// convert to flat bottom
|
|
count2 = 0;
|
|
}
|
|
}
|
|
|
|
// main slope - based on precise vertices
|
|
//USING MACROS TO OVERLAP DIVIDE WITH INTEGER OPERATIONS
|
|
// frecip_main = FLT_TYPE 1.0/fv3y;
|
|
|
|
fdx_main = fv3x * frecip_main;
|
|
PREC_1616(fdx_main,fdx_main);
|
|
|
|
// width at vtx b - based on precise vertices
|
|
fwidth = fv2x - (fdx_main * fv2y);
|
|
|
|
// make width positive, and set direction flag
|
|
if (fwidth<0)
|
|
{
|
|
fwidth = -fwidth;
|
|
xflags = RIGHT_TO_LEFT_DIR | EDGE_DISABLE_X;
|
|
}
|
|
else
|
|
{
|
|
xflags = LEFT_TO_RIGHT_DIR | EDGE_DISABLE_X;
|
|
}
|
|
|
|
// if triangle has a top section (i.e. not flat top)....
|
|
if (count1)
|
|
{
|
|
fdwidth1 = fwidth / fv2y;
|
|
|
|
PREC_1616(fdwidth1,fdwidth1);
|
|
|
|
if (aroundy < awiny)
|
|
{
|
|
// rounding produced y less than original, so step to next scan line
|
|
// since init width would be negative
|
|
aroundy += FLT_TYPE 1.0;
|
|
}
|
|
|
|
// determine distance between actual a and scanline we'll start on
|
|
fmain_adj = aroundy - awiny;
|
|
|
|
// step width1 and x to scan line where we'll start
|
|
finitwidth1 = fmain_adj * fdwidth1;
|
|
fxincrement = fmain_adj * fdx_main;
|
|
|
|
}
|
|
#ifdef QUAKEEDGE_FIX
|
|
else
|
|
{
|
|
// flat top...
|
|
if ((bwiny - int_bwiny) == FLT_TYPE 0.0)
|
|
{
|
|
// if b on exact scanline, it's part of top, and is counted in count1 above,
|
|
// unless this is flat top triangle - in that case, bump count2
|
|
// also, if identical to C's y, then flat bottom, so count2 should remain 0
|
|
if (cwiny != bwiny) count2++;
|
|
}
|
|
}
|
|
#endif // QUAKEEDGE_FIX
|
|
|
|
// if triangle has a bottom section (i.e. not flat bottom)....
|
|
if (count2)
|
|
{
|
|
float mid_adjust;
|
|
|
|
fdwidth2 = fwidth / fv32y;
|
|
NEG_PREC_1616(fdwidth2,fdwidth2);
|
|
|
|
#ifdef QUAKEEDGE_FIX // badedge.sav fix
|
|
if ((broundy < bwiny) || ((broundy==bwiny) && count1)) // step to next if b.y on exact scanline, unless flat top triangle
|
|
#else
|
|
if (broundy < bwiny)
|
|
#endif
|
|
{
|
|
// rounding produced y less than original, so step to next scan line
|
|
mid_adjust = (broundy + (float)1.0) - bwiny;
|
|
}
|
|
else
|
|
{
|
|
// rounding produced y greater than original (i.e on scan below actual start vertex)
|
|
mid_adjust = broundy - bwiny;
|
|
}
|
|
|
|
finitwidth2 = fwidth - (fdwidth2 * mid_adjust);
|
|
|
|
// if flat top, start x/y adjustments weren't made above
|
|
if (!count1)
|
|
{
|
|
|
|
if (aroundy < awiny)
|
|
{
|
|
// rounding produced y less than original, so step to next scan line
|
|
aroundy += FLT_TYPE 1.0;
|
|
}
|
|
|
|
// determine distance between actual a and scanline we'll start on
|
|
fmain_adj = aroundy - awiny;
|
|
|
|
// step x to scan line where we'll start
|
|
fxincrement = fmain_adj * fdx_main;
|
|
}
|
|
}
|
|
#ifdef QUAKEEDGE_FIX // badedge2.sav fix
|
|
else
|
|
{
|
|
// flat bottom - if bottom is on exact scanline, don't draw that last scanline
|
|
// this will enforce GL restriction that bottom scanlines not drawn for polys
|
|
// (special case for this setup code for case of bottom of poly being on exact y value)
|
|
if ((bwiny - int_bwiny) == FLT_TYPE 0.0)
|
|
{
|
|
if ((cwiny == bwiny) && count1) count1--;
|
|
}
|
|
}
|
|
#endif // badedge2.sav fix
|
|
|
|
// if triangle not a horizontal line (i.e. it traverses at least 1 scan line)....
|
|
if (count1 || count2)
|
|
{
|
|
*(pdwNext+1) = (FTOL((awinx + fxincrement)*FLOAT_TO_1616) + FIXED_X_ROUND_FACTOR) | xflags;
|
|
// subtracting special offset added to y to make visual match MSFT software
|
|
*(pdwNext+2) = (DWORD)( (FTOL(aroundy)-MCD_CONFORM_ADJUST) << 16 ) | EDGE_DISABLE_Y;
|
|
|
|
MCDTRI_PRINT(" x, y output = %x %x, yoffset=%x",*(pdwNext+1),*(pdwNext+2),pRc->yOffset);
|
|
|
|
*(pdwNext+6) = FTOL(fdx_main*FLOAT_TO_1616);
|
|
|
|
// if triangle has a bottom section, decrement number of scans in top so middle
|
|
// scanline is first scanline of bottom section, and has length = finitwidth2
|
|
|
|
if (!count2)
|
|
{
|
|
MCDTRI_PRINT(" FLATBOTTOM");
|
|
*(pdwNext+8) = ONE + FTOL(finitwidth1*FLOAT_TO_1616);
|
|
*(pdwNext+10)= FTOL(fdwidth1*FLOAT_TO_1616);
|
|
#ifdef FASTER_RECIP_ORTHO
|
|
__MCD_FLOAT_BEGIN_DIVIDE(__MCDONE, fwidth, &frecip_ortho);
|
|
#endif
|
|
*(pdwNext+7) = count1-1;
|
|
*(pdwNext+9) = 0;
|
|
*(pdwNext+11)= 0;
|
|
}
|
|
else if (!count1)
|
|
{
|
|
MCDTRI_PRINT(" FLATTOP");
|
|
*(pdwNext+8) = ONE + FTOL(finitwidth2*FLOAT_TO_1616);
|
|
*(pdwNext+10) = FTOL(FLT_TYPE -1.0*fdwidth2*FLOAT_TO_1616);
|
|
#ifdef FASTER_RECIP_ORTHO
|
|
__MCD_FLOAT_BEGIN_DIVIDE(__MCDONE, fwidth, &frecip_ortho);
|
|
#endif
|
|
*(pdwNext+7) = count2-1;
|
|
*(pdwNext+9) = 0;
|
|
*(pdwNext+11)= 0;
|
|
}
|
|
else
|
|
{
|
|
MCDTRI_PRINT(" GENERAL");
|
|
// sub 1 from count1, since hw adds 1 to account for first scan line
|
|
*(pdwNext+8) = ONE + FTOL(finitwidth1*FLOAT_TO_1616);
|
|
*(pdwNext+9) = ONE + FTOL(finitwidth2*FLOAT_TO_1616);
|
|
*(pdwNext+10)= FTOL(fdwidth1*FLOAT_TO_1616);
|
|
*(pdwNext+11)= FTOL(FLT_TYPE -1.0*fdwidth2*FLOAT_TO_1616);
|
|
#ifdef FASTER_RECIP_ORTHO
|
|
__MCD_FLOAT_BEGIN_DIVIDE(__MCDONE, fwidth, &frecip_ortho);
|
|
#endif
|
|
*(pdwNext+7) = (count1-1) + (count2 << 16);
|
|
}
|
|
|
|
MCDTRI_PRINT("dxm =%d w1=%d w2=%d dw1=%d dw2=%d",
|
|
INTPR(fdx_main),INTPR(finitwidth1),INTPR(finitwidth2),INTPR(fdwidth1),INTPR(fdwidth2));
|
|
MCDTRI_PRINT(" %x %x %x %x %x %x",*(pdwNext+6),*(pdwNext+7),*(pdwNext+8),*(pdwNext+9),*(pdwNext+10),*(pdwNext+11));
|
|
|
|
pdwColor = pdwNext+3;
|
|
pdwNext += 12;
|
|
|
|
}
|
|
else
|
|
{
|
|
// nothing to draw, triangle doesn't traverse any scan lines
|
|
MCDTRI_PRINT(" Early return - flat top and bottom");
|
|
return;
|
|
}
|
|
|
|
// various integer ops to overlap with fdiv
|
|
dwOpcode = pRc->dwPolyOpcode;
|
|
pDest = ppdev->LL_State.pRegs + HOST_3D_DATA_PORT;
|
|
pdwStart = ppdev->LL_State.pDL->pdwStartOutPtr;
|
|
|
|
// do inside divide - won't slow us down unless 3D engine indeed not idle
|
|
USB_TIMEOUT_FIX(ppdev)
|
|
|
|
// compute 1/width, used in rgbzuv computations that follow
|
|
#ifdef FASTER_RECIP_ORTHO
|
|
__MCD_FLOAT_SIMPLE_END_DIVIDE(frecip_ortho);
|
|
#else
|
|
frecip_ortho = FLT_TYPE 1.0/fwidth;
|
|
#endif
|
|
|
|
PREC_1616(frecip_ortho,frecip_ortho);
|
|
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_SMOOTH)
|
|
{
|
|
// Calculate and set the color gradients, using gradients to adjust start color
|
|
v1red = a->colors[0].r * pRc->rScale;
|
|
v1grn = a->colors[0].g * pRc->gScale;
|
|
v1blu = a->colors[0].b * pRc->bScale;
|
|
|
|
ftemp = ((c->colors[0].r * pRc->rScale) - v1red) * frecip_main;
|
|
|
|
*(pdwNext+0) = FTOL(ftemp);
|
|
*(pdwNext+3) = FTOL(((b->colors[0].r * pRc->rScale) - (v1red + (ftemp * fv2y)) ) * frecip_ortho);
|
|
|
|
// adjust v1red for start vertex's variance from vertex a
|
|
*(pdwColor) = FTOL(v1red + (ftemp * fmain_adj));
|
|
|
|
ftemp = ((c->colors[0].g * pRc->gScale) - v1grn) * frecip_main;
|
|
*(pdwNext+1) = FTOL(ftemp);
|
|
*(pdwNext+4) = FTOL(((b->colors[0].g * pRc->gScale) - (v1grn + (ftemp * fv2y)) ) * frecip_ortho);
|
|
|
|
// adjust v1grn for start vertex's variance from vertex a
|
|
*(pdwColor+1) = FTOL(v1grn + (ftemp * fmain_adj));
|
|
|
|
ftemp = ((c->colors[0].b * pRc->bScale) - v1blu) * frecip_main;
|
|
*(pdwNext+2) = FTOL(ftemp);
|
|
*(pdwNext+5) = FTOL(((b->colors[0].b * pRc->bScale) - (v1blu + (ftemp * fv2y)) ) * frecip_ortho);
|
|
|
|
// adjust v1blu for start vertex's variance from vertex a
|
|
*(pdwColor+2) = FTOL(v1blu + (ftemp * fmain_adj));
|
|
|
|
MCDTRI_PRINT(" SHADE rgbout = %x %x %x",*(pdwColor),*(pdwColor+1),*(pdwColor+2));
|
|
MCDTRI_PRINT(" CSLOPES: %x %x %x %x %x %x",*pdwNext,*(pdwNext+1),*(pdwNext+2),*(pdwNext+3),*(pdwNext+4),*(pdwNext+5));
|
|
|
|
pdwNext += 6;
|
|
}
|
|
else
|
|
{
|
|
MCDCOLOR *pColor = &pRc->pvProvoking->colors[0];
|
|
|
|
// flat shaded - no adjustment of original colors needed
|
|
|
|
*(pdwColor) = FTOL(pColor->r * pRc->rScale);
|
|
*(pdwColor+1) = FTOL(pColor->g * pRc->gScale);
|
|
*(pdwColor+2) = FTOL(pColor->b * pRc->bScale);
|
|
|
|
MCDTRI_PRINT(" FLAT rgbout = %x %x %x",*(pdwColor),*(pdwColor+1),*(pdwColor+2));
|
|
}
|
|
|
|
|
|
|
|
if( pRc->privateEnables & __MCDENABLE_Z)
|
|
{
|
|
// "NICE" Polys for Alpha blended case - see comments above in
|
|
// geometry slopes calculations
|
|
|
|
// Calculate and set the Z value base and gradient using floats
|
|
float fdz_main = (c->windowCoord.z - a->windowCoord.z) * frecip_main;
|
|
|
|
// compute adjustment - if negative z would result, set adjust so final = 0
|
|
fadjust = fdz_main * fmain_adj;
|
|
if ((a->windowCoord.z + fadjust) < (float)0.0) fadjust = - a->windowCoord.z;
|
|
|
|
if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_FILL_ENABLE)
|
|
{
|
|
// APPLY Z OFFSET, and adjust for moved start vertex
|
|
MCDFLOAT zOffset;
|
|
if (fdz_main > 0)
|
|
{
|
|
zOffset = (fdz_main * pRc->MCDState.zOffsetFactor) + pRc->MCDState.zOffsetUnits;
|
|
}
|
|
else
|
|
{
|
|
zOffset = ((float)-1.0 * fdz_main * pRc->MCDState.zOffsetFactor) + pRc->MCDState.zOffsetUnits;
|
|
}
|
|
|
|
*(pdwNext+0) = FTOL((a->windowCoord.z + fadjust + zOffset) * FLT_TYPE 65536.0);
|
|
}
|
|
else
|
|
{
|
|
// NO Z OFFSET - just adjust for moved start vertex
|
|
*(pdwNext+0) = FTOL((a->windowCoord.z + fadjust) * FLT_TYPE 65536.0);
|
|
}
|
|
|
|
*(pdwNext+1) = FTOL(fdz_main * FLT_TYPE 65536.0);
|
|
*(pdwNext+2) = FTOL((b->windowCoord.z - a->windowCoord.z - (fdz_main * fv2y)) * FLT_TYPE 65536.0 * frecip_ortho);
|
|
|
|
MCDTRI_PRINT(" Z: %x %x %x",*pdwNext,*(pdwNext+1),*(pdwNext+2));
|
|
|
|
pdwNext += 3;
|
|
|
|
}
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_TEXTURE)
|
|
{
|
|
if ( (pRc->privateEnables & __MCDENABLE_PERSPECTIVE) && !linear_ok )
|
|
{
|
|
TEXTURE_VERTEX vmin, vmid, vmax;
|
|
QUADRATIC main, mid;
|
|
TEXTURE_VERTEX i,imain,midmain,j,jmain;
|
|
float del_u_i, del_v_i;
|
|
float um,vm;
|
|
float a1, a2, du_ortho_add;
|
|
float b1, b2, dv_ortho_add;
|
|
float sq, recip;
|
|
float delta_sq, inv_sumw;
|
|
float u1, v1;
|
|
float frecip_del_x_mid = frecip_ortho;
|
|
int tempi;
|
|
|
|
vmin.u = a->texCoord.x * pRc->texture_width;
|
|
vmin.v = a->texCoord.y * pRc->texture_height;
|
|
vmin.w = a->windowCoord.w;
|
|
|
|
vmid.x = fv2x;
|
|
vmid.y = fv2y;
|
|
vmid.u = b->texCoord.x * pRc->texture_width;
|
|
vmid.v = b->texCoord.y * pRc->texture_height;
|
|
vmid.w = b->windowCoord.w;
|
|
|
|
vmax.x = fv3x;
|
|
vmax.y = fv3y;
|
|
vmax.u = c->texCoord.x * pRc->texture_width;
|
|
vmax.v = c->texCoord.y * pRc->texture_height;
|
|
vmax.w = c->windowCoord.w;
|
|
|
|
// solve quadratic equation for main slope - we'll need exact u values
|
|
// along main, and the a1/b1, a2/b2 terms computed are used to compute
|
|
// du/v_main, d2u/v_main
|
|
delta_sq = frecip_main * frecip_main;
|
|
|
|
inv_sumw = (float)1.0/(vmin.w + vmax.w);
|
|
u1 = (vmin.u*vmin.w + vmax.u*vmax.w) * inv_sumw;
|
|
v1 = (vmin.v*vmin.w + vmax.v*vmax.w) * inv_sumw;
|
|
|
|
main.a1 = (-3*vmin.u + 4*u1 - vmax.u) * frecip_main;
|
|
main.a2 = 2*(vmin.u - 2*u1 + vmax.u) * delta_sq;
|
|
|
|
main.b1 = (-3*vmin.v + 4*v1 - vmax.v) * frecip_main;
|
|
main.b2 = 2*(vmin.v - 2*v1 + vmax.v) * delta_sq;
|
|
|
|
i.y = (float)0.5 * vmid.y;
|
|
recip = (float)1.0 / (vmin.w + vmid.w);
|
|
i.u = ((vmin.u * vmin.w) + (vmid.u * vmid.w)) * recip;
|
|
i.v = ((vmin.v * vmin.w) + (vmid.v * vmid.w)) * recip;
|
|
|
|
sq = i.y * i.y;
|
|
imain.u = main.a2*sq + main.a1*i.y + vmin.u;
|
|
imain.v = main.b2*sq + main.b1*i.y + vmin.v;
|
|
|
|
// vmid coordinates given, just need midmain
|
|
sq = vmid.y * vmid.y;
|
|
midmain.u = main.a2*sq + main.a1*vmid.y + vmin.u;
|
|
midmain.v = main.b2*sq + main.b1*vmid.y + vmin.v;
|
|
|
|
// j and jmain
|
|
j.y = (float)0.5 * (vmax.y + vmid.y);
|
|
recip = (float)1.0 / (vmid.w + vmax.w);
|
|
j.u = ((vmid.u * vmid.w) + (vmax.u * vmax.w)) * recip;
|
|
j.v = ((vmid.v * vmid.w) + (vmax.v * vmax.w)) * recip;
|
|
|
|
sq = j.y * j.y;
|
|
jmain.u = main.a2*sq + main.a1*j.y + vmin.u;
|
|
jmain.v = main.b2*sq + main.b1*j.y + vmin.v;
|
|
|
|
// compute intermediate parameters needed to calculate a1
|
|
del_u_i = i.u - imain.u;
|
|
del_v_i = i.v - imain.v;
|
|
um = j.u - jmain.u - del_u_i;
|
|
vm = j.v - jmain.v - del_v_i;
|
|
|
|
frecip_del_x_mid *= (float)2.0;
|
|
|
|
a1 = 2*del_u_i - (float)0.5*(vmid.u - midmain.u);
|
|
a1 += (vmid.y*frecip_main)*um;
|
|
a1 *= frecip_del_x_mid;
|
|
a2 = frecip_del_x_mid*(del_u_i*frecip_del_x_mid - a1);
|
|
du_ortho_add = 2*um*frecip_del_x_mid*frecip_main;
|
|
|
|
b1 = 2*del_v_i - (float)0.5*(vmid.v - midmain.v);
|
|
b1 += (vmid.y*frecip_main)*vm;
|
|
b1 *= frecip_del_x_mid;
|
|
b2 = frecip_del_x_mid*(del_v_i*frecip_del_x_mid - b1);
|
|
dv_ortho_add = 2*vm*frecip_del_x_mid*frecip_main;
|
|
|
|
// rewind a1 from i scanline to top of triangle
|
|
a1 -= (i.y) * du_ortho_add;
|
|
b1 -= (i.y) * dv_ortho_add;
|
|
|
|
// convert to forward difference terms
|
|
a1 += a2;
|
|
b1 += b2;
|
|
a2 = 2 * a2;
|
|
b2 = 2 * b2;
|
|
|
|
// compute adjustment for v start - if negative would result -> no problem
|
|
fadjust = ((main.b1 + main.b2) * fmain_adj) + pRc->texture_bias;
|
|
*(pdwNext+0) = fix_ieee(vmin.v + fadjust) & 0x1ffffff; // v
|
|
|
|
// likewise for u
|
|
fadjust = ((main.a1 + main.a2) * fmain_adj) + pRc->texture_bias;
|
|
*(pdwNext+1) = fix_ieee(vmin.u + fadjust) & 0x1ffffff; // u
|
|
|
|
*(pdwNext+2) = fix_ieee(main.b1 + main.b2); // dv_main
|
|
*(pdwNext+3) = fix_ieee(main.a1 + main.a2); // du_main
|
|
*(pdwNext+4) = fix_ieee(b1); // dv_ortho
|
|
*(pdwNext+5) = fix_ieee(a1); // du_ortho
|
|
#if DRIVER_5465
|
|
*(pdwNext+6) = fix824_ieee(2 * main.b2); // d2v_main
|
|
*(pdwNext+7) = fix824_ieee(2 * main.a2); // d2u_main
|
|
*(pdwNext+8) = fix824_ieee(b2); // d2v_ortho
|
|
*(pdwNext+9) = fix824_ieee(a2); // d2u_ortho
|
|
*(pdwNext+10)= fix824_ieee(dv_ortho_add); // dv_ortho_add
|
|
*(pdwNext+11)= fix824_ieee(du_ortho_add); // du_ortho_add
|
|
#else // DRIVER_5465
|
|
// before 5465, only 16 bit fraction in second order terms
|
|
*(pdwNext+6) = fix_ieee(2 * main.b2); // d2v_main
|
|
*(pdwNext+7) = fix_ieee(2 * main.a2); // d2u_main
|
|
*(pdwNext+8) = fix_ieee(b2); // d2v_ortho
|
|
*(pdwNext+9) = fix_ieee(a2); // d2u_ortho
|
|
*(pdwNext+10)= fix_ieee(dv_ortho_add); // dv_ortho_add
|
|
*(pdwNext+11)= fix_ieee(du_ortho_add); // du_ortho_add
|
|
#endif // DRIVER_5465
|
|
|
|
dwOpcode += 6; // 6 parms assumed (linear), add 6 since 12 total
|
|
pdwNext += 12;
|
|
|
|
}
|
|
else
|
|
// Linear texture mapping parametarization
|
|
//
|
|
{
|
|
float v1_u, v1_v;
|
|
float du_main, dv_main;
|
|
|
|
dwOpcode &= ~LL_PERSPECTIVE; // turn persp bit off
|
|
|
|
v1_v = a->texCoord.y * pRc->texture_height;
|
|
v1_u = a->texCoord.x * pRc->texture_width;
|
|
|
|
dv_main = ((c->texCoord.y * pRc->texture_height)- v1_v) * frecip_main;
|
|
du_main = ((c->texCoord.x * pRc->texture_width) - v1_u) * frecip_main;
|
|
|
|
// compute adjustment for v start - if negative would result -> no problem
|
|
fadjust = (dv_main * fmain_adj) + pRc->texture_bias;
|
|
*(pdwNext+0) = fix_ieee(v1_v + fadjust) & 0x1ffffff; // v
|
|
|
|
// likewise for u...
|
|
fadjust = (du_main * fmain_adj) + pRc->texture_bias;
|
|
*(pdwNext+1) = fix_ieee(v1_u + fadjust) & 0x1ffffff; // u
|
|
|
|
*(pdwNext+2) = fix_ieee(dv_main);
|
|
*(pdwNext+3) = fix_ieee(du_main);
|
|
|
|
// dv_ortho, du_ortho
|
|
*(pdwNext+4) = fix_ieee(((b->texCoord.y * pRc->texture_height) - (v1_v + (dv_main * count1))) * frecip_ortho);
|
|
*(pdwNext+5) = fix_ieee(((b->texCoord.x * pRc->texture_width) - (v1_u + (du_main * count1))) * frecip_ortho);
|
|
|
|
MCDTRI_PRINT(" LINTEXT: %x %x %x %x %x %x",*pdwNext,*(pdwNext+1),*(pdwNext+2),*(pdwNext+3),*(pdwNext+4),*(pdwNext+5));
|
|
|
|
pdwNext += 6;
|
|
}
|
|
|
|
}
|
|
|
|
if (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG))
|
|
{
|
|
float v1alp;
|
|
|
|
// if CONST alpha blend, don't change alpha regs
|
|
if (dwOpcode & ALPHA)
|
|
{
|
|
if (pRc->privateEnables & __MCDENABLE_BLEND)
|
|
{
|
|
if (pRc->privateEnables & __MCDENABLE_SMOOTH)
|
|
{
|
|
// recall that if both blending and fog active, all prims punted back to software
|
|
v1alp = a->colors[0].a * pRc->aScale;
|
|
|
|
ftemp = ((c->colors[0].a * pRc->aScale) - v1alp) * frecip_main;
|
|
|
|
// load start alpha - adjusting for movement of start vertex from original
|
|
*pdwNext = FTOL(v1alp + (ftemp * fmain_adj));
|
|
// adjustment could result in negative alpha - set to 0 if so
|
|
if (*pdwNext & 0x80000000) *pdwNext = 0;
|
|
|
|
*(pdwNext+1) = FTOL(ftemp);
|
|
*(pdwNext+2) = FTOL(((b->colors[0].a * pRc->aScale) - (v1alp + (ftemp * count1)) ) * frecip_ortho);
|
|
}
|
|
else
|
|
{
|
|
v1alp = pRc->pvProvoking->colors[0].a * pRc->aScale;
|
|
// alpha constant across triangle, so no adjustment to start
|
|
*(pdwNext+0) = FTOL(v1alp) & 0x00ffff00;// bits 31->24 and 7->0 reserved
|
|
*(pdwNext+1) = 0;
|
|
*(pdwNext+2) = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// FOG...
|
|
v1alp = a->fog * FLT_TYPE 16777215.0; // convert from 0->1.0 val to 0->ff.ffff val
|
|
ftemp = ((c->fog * FLT_TYPE 16777215.0) - v1alp) * frecip_main;
|
|
|
|
// load start alpha - adjusting for movement of start vertex from original
|
|
*pdwNext = FTOL(v1alp + (ftemp * fmain_adj));
|
|
// adjustment could result in negative alpha - set to 0 if so
|
|
if (*pdwNext & 0x80000000) *pdwNext = 0;
|
|
*(pdwNext+1) = FTOL(ftemp);
|
|
*(pdwNext+2) = FTOL(((b->fog * FLT_TYPE 16777215.0) - (v1alp + (ftemp * count1)) ) * frecip_ortho);
|
|
}
|
|
|
|
*(pdwNext+0) &= 0x00ffff00;// bits 31->24 and 7->0 reserved
|
|
*(pdwNext+1) &= 0xffffff00;// bits 7->0 reserved
|
|
*(pdwNext+2) &= 0xffffff00;// bits 7->0 reserved
|
|
|
|
pdwNext += 3;
|
|
}
|
|
|
|
}
|
|
|
|
*pdwOrig = dwOpcode;
|
|
|
|
// output queued data here....
|
|
pSrc = pdwStart;
|
|
while (pSrc != pdwNext)
|
|
{
|
|
int len = (*pSrc & 0x3F) + 1;
|
|
while( len-- ) *pDest = *pSrc++;
|
|
}
|
|
|
|
ppdev->LL_State.pDL->pdwNext = ppdev->LL_State.pDL->pdwStartOutPtr = pdwStart;
|
|
|
|
}
|
|
|