gfxinit.cpp

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