Next: Core algorithm, Previous: Architecture, Up: Hacker's guide [Contents][Index]
Liquid War 6 has a modular architecture which allows the programmer (and the player) to plug pretty much any rendering/graphics backend, provided this one is... developped.
As of 2009 the only available backend was mod-gl1
, it would
display the game using 3D acceleration, if available, through the
SDL library, using its GL bindings.
As of 2012, other backends are begin developped, the idea is that each backend can provide the user with enough visual feedback to play, and convey input informations to the core engine.
The rest of the game is exactly the same, this means playing with
mod-gl1
you can do exactly the same things than with mod-caca
.
Liquid War 6 has a modular architecture which allows the programmer (and the player) to plug pretty much any rendering/graphics backend, provided this one is... developped.
As of 2009 the only available backend is still mod-gl1
, it will
display the game using 3D acceleration, if available, through the
SDL library, using its GL bindings.
Additionnally, versions available for Microsoft Windows and Mac OS X will
probably never any other backends available. For technical reasons, those
platforms do not have the flexibility of GNU/Linux and do not allow
graphical libraries to be loaded dynamically. In practice, both of them
require hacks that override the standard main
function. Microsoft Windows
has its WinMain
instead, and Mac OS X is even more pedantic,
requiring graphical functions to be executed in the main thread.
So mod-gl1
is just linked statically in those versions, and
the modularity of the game is purely theorical on these platforms.
This mod-gl1
module is really one of the key stones of
Liquid War 6, and if you want to change graphical things, it’s definitely
the place to hack on. The source is in src/lib/gfx/mod-gl1
.
The mod-gl1
backend requires “moderate” hardware, but it
still does require hardware acceleration. Pure software rendering
through mesa for instance, won’t
be enough.
So if you’re running Xorg on GNU/Linux and there’s a DRI driver for your card, the game should run fine.
On the programmer side, the counterpart is that one should not rely
on fancy OpenGL features. Textures have a maximum size of 512x512
for instance. Of course some maps are bigger than this but this
means that internally, mod-gl1
splits them into smaller tiles,
and displays those tiles one by one.
Inside the mod-gl1
backend, the src/lib/gfx/mod-gl1/gl-utils
directory contains lots of common structures, factorized functions which
can (and should, if appliable) be used.
This is under development, the idea is to provide an alternative renderer based on OpenGL ES 2, which could be used on standard computers but also on mobile platforms.
Work in progress, don’t hold your breath.
This is under development, the idea is to provide a very basic rendered which can be compiled pretty much anywhere as long as SDL is available, since it does use software rendering only.
Work in progress, don’t hold your breath.
This is under heavy development, the idea is to provide a basic yet surprising alternative text-based renderer, using libcaca.
The starting point for any hack are the files src/lib/gfx/gfx.h
.
This is where the API is defined.
Basically, the type lw6gfx_backend_t
contains all the required
callbacks. You must provide an implementation for each function.
Let’s take an example, taken from mod-gl1
. When calling
lw6gfx_get_video_mode
and passing it a first argument which
is a valid mod-gl1
backend, the function
mod_gl1_utils_get_video_mode
will be called. How this is done
is a little C casting wizardry.
To understand how this works, read the files:
src/lib/gfx/gfx-api.c
: contains all the functions which
are part of the API and can be called elsewhere in the code.
src/lib/gfx/gfx-register.c
: contains the code that allows
a module to be loaded/unloaded at runtime. Will act differently
if the games is compile with the --allinone
flag, but
for the caller this is transparent, just create and destroy
backend, period.
src/lib/gfx/mod-gl1/mod-gl1-backend.c
: this is where the
module actually binds its internal functions with the callbacks
defined in the lw6gfx_backend_s
struct. None of these
internal functions should be called directly, code in
libdsp
for instance should only refer to the lw6gfx_...
bindings. Reading the code in src/lib/gfx/gfx-test.c
shows how these functions can be called, and in which order.
All the functions should be defined, but some of them are obviously more important. The two most critical functions are:
pump_events
This is used to process inputs. The function should update
a lw6gui_input_s
struct and return it to the caller.
How this done is really up to the backend, it happens that
all SDL based backends (mod-gl1
, mod-gles2
and mod-soft
)
share the same code for this, but another backend could
do this differently, there’s no real need to use SDL.
Only, the returned input should behave correctly when queried
with function from libgui
. As a consequence, one needs
to have a look at libgui
to understand how input works.
A look at src/lib/gfx/shared-sdl/shared-sdl-event.c
is a good example
of this, as this file contains the implementation for SDL-based input.
See libgfx reference. See libgui reference.
display
By far the most complicated function, this one is called
on each display loop to render the game. It’s always used in the
same thread, so need not be reentrant,
and on some platforms (eg Mac OS X) it will even be
called in the main thread (this can be of some importance regarding
some libraries such as SDL).
Still, beware, the game_state
object it uses can change
on the fly while rendering. In that case “changing” means that
fighters can move and gradients be updated but the global structure
won’t change. So any pointer on a fighter will still be valid after
it’s been obtained, but the renderer should not expect the game
to be static. In practice this is not really a problem. If you are
curious, you can look in libdsp
how and when this function
is called.
A very important parameter is mask
, depending on its value,
the backend should, or not, display the menu, or the map, or both, etc.
The reference for this are the LW6GUI_DISPLAY_...
constants
in src/lib/gui/gui.h
.
As a starting point, implementing menu display before anything else is probably the best bet, since without menus it’s hard to do anything within the game.
To test out a backend, one can either launch the full game using
the “under development” backend, or launch the test suite by
typing ./liquidwar6gfx-test 1
in ./src/lib/gfx
.
See libdsp reference.
Next: Core algorithm, Previous: Architecture, Up: Hacker's guide [Contents][Index]