Radium Engine  1.5.20
Loading...
Searching...
No Matches
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>
27
28#include <iostream>
29#include <string>
30
31#include <glbinding-aux/ContextInfo.h>
32#include <glbinding/Version.h>
33
34namespace Ra {
35namespace Engine {
36
37using namespace Core::Utils; // log
38using namespace Core::Asset;
39
40RadiumEngine::RadiumEngine() = default;
41
42RadiumEngine::~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
81glbinding::Version RadiumEngine::getOpenGLVersion() const {
82 return m_glVersion;
83}
84
85void 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
168void 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
183bool 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
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
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
233bool 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
281Rendering::RenderObjectManager* RadiumEngine::getRenderObjectManager() const {
282 return m_renderObjectManager.get();
283}
284
285Scene::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
302 m_fileLoaders.push_back( fileLoader );
303}
304
308
309RA_SINGLETON_IMPLEMENTATION( RadiumEngine );
310
311const 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
316RadiumEngine::SystemContainer::const_iterator
317RadiumEngine::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
323RadiumEngine::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
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
365void 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
377bool 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
383void 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
397void RadiumEngine::setTime( Scalar t ) {
398 m_timeData.m_time = t;
399}
400
402 m_timeData.m_startTime = std::max( t, 0_ra );
403}
404
406 return m_timeData.m_startTime;
407}
408
409void RadiumEngine::setEndTime( Scalar t ) {
410 m_timeData.m_endTime = t;
411}
412
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
423Scalar 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
431void 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
478 return m_gpuTaskQueue->registerTask( std::move( task ) );
479}
480
482 m_gpuTaskQueue->removeTask( taskId );
483}
484
485} // namespace Engine
486} // namespace Ra
T cbegin(T... args)
T c_str(T... args)
T ceil(T... args)
This class allows tasks to be registered and then executed in parallel on separate threads.
Definition TaskQueue.hpp:48
Utils::Index TaskId
Identifier for a task in the task queue.
Definition TaskQueue.hpp:51
static void unregisterMaterial()
Remove the material from the material library.
static void registerMaterial()
Register the material in the material library.
static void setOpenGLVersion(const glbinding::Version &version)
set the OpenGL version to use in the generated header for shaders.
Manage Texture loading and registration.
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 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
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
T data(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T find_if(T... args)
T fmod(T... args)
T get(T... args)
T make_pair(T... args)
T max(T... args)
T move(T... args)
optional< std::string > getRadiumResourcesPath()
Get the path of Radium internal resources.
Definition Resources.cpp:35
void addConfiguration(const ShaderConfiguration &config)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T pop(T... args)
T push_back(T... args)
T reset(T... args)
Structure passed to each system before they fill the task queue.
Definition FrameInfo.hpp:8
T top(T... args)