539 lines
20 KiB
C
539 lines
20 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: mcdrend.c
|
|
*
|
|
* This file contains routines to do high-level triangle rendering for the
|
|
* Millenium MCD driver, including culling and face computations. Note that
|
|
* in this driver, we don't use vertex color pointer at all since all pointer
|
|
* references need to be checked to avoid the possibility of an invalid
|
|
* memory reference. Instead, we copy the color data in the cases where we
|
|
* need to during two-sided operation. This is not the common case, and even
|
|
* in the case where the color data needs to be copied to colors[0] (and back),
|
|
* the copy only needs to be done for (on average) half the faces.
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "mcdhw.h"
|
|
#include "mcdutil.h"
|
|
#include "mcdmath.h"
|
|
#include "math.h"
|
|
|
|
#if _X86_
|
|
|
|
#define GET_HALF_AREA(pRc, a, b, c)\
|
|
\
|
|
__asm{ mov ecx, c };\
|
|
__asm{ mov eax, a };\
|
|
__asm{ mov ebx, b };\
|
|
__asm{ mov edx, pRc };\
|
|
__asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ecx] };\
|
|
__asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][eax] /* dxAC */ };\
|
|
__asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ecx] };\
|
|
__asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ebx] /* dyBC dxAC */ };\
|
|
__asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ecx] /* dxBC dyBC dxAC */ };\
|
|
__asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ebx] };\
|
|
__asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ecx] };\
|
|
__asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][eax] /* dyAC dxBC dyBC dxAC */ };\
|
|
__asm{ fxch ST(2) /* dyBC dxBC dyAC dxAC */ };\
|
|
__asm{ fst DWORD PTR [OFFSET(DEVRC.dyBC)][edx] };\
|
|
__asm{ fmul ST, ST(3) /* dxACdyBC dxBC dyAC dxAC */ };\
|
|
__asm{ fxch ST(2) /* dyAC dxBC dxACdyBC dxAC */ };\
|
|
__asm{ fst DWORD PTR [OFFSET(DEVRC.dyAC)][edx] };\
|
|
__asm{ fmul ST, ST(1) /* dxBCdyAC dxBC dxACdyBC dxAC */ };\
|
|
__asm{ fxch ST(1) /* dxBC dxBCdyAC dxACdyBC dxAC */ };\
|
|
__asm{ fstp DWORD PTR [OFFSET(DEVRC.dxBC)][edx] /* dxBCdyAC dxACdyBC dxAC */ };\
|
|
__asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ebx] };\
|
|
__asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][eax] /* dxAB dxBCdyAC dxACdyBC dxAC */ };\
|
|
__asm{ fxch ST(1) /* dxBCdyAC dxAB dxACdyBC dxAC */ };\
|
|
__asm{ fsubp ST(2), ST /* dxAB area dxAC */ };\
|
|
__asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ebx] };\
|
|
__asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][eax] /* dyAB dxAB area dxAC */ };\
|
|
__asm{ fxch ST(3) /* dxAC dxAB area dyAB */ };\
|
|
__asm{ fstp DWORD PTR [OFFSET(DEVRC.dxAC)][edx] /* dxAB area dyAB */ };\
|
|
__asm{ fstp DWORD PTR [OFFSET(DEVRC.dxAB)][edx] /* area dyAB */ };\
|
|
__asm{ fstp DWORD PTR [OFFSET(DEVRC.halfArea)][edx] /* dyAB */ };\
|
|
__asm{ fstp DWORD PTR [OFFSET(DEVRC.dyAB)][edx] /* (empty) */ };
|
|
|
|
#else
|
|
|
|
#define GET_HALF_AREA(pRc, a, b, c)\
|
|
/* Compute signed half-area of the triangle */ \
|
|
(pRc)->dxAC = (c)->windowCoord.x - (a)->windowCoord.x; \
|
|
(pRc)->dxBC = (c)->windowCoord.x - (b)->windowCoord.x; \
|
|
(pRc)->dyAC = (c)->windowCoord.y - (a)->windowCoord.y; \
|
|
(pRc)->dyBC = (c)->windowCoord.y - (b)->windowCoord.y; \
|
|
(pRc)->dxAB = (b)->windowCoord.x - (a)->windowCoord.x; \
|
|
(pRc)->dyAB = (b)->windowCoord.y - (a)->windowCoord.y; \
|
|
\
|
|
(pRc)->halfArea = (pRc)->dxAC * (pRc)->dyBC - (pRc)->dxBC * (pRc)->dyAC;
|
|
|
|
#endif
|
|
|
|
|
|
#define SORT_AND_CULL_FACE(a, b, c, face, ccw)\
|
|
{ \
|
|
LONG reversed; \
|
|
MCDVERTEX *temp; \
|
|
\
|
|
\
|
|
reversed = 0; \
|
|
if (__MCD_VERTEX_COMPARE((a)->windowCoord.y, <, (b)->windowCoord.y)) { \
|
|
if (__MCD_VERTEX_COMPARE((b)->windowCoord.y, <, (c)->windowCoord.y)) { \
|
|
/* Already sorted */ \
|
|
} else { \
|
|
if (__MCD_VERTEX_COMPARE((a)->windowCoord.y, <, (c)->windowCoord.y)) {\
|
|
temp=(b); (b)=(c); (c)=temp; \
|
|
reversed = 1; \
|
|
} else { \
|
|
temp=(a); (a)=(c); (c)=(b); (b)=temp; \
|
|
} \
|
|
} \
|
|
} else { \
|
|
if (__MCD_VERTEX_COMPARE((b)->windowCoord.y, <, (c)->windowCoord.y)) { \
|
|
if (__MCD_VERTEX_COMPARE((a)->windowCoord.y, <, (c)->windowCoord.y)) {\
|
|
temp=(a); (a)=(b); (b)=temp; \
|
|
reversed = 1; \
|
|
} else { \
|
|
temp=(a); (a)=(b); (b)=(c); (c)=temp; \
|
|
} \
|
|
} else { \
|
|
temp=(a); (a)=(c); (c)=temp; \
|
|
reversed = 1; \
|
|
} \
|
|
} \
|
|
\
|
|
GET_HALF_AREA(pRc, (a), (b), (c)); \
|
|
\
|
|
(ccw) = !__MCD_FLOAT_LTZ(pRc->halfArea); \
|
|
\
|
|
/* \
|
|
** Figure out if face is culled or not. The face check needs to be \
|
|
** based on the vertex winding before sorting. This code uses the \
|
|
** reversed flag to invert the sense of ccw - an xor accomplishes \
|
|
** this conversion without an if test. \
|
|
** \
|
|
** ccw reversed xor \
|
|
** --- -------- --- \
|
|
** 0 0 0 (remain !ccw) \
|
|
** 1 0 1 (remain ccw) \
|
|
** 0 1 1 (become ccw) \
|
|
** 1 1 0 (become cw) \
|
|
*/ \
|
|
(face) = pRc->polygonFace[(ccw) ^ reversed]; \
|
|
if ((face) == pRc->cullFlag) { \
|
|
/* Culled */ \
|
|
return; \
|
|
} \
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VOID FASTCALL __MCDCalcZSlope(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c)
|
|
//
|
|
// Local helper routine to calculate z slopes for z-offseting primitives.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID FASTCALL __MCDCalcZSlope(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c)
|
|
{
|
|
MCDFLOAT oneOverArea, t1, t2, t3, t4;
|
|
MCDFLOAT dzAC, dzBC;
|
|
|
|
if (CASTINT(pRc->halfArea) == 0) {
|
|
pRc->dzdx = __MCDZERO;
|
|
pRc->dzdy = __MCDZERO;
|
|
return;
|
|
}
|
|
|
|
oneOverArea = __MCDONE / pRc->halfArea;
|
|
|
|
t1 = pRc->dyAC * oneOverArea;
|
|
t2 = pRc->dyBC * oneOverArea;
|
|
t3 = pRc->dxAC * oneOverArea;
|
|
t4 = pRc->dxBC * oneOverArea;
|
|
|
|
dzAC = c->windowCoord.z - a->windowCoord.z;
|
|
dzBC = c->windowCoord.z - b->windowCoord.z;
|
|
pRc->dzdx = (dzAC * t2 - dzBC * t1);
|
|
pRc->dzdy = (dzBC * t3 - dzAC * t4);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VOID FASTCALL __MCDGetZOffsetDelta(DEVRC *pRc)
|
|
//
|
|
// Returns required z offset value for current primitive. Assumes that
|
|
// z deltas are already in RC.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
MCDFLOAT FASTCALL __MCDGetZOffsetDelta(DEVRC *pRc)
|
|
{
|
|
#define FABS(f) ((MCDFLOAT)fabs((double) (f)))
|
|
MCDFLOAT maxdZ;
|
|
|
|
// Find maximum x or y slope:
|
|
|
|
if(FABS(pRc->dzdx) > FABS(pRc->dzdy))
|
|
maxdZ = FABS(pRc->dzdx);
|
|
else
|
|
maxdZ = FABS(pRc->dzdy);
|
|
|
|
return (pRc->MCDState.zOffsetFactor * maxdZ);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VOID FASTCALL __MCDRenderGenTriangle(DEVRC *pRc, MCDVERTEX *a,
|
|
// MCDVERTEX *b, MCDVERTEX *c)
|
|
//
|
|
//
|
|
// This is the generic triangle-rendering routine. This is used if either
|
|
// of the polygon faces are not GL_FILL.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//!! Fix clipping logic, add startXXX logic
|
|
|
|
VOID FASTCALL __MCDRenderGenTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
|
|
MCDVERTEX *c)
|
|
{
|
|
LONG ccw, face;
|
|
MCDVERTEX *oa, *ob, *oc;
|
|
RECTL *pClip;
|
|
ULONG clipNum;
|
|
MCDFLOAT zOffset;
|
|
MCDCOLOR tempA, tempB, tempC;
|
|
ULONG polygonMode;
|
|
BOOL backFace;
|
|
MCDVERTEX *pv;
|
|
|
|
//!! MCDBG_PRINT("__MCDRenderGenTriangle");
|
|
|
|
/*
|
|
** Save old vertex pointers in case we end up not doing a fill.
|
|
*/
|
|
|
|
oa = a; ob = b; oc = c;
|
|
|
|
SORT_AND_CULL_FACE(a, b, c, face, ccw);
|
|
|
|
if ((clipNum = pRc->pEnumClip->c) > 1) {
|
|
pClip = &pRc->pEnumClip->arcl[0];
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
}
|
|
|
|
polygonMode = pRc->polygonMode[face];
|
|
backFace = (pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
|
|
(face == __MCD_BACKFACE);
|
|
|
|
// Pick correct face color and render the triangle:
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_SMOOTH) {
|
|
|
|
if (backFace) {
|
|
SWAP_COLOR(a);
|
|
SWAP_COLOR(b);
|
|
SWAP_COLOR(c);
|
|
}
|
|
|
|
} else { // Flat shading
|
|
|
|
pv = pRc->pvProvoking;
|
|
|
|
if (polygonMode == GL_FILL) {
|
|
if (backFace) {
|
|
SWAP_COLOR(pv);
|
|
}
|
|
} else {
|
|
|
|
SAVE_COLOR(tempA, a);
|
|
SAVE_COLOR(tempB, b);
|
|
SAVE_COLOR(tempC, c);
|
|
|
|
if (backFace) {
|
|
SWAP_COLOR(pv);
|
|
}
|
|
|
|
a->colors[0] = pv->colors[0];
|
|
b->colors[0] = pv->colors[0];
|
|
c->colors[0] = pv->colors[0];
|
|
}
|
|
}
|
|
|
|
// Render triangle using the current polygon mode for the face:
|
|
|
|
switch (pRc->polygonMode[face]) {
|
|
case GL_FILL:
|
|
if (CASTINT(pRc->halfArea) != 0) {
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
while (--clipNum) {
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
}
|
|
}
|
|
break;
|
|
case GL_POINT:
|
|
|
|
(*pRc->beginPointDrawing)(pRc);
|
|
|
|
if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_POINT_ENABLE) {
|
|
__MCDCalcZSlope(pRc, a, b, c);
|
|
zOffset = __MCDGetZOffsetDelta(pRc) + pRc->MCDState.zOffsetUnits;
|
|
oa->windowCoord.z += zOffset;
|
|
ob->windowCoord.z += zOffset;
|
|
oc->windowCoord.z += zOffset;
|
|
}
|
|
|
|
if (oa->flags & MCDVERTEX_EDGEFLAG) {
|
|
(*pRc->drawPoint)(pRc, oa);
|
|
}
|
|
if (ob->flags & MCDVERTEX_EDGEFLAG) {
|
|
(*pRc->drawPoint)(pRc, ob);
|
|
}
|
|
if (oc->flags & MCDVERTEX_EDGEFLAG) {
|
|
(*pRc->drawPoint)(pRc, oc);
|
|
}
|
|
|
|
if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_POINT_ENABLE) {
|
|
oa->windowCoord.z -= zOffset;
|
|
ob->windowCoord.z -= zOffset;
|
|
oc->windowCoord.z -= zOffset;
|
|
}
|
|
|
|
break;
|
|
|
|
case GL_LINE:
|
|
if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_LINE_ENABLE) {
|
|
__MCDCalcZSlope(pRc, a, b, c);
|
|
zOffset = __MCDGetZOffsetDelta(pRc) + pRc->MCDState.zOffsetUnits;
|
|
oa->windowCoord.z += zOffset;
|
|
ob->windowCoord.z += zOffset;
|
|
oc->windowCoord.z += zOffset;
|
|
}
|
|
|
|
(*pRc->beginLineDrawing)(pRc);
|
|
|
|
if ((oa->flags & MCDVERTEX_EDGEFLAG) &&
|
|
(ob->flags & MCDVERTEX_EDGEFLAG) &&
|
|
(oc->flags & MCDVERTEX_EDGEFLAG)) {
|
|
|
|
(*pRc->drawLine)(pRc, oa, ob, TRUE);
|
|
(*pRc->drawLine)(pRc, ob, oc, 0);
|
|
(*pRc->drawLine)(pRc, oc, oa, 0);
|
|
|
|
} else {
|
|
|
|
if (oa->flags & MCDVERTEX_EDGEFLAG)
|
|
(*pRc->drawLine)(pRc, oa, ob, TRUE);
|
|
if (ob->flags & MCDVERTEX_EDGEFLAG)
|
|
(*pRc->drawLine)(pRc, ob, oc, TRUE);
|
|
if (oc->flags & MCDVERTEX_EDGEFLAG)
|
|
(*pRc->drawLine)(pRc, oc, oa, TRUE);
|
|
}
|
|
|
|
(*pRc->endLineDrawing)(pRc);
|
|
|
|
if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_LINE_ENABLE) {
|
|
oa->windowCoord.z -= zOffset;
|
|
ob->windowCoord.z -= zOffset;
|
|
oc->windowCoord.z -= zOffset;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Restore original colors if needed:
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_SMOOTH) {
|
|
|
|
if (backFace) {
|
|
|
|
SWAP_COLOR(a);
|
|
SWAP_COLOR(b);
|
|
SWAP_COLOR(c);
|
|
}
|
|
} else { // Flat shading
|
|
|
|
if (polygonMode == GL_FILL) {
|
|
if (backFace) {
|
|
SWAP_COLOR(pv);
|
|
}
|
|
} else {
|
|
|
|
if (backFace) {
|
|
SWAP_COLOR(pv);
|
|
}
|
|
|
|
RESTORE_COLOR(tempA, a);
|
|
RESTORE_COLOR(tempB, b);
|
|
RESTORE_COLOR(tempC, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VOID FASTCALL __MCDRenderFlatTriangle(DEVRC *pRc, MCDVERTEX *a,
|
|
// MCDVERTEX *b, MCDVERTEX *c)
|
|
//
|
|
//
|
|
// This is the top-level flat-shaded triangle renderer.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID FASTCALL __MCDRenderFlatTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
|
|
MCDVERTEX *c)
|
|
{
|
|
LONG ccw, face;
|
|
RECTL *pClip;
|
|
ULONG clipNum;
|
|
|
|
//!! MCDBG_PRINT("__MCDRenderFlatTriangle");
|
|
|
|
SORT_AND_CULL_FACE(a, b, c, face, ccw);
|
|
if (CASTINT(pRc->halfArea) == 0)
|
|
return;
|
|
|
|
if ((clipNum = pRc->pEnumClip->c) > 1) {
|
|
pClip = &pRc->pEnumClip->arcl[0];
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
}
|
|
|
|
// Pick correct face color and render the triangle:
|
|
|
|
if ((pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
|
|
(face == __MCD_BACKFACE))
|
|
{
|
|
MCDVERTEX *pv = pRc->pvProvoking;
|
|
|
|
SWAP_COLOR(pv);
|
|
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
while (--clipNum) {
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
}
|
|
|
|
SWAP_COLOR(pv);
|
|
}
|
|
else
|
|
{
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
while (--clipNum) {
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VOID FASTCALL __MCDRenderSmoothTriangle(DEVRC *pRc, MCDVERTEX *a,
|
|
// MCDVERTEX *b, MCDVERTEX *c)
|
|
//
|
|
//
|
|
// This is the top-level smooth triangle renderer.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID FASTCALL __MCDRenderSmoothTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
|
|
MCDVERTEX *c)
|
|
{
|
|
LONG ccw, face;
|
|
RECTL *pClip;
|
|
ULONG clipNum;
|
|
|
|
//!! MCDBG_PRINT("__MCDRenderSmoothTriangle");
|
|
|
|
SORT_AND_CULL_FACE(a, b, c, face, ccw);
|
|
if (CASTINT(pRc->halfArea) == 0)
|
|
return;
|
|
|
|
if ((clipNum = pRc->pEnumClip->c) > 1) {
|
|
pClip = &pRc->pEnumClip->arcl[0];
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
}
|
|
|
|
// Pick correct face color and render the triangle:
|
|
|
|
if ((pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
|
|
(face == __MCD_BACKFACE))
|
|
{
|
|
SWAP_COLOR(a);
|
|
SWAP_COLOR(b);
|
|
SWAP_COLOR(c);
|
|
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
while (--clipNum) {
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
}
|
|
|
|
SWAP_COLOR(a);
|
|
SWAP_COLOR(b);
|
|
SWAP_COLOR(c);
|
|
}
|
|
else
|
|
{
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
while (--clipNum) {
|
|
(*pRc->HWSetupClipRect)(pRc, pClip++);
|
|
(*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID FASTCALL __MCDRenderFlatFogTriangle(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2,
|
|
MCDVERTEX *pv3)
|
|
{
|
|
MCDCOLOR c1, c2, c3;
|
|
MCDCOLOR bc1, bc2, bc3;
|
|
MCDCOLOR cProvoking;
|
|
|
|
c1 = pv1->colors[0];
|
|
c2 = pv2->colors[0];
|
|
c3 = pv3->colors[0];
|
|
|
|
// We have to save a copy of the provoking color since we
|
|
// can overwrite it!
|
|
|
|
cProvoking = pRc->pvProvoking->colors[0];
|
|
|
|
__MCDCalcFogColor(pRc, pv1, &pv1->colors[0], &cProvoking);
|
|
__MCDCalcFogColor(pRc, pv2, &pv2->colors[0], &cProvoking);
|
|
__MCDCalcFogColor(pRc, pv3, &pv3->colors[0], &cProvoking);
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
|
|
cProvoking = pRc->pvProvoking->colors[1];
|
|
bc1 = pv1->colors[1];
|
|
bc2 = pv2->colors[1];
|
|
bc3 = pv3->colors[1];
|
|
__MCDCalcFogColor(pRc, pv1, &pv1->colors[1], &cProvoking);
|
|
__MCDCalcFogColor(pRc, pv2, &pv2->colors[1], &cProvoking);
|
|
__MCDCalcFogColor(pRc, pv3, &pv3->colors[1], &cProvoking);
|
|
}
|
|
|
|
(*pRc->renderTriX)(pRc, pv1, pv2, pv3);
|
|
|
|
pv1->colors[0] = c1;
|
|
pv2->colors[0] = c2;
|
|
pv3->colors[0] = c3;
|
|
if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
|
|
pv1->colors[1] = bc1;
|
|
pv2->colors[1] = bc2;
|
|
pv3->colors[1] = bc3;
|
|
}
|
|
}
|
|
|