Cogs.Core
Context.cpp
1#include "Context.h"
2
3#include "MemoryContext.h"
4#include "ViewContext.h"
5
6#include "Types.h"
7
8#include "ExtensionRegistry.h"
9#include "Engine.h"
10#include "EntityStore.h"
11
12#include "Scene.h"
13
14#include "Renderer/CullingManager.h"
15#include "Renderer/RenderResources.h"
16#include "Renderer/RenderTexture.h"
17#include "Renderer/Renderer.h"
18
19#include "Scene/RayPick.h"
20#include "Scene/GetBounds.h"
21
22#include "Services/PipelineService.h"
23#include "Services/QualityService.h"
24#include "Services/Services.h"
25#include "Services/DPIService.h"
26#include "Services/Features.h"
27#include "Services/Variables.h"
28#include "Services/TaskManager.h"
29#include "Services/Time.h"
30#include "Services/Random.h"
31#include "Services/DeferredNameResolution.h"
32#include "Services/ResourceUsageLogger.h"
33
34#include "Scripting/ScriptingManager.h"
35
36#include "Components/Data/TrajectoryComponent.h"
37#include "Components/Data/DataSetComponent.h"
38#include "Components/Geometry/MarkerPointSetComponent.h"
39
40#include "Generators/MeshGenerator.h"
41#include "Generators/TextureGenerator.h"
42
43#include "Input/InputManager.h"
44
45#include "Systems/Core/DynamicComponentSystem.h"
46#include "Systems/Core/InstancedModelSystem.h"
47#include "Systems/Core/LightSystem.h"
48#include "Systems/Core/ModelSystem.h"
49
50#include "Systems/Data/TrajectorySystem.h"
51
52#include "Systems/Geometry/ExtrusionSystem.h"
53#include "Systems/Geometry/ShapeSystem.h"
54#include "Systems/Geometry/VariableExtrusionSystem.h"
55#include "Systems/Geometry/MarkerPointSetSystem.h"
56#include "Systems/Geometry/MeshGeneratorSystem.h"
57#include "Systems/Geometry/AdaptivePlanarGridSystem.h"
58
59#include "Systems/Appearance/MaterialSystem.h"
60#include "Systems/Appearance/TextureGeneratorSystem.h"
61#include "Systems/Appearance/BasicOceanSystem.h"
62#include "Systems/Appearance/ScreenSizeSystem.h"
63
64#include "Systems/Geometry/InstancedMeshBuilderSystem.h"
65
66#include "Systems/Layout/TrajectoryLayoutSystem.h"
67
68#include "Resources/MaterialManager.h"
69#include "Resources/ModelManager.h"
70#include "Resources/ResourceStore.h"
71#include "Resources/Texture.h"
72#include "Resources/TextureManager.h"
73
74#include "ResourceManifest.h"
75
76#include "Serialization/AssetReader.h"
77
78#include "Rendering/Factory.h"
79#include "Rendering/ISwapChain.h"
80
81#include "Foundation/Logging/Logger.h"
82#include "Foundation/Platform/FileSystemWatcher.h"
83#include "Foundation/Platform/WindowData.h"
84
85namespace
86{
88
95 void onRedrawRequested(void* userData)
96 {
97 static_cast<Cogs::Core::Context*>(userData)->engine->triggerUpdate();
98 }
99}
100
101namespace Cogs
102{
103 namespace Core
104 {
107 {
108 public:
109 std::unordered_map<Reflection::TypeId, ComponentSystemBase *> systems;
110 };
111 }
112}
113
114Cogs::Core::Context::Context() : Context(nullptr, 0) {
115}
116
117Cogs::Core::Context::Context(const char ** variableValues, int count) :
118 memory(std::make_unique<MemoryContext>()),
119 services(std::make_unique<Services>(this)),
120 features(std::make_unique<Features>()),
121 variables(std::make_unique<Variables>(variableValues, count)),
122 resourceUsageLogger(std::make_unique<ResourceUsageLogger>(this)),
123 taskManager(std::make_unique<TaskManager>(this)),
124 random(std::make_unique<Random>(this)),
125 scriptingManager(std::make_unique<ScriptingManager>(this)),
126 cullingManager(std::make_unique<CullingManager>(this)),
127 time(std::make_unique<Time>(this)),
128 qualityService(std::make_unique<QualityService>(this)),
129 deferredResolution(std::make_unique<DeferredNameResolution>(this)),
130 resourceStore(std::make_unique<ResourceStore>(this)),
131 rayPicking(std::make_unique<RayPicking>()),
132 bounds(std::make_unique<Bounds>()),
133 extensionSystems(std::make_unique<ExtensionSystems>()),
134 engine(std::make_unique<Engine>(this)),
135 scene(std::make_unique<Scene>(this)),
136 renderer(new Renderer(this)) // NOTE change all dynamic_cast<Cogs::Core::Renderer> if changing.
137{
138 LOG_TRACE(logger, "Created context.");
139
140 if (variables->exist("filesystemwatcher")) {
141 LOG_DEBUG(logger, "Enabling filesystemwatcher for auto-reload");
142 watcher = std::make_unique<FileSystemWatcher>();
143 }
144
145 store = new EntityStore(this);
146
147 if (variables->exist("nowindow") && !variables->exist("renderer.graphicsDevice")) {
148 variables->set("renderer.graphicsDevice", "Null");
149 }
150 else if (variables->exist("nowindow")) {
151 LOG_DEBUG(logger, "renderer.graphicsDevice is already set. Ignoring nowindow.");
152 }
153
154 // Load configuration variables as early as possible.
155#ifndef __EMSCRIPTEN__
156 // this is done in Engine for Cogs.js since on the web we need to download config file from web before we can initialize variables
157 resourceStore->addResourceArchive(variables->get("resources.zipPath", "Cogs.Resources.zip"));
158 variables->initialize(*resourceStore);
159#endif
160
161 dynamicComponentSystem = Memory::create<DynamicComponentSystem>(memory->baseAllocator);
162}
163
165{
166 // Relese services that cache engine resources.
167 if (auto textureGenerator = services->getService<TextureGenerator>()) {
168 textureGenerator->cleanup();
169 }
170 if (auto meshGenerator = services->getService<MeshGenerator>()) {
171 meshGenerator->cleanup();
172 }
173
174 for (ViewContext* viewContext : views) {
175 delete viewContext;
176 }
177 views.clear();
178 defaultView = nullptr;
179
180 scriptingManager->cleanup();
181
182 // Make sure all tasks are finished before proceeding. Otherwise a task
183 // might try to update the engine's dirty status after it's been deleted.
184 taskManager->waitAll();
185
186 if (device) {
187 // Unregister the redraw-request callback before the engine is destroyed, since the device (or its
188 // async worker threads) could otherwise invoke it and dereference a stale engine pointer.
189 GraphicsDeviceSettings deviceSettings = device->getSettings();
190 deviceSettings.redrawRequestCallback = nullptr;
191 deviceSettings.redrawRequestCallbackUserData = nullptr;
192 device->setSettings(deviceSettings);
193 }
194
195 renderer->cleanup();
196 store->clear();
197
198 scene.reset();
199 engine.reset();
200 services->clear();
201
202 delete store;
203 delete renderer;
204
205 if (device) {
206
208 }
209
210 LOG_DEBUG(logger, "Destroyed context.");
211}
212
214{
215 // Avoid double initialization.
216 static bool initialized = false;
217
218 if (initialized) {
219 LOG_WARNING(logger, "Context already statically initialized.");
220
221 return;
222 }
223
224 LOG_DEBUG(logger, "COGS_VERSION_STRING %s", COGS_VERSION_STRING);
225 LOG_DEBUG(logger, "COGS_GIT_REVISION %s", COGS_XQUOTE(COGS_GIT_REVISION));
226
227 initialized = true;
228
229 srand(42);
230
231 initializeTypes();
232
234
235 LOG_DEBUG(logger, "Initialized types for reflection.");
236}
237
239{
240 // Avoid double cleanup.
241 static bool cleaned = false;
242
243 if (cleaned) {
244 LOG_WARNING(logger, "Context already statically cleaned.");
245
246 return;
247 }
248
249 Cogs::Core::cleanupTypes();
250 Cogs::Core::Strings::cleanup();
251}
252
253bool Cogs::Core::Context::createDevice()
254{
255 Cogs::RenderingAllocatorInfo allocatorInfo = { memory->baseAllocator, memory->resourceAllocator };
256 auto deviceType = parseEnum<GraphicsDeviceType>(variables->get("renderer.graphicsDevice", "Default"), GraphicsDeviceType::Default);
257
258 device = Cogs::Factory::createDevice(deviceType, &allocatorInfo);
259
260 if (!device && deviceType != GraphicsDeviceType::Default) {
261 LOG_WARNING(logger, "Device could not be created using the given type id: %d", static_cast<int>(deviceType));
262 LOG_DEBUG(logger, "Trying to create default device.");
263
264 // If no device could be created using the provided type, try to fall back to creating a default device.
266
267 if (device) {
268 LOG_DEBUG(logger, "Successfully created fallback device of type %s", device->getIdentifier().c_str());
269 }
270 }
271 else if (device) {
272 LOG_DEBUG(logger, "Initialized device of type %s", device->getIdentifier().c_str());
273 }
274
275 if (!device) {
276 LOG_ERROR(logger, "Could not create graphics device. Destroying context.");
277 return false;
278 }
279
280 GraphicsDeviceSettings settings = {};
281 settings.windowData = getDefaultView()->refWindowData();
282 settings.redrawRequestCallback = &onRedrawRequested;
283 settings.redrawRequestCallbackUserData = this;
284
285 if (device->getType() == GraphicsDeviceType::OpenGL20) {
286 // We request a feature level roughly matching what we can run all our features on. This is currently only
287 // relevant when using the OpenGL20 device, and is ignored by other types of devices.
288 settings.featureLevelMajor = 4;
289 settings.featureLevelMinor = 6;
290 }
291
292 settings.numSamples = variables->get("renderer.samples", 2);
293
294 int fakeAsyncEffectLoadFrames = variables->get("renderer.fakeAsyncEffectLoadFrames", 0);
295 if (fakeAsyncEffectLoadFrames > 0) {
296 LOG_DEBUG(logger, "renderer.fakeAsyncEffectLoadFrames set to %d, effects will simulate async loading.", fakeAsyncEffectLoadFrames);
297 settings.fakeAsyncEffectLoadFrames = static_cast<uint32_t>(fakeAsyncEffectLoadFrames);
298 }
299
300 if (variables->get("cache.enableShaderCache", false)) {
302 }
303
304 if (variables->get("effects.dumpShaders", false)) {
306 }
307
308 if (variables->get("renderer.forceSoftwareRendering", false)) {
310 }
311
312 if (variables->get("renderer.sharedSurface", false)) {
314 }
315
316 if (variables->get("renderer.debugDevice", false)) {
317 settings.flags |= GraphicsDeviceFlags::Debug;
318 }
319
320 if (variables->get("renderer.useSwapEffectDiscard", false)) {
322 }
323
324 if (!variables->get("renderer.disableClipControl", false)) {
326 }
327
328 settings.colorFormat = parseTextureFormat(variables->get("renderer.colorFormat", "R8G8B8A8_UNORM_SRGB"), TextureFormat::R8G8B8A8_UNORM_SRGB);
329 settings.depthFormat = parseTextureFormat(variables->get("renderer.depthFormat", "D32_FLOAT"), TextureFormat::D32_FLOAT);
330 settings.ioHandler = resourceStore->getIOHandler();
331 settings.sharedSurface = &sharedSurface; // Provide storage for shared surface pointer.
332
333 return device->setSettings(settings);
334}
335
337 scriptingManager->initialize();
338
339 services->registerService<PipelineService>(this);
340 services->registerService<MeshGenerator>(this);
341 services->registerService<TextureGenerator>(this);
342
343 readAsset(this, variables->get("store.entityDefinitions", "Default.entities"), AssetLoadFlags::NoDefault);
344
345 engine->registerSystem<ComponentSystem<DataSetComponent>>(SystemPriority::PreTransform, nullptr, 128);
346
347 LOG_TRACE(logger, "Initialized static systems.");
348
349 trajectorySystem = engine->registerSystem<TrajectorySystem>(SystemPriority::PreTransform, nullptr, 128);
350 modelSystem = engine->registerSystem<ModelSystem>(SystemPriority::PreTransform, nullptr, 1024);
351 instancedModelSystem = engine->registerSystem<InstancedModelSystem>(SystemPriority::PreTransform, nullptr, 128);
352 engine->registerSystem<ShapeSystem>(SystemPriority::PreTransform, nullptr, 1024);
353
354 engine->registerSystem<ExtrusionSystem>(SystemPriority::Geometry, nullptr, 128);
355 engine->registerSystem<VariableExtrusionSystem>(SystemPriority::Geometry, nullptr, 128);
356 engine->registerSystem<TextureGeneratorSystem>(SystemPriority::Geometry, nullptr, 128);
357 engine->registerSystem<MarkerPointSetSystem>(SystemPriority::Geometry, nullptr, 128);
358 engine->registerSystem<MeshGeneratorSystem>(SystemPriority::Geometry, nullptr, 128);
359
360 materialSystem = engine->registerSystem<MaterialSystem>(SystemPriority::PreRendering, nullptr, 1024);
361
362 engine->registerSystem<TrajectoryLayoutSystem>(SystemPriority::PostTransform, nullptr, 32);
363 adaptivePlanarGridSystem = engine->registerSystem<AdaptivePlanarGridSystem>(SystemPriority::PreTransform, nullptr, 32);
364 basicOceanSystem = engine->registerSystem<BasicOceanSystem>(SystemPriority::PostView, nullptr, 32);
365
366 engine->registerSystem<ScreenSizeSystem>(SystemPriority::PreLightView, nullptr, 32);
367
368 engine->registerSystem<InstancedMeshBuilderSystem>(SystemPriority::PreRendering, nullptr, 32);
369
370 initializeDynamicComponents();
371
372 materialManager->initializeDefaultMaterial();
373 materialInstanceManager->initializeDefaultMaterialInstance();
374
375 LOG_TRACE(logger, "Initializing extensions...");
376
378
379 LOG_TRACE(logger, "Extensions initialized.");
380
381 if (defaultView) {
382 // The camera will be set in scene->setup(), after the mainCamera is created.
383 defaultView->initialize(nullptr);
384 }
385
386 scene->setup(true);
387}
388
390{
391 scene->clear();
392 transformSystem->setOrigin({ 0, 0, 0 });
393 engine->setDirty();
394}
395
397{
398 registerDynamicComponentType("CurvedEarthPositionComponent");
399 registerDynamicComponentType("FontSelectorComponent");
400 registerDynamicComponentType("TrajectoryAlignedComponent");
401 registerDynamicComponentType("ReflectionComponent");
402 registerDynamicComponentType("BasicTerrainComponent");
403 registerDynamicComponentType("NearLimitComponent");
404 registerDynamicComponentType("ExpressionComponent");
405 registerDynamicComponentType("FPSNavigationComponent");
406 registerDynamicComponentType("TeleportNavigationComponent");
407 registerDynamicComponentType("PickingBeamComponent");
408 registerDynamicComponentType("MotionComponent");
409 registerDynamicComponentType("SwitchComponent");
410 registerDynamicComponentType("OrbitingCameraController");
411}
412
414{
415 auto & type = Reflection::TypeDatabase::getType(typeName);
416
417 if (!type.isValid()) {
418 LOG_ERROR(logger, "Cannot register %.*s as dynamic component. Did you forget to register the type?", StringViewFormat(typeName));
419
420 return;
421 }
422
423 auto base = type.getBase();
424 while (base && base != &Reflection::TypeDatabase::getType<DynamicComponent>()) {
425 base = base->getBase();
426 }
427
428 if (!base) {
429 LOG_ERROR(logger, "Cannot register %.*s as dynamic component without inheriting from DynamicComponent base class.", StringViewFormat(typeName));
430
431 assert(false && "Invalid dynamic component base class.");
432 }
433
434 dynamicComponentSystem->registerType(this, type);
435}
436
438{
439 extensionSystems->systems[id] = system;
440
441 // The engine will run initialization of registered systems when it initializes. If the extension is
442 // registered after the engine has run, we must initialize it.
443 if (engine && engine->isReady()) {
444 system->initialize(this);
445 }
446}
447
449{
450 return extensionSystems->systems[id];
451}
452
453void Cogs::Core::Context::update() {
454 // Update time before everything else.
455 time->update();
456 taskManager->updateState(this);
457
458 // Notify all a new frame is in progress.
459 services->dispatchFrameCallbacks();
460
461 for (ViewContext* view : views) {
462 view->update();
463 }
464}
465
466void Cogs::Core::Context::preRender() {
467 for (auto & c : cameraSystem->pool) {
469 cullingManager->dispatchCulling(&cameraSystem->getData(&c));
470 }
471 }
472 lightSystem->preRender(this);
473
474 if (callbacks.preRenderCallback) {
475 callbacks.preRenderCallback(this);
476 }
477 for (ViewContext* view : views) {
478 view->preRender();
479 }
480}
481
482Cogs::Core::ViewContext* Cogs::Core::Context::createView(WindowData* windowData) {
483 ViewContext* viewContext = new ViewContext(this, windowData);
484
485 views.push_back(viewContext);
486 return viewContext;
487}
488
489void Cogs::Core::Context::deleteView(ViewContext* view) {
490 auto e = views.end();
491 auto i = std::find(views.begin(), e, view);
492
493 if (i != e) {
494 views.erase(i);
495 delete view;
496 }
497}
Utility class for bounds calculation of Scene / Entity.
Definition: GetBounds.h:46
Base class for component systems.
virtual void initialize(Context *context)
Initialize the system.
Typed component system managing a pool of components with the given ComponentType.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
static void cleanupStatic()
Perform static cleanup of the Context.
Definition: Context.cpp:238
class ComponentSystemBase * getExtensionSystem(const uint16_t id)
Retrieve the system with the given id.
Definition: Context.cpp:448
void initializeDynamicComponents()
Initialize and register dynamic component types.
Definition: Context.cpp:396
void initialize()
Initialize all services and component systems.
Definition: Context.cpp:336
static void initializeStatic()
Perform static initialization of the Context.
Definition: Context.cpp:213
void clear()
Does clearing of context.
Definition: Context.cpp:389
void registerDynamicComponentType(const StringView &typeName)
Register a dynamic component type with the given typeName.
Definition: Context.cpp:413
class EntityStore * store
Entity store.
Definition: Context.h:231
std::unique_ptr< struct MemoryContext > memory
Memory and allocation info.
Definition: Context.h:171
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
Context(const char **variables, int count)
Constructs a new context instance, initializing all services, an engine instance, and extension syste...
Definition: Context.cpp:117
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
Definition: Context.h:210
void registerExtensionSystem(const uint16_t id, class ComponentSystemBase *system)
Register an extension component system using the given id.
Definition: Context.cpp:437
~Context() override
Destructs a context instance.
Definition: Context.cpp:164
std::unique_ptr< FileSystemWatcher > watcher
File system watcher.
Definition: Context.h:207
The engine owns all the systems and resource managers, and is responsible for executing different sta...
Definition: Engine.h:88
Stores top level entities for the engine.
Definition: EntityStore.h:50
static void initialize(Context *context)
Performs initialization of all extensions registered with add().
static void initializeStatic()
Performs static initialization of all extensions registered with add().
Contains extension systems accessible by key.
Definition: Context.cpp:107
Updates material components.
Core renderer system.
Definition: Renderer.h:29
Provides handling of reading and caching of external resources.
Service registry.
Definition: Services.h:32
Manages Task queuing and execution.
Definition: TaskManager.h:61
Provides time services for components depending on elapsed or system time for animation or other trac...
Definition: Time.h:16
Manages runtime variables for the engine.
Definition: Variables.h:103
Log implementation class.
Definition: LogManager.h:140
static const Type & getType()
Get the Type of the given template argument.
Definition: TypeDatabase.h:168
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:50
@ EnableRender
Renderable.
@ NoDefault
Don't load the default scene. Highly recommended as not setting this flag cause extra scene parse.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ Default
Default type of graphics device, same as unknown.
@ OpenGL20
Graphics device using OpenGL, supporting at least OpenGL 2.0.
@ ForceSoftwareRendering
Force software rendering.
@ DumpShaderContents
Dump shader contents for debugging.
@ EnableShaderCache
Enables using a shader cache to avoid recompiling previously seen shaders.
@ UseOpenGLClipControl
For OpenGL / OpenGLES backends.
@ Debug
If available, the device will operate in debug mode, performing additional validation of input data,...
@ UseSwapEffectDiscard
Under DX11 the default swap effect is FLIP_DISCARD, however there are some systems where this does no...
@ UseSharedSurface
Use shared surface for D3D9 interop.
STL namespace.
@ PreTransform
Run before transformations are updated.
Definition: Engine.h:50
@ PreRendering
Run before rendering is performed.
Definition: Engine.h:74
@ PostView
Run after view data has been updated. Anything after this is appropriate for geometry depending on e....
Definition: Engine.h:66
@ Geometry
Run at the time geometry data is updated.
Definition: Engine.h:70
@ PreLightView
Run after view, but before the time light views are updated.
Definition: Engine.h:60
@ PostTransform
Run immediately after transformations are updated.
Definition: Engine.h:54
static void releaseDevice(class IGraphicsDevice *device)
Release the given graphics device, freeing all associated resources.
Definition: Factory.cpp:147
static class IGraphicsDevice * createDevice(RenderingAllocatorInfo *allocatorInfo=nullptr)
Creates a graphics device.
Definition: Factory.cpp:46
Settings for graphics device initialization.
Allocation information.
Definition: Base.h:35
Memory::Allocator * baseAllocator
Base allocator. Used for misc. internal memory allocations.
Definition: Base.h:37