#include "trop.h" #include "loop_macros.h" #include "tpixelutils.h" #include "quickputP.h" #ifndef TNZCORE_LIGHT #include "tpalette.h" #include "tcolorstyles.h" #endif /* #ifndef __sgi #include #endif */ // The following must be old IRIX code. Should be re-tested. // It seems that gcc compiles it, but requiring a LOT of // resources... very suspect... /*#ifdef __LP64__ #include "optimize_for_lp64.h" #endif*/ //============================================================================= //============================================================================= //============================================================================= #ifdef OPTIMIZE_FOR_LP64 void quickResample_optimized(const TRasterP &dn, const TRasterP &up, const TAffine &aff, TRop::ResampleFilterType filterType); #endif namespace { inline TPixel32 applyColorScale(const TPixel32 &color, const TPixel32 &colorScale, bool toBePremultiplied = false) { /*-- * 半透明のラスタをViewer上で半透明にquickputするとき、色が暗くなってしまうのを防ぐ * --*/ if (colorScale.r == 0 && colorScale.g == 0 && colorScale.b == 0) { /*-- * toBePremultipliedがONのときは、後でPremultiplyをするので、ここでは行わない * --*/ if (toBePremultiplied) return TPixel32(color.r, color.g, color.b, color.m * colorScale.m / 255); else return TPixel32( color.r * colorScale.m / 255, color.g * colorScale.m / 255, color.b * colorScale.m / 255, color.m * colorScale.m / 255); } int r = color.r + colorScale.r; int g = color.g + colorScale.g; int b = color.b + colorScale.b; return premultiply(TPixel32(r > 255 ? 255 : r, g > 255 ? 255 : g, b > 255 ? 255 : b, color.m * colorScale.m / 255)); } //------------------------------------------------------------------------------ inline TPixel32 applyColorScaleCMapped(const TPixel32 &color, const TPixel32 &colorScale) { int r = color.r + colorScale.r; int g = color.g + colorScale.g; int b = color.b + colorScale.b; return premultiply(TPixel32(r > 255 ? 255 : r, g > 255 ? 255 : g, b > 255 ? 255 : b, color.m * colorScale.m / 255)); } //------------------------------------------------------------------------------ void doQuickPutFilter(const TRaster32P &dn, const TRaster32P &up, const TAffine &aff) { // se aff e' degenere la controimmagine di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - 2, up->getLy() - 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff // nel disegnare la y-esima scanline di dn, il passaggio al pixel successivo // comporta l'incremento (deltaXD, deltaYD) delle coordinate del pixel // corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; // naturale predecessore di up->getLx() - 1 int lxPred = (up->getLx() - 2) * (1 << PADN); // naturale predecessore di up->getLy() - 1 int lyPred = (up->getLy() - 2) * (1 << PADN); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel32 *upBasePix = up->pixels(); // scorre le scanline di boundingBoxD for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { // (1) equazione k-parametrica della y-esima // scanline di boundingBoxD: // (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin) // (2) equazione k-parametrica dell'immagine mediante // invAff di (1): // invAff*(xMin, y) + k*(deltaXD, deltaYD), // k = kMin, ..., kMax // con 0 <= kMin <= kMax <= (xMax - xMin) // calcola kMin, kMax per la scanline corrente intersecando la (2) // con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff // della porzione di scanline [ (xMin, y), (xMax, y) ] di dn // TPointD b = invAff*TPointD(xMax, y); TPointD a = invAff * TPointD(xMin, y); // (xL0, yL0) sono le coordinate di a in versione "TLonghizzata" // 0 <= xL0 + k*deltaXL // <= (up->getLx() - 2)*(1<getLy() - 2)*(1<getLx() - 2)*(1< // 0 <= xL0 + k*deltaXL <= lxPred // // // 0 <= yL0 + k*deltaYL <= (up->getLy() - 2)*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinX, kMaxX if (deltaXL == 0) { // [a, b] verticale esterno ad up contratto if ((xL0 < 0) || (lxPred < xL0)) continue; // altrimenti usa solo // kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaXL > 0) { if (lxPred < xL0) // [a, b] esterno ad up+(bordo destro) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { if (xL0 < 0) // [a, b] esterno ad up contratto continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up contratto if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { if (lyPred < yL0) // [a, b] esterno ad up contratto continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { if (yL0 < 0) // [a, b] esterno ad up contratto continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clipping su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" // del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // troncato int yI = yL >> PADN; // troncato assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); // (xI, yI) TPixel32 *upPix00 = upBasePix + (yI * upWrap + xI); // (xI + 1, yI) TPixel32 *upPix10 = upPix00 + 1; // (xI, yI + 1) TPixel32 *upPix01 = upPix00 + upWrap; // (xI + 1, yI + 1) TPixel32 *upPix11 = upPix00 + upWrap + 1; // filtro bilineare 4 pixels: calcolo dei pesi int xWeight1 = (xL & MASKN); int xWeight0 = (1 << PADN) - xWeight1; int yWeight1 = (yL & MASKN); int yWeight0 = (1 << PADN) - yWeight1; // filtro bilineare 4 pixels: media pesata sui singoli canali int rColDownTmp = (xWeight0 * (upPix00->r) + xWeight1 * ((upPix10)->r)) >> PADN; int gColDownTmp = (xWeight0 * (upPix00->g) + xWeight1 * ((upPix10)->g)) >> PADN; int bColDownTmp = (xWeight0 * (upPix00->b) + xWeight1 * ((upPix10)->b)) >> PADN; int rColUpTmp = (xWeight0 * ((upPix01)->r) + xWeight1 * ((upPix11)->r)) >> PADN; int gColUpTmp = (xWeight0 * ((upPix01)->g) + xWeight1 * ((upPix11)->g)) >> PADN; int bColUpTmp = (xWeight0 * ((upPix01)->b) + xWeight1 * ((upPix11)->b)) >> PADN; unsigned char rCol = (unsigned char)((yWeight0 * rColDownTmp + yWeight1 * rColUpTmp) >> PADN); unsigned char gCol = (unsigned char)((yWeight0 * gColDownTmp + yWeight1 * gColUpTmp) >> PADN); unsigned char bCol = (unsigned char)((yWeight0 * bColDownTmp + yWeight1 * bColUpTmp) >> PADN); TPixel32 upPix = TPixel32(rCol, gCol, bCol, upPix00->m); if (upPix.m == 0) continue; else if (upPix.m == 255) *dnPix = upPix; else *dnPix = quickOverPix(*dnPix, upPix); } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickPutNoFilter(const TRaster32P &dn, const TRaster32P &up, const TAffine &aff, const TPixel32 &colorScale, bool doPremultiply, bool whiteTransp, bool firstColumn, bool doRasterDarkenBlendedView) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; // TINT32 predecessore di up->getLx() int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int lyPred = up->getLy() * (1 << PADN) - 1; int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel32 *upBasePix = up->pixels(); // scorre le scanline di boundingBoxD for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { // (1) equazione k-parametrica della y-esima scanline di boundingBoxD: // (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin) // (2) equazione k-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, y) + k*(deltaXD, deltaYD), // k = kMin, ..., kMax con 0 <= kMin <= kMax <= (xMax - xMin) // calcola kMin, kMax per la scanline corrente // intersecando la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, y), (xMax, y) ] di dn // TPointD b = invAff*TPointD(xMax, y); TPointD a = invAff * TPointD(xMin, y); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + k*deltaXL // < up->getLx()*(1<getLy()*(1<getLx()*(1< // 0 <= xL0 + k*deltaXL // <= lxPred // // 0 <= yL0 + k*deltaYL // < up->getLy()*(1< // 0 <= yL0 + k*deltaYL // <= lyPred // calcola kMinX, kMaxX if (deltaXL == 0) { // [a, b] verticale esterno ad up+(bordo destro/basso) if ((xL0 < 0) || (lxPred < xL0)) continue; // altrimenti usa solo // kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaXL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up+(bordo destro/basso) if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clippind su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixel32 upPix = *(upBasePix + (yI * upWrap + xI)); if (firstColumn) upPix.m = 255; if (upPix.m == 0 || (whiteTransp && upPix == TPixel::White)) continue; if (colorScale != TPixel32::Black) upPix = applyColorScale(upPix, colorScale, doPremultiply); if (doRasterDarkenBlendedView) *dnPix = quickOverPixDarkenBlended(*dnPix, upPix); else { if (upPix.m == 255) *dnPix = upPix; else if (doPremultiply) *dnPix = quickOverPixPremult(*dnPix, upPix); else *dnPix = quickOverPix(*dnPix, upPix); } } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickPutNoFilter(const TRaster32P &dn, const TRaster64P &up, const TAffine &aff, bool doPremultiply, bool firstColumn) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; // TINT32 predecessore di up->getLx() int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int lyPred = up->getLy() * (1 << PADN) - 1; int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel64 *upBasePix = up->pixels(); // scorre le scanline di boundingBoxD for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { // (1) equazione k-parametrica della y-esima scanline di boundingBoxD: // (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin) // (2) equazione k-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, y) + k*(deltaXD, deltaYD), // k = kMin, ..., kMax con 0 <= kMin <= kMax <= (xMax - xMin) // calcola kMin, kMax per la scanline corrente // intersecando la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, y), (xMax, y) ] di dn // TPointD b = invAff*TPointD(xMax, y); TPointD a = invAff * TPointD(xMin, y); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + k*deltaXL // < up->getLx()*(1<getLy()*(1<getLx()*(1< // 0 <= xL0 + k*deltaXL // <= lxPred // // 0 <= yL0 + k*deltaYL // < up->getLy()*(1< // 0 <= yL0 + k*deltaYL // <= lyPred // calcola kMinX, kMaxX if (deltaXL == 0) { // [a, b] verticale esterno ad up+(bordo destro/basso) if ((xL0 < 0) || (lxPred < xL0)) continue; // altrimenti usa solo // kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaXL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up+(bordo destro/basso) if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clippind su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixel64 *upPix = upBasePix + (yI * upWrap + xI); if (firstColumn) upPix->m = 65535; if (upPix->m == 0) continue; else if (upPix->m == 65535) *dnPix = PixelConverter::from(*upPix); else if (doPremultiply) *dnPix = quickOverPixPremult(*dnPix, PixelConverter::from(*upPix)); else *dnPix = quickOverPix(*dnPix, PixelConverter::from(*upPix)); } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickPutNoFilter(const TRaster32P &dn, const TRasterGR8P &up, const TAffine &aff, const TPixel32 &colorScale) { if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); int xMin = std::max(tfloor(boundingBoxD.x0), 0); int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); int deltaYL = tround(deltaYD * (1 << PADN)); if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = up->getLx() * (1 << PADN) - 1; int lyPred = up->getLy() * (1 << PADN) - 1; int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixelGR8 *upBasePix = up->pixels(); for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { TPointD a = invAff * TPointD(xMin, y); int xL0 = tround((a.x + 0.5) * (1 << PADN)); int yL0 = tround((a.y + 0.5) * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn if (deltaXL == 0) { if ((xL0 < 0) || (lxPred < xL0)) continue; } else if (deltaXL > 0) { if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up+(bordo destro/basso) if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clippind su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixelGR8 *upPix = upBasePix + (yI * upWrap + xI); if (colorScale == TPixel32::Black) { if (upPix->value == 0) dnPix->r = dnPix->g = dnPix->b = 0; else if (upPix->value == 255) dnPix->r = dnPix->g = dnPix->b = upPix->value; else *dnPix = quickOverPix(*dnPix, *upPix); dnPix->m = 255; } else { TPixel32 upPix32(upPix->value, upPix->value, upPix->value, 255); upPix32 = applyColorScale(upPix32, colorScale); if (upPix32.m == 255) *dnPix = upPix32; else *dnPix = quickOverPix(*dnPix, upPix32); } } } dn->unlock(); up->unlock(); } //============================================================================= void doQuickPutFilter(const TRaster32P &dn, const TRaster32P &up, double sx, double sy, double tx, double ty) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - 2, up->getLy() - 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine // mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up (con gli estremi eventualmente invertiti) e' // la controimmagine // mediante aff della porzione di scanline [ (xMin, yMin), (xMax, yMin) ] // di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) in // versione "TLonghizzata" // // 0 <= xL0 + kX*deltaXL // <= (up->getLx() - 2)*(1<getLy() - 2)*(1<getLx() - 1) int lxPred = (up->getLx() - 2) * (1 << PADN); // TINT32 predecessore di (up->getLy() - 1) int lyPred = (up->getLy() - 2) * (1 << PADN); // 0 <= xL0 + k*deltaXL // <= (up->getLx() - 2)*(1< // 0 <= xL0 + k*deltaXL <= lxPred // // 0 <= yL0 + k*deltaYL // <= (up->getLy() - 2)*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con // i lati (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { // [a, b] interno ad up contratto assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up contratto assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con // i lati (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up contratto assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up contratto assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up // inizializza yL int yL = yL0 + (kMinY - 1) * deltaYL; // scorre le scanline di boundingBoxD for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { // inizializza xL int xL = xL0 + (kMinX - 1) * deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // troncato // filtro bilineare 4 pixels: calcolo degli y-pesi int yWeight1 = (yL & MASKN); int yWeight0 = (1 << PADN) - yWeight1; TPixel32 *dnPix = dnRow + xMin + kMinX; TPixel32 *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; // il punto di up TPointD(xL/(1<> PADN; // troncato assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); // (xI, yI) TPixel32 *upPix00 = upBasePix + (yI * upWrap + xI); // (xI + 1, yI) TPixel32 *upPix10 = upPix00 + 1; // (xI, yI + 1) TPixel32 *upPix01 = upPix00 + upWrap; // (xI + 1, yI + 1) TPixel32 *upPix11 = upPix00 + upWrap + 1; // filtro bilineare 4 pixels: calcolo degli x-pesi int xWeight1 = (xL & MASKN); int xWeight0 = (1 << PADN) - xWeight1; // filtro bilineare 4 pixels: media pesata sui singoli canali int rColDownTmp = (xWeight0 * (upPix00->r) + xWeight1 * ((upPix10)->r)) >> PADN; int gColDownTmp = (xWeight0 * (upPix00->g) + xWeight1 * ((upPix10)->g)) >> PADN; int bColDownTmp = (xWeight0 * (upPix00->b) + xWeight1 * ((upPix10)->b)) >> PADN; int rColUpTmp = (xWeight0 * ((upPix01)->r) + xWeight1 * ((upPix11)->r)) >> PADN; int gColUpTmp = (xWeight0 * ((upPix01)->g) + xWeight1 * ((upPix11)->g)) >> PADN; int bColUpTmp = (xWeight0 * ((upPix01)->b) + xWeight1 * ((upPix11)->b)) >> PADN; unsigned char rCol = (unsigned char)((yWeight0 * rColDownTmp + yWeight1 * rColUpTmp) >> PADN); unsigned char gCol = (unsigned char)((yWeight0 * gColDownTmp + yWeight1 * gColUpTmp) >> PADN); unsigned char bCol = (unsigned char)((yWeight0 * bColDownTmp + yWeight1 * bColUpTmp) >> PADN); TPixel32 upPix = TPixel32(rCol, gCol, bCol, upPix00->m); if (upPix.m == 0) continue; else if (upPix.m == 255) *dnPix = upPix; else *dnPix = quickOverPix(*dnPix, upPix); } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickPutNoFilter(const TRaster32P &dn, const TRaster32P &up, double sx, double sy, double tx, double ty, const TPixel32 &colorScale, bool doPremultiply, bool whiteTransp, bool firstColumn, bool doRasterDarkenBlendedView) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine // mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, yMin), (xMax, yMin) ] di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + kX*deltaXL // < up->getLx()*(1<getLy()*(1<getLx() int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int lyPred = up->getLy() * (1 << PADN) - 1; // 0 <= xL0 + k*deltaXL < up->getLx()*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL < up->getLy()*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con i lati // (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { // [a, b] interno ad up+(bordo destro/basso) assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up+(bordo destro/basso) assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con i lati // (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up+(bordo destro/basso) assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up+(bordo destro/basso) assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up // inizializza yL int yL = yL0 + (kMinY - 1) * deltaYL; // scorre le scanline di boundingBoxD for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { // inizializza xL int xL = xL0 + (kMinX - 1) * deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round TPixel32 *dnPix = dnRow + xMin + kMinX; TPixel32 *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; // il punto di up TPointD(xL/(1<> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixel32 upPix = *(upBasePix + (yI * upWrap + xI)); if (firstColumn) upPix.m = 65535; if (upPix.m == 0 || (whiteTransp && upPix == TPixel::White)) continue; if (colorScale != TPixel32::Black) upPix = applyColorScale(upPix, colorScale, doPremultiply); if (doRasterDarkenBlendedView) *dnPix = quickOverPixDarkenBlended(*dnPix, upPix); else { if (upPix.m == 255) *dnPix = upPix; else if (doPremultiply) *dnPix = quickOverPixPremult(*dnPix, upPix); else *dnPix = quickOverPix(*dnPix, upPix); } } } dn->unlock(); up->unlock(); } //============================================================================= void doQuickPutNoFilter(const TRaster32P &dn, const TRasterGR8P &up, double sx, double sy, double tx, double ty, const TPixel32 &colorScale) { if ((sx == 0) || (sy == 0)) return; const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); int xMin = std::max(tfloor(boundingBoxD.x0), 0); int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff double deltaXD = invAff.a11; double deltaYD = invAff.a22; int deltaXL = tround(deltaXD * (1 << PADN)); int deltaYL = tround(deltaYD * (1 << PADN)); if ((deltaXL == 0) || (deltaYL == 0)) return; TPointD a = invAff * TPointD(xMin, yMin); int xL0 = tround((a.x + 0.5) * (1 << PADN)); int yL0 = tround((a.y + 0.5) * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn int kMinY = 0, kMaxY = yMax - yMin; // clipping su dn int lxPred = up->getLx() * (1 << PADN) - 1; int lyPred = up->getLy() * (1 << PADN) - 1; if (deltaYL > 0) // (deltaYL != 0) { assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); if (deltaXL > 0) // (deltaXL != 0) { assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixelGR8 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); int yL = yL0 + (kMinY - 1) * deltaYL; for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { // inizializza xL int xL = xL0 + (kMinX - 1) * deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round TPixel32 *dnPix = dnRow + xMin + kMinX; TPixel32 *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; int xI = xL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixelGR8 *upPix = upBasePix + (yI * upWrap + xI); if (colorScale == TPixel32::Black) { dnPix->r = dnPix->g = dnPix->b = upPix->value; dnPix->m = 255; } else { TPixel32 upPix32(upPix->value, upPix->value, upPix->value, 255); upPix32 = applyColorScale(upPix32, colorScale); if (upPix32.m == 255) *dnPix = upPix32; else *dnPix = quickOverPix(*dnPix, upPix32); } /* if (upPix->value == 0) dnPix->r = dnPix->g = dnPix->b = dnPix->m = upPix->value; else if (upPix->value == 255) dnPix->r = dnPix->g = dnPix->b = dnPix->m = upPix->value; else *dnPix = quickOverPix(*dnPix, *upPix); */ } } dn->unlock(); up->unlock(); } void doQuickResampleFilter(const TRaster32P &dn, const TRaster32P &up, const TAffine &aff) { // se aff e' degenere la controimmagine di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - 2, up->getLy() - 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate // del pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; // naturale predecessore di up->getLx() - 1 int lxPred = (up->getLx() - 2) * (1 << PADN); // naturale predecessore di up->getLy() - 1 int lyPred = (up->getLy() - 2) * (1 << PADN); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel32 *upBasePix = up->pixels(); // scorre le scanline di boundingBoxD for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { // (1) equazione k-parametrica della y-esima scanline di boundingBoxD: // (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin) // // (2) equazione k-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, y) + k*(deltaXD, deltaYD), // k = kMin, ..., kMax // con 0 <= kMin <= kMax <= (xMax - xMin) // calcola kMin, kMax per la scanline corrente intersecando // la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, y), (xMax, y) ] di dn // TPointD b = invAff*TPointD(xMax, y); TPointD a = invAff * TPointD(xMin, y); // (xL0, yL0) sono le coordinate di a in versione "TLonghizzata" // 0 <= xL0 + k*deltaXL // <= (up->getLx() - 2)*(1<getLy() - 2)*(1<getLx() - 2)*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL <= (up->getLy() - 2)*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinX, kMaxX if (deltaXL == 0) { // [a, b] verticale esterno ad up contratto if ((xL0 < 0) || (lxPred < xL0)) continue; // altrimenti usa solo // kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaXL > 0) { // [a, b] esterno ad up+(bordo destro) if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] esterno ad up contratto if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up contratto if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { // [a, b] esterno ad up contratto if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] esterno ad up contratto if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clippind su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "longhizzata" del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // troncato int yI = yL >> PADN; // troncato assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); // (xI, yI) TPixel32 *upPix00 = upBasePix + (yI * upWrap + xI); // (xI + 1, yI) TPixel32 *upPix10 = upPix00 + 1; // (xI, yI + 1) TPixel32 *upPix01 = upPix00 + upWrap; // (xI + 1, yI + 1) TPixel32 *upPix11 = upPix00 + upWrap + 1; // filtro bilineare 4 pixels: calcolo dei pesi int xWeight1 = (xL & MASKN); int xWeight0 = (1 << PADN) - xWeight1; int yWeight1 = (yL & MASKN); int yWeight0 = (1 << PADN) - yWeight1; // filtro bilineare 4 pixels: media pesata sui singoli canali int rColDownTmp = (xWeight0 * (upPix00->r) + xWeight1 * ((upPix10)->r)) >> PADN; int gColDownTmp = (xWeight0 * (upPix00->g) + xWeight1 * ((upPix10)->g)) >> PADN; int bColDownTmp = (xWeight0 * (upPix00->b) + xWeight1 * ((upPix10)->b)) >> PADN; int mColDownTmp = (xWeight0 * (upPix00->m) + xWeight1 * ((upPix10)->m)) >> PADN; int rColUpTmp = (xWeight0 * ((upPix01)->r) + xWeight1 * ((upPix11)->r)) >> PADN; int gColUpTmp = (xWeight0 * ((upPix01)->g) + xWeight1 * ((upPix11)->g)) >> PADN; int bColUpTmp = (xWeight0 * ((upPix01)->b) + xWeight1 * ((upPix11)->b)) >> PADN; int mColUpTmp = (xWeight0 * ((upPix01)->m) + xWeight1 * ((upPix11)->m)) >> PADN; dnPix->r = (unsigned char)((yWeight0 * rColDownTmp + yWeight1 * rColUpTmp) >> PADN); dnPix->g = (unsigned char)((yWeight0 * gColDownTmp + yWeight1 * gColUpTmp) >> PADN); dnPix->b = (unsigned char)((yWeight0 * bColDownTmp + yWeight1 * bColUpTmp) >> PADN); dnPix->m = (unsigned char)((yWeight0 * mColDownTmp + yWeight1 * mColUpTmp) >> PADN); } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickResampleFilter(const TRaster32P &dn, const TRasterGR8P &up, const TAffine &aff) { if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; const int PADN = 16; const int MASKN = (1 << PADN) - 1; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - 2, up->getLy() - 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); int xMin = std::max(tfloor(boundingBoxD.x0), 0); int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); int deltaYL = tround(deltaYD * (1 << PADN)); if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = (up->getLx() - 2) * (1 << PADN); int lyPred = (up->getLy() - 2) * (1 << PADN); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixelGR8 *upBasePix = up->pixels(); for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { TPointD a = invAff * TPointD(xMin, y); int xL0 = tround(a.x * (1 << PADN)); int yL0 = tround(a.y * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn if (deltaXL == 0) { if ((xL0 < 0) || (lxPred < xL0)) continue; } else if (deltaXL > 0) { if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else { if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } if (deltaYL == 0) { if ((yL0 < 0) || (lyPred < yL0)) continue; } else if (deltaYL > 0) { if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; int xI = xL >> PADN; // troncato int yI = yL >> PADN; // troncato assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); // (xI, yI) TPixelGR8 *upPix00 = upBasePix + (yI * upWrap + xI); // (xI + 1, yI) TPixelGR8 *upPix10 = upPix00 + 1; // (xI, yI + 1) TPixelGR8 *upPix01 = upPix00 + upWrap; // (xI + 1, yI + 1) TPixelGR8 *upPix11 = upPix00 + upWrap + 1; // filtro bilineare 4 pixels: calcolo dei pesi int xWeight1 = (xL & MASKN); int xWeight0 = (1 << PADN) - xWeight1; int yWeight1 = (yL & MASKN); int yWeight0 = (1 << PADN) - yWeight1; // filtro bilineare 4 pixels: media pesata sui singoli canali int colDownTmp = (xWeight0 * (upPix00->value) + xWeight1 * ((upPix10)->value)) >> PADN; int colUpTmp = (xWeight0 * ((upPix01)->value) + xWeight1 * ((upPix11)->value)) >> PADN; dnPix->r = dnPix->g = dnPix->b = (unsigned char)((yWeight0 * colDownTmp + yWeight1 * colUpTmp) >> PADN); dnPix->m = 255; } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickResampleColorFilter(const TRaster32P &dn, const TRaster32P &up, const TAffine &aff, UCHAR colorMask) { if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping y su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // clipping x su dn TAffine invAff = inv(aff); // inversa di aff double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLx() int lyPred = up->getLy() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel32 *upBasePix = up->pixels(); for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { TPointD a = invAff * TPointD(xMin, y); int xL0 = tround((a.x + 0.5) * (1 << PADN)); int yL0 = tround((a.y + 0.5) * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn if (deltaXL == 0) { if ((xL0 < 0) || (lxPred < xL0)) continue; } else if (deltaXL > 0) { if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } else // (deltaXL < 0) { if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } if (deltaYL == 0) { if ((yL0 < 0) || (lyPred < yL0)) continue; } else if (deltaYL > 0) { if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } else // (deltaYL < 0) { if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; int xI = xL >> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); if (colorMask == TRop::MChan) dnPix->r = dnPix->g = dnPix->b = (upBasePix + (yI * upWrap + xI))->m; else { TPixel32 *pix = upBasePix + (yI * upWrap + xI); dnPix->r = ((colorMask & TRop::RChan) ? pix->r : 0); dnPix->g = ((colorMask & TRop::GChan) ? pix->g : 0); dnPix->b = ((colorMask & TRop::BChan) ? pix->b : 0); } dnPix->m = 255; } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= void doQuickResampleColorFilter(const TRaster32P &dn, const TRaster64P &up, const TAffine &aff, UCHAR colorMask) { if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping y su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // clipping x su dn TAffine invAff = inv(aff); // inversa di aff double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLx() int lyPred = up->getLy() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel64 *upBasePix = up->pixels(); for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { TPointD a = invAff * TPointD(xMin, y); int xL0 = tround((a.x + 0.5) * (1 << PADN)); int yL0 = tround((a.y + 0.5) * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn if (deltaXL == 0) { if ((xL0 < 0) || (lxPred < xL0)) continue; } else if (deltaXL > 0) { if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } else // (deltaXL < 0) { if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } if (deltaYL == 0) { if ((yL0 < 0) || (lyPred < yL0)) continue; } else if (deltaYL > 0) { if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } else // (deltaYL < 0) { if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; int xI = xL >> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); if (colorMask == TRop::MChan) dnPix->r = dnPix->g = dnPix->b = byteFromUshort((upBasePix + (yI * upWrap + xI))->m); else { TPixel64 *pix = upBasePix + (yI * upWrap + xI); dnPix->r = byteFromUshort(((colorMask & TRop::RChan) ? pix->r : 0)); dnPix->g = byteFromUshort(((colorMask & TRop::GChan) ? pix->g : 0)); dnPix->b = byteFromUshort(((colorMask & TRop::BChan) ? pix->b : 0)); } dnPix->m = 255; } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickResampleFilter(const TRaster32P &dn, const TRaster32P &up, double sx, double sy, double tx, double ty) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - /*1*/ 2, up->getLy() - /*1*/ 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' // un segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up (con gli estremi eventualmente invertiti) e' // la controimmagine mediante aff della porzione di scanline // [ (xMin, yMin), (xMax, yMin) ] di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + kX*deltaXL <= (up->getLx() - 2)*(1<getLy() - 2)*(1<getLx() - 1) int lxPred = (up->getLx() - /*1*/ 2) * (1 << PADN); // TINT32 predecessore di (up->getLy() - 1) int lyPred = (up->getLy() - /*1*/ 2) * (1 << PADN); // 0 <= xL0 + k*deltaXL <= (up->getLx() - 2)*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL <= (up->getLy() - 2)*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con i lati // (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { // [a, b] interno ad up contratto assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up contratto assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con i lati // (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up contratto assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up contratto assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" // del pixel corrente di up int yL = yL0 + (kMinY - 1) * deltaYL; // inizializza yL // scorre le scanline di boundingBoxD for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { int xL = xL0 + (kMinX - 1) * deltaXL; // inizializza xL yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // troncato // filtro bilineare 4 pixels: calcolo degli y-pesi int yWeight1 = (yL & MASKN); int yWeight0 = (1 << PADN) - yWeight1; TPixel32 *dnPix = dnRow + xMin + kMinX; TPixel32 *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; // il punto di up TPointD(xL/(1<> PADN; // troncato assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); // (xI, yI) TPixel32 *upPix00 = upBasePix + (yI * upWrap + xI); // (xI + 1, yI) TPixel32 *upPix10 = upPix00 + 1; // (xI, yI + 1) TPixel32 *upPix01 = upPix00 + upWrap; // (xI + 1, yI + 1) TPixel32 *upPix11 = upPix00 + upWrap + 1; // filtro bilineare 4 pixels: calcolo degli x-pesi int xWeight1 = (xL & MASKN); int xWeight0 = (1 << PADN) - xWeight1; // filtro bilineare 4 pixels: media pesata sui singoli canali int rColDownTmp = (xWeight0 * (upPix00->r) + xWeight1 * ((upPix10)->r)) >> PADN; int gColDownTmp = (xWeight0 * (upPix00->g) + xWeight1 * ((upPix10)->g)) >> PADN; int bColDownTmp = (xWeight0 * (upPix00->b) + xWeight1 * ((upPix10)->b)) >> PADN; int mColDownTmp = (xWeight0 * (upPix00->m) + xWeight1 * ((upPix10)->m)) >> PADN; int rColUpTmp = (xWeight0 * ((upPix01)->r) + xWeight1 * ((upPix11)->r)) >> PADN; int gColUpTmp = (xWeight0 * ((upPix01)->g) + xWeight1 * ((upPix11)->g)) >> PADN; int bColUpTmp = (xWeight0 * ((upPix01)->b) + xWeight1 * ((upPix11)->b)) >> PADN; int mColUpTmp = (xWeight0 * ((upPix01)->m) + xWeight1 * ((upPix11)->m)) >> PADN; dnPix->r = (unsigned char)((yWeight0 * rColDownTmp + yWeight1 * rColUpTmp) >> PADN); dnPix->g = (unsigned char)((yWeight0 * gColDownTmp + yWeight1 * gColUpTmp) >> PADN); dnPix->b = (unsigned char)((yWeight0 * bColDownTmp + yWeight1 * bColUpTmp) >> PADN); dnPix->m = (unsigned char)((yWeight0 * mColDownTmp + yWeight1 * mColUpTmp) >> PADN); } } dn->unlock(); up->unlock(); } //------------------------------------------------------------------------------------------ void doQuickResampleFilter(const TRaster32P &dn, const TRasterGR8P &up, double sx, double sy, double tx, double ty) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - /*1*/ 2, up->getLy() - /*1*/ 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' // un segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up (con gli estremi eventualmente invertiti) e' // la controimmagine mediante aff della porzione di scanline // [ (xMin, yMin), (xMax, yMin) ] di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + kX*deltaXL <= (up->getLx() - 2)*(1<getLy() - 2)*(1<getLx() - 1) int lxPred = (up->getLx() - /*1*/ 2) * (1 << PADN); // TINT32 predecessore di (up->getLy() - 1) int lyPred = (up->getLy() - /*1*/ 2) * (1 << PADN); // 0 <= xL0 + k*deltaXL <= (up->getLx() - 2)*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL <= (up->getLy() - 2)*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con i lati // (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { // [a, b] interno ad up contratto assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up contratto assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con i lati // (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up contratto assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up contratto assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixelGR8 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" // del pixel corrente di up int yL = yL0 + (kMinY - 1) * deltaYL; // inizializza yL // scorre le scanline di boundingBoxD for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { int xL = xL0 + (kMinX - 1) * deltaXL; // inizializza xL yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // troncato // filtro bilineare 4 pixels: calcolo degli y-pesi int yWeight1 = (yL & MASKN); int yWeight0 = (1 << PADN) - yWeight1; TPixel32 *dnPix = dnRow + xMin + kMinX; TPixel32 *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; // il punto di up TPointD(xL/(1<> PADN; // troncato assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); // (xI, yI) TPixelGR8 *upPix00 = upBasePix + (yI * upWrap + xI); // (xI + 1, yI) TPixelGR8 *upPix10 = upPix00 + 1; // (xI, yI + 1) TPixelGR8 *upPix01 = upPix00 + upWrap; // (xI + 1, yI + 1) TPixelGR8 *upPix11 = upPix00 + upWrap + 1; // filtro bilineare 4 pixels: calcolo degli x-pesi int xWeight1 = (xL & MASKN); int xWeight0 = (1 << PADN) - xWeight1; // filtro bilineare 4 pixels: media pesata sui singoli canali int colDownTmp = (xWeight0 * (upPix00->value) + xWeight1 * (upPix10->value)) >> PADN; int colUpTmp = (xWeight0 * ((upPix01)->value) + xWeight1 * (upPix11->value)) >> PADN; dnPix->m = 255; dnPix->r = dnPix->g = dnPix->b = (unsigned char)((yWeight0 * colDownTmp + yWeight1 * colUpTmp) >> PADN); } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= template void doQuickResampleNoFilter(const TRasterPT &dn, const TRasterPT &up, double sx, double sy, double tx, double ty) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, yMin), (xMax, yMin) ] di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + kX*deltaXL < up->getLx()*(1<getLy()*(1<getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLx() int lyPred = up->getLy() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() // 0 <= xL0 + k*deltaXL < up->getLx()*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL < up->getLy()*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con i lati // (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { assert(yL0 <= lyPred); // [a, b] interno ad up+(bordo destro/basso) kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up+(bordo destro/basso) assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con i lati // (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up+(bordo destro/basso) assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up+(bordo destro/basso) assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); PIX *upBasePix = up->pixels(); PIX *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up int yL = yL0 + (kMinY - 1) * deltaYL; // inizializza yL // scorre le scanline di boundingBoxD for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { int xL = xL0 + (kMinX - 1) * deltaXL; // inizializza xL yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round PIX *dnPix = dnRow + xMin + kMinX; PIX *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; // il punto di up TPointD(xL/(1<> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); *dnPix = *(upBasePix + (yI * upWrap + xI)); } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= #ifndef TNZCORE_LIGHT //============================================================================= //============================================================================= //============================================================================= //============================================================================= // // doQuickPutCmapped // //============================================================================= void doQuickPutCmapped(const TRaster32P &dn, const TRasterCM32P &up, const TPaletteP &palette, const TAffine &aff, const TPixel32 &globalColorScale, bool inksOnly) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; // TINT32 predecessore di up->getLx() int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int lyPred = up->getLy() * (1 << PADN) - 1; int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); std::vector colors(palette->getStyleCount()); // vector inks(palette->getStyleCount()); if (globalColorScale != TPixel::Black) for (int i = 0; i < palette->getStyleCount(); i++) colors[i] = applyColorScaleCMapped( palette->getStyle(i)->getAverageColor(), globalColorScale); else for (int i = 0; i < palette->getStyleCount(); i++) colors[i] = ::premultiply(palette->getStyle(i)->getAverageColor()); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixelCM32 *upBasePix = up->pixels(); // scorre le scanline di boundingBoxD for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { // (1) equazione k-parametrica della y-esima scanline di boundingBoxD: // (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin) // (2) equazione k-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, y) + k*(deltaXD, deltaYD), // k = kMin, ..., kMax con 0 <= kMin <= kMax <= (xMax - xMin) // calcola kMin, kMax per la scanline corrente // intersecando la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, y), (xMax, y) ] di dn // TPointD b = invAff*TPointD(xMax, y); TPointD a = invAff * TPointD(xMin, y); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + k*deltaXL // < up->getLx()*(1<getLy()*(1<getLx()*(1< // 0 <= xL0 + k*deltaXL // <= lxPred // // 0 <= yL0 + k*deltaYL // < up->getLy()*(1< // 0 <= yL0 + k*deltaYL // <= lyPred // calcola kMinX, kMaxX if (deltaXL == 0) { // [a, b] verticale esterno ad up+(bordo destro/basso) if ((xL0 < 0) || (lxPred < xL0)) continue; // altrimenti usa solo // kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaXL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up+(bordo destro/basso) if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clippind su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixelCM32 *upPix = upBasePix + (yI * upWrap + xI); int t = upPix->getTone(); int p = upPix->getPaint(); if (t == 0xff && p == 0) continue; else { int i = upPix->getInk(); TPixel32 colorUp; if (inksOnly) switch (t) { case 0: colorUp = colors[i]; break; case 255: colorUp = TPixel::Transparent; break; default: colorUp = antialias(colors[i], 255 - t); break; } else switch (t) { case 0: colorUp = colors[i]; break; case 255: colorUp = colors[p]; break; default: colorUp = blend(colors[i], colors[p], t, TPixelCM32::getMaxTone()); break; } if (colorUp.m == 255) *dnPix = colorUp; else if (colorUp.m != 0) *dnPix = quickOverPix(*dnPix, colorUp); } } } dn->unlock(); up->unlock(); } //============================================================================= // // doQuickPutCmapped + transparencyCheck + inkCheck + paintcheck // //============================================================================= /* TPixel TransparencyCheckBlackBgInk = TPixel(255,255,255); //bg TPixel TransparencyCheckWhiteBgInk = TPixel(0,0,0); //ink TPixel TransparencyCheckPaint = TPixel(127,127,127); //paint*/ void doQuickPutCmapped(const TRaster32P &dn, const TRasterCM32P &up, const TPaletteP &palette, const TAffine &aff, const TRop::CmappedQuickputSettings &s) /*const TPixel32& globalColorScale, bool inksOnly, bool transparencyCheck, bool blackBgCheck, int inkIndex, int paintIndex)*/ { if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); int xMin = std::max(tfloor(boundingBoxD.x0), 0); int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); int deltaYL = tround(deltaYD * (1 << PADN)); if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = up->getLx() * (1 << PADN) - 1; int lyPred = up->getLy() * (1 << PADN) - 1; int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); std::vector paints(palette->getStyleCount()); std::vector inks(palette->getStyleCount()); if (s.m_transparencyCheck) for (int i = 0; i < palette->getStyleCount(); i++) { paints[i] = s.m_transpCheckPaint; inks[i] = s.m_blackBgCheck ? s.m_transpCheckBg : s.m_transpCheckInk; } else if (s.m_globalColorScale == TPixel::Black) for (int i = 0; i < palette->getStyleCount(); i++) paints[i] = inks[i] = ::premultiply(palette->getStyle(i)->getAverageColor()); else for (int i = 0; i < palette->getStyleCount(); i++) paints[i] = inks[i] = applyColorScaleCMapped( palette->getStyle(i)->getAverageColor(), s.m_globalColorScale); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixelCM32 *upBasePix = up->pixels(); for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { TPointD a = invAff * TPointD(xMin, y); int xL0 = tround((a.x + 0.5) * (1 << PADN)); int yL0 = tround((a.y + 0.5) * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; int kMinY = 0, kMaxY = xMax - xMin; if (deltaXL == 0) { if ((xL0 < 0) || (lxPred < xL0)) continue; } else if (deltaXL > 0) { if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } else { if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } if (deltaYL == 0) { if ((yL0 < 0) || (lyPred < yL0)) continue; } else if (deltaYL > 0) { if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; if (yL0 < 0) kMinY = ((-yL0) + deltaYL - 1) / deltaYL; } else { if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; int xL = xL0 + (kMin - 1) * deltaXL; int yL = yL0 + (kMin - 1) * deltaYL; for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; int xI = xL >> PADN; int yI = yL >> PADN; assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixelCM32 *upPix = upBasePix + (yI * upWrap + xI); int t = upPix->getTone(); int p = upPix->getPaint(); if (t == 0xff && p == 0) continue; else { int i = upPix->getInk(); TPixel32 colorUp; if (s.m_inksOnly) switch (t) { case 0: colorUp = (i == s.m_inkIndex) ? TPixel::Red : inks[i]; break; case 255: colorUp = TPixel::Transparent; break; default: { TPixel inkColor; if (i == s.m_inkIndex) { inkColor = TPixel::Red; if (p == 0) { t = t / 2; // transparency check(for a bug!) darken // semitrasparent pixels; ghibli likes it, and wants // it also for ink checks... // otherwise, ramps goes always from reds towards grey... } } else inkColor = inks[i]; colorUp = antialias(inkColor, 255 - t); break; } } else switch (t) { case 0: colorUp = (i == s.m_inkIndex) ? TPixel::Red : inks[i]; break; case 255: colorUp = (p == s.m_paintIndex) ? TPixel::Red : paints[p]; break; default: { TPixel paintColor = (p == s.m_paintIndex) ? TPixel::Red : paints[p]; TPixel inkColor; if (i == s.m_inkIndex) { inkColor = TPixel::Red; if (p == 0) { paintColor = TPixel::Transparent; } } else inkColor = inks[i]; if (s.m_transparencyCheck) t = t / 2; colorUp = blend(inkColor, paintColor, t, TPixelCM32::getMaxTone()); break; } } if (colorUp.m == 255) *dnPix = colorUp; else if (colorUp.m != 0) *dnPix = quickOverPix(*dnPix, colorUp); } } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= void doQuickPutCmapped(const TRaster32P &dn, const TRasterCM32P &up, const TPaletteP &palette, double sx, double sy, double tx, double ty, const TPixel32 &globalColorScale, bool inksOnly) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine // mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, yMin), (xMax, yMin) ] di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + kX*deltaXL // < up->getLx()*(1<getLy()*(1<getLx() int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int lyPred = up->getLy() * (1 << PADN) - 1; // 0 <= xL0 + k*deltaXL < up->getLx()*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL < up->getLy()*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con i lati // (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { // [a, b] interno ad up+(bordo destro/basso) assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up+(bordo destro/basso) assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con i lati // (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up+(bordo destro/basso) assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up+(bordo destro/basso) assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); int count = std::max({palette->getStyleCount(), TPixelCM32::getMaxInk(), TPixelCM32::getMaxPaint()}); std::vector paints(count, TPixel32::Red); std::vector inks(count, TPixel32::Red); if (globalColorScale != TPixel::Black) for (int i = 0; i < palette->getStyleCount(); i++) paints[i] = inks[i] = applyColorScaleCMapped( palette->getStyle(i)->getAverageColor(), globalColorScale); else for (int i = 0; i < palette->getStyleCount(); i++) paints[i] = inks[i] = ::premultiply(palette->getStyle(i)->getAverageColor()); dn->lock(); up->lock(); TPixelCM32 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up // inizializza yL int yL = yL0 + (kMinY - 1) * deltaYL; // scorre le scanline di boundingBoxD for (int kY = kMinY; kY <= kMaxY; kY++, dnRow += dnWrap) { // inizializza xL int xL = xL0 + (kMinX - 1) * deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round TPixel32 *dnPix = dnRow + xMin + kMinX; TPixel32 *dnEndPix = dnRow + xMin + kMaxX + 1; // scorre i pixel sulla (yMin + kY)-esima scanline di dn for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; // il punto di up TPointD(xL/(1<> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixelCM32 *upPix = upBasePix + (yI * upWrap + xI); int t = upPix->getTone(); int p = upPix->getPaint(); assert(0 <= t && t < 256); assert(0 <= p && p < (int)paints.size()); if (t == 0xff && p == 0) continue; else { int i = upPix->getInk(); assert(0 <= i && i < (int)inks.size()); TPixel32 colorUp; if (inksOnly) switch (t) { case 0: colorUp = inks[i]; break; case 255: colorUp = TPixel::Transparent; break; default: colorUp = antialias(inks[i], 255 - t); break; } else switch (t) { case 0: colorUp = inks[i]; break; case 255: colorUp = paints[p]; break; default: colorUp = blend(inks[i], paints[p], t, TPixelCM32::getMaxTone()); break; } if (colorUp.m == 255) *dnPix = colorUp; else if (colorUp.m != 0) *dnPix = quickOverPix(*dnPix, colorUp); } } } dn->unlock(); up->unlock(); } //============================================================================= //============================================================================= //============================================================================= void doQuickResampleColorFilter(const TRaster32P &dn, const TRasterCM32P &up, const TPaletteP &plt, const TAffine &aff, UCHAR colorMask) { if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; const int PADN = 16; std::vector paints(plt->getStyleCount()); std::vector inks(plt->getStyleCount()); for (int i = 0; i < plt->getStyleCount(); i++) paints[i] = inks[i] = ::premultiply(plt->getStyle(i)->getAverageColor()); assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping y su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // clipping x su dn TAffine invAff = inv(aff); // inversa di aff double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLx() int lyPred = up->getLy() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixelCM32 *upBasePix = up->pixels(); for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { TPointD a = invAff * TPointD(xMin, y); int xL0 = tround((a.x + 0.5) * (1 << PADN)); int yL0 = tround((a.y + 0.5) * (1 << PADN)); int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn if (deltaXL == 0) { if ((xL0 < 0) || (lxPred < xL0)) continue; } else if (deltaXL > 0) { if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } else // (deltaXL < 0) { if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } if (deltaYL == 0) { if ((yL0 < 0) || (lyPred < yL0)) continue; } else if (deltaYL > 0) { if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } else // (deltaYL < 0) { if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); TPixel32 *dnPix = dnRow + xMin + kMin; TPixel32 *dnEndPix = dnRow + xMin + kMax + 1; int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; int xI = xL >> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); TPixelCM32 *upPix = upBasePix + (yI * upWrap + xI); int t = upPix->getTone(); int p = upPix->getPaint(); int i = upPix->getInk(); TPixel32 colorUp; switch (t) { case 0: colorUp = inks[i]; break; case 255: colorUp = paints[p]; break; default: colorUp = blend(inks[i], paints[p], t, TPixelCM32::getMaxTone()); break; } if (colorMask == TRop::MChan) dnPix->r = dnPix->g = dnPix->b = colorUp.m; else { dnPix->r = ((colorMask & TRop::RChan) ? colorUp.r : 0); dnPix->g = ((colorMask & TRop::GChan) ? colorUp.g : 0); dnPix->b = ((colorMask & TRop::BChan) ? colorUp.b : 0); } dnPix->m = 255; } } dn->unlock(); up->unlock(); } //========================================================== #endif // TNZCORE_LIGHT #ifdef OPTIMIZE_FOR_LP64 void doQuickResampleFilter_optimized(const TRaster32P &dn, const TRaster32P &up, const TAffine &aff) { // se aff e' degenere la controimmagine di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - 2, up->getLy() - 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); TAffine invAff = inv(aff); // inversa di aff // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate // del pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; // deltaXD "TLonghizzato" (round) int deltaXL = tround(deltaXD * (1 << PADN)); // deltaYD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un // segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; // naturale predecessore di up->getLx() - 1 int lxPred = (up->getLx() - 2) * (1 << PADN); // naturale predecessore di up->getLy() - 1 int lyPred = (up->getLy() - 2) * (1 << PADN); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *dnRow = dn->pixels(yMin); TPixel32 *upBasePix = up->pixels(); long c1; long c2; long c3; long c4; long c5; long c6; long s_rg; long s_br; long s_gb; UINT32 rColDownTmp; UINT32 gColDownTmp; UINT32 bColDownTmp; UINT32 rColUpTmp; UINT32 gColUpTmp; UINT32 bColUpTmp; unsigned char rCol; unsigned char gCol; unsigned char bCol; int xI; int yI; int xWeight1; int xWeight0; int yWeight1; int yWeight0; TPixel32 *upPix00; TPixel32 *upPix10; TPixel32 *upPix01; TPixel32 *upPix11; TPointD a; int xL0; int yL0; int kMinX; int kMaxX; int kMinY; int kMaxY; int kMin; int kMax; TPixel32 *dnPix; TPixel32 *dnEndPix; int xL; int yL; int y = yMin; ++yMax; // scorre le scanline di boundingBoxD for (; y < yMax - 32; ++y, dnRow += dnWrap) { EXTERNAL_LOOP_THE_FIRST_X_32 } for (; y < yMax - 16; ++y, dnRow += dnWrap) { EXTERNAL_LOOP_THE_FIRST_X_16 } for (; y < yMax - 8; ++y, dnRow += dnWrap) { EXTERNAL_LOOP_THE_FIRST_X_8 } for (; y < yMax - 4; ++y, dnRow += dnWrap) { EXTERNAL_LOOP_THE_FIRST_X_4 } for (; y < yMax - 2; ++y, dnRow += dnWrap) { EXTERNAL_LOOP_THE_FIRST_X_2 } for (; y < yMax; ++y, dnRow += dnWrap) { EXTERNAL_LOOP_THE_FIRST } dn->unlock(); up->unlock(); } #endif //============================================================================= //============================================================================= //============================================================================= #ifdef OPTIMIZE_FOR_LP64 void doQuickResampleFilter_optimized(const TRaster32P &dn, const TRaster32P &up, double sx, double sy, double tx, double ty) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((sx == 0) || (sy == 0)) return; // contatore bit di shift const int PADN = 16; // maschera del filtro bilineare const int MASKN = (1 << PADN) - 1; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TAffine aff(sx, 0, tx, 0, sy, ty); TRectD boundingBoxD = TRectD(convert(dn->getSize())) * (aff * TRectD(0, 0, up->getLx() - 2, up->getLy() - 2)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; // clipping y su dn int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping x su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // inversa di aff TAffine invAff = inv(aff); // nello scorrere le scanline di boundingBoxD, il passaggio alla scanline // successiva comporta l'incremento (0, deltaYD) delle coordinate dei // pixels corrispondenti di up // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, 0) delle coordinate del // pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a22; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' // un segmento (o un punto) if ((deltaXL == 0) || (deltaYL == 0)) return; // (1) equazione (kX, kY)-parametrica di boundingBoxD: // (xMin, yMin) + kX*(1, 0) + kY*(0, 1), // kX = 0, ..., (xMax - xMin), // kY = 0, ..., (yMax - yMin) // (2) equazione (kX, kY)-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, yMin) + kX*(deltaXD, 0) + kY*(0, deltaYD), // kX = kMinX, ..., kMaxX // con 0 <= kMinX <= kMaxX <= (xMax - xMin) // // kY = kMinY, ..., kMaxY // con 0 <= kMinY <= kMaxY <= (yMax - yMin) // calcola kMinX, kMaxX, kMinY, kMaxY intersecando la (2) con i lati di up // il segmento [a, b] di up (con gli estremi eventualmente invertiti) e' // la controimmagine mediante aff della porzione di scanline // [ (xMin, yMin), (xMax, yMin) ] di dn // TPointD b = invAff*TPointD(xMax, yMin); TPointD a = invAff * TPointD(xMin, yMin); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + kX*deltaXL <= (up->getLx() - 2)*(1<getLy() - 2)*(1<getLx() - 1) int lxPred = (up->getLx() - 2) * (1 << PADN); // TINT32 predecessore di (up->getLy() - 1) int lyPred = (up->getLy() - 2) * (1 << PADN); // 0 <= xL0 + k*deltaXL <= (up->getLx() - 2)*(1< // 0 <= xL0 + k*deltaXL <= lxPred // 0 <= yL0 + k*deltaYL <= (up->getLy() - 2)*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinY, kMaxY intersecando la (2) con i lati // (y = yMin) e (y = yMax) di up if (deltaYL > 0) // (deltaYL != 0) { // [a, b] interno ad up contratto assert(yL0 <= lyPred); kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] interno ad up contratto assert(0 <= yL0); kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMinY, kMaxY effettuando anche il clippind su dn kMinY = std::max(kMinY, (int)0); kMaxY = std::min(kMaxY, yMax - yMin); // calcola kMinX, kMaxX intersecando la (2) con i lati // (x = xMin) e (x = xMax) di up if (deltaXL > 0) // (deltaXL != 0) { // [a, b] interno ad up contratto assert(xL0 <= lxPred); kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] interno ad up contratto assert(0 <= xL0); kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinX, kMaxX effettuando anche il clippind su dn kMinX = std::max(kMinX, (int)0); kMaxX = std::min(kMaxX, xMax - xMin); int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); TPixel32 *upBasePix = up->pixels(); TPixel32 *dnRow = dn->pixels(yMin + kMinY); // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" // del pixel corrente di up int yL = yL0 + (kMinY - 1) * deltaYL; // inizializza yL long c1; long c2; long c3; long c4; long c5; long c6; long s_rg; long s_br; long s_gb; UINT32 rColDownTmp; UINT32 gColDownTmp; UINT32 bColDownTmp; UINT32 rColUpTmp; UINT32 gColUpTmp; UINT32 bColUpTmp; int xI; TPixel32 *upPix00; TPixel32 *upPix10; TPixel32 *upPix01; TPixel32 *upPix11; int xWeight1; int xWeight0; unsigned char rCol; unsigned char gCol; unsigned char bCol; int xL; int yI; int yWeight1; int yWeight0; TPixel32 *dnPix; TPixel32 *dnEndPix; int kY = kMinY; ++kMaxY; // scorre le scanline di boundingBoxD for (; kY < kMaxY - 32; kY++, dnRow += dnWrap) { EXTERNAL_LOOP_THE_SECOND_X_32 } for (; kY < kMaxY - 16; kY++, dnRow += dnWrap) { EXTERNAL_LOOP_THE_SECOND_X_16 } for (; kY < kMaxY - 8; kY++, dnRow += dnWrap) { EXTERNAL_LOOP_THE_SECOND_X_8 } for (; kY < kMaxY - 4; kY++, dnRow += dnWrap) { EXTERNAL_LOOP_THE_SECOND_X_4 } for (; kY < kMaxY - 2; kY++, dnRow += dnWrap) { EXTERNAL_LOOP_THE_SECOND_X_2 } for (; kY < kMaxY; kY++, dnRow += dnWrap) { EXTERNAL_LOOP_THE_SECOND } dn->unlock(); up->unlock(); } #endif // namespace }; #ifndef TNZCORE_LIGHT //============================================================================= // // quickPut (paletted) // //============================================================================= void TRop::quickPut(const TRasterP &dn, const TRasterCM32P &upCM32, const TPaletteP &plt, const TAffine &aff, const TPixel32 &globalColorScale, bool inksOnly) { TRaster32P dn32 = dn; if (dn32 && upCM32) if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickPutCmapped(dn32, upCM32, plt, aff.a11, aff.a22, aff.a13, aff.a23, globalColorScale, inksOnly); else doQuickPutCmapped(dn32, upCM32, plt, aff, globalColorScale, inksOnly); else throw TRopException("raster type mismatch"); } //============================================================================= // // quickPut (paletted + transparency check + ink check + paint check) // //============================================================================= void TRop::quickPut(const TRasterP &dn, const TRasterCM32P &upCM32, const TPaletteP &plt, const TAffine &aff, const CmappedQuickputSettings &settings) // const TPixel32& // globalColorScale, bool // inksOnly, bool // transparencyCheck, bool // blackBgCheck, int inkIndex, int // paintIndex) { TRaster32P dn32 = dn; if (dn32 && upCM32) doQuickPutCmapped(dn32, upCM32, plt, aff, settings); // globalColorScale, inksOnly, // transparencyCheck, blackBgCheck, inkIndex, // paintIndex); else throw TRopException("raster type mismatch"); } void TRop::quickResampleColorFilter(const TRasterP &dn, const TRasterP &up, const TAffine &aff, const TPaletteP &plt, UCHAR colorMask) { TRaster32P dn32 = dn; TRaster32P up32 = up; TRaster64P up64 = up; TRasterCM32P upCM32 = up; if (dn32 && up32) doQuickResampleColorFilter(dn32, up32, aff, colorMask); else if (dn32 && upCM32) doQuickResampleColorFilter(dn32, upCM32, plt, aff, colorMask); else if (dn32 && up64) doQuickResampleColorFilter(dn32, up64, aff, colorMask); // else if (dn32 && upCM32) // doQuickResampleColorFilter(dn32, upCM32, aff, plt, colorMask); else throw TRopException("raster type mismatch"); } #endif // TNZCORE_LIGHT //============================================================================= //============================================================================= // // quickPut (Bilinear/Closest) // //============================================================================= void quickPut(const TRasterP &dn, const TRasterP &up, const TAffine &aff, TRop::ResampleFilterType filterType, const TPixel32 &colorScale, bool doPremultiply, bool whiteTransp, bool firstColumn, bool doRasterDarkenBlendedView) { assert(filterType == TRop::Bilinear || filterType == TRop::ClosestPixel); bool bilinear = filterType == TRop::Bilinear; TRaster32P dn32 = dn; TRaster32P up32 = up; TRasterGR8P dn8 = dn; TRasterGR8P up8 = up; TRaster64P up64 = up; if (up8 && dn32) { assert(filterType == TRop::ClosestPixel); if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickPutNoFilter(dn32, up8, aff.a11, aff.a22, aff.a13, aff.a23, colorScale); else doQuickPutNoFilter(dn32, up8, aff, colorScale); } else if (dn32 && up32) { if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) { if (bilinear) doQuickPutFilter(dn32, up32, aff.a11, aff.a22, aff.a13, aff.a23); else { doQuickPutNoFilter(dn32, up32, aff.a11, aff.a22, aff.a13, aff.a23, colorScale, doPremultiply, whiteTransp, firstColumn, doRasterDarkenBlendedView); } } else if (bilinear) doQuickPutFilter(dn32, up32, aff); else { doQuickPutNoFilter(dn32, up32, aff, colorScale, doPremultiply, whiteTransp, firstColumn, doRasterDarkenBlendedView); } } else if (dn32 && up64) doQuickPutNoFilter(dn32, up64, aff, doPremultiply, firstColumn); else throw TRopException("raster type mismatch"); } //============================================================================= template void doQuickResampleNoFilter(const TRasterPT &dn, const TRasterPT &up, const TAffine &aff) { // se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine // di up e' un segmento (o un punto) if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return; // contatore bit di shift const int PADN = 16; // max dimensioni di up gestibili (limite imposto dal numero di bit // disponibili per la parte intera di xL, yL) assert(std::max(up->getLx(), up->getLy()) < (1 << (8 * sizeof(int) - PADN - 1))); TRectD boundingBoxD = TRectD(convert(dn->getBounds())) * (aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5)); // clipping if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1) return; int yMin = std::max(tfloor(boundingBoxD.y0), 0); // clipping y su dn int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1); // clipping y su dn int xMin = std::max(tfloor(boundingBoxD.x0), 0); // clipping x su dn int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1); // clipping x su dn TAffine invAff = inv(aff); // inversa di aff // nel disegnare la y-esima scanline di dn, il passaggio al pixel // successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate // del pixel corrispondente di up double deltaXD = invAff.a11; double deltaYD = invAff.a21; int deltaXL = tround(deltaXD * (1 << PADN)); // deltaXD "TLonghizzato" (round) int deltaYL = tround(deltaYD * (1 << PADN)); // deltaYD "TLonghizzato" (round) // se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' // un segmento (o un punto) if ((deltaXL == 0) && (deltaYL == 0)) return; int lxPred = up->getLx() * (1 << PADN) - 1; // TINT32 predecessore di up->getLx() int lyPred = up->getLy() * (1 << PADN) - 1; // TINT32 predecessore di up->getLy() int dnWrap = dn->getWrap(); int upWrap = up->getWrap(); dn->lock(); up->lock(); PIX *dnRow = dn->pixels(yMin); PIX *upBasePix = up->pixels(); // scorre le scanline di boundingBoxD for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) { // (1) equazione k-parametrica della y-esima scanline di boundingBoxD: // (xMin, y) + k*(1, 0), // k = 0, ..., (xMax - xMin) // (2) equazione k-parametrica dell'immagine mediante invAff di (1): // invAff*(xMin, y) + k*(deltaXD, deltaYD), // k = kMin, ..., kMax // con 0 <= kMin <= kMax <= (xMax - xMin) // calcola kMin, kMax per la scanline corrente intersecando // la (2) con i lati di up // il segmento [a, b] di up e' la controimmagine mediante aff della // porzione di scanline [ (xMin, y), (xMax, y) ] di dn // TPointD b = invAff*TPointD(xMax, y); TPointD a = invAff * TPointD(xMin, y); // (xL0, yL0) sono le coordinate di a (inizializzate per il round) // in versione "TLonghizzata" // 0 <= xL0 + k*deltaXL < up->getLx()*(1<getLy()*(1<getLx()*(1< // 0 <= xL0 + k*eltaXL <= lxPred // 0 <= yL0 + k*deltaYL < up->getLy()*(1< // 0 <= yL0 + k*deltaYL <= lyPred // calcola kMinX, kMaxX if (deltaXL == 0) { // [a, b] verticale esterno ad up+(bordo destro/basso) if ((xL0 < 0) || (lxPred < xL0)) continue; // altrimenti usa solo // kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaXL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lxPred < xL0) continue; kMaxX = (lxPred - xL0) / deltaXL; // floor if (xL0 < 0) { kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil } } else // (deltaXL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (xL0 < 0) continue; kMaxX = xL0 / (-deltaXL); // floor if (lxPred < xL0) { kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil } } // calcola kMinY, kMaxY if (deltaYL == 0) { // [a, b] orizzontale esterno ad up+(bordo destro/basso) if ((yL0 < 0) || (lyPred < yL0)) continue; // altrimenti usa solo // kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0)) } else if (deltaYL > 0) { // [a, b] esterno ad up+(bordo destro/basso) if (lyPred < yL0) continue; kMaxY = (lyPred - yL0) / deltaYL; // floor if (yL0 < 0) { kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil } } else // (deltaYL < 0) { // [a, b] esterno ad up+(bordo destro/basso) if (yL0 < 0) continue; kMaxY = yL0 / (-deltaYL); // floor if (lyPred < yL0) { kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil } } // calcola kMin, kMax effettuando anche il clippind su dn int kMin = std::max({kMinX, kMinY, (int)0}); int kMax = std::min({kMaxX, kMaxY, xMax - xMin}); PIX *dnPix = dnRow + xMin + kMin; PIX *dnEndPix = dnRow + xMin + kMax + 1; // (xL, yL) sono le coordinate (inizializzate per il round) // in versione "TLonghizzata" del pixel corrente di up int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL // scorre i pixel sulla y-esima scanline di boundingBoxD for (; dnPix < dnEndPix; ++dnPix) { xL += deltaXL; yL += deltaYL; // il punto di up TPointD(xL/(1<> PADN; // round int yI = yL >> PADN; // round assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) && (yI <= up->getLy() - 1)); *dnPix = *(upBasePix + (yI * upWrap + xI)); } } dn->unlock(); up->unlock(); } //============================================================================= #ifdef OPTIMIZE_FOR_LP64 void quickResample_optimized(const TRasterP &dn, const TRasterP &up, const TAffine &aff, TRop::ResampleFilterType filterType) { assert(filterType == TRop::Bilinear || filterType == TRop::ClosestPixel); bool bilinear = filterType == TRop::Bilinear; TRaster32P dn32 = dn; TRaster32P up32 = up; TRasterGR8P dn8 = dn; TRasterGR8P up8 = up; if (dn32 && up32) if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) if (bilinear) doQuickResampleFilter_optimized(dn32, up32, aff.a11, aff.a22, aff.a13, aff.a23); else doQuickResampleNoFilter(dn32, up32, aff.a11, aff.a22, aff.a13, aff.a23); else if (bilinear) doQuickResampleFilter_optimized(dn32, up32, aff); else doQuickResampleNoFilter(dn32, up32, aff); else throw TRopException("raster type mismatch"); } #endif //============================================================================= void quickResample(const TRasterP &dn, const TRasterP &up, const TAffine &aff, TRop::ResampleFilterType filterType) { #ifdef OPTIMIZE_FOR_LP64 quickResample_optimized(dn, up, aff, filterType); #else assert(filterType == TRop::Bilinear || filterType == TRop::ClosestPixel); bool bilinear = filterType == TRop::Bilinear; TRaster32P dn32 = dn; TRaster32P up32 = up; TRasterCM32P dnCM32 = dn; TRasterCM32P upCM32 = up; TRasterGR8P dn8 = dn; TRasterGR8P up8 = up; dn->clear(); if (bilinear) { if (dn32 && up32) { if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickResampleFilter(dn32, up32, aff.a11, aff.a22, aff.a13, aff.a23); else doQuickResampleFilter(dn32, up32, aff); } else if (dn32 && up8) { if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickResampleFilter(dn32, up8, aff.a11, aff.a22, aff.a13, aff.a23); else doQuickResampleFilter(dn32, up8, aff); } else throw TRopException("raster type mismatch"); } else { if (dn32 && up32) { if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickResampleNoFilter(dn32, up32, aff.a11, aff.a22, aff.a13, aff.a23); else doQuickResampleNoFilter(dn32, up32, aff); } else if (dnCM32 && upCM32) { if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickResampleNoFilter(dnCM32, upCM32, aff.a11, aff.a22, aff.a13, aff.a23); else doQuickResampleNoFilter(dnCM32, upCM32, aff); } else if (dn8 && up8) { if (areAlmostEqual(aff.a12, 0) && areAlmostEqual(aff.a21, 0)) doQuickResampleNoFilter(dn8, up8, aff.a11, aff.a22, aff.a13, aff.a23); else doQuickResampleNoFilter(dn8, up8, aff); } else throw TRopException("raster type mismatch"); } #endif } void quickPut(const TRasterP &out, const TRasterCM32P &up, const TAffine &aff, const TPixel32 &inkCol, const TPixel32 &paintCol);