SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLAssetLoader.cpp
Go to the documentation of this file.
1 /**
2  * \file SLAssetLoader.cpp
3  * \date May 2024
4  * \authors Marino von Wattenwyl
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8  */
9 
10 #include "SLAssetLoader.h"
11 
12 #include <mutex>
13 #include <iostream>
14 
15 #include "SLFileStorage.h"
16 #include "SLGLProgramManager.h"
17 #include "SLGLTexture.h"
18 #include "SLSkybox.h"
19 #include "SLAssimpImporter.h"
20 #include "SLScene.h"
21 #include "SLAssetManager.h"
22 #include "SLDeviceLocation.h"
23 
24 //-----------------------------------------------------------------------------
25 using std::unique_lock;
26 //-----------------------------------------------------------------------------
28  SLstring texturePath,
29  SLstring shaderPath,
30  SLstring fontPath)
31  : _modelPath(modelPath),
32  _texturePath(texturePath),
33  _shaderPath(shaderPath),
34  _fontPath(fontPath),
35  _state(State::IDLE)
36 {
37  auto workerFunc = [this]()
38  {
39  while (true)
40  {
41  // Wait until the main thread sends a message.
42  // 'Sending a message' means updating the state to a value that instructs
43  // the worker thread to do something.
44  unique_lock lock(_messageMutex);
45  _messageCondVar.wait(lock, [this]()
46  { return _state == State::SUBMITTED || _state == State::STOPPING; });
47 
48  // Do something depending on the current state.
49  if (_state == State::SUBMITTED)
50  {
51  // Process the tasks defined by the main thread.
52  for (SLAssetLoadTask& task : _loadTasks)
53  task();
54 
55  // Notify the main thread that the worker thread is done.
56  // The main thread checks this in checkIfAsyncLoadingIsDone.
58  }
59  else if (_state == State::STOPPING)
60  {
61  // Stops the worker thread by jumping...
62  break;
63  }
64  }
65 
66  // ...here and notifying the main thread that it can now join the worker thread.
68  _messageCondVar.notify_one();
69  };
70 
71  _worker = std::thread(workerFunc);
72 }
73 //-----------------------------------------------------------------------------
75 {
76  // Instruct the worker thread to stop.
77  unique_lock lock(_messageMutex);
79  lock.unlock();
80  _messageCondVar.notify_one();
81 
82  // Wait until the worker thread has stopped so we can join it.
83  lock.lock();
84  _messageCondVar.wait(lock, [this]()
85  { return _state == State::STOPPED; });
86  _worker.join();
87 }
88 //-----------------------------------------------------------------------------
90  SLstring filename,
91  SLIOStreamKind kind)
92 {
93  _loadTasks.push_back([this, &buffer, filename, kind]
94  { buffer = SLFileStorage::readIntoBuffer(filename, kind); });
95 }
96 //-----------------------------------------------------------------------------
98  const SLstring& path,
99  SLint min_filter,
100  SLint mag_filter,
101  SLTextureType type,
102  SLint wrapS,
103  SLint wrapT)
104 {
105  _loadTasks.push_back([this,
106  &texture,
107  path,
108  min_filter,
109  mag_filter,
110  type,
111  wrapS,
112  wrapT]
113  { texture = new SLGLTexture(_scene->assetManager(),
114  path,
115  min_filter,
116  mag_filter,
117  type,
118  wrapS,
119  wrapT); });
120 }
121 //-----------------------------------------------------------------------------
123  const SLstring& filenameXPos,
124  const SLstring& filenameXNeg,
125  const SLstring& filenameYPos,
126  const SLstring& filenameYNeg,
127  const SLstring& filenameZPos,
128  const SLstring& filenameZNeg,
129  SLint min_filter,
130  SLint mag_filter,
131  SLTextureType type)
132 {
133  _loadTasks.push_back([this,
134  &texture,
135  filenameXPos,
136  filenameXNeg,
137  filenameYPos,
138  filenameYNeg,
139  filenameZPos,
140  filenameZNeg,
141  min_filter,
142  mag_filter,
143  type]
144  { texture = new SLGLTexture(_scene->assetManager(),
145  filenameXPos,
146  filenameXNeg,
147  filenameYPos,
148  filenameYNeg,
149  filenameZPos,
150  filenameZNeg,
151  min_filter,
152  mag_filter,
153  type); });
154 }
155 //-----------------------------------------------------------------------------
157  SLint depth,
158  const SLstring& imagePath,
159  SLint min_filter,
160  SLint mag_filter,
161  SLint wrapS,
162  SLint wrapT,
163  const SLstring& name,
164  SLbool loadGrayscaleIntoAlpha)
165 
166 {
167  _loadTasks.push_back([this,
168  &texture,
169  depth,
170  imagePath,
171  min_filter,
172  mag_filter,
173  wrapS,
174  wrapT,
175  name,
176  loadGrayscaleIntoAlpha]
177  { texture = new SLGLTexture(_scene->assetManager(),
178  depth,
179  imagePath,
180  min_filter,
181  mag_filter,
182  wrapS,
183  wrapT,
184  name,
185  loadGrayscaleIntoAlpha); });
186 }
187 //-----------------------------------------------------------------------------
188 /*! Method for adding a 3D texture from a vector of images to load in parallel
189  * thread.
190  * \param texture Pointer to SLGLTexture to return
191  * \param imageFilenames Vector of texture image files. If only filenames are
192  * passed they will be searched on the SLGLTexture::defaultPath.
193  * \param min_filter Minification filter constant from OpenGL
194  * \param mag_filter Magnification filter constant from OpenGL
195  * \param wrapS Texture wrapping in S direction (OpenGL constant)
196  * \param wrapT Texture wrapping in T direction (OpenGL constant)
197  * \param name Name of the 3D texture
198  * \param loadGrayscaleIntoAlpha Flag if grayscale image should be loaded into
199  * alpha channel.
200  */
202  const SLVstring& imagePaths,
203  SLint min_filter,
204  SLint mag_filter,
205  SLint wrapS,
206  SLint wrapT,
207  const SLstring& name,
208  SLbool loadGrayscaleIntoAlpha)
209 {
210  _loadTasks.push_back([this,
211  &texture,
212  imagePaths,
213  min_filter,
214  mag_filter,
215  wrapS,
216  wrapT,
217  name,
218  loadGrayscaleIntoAlpha]
219  { texture = new SLGLTexture(_scene->assetManager(),
220  imagePaths,
221  min_filter,
222  mag_filter,
223  wrapS,
224  wrapT,
225  name,
226  loadGrayscaleIntoAlpha); });
227 }
228 //-----------------------------------------------------------------------------
230  const SLstring& imageFileWithPath)
231 {
232  _loadTasks.push_back([this,
233  &devLoc,
234  imageFileWithPath]
235  { devLoc.loadGeoTiff(imageFileWithPath); });
236 }
237 //-----------------------------------------------------------------------------
239  const SLstring& vertShaderPath,
240  const SLstring& fragShaderPath)
241 {
242  _loadTasks.push_back([this,
243  &program,
244  vertShaderPath,
245  fragShaderPath]
246  { program = new SLGLProgramGeneric(_scene->assetManager(),
247  vertShaderPath,
248  fragShaderPath); });
249 }
250 //-----------------------------------------------------------------------------
252  const SLstring& modelPath,
253  SLSkybox* skybox,
254  SLbool deleteTexImgAfterBuild,
255  SLbool loadMeshesOnly,
256  SLMaterial* overrideMat,
257  float ambientFactor,
258  SLbool forceCookTorranceRM,
259  SLuint flags)
260 {
261  _loadTasks.push_back([this,
262  &node,
263  modelPath,
264  skybox,
265  deleteTexImgAfterBuild,
266  loadMeshesOnly,
267  overrideMat,
268  ambientFactor,
269  forceCookTorranceRM,
270  flags]
271  {
272  SLAssimpImporter importer;
273  node = importer.load(_scene->animManager(),
274  _scene->assetManager(),
275  modelPath,
276  _texturePath,
277  skybox,
278  deleteTexImgAfterBuild,
279  loadMeshesOnly,
280  overrideMat,
281  ambientFactor,
282  forceCookTorranceRM,
283  nullptr,
284  flags); });
285 }
286 //-----------------------------------------------------------------------------
288  const SLstring& hdrImageWithFullPath,
289  SLVec2i resolution,
290  SLstring name)
291 {
292  _loadTasks.push_back([this,
293  &skybox,
294  hdrImageWithFullPath,
295  resolution,
296  name]
297  { skybox = new SLSkybox(_scene->assetManager(),
298  _shaderPath,
299  hdrImageWithFullPath,
300  resolution,
301  name); });
302 }
303 //-----------------------------------------------------------------------------
305 {
306  _loadTasks.push_back(task);
307 }
308 //-----------------------------------------------------------------------------
310  const SLstring& cubeMapXPos,
311  const SLstring& cubeMapXNeg,
312  const SLstring& cubeMapYPos,
313  const SLstring& cubeMapYNeg,
314  const SLstring& cubeMapZPos,
315  const SLstring& cubeMapZNeg)
316 {
317  _loadTasks.push_back([this,
318  &skybox,
319  cubeMapXPos,
320  cubeMapXNeg,
321  cubeMapYPos,
322  cubeMapYNeg,
323  cubeMapZPos,
324  cubeMapZNeg]
325  { skybox = new SLSkybox(_scene->assetManager(),
326  _shaderPath,
327  _texturePath + cubeMapXPos,
328  _texturePath + cubeMapXNeg,
329  _texturePath + cubeMapYPos,
330  _texturePath + cubeMapYNeg,
331  _texturePath + cubeMapZPos,
332  _texturePath + cubeMapZNeg); });
333 }
334 //-----------------------------------------------------------------------------
336 {
337  for (const SLAssetLoadTask& task : _loadTasks)
338  task();
339 
340  _loadTasks.clear();
341 }
342 //-----------------------------------------------------------------------------
343 void SLAssetLoader::loadAssetsAsync(function<void()> onDoneLoading)
344 {
345  _onDoneLoading = onDoneLoading;
346 
347  // Instruct the worker thread to start processing tasks.
348  unique_lock lock(_messageMutex);
350  lock.unlock();
351  _messageCondVar.notify_one();
352 }
353 //-----------------------------------------------------------------------------
354 /*! This method is called from the main thread to check if the async loading is
355  * is finished. If so, the assembly can be done in _onDoneLoading.
356  */
358 {
359  if (_state == State::DONE)
360  {
362  _loadTasks.clear();
363 
364  _onDoneLoading();
365  }
366 }
367 //-----------------------------------------------------------------------------
unsigned int SLuint
Definition: SL.h:171
bool SLbool
Definition: SL.h:175
vector< SLstring > SLVstring
Definition: SL.h:201
string SLstring
Definition: SL.h:158
int SLint
Definition: SL.h:170
function< void()> SLAssetLoadTask
Definition: SLAssetLoader.h:41
Mobile device location class declaration.
SLIOStreamKind
Enum of file kinds.
Definition: SLFileStorage.h:38
SLTextureType
Texture type enumeration & their filename appendix for auto type detection.
Definition: SLGLTexture.h:76
SLstring _texturePath
void addProgramToLoad(SLGLProgram *&program, const SLstring &vertShaderFile, const SLstring &fragShaderFile)
Add generic GLSL program with shader files to load.
SLVAssetLoadTask _loadTasks
SLstring _shaderPath
SLScene * _scene
void loadAssetsAsync(function< void()> onDone)
void checkIfAsyncLoadingIsDone()
mutex _messageMutex
mutex protecting state between threads
void addGeoTiffToLoad(SLDeviceLocation &devLoc, const SLstring &imageFileWithPath)
Add GeoTiff file to load for the SLDevLocation.
condition_variable _messageCondVar
mutex for waiting until state has changed
atomic< State > _state
current state (used for communication between threads)
void addSkyboxToLoad(SLSkybox *&skybox, const SLstring &path, SLVec2i resolution, SLstring name)
Add skybox with HDR texture to load.
thread _worker
worker thread for parallel loading
SLstring modelPath() const
Definition: SLAssetLoader.h:69
void addLoadTask(SLAssetLoadTask task)
Add generic task.
void addTextureToLoad(SLGLTexture *&texture, const SLstring &path, SLint min_filter=GL_LINEAR_MIPMAP_LINEAR, SLint mag_filter=GL_LINEAR, SLTextureType type=TT_unknown, SLint wrapS=GL_REPEAT, SLint wrapT=GL_REPEAT)
Add 2D textures with internal image allocation.
SLAssetLoader(SLstring modelPath, SLstring texturePath, SLstring shaderPath, SLstring fontPath)
function< void()> _onDoneLoading
Callback after threaded loading.
void addNodeToLoad(SLNode *&node, const SLstring &modelPath, SLSkybox *skybox=nullptr, SLbool deleteTexImgAfterBuild=false, SLbool loadMeshesOnly=true, SLMaterial *overrideMat=nullptr, float ambientFactor=0.5f, SLbool forceCookTorranceRM=false, SLuint flags=SLProcess_Triangulate|SLProcess_JoinIdenticalVertices|SLProcess_RemoveRedundantMaterials|SLProcess_FindDegenerates|SLProcess_FindInvalidData|SLProcess_SplitLargeMeshes)
Add mesh from file to load via assimp loader.
void addRawDataToLoad(SLIOBuffer &buffer, SLstring filename, SLIOStreamKind kind)
Encapsulation of a mobile device location set by the device's GPS sensor.
void loadGeoTiff(const SLstring &geoTiffFile)
Loads a GeoTiff DEM (Digital Elevation Model) Image.
Generic Shader Program class inherited from SLGLProgram.
Encapsulation of an OpenGL shader program object.
Definition: SLGLProgram.h:56
Texture object for OpenGL texturing.
Definition: SLGLTexture.h:110
Defines a standard CG material with textures and a shader program.
Definition: SLMaterial.h:56
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
SLAssetManager * assetManager()
Definition: SLScene.h:98
SLAnimManager & animManager()
Definition: SLScene.h:97
Skybox node class with a SLBox mesh.
Definition: SLSkybox.h:29
SLIOBuffer readIntoBuffer(std::string path, SLIOStreamKind kind)
Reads an entire file into memory.
Utility struct that holds a pointer and its length.
Definition: SLFileStorage.h:28