mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-09-10 12:02:53 +02:00
Add settable bitmap patterns on Sprites
This commit is contained in:
parent
3da0f4c948
commit
6722a1e61a
7 changed files with 569 additions and 464 deletions
|
@ -52,6 +52,7 @@ RB_METHOD(spriteInitialize) {
|
|||
}
|
||||
|
||||
DEF_GFX_PROP_OBJ_REF(Sprite, Bitmap, Bitmap, "bitmap")
|
||||
DEF_GFX_PROP_OBJ_REF(Sprite, Bitmap, Pattern, "pattern")
|
||||
DEF_GFX_PROP_OBJ_VAL(Sprite, Rect, SrcRect, "src_rect")
|
||||
DEF_GFX_PROP_OBJ_VAL(Sprite, Color, Color, "color")
|
||||
DEF_GFX_PROP_OBJ_VAL(Sprite, Tone, Tone, "tone")
|
||||
|
@ -64,6 +65,9 @@ DEF_GFX_PROP_I(Sprite, BushDepth)
|
|||
DEF_GFX_PROP_I(Sprite, BushOpacity)
|
||||
DEF_GFX_PROP_I(Sprite, Opacity)
|
||||
DEF_GFX_PROP_I(Sprite, BlendType)
|
||||
DEF_GFX_PROP_I(Sprite, PatternOpacity)
|
||||
DEF_GFX_PROP_I(Sprite, PatternScrollX)
|
||||
DEF_GFX_PROP_I(Sprite, PatternScrollY)
|
||||
DEF_GFX_PROP_I(Sprite, WaveAmp)
|
||||
DEF_GFX_PROP_I(Sprite, WaveLength)
|
||||
DEF_GFX_PROP_I(Sprite, WaveSpeed)
|
||||
|
@ -132,6 +136,11 @@ void spriteBindingInit() {
|
|||
|
||||
INIT_PROP_BIND(Sprite, BushOpacity, "bush_opacity");
|
||||
|
||||
INIT_PROP_BIND(Sprite, Pattern, "pattern");
|
||||
INIT_PROP_BIND(Sprite, PatternOpacity, "pattern_opacity");
|
||||
INIT_PROP_BIND(Sprite, PatternScrollX, "pattern_scroll_x");
|
||||
INIT_PROP_BIND(Sprite, PatternScrollY, "pattern_scroll_y");
|
||||
|
||||
INIT_PROP_BIND(Sprite, WaveAmp, "wave_amp");
|
||||
INIT_PROP_BIND(Sprite, WaveLength, "wave_length");
|
||||
INIT_PROP_BIND(Sprite, WaveSpeed, "wave_speed");
|
||||
|
|
|
@ -9,15 +9,27 @@ uniform lowp vec4 color;
|
|||
uniform float bushDepth;
|
||||
uniform lowp float bushOpacity;
|
||||
|
||||
uniform sampler2D pattern;
|
||||
uniform lowp float patternOpacity;
|
||||
uniform bool renderPattern;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_patCoord;
|
||||
|
||||
const vec3 lumaF = vec3(.299, .587, .114);
|
||||
const vec2 repeat = vec2(1, 1);
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Sample source color */
|
||||
vec4 frag = texture2D(texture, v_texCoord);
|
||||
|
||||
/* Apply the pattern if needed */
|
||||
if (renderPattern) {
|
||||
vec4 pattfrag = texture2D(pattern, mod(v_patCoord, repeat));
|
||||
frag.rgb = mix(frag.rgb, pattfrag.rgb, pattfrag.a * patternOpacity);
|
||||
}
|
||||
|
||||
/* Apply gray */
|
||||
float luma = dot(frag.rgb, lumaF);
|
||||
frag.rgb = mix(frag.rgb, vec3(luma), tone.w);
|
||||
|
|
|
@ -4,14 +4,22 @@ uniform mat4 projMat;
|
|||
uniform mat4 spriteMat;
|
||||
|
||||
uniform vec2 texSizeInv;
|
||||
uniform vec2 patternSizeInv;
|
||||
uniform vec2 patternScroll;
|
||||
uniform bool renderPattern;
|
||||
|
||||
attribute vec2 position;
|
||||
attribute vec2 texCoord;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_patCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projMat * spriteMat * vec4(position, 0, 1);
|
||||
|
||||
v_texCoord = texCoord * texSizeInv;
|
||||
if (renderPattern) {
|
||||
v_patCoord = (texCoord * patternSizeInv) - (patternScroll * patternSizeInv);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -245,6 +245,11 @@ void Shader::initFromFile(const char *_vertFile, const char *_fragFile,
|
|||
_vertFile, _fragFile, programName);
|
||||
}
|
||||
|
||||
void Shader::setVec2Uniform(GLint location, const Vec2 &vec)
|
||||
{
|
||||
gl.Uniform2f(location, vec.x, vec.y);
|
||||
}
|
||||
|
||||
void Shader::setVec4Uniform(GLint location, const Vec4 &vec)
|
||||
{
|
||||
gl.Uniform4f(location, vec.x, vec.y, vec.z, vec.w);
|
||||
|
@ -463,6 +468,11 @@ SpriteShader::SpriteShader()
|
|||
GET_U(opacity);
|
||||
GET_U(bushDepth);
|
||||
GET_U(bushOpacity);
|
||||
GET_U(pattern);
|
||||
GET_U(renderPattern);
|
||||
GET_U(patternSizeInv);
|
||||
GET_U(patternOpacity);
|
||||
GET_U(patternScroll);
|
||||
}
|
||||
|
||||
void SpriteShader::setSpriteMat(const float value[16])
|
||||
|
@ -495,6 +505,27 @@ void SpriteShader::setBushOpacity(float value)
|
|||
gl.Uniform1f(u_bushOpacity, value);
|
||||
}
|
||||
|
||||
void SpriteShader::setPattern(const TEX::ID pattern, const Vec2 &dimensions)
|
||||
{
|
||||
setTexUniform(u_pattern, 1, pattern);
|
||||
gl.Uniform2f(u_patternSizeInv, 1.f / dimensions.x, 1.f / dimensions.y);
|
||||
}
|
||||
|
||||
void SpriteShader::setShouldRenderPattern(bool value)
|
||||
{
|
||||
gl.Uniform1i(u_renderPattern, value);
|
||||
}
|
||||
|
||||
void SpriteShader::setPatternOpacity(float value)
|
||||
{
|
||||
gl.Uniform1f(u_patternOpacity, value);
|
||||
}
|
||||
|
||||
void SpriteShader::setPatternScroll(const Vec2 &scroll)
|
||||
{
|
||||
setVec2Uniform(u_patternScroll, scroll);
|
||||
}
|
||||
|
||||
|
||||
PlaneShader::PlaneShader()
|
||||
{
|
||||
|
|
|
@ -53,6 +53,7 @@ protected:
|
|||
const char *programName);
|
||||
|
||||
static void setVec4Uniform(GLint location, const Vec4 &vec);
|
||||
static void setVec2Uniform(GLint location, const Vec2 &vec);
|
||||
static void setTexUniform(GLint location, unsigned unitIndex, TEX::ID texture);
|
||||
|
||||
GLuint vertShader, fragShader;
|
||||
|
@ -190,9 +191,13 @@ public:
|
|||
void setOpacity(float value);
|
||||
void setBushDepth(float value);
|
||||
void setBushOpacity(float value);
|
||||
void setPattern(const TEX::ID pattern, const Vec2 &dimensions);
|
||||
void setShouldRenderPattern(bool value);
|
||||
void setPatternOpacity(float value);
|
||||
void setPatternScroll(const Vec2 &scroll);
|
||||
|
||||
private:
|
||||
GLint u_spriteMat, u_tone, u_opacity, u_color, u_bushDepth, u_bushOpacity;
|
||||
GLint u_spriteMat, u_tone, u_opacity, u_color, u_bushDepth, u_bushOpacity, u_pattern, u_renderPattern, u_patternSizeInv, u_patternOpacity, u_patternScroll;
|
||||
};
|
||||
|
||||
class PlaneShader : public ShaderBase
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
/*
|
||||
** sprite.cpp
|
||||
**
|
||||
** This file is part of mkxp.
|
||||
**
|
||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
|
||||
**
|
||||
** mkxp is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** mkxp is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
** sprite.cpp
|
||||
**
|
||||
** This file is part of mkxp.
|
||||
**
|
||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
|
||||
**
|
||||
** mkxp is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** mkxp is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sprite.h"
|
||||
|
||||
|
@ -45,269 +45,277 @@
|
|||
|
||||
struct SpritePrivate
|
||||
{
|
||||
Bitmap *bitmap;
|
||||
Bitmap *bitmap;
|
||||
|
||||
Quad quad;
|
||||
Transform trans;
|
||||
Quad quad;
|
||||
Transform trans;
|
||||
|
||||
Rect *srcRect;
|
||||
sigslot::connection srcRectCon;
|
||||
Rect *srcRect;
|
||||
sigslot::connection srcRectCon;
|
||||
|
||||
bool mirrored;
|
||||
int bushDepth;
|
||||
float efBushDepth;
|
||||
NormValue bushOpacity;
|
||||
NormValue opacity;
|
||||
BlendType blendType;
|
||||
bool mirrored;
|
||||
int bushDepth;
|
||||
float efBushDepth;
|
||||
NormValue bushOpacity;
|
||||
NormValue opacity;
|
||||
BlendType blendType;
|
||||
|
||||
IntRect sceneRect;
|
||||
Vec2i sceneOrig;
|
||||
Bitmap *pattern;
|
||||
NormValue patternOpacity;
|
||||
Vec2 patternScroll;
|
||||
|
||||
/* Would this sprite be visible on
|
||||
* the screen if drawn? */
|
||||
bool isVisible;
|
||||
IntRect sceneRect;
|
||||
Vec2i sceneOrig;
|
||||
|
||||
Color *color;
|
||||
Tone *tone;
|
||||
/* Would this sprite be visible on
|
||||
* the screen if drawn? */
|
||||
bool isVisible;
|
||||
|
||||
struct
|
||||
{
|
||||
int amp;
|
||||
int length;
|
||||
int speed;
|
||||
float phase;
|
||||
Color *color;
|
||||
Tone *tone;
|
||||
|
||||
/* Wave effect is active (amp != 0) */
|
||||
bool active;
|
||||
/* qArray needs updating */
|
||||
bool dirty;
|
||||
SimpleQuadArray qArray;
|
||||
} wave;
|
||||
struct
|
||||
{
|
||||
int amp;
|
||||
int length;
|
||||
int speed;
|
||||
float phase;
|
||||
|
||||
EtcTemps tmp;
|
||||
/* Wave effect is active (amp != 0) */
|
||||
bool active;
|
||||
/* qArray needs updating */
|
||||
bool dirty;
|
||||
SimpleQuadArray qArray;
|
||||
} wave;
|
||||
|
||||
sigslot::connection prepareCon;
|
||||
EtcTemps tmp;
|
||||
|
||||
SpritePrivate()
|
||||
: bitmap(0),
|
||||
srcRect(&tmp.rect),
|
||||
mirrored(false),
|
||||
bushDepth(0),
|
||||
efBushDepth(0),
|
||||
bushOpacity(128),
|
||||
opacity(255),
|
||||
blendType(BlendNormal),
|
||||
isVisible(false),
|
||||
color(&tmp.color),
|
||||
tone(&tmp.tone)
|
||||
sigslot::connection prepareCon;
|
||||
|
||||
{
|
||||
sceneRect.x = sceneRect.y = 0;
|
||||
SpritePrivate()
|
||||
: bitmap(0),
|
||||
srcRect(&tmp.rect),
|
||||
mirrored(false),
|
||||
bushDepth(0),
|
||||
efBushDepth(0),
|
||||
bushOpacity(128),
|
||||
opacity(255),
|
||||
blendType(BlendNormal),
|
||||
pattern(0),
|
||||
patternOpacity(255),
|
||||
isVisible(false),
|
||||
color(&tmp.color),
|
||||
tone(&tmp.tone)
|
||||
|
||||
updateSrcRectCon();
|
||||
{
|
||||
sceneRect.x = sceneRect.y = 0;
|
||||
|
||||
prepareCon = shState->prepareDraw.connect
|
||||
(&SpritePrivate::prepare, this);
|
||||
updateSrcRectCon();
|
||||
|
||||
wave.amp = 0;
|
||||
wave.length = 180;
|
||||
wave.speed = 360;
|
||||
wave.phase = 0.0f;
|
||||
wave.dirty = false;
|
||||
}
|
||||
prepareCon = shState->prepareDraw.connect
|
||||
(&SpritePrivate::prepare, this);
|
||||
|
||||
~SpritePrivate()
|
||||
{
|
||||
srcRectCon.disconnect();
|
||||
prepareCon.disconnect();
|
||||
}
|
||||
patternScroll = Vec2(0,0);
|
||||
|
||||
void recomputeBushDepth()
|
||||
{
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
wave.amp = 0;
|
||||
wave.length = 180;
|
||||
wave.speed = 360;
|
||||
wave.phase = 0.0f;
|
||||
wave.dirty = false;
|
||||
}
|
||||
|
||||
/* Calculate effective (normalized) bush depth */
|
||||
float texBushDepth = (bushDepth / trans.getScale().y) -
|
||||
(srcRect->y + srcRect->height) +
|
||||
bitmap->height();
|
||||
~SpritePrivate()
|
||||
{
|
||||
srcRectCon.disconnect();
|
||||
prepareCon.disconnect();
|
||||
}
|
||||
|
||||
efBushDepth = 1.0f - texBushDepth / bitmap->height();
|
||||
}
|
||||
void recomputeBushDepth()
|
||||
{
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
void onSrcRectChange()
|
||||
{
|
||||
FloatRect rect = srcRect->toFloatRect();
|
||||
Vec2i bmSize;
|
||||
/* Calculate effective (normalized) bush depth */
|
||||
float texBushDepth = (bushDepth / trans.getScale().y) -
|
||||
(srcRect->y + srcRect->height) +
|
||||
bitmap->height();
|
||||
|
||||
if (!nullOrDisposed(bitmap))
|
||||
bmSize = Vec2i(bitmap->width(), bitmap->height());
|
||||
efBushDepth = 1.0f - texBushDepth / bitmap->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);
|
||||
void onSrcRectChange()
|
||||
{
|
||||
FloatRect rect = srcRect->toFloatRect();
|
||||
Vec2i bmSize;
|
||||
|
||||
quad.setTexRect(mirrored ? rect.hFlipped() : rect);
|
||||
if (!nullOrDisposed(bitmap))
|
||||
bmSize = Vec2i(bitmap->width(), bitmap->height());
|
||||
|
||||
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
||||
recomputeBushDepth();
|
||||
/* 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);
|
||||
|
||||
wave.dirty = true;
|
||||
}
|
||||
quad.setTexRect(mirrored ? rect.hFlipped() : rect);
|
||||
|
||||
void updateSrcRectCon()
|
||||
{
|
||||
/* Cut old connection */
|
||||
srcRectCon.disconnect();
|
||||
/* Create new one */
|
||||
srcRectCon = srcRect->valueChanged.connect
|
||||
(&SpritePrivate::onSrcRectChange, this);
|
||||
}
|
||||
quad.setPosRect(FloatRect(0, 0, rect.w, rect.h));
|
||||
recomputeBushDepth();
|
||||
|
||||
void updateVisibility()
|
||||
{
|
||||
isVisible = false;
|
||||
wave.dirty = true;
|
||||
}
|
||||
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
void updateSrcRectCon()
|
||||
{
|
||||
/* Cut old connection */
|
||||
srcRectCon.disconnect();
|
||||
/* Create new one */
|
||||
srcRectCon = srcRect->valueChanged.connect
|
||||
(&SpritePrivate::onSrcRectChange, this);
|
||||
}
|
||||
|
||||
if (!opacity)
|
||||
return;
|
||||
void updateVisibility()
|
||||
{
|
||||
isVisible = false;
|
||||
|
||||
if (wave.active)
|
||||
{
|
||||
/* Don't do expensive wave bounding box
|
||||
* calculations */
|
||||
isVisible = true;
|
||||
return;
|
||||
}
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
/* Compare sprite bounding box against the scene */
|
||||
if (!opacity)
|
||||
return;
|
||||
|
||||
/* If sprite is zoomed/rotated, just opt out for now
|
||||
* for simplicity's sake */
|
||||
const Vec2 &scale = trans.getScale();
|
||||
if (scale.x != 1 || scale.y != 1 || trans.getRotation() != 0)
|
||||
{
|
||||
isVisible = true;
|
||||
return;
|
||||
}
|
||||
if (wave.active)
|
||||
{
|
||||
/* Don't do expensive wave bounding box
|
||||
* calculations */
|
||||
isVisible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
IntRect self;
|
||||
self.setPos(trans.getPositionI() - (trans.getOriginI() + sceneOrig));
|
||||
self.w = bitmap->width();
|
||||
self.h = bitmap->height();
|
||||
/* Compare sprite bounding box against the scene */
|
||||
|
||||
isVisible = SDL_HasIntersection(&self, &sceneRect);
|
||||
}
|
||||
/* If sprite is zoomed/rotated, just opt out for now
|
||||
* for simplicity's sake */
|
||||
const Vec2 &scale = trans.getScale();
|
||||
if (scale.x != 1 || scale.y != 1 || trans.getRotation() != 0)
|
||||
{
|
||||
isVisible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
void emitWaveChunk(SVertex *&vert, float phase, int width,
|
||||
float zoomY, int chunkY, int chunkLength)
|
||||
{
|
||||
float wavePos = phase + (chunkY / (float) wave.length) * (float) (M_PI * 2);
|
||||
float chunkX = sin(wavePos) * wave.amp;
|
||||
IntRect self;
|
||||
self.setPos(trans.getPositionI() - (trans.getOriginI() + sceneOrig));
|
||||
self.w = bitmap->width();
|
||||
self.h = bitmap->height();
|
||||
|
||||
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
|
||||
FloatRect pos = tex;
|
||||
pos.x = chunkX;
|
||||
isVisible = SDL_HasIntersection(&self, &sceneRect);
|
||||
}
|
||||
|
||||
Quad::setTexPosRect(vert, mirrored ? tex.hFlipped() : tex, pos);
|
||||
vert += 4;
|
||||
}
|
||||
void emitWaveChunk(SVertex *&vert, float phase, int width,
|
||||
float zoomY, int chunkY, int chunkLength)
|
||||
{
|
||||
float wavePos = phase + (chunkY / (float) wave.length) * (float) (M_PI * 2);
|
||||
float chunkX = sin(wavePos) * wave.amp;
|
||||
|
||||
void updateWave()
|
||||
{
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
|
||||
FloatRect pos = tex;
|
||||
pos.x = chunkX;
|
||||
|
||||
if (wave.amp == 0)
|
||||
{
|
||||
wave.active = false;
|
||||
return;
|
||||
}
|
||||
Quad::setTexPosRect(vert, mirrored ? tex.hFlipped() : tex, pos);
|
||||
vert += 4;
|
||||
}
|
||||
|
||||
wave.active = true;
|
||||
void updateWave()
|
||||
{
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
int width = srcRect->width;
|
||||
int height = srcRect->height;
|
||||
float zoomY = trans.getScale().y;
|
||||
if (wave.amp == 0)
|
||||
{
|
||||
wave.active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (wave.amp < -(width / 2))
|
||||
{
|
||||
wave.qArray.resize(0);
|
||||
wave.qArray.commit();
|
||||
wave.active = true;
|
||||
|
||||
return;
|
||||
}
|
||||
int width = srcRect->width;
|
||||
int height = srcRect->height;
|
||||
float zoomY = trans.getScale().y;
|
||||
|
||||
/* RMVX does this, and I have no fucking clue why */
|
||||
if (wave.amp < 0)
|
||||
{
|
||||
wave.qArray.resize(1);
|
||||
if (wave.amp < -(width / 2))
|
||||
{
|
||||
wave.qArray.resize(0);
|
||||
wave.qArray.commit();
|
||||
|
||||
int x = -wave.amp;
|
||||
int w = width - x * 2;
|
||||
return;
|
||||
}
|
||||
|
||||
FloatRect tex(x, srcRect->y, w, srcRect->height);
|
||||
/* RMVX does this, and I have no fucking clue why */
|
||||
if (wave.amp < 0)
|
||||
{
|
||||
wave.qArray.resize(1);
|
||||
|
||||
Quad::setTexPosRect(&wave.qArray.vertices[0], tex, tex);
|
||||
wave.qArray.commit();
|
||||
int x = -wave.amp;
|
||||
int w = width - x * 2;
|
||||
|
||||
return;
|
||||
}
|
||||
FloatRect tex(x, srcRect->y, w, srcRect->height);
|
||||
|
||||
/* The length of the sprite as it appears on screen */
|
||||
int visibleLength = height * zoomY;
|
||||
Quad::setTexPosRect(&wave.qArray.vertices[0], tex, tex);
|
||||
wave.qArray.commit();
|
||||
|
||||
/* First chunk length (aligned to 8 pixel boundary */
|
||||
int firstLength = ((int) trans.getPosition().y) % 8;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Amount of full 8 pixel chunks in the middle */
|
||||
int chunks = (visibleLength - firstLength) / 8;
|
||||
/* The length of the sprite as it appears on screen */
|
||||
int visibleLength = height * zoomY;
|
||||
|
||||
/* Final chunk length */
|
||||
int lastLength = (visibleLength - firstLength) % 8;
|
||||
/* First chunk length (aligned to 8 pixel boundary */
|
||||
int firstLength = ((int) trans.getPosition().y) % 8;
|
||||
|
||||
wave.qArray.resize(!!firstLength + chunks + !!lastLength);
|
||||
SVertex *vert = &wave.qArray.vertices[0];
|
||||
/* Amount of full 8 pixel chunks in the middle */
|
||||
int chunks = (visibleLength - firstLength) / 8;
|
||||
|
||||
float phase = (wave.phase * (float) M_PI) / 180.0f;
|
||||
/* Final chunk length */
|
||||
int lastLength = (visibleLength - firstLength) % 8;
|
||||
|
||||
if (firstLength > 0)
|
||||
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
|
||||
wave.qArray.resize(!!firstLength + chunks + !!lastLength);
|
||||
SVertex *vert = &wave.qArray.vertices[0];
|
||||
|
||||
for (int i = 0; i < chunks; ++i)
|
||||
emitWaveChunk(vert, phase, width, zoomY, firstLength + i * 8, 8);
|
||||
float phase = (wave.phase * (float) M_PI) / 180.0f;
|
||||
|
||||
if (lastLength > 0)
|
||||
emitWaveChunk(vert, phase, width, zoomY, firstLength + chunks * 8, lastLength);
|
||||
if (firstLength > 0)
|
||||
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
|
||||
|
||||
wave.qArray.commit();
|
||||
}
|
||||
for (int i = 0; i < chunks; ++i)
|
||||
emitWaveChunk(vert, phase, width, zoomY, firstLength + i * 8, 8);
|
||||
|
||||
void prepare()
|
||||
{
|
||||
if (wave.dirty)
|
||||
{
|
||||
updateWave();
|
||||
wave.dirty = false;
|
||||
}
|
||||
if (lastLength > 0)
|
||||
emitWaveChunk(vert, phase, width, zoomY, firstLength + chunks * 8, lastLength);
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
wave.qArray.commit();
|
||||
}
|
||||
|
||||
void prepare()
|
||||
{
|
||||
if (wave.dirty)
|
||||
{
|
||||
updateWave();
|
||||
wave.dirty = false;
|
||||
}
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite::Sprite(Viewport *viewport)
|
||||
: ViewportElement(viewport)
|
||||
: ViewportElement(viewport)
|
||||
{
|
||||
p = new SpritePrivate;
|
||||
onGeometryChange(scene->getGeometry());
|
||||
p = new SpritePrivate;
|
||||
onGeometryChange(scene->getGeometry());
|
||||
}
|
||||
|
||||
Sprite::~Sprite()
|
||||
{
|
||||
dispose();
|
||||
dispose();
|
||||
}
|
||||
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, Bitmap, Bitmap*, p->bitmap)
|
||||
|
@ -321,6 +329,7 @@ DEF_ATTR_RD_SIMPLE(Sprite, Angle, float, p->trans.getRotation())
|
|||
DEF_ATTR_RD_SIMPLE(Sprite, Mirror, bool, p->mirrored)
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, BushDepth, int, p->bushDepth)
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, BlendType, int, p->blendType)
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, Pattern, Bitmap*, p->pattern)
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, Width, int, p->srcRect->width)
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, Height, int, p->srcRect->height)
|
||||
DEF_ATTR_RD_SIMPLE(Sprite, WaveAmp, int, p->wave.amp)
|
||||
|
@ -333,158 +342,174 @@ DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity)
|
|||
DEF_ATTR_SIMPLE(Sprite, SrcRect, Rect&, *p->srcRect)
|
||||
DEF_ATTR_SIMPLE(Sprite, Color, Color&, *p->color)
|
||||
DEF_ATTR_SIMPLE(Sprite, Tone, Tone&, *p->tone)
|
||||
DEF_ATTR_SIMPLE(Sprite, PatternOpacity, int, p->patternOpacity)
|
||||
DEF_ATTR_SIMPLE(Sprite, PatternScrollX, int, p->patternScroll.x)
|
||||
DEF_ATTR_SIMPLE(Sprite, PatternScrollY, int, p->patternScroll.y)
|
||||
|
||||
void Sprite::setBitmap(Bitmap *bitmap)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->bitmap == bitmap)
|
||||
return;
|
||||
if (p->bitmap == bitmap)
|
||||
return;
|
||||
|
||||
p->bitmap = bitmap;
|
||||
p->bitmap = bitmap;
|
||||
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
if (nullOrDisposed(bitmap))
|
||||
return;
|
||||
|
||||
bitmap->ensureNonMega();
|
||||
bitmap->ensureNonMega();
|
||||
|
||||
*p->srcRect = bitmap->rect();
|
||||
p->onSrcRectChange();
|
||||
p->quad.setPosRect(p->srcRect->toFloatRect());
|
||||
*p->srcRect = bitmap->rect();
|
||||
p->onSrcRectChange();
|
||||
p->quad.setPosRect(p->srcRect->toFloatRect());
|
||||
|
||||
p->wave.dirty = true;
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setX(int value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getPosition().x == value)
|
||||
return;
|
||||
if (p->trans.getPosition().x == value)
|
||||
return;
|
||||
|
||||
p->trans.setPosition(Vec2(value, getY()));
|
||||
p->trans.setPosition(Vec2(value, getY()));
|
||||
}
|
||||
|
||||
void Sprite::setY(int value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getPosition().y == value)
|
||||
return;
|
||||
if (p->trans.getPosition().y == value)
|
||||
return;
|
||||
|
||||
p->trans.setPosition(Vec2(getX(), value));
|
||||
p->trans.setPosition(Vec2(getX(), value));
|
||||
|
||||
if (rgssVer >= 2)
|
||||
{
|
||||
p->wave.dirty = true;
|
||||
setSpriteY(value);
|
||||
}
|
||||
if (rgssVer >= 2)
|
||||
{
|
||||
p->wave.dirty = true;
|
||||
setSpriteY(value);
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::setOX(int value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getOrigin().x == value)
|
||||
return;
|
||||
if (p->trans.getOrigin().x == value)
|
||||
return;
|
||||
|
||||
p->trans.setOrigin(Vec2(value, getOY()));
|
||||
p->trans.setOrigin(Vec2(value, getOY()));
|
||||
}
|
||||
|
||||
void Sprite::setOY(int value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getOrigin().y == value)
|
||||
return;
|
||||
if (p->trans.getOrigin().y == value)
|
||||
return;
|
||||
|
||||
p->trans.setOrigin(Vec2(getOX(), value));
|
||||
p->trans.setOrigin(Vec2(getOX(), value));
|
||||
}
|
||||
|
||||
void Sprite::setZoomX(float value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getScale().x == value)
|
||||
return;
|
||||
if (p->trans.getScale().x == value)
|
||||
return;
|
||||
|
||||
p->trans.setScale(Vec2(value, getZoomY()));
|
||||
p->trans.setScale(Vec2(value, getZoomY()));
|
||||
}
|
||||
|
||||
void Sprite::setZoomY(float value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getScale().y == value)
|
||||
return;
|
||||
if (p->trans.getScale().y == value)
|
||||
return;
|
||||
|
||||
p->trans.setScale(Vec2(getZoomX(), value));
|
||||
p->recomputeBushDepth();
|
||||
p->trans.setScale(Vec2(getZoomX(), value));
|
||||
p->recomputeBushDepth();
|
||||
|
||||
if (rgssVer >= 2)
|
||||
p->wave.dirty = true;
|
||||
if (rgssVer >= 2)
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
void Sprite::setAngle(float value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->trans.getRotation() == value)
|
||||
return;
|
||||
if (p->trans.getRotation() == value)
|
||||
return;
|
||||
|
||||
p->trans.setRotation(value);
|
||||
p->trans.setRotation(value);
|
||||
}
|
||||
|
||||
void Sprite::setMirror(bool mirrored)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->mirrored == mirrored)
|
||||
return;
|
||||
if (p->mirrored == mirrored)
|
||||
return;
|
||||
|
||||
p->mirrored = mirrored;
|
||||
p->onSrcRectChange();
|
||||
p->mirrored = mirrored;
|
||||
p->onSrcRectChange();
|
||||
}
|
||||
|
||||
void Sprite::setBushDepth(int value)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
if (p->bushDepth == value)
|
||||
return;
|
||||
if (p->bushDepth == value)
|
||||
return;
|
||||
|
||||
p->bushDepth = value;
|
||||
p->recomputeBushDepth();
|
||||
p->bushDepth = value;
|
||||
p->recomputeBushDepth();
|
||||
}
|
||||
|
||||
void Sprite::setBlendType(int type)
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default :
|
||||
case BlendNormal :
|
||||
p->blendType = BlendNormal;
|
||||
return;
|
||||
case BlendAddition :
|
||||
p->blendType = BlendAddition;
|
||||
return;
|
||||
case BlendSubstraction :
|
||||
p->blendType = BlendSubstraction;
|
||||
return;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
default :
|
||||
case BlendNormal :
|
||||
p->blendType = BlendNormal;
|
||||
return;
|
||||
case BlendAddition :
|
||||
p->blendType = BlendAddition;
|
||||
return;
|
||||
case BlendSubstraction :
|
||||
p->blendType = BlendSubstraction;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::setPattern(Bitmap *value)
|
||||
{
|
||||
guardDisposed();
|
||||
|
||||
if (p->pattern == value)
|
||||
return;
|
||||
|
||||
p->pattern = value;
|
||||
|
||||
if (!nullOrDisposed(value))
|
||||
value->ensureNonMega();
|
||||
}
|
||||
|
||||
#define DEF_WAVE_SETTER(Name, name, type) \
|
||||
void Sprite::setWave##Name(type value) \
|
||||
{ \
|
||||
guardDisposed(); \
|
||||
if (p->wave.name == value) \
|
||||
return; \
|
||||
p->wave.name = value; \
|
||||
p->wave.dirty = true; \
|
||||
}
|
||||
void Sprite::setWave##Name(type value) \
|
||||
{ \
|
||||
guardDisposed(); \
|
||||
if (p->wave.name == value) \
|
||||
return; \
|
||||
p->wave.name = value; \
|
||||
p->wave.dirty = true; \
|
||||
}
|
||||
|
||||
DEF_WAVE_SETTER(Amp, amp, int)
|
||||
DEF_WAVE_SETTER(Length, length, int)
|
||||
|
@ -495,107 +520,118 @@ DEF_WAVE_SETTER(Phase, phase, float)
|
|||
|
||||
void Sprite::initDynAttribs()
|
||||
{
|
||||
p->srcRect = new Rect;
|
||||
p->color = new Color;
|
||||
p->tone = new Tone;
|
||||
p->srcRect = new Rect;
|
||||
p->color = new Color;
|
||||
p->tone = new Tone;
|
||||
|
||||
p->updateSrcRectCon();
|
||||
p->updateSrcRectCon();
|
||||
}
|
||||
|
||||
/* Flashable */
|
||||
void Sprite::update()
|
||||
{
|
||||
guardDisposed();
|
||||
guardDisposed();
|
||||
|
||||
Flashable::update();
|
||||
Flashable::update();
|
||||
|
||||
p->wave.phase += p->wave.speed / 180;
|
||||
p->wave.dirty = true;
|
||||
p->wave.phase += p->wave.speed / 180;
|
||||
p->wave.dirty = true;
|
||||
}
|
||||
|
||||
/* SceneElement */
|
||||
void Sprite::draw()
|
||||
{
|
||||
if (!p->isVisible)
|
||||
return;
|
||||
if (!p->isVisible)
|
||||
return;
|
||||
|
||||
if (emptyFlashFlag)
|
||||
return;
|
||||
if (emptyFlashFlag)
|
||||
return;
|
||||
|
||||
ShaderBase *base;
|
||||
ShaderBase *base;
|
||||
|
||||
bool renderEffect = p->color->hasEffect() ||
|
||||
p->tone->hasEffect() ||
|
||||
flashing ||
|
||||
p->bushDepth != 0;
|
||||
bool renderEffect = p->color->hasEffect() ||
|
||||
p->tone->hasEffect() ||
|
||||
flashing ||
|
||||
p->bushDepth != 0 ||
|
||||
(p->pattern && !p->pattern->isDisposed());
|
||||
|
||||
if (renderEffect)
|
||||
{
|
||||
SpriteShader &shader = shState->shaders().sprite;
|
||||
if (renderEffect)
|
||||
{
|
||||
SpriteShader &shader = shState->shaders().sprite;
|
||||
|
||||
shader.bind();
|
||||
shader.applyViewportProj();
|
||||
shader.setSpriteMat(p->trans.getMatrix());
|
||||
shader.bind();
|
||||
shader.applyViewportProj();
|
||||
shader.setSpriteMat(p->trans.getMatrix());
|
||||
|
||||
shader.setTone(p->tone->norm);
|
||||
shader.setOpacity(p->opacity.norm);
|
||||
shader.setBushDepth(p->efBushDepth);
|
||||
shader.setBushOpacity(p->bushOpacity.norm);
|
||||
shader.setTone(p->tone->norm);
|
||||
shader.setOpacity(p->opacity.norm);
|
||||
shader.setBushDepth(p->efBushDepth);
|
||||
shader.setBushOpacity(p->bushOpacity.norm);
|
||||
|
||||
/* When both flashing and effective color are set,
|
||||
* the one with higher alpha will be blended */
|
||||
const Vec4 *blend = (flashing && flashColor.w > p->color->norm.w) ?
|
||||
&flashColor : &p->color->norm;
|
||||
if (p->pattern) {
|
||||
shader.setPattern(p->pattern->getGLTypes().tex, Vec2(p->pattern->width(), p->pattern->height()));
|
||||
shader.setPatternOpacity(p->patternOpacity.norm);
|
||||
shader.setPatternScroll(p->patternScroll);
|
||||
shader.setShouldRenderPattern(true);
|
||||
}
|
||||
else {
|
||||
shader.setShouldRenderPattern(false);
|
||||
}
|
||||
|
||||
shader.setColor(*blend);
|
||||
/* When both flashing and effective color are set,
|
||||
* the one with higher alpha will be blended */
|
||||
const Vec4 *blend = (flashing && flashColor.w > p->color->norm.w) ?
|
||||
&flashColor : &p->color->norm;
|
||||
|
||||
base = &shader;
|
||||
}
|
||||
else if (p->opacity != 255)
|
||||
{
|
||||
AlphaSpriteShader &shader = shState->shaders().alphaSprite;
|
||||
shader.bind();
|
||||
shader.setColor(*blend);
|
||||
|
||||
shader.setSpriteMat(p->trans.getMatrix());
|
||||
shader.setAlpha(p->opacity.norm);
|
||||
shader.applyViewportProj();
|
||||
base = &shader;
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleSpriteShader &shader = shState->shaders().simpleSprite;
|
||||
shader.bind();
|
||||
base = &shader;
|
||||
}
|
||||
else if (p->opacity != 255)
|
||||
{
|
||||
AlphaSpriteShader &shader = shState->shaders().alphaSprite;
|
||||
shader.bind();
|
||||
|
||||
shader.setSpriteMat(p->trans.getMatrix());
|
||||
shader.applyViewportProj();
|
||||
base = &shader;
|
||||
}
|
||||
shader.setSpriteMat(p->trans.getMatrix());
|
||||
shader.setAlpha(p->opacity.norm);
|
||||
shader.applyViewportProj();
|
||||
base = &shader;
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleSpriteShader &shader = shState->shaders().simpleSprite;
|
||||
shader.bind();
|
||||
|
||||
glState.blendMode.pushSet(p->blendType);
|
||||
shader.setSpriteMat(p->trans.getMatrix());
|
||||
shader.applyViewportProj();
|
||||
base = &shader;
|
||||
}
|
||||
|
||||
p->bitmap->bindTex(*base);
|
||||
glState.blendMode.pushSet(p->blendType);
|
||||
|
||||
p->bitmap->bindTex(*base);
|
||||
|
||||
if (p->wave.active)
|
||||
p->wave.qArray.draw();
|
||||
else
|
||||
p->quad.draw();
|
||||
p->wave.qArray.draw();
|
||||
else
|
||||
p->quad.draw();
|
||||
|
||||
glState.blendMode.pop();
|
||||
glState.blendMode.pop();
|
||||
}
|
||||
|
||||
void Sprite::onGeometryChange(const Scene::Geometry &geo)
|
||||
{
|
||||
/* Offset at which the sprite will be drawn
|
||||
* relative to screen origin */
|
||||
p->trans.setGlobalOffset(geo.offset());
|
||||
/* Offset at which the sprite will be drawn
|
||||
* relative to screen origin */
|
||||
p->trans.setGlobalOffset(geo.offset());
|
||||
|
||||
p->sceneRect.setSize(geo.rect.size());
|
||||
p->sceneOrig = geo.orig;
|
||||
p->sceneRect.setSize(geo.rect.size());
|
||||
p->sceneOrig = geo.orig;
|
||||
}
|
||||
|
||||
void Sprite::releaseResources()
|
||||
{
|
||||
unlink();
|
||||
unlink();
|
||||
|
||||
delete p;
|
||||
delete p;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,10 @@ public:
|
|||
DECL_ATTR( BlendType, int )
|
||||
DECL_ATTR( Color, Color& )
|
||||
DECL_ATTR( Tone, Tone& )
|
||||
DECL_ATTR( Pattern, Bitmap* )
|
||||
DECL_ATTR( PatternOpacity, int )
|
||||
DECL_ATTR( PatternScrollX, int )
|
||||
DECL_ATTR( PatternScrollY, int )
|
||||
DECL_ATTR( WaveAmp, int )
|
||||
DECL_ATTR( WaveLength, int )
|
||||
DECL_ATTR( WaveSpeed, int )
|
||||
|
|
Loading…
Add table
Reference in a new issue