292 lines
6.5 KiB
C++
292 lines
6.5 KiB
C++
|
|
#include <GL/glew.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/scene.h>
|
|
#include <assimp/postprocess.h>
|
|
#include <assimp/material.h>
|
|
#include <glm/matrix.hpp>
|
|
|
|
#include <unordered_map>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include "mesh.hpp"
|
|
#include "arrays.hpp"
|
|
#include "texture.hpp"
|
|
#include "../../util/streams.hpp"
|
|
|
|
using namespace Sim::Graphics;
|
|
|
|
struct ProcState
|
|
{
|
|
unsigned int offset = 0;
|
|
|
|
std::string base;
|
|
std::vector<Light> lights;
|
|
std::vector<Arrays::Vertex> vertices;
|
|
std::vector<unsigned int> indices;
|
|
std::unordered_map<const aiTexture*, unsigned int> handles;
|
|
std::unordered_map<std::string, glm::mat4> mat_nodes;
|
|
};
|
|
|
|
static unsigned int proc_texture(const ProcState& state, aiMaterial* mat, const aiScene* scene, aiTextureType type, int index)
|
|
{
|
|
aiString str;
|
|
mat->GetTexture(type, index, &str);
|
|
|
|
if(str.C_Str()[0] == '\0')
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const aiTexture* tex = scene->GetEmbeddedTexture(str.C_Str());
|
|
|
|
if(tex != nullptr)
|
|
{
|
|
unsigned int handle = state.handles.find(tex)->second;
|
|
std::cout << "Using preloaded texture: " << tex->mFilename.C_Str() << "\n";
|
|
return handle;
|
|
}
|
|
|
|
std::string filename(str.C_Str());
|
|
std::replace(filename.begin(), filename.end(), '\\', '/');
|
|
|
|
return Texture::load(state.base + "/" + filename);
|
|
}
|
|
|
|
static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiScene* scene)
|
|
{
|
|
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
|
|
aiString name;
|
|
|
|
material->Get(AI_MATKEY_NAME, name);
|
|
|
|
std::cout << "Material " << name.C_Str() << " has " << material->mNumProperties << " properties\n";
|
|
|
|
for(int i = 0; i < material->mNumProperties; i++)
|
|
{
|
|
aiMaterialProperty* prop = material->mProperties[i];
|
|
|
|
std::cout << " " << prop->mKey.C_Str() << ": type=" << prop->mType << " index=" << prop->mIndex << " length=" << prop->mDataLength;
|
|
|
|
if(prop->mType == 1)
|
|
{
|
|
float* v = (float*)prop->mData;
|
|
|
|
std::cout << " value=";
|
|
|
|
switch(prop->mDataLength)
|
|
{
|
|
case 4:
|
|
std::cout << v[0];
|
|
break;
|
|
case 8:
|
|
std::cout << "{" << v[0] << ", " << v[1] << "}";
|
|
break;
|
|
case 12:
|
|
std::cout << "{" << v[0] << ", " << v[1] << ", " << v[2] << "}";
|
|
break;
|
|
case 16:
|
|
std::cout << "{" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << "}";
|
|
break;
|
|
default:
|
|
std::cout << "unknown";
|
|
}
|
|
}
|
|
|
|
std::cout << "\n";
|
|
}
|
|
|
|
glm::vec3 matv(0);
|
|
aiColor4D ai_cb;
|
|
aiColor4D ai_em;
|
|
|
|
material->Get(AI_MATKEY_ROUGHNESS_FACTOR, matv[0]);
|
|
material->Get(AI_MATKEY_METALLIC_FACTOR, matv[1]);
|
|
material->Get(AI_MATKEY_EMISSIVE_INTENSITY, matv[2]);
|
|
material->Get(AI_MATKEY_COLOR_EMISSIVE, ai_em);
|
|
material->Get(AI_MATKEY_BASE_COLOR, ai_cb);
|
|
|
|
glm::vec4 cb = {ai_cb[0], ai_cb[1], ai_cb[2], ai_cb[3]};
|
|
glm::vec4 em = {ai_em[0], ai_em[1], ai_em[2], ai_em[3]};
|
|
|
|
if(em.x > 0 || em.y > 0 || em.z > 0)
|
|
{
|
|
cb = em;
|
|
}
|
|
|
|
std::cout << "Material: " << matv << "\n";
|
|
|
|
unsigned int handle = proc_texture(state, material, scene, aiTextureType_BASE_COLOR, 0);
|
|
unsigned int offset = state.offset;
|
|
glm::mat3 mat3(mat);
|
|
|
|
if(!handle)
|
|
{
|
|
handle = proc_texture(state, material, scene, aiTextureType_DIFFUSE, 0);
|
|
}
|
|
|
|
if(!handle)
|
|
{
|
|
handle = Texture::handle_white;
|
|
}
|
|
|
|
for(unsigned int i = 0; i < mesh->mNumVertices; i++)
|
|
{
|
|
Arrays::Vertex vertex;
|
|
|
|
auto [x, y, z] = mesh->mVertices[i];
|
|
vertex.pos = glm::vec4(x, y, z, 1) * mat;
|
|
vertex.material = matv;
|
|
vertex.texid = handle;
|
|
vertex.colour = cb;
|
|
|
|
if(mesh->HasNormals())
|
|
{
|
|
auto [x, y, z] = mesh->mNormals[i];
|
|
vertex.normal = glm::vec3(x, y, z) * mat3;
|
|
}
|
|
|
|
/*if(mesh->HasTangentsAndBitangents())
|
|
{
|
|
auto [x1, y1, z1] = mesh->mTangents[i];
|
|
auto [x2, y2, z2] = mesh->mBitangents[i];
|
|
vertex.tangent = {x1, y1, z1};
|
|
vertex.bitangent = {x2, y2, z2};
|
|
}*/
|
|
|
|
if(mesh->mTextureCoords[0])
|
|
{
|
|
auto [x, y, z] = mesh->mTextureCoords[0][i];
|
|
vertex.texpos = {x, y};
|
|
}
|
|
|
|
state.vertices.push_back(vertex);
|
|
}
|
|
|
|
for(unsigned int i = 0; i < mesh->mNumFaces; i++)
|
|
{
|
|
aiFace face = mesh->mFaces[i];
|
|
|
|
for(unsigned int j = 0; j < face.mNumIndices; j++)
|
|
{
|
|
state.indices.push_back(face.mIndices[j] + offset);
|
|
}
|
|
}
|
|
|
|
state.offset += mesh->mNumVertices;
|
|
}
|
|
|
|
glm::mat4 get_mat(aiMatrix4x4 m)
|
|
{
|
|
return {
|
|
m.a1, m.a2, m.a3, m.a4,
|
|
m.b1, m.b2, m.b3, m.b4,
|
|
m.c1, m.c2, m.c3, m.c4,
|
|
m.d1, m.d2, m.d3, m.d4
|
|
};
|
|
}
|
|
|
|
static void proc_node(ProcState& state, glm::mat4 mat, aiNode* node, const aiScene* scene)
|
|
{
|
|
mat = get_mat(node->mTransformation) * mat;
|
|
std::string name(node->mName.C_Str());
|
|
state.mat_nodes[name] = mat;
|
|
|
|
for(size_t i = 0; i < node->mNumMeshes; i++)
|
|
{
|
|
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
|
proc_mesh(state, mat, mesh, scene);
|
|
}
|
|
|
|
for(size_t i = 0; i < node->mNumChildren; i++)
|
|
{
|
|
proc_node(state, mat, node->mChildren[i], scene);
|
|
}
|
|
}
|
|
|
|
static unsigned int proc_embedded_texture(aiTexture* tex)
|
|
{
|
|
std::cout << "Loading embedded data: " << tex->mFilename.C_Str() << "\n";
|
|
|
|
if(tex->mHeight == 0)
|
|
{
|
|
return Texture::load_mem((unsigned char*)tex->pcData, tex->mWidth);
|
|
}
|
|
|
|
// swizzle each pixel to get RGBA
|
|
for(int i = 0; i < tex->mWidth * tex->mHeight; i++)
|
|
{
|
|
aiTexel t = tex->pcData[i];
|
|
tex->pcData[i] = {t.r, t.g, t.b, t.a};
|
|
}
|
|
|
|
return Texture::load_mem((unsigned char*)tex->pcData, tex->mWidth, tex->mHeight, 4);
|
|
}
|
|
|
|
glm::mat4 get_transforms(aiNode* node)
|
|
{
|
|
glm::mat4 mat(1);
|
|
|
|
while(node->mParent != nullptr)
|
|
{
|
|
mat *= get_mat(node->mTransformation);
|
|
node = node->mParent;
|
|
}
|
|
|
|
return mat;
|
|
}
|
|
|
|
void Mesh::load_model(std::string path)
|
|
{
|
|
load_model(".", path);
|
|
}
|
|
|
|
void Mesh::load_model(std::string base, std::string filename)
|
|
{
|
|
ProcState state {.base = base};
|
|
std::string path = base + "/" + filename;
|
|
Assimp::Importer importer;
|
|
|
|
const aiScene *scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs);
|
|
|
|
if(scene == nullptr)
|
|
{
|
|
std::cerr << "AssImp: Error loading model\n";
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < scene->mNumTextures; i++)
|
|
{
|
|
aiTexture* tex = scene->mTextures[i];
|
|
unsigned int handle = proc_embedded_texture(tex);
|
|
state.handles[tex] = handle;
|
|
}
|
|
|
|
for(int i = 0; i < scene->mNumLights; i++)
|
|
{
|
|
aiLight* light = scene->mLights[i];
|
|
glm::mat4 mat = get_transforms(scene->mRootNode->FindNode(light->mName));
|
|
|
|
auto [x, y, z] = light->mPosition;
|
|
auto [r, g, b] = light->mColorDiffuse;
|
|
|
|
glm::vec4 pos = glm::vec4(x, y, z, 1) * mat;
|
|
|
|
state.lights.push_back({
|
|
glm::vec3(pos),
|
|
{r, g, b},
|
|
});
|
|
}
|
|
|
|
proc_node(state, glm::mat4(1), scene->mRootNode, scene);
|
|
|
|
mat_nodes = std::move(state.mat_nodes);
|
|
vertices = std::move(state.vertices);
|
|
indices = std::move(state.indices);
|
|
lights = std::move(state.lights);
|
|
}
|
|
|