ModelLoader.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #include <assimp\Importer.hpp>
  2. #include <assimp\postprocess.h>
  3. #include <assimp\ProgressHandler.hpp>
  4. #include <functional>
  5. #include <iostream>
  6. #include "Config.h"
  7. #include "ErrorHandlerLocator.h"
  8. #include "ModelLoader.h"
  9. #include "TaskManagerLocator.h"
  10. #include "Loaders.h"
  11. // This initialization depends on the order of BufferType enum entries
  12. const int Model::m_numElements[ModelBuffer_NumAllTypes] = { 3, 3, 2, 3, 3, 0 };
  13. ErrorCode Model::loadToMemory()
  14. {
  15. // If the model is not currently already being loaded in another thread
  16. if(!m_isBeingLoaded)
  17. {
  18. // Make sure another thread doesn't start another instance of loading
  19. m_isBeingLoaded = true;
  20. // Lock calls from other treads
  21. SpinWait::Lock lock(m_mutex);
  22. // To not cause crashes from outside code, since meshes will be modified when loading
  23. //m_currentNumMeshes = 0;
  24. // Assign flags for assimp loader
  25. unsigned int assimpFlags = 0;
  26. if(Config::modelVar().joinIdenticalVertices)
  27. assimpFlags |= aiProcess_JoinIdenticalVertices;
  28. if(Config::modelVar().makeLeftHanded)
  29. assimpFlags |= aiProcess_MakeLeftHanded;
  30. if(Config::modelVar().triangulate)
  31. assimpFlags |= aiProcess_Triangulate;
  32. if(Config::modelVar().removeComponent)
  33. assimpFlags |= aiProcess_RemoveComponent;
  34. if(Config::modelVar().genNormals)
  35. assimpFlags |= aiProcess_GenNormals;
  36. if(Config::modelVar().genSmoothNormals)
  37. assimpFlags |= aiProcess_GenSmoothNormals;
  38. if(Config::modelVar().genUVCoords)
  39. assimpFlags |= aiProcess_GenUVCoords;
  40. if(Config::modelVar().optimizeMeshes)
  41. assimpFlags |= aiProcess_OptimizeMeshes;
  42. if(Config::modelVar().optimizeGraph)
  43. assimpFlags |= aiProcess_OptimizeGraph;
  44. Assimp::Importer assimpImporter;
  45. // Load data from file to Assimp scene structure
  46. const aiScene* assimpScene = assimpImporter.ReadFile(Config::filepathVar().model_path + m_filename, assimpFlags);
  47. // If loading wasn't successful, log an error
  48. if(!assimpScene)
  49. {
  50. ErrHandlerLoc::get().log(ErrorCode::AssimpScene_failed, ErrorSource::Source_ModelLoader, m_filename);
  51. m_loadingToMemoryError = ErrorCode::AssimpScene_failed;
  52. }
  53. // If loading was successful, start restructuring the data to be loaded to video memory later
  54. else
  55. {
  56. m_loadingToMemoryError = loadFromScene(*assimpScene);
  57. // If data restructuring failed, log an error
  58. if(m_loadingToMemoryError != ErrorCode::Success)
  59. {
  60. ErrHandlerLoc::get().log(m_loadingToMemoryError, ErrorSource::Source_ModelLoader, m_filename);
  61. }
  62. }
  63. m_isBeingLoaded = false;
  64. }
  65. else
  66. {
  67. // Wait for loading in another thread to finish before continuing
  68. SpinWait::Lock lock(m_mutex);
  69. }
  70. return m_loadingToMemoryError;
  71. }
  72. ErrorCode Model::unloadMemory()
  73. {
  74. ErrorCode returnError = ErrorCode::Success;
  75. m_indices.clear();
  76. m_positions.clear();
  77. m_normals.clear();
  78. m_texCoords.clear();
  79. m_tangents.clear();
  80. m_bitangents.clear();
  81. m_meshPool.clear();
  82. for(int matType = 0; matType < MaterialType_NumOfTypes; matType++)
  83. m_materials.m_materials[matType].clear();
  84. return returnError;
  85. }
  86. /*ErrorCode Model::unloadVideoMemory()
  87. {
  88. ErrorCode returnError = ErrorCode::Success;
  89. glDeleteBuffers(NumBufferTypes, m_buffers);
  90. return returnError;
  91. }*/
  92. void Model::loadFromFile()
  93. {
  94. ErrorCode error = loadToMemory();
  95. // If data restructuring was successful, set loaded to memory flag
  96. if(error == ErrorCode::Success)
  97. setLoadedToMemory(true);
  98. else // If data restructuring failed, log an error
  99. ErrHandlerLoc::get().log(error, ErrorSource::Source_ModelLoader);
  100. }
  101. ErrorCode Model::loadFromScene(const aiScene &p_assimpScene)
  102. {
  103. ErrorCode returnError = ErrorCode::Success;
  104. // Reserve space in the vectors for every mesh
  105. m_meshPool.resize(p_assimpScene.mNumMeshes);
  106. m_numMeshes = p_assimpScene.mNumMeshes;
  107. unsigned int numIndicesTotal = 0;
  108. // Count the number of vertices and m_indices
  109. for(unsigned int i = 0; i < p_assimpScene.mNumMeshes; i++)
  110. {
  111. m_meshPool[i].m_materialIndex = p_assimpScene.mMeshes[i]->mMaterialIndex;
  112. m_meshPool[i].m_numIndices = p_assimpScene.mMeshes[i]->mNumFaces * 3;
  113. m_meshPool[i].m_baseVertex = (unsigned int)m_numVertices;
  114. m_meshPool[i].m_baseIndex = numIndicesTotal;
  115. m_numVertices += p_assimpScene.mMeshes[i]->mNumVertices;
  116. numIndicesTotal += m_meshPool[i].m_numIndices;
  117. }
  118. // Reserve space in the vectors for the vertex attributes and m_indices
  119. m_positions.resize(m_numVertices);
  120. m_normals.resize(m_numVertices);
  121. m_texCoords.resize(m_numVertices);
  122. m_tangents.resize(m_numVertices);
  123. m_bitangents.resize(m_numVertices);
  124. m_indices.resize(numIndicesTotal);
  125. // Set buffer sizes
  126. m_bufferSize[ModelBuffer_Position] = sizeof(m_positions[0]) * m_numVertices;
  127. m_bufferSize[ModelBuffer_Normal] = sizeof(m_normals[0]) * m_numVertices;
  128. m_bufferSize[ModelBuffer_TexCoord] = sizeof(m_texCoords[0]) * m_numVertices;
  129. m_bufferSize[ModelBuffer_Tangents] = sizeof(m_tangents[0]) * m_numVertices;
  130. m_bufferSize[ModelBuffer_Bitangents] = sizeof(m_bitangents[0]) * m_numVertices;
  131. m_bufferSize[ModelBuffer_Index] = sizeof(m_indices[0]) * m_numVertices;
  132. // Deal with each mesh
  133. returnError = loadMeshes(p_assimpScene);
  134. // Load material file names
  135. if(returnError == ErrorCode::Success)
  136. returnError = loadMaterials(p_assimpScene);
  137. return returnError;
  138. }
  139. ErrorCode Model::loadMeshes(const aiScene &p_assimpScene)
  140. {
  141. ErrorCode returnError = ErrorCode::Success;
  142. for(size_t meshIndex = 0, verticeIndex = 0, indicesIndex = 0; meshIndex < p_assimpScene.mNumMeshes; meshIndex++)
  143. {
  144. // Make sure that the texture coordinates array exist (by checking if the first member of the array does)
  145. bool textureCoordsExist = p_assimpScene.mMeshes[meshIndex]->mTextureCoords[0] ? true : false;
  146. // Check if arrays exist (to not cause an error if they are absent)
  147. //bool normalsExist = p_assimpMeshes[meshIndex]->mNormals != nullptr;
  148. const bool tangentsExist = p_assimpScene.mMeshes[meshIndex]->mTangents != nullptr;
  149. const bool bitangentsExist = p_assimpScene.mMeshes[meshIndex]->mBitangents != nullptr;
  150. for(decltype(m_positions.size()) i = 0, size = m_positions.size(); i < size; i++)
  151. {
  152. }
  153. // Put the mesh data from assimp to memory
  154. for(decltype(p_assimpScene.mMeshes[meshIndex]->mNumVertices) i = 0, tangentIndex = 2, size = p_assimpScene.mMeshes[meshIndex]->mNumVertices; i < size; i++, verticeIndex++)
  155. {
  156. m_positions[verticeIndex].x = p_assimpScene.mMeshes[meshIndex]->mVertices[i].x;
  157. m_positions[verticeIndex].y = p_assimpScene.mMeshes[meshIndex]->mVertices[i].y;
  158. m_positions[verticeIndex].z = p_assimpScene.mMeshes[meshIndex]->mVertices[i].z;
  159. m_normals[verticeIndex].x = p_assimpScene.mMeshes[meshIndex]->mNormals[i].x;
  160. m_normals[verticeIndex].y = p_assimpScene.mMeshes[meshIndex]->mNormals[i].y;
  161. m_normals[verticeIndex].z = p_assimpScene.mMeshes[meshIndex]->mNormals[i].z;
  162. if(textureCoordsExist)
  163. {
  164. m_texCoords[verticeIndex].x = p_assimpScene.mMeshes[meshIndex]->mTextureCoords[0][i].x;
  165. m_texCoords[verticeIndex].y = p_assimpScene.mMeshes[meshIndex]->mTextureCoords[0][i].y;
  166. }
  167. if(!tangentsExist || !bitangentsExist)
  168. {
  169. if(verticeIndex == tangentIndex)
  170. {
  171. // Get vertex positions of the polygon
  172. const glm::vec3 &v0 = m_positions[verticeIndex - 2];
  173. const glm::vec3 &v1 = m_positions[verticeIndex - 1];
  174. const glm::vec3 &v2 = m_positions[verticeIndex - 0];
  175. // Get texture coordinates of the polygon
  176. const glm::vec2 &uv0 = m_texCoords[verticeIndex - 2];
  177. const glm::vec2 &uv1 = m_texCoords[verticeIndex - 1];
  178. const glm::vec2 &uv2 = m_texCoords[verticeIndex - 0];
  179. // Get normals of the polygon
  180. const glm::vec3 &n0 = m_normals[verticeIndex - 2];
  181. const glm::vec3 &n1 = m_normals[verticeIndex - 1];
  182. const glm::vec3 &n2 = m_normals[verticeIndex - 0];
  183. // Calculate position difference
  184. glm::vec3 deltaPos1 = v1 - v0;
  185. glm::vec3 deltaPos2 = v2 - v0;
  186. // Calculate texture coordinate difference
  187. glm::vec2 deltaUV1 = uv1 - uv0;
  188. glm::vec2 deltaUV2 = uv2 - uv0;
  189. // Calculate tangent and bitangent
  190. float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
  191. glm::vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
  192. glm::vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
  193. // Orthogonalize using Gram–Schmidt process, to make tangents and bitangents smooth based on normal
  194. m_tangents[verticeIndex - 2] = glm::normalize(tangent - n0 * glm::dot(n0, tangent));
  195. m_tangents[verticeIndex - 1] = glm::normalize(tangent - n1 * glm::dot(n1, tangent));
  196. m_tangents[verticeIndex - 0] = glm::normalize(tangent - n2 * glm::dot(n2, tangent));
  197. m_bitangents[verticeIndex - 2] = glm::normalize(bitangent - n0 * glm::dot(n0, bitangent));
  198. m_bitangents[verticeIndex - 1] = glm::normalize(bitangent - n1 * glm::dot(n1, bitangent));
  199. m_bitangents[verticeIndex - 0] = glm::normalize(bitangent - n2 * glm::dot(n2, bitangent));
  200. tangentIndex += 3;
  201. }
  202. }
  203. else
  204. {
  205. m_tangents[verticeIndex].x = p_assimpScene.mMeshes[meshIndex]->mTangents[i].x;
  206. m_tangents[verticeIndex].y = p_assimpScene.mMeshes[meshIndex]->mTangents[i].y;
  207. m_tangents[verticeIndex].z = p_assimpScene.mMeshes[meshIndex]->mTangents[i].z;
  208. m_bitangents[verticeIndex].x = p_assimpScene.mMeshes[meshIndex]->mBitangents[i].x;
  209. m_bitangents[verticeIndex].y = p_assimpScene.mMeshes[meshIndex]->mBitangents[i].y;
  210. m_bitangents[verticeIndex].z = p_assimpScene.mMeshes[meshIndex]->mBitangents[i].z;
  211. }
  212. }
  213. // Put the m_indices data from assimp to memory
  214. for(unsigned int i = 0, size = p_assimpScene.mMeshes[meshIndex]->mNumFaces; i < size; i++)
  215. {
  216. if(p_assimpScene.mMeshes[meshIndex]->mFaces[i].mNumIndices == 3)
  217. {
  218. m_indices[indicesIndex] = p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[0];
  219. m_indices[indicesIndex + 1] = p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[1];
  220. m_indices[indicesIndex + 2] =
  221. p_assimpScene.mMeshes[meshIndex]->mFaces[i].mIndices[2];
  222. indicesIndex += 3;
  223. }
  224. }
  225. }
  226. return returnError;
  227. }
  228. ErrorCode Model::loadMaterials(const aiScene &p_assimpScene)
  229. {
  230. ErrorCode returnError = ErrorCode::Success;
  231. aiString materialPath;
  232. // Assign number of materials. If there are more meshes than the materials,
  233. // set the number of materials the same as the number of meshes, to avoid
  234. // going out of bounds of materials vector, when rendering (as each mesh must have a texture)
  235. size_t numMaterials = p_assimpScene.mNumMaterials;
  236. if(p_assimpScene.mNumMeshes > numMaterials)
  237. numMaterials = p_assimpScene.mNumMeshes;
  238. // Make space in materials arrays
  239. m_materials.resize(numMaterials);
  240. // Iterate over all Assimp textures; the m_materials vector might be larger than the Assimp mMaterials array, but never smaller
  241. for(decltype(p_assimpScene.mNumMaterials) size = p_assimpScene.mNumMaterials, index = 0, i = 0; i < size; i++)
  242. {
  243. if(p_assimpScene.mMaterials[i]->GetTexture(aiTextureType_DIFFUSE, index, &materialPath) == aiReturn_SUCCESS)
  244. m_materials.m_materials[MaterialType_Diffuse][i].m_filename = materialPath.data;
  245. if(p_assimpScene.mMaterials[i]->GetTexture(aiTextureType_NORMALS, index, &materialPath) == aiReturn_SUCCESS)
  246. m_materials.m_materials[MaterialType_Normal][i].m_filename = materialPath.data;
  247. if(p_assimpScene.mMaterials[i]->GetTexture(aiTextureType_EMISSIVE, index, &materialPath) == aiReturn_SUCCESS)
  248. m_materials.m_materials[MaterialType_Emissive][i].m_filename = materialPath.data;
  249. // Unused with the new shading model (PBS). Might be used in the future to combine textures into one (RMHAO)
  250. /*
  251. if(p_assimpMaterials[i]->GetTexture(aiTextureType_SPECULAR, index, &materialPath) == aiReturn_SUCCESS)
  252. m_materials.m_materials[ModelMat_specular][i].m_filename = materialPath.data;
  253. if(p_assimpMaterials[i]->GetTexture(aiTextureType_SHININESS, index, &materialPath) == aiReturn_SUCCESS)
  254. m_materials.m_materials[ModelMat_gloss][i].m_filename = materialPath.data;
  255. if((p_assimpMaterials[i]->GetTexture(aiTextureType_HEIGHT, index, &materialPath) == aiReturn_SUCCESS) ||
  256. (p_assimpMaterials[i]->GetTexture(aiTextureType_DISPLACEMENT, index, &materialPath) == aiReturn_SUCCESS))
  257. m_materials.m_materials[ModelMat_height][i].m_filename = materialPath.data;
  258. */
  259. }
  260. return returnError;
  261. }
  262. ErrorCode Model::loadTextures(aiTexture **p_assimpTextures, size_t p_numTextures)
  263. {
  264. return ErrorCode::Success;
  265. }
  266. ModelLoader::ModelLoader()
  267. {
  268. m_defaultModel = new Model(this, "null_model", 0, 0);
  269. }
  270. ModelLoader::~ModelLoader()
  271. {
  272. }
  273. ErrorCode ModelLoader::init()
  274. {
  275. m_defaultModel->setLoadedToMemory(true);
  276. m_defaultModel->setLoadedToVideoMemory(true);
  277. m_objectPool.push_back(m_defaultModel);
  278. return ErrorCode::Success;
  279. }
  280. ModelLoader::ModelHandle ModelLoader::load(std::string p_filename, bool p_startBackgroundLoading)
  281. {
  282. // Make sure calls from other threads are locked, while current call is in progress
  283. // This is needed to as the object that is being requested might be currently loading /
  284. // being added to the pool. Mutex prevents duplicates being loaded, and same data being changed.
  285. SpinWait::Lock lock(m_mutex);
  286. if(p_filename.empty())
  287. return ModelHandle(*m_defaultModel);
  288. // Go through the model pool and check if the model hasn't been already loaded (to avoid duplicates)
  289. for(decltype(m_objectPool.size()) size = m_objectPool.size(), i = 0; i < size; i++)
  290. {
  291. if(*(m_objectPool[i]) == p_filename)
  292. return ModelHandle(*m_objectPool[i]);
  293. }
  294. // Model wasn't loaded before, so create a new one and assign the default placeholder handle
  295. // (since it's not loaded yet, and might fail to load)
  296. Model *model = new Model(this, p_filename, m_objectPool.size(), m_defaultModel->m_handle);
  297. if(p_startBackgroundLoading)
  298. {
  299. // Start loading the model from file, in a background thread
  300. TaskManagerLocator::get().startBackgroundThread(std::bind(&Model::loadFromFile, model));
  301. //TaskManagerLocator::get().startBackgroundThread([&] { model->loadFromFile(); });
  302. }
  303. // Add the new model to the list
  304. m_objectPool.push_back(model);
  305. // Return the new texture
  306. return ModelHandle(*model);
  307. }