CG32bitPixel CG32bitPixel::Blend (CG32bitPixel rgbDest, CG32bitPixel rgbSrc) // Blend // // Combines rgbSrc with rgbDest, using rgbSrc as the source opacity. // We assume dest has no alpha component and we assume that rgbSrc does. { BYTE *pAlpha = g_Alpha8[rgbSrc.GetAlpha()]; BYTE *pAlphaInv = g_Alpha8[rgbSrc.GetAlpha() ^ 0xff]; // Equivalent to 255 - rgbSrc.GetAlpha() BYTE byRedResult = pAlphaInv[rgbDest.GetRed()] + pAlpha[rgbSrc.GetRed()]; BYTE byGreenResult = pAlphaInv[rgbDest.GetGreen()] + pAlpha[rgbSrc.GetGreen()]; BYTE byBlueResult = pAlphaInv[rgbDest.GetBlue()] + pAlpha[rgbSrc.GetBlue()]; return CG32bitPixel(byRedResult, byGreenResult, byBlueResult); }
CG32bitPixel CG32bitPixel::Blend (CG32bitPixel rgbDest, CG32bitPixel rgbSrc, BYTE bySrcAlpha) // Blend // // Combines rgbSrc with rgbDest, using bySrcAlpha as the source opacity. // We assume source and dest have no alpha component. { BYTE *pAlpha = g_Alpha8[bySrcAlpha]; BYTE *pAlphaInv = g_Alpha8[255 - bySrcAlpha]; BYTE byRedResult = pAlphaInv[rgbDest.GetRed()] + pAlpha[rgbSrc.GetRed()]; BYTE byGreenResult = pAlphaInv[rgbDest.GetGreen()] + pAlpha[rgbSrc.GetGreen()]; BYTE byBlueResult = pAlphaInv[rgbDest.GetBlue()] + pAlpha[rgbSrc.GetBlue()]; return CG32bitPixel(byRedResult, byGreenResult, byBlueResult); }
CGlowingRingPainter::CGlowingRingPainter (CG32bitImage &Dest, int iRadius, int iWidth, CG32bitPixel rgbColor) : m_Dest(Dest), m_rcClip(Dest.GetClipRect()), m_iRadius(iRadius), m_iWidth(iWidth) // CGlowingRingPainter constructor { int i; if (m_iWidth <= 0) { m_pColorRamp = NULL; return; } // Generate a color ramp int iCenter = m_iWidth / 2; int iExtra = m_iWidth % 2; int iOuter = iCenter - 1; int iInner = iCenter + iExtra; m_ColorRamp.InsertEmpty(m_iWidth); // We expect the color ramp to be pre-multiplied CG32bitPixel rgbPreMult = CG32bitPixel::PreMult(rgbColor); // Init the center if (iExtra) m_ColorRamp[iCenter] = rgbPreMult; // Edges for (i = 0; i < iCenter; i++) { ASSERT(iOuter >= 0 && iOuter < m_iWidth); ASSERT(iInner >=0 && iInner < m_iWidth); BYTE byAlpha = (BYTE)Min((WORD)0xff, (WORD)(rgbPreMult.GetAlpha() * (iCenter - i) / (iCenter + 1))); BYTE byRed = (BYTE)Min((WORD)0xff, (WORD)(rgbPreMult.GetRed() * (iCenter - i) / (iCenter + 1))); BYTE byGreen = (BYTE)Min((WORD)0xff, (WORD)(rgbPreMult.GetGreen() * (iCenter - i) / (iCenter + 1))); BYTE byBlue = (BYTE)Min((WORD)0xff, (WORD)(rgbPreMult.GetBlue() * (iCenter - i) / (iCenter + 1))); m_ColorRamp[iOuter] = CG32bitPixel(byRed, byGreen, byBlue, byAlpha); m_ColorRamp[iInner] = CG32bitPixel(byRed, byGreen, byBlue, byAlpha); iOuter--; iInner++; } m_pColorRamp = &m_ColorRamp; }
CGRealRGB::CGRealRGB (CG32bitPixel rgbColor) : m_rR(rgbColor.GetRed() / 255.0), m_rG(rgbColor.GetGreen() / 255.0), m_rB(rgbColor.GetBlue() / 255.0), m_rA(rgbColor.GetAlpha() / 255.0) // CGRealRGB constructor { }
CG32bitPixel CG32bitPixel::Darken (CG32bitPixel rgbSource, BYTE byOpacity) // Darken // // Equivalent to Blend(0, rgbSource, byOpacity) { BYTE *pAlpha = g_Alpha8[byOpacity]; return CG32bitPixel(pAlpha[rgbSource.GetRed()], pAlpha[rgbSource.GetGreen()], pAlpha[rgbSource.GetBlue()]); }
CG32bitPixel CG32bitPixel::Desaturate (CG32bitPixel rgbColor) // Desaturate // // Desaturate the given color { BYTE byMax = Max(Max(rgbColor.GetRed(), rgbColor.GetGreen()), rgbColor.GetBlue()); BYTE byMin = Min(Min(rgbColor.GetRed(), rgbColor.GetGreen()), rgbColor.GetBlue()); return CG32bitPixel::FromGrayscale((BYTE)(((DWORD)byMax + (DWORD)byMin) / 2), rgbColor.GetAlpha()); }
CG32bitPixel CG32bitPixel::Blend (CG32bitPixel rgbFrom, CG32bitPixel rgbTo, double rFade) // Fade // // Fade from one value to the other. rFade goes from 0 to 1. { if (rFade <= 0.0) return rgbFrom; else if (rFade >= 1.0) return rgbTo; else { int iRDiff = (int)(DWORD)rgbTo.GetRed() - (int)(DWORD)rgbFrom.GetRed(); int iGDiff = (int)(DWORD)rgbTo.GetGreen() - (int)(DWORD)rgbFrom.GetGreen(); int iBDiff = (int)(DWORD)rgbTo.GetBlue() - (int)(DWORD)rgbFrom.GetBlue(); BYTE byRed = (BYTE)((int)(DWORD)rgbFrom.GetRed() + (iRDiff * rFade)); BYTE byGreen = (BYTE)((int)(DWORD)rgbFrom.GetGreen() + (iGDiff * rFade)); BYTE byBlue = (BYTE)((int)(DWORD)rgbFrom.GetBlue() + (iBDiff * rFade)); return CG32bitPixel(byRed, byGreen, byBlue); } }
CG32bitPixel CG32bitPixel::Fade (CG32bitPixel rgbFrom, CG32bitPixel rgbTo, int iPercent) // Fade // // Fade from one value to the other by percent. { if (iPercent <= 0) return rgbFrom; else if (iPercent >= 100) return rgbTo; else { int iRDiff = (int)(DWORD)rgbTo.GetRed() - (int)(DWORD)rgbFrom.GetRed(); int iGDiff = (int)(DWORD)rgbTo.GetGreen() - (int)(DWORD)rgbFrom.GetGreen(); int iBDiff = (int)(DWORD)rgbTo.GetBlue() - (int)(DWORD)rgbFrom.GetBlue(); BYTE byRed = (BYTE)((int)(DWORD)rgbFrom.GetRed() + (iRDiff * iPercent / 100)); BYTE byGreen = (BYTE)((int)(DWORD)rgbFrom.GetGreen() + (iGDiff * iPercent / 100)); BYTE byBlue = (BYTE)((int)(DWORD)rgbFrom.GetBlue() + (iBDiff * iPercent / 100)); return CG32bitPixel(byRed, byGreen, byBlue); } }
CG32bitPixel CG32bitPixel::PreMult (CG32bitPixel rgbColor, BYTE byAlpha) // PreMult // // Returns a new color premultiplied by the alpha value. { if (byAlpha == 0x00) return CG32bitPixel::Null(); else if (byAlpha == 0xff) return CG32bitPixel(rgbColor, 0xff); else { BYTE *pAlpha = CG32bitPixel::AlphaTable(byAlpha); BYTE byRed = rgbColor.GetRed(); BYTE byGreen = rgbColor.GetGreen(); BYTE byBlue = rgbColor.GetBlue(); return CG32bitPixel(pAlpha[byRed], pAlpha[byGreen], pAlpha[byBlue], byAlpha); } }
void CGlowingRingPainter::DrawLine (int x, int y) // DrawLine // // Draws a line { int xStart = m_xDest - x; int xEnd = m_xDest + x + 1; if (xEnd <= m_rcClip.left || xStart >= m_rcClip.right) return; // See which lines we need to paint int yLine = m_yDest - y; bool bPaintTop = (yLine >= m_rcClip.top && yLine < m_rcClip.bottom); CG32bitPixel *pCenterTop = m_Dest.GetPixelPos(m_xDest, yLine); yLine = m_yDest + y; bool bPaintBottom = ((y > 0) && (yLine >= m_rcClip.top && yLine < m_rcClip.bottom)); CG32bitPixel *pCenterBottom = m_Dest.GetPixelPos(m_xDest, yLine); // Compute radius increment int iRadius = y; int d = -y; int deltaE = 3; int deltaSE = -2 * y + 1; // Loop int xPos = 0; // This will skip the center pixel in the circle (avoids a divide by // zero in the inner loop). if (y == 0) { xPos = 1; d += deltaSE; deltaE += 2; iRadius++; } // Blt the line while (xPos <= x) { // Figure out the radius of the pixel at this location if (d < 0) { d += deltaE; deltaE += 2; deltaSE += 2; } else { d += deltaSE; deltaE += 2; // deltaSE += 0; iRadius++; } // Compute the index into the ramp based on radius and ring thickness // (If we're outside the ramp, then continue) int iIndex = m_iRadius - iRadius; if (iIndex >= m_iWidth || iIndex < 0) { xPos++; continue; } // Compute the transparency CG32bitPixel rgbColor = m_pColorRamp->GetAt(iIndex); BYTE byOpacity = rgbColor.GetAlpha(); // Optimize opaque painting if (byOpacity == 0x00) ; else if (byOpacity == 0xff) { if (m_xDest - xPos < m_rcClip.right && m_xDest - xPos >= m_rcClip.left) { if (bPaintTop) *(pCenterTop - xPos) = rgbColor; if (bPaintBottom) *(pCenterBottom - xPos) = rgbColor; } if (xPos > 0 && m_xDest + xPos < m_rcClip.right && m_xDest + xPos >= m_rcClip.left) { if (bPaintTop) *(pCenterTop + xPos) = rgbColor; if (bPaintBottom) *(pCenterBottom + xPos) = rgbColor; } } else { BYTE *pAlphaInv = CG32bitPixel::AlphaTable(byOpacity ^ 0xff); WORD wRed = rgbColor.GetRed(); WORD wGreen = rgbColor.GetGreen(); WORD wBlue = rgbColor.GetBlue(); // Draw transparent #define DRAW_PIXEL(pos) \ { \ BYTE byRedResult = (BYTE)Min((WORD)0xff, (WORD)(pAlphaInv[(pos)->GetRed()] + wRed)); \ BYTE byGreenResult = (BYTE)Min((WORD)0xff, (WORD)(pAlphaInv[(pos)->GetGreen()] + wGreen)); \ BYTE byBlueResult = (BYTE)Min((WORD)0xff, (WORD)(pAlphaInv[(pos)->GetBlue()] + wBlue)); \ \ *(pos) = CG32bitPixel(byRedResult, byGreenResult, byBlueResult); \ } // Paint if (m_xDest - xPos < m_rcClip.right && m_xDest - xPos >= m_rcClip.left) { if (bPaintTop) DRAW_PIXEL(pCenterTop - xPos); if (bPaintBottom) DRAW_PIXEL(pCenterBottom - xPos); } if (xPos > 0 && m_xDest + xPos < m_rcClip.right && m_xDest + xPos >= m_rcClip.left) { if (bPaintTop) DRAW_PIXEL(pCenterTop + xPos); if (bPaintBottom) DRAW_PIXEL(pCenterBottom + xPos); } #undef DRAW_PIXEL } xPos++; } }
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; } }