mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-04-21 21:52:04 +02:00
Implement smooth scaling for simple sprites
This commit is contained in:
parent
ef822d1806
commit
58d7ec8519
8 changed files with 235 additions and 14 deletions
17
mkxp.json
17
mkxp.json
|
@ -96,8 +96,23 @@
|
||||||
// "smoothScalingDown": 0,
|
// "smoothScalingDown": 0,
|
||||||
|
|
||||||
|
|
||||||
|
// Apply smooth interpolation when bitmaps
|
||||||
|
// are upscaled (same values as smoothScaling)
|
||||||
|
// (default: 0)
|
||||||
|
//
|
||||||
|
// "bitmapSmoothScaling": 0,
|
||||||
|
|
||||||
|
|
||||||
|
// Apply smooth interpolation when bitmaps
|
||||||
|
// are downscaled (same values as smoothScaling)
|
||||||
|
// (default: 0)
|
||||||
|
//
|
||||||
|
// "bitmapSmoothScalingDown": 0,
|
||||||
|
|
||||||
|
|
||||||
// Apply mipmap interpolation when game screen
|
// Apply mipmap interpolation when game screen
|
||||||
// is downscaled (requires "smoothScalingDown": 1)
|
// or bitmaps are downscaled (requires
|
||||||
|
// "smoothScalingDown": 1 or "bitmapSmoothScalingDown": 1)
|
||||||
// (default: false)
|
// (default: false)
|
||||||
//
|
//
|
||||||
// "smoothScalingMipmaps": false,
|
// "smoothScalingMipmaps": false,
|
||||||
|
|
|
@ -136,6 +136,8 @@ void Config::read(int argc, char *argv[]) {
|
||||||
{"fixedAspectRatio", true},
|
{"fixedAspectRatio", true},
|
||||||
{"smoothScaling", 0},
|
{"smoothScaling", 0},
|
||||||
{"smoothScalingDown", 0},
|
{"smoothScalingDown", 0},
|
||||||
|
{"bitmapSmoothScaling", 0},
|
||||||
|
{"bitmapSmoothScalingDown", 0},
|
||||||
{"smoothScalingMipmaps", false},
|
{"smoothScalingMipmaps", false},
|
||||||
{"bicubicSharpness", 100},
|
{"bicubicSharpness", 100},
|
||||||
#ifdef MKXPZ_SSL
|
#ifdef MKXPZ_SSL
|
||||||
|
@ -272,6 +274,8 @@ try { exp } catch (...) {}
|
||||||
SET_OPT(fixedAspectRatio, boolean);
|
SET_OPT(fixedAspectRatio, boolean);
|
||||||
SET_OPT(smoothScaling, integer);
|
SET_OPT(smoothScaling, integer);
|
||||||
SET_OPT(smoothScalingDown, integer);
|
SET_OPT(smoothScalingDown, integer);
|
||||||
|
SET_OPT(bitmapSmoothScaling, integer);
|
||||||
|
SET_OPT(bitmapSmoothScalingDown, integer);
|
||||||
SET_OPT(smoothScalingMipmaps, boolean);
|
SET_OPT(smoothScalingMipmaps, boolean);
|
||||||
SET_OPT(bicubicSharpness, integer);
|
SET_OPT(bicubicSharpness, integer);
|
||||||
#ifdef MKXPZ_SSL
|
#ifdef MKXPZ_SSL
|
||||||
|
|
|
@ -45,6 +45,8 @@ struct Config {
|
||||||
bool fixedAspectRatio;
|
bool fixedAspectRatio;
|
||||||
int smoothScaling;
|
int smoothScaling;
|
||||||
int smoothScalingDown;
|
int smoothScalingDown;
|
||||||
|
int bitmapSmoothScaling;
|
||||||
|
int bitmapSmoothScalingDown;
|
||||||
bool smoothScalingMipmaps;
|
bool smoothScalingMipmaps;
|
||||||
int bicubicSharpness;
|
int bicubicSharpness;
|
||||||
#ifdef MKXPZ_SSL
|
#ifdef MKXPZ_SSL
|
||||||
|
|
|
@ -337,7 +337,7 @@ struct BitmapPrivate
|
||||||
void bindTexture(ShaderBase &shader, bool substituteLoresSize = true)
|
void bindTexture(ShaderBase &shader, bool substituteLoresSize = true)
|
||||||
{
|
{
|
||||||
if (selfHires) {
|
if (selfHires) {
|
||||||
selfHires->bindTex(shader);
|
selfHires->bindTex(shader, substituteLoresSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2566,11 +2566,11 @@ bool Bitmap::getLooping() const
|
||||||
return p->animation.loop;
|
return p->animation.loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::bindTex(ShaderBase &shader)
|
void Bitmap::bindTex(ShaderBase &shader, bool substituteLoresSize)
|
||||||
{
|
{
|
||||||
// Hires mode is handled by p->bindTexture.
|
// Hires mode is handled by p->bindTexture.
|
||||||
|
|
||||||
p->bindTexture(shader);
|
p->bindTexture(shader, substituteLoresSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::taintArea(const IntRect &rect)
|
void Bitmap::taintArea(const IntRect &rect)
|
||||||
|
|
|
@ -158,7 +158,7 @@ public:
|
||||||
|
|
||||||
/* Binds the backing texture and sets the correct
|
/* Binds the backing texture and sets the correct
|
||||||
* texture size uniform in shader */
|
* texture size uniform in shader */
|
||||||
void bindTex(ShaderBase &shader);
|
void bindTex(ShaderBase &shader, bool substituteLoresSize = true);
|
||||||
|
|
||||||
/* Adds 'rect' to tainted area */
|
/* Adds 'rect' to tainted area */
|
||||||
void taintArea(const IntRect &rect);
|
void taintArea(const IntRect &rect);
|
||||||
|
|
|
@ -385,6 +385,55 @@ void SimpleSpriteShader::setSpriteMat(const float value[16])
|
||||||
gl.UniformMatrix4fv(u_spriteMat, 1, GL_FALSE, value);
|
gl.UniformMatrix4fv(u_spriteMat, 1, GL_FALSE, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BicubicSpriteShader::BicubicSpriteShader()
|
||||||
|
{
|
||||||
|
INIT_SHADER(sprite, bicubic, BicubicSpriteShader);
|
||||||
|
|
||||||
|
ShaderBase::init();
|
||||||
|
|
||||||
|
GET_U(spriteMat);
|
||||||
|
GET_U(sourceSize);
|
||||||
|
GET_U(bc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BicubicSpriteShader::setSharpness(int sharpness)
|
||||||
|
{
|
||||||
|
gl.Uniform2f(u_bc, 1.f - sharpness * 0.01f, sharpness * 0.005f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lanczos3SpriteShader::Lanczos3SpriteShader()
|
||||||
|
{
|
||||||
|
INIT_SHADER(sprite, lanczos3, Lanczos3SpriteShader);
|
||||||
|
|
||||||
|
ShaderBase::init();
|
||||||
|
|
||||||
|
GET_U(spriteMat);
|
||||||
|
GET_U(sourceSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lanczos3SpriteShader::setTexSize(const Vec2i &value)
|
||||||
|
{
|
||||||
|
ShaderBase::setTexSize(value);
|
||||||
|
gl.Uniform2f(u_sourceSize, (float)value.x, (float)value.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MKXPZ_SSL
|
||||||
|
XbrzSpriteShader::XbrzSpriteShader()
|
||||||
|
{
|
||||||
|
INIT_SHADER(sprite, xbrz, XbrzSpriteShader);
|
||||||
|
|
||||||
|
ShaderBase::init();
|
||||||
|
|
||||||
|
GET_U(spriteMat);
|
||||||
|
GET_U(sourceSize);
|
||||||
|
GET_U(targetScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XbrzSpriteShader::setTargetScale(const Vec2 &value)
|
||||||
|
{
|
||||||
|
gl.Uniform2f(u_targetScale, value.x, value.y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
AlphaSpriteShader::AlphaSpriteShader()
|
AlphaSpriteShader::AlphaSpriteShader()
|
||||||
{
|
{
|
||||||
|
|
|
@ -137,7 +137,7 @@ public:
|
||||||
|
|
||||||
void setSpriteMat(const float value[16]);
|
void setSpriteMat(const float value[16]);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
GLint u_spriteMat;
|
GLint u_spriteMat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -365,6 +365,39 @@ protected:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class Lanczos3SpriteShader : public SimpleSpriteShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Lanczos3SpriteShader();
|
||||||
|
|
||||||
|
void setTexSize(const Vec2i &value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GLint u_sourceSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BicubicSpriteShader : public Lanczos3SpriteShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BicubicSpriteShader();
|
||||||
|
|
||||||
|
void setSharpness(int sharpness);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GLint u_bc;
|
||||||
|
};
|
||||||
|
|
||||||
|
class XbrzSpriteShader : public Lanczos3SpriteShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XbrzSpriteShader();
|
||||||
|
|
||||||
|
void setTargetScale(const Vec2 &value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GLint u_targetScale;
|
||||||
|
};
|
||||||
|
|
||||||
/* Global object containing all available shaders */
|
/* Global object containing all available shaders */
|
||||||
struct ShaderSet
|
struct ShaderSet
|
||||||
{
|
{
|
||||||
|
@ -390,6 +423,11 @@ struct ShaderSet
|
||||||
Lanczos3Shader lanczos3;
|
Lanczos3Shader lanczos3;
|
||||||
#ifdef MKXPZ_SSL
|
#ifdef MKXPZ_SSL
|
||||||
XbrzShader xbrz;
|
XbrzShader xbrz;
|
||||||
|
#endif
|
||||||
|
Lanczos3SpriteShader lanczos3Sprite;
|
||||||
|
BicubicSpriteShader bicubicSprite;
|
||||||
|
#ifdef MKXPZ_SSL
|
||||||
|
XbrzSpriteShader xbrzSprite;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "sharedstate.h"
|
#include "sharedstate.h"
|
||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "debugwriter.h"
|
#include "debugwriter.h"
|
||||||
|
#include "config.h"
|
||||||
#include "etc.h"
|
#include "etc.h"
|
||||||
#include "etc-internal.h"
|
#include "etc-internal.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -156,16 +157,34 @@ struct SpritePrivate
|
||||||
{
|
{
|
||||||
FloatRect rect = srcRect->toFloatRect();
|
FloatRect rect = srcRect->toFloatRect();
|
||||||
Vec2i bmSize;
|
Vec2i bmSize;
|
||||||
|
Vec2i bmSizeHires;
|
||||||
|
|
||||||
if (!nullOrDisposed(bitmap))
|
if (!nullOrDisposed(bitmap))
|
||||||
|
{
|
||||||
bmSize = Vec2i(bitmap->width(), bitmap->height());
|
bmSize = Vec2i(bitmap->width(), bitmap->height());
|
||||||
|
if (bitmap->hasHires())
|
||||||
|
{
|
||||||
|
bmSizeHires = Vec2i(bitmap->getHires()->width(), bitmap->getHires()->height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Clamp the rectangle so it doesn't reach outside
|
/* Clamp the rectangle so it doesn't reach outside
|
||||||
* the bitmap bounds */
|
* the bitmap bounds */
|
||||||
rect.w = clamp<int>(rect.w, 0, bmSize.x-rect.x);
|
rect.w = clamp<int>(rect.w, 0, bmSize.x-rect.x);
|
||||||
rect.h = clamp<int>(rect.h, 0, bmSize.y-rect.y);
|
rect.h = clamp<int>(rect.h, 0, bmSize.y-rect.y);
|
||||||
|
|
||||||
quad.setTexRect(mirrored ? rect.hFlipped() : rect);
|
if (bmSizeHires.x && bmSizeHires.y && bmSize.x && bmSize.y)
|
||||||
|
{
|
||||||
|
FloatRect rectHires(rect.x * bmSizeHires.x / bmSize.x,
|
||||||
|
rect.y * bmSizeHires.y / bmSize.y,
|
||||||
|
rect.w * bmSizeHires.x / bmSize.x,
|
||||||
|
rect.h * bmSizeHires.y / bmSize.y);
|
||||||
|
quad.setTexRect(mirrored ? rectHires.hFlipped() : rectHires);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quad.setTexRect(mirrored ? rect.hFlipped() : rect);
|
||||||
|
}
|
||||||
|
|
||||||
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
||||||
recomputeBushDepth();
|
recomputeBushDepth();
|
||||||
|
@ -592,6 +611,8 @@ void Sprite::draw()
|
||||||
p->invert ||
|
p->invert ||
|
||||||
(p->pattern && !p->pattern->isDisposed());
|
(p->pattern && !p->pattern->isDisposed());
|
||||||
|
|
||||||
|
int scalingMethod = NearestNeighbor;
|
||||||
|
|
||||||
if (renderEffect)
|
if (renderEffect)
|
||||||
{
|
{
|
||||||
SpriteShader &shader = shState->shaders().sprite;
|
SpriteShader &shader = shState->shaders().sprite;
|
||||||
|
@ -645,23 +666,115 @@ void Sprite::draw()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SimpleSpriteShader &shader = shState->shaders().simpleSprite;
|
int sourceWidthHires = p->bitmap->hasHires() ? p->bitmap->getHires()->width() : p->bitmap->width();
|
||||||
shader.bind();
|
int sourceHeightHires = p->bitmap->hasHires() ? p->bitmap->getHires()->height() : p->bitmap->height();
|
||||||
|
|
||||||
shader.setSpriteMat(p->trans.getMatrix());
|
double framebufferScalingFactor = shState->config().enableHires ? shState->config().framebufferScalingFactor : 1.0;
|
||||||
shader.applyViewportProj();
|
|
||||||
base = &shader;
|
int targetWidthHires = (int)lround(framebufferScalingFactor * p->bitmap->width() * p->trans.getScale().x);
|
||||||
|
int targetHeightHires = (int)lround(framebufferScalingFactor * p->bitmap->height() * p->trans.getScale().y);
|
||||||
|
|
||||||
|
int scaleIsSpecial = UpScale;
|
||||||
|
|
||||||
|
if (targetWidthHires == sourceWidthHires && targetHeightHires == sourceHeightHires)
|
||||||
|
{
|
||||||
|
scaleIsSpecial = SameScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetWidthHires < sourceWidthHires && targetHeightHires < sourceHeightHires)
|
||||||
|
{
|
||||||
|
scaleIsSpecial = DownScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (scaleIsSpecial)
|
||||||
|
{
|
||||||
|
case SameScale:
|
||||||
|
scalingMethod = NearestNeighbor;
|
||||||
|
break;
|
||||||
|
case DownScale:
|
||||||
|
scalingMethod = shState->config().bitmapSmoothScalingDown;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scalingMethod = shState->config().bitmapSmoothScaling;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->trans.getRotation() != 0.0)
|
||||||
|
{
|
||||||
|
scalingMethod = shState->config().bitmapSmoothScaling;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (scalingMethod)
|
||||||
|
{
|
||||||
|
case Bicubic:
|
||||||
|
{
|
||||||
|
BicubicSpriteShader &shader = shState->shaders().bicubicSprite;
|
||||||
|
shader.bind();
|
||||||
|
|
||||||
|
shader.setTexSize(Vec2i(sourceWidthHires, sourceHeightHires));
|
||||||
|
shader.setSharpness(shState->config().bicubicSharpness);
|
||||||
|
shader.setSpriteMat(p->trans.getMatrix());
|
||||||
|
shader.applyViewportProj();
|
||||||
|
base = &shader;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Lanczos3:
|
||||||
|
{
|
||||||
|
Lanczos3SpriteShader &shader = shState->shaders().lanczos3Sprite;
|
||||||
|
shader.bind();
|
||||||
|
|
||||||
|
shader.setTexSize(Vec2i(sourceWidthHires, sourceHeightHires));
|
||||||
|
shader.setSpriteMat(p->trans.getMatrix());
|
||||||
|
shader.applyViewportProj();
|
||||||
|
base = &shader;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef MKXPZ_SSL
|
||||||
|
case xBRZ:
|
||||||
|
{
|
||||||
|
XbrzSpriteShader &shader = shState->shaders().xbrzSprite;
|
||||||
|
shader.bind();
|
||||||
|
|
||||||
|
shader.setTexSize(Vec2i(sourceWidthHires, sourceHeightHires));
|
||||||
|
shader.setTargetScale(Vec2((float)(shState->config().xbrzScalingFactor), (float)(shState->config().xbrzScalingFactor)));
|
||||||
|
shader.setSpriteMat(p->trans.getMatrix());
|
||||||
|
shader.applyViewportProj();
|
||||||
|
base = &shader;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
SimpleSpriteShader &shader = shState->shaders().simpleSprite;
|
||||||
|
shader.bind();
|
||||||
|
|
||||||
|
shader.setSpriteMat(p->trans.getMatrix());
|
||||||
|
shader.applyViewportProj();
|
||||||
|
base = &shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glState.blendMode.pushSet(p->blendType);
|
glState.blendMode.pushSet(p->blendType);
|
||||||
|
|
||||||
p->bitmap->bindTex(*base);
|
p->bitmap->bindTex(*base, false);
|
||||||
|
|
||||||
|
#ifdef MKXPZ_SSL
|
||||||
|
if (scalingMethod == xBRZ)
|
||||||
|
{
|
||||||
|
XbrzShader &shader = shState->shaders().xbrz;
|
||||||
|
shader.setTargetScale(Vec2((float)(shState->config().xbrzScalingFactor), (float)(shState->config().xbrzScalingFactor)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEX::setSmooth(scalingMethod == Bilinear);
|
||||||
|
|
||||||
if (p->wave.active)
|
if (p->wave.active)
|
||||||
p->wave.qArray.draw();
|
p->wave.qArray.draw();
|
||||||
else
|
else
|
||||||
p->quad.draw();
|
p->quad.draw();
|
||||||
|
|
||||||
|
TEX::setSmooth(false);
|
||||||
|
|
||||||
glState.blendMode.pop();
|
glState.blendMode.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue