From c7bbb024732ceb6ab76485ed077d6468b009035b Mon Sep 17 00:00:00 2001 From: CatWindow Date: Sat, 15 Aug 2026 16:17:37 +0300 Subject: [PATCH] viewport rotation --- binding-mri/viewport-binding.cpp | 16 +++--- src/sprite.cpp | 8 ++- src/transform.h | 93 +++++++++++++++++++++++--------- src/viewport.cpp | 17 +++++- src/viewport.h | 15 +++--- 5 files changed, 105 insertions(+), 44 deletions(-) diff --git a/binding-mri/viewport-binding.cpp b/binding-mri/viewport-binding.cpp index dd5901b..a82553d 100644 --- a/binding-mri/viewport-binding.cpp +++ b/binding-mri/viewport-binding.cpp @@ -80,6 +80,7 @@ DEF_PROP_I(Viewport, OY) DEF_PROP_F(Viewport, ScaleX) DEF_PROP_F(Viewport, ScaleY) +DEF_PROP_F(Viewport, Rotation) void viewportBindingInit(){ VALUE klass = rb_define_class("Viewport", rb_cObject); @@ -91,12 +92,13 @@ void viewportBindingInit(){ _rb_define_method(klass, "initialize", viewportInitialize); - INIT_PROP_BIND( Viewport, Rect, "rect" ); - INIT_PROP_BIND( Viewport, OX, "ox" ); - INIT_PROP_BIND( Viewport, OY, "oy" ); - INIT_PROP_BIND( Viewport, ScaleX, "scale_x"); - INIT_PROP_BIND( Viewport, ScaleY, "scale_y"); - INIT_PROP_BIND( Viewport, Color, "color" ); - INIT_PROP_BIND( Viewport, Tone, "tone" ); + INIT_PROP_BIND( Viewport, Rect, "rect" ); + INIT_PROP_BIND( Viewport, OX, "ox" ); + INIT_PROP_BIND( Viewport, OY, "oy" ); + INIT_PROP_BIND( Viewport, ScaleX, "scale_x" ); + INIT_PROP_BIND( Viewport, ScaleY, "scale_y" ); + INIT_PROP_BIND( Viewport, Rotation, "rotation"); + INIT_PROP_BIND( Viewport, Color, "color" ); + INIT_PROP_BIND( Viewport, Tone, "tone" ); } diff --git a/src/sprite.cpp b/src/sprite.cpp index 907ae13..cfbbeab 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -623,10 +623,14 @@ void Sprite::onGeometryChange(const Scene::Geometry &geo){ * relative to screen origin */ p->trans.setGlobalOffset(geo.offset()); Viewport* viewport = ViewportElement::getViewport(); - if (viewport) + if (viewport) { p->trans.setGlobalScale(Vec2(viewport->getScaleX(), viewport->getScaleY())); - else + p->trans.setGlobalRotation(viewport->getRotation()); + } + else { p->trans.setGlobalScale(Vec2(1.0, 1.0)); + p->trans.setGlobalRotation(0); + } p->sceneRect.setSize(geo.rect.size()); p->sceneOrig = geo.orig; diff --git a/src/transform.h b/src/transform.h index ee69416..8fb4f57 100644 --- a/src/transform.h +++ b/src/transform.h @@ -43,15 +43,17 @@ // //////////////////////////////////////////////////////////// +// added global rotation and global scale, modified updateMatrix(), using SDL funcs instead of math.h #ifndef TRANSFORM_H #define TRANSFORM_H #include "etc-internal.h" -#include #include +constexpr float PI = 3.14159265358979323846f; + class Transform{ public: Transform() @@ -65,10 +67,12 @@ public: matrix[15] = 1; } - Vec2 &getPosition() { return position; } - Vec2 &getOrigin() { return origin; } - Vec2 &getScale() { return scale; } - float getRotation() { return rotation; } + Vec2 &getPosition() { return position; } + Vec2 &getOrigin() { return origin; } + Vec2 &getScale() { return scale; } + Vec2 &getGlobalScale() { return globalScale; } + float getRotation() { return rotation; } + float getGlobalRotation() { return globalRotation; } Vec2i getPositionI() const{ return Vec2i(position.x, position.y); @@ -98,6 +102,11 @@ public: dirty = true; } + void setGlobalRotation(float value){ + globalRotation = value; + dirty = true; + } + void setGlobalOffset(const Vec2i &value){ offset = value; dirty = true; @@ -119,33 +128,65 @@ public: private: void updateMatrix(){ - if (rotation >= 360 || rotation < -360) - rotation = (float) SDL_fmod(rotation, 360); - if (rotation < 0) - rotation += 360; - - float angle = rotation * 3.141592654f / 180.0f; - float cosine = (float) SDL_cos(angle); - float sine = (float) SDL_sin(angle); - float sxc = scale.x * cosine; - 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) * globalScale.x + offset.x; - float ty = ( origin.x * sxs - origin.y * syc + position.y) * globalScale.y + offset.y; - - matrix[0] = sxc * globalScale.x; - matrix[1] = -sxs * globalScale.y; - matrix[4] = sys * globalScale.x; - matrix[5] = syc * globalScale.y; - matrix[12] = tx; - matrix[13] = ty; + if (rotation >= 360 || rotation < -360) + rotation = (float)SDL_fmod(rotation, 360); + + 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; } Vec2 position; Vec2 origin; Vec2 scale; float rotation; + float globalRotation; /* Silently added to position */ Vec2i offset; diff --git a/src/viewport.cpp b/src/viewport.cpp index a273464..456b4dc 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -46,6 +46,7 @@ struct ViewportPrivate{ double scaleX; double scaleY; + double rotation; EtcTemps tmp; @@ -56,6 +57,7 @@ struct ViewportPrivate{ tone(&tmp.tone), scaleX(1.0), scaleY(1.0), + rotation(0.0), isOnScreen(false) { rect->set(x, y, width, height); @@ -139,8 +141,9 @@ void Viewport::update(){ DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.orig.x) DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.orig.y) -DEF_ATTR_RD_SIMPLE(Viewport, ScaleX, double, p->scaleX) -DEF_ATTR_RD_SIMPLE(Viewport, ScaleY, double, p->scaleY) +DEF_ATTR_RD_SIMPLE(Viewport, ScaleX, double, p->scaleX) +DEF_ATTR_RD_SIMPLE(Viewport, ScaleY, double, p->scaleY) +DEF_ATTR_RD_SIMPLE(Viewport, Rotation, double, p->rotation) DEF_ATTR_SIMPLE(Viewport, Rect, Rect&, *p->rect) DEF_ATTR_SIMPLE(Viewport, Color, Color&, *p->color) @@ -186,6 +189,16 @@ void Viewport::setScaleY(double value){ notifyGeometryChange(); } +void Viewport::setRotation(double value){ + guardDisposed(); + + if (p->rotation == value) + return; + + p->rotation = value; + notifyGeometryChange(); +} + void Viewport::initDynAttribs(){ p->rect = new Rect(*p->rect); p->color = new Color; diff --git a/src/viewport.h b/src/viewport.h index b45e7f8..6484f49 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -38,13 +38,14 @@ public: void update(); - DECL_ATTR( Rect, Rect& ) - DECL_ATTR( OX, int ) - DECL_ATTR( OY, int ) - DECL_ATTR( ScaleX, double ) - DECL_ATTR( ScaleY, double ) - DECL_ATTR( Color, Color& ) - DECL_ATTR( Tone, Tone& ) + DECL_ATTR( Rect, Rect& ) + DECL_ATTR( OX, int ) + DECL_ATTR( OY, int ) + DECL_ATTR( ScaleX, double ) + DECL_ATTR( ScaleY, double ) + DECL_ATTR( Rotation, double ) + DECL_ATTR( Color, Color& ) + DECL_ATTR( Tone, Tone& ) void initDynAttribs();