minecraftvulkan/engine/xe_model.cpp

157 lines
4.3 KiB
C++
Raw Normal View History

2022-09-19 01:20:51 +00:00
#include "xe_model.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>
2022-09-25 16:07:49 +00:00
#include <iostream>
2022-09-19 01:20:51 +00:00
namespace xe {
2022-09-25 01:16:13 +00:00
Model::Model(Device &device, const Model::Builder &builder) : xeDevice{device} {
2022-09-25 16:07:49 +00:00
createVertexBuffers(builder.vertexData, builder.vertexSize);
2022-09-19 01:20:51 +00:00
createIndexBuffers(builder.indices);
}
2022-09-25 01:16:13 +00:00
Model::~Model() {}
2022-09-19 01:20:51 +00:00
2022-09-25 01:16:13 +00:00
std::unique_ptr<Model> Model::createModelFromFile(Device &device, const std::string &filepath) {
2022-09-19 01:20:51 +00:00
Builder builder{};
builder.loadModel(filepath);
2022-09-25 01:16:13 +00:00
return std::make_unique<Model>(device, builder);
2022-09-19 01:20:51 +00:00
}
2022-09-25 16:07:49 +00:00
void Model::createVertexBuffers(const std::vector<float> &vertexData, uint32_t vertexSize) {
vertexCount = static_cast<uint32_t>(vertexData.size()) / (vertexSize / 4);
2022-09-19 01:20:51 +00:00
assert(vertexCount >= 3 && "Vertex count must be atleast 3");
2022-09-25 16:07:49 +00:00
VkDeviceSize bufferSize = vertexData.size() * 4;
2022-09-19 01:20:51 +00:00
2022-09-25 01:16:13 +00:00
Buffer stagingBuffer {
2022-09-19 01:20:51 +00:00
xeDevice,
vertexSize,
vertexCount,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
};
stagingBuffer.map();
2022-09-25 16:07:49 +00:00
stagingBuffer.writeToBuffer((void *)vertexData.data());
2022-09-19 01:20:51 +00:00
2022-09-25 01:16:13 +00:00
vertexBuffer = std::make_unique<Buffer>(
2022-09-19 01:20:51 +00:00
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);
}
2022-09-25 16:07:49 +00:00
void Model::createIndexBuffers(const std::vector<uint32_t> &indexData) {
indexCount = static_cast<uint32_t>(indexData.size());
2022-09-19 01:20:51 +00:00
hasIndexBuffer = indexCount > 0;
if (!hasIndexBuffer) {
return;
}
2022-09-25 16:07:49 +00:00
VkDeviceSize bufferSize = sizeof(indexData[0]) * indexCount;
uint32_t indexSize = sizeof(indexData[0]);
2022-09-19 01:20:51 +00:00
2022-09-25 01:16:13 +00:00
Buffer stagingBuffer {
2022-09-19 01:20:51 +00:00
xeDevice,
indexSize,
indexCount,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
};
stagingBuffer.map();
2022-09-25 16:07:49 +00:00
stagingBuffer.writeToBuffer((void *)indexData.data());
2022-09-19 01:20:51 +00:00
2022-09-25 01:16:13 +00:00
indexBuffer = std::make_unique<Buffer>(
2022-09-19 01:20:51 +00:00
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);
}
2022-09-25 01:16:13 +00:00
void Model::bind(VkCommandBuffer commandBuffer) {
2022-09-19 01:20:51 +00:00
VkBuffer buffers[] = {vertexBuffer->getBuffer()};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, buffers, offsets);
if (hasIndexBuffer) {
vkCmdBindIndexBuffer(commandBuffer, indexBuffer->getBuffer(), 0, VK_INDEX_TYPE_UINT32);
}
}
2022-09-25 01:16:13 +00:00
void Model::draw(VkCommandBuffer commandBuffer) {
2022-09-19 01:20:51 +00:00
if (hasIndexBuffer) {
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
} else {
vkCmdDraw(commandBuffer, vertexCount, 1, 0, 0);
}
}
2022-09-25 01:16:13 +00:00
void Model::Builder::loadModel(const std::string &filepath) {
2022-09-19 01:20:51 +00:00
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);
}
2022-09-25 16:07:49 +00:00
vertexData.clear();
2022-09-19 01:20:51 +00:00
indices.clear();
2022-09-25 16:07:49 +00:00
vertexSize = 0;
2022-09-26 03:08:03 +00:00
bool vertex, normal, uvs;
2022-09-19 01:20:51 +00:00
for (const auto &shape : shapes) {
for (const auto &index : shape.mesh.indices) {
if(index.vertex_index >= 0) {
2022-09-25 16:07:49 +00:00
vertexData.push_back(attrib.vertices[3 * index.vertex_index + 0]);
vertexData.push_back(attrib.vertices[3 * index.vertex_index + 1]);
vertexData.push_back(attrib.vertices[3 * index.vertex_index + 2]);
vertex = true;
2022-09-19 01:20:51 +00:00
}
if(index.normal_index >= 0) {
2022-09-25 16:07:49 +00:00
vertexData.push_back(attrib.normals[3 * index.normal_index + 0]);
vertexData.push_back(attrib.normals[3 * index.normal_index + 1]);
vertexData.push_back(attrib.normals[3 * index.normal_index + 2]);
normal = true;
2022-09-19 01:20:51 +00:00
}
if(index.texcoord_index >= 0) {
2022-09-25 16:07:49 +00:00
vertexData.push_back(attrib.texcoords[2 * index.texcoord_index + 0]);
vertexData.push_back(attrib.texcoords[2 * index.texcoord_index + 1]);
uvs = true;
2022-09-19 01:20:51 +00:00
}
}
}
2022-09-25 16:07:49 +00:00
if(vertex)
vertexSize += 12;
if(normal)
vertexSize += 12;
if(uvs)
vertexSize += 8;
2022-09-19 01:20:51 +00:00
}
}