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