Recently I noticed that there would be another release of the DF after all.
Also, it so happened, FDw Taffer contacted me some time ago about work that have been done on DF graphics.
All of the above makes me to post a reedited take on the the problem (it's in ReST format):
The Tile Reuse Problem And Proposed Solution.
=============================================
The problem:
------------
- Dwarf Fortress interface is by design limited to 256 characters of 16 colors (cp437 / "ascii" + "ansi" colors).
- Dwarf Fortress has orders of magnitude more information than can be unambigously expressed by that.
- Relaxing this limitation is a lot of work, while there isn't even an understanding what that is to achieve.
- Graphics code is old, rotten and Toady undestandably has no desire to touch it. Even if the code was in perfect
condition, it is not his area of interest or expertise.
- Graphics code can not be updated for Windows releases without making yet another full release of the game.
Coupled with above this means that the graphics code just continues to rot.
Thus the problem is split in two parts:
---------------------------------------
- Graphics code is old, unmaintainable and too tightly coupled with the rest of the game code.
- Graphics code can not express most of the information available (since it gets the tiles, items, parts of interface
already mapped to cp437 and baked into a single layer).
The solution also cames in two parts:
-------------------------------------
- An easy to understand and work with, maintainable graphics subsystem, where Toady isn't required to understand
or mess with its internals, while third parties can maintain it without any access to the core game code.
- An extensible, easy modded graphics subsystem that can express most, if not all, of the information
available without Toady having to put any work into besides a modest initial investment.
Which also fully supports anything up from and including the original cp437 interface.
The first part
--------------
of the solution is pluggable renderer bound to the core game only by a strict and stable API+ABI.
Feasibility of that was demostrated in the `rendumper project <https://github.com/lxnt/rendumper>`__
The second part
---------------
of the solution was prototyped in the `fgtestbed project <https://github.com/lxnt/fgtestbed>`__
As the latter attempt has shown, graphics mods require quite a lot of information from the core game.
Designing a stable interface that is still capable of exposing enough in-game information is the current focus.
Such interface has not been prototyped because initial fgtestbed work focused on using df-structures/dfhack code,
which provides direct access to the internal game structures. Alas, this is quite complicated and unusable for
extended periods of time after each major release because changes in the data structures have to be reverse-engineered.
The existing interface
----------------------
as implemented in the rendumper prototype receives three layers of information for the entire game
screen each frame. Those are:
- Basic cp437 rendering of the interface,
- Creature overlay, which holds creature "texture" indices,
- If enabled, a truetype overlay, which is a list of text strings and their screen coordinates, to be TTF-rendered on top of everything else.
The renderer knows which creature texture indices correspond to what graphics because creature graphics loading is also done
via renderer-side code (as opposed to game-side).
As you can see, core game code converts tile types and materials, as set in the raw files, into cp437 characters and ANSI color codes
before submitting all that to the renderer. This is where the tile reuse problem originates.
To get rid of it, the renderer is instead to be supplied with:
- Original tile type and material ids.
- A mapping from tile type and material ids into actual graphics to render
To this end, the fgtestbed prototype renderer first parses all the raw files the game has. Then it parses another set of raw files,
that describe the hardcoded mappings for stuff like constructed walls/floors ("constructions"), raw tiles (undigged walls), items and buildings.
Those files also include overrides, so that the hardcoded mappings become moddable.
This information lets it know how to render raw map data, which, generally speaking, consists of triplets of "tile_type, material_type, material_index",
plus information about water/magma levels, any construction, zone or building present in the tile (and their material),
dust/steam/cloud in the tile (and their material), any contaminants (and their material).
On top of that go items (and their material, hehe), and, finally, creatures. Oh, I forgot about projectiles. And game interface (selections,
burrows, cart routes I haven't even thought about.
Long story short,
-----------------
the solution of the tile reuse problem is to move the hardcoded mapping of all the stuff in the game from the core game code
to some kind of "raw" or resource files. And let the pluggable renderer parse and map them.
As any big project, this has to be done in many small steps.
============================================================
The first step
--------------
is to adopt the pluggable renderer architecture, as in the rendumper. This does not require any changes in the core game code.
The second step
---------------
would be to enable basic map modding. To this end:
- Another layer is to be added to the information already supplied to the renderer, that is - (tile_type, mat_type, mat_index).
Here tile_type is a "derived" tile type, that is, if a wall is constructed somewhere, then the tile_type is one of the wall,
not the underlying floor or ramp.
- Raw material information is to be exported from the game to the renderer in such a way that (mat_type, mat_index) tuple is
easily mapped to the information from the parsed raws. Keeping raws parsing for the graphics data in the renderer allows more
modding. If that's not acceptable (eg, worldgen-time generated materials begin to matter much), some interface to the core game
raws database becomes necessary.
Ideally, rendering info (cp437 codepoint, color) will be purged from the
item definition raws to some kind of rendering definition raws (as is done in the fgtestbed yaml raws) (which, ostensibly, can be inlined into the item raws, but clearly
separated and overridable)
The third step
--------------
- Yet another layer with item representations. It would suffice to do one item per tile, but again with item_type and material.
- The designation bitfield, whose definition would have to be fixed eternally. That would allow for nice presentation of liquid levels,
designations, etc.
The fourth step
---------------
tbd