From 8f7e6b94b633ca1ffba17e4eefdca1aea8808e22 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 27 Feb 2025 21:47:03 -0500 Subject: [PATCH] Cache metatile images for each render pass --- src/core/maplayout.cpp | 50 +++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/core/maplayout.cpp b/src/core/maplayout.cpp index 79e3b832..ee7040a0 100644 --- a/src/core/maplayout.cpp +++ b/src/core/maplayout.cpp @@ -322,44 +322,58 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) { bool changed_any = false; int width_ = getWidth(); int height_ = getHeight(); - if (image.isNull() || image.width() != width_ * 16 || image.height() != height_ * 16) { - image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + if (this->image.isNull() || this->image.width() != width_ * 16 || this->image.height() != height_ * 16) { + this->image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); changed_any = true; } if (this->blockdata.isEmpty() || !width_ || !height_) { - pixmap = pixmap.fromImage(image); - return pixmap; + this->pixmap = this->pixmap.fromImage(this->image); + return this->pixmap; } - QPainter painter(&image); + // There are a lot of external changes that can invalidate a general metatile image cache. + // However, during a single pass at rendering the layout there shouldn't be any changes to + // the tiles, tileset palettes, or metatile layer order/opacity, and layouts often have + // many repeated metatile IDs, so we create a cache for each request to render the layout. + QHash imageCache; + + QPainter painter(&this->image); for (int i = 0; i < this->blockdata.length(); i++) { if (!ignoreCache && !layoutBlockChanged(i, this->cached_blockdata)) { continue; } - changed_any = true; int map_y = width_ ? i / width_ : 0; int map_x = width_ ? i % width_ : 0; if (bounds.isValid() && !bounds.contains(map_x, map_y)) { continue; } - QPoint metatile_origin = QPoint(map_x * 16, map_y * 16); - Block block = this->blockdata.at(i); - QImage metatile_image = getMetatileImage( - block.metatileId(), - fromLayout ? fromLayout->tileset_primary : this->tileset_primary, - fromLayout ? fromLayout->tileset_secondary : this->tileset_secondary, - metatileLayerOrder, - metatileLayerOpacity - ); - painter.drawImage(metatile_origin, metatile_image); + + uint16_t metatileId = this->blockdata.at(i).metatileId(); + QImage metatileImage; + if (imageCache.contains(metatileId)) { + metatileImage = imageCache.value(metatileId); + } else { + metatileImage = getMetatileImage( + metatileId, + fromLayout ? fromLayout->tileset_primary : this->tileset_primary, + fromLayout ? fromLayout->tileset_secondary : this->tileset_secondary, + metatileLayerOrder, + metatileLayerOpacity + ); + imageCache.insert(metatileId, metatileImage); + } + + QPoint metatileOrigin = QPoint(map_x * 16, map_y * 16); + painter.drawImage(metatileOrigin, metatileImage); + changed_any = true; } painter.end(); if (changed_any) { cacheBlockdata(); - pixmap = pixmap.fromImage(image); + this->pixmap = this->pixmap.fromImage(this->image); } - return pixmap; + return this->pixmap; } QPixmap Layout::renderCollision(bool ignoreCache) {