|
|
/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name
trimesh.cxx
Abstract:
Implement triangle mesh API
Author:
Mark Enstrom (marke) 23-Jun-1996
Enviornment:
User Mode
Revision History:
--*/
#include "precomp.hxx"
#include "dciman.h"
#pragma hdrstop
#if !(_WIN32_WINNT >= 0x500)
//
// temp global
//
HBITMAP hbmDefault;
#if DBG
ULONG DbgRecord = 0; #endif
/******************************Public*Routine******************************\
* vHorizontalLine * * * Arguments: * * * * Return Value: * * * * History: * * 11/20/1996 Mark Enstrom [marke] * \**************************************************************************/
inline VOID vHorizontalLine( PTRIVERTEX pv1, PTRIVERTEX pv2, PTRIANGLEDATA ptData, PTRIDDA ptridda ) { LONG yPosition = ptridda->N0 >> 4; LONG yIndex = yPosition - ptData->rcl.top;
ptridda->L = ptridda->M0 >> 4;
#if DBG
if (DbgRecord >= 1) { DbgPrint("vCalculateLine:Horizontal Line: L = 0x%lx, yIndex = 0x%lx\n",ptridda->L,yIndex); } #endif
if ((yPosition >= ptData->rcl.top) && (yPosition < ptData->rcl.bottom)) { //
// find left edge
//
if (pv1->x <= pv2->x) { //
// left edge
// !!! is the check necessary? overlap from another
// line segment.
//
ptData->TriEdge[yIndex].xLeft = pv1->x >> 4; ptData->TriEdge[yIndex].Red = pv1->Red << 8; ptData->TriEdge[yIndex].Green = pv1->Green << 8; ptData->TriEdge[yIndex].Blue = pv1->Blue << 8; ptData->TriEdge[yIndex].Alpha = pv1->Alpha << 8;
//
// right edge
//
ptData->TriEdge[yIndex].xRight = pv2->x >> 4; } else { //
// left edge
//
ptData->TriEdge[yIndex].xLeft = pv2->x >> 4; ptData->TriEdge[yIndex].Red = pv2->Red << 8; ptData->TriEdge[yIndex].Green = pv2->Green << 8; ptData->TriEdge[yIndex].Blue = pv2->Blue << 8; ptData->TriEdge[yIndex].Alpha = pv2->Alpha << 8;
//
// right edge
//
ptData->TriEdge[yIndex].xRight = pv1->x >> 4; } } }
/******************************Public*Routine******************************\
* vLeftEdgeDDA * * Run line DDA down a left edge of the triangle recording left edge * position and color * * Arguments: * * NumScanLines * yIndex * Red * Green * Blue * Alpha * L * Rb * * Return Value: * * None * * History: * * 11/20/1996 Mark Enstrom [marke] * \**************************************************************************/
inline VOID vLeftEdgeDDA( PTRIANGLEDATA ptData, PTRIDDA ptridda ) { LONG NumScanLines = ptridda->NumScanLines; LONG yIndex = ptridda->yIndex; LONG Red = ptridda->Red; LONG Green = ptridda->Green; LONG Blue = ptridda->Blue; LONG Alpha = ptridda->Alpha; LONG L = ptridda->L; LONG Rb = ptridda->Rb;
#if DBG
if (DbgRecord >= 1) { DbgPrint("vLeftEdgeDDA:Scan yIndex = %li\n",yIndex); } #endif
// Scan all lines, only record lines contained by
// the clipping in ptData->rcl (y)
while (NumScanLines--) {
#if DBG
if (DbgRecord >= 3) { DbgPrint("vCalculateLine:Scan yIndex = %li\n",yIndex); DbgPrint("vCalculateLine:L = %li\n",L); DbgPrint("vCalculateLine:Rb = %li\n",Rb); } #endif
// record left edge
if (yIndex >= 0) { ptData->TriEdge[yIndex].xLeft = L; ptData->TriEdge[yIndex].Red = Red; ptData->TriEdge[yIndex].Green = Green; ptData->TriEdge[yIndex].Blue = Blue; ptData->TriEdge[yIndex].Alpha = Alpha; }
// inc y by one scan line, inc x(L) by integer step
// and inc error term by dR
yIndex++; L += ptridda->dL; Rb -= ptridda->dR;
// inc color components by y and integer x components
Red += (ptridda->dxyRed); Green += (ptridda->dxyGreen); Blue += (ptridda->dxyBlue); Alpha += (ptridda->dxyAlpha);
// check for DDA error term overflow, add one
// more step in x if true, and correct error term
if (Rb < 0) { // DDA
L += ptridda->Linc; Rb += ptridda->dN;
// inc color components
Red += ptData->dRdX; Green += ptData->dGdX; Blue += ptData->dBdX; Alpha += ptData->dAdX; } } }
/******************************Public*Routine******************************\
* vRightEdgeDDA * * Run the line DDA along the right edge of the triangle recording right * edge position * * Arguments: * * NumScanLines * yIndex * Red * Green * Blue * Alpha * L * Rb * * Return Value: * * None * * History: * * 11/25/1996 Mark Enstrom [marke] * \**************************************************************************/
inline VOID vRightEdgeDDA( PTRIANGLEDATA ptData, PTRIDDA ptridda ) { LONG NumScanLines = ptridda->NumScanLines; LONG yIndex = ptridda->yIndex; LONG Red = ptridda->Red; LONG Green = ptridda->Green; LONG Blue = ptridda->Blue; LONG Alpha = ptridda->Alpha; LONG L = ptridda->L; LONG Rb = ptridda->Rb;
// Scan all lines, only record lines contained by
// the clipping in ptData->rcl (y)
#if DBG
if (DbgRecord >= 1) { DbgPrint("vRightEdgeDDA:Scan yIndex = %li\n",yIndex); } #endif
while (ptridda->NumScanLines--) { #if DBG
if (DbgRecord >= 3) { DbgPrint("vCalculateLine:Scan yIndex = %li\n",yIndex); DbgPrint("vCalculateLine:L = %li\n",L); DbgPrint("vCalculateLine:Rb = %li\n",Rb); } #endif
// record left, right edge
if (yIndex >= 0) { ptData->TriEdge[yIndex].xRight = L; }
// inc y by one scan line, inc x(L) by integer step
// and inc error term by dR
yIndex++; L += ptridda->dL; Rb -= ptridda->dR;
// inc color components by y and integer x components
Red += (ptridda->dxyRed); Green += (ptridda->dxyGreen); Blue += (ptridda->dxyBlue); Alpha += (ptridda->dxyAlpha);
// check for DDA error term overflow, add one
// more step in x if true, and correct error term
if (Rb < 0) { // DDA
L += ptridda->Linc; Rb += ptridda->dN;
// inc color components
Red += ptData->dRdX; Green += ptData->dGdX; Blue += ptData->dBdX; Alpha += ptData->dAdX; } } }
/******************************Public*Routine******************************\
* vCalulateLine * * * Arguments: * * * * Return Value: * * * * History: * * 11/20/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vCalculateLine( PTRIVERTEX pv1, PTRIVERTEX pv2, PTRIANGLEDATA ptData, BOOL bLeftEdge ) { TRIDDA tridda;
//
// initial y component
//
tridda.dxyRed = ptData->dRdY; tridda.dxyGreen = ptData->dGdY; tridda.dxyBlue = ptData->dBdY; tridda.dxyAlpha = ptData->dAdY;
#if DBG
if (DbgRecord >= 1) { DbgPrint("vCalculateLine:\n"); DbgPrint("vCalculateLine:pv1.x = %li, pv1.y = %li\n",pv1->x,pv1->y); DbgPrint("vCalculateLine:pv1->Red = 0x%lx, pv1->Green = 0x%lx, pv1->Blue = 0x%lx\n", pv1->Red,pv1->Green,pv1->Blue); DbgPrint("vCalculateLine:pv2.x = %li, pv2.y = %li\n",pv2->x,pv2->y); DbgPrint("vCalculateLine:pv2->Red = 0x%lx, pv2->Green = 0x%lx, pv2->Blue = 0x%lx\n", pv2->Red,pv2->Green,pv2->Blue); } #endif
//
// Arrange lines, must run in positive delta y.
// !!! what other effect of swap is there? !!!
//
if (pv2->y >= pv1->y) { tridda.dN = pv2->y - pv1->y; tridda.dM = pv2->x - pv1->x; tridda.N0 = pv1->y; tridda.M0 = pv1->x; tridda.Red = pv1->Red << 8; tridda.Green = pv1->Green << 8; tridda.Blue = pv1->Blue << 8; tridda.Alpha = pv1->Alpha << 8; } else { tridda.dN = pv1->y - pv2->y; tridda.dM = pv1->x - pv2->x; tridda.N0 = pv2->y; tridda.M0 = pv2->x; tridda.Red = pv2->Red << 8; tridda.Green = pv2->Green << 8; tridda.Blue = pv2->Blue << 8; tridda.Alpha = pv2->Alpha << 8; tridda.dxyRed = -tridda.dxyRed; tridda.dxyGreen = -tridda.dxyGreen; tridda.dxyBlue = -tridda.dxyBlue; tridda.dxyAlpha = -tridda.dxyAlpha; }
//
// Check for horizontal line, dN == 0 is a horizontal line.
// In this case just record the end points.
//
if (tridda.dN == 0) { vHorizontalLine(pv1,pv2,ptData,&tridda); } else { //
// this is as cryptic as ASM at the moment
//
LONG l0,Frac;
tridda.Linc = 1;
//
// yIndex is the offset into the edge array for
// the current line
//
tridda.yIndex = (tridda.N0 >> 4) - ptData->y0;
tridda.NumScanLines = (tridda.dN >> 4);
LONG NMax = (tridda.N0 >> 4) + tridda.NumScanLines;
//
// make sure scan lines do not overrun buffer due to
// clipping
//
if ( ((tridda.N0 >> 4) > ptData->rcl.bottom) || (NMax < ptData->rcl.top) ) { // nothing to draw
return; } else if (NMax > ptData->rcl.bottom) { tridda.NumScanLines = tridda.NumScanLines - (NMax - ptData->rcl.bottom); }
tridda.j = tridda.N0 >> 4;
tridda.C = ((LONGLONG)tridda.M0 * (LONGLONG)tridda.dN) - ((LONGLONG)tridda.N0 * (LONGLONG)tridda.dM) -1;
tridda.C = (tridda.C >> 4) + tridda.dN;
LONGLONG LongL;
if (tridda.dM > 0) { tridda.dL = tridda.dM / tridda.dN; tridda.dR = tridda.dM - tridda.dL * tridda.dN; } else if (tridda.dM < 0) { // negative divide
LONG dLQ,dLR;
tridda.dM = -tridda.dM;
dLQ = (tridda.dM - 1) / tridda.dN; dLR = tridda.dM - 1 - (dLQ * tridda.dN); tridda.dL = -(dLQ + 1); tridda.dR = tridda.dN - dLR - 1; } else { // dM = 0
tridda.dL = 0; tridda.dR = 0; }
l0 = tridda.j * tridda.dL; LongL = tridda.j * tridda.dR + tridda.C;
if (LongL > 0) { Frac = (LONG)(LongL/tridda.dN); // integer portion
} else if (LongL < 0) { LONG Q = (LONG)((-LongL - 1)/tridda.dN); Frac = -(Q + 1); } else { Frac = 0; }
tridda.R = (LONG)(LongL - (Frac * tridda.dN)); tridda.L = l0 + Frac; tridda.Rb = tridda.dN - tridda.R - 1;
//
// Calculate color steps for dx !!! could it be more expensive !!!
//
if (tridda.dL != 0) { tridda.dxyRed = tridda.dxyRed + (LONG)((ptData->dRdXA * tridda.dL) / ptData->Area); tridda.dxyGreen = tridda.dxyGreen + (LONG)((ptData->dGdXA * tridda.dL) / ptData->Area); tridda.dxyBlue = tridda.dxyBlue + (LONG)((ptData->dBdXA * tridda.dL) / ptData->Area); tridda.dxyAlpha = tridda.dxyAlpha + (LONG)((ptData->dAdXA * tridda.dL) / ptData->Area); }
#if DBG
if (DbgRecord >= 1) { LONG CL = (LONG)tridda.C; LONG CH = (LONG)(tridda.C/4294967296); DbgPrint("vCalculateLine:Normal Line\n"); DbgPrint("vCalculateLine:N0 = %li\n",tridda.N0); DbgPrint("vCalculateLine:dN = %li\n",tridda.dN); DbgPrint("vCalculateLine:M0 = %li\n",tridda.M0); DbgPrint("vCalculateLine:dM = %li\n",tridda.dM); DbgPrint("vCalculateLine:C = %08lx %08lx\n",CH,CL); DbgPrint("vCalculateLine:Frac = %li\n",Frac); DbgPrint("vCalculateLine:l0 = %li\n",l0); DbgPrint("vCalculateLine:L = %li\n",tridda.L); DbgPrint("vCalculateLine:dL = %li\n",tridda.dL); DbgPrint("vCalculateLine:R = %li\n",tridda.R); DbgPrint("vCalculateLine:dR = %li\n",tridda.dR); DbgPrint("vCalculateLine:Rb = %li\n",tridda.Rb); DbgPrint("vCalculateLine:dxyRed = 0x%lx\n",tridda.dxyRed); DbgPrint("vCalculateLine:dxyGreen = 0x%lx\n",tridda.dxyGreen); DbgPrint("vCalculateLine:dxyBlue = 0x%lx\n",tridda.dxyBlue); DbgPrint("vCalculateLine:dxyAlpha = 0x%lx\n",tridda.dxyAlpha);
} #endif
//
// left or right edge
//
if (bLeftEdge) { vLeftEdgeDDA(ptData,&tridda); } else { vRightEdgeDDA(ptData,&tridda); } } }
/******************************Public*Routine******************************\
* vCalulateColorGradient * * * Arguments: * * * * Return Value: * * * * History: * * 11/20/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vCalulateColorGradient( PTRIVERTEX pv0, PTRIVERTEX pv1, PTRIVERTEX pv2, LONG C0, LONG C1, LONG C2, PLONGLONG pArea, PLONGLONG pGradXA, PLONG pGradX, PLONG pGradY ) { LONG dCdX = 0; LONG dCdY = 0; LONGLONG t1,t2,t3,tAll;
C0 = C0 << 8; C1 = C1 << 8; C2 = C2 << 8;
//
// dY
//
t1 = - ((LONGLONG)C0 * (LONGLONG)(pv2->x - pv1->x)); t2 = - ((LONGLONG)C1 * (LONGLONG)(pv0->x - pv2->x)); t3 = - ((LONGLONG)C2 * (LONGLONG)(pv1->x - pv0->x)); tAll = 16 * (t1 + t2 + t3);
if (tAll > 0) { dCdY = (LONG)(tAll / *pArea); } else if (tAll < 0) { tAll = -tAll; dCdY = (LONG)((tAll - 1) / *pArea); dCdY = -(dCdY + 1); }
*pGradY = dCdY;
//
// Divide by area to get single step x. Keep undivided
// value around to calc multiple integer step in x
//
t1 = - ((LONGLONG)C0 * (LONGLONG)(pv2->y - pv1->y)); t2 = - ((LONGLONG)C1 * (LONGLONG)(pv0->y - pv2->y)); t3 = - ((LONGLONG)C2 * (LONGLONG)(pv1->y - pv0->y)); tAll = t1; tAll += t2; tAll += t3; tAll *= 16;
*pGradXA = tAll;
dCdX = 0;
if (tAll > 0) { dCdX = (LONG)(tAll / *pArea); } else if (tAll < 0) { tAll = -tAll; dCdX = (LONG)((tAll - 1) / *pArea); dCdX = -(dCdX + 1); }
*pGradX = dCdX; }
/******************************Public*Routine******************************\
* vCalculateTriangle * * Calculate color gradients, then scan the three lines that make up the * triangle. Fill out a structure that can later be used to fill in the * interior of the triangle. * * Arguments: * * * * Return Value: * * * * History: * * 17-Jul-1996 -by- Mark Enstrom [marke] * \**************************************************************************/
BOOL bCalculateTriangle( PTRIVERTEX pv0, PTRIVERTEX pv1, PTRIVERTEX pv2, PTRIANGLEDATA ptData ) { LONG index;
#if DBG
if (DbgRecord >= 1) { DbgPrint("vCalculateTriangle:\n"); DbgPrint("vCalculateTriangle:rcl = [%li,%li] to [%li,%li]\n", ptData->rcl.left, ptData->rcl.top, ptData->rcl.right, ptData->rcl.bottom ); DbgPrint("vCalculateTriangle:pv0.x = %li, pv0.y = %li\n",pv0->x,pv0->y); DbgPrint("vCalculateTriangle:pv0->Red = 0x%lx, pv0->Green = 0x%lx, pv0->Blue = 0x%lx\n", pv0->Red,pv0->Green,pv0->Blue); DbgPrint("vCalculateTriangle:pv1.x = %li, pv1.y = %li\n",pv1->x,pv1->y); DbgPrint("vCalculateTriangle:pv1->Red = 0x%lx, pv1->Green = 0x%lx, pv1->Blue = 0x%lx\n", pv1->Red,pv1->Green,pv1->Blue); DbgPrint("vCalculateTriangle:pv2.x = %li, pv2.y = %li\n",pv2->x,pv2->y); DbgPrint("vCalculateTriangle:pv2->Red = 0x%lx, pv2->Green = 0x%lx, pv2->Blue = 0x%lx\n", pv2->Red,pv2->Green,pv2->Blue);
} #endif
//
// calc area, color gradients in x,y
//
// area = (v2-v0) X (v1 - v2)
//
LONGLONG v12x = pv1->x - pv2->x; LONGLONG v12y = pv1->y - pv2->y;
LONGLONG v02x = pv0->x - pv2->x; LONGLONG v02y = pv0->y - pv2->y;
LONGLONG Area = (v12y * v02x) - (v12x * v02y); ptData->Area = Area;
#if DBG
if (DbgRecord >= 1) { LONG AreaL = (LONG)Area; LONG AreaH = (LONG)(Area/4294967296); DbgPrint("vCalculateTriangle:v12x = %lx\n",v12x); DbgPrint("vCalculateTriangle:v12y = %lx\n",v12y); DbgPrint("vCalculateTriangle:v02x = %lx\n",v02x); DbgPrint("vCalculateTriangle:v02y = %lx\n",v02y); DbgPrint("vCalculateTriangle:Area = %lx %lx\n",AreaH,AreaL); } #endif
//
// if area is zero then this is a degenerate triangle
//
if (Area == 0) { return(FALSE); }
//
// calc min and max drawing y
//
ptData->y0 = MAX((pv0->y >> 4),ptData->rcl.top); LONG MaxY = (MAX(pv1->y,pv2->y)) >> 4; ptData->y1 = MIN(MaxY,ptData->rcl.bottom);
//
// calculate color gradients for each color. There is a little redundant
// work here with calculation of deltas. Should make this one call or
// do it in place.
//
vCalulateColorGradient(pv0,pv1,pv2,pv0->Red ,pv1->Red ,pv2->Red ,&Area,&ptData->dRdXA,&ptData->dRdX,&ptData->dRdY); vCalulateColorGradient(pv0,pv1,pv2,pv0->Green,pv1->Green,pv2->Green,&Area,&ptData->dGdXA,&ptData->dGdX,&ptData->dGdY); vCalulateColorGradient(pv0,pv1,pv2,pv0->Blue ,pv1->Blue ,pv2->Blue ,&Area,&ptData->dBdXA,&ptData->dBdX,&ptData->dBdY); vCalulateColorGradient(pv0,pv1,pv2,pv0->Alpha,pv1->Alpha,pv2->Alpha,&Area,&ptData->dAdXA,&ptData->dAdX,&ptData->dAdY);
#if DBG
if (DbgRecord >= 1) { DbgPrint("vCalculateTriangle:dRdx = 0x%lx,dRdy = 0x%lx\n",ptData->dRdX,ptData->dRdY); DbgPrint("vCalculateTriangle:dGdx = 0x%lx,dGdy = 0x%lx\n",ptData->dGdX,ptData->dGdY); DbgPrint("vCalculateTriangle:dBdx = 0x%lx,dBdy = 0x%lx\n",ptData->dBdX,ptData->dBdY); DbgPrint("vCalculateTriangle:dAdx = 0x%lx,dAdy = 0x%lx\n",ptData->dAdX,ptData->dAdY); } #endif
//
// draw lines into data array
//
vCalculateLine(pv0,pv1,ptData,FALSE); vCalculateLine(pv1,pv2,ptData,(pv1->y > pv2->y)); vCalculateLine(pv2,pv0,ptData,TRUE);
return(TRUE); }
/**************************************************************************\
* bCalculateTriangle * * * Arguments: * * * * Return Value: * * * * History: * * 2/12/1997 Mark Enstrom [marke] * \**************************************************************************/
BYTE GetNearestEntry( PULONG prgbIn, ULONG ulNumEntries, ALPHAPIX MatchColor ) { LONG lError = MAX_INT; ULONG ulBest = 0; ULONG ulIndex; LPRGBQUAD prgb = (LPRGBQUAD)prgbIn;
for (ulIndex=0;ulIndex<ulNumEntries;ulIndex++) { LONG eRed = (LONG)(MatchColor.pix.r - prgb->rgbRed); LONG eGreen = (LONG)(MatchColor.pix.g - prgb->rgbGreen); LONG eBlue = (LONG)(MatchColor.pix.b - prgb->rgbBlue);
eRed = eRed*eRed + eGreen*eGreen + eBlue*eBlue;
if (eRed < lError) { lError = eRed; ulBest = ulIndex; }
prgb++; }
return((BYTE)ulBest); }
/**************************************************************************\
* GenColorXform332 * * * Arguments: * * * * Return Value: * * * * History: * * 2/12/1997 Mark Enstrom [marke] * \**************************************************************************/ PBYTE pGenColorXform332( PULONG ppalIn, ULONG ulNumEntries ) { ASSERTGDI((ppalIn != NULL),"pGenColorXform332 called with NULL input palette\n"); ASSERTGDI((ulNumEntries <= 256),"pGenColorXform332 called with invalid ulNumEntries\n");
if ((ppalIn == NULL) || (ulNumEntries > 256)) { return(FALSE); }
//
// check for halftone palette
//
if (ulNumEntries == 256) { if (bIsHalftonePalette(ppalIn)) { return(gHalftoneColorXlate332); } }
//
// allocate and generate color lookup table
//
PBYTE pxlate = (PBYTE)LOCALALLOC(256);
if (pxlate) { PBYTE pXlateTable = pxlate;
//
// generate color xlate from RGB 332 to palette
//
BYTE Red[8] = {0,37,73,110,146,183,219,255}; BYTE Green[8] = {0,37,73,110,146,183,219,255}; BYTE Blue[4] = {0,85,171,255}; //
// ppalOut must be a 256 entry table
//
ULONG ulB,ulG,ulR; ALPHAPIX Pixel; for (ulR = 0;ulR<8;ulR++) { Pixel.pix.r = Red[ulR]; for (ulG = 0;ulG<8;ulG++) { Pixel.pix.g = Green[ulG]; for (ulB = 0;ulB<4;ulB++) { Pixel.pix.b = Blue[ulB]; *pXlateTable++ = GetNearestEntry(ppalIn,ulNumEntries,Pixel); } } } }
return(pxlate); }
#endif
|