342 lines
8.4 KiB
C++
342 lines
8.4 KiB
C++
#include "shared/Scene/VtxData.h"
|
|
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
bool isMeshDataValid(const char* fileName)
|
|
{
|
|
FILE* f = fopen(fileName, "rb");
|
|
|
|
if (!f)
|
|
return false;
|
|
|
|
SCOPE_EXIT
|
|
{
|
|
fclose(f);
|
|
};
|
|
|
|
MeshFileHeader header;
|
|
|
|
if (fread(&header, 1, sizeof(header), f) != sizeof(header))
|
|
return false;
|
|
|
|
if (fseek(f, sizeof(Mesh) * header.meshCount, SEEK_CUR))
|
|
return false;
|
|
|
|
if (fseek(f, sizeof(BoundingBox) * header.meshCount, SEEK_CUR))
|
|
return false;
|
|
|
|
if (fseek(f, header.indexDataSize, SEEK_CUR))
|
|
return false;
|
|
|
|
if (fseek(f, header.vertexDataSize, SEEK_CUR))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool isMeshHierarchyValid(const char* fileName)
|
|
{
|
|
FILE* f = fopen(fileName, "rb");
|
|
|
|
if (!f)
|
|
return false;
|
|
|
|
SCOPE_EXIT
|
|
{
|
|
fclose(f);
|
|
};
|
|
|
|
return true;
|
|
}
|
|
|
|
bool isMeshMaterialsValid(const char* fileName)
|
|
{
|
|
FILE* f = fopen(fileName, "rb");
|
|
|
|
if (!f)
|
|
return false;
|
|
|
|
SCOPE_EXIT
|
|
{
|
|
fclose(f);
|
|
};
|
|
|
|
uint64_t numMaterials = 0;
|
|
uint64_t materialsSize = 0;
|
|
|
|
if (fread(&numMaterials, 1, sizeof(numMaterials), f) != sizeof(numMaterials))
|
|
return false;
|
|
if (fread(&materialsSize, 1, sizeof(materialsSize), f) != sizeof(materialsSize))
|
|
return false;
|
|
if (numMaterials * sizeof(Material) != materialsSize)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
MeshFileHeader loadMeshData(const char* meshFile, MeshData& out)
|
|
{
|
|
FILE* f = fopen(meshFile, "rb");
|
|
|
|
assert(f);
|
|
|
|
if (!f) {
|
|
printf("Cannot open '%s'.\n", meshFile);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
SCOPE_EXIT
|
|
{
|
|
fclose(f);
|
|
};
|
|
|
|
MeshFileHeader header;
|
|
|
|
if (fread(&header, 1, sizeof(header), f) != sizeof(header)) {
|
|
printf("Unable to read mesh file header.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (fread(&out.streams, 1, sizeof(out.streams), f) != sizeof(out.streams)) {
|
|
printf("Unable to read vertex streams description.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
out.meshes.resize(header.meshCount);
|
|
if (fread(out.meshes.data(), sizeof(Mesh), header.meshCount, f) != header.meshCount) {
|
|
printf("Could not read mesh descriptors.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
out.boxes.resize(header.meshCount);
|
|
if (fread(out.boxes.data(), sizeof(BoundingBox), header.meshCount, f) != header.meshCount) {
|
|
printf("Could not read bounding boxes.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
out.indexData.resize(header.indexDataSize / sizeof(uint32_t));
|
|
out.vertexData.resize(header.vertexDataSize);
|
|
|
|
if (fread(out.indexData.data(), 1, header.indexDataSize, f) != header.indexDataSize) {
|
|
printf("Unable to read index data.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (fread(out.vertexData.data(), 1, header.vertexDataSize, f) != header.vertexDataSize) {
|
|
printf("Unable to read vertex data.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
void loadMeshDataMaterials(const char* fileName, MeshData& out)
|
|
{
|
|
FILE* f = fopen(fileName, "rb");
|
|
|
|
if (!f) {
|
|
printf("Cannot open '%s'.\n", fileName);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
uint64_t numMaterials = 0;
|
|
uint64_t materialsSize = 0;
|
|
|
|
if (fread(&numMaterials, 1, sizeof(numMaterials), f) != sizeof(numMaterials)) {
|
|
printf("Unable to read numMaterials.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (fread(&materialsSize, 1, sizeof(materialsSize), f) != sizeof(materialsSize)) {
|
|
printf("Unable to read materialsSize.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (numMaterials * sizeof(Material) != materialsSize) {
|
|
printf("Corrupted material file '%s'.\n", fileName);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
out.materials.resize(numMaterials);
|
|
if (fread(out.materials.data(), 1, materialsSize, f) != materialsSize) {
|
|
printf("Unable to read material data.\n");
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
loadStringList(f, out.textureFiles);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void saveMeshData(const char* fileName, const MeshData& m)
|
|
{
|
|
FILE* f = fopen(fileName, "wb");
|
|
|
|
if (!f) {
|
|
printf("Error opening file '%s' for writing.\n", fileName);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
const MeshFileHeader header = {
|
|
.meshCount = (uint32_t)m.meshes.size(),
|
|
.indexDataSize = (uint32_t)(m.indexData.size() * sizeof(uint32_t)),
|
|
.vertexDataSize = (uint32_t)(m.vertexData.size()),
|
|
};
|
|
|
|
fwrite(&header, 1, sizeof(header), f);
|
|
fwrite(&m.streams, 1, sizeof(m.streams), f);
|
|
fwrite(m.meshes.data(), sizeof(Mesh), header.meshCount, f);
|
|
fwrite(m.boxes.data(), sizeof(BoundingBox), header.meshCount, f);
|
|
fwrite(m.indexData.data(), 1, header.indexDataSize, f);
|
|
fwrite(m.vertexData.data(), 1, header.vertexDataSize, f);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void saveMeshDataMaterials(const char* fileName, const MeshData& m)
|
|
{
|
|
FILE* f = fopen(fileName, "wb");
|
|
|
|
if (!f) {
|
|
printf("Error opening file '%s' for writing.\n", fileName);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
const uint64_t numMaterials = m.materials.size();
|
|
const uint64_t materialsSize = m.materials.size() * sizeof(Material);
|
|
|
|
fwrite(&numMaterials, 1, sizeof(numMaterials), f);
|
|
fwrite(&materialsSize, 1, sizeof(materialsSize), f);
|
|
fwrite(m.materials.data(), sizeof(Material), numMaterials, f);
|
|
|
|
saveStringList(f, m.textureFiles);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void saveBoundingBoxes(const char* fileName, const std::vector<BoundingBox>& boxes)
|
|
{
|
|
FILE* f = fopen(fileName, "wb");
|
|
|
|
if (!f) {
|
|
printf("Error opening bounding boxes file '%s' for writing.\n", fileName);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
const uint32_t sz = (uint32_t)boxes.size();
|
|
fwrite(&sz, 1, sizeof(sz), f);
|
|
fwrite(boxes.data(), sz, sizeof(BoundingBox), f);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void loadBoundingBoxes(const char* fileName, std::vector<BoundingBox>& boxes)
|
|
{
|
|
FILE* f = fopen(fileName, "rb");
|
|
|
|
if (!f) {
|
|
printf("Error opening bounding boxes file '%s'\n", fileName);
|
|
assert(false);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
uint32_t sz;
|
|
fread(&sz, 1, sizeof(sz), f);
|
|
|
|
// TODO: check file size, divide by bounding box size
|
|
boxes.resize(sz);
|
|
fread(boxes.data(), sz, sizeof(BoundingBox), f);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
// combine a collection of meshes into a single MeshData container
|
|
MeshFileHeader mergeMeshData(MeshData& m, const std::vector<MeshData*> md)
|
|
{
|
|
uint32_t numTotalVertices = 0;
|
|
uint32_t numTotalIndices = 0;
|
|
|
|
if (!md.empty()) {
|
|
m.streams = md[0]->streams;
|
|
}
|
|
|
|
const uint32_t vertexSize = m.streams.getVertexSize();
|
|
|
|
uint32_t offset = 0;
|
|
uint32_t mtlOffset = 0;
|
|
|
|
for (const MeshData* i : md) {
|
|
LVK_ASSERT(m.streams == i->streams);
|
|
mergeVectors(m.indexData, i->indexData);
|
|
mergeVectors(m.vertexData, i->vertexData);
|
|
mergeVectors(m.meshes, i->meshes);
|
|
mergeVectors(m.boxes, i->boxes);
|
|
|
|
for (size_t j = 0; j != i->meshes.size(); j++) {
|
|
// m.vertexCount, m.lodCount and m.streamCount do not change
|
|
// m.vertexOffset also does not change, because vertex offsets are local (i.e., baked into the indices)
|
|
m.meshes[offset + j].indexOffset += numTotalIndices;
|
|
m.meshes[offset + j].materialID += mtlOffset;
|
|
}
|
|
|
|
// shift individual indices
|
|
for (size_t j = 0; j != i->indexData.size(); j++) {
|
|
m.indexData[numTotalIndices + j] += numTotalVertices;
|
|
}
|
|
|
|
offset += (uint32_t)i->meshes.size();
|
|
mtlOffset += (uint32_t)i->materials.size();
|
|
|
|
numTotalIndices += (uint32_t)i->indexData.size();
|
|
numTotalVertices += (uint32_t)i->vertexData.size() / vertexSize;
|
|
}
|
|
|
|
return MeshFileHeader{
|
|
.magicValue = 0x12345678,
|
|
.meshCount = (uint32_t)offset,
|
|
.indexDataSize = static_cast<uint32_t>(numTotalIndices * sizeof(uint32_t)),
|
|
.vertexDataSize = static_cast<uint32_t>(m.vertexData.size()),
|
|
};
|
|
}
|
|
|
|
void recalculateBoundingBoxes(MeshData& m)
|
|
{
|
|
LVK_ASSERT(m.streams.attributes[0].format == lvk::VertexFormat::Float3);
|
|
|
|
const uint32_t stride = m.streams.getVertexSize();
|
|
|
|
m.boxes.clear();
|
|
m.boxes.reserve(m.meshes.size());
|
|
|
|
for (const Mesh& mesh : m.meshes) {
|
|
const uint32_t numIndices = mesh.getLODIndicesCount(0);
|
|
|
|
glm::vec3 vmin(std::numeric_limits<float>::max());
|
|
glm::vec3 vmax(std::numeric_limits<float>::lowest());
|
|
|
|
for (uint32_t i = 0; i != numIndices; i++) {
|
|
const uint32_t vtxOffset = m.indexData[mesh.indexOffset + i] + mesh.vertexOffset;
|
|
const float* vf = (const float*)&m.vertexData[vtxOffset * stride];
|
|
|
|
vmin = glm::min(vmin, vec3(vf[0], vf[1], vf[2]));
|
|
vmax = glm::max(vmax, vec3(vf[0], vf[1], vf[2]));
|
|
}
|
|
|
|
m.boxes.emplace_back(vmin, vmax);
|
|
}
|
|
}
|