Table of contents:
- Modules
- Design Patterns
- Game Loop
- Game Objects
- Resource Management
- Scripting
- Graphics
- 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 NcsReader
s into ScriptProgram
s and are executed by ScriptExecution
s.
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 Animation
s 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.