Archived
1
Fork 0
This repository has been archived on 2025-04-12. You can view files and clone it, but cannot push or open issues or pull requests.
prism/engine/asset/src/asset.cpp

314 lines
9 KiB
C++
Raw Normal View History

2020-08-11 12:07:21 -04:00
#include "asset.hpp"
#include <map>
#include <array>
#include <stb_image.h>
#include "log.hpp"
#include "engine.hpp"
#include "gfx.hpp"
#include "json_conversions.hpp"
#include "gfx_commandbuffer.hpp"
#include "assertions.hpp"
2020-09-21 09:37:52 -04:00
#include "renderer.hpp"
#include "input.hpp"
#include "physics.hpp"
2021-04-20 10:37:56 -04:00
#include "imgui_backend.hpp"
2020-08-11 12:07:21 -04:00
2021-05-12 09:05:56 -04:00
std::unique_ptr<Mesh> load_mesh(const prism::path path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
auto file = prism::open_file(path, true);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load mesh from {}!", path.string());
2020-08-11 12:07:21 -04:00
return nullptr;
}
int version = 0;
file->read(&version);
if(version == 5 || version == 6 || version == 7) {
2020-08-11 12:07:21 -04:00
} else {
prism::log("{} failed the mesh version check! reported version = {}", path.string(), version);
2020-08-11 12:07:21 -04:00
return nullptr;
}
auto mesh = std::make_unique<Mesh>();
2020-08-13 07:48:50 -04:00
mesh->path = path.string();
2020-08-11 12:07:21 -04:00
enum MeshType : int {
Static,
Skinned
} mesh_type;
file->read(&mesh_type);
// TODO: use unsigned int here
int numVertices = 0;
file->read(&numVertices);
Expects(numVertices > 0);
const auto read_buffer = [&f = file.value(), numVertices](unsigned int size) -> GFXBuffer* {
auto buffer = engine->get_gfx()->create_buffer(nullptr, size * static_cast<unsigned int>(numVertices), false, GFXBufferUsage::Vertex);
auto buffer_ptr = reinterpret_cast<unsigned char*>(engine->get_gfx()->get_buffer_contents(buffer));
2020-08-11 12:07:21 -04:00
f.read(buffer_ptr, size * static_cast<unsigned int>(numVertices));
engine->get_gfx()->release_buffer_contents(buffer, buffer_ptr);
return buffer;
};
// read positions
2021-05-12 09:56:44 -04:00
mesh->position_buffer = read_buffer(sizeof(prism::float3));
mesh->normal_buffer = read_buffer(sizeof(prism::float3));
mesh->texture_coord_buffer = read_buffer(sizeof(prism::float2));
mesh->tangent_buffer = read_buffer(sizeof(prism::float3));
mesh->bitangent_buffer = read_buffer(sizeof(prism::float3));
2020-08-11 12:07:21 -04:00
if(mesh_type == MeshType::Skinned)
mesh->bone_buffer = read_buffer(sizeof(BoneVertexData));
int numIndices = 0;
file->read(&numIndices);
Expects(numIndices > 0);
mesh->index_buffer = engine->get_gfx()->create_buffer(nullptr, sizeof(uint32_t) * numIndices, false, GFXBufferUsage::Index);
auto index_ptr = reinterpret_cast<uint32_t*>(engine->get_gfx()->get_buffer_contents(mesh->index_buffer));
file->read(index_ptr, sizeof(uint32_t) * numIndices);
engine->get_gfx()->release_buffer_contents(mesh->index_buffer, index_ptr);
int bone_len = 0;
file->read(&bone_len);
mesh->bones.reserve(bone_len);
if(bone_len > 0) {
file->read(&mesh->global_inverse_transformation);
std::map<std::string, uint32_t> boneMapping;
std::map<int, std::string> parentQueue;
for (int v = 0; v < bone_len; v++) {
std::string bone, parent;
file->read_string(bone);
file->read_string(parent);
2021-05-12 09:56:44 -04:00
prism::float3 pos;
2020-08-11 12:07:21 -04:00
file->read(&pos);
Quaternion rot;
file->read(&rot);
2021-05-12 09:56:44 -04:00
prism::float3 scl;
2020-08-11 12:07:21 -04:00
file->read(&scl);
if(!boneMapping.count(bone)) {
2020-08-11 12:07:21 -04:00
Bone b;
b.index = mesh->bones.size();
b.name = bone;
b.name = bone;
b.position = pos;
b.rotation = rot;
b.scale = scl;
if(parent != "none" && !parent.empty())
parentQueue[b.index] = parent;
mesh->bones.push_back(b);
boneMapping[bone] = b.index;
}
}
for(auto& [index, parentName] : parentQueue) {
for(auto& bone : mesh->bones) {
if(bone.name == parentName)
mesh->bones[index].parent = &bone;
}
}
for(auto& bone : mesh->bones) {
if(bone.parent == nullptr)
mesh->root_bone = &bone;
}
}
int numMeshes = 0;
file->read(&numMeshes);
Expects(numMeshes > 0);
mesh->parts.resize(numMeshes);
uint32_t vertexOffset = 0, indexOffset = 0;
for(int i = 0; i < numMeshes; i++) {
auto& p = mesh->parts[i];
p.vertex_offset = vertexOffset;
p.index_offset = indexOffset;
file->read_string(p.name);
if(version >= 6) {
2021-05-12 09:56:44 -04:00
file->read(&p.bounding_box);
2020-08-11 12:07:21 -04:00
}
int numVerts = 0;
file->read(&numVerts);
file->read(&p.index_count);
int numBones = 0;
file->read(&numBones);
p.bone_batrix_buffer = engine->get_gfx()->create_buffer(nullptr, sizeof(Matrix4x4) * 128, true, GFXBufferUsage::Storage);
if(numBones > 0) {
p.offset_matrices.resize(numBones);
file->read(p.offset_matrices.data(), sizeof(Matrix4x4) * numBones);
}
file->read(&p.material_override);
if(version == 7) {
file->read_string(p.material_hint);
}
2020-08-11 12:07:21 -04:00
vertexOffset += numVerts;
indexOffset += p.index_count;
}
mesh->num_indices = static_cast<uint32_t>(numIndices);
return mesh;
}
2021-05-12 09:05:56 -04:00
std::unique_ptr<Texture> load_texture(const prism::path path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
auto file = prism::open_file(path, true);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load texture from {}!", path.string());
2020-08-11 12:07:21 -04:00
return nullptr;
}
// TODO: expose somehow??
const bool should_generate_mipmaps = true;
2020-08-11 12:07:21 -04:00
file->read_all();
int width, height, channels;
unsigned char* data = stbi_load_from_memory(file->cast_data<unsigned char>(), file->size(), &width, &height, &channels, 4);
if(!data) {
prism::log("Failed to load texture from {}!", path.string());
2020-08-11 12:07:21 -04:00
return nullptr;
}
Expects(width > 0);
Expects(height > 0);
auto texture = std::make_unique<Texture>();
2020-08-13 07:48:50 -04:00
texture->path = path.string();
2020-08-11 12:07:21 -04:00
texture->width = width;
texture->height = height;
GFXTextureCreateInfo createInfo = {};
createInfo.label = path.string();
2020-08-11 12:07:21 -04:00
createInfo.width = width;
createInfo.height = height;
createInfo.format = GFXPixelFormat::R8G8B8A8_UNORM;
createInfo.usage = GFXTextureUsage::Sampled | GFXTextureUsage::TransferDst | GFXTextureUsage::TransferSrc; // src and dst are needed for copy tex data -> image and mipmap gen (from image data) respectively
2020-08-11 12:07:21 -04:00
if(should_generate_mipmaps)
createInfo.mip_count = std::floor(std::log2(std::max(width, height))) + 1;
texture->handle = engine->get_gfx()->create_texture(createInfo);
engine->get_gfx()->copy_texture(texture->handle, data, width * height * 4);
if(createInfo.mip_count > 1) {
GFXCommandBuffer* cmd_buf = engine->get_gfx()->acquire_command_buffer();
2020-08-11 12:07:21 -04:00
cmd_buf->generate_mipmaps(texture->handle, createInfo.mip_count);
engine->get_gfx()->submit(cmd_buf);
}
stbi_image_free(data);
return texture;
}
2021-05-12 09:05:56 -04:00
std::unique_ptr<Material> load_material(const prism::path path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
auto file = prism::open_file(path);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load material from {}!", path.string());
2020-08-11 12:07:21 -04:00
return {};
}
nlohmann::json j;
file->read_as_stream() >> j;
auto mat = std::make_unique<Material>();
2020-08-13 07:48:50 -04:00
mat->path = path.string();
2020-08-11 12:07:21 -04:00
if(!j.count("version") || j["version"] != 3) {
prism::log("Material {} failed the version check!", path.string());
2020-08-11 12:07:21 -04:00
return mat;
}
const auto loadProperty = [](nlohmann::json property) -> MaterialProperty {
MaterialProperty p;
p.value = property["value"];
p.float_value = property["float_value"];
p.type = property["type"];
if(!property["asset_value"].get<std::string>().empty()) {
p.value_tex = assetm->get<Texture>(prism::app_domain / property["asset_value"].get<std::string>());
}
return p;
};
mat->colorProperty = loadProperty(j["color"]);
if(j.contains("normal"))
mat->normalProperty = loadProperty(j["normal"]);
2020-08-11 12:07:21 -04:00
return mat;
}
2021-05-12 09:05:56 -04:00
void save_material(Material* material, const prism::path path) {
2020-08-11 12:07:21 -04:00
Expects(material != nullptr);
Expects(!path.empty());
nlohmann::json j;
j["version"] = 3;
2020-08-11 12:07:21 -04:00
const auto save_property = [](MaterialProperty& property) -> nlohmann::json {
nlohmann::json p;
p["name"] = property.name;
p["value"] = property.value;
p["asset_value"] = property.value_tex ? property.value_tex->path : "";
p["float_value"] = property.float_value;
p["type"] = property.type;
return p;
};
j["color"] = save_property(material->colorProperty);
j["normal"] = save_property(material->normalProperty);
2020-08-11 12:07:21 -04:00
2020-08-17 10:21:32 -04:00
std::ofstream out(path);
2020-08-11 12:07:21 -04:00
out << j;
}