5#include "assimp/Importer.hpp"
6#include "assimp/postprocess.h"
7#include "assimp/scene.h"
10#define STB_IMAGE_IMPLEMENTATION
13#include "tinyobj/tiny_obj_loader.h"
15#include <glm/gtc/matrix_transform.hpp>
21#include <unordered_map>
26static std::string directory;
27static std::vector<std::string> textures_loaded;
28static std::unordered_map<std::string, node> models_loaded;
29static std::unordered_map<std::string, node *> models_loaded_path;
30static std::unordered_map<std::string, Mesh> meshes_loaded;
41static std::string loadMaterialTexture(aiMaterial *
mat, aiTextureType type,
const std::string &typeName) {
42 std::vector<std::string> textures;
44 if (
mat->GetTextureCount(type) > 1) {
45 printf(
"there were multiple textures but only single was processed\n");
49 for (
unsigned int i = 0; i <
mat->GetTextureCount(type); i++) {
51 mat->GetTexture(type, i, &str);
53 std::string relPath(str.C_Str());
57 pos = relPath.find(
"\\");
58 while (pos != std::string::npos) {
59 relPath.replace(pos, 1,
"/");
60 pos = relPath.find(
"\\");
64 textures.push_back(directory +
"/" + relPath);
67 if (!textures.empty())
74 std::vector<Vertex> vertices;
75 std::vector<unsigned int> indices;
76 std::vector<std::string> textures;
79 for (
unsigned int i = 0; i < mesh->mNumVertices; i++) {
83 vector.
x = mesh->mVertices[i].x;
84 vector.y = mesh->mVertices[i].y;
85 vector.z = mesh->mVertices[i].z;
88 if (mesh->HasNormals()) {
89 vector.
x = mesh->mNormals[i].x;
90 vector.y = mesh->mNormals[i].y;
91 vector.z = mesh->mNormals[i].z;
95 if (mesh->mTextureCoords[0])
100 vec.
x = mesh->mTextureCoords[0][i].x;
101 vec.y = mesh->mTextureCoords[0][i].y;
104 vector.
x = mesh->mTangents[i].x;
105 vector.y = mesh->mTangents[i].y;
106 vector.z = mesh->mTangents[i].z;
107 vertex.tangent = vector;
109 vector.x = mesh->mBitangents[i].x;
110 vector.y = mesh->mBitangents[i].y;
111 vector.z = mesh->mBitangents[i].z;
112 vertex.bitangent = vector;
116 vertices.push_back(vertex);
120 for (
unsigned int i = 0; i < mesh->mNumFaces; i++) {
121 aiFace face = mesh->mFaces[i];
123 for (
unsigned int j = 0; j < face.mNumIndices; j++)
124 indices.push_back(face.mIndices[j]);
127 aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
130 std::string ambientMaps = loadMaterialTexture(material, aiTextureType_AMBIENT,
"texture_ambient");
131 textures.push_back(ambientMaps);
133 std::string diffuseMaps = loadMaterialTexture(material, aiTextureType_DIFFUSE,
"texture_diffuse");
134 textures.push_back(diffuseMaps);
136 std::string specularMaps = loadMaterialTexture(material, aiTextureType_SPECULAR,
"texture_specular");
137 textures.push_back(specularMaps);
139 std::string normalMaps = loadMaterialTexture(material, aiTextureType_HEIGHT,
"texture_normal");
140 textures.push_back(normalMaps);
142 std::string name(mesh->mName.C_Str());
144 while (meshes_loaded.find(name) != meshes_loaded.end()) {
147 meshes_loaded[name] =
Mesh(vertices, indices, name, textures);
148 Mesh &m = meshes_loaded[name];
150 aiColor4D diffuse, specular;
152 m.
material.
diffuseColor = AI_SUCCESS != aiGetMaterialColor(material, AI_MATKEY_COLOR_DIFFUSE, &diffuse) ?
vec3(1, 0, 0) :
vec3(diffuse.r, diffuse.g, diffuse.b);
153 m.
material.
specularColor = AI_SUCCESS != aiGetMaterialColor(material, AI_MATKEY_COLOR_SPECULAR, &specular) ?
vec3(1, 1, 1) :
vec3(specular.r, specular.g, specular.b);
154 m.
material.
shininess = AI_SUCCESS != aiGetMaterialFloat(material, AI_MATKEY_SHININESS, &shininess) ? 512 : shininess;
160static void processNode(aiNode *
node,
const aiScene *scene, std::vector<
drawable<Vertex> *> &meshes,
int num) {
165 for (
unsigned int i = 0; i <
node->mNumMeshes; i++) {
168 aiMesh *mesh = scene->mMeshes[
node->mMeshes[i]];
169 auto me = processMesh(mesh, scene);
170 meshes.push_back(me);
174 for (
unsigned int i = 0; i <
node->mNumChildren; i++) {
175 processNode(
node->mChildren[i], scene, meshes, ++num);
180node *loadModel(std::string
const &path,
const std::string &name,
bool flipUV =
false) {
182 if (models_loaded_path.find(path) != models_loaded_path.end()) {
183 if (models_loaded_path[path] == &models_loaded[name]) {
184 std::cout <<
"already loaded same module with same name and path os returning refrence to previous obj\n";
187 auto previous_node = *models_loaded_path[path];
189 for (
auto &m : previous_node.meshes) {
194 auto name = m->name +
"_copy";
195 while (meshes_loaded.find(name) != meshes_loaded.end())
198 temp_mesh.
name = name;
199 meshes_loaded[temp_mesh.
name] = std::move(temp_mesh);
200 temp.
meshes.push_back(&meshes_loaded[name]);
202 models_loaded[name] = std::move(temp);
203 return &models_loaded[name];
206 if (models_loaded.find(name) != models_loaded.end()) {
207 return &models_loaded[name];
210 Assimp::Importer importer;
211 auto flags = aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace;
213 flags |= aiProcess_FlipUVs;
215 const aiScene *scene = importer.ReadFile(path, flags);
217 if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
219 std::cout <<
"ERROR::ASSIMP:: " << importer.GetErrorString() << std::endl;
224 directory = path.substr(0, path.find_last_of(
'/'));
230 processNode(scene->mRootNode, scene, temp.
meshes, 0);
232 models_loaded[name] = std::move(temp);
233 models_loaded_path[path] = &models_loaded[name];
234 return &models_loaded[name];
243 if (models_loaded_path.find(path) != models_loaded_path.end()) {
244 if (models_loaded_path[path] == &models_loaded[name]) {
245 std::cout <<
"already loaded same model with same name and path so returning refrence to previous model\n";
248 auto previous_node = *models_loaded_path[path];
250 for (
auto &m : previous_node.meshes) {
255 auto name = m->name +
"_copy";
256 while (meshes_loaded.find(name) != meshes_loaded.end())
259 temp_mesh.
name = name;
260 meshes_loaded[temp_mesh.
name] = std::move(temp_mesh);
261 temp.
meshes.push_back(&meshes_loaded[name]);
264 models_loaded[name] = std::move(temp);
265 return &models_loaded[name];
268 if (models_loaded.find(name) != models_loaded.end()) {
269 return &models_loaded[name];
273 directory = path.substr(0, path.find_last_of(
'/'));
276 tinyobj::ObjReaderConfig reader_config;
277 reader_config.mtl_search_path = directory;
278 reader_config.triangulate =
true;
281 tinyobj::ObjReader reader;
283 if (!reader.ParseFromFile(path, reader_config)) {
284 if (!reader.Error().empty()) {
285 std::cerr <<
"TinyObjReader: " << reader.Error();
290 if (!reader.Warning().empty()) {
291 std::cout <<
"[WARNING]: TinyObjReader: " << reader.Warning();
294 if (!reader.Error().empty()) {
295 std::cout <<
"[Error]: TinyObjReader: " << reader.Error();
298 const tinyobj::attrib_t &attrib = reader.GetAttrib();
299 auto &shapes = reader.GetShapes();
300 auto &materials = reader.GetMaterials();
302 std::unordered_map<int, std::string> material_to_mesh_map;
305 for (
size_t s = 0; s < shapes.size(); s++) {
307 auto name = shapes[s].name;
311 size_t index_offset = 0;
312 uint32_t current_index = 0;
315 for (
size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
318 int current_material_id = shapes[s].mesh.material_ids[f];
319 if ((current_material_id < 0) || (current_material_id >=
static_cast<int>(materials.size()))) {
321 current_material_id = materials.size() - 1;
327 if (name == std::string(
"CubeMaterial.005")) {
331 meshes_loaded[name] = std::move(*m1);
332 temp.
meshes.push_back(&meshes_loaded[name]);
336 if (material_to_mesh_map.find(current_material_id) == material_to_mesh_map.end()) {
339 name = shapes[s].name;
341 m1 = &meshes_loaded[material_to_mesh_map[current_material_id]];
343 name = shapes[s].name;
351 unsigned char *m_LocalBuffer;
352 stbi_set_flip_vertically_on_load(1);
353 if (!materials[current_material_id].diffuse_texname.empty()) {
355 if (!m_LocalBuffer) {
356 std::cout <<
"texture file unable to load" << directory + materials[current_material_id].diffuse_texname << std::endl;
361 stbi_image_free(m_LocalBuffer);
364 if (!materials[current_material_id].specular_texname.empty()) {
366 if (!m_LocalBuffer) {
367 std::cout <<
"texture file unable to load" << directory + materials[current_material_id].specular_texname << std::endl;
372 stbi_image_free(m_LocalBuffer);
375 m1->
material.
diffuseColor =
color(materials[current_material_id].diffuse[0] * 255, materials[current_material_id].diffuse[1] * 255, materials[current_material_id].diffuse[2] * 255);
376 m1->
material.
specularColor =
color(materials[current_material_id].specular[0] * 255, materials[current_material_id].specular[1] * 255, materials[current_material_id].specular[2] * 255);
381 size_t fv = size_t(shapes[s].mesh.num_face_vertices[f]);
385 for (
size_t v = 0; v < fv; v++) {
386 tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
388 vertex.
position =
vec3(attrib.vertices[3 *
size_t(idx.vertex_index) + 0], attrib.vertices[3 *
size_t(idx.vertex_index) + 1], attrib.vertices[3 *
size_t(idx.vertex_index) + 2]);
391 if (idx.normal_index >= 0) {
392 vertex.
normal =
vec3(attrib.normals[3 *
size_t(idx.normal_index) + 0], attrib.normals[3 *
size_t(idx.normal_index) + 1], attrib.normals[3 *
size_t(idx.normal_index) + 2]);
396 if (idx.texcoord_index >= 0) {
397 vertex.
texCoord =
vec2(attrib.texcoords[2 *
size_t(idx.texcoord_index) + 0], attrib.texcoords[2 *
size_t(idx.texcoord_index) + 1]);
400 m1->
m_indices.push_back(current_index++);
412 if ((current_material_id < 0) || (current_material_id >=
static_cast<int>(materials.size()))) {
414 current_material_id = materials.size() - 1;
416 if ((current_material_id >= 0)) {
417 name += materials[current_material_id].name;
420 while (meshes_loaded.find(name) != meshes_loaded.end()) {
425 meshes_loaded[name] = std::move(*m1);
426 temp.
meshes.push_back(&meshes_loaded[name]);
430 models_loaded[name] = std::move(temp);
431 models_loaded_path[path] = &models_loaded[name];
432 return &models_loaded[name];
A general matrix class for any size of matrix.
all functions related to model loading and managing
node * loadModel_obj(std::string const &path, const std::string &name, bool flipUV=false)
loads model with given path and register it with given name.
class that holds color with 8 bits per channel with 4 channels rgba.
this class represents all drawable entities that has a material and vertices
std::vector< uint32_t > m_indices
std::vector< T > m_vertices
anything that can be transformed( has modelmatrix )
std::vector< drawable< Vertex > * > meshes