NoesisEngine Architecture Layers
There are, at least, two possible ways to view the logical organization of NoesisSDK. One is as a set of modules where the packages belongs to. The other one is decomposing the organization in several usage layers. Both logical views are described in this section.
Modules
Modules are high-level categories used to classify the package network. To identify a package, the module it belongs to is used as part of the identifier. For example, the full qualified name for the VirtualFileSystem package is File/VirtualFileSystem. To simplify the organization, there is only one hierarchical level of modules. Each module is stored physically in a folder inside the packages directory. All the packages belonging to that module are stored inside that folder. See SDK for more information.
What follows is a brief description of the main modules that compose Noesis Engine.
Core
This is the module where low-level packages, in direct contact with the operating system are stored. The Kernel package is located in this module. This package is the main entry point for initializing the SDK. The Kernel controls the lifetime of the memory manager, logger and component factory. Kernel systems are managed by the Kernel. The reflection information of each component is stored inside the kernel. This information is accessible to other modules.
The Serialization package is implemented in this category too. This package offers the functionality to save and load component information to streams. The serialization format is used by all the modules that want to save or load information from a file, network, etc.
The Configsystem package offers configuration functionality to other systems. Inside the configsystem all kind of configuration properties can be stored (and they can be stored inside a file). The Commandsystem connects the configsystem with the console and offers the possibility to execute remotely commands and interacts with the configsystem.
The Tasksystem is used to decompose high level algorithms in small tasks that can be easily parallelized. This package is used to obtain the maximum benefit from all the hardware threads that can be found in the different architectures.
File
This is the module for file related packages. The different filesystems are implemented here. A filesystem offers an uniform access to a container of files. Examples of filesystem include the DiskFileSystem for files stored in the harddisk, ZipFileSystem for files stored inside a zip, etc.
The VirtualFileSystem package allows for hooking different filesystem inside a common namespace. It offers an abstraction to access the different filesystem in an uniform way. This way, a program can load files without knowing the exact location of each file. They could be stored in the disk, in the network, inside a zip.
Math
Packages related to math are stored here. The VectorMath package is located here. It offers implementation for vector, matrices, quaterions and related operations.
The Tessellation package implements different tessellation algorithms.
Import
All the data importers are located here. The ColladaMeshImporter imports geometries and materials from collada files. The ImageImporter imports typical image files like jpeg, tga, gif, png, dds, etc. ShaderImporter is able to import shader files to be used by the Render. SoundImporter reads sound file formats (wav, ogg).
The ImporterSystem offers an interface to import all kind of formats. It maintains a database of source files and imported files that can be used to easily regenerate any resource in the database.
GUI
Packages related to User Interface are classified under this module. Noesis GUI System is implemented here. The UISystem implements a XAML interpreter that is able to render widgets described in that language.
Drawing
The Image, a platform independent bitmap class, is implemented here with typical operations like conversion between different formats, resizing, cropping, rotation, etc. The VGL, a vector graphic library, is located inside this module. It offers an interface very similar to OpenVG and is implemented using the rendersystem. The FontRenderer, implements the font rasterizer using the VGL. The UISystem uses both he VGL and FontRenderer to draw the different GUI controls.
Render
Inside the render module you find all packages related to 3D Rendering. Implementations for each platform of the RenderSystem are located here. The DX9RenderSystem implements the RenderSystem using the DirectX v9.0 API.
Other packages related to the render driver are located here too. For example, the VCacheOptimizer offers an vertex cache optimizer that can be used to improve the render efficiency ofvertex buffers.
Audio
The audio driver is implemented here. The AudioSystem package offers the public platform independent interface for the driver. OALAudioSystem implements a driver using the OpenAL API.
Scene
Scene packages are related to high level rendering and algorithms like culling, kd-tree, light calculations, shadow mapping, etc.
Input
Packages related to input devices are located under this module. The InputSystem offers functionality to read from keyboard, mouse and joysticks. Physical inputs can be mapped to virtual inputs allowing the application to read input that can be easily redefined using the configsystem.
Logic
In the Logic module, packages associated to the logic part of an application or game can be found. The Entity package implements the entity layer. The entity layer is an abstraction very useful to describe how an application interacts. Each entity is composed of several components that interacts using messages. Entity components allows for easily reusing functionality among different entities.
Layers
NoesisSDK is structured in layers with each layer based in the previous one. From low-level to high-level we find the Kernel Layer, the System Layer and the Application Layer. What follows is a description of each one.
Kernel Layer
The kernel layer is defined in the Core/Kernel package as a singleton. Before using any other part of the SDK, the kernel must be properly initialized. Core/Kernel is the unique package that is a mandatory dependency for the rest of the packages. A minimal Noesis distribution is the Core/Kernel package (and its dependencies, like the Core/Parser and Core/UnitTestSystem for example)
// Minimal example of Noesis Initialization
NS_TRY
{
IKernel* kernel = NsGetKernel();
kernel->Init();
// Kernel initialized
NS_INFO(NST("Inside Noesis!"));
// ...
kernel->Shutdown();
}
NS_CATCH
{
NS_SHOW_ERRORDIALOG;
NS_CLEAR_CRITICALFLAG;
}
The kernel implements the core functionality of the engine through kernel modules. The kernel Init() function initializes each kernel module in the appropiate order and kernel Shutdown() destroy them in reverse order.
The kernel is designed to be:
- Monolithic: Packages are not available in this layer, so kernel modules forming part of the Kernel are statically determined.
- Minimalist: Due to previous point, kernel should be as small as possible. All the functionality that could be implemented in the System Layer must be done at that level.
Kernel System Layer
A Kernel System is a normal component implementing the IKernelSystem interface. As a normal component, the organization of Kernel System in packages is totally arbitrary. This is the layer where most of the reusable work should be implemented and it is the better way to expand the kernel functionality.
KernelSystems are described in more depth in the KernelSystem section of the core documentation.
Examples of Kernel System are: ConfigSystem, CommandSystem, RemoteCommandSystem, RenderSystem, UnitTestSystem
Before initializing any system, components should be registered:
kernel->RegisterDirectory(NST("AppDllDirectory"));
After that, Kernel Systems are explicitly initialized using system class identifier:
kernel->AddSystem(NSS("ConfigSystem"));
kernel->AddSystem(NSS("CommandSystem"));
kernel->AddSystem(NSS("RemoteCommandSystem"));
Initialized Kernel Systems can be accessed from the kernel like singleton:
Ptr<IConfigSystem> configSystem = kernel->GetSystem(NSS("ConfigSystem"));
Ptr<ICommandSystem> commandSystem = kernel->GetSystem(NSS("CommandSystem"));
A user identifier could be assigned to any system instance, and use it instead of class identifier:
kernel->AddSystem(NSS("DX9RenderSystem"), NSS("RenderSystem"));
Ptr<IRenderSystem> renderSystem = kernel->GetSystem(NSS("RenderSystem"));
Kernel Systems are uninitialized (when calling Kernel::Shutdown()) in the reverse order of initialization.
Application Layer
Applications are derived from specific platform dependant classes implemented in the GUI/Application package. For example, a Windows application must inherit from Gui::WindowsApplication.