2005-08-14 20:10:18 +02:00
/* $Id$ */
2009-08-21 22:21:05 +02:00
/*
* This file is part of OpenTTD .
* 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.
* 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 .
* 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/>.
*/
2008-05-06 17:11:33 +02:00
/** @file gfxinit.cpp Initializing of the (GRF) graphics. */
2007-03-01 02:24:44 +01:00
2005-08-14 20:10:18 +02:00
# include "stdafx.h"
# include "debug.h"
# include "spritecache.h"
2007-10-30 00:02:31 +01:00
# include "fios.h"
2005-08-14 20:10:18 +02:00
# include "newgrf.h"
2009-08-21 22:15:17 +02:00
# include "3rdparty/md5/md5.h"
2006-11-24 21:47:29 +01:00
# include "fontcache.h"
2007-12-23 11:56:02 +01:00
# include "gfx_func.h"
2008-01-13 15:37:30 +01:00
# include "settings_type.h"
2009-08-09 18:54:03 +02:00
/* The type of set we're replacing */
# define SET_TYPE "graphics"
# include "base_media_func.h"
2005-08-14 20:10:18 +02:00
2008-01-13 02:21:35 +01:00
# include "table/sprites.h"
2008-09-02 20:45:15 +02:00
# include "table/palette_convert.h"
2008-01-13 02:21:35 +01:00
2008-08-31 10:46:43 +02:00
/** The currently used palette */
2008-08-24 11:48:21 +02:00
PaletteType _use_palette = PAL_AUTODETECT ;
2008-09-02 20:45:15 +02:00
/** Whether the given NewGRFs must get a palette remap or not. */
bool _palette_remap_grf [ MAX_FILE_SLOTS ] ;
/** Palette map to go from the !_use_palette to the _use_palette */
const byte * _palette_remap = NULL ;
/** Palette map to go from the _use_palette to the !_use_palette */
const byte * _palette_reverse_remap = NULL ;
2005-08-14 20:10:18 +02:00
# include "table/landscape_sprite.h"
static const SpriteID * const _landscape_spriteindexes [ ] = {
_landscape_spriteindexes_1 ,
_landscape_spriteindexes_2 ,
_landscape_spriteindexes_3 ,
} ;
2007-11-08 00:29:43 +01:00
static uint LoadGrfFile ( const char * filename , uint load_index , int file_index )
2005-08-14 20:10:18 +02:00
{
2005-08-15 13:39:13 +02:00
uint load_index_org = load_index ;
2007-06-14 16:31:48 +02:00
uint sprite_id = 0 ;
2005-08-14 20:10:18 +02:00
FioOpenFile ( file_index , filename ) ;
2006-12-26 18:36:18 +01:00
DEBUG ( sprite , 2 , " Reading grf-file '%s' " , filename ) ;
2005-08-14 20:10:18 +02:00
2007-06-14 16:31:48 +02:00
while ( LoadNextSprite ( load_index , file_index , sprite_id ) ) {
2005-08-14 20:10:18 +02:00
load_index + + ;
2007-06-14 16:31:48 +02:00
sprite_id + + ;
2005-08-14 20:10:18 +02:00
if ( load_index > = MAX_SPRITES ) {
2008-06-05 22:54:52 +02:00
usererror ( " Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files. " ) ;
2005-08-14 20:10:18 +02:00
}
}
2006-12-26 18:36:18 +01:00
DEBUG ( sprite , 2 , " Currently %i sprites are loaded " , load_index ) ;
2005-08-14 20:10:18 +02:00
return load_index - load_index_org ;
}
2007-10-20 23:39:50 +02:00
void LoadSpritesIndexed ( int file_index , uint * sprite_id , const SpriteID * index_tbl )
2005-08-14 20:10:18 +02:00
{
2005-08-15 13:39:13 +02:00
uint start ;
2005-11-03 16:25:45 +01:00
while ( ( start = * index_tbl + + ) ! = END ) {
2005-08-15 13:39:13 +02:00
uint end = * index_tbl + + ;
2008-01-28 18:51:45 +01:00
do {
bool b = LoadNextSprite ( start , file_index , * sprite_id ) ;
assert ( b ) ;
( * sprite_id ) + + ;
} while ( + + start < = end ) ;
2005-08-14 20:10:18 +02:00
}
}
2009-01-10 01:31:47 +01:00
static void LoadGrfIndexed ( const char * filename , const SpriteID * index_tbl , int file_index )
2007-10-20 23:39:50 +02:00
{
uint sprite_id = 0 ;
FioOpenFile ( file_index , filename ) ;
DEBUG ( sprite , 2 , " Reading indexed grf-file '%s' " , filename ) ;
LoadSpritesIndexed ( file_index , & sprite_id , index_tbl ) ;
}
2007-11-08 00:29:43 +01:00
/**
* Checks whether the MD5 checksums of the files are correct .
*
* @ note Also checks sample . cat and other required non - NewGRF GRFs for corruption .
*/
void CheckExternalFiles ( )
{
2009-08-09 21:50:44 +02:00
if ( BaseGraphics : : GetUsedSet ( ) = = NULL | | BaseSounds : : GetUsedSet ( ) = = NULL ) return ;
2009-08-09 18:54:03 +02:00
BaseGraphics : : DeterminePalette ( ) ;
const GraphicsSet * used_set = BaseGraphics : : GetUsedSet ( ) ;
2007-11-08 00:29:43 +01:00
2009-08-09 18:54:03 +02:00
DEBUG ( grf , 1 , " Using the %s base graphics set with the %s palette " , used_set - > name , _use_palette = = PAL_DOS ? " DOS " : " Windows " ) ;
2008-09-02 20:45:15 +02:00
2009-08-20 17:37:24 +02:00
static const size_t ERROR_MESSAGE_LENGTH = 256 ;
static const size_t MISSING_FILE_MESSAGE_LENGTH = 128 ;
/* Allocate for a message for each missing file and for one error
* message per set .
*/
char error_msg [ MISSING_FILE_MESSAGE_LENGTH * ( GraphicsSet : : NUM_FILES + SoundsSet : : NUM_FILES ) + 2 * ERROR_MESSAGE_LENGTH ] ;
2007-11-08 00:29:43 +01:00
error_msg [ 0 ] = ' \0 ' ;
char * add_pos = error_msg ;
2008-10-28 15:42:31 +01:00
const char * last = lastof ( error_msg ) ;
2007-11-08 00:29:43 +01:00
2009-08-20 19:02:44 +02:00
if ( used_set - > GetNumInvalid ( ) ! = 0 ) {
2009-08-20 17:37:24 +02:00
/* Not all files were loaded succesfully, see which ones */
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. \n \n The following files are corrupted or missing: \n " , used_set - > name ) ;
for ( uint i = 0 ; i < GraphicsSet : : NUM_FILES ; i + + ) {
2009-08-20 19:02:44 +02:00
MD5File : : ChecksumResult res = used_set - > files [ i ] . CheckMD5 ( ) ;
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 ) ;
2007-11-08 00:29:43 +01:00
}
2009-08-20 17:37:24 +02:00
add_pos + = seprintf ( add_pos , last , " \n " ) ;
2007-11-08 00:29:43 +01:00
}
2009-08-09 21:50:44 +02:00
const SoundsSet * sounds_set = BaseSounds : : GetUsedSet ( ) ;
2009-08-20 19:02:44 +02:00
if ( sounds_set - > GetNumInvalid ( ) ! = 0 ) {
2009-08-20 17:37:24 +02:00
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. \n \n The following files are corrupted or missing: \n " , sounds_set - > name ) ;
assert_compile ( SoundsSet : : NUM_FILES = = 1 ) ;
/* No need to loop each file, as long as there is only a single
* sound file . */
2009-08-20 19:02:44 +02:00
add_pos + = seprintf ( add_pos , last , " \t %s is %s (%s) \n " , sounds_set - > files - > filename , sounds_set - > files - > CheckMD5 ( ) = = MD5File : : CR_MISMATCH ? " corrupt " : " missing " , sounds_set - > files - > missing_warning ) ;
2007-11-08 00:29:43 +01:00
}
2009-05-10 19:27:25 +02:00
if ( add_pos ! = error_msg ) ShowInfoF ( " %s " , error_msg ) ;
2007-11-08 00:29:43 +01:00
}
2005-08-15 13:39:13 +02:00
2007-03-07 12:47:46 +01:00
static void LoadSpriteTables ( )
2005-08-14 20:10:18 +02:00
{
2008-09-02 20:45:15 +02:00
memset ( _palette_remap_grf , 0 , sizeof ( _palette_remap_grf ) ) ;
2007-10-30 00:02:31 +01:00
uint i = FIRST_GRF_SLOT ;
2009-08-09 18:54:03 +02:00
const GraphicsSet * used_set = BaseGraphics : : GetUsedSet ( ) ;
2005-08-14 20:10:18 +02:00
2009-08-09 18:54:03 +02:00
_palette_remap_grf [ i ] = ( _use_palette ! = used_set - > palette ) ;
LoadGrfFile ( used_set - > files [ GFT_BASE ] . filename , 0 , i + + ) ;
2005-08-20 20:14:32 +02:00
2007-11-08 00:29:43 +01:00
/*
* The second basic file always starts at the given location and does
* contain a different amount of sprites depending on the " type " ; DOS
* has a few sprites less . However , we do not care about those missing
* sprites as they are not shown anyway ( logos in intro game ) .
*/
2009-08-09 18:54:03 +02:00
_palette_remap_grf [ i ] = ( _use_palette ! = used_set - > palette ) ;
LoadGrfFile ( used_set - > files [ GFT_LOGOS ] . filename , 4793 , i + + ) ;
2005-08-14 20:10:18 +02:00
2007-11-08 00:29:43 +01:00
/*
* Load additional sprites for climates other than temperate .
* This overwrites some of the temperate sprites , such as foundations
* and the ground sprites .
*/
2008-05-29 17:13:28 +02:00
if ( _settings_game . game_creation . landscape ! = LT_TEMPERATE ) {
2009-08-09 18:54:03 +02:00
_palette_remap_grf [ i ] = ( _use_palette ! = used_set - > palette ) ;
2005-08-14 20:10:18 +02:00
LoadGrfIndexed (
2009-08-09 18:54:03 +02:00
used_set - > files [ GFT_ARCTIC + _settings_game . game_creation . landscape - 1 ] . filename ,
2008-05-29 17:13:28 +02:00
_landscape_spriteindexes [ _settings_game . game_creation . landscape - 1 ] ,
2005-08-14 20:10:18 +02:00
i + +
) ;
}
2006-11-24 21:47:29 +01:00
/* Initialize the unicode to sprite mapping table */
InitializeUnicodeGlyphMap ( ) ;
2007-11-15 08:42:25 +01:00
/*
* Load the base NewGRF with OTTD required graphics as first NewGRF .
* However , we do not want it to show up in the list of used NewGRFs ,
* so we have to manually add it , and then remove it later .
*/
GRFConfig * top = _grfconfig ;
GRFConfig * master = CallocT < GRFConfig > ( 1 ) ;
2009-08-09 18:54:03 +02:00
master - > filename = strdup ( used_set - > files [ GFT_EXTRA ] . filename ) ;
2007-11-15 08:42:25 +01:00
FillGRFDetails ( master , false ) ;
2009-08-09 18:54:03 +02:00
master - > windows_paletted = ( used_set - > palette = = PAL_WINDOWS ) ;
2007-11-19 22:32:20 +01:00
ClrBit ( master - > flags , GCF_INIT_ONLY ) ;
2007-11-15 08:42:25 +01:00
master - > next = top ;
_grfconfig = master ;
LoadNewGRF ( SPR_NEWGRFS_BASE , i ) ;
/* Free and remove the top element. */
ClearGRFConfig ( & master ) ;
_grfconfig = top ;
2005-08-14 20:10:18 +02:00
}
2007-03-07 12:47:46 +01:00
void GfxLoadSprites ( )
2005-08-14 20:10:18 +02:00
{
2008-05-29 17:13:28 +02:00
DEBUG ( sprite , 2 , " Loading sprite set %d " , _settings_game . game_creation . landscape ) ;
2005-08-14 20:10:18 +02:00
2006-11-24 13:39:13 +01:00
GfxInitSpriteMem ( ) ;
LoadSpriteTables ( ) ;
GfxInitPalettes ( ) ;
2005-08-14 20:10:18 +02:00
}
2008-08-24 10:41:38 +02:00
2009-08-09 18:54:03 +02:00
bool GraphicsSet : : FillSetDetails ( IniFile * ini , const char * path )
2008-08-31 10:46:43 +02:00
{
2009-08-09 18:54:03 +02:00
bool ret = this - > BaseSet < GraphicsSet , MAX_GFT > : : FillSetDetails ( ini , path ) ;
if ( ret ) {
IniGroup * metadata = ini - > GetGroup ( " metadata " ) ;
IniItem * item ;
2008-08-31 10:46:43 +02:00
2009-08-09 18:54:03 +02:00
fetch_metadata ( " palette " ) ;
this - > palette = ( * item - > value = = ' D ' | | * item - > value = = ' d ' ) ? PAL_DOS : PAL_WINDOWS ;
2008-08-31 10:46:43 +02:00
}
return true ;
}
/**
2009-08-09 18:54:03 +02:00
* Calculate and check the MD5 hash of the supplied filename .
2009-08-20 19:02:44 +02:00
* @ return
* CR_MATCH if the MD5 hash matches
* CR_MISMATCH if the MD5 does not match
* CR_NO_FILE if the file misses
2008-08-31 10:46:43 +02:00
*/
2009-08-20 19:02:44 +02:00
MD5File : : ChecksumResult MD5File : : CheckMD5 ( ) const
2008-08-24 10:41:38 +02:00
{
2009-08-09 18:54:03 +02:00
size_t size ;
FILE * f = FioFOpenFile ( this - > filename , " rb " , DATA_DIR , & size ) ;
2008-08-31 10:46:43 +02:00
2009-08-20 19:02:44 +02:00
if ( f = = NULL ) return CR_NO_FILE ;
2008-08-24 10:41:38 +02:00
2009-08-20 19:02:44 +02:00
Md5 checksum ;
uint8 buffer [ 1024 ] ;
uint8 digest [ 16 ] ;
size_t len ;
2008-08-24 10:41:38 +02:00
2009-08-20 19:02:44 +02:00
while ( ( len = fread ( buffer , 1 , ( size > sizeof ( buffer ) ) ? sizeof ( buffer ) : size , f ) ) ! = 0 & & size ! = 0 ) {
size - = len ;
checksum . Append ( buffer , len ) ;
2008-08-24 10:41:38 +02:00
}
2009-08-20 19:02:44 +02:00
FioFCloseFile ( f ) ;
checksum . Finish ( digest ) ;
return memcmp ( this - > hash , digest , sizeof ( this - > hash ) ) = = 0 ? CR_MATCH : CR_MISMATCH ;
2008-08-24 10:41:38 +02:00
}
2009-08-09 18:54:03 +02:00
/** Names corresponding to the GraphicsFileType */
2009-09-21 01:11:01 +02:00
static const char * const _graphics_file_names [ ] = { " base " , " logos " , " arctic " , " tropical " , " toyland " , " extra " } ;
2009-08-10 12:25:40 +02:00
/** Implementation */
2009-08-09 18:54:03 +02:00
template < class T , size_t Tnum_files >
2009-09-21 01:11:01 +02:00
/* static */ const char * const * BaseSet < T , Tnum_files > : : file_names = _graphics_file_names ;
2009-01-17 17:53:32 +01:00
2009-08-09 18:54:03 +02:00
extern void UpdateNewGRFConfigPalette ( ) ;
2009-01-17 17:53:32 +01:00
/**
2009-08-09 18:54:03 +02:00
* Determine the palette that has to be used .
* - forced palette via command line - > leave it that way
* - otherwise - > palette based on the graphics pack
2009-01-17 17:53:32 +01:00
*/
2009-08-09 18:54:03 +02:00
/* static */ void BaseGraphics : : DeterminePalette ( )
2009-01-17 17:53:32 +01:00
{
2009-08-09 18:54:03 +02:00
assert ( BaseGraphics : : used_set ! = NULL ) ;
if ( _use_palette > = MAX_PAL ) _use_palette = BaseGraphics : : used_set - > palette ;
2009-01-17 17:53:32 +01:00
2009-08-09 18:54:03 +02:00
switch ( _use_palette ) {
case PAL_DOS :
_palette_remap = _palmap_w2d ;
_palette_reverse_remap = _palmap_d2w ;
break ;
2009-01-17 17:53:32 +01:00
2009-08-09 18:54:03 +02:00
case PAL_WINDOWS :
_palette_remap = _palmap_d2w ;
_palette_reverse_remap = _palmap_w2d ;
break ;
2009-02-07 02:01:02 +01:00
2009-08-09 18:54:03 +02:00
default :
NOT_REACHED ( ) ;
2009-02-07 02:01:02 +01:00
}
2009-08-09 18:54:03 +02:00
UpdateNewGRFConfigPalette ( ) ;
2009-02-07 02:01:02 +01:00
}
2009-08-09 18:54:03 +02:00
template < class Tbase_set >
/* static */ bool BaseMedia < Tbase_set > : : DetermineBestSet ( )
2009-02-07 02:01:02 +01:00
{
2009-08-09 18:54:03 +02:00
if ( BaseMedia < Tbase_set > : : used_set ! = NULL ) return true ;
2009-08-20 19:02:44 +02:00
const Tbase_set * best = NULL ;
2009-08-09 18:54:03 +02:00
for ( const Tbase_set * c = BaseMedia < Tbase_set > : : available_sets ; c ! = NULL ; c = c - > next ) {
2009-08-20 19:02:44 +02:00
/* Skip unuseable sets */
if ( c - > GetNumMissing ( ) ! = 0 ) continue ;
if ( best = = NULL | |
best - > valid_files < c - > valid_files | |
( best - > valid_files = = c - > valid_files & & (
2009-08-09 18:54:03 +02:00
( best - > shortname = = c - > shortname & & best - > version < c - > version ) | |
( best - > palette ! = _use_palette & & c - > palette = = _use_palette ) ) ) ) {
best = c ;
}
2009-02-07 02:01:02 +01:00
}
2009-05-17 20:21:21 +02:00
2009-08-09 18:54:03 +02:00
BaseMedia < Tbase_set > : : used_set = best ;
return BaseMedia < Tbase_set > : : used_set ! = NULL ;
2009-05-17 20:21:21 +02:00
}
2009-08-09 18:54:03 +02:00
template < class Tbase_set >
/* static */ const char * BaseMedia < Tbase_set > : : GetExtension ( )
2009-05-17 20:21:21 +02:00
{
2009-08-09 18:54:03 +02:00
return " .obg " ; // OpenTTD Base Graphics
2009-05-17 20:21:21 +02:00
}
2009-08-09 18:54:03 +02:00
INSTANTIATE_BASE_MEDIA_METHODS ( BaseMedia < GraphicsSet > , GraphicsSet )