summaryrefslogtreecommitdiff
path: root/engine/xe_model.cpp
diff options
context:
space:
mode:
authortylermurphy534 <tylermurphy534@gmail.com>2022-09-18 21:20:51 -0400
committertylermurphy534 <tylermurphy534@gmail.com>2022-09-18 21:20:51 -0400
commit8045b8ba04aae39a4cf9733e72413f648b6ebe2b (patch)
treef90a9bd50a2316d5077df99c9e8584afc76ed656 /engine/xe_model.cpp
downloadminecraftvulkan-8045b8ba04aae39a4cf9733e72413f648b6ebe2b.tar.gz
minecraftvulkan-8045b8ba04aae39a4cf9733e72413f648b6ebe2b.tar.bz2
minecraftvulkan-8045b8ba04aae39a4cf9733e72413f648b6ebe2b.zip
stanford dragon rendering
Diffstat (limited to 'engine/xe_model.cpp')
-rw-r--r--engine/xe_model.cpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/engine/xe_model.cpp b/engine/xe_model.cpp
new file mode 100644
index 0000000..e6835a6
--- /dev/null
+++ b/engine/xe_model.cpp
@@ -0,0 +1,193 @@
+#include "xe_model.hpp"
+#include "xe_utils.hpp"
+
+#define TINYOBJLOADER_IMPLEMENTATION
+#include "xe_obj_loader.hpp"
+
+#define GLM_ENABLE_EXPERIMENTAL
+#include <glm/gtx/hash.hpp>
+
+#include <cassert>
+#include <cstring>
+#include <unordered_map>
+
+namespace std {
+template<>
+struct hash<xe::XeModel::Vertex> {
+ size_t operator()(xe::XeModel::Vertex const &vertex) const {
+ size_t seed = 0;
+ xe::hashCombine(seed, vertex.position, vertex.normal, vertex.uv);
+ return seed;
+ }
+};
+}
+
+namespace xe {
+
+XeModel::XeModel(XeDevice &device, const XeModel::Builder &builder) : xeDevice{device} {
+ createVertexBuffers(builder.vertices);
+ createIndexBuffers(builder.indices);
+}
+
+XeModel::~XeModel() {}
+
+std::unique_ptr<XeModel> XeModel::createModelFromFile(XeDevice &device, const std::string &filepath) {
+ Builder builder{};
+ builder.loadModel(filepath);
+ return std::make_unique<XeModel>(device, builder);
+}
+
+void XeModel::createVertexBuffers(const std::vector<Vertex> &vertices) {
+ vertexCount = static_cast<uint32_t>(vertices.size());
+ assert(vertexCount >= 3 && "Vertex count must be atleast 3");
+ VkDeviceSize bufferSize = sizeof(vertices[0]) * vertexCount;
+ uint32_t vertexSize = sizeof(vertices[0]);
+
+ XeBuffer stagingBuffer {
+ xeDevice,
+ vertexSize,
+ vertexCount,
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ };
+
+ stagingBuffer.map();
+ stagingBuffer.writeToBuffer((void *)vertices.data());
+
+ vertexBuffer = std::make_unique<XeBuffer>(
+ xeDevice,
+ vertexSize,
+ vertexCount,
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
+ );
+
+ xeDevice.copyBuffer(stagingBuffer.getBuffer(), vertexBuffer->getBuffer(), bufferSize);
+}
+
+void XeModel::createIndexBuffers(const std::vector<uint32_t> &indices) {
+ indexCount = static_cast<uint32_t>(indices.size());
+ hasIndexBuffer = indexCount > 0;
+
+ if (!hasIndexBuffer) {
+ return;
+ }
+
+ VkDeviceSize bufferSize = sizeof(indices[0]) * indexCount;
+ uint32_t indexSize = sizeof(indices[0]);
+
+ XeBuffer stagingBuffer {
+ xeDevice,
+ indexSize,
+ indexCount,
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ };
+
+ stagingBuffer.map();
+ stagingBuffer.writeToBuffer((void *)indices.data());
+
+ indexBuffer = std::make_unique<XeBuffer>(
+ xeDevice,
+ indexSize,
+ indexCount,
+ VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
+ );
+
+ xeDevice.copyBuffer(stagingBuffer.getBuffer(), indexBuffer->getBuffer(), bufferSize);
+}
+
+void XeModel::bind(VkCommandBuffer commandBuffer) {
+ VkBuffer buffers[] = {vertexBuffer->getBuffer()};
+ VkDeviceSize offsets[] = {0};
+ vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers, offsets);
+
+ if (hasIndexBuffer) {
+ vkCmdBindIndexBuffer(commandBuffer, indexBuffer->getBuffer(), 0, VK_INDEX_TYPE_UINT32);
+ }
+}
+
+void XeModel::draw(VkCommandBuffer commandBuffer) {
+ if (hasIndexBuffer) {
+ vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
+ } else {
+ vkCmdDraw(commandBuffer, vertexCount, 1, 0, 0);
+ }
+}
+
+std::vector<VkVertexInputBindingDescription> XeModel::Vertex::getBindingDescriptions() {
+ std::vector<VkVertexInputBindingDescription> bindingDescriptions(1);
+ bindingDescriptions[0].binding = 0;
+ bindingDescriptions[0].stride = sizeof(Vertex);
+ bindingDescriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+ return bindingDescriptions;
+}
+
+std::vector<VkVertexInputAttributeDescription> XeModel::Vertex::getAttributeDescriptions() {
+ std::vector<VkVertexInputAttributeDescription> attributeDescptions{};
+
+ attributeDescptions.push_back({0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, position)});
+ attributeDescptions.push_back({1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color)});
+ attributeDescptions.push_back({2, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal)});
+ attributeDescptions.push_back({3, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, uv)});
+
+ return attributeDescptions;
+}
+
+void XeModel::Builder::loadModel(const std::string &filepath) {
+ tinyobj::attrib_t attrib;
+ std::vector<tinyobj::shape_t> shapes;
+ std::vector<tinyobj::material_t> materials;
+ std::string warn, err;
+ if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filepath.c_str())) {
+ throw std::runtime_error(warn + err);
+ }
+
+ vertices.clear();
+ indices.clear();
+
+ std::unordered_map<Vertex, uint32_t> uniqueVertices{};
+ for (const auto &shape : shapes) {
+ for (const auto &index : shape.mesh.indices) {
+ Vertex vertex{};
+
+ if(index.vertex_index >= 0) {
+ vertex.position = {
+ attrib.vertices[3 * index.vertex_index + 0],
+ attrib.vertices[3 * index.vertex_index + 1],
+ attrib.vertices[3 * index.vertex_index + 2]
+ };
+
+ vertex.color = {
+ attrib.colors[3 * index.vertex_index + 0],
+ attrib.colors[3 * index.vertex_index + 1],
+ attrib.colors[3 * index.vertex_index + 2]
+ };
+ }
+
+ if(index.normal_index >= 0) {
+ vertex.normal = {
+ attrib.normals[3 * index.normal_index + 0],
+ attrib.normals[3 * index.normal_index + 1],
+ attrib.normals[3 * index.normal_index + 2]
+ };
+ }
+
+ if(index.texcoord_index >= 0) {
+ vertex.uv = {
+ attrib.texcoords[2 * index.texcoord_index + 0],
+ attrib.texcoords[2 * index.texcoord_index + 1],
+ };
+ }
+
+ if (uniqueVertices.count(vertex) == 0) {
+ uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
+ vertices.push_back(vertex);
+ }
+ indices.push_back(uniqueVertices[vertex]);
+ }
+ }
+}
+
+} \ No newline at end of file