feat: updated transforms
parent
5b690a2e8d
commit
b486f09939
|
@ -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',
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue