This commit is contained in:
Ben Kyd
2023-12-20 19:17:57 +00:00
parent 5c5dfbee40
commit 0155cb9804
22 changed files with 1603 additions and 5753055 deletions

View File

@@ -3,6 +3,8 @@ project(inferno)
file(GLOB SRC "src/*.cpp" "src/graphics/*.cpp" "src/preview_renderer/*.cpp" "src/scene/*.cpp" "src/thirdparty/imgui/*.cpp" "src/preview_renderer/*.cpp")
add_subdirectory("thirdparty/assimp")
add_executable(inferno ${SRC})
target_include_directories(inferno PRIVATE "libhart/thirdparty")
target_include_directories(inferno PRIVATE "libhart/")
@@ -72,6 +74,8 @@ find_package(OpenMP REQUIRED)
find_package(Vulkan REQUIRED)
# Libraries
target_link_libraries(inferno PRIVATE assimp)
if (WIN32)
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
find_package(glfw3 CONFIG REQUIRED)

1454
res/Bistro.mtl Normal file

File diff suppressed because it is too large Load Diff

3
res/Bistro.obj Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3e515264cf8692dfb1db7e7b222c26de72ff9124987dc15e16f240cb1c5e8784
size 309834053

3
res/BistroExterior.fbx Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2fd51c43ba2c2e0bffeb59435123d328b3b8f34f413ec14c6c2d2f3d3a4e167d
size 132582812

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:52878f6cb8634482f9eca10551e28d262ba31bb4d0603cc5e3ac9d0886c02ed7
size 131297084

Binary file not shown.

BIN
res/cornell.obj LFS

Binary file not shown.

File diff suppressed because it is too large Load Diff

2180253
res/dragon.obj

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

200011
res/lucy.obj

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
namespace inferno::graphics {
#define VALIDATION_LAYERS_ENABLED 1
// #define VALIDATION_LAYERS_ENABLED 1
#ifdef VALIDATION_LAYERS_ENABLED
const std::vector<const char*> VALIDATION_LAYERS = {
"VK_LAYER_KHRONOS_validation",

View File

@@ -121,19 +121,18 @@ InfernoApp* inferno_create()
},
true);
scene::Mesh* mesh = scene::mesh_create(app->Device);
scene::mesh_load_obj(mesh, "res/cornell-box.obj");
scene::mesh_ready(mesh);
scene::SceneObject* object = scene::scene_object_create();
scene::scene_object_add_mesh(object, mesh);
scene::SceneObject* object = scene::scene_object_create(app->Device);
scene::scene_object_load(object, "res/Bistro.obj");
// scene::scene_object_load(object, "res/sponza.obj");
// scene::mesh_load_obj(object, "res/cornell-box.obj");
scene::scene_add_object(app->Scene, object);
scene::Mesh* lucy = scene::mesh_create(app->Device);
scene::mesh_load_obj(lucy, "res/lucy.obj");
scene::mesh_ready(lucy);
scene::SceneObject* lucyObject = scene::scene_object_create();
scene::scene_object_add_mesh(lucyObject, lucy);
scene::scene_add_object(app->Scene, lucyObject);
// scene::Mesh* lucy = scene::mesh_create(app->Device);
// scene::mesh_load_obj(lucy, "res/lucy.obj");
// scene::mesh_ready(lucy);
// scene::SceneObject* lucyObject = scene::scene_object_create();
// scene::scene_object_add_mesh(lucyObject, lucy);
// scene::scene_add_object(app->Scene, lucyObject);
// app->PreviewRenderer = graphics::preview_create();
// graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera);

21
src/scene/filemanager.hpp Normal file
View File

@@ -0,0 +1,21 @@
#include <vector>
#include <filesystem>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <hart_graphics.hpp>
namespace inferno::scene {
typedef struct FileManager {
Assimp::Importer Importer;
} File;
FileManager* filemanager_create();
void filemanager_cleanup();
aiScene* filemanager_load
}

View File

