# Color Utils The game's colour model. Colours are not stored as RGB but as a 16 bit hue, saturation and luminance index into a palette built once at startup - see {ref}`TColorUtils.PackHSL` and {ref}`TColorUtils.CreateHSVPalette`. The global `ColorUtils` holds those palettes. There is one palette, and everything draws through it - the map renderer and the sprite rasterizer both read `ColorUtils.Palette` rather than carrying one of their own. Its entries are already in the order the `PColorBGRA` buffer `TImage.FromData` reads, with the alpha byte full, so neither has to convert a pixel on the way out. It is built by {ref}`TColorUtils.Setup` at whatever brightness you ask for and stays put; {ref}`TColorUtils.SetBrightness` rebuilds it if you want a different look. - - - ## ColorUtils.PackHSL ```pascal function TColorUtils.PackHSL(hue, saturation, luminance: Integer): Integer; static; ``` Packs a colour into the 16 bit index the game's palettes are addressed by: 6 bits of hue, 3 of saturation and 7 of luminance. Saturation is halved at each of four luminance thresholds on the way up, because a colour that bright cannot carry much saturation without looking wrong - the same taper the client applies. - - - ## ColorUtils.CreateHSVPalette ```pascal function TColorUtils.CreateHSVPalette(brightness: Double; mn, mx: Integer): TIntegerArray; static; ``` Builds the 65536 entry palette that a {ref}`TColorUtils.PackHSL` index looks up. Every index is unpacked back into hue, saturation and luminance, converted to RGB, and then bent by `brightness` - a gamma exponent, where a lower number means a brighter image. The client offers a few fixed brightness settings, which are the `BRIGHTNESS_` constants. Entries are alpha, red, green and blue from the top byte down, which is what the `PColorBGRA` buffer `TImage.FromData` reads - not a `TColor`, which has red and blue the other way round. `mn` and `mx` bound which entries are actually computed; the rest are left at `0`. - - - ## ColorUtils.SetBrightness ```pascal procedure TColorUtils.SetBrightness(brightness: Double); ``` Rebuilds both palettes at a new brightness. Everything that draws - the map renderer and the sprite rasterizer alike - reads them, so this changes the whole library's colours at once. `Palette` is the plain lookup a packed HSL index goes through. `MinimapPalette` is that same lookup with the flatter minimap lighting already folded into it, so that {ref}`TColorUtils.UnderlayColor` and {ref}`TColorUtils.OverlayColor` are a single array read rather than a rescale and a clamp per tile. Both are in the order {ref}`TColorUtils.CreateHSVPalette` produces - alpha, red, green, blue - which is what the `PColorBGRA` buffer `TImage.FromData` reads, so whatever is drawn through them is handed to an image as it is. Rebuilding costs around 25ms, nearly all of it the brightness curve, so this is meant for setting a look up front rather than for switching back and forth. Setting the brightness it already has does nothing. Work already derived from the old palette is thrown away rather than left to go stale, but not from here - `ColorUtils` is defined long before anything that draws and there may be more than one map renderer. Instead `Revision` counts the changes, and {ref}`TMapChunkLoader.EnsureColorsCurrent` compares it against the revision its caches were built at and rebuilds them when they no longer match. - - - ## ColorUtils.UnderlayColor ```pascal function TColorUtils.UnderlayColor(hsl: Integer): Integer; ``` The colour a ground underlay is drawn as on the minimap. The minimap is lit flatter than the world is, so the luminance in the index is scaled towards a fixed level before the palette is looked up. That rescale is already baked into `MinimapPalette` by {ref}`TColorUtils.Setup`, which leaves this a plain lookup. An `hsl` of `-1` means the tile has no underlay. - - - ## ColorUtils.OverlayColor ```pascal function TColorUtils.OverlayColor(hsl: Integer): Integer; ``` {ref}`TColorUtils.UnderlayColor` for an overlay, which additionally distinguishes an overlay that is deliberately blank, `-2`, from one that is drawn at the flat minimap luminance, `-1`. - - - ## ColorUtils.Height2Color ```pascal function TColorUtils.Height2Color(height: Integer): Integer; static; ``` A terrain height as a shade of grey, black at ground level and white at the highest terrain the game uses. Heights are negative upwards, which is why the sign is flipped. - - - ## ColorUtils.SetupHeightColors ```pascal procedure TColorUtils.SetupHeightColors(); ``` Fills `HeightColors` with {ref}`TColorUtils.Height2Color` for every height from ground level, index `0`, up to `MAX_HEIGHT`. A height is negative upwards, so height `h` is at index `-h`. Everything past either end is the same colour as that end, so a lookup only has to clamp the index rather than redo the division and rounding for every tile. - - - ## ColorUtils.Collision2Color ```pascal function TColorUtils.Collision2Color(flag: Integer): Integer; static; ``` A collision flag as a colour: white for walkable, black for blocked, grey for a tile an object stands on.