diff --git a/mkxp.json b/mkxp.json index 0ddc9d6..20e7993 100644 --- a/mkxp.json +++ b/mkxp.json @@ -460,4 +460,10 @@ // "x": ... // } + + // Dump tile atlas (for debugging purposes) + // (default: false) + // + // "dumpAtlas": false, + } diff --git a/src/config.cpp b/src/config.cpp index 298da5d..46b809f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -188,6 +188,7 @@ void Config::read(int argc, char *argv[]) { {"JITMaxCache", 100}, {"JITMinCalls", 10000}, {"YJITEnable", false}, + {"dumpAtlas", false}, {"bindingNames", json::object({ {"a", "A"}, {"b", "B"}, @@ -296,6 +297,7 @@ try { exp } catch (...) {} SET_OPT_CUSTOMKEY(BGM.trackCount, BGMTrackCount, integer); SET_STRINGOPT(customScript, customScript); SET_OPT(useScriptNames, boolean); + SET_OPT(dumpAtlas, boolean); fillStringVec(opts["preloadScript"], preloadScripts); fillStringVec(opts["RTP"], rtps); diff --git a/src/config.h b/src/config.h index a3d7de3..8f18777 100644 --- a/src/config.h +++ b/src/config.h @@ -111,7 +111,7 @@ struct Config { std::vector fontSubs; std::vector rubyLoadpaths; - + /* Editor flags */ struct { bool debug; @@ -137,6 +137,8 @@ struct Config { bool enabled; } yjit; + bool dumpAtlas; + // Keybinding action name mappings struct { std::string a; diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 847539f..b23bdf5 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -618,49 +618,10 @@ Bitmap::Bitmap(const char *filename) p->addTaintedArea(rect()); return; } - + SDL_Surface *imgSurf = handler.surface; - - - p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888); - - if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize) - { - /* Mega surface */ - p = new BitmapPrivate(this); - p->selfHires = hiresBitmap; - p->megaSurface = imgSurf; - SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE); - } - else - { - /* Regular surface */ - TEXFBO tex; - - try - { - tex = shState->texPool().request(imgSurf->w, imgSurf->h); - } - catch (const Exception &e) - { - SDL_FreeSurface(imgSurf); - throw e; - } - - p = new BitmapPrivate(this); - p->selfHires = hiresBitmap; - p->gl = tex; - if (p->selfHires != nullptr) { - p->gl.selfHires = &p->selfHires->getGLTypes(); - } - - TEX::bind(p->gl.tex); - TEX::uploadImage(p->gl.width, p->gl.height, imgSurf->pixels, GL_RGBA); - - SDL_FreeSurface(imgSurf); - } - - p->addTaintedArea(rect()); + + initFromSurface(imgSurf, hiresBitmap, true); } Bitmap::Bitmap(int width, int height, bool isHires) @@ -683,10 +644,10 @@ Bitmap::Bitmap(int width, int height, bool isHires) p = new BitmapPrivate(this); p->gl = tex; + p->selfHires = hiresBitmap; if (p->selfHires != nullptr) { p->gl.selfHires = &p->selfHires->getGLTypes(); } - p->selfHires = hiresBitmap; clear(); } @@ -798,11 +759,104 @@ Bitmap::Bitmap(const Bitmap &other, int frame) p->addTaintedArea(rect()); } +Bitmap::Bitmap(TEXFBO &other) +{ + Bitmap *hiresBitmap = nullptr; + + if (other.selfHires != nullptr) { + // Create a high-res version as well. + hiresBitmap = new Bitmap(*other.selfHires); + hiresBitmap->setLores(this); + } + + p = new BitmapPrivate(this); + + p->gl = shState->texPool().request(other.width, other.height); + + p->selfHires = hiresBitmap; + if (p->selfHires != nullptr) { + p->gl.selfHires = &p->selfHires->getGLTypes(); + } + + // Skip blitting to lores texture, since only the hires one will be displayed. + if (p->selfHires == nullptr) { + GLMeta::blitBegin(p->gl); + GLMeta::blitSource(other); + GLMeta::blitRectangle(rect(), rect(), true); + GLMeta::blitEnd(); + } + + p->addTaintedArea(rect()); +} + +Bitmap::Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires) +{ + Bitmap *hiresBitmap = nullptr; + + if (imgSurfHires != nullptr) { + // Create a high-res version as well. + hiresBitmap = new Bitmap(imgSurfHires, nullptr); + hiresBitmap->setLores(this); + } + + initFromSurface(imgSurf, hiresBitmap, false); +} + Bitmap::~Bitmap() { dispose(); } +void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool freeSurface) +{ + p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888); + + if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize) + { + /* Mega surface */ + + if(!freeSurface) { + throw Exception(Exception::RGSSError, "Cloning Mega Bitmap from Surface not supported"); + } + + p = new BitmapPrivate(this); + p->selfHires = hiresBitmap; + p->megaSurface = imgSurf; + SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE); + } + else + { + /* Regular surface */ + TEXFBO tex; + + try + { + tex = shState->texPool().request(imgSurf->w, imgSurf->h); + } + catch (const Exception &e) + { + SDL_FreeSurface(imgSurf); + throw e; + } + + p = new BitmapPrivate(this); + p->selfHires = hiresBitmap; + p->gl = tex; + if (p->selfHires != nullptr) { + p->gl.selfHires = &p->selfHires->getGLTypes(); + } + + TEX::bind(p->gl.tex); + TEX::uploadImage(p->gl.width, p->gl.height, imgSurf->pixels, GL_RGBA); + + if (freeSurface) { + SDL_FreeSurface(imgSurf); + } + } + + p->addTaintedArea(rect()); +} + int Bitmap::width() const { guardDisposed(); diff --git a/src/display/bitmap.h b/src/display/bitmap.h index 44760bb..98c3d5f 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -40,13 +40,18 @@ class Bitmap : public Disposable public: Bitmap(const char *filename); Bitmap(int width, int height, bool isHires = false); - Bitmap(void *pixeldata, int width, int height); + Bitmap(void *pixeldata, int width, int height); + Bitmap(TEXFBO &other); + Bitmap(SDL_Surface *imgSurf, SDL_Surface *imgSurfHires); + /* Clone constructor */ // frame is -2 for "any and all", -1 for "current", anything else for a specific frame Bitmap(const Bitmap &other, int frame = -2); ~Bitmap(); + void initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool freeSurface); + int width() const; int height() const; bool hasHires() const; diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index 348a713..598e502 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -179,7 +179,9 @@ struct Movie SDL_Delay(VIDEO_DELAY); } } - videoBitmap = new Bitmap(video->width, video->height); + // Create this Bitmap without a hires replacement, because we don't + // support hires replacement for Movies yet. + videoBitmap = new Bitmap(video->width, video->height, true); audioQueueHead = NULL; audioQueueTail = NULL; @@ -1401,17 +1403,17 @@ void Graphics::fadein(int duration) { } Bitmap *Graphics::snapToBitmap() { - Bitmap *bitmap = new Bitmap(width(), height()); - - if (bitmap->hasHires()) { - p->compositeToBufferScaled(bitmap->getHires()->getGLTypes(), bitmap->getHires()->width(), bitmap->getHires()->height()); + if (shState->config().enableHires) { + // TODO: Maybe don't reconstruct this struct every time? + TEXFBO tf; + tf.width = width(); + tf.height = height(); + tf.selfHires = &p->screen.getPP().frontBuffer(); + + return new Bitmap(tf); } - p->compositeToBufferScaled(bitmap->getGLTypes(), bitmap->width(), bitmap->height()); - - /* Taint entire bitmap */ - bitmap->taintArea(IntRect(0, 0, width(), height())); - return bitmap; + return new Bitmap(p->screen.getPP().frontBuffer()); } int Graphics::width() const { return p->scResLores.x; } diff --git a/src/display/tilemapvx.cpp b/src/display/tilemapvx.cpp index 678f1a6..4ffe143 100644 --- a/src/display/tilemapvx.cpp +++ b/src/display/tilemapvx.cpp @@ -190,6 +190,16 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader void rebuildAtlas() { TileAtlasVX::build(atlas, bitmaps); + + if (shState->config().dumpAtlas) + { + Bitmap dump(atlas); + dump.saveToFile("dumped_atlas.png"); + if (dump.hasHires()) + { + dump.getHires()->saveToFile("dumped_atlas_hires.png"); + } + } } void updateMapViewport()