@@ -1,12 +1,14 @@
#include "mesh.hpp"
#include <scene/objloader.hpp>
#include "graphics/buffer.hpp"
#include "graphics/device.hpp"
#include <yolo/yolo.hpp>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <iostream>
namespace inferno::scene {
@@ -48,64 +50,55 @@ Mesh* mesh_create(graphics::GraphicsDevice* device)
return mesh;
}
void mesh_cleanup(Mesh* mesh)
void mesh_cleanup(Mesh* mesh) { delete mesh; }
void mesh_process(Mesh* out, aiMesh* mesh)
{
delete mesh->MeshObjLoader;
delete mesh;
}
void mesh_load_obj(Mesh* mesh, std::filesystem::path file)
{
mesh->MeshObjLoader = new ObjLoader();
mesh->MeshObjLoader->load(file);
int vertCount = mesh->MeshObjLoader->getVertCount();
for (int i = 0; i < vertCount * 3; i += 3) {
Vert vert;
vert.Position = {
mesh->MeshObjLoader->getPositions()[i],
mesh->MeshObjLoader->getPositions()[i + 1],
mesh->MeshObjLoader->getPositions()[i + 2],
};
vert.Normal = {
mesh->MeshObjLoader->getNormals()[i],
mesh->MeshObjLoader->getNormals()[i + 1],
mesh->MeshObjLoader->getNormals()[i + 2],
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
Vert vertex = {
.Position = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z),
.Normal = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z),
};
out->Verticies.push_back(vertex);
}
mesh->Verticies.push_back(vert);
// indicies
for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++) {
out->Indicies.push_back(face.mIndices[j]);
}
}
}
void mesh_ready(Mesh* mesh)
{
void* data = mesh->Verticies.data();
void* indexData = (void*)mesh->MeshObjLoader->getFaces();
void* indexData = mesh->Indicies.data();
uint32_t size = mesh->Verticies.size();
// yolo::debug("Mesh size: {}", size);
yolo::debug("Mesh size: {}", size);
mesh->VertexBuffer = graphics::vertex_buffer_create(mesh->Device, data, size);
mesh->IndexBuffer = graphics::index_buffer_create(
mesh->Device, indexData, mesh->MeshObjLoader->getIndexCount());
mesh->IndexBuffer
= graphics::index_buffer_create(mesh->Device, indexData, mesh->Indicies.size());
yolo::debug("Mesh for preview ready...");
}
// TODO: Extract vertex and normal data from internal mesh
uint32_t mesh_get_verticies(Mesh* mesh, const float** v, const float** n)
{
*v = &mesh->MeshObjLoader->getPositions()[0];
*n = &mesh->MeshObjLoader->getNormals()[0];
return mesh->MeshObjLoader->getVertCount();
return mesh->Verticies.size();
}
uint32_t mesh_get_indicies(Mesh* mesh, const uint32_t** i)
{
*i = &mesh->MeshObjLoader->getFaces()[0];
return mesh->MeshObjLoader->getIndexCount();
*i = mesh->Indicies.data();
return mesh_get_index_count(mesh);
}
uint32_t mesh_get_index_count(Mesh* mesh) { return mesh->MeshObjLoader->getIndexCount(); }
uint32_t mesh_get_index_count(Mesh* mesh) { return mesh->Indicies.size(); }
void mesh_set_model_matrix(Mesh* mesh, glm::mat4 model) { mesh->ModelMatrix = model; }

View File

