feat: updated transforms

main
Sara 2024-12-23 18:48:52 +01:00
parent 5b690a2e8d
commit b486f09939
13 changed files with 104 additions and 27 deletions

View File

@ -17,7 +17,8 @@ env = Environment(CCFLAGS=[
'-fno-exceptions', '-fno-exceptions',
'-Wall', '-Wpedantic', '-Wextra', '-Werror', '-Wall', '-Wpedantic', '-Wextra', '-Werror',
'-O0', '-g3', '-Isrc', '-O0', '-g3', '-Isrc',
'-DPROJECTNAME=\\\"'+project+'\\\"' '-DPROJECTNAME=\\\"'+project+'\\\"',
'-DDEBUG'
], ],
LINKFLAGS=[ LINKFLAGS=[
'-lSDL2', '-lSDL2_image', '-lm', '-lSDL2', '-lSDL2_image', '-lm',

View File

@ -29,7 +29,8 @@ CanvasEngine::CanvasEngine() {
SDL_Quit(); SDL_Quit();
return; return;
} }
this->window = SDL_CreateWindow(PROJECTNAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1000, 800, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE); if(this->window == nullptr) { this->window = SDL_CreateWindow(PROJECTNAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1000, 800, SDL_WINDOW_RESIZABLE | SDL_WINDOW_FULLSCREEN_DESKTOP);
if(this->window == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create window, SDL error: %s", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create window, SDL error: %s", SDL_GetError());
IMG_Quit(); IMG_Quit();
SDL_Quit(); SDL_Quit();

View File

@ -1,4 +1,5 @@
#include "transform.hpp" #include "transform.hpp"
#include <cassert>
namespace ce { namespace ce {
void Transform::translate_by(Vecf const &translation) { void Transform::translate_by(Vecf const &translation) {
@ -22,17 +23,20 @@ Vecf Transform::up() const {
} }
Transform operator *(Transform const &lhs, Transform const &rhs) { Transform operator *(Transform const &lhs, Transform const &rhs) {
return Transform { Transform t{
.position = rhs.position + lhs.position.rotated(rhs.rotation), .position = rhs.position + lhs.position.rotated(rhs.rotation),
.rotation = rhs.rotation + lhs.rotation, .rotation = rhs.rotation + lhs.rotation,
.scale = lhs.scale.scaled(rhs.scale) .scale = lhs.scale.scaled(rhs.scale)
}; };
assert(t.scale.x != 0.f || t.scale.y != 0.f); // !!!
return t;
} }
Transform &operator *=(Transform &lhs, Transform const &rhs) { Transform &operator *=(Transform &lhs, Transform const &rhs) {
lhs.position += rhs.position.rotated(lhs.rotation); lhs.position += lhs.position.rotated(rhs.rotation);
lhs.rotation += rhs.rotation; lhs.rotation += rhs.rotation;
lhs.scale.scale(rhs.scale); lhs.scale.scale(rhs.scale);
assert(lhs.scale.x != 0.f || lhs.scale.y != 0.f); // !!!
return lhs; return lhs;
} }
} }

View File

@ -5,9 +5,9 @@
namespace ce { namespace ce {
struct Transform { struct Transform {
Vecf position; Vecf position{0.f, 0.f};
double rotation; double rotation{0.0};
Vecf scale; Vecf scale{1.f, 1.f};
void translate_by(Vecf const &translation); void translate_by(Vecf const &translation);
void rotate_by(double rotation); void rotate_by(double rotation);
void scale_by(Vecf const &factors); void scale_by(Vecf const &factors);

View File

@ -5,6 +5,10 @@
#include <vector> #include <vector>
namespace ce { namespace ce {
Node::Node(std::string name) {
this->name = name;
}
Node::~Node() { Node::~Node() {
this->destroyed.invoke(); this->destroyed.invoke();
} }
@ -111,7 +115,6 @@ void Node::propagate_post_tick() {
}); });
for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children) for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children)
pair.second->propagate_post_tick(); pair.second->propagate_post_tick();
this->_update_transform();
} }
void Node::propagate_removed() { void Node::propagate_removed() {
@ -121,6 +124,7 @@ void Node::propagate_removed() {
} }
void Node::propagate_draw(SDL_Renderer *render) { void Node::propagate_draw(SDL_Renderer *render) {
this->_update_transform();
if(this->visible) { if(this->visible) {
this->_draw(render); this->_draw(render);
for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children) for(std::pair<std::string const, Node::OwnedPtr> &pair : this->children)

View File

@ -27,7 +27,7 @@ public:
Signal<Node*> child_removed{}; //!< Signal invoked when a child is removed. Signal<Node*> child_removed{}; //!< Signal invoked when a child is removed.
Signal<Node*> child_added{}; //!< Signal invoked when a child is added. Signal<Node*> child_added{}; //!< Signal invoked when a child is added.
public: public:
Node() = default; Node(std::string name);
virtual ~Node(); virtual ~Node();
protected: protected:
virtual void _added(Node *parent [[maybe_unused]]) {} //!< called the moment after the object is added as a child to another node virtual void _added(Node *parent [[maybe_unused]]) {} //!< called the moment after the object is added as a child to another node
@ -38,6 +38,7 @@ protected:
virtual void _update_transform() {} virtual void _update_transform() {}
public: public:
template <class TNode> TNode *get_child(std::string const &name); //!< get a non-owning pointer to a child template <class TNode> TNode *get_child(std::string const &name); //!< get a non-owning pointer to a child
template <class TNode, typename... Args> TNode *create_child(Args... cargs);
void add_child(Node::OwnedPtr &child); //!< add a child, the caller must own the pointer void add_child(Node::OwnedPtr &child); //!< add a child, the caller must own the pointer
void set_parent(Node *new_parent); void set_parent(Node *new_parent);
Node *get_parent() const; //!< get the parent. Node *get_parent() const; //!< get the parent.
@ -61,6 +62,12 @@ private:
template <class TNode> TNode *Node::get_child(std::string const &name) { template <class TNode> TNode *Node::get_child(std::string const &name) {
return children.contains(name) ? dynamic_cast<TNode*>(children.at(name).get()) : nullptr; return children.contains(name) ? dynamic_cast<TNode*>(children.at(name).get()) : nullptr;
} }
template <class TNode, typename... Args> TNode *Node::create_child(Args... cargs) {
OwnedPtr owned{std::make_unique<TNode>(cargs...)};
TNode *referenced{dynamic_cast<TNode*>(owned.get())};
this->add_child(owned);
return referenced;
}
} }
#endif // !CANVAS_NODE_HPP #endif // !CANVAS_NODE_HPP

View File

@ -1,6 +1,9 @@
#include "node2d.hpp" #include "node2d.hpp"
#include <cassert>
namespace ce { namespace ce {
Node2D::Node2D(std::string name) : Node(name) {}
void Node2D::_added(Node *parent) { void Node2D::_added(Node *parent) {
this->parent_node2d = dynamic_cast<Node2D*>(parent); this->parent_node2d = dynamic_cast<Node2D*>(parent);
} }
@ -8,14 +11,13 @@ void Node2D::_added(Node *parent) {
void Node2D::_update_transform() { void Node2D::_update_transform() {
if(this->parent_node2d != nullptr) if(this->parent_node2d != nullptr)
this->global_transform = this->transform * this->parent_node2d->get_global_transform(); this->global_transform = this->transform * this->parent_node2d->get_global_transform();
else
this->global_transform = this->transform;
} }
void Node2D::set_transform(Transform const &transform) { void Node2D::set_transform(Transform const &transform) {
this->transform = transform; this->transform = transform;
} this->_update_transform();
Transform &Node2D::get_transform() {
return this->transform;
} }
Transform const &Node2D::get_transform() const { Transform const &Node2D::get_transform() const {
@ -28,12 +30,13 @@ void Node2D::set_global_transform(Transform transform) {
Transform parent = this->parent_node2d->get_global_transform(); Transform parent = this->parent_node2d->get_global_transform();
transform.position -= parent.position.rotated(-parent.rotation); transform.position -= parent.position.rotated(-parent.rotation);
transform.scale_by(parent.scale.reciprocal()); transform.scale_by(parent.scale.reciprocal());
assert(transform.scale.x != 0.f || transform.scale.y != 0.f); // !!!
transform.rotation -= parent.rotation; transform.rotation -= parent.rotation;
} }
this->transform = transform; this->transform = transform;
} }
Transform Node2D::get_global_transform() const { Transform const &Node2D::get_global_transform() const {
return this->global_transform; return this->global_transform;
} }
} }

View File

@ -10,14 +10,14 @@ class Node2D : public Node {
Transform global_transform{}; Transform global_transform{};
Node2D *parent_node2d{nullptr}; Node2D *parent_node2d{nullptr};
public: public:
Node2D(std::string name);
virtual void _added(Node *parent) override; virtual void _added(Node *parent) override;
Node2D *get_parent_node2d() const; Node2D *get_parent_node2d() const;
virtual void _update_transform() override; virtual void _update_transform() override;
void set_transform(Transform const &transform); void set_transform(Transform const &transform);
Transform &get_transform();
Transform const &get_transform() const; Transform const &get_transform() const;
void set_global_transform(Transform transform); void set_global_transform(Transform transform);
Transform get_global_transform() const; Transform const &get_global_transform() const;
}; };
} }

View File

@ -5,23 +5,30 @@
#include <cmath> #include <cmath>
namespace ce { namespace ce {
Sprite::Sprite(std::string const &texture) Sprite::Sprite(std::string name, std::string texture)
: Node2D() { : Node2D(name) {
std::optional<std::shared_ptr<Texture>> asset = CanvasEngine::get_singleton()->get_assets().get_asset<Texture>(texture); std::optional<std::shared_ptr<Texture>> asset = CanvasEngine::get_singleton()->get_assets().get_asset<Texture>(texture);
this->texture = asset.value(); this->texture = asset.value();
} }
void Sprite::_draw(SDL_Renderer *render) { void Sprite::_draw(SDL_Renderer *render) {
if(this->texture == nullptr) if(this->texture == nullptr) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "No texture assigned");
this->set_visible(false);
return; return;
}
int w, h; int w, h;
SDL_QueryTexture(this->texture->get(), NULL, NULL, &w, &h); SDL_QueryTexture(this->texture->get(), NULL, NULL, &w, &h);
Transform transform{this->get_transform()}; Transform transform{this->get_global_transform()};
assert(transform.scale.x != 0 && transform.scale.y != 0); // !!!
float fw{w * transform.scale.x}, fh{h * transform.scale.y};
assert(fw != 0.f && fh != 0.f);
//float fw(w), fh(h);
SDL_Rect src{0, 0, w, h}; SDL_Rect src{0, 0, w, h};
SDL_FRect dst{transform.position.x, transform.position.y, float(w), float(h)}; SDL_FRect dst{transform.position.x - fw/2.f, transform.position.y - fh/2.f, fw, fh};
SDL_RenderCopyExF(render, this->texture->get(), SDL_RenderCopyExF(render, this->texture->get(),
&src, &dst, &src, &dst,
transform.rotation,NULL, transform.rotation * 57.2958f,NULL,
SDL_FLIP_NONE); SDL_FLIP_NONE);
} }
} }

