diff --git a/src/gfx_func.h b/src/gfx_func.h --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -180,5 +180,8 @@ extern DrawPixelInfo *_cur_dpi; extern byte _colour_gradient[COLOUR_END][8]; extern PaletteType _use_palette; +extern bool _palette_remap_grf[]; +extern const byte *_palette_remap; +extern const byte *_palette_reverse_remap; #endif /* GFX_FUNC_H */ diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -23,9 +23,17 @@ #include "ini_type.h" #include "table/sprites.h" +#include "table/palette_convert.h" /** The currently used palette */ PaletteType _use_palette = PAL_AUTODETECT; +/** Whether the given NewGRFs must get a palette remap or not. */ +bool _palette_remap_grf[MAX_FILE_SLOTS]; +/** Palette map to go from the !_use_palette to the _use_palette */ +const byte *_palette_remap = NULL; +/** Palette map to go from the _use_palette to the !_use_palette */ +const byte *_palette_reverse_remap = NULL; + char _ini_graphics_set[32]; /** Structure holding filename and MD5 information about a single file */ @@ -176,7 +184,9 @@ static bool DetermineGraphicsPack() const GraphicsSet *best = _available_graphics_sets; for (const GraphicsSet *c = _available_graphics_sets; c != NULL; c = c->next) { if (best->found_grfs < c->found_grfs || - (best->found_grfs == c->found_grfs && best->shortname == c->shortname && best->version < c->version)) { + (best->found_grfs == c->found_grfs && ( + (best->shortname == c->shortname && best->version < c->version) || + (best->palette != _use_palette && c->palette == _use_palette)))) { best = c; } } @@ -193,9 +203,22 @@ static bool DetermineGraphicsPack() static void DeterminePalette() { assert(_used_graphics_set != NULL); - if (_use_palette < MAX_PAL) return; + if (_use_palette >= MAX_PAL) _use_palette = _used_graphics_set->palette; + + switch (_use_palette) { + case PAL_DOS: + _palette_remap = _palmap_w2d; + _palette_reverse_remap = _palmap_d2w; + break; - _use_palette = _used_graphics_set->palette; + case PAL_WINDOWS: + _palette_remap = _palmap_d2w; + _palette_reverse_remap = _palmap_w2d; + break; + + default: + NOT_REACHED(); + } } /** @@ -207,6 +230,8 @@ void CheckExternalFiles() { DeterminePalette(); + DEBUG(grf, 1, "Using the %s base graphics set with the %s palette", _used_graphics_set->name, _use_palette == PAL_DOS ? "DOS" : "Windows"); + static const size_t ERROR_MESSAGE_LENGTH = 128; char error_msg[ERROR_MESSAGE_LENGTH * (MAX_GFT + 1)]; error_msg[0] = '\0'; @@ -233,8 +258,10 @@ void CheckExternalFiles() static void LoadSpriteTables() { + memset(_palette_remap_grf, 0, sizeof(_palette_remap_grf)); uint i = FIRST_GRF_SLOT; + _palette_remap_grf[i] = (_use_palette != _used_graphics_set->palette); LoadGrfFile(_used_graphics_set->files[GFT_BASE].filename, 0, i++); /* @@ -243,6 +270,7 @@ static void LoadSpriteTables() * has a few sprites less. However, we do not care about those missing * sprites as they are not shown anyway (logos in intro game). */ + _palette_remap_grf[i] = (_use_palette != _used_graphics_set->palette); LoadGrfFile(_used_graphics_set->files[GFT_LOGOS].filename, 4793, i++); /* @@ -251,6 +279,7 @@ static void LoadSpriteTables() * and the ground sprites. */ if (_settings_game.game_creation.landscape != LT_TEMPERATE) { + _palette_remap_grf[i] = (_use_palette != _used_graphics_set->palette); LoadGrfIndexed( _used_graphics_set->files[GFT_ARCTIC + _settings_game.game_creation.landscape - 1].filename, _landscape_spriteindexes[_settings_game.game_creation.landscape - 1], @@ -274,6 +303,7 @@ static void LoadSpriteTables() master->next = top; _grfconfig = master; + _palette_remap_grf[i] = (_use_palette != _used_graphics_set->palette); LoadNewGRF(SPR_NEWGRFS_BASE, i); /* Free and remove the top element. */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -3652,7 +3652,11 @@ bool GetGlobalVariable(byte param, uint3 } case 0x0D: // TTD Version, 00=DOS, 01=Windows - *value = _use_palette; + if (_palette_remap_grf[_file_index]) { + *value = !_use_palette; + } else { + *value = _use_palette; + } return true; case 0x0E: // Y-offset for train sprites diff --git a/src/spritecache.cpp b/src/spritecache.cpp --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -11,6 +11,7 @@ #include "spriteloader/grf.hpp" #include "core/alloc_func.hpp" #include "core/math_func.hpp" +#include "gfx_func.h" #ifdef WITH_PNG #include "spriteloader/png.hpp" #endif /* WITH_PNG */ @@ -188,11 +189,30 @@ static void* ReadSprite(SpriteCache *sc, return (void*)GetRawSprite(SPR_IMG_QUERY, ST_NORMAL); } - byte *dest = (byte *)AllocSprite(num); + /* "Normal" recolour sprites are ALWAYS 257 bytes. Then there is a small + * number of recolour sprites that are 17 bytes that only exist in DOS + * GRFs which are the same as 257 byte recolour sprites, but with the last + * 240 bytes zeroed. */ + static const int RECOLOUR_SPRITE_SIZE = 257; + byte *dest = (byte *)AllocSprite(max(RECOLOUR_SPRITE_SIZE, num)); sc->ptr = dest; sc->type = sprite_type; - FioReadBlock(dest, num); + + if (_palette_remap_grf[sc->file_slot]) { + byte *dest_tmp = AllocaM(byte, max(RECOLOUR_SPRITE_SIZE, num)); + + /* Only a few recolour sprites are less than 257 bytes */ + if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE); + FioReadBlock(dest_tmp, num); + + /* The data of index 0 is never used; "literal 00" according to the (New)GRF specs. */ + for (int i = 1; i < RECOLOUR_SPRITE_SIZE; i++) { + dest[i] = _palette_remap[dest_tmp[_palette_reverse_remap[i - 1] + 1]]; + } + } else { + FioReadBlock(dest, num); + } return sc->ptr; } diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp --- a/src/spriteloader/grf.cpp +++ b/src/spriteloader/grf.cpp @@ -83,7 +83,7 @@ bool SpriteLoaderGrf::LoadSprite(SpriteL data = &sprite->data[y * sprite->width + skip]; for (int x = 0; x < length; x++) { - data->m = *dest; + data->m = ((sprite_type == ST_NORMAL && _palette_remap_grf[file_slot]) ? _palette_remap[*dest] : *dest); dest++; data++; } @@ -91,8 +91,10 @@ bool SpriteLoaderGrf::LoadSprite(SpriteL } } else { dest = dest_orig; - for (int i = 0; i < sprite->width * sprite->height; i++) - sprite->data[i].m = dest[i]; + + for (int i = 0; i < sprite->width * sprite->height; i++) { + sprite->data[i].m = ((sprite_type == ST_NORMAL && _palette_remap_grf[file_slot]) ? _palette_remap[dest[i]] : dest[i]); + } } /* Make sure to mark all transparent pixels transparent on the alpha channel too */ diff --git a/src/table/palette_convert.h b/src/table/palette_convert.h new file mode 100644 --- /dev/null +++ b/src/table/palette_convert.h @@ -0,0 +1,75 @@ +/* $Id$ */ + +/** @file palette_convert.h Translation tables from one GRF to another GRF. */ + +/** Converting from the Windows palette to the DOS palette */ +static const byte _palmap_w2d[] = { + 0, 1, 2, 3, 4, 5, 6, 7, // 0..7 + 8, 9, 10, 11, 12, 13, 14, 15, // 8..15 + 16, 17, 18, 19, 20, 21, 22, 23, // 16..23 + 24, 25, 26, 27, 28, 29, 30, 31, // 24..31 + 6, 7, 34, 35, 36, 37, 38, 39, // 32..39 + 8, 41, 42, 43, 44, 45, 46, 47, // 40..47 + 48, 49, 50, 51, 52, 53, 54, 55, // 48..55 + 56, 57, 58, 59, 60, 61, 62, 63, // 56..63 + 64, 65, 66, 67, 68, 69, 70, 71, // 64..71 + 72, 73, 74, 75, 76, 77, 78, 79, // 72..79 + 80, 81, 82, 83, 84, 85, 86, 87, // 80..87 + 4, 89, 90, 91, 92, 93, 94, 95, // 88..95 + 96, 97, 98, 99, 100, 101, 102, 103, // 96..103 + 104, 105, 5, 107, 108, 109, 110, 111, // 104..111 + 112, 113, 114, 115, 116, 117, 118, 119, // 112..119 + 120, 121, 122, 123, 124, 125, 126, 127, // 120..127 + 128, 129, 130, 131, 132, 133, 134, 135, // 128..135 + 3, 137, 138, 139, 140, 141, 142, 143, // 136..143 + 144, 145, 146, 147, 148, 149, 150, 151, // 144..151 + 152, 153, 154, 155, 156, 157, 158, 159, // 152..159 + 160, 161, 162, 163, 164, 165, 166, 167, // 160..167 + 168, 169, 170, 171, 172, 173, 174, 175, // 168..175 + 176, 177, 178, 179, 180, 181, 182, 183, // 176..183 + 184, 185, 186, 187, 188, 189, 190, 191, // 184..191 + 192, 193, 194, 195, 196, 197, 198, 199, // 192..199 + 200, 201, 202, 203, 204, 205, 206, 207, // 200..207 + 208, 209, 210, 211, 212, 213, 214, 1, // 208..215 + 2, 245, 246, 247, 248, 249, 250, 251, // 216..223 + 252, 253, 254, 229, 230, 231, 227, 228, // 224..231 + 235, 236, 237, 238, 232, 233, 234, 239, // 232..239 + 240, 241, 242, 244, 243, 9, 218, 219, // 240..247 + 220, 221, 222, 223, 224, 225, 226, 255, // 248..255 +}; + +/** Converting from the DOS palette to the Windows palette */ +static const byte _palmap_d2w[] = { + 0, 215, 216, 136, 88, 106, 32, 33, // 0..7 + 40, 245, 10, 11, 12, 13, 14, 15, // 8..15 + 16, 17, 18, 19, 20, 21, 22, 23, // 16..23 + 24, 25, 26, 27, 28, 29, 30, 31, // 24..31 + 53, 54, 34, 35, 36, 37, 38, 39, // 32..39 + 178, 41, 42, 43, 44, 45, 46, 47, // 40..47 + 48, 49, 50, 51, 52, 53, 54, 55, // 48..55 + 56, 57, 58, 59, 60, 61, 62, 63, // 56..63 + 64, 65, 66, 67, 68, 69, 70, 71, // 64..71 + 72, 73, 74, 75, 76, 77, 78, 79, // 72..79 + 80, 81, 82, 83, 84, 85, 86, 87, // 80..87 + 96, 89, 90, 91, 92, 93, 94, 95, // 88..95 + 96, 97, 98, 99, 100, 101, 102, 103, // 96..103 + 104, 105, 53, 107, 108, 109, 110, 111, // 104..111 + 112, 113, 114, 115, 116, 117, 118, 119, // 112..119 + 120, 121, 122, 123, 124, 125, 126, 127, // 120..127 + 128, 129, 130, 131, 132, 133, 134, 135, // 128..135 + 170, 137, 138, 139, 140, 141, 142, 143, // 136..143 + 144, 145, 146, 147, 148, 149, 150, 151, // 144..151 + 152, 153, 154, 155, 156, 157, 158, 159, // 152..159 + 160, 161, 162, 163, 164, 165, 166, 167, // 160..167 + 168, 169, 170, 171, 172, 173, 174, 175, // 168..175 + 176, 177, 178, 179, 180, 181, 182, 183, // 176..183 + 184, 185, 186, 187, 188, 189, 190, 191, // 184..191 + 192, 193, 194, 195, 196, 197, 198, 199, // 192..199 + 200, 201, 202, 203, 204, 205, 206, 207, // 200..207 + 208, 209, 210, 211, 212, 213, 214, 215, // 208..215 + 216, 217, 246, 247, 248, 249, 250, 251, // 216..223 + 252, 253, 254, 227, 228, 229, 230, 231, // 224..231 + 232, 233, 234, 235, 236, 237, 238, 239, // 232..239 + 240, 241, 242, 243, 244, 217, 218, 219, // 240..247 + 220, 221, 222, 223, 224, 225, 226, 255, // 248..255 +};