56 Project Architecture
seedhartha edited this page 2021-04-06 13:06:14 +07:00

Table of contents:

  1. Modules
    1. Executables
    2. Libraries
  2. Design Patterns
  3. Game Loop
  4. Game Objects
  5. Resource Management
  6. Scripting
  7. Graphics
    1. Models
    2. Scene Management
  8. Threading Model

Modules

Source code is organized into multiple modules, each module being on a different abstraction level. As a rule of thumb, higher-level modules must only depend on their lower-level counterparts. Circular dependencies must be avoided.

Libraries

  • libgame contains the game logic
  • libscene contains the scene management subsystem
  • libgui contains the GUI subsystem
  • libscript contains the scripting subsystem
  • libvideo contains the video playback subsystem
  • librender contains the rendering subsystem
  • libaudio contains the audio subsystem
  • libresource contains the resource management subsystem
  • libcommon contains common utility classes and functions

Design Patterns

types.h files contain constants, enums and typedefs that do not belong to a particular class.

*util.(h|cpp) files contain utility functions and global variables that do not belong to a particular class.

Plurals denote classes that provide a particular type of entities, e.g. Resources, Models, or structs that are used to group related bit flags together.

File format handling is encapsulated in *Reader and *Writer classes.

Game Loop

Main game loop follows a typical "handle input, update, render" pattern. User input is handled exclusively during the handle phase, and game logic execution - during the update phase.

Game Objects

Game objects are entities that fill the game world. All game objects inherit from either the Object or the SpatialObject class. Spatial objects have position and orientation, and optionally have a scene node associated with them.

Game objects are instantiated from blueprints (aka templates).

Resource Management

Resource management is encapsulated in the Resources class. Internally it has a prioritized list of resource providers, that it queries for resources by ResRef and ResType.

Getter functions in Resources return either raw data or generic structures, such as TwoDA and GffStruct, that need to be processed by a higher level entity.

Scripting

NCS scripts are loaded by NcsReaders into ScriptPrograms and are executed by ScriptExecutions.

Scripts access the game logic through engine routines, which are defined per game in the Routines class. These routines mirror the functions found in nwscript.nss files.

Graphics

reone comes with a custom rendering engine based on SDL 2 and OpenGL 3.3. Rendering is shader-based and multi-pass.

Prior to rendering a particular model, a corresponding shader must be activated, together with a set of uniforms, that are used to parametrize shaders. Shaders are defined in the Shaders class.

Rendering passes are defined by *RenderPipeline classes.

Models

Models are loaded from MDL files and have a tree-like structure, where each node has an arbitrary number of children. ModelSceneNode and ModelNodeSceneNode mirror that structure - they are, in essence, instances of Model and ModelNode respectively. SceneNodeAnimator is responsible for applying Animations to the associated ModelSceneNode.

Scene Management

Draw order and dynamic lighting are handled using a scene graph. During area load, room and object models are added to the scene graph as root scene nodes. Then, every frame, meshes and lights are extracted from the root scene nodes - transparent meshes are sorted by their distance to the camera.

Threading Model

Currently, reone uses only two threads: one for the main game loop, and the other one for audio playback. AudioPlayer class is responsible for thread synchronization.

In the future, game logic execution should be delegated to the thread pool.