From d99aae5b645365332a1410f094f02b57f9b10cab Mon Sep 17 00:00:00 2001 From: Stefano Musumeci Date: Sun, 13 Jul 2014 18:49:27 +0200 Subject: [PATCH] TINYGL: Split blitting function in multiple routines to make code more readable. --- graphics/tinygl/zblit.cpp | 423 +++++++++++++++++++++----------------- 1 file changed, 237 insertions(+), 186 deletions(-) diff --git a/graphics/tinygl/zblit.cpp b/graphics/tinygl/zblit.cpp index 5fc642e1f34..b5c1b334761 100644 --- a/graphics/tinygl/zblit.cpp +++ b/graphics/tinygl/zblit.cpp @@ -6,6 +6,9 @@ namespace Graphics { + Common::Point transformPoint(float x, float y, int rotation); + Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY); + struct BlitImage { public: BlitImage() { } @@ -118,52 +121,19 @@ void tglDeleteBlitImage(BlitImage *blitImage) { } } -Common::Point transformPoint(float x, float y, int rotation) { - float rotateRad = rotation * M_PI / 180.0f; - Common::Point newPoint; - newPoint.x = x * cos(rotateRad) - y * sin(rotateRad); - newPoint.y = x * sin(rotateRad) + y * cos(rotateRad); - return newPoint; -} - -Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY) { - Common::Point nw, ne, sw, se; - nw = transformPoint(x - originX, y - originY, rotation); - ne = transformPoint(x + width - originX, y - originY, rotation); - sw = transformPoint(x + width - originX, y + height- originY, rotation); - se = transformPoint(x - originX, y + height - originY, rotation); - - float top = MIN(nw.y, MIN(ne.y, MIN(sw.y, se.y))); - float bottom = MAX(nw.y, MAX(ne.y, MAX(sw.y, se.y))); - float left = MIN(nw.x, MIN(ne.x, MIN(sw.x, se.x))); - float right = MAX(nw.x, MAX(ne.x, MAX(sw.x, se.x))); - - Common::Rect res; - res.top = (int32)(floor(top)) + originY; - res.bottom = (int32)(ceil(bottom)) + originY; - res.left = (int32)(floor(left)) + originX; - res.right = (int32)(ceil(right)) + originX; - - return res; -} - -template -void tglBlitGenericNoTransform(BlitImage *blitImage, int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) { - TinyGL::GLContext *c = TinyGL::gl_get_context(); - +FORCEINLINE bool clipBlitImage(BlitImage *blitImage, TinyGL::GLContext *c, int &srcWidth, int &srcHeight, int &width, int &height, int &dstX, int &dstY, int &clampWidth, int &clampHeight) { if (srcWidth == 0 || srcHeight == 0) { srcWidth = blitImage->_surface.w; srcHeight = blitImage->_surface.h; } - // Width and height are always 0 when you call this function. - int width = srcWidth; - int height = srcHeight; + if (width == 0 && height == 0) { + width = srcWidth; + height = srcHeight; + } if (dstX >= c->fb->xsize|| dstY >= c->fb->ysize) - return; - - int clampWidth, clampHeight; + return false; if (dstX + width > c->fb->xsize) clampWidth = c->fb->xsize - dstX; @@ -180,18 +150,24 @@ void tglBlitGenericNoTransform(BlitImage *blitImage, int dstX, int dstY, int src if (dstY < 0) dstY = 0; + return true; +} + +template +void tglBlitRLE(BlitImage *blitImage, int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + + int clampWidth, clampHeight; + int width = srcWidth, height = srcHeight; + if (clipBlitImage(blitImage, c, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false) + return; Graphics::PixelBuffer srcBuf(blitImage->_surface.format, (byte *)blitImage->_surface.getPixels()); - - if (flipVertical) { - srcBuf.shiftBy(srcX + ((srcY + srcHeight - 1) * blitImage->_surface.w)); - } else { - srcBuf.shiftBy(srcX + (srcY * blitImage->_surface.w)); - } + srcBuf.shiftBy(srcX + (srcY * blitImage->_surface.w)); Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer()); - if (disableColoring && disableBlending) { + if (disableColoring) { const int kBytesPerPixel = 2; int lineIndex = 0; int maxY = srcY + clampHeight; @@ -213,96 +189,195 @@ void tglBlitGenericNoTransform(BlitImage *blitImage, int dstX, int dstY, int src lineIndex++; } } else { - for (int l = 0; l < clampHeight; l++) { - for (int r = 0; r < clampWidth; ++r) { - byte aDst, rDst, gDst, bDst; - if (flipHorizontal) { - srcBuf.getARGBAt(clampWidth - r, aDst, rDst, gDst, bDst); - } else { - srcBuf.getARGBAt(r, aDst, rDst, gDst, bDst); - } - if (disableColoring) { - if (disableBlending && aDst != 0) { - dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); - } else { - c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); - } - } else { - if (disableBlending && aDst != 0) { - dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); - } else { - c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); - } + const int kBytesPerPixel = 2; + int lineIndex = 0; + int maxY = srcY + clampHeight; + int maxX = srcX + clampWidth; + while (lineIndex < blitImage->_lines.size() && blitImage->_lines[lineIndex]._y < srcY) { + lineIndex++; + } + while (lineIndex < blitImage->_lines.size() && blitImage->_lines[lineIndex]._y < maxY) { + const BlitImage::Line &l = blitImage->_lines[lineIndex]; + if (l._x < maxX && l._x + l._length > srcX) { + int length = l._length; + int skipStart = (l._x < srcX) ? (srcX - l._x) : 0; + length -= skipStart; + int skipEnd = (l._x + l._length > maxX) ? (l._x + l._length - maxX) : 0; + length -= skipEnd; + // Colorize those pixels. + int xStart = MAX(l._x - srcX, 0); + for(int x = xStart; x < xStart + length; x++) { + byte aDst, rDst, gDst, bDst; + srcBuf.getARGBAt((l._y - srcY) *c->fb->xsize + x, aDst, rDst, gDst, bDst); + c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); } } - if (flipVertical) { - srcBuf.shiftBy(-blitImage->_surface.w); - } else { - srcBuf.shiftBy(blitImage->_surface.w); - } + lineIndex++; } } } template -void tglBlitGenericTransform(BlitImage *blitImage, int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation, - int originX, int originY, float aTint, float rTint, float gTint, float bTint) { +void tglBlitSimple(BlitImage *blitImage, int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) { TinyGL::GLContext *c = TinyGL::gl_get_context(); - if (srcWidth == 0 || srcHeight == 0) { - srcWidth = blitImage->_surface.w; - srcHeight = blitImage->_surface.h; - } - - if (width == 0 && height == 0) { - width = srcWidth; - height = srcHeight; - } - - if (dstX >= c->fb->xsize|| dstY >= c->fb->ysize) + int clampWidth, clampHeight; + int width = srcWidth, height = srcHeight; + if (clipBlitImage(blitImage, c, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false) return; + Graphics::PixelBuffer srcBuf(blitImage->_surface.format, (byte *)blitImage->_surface.getPixels()); + + if (flipVertical) { + srcBuf.shiftBy(srcX + ((srcY + srcHeight - 1) * blitImage->_surface.w)); + } else { + srcBuf.shiftBy(srcX + (srcY * blitImage->_surface.w)); + } + + Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer()); + + for (int l = 0; l < clampHeight; l++) { + for (int r = 0; r < clampWidth; ++r) { + byte aDst, rDst, gDst, bDst; + if (flipHorizontal) { + srcBuf.getARGBAt(clampWidth - r, aDst, rDst, gDst, bDst); + } else { + srcBuf.getARGBAt(r, aDst, rDst, gDst, bDst); + } + if (disableColoring) { + if (disableBlending && aDst != 0) { + dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); + } else { + c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); + } + } else { + if (disableBlending && aDst != 0) { + dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); + } else { + c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); + } + } + } + if (flipVertical) { + srcBuf.shiftBy(-blitImage->_surface.w); + } else { + srcBuf.shiftBy(blitImage->_surface.w); + } + } +} + +template +void tglBlitScale(BlitImage *blitImage, int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation, + int originX, int originY, float aTint, float rTint, float gTint, float bTint) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + int clampWidth, clampHeight; - - if (dstX + width > c->fb->xsize) - clampWidth = c->fb->xsize - dstX; - else - clampWidth = width; - - if (dstY + height > c->fb->ysize) - clampHeight = c->fb->ysize - dstY; - else - clampHeight = height; - - if (dstX < 0) - dstX = 0; - if (dstY < 0) - dstY = 0; + if (clipBlitImage(blitImage, c, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false) + return; Graphics::PixelBuffer srcBuf(blitImage->_surface.format, (byte *)blitImage->_surface.getPixels()); srcBuf.shiftBy(srcX + (srcY * blitImage->_surface.w)); Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer()); - if (rotation == 0) { - for (int l = 0; l < clampHeight; l++) { - for (int r = 0; r < clampWidth; ++r) { - byte aDst, rDst, gDst, bDst; - int xSource, ySource; - if (flipVertical) { - ySource = clampHeight - l - 1; + for (int l = 0; l < clampHeight; l++) { + for (int r = 0; r < clampWidth; ++r) { + byte aDst, rDst, gDst, bDst; + int xSource, ySource; + if (flipVertical) { + ySource = clampHeight - l - 1; + } else { + ySource = l; + } + + if (flipHorizontal) { + xSource = clampWidth - r - 1; + } else { + xSource = r; + } + + srcBuf.getARGBAt(((ySource * srcHeight) / height) * blitImage->_surface.w + ((xSource * srcWidth) / width), aDst, rDst, gDst, bDst); + + if (disableColoring) { + if (disableBlending && aDst != 0) { + dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); } else { - ySource = l; + c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); } - - if (flipHorizontal) { - xSource = clampWidth - r - 1; + } else { + if (disableBlending && aDst != 0) { + dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); } else { - xSource = r; + c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); } + } + } + } +} - srcBuf.getARGBAt(((ySource * srcHeight) / height) * blitImage->_surface.w + ((xSource * srcWidth) / width), aDst, rDst, gDst, bDst); +template +void tglBlitRotoScale(BlitImage *blitImage, int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation, + int originX, int originY, float aTint, float rTint, float gTint, float bTint) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + int clampWidth, clampHeight; + if (clipBlitImage(blitImage, c, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false) + return; + + Graphics::PixelBuffer srcBuf(blitImage->_surface.format, (byte *)blitImage->_surface.getPixels()); + srcBuf.shiftBy(srcX + (srcY * blitImage->_surface.w)); + + Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer()); + + // Transform destination rectangle accordingly. + Common::Rect destinationRectangle = rotateRectangle(dstX, dstY, width, height, rotation, originX, originY); + + if (dstX + destinationRectangle.width() > c->fb->xsize) + clampWidth = c->fb->xsize - dstX; + else + clampWidth = destinationRectangle.width(); + + if (dstY + destinationRectangle.height() > c->fb->ysize) + clampHeight = c->fb->ysize - dstY; + else + clampHeight = destinationRectangle.height(); + + uint32 invAngle = 360 - (rotation % 360); + float invCos = cos(invAngle * M_PI / 180.0f); + float invSin = sin(invAngle * M_PI / 180.0f ); + + int icosx = (int)(invCos * (65536.0f * srcWidth / width)); + int isinx = (int)(invSin * (65536.0f * srcWidth / width)); + int icosy = (int)(invCos * (65536.0f * srcHeight / height)); + int isiny = (int)(invSin * (65536.0f * srcHeight / height)); + + int xd = (srcX + originX) << 16; + int yd = (srcY + originY) << 16; + int cx = originX; + int cy = originY; + + int ax = -icosx * cx; + int ay = -isiny * cx; + int sw = width - 1; + int sh = height - 1; + + for (int l = 0; l < clampHeight; l++) { + int t = cy - l; + int sdx = ax + (isinx * t) + xd; + int sdy = ay - (icosy * t) + yd; + for (int r = 0; r < clampWidth; ++r) { + byte aDst, rDst, gDst, bDst; + + int dx = (sdx >> 16); + int dy = (sdy >> 16); + + if (flipHorizontal) + dx = sw - dx; + if (flipVertical) + dy = sh - dy; + + if ((dx >= 0) && (dy >= 0) && (dx < srcWidth) && (dy < srcHeight)) { + srcBuf.getARGBAt(dy * blitImage->_surface.w + dx, aDst, rDst, gDst, bDst); if (disableColoring) { if (disableBlending && aDst != 0) { dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); @@ -317,74 +392,8 @@ void tglBlitGenericTransform(BlitImage *blitImage, int dstX, int dstY, int width } } } - } - } else { - // Transform destination rectangle accordingly. - Common::Rect destinationRectangle = rotateRectangle(dstX, dstY, width, height, rotation, originX, originY); - - if (dstX + destinationRectangle.width() > c->fb->xsize) - clampWidth = c->fb->xsize - dstX; - else - clampWidth = destinationRectangle.width(); - - if (dstY + destinationRectangle.height() > c->fb->ysize) - clampHeight = c->fb->ysize - dstY; - else - clampHeight = destinationRectangle.height(); - - uint32 invAngle = 360 - (rotation % 360); - float invCos = cos(invAngle * M_PI / 180.0f); - float invSin = sin(invAngle * M_PI / 180.0f ); - - int icosx = (int)(invCos * (65536.0f * srcWidth / width)); - int isinx = (int)(invSin * (65536.0f * srcWidth / width)); - int icosy = (int)(invCos * (65536.0f * srcHeight / height)); - int isiny = (int)(invSin * (65536.0f * srcHeight / height)); - - int xd = (srcX + originX) << 16; - int yd = (srcY + originY) << 16; - int cx = originX; - int cy = originY; - - int ax = -icosx * cx; - int ay = -isiny * cx; - int sw = width - 1; - int sh = height - 1; - - for (int l = 0; l < clampHeight; l++) { - int t = cy - l; - int sdx = ax + (isinx * t) + xd; - int sdy = ay - (icosy * t) + yd; - for (int r = 0; r < clampWidth; ++r) { - byte aDst, rDst, gDst, bDst; - - int dx = (sdx >> 16); - int dy = (sdy >> 16); - - if (flipHorizontal) - dx = sw - dx; - if (flipVertical) - dy = sh - dy; - - if ((dx >= 0) && (dy >= 0) && (dx < srcWidth) && (dy < srcHeight)) { - srcBuf.getARGBAt(dy * blitImage->_surface.w + dx, aDst, rDst, gDst, bDst); - if (disableColoring) { - if (disableBlending && aDst != 0) { - dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); - } else { - c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst, rDst, gDst, bDst); - } - } else { - if (disableBlending && aDst != 0) { - dstBuf.setPixelAt((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); - } else { - c->fb->writePixel((dstX + r) + (dstY + l) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint); - } - } - } - sdx += icosx; - sdy += isiny; - } + sdx += icosx; + sdy += isiny; } } } @@ -393,13 +402,26 @@ void tglBlitGenericTransform(BlitImage *blitImage, int dstX, int dstY, int width template FORCEINLINE void tglBlitGeneric(BlitImage *blitImage, const BlitTransform &transform) { if (disableTransform) { - tglBlitGenericNoTransform(blitImage, transform._destinationRectangle.left, transform._destinationRectangle.top, - transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width() , transform._sourceRectangle.height(), - transform._aTint, transform._rTint, transform._gTint, transform._bTint); + if (disableBlending && flipVertical == false && flipHorizontal == false) { + tglBlitRLE(blitImage, transform._destinationRectangle.left, transform._destinationRectangle.top, + transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width() , transform._sourceRectangle.height(), + transform._aTint, transform._rTint, transform._gTint, transform._bTint); + } else { + tglBlitSimple(blitImage, transform._destinationRectangle.left, transform._destinationRectangle.top, + transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width() , transform._sourceRectangle.height(), + transform._aTint, transform._rTint, transform._gTint, transform._bTint); + } } else { - tglBlitGenericTransform(blitImage, transform._destinationRectangle.left, transform._destinationRectangle.top, - transform._destinationRectangle.width(), transform._destinationRectangle.height(), transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width() , transform._sourceRectangle.height(), transform._rotation, - transform._originX, transform._originY, transform._aTint, transform._rTint, transform._gTint, transform._bTint); + if (transform._rotation == 0) { + tglBlitScale(blitImage, transform._destinationRectangle.left, transform._destinationRectangle.top, + transform._destinationRectangle.width(), transform._destinationRectangle.height(), transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width() , transform._sourceRectangle.height(), transform._rotation, + transform._originX, transform._originY, transform._aTint, transform._rTint, transform._gTint, transform._bTint); + } else + { + tglBlitRotoScale(blitImage, transform._destinationRectangle.left, transform._destinationRectangle.top, + transform._destinationRectangle.width(), transform._destinationRectangle.height(), transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width() , transform._sourceRectangle.height(), transform._rotation, + transform._originX, transform._originY, transform._aTint, transform._rTint, transform._gTint, transform._bTint); + } } } @@ -456,4 +478,33 @@ void tglBlitFast(BlitImage *blitImage, int x, int y) { tglBlitGeneric(blitImage, transform); } +Common::Point transformPoint(float x, float y, int rotation) { + float rotateRad = rotation * M_PI / 180.0f; + Common::Point newPoint; + newPoint.x = x * cos(rotateRad) - y * sin(rotateRad); + newPoint.y = x * sin(rotateRad) + y * cos(rotateRad); + return newPoint; +} + +Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY) { + Common::Point nw, ne, sw, se; + nw = transformPoint(x - originX, y - originY, rotation); + ne = transformPoint(x + width - originX, y - originY, rotation); + sw = transformPoint(x + width - originX, y + height- originY, rotation); + se = transformPoint(x - originX, y + height - originY, rotation); + + float top = MIN(nw.y, MIN(ne.y, MIN(sw.y, se.y))); + float bottom = MAX(nw.y, MAX(ne.y, MAX(sw.y, se.y))); + float left = MIN(nw.x, MIN(ne.x, MIN(sw.x, se.x))); + float right = MAX(nw.x, MAX(ne.x, MAX(sw.x, se.x))); + + Common::Rect res; + res.top = (int32)(floor(top)) + originY; + res.bottom = (int32)(ceil(bottom)) + originY; + res.left = (int32)(floor(left)) + originX; + res.right = (int32)(ceil(right)) + originX; + + return res; +} + }