|
|
/*++
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
extern PFNGRFILL gpfnGradientFill;
#if !(_WIN32_WINNT >= 0x500)
/**************************************************************************\
* gulDither32 - 4-4 dither matrix * * * History: * * 1/31/1997 Mark Enstrom [marke] * \**************************************************************************/
ULONG gulDither32[] = { 0x00000000, 0x00008000, 0x00002000, 0x0000a000,
0x0000c000, 0x00004000, 0x0000e000, 0x00006000,
0x00003000, 0x0000b000, 0x00001000, 0x00009000,
0x0000f000, 0x00007000, 0x0000d000, 0x00005000 };
/******************************Public*Routine******************************\
* vFillTriDIBUnreadable * * If a surface can't be read, draw triangle to a scan line, then call * SetDIBitsToDevice on each scan line * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIBUnreadable( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; LONG cxClip = ptData->rcl.right - ptData->rcl.left; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; LONG dAlpha = ptData->dAdX; ULONG Red; ULONG Green; ULONG Blue; ULONG Alpha; BITMAPINFO bmi;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = cxClip; bmi.bmiHeader.biHeight = 1; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 0; bmi.bmiHeader.biXPelsPerMeter = 0; bmi.bmiHeader.biYPelsPerMeter = 0; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0;
PBYTE pDst = (PBYTE)LOCALALLOC(4 * cxClip);
if (pDst == NULL) { return; }
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
while(yScan < yScanBottom) { PULONG pulDstX; PULONG pulDstScanRight,pulDstScanLeft; LONG xScanRight; LONG xScanLeft;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue; Alpha = pEdge->Alpha;
xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
if (xScanLeft < xScanRight) { pulDstX = (PULONG)pDst + xScanLeft - ptData->rcl.left; pulDstScanRight = (PULONG)pDst + xScanRight - ptData->rcl.left;
//
// skip span from left edge scan to left edge clip rect
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; Alpha += dAlpha * GradientLeft; }
//
// fill span within clipping boundary
//
while (pulDstX < pulDstScanRight) { *pulDstX = ((Alpha & 0x00ff0000) << 8) | ((Red & 0x00ff0000) ) | ((Green & 0x00ff0000) >> 8) | ((Blue & 0x00ff0000) >> 16);
pulDstX++; Red += dRed; Green += dGreen; Blue += dBlue; Alpha += dAlpha; }
//
// write span to device
//
SetDIBitsToDevice(pDibInfo->hdc, xScanLeft, yScan, xScanRight-xScanLeft, 1, xScanLeft-ptData->rcl.left, 0, 0, 1, pDst, &bmi, DIB_RGB_COLORS ); }
pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillTriDIB32BGRA * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB32BGRA( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; LONG dAlpha = ptData->dAdX; ULONG Red; ULONG Green; ULONG Blue; ULONG Alpha;
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
while(yScan < yScanBottom) { PULONG pulDstX; PULONG pulDstScanRight,pulDstScanLeft;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue; Alpha = pEdge->Alpha;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
if (xScanLeft < xScanRight) { pulDstX = (PULONG)pDst + xScanLeft; pulDstScanRight = (PULONG)pDst + xScanRight;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; Alpha += dAlpha * GradientLeft; }
//
// fill span
//
while (pulDstX < pulDstScanRight) { *pulDstX = ((Alpha & 0x00ff0000) << 8) | ((Red & 0x00ff0000) ) | ((Green & 0x00ff0000) >> 8) | ((Blue & 0x00ff0000) >> 16);
pulDstX++; Red += dRed; Green += dGreen; Blue += dBlue; Alpha += dAlpha; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillTriDIB32RGB * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB32RGB( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue;
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
while(yScan < yScanBottom) { PULONG pulDstX; PULONG pulDstScanRight,pulDstScanLeft;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
if (xScanLeft < xScanRight) { pulDstX = (PULONG)pDst + xScanLeft; pulDstScanRight = (PULONG)pDst + xScanRight;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
//
// fill scan
//
while (pulDstX < pulDstScanRight) { *pulDstX = ((Red & 0x00ff0000)) | ((Green & 0x00ff0000) >> 8) | ((Blue & 0x00ff0000) >> 16);
pulDstX++; Red += dRed; Green += dGreen; Blue += dBlue; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillTriDIB24RGB * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB24RGB( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue;
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
while(yScan < yScanBottom) { PBYTE pDstX; PBYTE pDstScanRight;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
if (xScanLeft < xScanRight) { pDstX = pDst + 3 * xScanLeft; pDstScanRight = pDst + 3 * xScanRight;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
while (pDstX < pDstScanRight) { *pDstX = (BYTE)((Blue & 0x00ff0000) >> 16); *(pDstX+1) = (BYTE)((Green & 0x00ff0000) >> 16); *(pDstX+2) = (BYTE)((Red & 0x00ff0000) >> 16);
Red += dRed; Green += dGreen; Blue += dBlue;
pDstX+=3; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillDIB16_565 * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB16_565( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue; PULONG pulDither;
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
LONG yDitherOrg = ptData->ptDitherOrg.y; LONG xDitherOrg = ptData->ptDitherOrg.x;
while(yScan < yScanBottom) { PUSHORT pusDstX; PUSHORT pusDstScanRight;
pulDither = &gulDither32[0] + 4 * ((yScan+yDitherOrg) & 3);
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
if (xScanLeft < xScanRight) { pusDstX = (PUSHORT)pDst + xScanLeft; pusDstScanRight = (PUSHORT)pDst + xScanRight;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
//
// Gradient fill scan line with dither
//
while (pusDstX < pusDstScanRight) { ULONG ulDither = pulDither[(((ULONG)pusDstX >> 1)+xDitherOrg) & 3];
BYTE iRed = (BYTE)(((Red >> 3) + ulDither) >> 16); BYTE iGreen = (BYTE)(((Green >> 2) + ulDither) >> 16); BYTE iBlue = (BYTE)(((Blue >> 3) + ulDither) >> 16);
//
// check for overflow
//
if (((iRed | iBlue) & 0xe0) || (iGreen & 0xc0)) { if (iRed & 0xe0) { iRed = 0x1f; }
if (iBlue & 0xe0) { iBlue = 0x1f; }
if (iGreen & 0xc0) { iGreen = 0x3f; } }
*pusDstX = rgb565(iRed,iGreen,iBlue);
pusDstX++; Red += dRed; Green += dGreen; Blue += dBlue; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillTriDIB16_555 * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB16_555( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue; PULONG pulDither;
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
LONG yDitherOrg = ptData->ptDitherOrg.y; LONG xDitherOrg = ptData->ptDitherOrg.x;
while(yScan < yScanBottom) { PUSHORT pusDstX; PUSHORT pusDstScanRight;
pulDither = &gulDither32[0] + 4 * ((yScan+yDitherOrg) & 3);
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
if (xScanLeft < xScanRight) { pusDstX = (PUSHORT)pDst + xScanLeft; pusDstScanRight = (PUSHORT)pDst + xScanRight;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
//
// Gradient fill scan line with dither
//
while (pusDstX < pusDstScanRight) { ULONG ulDither = pulDither[(((ULONG)pusDstX >> 1)+xDitherOrg) & 3];
BYTE iRed = (BYTE)(((Red >> 3) + ulDither) >> 16); BYTE iGreen = (BYTE)(((Green >> 3) + ulDither) >> 16); BYTE iBlue = (BYTE)(((Blue >> 3) + ulDither) >> 16);
//
// check for overflow
//
if ((iRed | iBlue | iGreen) & 0xe0) { if (iRed & 0xe0) { iRed = 0x1f; }
if (iBlue & 0xe0) { iBlue = 0x1f; }
if (iGreen & 0xe0) { iGreen = 0x1f; } }
*pusDstX = rgb555(iRed,iGreen,iBlue);
pusDstX++; Red += dRed; Green += dGreen; Blue += dBlue; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillDIB8 * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB8( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue; PBYTE pxlate = pDibInfo->pxlate332; PBYTE pDitherMatrix; PBYTE pSaturationTable;
//
// get/build rgb to palette table
//
if (pxlate == NULL) { WARNING("vTriFillDIB8:Failed to generate rgb555 xlate table\n"); return; }
//
// either use default palette or halftone palette dither
//
if (pxlate == gHalftoneColorXlate332) { pDitherMatrix = gDitherMatrix16x16Halftone; pSaturationTable = HalftoneSaturationTable; } else { pDitherMatrix = gDitherMatrix16x16Default; pSaturationTable = DefaultSaturationTable; }
//
// scan from top to bottom of triangle scan lines
//
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
LONG yDitherOrg = ptData->ptDitherOrg.y; LONG xDitherOrg = ptData->ptDitherOrg.x;
while(yScan < yScanBottom) { PBYTE pjDstX; PBYTE pjDstScanRight,pjDstScanLeft;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
PBYTE pDitherLevel = &pDitherMatrix[(16 * ((yScan+yDitherOrg) & DITHER_8_MASK_Y))];
if (xScanLeft < xScanRight) { pjDstX = pDst + xScanLeft; pjDstScanRight = pDst + xScanRight;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
//
// gradient fill scan with dither
//
while (pjDstX < pjDstScanRight) { //
// offset into dither array
//
BYTE jDitherMatrix = *(pDitherLevel + (((ULONG)pjDstX+xDitherOrg) & DITHER_8_MASK_X));
ULONG iRed = (ULONG)((Red >> 16) & 0xff); ULONG iGreen = (ULONG)((Green >> 16) & 0xff); ULONG iBlue = (ULONG)((Blue >> 16) & 0xff);
iRed = pSaturationTable[iRed + jDitherMatrix]; iGreen = pSaturationTable[iGreen + jDitherMatrix]; iBlue = pSaturationTable[iBlue + jDitherMatrix];
BYTE jIndex;
GRAD_PALETTE_MATCH(jIndex,pxlate,((BYTE)iRed),((BYTE)iGreen),((BYTE)iBlue));
*pjDstX = jIndex;
pjDstX++; Red += dRed; Green += dGreen; Blue += dBlue; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillDIB4 * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB4( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue; PBYTE pDitherMatrix = gDitherMatrix16x16Default; PBYTE pSaturationTable = DefaultSaturationTable; PBYTE pxlate = pDibInfo->pxlate332;
if (pxlate == NULL) { WARNING("Failed to generate rgb555 xlate table\n"); return; }
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
LONG yDitherOrg = ptData->ptDitherOrg.y; LONG xDitherOrg = ptData->ptDitherOrg.x;
while(yScan < yScanBottom) { PBYTE pjDstX; LONG iDstX;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
PBYTE pDitherLevel = &pDitherMatrix[(16 * ((yScan+yDitherOrg) & DITHER_8_MASK_Y))];
if (xScanLeft < xScanRight) { pjDstX = pDst + (xScanLeft/2); iDstX = xScanLeft & 1;
//
// skip pixels from left edge to left clip, while
// incrementing gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
//
// fill scan line with dither
//
PALETTEENTRY palEntry; palEntry.peFlags = 2;
while (xScanLeft < xScanRight) { //
// offset into dither array
//
BYTE jDitherMatrix = *(pDitherLevel + ((xScanLeft+xDitherOrg) & DITHER_8_MASK_X));
ULONG iRed = (ULONG)((Red >> 16) & 0xff); ULONG iGreen = (ULONG)((Green >> 16) & 0xff); ULONG iBlue = (ULONG)((Blue >> 16) & 0xff);
iRed = pSaturationTable[iRed + jDitherMatrix]; iGreen = pSaturationTable[iGreen + jDitherMatrix]; iBlue = pSaturationTable[iBlue + jDitherMatrix];
BYTE jIndex;
GRAD_PALETTE_MATCH(jIndex,pxlate,((BYTE)iRed),((BYTE)iGreen),((BYTE)iBlue));
//
// write nibble
//
if (iDstX) { iDstX = 0; *pjDstX = (*pjDstX & 0xf0) | jIndex; pjDstX++; } else { *pjDstX = (*pjDstX & 0x0f) | (jIndex << 4); iDstX = 1; }
xScanLeft++; Red += dRed; Green += dGreen; Blue += dBlue; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* vFillDIB1 * * * Arguments: * * * * Return Value: * * * * History: * * 11/21/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vFillTriDIB1( PDIBINFO pDibInfo, PTRIANGLEDATA ptData ) { LONG lDelta = pDibInfo->stride; LONG yScan = ptData->y0; LONG yScanBottom; PBYTE pDst = (PBYTE)pDibInfo->pvBase + lDelta * yScan; PTRIEDGE pEdge = &ptData->TriEdge[0]; LONG dRed = ptData->dRdX; LONG dGreen = ptData->dGdX; LONG dBlue = ptData->dBdX; ULONG Red; ULONG Green; ULONG Blue; PBYTE pxlate = pDibInfo->pxlate332; PBYTE pDitherMatrix = gDitherMatrix16x16Default;
//
// must have palette xlate
//
if (pxlate == NULL) { WARNING("Failed to generate rgb555 xlate table\n"); return; }
yScanBottom = MIN(ptData->rcl.bottom,ptData->y1);
LONG yDitherOrg = ptData->ptDitherOrg.y; LONG xDitherOrg = ptData->ptDitherOrg.x;
while(yScan < yScanBottom) { PBYTE pjDstX; LONG iDstX;
LONG ScanRight; LONG ScanLeft; LONG xScan;
Red = pEdge->Red; Green = pEdge->Green; Blue = pEdge->Blue;
LONG xScanLeft = MAX(pEdge->xLeft,ptData->rcl.left); LONG xScanRight = MIN(pEdge->xRight,ptData->rcl.right);
PBYTE pDitherLevel = &pDitherMatrix[(16 * ((yScan+yDitherOrg) & DITHER_8_MASK_Y))];
if (xScanLeft < xScanRight) { pjDstX = pDst + (xScanLeft/8); iDstX = xScanLeft & 7;
//
// skip clipped out portion of scan line whille
// running color gradient
//
LONG GradientLeft = ptData->rcl.left - pEdge->xLeft;
if (GradientLeft > 0) { Red += dRed * GradientLeft; Green += dGreen * GradientLeft; Blue += dBlue * GradientLeft; }
PALETTEENTRY palEntry; palEntry.peFlags = 2;
while (xScanLeft < xScanRight) { //
// offset into dither array
//
BYTE jDitherMatrix = 2 * (*(pDitherLevel + ((xScanLeft+xDitherOrg) & DITHER_8_MASK_X)));
ULONG iRed = (ULONG)((Red >> 16) & 0xff); ULONG iGreen = (ULONG)((Green >> 16) & 0xff); ULONG iBlue = (ULONG)((Blue >> 16) & 0xff);
//
// add dither and saturate. 1bpp non-optimized
//
iRed = iRed + jDitherMatrix;
if (iRed >= 255) { iRed = 255; } else { iRed = 0; }
iGreen = iGreen + jDitherMatrix;
if (iGreen >= 255) { iGreen = 255; } else { iGreen = 0; }
iBlue = iBlue + jDitherMatrix;
if (iBlue >= 255) { iBlue = 255; } else { iBlue = 0; }
BYTE jIndex;
//
// pjVector is known to be identity, so could make new macro for
// palette_match_1 if perf ever an issue
//
GRAD_PALETTE_MATCH(jIndex,pxlate,((BYTE)iRed),((BYTE)iGreen),((BYTE)iBlue));
//
// write bit (!!! completely and totally non-optimized)
//
LONG iShift = 7 - iDstX; BYTE OrMask = 1 << iShift; BYTE AndMask = ~OrMask;
jIndex = jIndex << iShift;
*pjDstX = (*pjDstX & AndMask) | jIndex;
iDstX++;
if (iDstX == 8) { iDstX = 0; pjDstX++; }
xScanLeft++; Red += dRed; Green += dGreen; Blue += dBlue; } }
pDst += lDelta; pEdge++; yScan++; } }
/******************************Public*Routine******************************\
* DIBTriangleMesh * * * Arguments: * * * * Return Value: * * * * History: * * 12/4/1996 Mark Enstrom [marke] * \**************************************************************************/
BOOL DIBTriangleMesh( HDC hdc, PTRIVERTEX pVertex, ULONG nVertex, PGRADIENT_TRIANGLE pMesh, ULONG nMesh, ULONG ulMode, PRECTL prclPhysExt, PDIBINFO pDibInfo, PPOINTL pptlDitherOrg, BOOL bReadable ) { BOOL bStatus = TRUE; RECTL rclDst; RECTL rclDstWk; ULONG ulIndex; PTRIANGLEDATA ptData = NULL; PULONG pulDIB = NULL; PFN_TRIFILL pfnTriFill = NULL;
pfnTriFill = pfnTriangleFillFunction(pDibInfo,bReadable);
if (pfnTriFill == NULL) { WARNING("DIBTriangleMesh:Can't draw to surface\n"); return(TRUE); }
//
// work in physical map mode, restore before return
//
ULONG OldMode = SetMapMode(hdc,MM_TEXT);
//
// fake up scale !!!
//
for (ulIndex=0;ulIndex<nVertex;ulIndex++) { pVertex[ulIndex].x = pVertex[ulIndex].x * 16; pVertex[ulIndex].y = pVertex[ulIndex].y * 16; }
//
// limit recorded triangle to clipped output
//
LONG dxTri = prclPhysExt->right - prclPhysExt->left; LONG dyTri = prclPhysExt->bottom - prclPhysExt->top;
//
// check for clipped out
//
if ((dyTri > 0) && (dxTri > 0)) { //
// allocate structure to hold scan line data for all triangles
// drawn during this call
//
ptData = (PTRIANGLEDATA)LOCALALLOC(sizeof(TRIANGLEDATA) + (dyTri-1) * sizeof(TRIEDGE));
if (ptData != NULL) { //
// draw each triangle
//
ptData->rcl = *prclPhysExt; ptData->DrawMode = ulMode; ptData->ptDitherOrg = *pptlDitherOrg;
for (ulIndex=0;ulIndex<nMesh;ulIndex++) { ULONG ulTri1 = pMesh[ulIndex].Vertex1; ULONG ulTri2 = pMesh[ulIndex].Vertex2; ULONG ulTri3 = pMesh[ulIndex].Vertex3;
//
// make sure index are in array
//
if ( (ulTri1 > nVertex) || (ulTri2 > nVertex) || (ulTri3 > nVertex) ) { bStatus = FALSE; break; }
PTRIVERTEX pv0 = &pVertex[ulTri1]; PTRIVERTEX pv1 = &pVertex[ulTri2]; PTRIVERTEX pv2 = &pVertex[ulTri3]; PTRIVERTEX pvt;
if (pv0->y > pv1->y) { SWAP_VERTEX(pv0,pv1,pvt); }
if (pv1->y > pv2->y) { SWAP_VERTEX(pv1,pv2,pvt); }
if (pv0->y > pv1->y) { SWAP_VERTEX(pv0,pv1,pvt); }
if (pv2->x > pv1->x) { SWAP_VERTEX(pv1,pv2,pvt); }
//
// record triangle
//
bStatus = bCalculateTriangle(pv0,pv1,pv2,ptData);
if (bStatus) { //
// draw scan lines
//
(*pfnTriFill)(pDibInfo,ptData); } } } else { DbgPrint("DIBTriangleMesh:Failed alloc \n"); bStatus = FALSE; }
//
// cleanup
//
if (ptData) { LOCALFREE(ptData); }
if (pulDIB) { LOCALFREE(pulDIB); } }
SetMapMode(hdc,OldMode);
return(bStatus); }
/******************************Public*Routine******************************\
* vCalcMeshExtent * * * Arguments: * * * * Return Value: * * * * History: * * 12/3/1996 Mark Enstrom [marke] * \**************************************************************************/
VOID vCalcMeshExtent( PTRIVERTEX pVertex, ULONG nVertex, RECTL *prclExt ) { ULONG ulIndex; LONG xmin = MAX_INT; LONG xmax = MIN_INT; LONG ymin = MAX_INT; LONG ymax = MIN_INT;
for (ulIndex = 0;ulIndex < nVertex;ulIndex++) { if (pVertex[ulIndex].x < xmin) { xmin = pVertex[ulIndex].x; }
if (pVertex[ulIndex].x > xmax) { xmax = pVertex[ulIndex].x; }
if (pVertex[ulIndex].y < ymin) { ymin = pVertex[ulIndex].y; }
if (pVertex[ulIndex].y > ymax) { ymax = pVertex[ulIndex].y; } }
prclExt->left = xmin; prclExt->right = xmax; prclExt->top = ymin; prclExt->bottom = ymax; }
/******************************Public*Routine******************************\
* bConvertVertexToPhysical * !!! slow way to convert. * * Arguments: * * * * Return Value: * * * * History: * * 12/4/1996 Mark Enstrom [marke] * \**************************************************************************/
BOOL bConvertVertexToPhysical( HDC hdc, PTRIVERTEX pVertex, ULONG nVertex, PTRIVERTEX pPhysVert) { ULONG ulIndex;
for (ulIndex = 0;ulIndex<nVertex;ulIndex++) { POINT pt;
pt.x = pVertex[ulIndex].x; pt.y = pVertex[ulIndex].y;
if (!LPtoDP(hdc,&pt,1)) { return(FALSE); }
pPhysVert[ulIndex].x = pt.x; pPhysVert[ulIndex].y = pt.y; pPhysVert[ulIndex].Red = pVertex[ulIndex].Red; pPhysVert[ulIndex].Green = pVertex[ulIndex].Green; pPhysVert[ulIndex].Blue = pVertex[ulIndex].Blue; pPhysVert[ulIndex].Alpha = pVertex[ulIndex].Alpha; }
return(TRUE); }
/******************************Public*Routine******************************\
* bGetRectRegionFromDC * * Use DCI to get the rectanglular region from a HDC. If the clipping is * more complex then 1 rectangle then return false. * * Arguments: * * hdc - destination DC * prcClip - Clip Rect, fill out if RECT clipping * * Return Value: * * TRUE if clip rect was filled * * History: * * 12/6/1996 Mark Enstrom [marke] * \**************************************************************************/
BOOL bGetRectRegionFromDC( HDC hdc, PRECT prcClip ) { //
// visible region
//
BOOL bRet = FALSE; DWORD dwSize = 0; LPRGNDATA lpRgnData = NULL;
//
// init clip rect to NULL
//
dwSize = GetDCRegionData(hdc,dwSize,lpRgnData);
if (dwSize) { lpRgnData = (LPRGNDATA)LOCALALLOC(dwSize);
if (lpRgnData) { dwSize = GetDCRegionData(hdc,dwSize,lpRgnData);
if (dwSize) { if (lpRgnData->rdh.nCount == 1) { bRet = TRUE; *prcClip = lpRgnData->rdh.rcBound; } } LOCALFREE(lpRgnData); } } return(bRet); }
/******************************Public*Routine******************************\
* pfnTriangleFillFunction * * look at format to decide if DIBSection should be drawn directly * * 32 bpp RGB * 32 bpp BGR * 24 bpp * 16 bpp 565 * 16 bpp 555 * * Trangles are only filled in high color (no palette) surfaces * * Arguments: * * pDibInfo - information about destination surface * * Return Value: * * PFN_TRIFILL - triangle filling routine * * History: * * 12/6/1996 Mark Enstrom [marke] * \**************************************************************************/
PFN_TRIFILL pfnTriangleFillFunction( PDIBINFO pDibInfo, BOOL bReadable ) { PFN_TRIFILL pfnRet = NULL;
PULONG pulMasks = (PULONG)&pDibInfo->pbmi->bmiColors[0];
//
// 32 bpp RGB
//
if (!bReadable) { pfnRet = vFillTriDIBUnreadable; } else if ( (pDibInfo->pbmi->bmiHeader.biBitCount == 32) && (pDibInfo->pbmi->bmiHeader.biCompression == BI_RGB) ) { pfnRet = vFillTriDIB32BGRA; }
else if ( (pDibInfo->pbmi->bmiHeader.biBitCount == 32) && (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) && (pulMasks[0] == 0xff0000) && (pulMasks[1] == 0x00ff00) && (pulMasks[2] == 0x0000ff) ) { pfnRet = vFillTriDIB32BGRA; }
else if ( (pDibInfo->pbmi->bmiHeader.biBitCount == 32) && (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) && (pulMasks[0] == 0x0000ff) && (pulMasks[1] == 0x00ff00) && (pulMasks[2] == 0xff0000) ) { pfnRet = vFillTriDIB32RGB; }
else if ( (pDibInfo->pbmi->bmiHeader.biBitCount == 24) && (pDibInfo->pbmi->bmiHeader.biCompression == BI_RGB) ) { pfnRet = vFillTriDIB24RGB; }
//
// 16 BPP
//
else if ( (pDibInfo->pbmi->bmiHeader.biBitCount == 16) && (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) ) {
//
// 565,555
//
if ( (pulMasks[0] == 0xf800) && (pulMasks[1] == 0x07e0) && (pulMasks[2] == 0x001f) ) { pfnRet = vFillTriDIB16_565; } else if ( (pulMasks[0] == 0x7c00) && (pulMasks[1] == 0x03e0) && (pulMasks[2] == 0x001f) ) { pfnRet = vFillTriDIB16_555; } } else if (pDibInfo->pbmi->bmiHeader.biBitCount == 8) { pfnRet = vFillTriDIB8; } else if (pDibInfo->pbmi->bmiHeader.biBitCount == 4) { pfnRet = vFillTriDIB4; } else if (pDibInfo->pbmi->bmiHeader.biBitCount == 1) { pfnRet = vFillTriDIB1; }
return(pfnRet); }
/******************************Public*Routine******************************\
* WinTriangleMesh * win95 emulation * * Arguments: * * * * Return Value: * * * * History: * * 12/3/1996 Mark Enstrom [marke] * \**************************************************************************/
BOOL WinGradientFill( HDC hdc, PTRIVERTEX pLogVertex, ULONG nVertex, PVOID pMesh, ULONG nMesh, ULONG ulMode ) {
//
// If the DC has a DIBSection selected, then draw direct to DIBSECTION.
// else copy the rectangle needed from the dst to a 32bpp temp buffer,
// draw into the buffer, then bitblt to dst.
//
// calc extents for drawing
//
// convert extents and points to physical
//
// if no global then
// create memory DC with dibsection of correct size
// copy dst into dibsection (if can't make clipping)
// draw physical into dibsection
// copy dibsection to destination
//
PBYTE pDIB; RECTL rclPhysExt; RECTL rclLogExt; PRECTL prclClip; BOOL bStatus = FALSE; PFN_TRIFILL pfnTriFill; DIBINFO dibInfoDst; PALINFO palDst; ULONG ulDIBMode = SOURCE_GRADIENT_TRI; BOOL bReadable; POINTL ptlDitherOrg = {0,0};
//
// validate params and buffers
//
if (ulMode & (GRADIENT_FILL_RECT_H | GRADIENT_FILL_RECT_V)) { //
// if threre is only 1 rect, don't bother reading destination
// bits
//
//
// !!! make repeated calls in case nMesh != 1 to avoid
// reading surface???
//
if (nMesh == 1) { ulDIBMode = SOURCE_GRADIENT_RECT; } } else if (!(ulMode & GRADIENT_FILL_TRIANGLE)) { WARNING("Invalid mode in call to GradientFill\n"); // !!! set last error
return(FALSE); }
PTRIVERTEX pPhysVertex = (PTRIVERTEX)LOCALALLOC(nVertex * sizeof(TRIVERTEX));
if (pPhysVertex != NULL) { //
// convert to physical
//
bStatus = bConvertVertexToPhysical(hdc,pLogVertex,nVertex,pPhysVertex);
if (bStatus) { //
// get logical extents
//
vCalcMeshExtent(pLogVertex,nVertex,&rclLogExt);
//
// convert to physical extents
//
rclPhysExt = rclLogExt;
LPtoDP(hdc,(LPPOINT)&rclPhysExt,2);
//
// Set DIB information, convert to physical
//
bStatus = bInitDIBINFO(hdc, rclLogExt.left, rclLogExt.top, rclLogExt.right - rclLogExt.left, rclLogExt.bottom - rclLogExt.top, &dibInfoDst);
if (bStatus) { //
// get a destination DIB. For RECT Mode, the destination is not read.
//
bSetupBitmapInfos(&dibInfoDst, NULL);
bStatus = bGetDstDIBits(&dibInfoDst, &bReadable,ulDIBMode);
if (!((!bStatus) || (dibInfoDst.rclClipDC.left == dibInfoDst.rclClipDC.right))) { ULONG ulIndex;
//
// if 1,4,8 format then allocate rgb332 to palette xlate
//
ULONG BitCount = dibInfoDst.pbmi->bmiHeader.biBitCount;
if (BitCount <= 8) { ULONG NumPalEntries; PBYTE pxlate = NULL;
switch (BitCount) { case 1: NumPalEntries = 2; break;
case 4: NumPalEntries = 16;
if ((dibInfoDst.pbmi->bmiHeader.biClrUsed > 0) && (dibInfoDst.pbmi->bmiHeader.biClrUsed < 16)) { NumPalEntries = dibInfoDst.pbmi->bmiHeader.biClrUsed; } break; case 8: NumPalEntries = 256;
if ((dibInfoDst.pbmi->bmiHeader.biClrUsed > 0) && (dibInfoDst.pbmi->bmiHeader.biClrUsed < 256)) { NumPalEntries = dibInfoDst.pbmi->bmiHeader.biClrUsed; } break; }
pxlate = pGenColorXform332((PULONG)(&dibInfoDst.pbmi->bmiColors[0]),NumPalEntries);
dibInfoDst.pxlate332 = pxlate;
if (pxlate == NULL) {
WARNING("Failed to allocate xlate\n"); bStatus = FALSE; } }
if (bStatus) { if (dibInfoDst.hDIB) { //
// if temp surface has been allocated,
// subtract origin from points
//
for (ulIndex=0;ulIndex<nVertex;ulIndex++) { pPhysVertex[ulIndex].x -= dibInfoDst.ptlGradOffset.x; pPhysVertex[ulIndex].y -= dibInfoDst.ptlGradOffset.y; }
//
// clipping now in relation to temp DIB
//
rclPhysExt = dibInfoDst.rclDIB;
//
// adjust dither org
//
ptlDitherOrg.x = dibInfoDst.rclBounds.left; ptlDitherOrg.y = dibInfoDst.rclBounds.top; } else { //
// clip extents to destination clip rect
//
if (rclPhysExt.left < dibInfoDst.rclClipDC.left) { rclPhysExt.left = dibInfoDst.rclClipDC.left; }
if (rclPhysExt.right > dibInfoDst.rclClipDC.right) { rclPhysExt.right = dibInfoDst.rclClipDC.right; }
if (rclPhysExt.top < dibInfoDst.rclClipDC.top) { rclPhysExt.top = dibInfoDst.rclClipDC.top; }
if (rclPhysExt.bottom > dibInfoDst.rclClipDC.bottom) { rclPhysExt.bottom = dibInfoDst.rclClipDC.bottom; } }
if ( (ulMode & (GRADIENT_FILL_RECT_H | GRADIENT_FILL_RECT_V)) ) { //
// draw gradient rectangles
//
bStatus = DIBGradientRect(hdc,pPhysVertex,nVertex,(PGRADIENT_RECT)pMesh,nMesh,ulMode,&rclPhysExt,&dibInfoDst,&ptlDitherOrg); } else if (ulMode == GRADIENT_FILL_TRIANGLE) { //
// draw triangles
//
bStatus = DIBTriangleMesh(hdc,pPhysVertex,nVertex,(PGRADIENT_TRIANGLE)pMesh,nMesh,ulMode,&rclPhysExt,&dibInfoDst,&ptlDitherOrg,bReadable); }
//
// copy output to final dest if needed
//
if (bStatus && bReadable) { bStatus = bSendDIBINFO (hdc,&dibInfoDst); } } } }
vCleanupDIBINFO(&dibInfoDst); }
LOCALFREE(pPhysVertex); } else { bStatus = FALSE; }
//
//
//
return(bStatus); }
#endif
/******************************Public*Routine******************************\
* TriangleMesh * * * Arguments: * * * * Return Value: * * * * History: * * 12/3/1996 Mark Enstrom [marke] * \**************************************************************************/
BOOL GradientFill( HDC hdc, PTRIVERTEX pVertex, ULONG nVertex, PVOID pMesh, ULONG nMesh, ULONG ulMode ) { BOOL bRet;
bRet = gpfnGradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode ); return(bRet); }
|