This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Callisto Game Engine

A desktop game engine written in Odin.

Callisto is a desktop game engine written in Odin with a Vulkan renderer. It is still early in development and the API is subject to change. When there is a stable release I will add documentation here.

At the moment, the notes here are to record decisions that I have made.

In the meantime, see the Callisto GitHub repository for a brief overview of how the engine is used, or Callisto-Sandbox for a sample implementation.

1 - Assets

Game data stored on the disk.

Assets are classified as either Primitive or Aggregate. Primitive assets MUST contain only information about themselves, while aggregate assets MAY contain references to other assets.

Planned primitives:

  • Image
  • Mesh
  • Audio
  • Input action map
  • Shader

Planned aggregates:

  • Material (shader + images)
  • Model (mesh + materials)
  • Construct (fixed-length transform hierarchy)
  • Level

File format

This section is a work in progress. I may end up implementing a custom format that requires very little processing to deserialize.

In the meantime, I’m using Concise Binary Object Representation (CBOR) for serialization, as it provides some desired attributes to the asset files:

  • Named fields to avoid data loss when struct definitions change
  • Small file size
  • Existing Odin core library

File loading

Inspiration from Timothy Cain’s video, Arcanum “dat” files, development builds use a raw OS file system, or “loose assets”, while release builds use packed bundles.

  • data locality on the disk
  • “seek” is much faster than “open”
  • avoid file descriptor limits
  • less overhead for many tiny assets (block alignment, OS file nodes)
  • easy patches/modding with sequential overriding of the asset database
  • more efficient compression

2 - Graphics

Details about the renderer, shaders, render passes etc.

2.1 - Coordinates for rendering

Transforming coordinates from world space to other spaces.

World coordinates

World coordinates are right-handed, +Z forward, +Y up, -X right.

Why?

  • Want right handed coords
  • glTF default, easy import
  • Y-up intuitive for gravity

Projection and Clip space

Vulkan’s NDC space is defined as [x: -1, y: -1] top-left, [x: 1, y: 1] bottom-right, and z depth in the range [0, 1].

Callisto uses a reversed-depth, infinite far plane perspective projection.

  • Better distribution of floating point precision
  • No far plane clipping artifacts

Because of the reversed depth, shaders must use Greater depth test (higher depth is closer).

To get from Callisto coords to Vulkan coords, the x and y axes must be flipped.

perspective :: proc(fovy, aspect, near: f32) -> (mat: Matrix4x4) {
    ep :: math.pow(2, -20)          // ep is a small value to prevent float rounding errors 
    g := 1 / math.tan(0.5 * fovy)
    
    // Column-major matrix
    //
    // -g/s     0       0       0
    //  0      -g       0       0
    //  0       0       ep      near * (1-ep) 
    //  0       0       1       0

    mat[0, 0] = -g / aspect
    mat[1, 1] = -g
    mat[2, 2] = ep
    mat[2, 3] = 1
    mat[3, 2] = near * (1 - ep)


    return mat
}