View File

@ -8,7 +8,7 @@ namespace ce {
class Sprite : public Node2D { class Sprite : public Node2D {
std::shared_ptr<Texture> texture{nullptr}; std::shared_ptr<Texture> texture{nullptr};
public: public:
Sprite(std::string const &texture); Sprite(std::string name, std::string texture);
virtual void _draw(SDL_Renderer *render) override; virtual void _draw(SDL_Renderer *render) override;
}; };
} }

View File

@ -1,10 +1,10 @@
#include "level_1.hpp" #include "level_1.hpp"
#include "core/node.hpp" #include "core/node.hpp"
#include "core/sprite.hpp" #include "test_node.hpp"
void Level1::instantiate() { void Level1::instantiate() {
ce::Node::OwnedPtr &root_ptr{this->get_owned_root()}; ce::Node::OwnedPtr &root_ptr{this->get_owned_root()};
root_ptr.reset(new ce::Node()); root_ptr.reset(new ce::Node("root"));
ce::Node::OwnedPtr sprite{std::make_unique<ce::Sprite>("neocat")}; ce::Node::OwnedPtr node{std::make_unique<TestNode>()};
root->add_child(sprite); root->add_child(node);
} }

33
src/test_node.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "test_node.hpp"
#include "core/math/transform.hpp"
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_timer.h>
#include <cmath>
TestNode::TestNode()
: ce::Node2D("TestNode") {
this->sprite = this->create_child<ce::Sprite>("neocat", "neocat");
}
void TestNode::_first_tick() {
ce::Transform st{this->sprite->get_global_transform()};
st.position.x += 200;
this->sprite->set_global_transform(st);
}
void TestNode::_tick(double const &delta) {
ce::Node2D::_tick(delta);
ce::Transform trans{this->get_transform()};
trans.position.x = 500 + std::sin(SDL_GetTicks64() * 0.001) * 100.f;
trans.position.y = 500 + std::cos(SDL_GetTicks64() * 0.001) * 100.f;
trans.rotate_by(delta * 10.f);
this->set_transform(trans);
}
void TestNode::_draw(SDL_Renderer *render) {
ce::Node2D::_draw(render);
ce::Transform trans{this->get_global_transform()};
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_FRect rect{trans.position.x-101.f, trans.position.y-101.f, 202.f, 202.f};
SDL_RenderDrawRectF(render, &rect);
}

17
src/test_node.hpp Normal file
View File

@ -0,0 +1,17 @@
#ifndef TEST_NODE_HPP
#define TEST_NODE_HPP
#include "core/node2d.hpp"
#include "core/sprite.hpp"
class TestNode : public ce::Node2D {
private:
ce::Sprite *sprite{nullptr};
public:
TestNode();
virtual void _first_tick() override;
virtual void _tick(double const &delta) override;
virtual void _draw(SDL_Renderer *render) override;
};
#endif // !TEST_NODE_HPP