00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "graphics/managed_surface.h"
00024 #include "common/algorithm.h"
00025 #include "common/textconsole.h"
00026
00027 namespace Graphics {
00028
00029 const int SCALE_THRESHOLD = 0x100;
00030
00031 ManagedSurface::ManagedSurface() :
00032 w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
00033 _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
00034 }
00035
00036 ManagedSurface::ManagedSurface(ManagedSurface &surf) :
00037 w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
00038 _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
00039 *this = surf;
00040 }
00041
00042 ManagedSurface::ManagedSurface(int width, int height) :
00043 w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
00044 _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
00045 create(width, height);
00046 }
00047
00048 ManagedSurface::ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat) :
00049 w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
00050 _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
00051 create(width, height, pixelFormat);
00052 }
00053
00054 ManagedSurface::ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds) :
00055 w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
00056 _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
00057 create(surf, bounds);
00058 }
00059
00060 ManagedSurface::~ManagedSurface() {
00061 free();
00062 }
00063
00064 ManagedSurface &ManagedSurface::operator=(ManagedSurface &surf) {
00065
00066 free();
00067
00068 if (surf._disposeAfterUse == DisposeAfterUse::YES) {
00069
00070 create(surf.w, surf.h, surf.format);
00071 Common::copy((const byte *)surf.getPixels(), (const byte *)surf.getPixels() +
00072 surf.w * surf.h * surf.format.bytesPerPixel, (byte *)this->getPixels());
00073 } else {
00074
00075 _owner = surf._owner;
00076 _offsetFromOwner = surf._offsetFromOwner;
00077 void *srcPixels = surf._innerSurface.getPixels();
00078 _innerSurface.setPixels(srcPixels);
00079 _innerSurface.w = surf.w;
00080 _innerSurface.h = surf.h;
00081 _innerSurface.pitch = surf.pitch;
00082 this->format = surf.format;
00083 }
00084
00085 return *this;
00086 }
00087
00088 void ManagedSurface::setPixels(void *newPixels) {
00089 free();
00090 _innerSurface.setPixels(newPixels);
00091 }
00092
00093 void ManagedSurface::create(uint16 width, uint16 height) {
00094 create(width, height, PixelFormat::createFormatCLUT8());
00095 }
00096
00097 void ManagedSurface::create(uint16 width, uint16 height, const PixelFormat &pixelFormat) {
00098 free();
00099 _innerSurface.create(width, height, pixelFormat);
00100
00101 _disposeAfterUse = DisposeAfterUse::YES;
00102 markAllDirty();
00103 }
00104
00105 void ManagedSurface::create(ManagedSurface &surf, const Common::Rect &bounds) {
00106 free();
00107
00108 _offsetFromOwner = Common::Point(bounds.left, bounds.top);
00109 _innerSurface.setPixels(surf.getBasePtr(bounds.left, bounds.top));
00110 _innerSurface.pitch = surf.pitch;
00111 _innerSurface.format = surf.format;
00112 _innerSurface.w = bounds.width();
00113 _innerSurface.h = bounds.height();
00114 _owner = &surf;
00115 _disposeAfterUse = DisposeAfterUse::NO;
00116 }
00117
00118 void ManagedSurface::free() {
00119 if (_disposeAfterUse == DisposeAfterUse::YES)
00120 _innerSurface.free();
00121
00122 _disposeAfterUse = DisposeAfterUse::NO;
00123 _owner = nullptr;
00124 _offsetFromOwner = Common::Point(0, 0);
00125 }
00126
00127 bool ManagedSurface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) {
00128 if (destBounds.left >= this->w || destBounds.top >= this->h ||
00129 destBounds.right <= 0 || destBounds.bottom <= 0)
00130 return false;
00131
00132
00133 if (destBounds.right > this->w) {
00134 srcBounds.right -= destBounds.right - this->w;
00135 destBounds.right = this->w;
00136 }
00137
00138 if (destBounds.bottom > this->h) {
00139 srcBounds.bottom -= destBounds.bottom - this->h;
00140 destBounds.bottom = this->h;
00141 }
00142
00143 if (destBounds.top < 0) {
00144 srcBounds.top += -destBounds.top;
00145 destBounds.top = 0;
00146 }
00147
00148 if (destBounds.left < 0) {
00149 srcBounds.left += -destBounds.left;
00150 destBounds.left = 0;
00151 }
00152
00153 return true;
00154 }
00155
00156 void ManagedSurface::blitFrom(const Surface &src) {
00157 blitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0));
00158 }
00159
00160 void ManagedSurface::blitFrom(const Surface &src, const Common::Point &destPos) {
00161 blitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos);
00162 }
00163
00164 void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect,
00165 const Common::Point &destPos) {
00166 Common::Rect srcBounds = srcRect;
00167 Common::Rect destBounds(destPos.x, destPos.y, destPos.x + srcRect.width(),
00168 destPos.y + srcRect.height());
00169 uint destPixel;
00170 byte rSrc, gSrc, bSrc, aSrc;
00171 byte rDest, gDest, bDest;
00172 double alpha;
00173
00174 if (!srcRect.isValidRect() || !clip(srcBounds, destBounds))
00175 return;
00176
00177 if (format != src.format) {
00178
00179
00180 assert(format.bytesPerPixel == 2 || format.bytesPerPixel == 4);
00181 assert(src.format.bytesPerPixel == 2 || src.format.bytesPerPixel == 4);
00182 }
00183
00184 for (int y = 0; y < srcBounds.height(); ++y) {
00185 const byte *srcP = (const byte *)src.getBasePtr(srcBounds.left, srcBounds.top + y);
00186 byte *destP = (byte *)getBasePtr(destBounds.left, destBounds.top + y);
00187
00188 if (src.format == format) {
00189
00190 Common::copy(srcP, srcP + srcBounds.width() * format.bytesPerPixel, destP);
00191 } else {
00192 for (int x = 0; x < srcBounds.width(); ++x,
00193 srcP += src.format.bytesPerPixel,
00194 destP += format.bytesPerPixel) {
00195 src.format.colorToARGB(src.format.bytesPerPixel == 2 ? *(const uint16 *)srcP : *(const uint32 *)srcP,
00196 aSrc, rSrc, gSrc, bSrc);
00197 format.colorToRGB(format.bytesPerPixel == 2 ? *(const uint16 *)destP : *(const uint32 *)destP,
00198 rDest, gDest, bDest);
00199
00200 if (aSrc == 0) {
00201
00202 continue;
00203 } else if (aSrc == 0xff) {
00204
00205 rDest = rSrc;
00206 gDest = gSrc;
00207 bDest = bSrc;
00208 } else {
00209
00210 alpha = (double)aSrc / 255.0;
00211 rDest = static_cast<byte>((rSrc * alpha) + (rDest * (1.0 - alpha)));
00212 gDest = static_cast<byte>((gSrc * alpha) + (gDest * (1.0 - alpha)));
00213 bDest = static_cast<byte>((bSrc * alpha) + (bDest * (1.0 - alpha)));
00214 }
00215
00216 destPixel = format.ARGBToColor(0xff, rDest, gDest, bDest);
00217 if (format.bytesPerPixel == 2)
00218 *(uint16 *)destP = destPixel;
00219 else
00220 *(uint32 *)destP = destPixel;
00221 }
00222 }
00223 }
00224
00225 addDirtyRect(Common::Rect(0, 0, this->w, this->h));
00226 }
00227
00228 void ManagedSurface::transBlitFrom(const Surface &src, uint transColor, bool flipped, uint overrideColor) {
00229 transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(0, 0, this->w, this->h),
00230 transColor, false, overrideColor);
00231 }
00232
00233 void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos,
00234 uint transColor, bool flipped, uint overrideColor) {
00235 transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y,
00236 destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor);
00237 }
00238
00239 void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect,
00240 const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor) {
00241 transBlitFrom(src, srcRect, Common::Rect(destPos.x, destPos.y,
00242 destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor);
00243 }
00244
00245 template<typename TSRC, typename TDEST>
00246 void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, const Common::Rect &destRect, TSRC transColor, bool flipped, uint overrideColor) {
00247 int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width();
00248 int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height();
00249 const Graphics::PixelFormat &srcFormat = src.format;
00250 const Graphics::PixelFormat &destFormat = dest.format;
00251 byte aSrc, rSrc, gSrc, bSrc;
00252 byte rDest, gDest, bDest;
00253 double alpha;
00254
00255
00256 for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) {
00257 if (destY < 0 || destY >= dest.h)
00258 continue;
00259 const TSRC *srcLine = (const TSRC *)src.getBasePtr(srcRect.left, scaleYCtr / SCALE_THRESHOLD + srcRect.top);
00260 TDEST *destLine = (TDEST *)dest.getBasePtr(destRect.left, destY);
00261
00262
00263 for (int destX = destRect.left, xCtr = 0, scaleXCtr = 0; destX < destRect.right; ++destX, ++xCtr, scaleXCtr += scaleX) {
00264 if (destX < 0 || destX >= dest.w)
00265 continue;
00266
00267 TSRC srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD];
00268 if (srcVal == transColor)
00269 continue;
00270
00271 if (srcFormat == destFormat) {
00272
00273 destLine[xCtr] = overrideColor ? overrideColor : srcVal;
00274 } else {
00275
00276 srcFormat.colorToARGB(*srcLine, aSrc, rSrc, gSrc, bSrc);
00277 destFormat.colorToRGB(destLine[xCtr], rDest, gDest, bDest);
00278
00279 if (aSrc == 0) {
00280
00281 continue;
00282 } else if (aSrc == 0xff) {
00283
00284 rDest = rSrc;
00285 gDest = gSrc;
00286 bDest = bSrc;
00287 } else {
00288
00289 alpha = (double)aSrc / 255.0;
00290 rDest = static_cast<byte>((rSrc * alpha) + (rDest * (1.0 - alpha)));
00291 gDest = static_cast<byte>((gSrc * alpha) + (gDest * (1.0 - alpha)));
00292 bDest = static_cast<byte>((bSrc * alpha) + (bDest * (1.0 - alpha)));
00293 }
00294
00295 destLine[xCtr] = destFormat.ARGBToColor(0xff, rDest, gDest, bDest);
00296 }
00297 }
00298 }
00299 }
00300
00301 #define HANDLE_BLIT(SRC_BYTES, DEST_BYTES, SRC_TYPE, DEST_TYPE) \
00302 if (src.format.bytesPerPixel == SRC_BYTES && format.bytesPerPixel == DEST_BYTES) \
00303 transBlit<SRC_TYPE, DEST_TYPE>(src, srcRect, _innerSurface, destRect, transColor, flipped, overrideColor); \
00304 else
00305
00306 void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect,
00307 const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) {
00308 if (src.w == 0 || src.h == 0 || destRect.width() == 0 || destRect.height() == 0)
00309 return;
00310
00311 HANDLE_BLIT(1, 1, byte, byte)
00312 HANDLE_BLIT(2, 2, uint16, uint16)
00313 HANDLE_BLIT(4, 4, uint32, uint32)
00314 HANDLE_BLIT(2, 4, uint16, uint32)
00315 HANDLE_BLIT(4, 2, uint32, uint16)
00316 error("Surface::transBlitFrom: bytesPerPixel must be 1, 2, or 4");
00317
00318
00319 addDirtyRect(destRect);
00320 }
00321
00322 #undef HANDLE_BLIT
00323
00324 void ManagedSurface::markAllDirty() {
00325 addDirtyRect(Common::Rect(0, 0, this->w, this->h));
00326 }
00327
00328 void ManagedSurface::addDirtyRect(const Common::Rect &r) {
00329 if (_owner) {
00330 Common::Rect bounds = r;
00331 bounds.clip(Common::Rect(0, 0, this->w, this->h));
00332 bounds.translate(_offsetFromOwner.x, _offsetFromOwner.y);
00333 _owner->addDirtyRect(bounds);
00334 }
00335 }
00336
00337 void ManagedSurface::clear(uint color) {
00338 if (!empty())
00339 fillRect(getBounds(), color);
00340 }
00341
00342 }