6dof core documentation

Author: Pim Goossens
Contact: irc://irc.freenode.net/6dof

Contents

Core

This section describes the "glue" that ties the various components together. The Lua environment has its own section further below.

Core project files

  • common.h includes all header files used and defines a couple of macros used throughout the project.
  • config.c and config.h define the functions for retrieving configuration values in C code.
  • config.lua sets up the configuration table and loads it with values from defaults.lua.
  • debug.h defines the debug macros.
  • defaults.lua defines options and their initial default values.
  • game.c and game.h define the core of the game world model and contain the main loop. (Currently the "model" is just the level with a camera flying through it - basic physics for the camera are also implemented here for now).
  • global.c and global.h define global variables and miscellaneous functions that are used throughout the code.
  • init.lua sets up the Lua environment and processes the commandline.
  • lua_funcs.c and lua_funcs.h define miscellaneous Lua functions written in C. Currently these are just the unpack function which acts in a way similar to Perl's function of the same name, and the binread function which combines this functionality with reading from a file handle. The latter is used extensively by the Descent and Forsaken level/model reader scripts.
  • main.c contains the game's entry point. See below.
  • scalar.h contains some macros for working with the scalar type. It provides scalar equivalents for math library functions such as sin, cos, and sqrt. These scalar versions use the s suffix, yielding function names like sins, coss, and sqrts.
  • types.h: declares commonly used types. These include the vector and quat (quaternion) types. They are defined here instead of in vector.h and quaternion.h since some operations may involve both of these types, so they have to be declared before any functions that involve both types.
  • util.lua contains miscellaneous functions written in Lua.

main and the initialization process

When main() is called, the first thing the game does is create the Lua environment and initialize it, then execute the init.lua script, which in turn runs config.lua to set up the configuration table, then loads the Lua utility functions in util.lua and vector.lua, and finally processes the commandline.

Controls goes back to C at which point the lua_funcs will be registered (this step may later be performed before running init.lua). The game then proceeds by initializing each subsystem (audio, graphics, input) and the game world code, and finally running bindings.lua to load the user's input configuration.

What happens at this point is subject to some major change as the game develops. Currently, a level is loaded as indicated by some configuration values and the main game loop is entered immediately.

Debug information

The game has two debugging parameters: channel mask and level. Channels separate different types of debug info and can be enabled or disabled in debugging output. The debug level specifies the detail of information that is printed.

debug.h defines a DEBUGX macro that the rest of the code can use to print debugging messages:

DEBUGX(type, level, format, ...)

where format and any remaining arguments are the same as for printf. Typically, a module will define a DEBUG macro for itself that calls DEBUGX with a default debug channel. For example:

#define DEBUG(level, x...) DEBUGX(DBG_AUDIO, level, x)
/* ... */
DEBUG(1, "Initializing audio subsystem\n");

There are 3 debug levels:

  • 1 - initialization and shutdown information; major changes in state such as starting a new game:

    DEBUG(1, "Initializing graphics subsystem\n");
    DEBUG(1, "Using SDL for graphics\n");
    DEBUG(1, "gfx_sdl: using video driver \"%s\"\n",
      SDL_VideoDriverName(drv_name, 64));
    DEBUG(1, "Found joystick %d: \"%s\"\n", i+1, SDL_JoystickName(i));
    
  • 2 - information about uncommon events and the actions triggered by them. As a guideline, take 'uncommon' here to mean 'not at least once every frame':

    DEBUG(2, "audio_null: load_sound(%s)\n", filename);
    (in Lua)  DEBUG(2, ('Header says %d verts, %d cubes'):
                format(nverts, ncubes))
    DEBUG(2, "audio_null: play_sound(%d, %d, %.3f, %#x)\n",
      soundno, volume, panning, flags);
    DEBUG(2, "Calling C function for input event %d\n", event.id);
    DEBUG(2, "Key press event, id == %d\n", event->id);
    
  • 3 - information about common events (triggered at least once every frame) and functions typically invoked in a loop:

    DEBUG(3, "%s:%d: reading %d bytes\n", __FILE__, __LINE__, n);
    DEBUG(3, "Processing input events\n");
    DEBUG(3, "gfx_sdl: render()\n");
    

Global configuration system

The game has a global table to store configuration values. Its purpose is to make certain parameters easily adjustable by the user, and easily accessible by the game's code (even its C code). Here's how it works and how to use it:

  • In the early stage of game initialization, a special Lua table called config is created and loaded with values from defaults.lua. This file contains initial (default) values for the options. At the same time, it determines what options exist; it is not possible to add new options after initialization.

  • Immediately after this, the game parses the commandline used to run it. Commandline options can be used to override the default values specified in defaults.lua. The game looks for arguments of the form --option=value, --no-option, and --option. The first form assigns a string or number value to an option. The second and third forms disable and enable a boolean (on/off) option, respectively.

  • From within the Lua environment, options can be accessed as config.optionname. For example:

    print(('The current screen mode is %dx%dx%d'):format(
      config.width, config.height, config.bpp
    ))
    
  • In C code, use the config_get_int, config_get_float, and config_get_str functions. config_get_int is also used for booleans. Example:

    printf("Current mouse sensitivity: x=%f, y=%f\n",
      config_get_float("mousesensx"), config_get_float("mousesensy")
    );
    printf("Joystick is %s\n",
      config_get_int("joystick") ? "enabled" : "disabled"
    );
    
  • Options can be changed from within the Lua environment, but there are no equivalent config_set_* functions in C. Currently, most (if not all) options are used only during initialization, so changing them afterwards has no effect. This may change if/when configuration events are introduced (see below).

That's pretty much all there is to it. To introduce a new option all you have to do is add it to defaults.lua, and you can start using it.

Later on, an event system may be introduced that can notify modules of changes in the configuration, so they can use local variables to hold parameters and don't have to repeatedly poll the config table.