src/gfxinit.cpp
changeset 5835 e0ff603ae0b7
parent 5827 20879afb77f6
child 5650 aefc131bf5ce
equal deleted inserted replaced
5834:7bf92d5a5a0f 5835:e0ff603ae0b7
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "debug.h"
       
     6 #include "functions.h"
       
     7 #include "gfx.h"
       
     8 #include "gfxinit.h"
       
     9 #include "spritecache.h"
       
    10 #include "table/sprites.h"
       
    11 #include "fileio.h"
       
    12 #include "string.h"
       
    13 #include "newgrf.h"
       
    14 #include "md5.h"
       
    15 #include "variables.h"
       
    16 #include "fontcache.h"
       
    17 #include <string.h>
       
    18 
       
    19 typedef struct MD5File {
       
    20 	const char * const filename;     // filename
       
    21 	const md5_byte_t hash[16]; // md5 sum of the file
       
    22 } MD5File;
       
    23 
       
    24 typedef struct FileList {
       
    25 	const MD5File basic[4];     // grf files that always have to be loaded
       
    26 	const MD5File landscape[3]; // landscape specific grf files
       
    27 } FileList;
       
    28 
       
    29 enum {
       
    30 	SKIP = 0xFFFE,
       
    31 	END  = 0xFFFF
       
    32 };
       
    33 
       
    34 #include "table/files.h"
       
    35 #include "table/landscape_sprite.h"
       
    36 
       
    37 static const SpriteID * const _landscape_spriteindexes[] = {
       
    38 	_landscape_spriteindexes_1,
       
    39 	_landscape_spriteindexes_2,
       
    40 	_landscape_spriteindexes_3,
       
    41 };
       
    42 
       
    43 static const SpriteID * const _slopes_spriteindexes[] = {
       
    44 	_slopes_spriteindexes_0,
       
    45 	_slopes_spriteindexes_1,
       
    46 	_slopes_spriteindexes_2,
       
    47 	_slopes_spriteindexes_3,
       
    48 };
       
    49 
       
    50 
       
    51 static uint LoadGrfFile(const char* filename, uint load_index, int file_index)
       
    52 {
       
    53 	uint load_index_org = load_index;
       
    54 
       
    55 	FioOpenFile(file_index, filename);
       
    56 
       
    57 	DEBUG(sprite, 2, "Reading grf-file '%s'", filename);
       
    58 
       
    59 	while (LoadNextSprite(load_index, file_index)) {
       
    60 		load_index++;
       
    61 		if (load_index >= MAX_SPRITES) {
       
    62 			error("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files.");
       
    63 		}
       
    64 	}
       
    65 	DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index);
       
    66 
       
    67 	return load_index - load_index_org;
       
    68 }
       
    69 
       
    70 
       
    71 static void LoadGrfIndexed(const char* filename, const SpriteID* index_tbl, int file_index)
       
    72 {
       
    73 	uint start;
       
    74 
       
    75 	FioOpenFile(file_index, filename);
       
    76 
       
    77 	DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename);
       
    78 
       
    79 	while ((start = *index_tbl++) != END) {
       
    80 		uint end = *index_tbl++;
       
    81 
       
    82 		if (start == SKIP) { // skip sprites (amount in second var)
       
    83 			SkipSprites(end);
       
    84 		} else { // load sprites and use indexes from start to end
       
    85 			do {
       
    86 			#ifdef NDEBUG
       
    87 				LoadNextSprite(start, file_index);
       
    88 			#else
       
    89 				bool b = LoadNextSprite(start, file_index);
       
    90 				assert(b);
       
    91 			#endif
       
    92 			} while (++start <= end);
       
    93 		}
       
    94 	}
       
    95 }
       
    96 
       
    97 
       
    98 /* Check that the supplied MD5 hash matches that stored for the supplied filename */
       
    99 static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn)
       
   100 {
       
   101 	if (memcmp(file.hash, digest, sizeof(file.hash)) == 0) return true;
       
   102 	if (warn) fprintf(stderr, "MD5 of %s is ****INCORRECT**** - File Corrupt.\n", file.filename);
       
   103 	return false;
       
   104 }
       
   105 
       
   106 /* Calculate and check the MD5 hash of the supplied filename.
       
   107  * returns true if the checksum is correct */
       
   108 static bool FileMD5(const MD5File file, bool warn)
       
   109 {
       
   110 	FILE *f;
       
   111 	char buf[MAX_PATH];
       
   112 
       
   113 	// open file
       
   114 	snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, file.filename);
       
   115 	f = fopen(buf, "rb");
       
   116 
       
   117 #if !defined(WIN32)
       
   118 	if (f == NULL) {
       
   119 		strtolower(buf + strlen(_paths.data_dir) - 1);
       
   120 		f = fopen(buf, "rb");
       
   121 	}
       
   122 #endif
       
   123 
       
   124 #if defined SECOND_DATA_DIR
       
   125 	/* If we failed to find the file in the first data directory, we will try the other one */
       
   126 
       
   127 	if (f == NULL) {
       
   128 		snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, file.filename);
       
   129 		f = fopen(buf, "rb");
       
   130 
       
   131 		if (f == NULL) {
       
   132 			strtolower(buf + strlen(_paths.second_data_dir) - 1);
       
   133 			f = fopen(buf, "rb");
       
   134 		}
       
   135 	}
       
   136 #endif
       
   137 
       
   138 	if (f != NULL) {
       
   139 		md5_state_t filemd5state;
       
   140 		md5_byte_t buffer[1024];
       
   141 		md5_byte_t digest[16];
       
   142 		size_t len;
       
   143 
       
   144 		md5_init(&filemd5state);
       
   145 		while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0)
       
   146 			md5_append(&filemd5state, buffer, len);
       
   147 
       
   148 		if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf);
       
   149 		fclose(f);
       
   150 
       
   151 		md5_finish(&filemd5state, digest);
       
   152 		return CheckMD5Digest(file, digest, warn);
       
   153 	} else { // file not found
       
   154 		return false;
       
   155 	}
       
   156 }
       
   157 
       
   158 /* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF)
       
   159  * by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly.
       
   160  * If neither are found, Windows palette is assumed.
       
   161  *
       
   162  * (Note: Also checks sample.cat for corruption) */
       
   163 void CheckExternalFiles(void)
       
   164 {
       
   165 	uint i;
       
   166 	// count of files from this version
       
   167 	uint dos = 0;
       
   168 	uint win = 0;
       
   169 
       
   170 	for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++;
       
   171 	for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++;
       
   172 
       
   173 	for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++;
       
   174 	for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++;
       
   175 
       
   176 	if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false))
       
   177 		ShowInfo("Your 'sample.cat' file is corrupted or missing!");
       
   178 
       
   179 	for (i = 0; i < lengthof(files_openttd); i++) {
       
   180 		if (!FileMD5(files_openttd[i], false)) {
       
   181 			ShowInfoF("Your '%s' file is corrupted or missing!", files_openttd[i].filename);
       
   182 		}
       
   183 	}
       
   184 
       
   185 	/*
       
   186 	 * forced DOS palette via command line -> leave it that way
       
   187 	 * all Windows files present -> Windows palette
       
   188 	 * all DOS files present -> DOS palette
       
   189 	 * no Windows files present and any DOS file present -> DOS palette
       
   190 	 * otherwise -> Windows palette
       
   191 	 */
       
   192 	if (_use_dos_palette) {
       
   193 		return;
       
   194 	} else if (win == 5) {
       
   195 		_use_dos_palette = false;
       
   196 	} else if (dos == 5 || (win == 0 && dos > 0)) {
       
   197 		_use_dos_palette = true;
       
   198 	} else {
       
   199 		_use_dos_palette = false;
       
   200 	}
       
   201 }
       
   202 
       
   203 
       
   204 static const SpriteID trg1idx[] = {
       
   205 	   0,    1, // Mouse cursor, ZZZ
       
   206 /* Medium font */
       
   207 	   2,   92, // ' ' till 'z'
       
   208 	SKIP,   36,
       
   209 	 160,  160, // Move ¾ to the correct position
       
   210 	  98,   98, // Up arrow
       
   211 	 131,  133,
       
   212 	SKIP,    1, // skip currency sign
       
   213 	 135,  135,
       
   214 	SKIP,    1,
       
   215 	 137,  137,
       
   216 	SKIP,    1,
       
   217 	 139,  139,
       
   218 	 140,  140, // TODO Down arrow
       
   219 	 141,  141,
       
   220 	 142,  142, // TODO Check mark
       
   221 	 143,  143, // TODO Cross
       
   222 	 144,  144,
       
   223 	 145,  145, // TODO Right arrow
       
   224 	 146,  149,
       
   225 	 118,  122, // Transport markers
       
   226 	SKIP,    2,
       
   227 	 157,  157,
       
   228 	 114,  115, // Small up/down arrows
       
   229 	SKIP,    1,
       
   230 	 161,  225,
       
   231 /* Small font */
       
   232 	 226,  316, // ' ' till 'z'
       
   233 	SKIP,   36,
       
   234 	 384,  384, // Move ¾ to the correct position
       
   235 	 322,  322, // Up arrow
       
   236 	 355,  357,
       
   237 	SKIP,    1, // skip currency sign
       
   238 	 359,  359,
       
   239 	SKIP,    1,
       
   240 	 361,  361,
       
   241 	SKIP,    1,
       
   242 	 363,  363,
       
   243 	 364,  364, // TODO Down arrow
       
   244 	 365,  366,
       
   245 	SKIP,    1,
       
   246 	 368,  368,
       
   247 	 369,  369, // TODO Right arrow
       
   248 	 370,  373,
       
   249 	SKIP,    7,
       
   250 	 381,  381,
       
   251 	SKIP,    3,
       
   252 	 385,  449,
       
   253 /* Big font */
       
   254 	 450,  540, // ' ' till 'z'
       
   255 	SKIP,   36,
       
   256 	 608,  608, // Move ¾ to the correct position
       
   257 	SKIP,    1,
       
   258 	 579,  581,
       
   259 	SKIP,    1,
       
   260 	 583,  583,
       
   261 	SKIP,    5,
       
   262 	 589,  589,
       
   263 	SKIP,   15,
       
   264 	 605,  605,
       
   265 	SKIP,    3,
       
   266 	 609,  625,
       
   267 	SKIP,    1,
       
   268 	 627,  632,
       
   269 	SKIP,    1,
       
   270 	 634,  639,
       
   271 	SKIP,    1,
       
   272 	 641,  657,
       
   273 	SKIP,    1,
       
   274 	 659,  664,
       
   275 	SKIP,    2,
       
   276 	 667,  671,
       
   277 	SKIP,    1,
       
   278 	 673,  673,
       
   279 /* Graphics */
       
   280 	 674, 4792,
       
   281 	END
       
   282 };
       
   283 
       
   284 /* NOTE: When adding a normal sprite, increase OPENTTD_SPRITES_COUNT with the
       
   285  * amount of sprites and add them to the end of the list, with the index of
       
   286  * the old sprite-count offset from SPR_OPENTTD_BASE. With this there is no
       
   287  * correspondence of any kind with the ID's in the grf file, but results in
       
   288  * a maximum use of sprite slots. */
       
   289 static const SpriteID _openttd_grf_indexes[] = {
       
   290 	SPR_IMG_AUTORAIL, SPR_CURSOR_WAYPOINT, // icons etc
       
   291 	134, 134,  // euro symbol medium size
       
   292 	582, 582,  // euro symbol large size
       
   293 	358, 358,  // euro symbol tiny
       
   294 	SPR_CURSOR_CANAL, SPR_IMG_FASTFORWARD, // more icons
       
   295 	648, 648, // nordic char: æ
       
   296 	616, 616, // nordic char: Æ
       
   297 	666, 666, // nordic char: ø
       
   298 	634, 634, // nordic char: Ø
       
   299 	SPR_PIN_UP, SPR_CURSOR_CLONE_TRAIN, // more icons
       
   300 	382, 383, // ¼ ½ tiny
       
   301 	158, 159, // ¼ ½ medium
       
   302 	606, 607, // ¼ ½ large
       
   303 	360, 360, // ¦ tiny
       
   304 	362, 362, // ¨ tiny
       
   305 	136, 136, // ¦ medium
       
   306 	138, 138, // ¨ medium
       
   307 	584, 584, // ¦ large
       
   308 	586, 586, // ¨ large
       
   309 	626, 626, // Ð large
       
   310 	658, 658, // ð large
       
   311 	374, 374, // ´ tiny
       
   312 	378, 378, // ¸ tiny
       
   313 	150, 150, // ´ medium
       
   314 	154, 154, // ¸ medium
       
   315 	598, 598, // ´ large
       
   316 	602, 602, // ¸ large
       
   317 	640, 640, // Þ large
       
   318 	672, 672, // þ large
       
   319 	380, 380, // º tiny
       
   320 	156, 156, // º medium
       
   321 	604, 604, // º large
       
   322 	317, 320, // { | } ~ tiny
       
   323 	 93,  96, // { | } ~ medium
       
   324 	541, 544, // { | } ~ large
       
   325 	SPR_HOUSE_ICON, SPR_HOUSE_ICON,
       
   326 	585, 585, // § large
       
   327 	587, 587, // © large
       
   328 	592, 592, // ® large
       
   329 	594, 597, // ° ± ² ³ large
       
   330 	633, 633, // × large
       
   331 	665, 665, // ÷ large
       
   332 	SPR_SELL_TRAIN, SPR_SHARED_ORDERS_ICON,
       
   333 	377, 377, // · small
       
   334 	153, 153, // · medium
       
   335 	601, 601, // · large
       
   336 	END
       
   337 };
       
   338 
       
   339 
       
   340 static void LoadSpriteTables(void)
       
   341 {
       
   342 	const FileList* files = _use_dos_palette ? &files_dos : &files_win;
       
   343 	uint load_index;
       
   344 	uint i;
       
   345 
       
   346 	LoadGrfIndexed(files->basic[0].filename, trg1idx, 0);
       
   347 	DupSprite(  2, 130); // non-breaking space medium
       
   348 	DupSprite(226, 354); // non-breaking space tiny
       
   349 	DupSprite(450, 578); // non-breaking space large
       
   350 	load_index = 4793;
       
   351 
       
   352 	for (i = 1; files->basic[i].filename != NULL; i++) {
       
   353 		load_index += LoadGrfFile(files->basic[i].filename, load_index, i);
       
   354 	}
       
   355 
       
   356 	/* Load additional sprites for climates other than temperate */
       
   357 	if (_opt.landscape != LT_NORMAL) {
       
   358 		LoadGrfIndexed(
       
   359 			files->landscape[_opt.landscape - 1].filename,
       
   360 			_landscape_spriteindexes[_opt.landscape - 1],
       
   361 			i++
       
   362 		);
       
   363 	}
       
   364 
       
   365 	assert(load_index == SPR_SIGNALS_BASE);
       
   366 	load_index += LoadGrfFile("nsignalsw.grf", load_index, i++);
       
   367 
       
   368 	assert(load_index == SPR_CANALS_BASE);
       
   369 	load_index += LoadGrfFile("canalsw.grf", load_index, i++);
       
   370 
       
   371 	assert(load_index == SPR_SLOPES_BASE);
       
   372 	LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
       
   373 
       
   374 	load_index = SPR_AUTORAIL_BASE;
       
   375 	load_index += LoadGrfFile("autorail.grf", load_index, i++);
       
   376 
       
   377 	assert(load_index == SPR_ELRAIL_BASE);
       
   378 	load_index += LoadGrfFile("elrailsw.grf", load_index, i++);
       
   379 
       
   380 	assert(load_index == SPR_2CCMAP_BASE);
       
   381 	load_index += LoadGrfFile("2ccmap.grf", load_index, i++);
       
   382 
       
   383 	assert(load_index == SPR_OPENTTD_BASE);
       
   384 	LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++);
       
   385 	load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT;
       
   386 
       
   387 	assert(load_index == SPR_AIRPORTX_BASE);
       
   388 	load_index += LoadGrfFile("airports.grf", load_index, i++);
       
   389 
       
   390 	/* Initialize the unicode to sprite mapping table */
       
   391 	InitializeUnicodeGlyphMap();
       
   392 
       
   393 	LoadNewGRF(load_index, i);
       
   394 }
       
   395 
       
   396 
       
   397 void GfxLoadSprites(void)
       
   398 {
       
   399 	DEBUG(sprite, 2, "Loading sprite set %d", _opt.landscape);
       
   400 
       
   401 	GfxInitSpriteMem();
       
   402 	LoadSpriteTables();
       
   403 	GfxInitPalettes();
       
   404 }