Leaked source code of windows server 2003
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

/******************************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;
}