first release
This commit is contained in:
98
openVulkanoCpp/Scene/AABB.hpp
Normal file
98
openVulkanoCpp/Scene/AABB.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
#include <glm/glm.hpp>
|
||||
#include "../Base/IInitable.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
/**
|
||||
* \brief A class that represents an axis aligned bounding box
|
||||
*/
|
||||
class AABB final : public virtual IInitable
|
||||
{
|
||||
glm::vec3 min, max;
|
||||
|
||||
public:
|
||||
AABB() : min(INFINITY), max(-INFINITY) {}
|
||||
~AABB() = default;
|
||||
|
||||
/**
|
||||
* \brief Initiates the AABB to min=Inf, max=-Inf
|
||||
*/
|
||||
void Init() override
|
||||
{
|
||||
min = glm::vec3(INFINITY);
|
||||
max = glm::vec3(-INFINITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initiates the AABB to a single point (min=max=point)
|
||||
* \param point The point that should be used as min and max of the AABB
|
||||
*/
|
||||
void Init(const glm::vec3& point)
|
||||
{
|
||||
min = max = point;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initiates the AABB from some other AABB
|
||||
* \param other The other AABB that should be copied
|
||||
*/
|
||||
void Init(const AABB& other)
|
||||
{
|
||||
min = other.GetMin();
|
||||
max = other.GetMax();
|
||||
}
|
||||
|
||||
const glm::vec3& GetMin() const { return min; }
|
||||
|
||||
const glm::vec3& GetMax() const { return max; }
|
||||
|
||||
void Grow(const glm::vec3& point)
|
||||
{
|
||||
min = glm::min(min, point);
|
||||
max = glm::max(max, point);
|
||||
}
|
||||
|
||||
void Grow(const AABB& otherAABB)
|
||||
{
|
||||
min = glm::min(min, otherAABB.GetMin());
|
||||
max = glm::max(max, otherAABB.GetMax());
|
||||
}
|
||||
|
||||
void Grow(const AABB& otherAABB, glm::mat4x4 transformation)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
glm::vec3 GetDiagonal() const
|
||||
{
|
||||
return max - min;
|
||||
}
|
||||
|
||||
glm::vec3 GetCenter() const
|
||||
{
|
||||
return min + (GetDiagonal() * 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if the AABB overlaps with an other AABB
|
||||
* \param other The other AABB that should be checked
|
||||
* \return true if the AABB overlaps with the other, false if not
|
||||
*/
|
||||
bool IsOverlapping(const AABB& other) const
|
||||
{
|
||||
return !(other.min.x > max.x || other.max.x < min.x || other.min.y > max.y || other.max.y < min.y || other.min.z > max.z || other.max.z < min.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resets the AABB to min=Inf, max=-Inf, same as Init()
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
169
openVulkanoCpp/Scene/Camera.hpp
Normal file
169
openVulkanoCpp/Scene/Camera.hpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#pragma once
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
class Camera : public Node
|
||||
{
|
||||
protected:
|
||||
float nearPlane, farPlane;
|
||||
float width, height;
|
||||
public:
|
||||
glm::mat4x4 projection, view, viewProjection;
|
||||
|
||||
Camera() = default;
|
||||
virtual ~Camera() = default;
|
||||
|
||||
public:
|
||||
void Init(float width, float height, float nearPlane, float farPlane)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->nearPlane = nearPlane;
|
||||
this->farPlane = farPlane;
|
||||
Node::Init();
|
||||
UpdateProjectionMatrix();
|
||||
}
|
||||
|
||||
virtual void SetSize(const float& width, const float& height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
UpdateProjectionMatrix();
|
||||
}
|
||||
|
||||
void SetNearPlane(float nearPlane)
|
||||
{
|
||||
this->nearPlane = nearPlane;
|
||||
}
|
||||
|
||||
void SetFarPlane(float farPlane)
|
||||
{
|
||||
this->farPlane = farPlane;
|
||||
}
|
||||
|
||||
|
||||
float NearPlane() const
|
||||
{
|
||||
return nearPlane;
|
||||
}
|
||||
|
||||
float FarPlane() const
|
||||
{
|
||||
return farPlane;
|
||||
}
|
||||
|
||||
virtual void UpdateProjectionMatrix() = 0;
|
||||
|
||||
void UpdateViewProjectionMatrix()
|
||||
{ // In vulkan the screen space is defined as y=0=top and y=1=bottom and thus the coordinate have to be flipped
|
||||
viewProjection = projection * glm::mat4x4(1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1) * view;
|
||||
}
|
||||
|
||||
void UpdateWorldMatrix(const glm::mat4x4& parentWorldMat) override
|
||||
{
|
||||
Node::UpdateWorldMatrix(parentWorldMat);
|
||||
view = glm::inverse(GetWorldMatrix());
|
||||
UpdateViewProjectionMatrix();
|
||||
}
|
||||
|
||||
const glm::mat4x4& GetViewProjectionMatrix() const
|
||||
{
|
||||
return viewProjection;
|
||||
}
|
||||
|
||||
const glm::mat4x4* GetViewProjectionMatrixPointer() const
|
||||
{
|
||||
return &viewProjection;
|
||||
}
|
||||
};
|
||||
|
||||
class PerspectiveCamera : public Camera
|
||||
{
|
||||
protected:
|
||||
float fov, aspect;
|
||||
|
||||
public:
|
||||
void Init(float fovDegrees, float width, float height, float nearPlane, float farPlane)
|
||||
{
|
||||
this->fov = glm::radians(fovDegrees);
|
||||
aspect = width / height;
|
||||
Camera::Init(width, height, nearPlane, farPlane);
|
||||
}
|
||||
|
||||
void SetSize(const float& width, const float& height) override
|
||||
{
|
||||
aspect = width / height;
|
||||
Camera::SetSize(width, height);
|
||||
}
|
||||
|
||||
void SetAspect(const float& aspect)
|
||||
{
|
||||
this->aspect = aspect;
|
||||
Camera::SetSize(aspect, 1);
|
||||
}
|
||||
|
||||
void SetFovX(const float& fov)
|
||||
{
|
||||
SetFov(2 * atan(tan(fov * 0.5f) * aspect));
|
||||
}
|
||||
|
||||
void SetFovXRad(const float& fov)
|
||||
{
|
||||
SetFovRad(2 * atan(tan(fov * 0.5f) * aspect));
|
||||
}
|
||||
|
||||
void SetFov(const float& fov)
|
||||
{
|
||||
SetFovRad(glm::radians(fov));
|
||||
}
|
||||
|
||||
void SetFovRad(const float& fov)
|
||||
{
|
||||
this->fov = fov;
|
||||
}
|
||||
|
||||
float GetFov() const
|
||||
{
|
||||
return glm::degrees(fov);
|
||||
}
|
||||
|
||||
float GetFovX() const
|
||||
{
|
||||
return 2 * atan(tan(GetFov() * 0.5f) * aspect);
|
||||
}
|
||||
|
||||
float GetFovRad() const
|
||||
{
|
||||
return fov;
|
||||
}
|
||||
|
||||
float GetFovXRad() const
|
||||
{
|
||||
return 2 * atan(tan(fov * 0.5f) * aspect);
|
||||
}
|
||||
|
||||
void UpdateProjectionMatrix() override
|
||||
{
|
||||
projection = glm::perspectiveLH_ZO(fov, aspect, nearPlane, farPlane);
|
||||
UpdateViewProjectionMatrix();
|
||||
}
|
||||
};
|
||||
|
||||
class OrthographicCamera : public Camera
|
||||
{
|
||||
public:
|
||||
void UpdateProjectionMatrix() override
|
||||
{
|
||||
const float widthHalf = width * 0.5f, heightHalf = height * 0.5f;
|
||||
projection = glm::orthoLH_ZO(-widthHalf, widthHalf, -heightHalf, heightHalf, nearPlane, farPlane);
|
||||
UpdateViewProjectionMatrix();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
26
openVulkanoCpp/Scene/Drawable.cpp
Normal file
26
openVulkanoCpp/Scene/Drawable.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "Drawable.hpp"
|
||||
#include "Scene.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
void Drawable::SetScene(Scene* scene)
|
||||
{
|
||||
if (this->scene == scene) return;
|
||||
if (scene && this->scene) throw std::runtime_error("Drawable has been associated with a scene already!");
|
||||
this->scene = scene;
|
||||
if(scene) scene->RegisterDrawable(this);
|
||||
}
|
||||
|
||||
void Drawable::RemoveNode(Node* node)
|
||||
{
|
||||
Utils::Remove(nodes, node);
|
||||
if (nodes.empty())
|
||||
{
|
||||
scene = nullptr;
|
||||
scene->RemoveDrawable(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
82
openVulkanoCpp/Scene/Drawable.hpp
Normal file
82
openVulkanoCpp/Scene/Drawable.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include "../Base/ICloseable.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Material.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
class Node;
|
||||
class Scene;
|
||||
|
||||
struct Drawable : virtual public ICloseable
|
||||
{
|
||||
std::vector<Node*> nodes;
|
||||
Scene* scene = nullptr;
|
||||
Geometry* mesh = nullptr;
|
||||
Material* material = nullptr;
|
||||
|
||||
public:
|
||||
Drawable() = default;
|
||||
|
||||
explicit Drawable(const Drawable* toCopy)
|
||||
{
|
||||
mesh = toCopy->mesh;
|
||||
material = toCopy->material;
|
||||
}
|
||||
|
||||
virtual ~Drawable()
|
||||
{
|
||||
if(mesh) Drawable::Close();
|
||||
}
|
||||
|
||||
Drawable* Copy() const
|
||||
{
|
||||
return new Drawable(this);
|
||||
}
|
||||
|
||||
void Init(Geometry* mesh, Material* material)
|
||||
{
|
||||
if (this->mesh || this->material) throw std::runtime_error("Drawable is already initialized.");
|
||||
this->mesh = mesh;
|
||||
this->material = material;
|
||||
}
|
||||
|
||||
void Init(Drawable* drawable)
|
||||
{
|
||||
if (mesh || material) throw std::runtime_error("Drawable is already initialized.");
|
||||
this->mesh = drawable->mesh;
|
||||
this->material = drawable->material;
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
if (!nodes.empty()) throw std::runtime_error("Drawable is still being used!!!");
|
||||
mesh = nullptr;
|
||||
material = nullptr;
|
||||
}
|
||||
|
||||
Scene* GetScene() const
|
||||
{
|
||||
return scene;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Node;
|
||||
friend class Scene;
|
||||
|
||||
void AddNode(Node* node)
|
||||
{
|
||||
if (!mesh) throw std::runtime_error("Drawable is not initialized.");
|
||||
if (Utils::Contains(nodes, node)) throw std::runtime_error("A drawable must not use the same node more than once.");
|
||||
nodes.push_back(node);
|
||||
}
|
||||
|
||||
void SetScene(Scene* scene);
|
||||
|
||||
void RemoveNode(Node* node);
|
||||
};
|
||||
}
|
||||
}
|
||||
206
openVulkanoCpp/Scene/Geometry.hpp
Normal file
206
openVulkanoCpp/Scene/Geometry.hpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include "Vertex.hpp"
|
||||
#include "../Base/Logger.hpp"
|
||||
#include "../Base/Utils.hpp"
|
||||
#include "../Base/ICloseable.hpp"
|
||||
#include "AABB.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
enum class VertexIndexType
|
||||
{
|
||||
UINT16 = sizeof(uint16_t), UINT32 = sizeof(uint32_t)
|
||||
};
|
||||
|
||||
struct Geometry : public virtual ICloseable
|
||||
{
|
||||
uint32_t vertexCount = 0, indexCount = 0;
|
||||
Vertex* vertices;
|
||||
void* indices;
|
||||
VertexIndexType indexType;
|
||||
AABB aabb;
|
||||
ICloseable* renderGeo = nullptr;
|
||||
|
||||
Vertex* GetVertices() const { return vertices; }
|
||||
void* GetIndices() const { return indices; }
|
||||
uint16_t* GetIndices16() const { return static_cast<uint16_t*>(indices); }
|
||||
uint32_t* GetIndices32() const { return static_cast<uint32_t*>(indices); }
|
||||
uint32_t GetIndexCount() const { return indexCount; }
|
||||
uint32_t GetVertexCount() const { return vertexCount; }
|
||||
|
||||
static Geometry* LoadFromFile(const std::string file)
|
||||
{
|
||||
Geometry* mesh = new Geometry();
|
||||
mesh->InitFromFile(file);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Geometry() : vertexCount(0), indexCount(0), vertices(nullptr), indices(nullptr), indexType(VertexIndexType::UINT16) {}
|
||||
|
||||
~Geometry()
|
||||
{
|
||||
if (vertices) Geometry::Close();
|
||||
}
|
||||
|
||||
void InitFromFile(const std::string file)
|
||||
{
|
||||
Assimp::Importer importer;
|
||||
|
||||
const uint32_t flags = aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_GenNormals |
|
||||
aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials | aiProcess_GenUVCoords | aiProcess_TransformUVCoords |
|
||||
aiProcess_ConvertToLeftHanded | aiProcess_PreTransformVertices | aiProcess_OptimizeGraph;
|
||||
|
||||
const aiScene* scene = importer.ReadFile(file, flags);
|
||||
if (!scene) throw std::runtime_error("Failed to load file \"" + file + "\" Error: " + importer.GetErrorString());
|
||||
if (!scene->HasMeshes()) throw std::runtime_error("File \"" + file + "\" does not have any meshes");
|
||||
if (scene->mNumMeshes > 1) Logger::DATA->warn("File {0} contains more than one mesh. Only first one will be loaded", file);
|
||||
Init(scene->mMeshes[0]);
|
||||
importer.FreeScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates the arrays for the vertices and indices. They will not be filled!
|
||||
* \param vertexCount The amount of vertices that will be used
|
||||
* \param indexCount The amount of indices that will be used
|
||||
*/
|
||||
void Init(uint32_t vertexCount, uint32_t indexCount)
|
||||
{
|
||||
if (this->vertexCount || this->indexCount) throw std::runtime_error("Geometry is already initialized.");
|
||||
this->vertexCount = vertexCount;
|
||||
this->indexCount = indexCount;
|
||||
indexType = (vertexCount > UINT16_MAX) ? VertexIndexType::UINT32 : VertexIndexType::UINT16;
|
||||
vertices = new Vertex[vertexCount];
|
||||
indices = malloc(static_cast<size_t>(Utils::EnumAsInt(indexType)) * indexCount);
|
||||
renderGeo = nullptr;
|
||||
}
|
||||
|
||||
void Init(aiMesh* mesh)
|
||||
{
|
||||
aabb.Init();
|
||||
Init(mesh->mNumVertices, mesh->mNumFaces * 3); // Reserve the space for the data
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
|
||||
{
|
||||
vertices[i].Set(mesh->mVertices[i]);
|
||||
if (mesh->HasNormals()) vertices[i].SetNormal(mesh->mNormals[i]);
|
||||
if (mesh->HasTangentsAndBitangents())
|
||||
{
|
||||
vertices[i].SetTangentAndBiTangent(mesh->mTangents[i], mesh->mBitangents[i]);
|
||||
}
|
||||
if (mesh->HasTextureCoords(0)) vertices[i].SetTextureCoordinates(mesh->mTextureCoords[0][i]);
|
||||
if (mesh->HasVertexColors(0)) vertices[i].SetColor(mesh->mColors[0][i]);
|
||||
aabb.Grow(vertices[i].position);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
|
||||
{
|
||||
const aiFace face = mesh->mFaces[i];
|
||||
if (face.mNumIndices != 3) throw std::runtime_error("Mesh is not a triangle mesh!");
|
||||
for (unsigned int j = 0; j < face.mNumIndices; j++)
|
||||
{
|
||||
if (indexType == VertexIndexType::UINT16)
|
||||
{
|
||||
static_cast<uint16_t*>(indices)[i * face.mNumIndices + j] = static_cast<uint16_t>(face.mIndices[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cast<uint32_t*>(indices)[i * face.mNumIndices + j] = face.mIndices[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO load bones
|
||||
//TODO load materials
|
||||
}
|
||||
|
||||
void InitCube(float x = 1, float y = 1, float z = 1, glm::vec4 color = glm::vec4(1))
|
||||
{
|
||||
Init(24, 36);
|
||||
SetIndices(new uint32_t[indexCount]{
|
||||
0, 1, 2, 0, 2, 3, // front face index data
|
||||
4, 5, 6, 4, 6, 7, // back face index data
|
||||
8, 9, 10, 8, 10, 11, // top face index data
|
||||
12, 13, 14, 12, 14, 15, // bottom face index data
|
||||
16, 17, 18, 16, 18, 19, // left face index data
|
||||
20, 21, 22, 20, 22, 23 // right face index data
|
||||
}, indexCount);
|
||||
x *= 0.5f; y *= 0.5f; z *= 0.5f;
|
||||
int i = 0;
|
||||
// front face vertex data
|
||||
vertices[i++].Set(-x, +y, -z, +0, +0, -1, +0, +0);
|
||||
vertices[i++].Set(-x, -y, -z, +0, +0, -1, +0, +1);
|
||||
vertices[i++].Set(+x, -y, -z, +0, +0, -1, +1, +1);
|
||||
vertices[i++].Set(+x, +y, -z, +0, +0, -1, +1, +0);
|
||||
// back face vertex data
|
||||
vertices[i++].Set(-x, +y, +z, +0, +0, +1, +1, +0);
|
||||
vertices[i++].Set(+x, +y, +z, +0, +0, +1, +0, +0);
|
||||
vertices[i++].Set(+x, -y, +z, +0, +0, +1, +0, +1);
|
||||
vertices[i++].Set(-x, -y, +z, +0, +0, +1, +1, +1);
|
||||
// top face vertex data
|
||||
vertices[i++].Set(-x, -y, -z, +0, +1, +0, +0, +0);
|
||||
vertices[i++].Set(-x, -y, +z, +0, +1, +0, +0, +1);
|
||||
vertices[i++].Set(+x, -y, +z, +0, +1, +0, +1, +1);
|
||||
vertices[i++].Set(+x, -y, -z, +0, +1, +0, +1, +0);
|
||||
// bottom face vertex data
|
||||
vertices[i++].Set(-x, +y, -z, +0, -1, +0, +1, +0);
|
||||
vertices[i++].Set(+x, +y, -z, +0, -1, +0, +0, +0);
|
||||
vertices[i++].Set(+x, +y, +z, +0, -1, +0, +0, +1);
|
||||
vertices[i++].Set(-x, +y, +z, +0, -1, +0, +1, +1);
|
||||
// Fill in the left face vertex data
|
||||
vertices[i++].Set(-x, +y, +z, -1, +0, +0, +0, +0);
|
||||
vertices[i++].Set(-x, -y, +z, -1, +0, +0, +0, +1);
|
||||
vertices[i++].Set(-x, -y, -z, -1, +0, +0, +1, +1);
|
||||
vertices[i++].Set(-x, +y, -z, -1, +0, +0, +1, +0);
|
||||
// Fill in the right face vertex data
|
||||
vertices[i++].Set(+x, +y, -z, +1, +0, +0, +0, +0);
|
||||
vertices[i++].Set(+x, -y, -z, +1, +0, +0, +0, +1);
|
||||
vertices[i++].Set(+x, -y, +z, +1, +0, +0, +1, +1);
|
||||
vertices[i].Set(+x, +y, +z, +1, +0, +0, +1, +0);
|
||||
|
||||
for(i = 0; i < vertexCount; i++)
|
||||
{
|
||||
vertices[i].color = color;
|
||||
}
|
||||
}
|
||||
|
||||
void SetIndices(const uint32_t* data, uint32_t size, uint32_t offset = 0) const
|
||||
{
|
||||
size += offset;
|
||||
for(; offset < size; offset++)
|
||||
{
|
||||
if (indexType == VertexIndexType::UINT16)
|
||||
{
|
||||
static_cast<uint16_t*>(indices)[offset] = static_cast<uint16_t>(data[offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cast<uint32_t*>(indices)[offset] = data[offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
vertexCount = 0;
|
||||
indexCount = 0;
|
||||
Free();
|
||||
renderGeo->Close();
|
||||
renderGeo = nullptr;
|
||||
}
|
||||
|
||||
void Free()
|
||||
{
|
||||
if(vertices) delete[] vertices;
|
||||
free(indices);
|
||||
vertices = nullptr;
|
||||
indices = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
13
openVulkanoCpp/Scene/Material.hpp
Normal file
13
openVulkanoCpp/Scene/Material.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "Shader.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
struct Material
|
||||
{
|
||||
Shader* shader;
|
||||
};
|
||||
}
|
||||
}
|
||||
9
openVulkanoCpp/Scene/Node.cpp
Normal file
9
openVulkanoCpp/Scene/Node.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
const glm::mat4x4 Node::IDENTITY = glm::mat4(1);
|
||||
}
|
||||
}
|
||||
212
openVulkanoCpp/Scene/Node.hpp
Normal file
212
openVulkanoCpp/Scene/Node.hpp
Normal file
@@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <glm/glm.hpp>
|
||||
#include "../Base/Utils.hpp"
|
||||
#include "../Base/IInitable.hpp"
|
||||
#include "../Base/ICloseable.hpp"
|
||||
#include "Drawable.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
class Scene;
|
||||
|
||||
enum class UpdateFrequency
|
||||
{
|
||||
Always, Sometimes, Never
|
||||
};
|
||||
|
||||
struct Node : virtual IInitable, virtual ICloseable
|
||||
{
|
||||
friend Scene;
|
||||
protected:
|
||||
static const glm::mat4x4 IDENTITY;
|
||||
public:
|
||||
glm::mat4x4 localMat, worldMat;
|
||||
bool enabled = true;
|
||||
Node* parent = nullptr;
|
||||
Scene* scene = nullptr;
|
||||
std::vector<Node*> children;
|
||||
std::vector<Drawable*> drawables;
|
||||
UpdateFrequency matrixUpdateFrequency = UpdateFrequency::Never;
|
||||
ICloseable* renderNode = nullptr;
|
||||
|
||||
public:
|
||||
Node() = default;
|
||||
virtual ~Node() = default;
|
||||
|
||||
void Init() override
|
||||
{
|
||||
if (parent || scene || !children.empty() || !drawables.empty()) throw std::runtime_error("Node already initialized");
|
||||
localMat = worldMat = IDENTITY;
|
||||
enabled = true;
|
||||
parent = nullptr;
|
||||
children = std::vector<Node*>();
|
||||
drawables = std::vector<Drawable*>();
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
children.clear();
|
||||
if (renderNode) renderNode->Close();
|
||||
parent = nullptr;
|
||||
scene = nullptr;
|
||||
enabled = false;
|
||||
if (!children.empty()) Logger::SCENE->warn("Closing Node that has children!");
|
||||
for (Node* child : children)
|
||||
{
|
||||
child->SetParent(nullptr);
|
||||
}
|
||||
children.clear();
|
||||
for(size_t i = drawables.size(); i > 0; i--)
|
||||
{
|
||||
RemoveDrawable(drawables[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AddChild(Node* node)
|
||||
{
|
||||
node->SetParent(this);
|
||||
children.push_back(node);
|
||||
node->UpdateWorldMatrix(worldMat);
|
||||
}
|
||||
|
||||
void AddChild(Drawable* drawable)
|
||||
{
|
||||
AddDrawable(drawable);
|
||||
}
|
||||
|
||||
void RemoveChild(Node* node)
|
||||
{
|
||||
if (node->parent == this)
|
||||
{
|
||||
Utils::Remove(children, node);
|
||||
node->SetParent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveChild(Drawable* drawable)
|
||||
{
|
||||
RemoveDrawable(drawable);
|
||||
}
|
||||
|
||||
void AddDrawable(Drawable* drawable)
|
||||
{
|
||||
if (scene) drawable->SetScene(scene);
|
||||
else if (drawable->GetScene()) Logger::SCENE->warn("Drawable is already associated with a scene, but the node it was added to is not!");
|
||||
drawable->AddNode(this);
|
||||
drawables.push_back(drawable);
|
||||
}
|
||||
|
||||
void RemoveDrawable(Drawable* drawable)
|
||||
{
|
||||
drawable->RemoveNode(this);
|
||||
Utils::Remove(drawables, drawable);
|
||||
}
|
||||
|
||||
void SetMatrix(glm::mat4x4 mat)
|
||||
{
|
||||
localMat = mat;
|
||||
UpdateWorldMatrix(parent ? parent->GetWorldMatrix() : IDENTITY);
|
||||
}
|
||||
|
||||
const glm::mat4x4& GetMatrix() const
|
||||
{
|
||||
return localMat;
|
||||
}
|
||||
|
||||
const glm::mat4x4& GetWorldMatrix() const
|
||||
{
|
||||
return worldMat;
|
||||
}
|
||||
|
||||
bool IsEnabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void Enable()
|
||||
{
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
Node* GetParent() const
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
Scene* GetScene() const
|
||||
{
|
||||
return scene;
|
||||
}
|
||||
|
||||
bool IsRoot() const
|
||||
{
|
||||
return scene && parent == this;
|
||||
}
|
||||
|
||||
UpdateFrequency GetUpdateFrequency()
|
||||
{
|
||||
return matrixUpdateFrequency;
|
||||
}
|
||||
|
||||
void SetUpdateFrequency(UpdateFrequency frequency)
|
||||
{
|
||||
if (!children.empty()) throw std::runtime_error("The update must not be changed for nodes with children.");
|
||||
this->matrixUpdateFrequency = frequency;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void UpdateWorldMatrix(const glm::mat4x4& parentWorldMat)
|
||||
{
|
||||
worldMat = parentWorldMat * localMat;
|
||||
for (const auto& node : children)
|
||||
{
|
||||
node->UpdateWorldMatrix(worldMat);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void SetParent(Node* parent)
|
||||
{
|
||||
if (this->parent && parent) throw std::runtime_error("Node already has a parent! Nodes must not be used multiple times!");
|
||||
this->parent = parent;
|
||||
if(parent && parent != this) this->scene = parent->scene;
|
||||
if (!parent) SetScene(nullptr);
|
||||
}
|
||||
|
||||
void SetScene(Scene* scene)
|
||||
{
|
||||
if (this->scene && scene) throw std::runtime_error("Node already has a scene!");
|
||||
this->scene = scene;
|
||||
for (const auto& node : children)
|
||||
{
|
||||
node->SetScene(scene);
|
||||
}
|
||||
if (scene)
|
||||
{
|
||||
for (size_t i = 0; i < drawables.size(); i++)
|
||||
{
|
||||
Scene* drawableScene = drawables[i]->GetScene();
|
||||
if(drawableScene)
|
||||
{
|
||||
if(drawableScene != scene)
|
||||
{
|
||||
Logger::SCENE->warn("Drawable is already associated with a scene! Creating copy.");
|
||||
drawables[i] = drawables[i]->Copy();
|
||||
}
|
||||
}
|
||||
drawables[i]->SetScene(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
89
openVulkanoCpp/Scene/Scene.hpp
Normal file
89
openVulkanoCpp/Scene/Scene.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#include "Node.hpp"
|
||||
#include "Camera.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
struct Scene : virtual public IInitable, virtual public ICloseable
|
||||
{
|
||||
Node* root;
|
||||
std::vector<Drawable*> shapeList;
|
||||
Shader* shader;
|
||||
Camera* camera;
|
||||
|
||||
public:
|
||||
Scene() : root(nullptr) {}
|
||||
|
||||
virtual ~Scene()
|
||||
{
|
||||
if (root) Scene::Close();
|
||||
}
|
||||
|
||||
void Init() override
|
||||
{
|
||||
Node* newRoot = new Node();
|
||||
newRoot->Init();
|
||||
Init(newRoot);
|
||||
}
|
||||
|
||||
void Init(Node* root)
|
||||
{
|
||||
if (root->GetParent()) throw std::runtime_error("Node has a parent! Only nodes without a parent may be a root node!");
|
||||
root->SetScene(this);
|
||||
root->SetParent(root);
|
||||
this->root = root;
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
Node* GetRoot() const
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
void RegisterDrawable(Drawable* drawable)
|
||||
{
|
||||
if (drawable->GetScene() != this) drawable->SetScene(this);
|
||||
if (Utils::Contains(shapeList, drawable)) return; // Prevent duplicate entries
|
||||
shapeList.push_back(drawable);
|
||||
}
|
||||
|
||||
void RemoveDrawable(Drawable* drawable)
|
||||
{
|
||||
Utils::Remove(shapeList, drawable);
|
||||
drawable->SetScene(nullptr);
|
||||
}
|
||||
|
||||
void SetCamera(Camera* camera)
|
||||
{
|
||||
this->camera = camera;
|
||||
}
|
||||
|
||||
Camera* GetCamera() const
|
||||
{
|
||||
return camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if the scene is valid and attempts to fix problems.
|
||||
*/
|
||||
void Validate()
|
||||
{
|
||||
for (Drawable* drawable : shapeList)
|
||||
{
|
||||
if(drawable->GetScene() != this)
|
||||
{
|
||||
if (!drawable->GetScene()) drawable->SetScene(this);
|
||||
else Logger::SCENE->error("Scene is linked with drawable from different scene!!!"); //TODO handle
|
||||
}
|
||||
}
|
||||
//TODO check node tree
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
38
openVulkanoCpp/Scene/Shader.hpp
Normal file
38
openVulkanoCpp/Scene/Shader.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "../Base/ICloseable.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Scene
|
||||
{
|
||||
enum class Topology
|
||||
{
|
||||
PointList, LineList, LineStripe, TriangleList, TriangleStripe
|
||||
};
|
||||
|
||||
struct Shader : public virtual ICloseable
|
||||
{
|
||||
std::string vertexShaderName, fragmentShaderName;
|
||||
Topology topology = Topology::TriangleList;
|
||||
ICloseable* renderShader = nullptr;
|
||||
|
||||
Shader() = default;
|
||||
~Shader() { if (renderShader) Shader::Close(); }
|
||||
|
||||
void Init(const std::string& vertexShaderName, const std::string& fragmentShaderName)
|
||||
{
|
||||
if (renderShader) throw std::runtime_error("Shader already initialized!");
|
||||
this->vertexShaderName = vertexShaderName;
|
||||
this->fragmentShaderName = fragmentShaderName;
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
renderShader->Close();
|
||||
renderShader = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
178
openVulkanoCpp/Scene/Vertex.hpp
Normal file
178
openVulkanoCpp/Scene/Vertex.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
#include <glm/glm.hpp>
|
||||
#include <assimp/vector2.h>
|
||||
#include <assimp/vector3.h>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec3 position, normal, tangent, biTangent, textureCoordinates;
|
||||
glm::vec4 color;
|
||||
|
||||
Vertex() = default;
|
||||
|
||||
Vertex(const aiVector3D& pos) : position(pos.x, pos.y, pos.z), normal(), tangent(), biTangent(), textureCoordinates(), color()
|
||||
{}
|
||||
|
||||
Vertex(const float& x, const float& y, const float& z, const float& nx, const float& ny, const float& nz, const float& u, const float& v)
|
||||
: position({ x, y, z }), normal({ nx, ny, nz }), tangent(), biTangent(), textureCoordinates({ u, v, 0 }), color()
|
||||
{}
|
||||
|
||||
Vertex(const glm::vec3& position, const glm::vec3& normal, const glm::vec3& tangent, const glm::vec3& biTangent, const glm::vec2& textureCoordinates)
|
||||
: position(position), normal(normal), tangent(tangent), biTangent(biTangent), textureCoordinates(textureCoordinates, 0), color()
|
||||
{}
|
||||
|
||||
Vertex(const glm::vec3 & position, const glm::vec3 & normal, const glm::vec3 & tangent, const glm::vec3 & biTangent, const glm::vec3 & textureCoordinates)
|
||||
: position(position), normal(normal), tangent(tangent), biTangent(biTangent), textureCoordinates(textureCoordinates), color()
|
||||
{}
|
||||
|
||||
~Vertex() = default;
|
||||
|
||||
void Set(const float& x, const float& y, const float& z)
|
||||
{
|
||||
position = { x, y, z };
|
||||
}
|
||||
|
||||
void Set(const glm::vec3& position)
|
||||
{
|
||||
this->position = position;
|
||||
}
|
||||
|
||||
void Set(const aiVector3D& position)
|
||||
{
|
||||
this->position = { position.x, position.y, position.z };
|
||||
}
|
||||
|
||||
void Set(const float& x, const float& y, const float& z, const float& nx, const float& ny, const float& nz, const float& u, const float& v)
|
||||
{
|
||||
this->position = { x, y, z };
|
||||
this->normal = { nx, ny, nz };
|
||||
this->textureCoordinates = { u, v, 0 };
|
||||
}
|
||||
|
||||
void Set(const glm::vec3& position, const glm::vec3& normal, const glm::vec2& textureCoordinates)
|
||||
{
|
||||
this->position = position;
|
||||
this->normal = normal;
|
||||
this->textureCoordinates = { textureCoordinates, 0 };
|
||||
}
|
||||
|
||||
void Set(const glm::vec3& position, const glm::vec3& normal, const glm::vec3& tangent, const glm::vec3& biTangent, const glm::vec2& textureCoordinates)
|
||||
{
|
||||
this->position = position;
|
||||
this->normal = normal;
|
||||
this->tangent = tangent;
|
||||
this->biTangent = biTangent;
|
||||
this->textureCoordinates = { textureCoordinates,0 };
|
||||
}
|
||||
|
||||
void SetNormal(const float& nx, const float& ny, const float& nz)
|
||||
{
|
||||
this->normal = { nx, ny, nz };
|
||||
}
|
||||
|
||||
void SetNormal(const glm::vec3& normal)
|
||||
{
|
||||
this->normal = normal;
|
||||
}
|
||||
|
||||
void SetNormal(const aiVector3D& normal)
|
||||
{
|
||||
this->normal = { normal.x, normal.y, normal.z };
|
||||
}
|
||||
|
||||
void SetTangent(const float& tx, const float& ty, const float& tz)
|
||||
{
|
||||
this->tangent = { tx, ty, tz };
|
||||
}
|
||||
|
||||
void SetTangent(const glm::vec3& tangent)
|
||||
{
|
||||
this->tangent = tangent;
|
||||
}
|
||||
|
||||
void SetTangent(const aiVector3D& tangent)
|
||||
{
|
||||
this->tangent = { tangent.x, tangent.y, tangent.z };
|
||||
}
|
||||
|
||||
void SetTangentAndBiTangent(const float& tx, const float& ty, const float& tz, const float& bx, const float& by, const float& bz)
|
||||
{
|
||||
this->biTangent = { bx, by, bz };
|
||||
this->tangent = { tx, ty, tz };
|
||||
}
|
||||
|
||||
void SetTangentAndBiTangent(const glm::vec3& tangent, const glm::vec3& biTangent)
|
||||
{
|
||||
this->biTangent = biTangent;
|
||||
this->tangent = tangent;
|
||||
}
|
||||
|
||||
void SetTangentAndBiTangent(const aiVector3D& tangent, const aiVector3D& biTangent)
|
||||
{
|
||||
this->tangent = { tangent.x, tangent.y, tangent.z };
|
||||
this->biTangent = { biTangent.x, biTangent.y, biTangent.z };
|
||||
}
|
||||
|
||||
void SetBiTangent(const float& bx, const float& by, const float& bz)
|
||||
{
|
||||
this->biTangent = { bx, by, bz };
|
||||
}
|
||||
|
||||
void SetBiTangent(const glm::vec3& biTangent)
|
||||
{
|
||||
this->biTangent = biTangent;
|
||||
}
|
||||
|
||||
void SetBiTangent(const aiVector3D& biTangent)
|
||||
{
|
||||
this->biTangent = { biTangent.x, biTangent.y, biTangent.z };
|
||||
}
|
||||
|
||||
void SetTextureCoordinates(const float& u, const float& v)
|
||||
{
|
||||
this->textureCoordinates = { u, v, 0 };
|
||||
}
|
||||
|
||||
void SetTextureCoordinates(const float& u, const float& v, const float& w)
|
||||
{
|
||||
this->textureCoordinates = { u, v, w };
|
||||
}
|
||||
|
||||
void SetTextureCoordinates(const glm::vec2& textureCoordinates)
|
||||
{
|
||||
this->textureCoordinates = { textureCoordinates, 0 };
|
||||
}
|
||||
|
||||
void SetTextureCoordinates(const glm::vec3& textureCoordinates)
|
||||
{
|
||||
this->textureCoordinates = textureCoordinates;
|
||||
}
|
||||
|
||||
void SetTextureCoordinates(const aiVector2D& textureCoordinates)
|
||||
{
|
||||
this->textureCoordinates = { textureCoordinates.x, textureCoordinates.y, 0 };
|
||||
}
|
||||
|
||||
void SetTextureCoordinates(const aiVector3D& textureCoordinates)
|
||||
{
|
||||
this->textureCoordinates = { textureCoordinates.x, textureCoordinates.y, textureCoordinates.z };
|
||||
}
|
||||
|
||||
void SetColor(const float& r, const float& g, const float& b, const float& a = 1)
|
||||
{
|
||||
color = { r,g,b,a };
|
||||
}
|
||||
|
||||
void SetColor(const glm::vec4& color)
|
||||
{
|
||||
this->color = color;
|
||||
}
|
||||
|
||||
void SetColor(const aiColor4D& color)
|
||||
{
|
||||
this->color = { color.r, color.g, color.b, color.a };
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user