making prefab work
This commit is contained in:
@ -24,7 +24,7 @@ public:
|
|||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_items[i].~Item();
|
m_items[i].~Item();
|
||||||
}
|
}
|
||||||
delete m_items;
|
::operator delete[](m_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
Array(Array&& other) {
|
Array(Array&& other) {
|
||||||
@ -37,6 +37,25 @@ public:
|
|||||||
other.m_items = nullptr;
|
other.m_items = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array& operator=(Array&& other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
// Destroy current contents
|
||||||
|
for (unsigned int i = 0; i < m_size; ++i)
|
||||||
|
m_items[i].~Item();
|
||||||
|
::operator delete[](m_items);
|
||||||
|
|
||||||
|
// Move from other
|
||||||
|
m_items = other.m_items;
|
||||||
|
m_size = other.m_size;
|
||||||
|
m_capacity = other.m_capacity;
|
||||||
|
|
||||||
|
other.m_items = nullptr;
|
||||||
|
other.m_size = 0;
|
||||||
|
other.m_capacity = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Array(const Array&) = delete;
|
Array(const Array&) = delete;
|
||||||
public:
|
public:
|
||||||
inline const Size GetSize() const noexcept { return m_size; }
|
inline const Size GetSize() const noexcept { return m_size; }
|
||||||
@ -79,11 +98,11 @@ private:
|
|||||||
|
|
||||||
std::uninitialized_move(
|
std::uninitialized_move(
|
||||||
std::make_move_iterator(m_items),
|
std::make_move_iterator(m_items),
|
||||||
std::make_move_iterator(m_items + m_capacity),
|
std::make_move_iterator(m_items + m_size),
|
||||||
newItems
|
newItems
|
||||||
);
|
);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < m_capacity; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_items[i].~Item();
|
m_items[i].~Item();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,7 +96,7 @@ private:
|
|||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render(Shader& shader) override {
|
void Render(Shader& shader, Scene& scene, unsigned int count) override {
|
||||||
// --- Basic material properties ---
|
// --- Basic material properties ---
|
||||||
shader.setFloat("opacity", m_material.GetOpacity());
|
shader.setFloat("opacity", m_material.GetOpacity());
|
||||||
|
|
||||||
@ -156,12 +156,11 @@ private:
|
|||||||
|
|
||||||
// --- Render mesh ---
|
// --- Render mesh ---
|
||||||
Bind();
|
Bind();
|
||||||
// TODO: support batch render
|
if (count > 1) {
|
||||||
// if (count > 1) {
|
glDrawElementsInstanced(GL_TRIANGLES, static_cast<GLsizei>(m_indices.GetSize()), GL_UNSIGNED_INT, 0, count);
|
||||||
// glDrawElementsInstanced(GL_TRIANGLES, static_cast<GLsizei>(m_indexBuffer.size()), GL_UNSIGNED_INT, 0, count);
|
} else {
|
||||||
// } else {
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indices.GetSize()), GL_UNSIGNED_INT, 0);
|
||||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indices.GetSize()), GL_UNSIGNED_INT, 0);
|
}
|
||||||
// }
|
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@ -192,9 +191,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render(Shader& shader) {
|
void Render(Shader& shader, Scene& scene, unsigned int count) {
|
||||||
for (auto it = Begin(); it != End(); ++it) {
|
for (auto it = Begin(); it != End(); ++it) {
|
||||||
it->Render(shader);
|
it->Render(shader, scene, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
148
engine/include/engine/3d/prefab.hpp
Normal file
148
engine/include/engine/3d/prefab.hpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#ifndef CORE_PREFAB_H_
|
||||||
|
#define CORE_PREFAB_H_
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <corecrt_math_defines.h>
|
||||||
|
#endif
|
||||||
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/gtx/euler_angles.hpp>
|
||||||
|
|
||||||
|
#include "engine/opengl/buffers.h"
|
||||||
|
#include "engine/renderer/renderable.hpp"
|
||||||
|
#include "engine/scene/scene.h"
|
||||||
|
#include "engine/3d/array.hpp"
|
||||||
|
#include "engine/3d/mesh.hpp"
|
||||||
|
|
||||||
|
#include "engine/components/transform.h"
|
||||||
|
#include "engine/components/batch.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class Prefab : public Renderable {
|
||||||
|
public:
|
||||||
|
Prefab(MeshGroup&& mesh) : m_mesh(std::move(mesh)), m_id(++LastID) {}
|
||||||
|
|
||||||
|
const unsigned int GetID() const { return m_id; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Prepare() override {
|
||||||
|
std::cout << "[PREFAB] Prepare called" << std::endl;
|
||||||
|
|
||||||
|
EnsureResources();
|
||||||
|
|
||||||
|
m_mesh.Prepare();
|
||||||
|
|
||||||
|
for (auto it = m_mesh.Begin(); it != m_mesh.End(); ++it) {
|
||||||
|
it->Bind();
|
||||||
|
|
||||||
|
std::cout << "[PREFAB] Configuring instance buffer for mesh" << std::endl;
|
||||||
|
m_instanceBuffer->StartConfigure();
|
||||||
|
std::size_t vec4Size = sizeof(glm::vec4);
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
glEnableVertexAttribArray(3 + i); // use locations 3,4,5,6 for instance matrix
|
||||||
|
glVertexAttribPointer(3 + i, 4, GL_FLOAT, GL_FALSE,
|
||||||
|
sizeof(glm::mat4), (void*)(i * vec4Size));
|
||||||
|
glVertexAttribDivisor(3 + i, 1); // IMPORTANT: one per instance, not per vertex
|
||||||
|
}
|
||||||
|
m_instanceBuffer->EndConfigure();
|
||||||
|
std::cout << "[PREFAB] Finished configuring" << std::endl;
|
||||||
|
|
||||||
|
it->Unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(Shader& shader, Scene& scene, unsigned int count) override {
|
||||||
|
std::cout << "[PREFAB] Render called" << std::endl;
|
||||||
|
Array<entt::entity> batches;
|
||||||
|
|
||||||
|
for (auto [entt, item] : scene.m_registry.view<batch::item>().each()) {
|
||||||
|
if (item.batchId == m_id) {
|
||||||
|
batches.PushBack(entt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[PREFAB] Collected " << batches.GetSize() << " batch items" << std::endl;
|
||||||
|
|
||||||
|
std::vector<glm::mat4> models;
|
||||||
|
models.reserve(batches.GetSize());
|
||||||
|
|
||||||
|
std::cout << "[PREFAB] Starting collecting models..." << std::endl;
|
||||||
|
|
||||||
|
for (auto it = batches.Begin(); it != batches.End(); ++it) {
|
||||||
|
auto &t = scene.m_registry.get<Transform>(*it);
|
||||||
|
glm::mat4 rotation = glm::yawPitchRoll(t.rotation.y, t.rotation.x, t.rotation.z);
|
||||||
|
auto itemModel = glm::translate(glm::mat4(1.f), t.position) * rotation;
|
||||||
|
models.push_back(itemModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[PREFAB] Collected " << models.size() << " models" << std::endl;
|
||||||
|
|
||||||
|
UploadInstances(models.data(), models.size());
|
||||||
|
|
||||||
|
shader.setBool("u_isInstanced", true);
|
||||||
|
shader.setBool("isLight", false);
|
||||||
|
shader.setVec3("currentLightColor", glm::vec3(0.f));
|
||||||
|
|
||||||
|
std::cout << "[PREFAB] Rendering mesh in instanced mode with size = " << models.size() << std::endl;
|
||||||
|
m_mesh.Render(shader, scene, models.size());
|
||||||
|
|
||||||
|
shader.setBool("u_isInstanced", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void EnsureResources(unsigned int count = 0) {
|
||||||
|
if (!m_instanceBuffer) {
|
||||||
|
std::cout << "[PREFAB] Instance buffer init..." << std::endl;
|
||||||
|
m_instanceBuffer = new OpenGL::InstanceBuffer(GL_DYNAMIC_DRAW);
|
||||||
|
OpenGL::Buffer::Bind(m_instanceBuffer);
|
||||||
|
OpenGL::Buffer::Data(m_instanceBuffer, nullptr, sizeof(glm::mat4) * count);
|
||||||
|
OpenGL::Buffer::Unbind(m_instanceBuffer);
|
||||||
|
m_instance_count = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UploadInstances(glm::mat4 *instances, unsigned int count) {
|
||||||
|
std::cout << "[PREFAB] UploadInstances called" << std::endl;
|
||||||
|
|
||||||
|
EnsureResources(count);
|
||||||
|
|
||||||
|
if (count > m_instance_count) {
|
||||||
|
std::cout << "[PREFAB] Reallocate buffer. Current = " << m_instance_count << " ; required = " << count << std::endl;
|
||||||
|
// Optional: reallocate only if you *really* have more instances than before
|
||||||
|
// FIXME: what the hell is m_instance_vbo
|
||||||
|
// glBindBuffer(GL_ARRAY_BUFFER, m_instance_vbo);
|
||||||
|
OpenGL::Buffer::Bind(m_instanceBuffer);
|
||||||
|
OpenGL::Buffer::Data(m_instanceBuffer, nullptr, sizeof(glm::mat4) * count);
|
||||||
|
OpenGL::Buffer::Unbind(m_instanceBuffer);
|
||||||
|
m_instance_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just update the data region — much cheaper
|
||||||
|
std::cout << "[PREFAB] Updating data of instance buffer..." << std::endl;
|
||||||
|
// std::cout << "[PREFAB] buffer target " << (m_instanceBuffer->GetTarget() == GL_ARRAY_BUFFER ? "array buffer" : "other") << std::endl;
|
||||||
|
// std::cout << "[PREFAB] buffer id " << m_instanceBuffer->GetID() << std::endl;
|
||||||
|
std::cout << "count = " << count << std::endl;
|
||||||
|
std::cout << "instances = " << instances << std::endl;
|
||||||
|
OpenGL::Buffer::Bind(m_instanceBuffer);
|
||||||
|
OpenGL::Buffer::SubData(m_instanceBuffer, instances, sizeof(glm::mat4) * count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static unsigned int LastID;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_id;
|
||||||
|
MeshGroup m_mesh;
|
||||||
|
OpenGL::InstanceBuffer* m_instanceBuffer = nullptr;
|
||||||
|
unsigned int m_instance_count = 0;
|
||||||
|
unsigned int m_instance_vbo = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int Prefab::LastID = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CORE_PREFAB_H_
|
||||||
@ -16,7 +16,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void Prepare() = 0;
|
virtual void Prepare() = 0;
|
||||||
virtual void Render(Shader& shader) = 0;
|
virtual void Render(Shader& shader, Scene& scene, unsigned int count = 1) = 0;
|
||||||
|
|
||||||
friend class Core::Renderer;
|
friend class Core::Renderer;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,8 @@
|
|||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class Entity;
|
class Entity;
|
||||||
|
class Renderer;
|
||||||
|
class Prefab;
|
||||||
|
|
||||||
class ENGINE_API Scene {
|
class ENGINE_API Scene {
|
||||||
public:
|
public:
|
||||||
@ -14,8 +16,9 @@ public:
|
|||||||
Entity CreateEntity();
|
Entity CreateEntity();
|
||||||
private:
|
private:
|
||||||
entt::registry m_registry;
|
entt::registry m_registry;
|
||||||
friend class Renderer;
|
friend class Core::Renderer;
|
||||||
friend class Entity;
|
friend class Core::Entity;
|
||||||
|
friend class Core::Prefab;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ENGINE_API Entity {
|
class ENGINE_API Entity {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ void batch::prepare(glm::mat4 *instances, unsigned int count) {
|
|||||||
m_instance_count = count;
|
m_instance_count = count;
|
||||||
} else if (count > m_instance_count) {
|
} else if (count > m_instance_count) {
|
||||||
// Optional: reallocate only if you *really* have more instances than before
|
// Optional: reallocate only if you *really* have more instances than before
|
||||||
|
// FIXME: what the hell is m_instance_vbo
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_instance_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, m_instance_vbo);
|
||||||
OpenGL::Buffer::Bind(m_instanceBuffer);
|
OpenGL::Buffer::Bind(m_instanceBuffer);
|
||||||
OpenGL::Buffer::Data(m_instanceBuffer, nullptr, sizeof(glm::mat4) * count);
|
OpenGL::Buffer::Data(m_instanceBuffer, nullptr, sizeof(glm::mat4) * count);
|
||||||
|
|||||||
@ -68,6 +68,7 @@ namespace OpenGL {
|
|||||||
|
|
||||||
VertexArray::VertexArray() : m_id(0) {
|
VertexArray::VertexArray() : m_id(0) {
|
||||||
glGenVertexArrays(1, &m_id);
|
glGenVertexArrays(1, &m_id);
|
||||||
|
std::cout << "[DEBUG] VArr initialized: " << m_id << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexArray::~VertexArray() {
|
VertexArray::~VertexArray() {
|
||||||
@ -81,6 +82,7 @@ namespace OpenGL {
|
|||||||
void VertexArray::Bind() {
|
void VertexArray::Bind() {
|
||||||
assert(m_id != 0 && "Vertex Array wasn't initialized.");
|
assert(m_id != 0 && "Vertex Array wasn't initialized.");
|
||||||
|
|
||||||
|
std::cout << "[DEBUG] VArr binding: " << m_id << std::endl;
|
||||||
glBindVertexArray(m_id);
|
glBindVertexArray(m_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include "engine/components/light.h"
|
#include "engine/components/light.h"
|
||||||
#include "engine/components/mesh.h"
|
#include "engine/components/mesh.h"
|
||||||
#include "engine/components/batch.h"
|
#include "engine/components/batch.h"
|
||||||
|
#include "engine/3d/prefab.hpp"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@ -61,6 +62,10 @@ void Renderer::Init() {
|
|||||||
for (auto [entt, mesh] : m_scene->m_registry.view<mesh>().each()) {
|
for (auto [entt, mesh] : m_scene->m_registry.view<mesh>().each()) {
|
||||||
mesh.mesh->Prepare();
|
mesh.mesh->Prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto [entt, prefab] : m_scene->m_registry.view<Prefab>().each()) {
|
||||||
|
prefab.Prepare();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::OnWindowResized(int w, int h) {
|
void Renderer::OnWindowResized(int w, int h) {
|
||||||
@ -142,46 +147,54 @@ void Renderer::UpdateView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::RenderScene(Shader &shader) {
|
void Renderer::RenderScene(Shader &shader) {
|
||||||
std::unordered_map<unsigned int, std::vector<entt::entity>> batches;
|
// std::unordered_map<unsigned int, std::vector<entt::entity>> batches;
|
||||||
|
|
||||||
for (auto [entt, item] : m_scene->m_registry.view<batch::item>().each()) {
|
// for (auto [entt, item] : m_scene->m_registry.view<batch::item>().each()) {
|
||||||
if (batches.find(item.batchId) == batches.end())
|
// if (batches.find(item.batchId) == batches.end())
|
||||||
batches.insert(std::make_pair(item.batchId, std::vector<entt::entity>()));
|
// batches.insert(std::make_pair(item.batchId, std::vector<entt::entity>()));
|
||||||
|
|
||||||
batches[item.batchId].push_back(entt);
|
// batches[item.batchId].push_back(entt);
|
||||||
}
|
// }
|
||||||
|
|
||||||
shader.setBool("u_isInstanced", true);
|
// shader.setBool("u_isInstanced", true);
|
||||||
|
// shader.setBool("isLight", false);
|
||||||
|
// shader.setVec3("currentLightColor", glm::vec3(0.f));
|
||||||
|
// for (auto [entt, b, m] : m_scene->m_registry.view<batch, mesh>().each()) {
|
||||||
|
// // check if have items for batch render
|
||||||
|
// if (batches.find(b.id()) == batches.end()) continue;
|
||||||
|
|
||||||
|
// auto &batchItems = batches[b.id()];
|
||||||
|
|
||||||
|
// std::vector<glm::mat4> models;
|
||||||
|
// models.reserve(batchItems.size());
|
||||||
|
|
||||||
|
// for (auto item : batchItems) {
|
||||||
|
// auto &t = m_scene->m_registry.get<Transform>(item);
|
||||||
|
// glm::mat4 rotation = glm::yawPitchRoll(t.rotation.y, t.rotation.x, t.rotation.z);
|
||||||
|
// auto itemModel = glm::translate(glm::mat4(1.f), t.position) * rotation;
|
||||||
|
// models.push_back(itemModel);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// auto prevState = b.Initialized();
|
||||||
|
// b.prepare(models.data(), models.size());
|
||||||
|
// if (!prevState) {
|
||||||
|
// std::cout << "[DEBUG] enabling batch" << std::endl;
|
||||||
|
// // TODO:
|
||||||
|
// // m.object->EnableBatch(b.m_instanceBuffer);
|
||||||
|
// }
|
||||||
|
// m.mesh->Render(shader);
|
||||||
|
// }
|
||||||
|
// shader.setBool("u_isInstanced", false);
|
||||||
|
|
||||||
|
// light cannot be batch rendered (yet :3)
|
||||||
shader.setBool("isLight", false);
|
shader.setBool("isLight", false);
|
||||||
shader.setVec3("currentLightColor", glm::vec3(0.f));
|
shader.setVec3("currentLightColor", glm::vec3(0.f));
|
||||||
for (auto [entt, b, m] : m_scene->m_registry.view<batch, mesh>().each()) {
|
for (auto [entity, prefab] : m_scene->m_registry.view<Prefab>().each()) {
|
||||||
// check if have items for batch render
|
prefab.Render(shader, *m_scene.get(), 1);
|
||||||
if (batches.find(b.id()) == batches.end()) continue;
|
|
||||||
|
|
||||||
auto &batchItems = batches[b.id()];
|
|
||||||
|
|
||||||
std::vector<glm::mat4> models;
|
|
||||||
models.reserve(batchItems.size());
|
|
||||||
|
|
||||||
for (auto item : batchItems) {
|
|
||||||
auto &t = m_scene->m_registry.get<Transform>(item);
|
|
||||||
glm::mat4 rotation = glm::yawPitchRoll(t.rotation.y, t.rotation.x, t.rotation.z);
|
|
||||||
auto itemModel = glm::translate(glm::mat4(1.f), t.position) * rotation;
|
|
||||||
models.push_back(itemModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto prevState = b.Initialized();
|
|
||||||
b.prepare(models.data(), models.size());
|
|
||||||
if (!prevState) {
|
|
||||||
std::cout << "[DEBUG] enabling batch" << std::endl;
|
|
||||||
// TODO:
|
|
||||||
// m.object->EnableBatch(b.m_instanceBuffer);
|
|
||||||
}
|
|
||||||
m.mesh->Render(shader);
|
|
||||||
}
|
}
|
||||||
shader.setBool("u_isInstanced", false);
|
|
||||||
|
|
||||||
for (auto [entity, transf, mesh] : m_scene->m_registry.view<Transform, mesh>(entt::exclude<batch, batch::item>).each()) {
|
// entt::exclude<batch, batch::item>
|
||||||
|
for (auto [entity, transf, mesh] : m_scene->m_registry.view<Transform, mesh>().each()) {
|
||||||
if (mesh.mesh == nullptr) {
|
if (mesh.mesh == nullptr) {
|
||||||
std::cerr << "WARN: Entity doesn't have a mesh to render" << std::endl;
|
std::cerr << "WARN: Entity doesn't have a mesh to render" << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -201,7 +214,7 @@ void Renderer::RenderScene(Shader &shader) {
|
|||||||
|
|
||||||
shader.setMat4("u_model", m_model);
|
shader.setMat4("u_model", m_model);
|
||||||
|
|
||||||
mesh.mesh->Render(shader);
|
mesh.mesh->Render(shader, *m_scene.get(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -344,7 +344,7 @@ Object* Object::LoadFile(const std::string& filename) {
|
|||||||
Vertex v;
|
Vertex v;
|
||||||
v.position = obj->m_vertices[vi];
|
v.position = obj->m_vertices[vi];
|
||||||
v.normal = (ni >= 0) ? obj->m_normals[ni] : glm::vec3(0.0f);
|
v.normal = (ni >= 0) ? obj->m_normals[ni] : glm::vec3(0.0f);
|
||||||
v.uv = (ti >= 0) ? obj->m_texCoords[ti] : glm::vec3(0.0f);
|
v.uv = (ti >= 0) ? obj->m_texCoords[ti] : glm::vec2(0.0f);
|
||||||
|
|
||||||
uint32_t idx = mesh.PushVertex(v);
|
uint32_t idx = mesh.PushVertex(v);
|
||||||
faceIndices.push_back(idx);
|
faceIndices.push_back(idx);
|
||||||
@ -352,6 +352,9 @@ Object* Object::LoadFile(const std::string& filename) {
|
|||||||
// mesh.m_indexBuffer.push_back(mesh.m_vertexBuffer.size() - 1);
|
// mesh.m_indexBuffer.push_back(mesh.m_vertexBuffer.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [0, 1, 2]
|
||||||
|
// ^
|
||||||
|
|
||||||
// triangulate polygon (fan)
|
// triangulate polygon (fan)
|
||||||
if (faceIndices.size() >= 3) {
|
if (faceIndices.size() >= 3) {
|
||||||
for (size_t i = 1; i + 1 < faceIndices.size(); ++i) {
|
for (size_t i = 1; i + 1 < faceIndices.size(); ++i) {
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
set(SANDBOX_TARGET sandbox)
|
set(SANDBOX_TARGET sandbox)
|
||||||
|
set(MODEL_TARGET model)
|
||||||
|
|
||||||
add_executable(${SANDBOX_TARGET} src/main.cpp)
|
add_executable(${SANDBOX_TARGET} src/main.cpp)
|
||||||
|
add_executable(${MODEL_TARGET} src/model.cpp)
|
||||||
|
|
||||||
set_target_properties(${SANDBOX_TARGET} PROPERTIES
|
set_target_properties(${SANDBOX_TARGET} PROPERTIES
|
||||||
CXX_STANDARD 17
|
CXX_STANDARD 17
|
||||||
CXX_STANDARD_REQUIRED ON
|
CXX_STANDARD_REQUIRED ON
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties(${MODEL_TARGET} PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(${SANDBOX_TARGET} PRIVATE ${ENGINE_TARGET})
|
target_link_libraries(${SANDBOX_TARGET} PRIVATE ${ENGINE_TARGET})
|
||||||
|
target_link_libraries(${MODEL_TARGET} PRIVATE ${ENGINE_TARGET})
|
||||||
|
|
||||||
# --- Copy engine.dll and all dependent DLLs next to sandbox.exe ---
|
# --- Copy engine.dll and all dependent DLLs next to sandbox.exe ---
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
@ -16,4 +24,10 @@ if (WIN32)
|
|||||||
$<TARGET_RUNTIME_DLLS:${SANDBOX_TARGET}> $<TARGET_FILE_DIR:${SANDBOX_TARGET}>
|
$<TARGET_RUNTIME_DLLS:${SANDBOX_TARGET}> $<TARGET_FILE_DIR:${SANDBOX_TARGET}>
|
||||||
COMMAND_EXPAND_LISTS
|
COMMAND_EXPAND_LISTS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_custom_command(TARGET ${MODEL_TARGET} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
$<TARGET_RUNTIME_DLLS:${MODEL_TARGET}> $<TARGET_FILE_DIR:${MODEL_TARGET}>
|
||||||
|
COMMAND_EXPAND_LISTS
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@ -17,7 +17,8 @@
|
|||||||
#include "engine/components/camera.h"
|
#include "engine/components/camera.h"
|
||||||
#include "engine/components/mesh.h"
|
#include "engine/components/mesh.h"
|
||||||
#include "engine/components/rotate.h"
|
#include "engine/components/rotate.h"
|
||||||
#include "engine/components/batch.h"
|
|
||||||
|
#include "engine/3d/prefab.hpp"
|
||||||
|
|
||||||
#include "engine/scene/scene.h"
|
#include "engine/scene/scene.h"
|
||||||
#include "engine/input/input.h"
|
#include "engine/input/input.h"
|
||||||
@ -55,13 +56,13 @@ public:
|
|||||||
assert(modelEntity.HasComponent<mesh>() && "model doesn't have any mesh!");
|
assert(modelEntity.HasComponent<mesh>() && "model doesn't have any mesh!");
|
||||||
|
|
||||||
// Cube template (use shared object to avoid reloading 1000 times)
|
// Cube template (use shared object to avoid reloading 1000 times)
|
||||||
std::shared_ptr<Object> cubeObj = std::shared_ptr<Object>(Object::LoadFile("./assets/grass_block/grass_block.obj"));
|
auto cubeObj = Object::LoadFile("./assets/grass_block/grass_block.obj");
|
||||||
auto batchEntt = scene->CreateEntity();
|
auto batchEntt = scene->CreateEntity();
|
||||||
auto& cubeBatch = batchEntt.AddComponent<batch>();
|
auto& cubeBatch = batchEntt.AddComponent<Prefab>(std::move(*cubeObj));
|
||||||
// auto& cubeBatch = batchEntt.GetComponent<batch>();
|
// auto& cubeBatch = batchEntt.GetComponent<batch>();
|
||||||
batchEntt.AddComponent<mesh>(cubeObj);
|
// batchEntt.AddComponent<mesh>(cubeObj);
|
||||||
assert(batchEntt.HasComponent<batch>() && "batch doesn't have any batch component!");
|
// assert(batchEntt.HasComponent<batch>() && "batch doesn't have any batch component!");
|
||||||
assert(batchEntt.HasComponent<mesh>() && "batch doesn't have any mesh component!");
|
// assert(batchEntt.HasComponent<mesh>() && "batch doesn't have any mesh component!");
|
||||||
// Generate 1000 random cubes
|
// Generate 1000 random cubes
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
auto cubeEntity = scene->CreateEntity();
|
auto cubeEntity = scene->CreateEntity();
|
||||||
@ -72,12 +73,12 @@ public:
|
|||||||
|
|
||||||
cubeEntity.AddComponent<Transform>(glm::vec3(x, y, z));
|
cubeEntity.AddComponent<Transform>(glm::vec3(x, y, z));
|
||||||
cubeEntity.AddComponent<rotate>();
|
cubeEntity.AddComponent<rotate>();
|
||||||
cubeEntity.AddComponent<batch::item>(cubeBatch.id());
|
cubeEntity.AddComponent<batch::item>(cubeBatch.GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
Object* floorObj = Object::LoadFile("./assets/common/plane/plane.obj");
|
Object* floorObj = Object::LoadFile("./assets/common/plane/plane.obj");
|
||||||
auto floorEntt = scene->CreateEntity();
|
auto floorEntt = scene->CreateEntity();
|
||||||
floorEntt.AddComponent<Transform>(glm::vec3(0.f), glm::vec3(2.f), glm::vec3(5.f));
|
floorEntt.AddComponent<Transform>(glm::vec3(0.f));
|
||||||
floorEntt.AddComponent<mesh>(std::shared_ptr<Object>(floorObj));
|
floorEntt.AddComponent<mesh>(std::shared_ptr<Object>(floorObj));
|
||||||
assert(floorEntt.HasComponent<mesh>() && "floor doesn't have any mesh component!");
|
assert(floorEntt.HasComponent<mesh>() && "floor doesn't have any mesh component!");
|
||||||
|
|
||||||
|
|||||||
92
sandbox/src/model.cpp
Normal file
92
sandbox/src/model.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/constants.hpp>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/gtx/extended_min_max.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "engine/renderer/wavefront.h"
|
||||||
|
|
||||||
|
#include "engine/app/app.h"
|
||||||
|
|
||||||
|
#include "engine/components/transform.h"
|
||||||
|
#include "engine/components/light.h"
|
||||||
|
#include "engine/components/camera.h"
|
||||||
|
#include "engine/components/mesh.h"
|
||||||
|
#include "engine/components/rotate.h"
|
||||||
|
|
||||||
|
#include "engine/3d/prefab.hpp"
|
||||||
|
|
||||||
|
#include "engine/scene/scene.h"
|
||||||
|
#include "engine/input/input.h"
|
||||||
|
|
||||||
|
#include "engine/api.h"
|
||||||
|
|
||||||
|
using namespace Core;
|
||||||
|
|
||||||
|
class ModelViewer : public IApplication {
|
||||||
|
public:
|
||||||
|
ModelViewer() = default;
|
||||||
|
~ModelViewer() override {}
|
||||||
|
|
||||||
|
void OnInit(std::shared_ptr<Scene> scene) override {
|
||||||
|
m_scene = scene;
|
||||||
|
|
||||||
|
Object* lightObj = Object::LoadFile("./assets/common/sphere/sphere.obj");
|
||||||
|
lightEntity = scene->CreateEntity();
|
||||||
|
lightEntity.AddComponent<Transform>(glm::vec3(5.f, 5.f, 5.f), glm::vec3(0.f));
|
||||||
|
lightEntity.AddComponent<light>(light::LightType::DIRECTIONAL, glm::vec3(1.f, 1.f, 1.f), 1.5f);
|
||||||
|
lightEntity.AddComponent<mesh>(std::shared_ptr<Renderable>(lightObj));
|
||||||
|
assert(lightEntity.HasComponent<mesh>() && "light doesn't have any mesh!");
|
||||||
|
|
||||||
|
cameraEntity = scene->CreateEntity();
|
||||||
|
cameraEntity.AddComponent<camera>();
|
||||||
|
cameraEntity.AddComponent<Transform>(glm::vec3(0.f, 2.f, 2.f));
|
||||||
|
assert(cameraEntity.HasComponent<camera>() && "Camera doesn't have required 'camera' component");
|
||||||
|
assert(cameraEntity.HasComponent<Transform>() && "Camera doesn't have 'transform' component");
|
||||||
|
|
||||||
|
Object* targetObj = Object::LoadFile("./assets/grass_block/grass_block.obj");
|
||||||
|
modelEntity = scene->CreateEntity();
|
||||||
|
modelEntity.AddComponent<Transform>(glm::vec3(0.f, 0.0f, 0.f));
|
||||||
|
modelEntity.AddComponent<mesh>(std::shared_ptr<Renderable>(targetObj));
|
||||||
|
assert(modelEntity.HasComponent<mesh>() && "model doesn't have any mesh!");
|
||||||
|
|
||||||
|
std::cout << "ModelViewer initialized" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnUpdate(Timestep dt) override {
|
||||||
|
m_elapsed += dt.GetMilliseconds();
|
||||||
|
|
||||||
|
if (m_elapsed >= 1000) { // one second passed
|
||||||
|
m_elapsed = 0;
|
||||||
|
double fps = 1 / dt;
|
||||||
|
std::cout << "FPS: " << fps << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEvent(const Event& event) override {
|
||||||
|
if (event.GetType() == EventType::WINDOW_RESIZE) {
|
||||||
|
auto resizeEvent = static_cast<const WindowResizeEvent&>(event);
|
||||||
|
std::cout << "[DEBUG] <EVENT> Window resized to " << resizeEvent.GetWidth() << "x" << resizeEvent.GetHeight() << std::endl;
|
||||||
|
}
|
||||||
|
else if (event.GetType() == EventType::WINDOW_CLOSE) {
|
||||||
|
std::cout << "[DEBUG] <EVENT> Window closing" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
// for internal 1-second timer
|
||||||
|
int m_elapsed;
|
||||||
|
|
||||||
|
std::shared_ptr<Scene> m_scene;
|
||||||
|
|
||||||
|
Entity lightEntity;
|
||||||
|
Entity cameraEntity;
|
||||||
|
Entity modelEntity;
|
||||||
|
};
|
||||||
|
|
||||||
|
IApplication* CreateApplication() {
|
||||||
|
return new ModelViewer();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user