mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-03-28 14:56:22 +01:00
Merge 7eec9a4774
into 68a344afcf
This commit is contained in:
commit
2b8a1d3078
2 changed files with 160 additions and 52 deletions
|
@ -68,17 +68,19 @@ public:
|
|||
|
||||
Vec2 &getPosition() { return position; }
|
||||
Vec2 &getOrigin() { return origin; }
|
||||
Vec2 &getSrcRectOrigin() { return srcRectOrigin; }
|
||||
Vec2 &getScale() { return scale; }
|
||||
float getRotation() { return rotation; }
|
||||
Vec2i &getGlobalOffset() { return offset; }
|
||||
|
||||
Vec2i getPositionI() const
|
||||
{
|
||||
return Vec2i(position.x, position.y);
|
||||
}
|
||||
|
||||
Vec2i getOriginI() const
|
||||
Vec2i getAdjustedOriginI() const
|
||||
{
|
||||
return Vec2i(origin.x, origin.y);
|
||||
return Vec2i(adjustedOrigin.x, adjustedOrigin.y);
|
||||
}
|
||||
|
||||
void setPosition(const Vec2 &value)
|
||||
|
@ -90,6 +92,18 @@ public:
|
|||
void setOrigin(const Vec2 &value)
|
||||
{
|
||||
origin = value;
|
||||
adjustedOrigin.x = origin.x + srcRectOrigin.x;
|
||||
adjustedOrigin.y = origin.y + srcRectOrigin.y;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
/* For Sprites. Set to the srcRect's position if it's negative,
|
||||
* or to 0 if it's positive. */
|
||||
void setSrcRectOrigin(const Vec2 &value)
|
||||
{
|
||||
srcRectOrigin = value;
|
||||
adjustedOrigin.x = origin.x + srcRectOrigin.x;
|
||||
adjustedOrigin.y = origin.y + srcRectOrigin.y;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
@ -139,8 +153,8 @@ private:
|
|||
float syc = scale.y * cosine;
|
||||
float sxs = scale.x * sine;
|
||||
float sys = scale.y * sine;
|
||||
float tx = -origin.x * sxc - origin.y * sys + position.x + offset.x;
|
||||
float ty = origin.x * sxs - origin.y * syc + position.y + offset.y;
|
||||
float tx = -adjustedOrigin.x * sxc - adjustedOrigin.y * sys + position.x + offset.x;
|
||||
float ty = adjustedOrigin.x * sxs - adjustedOrigin.y * syc + position.y + offset.y;
|
||||
|
||||
matrix[0] = sxc;
|
||||
matrix[1] = -sxs;
|
||||
|
@ -152,6 +166,8 @@ private:
|
|||
|
||||
Vec2 position;
|
||||
Vec2 origin;
|
||||
Vec2 srcRectOrigin;
|
||||
Vec2 adjustedOrigin;
|
||||
Vec2 scale;
|
||||
float rotation;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ struct SpritePrivate
|
|||
Transform trans;
|
||||
|
||||
Rect *srcRect;
|
||||
FloatRect adjustedSrcRect;
|
||||
sigslot::connection srcRectCon;
|
||||
|
||||
bool mirrored;
|
||||
|
@ -73,8 +74,7 @@ struct SpritePrivate
|
|||
|
||||
bool invert;
|
||||
|
||||
IntRect sceneRect;
|
||||
Vec2i sceneOrig;
|
||||
Scene::Geometry sceneGeo;
|
||||
|
||||
/* Would this sprite be visible on
|
||||
* the screen if drawn? */
|
||||
|
@ -119,8 +119,6 @@ struct SpritePrivate
|
|||
tone(&tmp.tone)
|
||||
|
||||
{
|
||||
sceneRect.x = sceneRect.y = 0;
|
||||
|
||||
updateSrcRectCon();
|
||||
|
||||
prepareCon = shState->prepareDraw.connect
|
||||
|
@ -165,7 +163,8 @@ struct SpritePrivate
|
|||
|
||||
void onSrcRectChange()
|
||||
{
|
||||
FloatRect rect = srcRect->toFloatRect();
|
||||
adjustedSrcRect = srcRect->toFloatRect();
|
||||
FloatRect &rect = adjustedSrcRect;
|
||||
Vec2i bmSize;
|
||||
Vec2i bmSizeHires;
|
||||
|
||||
|
@ -180,6 +179,22 @@ struct SpritePrivate
|
|||
|
||||
/* Clamp the rectangle so it doesn't reach outside
|
||||
* the bitmap bounds */
|
||||
if (rect.x < 0)
|
||||
{
|
||||
rect.w += rect.x;
|
||||
trans.setSrcRectOrigin(Vec2(rect.x, trans.getSrcRectOrigin().y));
|
||||
}
|
||||
else if(trans.getSrcRectOrigin().x != 0)
|
||||
trans.setSrcRectOrigin(Vec2(0, trans.getSrcRectOrigin().y));
|
||||
if (rect.y < 0)
|
||||
{
|
||||
rect.h += rect.y;
|
||||
trans.setSrcRectOrigin(Vec2(trans.getSrcRectOrigin().x, rect.y));
|
||||
}
|
||||
else if(trans.getSrcRectOrigin().y != 0)
|
||||
trans.setSrcRectOrigin(Vec2(trans.getSrcRectOrigin().x, 0));
|
||||
rect.x = clamp<int>(rect.x, 0, bmSize.x);
|
||||
rect.y = clamp<int>(rect.y, 0, bmSize.y);
|
||||
rect.w = clamp<int>(rect.w, 0, bmSize.x-rect.x);
|
||||
rect.h = clamp<int>(rect.h, 0, bmSize.y-rect.y);
|
||||
|
||||
|
@ -199,7 +214,8 @@ struct SpritePrivate
|
|||
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
||||
recomputeBushDepth();
|
||||
|
||||
wave.dirty = true;
|
||||
if (wave.active)
|
||||
wave.dirty = true;
|
||||
}
|
||||
|
||||
void updateSrcRectCon()
|
||||
|
@ -225,7 +241,7 @@ struct SpritePrivate
|
|||
{
|
||||
/* Don't do expensive wave bounding box
|
||||
* calculations */
|
||||
isVisible = true;
|
||||
isVisible = wave.qArray.quadCount != 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -240,30 +256,53 @@ struct SpritePrivate
|
|||
return;
|
||||
}
|
||||
|
||||
IntRect self;
|
||||
self.setPos(trans.getPositionI() - (trans.getOriginI() + sceneOrig));
|
||||
self.w = bitmap->width();
|
||||
self.h = bitmap->height();
|
||||
IntRect self = adjustedSrcRect;
|
||||
self.setPos(trans.getPositionI() + trans.getGlobalOffset() - trans.getAdjustedOriginI());
|
||||
|
||||
isVisible = SDL_HasIntersection(&self, &sceneRect);
|
||||
isVisible = SDL_HasIntersection(&self, &sceneGeo.rect);
|
||||
}
|
||||
|
||||
void emitWaveChunk(SVertex *&vert, float phase, int width,
|
||||
float zoomY, int chunkY, int chunkLength)
|
||||
const Vec2 &zoom, int chunkY, int chunkLength, int offsetLength)
|
||||
{
|
||||
float wavePos = phase + (chunkY / (float) wave.length) * (float) (M_PI * 2);
|
||||
float chunkX = sin(wavePos) * wave.amp;
|
||||
float wavePos = phase + ((offsetLength + chunkY) / (float) wave.length) * (float) (M_PI * 2);
|
||||
float chunkX = sin(wavePos) * wave.amp / zoom.x;
|
||||
|
||||
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
|
||||
FloatRect pos = tex;
|
||||
pos.x = chunkX;
|
||||
FloatRect pos(chunkX, chunkY / zoom.y, adjustedSrcRect.w, chunkLength / zoom.y);
|
||||
|
||||
Quad::setTexPosRect(vert, mirrored ? tex.hFlipped() : tex, pos);
|
||||
/* For some bizarre reason, combining a positive wave.amp with
|
||||
* a non-zero angle (including multiples of 360) reduces the width.
|
||||
* That being said, RGSS applies the wave effect after rotation
|
||||
* and we're applying it before, so since we're deviating anyway
|
||||
* and this behavior is weird I'm choosing to not do it. */
|
||||
//if (p->trans.getRotation())
|
||||
// pos.w *= pos.w / (pos.w + (2.0f * wave.amp));
|
||||
|
||||
FloatRect tex = mirrored ? adjustedSrcRect.hFlipped() : adjustedSrcRect;
|
||||
|
||||
tex.y += pos.y;
|
||||
tex.h = pos.h;
|
||||
if (bitmap->hasHires())
|
||||
{
|
||||
Vec2 bmSize = Vec2(bitmap->width(), bitmap->height());
|
||||
Vec2 bmSizeHires = Vec2(bitmap->getHires()->width(), bitmap->getHires()->height());
|
||||
if (bmSizeHires.x && bmSizeHires.y && bmSize.x && bmSize.y)
|
||||
{
|
||||
tex.x *= bmSizeHires.x / bmSize.x;
|
||||
tex.y *= bmSizeHires.y / bmSize.y;
|
||||
tex.w *= bmSizeHires.x / bmSize.x;
|
||||
tex.h *= bmSizeHires.y / bmSize.y;
|
||||
}
|
||||
}
|
||||
|
||||
Quad::setTexPosRect(vert, tex, pos);
|
||||
vert += 4;
|
||||
}
|
||||
|
||||
void updateWave()
|
||||
{
|
||||
wave.dirty = false;
|
||||
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
|
@ -275,11 +314,14 @@ struct SpritePrivate
|
|||
|
||||
wave.active = true;
|
||||
|
||||
int width = srcRect->width;
|
||||
int height = srcRect->height;
|
||||
float zoomY = trans.getScale().y;
|
||||
int width = adjustedSrcRect.w;
|
||||
int height = adjustedSrcRect.h;
|
||||
const Vec2 &zoom = trans.getScale();
|
||||
|
||||
if (wave.amp < -(width / 2))
|
||||
/* The length of the sprite as it appears on screen */
|
||||
int visibleLength = height * zoom.y;
|
||||
|
||||
if (!visibleLength || !width)
|
||||
{
|
||||
wave.qArray.resize(0);
|
||||
wave.qArray.commit();
|
||||
|
@ -290,24 +332,60 @@ struct SpritePrivate
|
|||
/* RMVX does this, and I have no fucking clue why */
|
||||
if (wave.amp < 0)
|
||||
{
|
||||
float scaledAmp = wave.amp / zoom.x;
|
||||
|
||||
FloatRect tex = mirrored ? adjustedSrcRect.hFlipped() : adjustedSrcRect;
|
||||
FloatRect pos(0, 0, 0, adjustedSrcRect.h);
|
||||
float mult = (scaledAmp * 2) / (float)srcRect->width;
|
||||
pos.x = -scaledAmp - (trans.getSrcRectOrigin().x * mult);
|
||||
pos.w = tex.w * (1 + mult);
|
||||
|
||||
if ((pos.w * zoom.x) < 0.5f)
|
||||
{
|
||||
wave.qArray.resize(0);
|
||||
wave.qArray.commit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (bitmap->hasHires())
|
||||
{
|
||||
Vec2 bmSize = Vec2(bitmap->width(), bitmap->height());
|
||||
Vec2 bmSizeHires = Vec2(bitmap->getHires()->width(), bitmap->getHires()->height());
|
||||
if (bmSizeHires.x && bmSizeHires.y && bmSize.x && bmSize.y)
|
||||
{
|
||||
tex.x *= bmSizeHires.x / bmSize.x;
|
||||
tex.y *= bmSizeHires.y / bmSize.y;
|
||||
tex.w *= bmSizeHires.x / bmSize.x;
|
||||
tex.h *= bmSizeHires.y / bmSize.y;
|
||||
}
|
||||
}
|
||||
wave.qArray.resize(1);
|
||||
|
||||
int x = -wave.amp;
|
||||
int w = width - x * 2;
|
||||
|
||||
FloatRect tex(x, srcRect->y, w, srcRect->height);
|
||||
|
||||
Quad::setTexPosRect(&wave.qArray.vertices[0], tex, tex);
|
||||
Quad::setTexPosRect(&wave.qArray.vertices[0], tex, pos);
|
||||
wave.qArray.commit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The length of the sprite as it appears on screen */
|
||||
int visibleLength = height * zoomY;
|
||||
/* A negative position in the srcRect affects the wave position. */
|
||||
int offsetLength = abs(trans.getSrcRectOrigin().y * zoom.y);
|
||||
|
||||
/* First chunk length (aligned to 8 pixel boundary */
|
||||
int firstLength = ((int) trans.getPosition().y) % 8;
|
||||
/* First chunk length (aligned to 8 pixel boundary) */
|
||||
int posY = (int) trans.getPosition().y - (int) (trans.getOrigin().y * zoom.y) + trans.getGlobalOffset().y;
|
||||
int firstLength = 8 - ((posY + offsetLength) % 8);
|
||||
firstLength = std::min(firstLength % 8, visibleLength);
|
||||
|
||||
/* If the position is negative, then the first chunk's alignment
|
||||
* needs a little more fiddling */
|
||||
int firstOffset;
|
||||
if (offsetLength && firstLength)
|
||||
{
|
||||
firstOffset = 8 - (posY % 8);
|
||||
firstOffset = std::min(firstOffset % 8, offsetLength);
|
||||
firstOffset += (offsetLength - firstOffset) & (~7);
|
||||
} else {
|
||||
firstOffset = 0;
|
||||
}
|
||||
|
||||
/* Amount of full 8 pixel chunks in the middle */
|
||||
int chunks = (visibleLength - firstLength) / 8;
|
||||
|
@ -321,13 +399,13 @@ struct SpritePrivate
|
|||
float phase = (wave.phase * (float) M_PI) / 180.0f;
|
||||
|
||||
if (firstLength > 0)
|
||||
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
|
||||
emitWaveChunk(vert, phase, width, zoom, 0, firstLength, firstOffset);
|
||||
|
||||
for (int i = 0; i < chunks; ++i)
|
||||
emitWaveChunk(vert, phase, width, zoomY, firstLength + i * 8, 8);
|
||||
emitWaveChunk(vert, phase, width, zoom, firstLength + i * 8, 8, offsetLength);
|
||||
|
||||
if (lastLength > 0)
|
||||
emitWaveChunk(vert, phase, width, zoomY, firstLength + chunks * 8, lastLength);
|
||||
emitWaveChunk(vert, phase, width, zoom, firstLength + chunks * 8, lastLength, offsetLength);
|
||||
|
||||
wave.qArray.commit();
|
||||
}
|
||||
|
@ -337,7 +415,6 @@ struct SpritePrivate
|
|||
if (wave.dirty)
|
||||
{
|
||||
updateWave();
|
||||
wave.dirty = false;
|
||||
}
|
||||
|
||||
updateVisibility();
|
||||
|
@ -414,7 +491,8 @@ void Sprite::setBitmap(Bitmap *bitmap)
|
|||
p->onSrcRectChange();
|
||||
p->quad.setPosRect(p->srcRect->toFloatRect());
|
||||
|
||||
p->wave.dirty = true;
|
||||
if (p->wave.active)
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setX(int value)
|
||||
|
@ -436,11 +514,11 @@ void Sprite::setY(int value)
|
|||
|
||||
p->trans.setPosition(Vec2(getX(), value));
|
||||
|
||||
if (rgssVer >= 2)
|
||||
{
|
||||
if (p->wave.active)
|
||||
p->wave.dirty = true;
|
||||
|
||||
if (rgssVer >= 2)
|
||||
setSpriteY(value);
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::setOX(int value)
|
||||
|
@ -461,6 +539,9 @@ void Sprite::setOY(int value)
|
|||
return;
|
||||
|
||||
p->trans.setOrigin(Vec2(getOX(), value));
|
||||
|
||||
if (p->wave.active)
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setZoomX(float value)
|
||||
|
@ -471,6 +552,9 @@ void Sprite::setZoomX(float value)
|
|||
return;
|
||||
|
||||
p->trans.setScale(Vec2(value, getZoomY()));
|
||||
|
||||
if (p->wave.active)
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setZoomY(float value)
|
||||
|
@ -483,7 +567,7 @@ void Sprite::setZoomY(float value)
|
|||
p->trans.setScale(Vec2(getZoomX(), value));
|
||||
p->recomputeBushDepth();
|
||||
|
||||
if (rgssVer >= 2)
|
||||
if (p->wave.active)
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
|
@ -506,6 +590,9 @@ void Sprite::setMirror(bool mirrored)
|
|||
|
||||
p->mirrored = mirrored;
|
||||
p->onSrcRectChange();
|
||||
|
||||
if (p->wave.active)
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setBushDepth(int value)
|
||||
|
@ -603,8 +690,11 @@ void Sprite::update()
|
|||
|
||||
Flashable::update();
|
||||
|
||||
p->wave.phase += p->wave.speed / 180;
|
||||
p->wave.dirty = true;
|
||||
if (p->wave.speed != 0)
|
||||
{
|
||||
p->wave.phase += p->wave.speed / 180;
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* SceneElement */
|
||||
|
@ -808,10 +898,12 @@ void Sprite::onGeometryChange(const Scene::Geometry &geo)
|
|||
{
|
||||
/* Offset at which the sprite will be drawn
|
||||
* relative to screen origin */
|
||||
p->trans.setGlobalOffset(geo.offset());
|
||||
const Vec2i &offset = geo.offset();
|
||||
if (p->wave.active && p->trans.getGlobalOffset().y != offset.y)
|
||||
p->wave.dirty = true;
|
||||
p->trans.setGlobalOffset(offset);
|
||||
|
||||
p->sceneRect.setSize(geo.rect.size());
|
||||
p->sceneOrig = geo.orig;
|
||||
p->sceneGeo = geo;
|
||||
}
|
||||
|
||||
void Sprite::releaseResources()
|
||||
|
|
Loading…
Add table
Reference in a new issue