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/Layout/TrajectoryLayoutSystem.h"
65
66#include "Resources/MaterialManager.h"
67#include "Resources/ModelManager.h"
68#include "Resources/ResourceStore.h"
69#include "Resources/Texture.h"
70#include "Resources/TextureManager.h"
71
72#include "ResourceManifest.h"
73
74#include "Serialization/AssetReader.h"
75
76#include "../Extensions/Components/FollowComponent.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}
89
90namespace Cogs
91{
92 namespace Core
93 {
96 {
97 public:
98 std::unordered_map<Reflection::TypeId, ComponentSystemBase *> systems;
99 };
100 }
101}
102
103Cogs::Core::Context::Context() : Context(nullptr, 0) {
104}
105
106Cogs::Core::Context::Context(const char ** variableValues, int count) :
107 memory(std::make_unique<MemoryContext>()),
108 services(std::make_unique<Services>(this)),
109 features(std::make_unique<Features>()),
110 variables(std::make_unique<Variables>(variableValues, count)),
111 resourceUsageLogger(std::make_unique<ResourceUsageLogger>(this)),
112 taskManager(std::make_unique<TaskManager>(this)),
113 random(std::make_unique<Random>(this)),
114 scriptingManager(std::make_unique<ScriptingManager>(this)),
115 cullingManager(std::make_unique<CullingManager>(this)),
116 time(std::make_unique<Time>(this)),
117 qualityService(std::make_unique<QualityService>(this)),
118 deferredResolution(std::make_unique<DeferredNameResolution>(this)),
119 resourceStore(std::make_unique<ResourceStore>(this)),
120 rayPicking(std::make_unique<RayPicking>()),
121 bounds(std::make_unique<Bounds>()),
122 extensionSystems(std::make_unique<ExtensionSystems>()),
123 engine(std::make_unique<Engine>(this)),
124 scene(std::make_unique<Scene>(this)),
125 renderer(new Renderer(this)) // NOTE change all dynamic_cast<Cogs::Core::Renderer> if changing.
126{
127 LOG_TRACE(logger, "Created context.");
128
129 if (variables->exist("filesystemwatcher")) {
130 LOG_INFO(logger, "Enabling filesystemwatcher for auto-reload");
131 watcher = std::make_unique<FileSystemWatcher>();
132 }
133
134 store = new EntityStore(this);
135
136 if (variables->exist("nowindow") && !variables->exist("renderer.graphicsDevice")) {
137 variables->set("renderer.graphicsDevice", "Null");
138 }
139 else if (variables->exist("nowindow")) {
140 LOG_INFO(logger, "renderer.graphicsDevice is already set. Ignoring nowindow.");
141 }
142
143 // Load configuration variables as early as possible.
144#ifndef EMSCRIPTEN
145 // 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
146 resourceStore->addResourceArchive(variables->get("resources.zipPath", "Cogs.Resources.zip"));
147 variables->initialize(*resourceStore);
148#endif
149
150 dynamicComponentSystem = Memory::create<DynamicComponentSystem>(memory->baseAllocator);
151}
152
154{
155 // Relese services that cache engine resources.
156 if (auto textureGenerator = services->getService<TextureGenerator>()) {
157 textureGenerator->cleanup();
158 }
159 if (auto meshGenerator = services->getService<MeshGenerator>()) {
160 meshGenerator->cleanup();
161 }
162
163 for (ViewContext* viewContext : views) {
164 delete viewContext;
165 }
166 views.clear();
167 defaultView = nullptr;
168
169 scriptingManager->cleanup();
170
171 // Make sure all tasks are finished before proceeding. Otherwise a task
172 // might try to update the engine's dirty status after it's been deleted.
173 taskManager->waitAll();
174
175 renderer->cleanup();
176 store->clear();
177
178 scene.reset();
179 engine.reset();
180 services->clear();
181
182 delete store;
183 delete renderer;
184
185 if (device) {
186
188 }
189
190 LOG_DEBUG(logger, "Destroyed context.");
191}
192
194{
195 // Avoid double initialization.
196 static bool initialized = false;
197
198 if (initialized) {
199 LOG_WARNING(logger, "Context already statically initialized.");
200
201 return;
202 }
203
204 LOG_INFO(logger, "COGS_VERSION_STRING %s", COGS_VERSION_STRING);
205 LOG_INFO(logger, "COGS_GIT_REVISION %s", COGS_XQUOTE(COGS_GIT_REVISION));
206
207 initialized = true;
208
209 srand(42);
210
211 initializeTypes();
212
214
215 LOG_DEBUG(logger, "Initialized types for reflection.");
216}
217
219{
220 // Avoid double cleanup.
221 static bool cleaned = false;
222
223 if (cleaned) {
224 LOG_WARNING(logger, "Context already statically cleaned.");
225
226 return;
227 }
228
229 Cogs::Core::cleanupTypes();
230 Cogs::Core::Strings::cleanup();
231}
232
233bool Cogs::Core::Context::createDevice()
234{
235 Cogs::RenderingAllocatorInfo allocatorInfo = { memory->baseAllocator, memory->resourceAllocator };
236 auto deviceType = parseEnum<GraphicsDeviceType>(variables->get("renderer.graphicsDevice", "Default"), GraphicsDeviceType::Default);
237
238 device = Cogs::Factory::createDevice(deviceType, &allocatorInfo);
239
240 if (!device && deviceType != GraphicsDeviceType::Default) {
241 LOG_WARNING(logger, "Device could not be created using the given type id: %d", static_cast<int>(deviceType));
242 LOG_INFO(logger, "Trying to create default device.");
243
244 // If no device could be created using the provided type, try to fall back to creating a default device.
246
247 if (device) {
248 LOG_INFO(logger, "Successfully created fallback device of type %s", device->getIdentifier().c_str());
249 }
250 }
251 else if (device) {
252 LOG_INFO(logger, "Initialized device of type %s", device->getIdentifier().c_str());
253 }
254
255 if (!device) {
256 LOG_ERROR(logger, "Could not create graphics device. Destroying context.");
257 return false;
258 }
259
260 GraphicsDeviceSettings settings = {};
261 settings.windowData = getDefaultView()->refWindowData();
262
263 if (device->getType() == GraphicsDeviceType::OpenGL20) {
264 // We request a feature level roughly matching what we can run all our features on. This is currently only
265 // relevant when using the OpenGL20 device, and is ignored by other types of devices.
266 settings.featureLevelMajor = 4;
267 settings.featureLevelMinor = 6;
268 }
269
270 settings.numSamples = variables->get("renderer.samples", 2);
271
272 if (variables->get("cache.enableShaderCache", false)) {
274 }
275
276 if (variables->get("effects.dumpShaders", false)) {
278 }
279
280 if (variables->get("renderer.forceSoftwareRendering", false)) {
282 }
283
284 if (variables->get("renderer.sharedSurface", false)) {
286 }
287
288 if (variables->get("renderer.debugDevice", false)) {
289 settings.flags |= GraphicsDeviceFlags::Debug;
290 }
291
292 if (variables->get("renderer.useSwapEffectDiscard", false)) {
294 }
295
296 if (!variables->get("renderer.disableClipControl", false)) {
298 }
299
300 settings.colorFormat = parseTextureFormat(variables->get("renderer.colorFormat", "R8G8B8A8_UNORM_SRGB"), TextureFormat::R8G8B8A8_UNORM_SRGB);
301 settings.depthFormat = parseTextureFormat(variables->get("renderer.depthFormat", "D32_FLOAT"), TextureFormat::D32_FLOAT);
302 settings.ioHandler = resourceStore->getIOHandler();
303 settings.sharedSurface = &sharedSurface; // Provide storage for shared surface pointer.
304
305 return device->setSettings(settings);
306}
307
309 scriptingManager->initialize();
310
311 services->registerService<PipelineService>(this);
312 services->registerService<MeshGenerator>(this);
313 services->registerService<TextureGenerator>(this);
314
315 readAsset(this, variables->get("store.entityDefinitions", "Default.entities"), AssetLoadFlags::NoDefault);
316
317 engine->registerSystem<ComponentSystem<DataSetComponent>>(SystemPriority::PreTransform, nullptr, 128);
318
319 LOG_TRACE(logger, "Initialized static systems.");
320
321 trajectorySystem = engine->registerSystem<TrajectorySystem>(SystemPriority::PreTransform, nullptr, 128);
322 modelSystem = engine->registerSystem<ModelSystem>(SystemPriority::PreTransform, nullptr, 1024);
323 instancedModelSystem = engine->registerSystem<InstancedModelSystem>(SystemPriority::PreTransform, nullptr, 128);
324 engine->registerSystem<ShapeSystem>(SystemPriority::PreTransform, nullptr, 1024);
325
326 engine->registerSystem<ExtrusionSystem>(SystemPriority::Geometry, nullptr, 128);
327 engine->registerSystem<VariableExtrusionSystem>(SystemPriority::Geometry, nullptr, 128);
328 engine->registerSystem<TextureGeneratorSystem>(SystemPriority::Geometry, nullptr, 128);
329 engine->registerSystem<MarkerPointSetSystem>(SystemPriority::Geometry, nullptr, 128);
330 engine->registerSystem<MeshGeneratorSystem>(SystemPriority::Geometry, nullptr, 128);
331
332 materialSystem = engine->registerSystem<MaterialSystem>(SystemPriority::PreRendering, nullptr, 1024);
333
334 engine->registerSystem<TrajectoryLayoutSystem>(SystemPriority::PostTransform, nullptr, 32);
335 adaptivePlanarGridSystem = engine->registerSystem<AdaptivePlanarGridSystem>(SystemPriority::PreTransform, nullptr, 32);
336 basicOceanSystem = engine->registerSystem<BasicOceanSystem>(SystemPriority::PostView, nullptr, 32);
337
338 engine->registerSystem<ScreenSizeSystem>(SystemPriority::PreLightView, nullptr, 32);
339
340 initializeDynamicComponents();
341
342 materialManager->initializeDefaultMaterial();
343 materialInstanceManager->initializeDefaultMaterialInstance();
344
345 LOG_TRACE(logger, "Initializing extensions...");
346
348
349 LOG_TRACE(logger, "Extensions initialized.");
350
351 if (defaultView) {
352 // The camera will be set in scene->setup(), after the mainCamera is created.
353 defaultView->initialize(nullptr);
354 }
355
356 scene->setup(true);
357}
358
360{
361 scene->clear();
362 transformSystem->setOrigin({ 0, 0, 0 });
363 engine->setDirty();
364}
365
367{
368 registerDynamicComponentType("CurvedEarthPositionComponent");
369 registerDynamicComponentType("FollowComponent");
370 registerDynamicComponentType("FontSelectorComponent");
371 registerDynamicComponentType("TrajectoryAlignedComponent");
372 registerDynamicComponentType("ReflectionComponent");
373 registerDynamicComponentType("BasicTerrainComponent");
374 registerDynamicComponentType("NearLimitComponent");
375 registerDynamicComponentType("ExpressionComponent");
376 registerDynamicComponentType("FPSNavigationComponent");
377 registerDynamicComponentType("TeleportNavigationComponent");
378 registerDynamicComponentType("PickingBeamComponent");
379 registerDynamicComponentType("MotionComponent");
380 registerDynamicComponentType("SwitchComponent");
381 registerDynamicComponentType("OrbitingCameraController");
382}
383
385{
386 auto & type = Reflection::TypeDatabase::getType(typeName);
387
388 if (!type.isValid()) {
389 LOG_ERROR(logger, "Cannot register %.*s as dynamic component. Did you forget to register the type?", StringViewFormat(typeName));
390
391 return;
392 }
393
394 auto base = type.getBase();
395 while (base && base != &Reflection::TypeDatabase::getType<DynamicComponent>()) {
396 base = base->getBase();
397 }
398
399 if (!base) {
400 LOG_ERROR(logger, "Cannot register %.*s as dynamic component without inheriting from DynamicComponent base class.", StringViewFormat(typeName));
401
402 assert(false && "Invalid dynamic component base class.");
403 }
404
405 dynamicComponentSystem->registerType(this, type);
406}
407
409{
410 extensionSystems->systems[id] = system;
411
412 // The engine will run initialization of registered systems when it initializes. If the extension is
413 // registered after the engine has run, we must initialize it.
414 if (engine && engine->isReady()) {
415 system->initialize(this);
416 }
417}
418
420{
421 return extensionSystems->systems[id];
422}
423
424void Cogs::Core::Context::update() {
425 // Update time before everything else.
426 time->update();
427 taskManager->updateState(this);
428
429 // Notify all a new frame is in progress.
430 services->dispatchFrameCallbacks();
431
432 for (ViewContext* view : views) {
433 view->update();
434 }
435}
436
437void Cogs::Core::Context::preRender() {
438 for (auto & c : cameraSystem->pool) {
440 cullingManager->dispatchCulling(&cameraSystem->getData(&c));
441 }
442 }
443 lightSystem->preRender(this);
444
445 if (callbacks.preRenderCallback) {
446 callbacks.preRenderCallback(this);
447 }
448 for (ViewContext* view : views) {
449 view->preRender();
450 }
451}
452
453Cogs::Core::ViewContext* Cogs::Core::Context::createView(WindowData* windowData) {
454 ViewContext* viewContext = new ViewContext(this, windowData);
455
456 views.push_back(viewContext);
457 return viewContext;
458}
459
460void Cogs::Core::Context::deleteView(ViewContext* view) {
461 auto e = views.end();
462 auto i = std::find(views.begin(), e, view);
463
464 if (i != e) {
465 views.erase(i);
466 delete view;
467 }
468}
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.
static void cleanupStatic()
Perform static cleanup of the Context.
Definition: Context.cpp:218
class ComponentSystemBase * getExtensionSystem(const uint16_t id)
Retrieve the system with the given id.
Definition: Context.cpp:419
void initializeDynamicComponents()
Initialize and register dynamic component types.
Definition: Context.cpp:366
void initialize()
Initialize all services and component systems.
Definition: Context.cpp:308
static void initializeStatic()
Perform static initialization of the Context.
Definition: Context.cpp:193
void clear()
Does clearing of context.
Definition: Context.cpp:359
void registerDynamicComponentType(const StringView &typeName)
Register a dynamic component type with the given typeName.
Definition: Context.cpp:384
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:106
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:408
~Context() override
Destructs a context instance.
Definition: Context.cpp:153
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:96
Updates material components.
Core renderer system.
Definition: Renderer.h:28
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:24
@ 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
Allocation information.
Definition: Base.h:35
Memory::Allocator * baseAllocator
Base allocator. Used for misc. internal memory allocations.
Definition: Base.h:37