viewport rotation

This commit is contained in:
CatWindow 2026-08-15 16:17:37 +03:00
parent 116ba28508
commit c7bbb02473
5 changed files with 105 additions and 44 deletions

View file

@ -80,6 +80,7 @@ DEF_PROP_I(Viewport, OY)
DEF_PROP_F(Viewport, ScaleX) DEF_PROP_F(Viewport, ScaleX)
DEF_PROP_F(Viewport, ScaleY) DEF_PROP_F(Viewport, ScaleY)
DEF_PROP_F(Viewport, Rotation)
void viewportBindingInit(){ void viewportBindingInit(){
VALUE klass = rb_define_class("Viewport", rb_cObject); VALUE klass = rb_define_class("Viewport", rb_cObject);
@ -96,6 +97,7 @@ void viewportBindingInit(){
INIT_PROP_BIND( Viewport, OY, "oy" ); INIT_PROP_BIND( Viewport, OY, "oy" );
INIT_PROP_BIND( Viewport, ScaleX, "scale_x" ); INIT_PROP_BIND( Viewport, ScaleX, "scale_x" );
INIT_PROP_BIND( Viewport, ScaleY, "scale_y" ); INIT_PROP_BIND( Viewport, ScaleY, "scale_y" );
INIT_PROP_BIND( Viewport, Rotation, "rotation");
INIT_PROP_BIND( Viewport, Color, "color" ); INIT_PROP_BIND( Viewport, Color, "color" );
INIT_PROP_BIND( Viewport, Tone, "tone" ); INIT_PROP_BIND( Viewport, Tone, "tone" );
} }

View file

@ -623,10 +623,14 @@ void Sprite::onGeometryChange(const Scene::Geometry &geo){
* relative to screen origin */ * relative to screen origin */
p->trans.setGlobalOffset(geo.offset()); p->trans.setGlobalOffset(geo.offset());
Viewport* viewport = ViewportElement::getViewport(); Viewport* viewport = ViewportElement::getViewport();
if (viewport) if (viewport) {
p->trans.setGlobalScale(Vec2(viewport->getScaleX(), viewport->getScaleY())); 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.setGlobalScale(Vec2(1.0, 1.0));
p->trans.setGlobalRotation(0);
}
p->sceneRect.setSize(geo.rect.size()); p->sceneRect.setSize(geo.rect.size());
p->sceneOrig = geo.orig; p->sceneOrig = geo.orig;

View file

@ -43,15 +43,17 @@
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// added global rotation and global scale, modified updateMatrix(), using SDL funcs instead of math.h
#ifndef TRANSFORM_H #ifndef TRANSFORM_H
#define TRANSFORM_H #define TRANSFORM_H
#include "etc-internal.h" #include "etc-internal.h"
#include <math.h>
#include <SDL3/SDL_stdinc.h> #include <SDL3/SDL_stdinc.h>
constexpr float PI = 3.14159265358979323846f;
class Transform{ class Transform{
public: public:
Transform() Transform()
@ -68,7 +70,9 @@ public:
Vec2 &getPosition() { return position; } Vec2 &getPosition() { return position; }
Vec2 &getOrigin() { return origin; } Vec2 &getOrigin() { return origin; }
Vec2 &getScale() { return scale; } Vec2 &getScale() { return scale; }
Vec2 &getGlobalScale() { return globalScale; }
float getRotation() { return rotation; } float getRotation() { return rotation; }
float getGlobalRotation() { return globalRotation; }
Vec2i getPositionI() const{ Vec2i getPositionI() const{
return Vec2i(position.x, position.y); return Vec2i(position.x, position.y);
@ -98,6 +102,11 @@ public:
dirty = true; dirty = true;
} }
void setGlobalRotation(float value){
globalRotation = value;
dirty = true;
}
void setGlobalOffset(const Vec2i &value){ void setGlobalOffset(const Vec2i &value){
offset = value; offset = value;
dirty = true; dirty = true;
@ -121,23 +130,54 @@ private:
void updateMatrix(){ void updateMatrix(){
if (rotation >= 360 || rotation < -360) if (rotation >= 360 || rotation < -360)
rotation = (float)SDL_fmod(rotation, 360); rotation = (float)SDL_fmod(rotation, 360);
if (rotation < 0)
rotation += 360;
float angle = rotation * 3.141592654f / 180.0f; if (globalRotation >= 360 || globalRotation < -360)
float cosine = (float) SDL_cos(angle); globalRotation = (float)SDL_fmod(globalRotation, 360);
float sine = (float) SDL_sin(angle);
// 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 sxc = scale.x * cosine;
float syc = scale.y * cosine; float syc = scale.y * cosine;
float sxs = scale.x * sine; float sxs = scale.x * sine;
float sys = scale.y * 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; // object matrix
matrix[1] = -sxs * globalScale.y; float a = sxc * globalScale.x;
matrix[4] = sys * globalScale.x; float b = -sxs * globalScale.y;
matrix[5] = syc * 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[12] = tx;
matrix[13] = ty; matrix[13] = ty;
} }
@ -146,6 +186,7 @@ private:
Vec2 origin; Vec2 origin;
Vec2 scale; Vec2 scale;
float rotation; float rotation;
float globalRotation;
/* Silently added to position */ /* Silently added to position */
Vec2i offset; Vec2i offset;

View file

@ -46,6 +46,7 @@ struct ViewportPrivate{
double scaleX; double scaleX;
double scaleY; double scaleY;
double rotation;
EtcTemps tmp; EtcTemps tmp;
@ -56,6 +57,7 @@ struct ViewportPrivate{
tone(&tmp.tone), tone(&tmp.tone),
scaleX(1.0), scaleX(1.0),
scaleY(1.0), scaleY(1.0),
rotation(0.0),
isOnScreen(false) isOnScreen(false)
{ {
rect->set(x, y, width, height); rect->set(x, y, width, height);
@ -141,6 +143,7 @@ DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.orig.y)
DEF_ATTR_RD_SIMPLE(Viewport, ScaleX, double, p->scaleX) DEF_ATTR_RD_SIMPLE(Viewport, ScaleX, double, p->scaleX)
DEF_ATTR_RD_SIMPLE(Viewport, ScaleY, double, p->scaleY) 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, Rect, Rect&, *p->rect)
DEF_ATTR_SIMPLE(Viewport, Color, Color&, *p->color) DEF_ATTR_SIMPLE(Viewport, Color, Color&, *p->color)
@ -186,6 +189,16 @@ void Viewport::setScaleY(double value){
notifyGeometryChange(); notifyGeometryChange();
} }
void Viewport::setRotation(double value){
guardDisposed();
if (p->rotation == value)
return;
p->rotation = value;
notifyGeometryChange();
}
void Viewport::initDynAttribs(){ void Viewport::initDynAttribs(){
p->rect = new Rect(*p->rect); p->rect = new Rect(*p->rect);
p->color = new Color; p->color = new Color;

View file

@ -43,6 +43,7 @@ public:
DECL_ATTR( OY, int ) DECL_ATTR( OY, int )
DECL_ATTR( ScaleX, double ) DECL_ATTR( ScaleX, double )
DECL_ATTR( ScaleY, double ) DECL_ATTR( ScaleY, double )
DECL_ATTR( Rotation, double )
DECL_ATTR( Color, Color& ) DECL_ATTR( Color, Color& )
DECL_ATTR( Tone, Tone& ) DECL_ATTR( Tone, Tone& )