kaliber/src/engine/mesh.cc

166 lines
4.7 KiB
C++

#include "engine/mesh.h"
#include <string.h>
#include "base/log.h"
#include "third_party/jsoncpp/json.h"
#include "engine/engine.h"
#include "engine/platform/asset_file.h"
namespace eng {
bool Mesh::Create(Primitive primitive,
const std::string& vertex_description,
size_t num_vertices,
const void* vertices,
DataType index_description,
size_t num_indices,
const void* indices) {
primitive_ = primitive;
num_vertices_ = num_vertices;
index_description_ = index_description;
num_indices_ = num_indices;
if (!ParseVertexDescription(vertex_description, vertex_description_)) {
LOG << "Failed to parse vertex description.";
return false;
}
int vertex_buffer_size = GetVertexSize() * num_vertices_;
if (vertex_buffer_size > 0) {
vertices_ = std::make_unique<char[]>(vertex_buffer_size);
memcpy(vertices_.get(), vertices, vertex_buffer_size);
}
if (!indices)
return true;
int index_buffer_size = GetIndexSize() * num_indices_;
if (index_buffer_size > 0) {
indices_ = std::make_unique<char[]>(index_buffer_size);
memcpy(indices_.get(), indices, index_buffer_size);
}
return true;
}
bool Mesh::Load(const std::string& file_name) {
size_t buffer_size = 0;
auto json_mesh = AssetFile::ReadWholeFile(file_name.c_str(),
Engine::Get().GetRootPath().c_str(),
&buffer_size, true);
if (!json_mesh) {
LOG << "Failed to read file: " << file_name;
return false;
}
std::string err;
Json::Value root;
Json::CharReaderBuilder builder;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(json_mesh.get(), json_mesh.get() + buffer_size, &root,
&err)) {
LOG << "Failed to load mesh. Json parser error: " << err;
return false;
}
const std::string& primitive_str = root["primitive"].asString();
if (primitive_str == "Triangles") {
primitive_ = kPrimitive_Triangles;
} else if (primitive_str == "TriangleStrip") {
primitive_ = kPrimitive_TriangleStrip;
} else {
LOG << "Failed to load mesh. Invalid primitive: " << primitive_str;
return false;
}
num_vertices_ = root["num_vertices"].asUInt();
if (!ParseVertexDescription(root["vertex_description"].asString(),
vertex_description_)) {
LOG << "Failed to parse vertex description.";
return false;
}
size_t array_size = 0;
for (auto& attr : vertex_description_) {
array_size += std::get<2>(attr);
}
array_size *= num_vertices_;
const Json::Value vertices = root["vertices"];
if (vertices.size() != array_size) {
LOG << "Failed to load mesh. Vertex array size: " << vertices.size()
<< ", expected " << array_size;
return false;
}
int vertex_buffer_size = GetVertexSize() * num_vertices_;
if (vertex_buffer_size <= 0) {
LOG << "Failed to load mesh. Invalid vertex size.";
return false;
}
LOG << "Loaded " << file_name << ". Vertex array size: " << vertices.size();
vertices_ = std::make_unique<char[]>(vertex_buffer_size);
char* dst = vertices_.get();
int i = 0;
while (i < vertices.size()) {
for (auto& attr : vertex_description_) {
auto [attrib_type, data_type, num_elements, type_size] = attr;
while (num_elements--) {
switch (data_type) {
case kDataType_Byte:
*((unsigned char*)dst) = (unsigned char)vertices[i].asUInt();
break;
case kDataType_Float:
*((float*)dst) = (float)vertices[i].asFloat();
break;
case kDataType_Int:
*((int*)dst) = vertices[i].asInt();
break;
case kDataType_Short:
*((short*)dst) = (short)vertices[i].asInt();
break;
case kDataType_UInt:
*((unsigned int*)dst) = vertices[i].asUInt();
break;
case kDataType_UShort:
*((unsigned short*)dst) = (unsigned short)vertices[i].asUInt();
break;
default:
NOTREACHED << "- Unknown data type: " << data_type;
}
dst += type_size;
++i;
}
}
}
return true;
}
size_t Mesh::GetVertexSize() const {
unsigned int size = 0;
for (auto& attr : vertex_description_) {
size += std::get<2>(attr) * std::get<3>(attr);
}
return size;
}
size_t Mesh::GetIndexSize() const {
switch (index_description_) {
case kDataType_Byte:
return sizeof(char);
case kDataType_UShort:
return sizeof(unsigned short);
case kDataType_UInt:
return sizeof(unsigned int);
default:
return 0;
}
}
} // namespace eng