diff options
Diffstat (limited to 'engines/wintermute/base')
17 files changed, 222 insertions, 141 deletions
diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp index 5b88dab90e..b2c05d271d 100644 --- a/engines/wintermute/base/base_game.cpp +++ b/engines/wintermute/base/base_game.cpp @@ -3068,8 +3068,8 @@ bool BaseGame::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_offsetX)); persistMgr->transfer(TMEMBER(_offsetY)); - persistMgr->transfer(TMEMBER(_offsetPercentX)); - persistMgr->transfer(TMEMBER(_offsetPercentY)); + persistMgr->transferFloat(TMEMBER(_offsetPercentX)); + persistMgr->transferFloat(TMEMBER(_offsetPercentY)); persistMgr->transfer(TMEMBER(_origInteractive)); persistMgr->transfer(TMEMBER_INT(_origState)); diff --git a/engines/wintermute/base/base_object.cpp b/engines/wintermute/base/base_object.cpp index 9d5548be0f..ea754f8f23 100644 --- a/engines/wintermute/base/base_object.cpp +++ b/engines/wintermute/base/base_object.cpp @@ -968,9 +968,9 @@ bool BaseObject::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_movable)); persistMgr->transfer(TMEMBER(_posX)); persistMgr->transfer(TMEMBER(_posY)); - persistMgr->transfer(TMEMBER(_relativeScale)); + persistMgr->transferFloat(TMEMBER(_relativeScale)); persistMgr->transfer(TMEMBER(_rotatable)); - persistMgr->transfer(TMEMBER(_scale)); + persistMgr->transferFloat(TMEMBER(_scale)); persistMgr->transferPtr(TMEMBER_PTR(_sFX)); persistMgr->transfer(TMEMBER(_sFXStart)); persistMgr->transfer(TMEMBER(_sFXVolume)); @@ -982,21 +982,21 @@ bool BaseObject::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_soundEvent)); persistMgr->transfer(TMEMBER(_zoomable)); - persistMgr->transfer(TMEMBER(_scaleX)); - persistMgr->transfer(TMEMBER(_scaleY)); + persistMgr->transferFloat(TMEMBER(_scaleX)); + persistMgr->transferFloat(TMEMBER(_scaleY)); - persistMgr->transfer(TMEMBER(_rotate)); + persistMgr->transferFloat(TMEMBER(_rotate)); persistMgr->transfer(TMEMBER(_rotateValid)); - persistMgr->transfer(TMEMBER(_relativeRotate)); + persistMgr->transferFloat(TMEMBER(_relativeRotate)); persistMgr->transfer(TMEMBER(_saveState)); persistMgr->transfer(TMEMBER(_nonIntMouseEvents)); persistMgr->transfer(TMEMBER_INT(_sFXType)); - persistMgr->transfer(TMEMBER(_sFXParam1)); - persistMgr->transfer(TMEMBER(_sFXParam2)); - persistMgr->transfer(TMEMBER(_sFXParam3)); - persistMgr->transfer(TMEMBER(_sFXParam4)); + persistMgr->transferFloat(TMEMBER(_sFXParam1)); + persistMgr->transferFloat(TMEMBER(_sFXParam2)); + persistMgr->transferFloat(TMEMBER(_sFXParam3)); + persistMgr->transferFloat(TMEMBER(_sFXParam4)); persistMgr->transfer(TMEMBER_INT(_blendMode)); diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index 6f0f7e289f..e5542d96b7 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -465,44 +465,53 @@ uint32 BasePersistenceManager::getDWORD() { ////////////////////////////////////////////////////////////////////////// -void BasePersistenceManager::putString(const Common::String &val) { - if (!val.size()) { - putString("(null)"); - } else { - _saveStream->writeUint32LE(val.size()); - _saveStream->writeString(val); +void BasePersistenceManager::putString(const char *val) { + if (!val) { + _saveStream->writeUint32LE(0); + return; } -} - -Common::String BasePersistenceManager::getStringObj() { - uint32 len = _loadStream->readUint32LE(); - char *ret = new char[len + 1]; - _loadStream->read(ret, len); - ret[len] = '\0'; - Common::String retString = ret; - delete[] ret; + uint32 len = strlen(val); - if (retString == "(null)") { - retString = ""; - } + _saveStream->writeUint32LE(len + 1); + _saveStream->write(val, len); +} - return retString; +Common::String BasePersistenceManager::getStringObj() { + return getString(); } ////////////////////////////////////////////////////////////////////////// char *BasePersistenceManager::getString() { uint32 len = _loadStream->readUint32LE(); - char *ret = new char[len + 1]; - _loadStream->read(ret, len); - ret[len] = '\0'; - if (!strcmp(ret, "(null)")) { - delete[] ret; - return nullptr; + if (checkVersion(1,2,2)) { + // Version 1.2.2 and above: len == strlen() + 1, NULL has len == 0 + + if (len == 0) + return nullptr; + + char *ret = new char[len]; + _loadStream->read(ret, len - 1); + ret[len - 1] = '\0'; + + return ret; + } else { + + // Version 1.2.1 and older: NULL strings are represented as "(null)" + char *ret = new char[len + 1]; + _loadStream->read(ret, len); + ret[len] = '\0'; + + if (!strcmp(ret, "(null)")) { + delete[] ret; + return nullptr; + } + return ret; } + } bool BasePersistenceManager::putTimeDate(const TimeDate &t) { @@ -536,8 +545,7 @@ void BasePersistenceManager::putFloat(float val) { int exponent = 0; float significand = frexp(val, &exponent); Common::String str = Common::String::format("FS%f", significand); - _saveStream->writeUint32LE(str.size()); - _saveStream->writeString(str); + putString(str.c_str()); _saveStream->writeSint32LE(exponent); } @@ -559,8 +567,7 @@ void BasePersistenceManager::putDouble(double val) { int exponent = 0; double significand = frexp(val, &exponent); Common::String str = Common::String::format("DS%f", significand); - _saveStream->writeUint32LE(str.size()); - _saveStream->writeString(str); + putString(str.c_str()); _saveStream->writeSint32LE(exponent); } @@ -637,7 +644,7 @@ bool BasePersistenceManager::transfer(const char *name, uint32 *val) { ////////////////////////////////////////////////////////////////////////// // float -bool BasePersistenceManager::transfer(const char *name, float *val) { +bool BasePersistenceManager::transferFloat(const char *name, float *val) { if (_saving) { putFloat(*val); if (_saveStream->err()) { @@ -711,7 +718,7 @@ bool BasePersistenceManager::transfer(const char *name, const char **val) { // Common::String bool BasePersistenceManager::transfer(const char *name, Common::String *val) { if (_saving) { - putString(*val); + putString(val->c_str()); return STATUS_OK; } else { char *str = getString(); diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index 6949bfe278..3c0587b362 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -52,7 +52,7 @@ public: void putDWORD(uint32 val); char *getString(); Common::String getStringObj(); - void putString(const Common::String &val); + void putString(const char *val); float getFloat(); void putFloat(float val); double getDouble(); @@ -76,7 +76,7 @@ public: bool transferPtr(const char *name, void *val); bool transfer(const char *name, int32 *val); bool transfer(const char *name, uint32 *val); - bool transfer(const char *name, float *val); + bool transferFloat(const char *name, float *val); bool transfer(const char *name, double *val); bool transfer(const char *name, bool *val); bool transfer(const char *name, byte *val); diff --git a/engines/wintermute/base/base_region.cpp b/engines/wintermute/base/base_region.cpp index 61e9deefb3..36036a1f18 100644 --- a/engines/wintermute/base/base_region.cpp +++ b/engines/wintermute/base/base_region.cpp @@ -432,7 +432,7 @@ bool BaseRegion::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_active)); persistMgr->transfer(TMEMBER(_editorSelectedPoint)); - persistMgr->transfer(TMEMBER(_lastMimicScale)); + persistMgr->transferFloat(TMEMBER(_lastMimicScale)); persistMgr->transfer(TMEMBER(_lastMimicX)); persistMgr->transfer(TMEMBER(_lastMimicY)); _points.persist(persistMgr); diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index 3059a69047..b6f372f377 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -272,7 +272,7 @@ BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width, // void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; Graphics::Surface *surface = new Graphics::Surface(); if (_deletableFont) { // We actually have a TTF - surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)); + surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), _gameRef->_renderer->getPixelFormat()); } else { // We are using a fallback, they can't do 32bpp surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)); } @@ -285,7 +285,7 @@ BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width, } BaseSurface *retSurface = _gameRef->_renderer->createSurface(); - Graphics::Surface *convertedSurface = surface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)); + Graphics::Surface *convertedSurface = surface->convertTo(_gameRef->_renderer->getPixelFormat()); retSurface->putSurface(*convertedSurface, true); convertedSurface->free(); surface->free(); @@ -559,7 +559,7 @@ bool BaseFontTT::initFont() { } if (file) { - _deletableFont = Graphics::loadTTFFont(*file, 96, _fontHeight); // Use the same dpi as WME (96 vs 72). + _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, 96); // Use the same dpi as WME (96 vs 72). _font = _deletableFont; BaseFileManager::getEngineInstance()->closeFile(file); file = nullptr; diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h index 31dc2a022d..b6615bc8fc 100644 --- a/engines/wintermute/base/gfx/base_renderer.h +++ b/engines/wintermute/base/gfx/base_renderer.h @@ -84,7 +84,7 @@ public: * @param a the alpha component to fade too. * @param rect the portion of the screen to fade (if nullptr, the entire screen will be faded). */ - virtual void fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect = nullptr) = 0; + virtual void fadeToColor(byte r, byte g, byte b, byte a) = 0; virtual bool drawLine(int x1, int y1, int x2, int y2, uint32 color); // Unused outside indicator-display virtual bool drawRect(int x1, int y1, int x2, int y2, uint32 color, int width = 1); // Unused outside indicator-display diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index b16cf60752..e4c19fde8b 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -84,7 +84,6 @@ BaseRenderOSystem::~BaseRenderOSystem() { delete _renderSurface; _blankSurface->free(); delete _blankSurface; - TransparentSurface::destroyLookup(); } ////////////////////////////////////////////////////////////////////////// @@ -127,7 +126,7 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) { _windowed = !ConfMan.getBool("fullscreen"); - Graphics::PixelFormat format(4, 8, 8, 8, 8, 16, 8, 0, 24); + Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0); g_system->beginGFXTransaction(); g_system->initSize(_width, _height, &format); OSystem::TransactionError gfxError = g_system->endGFXTransaction(); @@ -244,22 +243,16 @@ void BaseRenderOSystem::fade(uint16 alpha) { } ////////////////////////////////////////////////////////////////////////// -void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect) { +void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a) { Common::Rect fillRect; - if (rect) { - fillRect.left = rect->left; - fillRect.top = rect->top; - fillRect.setWidth(rect->width()); - fillRect.setHeight(rect->height()); - } else { - Rect32 rc; - _gameRef->getCurrentViewportRect(&rc); - fillRect.left = (int16)rc.left; - fillRect.top = (int16)rc.top; - fillRect.setWidth((int16)(rc.right - rc.left)); - fillRect.setHeight((int16)(rc.bottom - rc.top)); - } + Rect32 rc; + _gameRef->getCurrentViewportRect(&rc); + fillRect.left = (int16)rc.left; + fillRect.top = (int16)rc.top; + fillRect.setWidth((int16)(rc.right - rc.left)); + fillRect.setHeight((int16)(rc.bottom - rc.top)); + modTargetRect(&fillRect); //TODO: This is only here until I'm sure about the final pixelformat @@ -613,8 +606,8 @@ bool BaseRenderOSystem::setViewport(int left, int top, int right, int bottom) { // TODO: Hopefully this is the same logic that ScummVM uses. rect.left = (int16)(left + _borderLeft); rect.top = (int16)(top + _borderTop); - rect.right = (int16)((right - left) * _ratioX); - rect.bottom = (int16)((bottom - top) * _ratioY); + rect.setWidth((int16)((right - left) * _ratioX)); + rect.setHeight((int16)((bottom - top) * _ratioY)); _renderRect = rect; return STATUS_OK; @@ -631,15 +624,13 @@ Rect32 BaseRenderOSystem::getViewPort() { ////////////////////////////////////////////////////////////////////////// void BaseRenderOSystem::modTargetRect(Common::Rect *rect) { - // FIXME: This is wrong in quite a few ways right now, and ends up - // breaking the notebook in Dirty Split, so we disable the correction - // for now, this will need fixing when a game with odd aspect-ratios - // show up. return; - rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft - _renderRect.left); - rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop - _renderRect.top); - rect->setWidth((int16)MathUtil::roundUp(rect->width() * _ratioX)); - rect->setHeight((int16)MathUtil::roundUp(rect->height() * _ratioY)); + int newWidth = (int16)MathUtil::roundUp(rect->width() * _ratioX); + int newHeight = (int16)MathUtil::roundUp(rect->height() * _ratioY); + rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft); + rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop); + rect->setWidth(newWidth); + rect->setHeight(newHeight); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index bf2914b430..306563af3b 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -38,6 +38,25 @@ namespace Wintermute { class BaseSurfaceOSystem; class RenderTicket; +/** + * A 2D-renderer implementation for WME. + * This renderer makes use of a "ticket"-system, where all draw-calls + * are stored as tickets until flip() is called, and compared against the tickets + * from last frame, to determine which calls were the same as last round + * (i.e. in the exact same order, with the exact same arguments), and thus + * figure out which parts of the screen need to be redrawn. + * + * Important concepts to handle here, is the ordered number of any ticket + * which is called the "drawNum", every frame this starts from scratch, and + * then the incoming tickets created from the draw-calls are checked to see whether + * they came before, on, or after the drawNum they had last frame. Everything else + * being equal, this information is then used to check whether the draw order changed, + * which will then create a need for redrawing, as we draw with an alpha-channel here. + * + * There is also a draw path that draws without tickets, for debugging purposes, + * as well as to accomodate situations with large enough amounts of draw calls, + * that there will be too much overhead involved with comparing the generated tickets. + */ class BaseRenderOSystem : public BaseRenderer { public: BaseRenderOSystem(BaseGame *inGame); @@ -51,7 +70,7 @@ public: bool fill(byte r, byte g, byte b, Common::Rect *rect = nullptr) override; Graphics::PixelFormat getPixelFormat() const override; void fade(uint16 alpha) override; - void fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect = nullptr) override; + void fadeToColor(byte r, byte g, byte b, byte a) override; bool drawLine(int x1, int y1, int x2, int y2, uint32 color) override; @@ -59,6 +78,11 @@ public: void invalidateTicket(RenderTicket *renderTicket); void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf); + /** + * Insert a ticket into the queue, adding a dirty rect if it's + * new, or out-of-order from last draw from the ticket. + * param renderTicket the ticket to be added. + */ void drawFromTicket(RenderTicket *renderTicket); bool setViewport(int left, int top, int right, int bottom) override; @@ -79,11 +103,18 @@ public: virtual bool startSpriteBatch() override; virtual bool endSpriteBatch() override; void endSaveLoad(); - void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform); + void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform); void repeatLastDraw(int offsetX, int offsetY, int numTimesX, int numTimesY); BaseSurface *createSurface() override; private: - void addDirtyRect(const Common::Rect &rect) ; + /** + * Mark a specified rect of the screen as dirty. + * @param rect the region to be marked as dirty + */ + void addDirtyRect(const Common::Rect &rect); + /** + * Traverse the tickets that are dirty, and draw them + */ void drawTickets(); // Non-dirty-rects: void drawFromSurface(RenderTicket *ticket); @@ -96,7 +127,7 @@ private: RenderTicket *_previousTicket; bool _needsFlip; - uint32 _drawNum; + uint32 _drawNum; ///< The global number of the current draw-operation. Common::Rect _renderRect; Graphics::Surface *_renderSurface; Graphics::Surface *_blankSurface; diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index d4c5905c4b..14767aa067 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -48,7 +48,7 @@ namespace Wintermute { BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) { _surface = new Graphics::Surface(); _alphaMask = nullptr; - _hasAlpha = true; + _alphaType = TransparentSurface::ALPHA_FULL; _lockPixels = nullptr; _lockPitch = 0; _loaded = false; @@ -71,22 +71,37 @@ BaseSurfaceOSystem::~BaseSurfaceOSystem() { renderer->invalidateTicketsFromSurface(this); } -bool hasTransparency(Graphics::Surface *surf) { +TransparentSurface::AlphaType hasTransparencyType(const Graphics::Surface *surf) { if (surf->format.bytesPerPixel != 4) { - warning("hasTransparency:: non 32 bpp surface passed as argument"); - return false; + warning("hasTransparencyType:: non 32 bpp surface passed as argument"); + return TransparentSurface::ALPHA_OPAQUE; } uint8 r, g, b, a; + bool seenAlpha = false; + bool seenFullAlpha = false; for (int i = 0; i < surf->h; i++) { + if (seenFullAlpha) { + break; + } for (int j = 0; j < surf->w; j++) { - uint32 pix = *(uint32 *)surf->getBasePtr(j, i); + uint32 pix = *(const uint32 *)surf->getBasePtr(j, i); surf->format.colorToARGB(pix, a, r, g, b); if (a != 255) { - return true; + seenAlpha = true; + if (a != 0) { + seenFullAlpha = true; + break; + } } } } - return false; + if (seenFullAlpha) { + return TransparentSurface::ALPHA_FULL; + } else if (seenAlpha) { + return TransparentSurface::ALPHA_BINARY; + } else { + return TransparentSurface::ALPHA_OPAQUE; + } } ////////////////////////////////////////////////////////////////////////// @@ -128,39 +143,36 @@ bool BaseSurfaceOSystem::finishLoad() { _width = image->getSurface()->w; _height = image->getSurface()->h; - bool isSaveGameGrayscale = scumm_strnicmp(_filename.c_str(), "savegame:", 9) == 0 && (_filename.c_str()[_filename.size() - 1] == 'g' || _filename.c_str()[_filename.size() - 1] == 'G'); + bool isSaveGameGrayscale = _filename.matchString("savegame:*g", true); if (isSaveGameGrayscale) { warning("grayscaleConversion not yet implemented"); // FIBITMAP *newImg = FreeImage_ConvertToGreyscale(img); TODO } - // no alpha, set color key - /* if (surface->format.bytesPerPixel != 4) - SDL_SetColorKey(surf, SDL_TRUE, SDL_MapRGB(surf->format, ck_red, ck_green, ck_blue));*/ - - // convert 32-bit BMPs to 24-bit or they appear totally transparent (does any app actually write alpha in BMP properly?) - // Well, actually, we don't convert via 24-bit as the color-key application overwrites the Alpha-channel anyhow. _surface->free(); delete _surface; bool needsColorKey = false; bool replaceAlpha = true; - if (_filename.hasSuffix(".bmp") && image->getSurface()->format.bytesPerPixel == 4) { - _surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette()); - needsColorKey = true; - replaceAlpha = false; - } else if (image->getSurface()->format.bytesPerPixel == 1 && image->getPalette()) { + if (image->getSurface()->format.bytesPerPixel == 1) { + if (!image->getPalette()) { + error("Missing palette while loading 8bit image %s", _filename.c_str()); + } _surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette()); needsColorKey = true; - } else if (image->getSurface()->format.bytesPerPixel >= 3 && image->getSurface()->format != g_system->getScreenFormat()) { - _surface = image->getSurface()->convertTo(g_system->getScreenFormat()); - if (image->getSurface()->format.bytesPerPixel == 3) { - needsColorKey = true; - } } else { - _surface = new Graphics::Surface(); - _surface->copyFrom(*image->getSurface()); - if (_surface->format.aBits() == 0) { + if (image->getSurface()->format != g_system->getScreenFormat()) { + _surface = image->getSurface()->convertTo(g_system->getScreenFormat()); + } else { + _surface = new Graphics::Surface(); + _surface->copyFrom(*image->getSurface()); + } + + if (_filename.hasSuffix(".bmp") && image->getSurface()->format.bytesPerPixel == 4) { + // 32 bpp BMPs have nothing useful in their alpha-channel -> color-key + needsColorKey = true; + replaceAlpha = false; + } else if (image->getSurface()->format.aBits() == 0) { needsColorKey = true; } } @@ -170,7 +182,7 @@ bool BaseSurfaceOSystem::finishLoad() { trans.applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha); } - _hasAlpha = hasTransparency(_surface); + _alphaType = hasTransparencyType(_surface); _valid = true; _gameRef->addMem(_width * _height * 4); @@ -409,8 +421,6 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, if (newRect) { position.top = y; position.left = x; - position.right = x + newRect->width(); - position.bottom = y + newRect->height(); position.setWidth(newRect->width()); position.setHeight(newRect->height()); } else { @@ -422,17 +432,11 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, // TODO: This actually requires us to have the SAME source-offsets every time, // But no checking is in place for that yet. - // TODO: Optimize by not doing alpha-blits if we lack or disable alpha - - bool hasAlpha = false; - - if (_hasAlpha && !transform._alphaDisable) { - hasAlpha = true; - } - - if (transform._alphaDisable) { - warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored"); + // Optimize by not doing alpha-blits if we lack alpha + if (_alphaType == TransparentSurface::ALPHA_OPAQUE && !transform._alphaDisable) { + transform._alphaDisable = true; } + renderer->drawSurface(this, _surface, &srcRect, &position, transform); return STATUS_OK; } @@ -447,7 +451,11 @@ bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAl _loaded = true; _surface->free(); _surface->copyFrom(surface); - _hasAlpha = hasAlpha; + if (hasAlpha) { + _alphaType = TransparentSurface::ALPHA_FULL; + } else { + _alphaType = TransparentSurface::ALPHA_OPAQUE; + } BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); renderer->invalidateTicketsFromSurface(this); diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h index da86833517..6cf19d00fb 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -30,6 +30,7 @@ #define WINTERMUTE_BASE_SURFACESDL_H #include "graphics/surface.h" +#include "engines/wintermute/graphics/transparent_surface.h" #include "engines/wintermute/base/gfx/base_surface.h" #include "common/list.h" @@ -81,6 +82,7 @@ public: return _height; } + TransparentSurface::AlphaType getAlphaType() const { return _alphaType; } private: Graphics::Surface *_surface; bool _loaded; @@ -90,7 +92,7 @@ private: uint32 getPixelAt(Graphics::Surface *surface, int x, int y); uint32 _rotation; - bool _hasAlpha; + TransparentSurface::AlphaType _alphaType; void *_lockPixels; int _lockPitch; byte *_alphaMask; diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index 98739e0778..b1720c1b0b 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -28,6 +28,7 @@ #include "engines/wintermute/base/gfx/osystem/render_ticket.h" +#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h" #include "engines/wintermute/graphics/transform_tools.h" #include "common/textconsole.h" @@ -104,7 +105,13 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { clipRect.setWidth(getSurface()->w); clipRect.setHeight(getSurface()->h); - src._enableAlphaBlit = !_transform._alphaDisable; + if (_owner) { + if (_transform._alphaDisable) { + src._alphaMode = TransparentSurface::ALPHA_OPAQUE; + } else { + src._alphaMode = _owner->getAlphaType(); + } + } src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height()); } @@ -118,7 +125,13 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect clipRect->setHeight(getSurface()->h); } - src._enableAlphaBlit = !_transform._alphaDisable; + if (_owner) { + if (_transform._alphaDisable) { + src._alphaMode = TransparentSurface::ALPHA_OPAQUE; + } else { + src._alphaMode = _owner->getAlphaType(); + } + } src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height()); if (doDelete) { delete clipRect; diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h index b1313e932d..875102d01c 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.h +++ b/engines/wintermute/base/gfx/osystem/render_ticket.h @@ -36,6 +36,19 @@ namespace Wintermute { class BaseSurfaceOSystem; +/** + * A single RenderTicket. + * A render ticket is a collection of the data and draw specifications made + * for a single draw-call in the OSystem-backend for WME. The ticket additionally + * holds the order in which this call was made, so that it can be detected if + * the same call is done in the following frame. Thus allowing us to potentially + * skip drawing the same region again, unless anything has changed. Since a surface + * can have a potentially large amount of draw-calls made to it, at varying rotation, + * zoom, and crop-levels we also need to hold a copy of the necessary data. + * (Video-surfaces may even change their data). The promise that is made when a ticket + * is created is that what the state was of the surface at THAT point, is what will end + * up on screen at flip() time. + */ class RenderTicket { public: RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform); diff --git a/engines/wintermute/base/particles/part_emitter.cpp b/engines/wintermute/base/particles/part_emitter.cpp index 5c21988141..aaffa0965a 100644 --- a/engines/wintermute/base/particles/part_emitter.cpp +++ b/engines/wintermute/base/particles/part_emitter.cpp @@ -1163,12 +1163,12 @@ bool PartEmitter::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_angle1)); persistMgr->transfer(TMEMBER(_angle2)); - persistMgr->transfer(TMEMBER(_velocity1)); - persistMgr->transfer(TMEMBER(_velocity2)); + persistMgr->transferFloat(TMEMBER(_velocity1)); + persistMgr->transferFloat(TMEMBER(_velocity2)); persistMgr->transfer(TMEMBER(_velocityZBased)); - persistMgr->transfer(TMEMBER(_scale1)); - persistMgr->transfer(TMEMBER(_scale2)); + persistMgr->transferFloat(TMEMBER(_scale1)); + persistMgr->transferFloat(TMEMBER(_scale2)); persistMgr->transfer(TMEMBER(_scaleZBased)); persistMgr->transfer(TMEMBER(_maxParticles)); @@ -1196,14 +1196,14 @@ bool PartEmitter::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_alpha2)); persistMgr->transfer(TMEMBER(_alphaTimeBased)); - persistMgr->transfer(TMEMBER(_angVelocity1)); - persistMgr->transfer(TMEMBER(_angVelocity2)); + persistMgr->transferFloat(TMEMBER(_angVelocity1)); + persistMgr->transferFloat(TMEMBER(_angVelocity2)); - persistMgr->transfer(TMEMBER(_rotation1)); - persistMgr->transfer(TMEMBER(_rotation2)); + persistMgr->transferFloat(TMEMBER(_rotation1)); + persistMgr->transferFloat(TMEMBER(_rotation2)); - persistMgr->transfer(TMEMBER(_growthRate1)); - persistMgr->transfer(TMEMBER(_growthRate2)); + persistMgr->transferFloat(TMEMBER(_growthRate1)); + persistMgr->transferFloat(TMEMBER(_growthRate2)); persistMgr->transfer(TMEMBER(_exponentialGrowth)); persistMgr->transfer(TMEMBER(_useRegion)); diff --git a/engines/wintermute/base/particles/part_particle.cpp b/engines/wintermute/base/particles/part_particle.cpp index 2ae867fd42..86cacacb5c 100644 --- a/engines/wintermute/base/particles/part_particle.cpp +++ b/engines/wintermute/base/particles/part_particle.cpp @@ -234,9 +234,9 @@ bool PartParticle::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_alpha2)); persistMgr->transfer(TMEMBER(_border)); persistMgr->transfer(TMEMBER(_pos)); - persistMgr->transfer(TMEMBER(_posZ)); + persistMgr->transferFloat(TMEMBER(_posZ)); persistMgr->transfer(TMEMBER(_velocity)); - persistMgr->transfer(TMEMBER(_scale)); + persistMgr->transferFloat(TMEMBER(_scale)); persistMgr->transfer(TMEMBER(_creationTime)); persistMgr->transfer(TMEMBER(_lifeTime)); persistMgr->transfer(TMEMBER(_isDead)); @@ -244,9 +244,9 @@ bool PartParticle::persist(BasePersistenceManager *persistMgr) { persistMgr->transfer(TMEMBER(_fadeStart)); persistMgr->transfer(TMEMBER(_fadeTime)); persistMgr->transfer(TMEMBER(_currentAlpha)); - persistMgr->transfer(TMEMBER(_angVelocity)); - persistMgr->transfer(TMEMBER(_rotation)); - persistMgr->transfer(TMEMBER(_growthRate)); + persistMgr->transferFloat(TMEMBER(_angVelocity)); + persistMgr->transferFloat(TMEMBER(_rotation)); + persistMgr->transferFloat(TMEMBER(_growthRate)); persistMgr->transfer(TMEMBER(_exponentialGrowth)); persistMgr->transfer(TMEMBER(_fadeStartAlpha)); diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp index dd24457d6c..bb819b23e4 100644 --- a/engines/wintermute/base/scriptables/script_engine.cpp +++ b/engines/wintermute/base/scriptables/script_engine.cpp @@ -362,6 +362,8 @@ bool ScEngine::tick() { ////////////////////////////////////////////////////////////////////////// bool ScEngine::tickUnbreakable() { + ScScript *oldScript = _currentScript; + // execute unbreakable scripts for (uint32 i = 0; i < _scripts.size(); i++) { if (!_scripts[i]->_unbreakable) { @@ -373,9 +375,12 @@ bool ScEngine::tickUnbreakable() { _scripts[i]->executeInstruction(); } _scripts[i]->finish(); - _currentScript = nullptr; + _currentScript = oldScript; } - removeFinishedScripts(); + + // NB: Don't remove finished scripts here since we could be recursively + // executing scripts. Doing so could invalidate the outer iteration in + // ::tick() over _scripts. return STATUS_OK; } diff --git a/engines/wintermute/base/scriptables/script_value.cpp b/engines/wintermute/base/scriptables/script_value.cpp index 3532e127d0..31ec457df1 100644 --- a/engines/wintermute/base/scriptables/script_value.cpp +++ b/engines/wintermute/base/scriptables/script_value.cpp @@ -827,6 +827,17 @@ bool ScValue::persist(BasePersistenceManager *persistMgr) { persistMgr->transferPtr(TMEMBER_PTR(_valRef)); persistMgr->transfer(TMEMBER(_valString)); + if (!persistMgr->getIsSaving() && !persistMgr->checkVersion(1,2,2)) { + // Savegames prior to 1.2.2 stored empty strings as NULL. + // We disambiguate those by turning NULL strings into empty + // strings if _type is VAL_STRING instead of VAL_NULL. + + if (_type == VAL_STRING && !_valString) { + _valString = new char[1]; + _valString[0] = '\0'; + } + } + /* // TODO: Convert to Debug-statements. FILE* f = fopen("c:\\val.log", "a+"); switch(_type) |