121 lines
3.7 KiB
C++
121 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <iostream>
|
|
#include <ostream>
|
|
#include <sophia/handles.hpp>
|
|
#include <sophia/math.hpp>
|
|
#include <string>
|
|
|
|
namespace sophia {
|
|
|
|
struct TagComponent {
|
|
std::string tag; // entt::hashed_string ?
|
|
uint32_t mask = 0;
|
|
};
|
|
|
|
struct TransformComponent {
|
|
glm::vec3 position{0.f, 0.f, 0.f};
|
|
glm::quat rotation{1.f, 0.f, 0.f, 0.f};
|
|
glm::vec3 scale{1.f, 1.f, 1.f};
|
|
|
|
glm::mat4 mat4() const {
|
|
return glm::translate(glm::mat4{1.f}, position) * glm::mat4_cast(rotation) *
|
|
glm::scale(glm::mat4{1.f}, scale);
|
|
}
|
|
|
|
glm::mat3 normalMatrix() const {
|
|
return glm::mat3{glm::transpose(glm::inverse(mat4()))};
|
|
}
|
|
|
|
friend std::ostream& operator<<(std::ostream& os,
|
|
const TransformComponent& transform) {
|
|
os << "TransformComponent {\n"
|
|
<< " Position: (" << transform.position.x << ", "
|
|
<< transform.position.y << ", " << transform.position.z << ")\n"
|
|
<< " Rotation (w, x, y, z): (" << transform.rotation.w << ", "
|
|
<< transform.rotation.x << ", " << transform.rotation.y << ", "
|
|
<< transform.rotation.z << ")\n"
|
|
<< " Scale: (" << transform.scale.x << ", " << transform.scale.y << ", "
|
|
<< transform.scale.z << ")\n"
|
|
<< "}";
|
|
return os;
|
|
}
|
|
};
|
|
|
|
struct MeshComponent {
|
|
MeshHandle handle;
|
|
};
|
|
|
|
/**
|
|
* A textured quad in the XY plane, placed by the entity's TransformComponent.
|
|
* Only rotation around Z is meaningful.
|
|
*/
|
|
struct SpriteComponent {
|
|
// Invalid draws a solid quad in `color`.
|
|
TextureHandle texture = INVALID_HANDLE;
|
|
glm::vec4 color{1.f, 1.f, 1.f, 1.f};
|
|
|
|
// Size in world units, before the transform's scale.
|
|
glm::vec2 size{1.f, 1.f};
|
|
// Point on the sprite, from (0, 0) to (1, 1) across its size, that sits at
|
|
// the transform's position and that it rotates around.
|
|
glm::vec2 pivot{0.5f, 0.5f};
|
|
// Region of the texture to draw, as normalized (u0, v0, u1, v1).
|
|
glm::vec4 uvRect{0.f, 0.f, 1.f, 1.f};
|
|
|
|
// Higher draws on top. Ties are broken by the transform's position.z.
|
|
s32 sortOrder = 0;
|
|
|
|
// Maps the unit quad (0, 0)-(1, 1) to world space: to the sprite's
|
|
// rectangle around its pivot, then by `transform`.
|
|
glm::mat4 getModel(const TransformComponent& transform) const {
|
|
return transform.mat4() *
|
|
glm::translate(glm::mat4{1.f}, glm::vec3{-pivot * size, 0.f}) *
|
|
glm::scale(glm::mat4{1.f}, glm::vec3{size, 1.f});
|
|
}
|
|
};
|
|
|
|
struct CameraComponent {
|
|
struct Orthographic {
|
|
float height = 10.f;
|
|
float nearPlane = -1.f;
|
|
float farPlane = 1.f;
|
|
};
|
|
|
|
struct Perspective {
|
|
float fov = glm::radians(60.f);
|
|
float nearPlane = 0.1f;
|
|
float farPlane = 100.f;
|
|
};
|
|
|
|
enum class Projection { Orthographic, Perspective };
|
|
|
|
Projection projection = Projection::Orthographic;
|
|
Orthographic ortho;
|
|
Perspective perspective;
|
|
|
|
glm::mat4 getProjection(float aspect) const {
|
|
if (projection == Projection::Perspective) {
|
|
return glm::perspective(perspective.fov, aspect, perspective.nearPlane,
|
|
perspective.farPlane);
|
|
}
|
|
|
|
float halfHeight = ortho.height / 2.f;
|
|
float halfWidth = halfHeight * aspect;
|
|
return glm::ortho(-halfWidth, halfWidth, -halfHeight, halfHeight,
|
|
ortho.nearPlane, ortho.farPlane);
|
|
}
|
|
|
|
// World -> clip space for this camera placed by `transform`. The view
|
|
// ignores the transform's scale; zoom is the projection's job.
|
|
glm::mat4 getViewProjection(const TransformComponent& transform,
|
|
float aspect) const {
|
|
glm::mat4 world = glm::translate(glm::mat4{1.f}, transform.position) *
|
|
glm::mat4_cast(transform.rotation);
|
|
return getProjection(aspect) * glm::inverse(world);
|
|
}
|
|
};
|
|
|
|
} // namespace sophia
|