diff options
author | tron <tron@openttd.org> | 2005-08-15 11:39:13 +0000 |
---|---|---|
committer | tron <tron@openttd.org> | 2005-08-15 11:39:13 +0000 |
commit | 52c859cbe8f64cfe452b39d029701c4aa485b919 (patch) | |
tree | a9af328126a18cca6a3ee91e6890c036f97fd7f3 | |
parent | d057d8b366795e4fe82e6f63d985d35e6e363f64 (diff) | |
download | openttd-52c859cbe8f64cfe452b39d029701c4aa485b919.tar.xz |
(svn r2868) Change the way NewGRFs are loaded: The loading process i no longer bolted onto the normal graphics loading.
This has two major advantages:
- Removal of a maze of global variables and distinction of cases from the sprite loading routines, which weren't directly related to the loading process in the first place
- NewGRF actions no longer occupy sprite slots - for example when using DBSetXL this saves about 2000 slots! (you could regard this as a bug fix)
If i didn't make a major mistake this change should have no negative effect on NewGRF support, please test!
-rw-r--r-- | gfxinit.c | 114 | ||||
-rw-r--r-- | newgrf.c | 312 | ||||
-rw-r--r-- | newgrf.h | 3 | ||||
-rw-r--r-- | spritecache.c | 66 |
4 files changed, 199 insertions, 296 deletions
@@ -14,23 +14,6 @@ #include "variables.h" #include <ctype.h> -#define SPRITE_CACHE_SIZE 1024*1024 - -#define WANT_NEW_LRU - - -/* These are used in newgrf.c: */ - -int _skip_sprites = 0; // XXX -int _replace_sprites_count[16]; // XXX -int _replace_sprites_offset[16]; // XXX - -const char* _cur_grffile; // XXX -int _loading_stage; // XXX -int _skip_specials; // XXX -uint16 _custom_sprites_base; // XXX - - typedef struct MD5File { const char * const filename; // filename const md5_byte_t hash[16]; // md5 sum of the file @@ -58,17 +41,12 @@ static const SpriteID * const _slopes_spriteindexes[] = { }; -static int LoadGrfFile(const char *filename, int load_index, int file_index) +static uint LoadGrfFile(const char* filename, uint load_index, int file_index) { - int load_index_org = load_index; + uint load_index_org = load_index; FioOpenFile(file_index, filename); - /* Thou shalt use LoadNewGrfFile() if thou loadeth a GRF file that - * might contain some special sprites. */ - _skip_specials = 1; - _skip_sprites = 0; - DEBUG(spritecache, 2) ("Reading grf-file ``%s''", filename); while (LoadNextSprite(load_index, file_index)) { @@ -82,62 +60,19 @@ static int LoadGrfFile(const char *filename, int load_index, int file_index) return load_index - load_index_org; } -static int LoadNewGrfFile(const char *filename, int load_index, int file_index) -{ - int i; - - FioOpenFile(file_index, filename); - _cur_grffile = filename; - _skip_specials = 0; - _skip_sprites = 0; - - DEBUG(spritecache, 2) ("Reading newgrf-file ``%s'' [offset: %u]", - filename, load_index); - - /* Skip the first sprite; we don't care about how many sprites this - * does contain; newest TTDPatches and George's longvehicles don't - * neither, apparently. */ - { - int length; - byte type; - - length = FioReadWord(); - type = FioReadByte(); - - if (length == 4 && type == 0xFF) { - FioReadDword(); - } else { - error("Custom .grf has invalid format."); - } - } - - for (i = 0; LoadNextSprite(load_index + i, file_index); i++) { - if (load_index + i >= MAX_SPRITES) - error("Too many sprites (0x%X). Recompile with higher MAX_SPRITES value or remove some custom GRF files.", - load_index + i); - } - - /* Clean up. */ - _skip_sprites = 0; - memset(_replace_sprites_count, 0, sizeof(_replace_sprites_count)); - memset(_replace_sprites_offset, 0, sizeof(_replace_sprites_offset)); - return i; -} - -static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int file_index) +static void LoadGrfIndexed(const char* filename, const SpriteID* index_tbl, int file_index) { - int start; + uint start; FioOpenFile(file_index, filename); - _skip_specials = 1; - _skip_sprites = 0; DEBUG(spritecache, 2) ("Reading indexed grf-file ``%s''", filename); for (; (start = *index_tbl++) != 0xffff;) { - int end = *index_tbl++; - if(start == 0xfffe) { // skip sprites (amount in second var) + uint end = *index_tbl++; + + if (start == 0xfffe) { // skip sprites (amount in second var) SkipSprites(end); } else { // load sprites and use indexes from start to end do { @@ -153,8 +88,6 @@ static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int } -static byte _sprite_page_to_load = 0xFF; - #define OPENTTD_SPRITES_COUNT 100 static const SpriteID _openttd_grf_indexes[] = { SPR_OPENTTD_BASE + 0, SPR_OPENTTD_BASE + 7, // icons etc @@ -170,7 +103,6 @@ static const SpriteID _openttd_grf_indexes[] = { 0xffff, }; -/* FUNCTIONS FOR CHECKING MD5 SUMS OF GRF FILES */ /* Check that the supplied MD5 hash matches that stored for the supplied filename */ static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn) @@ -269,21 +201,15 @@ void CheckExternalFiles(void) } } + +static byte _sprite_page_to_load = 0xFF; + static void LoadSpriteTables(void) { - int load_index = 0; + uint load_index = 0; uint i; - uint j; const FileList *files; // list of grf files to be loaded. Either Windows files or DOS files - _loading_stage = 1; - - /* - * TODO: - * I think we can live entirely without Indexed GRFs, but I have to - * invest that further. --octo - */ - files = _use_dos_palette? &files_dos : &files_win; for (i = 0; files->basic[i].filename != NULL; i++) { @@ -310,23 +236,7 @@ static void LoadSpriteTables(void) load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT + 1; - - /* Load newgrf sprites - * in each loading stage, (try to) open each file specified in the config - * and load information from it. */ - _custom_sprites_base = load_index; - for (_loading_stage = 0; _loading_stage < 2; _loading_stage++) { - load_index = _custom_sprites_base; - for (j = 0; j != lengthof(_newgrf_files) && _newgrf_files[j]; j++) { - if (!FiosCheckFileExists(_newgrf_files[j])) { - // TODO: usrerror() - error("NewGRF file missing: %s", _newgrf_files[j]); - } - if (_loading_stage == 0) InitNewGRFFile(_newgrf_files[j], load_index); - load_index += LoadNewGrfFile(_newgrf_files[j], load_index, i++); - DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index); - } - } + LoadNewGRF(load_index, i); } @@ -10,6 +10,7 @@ #include "fileio.h" #include "functions.h" #include "engine.h" +#include "spritecache.h" #include "station.h" #include "sprite.h" #include "newgrf.h" @@ -25,9 +26,9 @@ * served as subject to the initial testing of this codec. */ -extern int _skip_sprites; -extern int _replace_sprites_count[16]; -extern int _replace_sprites_offset[16]; +uint16 _custom_sprites_base; +static int _skip_sprites; // XXX +static uint _file_index; // XXX extern int _traininfo_vehicle_pitch; static GRFFile *_cur_grffile; @@ -1156,14 +1157,29 @@ static void NewSpriteSet(byte *buf, int len) * different sprites that make up a station */ /* TODO: No stations support. */ uint8 feature; + uint num_sets; + uint num_ents; + uint i; check_length(len, 4, "NewSpriteSet"); feature = buf[1]; + num_sets = buf[2]; + num_ents = buf[3]; - _cur_grffile->spriteset_start = _cur_spriteid + 1; + _cur_grffile->spriteset_start = _cur_spriteid; _cur_grffile->spriteset_feature = feature; - _cur_grffile->spriteset_numsets = buf[2]; - _cur_grffile->spriteset_numents = buf[3]; + _cur_grffile->spriteset_numsets = num_sets; + _cur_grffile->spriteset_numents = num_ents; + + DEBUG(grf, 7) ( + "New sprite set at %d of type %d, " + "consisting of %d sets with %d views each (total %d)", + _cur_spriteid, feature, num_sets, num_ents, num_sets * num_ents + ); + + for (i = 0; i < num_sets * num_ents; i++) { + LoadNextSprite(_cur_spriteid++, _file_index); + } } /* Action 0x02 */ @@ -1790,7 +1806,7 @@ static void SkipIf(byte *buf, int len) } numsprites = grf_load_byte(&buf); - grfmsg(GMS_NOTICE, "Skipping %d->+%d sprites, test was true.", _cur_spriteid - _cur_grffile->sprite_offset, numsprites); + grfmsg(GMS_NOTICE, "Skipping %d sprites, test was true.", numsprites); _skip_sprites = numsprites; if (_skip_sprites == 0) { /* Zero means there are no sprites to skip, so @@ -1838,27 +1854,23 @@ static void SpriteReplace(byte *buf, int len) * B num-sprites How many sprites are in this set * W first-sprite First sprite number to replace */ uint8 num_sets; - int i; + uint i; buf++; /* skip action byte */ num_sets = grf_load_byte(&buf); - if (num_sets > 16) { - grfmsg(GMS_ERROR, "SpriteReplace: Too many sets (%d), taking only the first 16!", num_sets); - } + for (i = 0; i < num_sets; i++) { + uint8 num_sprites = grf_load_byte(&buf); + uint16 first_sprite = grf_load_word(&buf); + uint j; - for (i = 0; i < 16; i++) { - if (i < num_sets) { - uint8 num_sprites = grf_load_byte(&buf); - uint16 first_sprite = grf_load_word(&buf); + grfmsg(GMS_NOTICE, + "SpriteReplace: [Set %d] Changing %d sprites, beginning with %d", + i, num_sprites, first_sprite + ); - _replace_sprites_count[i] = num_sprites; - _replace_sprites_offset[i] = first_sprite; - grfmsg(GMS_NOTICE, "SpriteReplace: [Set %d] Changing %d sprites, beginning with %d", - i, num_sprites, first_sprite); - } else { - _replace_sprites_count[i] = 0; - _replace_sprites_offset[i] = 0; + for (j = 0; j < num_sprites; j++) { + LoadNextSprite(first_sprite + j, _file_index); // XXX } } } @@ -2090,7 +2102,7 @@ static void InitializeGRFSpecial(void) | (1 << 0x17); /* newstartyear */ } -void InitNewGRFFile(const char *filename, int sprite_offset) +static void InitNewGRFFile(const char* filename, int sprite_offset) { GRFFile *newfile; @@ -2126,130 +2138,170 @@ void InitNewGRFFile(const char *filename, int sprite_offset) /* XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by * a crafted invalid GRF file. We should tell that to the user somehow, or * better make this more robust in the future. */ - -void DecodeSpecialSprite(const char *filename, int num, int spriteid, int stage) +static void DecodeSpecialSprite(const char* filename, uint num, uint stage) { -#define NUM_ACTIONS 0xF - static const SpecialSpriteHandler handlers[NUM_ACTIONS] = { - /* 0x0 */ VehicleChangeInfo, - /* 0x1 */ NewSpriteSet, - /* 0x2 */ NewSpriteGroup, - /* 0x3 */ NewVehicle_SpriteGroupMapping, - /* 0x4 */ VehicleNewName, - /* 0x5 */ GraphicsNew, - /* 0x6 */ CfgApply, - /* 0x7 */ SkipIf, - /* 0x8 */ GRFInfo, - /* 0x9 */ SkipIf, - /* 0xa */ SpriteReplace, - /* 0xb */ GRFError, - /* 0xc */ GRFComment, - /* 0xd */ ParamSet, - /* 0xe */ GRFInhibit, + /* XXX: There is a difference between staged loading in TTDPatch and + * here. In TTDPatch, for some reason actions 1 and 2 are carried out + * during stage 0, whilst action 3 is carried out during stage 1 (to + * "resolve" cargo IDs... wtf). This is a little problem, because cargo + * IDs are valid only within a given set (action 1) block, and may be + * overwritten after action 3 associates them. But overwriting happens + * in an earlier stage than associating, so... We just process actions + * 1 and 2 in stage 1 now, let's hope that won't get us into problems. + * --pasky */ + uint32 action_mask = (stage == 0) ? 0x0001FF40 : 0x0001FFBF; + static const SpecialSpriteHandler handlers[] = { + /* 0x00 */ VehicleChangeInfo, + /* 0x01 */ NewSpriteSet, + /* 0x02 */ NewSpriteGroup, + /* 0x03 */ NewVehicle_SpriteGroupMapping, + /* 0x04 */ VehicleNewName, + /* 0x05 */ GraphicsNew, + /* 0x06 */ CfgApply, + /* 0x07 */ SkipIf, + /* 0x08 */ GRFInfo, + /* 0x09 */ SkipIf, + /* 0x0A */ SpriteReplace, + /* 0x0B */ GRFError, + /* 0x0C */ GRFComment, + /* 0x0D */ ParamSet, + /* 0x0E */ GRFInhibit, + /* 0x0F */ NULL, // TODO implement + /* 0x10 */ NULL // TODO implement }; - static bool initialized = false; + + byte* buf = malloc(num); byte action; - byte *buf = malloc(num); if (buf == NULL) error("DecodeSpecialSprite: Could not allocate memory"); - if (!initialized) { - InitializeGRFSpecial(); - initialized = true; + FioReadBlock(buf, num); + action = buf[0]; + + if (action >= lengthof(handlers)) { + DEBUG(grf, 7) ("Skipping unknown action 0x%02X", action); + free(buf); + return; } - _cur_stage = stage; - _cur_spriteid = spriteid; + if (!HASBIT(action_mask, action)) { + DEBUG(grf, 7) ("Skipping action 0x%02X in stage %d", action, stage); + free(buf); + return; + } - FioReadBlock(buf, num); + if (handlers[action] == NULL) { + DEBUG(grf, 7) ("Skipping unsupported Action 0x%02X", action); + free(buf); + return; + } - action = buf[0]; + DEBUG(grf, 7) ("Handling action 0x%02X in stage %d", action, stage); + handlers[action](buf, num); + free(buf); +} - /* XXX: There is a difference between staged loading in TTDPatch and - * here. In TTDPatch, for some reason actions 1 and 2 are carried out - * during stage 0, whilst action 3 is carried out during stage 1 (to - * "resolve" cargo IDs... wtf). This is a little problem, because cargo - * IDs are valid only within a given set (action 1) block, and may be - * overwritten after action 3 associates them. But overwriting happens - * in an earlier stage than associating, so... We just process actions - * 1 and 2 in stage 1 now, let's hope that won't get us into problems. - * --pasky */ - if (stage == 0) { - switch (action) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x07: - /* During initialization, these actions are ignored. */ - DEBUG (grf, 7) ( - "DecodeSpecialSprite: Action: %x, Stage 0, Skipped", action); - break; - - default: - if (action < NUM_ACTIONS) { - DEBUG (grf, 7) ("DecodeSpecialSprite: Action: %x, Stage 0", action); - handlers[action](buf, num); - } else { - grfmsg(GMS_WARN, - "Unknown special sprite action %x, skipping.", action); - } - } - } else if (stage == 1) { - /* A .grf file is activated only if it was active when the game was - * started. If a game is loaded, only its active .grfs will be - * reactivated, unless "loadallgraphics on" is used. A .grf file is - * considered active if its action 8 has been processed, i.e. its - * action 8 hasn't been skipped using an action 7. - * - * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are - * carried out. All others are ignored, because they only need to be - * processed once at initialization. */ - - if (_cur_grffile == NULL || strcmp(_cur_grffile->filename, filename) != 0) - _cur_grffile = GetFileByFilename(filename); - - if (_cur_grffile == NULL) - error("File ``%s'' lost in cache.\n", filename); - - if (_cur_grffile->flags & 0x0001) { - switch (action) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - DEBUG (grf, 7) ("DecodeSpecialSprite: Action: %x, Stage 1", action); - handlers[action](buf, num); - break; +static void LoadNewGRFFile(const char* filename, uint file_index, uint stage) +{ + uint16 num; + + /* A .grf file is activated only if it was active when the game was + * started. If a game is loaded, only its active .grfs will be + * reactivated, unless "loadallgraphics on" is used. A .grf file is + * considered active if its action 8 has been processed, i.e. its + * action 8 hasn't been skipped using an action 7. + * + * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are + * carried out. All others are ignored, because they only need to be + * processed once at initialization. */ + if (stage != 0) { + _cur_grffile = GetFileByFilename(filename); + if (_cur_grffile == NULL) error("File ``%s'' lost in cache.\n", filename); + if (!(_cur_grffile->flags & 0x0001)) return; + } + + FioOpenFile(file_index, filename); + _file_index = file_index; // XXX + + DEBUG(grf, 7) ("Reading NewGRF-file '%s'", filename); + + /* Skip the first sprite; we don't care about how many sprites this + * does contain; newest TTDPatches and George's longvehicles don't + * neither, apparently. */ + if (FioReadWord() == 4 && FioReadByte() == 0xFF) { + FioReadDword(); + } else { + error("Custom .grf has invalid format."); + } + + _skip_sprites = 0; // XXX + + while ((num = FioReadWord()) != 0) { + byte type = FioReadByte(); + + if (type == 0xFF) { + if (_skip_sprites == 0) { + DecodeSpecialSprite(filename, num, stage); + continue; + } else { + FioSkipBytes(num); + } + } else { + if (_skip_sprites == 0) DEBUG(grf, 7) ("Skipping unexpected sprite"); + + FioSkipBytes(7); + num -= 8; - default: - if (action < NUM_ACTIONS) { - DEBUG (grf, 7) ( - "DecodeSpecialSprite: Action: %x, Stage 1, Skipped", action); + if (type & 2) { + FioSkipBytes(num); + } else { + while (num > 0) { + int8 i = FioReadByte(); + if (i >= 0) { + num -= i; + FioSkipBytes(i); } else { - grfmsg(GMS_WARN, - "Unknown special sprite action %x, skipping.", action); + i = -(i >> 3); + num -= i; + FioReadByte(); } - break; + } } - } else { - DEBUG (grf, 7) ( - "DecodeSpecialSprite: Action: %x, Stage 1, Not activated", action); } - } else { - error("Invalid stage %d", stage); + + if (_skip_sprites > 0) _skip_sprites--; } +} - free(buf); -#undef NUM_ACTIONS + +void LoadNewGRF(uint load_index, uint file_index) +{ + static bool initialized = false; // XXX yikes + uint stage; + + if (!initialized) { + InitializeGRFSpecial(); + initialized = true; + } + + /* Load newgrf sprites + * in each loading stage, (try to) open each file specified in the config + * and load information from it. */ + _custom_sprites_base = load_index; + for (stage = 0; stage < 2; stage++) { + uint j; + + _cur_stage = stage; + _cur_spriteid = load_index; + for (j = 0; j != lengthof(_newgrf_files) && _newgrf_files[j] != NULL; j++) { + if (!FiosCheckFileExists(_newgrf_files[j])) { + // TODO: usrerror() + error("NewGRF file missing: %s", _newgrf_files[j]); + } + if (stage == 0) InitNewGRFFile(_newgrf_files[j], _cur_spriteid); + LoadNewGRFFile(_newgrf_files[j], file_index++, stage); // XXX different file indices in both stages? + DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index); + } + } } @@ -39,9 +39,8 @@ struct GRFFile { extern int _grffile_count; extern GRFFile *_first_grffile; -void InitNewGRFFile(const char *filename, int sprite_offset); -void DecodeSpecialSprite(const char *filename, int num, int spriteid, int stage); +void LoadNewGRF(uint load_index, uint file_index); #endif /* NEWGRF_H */ diff --git a/spritecache.c b/spritecache.c index aa6b2cf29..967538125 100644 --- a/spritecache.c +++ b/spritecache.c @@ -7,25 +7,12 @@ #include "spritecache.h" #include "table/sprites.h" #include "fileio.h" -#include "newgrf.h" #define SPRITE_CACHE_SIZE 1024*1024 #define WANT_NEW_LRU -/* These are used in newgrf.c: */ - -extern int _skip_sprites; // XXX -extern int _replace_sprites_count[16]; // XXX -extern int _replace_sprites_offset[16]; // XXX - -extern const char* _cur_grffile; // XXX -extern int _loading_stage; // XXX -extern int _skip_specials; // XXX -static Sprite _cur_sprite; // XXX - - static void* _sprite_ptr[MAX_SPRITES]; static uint32 _sprite_file_pos[MAX_SPRITES]; @@ -47,33 +34,16 @@ static int _compact_cache_counter; static void CompactSpriteCache(void); -static bool ReadSpriteHeaderSkipData(int load_index) +static bool ReadSpriteHeaderSkipData(void) { uint16 num = FioReadWord(); byte type; - int deaf = 0; if (num == 0) return false; - if (_skip_sprites) { - if (_skip_sprites > 0) - _skip_sprites--; - deaf = 1; - } - type = FioReadByte(); - _cur_sprite.info = type; if (type == 0xFF) { - /* We need to really skip only special sprites in the deaf - * mode. It won't hurt to proceed regular sprites as usual - * because if no special sprite referencing to them is - * processed, they themselves are never referenced and loaded - * on their own. */ - if (_skip_specials || deaf) { - FioSkipBytes(num); - } else { - DecodeSpecialSprite(_cur_grffile, num, load_index, _loading_stage); - } + FioSkipBytes(num); return true; } @@ -169,35 +139,7 @@ bool LoadNextSprite(int load_index, byte file_index) { uint32 file_pos = FioGetPos() | (file_index << 24); - if (!ReadSpriteHeaderSkipData(load_index)) return false; - - if (_replace_sprites_count[0] > 0 && _cur_sprite.info != 0xFF) { - int count = _replace_sprites_count[0]; - int offset = _replace_sprites_offset[0]; - - _replace_sprites_offset[0]++; - _replace_sprites_count[0]--; - - if ((offset + count) <= MAX_SPRITES) { - load_index = offset; - } else { - DEBUG(spritecache, 1) ("Sprites to be replaced are out of range: %x+%x", - count, offset); - _replace_sprites_offset[0] = 0; - _replace_sprites_count[0] = 0; - } - - if (_replace_sprites_count[0] == 0) { - int i; - - for (i = 0; i < 15; i++) { - _replace_sprites_count[i] = _replace_sprites_count[i + 1]; - _replace_sprites_offset[i] = _replace_sprites_offset[i + 1]; - } - _replace_sprites_count[i] = 0; - _replace_sprites_offset[i] = 0; - } - } + if (!ReadSpriteHeaderSkipData()) return false; _sprite_file_pos[load_index] = file_pos; @@ -216,7 +158,7 @@ bool LoadNextSprite(int load_index, byte file_index) void SkipSprites(uint count) { for (; count > 0; --count) { - if (!ReadSpriteHeaderSkipData(MAX_SPRITES - 1)) return; + if (!ReadSpriteHeaderSkipData()) return; } } |