diff --git a/binding-mri/sprite-binding.cpp b/binding-mri/sprite-binding.cpp index 7c53441..2c84321 100644 --- a/binding-mri/sprite-binding.cpp +++ b/binding-mri/sprite-binding.cpp @@ -64,15 +64,19 @@ DEF_PROP_I(Sprite, WaveAmp) DEF_PROP_I(Sprite, WaveLength) DEF_PROP_I(Sprite, WaveSpeed) DEF_PROP_I(Sprite, Shader) +DEF_PROP_I(Sprite, PerspectiveZ) DEF_PROP_F(Sprite, ZoomX) DEF_PROP_F(Sprite, ZoomY) DEF_PROP_F(Sprite, Angle) DEF_PROP_F(Sprite, WavePhase) +DEF_PROP_F(Sprite, PerspectiveRotationX) +DEF_PROP_F(Sprite, PerspectiveRotationY) DEF_PROP_B(Sprite, MirrorX) DEF_PROP_B(Sprite, MirrorY) DEF_PROP_B(Sprite, Obscured) +DEF_PROP_B(Sprite, PerspectiveMode) RB_METHOD(spriteWidth){ RB_UNUSED_PARAM; @@ -125,6 +129,10 @@ void spriteBindingInit(){ INIT_PROP_BIND( Sprite, Modulate, "modulate" ); INIT_PROP_BIND( Sprite, Obscured, "obscured" ); INIT_PROP_BIND( Sprite, Shader, "shader" ); + INIT_PROP_BIND( Sprite, PerspectiveMode, "pm"); + INIT_PROP_BIND( Sprite, PerspectiveZ, "pz"); + INIT_PROP_BIND( Sprite, PerspectiveRotationX, "rx"); + INIT_PROP_BIND( Sprite, PerspectiveRotationY, "ry"); _rb_define_method(klass, "width", spriteWidth); _rb_define_method(klass, "height", spriteHeight); diff --git a/scripts/Scene_OF.rb b/scripts/Scene_OF.rb index c7eda35..a8f6f8f 100644 --- a/scripts/Scene_OF.rb +++ b/scripts/Scene_OF.rb @@ -90,9 +90,10 @@ class Scene_OF @miss_sound = Audio.create_sound("Audio/SE/shatter") + @viewport_bg = Viewport.new(0, 0, Graphics.width, Graphics.height) @viewport_ui = Viewport.new(0, 0, Graphics.width, Graphics.height) - @viewport_ui.ox = -Graphics.width / 2 - @viewport_ui.oy = -Graphics.height / 2 + @viewport_ui.ox = @viewport_bg.ox = -Graphics.width / 2 + @viewport_ui.oy = @viewport_bg.oy = -Graphics.height / 2 @spritesheet = RPG::Cache.misc(".cats") @cat_flying_arrows = [] @@ -165,6 +166,20 @@ class Scene_OF @bst_debug = Sprite.new(@viewport_ui) @bst_debug.bitmap = Bitmap.new(300, 40) + @test_bitmap = Bitmap.new(64, 64) + @test_bitmap.stretch_blt(Rect.new(0, 0, 64, 64), @spritesheet, SPRITES[:player_target_arrow_down]) + @threeD_test1 = Sprite.new(@viewport_bg) + @threeD_test2 = Sprite.new(@viewport_bg) + @threeD_test1.bitmap = @test_bitmap + @threeD_test2.bitmap = @simple_bitmap + @threeD_test1.x = -300 + @threeD_test1.ry = 90 + @threeD_test1.pm = @threeD_test2.pm = true + @threeD_test1.zoom_x = @threeD_test1.zoom_y = 2 + @threeD_test2.zoom_x = @threeD_test2.zoom_y = 128 + @threeD_test1.ox = @threeD_test1.oy = 32 + @threeD_test2.ox = @threeD_test2.oy = 0.5 + @total_time = 0 @bump_timeout = 999999 @bump_time = 999999 @@ -213,11 +228,14 @@ class Scene_OF # fl studio b:s:t :3 beat = (@total_time / BPM_TIME / 2).to_i + 1 step = (@total_time / BPM_TIME * 15 / 2).to_i % 15 + 1 - tick = (@total_time / BPM_TIME * 24 * 15 / 2).to_i % 24 + tick = (@total_time / BPM_TIME * 24 * 15 / 2).to_i % 24 @bst_debug.bitmap.clear @bst_debug.bitmap.draw_text(Rect.new(0, 0, 300, 40), "#{beat} : #{step} : #{tick}") + @threeD_test1.pz = Math.sin(@total_time / 180.0 * Math::PI) * 400 + 400 + @threeD_test2.rx += 4 + @bump_timeout -= 1 @icons_bump_timeout -= 1 if @bump_timeout <= 0 diff --git a/src/etc-internal.h b/src/etc-internal.h index af56ee3..d7d6d00 100644 --- a/src/etc-internal.h +++ b/src/etc-internal.h @@ -26,6 +26,8 @@ #include +constexpr float PI = 3.14159265358979323846f; + struct Vec2{ float x, y; diff --git a/src/shader.cpp b/src/shader.cpp index 303eae8..2e41c7b 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -237,6 +237,34 @@ void ShaderBase::applyViewportProj(){ projMat.set(Vec2i(vp.w, vp.h)); } +void ShaderBase::applyPerspectiveProj() +{ + const IntRect &vp = glState.viewport.get(); + const float width = (float)vp.w; + const float height = (float)vp.h; + + const float cameraDistance = 1000.0f; + + const float nearPlane = 1.0f; + const float farPlane = 10000.0f; + + const float sx = 2.0f * cameraDistance / width; + const float sy = 2.0f * cameraDistance / height; + + const float A = -(farPlane + nearPlane) / (farPlane - nearPlane); + + const float B = -(2.0f * farPlane * nearPlane) / (farPlane - nearPlane); + + GLfloat mat[16] = { + sx, 0, 0, 0, + 0, sy, 0, 0, + 0, 0, A, -1, + -cameraDistance, -cameraDistance, B, cameraDistance + }; + + gl.UniformMatrix4fv(projMat.u_mat, 1, GL_FALSE, mat); +} + void ShaderBase::setTexSize(const Vec2i &value){ gl.Uniform2f(u_texSizeInv, 1.f / value.x, 1.f / value.y); } diff --git a/src/shader.h b/src/shader.h index 9f8a070..a1ea9bf 100644 --- a/src/shader.h +++ b/src/shader.h @@ -69,6 +69,7 @@ public: * calculates the corresponding ortho projection matrix * and loads it into the shaders uniform */ void applyViewportProj(); + void applyPerspectiveProj(); void setTexSize(const Vec2i &value); void setTranslation(const Vec2i &value); diff --git a/src/sprite.cpp b/src/sprite.cpp index cfbbeab..fb7c625 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -318,6 +318,11 @@ DEF_ATTR_RD_SIMPLE(Sprite, WaveAmp, int, p->wave.amp) DEF_ATTR_RD_SIMPLE(Sprite, WaveLength, int, p->wave.length) DEF_ATTR_RD_SIMPLE(Sprite, WaveSpeed, int, p->wave.speed) DEF_ATTR_RD_SIMPLE(Sprite, WavePhase, float, p->wave.phase) +// 3D shit +DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveMode, bool, p->trans.getPerspectiveMode()) +DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveZ, int, p->trans.getPerspectiveZ()) +DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveRotationX, float, p->trans.getPerspectiveRotation().x) +DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveRotationY, float, p->trans.getPerspectiveRotation().y) DEF_ATTR_SIMPLE(Sprite, BushOpacity, int, p->bushOpacity) DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity) @@ -462,6 +467,42 @@ void Sprite::setBlendType(int type){ } } +void Sprite::setPerspectiveMode(bool value){ + guardDisposed(); + + if (p->trans.getPerspectiveMode() == value) + return; + + p->trans.setPerspectiveMode(value); +} + +void Sprite::setPerspectiveZ(int value){ + guardDisposed(); + + if (p->trans.getPerspectiveZ() == value) + return; + + p->trans.setPerspectiveZ(value); +} + +void Sprite::setPerspectiveRotationX(float value){ + guardDisposed(); + + if (p->trans.getPerspectiveRotation().x == value) + return; + + p->trans.setPerspectiveRotation(Vec2(value, p->trans.getPerspectiveRotation().y)); +} + +void Sprite::setPerspectiveRotationY(float value){ + guardDisposed(); + + if (p->trans.getPerspectiveRotation().y == value) + return; + + p->trans.setPerspectiveRotation(Vec2(p->trans.getPerspectiveRotation().x, value)); +} + #define DEF_WAVE_SETTER(Name, name, type) \ void Sprite::setWave##Name(type value) \ { \ @@ -517,7 +558,6 @@ void Sprite::draw(){ if (p->obscured || p->shader == ShaderType::SHADER_obscured){ ObscuredShader &shader = shState->shaders().obscured; shader.bind(); - shader.applyViewportProj(); shader.setObscured(shState->graphics().obscuredTex()); base = &shader; } @@ -529,7 +569,6 @@ void Sprite::draw(){ PlaneShader &shader = shState->shaders().plane; shader.bind(); - shader.applyViewportProj(); shader.setTone(p->tone->norm); shader.setColor(p->color->norm); shader.setFlash(Vec4()); @@ -586,7 +625,6 @@ void Sprite::draw(){ shader.setSpriteMat(p->trans.getMatrix()); shader.setAlpha(p->opacity.norm); - shader.applyViewportProj(); base = &shader; } else{ @@ -594,7 +632,6 @@ void Sprite::draw(){ shader.bind(); shader.setSpriteMat(p->trans.getMatrix()); - shader.applyViewportProj(); base = &shader; } @@ -606,6 +643,10 @@ void Sprite::draw(){ boost::chrono::duration elapsed = currentTime - startTime; base->setTime(elapsed.count()); + base->applyViewportProj(); + if(p->trans.getPerspectiveMode()) + base->applyPerspectiveProj(); + glState.blendMode.pushSet(p->blendType); p->bitmap->bindTex(*base); @@ -644,7 +685,6 @@ void Sprite::releaseResources(){ void Sprite::defaultSpriteShaderInit(SpriteShaderBase &shader){ shader.bind(); - shader.applyViewportProj(); shader.setSpriteMat(p->trans.getMatrix()); shader.setTone(p->tone->norm); diff --git a/src/sprite.h b/src/sprite.h index 12cab0a..6f24dc7 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -72,6 +72,11 @@ public: DECL_ATTR( WavePhase, float ) DECL_ATTR( Obscured, bool ) DECL_ATTR( Shader, int ) + // 3D test shit + DECL_ATTR( PerspectiveMode, bool ) + DECL_ATTR( PerspectiveZ, int ) + DECL_ATTR( PerspectiveRotationX, float ) + DECL_ATTR( PerspectiveRotationY, float ) void initDynAttribs(); diff --git a/src/transform.h b/src/transform.h index 8fb4f57..069295a 100644 --- a/src/transform.h +++ b/src/transform.h @@ -52,13 +52,13 @@ #include -constexpr float PI = 3.14159265358979323846f; - class Transform{ public: Transform() : scale(1, 1), rotation(0), + perspectiveZ(0), + perspectiveRotation(0, 0), dirty(true) { SDL_memset(matrix, 0, sizeof(matrix)); @@ -67,12 +67,15 @@ public: matrix[15] = 1; } - Vec2 &getPosition() { return position; } - Vec2 &getOrigin() { return origin; } - Vec2 &getScale() { return scale; } - Vec2 &getGlobalScale() { return globalScale; } - float getRotation() { return rotation; } - float getGlobalRotation() { return globalRotation; } + Vec2 &getPosition() { return position; } + Vec2 &getOrigin() { return origin; } + Vec2 &getScale() { return scale; } + Vec2 &getGlobalScale() { return globalScale; } + Vec2 &getPerspectiveRotation() { return perspectiveRotation; } + float getRotation() { return rotation; } + float getGlobalRotation() { return globalRotation; } + float getPerspectiveZ() { return perspectiveZ; } + bool getPerspectiveMode() { return perspectiveMode; } Vec2i getPositionI() const{ return Vec2i(position.x, position.y); @@ -82,11 +85,21 @@ public: return Vec2i(origin.x, origin.y); } + void setPerspectiveMode(bool mode) { + perspectiveMode = mode; + dirty = true; + } + void setPosition(const Vec2 &value){ position = value; dirty = true; } + void setPerspectiveZ(float value) { + perspectiveZ = value; + dirty = true; + } + void setOrigin(const Vec2 &value){ origin = value; dirty = true; @@ -102,6 +115,11 @@ public: dirty = true; } + void setPerspectiveRotation(const Vec2 &value){ + perspectiveRotation = value; + dirty = true; + } + void setGlobalRotation(float value){ globalRotation = value; dirty = true; @@ -133,53 +151,161 @@ private: if (globalRotation >= 360 || globalRotation < -360) globalRotation = (float)SDL_fmod(globalRotation, 360); - - // object rotation cos and sin - float angle = rotation * PI / 180.0f; - float cosine = SDL_cos(angle); - float sine = SDL_sin(angle); - - float sxc = scale.x * cosine; - float syc = scale.y * cosine; - float sxs = scale.x * sine; - float sys = scale.y * sine; - - // object matrix - float a = sxc * globalScale.x; - float b = -sxs * globalScale.y; - float c = sys * globalScale.x; - float d = syc * globalScale.y; - - float tx = (-origin.x * sxc - origin.y * sys + position.x) - * globalScale.x; - - float ty = ( origin.x * sxs - origin.y * syc + position.y) - * globalScale.y; - - // viewport rotation cos and sin - float globalAngle = globalRotation * PI / 180.0f; - float gc = SDL_cos(globalAngle); - float gs = SDL_sin(globalAngle); - - // basis rotation - float na = a * gc - b * gs; - float nb = a * gs + b * gc; - float nc = c * gc - d * gs; - float nd = c * gs + d * gc; - - float dx = tx; - float dy = ty; - - // appling global rotation - tx = dx * gc - dy * gs + offset.x; - ty = dx * gs + dy * gc + offset.y; - - matrix[0] = na; - matrix[1] = nb; - matrix[4] = nc; - matrix[5] = nd; - matrix[12] = tx; - matrix[13] = ty; + if (!perspectiveMode) { + + // object rotation cos and sin + float angle = rotation * PI / 180.0f; + float cosine = SDL_cos(angle); + float sine = SDL_sin(angle); + + float sxc = scale.x * cosine; + float syc = scale.y * cosine; + float sxs = scale.x * sine; + float sys = scale.y * sine; + + // object matrix + float a = sxc * globalScale.x; + float b = -sxs * globalScale.y; + float c = sys * globalScale.x; + float d = syc * globalScale.y; + + float tx = (-origin.x * sxc - origin.y * sys + position.x) + * globalScale.x; + + float ty = ( origin.x * sxs - origin.y * syc + position.y) + * globalScale.y; + + // viewport rotation cos and sin + float globalAngle = globalRotation * PI / 180.0f; + float gc = SDL_cos(globalAngle); + float gs = SDL_sin(globalAngle); + + // basis rotation + float na = a * gc - b * gs; + float nb = a * gs + b * gc; + float nc = c * gc - d * gs; + float nd = c * gs + d * gc; + + float dx = tx; + float dy = ty; + + // appling global rotation + tx = dx * gc - dy * gs + offset.x; + ty = dx * gs + dy * gc + offset.y; + + matrix[0] = na; + matrix[1] = nb; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = nc; + matrix[5] = nd; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = tx; + matrix[13] = ty; + matrix[14] = -1; + matrix[15] = 1; + } + else { + if (perspectiveRotation.x >= 360 || perspectiveRotation.x < -360) + perspectiveRotation.x = (float)SDL_fmod(perspectiveRotation.x, 360); + + if (perspectiveRotation.y >= 360 || perspectiveRotation.y < -360) + perspectiveRotation.y = (float)SDL_fmod(perspectiveRotation.y, 360); + + float rx = perspectiveRotation.x * PI / 180.0f; + float ry = perspectiveRotation.y * PI / 180.0f; + float rz = rotation * PI / 180.0f; + + float cx = SDL_cos(rx); + float sx = SDL_sin(rx); + + float cy = SDL_cos(ry); + float sy = SDL_sin(ry); + + float cz = SDL_cos(rz); + float sz = SDL_sin(rz); + + float m00 = cy * cz; + float m01 = cz * sx * sy - cx * sz; + float m02 = sx * sz + cx * cz * sy; + + float m10 = cy * sz; + float m11 = cx * cz + sx * sy * sz; + float m12 = cx * sy * sz - cz * sx; + + float m20 = -sy; + float m21 = cy * sx; + float m22 = cx * cy; + + m00 *= scale.x; + m10 *= scale.x; + m20 *= scale.x; + + m01 *= scale.y; + m11 *= scale.y; + m21 *= scale.y; + + float globalAngle = globalRotation * PI / 180.0f; + float gc = SDL_cos(globalAngle); + float gs = SDL_sin(globalAngle); + + // Rotate X/Y basis around Z + + float r00 = m00 * gc - m01 * gs; + float r01 = m00 * gs + m01 * gc; + + float r10 = m10 * gc - m11 * gs; + float r11 = m10 * gs + m11 * gc; + + float r20 = m20 * gc - m21 * gs; + float r21 = m20 * gs + m21 * gc; + + m00 = r00; + m01 = r01; + + m10 = r10; + m11 = r11; + + m20 = r20; + m21 = r21; + + m00 *= globalScale.x; + m10 *= globalScale.x; + m20 *= globalScale.x; + + m01 *= globalScale.y; + m11 *= globalScale.y; + m21 *= globalScale.y; + + float tx = position.x - (m00 * origin.x + m01 * origin.y) + offset.x; + float ty = position.y - (m10 * origin.x + m11 * origin.y) + offset.y; + float tz = -perspectiveZ - (m20 * origin.x + m21 * origin.y); + + matrix[0] = m00; + matrix[1] = m10; + matrix[2] = m20; + matrix[3] = 0; + + matrix[4] = m01; + matrix[5] = m11; + matrix[6] = m21; + matrix[7] = 0; + + matrix[8] = m02; + matrix[9] = m12; + matrix[10] = m22; + matrix[11] = 0; + + matrix[12] = tx; + matrix[13] = ty; + matrix[14] = tz; + matrix[15] = 1; + } } Vec2 position; @@ -188,6 +314,12 @@ private: float rotation; float globalRotation; + // 3D moments lol + float perspectiveZ; + // X and Y, Z is just rotation + Vec2 perspectiveRotation; + bool perspectiveMode = false; + /* Silently added to position */ Vec2i offset; /* Silently added to scale */