Radium Engine  1.5.0
RadiumEngine.cpp
1 #include <Engine/RadiumEngine.hpp>
2 
3 #include <Core/Asset/FileData.hpp>
4 #include <Core/Asset/FileLoaderInterface.hpp>
5 #include <Core/Resources/Resources.hpp>
6 #include <Core/Tasks/Task.hpp>
7 #include <Core/Tasks/TaskQueue.hpp>
8 #include <Core/Utils/StringUtils.hpp>
9 #include <Engine/Data/BlinnPhongMaterial.hpp>
10 #include <Engine/Data/LambertianMaterial.hpp>
11 #include <Engine/Data/MaterialConverters.hpp>
12 #include <Engine/Data/PlainMaterial.hpp>
13 #include <Engine/Data/ShaderConfigFactory.hpp>
14 #include <Engine/Data/ShaderProgramManager.hpp>
15 #include <Engine/Data/TextureManager.hpp>
16 #include <Engine/Data/VolumetricMaterial.hpp>
17 #include <Engine/FrameInfo.hpp>
18 #include <Engine/Rendering/RenderObject.hpp>
19 #include <Engine/Rendering/RenderObjectManager.hpp>
20 #include <Engine/Scene/ComponentMessenger.hpp>
21 #include <Engine/Scene/DefaultCameraManager.hpp>
22 #include <Engine/Scene/Entity.hpp>
23 #include <Engine/Scene/EntityManager.hpp>
24 #include <Engine/Scene/SignalManager.hpp>
25 #include <Engine/Scene/System.hpp>
26 #include <Engine/Scene/SystemDisplay.hpp>
27 
28 #include <iostream>
29 #include <string>
30 
31 #include <glbinding-aux/ContextInfo.h>
32 #include <glbinding/Version.h>
33 
34 namespace Ra {
35 namespace Engine {
36 
37 using namespace Core::Utils; // log
38 using namespace Core::Asset;
39 
40 RadiumEngine::RadiumEngine() = default;
41 
42 RadiumEngine::~RadiumEngine() = default;
43 
45  LOG( logINFO ) << "*** Radium Engine ***";
46  auto resourceDir { Core::Resources::getRadiumResourcesPath() };
47  if ( !resourceDir ) {
48  LOG( logWARNING )
49  << "Default Radium resources dir not found. Setting resources path to \".\"";
50  resourceDir = { "." };
51  }
52  m_resourcesRootDir = *resourceDir;
53  m_signalManager = std::make_unique<Scene::SignalManager>();
54  m_entityManager = std::make_unique<Scene::EntityManager>();
55  m_renderObjectManager = std::make_unique<Rendering::RenderObjectManager>();
56  m_textureManager = std::make_unique<Data::TextureManager>();
57  m_shaderProgramManager = std::make_unique<Data::ShaderProgramManager>();
58 
59  m_loadedFile.reset();
60  Scene::ComponentMessenger::createInstance();
61 
62  auto cameraManager = new Scene::DefaultCameraManager();
63  cameraManager->initialize();
64  // register the CameraManager so that it is always activated after all other systems
65  Ra::Engine::RadiumEngine::getInstance()->registerSystem(
66  "DefaultCameraManager", cameraManager, std::numeric_limits<int>::min() );
67 }
68 
70  // get the OpenGL/GLSL version of the bounded context as default shader version
71  m_glVersion = glbinding::aux::ContextInfo::version();
73 
74  m_openglState = std::make_unique<globjects::State>( globjects::State::DeferredMode );
75  registerDefaultPrograms();
76  // needed to upload non multiple of 4 width texture loaded with stbi.
77  m_openglState->pixelStore( GL_UNPACK_ALIGNMENT, 1 );
78  m_openglState->apply();
79 }
80 
81 glbinding::Version RadiumEngine::getOpenGLVersion() const {
82  return m_glVersion;
83 }
84 
85 void RadiumEngine::registerDefaultPrograms() {
86 
87  CORE_ASSERT( m_shaderProgramManager != nullptr,
88  "ShaderProgramManager needs to be created first" );
89 
90  // Create named strings which correspond to shader files that you want to use in shaders's
91  // includes. NOTE: if you want to add a named string to handle a new shader include file, be
92  // SURE that the name (first parameter) begin with a "/", otherwise it won't work !
93  // Radium V2 : are these initialization required here ? They will be better in
94  // Engine::Initialize .... Define a better ressources management and initialization
95  // Add named string require opengl context, must be init before (e.g. by viewer)
96  /* Default definiton of a transformation matrices struct */
97  m_shaderProgramManager->addNamedString(
98  "/TransformStructs.glsl", m_resourcesRootDir + "Shaders/Transform/TransformStructs.glsl" );
99  m_shaderProgramManager->addNamedString(
100  "/DefaultLight.glsl", m_resourcesRootDir + "Shaders/Lights/DefaultLight.glsl" );
101 
102  // VertexAttribInterface :add this name string so that each material could include the same code
103  m_shaderProgramManager->addNamedString(
104  "/VertexAttribInterface.frag.glsl",
105  m_resourcesRootDir + "Shaders/Materials/VertexAttribInterface.frag.glsl" );
106 
107  // Engine support some built-in materials. Register here
109  Data::ShaderConfiguration lConfig( "Lines" );
110  lConfig.addShader( Data::ShaderType_VERTEX,
111  m_resourcesRootDir + "Shaders/Lines/Lines.vert.glsl" );
112  lConfig.addShader( Data::ShaderType_FRAGMENT,
113  m_resourcesRootDir + "Shaders/Lines/Lines.frag.glsl" );
115 
116  Data::ShaderConfiguration lgConfig( "LinesGeom" );
117  lgConfig.addShader( Data::ShaderType_VERTEX,
118  m_resourcesRootDir + "Shaders/Lines/Lines.vert.glsl" );
119  lgConfig.addShader( Data::ShaderType_FRAGMENT,
120  m_resourcesRootDir + "Shaders/Lines/Lines.frag.glsl" );
121  lgConfig.addShader( Data::ShaderType_GEOMETRY,
122  m_resourcesRootDir + "Shaders/Lines/Lines.geom.glsl" );
124 
125  Data::ShaderConfiguration lagConfig( "LinesAdjacencyGeom" );
126  lagConfig.addShader( Data::ShaderType_VERTEX,
127  m_resourcesRootDir + "Shaders/Lines/Lines.vert.glsl" );
128  lagConfig.addShader( Data::ShaderType_FRAGMENT,
129  m_resourcesRootDir + "Shaders/Lines/LinesAdjacency.frag.glsl" );
130  lagConfig.addShader( Data::ShaderType_GEOMETRY,
131  m_resourcesRootDir + "Shaders/Lines/Lines.geom.glsl" );
133 
134  // Plain is flat or diffuse
139 }
140 
146  m_signalManager->setOn( false );
147  m_entityManager.reset();
148  m_renderObjectManager.reset();
149  m_textureManager.reset( nullptr );
150  m_shaderProgramManager.reset( nullptr );
151 
152  m_loadedFile.reset();
153 
154  for ( auto& system : m_systems ) {
155  system.second.reset();
156  }
157 
158  Scene::ComponentMessenger::destroyInstance();
159 
160  m_loadingState = false;
161 }
162 
164  m_entityManager->swapBuffers();
165  m_signalManager->fireFrameEnded();
166 }
167 
168 void RadiumEngine::getTasks( Core::TaskQueue* taskQueue, Scalar dt ) {
169  static uint frameCounter = 0;
170 
171  if ( m_timeData.m_play || m_timeData.m_singleStep ) {
172  m_timeData.updateTime( dt );
173  m_timeData.m_singleStep = false;
174  }
175 
176  FrameInfo frameInfo {
177  m_timeData.m_time, m_timeData.m_realTime ? dt : m_timeData.m_dt, frameCounter++ };
178  for ( auto& syst : m_systems ) {
179  syst.second->generateTasks( taskQueue, frameInfo );
180  }
181 }
182 
183 bool RadiumEngine::registerSystem( const std::string& name, Scene::System* system, int priority ) {
184  if ( findSystem( name ) != m_systems.end() ) {
185  LOG( logWARNING ) << "Try to add system " << name.c_str()
186  << " multiple time. Keep the already registered one.";
187  return false;
188  }
189 
190  m_systems[std::make_pair( priority, name )] = std::shared_ptr<Scene::System>( system );
191  LOG( logINFO ) << "Loaded : " << name;
192  return true;
193 }
194 
195 Scene::System* RadiumEngine::getSystem( const std::string& system ) const {
196  Scene::System* sys = nullptr;
197  auto it = findSystem( system );
198 
199  if ( it != m_systems.end() ) { sys = it->second.get(); }
200 
201  return sys;
202 }
203 
204 Data::Displayable* RadiumEngine::getMesh( const std::string& entityName,
205  const std::string& componentName,
206  const std::string& roName ) const {
207 
208  // 1) Get entity
209  if ( m_entityManager->entityExists( entityName ) ) {
210  auto e = m_entityManager->getEntity( entityName );
211 
212  // 2) Get component
213  const auto c = e->getComponent( componentName );
214 
215  if ( c != nullptr && !c->m_renderObjects.empty() ) {
216  // 3) Get RO
217  if ( roName.empty() ) {
218  return m_renderObjectManager->getRenderObject( c->m_renderObjects.front() )
219  ->getMesh()
220  .get();
221  }
222  else {
223  for ( const auto& idx : c->m_renderObjects ) {
224  const auto& ro = m_renderObjectManager->getRenderObject( idx );
225  if ( ro->getName() == roName ) { return ro->getMesh().get(); }
226  }
227  }
228  }
229  }
230  return nullptr;
231 }
232 
233 bool RadiumEngine::loadFile( const std::string& filename ) {
234  releaseFile();
235 
236  std::string extension = Core::Utils::getFileExt( filename );
237 
238  for ( auto& l : m_fileLoaders ) {
239  if ( l->handleFileExtension( extension ) ) {
240  FileData* data = l->loadFile( filename );
241  if ( data != nullptr ) {
242  m_loadedFile.reset( data );
243  break;
244  }
245  }
246  }
247 
248  if ( m_loadedFile == nullptr ) {
249  LOG( logERROR ) << "There is no loader to handle \"" << extension
250  << "\" extension ! File can't be loaded.";
251 
252  return false;
253  }
254 
255  std::string entityName = Core::Utils::getBaseName( filename, false );
256 
257  Scene::Entity* entity = m_entityManager->createEntity( entityName );
258 
259  for ( auto& system : m_systems ) {
260  system.second->handleAssetLoading( entity, m_loadedFile.get() );
261  }
262 
263  if ( !entity->getComponents().empty() ) {
264  for ( auto& comp : entity->getComponents() ) {
265  comp->initialize();
266  }
267  }
268  else {
269  LOG( logWARNING ) << "File \"" << filename << "\" has no usable data. Deleting entity...";
270  m_entityManager->removeEntity( entity );
271  }
272  m_loadingState = true;
273  return true;
274 }
275 
277  m_loadedFile.reset( nullptr );
278  m_loadingState = false;
279 }
280 
281 Rendering::RenderObjectManager* RadiumEngine::getRenderObjectManager() const {
282  return m_renderObjectManager.get();
283 }
284 
285 Scene::EntityManager* RadiumEngine::getEntityManager() const {
286  return m_entityManager.get();
287 }
288 
290  return m_signalManager.get();
291 }
292 
294  return m_textureManager.get();
295 }
296 
298  return m_shaderProgramManager.get();
299 }
300 
301 void RadiumEngine::registerFileLoader( std::shared_ptr<FileLoaderInterface> fileLoader ) {
302  m_fileLoaders.push_back( fileLoader );
303 }
304 
305 const std::vector<std::shared_ptr<FileLoaderInterface>>& RadiumEngine::getFileLoaders() const {
306  return m_fileLoaders;
307 }
308 
309 RA_SINGLETON_IMPLEMENTATION( RadiumEngine );
310 
311 const FileData& RadiumEngine::getFileData() const {
312  CORE_ASSERT( m_loadingState, "Access to file content is only available at loading time." );
313  return *( m_loadedFile.get() );
314 }
315 
316 RadiumEngine::SystemContainer::const_iterator
317 RadiumEngine::findSystem( const std::string& name ) const {
318  return std::find_if( m_systems.cbegin(), m_systems.cend(), [&name]( const auto& el ) {
319  return el.first.second == name;
320  } );
321 }
322 
323 RadiumEngine::SystemContainer::iterator RadiumEngine::findSystem( const std::string& name ) {
324  return std::find_if( m_systems.begin(), m_systems.end(), [&name]( const auto& el ) {
325  return el.first.second == name;
326  } );
327 }
328 
329 Core::Aabb RadiumEngine::computeSceneAabb() const {
330 
331  Core::Aabb aabb;
332 
333  const auto& systemEntity = Scene::SystemEntity::getInstance();
334  auto entities = m_entityManager->getEntities();
335  for ( const auto& entity : entities ) {
336  if ( entity != systemEntity ) aabb.extend( entity->computeAabb() );
337  }
338  return aabb;
339 }
340 
342  int activeFbo;
343  std::array<int, 4> activeViewport;
344 
345  glGetIntegerv( GL_VIEWPORT, activeViewport.data() );
346  // save the currently bound FBO
347  GL_ASSERT( glGetIntegerv( GL_FRAMEBUFFER_BINDING, &activeFbo ) );
348  // Set the internal rendering viewport
349  m_fboAndViewportStack.emplace( activeFbo, std::move( activeViewport ) );
350 }
351 
353  if ( m_fboAndViewportStack.empty() ) {
354  LOG( logERROR ) << "RadiumEngine: try to pop from an empty Fbo and Viewport stack\n";
355  }
356  else {
357  auto b = m_fboAndViewportStack.top();
358 
359  glViewport( b.m_viewport[0], b.m_viewport[1], b.m_viewport[2], b.m_viewport[3] );
360  GL_ASSERT( glBindFramebuffer( GL_FRAMEBUFFER, b.m_fbo ) );
361  m_fboAndViewportStack.pop();
362  }
363 }
364 
365 void RadiumEngine::setRealTime( bool realTime ) {
366  m_timeData.m_realTime = realTime;
367 }
368 
370  return m_timeData.m_realTime;
371 }
372 
374  return !m_timeData.m_realTime;
375 }
376 
377 bool RadiumEngine::setConstantTimeStep( Scalar dt, bool forceConstantTime ) {
378  m_timeData.m_dt = dt;
379  if ( forceConstantTime ) { setRealTime( false ); }
380  return !m_timeData.m_realTime;
381 }
382 
383 void RadiumEngine::play( bool isPlaying ) {
384  m_timeData.m_play = isPlaying;
385 }
386 
388  m_timeData.m_singleStep = true;
389 }
390 
392  m_timeData.m_play = false;
393  m_timeData.m_singleStep = false;
394  m_timeData.m_time = m_timeData.m_startTime;
395 }
396 
397 void RadiumEngine::setTime( Scalar t ) {
398  m_timeData.m_time = t;
399 }
400 
401 void RadiumEngine::setStartTime( Scalar t ) {
402  m_timeData.m_startTime = std::max( t, 0_ra );
403 }
404 
406  return m_timeData.m_startTime;
407 }
408 
409 void RadiumEngine::setEndTime( Scalar t ) {
410  m_timeData.m_endTime = t;
411 }
412 
413 Scalar RadiumEngine::getEndTime() const {
414  return m_timeData.m_endTime;
415 }
416 
418  m_timeData.m_forwardBackward = mode;
419  // if just disabled forward-backward mode, then going forward
420  if ( !m_timeData.m_forwardBackward ) { m_timeData.m_isBackward = false; }
421 }
422 
423 Scalar RadiumEngine::getTime() const {
424  return m_timeData.m_time;
425 }
426 
428  return uint( std::ceil( m_timeData.m_time / m_timeData.m_dt ) );
429 }
430 
431 void RadiumEngine::TimeData::updateTime( Scalar dt ) {
432  dt += m_realTime ? dt : m_dt;
433  // update the time w.r.t. the time flow policy
434  if ( m_forwardBackward && m_isBackward ) { m_time -= dt; }
435  else { m_time += dt; }
436  // special case: empty time window => forever mode
437  if ( m_endTime < 0 || m_startTime >= m_endTime ) {
438  // just run forever
439  m_isBackward = false;
440  return;
441  }
442  // special case: m_time before time window
443  if ( m_time < m_startTime ) {
444  // reset whatever the mode
445  m_time = m_startTime;
446  // and go forward from now on
447  m_isBackward = false;
448  return;
449  }
450  // special case: m_time after time window in loop mode
451  if ( !m_forwardBackward && m_time > m_endTime ) {
452  // compute the overload of time
453  dt = Scalar( fmod( double( m_time - m_startTime ), double( m_endTime - m_startTime ) ) );
454  // loop around, applying the overload of time
455  m_time = m_startTime + dt;
456  return;
457  }
458  // special case: m_time after time window in forward-backward mode
459  if ( m_forwardBackward && m_time > m_endTime ) {
460  if ( !m_isBackward ) // start backwards
461  {
462  m_time = 2 * m_endTime - m_time;
463  }
464  else // restart backward from the end of the time window
465  {
466  m_time = m_endTime;
467  }
468  m_isBackward = true;
469  return;
470  }
471 }
472 
474  m_gpuTaskQueue->runTasksInThisThread();
475 }
476 
477 Core::TaskQueue::TaskId RadiumEngine::addGpuTask( std::unique_ptr<Core::Task> task ) {
478  return m_gpuTaskQueue->registerTask( std::move( task ) );
479 }
480 
482  m_gpuTaskQueue->removeTask( taskId );
483 }
484 
485 } // namespace Engine
486 } // namespace Ra
Utils::Index TaskId
Identifier for a task in the task queue.
Definition: TaskQueue.hpp:35
static void setOpenGLVersion(const glbinding::Version &version)
set the OpenGL version to use in the generated header for shaders.
const Core::Asset::FileData & getFileData() const
Scene::System * getSystem(const std::string &system) const
bool loadFile(const std::string &file)
Scene::EntityManager * getEntityManager() const
void setStartTime(Scalar t)
void getTasks(Core::TaskQueue *taskQueue, Scalar dt)
bool isRealTime() const
Indicates if Real-time time flow is on (Constant-time is off) .
Core::Aabb computeSceneAabb() const
const std::vector< std::shared_ptr< Core::Asset::FileLoaderInterface > > & getFileLoaders() const
void setRealTime(bool realTime)
Toggles Real-time (on) or Constant (off) time flow.
Data::TextureManager * getTextureManager() const
void setForwardBackward(bool mode)
Activates or disables ForwardBackward time flow.
Rendering::RenderObjectManager * getRenderObjectManager() const
Manager getters.
void play(bool isPlaying)
Scene::SignalManager * getSignalManager() const
Scalar getStartTime() const
glbinding::Version getOpenGLVersion() const
Get the currently used OpenGL version.
void registerFileLoader(std::shared_ptr< Core::Asset::FileLoaderInterface > fileLoader)
Data::Displayable * getMesh(const std::string &entityName, const std::string &componentName, const std::string &roName=std::string()) const
void removeGpuTask(Core::TaskQueue::TaskId taskId)
Core::TaskQueue::TaskId addGpuTask(std::unique_ptr< Core::Task >)
Data::ShaderProgramManager * getShaderProgramManager() const
bool setConstantTimeStep(Scalar dt, bool forceConstantTime=false)
Sets the time delta between two frames for Constant-time time flow.
bool isConstantTime() const
Indicates if Constant-time time flow is on (Real-time is off) .
bool registerSystem(const std::string &name, Scene::System *system, int priority=1)
DefaultCameraManager. A simple Camera Manager with a list of Cameras.
An entity is an scene element. It ties together components with a transform.
Definition: Entity.hpp:23
optional< std::string > getRadiumResourcesPath()
Get the path of Radium internal resources.
Definition: Resources.cpp:35
void addConfiguration(const ShaderConfiguration &config)
Definition: Cage.cpp:3
Structure passed to each system before they fill the task queue.
Definition: FrameInfo.hpp:8
Scalar m_dt
Time elapsed since the last frame in seconds.
Definition: FrameInfo.hpp:13