2005-08-14 20:10:18 +02:00
/* $Id$ */
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 "openttd.h"
# include "debug.h"
# include "gfxinit.h"
# include "spritecache.h"
# include "fileio.h"
2007-10-30 00:02:31 +01:00
# include "fios.h"
2005-08-14 20:10:18 +02:00
# include "newgrf.h"
# include "md5.h"
# include "variables.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-07 15:02:26 +01:00
# include "core/alloc_func.hpp"
2008-01-09 22:05:03 +01:00
# include "core/bitmath_func.hpp"
2006-08-31 09:52:20 +02:00
# include <string.h>
2008-01-13 15:37:30 +01:00
# include "settings_type.h"
2008-08-24 10:41:38 +02:00
# include "string_func.h"
2005-08-14 20:10:18 +02:00
2008-01-13 02:21:35 +01:00
# include "table/sprites.h"
2008-08-23 22:16:54 +02:00
Palette _use_palette = PAL_AUTODETECT ;
2007-03-07 13:11:48 +01:00
struct MD5File {
2007-03-01 02:24:44 +01:00
const char * filename ; ///< filename
2007-12-25 14:59:21 +01:00
uint8 hash [ 16 ] ; ///< md5 sum of the file
2007-03-07 13:11:48 +01:00
} ;
2005-08-14 20:10:18 +02:00
2008-08-24 10:41:38 +02:00
/**
* Information about a single graphics set .
*/
struct GraphicsSet {
const char * name ; ///< The name of the graphics set
const char * description ; ///< Description of the graphics set
Palette palette ; ///< Palette of this graphics set
MD5File basic [ 2 ] ; ///< GRF files that always have to be loaded
MD5File landscape [ 3 ] ; ///< Landscape specific grf files
const char * base_missing ; ///< Warning when one of the base GRF files is missing
MD5File extra ; ///< NewGRF File with extra graphics loaded using Action 05
const char * extra_missing ; ///< Warning when the extra (NewGRF) file is missing
uint found_grfs ; ///< Number of the GRFs that could be found
2007-03-07 13:11:48 +01:00
} ;
2005-08-14 20:10:18 +02:00
2008-08-24 10:41:38 +02:00
static const uint GRAPHICS_SET_GRF_COUNT = 6 ;
static int _use_graphics_set = - 1 ;
2005-08-14 20:10:18 +02:00
# include "table/files.h"
# 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
}
}
2007-10-20 23:39:50 +02:00
static void LoadGrfIndexed ( const char * filename , const SpriteID * index_tbl , int file_index )
{
uint sprite_id = 0 ;
FioOpenFile ( file_index , filename ) ;
DEBUG ( sprite , 2 , " Reading indexed grf-file '%s' " , filename ) ;
LoadSpritesIndexed ( file_index , & sprite_id , index_tbl ) ;
}
2005-08-14 20:10:18 +02:00
2007-11-08 00:29:43 +01:00
/**
* Calculate and check the MD5 hash of the supplied filename .
* @ param file filename and expected MD5 hash for the given filename .
* @ return true if the checksum is correct .
*/
static bool FileMD5 ( const MD5File file )
2005-08-14 20:10:18 +02:00
{
2007-09-13 20:46:29 +02:00
size_t size ;
FILE * f = FioFOpenFile ( file . filename , " rb " , DATA_DIR , & size ) ;
2007-01-02 21:39:07 +01:00
2005-08-14 20:10:18 +02:00
if ( f ! = NULL ) {
2007-12-25 14:59:21 +01:00
Md5 checksum ;
uint8 buffer [ 1024 ] ;
uint8 digest [ 16 ] ;
2005-08-14 20:10:18 +02:00
size_t len ;
2007-09-13 20:46:29 +02:00
while ( ( len = fread ( buffer , 1 , ( size > sizeof ( buffer ) ) ? sizeof ( buffer ) : size , f ) ) ! = 0 & & size ! = 0 ) {
size - = len ;
2007-12-25 14:59:21 +01:00
checksum . Append ( buffer , len ) ;
2007-09-13 20:46:29 +02:00
}
2005-08-14 20:10:18 +02:00
2007-09-16 20:10:52 +02:00
FioFCloseFile ( f ) ;
2005-08-14 20:10:18 +02:00
2007-12-25 14:59:21 +01:00
checksum . Finish ( digest ) ;
2007-11-08 00:29:43 +01:00
return memcmp ( file . hash , digest , sizeof ( file . hash ) ) = = 0 ;
2005-08-14 20:10:18 +02:00
} else { // file not found
return false ;
}
}
2007-11-08 00:29:43 +01:00
/**
2008-08-24 10:41:38 +02:00
* Determine the graphics pack that has to be used .
* The one with the most correct files wins .
2007-11-08 00:29:43 +01:00
*/
2008-08-24 10:41:38 +02:00
static void DetermineGraphicsPack ( )
2005-08-14 20:10:18 +02:00
{
2008-08-24 10:41:38 +02:00
if ( _use_graphics_set > = 0 ) return ;
2007-11-08 00:29:43 +01:00
2008-08-24 10:41:38 +02:00
uint max_index = 0 ;
for ( uint j = 1 ; j < lengthof ( _graphics_sets ) ; j + + ) {
if ( _graphics_sets [ max_index ] . found_grfs < _graphics_sets [ j ] . found_grfs ) max_index = j ;
}
2005-08-14 20:10:18 +02:00
2008-08-24 10:41:38 +02:00
_use_graphics_set = max_index ;
}
2005-08-14 20:10:18 +02:00
2008-08-24 10:41:38 +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
*/
static void DeterminePalette ( )
{
if ( _use_palette < MAX_PAL ) return ;
2006-10-24 12:15:56 +02:00
2008-08-24 10:41:38 +02:00
_use_palette = _graphics_sets [ _use_graphics_set ] . palette ;
2005-08-14 20:10:18 +02:00
}
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 ( )
{
2008-08-24 10:41:38 +02:00
DetermineGraphicsPack ( ) ;
2007-11-08 00:29:43 +01:00
DeterminePalette ( ) ;
static const size_t ERROR_MESSAGE_LENGTH = 128 ;
2008-08-24 10:41:38 +02:00
const GraphicsSet * graphics = & _graphics_sets [ _use_graphics_set ] ;
char error_msg [ ERROR_MESSAGE_LENGTH * ( GRAPHICS_SET_GRF_COUNT + 1 ) ] ;
2007-11-08 00:29:43 +01:00
error_msg [ 0 ] = ' \0 ' ;
char * add_pos = error_msg ;
2008-08-24 10:41:38 +02:00
for ( uint i = 0 ; i < lengthof ( graphics - > basic ) ; i + + ) {
if ( ! FileMD5 ( graphics - > basic [ i ] ) ) {
add_pos + = snprintf ( add_pos , ERROR_MESSAGE_LENGTH , " Your '%s' file is corrupted or missing! %s. \n " , graphics - > basic [ i ] . filename , graphics - > base_missing ) ;
2007-11-08 00:29:43 +01:00
}
}
2008-08-24 10:41:38 +02:00
for ( uint i = 0 ; i < lengthof ( graphics - > landscape ) ; i + + ) {
if ( ! FileMD5 ( graphics - > landscape [ i ] ) ) {
add_pos + = snprintf ( add_pos , ERROR_MESSAGE_LENGTH , " Your '%s' file is corrupted or missing! %s \n " , graphics - > landscape [ i ] . filename , graphics - > base_missing ) ;
2007-11-08 00:29:43 +01:00
}
}
2008-08-24 10:41:38 +02:00
bool sound = false ;
for ( uint i = 0 ; ! sound & & i < lengthof ( _sound_sets ) ; i + + ) {
sound = FileMD5 ( _sound_sets [ i ] ) ;
}
if ( ! sound ) {
2007-11-08 00:29:43 +01:00
add_pos + = snprintf ( add_pos , ERROR_MESSAGE_LENGTH , " Your 'sample.cat' file is corrupted or missing! You can find 'sample.cat' on your Transport Tycoon Deluxe CD-ROM. \n " ) ;
}
2008-08-24 10:41:38 +02:00
if ( ! FileMD5 ( graphics - > extra ) ) {
add_pos + = snprintf ( add_pos , ERROR_MESSAGE_LENGTH , " Your '%s' file is corrupted or missing! %s \n " , graphics - > extra . filename , graphics - > extra_missing ) ;
2007-11-08 00:29:43 +01:00
}
if ( add_pos ! = error_msg ) ShowInfoF ( error_msg ) ;
}
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-08-24 10:41:38 +02:00
const GraphicsSet * graphics = & _graphics_sets [ _use_graphics_set ] ;
2007-10-30 00:02:31 +01:00
uint i = FIRST_GRF_SLOT ;
2005-08-14 20:10:18 +02:00
2008-08-24 10:41:38 +02:00
LoadGrfFile ( graphics - > basic [ 0 ] . 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 ) .
*/
2008-08-24 10:41:38 +02:00
LoadGrfFile ( graphics - > basic [ 1 ] . 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 ) {
2005-08-14 20:10:18 +02:00
LoadGrfIndexed (
2008-08-24 10:41:38 +02:00
graphics - > landscape [ _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 ) ;
2008-08-24 10:41:38 +02:00
master - > filename = strdup ( graphics - > extra . filename ) ;
2007-11-15 08:42:25 +01:00
FillGRFDetails ( master , false ) ;
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
/**
* Find all graphics sets and populate their data .
*/
void FindGraphicsSets ( )
{
for ( uint j = 0 ; j < lengthof ( _graphics_sets ) ; j + + ) {
_graphics_sets [ j ] . found_grfs = 0 ;
for ( uint i = 0 ; i < lengthof ( _graphics_sets [ j ] . basic ) ; i + + ) {
if ( FioCheckFileExists ( _graphics_sets [ j ] . basic [ i ] . filename ) ) _graphics_sets [ j ] . found_grfs + + ;
}
for ( uint i = 0 ; i < lengthof ( _graphics_sets [ j ] . landscape ) ; i + + ) {
if ( FioCheckFileExists ( _graphics_sets [ j ] . landscape [ i ] . filename ) ) _graphics_sets [ j ] . found_grfs + + ;
}
if ( FioCheckFileExists ( _graphics_sets [ j ] . extra . filename ) ) _graphics_sets [ j ] . found_grfs + + ;
}
}
/**
* Set the graphics set to be used .
* @ param name of the graphics set to use
* @ return true if it could be loaded
*/
bool SetGraphicsSet ( const char * name )
{
if ( StrEmpty ( name ) ) {
DetermineGraphicsPack ( ) ;
CheckExternalFiles ( ) ;
return true ;
}
for ( uint i = 0 ; i < lengthof ( _graphics_sets ) ; i + + ) {
if ( strcmp ( name , _graphics_sets [ i ] . name ) = = 0 ) {
_use_graphics_set = i ;
CheckExternalFiles ( ) ;
return true ;
}
}
return false ;
}
/**
* Returns a list with the graphics sets .
* @ param p where to print to
* @ param last the last character to print to
* @ return the last printed character
*/
char * GetGraphicsSetsList ( char * p , const char * last )
{
p + = snprintf ( p , last - p , " List of graphics sets: \n " ) ;
for ( uint i = 0 ; i < lengthof ( _graphics_sets ) ; i + + ) {
if ( _graphics_sets [ i ] . found_grfs < = 1 ) continue ;
p + = snprintf ( p , last - p , " %18s: %s " , _graphics_sets [ i ] . name , _graphics_sets [ i ] . description ) ;
int difference = GRAPHICS_SET_GRF_COUNT - _graphics_sets [ i ] . found_grfs ;
if ( difference ! = 0 ) {
p + = snprintf ( p , last - p , " (missing %i file%s) \n " , difference , difference = = 1 ? " " : " s " ) ;
} else {
p + = snprintf ( p , last - p , " \n " ) ;
}
}
p + = snprintf ( p , last - p , " \n " ) ;
return p ;
}