Implement cropped and rescaling texture hack

This commit is contained in:
Jonas Kulla 2014-11-03 00:23:37 +01:00
parent f7a3e3c5d2
commit 9506c05ba6
3 changed files with 177 additions and 3 deletions

View File

@ -43,6 +43,7 @@
#include "filesystem.h" #include "filesystem.h"
#include "font.h" #include "font.h"
#include "eventthread.h" #include "eventthread.h"
#include "debugwriter.h"
#define GUARD_MEGA \ #define GUARD_MEGA \
{ \ { \
@ -100,10 +101,20 @@ struct BitmapPrivate
* ourselves the expensive blending calculation */ * ourselves the expensive blending calculation */
pixman_region16_t tainted; pixman_region16_t tainted;
bool isCrop;
CropTexture cropTex;
TEX::ID cropTexTex;
bool isResized;
Vec2i resizedSize;
TEX::ID resTex;
BitmapPrivate(Bitmap *self) BitmapPrivate(Bitmap *self)
: self(self), : self(self),
megaSurface(0), megaSurface(0),
surface(0) surface(0),
isCrop(false),
isResized(false)
{ {
format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888); format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
@ -167,7 +178,10 @@ struct BitmapPrivate
void bindTexture(ShaderBase &shader) void bindTexture(ShaderBase &shader)
{ {
TEX::bind(gl.tex); 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() void bindFBO()
@ -242,14 +256,114 @@ Bitmap::Bitmap(const char *filename)
throw Exception(Exception::SDLError, "Error loading image '%s': %s", throw Exception(Exception::SDLError, "Error loading image '%s': %s",
filename, SDL_GetError()); filename, SDL_GetError());
bool isCrop = false;
CropTexture cropTex;
const std::vector<CropTexture> &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); 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 */ /* Mega surface */
p = new BitmapPrivate(this); p = new BitmapPrivate(this);
p->megaSurface = imgSurf; 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 else
{ {
/* Regular surface */ /* Regular surface */
@ -274,6 +388,7 @@ Bitmap::Bitmap(const char *filename)
SDL_FreeSurface(imgSurf); SDL_FreeSurface(imgSurf);
} }
p->isCrop = isCrop;
p->addTaintedArea(rect()); p->addTaintedArea(rect());
} }
@ -1230,6 +1345,10 @@ void Bitmap::releaseResources()
{ {
if (p->megaSurface) if (p->megaSurface)
SDL_FreeSurface(p->megaSurface); SDL_FreeSurface(p->megaSurface);
else if (p->isCrop)
TEX::del(p->cropTexTex);
else if (p->isResized)
TEX::del(p->resTex);
else else
shState->texPool().release(p->gl); shState->texPool().release(p->gl);

View File

@ -261,6 +261,53 @@ void Config::read(int argc, char *argv[])
customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str()); customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str());
commonDataPath = prefPath(".", "mkxp"); 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) static std::string baseName(const std::string &path)

View File

@ -25,6 +25,12 @@
#include <string> #include <string>
#include <vector> #include <vector>
struct CropTexture
{
std::string filename;
int w, h;
};
struct Config struct Config
{ {
int rgssVersion; int rgssVersion;
@ -89,6 +95,8 @@ struct Config
std::string customDataPath; std::string customDataPath;
std::string commonDataPath; std::string commonDataPath;
std::vector<CropTexture> cropTexs;
Config(); Config();
void read(int argc, char *argv[]); void read(int argc, char *argv[]);