242 #endif |
211 #endif |
243 |
212 |
244 return true; |
213 return true; |
245 } |
214 } |
246 |
215 |
247 static void SkipSprites(uint count) |
216 void SkipSprites(uint count) |
248 { |
217 { |
249 for (; count > 0; --count) { |
218 for (; count > 0; --count) { |
250 if (!ReadSpriteHeaderSkipData(MAX_SPRITES - 1)) return; |
219 if (!ReadSpriteHeaderSkipData(MAX_SPRITES - 1)) return; |
251 } |
|
252 } |
|
253 |
|
254 static int LoadGrfFile(const char *filename, int load_index, int file_index) |
|
255 { |
|
256 int load_index_org = load_index; |
|
257 |
|
258 FioOpenFile(file_index, filename); |
|
259 |
|
260 /* Thou shalt use LoadNewGrfFile() if thou loadeth a GRF file that |
|
261 * might contain some special sprites. */ |
|
262 _skip_specials = 1; |
|
263 _skip_sprites = 0; |
|
264 |
|
265 DEBUG(spritecache, 2) ("Reading grf-file ``%s''", filename); |
|
266 |
|
267 while (LoadNextSprite(load_index, file_index)) { |
|
268 load_index++; |
|
269 if (load_index >= MAX_SPRITES) { |
|
270 error("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files."); |
|
271 } |
|
272 } |
|
273 DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index); |
|
274 |
|
275 return load_index - load_index_org; |
|
276 } |
|
277 |
|
278 static int LoadNewGrfFile(const char *filename, int load_index, int file_index) |
|
279 { |
|
280 int i; |
|
281 |
|
282 FioOpenFile(file_index, filename); |
|
283 _cur_grffile = filename; |
|
284 _skip_specials = 0; |
|
285 _skip_sprites = 0; |
|
286 |
|
287 DEBUG(spritecache, 2) ("Reading newgrf-file ``%s'' [offset: %u]", |
|
288 filename, load_index); |
|
289 |
|
290 /* Skip the first sprite; we don't care about how many sprites this |
|
291 * does contain; newest TTDPatches and George's longvehicles don't |
|
292 * neither, apparently. */ |
|
293 { |
|
294 int length; |
|
295 byte type; |
|
296 |
|
297 length = FioReadWord(); |
|
298 type = FioReadByte(); |
|
299 |
|
300 if (length == 4 && type == 0xFF) { |
|
301 FioReadDword(); |
|
302 } else { |
|
303 error("Custom .grf has invalid format."); |
|
304 } |
|
305 } |
|
306 |
|
307 for (i = 0; LoadNextSprite(load_index + i, file_index); i++) { |
|
308 if (load_index + i >= MAX_SPRITES) |
|
309 error("Too many sprites (0x%X). Recompile with higher MAX_SPRITES value or remove some custom GRF files.", |
|
310 load_index + i); |
|
311 } |
|
312 |
|
313 /* Clean up. */ |
|
314 _skip_sprites = 0; |
|
315 memset(_replace_sprites_count, 0, sizeof(_replace_sprites_count)); |
|
316 memset(_replace_sprites_offset, 0, sizeof(_replace_sprites_offset)); |
|
317 |
|
318 return i; |
|
319 } |
|
320 |
|
321 static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int file_index) |
|
322 { |
|
323 int start; |
|
324 |
|
325 FioOpenFile(file_index, filename); |
|
326 _skip_specials = 1; |
|
327 _skip_sprites = 0; |
|
328 |
|
329 DEBUG(spritecache, 2) ("Reading indexed grf-file ``%s''", filename); |
|
330 |
|
331 for (; (start = *index_tbl++) != 0xffff;) { |
|
332 int end = *index_tbl++; |
|
333 if(start == 0xfffe) { // skip sprites (amount in second var) |
|
334 SkipSprites(end); |
|
335 } else { // load sprites and use indexes from start to end |
|
336 do { |
|
337 #ifdef NDEBUG |
|
338 LoadNextSprite(start, file_index); |
|
339 #else |
|
340 bool b = LoadNextSprite(start, file_index); |
|
341 assert(b); |
|
342 #endif |
|
343 } while (++start <= end); |
|
344 } |
|
345 } |
220 } |
346 } |
221 } |
347 |
222 |
348 |
223 |
349 #define S_FREE_MASK 1 |
224 #define S_FREE_MASK 1 |
605 // Load the sprite, if it is not loaded, yet |
480 // Load the sprite, if it is not loaded, yet |
606 if (p == NULL) p = ReadSprite(sprite); |
481 if (p == NULL) p = ReadSprite(sprite); |
607 return p; |
482 return p; |
608 } |
483 } |
609 |
484 |
610 byte _sprite_page_to_load = 0xFF; |
485 |
611 |
486 void GfxInitSpriteMem(void) |
612 #define OPENTTD_SPRITES_COUNT 100 |
|
613 static const SpriteID _openttd_grf_indexes[] = { |
|
614 SPR_OPENTTD_BASE + 0, SPR_OPENTTD_BASE + 7, // icons etc |
|
615 134, 134, // euro symbol medium size |
|
616 582, 582, // euro symbol large size |
|
617 358, 358, // euro symbol tiny |
|
618 SPR_OPENTTD_BASE+11, SPR_OPENTTD_BASE+57, // more icons |
|
619 648, 648, // nordic char: æ |
|
620 616, 616, // nordic char: Æ |
|
621 666, 666, // nordic char: ø |
|
622 634, 634, // nordic char: Ø |
|
623 SPR_OPENTTD_BASE+62, SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT, // more icons |
|
624 0xffff, |
|
625 }; |
|
626 |
|
627 /* FUNCTIONS FOR CHECKING MD5 SUMS OF GRF FILES */ |
|
628 |
|
629 /* Check that the supplied MD5 hash matches that stored for the supplied filename */ |
|
630 static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn) |
|
631 { |
|
632 uint i; |
|
633 |
|
634 /* Loop through each byte of the file MD5 and the stored MD5... */ |
|
635 for (i = 0; i < 16; i++) if (file.hash[i] != digest[i]) break; |
|
636 |
|
637 /* If all bytes of the MD5's match (i.e. the MD5's match)... */ |
|
638 if (i == 16) { |
|
639 return true; |
|
640 } else { |
|
641 if (warn) fprintf(stderr, "MD5 of %s is ****INCORRECT**** - File Corrupt.\n", file.filename); |
|
642 return false; |
|
643 }; |
|
644 } |
|
645 |
|
646 /* Calculate and check the MD5 hash of the supplied filename. |
|
647 * returns true if the checksum is correct */ |
|
648 static bool FileMD5(const MD5File file, bool warn) |
|
649 { |
|
650 FILE *f; |
|
651 char buf[MAX_PATH]; |
|
652 |
|
653 // open file |
|
654 sprintf(buf, "%s%s", _path.data_dir, file.filename); |
|
655 f = fopen(buf, "rb"); |
|
656 |
|
657 #if !defined(WIN32) |
|
658 if (f == NULL) { |
|
659 char *s; |
|
660 // make lower case and check again |
|
661 for (s = buf + strlen(_path.data_dir) - 1; *s != '\0'; s++) |
|
662 *s = tolower(*s); |
|
663 f = fopen(buf, "rb"); |
|
664 } |
|
665 #endif |
|
666 |
|
667 if (f != NULL) { |
|
668 md5_state_t filemd5state; |
|
669 md5_byte_t buffer[1024]; |
|
670 md5_byte_t digest[16]; |
|
671 size_t len; |
|
672 |
|
673 md5_init(&filemd5state); |
|
674 while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) |
|
675 md5_append(&filemd5state, buffer, len); |
|
676 |
|
677 if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf); |
|
678 fclose(f); |
|
679 |
|
680 md5_finish(&filemd5state, digest); |
|
681 return CheckMD5Digest(file, digest, warn); |
|
682 } else { // file not found |
|
683 return false; |
|
684 } |
|
685 } |
|
686 |
|
687 /* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF) |
|
688 * by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly. |
|
689 * If neither are found, Windows palette is assumed. |
|
690 * |
|
691 * (Note: Also checks sample.cat for corruption) */ |
|
692 void CheckExternalFiles(void) |
|
693 { |
|
694 uint i; |
|
695 // count of files from this version |
|
696 uint dos = 0; |
|
697 uint win = 0; |
|
698 |
|
699 for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++; |
|
700 for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++; |
|
701 |
|
702 for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++; |
|
703 for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++; |
|
704 |
|
705 if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false)) |
|
706 fprintf(stderr, "Your sample.cat file is corrupted or missing!\n"); |
|
707 |
|
708 /* |
|
709 * forced DOS palette via command line -> leave it that way |
|
710 * all Windows files present -> Windows palette |
|
711 * all DOS files present -> DOS palette |
|
712 * no Windows files present and any DOS file present -> DOS palette |
|
713 * otherwise -> Windows palette |
|
714 */ |
|
715 if (_use_dos_palette) { |
|
716 return; |
|
717 } else if (win == 5) { |
|
718 _use_dos_palette = false; |
|
719 } else if (dos == 5 || (win == 0 && dos > 0)) { |
|
720 _use_dos_palette = true; |
|
721 } else { |
|
722 _use_dos_palette = false; |
|
723 } |
|
724 } |
|
725 |
|
726 static void LoadSpriteTables(void) |
|
727 { |
|
728 int load_index = 0; |
|
729 uint i; |
|
730 uint j; |
|
731 const FileList *files; // list of grf files to be loaded. Either Windows files or DOS files |
|
732 |
|
733 _loading_stage = 1; |
|
734 |
|
735 /* |
|
736 * TODO: |
|
737 * I think we can live entirely without Indexed GRFs, but I have to |
|
738 * invest that further. --octo |
|
739 */ |
|
740 |
|
741 files = _use_dos_palette? &files_dos : &files_win; |
|
742 |
|
743 for (i = 0; files->basic[i].filename != NULL; i++) { |
|
744 load_index += LoadGrfFile(files->basic[i].filename, load_index, i); |
|
745 } |
|
746 |
|
747 LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++); |
|
748 |
|
749 if (_sprite_page_to_load != 0) { |
|
750 LoadGrfIndexed( |
|
751 files->landscape[_sprite_page_to_load - 1].filename, |
|
752 _landscape_spriteindexes[_sprite_page_to_load - 1], |
|
753 i++ |
|
754 ); |
|
755 } |
|
756 |
|
757 LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++); |
|
758 |
|
759 load_index = SPR_AUTORAIL_BASE; |
|
760 load_index += LoadGrfFile("autorail.grf", load_index, i++); |
|
761 |
|
762 load_index = SPR_CANALS_BASE; |
|
763 load_index += LoadGrfFile("canalsw.grf", load_index, i++); |
|
764 |
|
765 load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT + 1; |
|
766 |
|
767 |
|
768 /* Load newgrf sprites |
|
769 * in each loading stage, (try to) open each file specified in the config |
|
770 * and load information from it. */ |
|
771 _custom_sprites_base = load_index; |
|
772 for (_loading_stage = 0; _loading_stage < 2; _loading_stage++) { |
|
773 load_index = _custom_sprites_base; |
|
774 for (j = 0; j != lengthof(_newgrf_files) && _newgrf_files[j]; j++) { |
|
775 if (!FiosCheckFileExists(_newgrf_files[j])) { |
|
776 // TODO: usrerror() |
|
777 error("NewGRF file missing: %s", _newgrf_files[j]); |
|
778 } |
|
779 if (_loading_stage == 0) InitNewGRFFile(_newgrf_files[j], load_index); |
|
780 load_index += LoadNewGrfFile(_newgrf_files[j], load_index, i++); |
|
781 DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index); |
|
782 } |
|
783 } |
|
784 |
|
785 _compact_cache_counter = 0; |
|
786 } |
|
787 |
|
788 static void GfxInitSpriteMem(void) |
|
789 { |
487 { |
790 // initialize sprite cache heap |
488 // initialize sprite cache heap |
791 if (_spritecache_ptr == NULL) _spritecache_ptr = malloc(SPRITE_CACHE_SIZE); |
489 if (_spritecache_ptr == NULL) _spritecache_ptr = malloc(SPRITE_CACHE_SIZE); |
792 |
490 |
793 // A big free block |
491 // A big free block |
794 _spritecache_ptr->size = (SPRITE_CACHE_SIZE - sizeof(MemBlock)) | S_FREE_MASK; |
492 _spritecache_ptr->size = (SPRITE_CACHE_SIZE - sizeof(MemBlock)) | S_FREE_MASK; |
795 // Sentinel block (identified by size == 0) |
493 // Sentinel block (identified by size == 0) |
796 NextBlock(_spritecache_ptr)->size = 0; |
494 NextBlock(_spritecache_ptr)->size = 0; |
797 |
495 |
798 memset(_sprite_ptr, 0, sizeof(_sprite_ptr)); |
496 memset(_sprite_ptr, 0, sizeof(_sprite_ptr)); |
799 } |
497 |
800 |
498 _compact_cache_counter = 0; |
801 |
499 } |
802 void GfxLoadSprites(void) |
|
803 { |
|
804 // Need to reload the sprites only if the landscape changed |
|
805 if (_sprite_page_to_load != _opt.landscape) { |
|
806 _sprite_page_to_load = _opt.landscape; |
|
807 |
|
808 // Sprite cache |
|
809 DEBUG(spritecache, 1) ("Loading sprite set %d.", _sprite_page_to_load); |
|
810 |
|
811 GfxInitSpriteMem(); |
|
812 LoadSpriteTables(); |
|
813 GfxInitPalettes(); |
|
814 } |
|
815 } |
|