From f70a8b38d05014213fc9bf38cf46066bb84c486c Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 7 Apr 2024 15:10:00 -0700 Subject: [PATCH 01/14] Add memory-buffer for vertex storage --- src/CMakeLists.txt | 10 +---- src/backstage/buffer.cpp | 66 ++++++++++++++++++++++++++++ src/backstage/buffer.h | 94 ++++++++++++++++++++++++++++++++++++++++ src/backstage/config.h | 16 +++++++ src/backstage/mesh.cpp | 13 ++++++ src/backstage/mesh.h | 31 +++++++++---- src/backstage/scene.cpp | 46 ++++++++++---------- src/backstage/scene.h | 34 ++++++++------- src/stage.h | 2 +- 9 files changed, 256 insertions(+), 56 deletions(-) create mode 100644 src/backstage/buffer.cpp create mode 100644 src/backstage/buffer.h create mode 100644 src/backstage/config.h create mode 100644 src/backstage/mesh.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df32df9..8870e33 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,17 +1,11 @@ find_package(TBB REQUIRED) add_library(stage - backstage/camera.h - backstage/image.h + backstage/buffer.cpp + backstage/mesh.cpp backstage/image.cpp - backstage/light.h - backstage/material.h - backstage/mesh.h - backstage/scene.h backstage/scene.cpp - stage.h stage.cpp - stage_c.h stage_c.cpp ) diff --git a/src/backstage/buffer.cpp b/src/backstage/buffer.cpp new file mode 100644 index 0000000..82573fb --- /dev/null +++ b/src/backstage/buffer.cpp @@ -0,0 +1,66 @@ +#include "buffer.h" + +#include + +#include "log.h" + +namespace stage { +namespace backstage { + + +Buffer::Buffer(Buffer& other) { + m_data = other.m_data; + m_size_in_bytes = other.m_size_in_bytes; + m_has_ownership = other.m_has_ownership; + + // other.m_data = nullptr; + other.m_has_ownership = false; +} + +Buffer& +Buffer::operator=(Buffer& other) { + m_data = other.m_data; + m_size_in_bytes = other.m_size_in_bytes; + m_has_ownership = other.m_has_ownership; + + // other.m_data = nullptr; + other.m_has_ownership = false; + return *this; +} + + +Buffer::~Buffer() { + if (m_data != nullptr && m_has_ownership) { + std::free(m_data); + } +} + +void +Buffer::data(uint8_t* blob, size_t size) { + resize(size); + std::memcpy(m_data, blob, m_size_in_bytes); +} + +void +Buffer::data(std::vector blob) { + resize(blob.size()); + std::memcpy(m_data, blob.data(), m_size_in_bytes); +} + +void +Buffer::resize(size_t newsize) { + size_t newsize_in_bytes = newsize; + if (newsize_in_bytes == m_size_in_bytes) return; + if (!m_has_ownership) + throw std::runtime_error("Cannot resize buffer that is not owned"); + + if (m_data != nullptr) { + m_data = (uint8_t*)std::realloc(m_data, newsize_in_bytes); + } else { + m_data = (uint8_t*)std::malloc(newsize_in_bytes); + } + m_size_in_bytes = newsize_in_bytes; +} + +} +} \ No newline at end of file diff --git a/src/backstage/buffer.h b/src/backstage/buffer.h new file mode 100644 index 0000000..b5dbbaa --- /dev/null +++ b/src/backstage/buffer.h @@ -0,0 +1,94 @@ +#pragma once +#include +#include +#include +#include + +namespace stage { +namespace backstage { + +struct Buffer { + Buffer() = default; + Buffer(uint8_t* blob, size_t size) { data(blob, size); } + Buffer(std::vector blob) { data(blob); } + Buffer(Buffer& other); + Buffer& operator=(Buffer& other); + ~Buffer(); + + uint8_t* data() { return m_data; }; + uint8_t* release() { + m_has_ownership = false; + return m_data; + }; + + void data(uint8_t* blob, size_t size); + void data(std::vector blob); + + void resize(size_t newsize); + + size_t size() { return m_size_in_bytes; } + +private: + uint8_t* m_data { nullptr }; + size_t m_size_in_bytes { 0 }; + + bool m_has_ownership { true }; +}; + +template +struct BufferView { + + BufferView() = default; + BufferView(std::shared_ptr& source, size_t offset, size_t size) : m_offset(offset), m_size(size) { + m_buffer = source; + } + + void setBuffer(std::shared_ptr& source) { + m_offset = source->size(); + m_size = 0; + m_buffer = source; + } + + void setBuffer(std::shared_ptr& source, size_t offset, size_t size) { + m_offset = offset; + m_size = size; + m_buffer = source; + } + + T* data() { + if (!m_buffer) return nullptr; + return (T*)(m_buffer->data() + m_offset); + } + + void push_back(const T& element) { + if (!m_buffer) + return; + size_t oldsize_in_bytes = m_buffer->size(); + m_buffer->resize(oldsize_in_bytes + sizeof(T)); + std::memcpy(m_buffer->data() + oldsize_in_bytes, &element, sizeof(T)); + m_size += 1; + } + + void push_back(const std::vector& elements) { + if (!m_buffer) + return; + size_t oldsize_in_bytes = m_buffer->size(); + m_buffer->resize(oldsize_in_bytes + sizeof(T) * elements.size()); + std::memcpy(m_buffer->data() + oldsize_in_bytes, elements.data(), sizeof(T) * elements.size()); + m_size += elements.size(); + } + + size_t sizeInBytes() { return m_size * sizeof(T); } + size_t size() { return m_size; } + size_t offset() { return m_offset; } + + T& operator[](uint32_t id) { return data()[id]; } + +private: + std::shared_ptr m_buffer; + size_t m_offset; + size_t m_size; +}; + +} +} \ No newline at end of file diff --git a/src/backstage/config.h b/src/backstage/config.h new file mode 100644 index 0000000..e442bed --- /dev/null +++ b/src/backstage/config.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include "image.h" +#include "light.h" +#include "material.h" +#include "mesh.h" + +namespace stage { +namespace backstage { + +struct Config { + VertexLayout layout; +}; + +} +} diff --git a/src/backstage/mesh.cpp b/src/backstage/mesh.cpp new file mode 100644 index 0000000..78fb89a --- /dev/null +++ b/src/backstage/mesh.cpp @@ -0,0 +1,13 @@ +#include "mesh.h" + +namespace stage { +namespace backstage { + +Geometry::Geometry(Object& parent) { + vertices.setBuffer(parent.payload); +} + +Object::Object() : payload(std::make_shared()) {} + +} +} \ No newline at end of file diff --git a/src/backstage/mesh.h b/src/backstage/mesh.h index ff8c9f5..6140efe 100644 --- a/src/backstage/mesh.h +++ b/src/backstage/mesh.h @@ -4,32 +4,45 @@ #include #include "math.h" #include "alignment.h" +#include "buffer.h" namespace stage { namespace backstage { -struct DEVICE_ALIGNED AligendVertex { +enum VertexLayout { + VertexLayout_Block_VNT = 0, + VertexLayout_Block_VN, + VertexLayout_Block_VT, + VertexLayout_Block_V, + VertexLayout_Interleaved_VNT, + VertexLayout_Interleaved_VN, + VertexLayout_Interleaved_VT, + VertexLayout_Interleaved_V, +}; + +struct DEVICE_ALIGNED AlignedVertex { DEVICE_ALIGNED stage_vec3f position; DEVICE_ALIGNED stage_vec3f normal; DEVICE_ALIGNED stage_vec2f uv; uint32_t material_id; }; +struct Object; struct Geometry { - public: - std::vector vertices; - std::vector indices; + Geometry(Object& parent); + std::vector indices; + BufferView vertices; }; struct Object { - public: - std::vector geometries; + Object(); + std::shared_ptr payload; + std::vector geometries; }; struct ObjectInstance { - public: - stage_mat4f instance_to_world; - uint32_t object_id; + stage_mat4f instance_to_world; + uint32_t object_id; }; } diff --git a/src/backstage/scene.cpp b/src/backstage/scene.cpp index a23bc0a..4f89e76 100644 --- a/src/backstage/scene.cpp +++ b/src/backstage/scene.cpp @@ -18,16 +18,16 @@ namespace stage { namespace backstage { -std::unique_ptr createScene(std::string scene) { +std::unique_ptr createScene(std::string scene, const Config& config) { std::string extension = std::filesystem::path(scene).extension().string(); std::unique_ptr scene_ptr; try { if (extension == ".obj") - scene_ptr = std::make_unique(scene); + scene_ptr = std::make_unique(scene, config); else if (extension == ".pbrt") - scene_ptr = std::make_unique(scene); + scene_ptr = std::make_unique(scene, config); else if (extension == ".fbx") - scene_ptr = std::make_unique(scene); + scene_ptr = std::make_unique(scene, config); else throw std::runtime_error("Unexpected file format " + extension); } catch (std::runtime_error e) { @@ -37,9 +37,9 @@ std::unique_ptr createScene(std::string scene) { } void -Scene::updateBasePath(std::string scene) { - m_base_path = std::filesystem::absolute(std::filesystem::path(scene)); - m_base_path = m_base_path.parent_path(); +Scene::updateFilePaths(std::string scene) { + m_scene_path = std::filesystem::absolute(std::filesystem::path(scene)); + m_base_path = m_scene_path.parent_path(); } float @@ -128,13 +128,13 @@ Scene::updateSceneScale() { void -OBJScene::loadObj(std::string scene) { +OBJScene::loadObj() { tinyobj::ObjReaderConfig reader_config; reader_config.mtl_search_path = m_base_path.string() + "/"; tinyobj::ObjReader reader; - if (!reader.ParseFromFile(scene, reader_config)) { + if (!reader.ParseFromFile(m_scene_path, reader_config)) { if (!reader.Error().empty()) { throw std::runtime_error(reader.Error()); } @@ -163,7 +163,7 @@ OBJScene::loadObj(std::string scene) { shapes = in_shapes; } - SUCC("Parsed OBJ file " + scene); + SUCC("Parsed OBJ file " + m_scene_path.string()); // Parse materials and textures std::unordered_map texture_index_map; @@ -204,7 +204,7 @@ OBJScene::loadObj(std::string scene) { std::map, uint32_t> index_map; - Geometry g; + Geometry g(obj); // Keep track of all the unique indices we use uint32_t g_n_unique_idx_cnt = 0; @@ -231,7 +231,7 @@ OBJScene::loadObj(std::string scene) { } else { g_index = g_n_unique_idx_cnt++; - AligendVertex vertex; + AlignedVertex vertex; vertex.position = make_vec3(&attrib.vertices[3 * idx.vertex_index]); vertex.normal = make_vec3(&attrib.normals[3 * idx.normal_index]); if (attrib.texcoords.size() > 0) { @@ -239,7 +239,7 @@ OBJScene::loadObj(std::string scene) { } vertex.material_id = mesh.material_ids[f] < 0 ? m_materials.size() - 1 : mesh.material_ids[f]; - g.vertices.emplace_back(vertex); + g.vertices.push_back(vertex); index_map[key] = g_index; } @@ -410,10 +410,10 @@ OBJScene::computeAllSmoothingNormals(tinyobj::attrib_t& attrib, void -PBRTScene::loadPBRT(std::string scene) { +PBRTScene::loadPBRT() { std::shared_ptr pbrt_scene; - pbrt_scene = pbrt::importPBRT(scene); + pbrt_scene = pbrt::importPBRT(m_scene_path); // Flatten hierarchy to avoid the pain of combining hierarchical instance transforms pbrt_scene->makeSingleLevel(); @@ -486,12 +486,12 @@ PBRTScene::loadPBRTObjectsRecursive(std::shared_ptr current, LOG("Parsed material '" + mesh->material->name + "'"); } - Geometry g; + Geometry g(obj); uint32_t g_n_idx_cnt = 0; for (auto& index : mesh->index) { for (int i = 0; i < 3; i++) { - AligendVertex vertex; + AlignedVertex vertex; auto position = mesh->vertex[*(&index.x + i)]; vertex.position = make_vec3(&position.x); @@ -511,7 +511,7 @@ PBRTScene::loadPBRTObjectsRecursive(std::shared_ptr current, } vertex.material_id = material_id; - g.vertices.emplace_back(vertex); + g.vertices.push_back(vertex); g.indices.emplace_back(g_n_idx_cnt++); } } @@ -951,13 +951,13 @@ PBRTScene::loadPBRTSpectrum(pbrt::Spectrum& spectrum) { return clamp(rgb, 0.f, 1.f); } -void FBXScene::loadFBX(std::string scene) { +void FBXScene::loadFBX() { ufbx_load_opts opts = { }; // Optional, pass NULL for defaults opts.progress_cb.fn = nullptr; opts.progress_cb.user = nullptr; ufbx_error error; // Optional, pass NULL if you don't care about errors - ufbx_scene *fbx_scene = ufbx_load_file(scene.c_str(), &opts, &error); + ufbx_scene *fbx_scene = ufbx_load_file(m_scene_path.string().c_str(), &opts, &error); if (!fbx_scene) { throw std::runtime_error(error.description.data); } @@ -1018,7 +1018,7 @@ void FBXScene::loadFBX(std::string scene) { std::map index_map; - Geometry g; + Geometry g(obj); // Keep track of all the unique indices we use uint32_t g_n_unique_idx_cnt = 0; @@ -1038,7 +1038,7 @@ void FBXScene::loadFBX(std::string scene) { ufbx_vec3 position = ufbx_get_vertex_vec3(&fbx_mesh->vertex_position, index); ufbx_vec3 normal = ufbx_get_vertex_vec3(&fbx_mesh->vertex_normal, index); ufbx_vec2 uv = fbx_mesh->vertex_uv.exists ? ufbx_get_vertex_vec2(&fbx_mesh->vertex_uv, index) : ufbx_vec2({0, 0}); - AligendVertex vertex; + AlignedVertex vertex; vertex.position.x = position.x; vertex.position.y = position.y; vertex.position.z = position.z; @@ -1060,7 +1060,7 @@ void FBXScene::loadFBX(std::string scene) { vertex.material_id = m_materials.size() - 1; } - g.vertices.emplace_back(vertex); + g.vertices.push_back(vertex); index_map[index] = g_index; } g.indices.push_back(g_index); diff --git a/src/backstage/scene.h b/src/backstage/scene.h index 3a139ec..9b156c0 100644 --- a/src/backstage/scene.h +++ b/src/backstage/scene.h @@ -7,6 +7,7 @@ #include #include "log.h" +#include "config.h" #include "math.h" #include "camera.h" #include "mesh.h" @@ -59,10 +60,13 @@ struct Scene { float getSceneScale() { return m_scene_scale; } protected: - Scene() {} + Scene(std::string scene, const Config& config) { + updateFilePaths(scene); + m_config = config; + } /* Utility Functions */ - void updateBasePath(std::string scene); + void updateFilePaths(std::string scene); void updateSceneScale(); float luminance(stage_vec3f c); std::filesystem::path getAbsolutePath(std::filesystem::path p); @@ -76,20 +80,22 @@ struct Scene { std::vector m_textures; float m_scene_scale { 1.f }; + std::filesystem::path m_scene_path; std::filesystem::path m_base_path; + Config m_config; }; struct OBJScene : public Scene { public: - OBJScene(std::string scene) : Scene() { - updateBasePath(scene); - loadObj(scene); + OBJScene(std::string scene, const Config& config) : Scene(scene, config) { + loadObj(); updateSceneScale(); SUCC("Finished loading " + std::to_string(m_objects.size()) + " objects and " + std::to_string(m_instances.size()) + " instances."); } private: /* OBJ Parsing */ - void loadObj(std::string scene); + void loadObj(); + void computeSmoothingShape(const tinyobj::attrib_t& in_attrib, const tinyobj::shape_t& in_shape, std::vector>& sorted_ids, unsigned int id_begin, unsigned int id_end, @@ -105,15 +111,14 @@ struct OBJScene : public Scene { struct PBRTScene : public Scene { public: - PBRTScene(std::string scene) : Scene() { - updateBasePath(scene); - loadPBRT(scene); + PBRTScene(std::string scene, const Config& config) : Scene(scene, config) { + loadPBRT(); updateSceneScale(); SUCC("Finished loading " + std::to_string(m_objects.size()) + " objects and " + std::to_string(m_instances.size()) + " instances."); } private: /* PBRT Parsing */ - void loadPBRT(std::string scene); + void loadPBRT(); void loadPBRTObjectsRecursive(std::shared_ptr current, std::map, uint32_t>& object_map, std::map, uint32_t>& material_map, @@ -138,18 +143,17 @@ struct PBRTScene : public Scene { struct FBXScene : public Scene { public: - FBXScene(std::string scene) : Scene() { - updateBasePath(scene); - loadFBX(scene); + FBXScene(std::string scene, const Config& config) : Scene(scene, config) { + loadFBX(); updateSceneScale(); SUCC("Finished loading " + std::to_string(m_objects.size()) + " objects and " + std::to_string(m_instances.size()) + " instances."); } private: - void loadFBX(std::string scene); + void loadFBX(); bool loadFBXTexture(ufbx_texture* texture); }; -std::unique_ptr createScene(std::string scene); +std::unique_ptr createScene(std::string scene, const Config& config = {}); } } \ No newline at end of file diff --git a/src/stage.h b/src/stage.h index 435a32c..26a425d 100644 --- a/src/stage.h +++ b/src/stage.h @@ -24,7 +24,7 @@ using backstage::Camera; using backstage::Image; using backstage::Light; using backstage::OpenPBRMaterial; -using backstage::AligendVertex; +using backstage::AlignedVertex; using backstage::Geometry; using backstage::Object; using backstage::ObjectInstance; From adec758d2c7274386c454c01eb9a2fb1dfe37a3c Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 11 Apr 2024 21:27:13 -0700 Subject: [PATCH 02/14] Add vertex layout options to buffer system --- src/backstage/buffer.cpp | 5 +-- src/backstage/buffer.h | 50 ++++++++++++++++------ src/backstage/mesh.cpp | 91 ++++++++++++++++++++++++++++++++++++++-- src/backstage/mesh.h | 25 ++++++----- src/backstage/scene.cpp | 67 ++++++++++++++++++++--------- 5 files changed, 187 insertions(+), 51 deletions(-) diff --git a/src/backstage/buffer.cpp b/src/backstage/buffer.cpp index 82573fb..962706e 100644 --- a/src/backstage/buffer.cpp +++ b/src/backstage/buffer.cpp @@ -13,7 +13,6 @@ Buffer::Buffer(Buffer& other) { m_size_in_bytes = other.m_size_in_bytes; m_has_ownership = other.m_has_ownership; - // other.m_data = nullptr; other.m_has_ownership = false; } @@ -23,7 +22,6 @@ Buffer::operator=(Buffer& other) { m_size_in_bytes = other.m_size_in_bytes; m_has_ownership = other.m_has_ownership; - // other.m_data = nullptr; other.m_has_ownership = false; return *this; } @@ -48,8 +46,7 @@ Buffer::data(std::vector blob) { } void -Buffer::resize(size_t newsize) { - size_t newsize_in_bytes = newsize; +Buffer::resize(size_t newsize_in_bytes) { if (newsize_in_bytes == m_size_in_bytes) return; if (!m_has_ownership) throw std::runtime_error("Cannot resize buffer that is not owned"); diff --git a/src/backstage/buffer.h b/src/backstage/buffer.h index b5dbbaa..8d1c3c0 100644 --- a/src/backstage/buffer.h +++ b/src/backstage/buffer.h @@ -24,13 +24,14 @@ struct Buffer { void data(uint8_t* blob, size_t size); void data(std::vector blob); - void resize(size_t newsize); + void resize(size_t newsize_in_bytes); size_t size() { return m_size_in_bytes; } private: uint8_t* m_data { nullptr }; size_t m_size_in_bytes { 0 }; + size_t m_capacity_in_bytes { 0 }; bool m_has_ownership { true }; }; @@ -39,55 +40,78 @@ template struct BufferView { BufferView() = default; - BufferView(std::shared_ptr& source, size_t offset, size_t size) : m_offset(offset), m_size(size) { + BufferView(std::shared_ptr source, size_t offset, size_t size, size_t stride = sizeof(T)) : m_offset(offset), m_size(size), m_stride(stride) { m_buffer = source; } - void setBuffer(std::shared_ptr& source) { + void setBuffer(std::shared_ptr source) { m_offset = source->size(); m_size = 0; + m_stride = sizeof(T); m_buffer = source; } - void setBuffer(std::shared_ptr& source, size_t offset, size_t size) { - m_offset = offset; + void setBuffer(std::shared_ptr source, size_t offset, size_t size, size_t stride = sizeof(T)) { + m_offset = source->size() + offset; m_size = size; + m_stride = stride; m_buffer = source; } - T* data() { + uint8_t* data() { if (!m_buffer) return nullptr; - return (T*)(m_buffer->data() + m_offset); + return (m_buffer->data() + m_offset); } void push_back(const T& element) { if (!m_buffer) return; size_t oldsize_in_bytes = m_buffer->size(); - m_buffer->resize(oldsize_in_bytes + sizeof(T)); - std::memcpy(m_buffer->data() + oldsize_in_bytes, &element, sizeof(T)); + if (oldsize_in_bytes <= positionInBuffer()) + m_buffer->resize(oldsize_in_bytes + m_stride); + std::memcpy(m_buffer->data() + positionInBuffer(), &element, sizeof(T)); m_size += 1; } - void push_back(const std::vector& elements) { + void push_back(std::vector& elements) { if (!m_buffer) return; size_t oldsize_in_bytes = m_buffer->size(); - m_buffer->resize(oldsize_in_bytes + sizeof(T) * elements.size()); - std::memcpy(m_buffer->data() + oldsize_in_bytes, elements.data(), sizeof(T) * elements.size()); + if (oldsize_in_bytes <= positionInBuffer()) + m_buffer->resize(positionInBuffer() + m_stride * elements.size()); + + // ERR("elements.size() \t" + std::to_string(elements.size())); + // ERR("m_buffer->size() \t" + std::to_string(m_buffer->size())); + // ERR("positionInBuffer() \t" + std::to_string(positionInBuffer())); + // ERR("m_size \t" + std::to_string(sizeInBytes())); + // std::cout << std::endl; + if (m_stride == sizeof(T)) + std::memcpy(m_buffer->data() + positionInBuffer(), elements.data(), sizeof(T) * elements.size()); + else { + for (size_t i = 0; i < elements.size(); i++) + std::memcpy(m_buffer->data() + positionInBuffer() + (i * m_stride), elements.data() + i, sizeof(T)); + } m_size += elements.size(); } size_t sizeInBytes() { return m_size * sizeof(T); } size_t size() { return m_size; } size_t offset() { return m_offset; } + size_t stride() { return m_stride; } - T& operator[](uint32_t id) { return data()[id]; } + T& operator[](uint32_t id) { + return *(T*)(data() + (id * m_stride)); + } private: std::shared_ptr m_buffer; size_t m_offset; + size_t m_stride; size_t m_size; + + size_t positionInBuffer() { + return (m_offset + m_size * m_stride); + } }; } diff --git a/src/backstage/mesh.cpp b/src/backstage/mesh.cpp index 78fb89a..5add128 100644 --- a/src/backstage/mesh.cpp +++ b/src/backstage/mesh.cpp @@ -1,13 +1,96 @@ #include "mesh.h" +#include "log.h" namespace stage { namespace backstage { -Geometry::Geometry(Object& parent) { - vertices.setBuffer(parent.payload); -} +Geometry::Geometry(Object& parent, std::vector positions, std::vector normals, std::vector uvs, std::vector material_ids, std::vector indices) { + this->indices = indices; + VertexLayout layout = parent.layout(); + layout = VertexLayout_Block_V; + + size_t stride_positions, stride_normals, stride_uvs, stride_material_ids; + stride_positions = stride_normals = stride_uvs = stride_material_ids = 0; + + size_t offset_positions, offset_normals, offset_uvs, offset_material_ids; + offset_positions = offset_normals = offset_uvs = offset_material_ids = 0; + + switch (layout) + { + case VertexLayout_Block_V: + stride_positions = sizeof(stage_vec3f); + offset_positions = 0; + stride_material_ids = sizeof(uint32_t); + offset_material_ids = positions.size() * stride_positions; + break; + case VertexLayout_Block_VN: + stride_positions = sizeof(stage_vec3f); + offset_positions = 0; + stride_normals = sizeof(stage_vec3f); + offset_normals = positions.size() * stride_positions; + stride_material_ids = sizeof(uint32_t); + offset_material_ids = offset_normals + normals.size() * stride_normals; + break; + case VertexLayout_Block_VNT: + stride_positions = sizeof(stage_vec3f); + offset_positions = 0; + stride_normals = sizeof(stage_vec3f); + offset_normals = positions.size() * stride_positions; + stride_uvs = sizeof(stage_vec2f); + offset_uvs = offset_normals + normals.size() * stride_normals; + stride_material_ids = sizeof(uint32_t); + offset_material_ids = offset_uvs + uvs.size() * stride_uvs; + break; + case VertexLayout_Interleaved_V: + offset_positions = 0; + offset_material_ids = sizeof(stage_vec3f); + break; + case VertexLayout_Interleaved_VN: + offset_positions = 0; + offset_normals = sizeof(stage_vec3f); + offset_material_ids = offset_normals + sizeof(stage_vec3f); + break; + case VertexLayout_Interleaved_VNT: + offset_positions = 0; + offset_normals = sizeof(stage_vec3f); + offset_uvs = offset_normals + sizeof(stage_vec3f); + offset_material_ids = offset_uvs + sizeof(stage_vec2f); + break; + default: + break; + } + + if (layout == VertexLayout_Interleaved_V || layout == VertexLayout_Interleaved_VN || layout == VertexLayout_Interleaved_VNT) { + stride_positions = stride_normals = stride_uvs = stride_material_ids = 2 * sizeof(stage_vec3f) + 1 * sizeof(stage_vec2f) + 1 * sizeof(uint32_t); + } -Object::Object() : payload(std::make_shared()) {} + // WARN("offset_positions " + std::to_string(offset_positions)); + // WARN("offset_normals " + std::to_string(offset_normals)); + // WARN("offset_uvs " + std::to_string(offset_uvs)); + // WARN("offset_material_ids " + std::to_string(offset_material_ids)); + + // WARN("stride_positions " + std::to_string(stride_positions)); + // WARN("stride_normals " + std::to_string(stride_normals)); + // WARN("stride_uvs " + std::to_string(stride_uvs)); + // WARN("stride_material_ids " + std::to_string(stride_material_ids)); + + if (layout == VertexLayout_Block_V || layout == VertexLayout_Interleaved_V) + this->positions.setBuffer(parent.data, offset_positions, 0, stride_positions); + if (layout == VertexLayout_Block_VN || layout == VertexLayout_Interleaved_VN) + this->normals.setBuffer(parent.data, offset_normals, 0, stride_normals); + if (layout == VertexLayout_Block_VNT || layout == VertexLayout_Interleaved_VNT) + this->uvs.setBuffer(parent.data, offset_uvs, 0, stride_uvs); + this->material_ids.setBuffer(parent.data, offset_material_ids, 0, stride_material_ids); + + if (layout == VertexLayout_Block_V || layout == VertexLayout_Interleaved_V) + this->positions.push_back(positions); + if (layout == VertexLayout_Block_VN || layout == VertexLayout_Interleaved_VN) + this->normals.push_back(normals); + if (layout == VertexLayout_Block_VNT || layout == VertexLayout_Interleaved_VNT) + this->uvs.push_back(uvs); + this->material_ids.push_back(material_ids); +} +Object::Object(VertexLayout layout) : m_layout(layout), data(std::make_shared()) {} } } \ No newline at end of file diff --git a/src/backstage/mesh.h b/src/backstage/mesh.h index 6140efe..ca921b6 100644 --- a/src/backstage/mesh.h +++ b/src/backstage/mesh.h @@ -10,14 +10,12 @@ namespace stage { namespace backstage { enum VertexLayout { - VertexLayout_Block_VNT = 0, - VertexLayout_Block_VN, - VertexLayout_Block_VT, - VertexLayout_Block_V, - VertexLayout_Interleaved_VNT, + VertexLayout_Interleaved_VNT = 0, VertexLayout_Interleaved_VN, - VertexLayout_Interleaved_VT, VertexLayout_Interleaved_V, + VertexLayout_Block_VNT, + VertexLayout_Block_VN, + VertexLayout_Block_V, }; struct DEVICE_ALIGNED AlignedVertex { @@ -29,15 +27,22 @@ struct DEVICE_ALIGNED AlignedVertex { struct Object; struct Geometry { - Geometry(Object& parent); + Geometry(Object& parent, std::vector positions, std::vector normals, std::vector uvs, std::vector material_ids, std::vector indices); std::vector indices; - BufferView vertices; + BufferView positions; + BufferView normals; + BufferView uvs; + BufferView material_ids; }; struct Object { - Object(); - std::shared_ptr payload; + Object(VertexLayout layout); + std::shared_ptr data; std::vector geometries; + + VertexLayout layout() { return m_layout; } +private: + VertexLayout m_layout; }; struct ObjectInstance { diff --git a/src/backstage/scene.cpp b/src/backstage/scene.cpp index 4f89e76..50855f2 100644 --- a/src/backstage/scene.cpp +++ b/src/backstage/scene.cpp @@ -101,10 +101,10 @@ Scene::updateSceneScale() { // stage_mat4 instance_to_world = make_mat4(&instance_to_world_[0][0]); for (auto& geometry : m_objects[m_instances[instance_id].object_id].geometries) { - auto extent = tbb::parallel_reduce(tbb::blocked_range(0, geometry.vertices.size()), local, [&](const auto& rr, auto ccurrent) { + auto extent = tbb::parallel_reduce(tbb::blocked_range(0, geometry.positions.size()), local, [&](const auto& rr, auto ccurrent) { auto llocal = ccurrent; for (size_t vertex_id = rr.begin(); vertex_id != rr.end(); vertex_id++) { - stage_vec3f vertex = stage_vec3f(instance_to_world * stage_vec4f(geometry.vertices[vertex_id].position, 1.f)); + stage_vec3f vertex = stage_vec3f(instance_to_world * stage_vec4f(geometry.positions[vertex_id], 1.f)); llocal = reduce_fn(std::make_tuple(vertex, vertex), llocal); } return llocal; @@ -198,13 +198,17 @@ OBJScene::loadObj() { m_materials.push_back(OpenPBRMaterial::defaultMaterial()); // Parse meshes - Object obj; + Object obj(m_config.layout); for (const auto& shape : shapes) { const auto& mesh = shape.mesh; std::map, uint32_t> index_map; - Geometry g(obj); + std::vector positions; + std::vector normals; + std::vector uvs; + std::vector material_ids; + std::vector indices; // Keep track of all the unique indices we use uint32_t g_n_unique_idx_cnt = 0; @@ -239,15 +243,21 @@ OBJScene::loadObj() { } vertex.material_id = mesh.material_ids[f] < 0 ? m_materials.size() - 1 : mesh.material_ids[f]; - g.vertices.push_back(vertex); + positions.push_back(vertex.position); + normals.push_back(vertex.normal); + if (attrib.texcoords.size() > 0) { + uvs.push_back(vertex.uv); + } + material_ids.push_back(vertex.material_id); index_map[key] = g_index; } - g.indices.push_back(g_index); + indices.push_back(g_index); } } - LOG("Read geometry (v: " + std::to_string(g.vertices.size()) + ", i: " + std::to_string(g.indices.size()) + ")"); + Geometry g(obj, positions, normals, uvs, material_ids, {}); obj.geometries.push_back(g); + LOG("Read geometry (v: " + std::to_string(g.positions.size()) + ", i: " + std::to_string(g.indices.size()) + ")"); } m_objects.push_back(obj); @@ -469,7 +479,7 @@ PBRTScene::loadPBRTObjectsRecursive(std::shared_ptr current, if (!current || object_map.find(current) != object_map.end()) return; // Load shapes - Object obj; + Object obj(m_config.layout); for (auto& shape : current->shapes) { // Non-triangle shapes are not supported pbrt::TriangleMesh::SP mesh = std::dynamic_pointer_cast(shape); @@ -486,7 +496,11 @@ PBRTScene::loadPBRTObjectsRecursive(std::shared_ptr current, LOG("Parsed material '" + mesh->material->name + "'"); } - Geometry g(obj); + std::vector positions; + std::vector normals; + std::vector uvs; + std::vector material_ids; + std::vector indices; uint32_t g_n_idx_cnt = 0; for (auto& index : mesh->index) { @@ -511,12 +525,17 @@ PBRTScene::loadPBRTObjectsRecursive(std::shared_ptr current, } vertex.material_id = material_id; - g.vertices.push_back(vertex); - g.indices.emplace_back(g_n_idx_cnt++); + positions.push_back(vertex.position); + normals.push_back(vertex.normal); + uvs.push_back(vertex.uv); + material_ids.push_back(vertex.material_id); + indices.emplace_back(g_n_idx_cnt++); } } + + Geometry g(obj, positions, normals, uvs, material_ids, indices); obj.geometries.push_back(g); - LOG("Read geometry (v: " + std::to_string(g.vertices.size()) + ", i: " + std::to_string(g.indices.size()) + ")"); + LOG("Read geometry (v: " + std::to_string(g.positions.size()) + ", i: " + std::to_string(g.indices.size()) + ")"); } // Load light sources @@ -1009,26 +1028,30 @@ void FBXScene::loadFBX() { m_materials.push_back(material); // Parse objects - uint32_t indices[1024]; + uint32_t triangulate_indices[1024]; for (size_t meshid = 0; meshid < fbx_scene->meshes.count; meshid++) { auto* fbx_mesh = fbx_scene->meshes[meshid]; if (fbx_mesh->instances.count == 0) continue; - Object obj; + Object obj(m_config.layout); std::map index_map; - Geometry g(obj); + std::vector positions; + std::vector normals; + std::vector uvs; + std::vector material_ids; + std::vector indices; // Keep track of all the unique indices we use uint32_t g_n_unique_idx_cnt = 0; for (uint32_t faceid = 0; faceid < fbx_mesh->num_faces; faceid++) { - size_t num_tris = ufbx_triangulate_face(indices, 1024, fbx_mesh, fbx_mesh->faces[faceid]); + size_t num_tris = ufbx_triangulate_face(triangulate_indices, 1024, fbx_mesh, fbx_mesh->faces[faceid]); for (uint32_t triangleid = 0; triangleid < num_tris; triangleid++) { for (uint32_t vertexid = 0; vertexid < 3; vertexid++) { - uint32_t index = indices[triangleid*3 + vertexid]; + uint32_t index = triangulate_indices[triangleid*3 + vertexid]; uint32_t g_index = 0; if (index_map.find(index) != index_map.end()) { g_index = index_map.at(index); @@ -1060,15 +1083,19 @@ void FBXScene::loadFBX() { vertex.material_id = m_materials.size() - 1; } - g.vertices.push_back(vertex); + positions.push_back(vertex.position); + normals.push_back(vertex.normal); + uvs.push_back(vertex.uv); + material_ids.push_back(vertex.material_id); index_map[index] = g_index; } - g.indices.push_back(g_index); + indices.push_back(g_index); } } } - LOG("Read geometry (v: " + std::to_string(g.vertices.size()) +", i: " + std::to_string(g.indices.size()) + ")"); + Geometry g(obj, positions, normals, uvs, material_ids, indices); obj.geometries.push_back(g); + LOG("Read geometry (v: " + std::to_string(g.positions.size()) +", i: " + std::to_string(g.indices.size()) + ")"); m_objects.push_back(obj); // Parse instances From 1b3094b6804ae749ecf0b2f1465d91f240069324 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 11 Apr 2024 21:27:40 -0700 Subject: [PATCH 03/14] Add gtest --- .gitignore | 5 +- CMakeLists.txt | 6 ++ dependencies/CMakeLists.txt | 12 +++ tests/CMakeLists.txt | 14 ++++ tests/test_buffer.cpp | 148 ++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/test_buffer.cpp diff --git a/.gitignore b/.gitignore index 31c2bf3..0e2df9c 100644 --- a/.gitignore +++ b/.gitignore @@ -73,4 +73,7 @@ build/ build # Install Folder -install \ No newline at end of file +install + +# Except Test Data +!tests/data/** \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f0da218..f1ccd62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ if (NOT WIN32) endif() OPTION(STAGE_BUILD_EXAMPLES OFF) +OPTION(STAGE_BUILD_TESTS OFF) + OPTION(STAGE_LOGGING_WARN OFF) OPTION(STAGE_LOGGING_LOG OFF) OPTION(STAGE_LOGGING_OFF OFF) @@ -21,5 +23,9 @@ if (STAGE_BUILD_EXAMPLES) add_subdirectory(examples) endif() +if (STAGE_BUILD_TESTS) + add_subdirectory(tests) +endif() + install(EXPORT stageConfig DESTINATION lib/cmake/stage) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 465dde9..8a52411 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -37,4 +37,16 @@ set(TINYEXR_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/tinyexr CACHE INTERNAL "") set(STAGE_EXPORTS miniz tinyexr ${STAGE_EXPORTS}) endif() +# GTest +if (STAGE_BUILD_TESTS) + include(FetchContent) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip + ) + # For Windows: Prevent overriding the parent project's compiler/linker settings + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) +endif() + install(TARGETS ${STAGE_EXPORTS} EXPORT stageConfig) \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..eb1ff3c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +enable_testing() + +add_executable( + test_stage + test_buffer.cpp +) +target_link_libraries( + test_stage + GTest::gtest_main + stage +) + +include(GoogleTest) +gtest_discover_tests(test_stage) \ No newline at end of file diff --git a/tests/test_buffer.cpp b/tests/test_buffer.cpp new file mode 100644 index 0000000..3533521 --- /dev/null +++ b/tests/test_buffer.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include + +using namespace stage::backstage; + +template +std::vector make_data_array(size_t size) { + std::vector data (size); + std::iota(data.begin(), data.end(), static_cast(0)); + return data; +} + +TEST(Buffer, CreateFromVector) { + std::vector data = make_data_array(1024); + Buffer buf(data); + + EXPECT_EQ(buf.size(), data.size()); + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(buf.data()[i], data[i]); + } +} + +TEST(Buffer, CreateFromPointer) { + std::vector data = make_data_array(1024); + Buffer buf(data.data(), data.size()); + + EXPECT_EQ(buf.size(), data.size()); + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(buf.data()[i], data[i]); + } +} + +TEST(Buffer, SetDataFromVector) { + std::vector data = make_data_array(1024); + Buffer buf; + buf.data(data); + + EXPECT_EQ(buf.size(), data.size()); + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(buf.data()[i], data[i]); + } +} + +TEST(Buffer, SetDataFromBlob) { + std::vector data = make_data_array(1024); + Buffer buf; + buf.data(data.data(), data.size()); + + EXPECT_EQ(buf.size(), data.size()); + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(buf.data()[i], data[i]); + } +} + +TEST(BufferViewLayouts, FromBuffer) { + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(data); + + BufferView view(buf, 0, buf->size()); + + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(data[i], view[i]); + } +} + +TEST(BufferViewLayouts, FromVector) { + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(); + + BufferView view(buf, 0, 0); + view.push_back(data); + + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(data[i], view[i]); + } +} + +TEST(BufferViewLayouts, FromScalar) { + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(); + + BufferView view(buf, 0, 0); + for (auto& d : data) + view.push_back(d); + + for (int i = 0; i < 1024; i++) { + EXPECT_EQ(data[i], view[i]); + } +} + +TEST(BufferViewLayouts, OffsetRead) { + size_t offset = 128; + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(data); + + BufferView view(buf, offset, buf->size()-offset); + + for (int i = offset; i < 1024; i++) { + EXPECT_EQ(data[i], view[i-offset]); + } +} + +TEST(BufferViewLayouts, OffsetWrite) { + size_t offset = 256; + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(data); + + BufferView view(buf, offset, buf->size()-offset); + for(int i = 0; i < offset; i++) { + view.push_back(data[i]); + } + + EXPECT_EQ(view.sizeInBytes(), buf->size()-offset); + for (int i = offset; i < 1024; i++) { + EXPECT_EQ(data[i], view[i]); + } +} + +TEST(BufferViewLayouts, StrideRead) { + size_t stride = 4 * sizeof(uint8_t); + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(data); + + BufferView view(buf, 0, buf->size(), stride); + + for (int i = 0; i < 1024 / 4; i++) { + EXPECT_EQ(data[i*4], view[i]); + } +} + +TEST(BufferViewLayouts, StrideWrite) { + size_t stride = 4 * sizeof(uint8_t); + std::vector data = make_data_array(1024); + std::shared_ptr buf = std::make_shared(data); + + BufferView view(buf, 0, buf->size(), stride); + for (int i = 0; i < 256; i++) { + view.push_back(i); + } + + EXPECT_EQ(view.sizeInBytes(), buf->size() / 4); + + for (int i = 0; i < 256; i++) { + EXPECT_EQ(i, view[i]); + } +} \ No newline at end of file From ac83be2366fcfd3bcbce2df37a5161623399856a Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 11 Apr 2024 22:03:47 -0700 Subject: [PATCH 04/14] Add mesh tests --- tests/CMakeLists.txt | 2 ++ tests/test_buffer.cpp | 14 +------------- tests/test_common.cpp | 13 +++++++++++++ tests/test_common.h | 22 ++++++++++++++++++++++ tests/test_mesh.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 tests/test_common.cpp create mode 100644 tests/test_common.h create mode 100644 tests/test_mesh.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eb1ff3c..9248656 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,9 @@ enable_testing() add_executable( test_stage + test_common.cpp test_buffer.cpp + test_mesh.cpp ) target_link_libraries( test_stage diff --git a/tests/test_buffer.cpp b/tests/test_buffer.cpp index 3533521..8aaafc7 100644 --- a/tests/test_buffer.cpp +++ b/tests/test_buffer.cpp @@ -1,16 +1,4 @@ -#include -#include -#include -#include - -using namespace stage::backstage; - -template -std::vector make_data_array(size_t size) { - std::vector data (size); - std::iota(data.begin(), data.end(), static_cast(0)); - return data; -} +#include "test_common.h" TEST(Buffer, CreateFromVector) { std::vector data = make_data_array(1024); diff --git a/tests/test_common.cpp b/tests/test_common.cpp new file mode 100644 index 0000000..0b423ab --- /dev/null +++ b/tests/test_common.cpp @@ -0,0 +1,13 @@ +#include "test_common.h" + +Geometry make_geometry(Object& obj, size_t size_vertices, size_t size_indices) { + std::vector vertices = make_data_array(size_vertices, {0, 1, 2}); + std::vector normals = make_data_array(size_vertices, {3, 4, 5}); + std::vector uvs = make_data_array(size_vertices, {6, 7}); + std::vector material_ids = make_data_array(size_vertices, 8); + + std::vector indices = make_data_array(size_indices); + + Geometry g(obj, vertices, normals, uvs, material_ids, indices); + return g; +} \ No newline at end of file diff --git a/tests/test_common.h b/tests/test_common.h new file mode 100644 index 0000000..c3cb03d --- /dev/null +++ b/tests/test_common.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include +#include + +using namespace stage::backstage; + +template +std::vector make_data_array(size_t size) { + std::vector data (size); + std::iota(data.begin(), data.end(), static_cast(0)); + return data; +} + +template +std::vector make_data_array(size_t size, T value) { + std::vector data (size); + return data; +} + +Geometry make_geometry(Object& obj, size_t size_vertices, size_t size_indices); diff --git a/tests/test_mesh.cpp b/tests/test_mesh.cpp new file mode 100644 index 0000000..d7ee57d --- /dev/null +++ b/tests/test_mesh.cpp @@ -0,0 +1,24 @@ +#include "test_common.h" + +TEST(Object, CreateEmpty) { + Object obj(VertexLayout_Block_VNT); + EXPECT_EQ(obj.data->size(), 0); +} + +TEST(Object, CreateWithEmptyGeometry) { + Object obj(VertexLayout_Block_VNT); + Geometry g = make_geometry(obj, 0, 0); + + obj.geometries.push_back(g); + + EXPECT_EQ(obj.data->size(), 0); +} + +TEST(Object, CreateWithPopulatedGeometry) { + Object obj(VertexLayout_Block_VNT); + Geometry g = make_geometry(obj, 512, 512); + + obj.geometries.push_back(g); + + EXPECT_EQ(obj.data->size(), 0); +} \ No newline at end of file From 0635da1125cd00e23e2cdfe114c6a5c4315099e1 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 11 Apr 2024 22:05:06 -0700 Subject: [PATCH 05/14] minor rename --- tests/test_buffer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_buffer.cpp b/tests/test_buffer.cpp index 8aaafc7..aad7628 100644 --- a/tests/test_buffer.cpp +++ b/tests/test_buffer.cpp @@ -42,7 +42,7 @@ TEST(Buffer, SetDataFromBlob) { } } -TEST(BufferViewLayouts, FromBuffer) { +TEST(BufferView, FromBuffer) { std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(data); @@ -53,7 +53,7 @@ TEST(BufferViewLayouts, FromBuffer) { } } -TEST(BufferViewLayouts, FromVector) { +TEST(BufferView, FromVector) { std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(); @@ -65,7 +65,7 @@ TEST(BufferViewLayouts, FromVector) { } } -TEST(BufferViewLayouts, FromScalar) { +TEST(BufferView, FromScalar) { std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(); @@ -78,7 +78,7 @@ TEST(BufferViewLayouts, FromScalar) { } } -TEST(BufferViewLayouts, OffsetRead) { +TEST(BufferView, OffsetRead) { size_t offset = 128; std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(data); @@ -90,7 +90,7 @@ TEST(BufferViewLayouts, OffsetRead) { } } -TEST(BufferViewLayouts, OffsetWrite) { +TEST(BufferView, OffsetWrite) { size_t offset = 256; std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(data); @@ -106,7 +106,7 @@ TEST(BufferViewLayouts, OffsetWrite) { } } -TEST(BufferViewLayouts, StrideRead) { +TEST(BufferView, StrideRead) { size_t stride = 4 * sizeof(uint8_t); std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(data); @@ -118,7 +118,7 @@ TEST(BufferViewLayouts, StrideRead) { } } -TEST(BufferViewLayouts, StrideWrite) { +TEST(BufferView, StrideWrite) { size_t stride = 4 * sizeof(uint8_t); std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(data); From 7b8ed14559c844a252d87659c39e97b13379b037 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 12 Apr 2024 20:37:19 -0700 Subject: [PATCH 06/14] Add more Object tests --- tests/test_common.h | 2 +- tests/test_mesh.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/tests/test_common.h b/tests/test_common.h index c3cb03d..5a3d387 100644 --- a/tests/test_common.h +++ b/tests/test_common.h @@ -15,7 +15,7 @@ std::vector make_data_array(size_t size) { template std::vector make_data_array(size_t size, T value) { - std::vector data (size); + std::vector data (size, value); return data; } diff --git a/tests/test_mesh.cpp b/tests/test_mesh.cpp index d7ee57d..f40a556 100644 --- a/tests/test_mesh.cpp +++ b/tests/test_mesh.cpp @@ -20,5 +20,59 @@ TEST(Object, CreateWithPopulatedGeometry) { obj.geometries.push_back(g); - EXPECT_EQ(obj.data->size(), 0); + size_t expected_buffer_size = g.positions.sizeInBytes() + g.normals.sizeInBytes() + g.uvs.sizeInBytes() + g.material_ids.sizeInBytes(); + EXPECT_EQ(obj.data->size(), expected_buffer_size); +} + +void +test_layout(VertexLayout layout) { + Object obj(layout); + Geometry g0 = make_geometry(obj, 512, 512); + Geometry g1 = make_geometry(obj, 512, 512); + + obj.geometries.push_back(g0); + obj.geometries.push_back(g1); + + size_t expected_size = g0.positions.sizeInBytes() + g0.normals.sizeInBytes() + g0.uvs.sizeInBytes() + g0.material_ids.sizeInBytes(); + expected_size += g1.positions.sizeInBytes() + g1.normals.sizeInBytes() + g1.uvs.sizeInBytes() + g1.material_ids.sizeInBytes(); + EXPECT_EQ(obj.data->size(), expected_size); + + stage_vec3f position(0, 1, 2); + stage_vec3f normal(3, 4, 5); + stage_vec2f uv(6, 7); + + for (Geometry& g : obj.geometries) { + for (int i = 0; i < 512; i++) { + EXPECT_EQ(g.positions[i], position); + if (i < g.normals.size()) + EXPECT_EQ(g.normals[i], normal); + if (i < g.uvs.size()) + EXPECT_EQ(g.uvs[i], uv); + EXPECT_EQ(g.material_ids[i], 8.f); + } + } +} + +TEST(Object, LayoutInterleavedV) { + test_layout(VertexLayout_Interleaved_V); +} + +TEST(Object, LayoutInterleavedVN) { + test_layout(VertexLayout_Interleaved_VN); +} + +TEST(Object, LayoutInterleavedVNT) { + test_layout(VertexLayout_Interleaved_VNT); +} + +TEST(Object, LayoutBlockV) { + test_layout(VertexLayout_Block_V); +} + +TEST(Object, LayoutBlockVN) { + test_layout(VertexLayout_Block_VN); +} + +TEST(Object, LayoutBlockVNT) { + test_layout(VertexLayout_Block_VNT); } \ No newline at end of file From 6ef4c927e3d8e6e2f54f65f55bf1981b2ac99ec6 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 12 Apr 2024 20:38:31 -0700 Subject: [PATCH 07/14] Fix some buffer bugs --- src/backstage/buffer.h | 20 ++++++++------------ src/backstage/math.h | 12 ++++++------ src/backstage/mesh.cpp | 32 +++++++++----------------------- src/backstage/mesh.h | 13 +++++++------ 4 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/backstage/buffer.h b/src/backstage/buffer.h index 8d1c3c0..689a99e 100644 --- a/src/backstage/buffer.h +++ b/src/backstage/buffer.h @@ -40,7 +40,7 @@ template struct BufferView { BufferView() = default; - BufferView(std::shared_ptr source, size_t offset, size_t size, size_t stride = sizeof(T)) : m_offset(offset), m_size(size), m_stride(stride) { + BufferView(std::shared_ptr source, size_t offset, size_t num_elements, size_t stride = sizeof(T)) : m_offset(offset), m_size(num_elements), m_stride(stride) { m_buffer = source; } @@ -51,9 +51,9 @@ struct BufferView { m_buffer = source; } - void setBuffer(std::shared_ptr source, size_t offset, size_t size, size_t stride = sizeof(T)) { + void setBuffer(std::shared_ptr source, size_t offset, size_t num_elements, size_t stride = sizeof(T)) { m_offset = source->size() + offset; - m_size = size; + m_size = num_elements; m_stride = stride; m_buffer = source; } @@ -80,16 +80,12 @@ struct BufferView { if (oldsize_in_bytes <= positionInBuffer()) m_buffer->resize(positionInBuffer() + m_stride * elements.size()); - // ERR("elements.size() \t" + std::to_string(elements.size())); - // ERR("m_buffer->size() \t" + std::to_string(m_buffer->size())); - // ERR("positionInBuffer() \t" + std::to_string(positionInBuffer())); - // ERR("m_size \t" + std::to_string(sizeInBytes())); - // std::cout << std::endl; - if (m_stride == sizeof(T)) + if (m_stride == sizeof(T)) { std::memcpy(m_buffer->data() + positionInBuffer(), elements.data(), sizeof(T) * elements.size()); - else { - for (size_t i = 0; i < elements.size(); i++) + } else { + for (size_t i = 0; i < elements.size(); i++) { std::memcpy(m_buffer->data() + positionInBuffer() + (i * m_stride), elements.data() + i, sizeof(T)); + } } m_size += elements.size(); } @@ -107,7 +103,7 @@ struct BufferView { std::shared_ptr m_buffer; size_t m_offset; size_t m_stride; - size_t m_size; + size_t m_size { 0 }; size_t positionInBuffer() { return (m_offset + m_size * m_stride); diff --git a/src/backstage/math.h b/src/backstage/math.h index c37078f..98425be 100644 --- a/src/backstage/math.h +++ b/src/backstage/math.h @@ -31,8 +31,8 @@ struct stage_vec4 { stage_vec4(const stage_vec3& val, S w) : x(val.x), y(val.y), z(val.z), w(w) {} T& operator[](uint32_t id) { return v[id]; } T operator[](uint32_t id) const { return v[id]; } - bool operator==(const stage_vec4& b) { return x == b.x && y == b.y && z == b.z && w == b.w; } - bool operator!=(const stage_vec4& b) { return !(*this == b); } + bool operator==(const stage_vec4& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; } + bool operator!=(const stage_vec4& b) const { return !(*this == b); } friend stage_vec4 operator+(stage_vec4 a, const stage_vec4& b) { return stage_vec4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } friend stage_vec4 operator-(stage_vec4 a, const stage_vec4& b) { return stage_vec4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } friend stage_vec4 operator*(stage_vec4 a, const stage_vec4& b) { return stage_vec4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } @@ -57,8 +57,8 @@ struct stage_vec3 { stage_vec3(const stage_vec4& val) : x(val.x), y(val.y), z(val.z) {} T& operator[](uint32_t id) { return v[id]; } T operator[](uint32_t id) const { return v[id]; } - bool operator==(const stage_vec3& b) { return x == b.x && y == b.y && z == b.z; } - bool operator!=(const stage_vec3& b) { return !(*this == b); } + bool operator==(const stage_vec3& b) const { return x == b.x && y == b.y && z == b.z; } + bool operator!=(const stage_vec3& b) const { return !(*this == b); } friend stage_vec3 operator+(stage_vec3 a, const stage_vec3& b) { return stage_vec3(a.x + b.x, a.y + b.y, a.z + b.z); } friend stage_vec3 operator-(stage_vec3 a, const stage_vec3& b) { return stage_vec3(a.x - b.x, a.y - b.y, a.z - b.z); } friend stage_vec3 operator*(stage_vec3 a, const stage_vec3& b) { return stage_vec3(a.x * b.x, a.y * b.y, a.z * b.z); } @@ -81,8 +81,8 @@ struct stage_vec2 { stage_vec2(const stage_vec3& val) : x(val.x), y(val.y) {} T& operator[](uint32_t id) { return v[id]; } T operator[](uint32_t id) const { return v[id]; } - bool operator==(const stage_vec2& b) { return x == b.x && y == b.y; } - bool operator!=(const stage_vec2& b) { return !(*this == b); } + bool operator==(const stage_vec2& b) const { return x == b.x && y == b.y; } + bool operator!=(const stage_vec2& b) const { return !(*this == b); } friend stage_vec2 operator+(stage_vec2 a, const stage_vec2& b) { return stage_vec2(a.x + b.x, a.y + b.y); } friend stage_vec2 operator-(stage_vec2 a, const stage_vec2& b) { return stage_vec2(a.x - b.x, a.y - b.y); } friend stage_vec2 operator*(stage_vec2 a, const stage_vec2& b) { return stage_vec2(a.x * b.x, a.y * b.y); } diff --git a/src/backstage/mesh.cpp b/src/backstage/mesh.cpp index 5add128..6545ee7 100644 --- a/src/backstage/mesh.cpp +++ b/src/backstage/mesh.cpp @@ -7,7 +7,6 @@ namespace backstage { Geometry::Geometry(Object& parent, std::vector positions, std::vector normals, std::vector uvs, std::vector material_ids, std::vector indices) { this->indices = indices; VertexLayout layout = parent.layout(); - layout = VertexLayout_Block_V; size_t stride_positions, stride_normals, stride_uvs, stride_material_ids; stride_positions = stride_normals = stride_uvs = stride_material_ids = 0; @@ -44,49 +43,36 @@ Geometry::Geometry(Object& parent, std::vector positions, std::vect case VertexLayout_Interleaved_V: offset_positions = 0; offset_material_ids = sizeof(stage_vec3f); + stride_positions = stride_material_ids = sizeof(stage_vec3f) + sizeof(uint32_t); break; case VertexLayout_Interleaved_VN: offset_positions = 0; offset_normals = sizeof(stage_vec3f); offset_material_ids = offset_normals + sizeof(stage_vec3f); + stride_positions = stride_normals = stride_material_ids = 2 * sizeof(stage_vec3f) + sizeof(uint32_t); break; case VertexLayout_Interleaved_VNT: offset_positions = 0; offset_normals = sizeof(stage_vec3f); offset_uvs = offset_normals + sizeof(stage_vec3f); offset_material_ids = offset_uvs + sizeof(stage_vec2f); + stride_positions = stride_normals = stride_uvs = stride_material_ids = 2 * sizeof(stage_vec3f) + sizeof(stage_vec2f) + sizeof(uint32_t); break; default: break; } - if (layout == VertexLayout_Interleaved_V || layout == VertexLayout_Interleaved_VN || layout == VertexLayout_Interleaved_VNT) { - stride_positions = stride_normals = stride_uvs = stride_material_ids = 2 * sizeof(stage_vec3f) + 1 * sizeof(stage_vec2f) + 1 * sizeof(uint32_t); - } - - // WARN("offset_positions " + std::to_string(offset_positions)); - // WARN("offset_normals " + std::to_string(offset_normals)); - // WARN("offset_uvs " + std::to_string(offset_uvs)); - // WARN("offset_material_ids " + std::to_string(offset_material_ids)); - - // WARN("stride_positions " + std::to_string(stride_positions)); - // WARN("stride_normals " + std::to_string(stride_normals)); - // WARN("stride_uvs " + std::to_string(stride_uvs)); - // WARN("stride_material_ids " + std::to_string(stride_material_ids)); - - if (layout == VertexLayout_Block_V || layout == VertexLayout_Interleaved_V) - this->positions.setBuffer(parent.data, offset_positions, 0, stride_positions); - if (layout == VertexLayout_Block_VN || layout == VertexLayout_Interleaved_VN) + this->positions.setBuffer(parent.data, offset_positions, 0, stride_positions); + if (layout & (VertexLayout_Block_VN | VertexLayout_Interleaved_VN | VertexLayout_Block_VNT | VertexLayout_Interleaved_VNT)) this->normals.setBuffer(parent.data, offset_normals, 0, stride_normals); - if (layout == VertexLayout_Block_VNT || layout == VertexLayout_Interleaved_VNT) + if (layout & (VertexLayout_Block_VNT | VertexLayout_Interleaved_VNT)) this->uvs.setBuffer(parent.data, offset_uvs, 0, stride_uvs); this->material_ids.setBuffer(parent.data, offset_material_ids, 0, stride_material_ids); - if (layout == VertexLayout_Block_V || layout == VertexLayout_Interleaved_V) - this->positions.push_back(positions); - if (layout == VertexLayout_Block_VN || layout == VertexLayout_Interleaved_VN) + this->positions.push_back(positions); + if (layout & (VertexLayout_Block_VN | VertexLayout_Interleaved_VN | VertexLayout_Block_VNT | VertexLayout_Interleaved_VNT)) this->normals.push_back(normals); - if (layout == VertexLayout_Block_VNT || layout == VertexLayout_Interleaved_VNT) + if (layout & (VertexLayout_Block_VNT | VertexLayout_Interleaved_VNT)) this->uvs.push_back(uvs); this->material_ids.push_back(material_ids); } diff --git a/src/backstage/mesh.h b/src/backstage/mesh.h index ca921b6..d83d07d 100644 --- a/src/backstage/mesh.h +++ b/src/backstage/mesh.h @@ -10,12 +10,12 @@ namespace stage { namespace backstage { enum VertexLayout { - VertexLayout_Interleaved_VNT = 0, - VertexLayout_Interleaved_VN, - VertexLayout_Interleaved_V, - VertexLayout_Block_VNT, - VertexLayout_Block_VN, - VertexLayout_Block_V, + VertexLayout_Interleaved_VNT = 0x001, + VertexLayout_Interleaved_VN = 0x002, + VertexLayout_Interleaved_V = 0x004, + VertexLayout_Block_VNT = 0x008, + VertexLayout_Block_VN = 0x010, + VertexLayout_Block_V = 0x020, }; struct DEVICE_ALIGNED AlignedVertex { @@ -28,6 +28,7 @@ struct DEVICE_ALIGNED AlignedVertex { struct Object; struct Geometry { Geometry(Object& parent, std::vector positions, std::vector normals, std::vector uvs, std::vector material_ids, std::vector indices); + std::vector indices; BufferView positions; BufferView normals; From 4787c3ab17c5860ea3c36cf71c87bccc1adfad5c Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 12 Apr 2024 20:45:52 -0700 Subject: [PATCH 08/14] minor --- tests/test_buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_buffer.cpp b/tests/test_buffer.cpp index aad7628..5e3947d 100644 --- a/tests/test_buffer.cpp +++ b/tests/test_buffer.cpp @@ -123,7 +123,7 @@ TEST(BufferView, StrideWrite) { std::vector data = make_data_array(1024); std::shared_ptr buf = std::make_shared(data); - BufferView view(buf, 0, buf->size(), stride); + BufferView view(buf, 0, 0, stride); for (int i = 0; i < 256; i++) { view.push_back(i); } From 10882bcc58bd127e2e5950cebc2339b90d5b41ef Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 21 Apr 2024 19:23:14 -0700 Subject: [PATCH 09/14] Made some buffer functions const and updated CPP API --- src/backstage/buffer.h | 12 ++++++------ src/stage.cpp | 4 ++-- src/stage.h | 6 ++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/backstage/buffer.h b/src/backstage/buffer.h index 689a99e..88ef1ba 100644 --- a/src/backstage/buffer.h +++ b/src/backstage/buffer.h @@ -58,7 +58,7 @@ struct BufferView { m_buffer = source; } - uint8_t* data() { + uint8_t* data() const { if (!m_buffer) return nullptr; return (m_buffer->data() + m_offset); } @@ -90,12 +90,12 @@ struct BufferView { m_size += elements.size(); } - size_t sizeInBytes() { return m_size * sizeof(T); } - size_t size() { return m_size; } - size_t offset() { return m_offset; } - size_t stride() { return m_stride; } + size_t sizeInBytes() const { return m_size * sizeof(T); } + size_t size() const { return m_size; } + size_t offset() const { return m_offset; } + size_t stride() const { return m_stride; } - T& operator[](uint32_t id) { + T& operator[](uint32_t id) const { return *(T*)(data() + (id * m_stride)); } diff --git a/src/stage.cpp b/src/stage.cpp index 2955f2f..fead5ca 100644 --- a/src/stage.cpp +++ b/src/stage.cpp @@ -4,8 +4,8 @@ namespace stage { -Scene::Scene(std::string scene) { - m_pimpl = backstage::createScene(scene); +Scene::Scene(std::string scene, Config config) { + m_pimpl = backstage::createScene(scene, config); } std::shared_ptr diff --git a/src/stage.h b/src/stage.h index 26a425d..c7a884e 100644 --- a/src/stage.h +++ b/src/stage.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include "backstage/config.h" #include "backstage/math.h" #include "backstage/camera.h" #include "backstage/image.h" @@ -20,18 +21,19 @@ using backstage::stage_vec4f; using backstage::stage_mat4f; /* Forward declare PODs */ +using backstage::Config; using backstage::Camera; using backstage::Image; using backstage::Light; using backstage::OpenPBRMaterial; -using backstage::AlignedVertex; +using backstage::VertexLayout; using backstage::Geometry; using backstage::Object; using backstage::ObjectInstance; /* Scene Facade */ struct Scene { - Scene(std::string scene); + Scene(std::string scene, Config config); ~Scene() = default; Scene(const Scene &) = delete; Scene &operator=(const Scene &) = delete; From 7be5091b45187db31e031a3c74b3a2b1675de6d3 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 21 Apr 2024 19:34:44 -0700 Subject: [PATCH 10/14] Fixed unset indices in OBJ parser --- src/backstage/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backstage/scene.cpp b/src/backstage/scene.cpp index 50855f2..1a16c2a 100644 --- a/src/backstage/scene.cpp +++ b/src/backstage/scene.cpp @@ -255,7 +255,7 @@ OBJScene::loadObj() { indices.push_back(g_index); } } - Geometry g(obj, positions, normals, uvs, material_ids, {}); + Geometry g(obj, positions, normals, uvs, material_ids, indices); obj.geometries.push_back(g); LOG("Read geometry (v: " + std::to_string(g.positions.size()) + ", i: " + std::to_string(g.indices.size()) + ")"); } From b7b6e4512f306f6e4b7ea3c6d66038340739e6d2 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Tue, 23 Apr 2024 15:50:34 -0700 Subject: [PATCH 11/14] Update default config --- src/backstage/config.h | 2 +- src/backstage/scene.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backstage/config.h b/src/backstage/config.h index e442bed..f3893d6 100644 --- a/src/backstage/config.h +++ b/src/backstage/config.h @@ -9,7 +9,7 @@ namespace stage { namespace backstage { struct Config { - VertexLayout layout; + VertexLayout layout { VertexLayout_Interleaved_VNT }; }; } diff --git a/src/backstage/scene.h b/src/backstage/scene.h index 9b156c0..977db14 100644 --- a/src/backstage/scene.h +++ b/src/backstage/scene.h @@ -153,7 +153,7 @@ struct FBXScene : public Scene { bool loadFBXTexture(ufbx_texture* texture); }; -std::unique_ptr createScene(std::string scene, const Config& config = {}); +std::unique_ptr createScene(std::string scene, const Config& config); } } \ No newline at end of file From b2b0e5074f4d9b0a20e0982519ab144cdcfe5b55 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Tue, 23 Apr 2024 15:50:56 -0700 Subject: [PATCH 12/14] Complete restructure of C API --- src/stage_c.cpp | 387 +++++++++++++++++++++++++++++++++++++++++------- src/stage_c.h | 294 ++++++++++++++++++++++++------------ 2 files changed, 534 insertions(+), 147 deletions(-) diff --git a/src/stage_c.cpp b/src/stage_c.cpp index 50ac188..e2b0436 100644 --- a/src/stage_c.cpp +++ b/src/stage_c.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "backstage/config.h" #include "backstage/math.h" #include "backstage/camera.h" #include "backstage/image.h" @@ -12,78 +13,352 @@ using namespace stage::backstage; -void stage_fill_objects_(std::vector&, stage_object_t**); -void stage_fill_geometries_(std::vector&, stage_geometry_t**); +struct stage_camera : public Camera {}; +struct stage_image : public Image {}; +struct stage_light : public Light {}; +struct stage_openpbr_material: public OpenPBRMaterial {}; +struct stage_geometry : public Geometry {}; +struct stage_object : public Object {}; +struct stage_object_instance : public ObjectInstance {}; +struct stage_scene : public Scene {}; +struct stage_config : public Config {}; -STAGE_STATUS -stage_load(char *scene_file, stage_scene_t **scene) { - std::string scene_file_str(scene_file); - auto scene_ptr = createScene(scene_file_str); - - if (!scene_ptr) - return STAGE_ERROR; - - stage_scene_t *scene_c = (stage_scene_t*)malloc(sizeof(stage_scene_t)); - scene_c->camera = (stage_camera_t*)scene_ptr->getCamera().get(); - stage_fill_objects_(scene_ptr->getObjects(), &scene_c->objects); - scene_c->instances = (stage_object_instance_t*)scene_ptr->getInstances().data(); - scene_c->materials = (stage_openpbrmaterial_t*)scene_ptr->getMaterials().data(); - scene_c->lights = (stage_light_t*)scene_ptr->getLights().data(); - scene_c->textures = (stage_image_t*)scene_ptr->getTextures().data(); +stage_config_t +stage_config_get_default() { + stage_config_t config = new stage_config(); + config->layout = VertexLayout::VertexLayout_Interleaved_VNT; + return config; +} - scene_c->n_objects = scene_ptr->getObjects().size(); - scene_c->n_instances = scene_ptr->getInstances().size(); - scene_c->n_materials = scene_ptr->getMaterials().size(); - scene_c->n_lights = scene_ptr->getLights().size(); - scene_c->n_textures = scene_ptr->getTextures().size(); +void +stage_config_set_layout(stage_config_t config, stage_vertex_layout_t layout) { + if (config == nullptr) return; + config->layout = VertexLayout(layout); +} - scene_c->scene_scale = scene_ptr->getSceneScale(); +stage_scene_t +stage_load(char *scene_file, stage_config_t config, stage_error_t* error) { + std::string scene_file_str(scene_file); + auto scene_ptr = createScene(scene_file_str, *config); - scene_c->pimpl = scene_ptr.release(); + if (!scene_ptr) { + *error = STAGE_ERROR; + return nullptr; + } - *scene = scene_c; + stage_scene_t stage_scene = reinterpret_cast(scene_ptr.release()); - return STAGE_NO_ERROR; + *error = STAGE_NO_ERROR; + return stage_scene; } -STAGE_STATUS -stage_free(stage_scene_t* scene) { +void +stage_free(stage_scene_t scene) { if (scene != nullptr) { - if (scene->pimpl != nullptr) { - Scene *scene_ptr = (Scene*)scene->pimpl; - delete scene_ptr; - } - for (uint32_t i = 0; i < scene->n_objects; ++i) { - free(scene->objects[i].geometries); - } - free(scene->objects); free(scene); } - return STAGE_NO_ERROR; } -void -stage_fill_objects_(std::vector& objects, stage_object_t **objects_c) { - stage_object_t* o = (stage_object_t*)malloc(sizeof(stage_object_t) * objects.size()); +/* Camera API */ +stage_vec3f_t +stage_camera_get_position(stage_camera_t camera) { + return *reinterpret_cast(&camera->position); +} - for (uint32_t i = 0; i < objects.size(); ++i) { - o[i].n_geometries = objects[i].geometries.size(); - stage_fill_geometries_(objects[i].geometries, &o[i].geometries); - } +stage_vec3f_t +stage_camera_get_lookat(stage_camera_t camera) { + return *reinterpret_cast(&camera->lookat); +} - *objects_c = o; +stage_vec3f_t +stage_camera_get_up(stage_camera_t camera) { + return *reinterpret_cast(&camera->up); } -void -stage_fill_geometries_(std::vector& geometries, stage_geometry_t **geometries_c) { - stage_geometry_t* g = (stage_geometry_t*)malloc(sizeof(stage_geometry_t) * geometries.size()); - - for (uint32_t i = 0; i < geometries.size(); ++i) { - g[i].n_vertices = geometries[i].vertices.size(); - g[i].vertices = (stage_alignedvertex_t*)geometries[i].vertices.data(); - g[i].n_indices = geometries[i].indices.size(); - g[i].indices = geometries[i].indices.data(); - } +float +stage_camera_get_fovy(stage_camera_t camera) { + return camera->fovy; +} + +/* Image API */ +stage_image_t +stage_image_get(stage_image_list_t imageList, size_t index) { + return &imageList[index]; +} + +uint8_t* +stage_image_get_data(stage_image_t image) { + return image->getData(); +} + +uint32_t +stage_image_get_width(stage_image_t image) { + return image->getWidth(); +} + +uint32_t +stage_image_get_height(stage_image_t image) { + return image->getHeight(); +} + +uint32_t +stage_image_get_channels(stage_image_t image) { + return image->getChannels(); +} + +bool +stage_image_is_hdr(stage_image_t image) { + return image->isHDR(); +} + +bool +stage_image_is_valid(stage_image_t image) { + return image->isValid(); +} + +/* Light API */ +stage_light_t +stage_light_get(stage_light_list_t lightList, size_t index) { + return &lightList[index]; +} + +stage_vec3f_t +stage_light_get_L(stage_light_t light) { + return *reinterpret_cast(&light->L); +} + +stage_vec3f_t +stage_light_get_from(stage_light_t light) { + return *reinterpret_cast(&light->from); +} + +stage_vec3f_t +stage_light_get_to(stage_light_t light) { + return *reinterpret_cast(&light->to); +} + +float +stage_light_get_radius(stage_light_t light) { + return light->radius; +} + +int32_t +stage_light_get_map_texid(stage_light_t light) { + return light->map_texid; +} + +uint32_t +stage_light_get_type(stage_light_t light) { + return light->type; +} + +/* Material API */ +stage_openpbr_material_t +stage_light_get(stage_openpbr_material_list_t materialList, size_t index) { + return &materialList[index]; +} + +stage_vec3f_t +stage_material_get_base_color(stage_openpbr_material_t material) { + return *reinterpret_cast(&material->base_color); +} + +int32_t +stage_material_get_base_color_texid(stage_openpbr_material_t material) { + return material->base_color_texid; +} + +float +stage_material_get_base_weight(stage_openpbr_material_t material) { + return material->base_weight; +} + +float +stage_material_get_base_roughness(stage_openpbr_material_t material) { + return material->base_roughness; +} + +float +stage_material_get_base_metalness(stage_openpbr_material_t material) { + return material->base_metalness; +} + +stage_vec3f_t +stage_material_get_specular_color(stage_openpbr_material_t material) { + return *reinterpret_cast(&material->specular_color); +} + +float +stage_material_get_specular_weight(stage_openpbr_material_t material) { + return material->specular_weight; +} + +float +stage_material_get_specular_roughness(stage_openpbr_material_t material) { + return material->specular_roughness; +} + +float +stage_material_get_specular_anisotropy(stage_openpbr_material_t material) { + return material->specular_anisotropy; +} + +float +stage_material_get_specular_rotation(stage_openpbr_material_t material) { + return material->specular_rotation; +} + +float +stage_material_get_specular_ior(stage_openpbr_material_t material) { + return material->specular_ior; +} + +float +stage_material_get_specular_ior_level(stage_openpbr_material_t material) { + return material->specular_ior_level; +} + +float +stage_material_get_transmission_weight(stage_openpbr_material_t material) { + return material->transmission_weight; +} + +float +stage_material_get_geometry_opacity(stage_openpbr_material_t material) { + return material->geometry_opacity; +} + +int32_t +stage_material_get_geometry_opacity_texid(stage_openpbr_material_t material) { + return material->geometry_opacity_texid; +} + +/* Mesh API */ +stage_object_instance_t +stage_object_instance_get(stage_object_instance_list_t objectInstanceList, size_t index) { + return &objectInstanceList[index]; +} + +stage_mat4f_t +stage_object_instance_get_instance_to_world(stage_object_instance_t instance) { + return *reinterpret_cast(&instance->instance_to_world[0]); +} + +uint32_t +stage_object_instance_get_object_id(stage_object_instance_t instance) { + return instance->object_id; +} + +stage_object_t +stage_object_get(stage_object_list_t objectList, size_t index) { + return &objectList[index]; +} + +stage_vertex_layout_t +stage_object_get_layout(stage_object_t object) { + return stage_vertex_layout_t(object->layout()); +} + +stage_geometry_list_t +stage_object_get_geometries(stage_object_t object, size_t* count) { + auto& geometries = object->geometries; + *count = geometries.size(); + return reinterpret_cast(geometries.data()); +} + +void* +stage_object_get_buffer(stage_object_t object, size_t* sizeInBytes) { + *sizeInBytes = object->data->size(); + return object->data->data(); +} + +stage_geometry_t +stage_geometry_get(stage_geometry_list_t geometryList, size_t index) { + return &geometryList[index]; +} + +uint32_t* +stage_geometry_get_indices(stage_geometry_t geometry, size_t* count) { + auto& indices = geometry->indices; + *count = indices.size(); + return indices.data(); +} + +stage_vec3f_t* +stage_geometry_get_positions(stage_geometry_t geometry, size_t* count, size_t* stride) { + auto& positions = geometry->positions; + *count = positions.size(); + *stride = positions.stride(); + return reinterpret_cast(positions.data()); +} + +stage_vec3f_t* +stage_geometry_get_normals(stage_geometry_t geometry, size_t* count, size_t* stride) { + auto& normals = geometry->normals; + *count = normals.size(); + *stride = normals.stride(); + return reinterpret_cast(normals.data()); +} + +stage_vec2f_t* +stage_geometry_get_uvs(stage_geometry_t geometry, size_t* count, size_t* stride) { + auto& uvs = geometry->uvs; + *count = uvs.size(); + *stride = uvs.stride(); + return reinterpret_cast(uvs.data()); +} + +uint32_t* +stage_geometry_get_material_ids(stage_geometry_t geometry, size_t* count, size_t* stride) { + auto& material_ids = geometry->material_ids; + *count = material_ids.size(); + *stride = material_ids.stride(); + return reinterpret_cast(material_ids.data()); +} + +/* Scene API */ +stage_camera_t +stage_scene_get_camera(stage_scene_t scene) { + auto camera = scene->getCamera(); + return reinterpret_cast(camera.get()); +} + +stage_object_list_t +stage_scene_get_objects(stage_scene_t scene, size_t* count) { + auto& objects = scene->getObjects(); + *count = objects.size(); + return reinterpret_cast(objects.data()); +} + +stage_object_instance_list_t +stage_scene_get_instances(stage_scene_t scene, size_t* count) { + auto& instances = scene->getInstances(); + *count = instances.size(); + return reinterpret_cast(instances.data()); +} + +stage_openpbr_material_list_t +stage_scene_get_materials(stage_scene_t scene, size_t* count) { + auto& materials = scene->getMaterials(); + *count = materials.size(); + return reinterpret_cast(materials.data()); +} + +stage_light_list_t +stage_scene_get_lights(stage_scene_t scene, size_t* count) { + auto& lights = scene->getLights(); + *count = lights.size(); + return reinterpret_cast(lights.data()); +} + +stage_image_list_t +stage_scene_get_textures(stage_scene_t scene, size_t* count) { + auto& textures = scene->getTextures(); + *count = textures.size(); + return reinterpret_cast(textures.data()); +} - *geometries_c = g; +float +stage_scene_get_scale(stage_scene_t scene) { + return scene->getSceneScale(); } \ No newline at end of file diff --git a/src/stage_c.h b/src/stage_c.h index d324814..b903aaa 100644 --- a/src/stage_c.h +++ b/src/stage_c.h @@ -9,7 +9,6 @@ extern "C" { #endif /* Math Definitions */ - typedef union { float v[4]; struct { float x, y, z, w; }; @@ -33,109 +32,222 @@ typedef union { stage_vec4f_t c[4]; } stage_mat4f_t; -/* POD Definitions */ +/* POD Declarations */ #define STAGE_DISTANT_LIGHT 0 #define STAGE_INFINITE_LIGHT 1 #define STAGE_POINT_LIGHT 2 #define STAGE_SPHERE_LIGHT 3 #define STAGE_DISK_LIGHT 4 -typedef struct { - stage_vec3f_t position, lookat, up; - float fovy; -} stage_camera_t; - -typedef struct { - uint8_t* data; - uint32_t width, height, channels; - bool is_hdr; -} stage_image_t; - -typedef struct { - stage_vec3f_t L, from, to; - float radius; - int32_t map_texid; - uint32_t type; -} stage_light_t; - -typedef struct { - /* Base */ - stage_vec3f_t base_color; - int32_t base_color_texid; - float base_weight; - float base_roughness; - float base_metalness; - - /* Specular */ - stage_vec3f_t specular_color; - float specular_weight; - float specular_roughness; - float specular_anisotropy; - float specular_rotation; - float specular_ior; - float specular_ior_level; - - /* Transmission */ - float transmission_weight; - - /* Geometry */ - float geometry_opacity; - int32_t geometry_opacity_texid; -} stage_openpbrmaterial_t; - -typedef struct { - stage_vec3f_t position, normal; - stage_vec2f_t uv; - uint32_t material_id; -} stage_alignedvertex_t; - -typedef struct { - stage_alignedvertex_t* vertices; - uint32_t n_vertices; - uint32_t* indices; - uint32_t n_indices; -} stage_geometry_t; - -typedef struct { - stage_geometry_t* geometries; - uint32_t n_geometries; -} stage_object_t; - -typedef struct { - stage_mat4f_t world_to_instance; - uint32_t object_id; -} stage_object_instance_t; - -typedef struct { - stage_camera_t* camera; - stage_object_t* objects; - stage_object_instance_t* instances; - stage_openpbrmaterial_t* materials; - stage_light_t* lights; - stage_image_t* textures; - - uint32_t n_objects; - uint32_t n_instances; - uint32_t n_materials; - uint32_t n_lights; - uint32_t n_textures; - - float scene_scale; - - void* pimpl; -} stage_scene_t; +typedef struct stage_camera* stage_camera_t; +typedef struct stage_image* stage_image_t; +typedef struct stage_image* stage_image_list_t; +typedef struct stage_light* stage_light_t; +typedef struct stage_light* stage_light_list_t; +typedef struct stage_openpbr_material* stage_openpbr_material_t; +typedef struct stage_openpbr_material* stage_openpbr_material_list_t; +typedef struct stage_geometry* stage_geometry_t; +typedef struct stage_geometry* stage_geometry_list_t; +typedef struct stage_object* stage_object_t; +typedef struct stage_object* stage_object_list_t; +typedef struct stage_object_instance* stage_object_instance_t; +typedef struct stage_object_instance* stage_object_instance_list_t; +typedef struct stage_scene* stage_scene_t; +typedef struct stage_config* stage_config_t; + +typedef enum { + VertexLayout_Interleaved_VNT = 0x001, + VertexLayout_Interleaved_VN = 0x002, + VertexLayout_Interleaved_V = 0x004, + VertexLayout_Block_VNT = 0x008, + VertexLayout_Block_VN = 0x010, + VertexLayout_Block_V = 0x020, +} stage_vertex_layout_t; /* API Functions */ +typedef unsigned int stage_error_t; #define STAGE_NO_ERROR 0x0000 #define STAGE_ERROR 0x0001 -#define STAGE_STATUS uint32_t -STAGE_STATUS -stage_load(char *scene_file, stage_scene_t **scene); +stage_config_t +stage_config_get_default(); + +void +stage_config_set_layout(stage_config_t config, stage_vertex_layout_t layout); + +stage_scene_t +stage_load(char *scene_file, stage_config_t config, stage_error_t* error); + +void +stage_free(stage_scene_t scene); + +/* Camera API */ +stage_vec3f_t +stage_camera_get_position(stage_camera_t camera); + +stage_vec3f_t +stage_camera_get_lookat(stage_camera_t camera); + +stage_vec3f_t +stage_camera_get_up(stage_camera_t camera); + +float +stage_camera_get_fovy(stage_camera_t camera); + +/* Image API */ +stage_image_t +stage_image_get(stage_image_list_t imageList, size_t index); + +uint8_t* +stage_image_get_data(stage_image_t image); + +uint32_t +stage_image_get_width(stage_image_t image); + +uint32_t +stage_image_get_height(stage_image_t image); + +uint32_t +stage_image_get_channels(stage_image_t image); + +bool +stage_image_is_hdr(stage_image_t image); + +bool +stage_image_is_valid(stage_image_t image); + +/* Light API */ +stage_light_t +stage_light_get(stage_light_list_t lightList, size_t index); + +stage_vec3f_t +stage_light_get_L(stage_light_t light); + +stage_vec3f_t +stage_light_get_from(stage_light_t light); + +stage_vec3f_t +stage_light_get_to(stage_light_t light); + +float +stage_light_get_radius(stage_light_t light); + +int32_t +stage_light_get_map_texid(stage_light_t light); + +uint32_t +stage_light_get_type(stage_light_t light); + +/* Material API */ +stage_openpbr_material_t +stage_maertial_get(stage_openpbr_material_list_t materialList, size_t index); + +stage_vec3f_t +stage_material_get_base_color(stage_openpbr_material_t material); + +int32_t +stage_material_get_base_color_texid(stage_openpbr_material_t material); + +float +stage_material_get_base_weight(stage_openpbr_material_t material); + +float +stage_material_get_base_roughness(stage_openpbr_material_t material); + +float +stage_material_get_base_metalness(stage_openpbr_material_t material); + +stage_vec3f_t +stage_material_get_specular_color(stage_openpbr_material_t material); + +float +stage_material_get_specular_weight(stage_openpbr_material_t material); + +float +stage_material_get_specular_roughness(stage_openpbr_material_t material); + +float +stage_material_get_specular_anisotropy(stage_openpbr_material_t material); + +float +stage_material_get_specular_rotation(stage_openpbr_material_t material); + +float +stage_material_get_specular_ior(stage_openpbr_material_t material); + +float +stage_material_get_specular_ior_level(stage_openpbr_material_t material); + +float +stage_material_get_transmission_weight(stage_openpbr_material_t material); + +float +stage_material_get_geometry_opacity(stage_openpbr_material_t material); + +int32_t +stage_material_get_geometry_opacity_texid(stage_openpbr_material_t material); + +/* Mesh API */ +stage_object_instance_t +stage_object_instance_get(stage_object_instance_list_t objectInstanceList, size_t index); + +stage_mat4f_t +stage_object_instance_get_instance_to_world(stage_object_instance_t instance); + +uint32_t +stage_object_instance_get_object_id(stage_object_instance_t instance); + +stage_object_t +stage_object_get(stage_object_list_t objectList, size_t index); + +stage_vertex_layout_t +stage_object_get_layout(stage_object_t object); + +stage_geometry_list_t +stage_object_get_geometries(stage_object_t object, size_t* count); + +void* +stage_object_get_buffer(stage_object_t object, size_t* sizeInBytes); + +stage_geometry_t +stage_geometry_get(stage_geometry_list_t geometryList, size_t index); + +uint32_t* +stage_geometry_get_indices(stage_geometry_t geometry, size_t* count); + +stage_vec3f_t* +stage_geometry_get_positions(stage_geometry_t geometry, size_t* count, size_t* stride); + +stage_vec3f_t* +stage_geometry_get_normals(stage_geometry_t geometry, size_t* count, size_t* stride); + +stage_vec2f_t* +stage_geometry_get_uvs(stage_geometry_t geometry, size_t* count, size_t* stride); + +uint32_t* +stage_geometry_get_material_ids(stage_geometry_t geometry, size_t* count, size_t* stride); + +/* Scene API */ +stage_camera_t +stage_scene_get_camera(stage_scene_t scene); + +stage_object_list_t +stage_scene_get_objects(stage_scene_t scene, size_t* count); + +stage_object_instance_list_t +stage_scene_get_instances(stage_scene_t scene, size_t* count); + +stage_openpbr_material_list_t +stage_scene_get_materials(stage_scene_t scene, size_t* count); + +stage_light_list_t +stage_scene_get_lights(stage_scene_t scene, size_t* count); -STAGE_STATUS -stage_free(stage_scene_t* scene); +stage_image_list_t +stage_scene_get_textures(stage_scene_t scene, size_t* count); +float +stage_scene_get_scale(stage_scene_t scene); #ifdef __cplusplus } From c544c99267177b6f5d3e00b19b6c8a61da0a007f Mon Sep 17 00:00:00 2001 From: David Bauer Date: Tue, 23 Apr 2024 15:51:02 -0700 Subject: [PATCH 13/14] Update examples --- examples/scene_info.c | 46 ++++++++++++++++++++++++++++------------- examples/scene_info.cpp | 3 ++- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/examples/scene_info.c b/examples/scene_info.c index 884ac73..75120eb 100644 --- a/examples/scene_info.c +++ b/examples/scene_info.c @@ -7,29 +7,47 @@ int main(int argc, char** argv) { return -1; } - stage_scene_t* scene = NULL; - STAGE_STATUS result = stage_load(argv[1], &scene); + stage_error_t error; + stage_config_t config = stage_config_get_default(); + stage_scene_t scene = stage_load(argv[1], config, &error); - if (result != STAGE_NO_ERROR) { + if (error != STAGE_NO_ERROR) { printf("Invalid scene\n"); return -1; } + size_t n_objects, n_instances, n_lights, n_materials, n_textures; + float scene_scale; + stage_scene_get_objects(scene, &n_objects); + stage_scene_get_instances(scene, &n_instances); + stage_scene_get_lights(scene, &n_lights); + stage_scene_get_materials(scene, &n_materials); + stage_scene_get_textures(scene, &n_textures); + scene_scale = stage_scene_get_scale(scene); + + printf("--- SCENE INFO ---\n"); - printf("Scale:\t%.4f\n", scene->scene_scale); - printf("Objects:\t%i\n", scene->n_objects); - printf("Instances:\t%i\n", scene->n_instances); - printf("Lights:\t\t%i\n", scene->n_lights); - printf("Materials:\t%i\n", scene->n_materials); - printf("Textures:\t%i\n", scene->n_textures); - if (scene->camera != NULL) { + printf("Scale:\t%.4f\n", scene_scale); + printf("Objects:\t%i\n", n_objects); + printf("Instances:\t%i\n", n_instances); + printf("Lights:\t\t%i\n", n_lights); + printf("Materials:\t%i\n", n_materials); + printf("Textures:\t%i\n", n_textures); + + stage_camera_t camera = stage_scene_get_camera(scene); + if (camera != NULL) { + stage_vec3f_t position = stage_camera_get_position(camera); + stage_vec3f_t lookat = stage_camera_get_lookat(camera); + stage_vec3f_t up = stage_camera_get_up(camera); + float fovy = stage_camera_get_fovy(camera); printf("Camera:\n"); - printf("\tFOV:\t%.4f", scene->camera->fovy); - printf("\tPosition:\t%.4f,\t%.4f,\t%.4f", scene->camera->position.x, scene->camera->position.y, scene->camera->position.z); - printf("\tLook At:\t%.4f,\t%.4f,\t%.4f", scene->camera->lookat.x, scene->camera->lookat.y, scene->camera->lookat.z); - printf("\tUp:\t\t%.4f,\t%.4f,\t%.4f", scene->camera->up.x, scene->camera->up.y, scene->camera->up.z); + printf("\tFOV:\t\t%.4f\n", fovy); + printf("\tPosition:\t%.4f,\t%.4f,\t%.4f\n", position.x, position.y, position.z); + printf("\tLook At:\t%.4f,\t%.4f,\t%.4f\n", lookat.x, lookat.y, lookat.z); + printf("\tUp:\t\t%.4f,\t%.4f,\t%.4f\n", up.x, up.y, up.z); } + stage_free(config); stage_free(scene); return 0; diff --git a/examples/scene_info.cpp b/examples/scene_info.cpp index 039d70b..c6b6c98 100644 --- a/examples/scene_info.cpp +++ b/examples/scene_info.cpp @@ -7,7 +7,8 @@ int main(int argc, char** argv) { return -1; } - stage::Scene scene(argv[1]); + stage::Config config; + stage::Scene scene(argv[1], config); if (!scene.isValid()) { std::cout << "Invalid scene" << std::endl; return -1; From 3d54a86c53e1fa118b60cf854558354b7d28d7b5 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Tue, 23 Apr 2024 15:51:47 -0700 Subject: [PATCH 14/14] Update readme to reflect new C API and buffer mechanics --- README.md | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b449339..0fa94a4 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ int main(int argc, char** argv) { return -1; } - stage::Scene scene(argv[1]); + stage::Config config; + stage::Scene scene(argv[1], config); if (!scene.isValid()) { std::cout << "Invalid scene" << std::endl; return -1; @@ -47,18 +48,26 @@ int main(int argc, char** argv) { return -1; } - stage_scene_t* scene = NULL; - STAGE_STATUS result = stage_load(argv[1], &scene); + stage_error_t error; + stage_config_t config = stage_config_get_default(); + stage_scene_t scene = stage_load(argv[1], config, &error); - if (result != STAGE_NO_ERROR) { + if (error != STAGE_NO_ERROR) { printf("Invalid scene\n"); return -1; } + size_t n_objects, n_instances; + stage_scene_get_objects(scene, &n_objects); + stage_scene_get_instances(scene, &n_instances); + + printf("--- SCENE INFO ---\n"); - printf("Objects:\t%i\n", scene->n_objects); - printf("Instances:\t%i\n", scene->n_instances); + printf("Scale:\t%.4f\n", scene_scale); + printf("Objects:\t%i\n", n_objects); + printf("Instances:\t%i\n", n_instances); + stage_free(config); stage_free(scene); return 0; @@ -78,21 +87,25 @@ A scene is what you'll get when you first load a file. It contains all the data * List of `Image`, a collection of image data like texture and environment maps * The `SceneScale` defines the maximum extent of the loaded scene +When creating scenes, you can pass a `Config` to determine the behavior of the parser and the data parsed + +* `layout` determines the vertex layout of the parsed data + --- -### The `Object`, `Geometry`, and `AlignedVertex` +### The `Object` and `Geometry` An `Object` represents a single 3D entity in a scene. It can be made up of several `Geometry` instances which, combined, represent the whole object. A `Geometry` is the smallest building block in the scene and contains: * A list of `indices` -* A list of `AlignedVertex` instances. +* A buffer of `positions` +* A buffer of `normals` +* A buffer of `uvs` +* A buffer of `material_ids` -The indices index into the list of vertex data. +The indices index into each of the buffer objects. +The memory layout of the underlying buffer that stores vertex data is determined by the `layout` config parameter when loading the scene. -An `AlignedVertex` represents a single vertex entry and contains: -* `position` -* `normal` -* `uv` -* `material_id` +All data within an `Object` is guaranteed to be contiguous and adhere to the chosen memory layout. Blocked layouts are blocked separately for each `Geometry`. The material ID can be used to locate the `Material` that is associated with this vertex.