void CG8bitSparseImage::MaskFill (CG32bitImage &Dest, int xDest, int yDest, int cxDest, int cyDest, int xSrc, int ySrc, CG32bitPixel rgbColor) const // MaskFill // // Fills the destination image with the given color through our mask. { // Make sure we're in bounds if (!Dest.AdjustCoords(&xSrc, &ySrc, GetWidth(), GetHeight(), &xDest, &yDest, &cxDest, &cyDest)) return; // Short-circuit if (rgbColor.GetAlpha() == 0x00) return; // Compute a pre-multiplied color BYTE *pAlpha = CG32bitPixel::AlphaTable(rgbColor.GetAlpha()); CG32bitPixel rgbPreMultColor = CG32bitPixel(pAlpha[rgbColor.GetRed()], pAlpha[rgbColor.GetGreen()], pAlpha[rgbColor.GetBlue()], rgbColor.GetAlpha()); // Loop int yPos = ySrc; int yPosEnd = ySrc + cyDest; int yTile = yPos / m_cyTile; int yOffset = ClockMod(yPos, m_cyTile); int xTileStart = xSrc / m_cxTile; int xOffsetStart = ClockMod(xSrc, m_cxTile); int yDestPos = yDest; while (yPos < yPosEnd) { int cyTileLeft = Min(m_cyTile - yOffset, yPosEnd - yPos); // Is this a valid tile row, then continue if (yTile >= 0 && yTile < m_yTileCount) { int xPos = xSrc; int xPosEnd = xSrc + cxDest; int xTile = xTileStart; int xOffset = xOffsetStart; int xDestPos = xDest; while (xPos < xPosEnd) { int cxTileLeft = Min(m_cxTile - xOffset, xPosEnd - xPos); // If this is a valid tile, then we can continue if (xTile >= 0 && xTile < m_xTileCount) { const CNode &Tile = GetTile(xTile, yTile); switch (Tile.GetType()) { case typeByte: { BYTE byAlpha = Tile.GetByte(); if (byAlpha == 0x00) {} else if (byAlpha == 0xff) Dest.Fill(xDestPos, yDestPos, cxTileLeft, cyTileLeft, rgbColor); else // We just modify the alpha on the original color (Fill will take care of the rest) Dest.Fill(xDestPos, yDestPos, cxTileLeft, cyTileLeft, CG32bitPixel(rgbColor, CG32bitPixel::BlendAlpha(rgbColor.GetAlpha(), byAlpha))); break; } case typeNodeArray: { CNode *Rows = Tile.GetNodeArray(); CNode *pSrcRow = Rows + yOffset; CNode *pSrcRowEnd = pSrcRow + cyTileLeft; CG32bitPixel *pDestRow = Dest.GetPixelPos(xDestPos, yDestPos); while (pSrcRow < pSrcRowEnd) { CG32bitPixel *pDest = pDestRow; CG32bitPixel *pDestEnd = pDestRow + cxTileLeft; switch (pSrcRow->GetType()) { case typeByte: { BYTE byAlpha = pSrcRow->GetByte(); if (byAlpha == 0x00) {} else if (byAlpha == 0xff) { BYTE byFillAlpha = rgbColor.GetAlpha(); if (byFillAlpha == 0xff) { while (pDest < pDestEnd) *pDest++ = rgbColor; } else { BYTE *pAlphaInv = CG32bitPixel::AlphaTable(byFillAlpha ^ 0xff); BYTE byRed = rgbPreMultColor.GetRed(); BYTE byGreen = rgbPreMultColor.GetGreen(); BYTE byBlue = rgbPreMultColor.GetBlue(); while (pDest < pDestEnd) { BYTE byRedResult = pAlphaInv[pDest->GetRed()] + byRed; BYTE byGreenResult = pAlphaInv[pDest->GetGreen()] + byGreen; BYTE byBlueResult = pAlphaInv[pDest->GetBlue()] + byBlue; *pDest++ = CG32bitPixel(byRedResult, byGreenResult, byBlueResult); } } } else { // Blend the alphas together BYTE byFillAlpha = CG32bitPixel::BlendAlpha(byAlpha, rgbColor.GetAlpha()); BYTE *pAlpha = CG32bitPixel::AlphaTable(byFillAlpha); BYTE *pAlphaInv = CG32bitPixel::AlphaTable(byFillAlpha ^ 0xff); BYTE byRed = pAlpha[rgbColor.GetRed()]; BYTE byGreen = pAlpha[rgbColor.GetBlue()]; BYTE byBlue = pAlpha[rgbColor.GetGreen()]; while (pDest < pDestEnd) { BYTE byRedResult = pAlphaInv[pDest->GetRed()] + byRed; BYTE byGreenResult = pAlphaInv[pDest->GetGreen()] + byGreen; BYTE byBlueResult = pAlphaInv[pDest->GetBlue()] + byBlue; *pDest++ = CG32bitPixel(byRedResult, byGreenResult, byBlueResult); } } break; } case typeByteArray: { BYTE *pSrcAlpha = pSrcRow->GetByteArray() + xOffset; BYTE *pSrcAlphaEnd = pSrcAlpha + cxTileLeft; BYTE byColorAlpha = rgbColor.GetAlpha(); if (byColorAlpha == 0xff) { while (pSrcAlpha < pSrcAlphaEnd) { if (*pSrcAlpha == 0x00) {} else if (*pSrcAlpha == 0xff) *pDest = rgbColor; else { BYTE *pAlpha = CG32bitPixel::AlphaTable(*pSrcAlpha); BYTE *pAlphaInv = CG32bitPixel::AlphaTable(*pSrcAlpha ^ 0xff); BYTE byRedResult = pAlphaInv[pDest->GetRed()] + pAlpha[rgbColor.GetRed()]; BYTE byGreenResult = pAlphaInv[pDest->GetGreen()] + pAlpha[rgbColor.GetGreen()]; BYTE byBlueResult = pAlphaInv[pDest->GetBlue()] + pAlpha[rgbColor.GetBlue()]; *pDest = CG32bitPixel(byRedResult, byGreenResult, byBlueResult); } pSrcAlpha++; pDest++; } } else { BYTE *pAlphaFFInv = CG32bitPixel::AlphaTable(byColorAlpha ^ 0xff); while (pSrcAlpha < pSrcAlphaEnd) { if (*pSrcAlpha == 0x00) {} else if (*pSrcAlpha == 0xff) { BYTE byRedResult = pAlphaFFInv[pDest->GetRed()] + rgbPreMultColor.GetRed(); BYTE byGreenResult = pAlphaFFInv[pDest->GetGreen()] + rgbPreMultColor.GetGreen(); BYTE byBlueResult = pAlphaFFInv[pDest->GetBlue()] + rgbPreMultColor.GetBlue(); *pDest = CG32bitPixel(byRedResult, byGreenResult, byBlueResult); } else { BYTE byFillAlpha = CG32bitPixel::BlendAlpha(*pSrcAlpha, byColorAlpha); BYTE *pAlpha = CG32bitPixel::AlphaTable(byFillAlpha); BYTE *pAlphaInv = CG32bitPixel::AlphaTable(byFillAlpha ^ 0xff); BYTE byRedResult = pAlphaInv[pDest->GetRed()] + pAlpha[rgbColor.GetRed()]; BYTE byGreenResult = pAlphaInv[pDest->GetGreen()] + pAlpha[rgbColor.GetGreen()]; BYTE byBlueResult = pAlphaInv[pDest->GetBlue()] + pAlpha[rgbColor.GetBlue()]; *pDest = CG32bitPixel(byRedResult, byGreenResult, byBlueResult); } pSrcAlpha++; pDest++; } } break; } } pSrcRow++; pDestRow = Dest.NextRow(pDestRow); } break; } } } // Move to the next tile xTile++; xOffset = 0; xPos += cxTileLeft; xDestPos += cxTileLeft; } } // Next tile row yTile++; yOffset = 0; yPos += cyTileLeft; yDestPos += cyTileLeft; } }