gfxinit.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "fios.h"
00015 #include "newgrf.h"
00016 #include "3rdparty/md5/md5.h"
00017 #include "fontcache.h"
00018 #include "gfx_func.h"
00019 #include "settings_type.h"
00020 
00021 /* The type of set we're replacing */
00022 #define SET_TYPE "graphics"
00023 #include "base_media_func.h"
00024 
00025 #include "table/sprites.h"
00026 #include "table/palette_convert.h"
00027 
00029 PaletteType _use_palette = PAL_AUTODETECT;
00031 bool _palette_remap_grf[MAX_FILE_SLOTS];
00033 const byte *_palette_remap = NULL;
00035 const byte *_palette_reverse_remap = NULL;
00036 
00037 #include "table/landscape_sprite.h"
00038 
00039 static const SpriteID * const _landscape_spriteindexes[] = {
00040   _landscape_spriteindexes_1,
00041   _landscape_spriteindexes_2,
00042   _landscape_spriteindexes_3,
00043 };
00044 
00045 static uint LoadGrfFile(const char *filename, uint load_index, int file_index)
00046 {
00047   uint load_index_org = load_index;
00048   uint sprite_id = 0;
00049 
00050   FioOpenFile(file_index, filename);
00051 
00052   DEBUG(sprite, 2, "Reading grf-file '%s'", filename);
00053 
00054   while (LoadNextSprite(load_index, file_index, sprite_id)) {
00055     load_index++;
00056     sprite_id++;
00057     if (load_index >= MAX_SPRITES) {
00058       usererror("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files.");
00059     }
00060   }
00061   DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index);
00062 
00063   return load_index - load_index_org;
00064 }
00065 
00066 
00067 static void LoadSpritesIndexed(int file_index, uint *sprite_id, const SpriteID *index_tbl)
00068 {
00069   uint start;
00070   while ((start = *index_tbl++) != END) {
00071     uint end = *index_tbl++;
00072 
00073     do {
00074       bool b = LoadNextSprite(start, file_index, *sprite_id);
00075       assert(b);
00076       (*sprite_id)++;
00077     } while (++start <= end);
00078   }
00079 }
00080 
00081 static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int file_index)
00082 {
00083   uint sprite_id = 0;
00084 
00085   FioOpenFile(file_index, filename);
00086 
00087   DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename);
00088 
00089   LoadSpritesIndexed(file_index, &sprite_id, index_tbl);
00090 }
00091 
00097 void CheckExternalFiles()
00098 {
00099   if (BaseGraphics::GetUsedSet() == NULL || BaseSounds::GetUsedSet() == NULL) return;
00100 
00101   BaseGraphics::DeterminePalette();
00102   const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
00103 
00104   DEBUG(grf, 1, "Using the %s base graphics set with the %s palette", used_set->name, _use_palette == PAL_DOS ? "DOS" : "Windows");
00105 
00106   static const size_t ERROR_MESSAGE_LENGTH = 256;
00107   static const size_t MISSING_FILE_MESSAGE_LENGTH = 128;
00108 
00109   /* Allocate for a message for each missing file and for one error
00110    * message per set.
00111    */
00112   char error_msg[MISSING_FILE_MESSAGE_LENGTH * (GraphicsSet::NUM_FILES + SoundsSet::NUM_FILES) + 2 * ERROR_MESSAGE_LENGTH];
00113   error_msg[0] = '\0';
00114   char *add_pos = error_msg;
00115   const char *last = lastof(error_msg);
00116 
00117   if (used_set->GetNumInvalid() != 0) {
00118     /* Not all files were loaded succesfully, see which ones */
00119     add_pos += seprintf(add_pos, last, "Trying to load graphics set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of readme.txt.\n\nThe following files are corrupted or missing:\n", used_set->name);
00120     for (uint i = 0; i < GraphicsSet::NUM_FILES; i++) {
00121       MD5File::ChecksumResult res = used_set->files[i].CheckMD5(DATA_DIR);
00122       if (res != MD5File::CR_MATCH) add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", used_set->files[i].filename, res == MD5File::CR_MISMATCH ? "corrupt" : "missing", used_set->files[i].missing_warning);
00123     }
00124     add_pos += seprintf(add_pos, last, "\n");
00125   }
00126 
00127   const SoundsSet *sounds_set = BaseSounds::GetUsedSet();
00128   if (sounds_set->GetNumInvalid() != 0) {
00129     add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of readme.txt.\n\nThe following files are corrupted or missing:\n", sounds_set->name);
00130 
00131     assert_compile(SoundsSet::NUM_FILES == 1);
00132     /* No need to loop each file, as long as there is only a single
00133      * sound file. */
00134     add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, sounds_set->files->CheckMD5(DATA_DIR) == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning);
00135   }
00136 
00137   if (add_pos != error_msg) ShowInfoF("%s", error_msg);
00138 }
00139 
00140 
00141 static void LoadSpriteTables()
00142 {
00143   memset(_palette_remap_grf, 0, sizeof(_palette_remap_grf));
00144   uint i = FIRST_GRF_SLOT;
00145   const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
00146 
00147   _palette_remap_grf[i] = (_use_palette != used_set->palette);
00148   LoadGrfFile(used_set->files[GFT_BASE].filename, 0, i++);
00149 
00150   /*
00151    * The second basic file always starts at the given location and does
00152    * contain a different amount of sprites depending on the "type"; DOS
00153    * has a few sprites less. However, we do not care about those missing
00154    * sprites as they are not shown anyway (logos in intro game).
00155    */
00156   _palette_remap_grf[i] = (_use_palette != used_set->palette);
00157   LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, i++);
00158 
00159   /*
00160    * Load additional sprites for climates other than temperate.
00161    * This overwrites some of the temperate sprites, such as foundations
00162    * and the ground sprites.
00163    */
00164   if (_settings_game.game_creation.landscape != LT_TEMPERATE) {
00165     _palette_remap_grf[i] = (_use_palette != used_set->palette);
00166     LoadGrfIndexed(
00167       used_set->files[GFT_ARCTIC + _settings_game.game_creation.landscape - 1].filename,
00168       _landscape_spriteindexes[_settings_game.game_creation.landscape - 1],
00169       i++
00170     );
00171   }
00172 
00173   /* Initialize the unicode to sprite mapping table */
00174   InitializeUnicodeGlyphMap();
00175 
00176   /*
00177    * Load the base NewGRF with OTTD required graphics as first NewGRF.
00178    * However, we do not want it to show up in the list of used NewGRFs,
00179    * so we have to manually add it, and then remove it later.
00180    */
00181   GRFConfig *top = _grfconfig;
00182   GRFConfig *master = CallocT<GRFConfig>(1);
00183   master->filename = strdup(used_set->files[GFT_EXTRA].filename);
00184   FillGRFDetails(master, false);
00185   master->windows_paletted = (used_set->palette == PAL_WINDOWS);
00186   ClrBit(master->flags, GCF_INIT_ONLY);
00187   master->next = top;
00188   _grfconfig = master;
00189 
00190   LoadNewGRF(SPR_NEWGRFS_BASE, i);
00191 
00192   /* Free and remove the top element. */
00193   ClearGRFConfig(&master);
00194   _grfconfig = top;
00195 }
00196 
00197 
00198 void GfxLoadSprites()
00199 {
00200   DEBUG(sprite, 2, "Loading sprite set %d", _settings_game.game_creation.landscape);
00201 
00202   GfxInitSpriteMem();
00203   LoadSpriteTables();
00204   GfxInitPalettes();
00205 }
00206 
00207 bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path)
00208 {
00209   bool ret = this->BaseSet<GraphicsSet, MAX_GFT, DATA_DIR>::FillSetDetails(ini, path);
00210   if (ret) {
00211     IniGroup *metadata = ini->GetGroup("metadata");
00212     IniItem *item;
00213 
00214     fetch_metadata("palette");
00215     this->palette = (*item->value == 'D' || *item->value == 'd') ? PAL_DOS : PAL_WINDOWS;
00216   }
00217   return true;
00218 }
00219 
00220 
00229 MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir) const
00230 {
00231   size_t size;
00232   FILE *f = FioFOpenFile(this->filename, "rb", subdir, &size);
00233 
00234   if (f == NULL) return CR_NO_FILE;
00235 
00236   Md5 checksum;
00237   uint8 buffer[1024];
00238   uint8 digest[16];
00239   size_t len;
00240 
00241   while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
00242     size -= len;
00243     checksum.Append(buffer, len);
00244   }
00245 
00246   FioFCloseFile(f);
00247 
00248   checksum.Finish(digest);
00249   return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH;
00250 }
00251 
00253 static const char * const _graphics_file_names[] = { "base", "logos", "arctic", "tropical", "toyland", "extra" };
00254 
00256 template <class T, size_t Tnum_files, Subdirectory Tsubdir>
00257 /* static */ const char * const *BaseSet<T, Tnum_files, Tsubdir>::file_names = _graphics_file_names;
00258 
00259 extern void UpdateNewGRFConfigPalette();
00260 
00266 /* static */ void BaseGraphics::DeterminePalette()
00267 {
00268   assert(BaseGraphics::used_set != NULL);
00269   if (_use_palette >= MAX_PAL) _use_palette = BaseGraphics::used_set->palette;
00270 
00271   switch (_use_palette) {
00272     case PAL_DOS:
00273       _palette_remap = _palmap_w2d;
00274       _palette_reverse_remap = _palmap_d2w;
00275       break;
00276 
00277     case PAL_WINDOWS:
00278       _palette_remap = _palmap_d2w;
00279       _palette_reverse_remap = _palmap_w2d;
00280       break;
00281 
00282     default:
00283       NOT_REACHED();
00284   }
00285 
00286   UpdateNewGRFConfigPalette();
00287 }
00288 
00289 template <class Tbase_set>
00290 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
00291 {
00292   if (BaseMedia<Tbase_set>::used_set != NULL) return true;
00293 
00294   const Tbase_set *best = NULL;
00295   for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
00296     /* Skip unuseable sets */
00297     if (c->GetNumMissing() != 0) continue;
00298 
00299     if (best == NULL ||
00300         best->valid_files < c->valid_files ||
00301         (best->valid_files == c->valid_files && (
00302           (best->shortname == c->shortname && best->version < c->version) ||
00303           (best->palette != _use_palette && c->palette == _use_palette)))) {
00304       best = c;
00305     }
00306   }
00307 
00308   BaseMedia<Tbase_set>::used_set = best;
00309   return BaseMedia<Tbase_set>::used_set != NULL;
00310 }
00311 
00312 template <class Tbase_set>
00313 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
00314 {
00315   return ".obg"; // OpenTTD Base Graphics
00316 }
00317 
00318 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<GraphicsSet>, GraphicsSet)

Generated on Wed Dec 30 20:40:02 2009 for OpenTTD by  doxygen 1.5.6