Engine
Frameworkcreatedbymeusableforthecreationofsimplegames.CurrentlysupportsOpenGL(Verysimple)andVulkan.
ResourceManager.cpp
Go to the documentation of this file.
4 
5 #ifdef USING_OPENGL
8 #endif
9 #ifdef USING_VULKAN
13 #endif
14 
15 #include <ThirdParty/EASTL-master/include/EASTL/algorithm.h>
16 #include <iostream>
17 #include <ThirdParty/assimp/include/assimp/postprocess.h>
18 
19 namespace Engine
20 {
21  eastl::weak_ptr<Model> ResourceManager::GetModel(eastl::string modelName)
22  {
23  // if already loaded
24  for (size_t i = 0, size = loadedModels_.size(); i < size; ++i)
25  {
26  if (loadedModels_[i]->GetName() == modelName)
27  return loadedModels_[i];
28  }
29 
30  // If not (yet) loaded
31  return eastl::shared_ptr<Model>();
32  }
33 
34  eastl::weak_ptr<Model> ResourceManager::CreateModel(eastl::string modelName, eastl::string meshToLoad, eastl::string skeletonToLoad)
35  {
36  Assimp::Importer importer;
37  eastl::string path = "Resources/Models/" + meshToLoad;
38  eastl::string skeletonPath;
39 
40  const aiScene* scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_JoinIdenticalVertices | aiProcess_ImproveCacheLocality |
41  aiProcess_OptimizeMeshes);
42 
43  // check if there's a scene or flags and check if the flags show incomplete scene
44  // or a missing root node (any successful import returns rood node)
45  if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
46  {
47  debug_warning("ResourceManager", "CreateModel", importer.GetErrorString());
48  return eastl::shared_ptr<Model>();
49  }
50 
51  eastl::weak_ptr<Skeleton> skeleton;
52  if (skeletonToLoad != "")
53  skeleton = CreateSkeleton(skeletonToLoad);
54  else
55  skeleton = CreateSkeleton(meshToLoad);
56 
57  loadedModels_.push_back(eastl::shared_ptr<Model>(new Model(scene, modelName)));
58  eastl::shared_ptr<Model>modelToAddTo = loadedModels_.back();
59 
60  // process the nodes and extract their data
61  ProcessModel(modelName, modelToAddTo, scene->mRootNode, scene, skeleton.lock());
62  return loadedModels_.back();
63  }
64 
65  eastl::weak_ptr<Skeleton> ResourceManager::CreateSkeleton(eastl::string skeletonToLoad)
66  {
67  Assimp::Importer importer;
68  eastl::string path = "Resources/Models/" + skeletonToLoad;
69 
70  for (size_t i = 0, size = loadedSkeletons_.size(); i < size; ++i) {
71  if (loadedSkeletons_[i]->GetName() == skeletonToLoad)
72  return loadedSkeletons_[i];
73  }
74 
75  const aiScene* scene = importer.ReadFile(path.c_str(), 0);
76 
77  // check if there's a scene or flags and check if the flags show incomplete scene
78  // or a missing root node (any successful import returns rood node)
79  if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
80  {
81  debug_warning("ResourceManager", "CreateSkeleton", importer.GetErrorString());
82  return eastl::shared_ptr<Skeleton>();
83  }
84 
85  eastl::shared_ptr<Skeleton> skeleton = eastl::shared_ptr<Skeleton>(new Skeleton(scene));
86  skeleton->SetName(skeletonToLoad);
87 
88  loadedSkeletons_.push_back(skeleton);
89  return skeleton;
90  }
91 
92  void ResourceManager::AddAnimationsToSkeleton(eastl::string skeletonName, eastl::string animationsToLoad, eastl::vector<eastl::string> names)
93  {
94  Assimp::Importer importer;
95  eastl::string path = "Resources/Animations/" + animationsToLoad;
96  const aiScene* scene = importer.ReadFile(path.c_str(), 0);
97 
98  for (size_t i = 0, size = loadedSkeletons_.size(); i < size; ++i)
99  {
100  if (loadedSkeletons_[i]->GetName() == skeletonName) {
101  loadedSkeletons_[i]->LoadAnimationSet(scene, names);
102  }
103  }
104  }
105 
106  eastl::weak_ptr<Mesh> ResourceManager::CreateMesh(aiMesh* mesh, eastl::shared_ptr<Skeleton> skeleton, eastl::vector<Vertex> vertices, eastl::vector<unsigned> indices)
107  {
108  // If already loaded
109  eastl::weak_ptr<Mesh> meshToReturn = GetMesh(vertices, indices);
110  if (meshToReturn.expired() == false && meshToReturn.lock().get() != nullptr)
111  return meshToReturn;
112 
113 #ifdef USING_OPENGL
114  eastl::shared_ptr<Mesh> createdMesh = eastl::shared_ptr<OpenGLMesh>(new OpenGLMesh(vertices, indices));
115 #endif
116 #ifdef USING_VULKAN
117  eastl::shared_ptr<Mesh> createdMesh = eastl::shared_ptr<VulkanMesh>(new VulkanMesh(mesh, skeleton, vertices, indices));
118 #endif
119  loadedMeshes_.push_back(eastl::move(createdMesh));
120 
121  return meshToReturn;
122  }
123 
124  eastl::weak_ptr<Texture> ResourceManager::GetTexture(eastl::string meshName)
125  {
126  // if not (yet) loaded
127  if (loadedTextures_.find(meshName) == loadedTextures_.end())
128  return eastl::shared_ptr<Texture>();
129 
130  // if already loaded
131  return loadedTextures_[meshName];
132  }
133 
134  eastl::weak_ptr<Texture> ResourceManager::CreateTexture(eastl::string textureName)
135  {
136  // If already loaded
137  eastl::weak_ptr<Texture> textureToReturn = GetTexture(textureName);
138  if (textureToReturn.expired() == false && textureToReturn.lock().get() != nullptr)
139  return textureToReturn;
140 
141 #ifdef USING_OPENGL
142  eastl::shared_ptr<Texture> createdTexture = eastl::shared_ptr<OpenGLTexture>(new OpenGLTexture(textureName));
143 #endif
144 #ifdef USING_VULKAN
145  eastl::shared_ptr<Texture> createdTexture = eastl::shared_ptr<VulkanTexture>(new VulkanTexture(textureName));
146 #endif
147  loadedTextures_.insert(eastl::make_pair(textureName, eastl::move(createdTexture)));
148 
149  return loadedTextures_[textureName];
150  }
151 
152  void ResourceManager::ProcessModel(eastl::string modelName, eastl::shared_ptr<Model> modelToAddTo, aiNode* node, const aiScene* scene, eastl::shared_ptr<Skeleton> skeleton)
153  {
154 
155  if (node->mParent == nullptr)
156  modelToAddTo->SetSkeleton(skeleton);
157 
158  // process all node's meshes if any
159  // if there aren't any try going through the children nodes
160  for (unsigned short i = 0; i < scene->mNumMeshes; i++)
161  {
162  aiMesh* mesh = scene->mMeshes[i];
163 
164 
165  modelToAddTo->AddMesh(ProcessMesh(mesh, scene, skeleton).lock());
166 
167  eastl::shared_ptr<Material> material;
168 
169 #ifdef USING_VULKAN
170  material = eastl::shared_ptr<VulkanMaterial>(new VulkanMaterial(scene,
171  static_cast<uint32_t>(mesh->mMaterialIndex), modelName));
172 #endif
173 #ifdef USING_OPENGL
174  material = eastl::shared_ptr<Material>(new Material(scene,
175  static_cast<uint32_t>(mesh->mMaterialIndex), modelName));
176 #endif
177 
178  modelToAddTo->SetMeshMaterial(modelToAddTo->GetModelMeshes()[modelToAddTo->GetModelMeshes().size() - 1], eastl::move(material));
179  }
180 
181  for (unsigned short i = 0; i < node->mNumChildren; i++)
182  {
183  ProcessModel(modelName, modelToAddTo, node->mChildren[i], scene, skeleton);
184  }
185  }
186 
187  eastl::weak_ptr<Mesh> ResourceManager::ProcessMesh(aiMesh* mesh, const aiScene* scene, eastl::shared_ptr<Skeleton> skeleton)
188  {
189  eastl::vector<Vertex> vertices;
190  eastl::vector<unsigned> indices;
191  eastl::vector<eastl::shared_ptr<Texture>> diffuseTextures;
192  eastl::vector<eastl::shared_ptr<Texture>> specularTextures;
193 
194  //unpack vertices
195  for (unsigned i = 0; i < mesh->mNumVertices; i++)
196  {
197  Vertex vertex;
198  //position vertex coords
199  vertex.position.x = mesh->mVertices[i].x;
200  vertex.position.y = mesh->mVertices[i].y;
201  vertex.position.z = mesh->mVertices[i].z;
202 
203  //check if we have normals
204  if (mesh->mNormals)
205  {
206  //normal vertex coordinates
207  vertex.normal.x = mesh->mNormals[i].x;
208  vertex.normal.y = mesh->mNormals[i].y;
209  vertex.normal.z = mesh->mNormals[i].z;
210  }
211 
212  //Assimp allows a mesh to have 8 sets of texture coordinates
213  //I'll load only the first set for now, if needed we can extend
214  if (mesh->mTextureCoords[0] > nullptr)
215  {
216  vertex.texCoords.s = mesh->mTextureCoords[0][i].x;
217  vertex.texCoords.t = mesh->mTextureCoords[0][i].y;
218  }
219  else
220  {
221  //no texture coordinates
222  vertex.texCoords = glm::vec2(0.0f, 0.0f);
223  }
224 
225  vertex.boneWeights[0] = 0.f;
226  vertex.boneWeights[1] = 0.f;
227  vertex.boneWeights[2] = 0.f;
228  vertex.boneWeights[3] = 0.f;
229  vertex.boneIds[0] = 0;
230  vertex.boneIds[1] = 0;
231  vertex.boneIds[2] = 0;
232  vertex.boneIds[3] = 0;
233 
234  vertices.push_back(vertex);
235  }
236 
237 
238  for (size_t i = 0; i < mesh->mNumFaces; ++i)
239  {
240  aiFace *face = &mesh->mFaces[i];
241 
242  // retrieve all indices of the face and store them in the indices vector
243  for (size_t j = 0; j < face->mNumIndices; j++)
244  {
245  indices.push_back(static_cast<unsigned>(face->mIndices[j]));
246  }
247  }
248 
249  //TODO - Parse materials
250  if (mesh->mMaterialIndex >= 0)
251  {
252  aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
253  }
254 
255  return CreateMesh(mesh, skeleton, vertices, indices);
256  }
257 
258  eastl::weak_ptr<Texture> ResourceManager::CreateTexture(eastl::string textureName, stbi_uc * data, int width, int height)
259  {
260  // If already loaded
261  eastl::weak_ptr<Texture> textureToReturn = GetTexture(textureName);
262  if (textureToReturn.expired() == false && textureToReturn.lock().get() != nullptr)
263  return textureToReturn;
264 
265 #ifdef USING_OPENGL
266  eastl::shared_ptr<Texture> createdTexture = eastl::shared_ptr<OpenGLTexture>(new OpenGLTexture(width, height));
267 #endif
268 #ifdef USING_VULKAN
269  eastl::shared_ptr<Texture> createdTexture = eastl::shared_ptr<VulkanTexture>(new VulkanTexture(width, height));
270 #endif
271  createdTexture->CreateTextureWithData(data, false);
272 
273  loadedTextures_.insert(eastl::make_pair(textureName, eastl::move(createdTexture)));
274 
275  return loadedTextures_[textureName];
276  }
277 
278  void ResourceManager::AddTexture(eastl::string textureName, eastl::shared_ptr<Texture> textureToAdd)
279  {
280  // If a texture with this name has already been loaded
281  eastl::weak_ptr<Texture> textureToReturn = GetTexture(textureName);
282  if (textureToReturn.expired() == false && textureToReturn.lock().get() != nullptr)
283  return;
284 
285  loadedTextures_[textureName] = eastl::move(textureToAdd);
286  }
287 
288  eastl::weak_ptr<Mesh> ResourceManager::GetMesh(eastl::vector<Vertex> vertices, eastl::vector<unsigned> indices)
289  {
290  if (loadedMeshes_.size() == 0) return eastl::shared_ptr<Mesh>();
291 
292  for (size_t i = 0, size = loadedMeshes_.size(); i < size; ++i)
293  {
294  bool isEqual = true;
295 
296  if (loadedMeshes_[i]->vertices.size() != vertices.size()) continue;
297  if (loadedMeshes_[i]->indices.size() != indices.size()) continue;
298 
299  for (size_t j = 0, verticesSize = loadedMeshes_[i]->vertices.size(); j < verticesSize; ++j)
300  {
301  Vertex vertex = loadedMeshes_[i]->vertices[j];
302 
303  if (vertex.normal != vertices[j].normal) { isEqual = false; break; }
304  if (vertex.position != vertices[j].position) { isEqual = false; break; }
305  if (vertex.texCoords != vertices[j].texCoords) { isEqual = false; break; }
306  }
307 
308  if (isEqual == false) continue;
309 
310  for (size_t j = 0, indicesSize = loadedMeshes_[i]->indices.size(); j < indicesSize; ++j)
311  {
312  if (loadedMeshes_[i]->indices[j] != indices[j]) { isEqual = false; break; }
313  }
314 
315  if (isEqual)
316  return loadedMeshes_[i];
317  }
318 
319  return eastl::shared_ptr<Mesh>();
320  }
321 
322  eastl::vector<eastl::shared_ptr<Texture>> ResourceManager::ProcessDiffuseTextures(aiMaterial* material)
323  {
324  eastl::vector<eastl::shared_ptr<Texture>> textures;
325 
326  eastl::vector<eastl::shared_ptr<Texture>> diffuseMaps = LoadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
327  textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
328 
329  return textures;
330  }
331 
332  eastl::vector<eastl::shared_ptr<Texture>> ResourceManager::ProcessSpecularTextures(aiMaterial* material)
333  {
334  eastl::vector<eastl::shared_ptr<Texture>> textures;
335 
336  eastl::vector<eastl::shared_ptr<Texture>> specularMaps = LoadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
337  textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
338 
339  return textures;
340  }
341 
342  eastl::vector<eastl::shared_ptr<Texture>> ResourceManager::LoadMaterialTextures(aiMaterial* material,
343  aiTextureType textureType, eastl::string typeName)
344  {
345  eastl::vector<eastl::shared_ptr<Texture>> textures;
346  for (unsigned short i = 0; i < material->GetTextureCount(textureType); i++)
347  {
348  aiString str;
349  material->GetTexture(textureType, i, &str);
350  eastl::string fileName = eastl::string(str.C_Str());
351 
352  // check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
353  bool skip = false;
354  for (unsigned short j = 0; j < loadedTextures_.size(); j++)
355  {
356  if (loadedTextures_.find(fileName) != loadedTextures_.end())
357  {
358  textures.push_back(loadedTextures_[fileName]);
359  skip = true; // a texture with the same filepath has already been loaded, continue to next one. (optimization)
360  break;
361  }
362  }
363  if (!skip)
364  { // if texture hasn't been loaded already, load it
365  //Texture texture;
366  //texture.id = loadTextureFromFile(str.C_Str(), this->directory);
367  //texture.type = typeName;
368  //texture.path = str;
369 
370  eastl::weak_ptr<Texture> texture = CreateTexture(fileName);
371  textures.push_back(texture.lock());
372 
373  // store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
374  loadedTextures_.insert(eastl::make_pair(fileName, texture.lock()));
375  }
376  }
377  return textures;
378  }
379 } // namespace Engine
eastl::weak_ptr< Skeleton > CreateSkeleton(eastl::string skeletonToLoad)
This will load the skeleton data from the file specified. NOTe: This method will not load in the skel...
eastl::weak_ptr< Texture > GetTexture(eastl::string textureName)
This method allows you to get a texture with the defined name.
void AddAnimationsToSkeleton(eastl::string skeletonName, eastl::string animationsToLoad="", eastl::vector< eastl::string > names={})
This method loads animations from a file, and adds them to the skeleton with the specified name...
eastl::weak_ptr< Model > GetModel(eastl::string modelName)
This method allows you to get a model with a specific name.
glm::vec2 texCoords
Definition: Vertex.hpp:11
glm::vec3 normal
Definition: Vertex.hpp:10
eastl::weak_ptr< Texture > CreateTexture(eastl::string textureName)
This method allows you to create a new texture with the given name.
glm::vec3 position
Definition: Vertex.hpp:9
eastl::weak_ptr< Mesh > CreateMesh(aiMesh *mesh, eastl::shared_ptr< Skeleton > skeleton, eastl::vector< Vertex > vertices, eastl::vector< unsigned > indices)
This method allows you to create a new mesh. NOTE: This method will not load in the mesh again...
eastl::weak_ptr< Model > CreateModel(eastl::string modelName, eastl::string meshToLoad="", eastl::string skeleton="")
This method will allow you to create a new model with the model name.
float boneWeights[4]
Definition: Vertex.hpp:12
#define debug_warning(debug_class, function, value)
This functions logs a debug warning to the log and console.
Definition: Logging.hpp:45
uint32_t boneIds[4]
Definition: Vertex.hpp:13
This object is used to store general data for a vertex.
Definition: Vertex.hpp:6