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