From 9506c05ba62ce91049f8d4c36c4dae94dc31560b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Mon, 3 Nov 2014 00:23:37 +0100 Subject: [PATCH] Implement cropped and rescaling texture hack --- src/bitmap.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++++-- src/config.cpp | 47 +++++++++++++++++++ src/config.h | 8 ++++ 3 files changed, 177 insertions(+), 3 deletions(-) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index fa499ad..dfc8ba2 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -43,6 +43,7 @@ #include "filesystem.h" #include "font.h" #include "eventthread.h" +#include "debugwriter.h" #define GUARD_MEGA \ { \ @@ -100,10 +101,20 @@ struct BitmapPrivate * ourselves the expensive blending calculation */ pixman_region16_t tainted; + bool isCrop; + CropTexture cropTex; + TEX::ID cropTexTex; + + bool isResized; + Vec2i resizedSize; + TEX::ID resTex; + BitmapPrivate(Bitmap *self) : self(self), megaSurface(0), - surface(0) + surface(0), + isCrop(false), + isResized(false) { format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888); @@ -167,7 +178,10 @@ struct BitmapPrivate void bindTexture(ShaderBase &shader) { TEX::bind(gl.tex); - shader.setTexSize(Vec2i(gl.width, gl.height)); + if (isCrop) + shader.setTexSize(Vec2i(cropTex.w, cropTex.h)); + else + shader.setTexSize(Vec2i(gl.width, gl.height)); } void bindFBO() @@ -242,14 +256,114 @@ Bitmap::Bitmap(const char *filename) throw Exception(Exception::SDLError, "Error loading image '%s': %s", filename, SDL_GetError()); + bool isCrop = false; + CropTexture cropTex; + const std::vector &crops = shState->config().cropTexs; + for (size_t i = 0; i < crops.size(); ++i) + { + if (crops[i].filename != filename) + continue; + + Debug() << "Loading cropped texture:" << filename << crops[i].w << crops[i].h; + isCrop = true; + cropTex = crops[i]; + break; + } + p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888); - if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize) + SDL_SetSurfaceBlendMode(imgSurf, SDL_BLENDMODE_NONE); + + // Try catching too large images, while trying NOT to catch giant tilesets + if ((imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize) && imgSurf->w != 256 && !isCrop) + { + Vec2i resSize(imgSurf->w/2, imgSurf->h/2); + while (resSize.x > glState.caps.maxTexSize || resSize.y > glState.caps.maxTexSize) + { + resSize.x = resSize.x/2; + resSize.y = resSize.y/2; + } + + Debug() << "Loading image" << filename << "at resolution" + << resSize.x << resSize.y << "down from" << imgSurf->w << imgSurf->h; + + // Use texture with halved dimensions instead + p = new BitmapPrivate(this); + p->isResized = true; + p->resizedSize = resSize; + + int bpp; Uint32 rm, gm, bm, am; + SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &rm, &gm, &bm, &am); + SDL_Surface *resImg = SDL_CreateRGBSurface(0, resSize.x, resSize.y, bpp, rm, gm, bm, am); + + SDL_BlitScaled(imgSurf, 0, resImg, 0); + + TEX::ID tex = TEX::gen(); + TEX::bind(tex); + TEX::uploadImage(resImg->w, resImg->h, resImg->pixels, GL_RGBA); + TEX::setRepeat(false); + TEX::setSmooth(true); + + p->resTex = tex; + p->gl.tex = tex; + p->gl.width = imgSurf->w; + p->gl.height = imgSurf->h; + + SDL_FreeSurface(imgSurf); + SDL_FreeSurface(resImg); + } + else if ((imgSurf->h > glState.caps.maxTexSize) && !isCrop) // Too large tilesets go here { /* Mega surface */ p = new BitmapPrivate(this); p->megaSurface = imgSurf; } + else if (isCrop) + { + p = new BitmapPrivate(this); + p->cropTex = cropTex; + + Vec2i resSize(cropTex.w, cropTex.h); + while (resSize.x > glState.caps.maxTexSize || resSize.y > glState.caps.maxTexSize) + { + resSize.x = resSize.x/2; + resSize.y = resSize.y/2; + } + + TEX::ID tex = TEX::gen(); + TEX::bind(tex); + TEX::setRepeat(false); + TEX::setSmooth(false); + + if (resSize == Vec2i(cropTex.w, cropTex.h)) + { + TEX::allocEmpty(cropTex.w, cropTex.h); + GLMeta::subRectImageUpload(imgSurf->w, 0, 0, 0, 0, cropTex.w, cropTex.h, imgSurf, GL_RGBA); + GLMeta::subRectImageEnd(); + } + else + { + int bpp; Uint32 rm, gm, bm, am; + SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &rm, &gm, &bm, &am); + SDL_Surface *resImg = SDL_CreateRGBSurface(0, resSize.x, resSize.y, bpp, rm, gm, bm, am); + + IntRect src(0, 0, cropTex.w, cropTex.h); + SDL_BlitScaled(imgSurf, &src, resImg, 0); + TEX::uploadImage(resSize.x, resSize.y, resImg->pixels, GL_RGBA); + + SDL_FreeSurface(resImg); + + Debug() << "Loading cropped image" << filename << "at resolution" + << resSize.x << resSize.y << "down from" << cropTex.w << cropTex.h; + } + + p->cropTexTex = tex; + + p->gl.tex = tex; + p->gl.width = imgSurf->w; + p->gl.height = imgSurf->h; + SDL_FreeSurface(imgSurf); + } else { /* Regular surface */ @@ -274,6 +388,7 @@ Bitmap::Bitmap(const char *filename) SDL_FreeSurface(imgSurf); } + p->isCrop = isCrop; p->addTaintedArea(rect()); } @@ -1230,6 +1345,10 @@ void Bitmap::releaseResources() { if (p->megaSurface) SDL_FreeSurface(p->megaSurface); + else if (p->isCrop) + TEX::del(p->cropTexTex); + else if (p->isResized) + TEX::del(p->resTex); else shState->texPool().release(p->gl); diff --git a/src/config.cpp b/src/config.cpp index 160e66b..b7f22ab 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -261,6 +261,53 @@ void Config::read(int argc, char *argv[]) customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str()); commonDataPath = prefPath(".", "mkxp"); + + /* parse cropped textures config */ + std::string cropTexFile; + if (!readFile("croptextures", cropTexFile)) + { + Debug() << "Couldn't read croptextures config file"; + return; + } + + size_t lineStart = 0; + bool atEnd = false; + + while (!atEnd) + { + CropTexture tex; + + size_t fnEnd = cropTexFile.find('"', lineStart+1); + size_t numSep = cropTexFile.find(' ', fnEnd+2); + size_t lineEnd = cropTexFile.find('\n', numSep); + + if (fnEnd == std::string::npos || numSep == std::string::npos) + break; + + if (lineEnd == std::string::npos) + { + lineEnd = cropTexFile.size(); + atEnd = true; + } + + try + { + tex.filename = cropTexFile.substr(lineStart+1, fnEnd-(lineStart+1)); + tex.w = atoi(cropTexFile.substr(fnEnd+2, numSep-(fnEnd+2)).c_str()); + tex.h = atoi(cropTexFile.substr(numSep+1, lineEnd-(numSep+1)).c_str()); + } + catch (...) + { + Debug() << "Couldn't parse croptextures config file"; + cropTexs.clear(); + break; + } + + cropTexs.push_back(tex); + Debug() << "Parsed:" << tex.filename << tex.w << tex.h; + + lineStart = lineEnd+1; + } } static std::string baseName(const std::string &path) diff --git a/src/config.h b/src/config.h index e7eb357..2f6635e 100644 --- a/src/config.h +++ b/src/config.h @@ -25,6 +25,12 @@ #include #include +struct CropTexture +{ + std::string filename; + int w, h; +}; + struct Config { int rgssVersion; @@ -89,6 +95,8 @@ struct Config std::string customDataPath; std::string commonDataPath; + std::vector cropTexs; + Config(); void read(int argc, char *argv[]);