ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

zblit.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
00025  * which is licensed under the zlib-license (see LICENSE).
00026  * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
00027  */
00028 
00029 #include "graphics/tinygl/zblit.h"
00030 #include "graphics/tinygl/zgl.h"
00031 #include "graphics/pixelbuffer.h"
00032 #include "common/array.h"
00033 #include "graphics/tinygl/zdirtyrect.h"
00034 #include "graphics/tinygl/gl.h"
00035 #include <math.h>
00036 
00037 namespace Graphics {
00038 
00039 Common::Point transformPoint(float x, float y, int rotation);
00040 Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY);
00041 
00042 struct BlitImage {
00043 public:
00044     BlitImage() : _isDisposed(false), _version(0), _binaryTransparent(false), _refcount(1) { }
00045 
00046     void loadData(const Graphics::Surface &surface, uint32 colorKey, bool applyColorKey) {
00047         const Graphics::PixelFormat textureFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
00048         int size = surface.w * surface.h;
00049         _surface.create(surface.w, surface.h, textureFormat);
00050         Graphics::PixelBuffer buffer(surface.format, (byte *)const_cast<void *>(surface.getPixels()));
00051         Graphics::PixelBuffer dataBuffer(textureFormat, (byte *)const_cast<void *>(_surface.getPixels()));
00052         dataBuffer.copyBuffer(0, 0, size, buffer);
00053         if (applyColorKey) {
00054             for (int x = 0; x < size; x++) {
00055                 if (buffer.getValueAt(x) == colorKey) {
00056                     // Color keyed pixels become transparent white.
00057                     dataBuffer.setPixelAt(x, 0, 255, 255, 255);
00058                 }
00059             }
00060         }
00061 
00062         // Create opaque lines data.
00063         // A line of pixels can not wrap more that one line of the image, since it would break
00064         // blitting of bitmaps with a non-zero x position.
00065         Graphics::PixelBuffer srcBuf = dataBuffer;
00066         _lines.clear();
00067         _binaryTransparent = true;
00068         for (int y = 0; y < surface.h; y++) {
00069             int start = -1;
00070             for (int x = 0; x < surface.w; ++x) {
00071                 // We found a transparent pixel, so save a line from 'start' to the pixel before this.
00072                 uint8 r, g, b, a;
00073                 srcBuf.getARGBAt(x, a, r, g, b);
00074                 if (a != 0 && a != 0xFF) {
00075                     _binaryTransparent = false;
00076                 }
00077                 if (a == 0 && start >= 0) {
00078                     _lines.push_back(Line(start, y, x - start, srcBuf.getRawBuffer(start), textureFormat));
00079                     start = -1;
00080                 } else if (a != 0 && start == -1) {
00081                     start = x;
00082                 }
00083             }
00084             // end of the bitmap line. if start is an actual pixel save the line.
00085             if (start >= 0) {
00086                 _lines.push_back(Line(start, y, surface.w - start, srcBuf.getRawBuffer(start), textureFormat));
00087             }
00088             srcBuf.shiftBy(surface.w);
00089         }
00090 
00091         _version++;
00092     }
00093 
00094     int getVersion() const {
00095         return _version;
00096     }
00097 
00098     ~BlitImage() {
00099         _surface.free();
00100     }
00101 
00102     struct Line {
00103         int _x;
00104         int _y;
00105         int _length;
00106         byte *_pixels;
00107         Graphics::PixelBuffer _buf; // This is needed for the conversion.
00108 
00109         Line() : _x(0), _y(0), _length(0), _pixels(nullptr) { }
00110         Line(int x, int y, int length, byte *pixels, const Graphics::PixelFormat &textureFormat) : _buf(TinyGL::gl_get_context()->fb->cmode, length, DisposeAfterUse::NO),
00111                     _x(x), _y(y), _length(length) {
00112             // Performing texture to screen conversion.
00113             Graphics::PixelBuffer srcBuf(textureFormat, pixels);
00114             _buf.copyBuffer(0, 0, length, srcBuf);
00115             _pixels = _buf.getRawBuffer();
00116         }
00117 
00118         Line(const Line& other) : _buf(other._buf.getFormat(), other._length, DisposeAfterUse::NO),
00119                     _x(other._x), _y(other._y), _length(other._length){
00120             _buf.copyBuffer(0, 0, _length, other._buf);
00121             _pixels = _buf.getRawBuffer();
00122         }
00123 
00124         ~Line() {
00125             _buf.free();
00126         }
00127     };
00128 
00129     FORCEINLINE bool clipBlitImage(TinyGL::GLContext *c, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &width, int &height, int &dstX, int &dstY, int &clampWidth, int &clampHeight) {
00130         if (srcWidth == 0 || srcHeight == 0) {
00131             srcWidth = _surface.w;
00132             srcHeight = _surface.h;
00133         }
00134 
00135         if (width == 0 && height == 0) {
00136             width = srcWidth;
00137             height = srcHeight;
00138         }
00139 
00140         if (dstX >= c->_scissorRect.right || dstY >= c->_scissorRect.bottom)
00141             return false;
00142 
00143         if (dstX + width < c->_scissorRect.left || dstY + height < c->_scissorRect.top) {
00144             return false;
00145         }
00146 
00147         if (dstX < c->_scissorRect.left) {
00148             srcX += (c->_scissorRect.left - dstX);
00149             width -= (c->_scissorRect.left - dstX);
00150             dstX = c->_scissorRect.left;
00151         }
00152         
00153         if (dstY < c->_scissorRect.top) {
00154             srcY += (c->_scissorRect.top - dstY);
00155             height -= (c->_scissorRect.top - dstY);
00156             dstY = c->_scissorRect.top;
00157         }
00158 
00159         if (width < 0 || height < 0) {
00160             return false;
00161         }
00162 
00163         if (dstX + width >= c->_scissorRect.right) {
00164             clampWidth = c->_scissorRect.right - dstX;
00165         } else {
00166             clampWidth = width;
00167         }
00168 
00169         if (dstY + height >= c->_scissorRect.bottom) {
00170             clampHeight = c->_scissorRect.bottom - dstY;
00171         } else {
00172             clampHeight = height;
00173         }
00174 
00175         return true;
00176     }
00177 
00178     // Blits an image to the z buffer.
00179     // The function only supports clipped blitting without any type of transformation or tinting.
00180     void tglBlitZBuffer(int dstX, int dstY) {
00181         TinyGL::GLContext *c = TinyGL::gl_get_context();
00182 
00183         int clampWidth, clampHeight;
00184         int width = _surface.w, height = _surface.h;
00185         int srcWidth = 0, srcHeight = 0;
00186         int srcX = 0, srcY = 0;
00187         if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
00188             return;
00189 
00190         Graphics::PixelBuffer srcBuf(_surface.format, (byte *)const_cast<void *>(_surface.getPixels())); // Blit image buffer
00191         Graphics::PixelBuffer dstBuf(_surface.format, (byte *)c->fb->getZBuffer()); // TinyGL z buffer
00192 
00193         srcBuf.shiftBy(srcY * _surface.w);
00194 
00195         dstBuf.shiftBy(dstY * c->fb->xsize);
00196         for (int y = 0; y < clampHeight; y++) {
00197             dstBuf.copyBuffer(dstX, srcX, clampWidth, srcBuf);
00198             dstBuf.shiftBy(c->fb->xsize);
00199             srcBuf.shiftBy(_surface.w);
00200         }
00201     }
00202 
00203     template <bool kDisableColoring, bool kDisableBlending, bool kEnableAlphaBlending>
00204     FORCEINLINE void tglBlitRLE(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint);
00205 
00206     template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
00207     FORCEINLINE void tglBlitSimple(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint);
00208 
00209     template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
00210     FORCEINLINE void tglBlitScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint);
00211 
00212     template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
00213     FORCEINLINE void tglBlitRotoScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation,
00214         int originX, int originY, float aTint, float rTint, float gTint, float bTint);
00215 
00216     //Utility function that calls the correct blitting function.
00217     template <bool kDisableBlending, bool kDisableColoring, bool kDisableTransform, bool kFlipVertical, bool kFlipHorizontal, bool kEnableAlphaBlending>
00218     FORCEINLINE void tglBlitGeneric(const BlitTransform &transform) {
00219         if (kDisableTransform) {
00220             if ((kDisableBlending || kEnableAlphaBlending) && kFlipVertical == false && kFlipHorizontal == false) {
00221                 tglBlitRLE<kDisableColoring, kDisableBlending, kEnableAlphaBlending>(transform._destinationRectangle.left,
00222                     transform._destinationRectangle.top, transform._sourceRectangle.left, transform._sourceRectangle.top, 
00223                     transform._sourceRectangle.width() , transform._sourceRectangle.height(), transform._aTint,
00224                     transform._rTint, transform._gTint, transform._bTint);
00225             } else {
00226                 tglBlitSimple<kDisableBlending, kDisableColoring, kFlipVertical, kFlipHorizontal>(transform._destinationRectangle.left, 
00227                     transform._destinationRectangle.top, transform._sourceRectangle.left, transform._sourceRectangle.top, 
00228                     transform._sourceRectangle.width() , transform._sourceRectangle.height(),
00229                     transform._aTint, transform._rTint, transform._gTint, transform._bTint);
00230             }
00231         } else {
00232             if (transform._rotation == 0) {
00233                 tglBlitScale<kDisableBlending, kDisableColoring, kFlipVertical, kFlipHorizontal>(transform._destinationRectangle.left,
00234                     transform._destinationRectangle.top, transform._destinationRectangle.width(), transform._destinationRectangle.height(),
00235                     transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width(), transform._sourceRectangle.height(),
00236                     transform._aTint, transform._rTint, transform._gTint, transform._bTint);
00237             } else {
00238                 tglBlitRotoScale<kDisableBlending, kDisableColoring, kFlipVertical, kFlipHorizontal>(transform._destinationRectangle.left,
00239                     transform._destinationRectangle.top, transform._destinationRectangle.width(), transform._destinationRectangle.height(),
00240                     transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width(),
00241                     transform._sourceRectangle.height(), transform._rotation, transform._originX, transform._originY, transform._aTint,
00242                     transform._rTint, transform._gTint, transform._bTint);
00243             }
00244         }
00245     }
00246 
00247     int getWidth() const { return _surface.w; }
00248     int getHeight() const { return _surface.h; }
00249     void incRefCount() { _refcount++; }
00250     void dispose() { if (--_refcount == 0) _isDisposed = true; }
00251     bool isDisposed() const { return _isDisposed; }
00252 private:
00253     bool _isDisposed;
00254     bool _binaryTransparent;
00255     Common::Array<Line> _lines;
00256     Graphics::Surface _surface;
00257     int _version;
00258     int _refcount;
00259 };
00260 
00261 void tglGetBlitImageSize(BlitImage *blitImage, int &width, int &height) {
00262     width = blitImage->getWidth();
00263     height = blitImage->getHeight();
00264 }
00265 
00266 void tglIncBlitImageRef(BlitImage *blitImage) {
00267     blitImage->incRefCount();
00268 }
00269 
00270 int tglGetBlitImageVersion(BlitImage *blitImage) {
00271     return blitImage->getVersion();
00272 }
00273 
00274 BlitImage *tglGenBlitImage() {
00275     TinyGL::GLContext *c = TinyGL::gl_get_context();
00276     BlitImage *image = new BlitImage();
00277     c->_blitImages.push_back(image);
00278     return image;
00279 }
00280 
00281 void tglUploadBlitImage(BlitImage *blitImage, const Graphics::Surface& surface, uint32 colorKey, bool applyColorKey) {
00282     if (blitImage != nullptr) {
00283         blitImage->loadData(surface, colorKey, applyColorKey);
00284     }
00285 }
00286 
00287 void tglDeleteBlitImage(BlitImage *blitImage) {
00288     if (blitImage != nullptr) {
00289         blitImage->dispose();
00290     }
00291 }
00292 
00293 // This function uses RLE encoding to skip transparent bitmap parts
00294 // This blit only supports tinting but it will fall back to simpleBlit
00295 // if flipping is required (or anything more complex than that, including rotationd and scaling).
00296 template <bool kDisableColoring, bool kDisableBlending, bool kEnableAlphaBlending>
00297 FORCEINLINE void BlitImage::tglBlitRLE(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) {
00298     TinyGL::GLContext *c = TinyGL::gl_get_context();
00299 
00300     int clampWidth, clampHeight;
00301     int width = srcWidth, height = srcHeight;
00302     if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
00303         return;
00304 
00305     if (aTint <= 0.0f)
00306         return;
00307 
00308     Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
00309     srcBuf.shiftBy(srcX + (srcY * _surface.w));
00310 
00311     Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer());
00312     dstBuf.shiftBy(dstY * c->fb->xsize + dstX);
00313 
00314     int kBytesPerPixel = c->fb->cmode.bytesPerPixel;
00315 
00316     uint32 lineIndex = 0;
00317     int maxY = srcY + clampHeight;
00318     int maxX = srcX + clampWidth;
00319     while (lineIndex < _lines.size() && _lines[lineIndex]._y < srcY) {
00320         lineIndex++;
00321     }
00322 
00323     if (_binaryTransparent || (kDisableBlending || !kEnableAlphaBlending)) { // If bitmap is binary transparent or if  we need complex forms of blending (not just alpha) we need to use writePixel, which is slower 
00324         while (lineIndex < _lines.size() && _lines[lineIndex]._y < maxY) {
00325             const BlitImage::Line &l = _lines[lineIndex];
00326             if (l._x < maxX && l._x + l._length > srcX) {
00327                 int length = l._length;
00328                 int skipStart = (l._x < srcX) ? (srcX - l._x) : 0;
00329                 length -= skipStart;
00330                 int skipEnd   = (l._x + l._length > maxX) ? (l._x + l._length - maxX) : 0;
00331                 length -= skipEnd;
00332                 if (kDisableColoring && (kEnableAlphaBlending == false || kDisableBlending)) {
00333                     memcpy(dstBuf.getRawBuffer((l._y - srcY) * c->fb->xsize + MAX(l._x - srcX, 0)),
00334                         l._pixels + skipStart * kBytesPerPixel, length * kBytesPerPixel);
00335                 } else {
00336                     int xStart = MAX(l._x - srcX, 0);
00337                     if (kDisableColoring) {
00338                         dstBuf.copyBuffer(xStart + (l._y - srcY) * c->fb->xsize, skipStart, length, l._buf);
00339                     } else {
00340                         for(int x = xStart; x < xStart + length; x++) {
00341                             byte aDst, rDst, gDst, bDst;
00342                             srcBuf.getARGBAt((l._y - srcY) * _surface.w + x, aDst, rDst, gDst, bDst);
00343                             c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00344                         }
00345                     }
00346 
00347                 }
00348             }
00349             lineIndex++;
00350         }
00351     } else { // Otherwise can use setPixel in some cases which speeds up things quite a bit
00352         while (lineIndex < _lines.size() && _lines[lineIndex]._y < maxY) {
00353             const BlitImage::Line &l = _lines[lineIndex];
00354             if (l._x < maxX && l._x + l._length > srcX) {
00355                 int length = l._length;
00356                 int skipStart = (l._x < srcX) ? (srcX - l._x) : 0;
00357                 length -= skipStart;
00358                 int skipEnd   = (l._x + l._length > maxX) ? (l._x + l._length - maxX) : 0;
00359                 length -= skipEnd;
00360                 if (kDisableColoring && (kEnableAlphaBlending == false || kDisableBlending)) {
00361                     memcpy(dstBuf.getRawBuffer((l._y - srcY) * c->fb->xsize + MAX(l._x - srcX, 0)),
00362                         l._pixels + skipStart * kBytesPerPixel, length * kBytesPerPixel);
00363                 } else {
00364                     int xStart = MAX(l._x - srcX, 0);
00365                     for(int x = xStart; x < xStart + length; x++) {
00366                         byte aDst, rDst, gDst, bDst;
00367                         srcBuf.getARGBAt((l._y - srcY) * _surface.w + x, aDst, rDst, gDst, bDst);
00368                         if (kDisableColoring) {
00369                             if (aDst != 0xFF) {
00370                                 c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * c->fb->xsize, aDst, rDst, gDst, bDst);
00371                             } else {
00372                                 dstBuf.setPixelAt(x + (l._y - srcY) * c->fb->xsize, aDst, rDst, gDst, bDst);
00373                             }
00374                         } else {
00375                             c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00376                         }
00377                     }
00378                 }
00379             }
00380             lineIndex++;
00381         }
00382     }
00383 }
00384 
00385 // This blit function is called when flipping is needed but transformation isn't.
00386 template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
00387 FORCEINLINE void BlitImage::tglBlitSimple(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) {
00388     TinyGL::GLContext *c = TinyGL::gl_get_context();
00389 
00390     int clampWidth, clampHeight;
00391     int width = srcWidth, height = srcHeight;
00392     if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
00393         return;
00394 
00395     Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
00396 
00397     if (kFlipVertical) {
00398         srcBuf.shiftBy(((srcHeight - srcY - 1) * _surface.w));
00399     } else {
00400         srcBuf.shiftBy((srcY * _surface.w));
00401     }
00402 
00403     Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer());
00404 
00405     for (int y = 0; y < clampHeight; y++) {
00406         for (int x = 0; x < clampWidth; ++x) {
00407             byte aDst, rDst, gDst, bDst;
00408             if (kFlipHorizontal) {
00409                 srcBuf.getARGBAt(srcX + clampWidth - x, aDst, rDst, gDst, bDst);
00410             } else {
00411                 srcBuf.getARGBAt(srcX + x, aDst, rDst, gDst, bDst);
00412             }
00413 
00414             // Those branches are needed to favor speed: avoiding writePixel always yield a huge performance boost when blitting images.
00415             if (kDisableColoring) { 
00416                 if (kDisableBlending && aDst != 0) {
00417                     dstBuf.setPixelAt((dstX + x) + (dstY + y) * c->fb->xsize, aDst, rDst, gDst, bDst);
00418                 } else {
00419                     c->fb->writePixel((dstX + x) + (dstY + y) * c->fb->xsize, aDst, rDst, gDst, bDst);
00420                 }
00421             } else {
00422                 if (kDisableBlending && aDst * aTint != 0) {
00423                     dstBuf.setPixelAt((dstX + x) + (dstY + y) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00424                 } else {
00425                     c->fb->writePixel((dstX + x) + (dstY + y) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00426                 }
00427             }
00428         }
00429         if (kFlipVertical) {
00430             srcBuf.shiftBy(-_surface.w);
00431         } else {
00432             srcBuf.shiftBy(_surface.w);
00433         }
00434     }
00435 }
00436 
00437 // This function is called when scale is needed: it uses a simple nearest
00438 // filter to scale the blit image before copying it to the screen.
00439 template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
00440 FORCEINLINE void BlitImage::tglBlitScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight,
00441                      float aTint, float rTint, float gTint, float bTint) {
00442     TinyGL::GLContext *c = TinyGL::gl_get_context();
00443 
00444     int clampWidth, clampHeight;
00445     if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
00446         return;
00447 
00448     Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
00449     srcBuf.shiftBy(srcX + (srcY * _surface.w));
00450 
00451     Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer());
00452 
00453     for (int y = 0; y < clampHeight; y++) {
00454         for (int x = 0; x < clampWidth; ++x) {
00455             byte aDst, rDst, gDst, bDst;
00456             int xSource, ySource;
00457             if (kFlipVertical) {
00458                 ySource = clampHeight - y - 1;
00459             } else {
00460                 ySource = y;
00461             }
00462 
00463             if (kFlipHorizontal) {
00464                 xSource = clampWidth - x - 1;
00465             } else {
00466                 xSource = x;
00467             }
00468 
00469             srcBuf.getARGBAt(((ySource * srcHeight) / height) * _surface.w + ((xSource * srcWidth) / width), aDst, rDst, gDst, bDst);
00470 
00471             if (kDisableColoring) {
00472                 if (kDisableBlending && aDst != 0) {
00473                     dstBuf.setPixelAt((dstX + x) + (dstY + y) * c->fb->xsize, aDst, rDst, gDst, bDst);
00474                 } else {
00475                     c->fb->writePixel((dstX + x) + (dstY + y) * c->fb->xsize, aDst, rDst, gDst, bDst);
00476                 }
00477             } else {
00478                 if (kDisableBlending && aDst * aTint != 0) {
00479                     dstBuf.setPixelAt((dstX + x) + (dstY + y) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00480                 } else {
00481                     c->fb->writePixel((dstX + x) + (dstY + y) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00482                 }
00483             }
00484         }
00485     }
00486 }
00487 
00488 /*
00489 
00490 The below two functions are adapted from SDL_rotozoom.c,
00491 taken from SDL_gfx-2.0.18.
00492 
00493 Its copyright notice:
00494 
00495 =============================================================================
00496 SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
00497 
00498 Copyright (C) 2001-2012  Andreas Schiffler
00499 
00500 This software is provided 'as-is', without any express or implied
00501 warranty. In no event will the authors be held liable for any damages
00502 arising from the use of this software.
00503 
00504 Permission is granted to anyone to use this software for any purpose,
00505 including commercial applications, and to alter it and redistribute it
00506 freely, subject to the following restrictions:
00507 
00508 1. The origin of this software must not be misrepresented; you must not
00509 claim that you wrote the original software. If you use this software
00510 in a product, an acknowledgment in the product documentation would be
00511 appreciated but is not required.
00512 
00513 2. Altered source versions must be plainly marked as such, and must not be
00514 misrepresented as being the original software.
00515 
00516 3. This notice may not be removed or altered from any source
00517 distribution.
00518 
00519 Andreas Schiffler -- aschiffler at ferzkopp dot net
00520 =============================================================================
00521 
00522 
00523 The functions have been adapted for different structures and coordinate
00524 systems.
00525 
00526 */
00527 
00528 template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
00529 FORCEINLINE void BlitImage::tglBlitRotoScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation,
00530                              int originX, int originY, float aTint, float rTint, float gTint, float bTint) {
00531     TinyGL::GLContext *c = TinyGL::gl_get_context();
00532     
00533     int clampWidth, clampHeight;
00534     if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
00535         return;
00536     
00537     Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
00538     srcBuf.shiftBy(srcX + (srcY * _surface.w));
00539     
00540     Graphics::PixelBuffer dstBuf(c->fb->cmode, c->fb->getPixelBuffer());
00541     
00542     // Transform destination rectangle accordingly.
00543     Common::Rect destinationRectangle = rotateRectangle(dstX, dstY, width, height, rotation, originX, originY);
00544     
00545     if (dstX + destinationRectangle.width() > c->fb->xsize)
00546         clampWidth = c->fb->xsize - dstX;
00547     else
00548         clampWidth = destinationRectangle.width();
00549     if (dstY + destinationRectangle.height() > c->fb->ysize)
00550         clampHeight = c->fb->ysize - dstY;
00551     else
00552         clampHeight = destinationRectangle.height();
00553     
00554     uint32 invAngle = 360 - (rotation % 360);
00555     float invCos = cos(invAngle * M_PI / 180.0f);
00556     float invSin = sin(invAngle * M_PI / 180.0f);
00557     
00558     int icosx = (int)(invCos * (65536.0f * srcWidth / width));
00559     int isinx = (int)(invSin * (65536.0f * srcWidth / width));
00560     int icosy = (int)(invCos * (65536.0f * srcHeight / height));
00561     int isiny = (int)(invSin * (65536.0f * srcHeight / height));
00562     
00563     int xd = (srcX + originX) << 16;
00564     int yd = (srcY + originY) << 16;
00565     int cx = originX * ((float)width / srcWidth);
00566     int cy = originY * ((float)height / srcHeight);
00567     
00568     int ax = -icosx * cx;
00569     int ay = -isiny * cx;
00570     int sw = width - 1;
00571     int sh = height - 1;
00572     
00573     for (int y = 0; y < clampHeight; y++) {
00574         int t = cy - y;
00575         int sdx = ax + (isinx * t) + xd;
00576         int sdy = ay - (icosy * t) + yd;
00577         for (int x = 0; x < clampWidth; ++x) {
00578             byte aDst, rDst, gDst, bDst;
00579             
00580             int dx = (sdx >> 16);
00581             int dy = (sdy >> 16);
00582             
00583             if (kFlipHorizontal) {
00584                 dx = sw - dx;
00585             }
00586 
00587             if (kFlipVertical) {
00588                 dy = sh - dy;
00589             }
00590             
00591             if ((dx >= 0) && (dy >= 0) && (dx < srcWidth) && (dy < srcHeight)) {
00592                 srcBuf.getARGBAt(dy * _surface.w + dx, aDst, rDst, gDst, bDst);
00593                 if (kDisableColoring) {
00594                     if (kDisableBlending && aDst != 0) {
00595                         dstBuf.setPixelAt((dstX + x) + (dstY + y) * c->fb->xsize, aDst, rDst, gDst, bDst);
00596                     } else {
00597                         c->fb->writePixel((dstX + x) + (dstY + y) * c->fb->xsize, aDst, rDst, gDst, bDst);
00598                     }
00599                 } else {
00600                     if (kDisableBlending && aDst * aTint != 0) {
00601                         dstBuf.setPixelAt((dstX + x) + (dstY + y) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00602                     } else {
00603                         c->fb->writePixel((dstX + x) + (dstY + y) * c->fb->xsize, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
00604                     }
00605                 }
00606             }
00607             sdx += icosx;
00608             sdy += isiny;
00609         }
00610     }
00611 }
00612 
00613 void tglBlit(BlitImage *blitImage, int x, int y) {
00614     BlitTransform transform(x, y);
00615     TinyGL::tglIssueDrawCall(new BlittingDrawCall(blitImage, transform, BlittingDrawCall::BlitMode_Regular));
00616 }
00617 
00618 void tglBlit(BlitImage *blitImage, const BlitTransform &transform) {
00619     TinyGL::tglIssueDrawCall(new BlittingDrawCall(blitImage, transform, BlittingDrawCall::BlitMode_Regular));
00620 }
00621 
00622 void tglBlitNoBlend(BlitImage *blitImage, const BlitTransform &transform) {
00623     TinyGL::tglIssueDrawCall(new BlittingDrawCall(blitImage, transform, BlittingDrawCall::BlitMode_NoBlend));
00624 }
00625 
00626 void tglBlitFast(BlitImage *blitImage, int x, int y) {
00627     BlitTransform transform(x, y);
00628     TinyGL::tglIssueDrawCall(new BlittingDrawCall(blitImage, transform, BlittingDrawCall::BlitMode_Fast));
00629 }
00630 
00631 void tglBlitZBuffer(BlitImage *blitImage, int x, int y) {
00632     BlitTransform transform(x, y);
00633     TinyGL::tglIssueDrawCall(new BlittingDrawCall(blitImage, transform, BlittingDrawCall::BlitMode_ZBuffer));
00634 }
00635 
00636 
00637 namespace Internal {
00638 
00639 template <bool kEnableAlphaBlending, bool kDisableColor, bool kDisableTransform, bool kDisableBlend>
00640 void tglBlit(BlitImage *blitImage, const BlitTransform &transform) {
00641     if (transform._flipHorizontally) {
00642         if (transform._flipVertically) {
00643             blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, true, true, kEnableAlphaBlending>(transform);
00644         } else {
00645             blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, false, true, kEnableAlphaBlending>(transform);
00646         }
00647     } else if (transform._flipVertically) {
00648         blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, true, false, kEnableAlphaBlending>(transform);
00649     } else {
00650         blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, false, false, kEnableAlphaBlending>(transform);
00651     }
00652 }
00653 
00654 template <bool kEnableAlphaBlending, bool kDisableColor, bool kDisableTransform>
00655 void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool disableBlend) {
00656     if (disableBlend) {
00657         tglBlit<kEnableAlphaBlending, kDisableColor, kDisableTransform, true>(blitImage, transform);
00658     } else {
00659         tglBlit<kEnableAlphaBlending, kDisableColor, kDisableTransform, false>(blitImage, transform);
00660     }
00661 }
00662 
00663 template <bool kEnableAlphaBlending, bool kDisableColor>
00664 void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool disableTransform, bool disableBlend) {
00665     if (disableTransform) {
00666         tglBlit<kEnableAlphaBlending, kDisableColor, true>(blitImage, transform, disableBlend);
00667     } else {
00668         tglBlit<kEnableAlphaBlending, kDisableColor, false>(blitImage, transform, disableBlend);
00669     }
00670 }
00671 
00672 template <bool kEnableAlphaBlending>
00673 void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool disableColor, bool disableTransform, bool disableBlend) {
00674     if (disableColor) {
00675         tglBlit<kEnableAlphaBlending, true>(blitImage, transform, disableTransform, disableBlend);
00676     } else {
00677         tglBlit<kEnableAlphaBlending, false>(blitImage, transform, disableTransform, disableBlend);
00678     }
00679 }
00680 
00681 void tglBlit(BlitImage *blitImage, const BlitTransform &transform) {
00682     TinyGL::GLContext *c =TinyGL::gl_get_context();
00683     bool disableColor = transform._aTint == 1.0f && transform._bTint == 1.0f && transform._gTint == 1.0f && transform._rTint == 1.0f;
00684     bool disableTransform = transform._destinationRectangle.width() == 0 && transform._destinationRectangle.height() == 0 && transform._rotation == 0;
00685     bool disableBlend = c->fb->isBlendingEnabled() == false;
00686     bool enableAlphaBlending = c->fb->isAlphaBlendingEnabled();
00687 
00688     if (enableAlphaBlending) {
00689         tglBlit<true>(blitImage, transform, disableColor, disableTransform, disableBlend);
00690     } else {
00691         tglBlit<false>(blitImage, transform, disableColor, disableTransform, disableBlend);
00692     }
00693 }
00694 
00695 void tglBlitNoBlend(BlitImage *blitImage, const BlitTransform &transform) {
00696     if (transform._flipHorizontally == false && transform._flipVertically == false) {
00697         blitImage->tglBlitGeneric<true, false, false, false, false, false>(transform);
00698     } else if(transform._flipHorizontally == false) {
00699         blitImage->tglBlitGeneric<true, false, false, true, false, false>(transform);
00700     } else {
00701         blitImage->tglBlitGeneric<true, false, false, false, true, false>(transform);
00702     }
00703 }
00704 
00705 void tglBlitFast(BlitImage *blitImage, int x, int y) {
00706     BlitTransform transform(x, y);
00707     blitImage->tglBlitGeneric<true, true, true, false, false, false>(transform);
00708 }
00709 
00710 void tglBlitZBuffer(BlitImage *blitImage, int x, int y) {
00711     blitImage->tglBlitZBuffer(x, y);
00712 }
00713 
00714 void tglCleanupImages() {
00715     TinyGL::GLContext *c = TinyGL::gl_get_context();
00716     Common::List<BlitImage *>::iterator it = c->_blitImages.begin();
00717     while (it != c->_blitImages.end()) {
00718         if ((*it)->isDisposed()) {
00719             delete (*it);
00720             it = c->_blitImages.erase(it);
00721         } else {
00722             ++it;
00723         }
00724     }
00725 }
00726 
00727 void tglBlitSetScissorRect(const Common::Rect &rect) {
00728     TinyGL::gl_get_context()->_scissorRect = rect;
00729 }
00730 
00731 void tglBlitResetScissorRect(void) {
00732     TinyGL::GLContext *c = TinyGL::gl_get_context();
00733     c->_scissorRect = c->renderRect;
00734 }
00735 
00736 } // end of namespace Internal
00737 
00738 Common::Point transformPoint(float x, float y, int rotation) {
00739     float rotateRad = rotation * M_PI / 180.0f;
00740     Common::Point newPoint;
00741     newPoint.x = x * cos(rotateRad) - y * sin(rotateRad);
00742     newPoint.y = x * sin(rotateRad) + y * cos(rotateRad);
00743     return newPoint;
00744 }
00745 
00746 Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY) {
00747     Common::Point nw, ne, sw, se;
00748     nw = transformPoint(x - originX, y - originY, rotation);
00749     ne = transformPoint(x + width - originX, y - originY, rotation);
00750     sw = transformPoint(x + width - originX, y + height -    originY, rotation);
00751     se = transformPoint(x - originX, y + height - originY, rotation);
00752 
00753     float top = MIN(nw.y, MIN(ne.y, MIN(sw.y, se.y)));
00754     float bottom = MAX(nw.y, MAX(ne.y, MAX(sw.y, se.y)));
00755     float left = MIN(nw.x, MIN(ne.x, MIN(sw.x, se.x)));
00756     float right = MAX(nw.x, MAX(ne.x, MAX(sw.x, se.x)));
00757 
00758     Common::Rect res;
00759     res.top = (int32)(floor(top)) + originY;
00760     res.bottom = (int32)(ceil(bottom)) + originY;
00761     res.left = (int32)(floor(left)) + originX;
00762     res.right = (int32)(ceil(right)) + originX;
00763 
00764     return res;
00765 }
00766 
00767 }


Generated on Sat Sep 14 2019 05:01:29 for ResidualVM by doxygen 1.7.1
curved edge   curved edge