Day/night cycle
The engine now supports a day/night cycle, tied into the new game clock. The primary effect of the day/night cycle is to alter the colour of the screen. Secondary effects (such as offering different missions or ped/car spawns) are possible, but currently must be implemented manually in mission scripts.
Recolouring method
The file daynight.c manages the day/night cycle, tracking what the current in-game time and date is, along with the different colours to use during the different periods of the day. It provides an interface to recolour a 256 entry palette to match the current time of day; palettes are the way in which all day-night cycle recolouring is performed.
Peds, cars, objects and tiles are now all stored in 8bit format, with 256 colour palettes. As each is needed for rendering, it has a new, recoloured, palette generated, and in the correct colour swapping state. This palette is then used to build a 16bit sprite, which is cached until the game discards it or the time of day changes. Fullbright colours are supported as part of the day/night cycle - the first N entries of the input palette does not have colour translation performed (where N is one of the parameters passed to daynight_recolour()), so by placing fullbright colours at the start of the palette the desired effect can be achieved. For details of how the N value is obtained for each ped/car/object/tile, see the doc for each type.
For each defined 'time index' in the day, 6 values are kept and used to guide the recolouring process. These are the red, green and blue offsets, and the red, green and blue multipliers. The output colour of each recoloured palette entry is equal to the offset components plus the multiplier components multiplied by the components of the source colour. Range checks on each component are also performed.
Stippling
The tile recolouring code support stippling; i.e. only recolouring half of a tile's pixels. By enabling the daynight_stipple variable, auto-gradient time index generation will generate twice as many entries: One with the stipple flag set, one with it clear. This means that initially only half the tile's pixels will be updated, followed soon after by a rebuild of the entire image (just in case the original tile was wrong somehow). Stippling of an individual cached tile is automatically disabled if the cached tile is older than one time index or is a new cache entry.
There are some downsides to stippling however:
- It causes tile sprites to be rebuilt twice as often, which may result in slowdown on some computers. But for this reason it has been designed as an option that can be disabled at runtime.
- The stippling does sometimes produce visible artifacts, especially due to the fact the tiles are drawn at a variety of scales. But for this reason, tiles are only stippled for short periods of time before being rebuilt entirely.
- Because the time index updates but the colour values don't, ped and car sprites are needlessly rebuilt. This will add to the amount of slowdown. One way around this, however, would be to implement stippling for peds and cars - a goal that is trickier but not impossible.
Improvement ideas
Speed optimisation - although current code seems to work fine on an Iyonix, slower machines may appreciate throttling of tile/car sprite generation. A maximum number of tiles/car sprites to rebuild per frame can be set; if this number has been exceeded, sprites which are changing because of the day/night cycle will be delayed until the next frame.
TODO:
CODE: MED: timeofday specific animation frames? Could be tricky tieing it down to time values without also tieing it down to a specific day-night cycle arrangement, though.
DOCS: UNKNOWN: Work out better way of deciding whether tile paint sprite is masked than examining the paint sprite to see if it has a mask channel (since the mask channel won't actually be used for anything, as the sprite should be using palette entry 0 for mask)
CODE: MED: Migrate ddconvert palette generation code into util.c, and update util_loadspr256 to convert 16bpp/24bpp sprites down to 8bpp. Main function (accessible from ddconvert) just needs to take a histogram as input write N palette entries as output.
DOCS: UNKOWN: Extend day/night cycle code to support other fullscreen recolouring effects, such as fade in/out, green(?) vision for radiation, etc. Or, since heavily irradiated areas will be rather large, just implement it as part of the day/night cycle? Mission script code can easily reset the colours on-the-fly, without any real performance impact.
???
Profit!