mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-03-28 14:56:22 +01:00
Merge 1c18e01ea3
into 68a344afcf
This commit is contained in:
commit
4b1745de13
6 changed files with 180 additions and 18 deletions
|
@ -6,7 +6,10 @@ uniform lowp vec4 tone;
|
|||
uniform lowp float opacity;
|
||||
uniform lowp vec4 color;
|
||||
|
||||
uniform float bushDepth;
|
||||
uniform bool bushY;
|
||||
uniform bool bushUnder;
|
||||
uniform float bushSlope;
|
||||
uniform float bushIntercept;
|
||||
uniform lowp float bushOpacity;
|
||||
|
||||
uniform sampler2D pattern;
|
||||
|
@ -102,8 +105,9 @@ void main()
|
|||
}
|
||||
|
||||
/* Apply bush alpha by mathematical if */
|
||||
lowp float underBush = float(v_texCoord.y < bushDepth);
|
||||
frag.a *= clamp(bushOpacity + underBush, 0.0, 1.0);
|
||||
bool underBush = (float(bushY) * v_texCoord.y + float(!bushY) * v_texCoord.x) <
|
||||
(bushSlope * (float(bushY) * v_texCoord.x + float(!bushY) * v_texCoord.y) + bushIntercept);
|
||||
frag.a *= clamp(bushOpacity + float(underBush == bushUnder), 0.0, 1.0);
|
||||
|
||||
gl_FragColor = frag;
|
||||
}
|
||||
|
|
|
@ -532,7 +532,10 @@ SpriteShader::SpriteShader()
|
|||
GET_U(tone);
|
||||
GET_U(color);
|
||||
GET_U(opacity);
|
||||
GET_U(bushDepth);
|
||||
GET_U(bushY);
|
||||
GET_U(bushUnder);
|
||||
GET_U(bushSlope);
|
||||
GET_U(bushIntercept);
|
||||
GET_U(bushOpacity);
|
||||
GET_U(pattern);
|
||||
GET_U(patternBlendType);
|
||||
|
@ -565,9 +568,12 @@ void SpriteShader::setOpacity(float value)
|
|||
gl.Uniform1f(u_opacity, value);
|
||||
}
|
||||
|
||||
void SpriteShader::setBushDepth(float value)
|
||||
void SpriteShader::setBushDepth(bool bushY, bool bushUnder, float bushSlope, float bushIntercept)
|
||||
{
|
||||
gl.Uniform1f(u_bushDepth, value);
|
||||
gl.Uniform1f(u_bushY, bushY);
|
||||
gl.Uniform1f(u_bushUnder, bushUnder);
|
||||
gl.Uniform1f(u_bushSlope, bushSlope);
|
||||
gl.Uniform1f(u_bushIntercept, bushIntercept);
|
||||
}
|
||||
|
||||
void SpriteShader::setBushOpacity(float value)
|
||||
|
|
|
@ -190,7 +190,7 @@ public:
|
|||
void setTone(const Vec4 &value);
|
||||
void setColor(const Vec4 &value);
|
||||
void setOpacity(float value);
|
||||
void setBushDepth(float value);
|
||||
void setBushDepth(bool bushY, bool bushUnder, float bushSlope, float bushIntercept);
|
||||
void setBushOpacity(float value);
|
||||
void setPattern(const TEX::ID pattern, const Vec2 &dimensions);
|
||||
void setPatternBlendType(int blendType);
|
||||
|
@ -202,7 +202,8 @@ public:
|
|||
void setInvert(bool value);
|
||||
|
||||
private:
|
||||
GLint u_spriteMat, u_tone, u_opacity, u_color, u_bushDepth, u_bushOpacity, u_pattern, u_renderPattern,
|
||||
GLint u_spriteMat, u_tone, u_opacity, u_color,
|
||||
u_bushY, u_bushUnder, u_bushSlope, u_bushIntercept, u_bushOpacity, u_pattern, u_renderPattern,
|
||||
u_patternBlendType, u_patternSizeInv, u_patternTile, u_patternOpacity, u_patternScroll, u_patternZoom, u_invert;
|
||||
};
|
||||
|
||||
|
|
|
@ -163,4 +163,22 @@ private:
|
|||
bool dirty;
|
||||
};
|
||||
|
||||
// Rotates a point around an origin point, counter-clockwise
|
||||
// https://stackoverflow.com/a/2259502
|
||||
static inline Vec2 rotate_point(const Vec2 &origin, const float &angle, Vec2 point)
|
||||
{
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
// translate point back to origin:
|
||||
point.x -= origin.x;
|
||||
point.y -= origin.y;
|
||||
// rotate point
|
||||
float xnew = point.x * c - point.y * s;
|
||||
float ynew = point.x * s + point.y * c;
|
||||
// translate point back:
|
||||
point.x = xnew + origin.x;
|
||||
point.y = ynew + origin.y;
|
||||
return point;
|
||||
}
|
||||
|
||||
#endif // TRANSFORM_H
|
||||
|
|
|
@ -45,6 +45,12 @@
|
|||
|
||||
#include "sigslot/signal.hpp"
|
||||
|
||||
static float fwrap(float value, float range)
|
||||
{
|
||||
float res = fmod(value, range);
|
||||
return res < 0 ? res + range : res;
|
||||
}
|
||||
|
||||
struct SpritePrivate
|
||||
{
|
||||
Bitmap *bitmap;
|
||||
|
@ -60,6 +66,11 @@ struct SpritePrivate
|
|||
bool mirrored;
|
||||
int bushDepth;
|
||||
float efBushDepth;
|
||||
float bushSlope;
|
||||
float bushIntercept;
|
||||
bool bushY;
|
||||
bool bushUnder;
|
||||
bool bushDirty;
|
||||
NormValue bushOpacity;
|
||||
NormValue opacity;
|
||||
BlendType blendType;
|
||||
|
@ -106,7 +117,11 @@ struct SpritePrivate
|
|||
srcRect(&tmp.rect),
|
||||
mirrored(false),
|
||||
bushDepth(0),
|
||||
efBushDepth(0),
|
||||
bushSlope(0),
|
||||
bushIntercept(1.0f),
|
||||
bushY(true),
|
||||
bushUnder(true),
|
||||
bushDirty(true),
|
||||
bushOpacity(128),
|
||||
opacity(255),
|
||||
blendType(BlendNormal),
|
||||
|
@ -155,12 +170,97 @@ struct SpritePrivate
|
|||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
/* Calculate effective (normalized) bush depth */
|
||||
float texBushDepth = (bushDepth / trans.getScale().y) -
|
||||
(srcRect->y + srcRect->height) +
|
||||
bitmap->height();
|
||||
bushDirty = false;
|
||||
|
||||
efBushDepth = 1.0f - texBushDepth / bitmap->height();
|
||||
if (bushDepth <= 0)
|
||||
{
|
||||
bushSlope = 0;
|
||||
bushIntercept = 1.0f;
|
||||
bushY = true;
|
||||
bushUnder = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Invert the angle if mirrored
|
||||
int mirror = mirrored ? -1 : 1;
|
||||
float angle = fwrap(mirror * trans.getRotation(), 360);
|
||||
|
||||
// If it's not rotated, then we can skip all of those other calculations.
|
||||
if (angle == 0.0f)
|
||||
{
|
||||
bushSlope = 0;
|
||||
bushIntercept = (srcRect->y + srcRect->height - (bushDepth / trans.getScale().y)) / bitmap->height();
|
||||
bushY = true;
|
||||
bushUnder = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the slope in segments of 45deg, so I don't have to deal with near-infinite slopes
|
||||
bushSlope = tan(abs(fwrap(angle - 45, 90) - 45) * M_PI / 180.0f);
|
||||
// Manually set negative slopes
|
||||
bushSlope *= fwrap(angle, 180) > 90 ? -1 : 1;
|
||||
|
||||
|
||||
// If the angle is within 45deg of 90deg or 270deg we use the x-axis instead
|
||||
// Additionally, since the shader's coordinates are percentage based, we need to make
|
||||
// the slope relative to the scaled bitmap's ratio
|
||||
float scaledW = bitmap->width() * trans.getScale().x;
|
||||
float scaledH = bitmap->height() * trans.getScale().y;
|
||||
if (fwrap(angle + 45, 180) < 90)
|
||||
{
|
||||
bushY = true;
|
||||
bushSlope = bushSlope * scaledW / scaledH;
|
||||
}
|
||||
else
|
||||
{
|
||||
bushY = false;
|
||||
bushSlope = bushSlope * scaledH / scaledW;
|
||||
}
|
||||
// Invert the check when we switch from the y-axis to the x-axis
|
||||
bushUnder = angle < 45 || angle >= 225;
|
||||
|
||||
// Zoom and rotate the srcRect
|
||||
FloatRect src = srcRect->toFloatRect();
|
||||
// Mirrored sprites whose src_rects extend beyond the bounds of the bitmap
|
||||
// need to swap the overflows
|
||||
if (mirrored)
|
||||
{
|
||||
float overflowX = std::max(src.x + src.w - bitmap->width(), 0.0f);
|
||||
|
||||
if (src.x < 0)
|
||||
{
|
||||
src.x = 0;
|
||||
}
|
||||
src.x -= overflowX;
|
||||
}
|
||||
src.x *= trans.getScale().x;
|
||||
src.y *= trans.getScale().y;
|
||||
src.w *= trans.getScale().x;
|
||||
src.h *= trans.getScale().y;
|
||||
|
||||
// We use a "left-handed" coordinate system, with positive y values being below the x-axis,
|
||||
// so we need to use the negative of the angle to get the proper y values.
|
||||
float rotation = -angle * M_PI / 180.0f;
|
||||
|
||||
// p1 doesn't change, so we can skip rotating it
|
||||
Vec2 p1 = src.topLeft();
|
||||
Vec2 p2 = rotate_point(p1, rotation, src.topRight());
|
||||
Vec2 p3 = rotate_point(p1, rotation, src.bottomLeft());
|
||||
Vec2 p4 = rotate_point(p1, rotation, src.bottomRight());
|
||||
|
||||
// Find the upper boundary of the bush effect and rotate it back.
|
||||
// The rotated slope is a horizontal line, so any x value will work.
|
||||
Vec2 point(0, std::max(std::max(p1.y, p2.y), std::max(p3.y, p4.y)) - bushDepth);
|
||||
point = rotate_point(p1, -rotation, point);
|
||||
|
||||
// Unzoom the point and convert it into a percentage
|
||||
point.y = point.y / trans.getScale().y / bitmap->height();
|
||||
point.x = point.x / trans.getScale().x / bitmap->width();
|
||||
|
||||
if (bushY)
|
||||
bushIntercept = (point.y - (bushSlope * point.x));
|
||||
else
|
||||
bushIntercept = (point.x - (bushSlope * point.y));
|
||||
}
|
||||
|
||||
void onSrcRectChange()
|
||||
|
@ -197,7 +297,7 @@ struct SpritePrivate
|
|||
}
|
||||
|
||||
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
||||
recomputeBushDepth();
|
||||
bushDirty = true;
|
||||
|
||||
wave.dirty = true;
|
||||
}
|
||||
|
@ -341,6 +441,9 @@ struct SpritePrivate
|
|||
}
|
||||
|
||||
updateVisibility();
|
||||
|
||||
if (isVisible && bushDirty)
|
||||
recomputeBushDepth();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -481,7 +584,7 @@ void Sprite::setZoomY(float value)
|
|||
return;
|
||||
|
||||
p->trans.setScale(Vec2(getZoomX(), value));
|
||||
p->recomputeBushDepth();
|
||||
p->bushDirty = true;
|
||||
|
||||
if (rgssVer >= 2)
|
||||
p->wave.dirty = true;
|
||||
|
@ -495,6 +598,8 @@ void Sprite::setAngle(float value)
|
|||
return;
|
||||
|
||||
p->trans.setRotation(value);
|
||||
|
||||
p->bushDirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setMirror(bool mirrored)
|
||||
|
@ -516,7 +621,7 @@ void Sprite::setBushDepth(int value)
|
|||
return;
|
||||
|
||||
p->bushDepth = value;
|
||||
p->recomputeBushDepth();
|
||||
p->bushDirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setBlendType(int type)
|
||||
|
@ -680,7 +785,7 @@ void Sprite::draw()
|
|||
|
||||
shader.setTone(p->tone->norm);
|
||||
shader.setOpacity(p->opacity.norm);
|
||||
shader.setBushDepth(p->efBushDepth);
|
||||
shader.setBushDepth(p->bushY, p->bushUnder, p->bushSlope, p->bushIntercept);
|
||||
shader.setBushOpacity(p->bushOpacity.norm);
|
||||
|
||||
if (p->pattern && p->patternOpacity > 0) {
|
||||
|
|
28
tests/sprite-bush-rotation/spriteBushRotation.rb
Normal file
28
tests/sprite-bush-rotation/spriteBushRotation.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
b = Bitmap.new(400, 400)
|
||||
s = Sprite.new
|
||||
s.bitmap = b
|
||||
|
||||
s.src_rect = Rect.new(100, 100, 200, 200)
|
||||
b.gradient_fill_rect(s.src_rect, Color.new(255,0,0), Color.new(0,0,255))
|
||||
|
||||
s.x = Graphics.width / 2
|
||||
s.y = Graphics.height / 2
|
||||
s.ox = s.src_rect.width / 2
|
||||
s.oy = s.src_rect.height / 2
|
||||
|
||||
s.bush_depth = 100
|
||||
s.bush_opacity = 128
|
||||
|
||||
s.zoom_x = 2
|
||||
|
||||
def rotate(s)
|
||||
seconds_per_rotation = 12
|
||||
s.angle += (360.0 / Graphics.frame_rate) / seconds_per_rotation
|
||||
end
|
||||
|
||||
loop {
|
||||
Graphics.update
|
||||
Input.update
|
||||
|
||||
rotate(s)
|
||||
}
|
Loading…
Add table
Reference in a new issue