@@ -2,6 +2,8 @@
#include <hart_graphics.hpp>
#include <assimp/mesh.h>
#include <array>
#include <filesystem>
#include <vector>
@@ -13,8 +15,6 @@ struct Buffer;
namespace inferno::scene {
class ObjLoader;
// TODO: This should be procedural like everything else
struct Vert {
glm::vec3 Position;
@@ -38,8 +38,8 @@ typedef struct Mesh {
glm::mat4 ModelMatrix;
ObjLoader* MeshObjLoader;
std::vector<Vert> Verticies;
std::vector<uint32_t> Indicies;
graphics::Buffer* VertexBuffer;
graphics::Buffer* IndexBuffer;
@@ -48,7 +48,8 @@ typedef struct Mesh {
Mesh* mesh_create(graphics::GraphicsDevice* device);
void mesh_cleanup(Mesh* mesh);
void mesh_load_obj(Mesh* mesh, std::filesystem::path file);
void mesh_process(Mesh* out, aiMesh* mesh);
void mesh_ready(Mesh* mesh);
uint32_t mesh_get_verticies(Mesh* mesh, const float** v, const float** n);

View File

@@ -1,18 +1,53 @@
#include "object.hpp"
#include "graphics/device.hpp"
#include "mesh.hpp"
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <yolo/yolo.hpp>
namespace inferno::scene {
SceneObject* scene_object_create()
SceneObject* scene_object_create(graphics::GraphicsDevice* device)
{
SceneObject* object = new SceneObject;
object->Device = device;
return object;
}
void scene_object_cleanup(SceneObject* object)
{
void scene_object_cleanup(SceneObject* object) { }
void processNode(SceneObject* object, const aiNode* node, const aiScene* scene)
{
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
Mesh* mesh = mesh_create(object->Device);
mesh_process(mesh, scene->mMeshes[node->mMeshes[i]]);
mesh_ready(mesh);
scene_object_add_mesh(object, mesh);
}
for (unsigned int i = 0; i < node->mNumChildren; i++) {
processNode(object, node->mChildren[i], scene);
}
}
void scene_object_load(SceneObject* object, std::filesystem::path file)
{
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(file.string(),
aiProcess_Triangulate | aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph
| aiProcess_GenNormals);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
yolo::error("Assimp error: {}", importer.GetErrorString());
return;
}
processNode(object, scene->mRootNode, scene);
}
void scene_object_add_mesh(SceneObject* object, Mesh* mesh)
@@ -20,10 +55,6 @@ void scene_object_add_mesh(SceneObject* object, Mesh* mesh)
object->Meshs.push_back(mesh);
}
std::vector<Mesh*>& scene_object_get_meshs(SceneObject* object)
{
return object->Meshs;
}
std::vector<Mesh*>& scene_object_get_meshs(SceneObject* object) { return object->Meshs; }
}

View File

@@ -2,18 +2,28 @@
#include <memory>
#include <vector>
#include <filesystem>
namespace inferno::graphics {
struct GraphicsDevice;
struct Buffer;
}
namespace inferno::scene {
class Mesh;
typedef struct SceneObject {
graphics::GraphicsDevice* Device;
std::vector<Mesh*> Meshs;
} SceneObject;
SceneObject* scene_object_create();
SceneObject* scene_object_create(graphics::GraphicsDevice* device);
void scene_object_cleanup(SceneObject* object);
void scene_object_load(SceneObject* object, std::filesystem::path file);
void scene_object_add_mesh(SceneObject* object, Mesh* mesh);
std::vector<Mesh*>& scene_object_get_meshs(SceneObject* object);

View File

@@ -1,267 +0,0 @@
// Adapted from https://raw.githubusercontent.com/tamato/simple-obj-loader/master/objloader.cpp
#include "objloader.hpp"
#include <yolo/yolo.hpp>
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <cstring>
#include <assert.h>
#include <map>
namespace inferno::scene {
struct FaceVert
{
FaceVert() : vert(-1), norm(-1), coord(-1) {}
int vert;
int norm;
int coord;
};
struct vert_less {
bool operator() (const FaceVert& lhs, const FaceVert& rhs) const
{
// handle any size mesh
if (lhs.vert != rhs.vert) return (lhs.vert<rhs.vert);
if (lhs.norm != rhs.norm) return (lhs.norm<rhs.norm);
if (lhs.coord!=rhs.coord) return (lhs.coord<rhs.coord);
return false;
// the following breaks down on very large meshes
// const unsigned long prime1 = 73856093;
// const unsigned long prime2 = 19349663;
// const unsigned long prime3 = 83492791;
// unsigned long lh = (lhs.vert * prime1) ^ (lhs.norm * prime2) ^ (lhs.coord * prime3);
// unsigned long rh = (rhs.vert * prime1) ^ (rhs.norm * prime2) ^ (rhs.coord * prime3);
// return lh < rh;
}
};
ObjLoader::ObjLoader()
: mTexCoordLayers(1)
{
}
ObjLoader::~ObjLoader()
{
}
void ObjLoader::load(std::filesystem::path file)
{
if (!std::filesystem::exists(file))
{
yolo::error("OBJ File does not exist at ", file.string());
return;
}
std::ifstream inf;
inf.open(file.c_str(), std::ios_base::in);
if (!inf.is_open())
{
yolo::error("Failed to open OBJ file ", file.string());
return;
}
mPositions.clear();
mNormals.clear();
mTexCoords.clear();
mFaces.clear();
char *delims = " \n\r";
const unsigned int CHARACTER_COUNT = 500;
char line[CHARACTER_COUNT] = {0};
std::vector<glm::vec3> verts;
std::vector<glm::vec3> norms;
std::vector<glm::vec2> texcoords;
std::map<FaceVert, int, vert_less> uniqueverts;
unsigned int vert_count = 0;
while (inf.good())
{
memset( (void*)line, 0, CHARACTER_COUNT);
inf.getline(line, CHARACTER_COUNT);
if (inf.eof()) break;
char *token = strtok(line, delims);
if (token == NULL || token[0] == '#' || token[0] == '$')
continue;
// verts look like:
// v float float float
if (strcmp(token, "v") == 0)
{
float x=0, y=0, z=0, w=1;
sscanf(line+2, "%f %f %f %f", &x, &y, &z, &w);
verts.push_back( glm::vec3(x/w,y/w,z/w) );
}
// normals:
// nv float float float
else if (strcmp(token, "vn") == 0) {
float x=0, y=0, z=0;
sscanf(line+3, "%f %f %f", &x, &y, &z);
norms.push_back( glm::vec3(x,y,z) );
}
// texcoords:
// vt float float
else if (strcmp(token, "vt") == 0)
{
float x=0, y=0, z=0;
sscanf(line+3, "%f %f %f", &x, &y, &z);
texcoords.push_back( glm::vec2(x, y) );
}
// keep track of smoothing groups
// s [number|off]
else if (strcmp(token, "s") == 0)
{
}
// faces start with:
// f
else if (strcmp(token, "f") == 0)
{
std::vector<int> vindices;
std::vector<int> nindices;
std::vector<int> tindices;
// fill out a triangle from the line, it could have 3 or 4 edges
char *lineptr = line + 2;
while (lineptr[0] != 0) {
while (lineptr[0] == ' ') ++lineptr;
int vi=0, ni=0, ti=0;
if (sscanf(lineptr, "%d/%d/%d", &vi, &ni, &ti) == 3) {
vindices.push_back(vi-1);
nindices.push_back(ni-1);
tindices.push_back(ti-1);
}
else
if (sscanf(lineptr, "%d//%d", &vi, &ni) == 2) {
vindices.push_back(vi-1);
nindices.push_back(ni-1);
}
else
if (sscanf(lineptr, "%d/%d", &vi, &ti) == 2) {
vindices.push_back(vi-1);
tindices.push_back(ti-1);
}
else
if (sscanf(lineptr, "%d", &vi) == 1) {
vindices.push_back(vi-1);
}
while(lineptr[0] != ' ' && lineptr[0] != 0) ++lineptr;
}
// being that some exporters can export either 3 or 4 sided polygon's
// convert what ever was exported into triangles
for (size_t i=1; i<vindices.size()-1; ++i)
{
Face face;
FaceVert tri;
tri.vert = vindices[0];
if (!nindices.empty())
tri.norm = nindices[0];
if (!tindices.empty())
tri.norm = tindices[0];
if (uniqueverts.count(tri) == 0)
uniqueverts[tri] = vert_count++;
face.a = uniqueverts[tri];
tri.vert = vindices[i];
if (!nindices.empty())
tri.norm = nindices[i];
if (!tindices.empty())
tri.norm = tindices[i];
if (uniqueverts.count(tri) == 0)
uniqueverts[tri] = vert_count++;
face.b = uniqueverts[tri];
tri.vert = vindices[i+1];
if (!nindices.empty())
tri.norm = nindices[i+1];
if (!tindices.empty())
tri.norm = tindices[i+1];
if (uniqueverts.count(tri) == 0)
uniqueverts[tri] = vert_count++;
face.c = uniqueverts[tri];
mFaces.push_back(face);
}
}
}
inf.close();
mPositions.resize(vert_count);
if (norms.size() > 0)
mNormals.resize(vert_count);
if (texcoords.size() > 0)
mTexCoords.resize(vert_count);
std::map<FaceVert, int, vert_less>::iterator iter;
for (iter = uniqueverts.begin(); iter != uniqueverts.end(); ++iter)
{
mPositions[iter->second] = verts[iter->first.vert];
if ( norms.size() > 0 )
{
mNormals[iter->second] = norms[iter->first.norm];
}
if ( texcoords.size() > 0)
{
mTexCoords[iter->second] = texcoords[iter->first.coord];
}
}
}
int ObjLoader::getIndexCount()
{
return (int)mFaces.size() * 3;
}
int ObjLoader::getVertCount()
{
return (int)mPositions.size();
}
const uint32_t* ObjLoader::getFaces()
{
return (const uint32_t*)&mFaces[0];
}
const float* ObjLoader::getPositions()
{
return (const float*)&mPositions[0];
}
const float* ObjLoader::getNormals()
{
return (const float*)&mNormals[0];
}
uint32_t ObjLoader::getTexCoordLayers()
{
return mTexCoordLayers;
}
const float* ObjLoader::getTexCoords(int multiTexCoordLayer)
{
assert(multiTexCoordLayer < mTexCoordLayers);
return (const float*)&mTexCoords[0];
}
}

View File

@@ -1,44 +0,0 @@
#pragma once
#include <vector>
#include <filesystem>
#include <hart_graphics.hpp>
namespace inferno::scene {
struct Face
{
int a;
int b;
int c;
};
class ObjLoader
{
public:
ObjLoader();
~ObjLoader();
void load(std::filesystem::path file);
int getIndexCount();
int getVertCount();
const uint32_t* getFaces();
const float* getPositions();
const float* getNormals();
uint32_t getTexCoordLayers();
const float* getTexCoords(int multiTexCoordLayer);
private:
std::vector<Face> mFaces;
std::vector<glm::vec3> mPositions;
std::vector<glm::vec3> mNormals;
// obj's only have 1 layer ever
std::vector<glm::vec2> mTexCoords;
uint32_t mTexCoordLayers;
};
}

Submodule src/thirdparty/assimp deleted from 762ad8e9b7