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,
|
||||
|
||||
|
||||
// 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
|
||||
// is downscaled (requires "smoothScalingDown": 1)
|
||||
// or bitmaps are downscaled (requires
|
||||
// "smoothScalingDown": 1 or "bitmapSmoothScalingDown": 1)
|
||||
// (default: false)
|
||||
//
|
||||
// "smoothScalingMipmaps": false,
|
||||
|
|
|
@ -136,6 +136,8 @@ void Config::read(int argc, char *argv[]) {
|
|||
{"fixedAspectRatio", true},
|
||||
{"smoothScaling", 0},
|
||||
{"smoothScalingDown", 0},
|
||||
{"bitmapSmoothScaling", 0},
|
||||
{"bitmapSmoothScalingDown", 0},
|
||||
{"smoothScalingMipmaps", false},
|
||||
{"bicubicSharpness", 100},
|
||||
#ifdef MKXPZ_SSL
|
||||
|
@ -272,6 +274,8 @@ try { exp } catch (...) {}
|
|||
SET_OPT(fixedAspectRatio, boolean);
|
||||
SET_OPT(smoothScaling, integer);
|
||||
SET_OPT(smoothScalingDown, integer);
|
||||
SET_OPT(bitmapSmoothScaling, integer);
|
||||
SET_OPT(bitmapSmoothScalingDown, integer);
|
||||
SET_OPT(smoothScalingMipmaps, boolean);
|
||||
SET_OPT(bicubicSharpness, integer);
|
||||
#ifdef MKXPZ_SSL
|
||||
|
|
|
@ -45,6 +45,8 @@ struct Config {
|
|||
bool fixedAspectRatio;
|
||||
int smoothScaling;
|
||||
int smoothScalingDown;
|
||||
int bitmapSmoothScaling;
|
||||
int bitmapSmoothScalingDown;
|
||||
bool smoothScalingMipmaps;
|
||||
int bicubicSharpness;
|
||||
#ifdef MKXPZ_SSL
|
||||
|
|
|
@ -337,7 +337,7 @@ struct BitmapPrivate
|
|||
void bindTexture(ShaderBase &shader, bool substituteLoresSize = true)
|
||||
{
|
||||
if (selfHires) {
|
||||
selfHires->bindTex(shader);
|
||||
selfHires->bindTex(shader, substituteLoresSize);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2566,11 +2566,11 @@ bool Bitmap::getLooping() const
|
|||
return p->animation.loop;
|
||||
}
|
||||
|
||||
void Bitmap::bindTex(ShaderBase &shader)
|
||||
void Bitmap::bindTex(ShaderBase &shader, bool substituteLoresSize)
|
||||
{
|
||||
// Hires mode is handled by p->bindTexture.
|
||||
|
||||
p->bindTexture(shader);
|
||||
p->bindTexture(shader, substituteLoresSize);
|
||||
}
|
||||
|
||||
void Bitmap::taintArea(const IntRect &rect)
|
||||
|
|
|
@ -158,7 +158,7 @@ public:
|
|||
|
||||
/* Binds the backing texture and sets the correct
|
||||
* texture size uniform in shader */
|
||||
void bindTex(ShaderBase &shader);
|
||||
void bindTex(ShaderBase &shader, bool substituteLoresSize = true);
|
||||
|
||||
/* Adds 'rect' to tainted area */
|
||||
void taintArea(const IntRect &rect);
|
||||
|
|
|
@ -385,6 +385,55 @@ void SimpleSpriteShader::setSpriteMat(const float value[16])
|
|||
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()
|
||||
{
|
||||
|
|
|
@ -137,7 +137,7 @@ public:
|
|||
|
||||
void setSpriteMat(const float value[16]);
|
||||
|
||||
private:
|
||||
protected:
|
||||
GLint u_spriteMat;
|
||||
};
|
||||
|
||||
|
@ -365,6 +365,39 @@ protected:
|
|||
};
|
||||
#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 */
|
||||
struct ShaderSet
|
||||
{
|
||||
|
@ -390,6 +423,11 @@ struct ShaderSet
|
|||
Lanczos3Shader lanczos3;
|
||||
#ifdef MKXPZ_SSL
|
||||
XbrzShader xbrz;
|
||||
#endif
|
||||
Lanczos3SpriteShader lanczos3Sprite;
|
||||
BicubicSpriteShader bicubicSprite;
|
||||
#ifdef MKXPZ_SSL
|
||||
XbrzSpriteShader xbrzSprite;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "sharedstate.h"
|
||||
#include "bitmap.h"
|
||||
#include "debugwriter.h"
|
||||
#include "config.h"
|
||||
#include "etc.h"
|
||||
#include "etc-internal.h"
|
||||
#include "util.h"
|
||||
|
@ -156,16 +157,34 @@ struct SpritePrivate
|
|||
{
|
||||
FloatRect rect = srcRect->toFloatRect();
|
||||
Vec2i bmSize;
|
||||
Vec2i bmSizeHires;
|
||||
|
||||
if (!nullOrDisposed(bitmap))
|
||||
{
|
||||
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
|
||||
* the bitmap bounds */
|
||||
rect.w = clamp<int>(rect.w, 0, bmSize.x-rect.x);
|
||||
rect.h = clamp<int>(rect.h, 0, bmSize.y-rect.y);
|
||||
|
||||
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));
|
||||
recomputeBushDepth();
|
||||
|
@ -592,6 +611,8 @@ void Sprite::draw()
|
|||
p->invert ||
|
||||
(p->pattern && !p->pattern->isDisposed());
|
||||
|
||||
int scalingMethod = NearestNeighbor;
|
||||
|
||||
if (renderEffect)
|
||||
{
|
||||
SpriteShader &shader = shState->shaders().sprite;
|
||||
|
@ -644,6 +665,84 @@ void Sprite::draw()
|
|||
base = &shader;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sourceWidthHires = p->bitmap->hasHires() ? p->bitmap->getHires()->width() : p->bitmap->width();
|
||||
int sourceHeightHires = p->bitmap->hasHires() ? p->bitmap->getHires()->height() : p->bitmap->height();
|
||||
|
||||
double framebufferScalingFactor = shState->config().enableHires ? shState->config().framebufferScalingFactor : 1.0;
|
||||
|
||||
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();
|
||||
|
@ -652,16 +751,30 @@ void Sprite::draw()
|
|||
shader.applyViewportProj();
|
||||
base = &shader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
p->wave.qArray.draw();
|
||||
else
|
||||
p->quad.draw();
|
||||
|
||||
TEX::setSmooth(false);
|
||||
|
||||
glState.blendMode.pop();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue