/*++ 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;ulIndexright - 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 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;ulIndexrdh.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 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); }