spritecache.c
changeset 184 dbeaaaf8b2bb
parent 182 1641047f1d9f
child 361 95307fb1c3f8
equal deleted inserted replaced
183:ec2b02ea4c88 184:dbeaaaf8b2bb
    50 
    50 
    51 static const char * const _filename_list[] = {
    51 static const char * const _filename_list[] = {
    52 	"TRG1R.GRF",
    52 	"TRG1R.GRF",
    53 	"TRGIR.GRF",
    53 	"TRGIR.GRF",
    54 	"signalsw.grf", //0x1320 - 0x1405 inclusive
    54 	"signalsw.grf", //0x1320 - 0x1405 inclusive
    55 //	"openttd.grf",	//0x1406 - 
    55 //	"openttd.grf",	//0x1406 -
    56 	NULL
    56 	NULL
    57 };
    57 };
    58 
    58 
    59 static const char * const _landscape_filenames[] = {
    59 static const char * const _landscape_filenames[] = {
    60 	"TRGCR.GRF",
    60 	"TRGCR.GRF",
    91 	if (_skip_sprites) {
    91 	if (_skip_sprites) {
    92 		if (_skip_sprites > 0)
    92 		if (_skip_sprites > 0)
    93 			_skip_sprites--;
    93 			_skip_sprites--;
    94 		deaf = 1;
    94 		deaf = 1;
    95 	}
    95 	}
    96 	
    96 
    97 	type = FioReadByte();
    97 	type = FioReadByte();
    98 	if (type == 0xFF) {
    98 	if (type == 0xFF) {
    99 		/* We need to really skip only special sprites in the deaf
    99 		/* We need to really skip only special sprites in the deaf
   100 		 * mode.  It won't hurt to proceed regular sprites as usual
   100 		 * mode.  It won't hurt to proceed regular sprites as usual
   101 		 * because if no special sprite referencing to them is
   101 		 * because if no special sprite referencing to them is
   106 		} else {
   106 		} else {
   107 			DecodeSpecialSprite(_cur_grffile, num, load_index);
   107 			DecodeSpecialSprite(_cur_grffile, num, load_index);
   108 		}
   108 		}
   109 		return;
   109 		return;
   110 	}
   110 	}
   111 	
   111 
   112 	_cur_sprite.info = type;
   112 	_cur_sprite.info = type;
   113 #ifdef WANT_SPRITESIZES
   113 #ifdef WANT_SPRITESIZES
   114 	_cur_sprite.height = FioReadByte();
   114 	_cur_sprite.height = FioReadByte();
   115 	_cur_sprite.width = FioReadWord();
   115 	_cur_sprite.width = FioReadWord();
   116 	_cur_sprite.x_offs = FioReadWord();
   116 	_cur_sprite.x_offs = FioReadWord();
   144 {
   144 {
   145 	byte type;
   145 	byte type;
   146 	byte *rel;
   146 	byte *rel;
   147 	int8 i;
   147 	int8 i;
   148 	int j, dist;
   148 	int j, dist;
   149 	
   149 
   150 	type = FioReadByte();
   150 	type = FioReadByte();
   151 	/* We've decoded special sprites when reading headers. */
   151 	/* We've decoded special sprites when reading headers. */
   152 	if (type != 0xFF) {
   152 	if (type != 0xFF) {
   153 		/* read sprite hdr */
   153 		/* read sprite hdr */
   154 		*dest++ = type;
   154 		*dest++ = type;
   171 				*dest++ = FioReadByte();
   171 				*dest++ = FioReadByte();
   172 		} else {
   172 		} else {
   173 			dist = -(((i&7)<<8)|FioReadByte());
   173 			dist = -(((i&7)<<8)|FioReadByte());
   174 			i = -(i >> 3);
   174 			i = -(i >> 3);
   175 			num -= i;
   175 			num -= i;
   176 			
   176 
   177 			rel = &dest[dist];
   177 			rel = &dest[dist];
   178 			while (i--)
   178 			while (i--)
   179 				*dest++ = *rel++;
   179 				*dest++ = *rel++;
   180 		}
   180 		}
   181 	}
   181 	}
   207 	_sprite_locked[load_index] = false;
   207 	_sprite_locked[load_index] = false;
   208 #endif
   208 #endif
   209 
   209 
   210 #if defined(WANT_NEW_LRU)
   210 #if defined(WANT_NEW_LRU)
   211 	_sprite_lru_new[load_index] = 0;
   211 	_sprite_lru_new[load_index] = 0;
   212 #else	
   212 #else
   213 	_sprite_lru[load_index] = 0xFFFF;
   213 	_sprite_lru[load_index] = 0xFFFF;
   214 	_sprite_lru_cur[load_index] = 0;
   214 	_sprite_lru_cur[load_index] = 0;
   215 #endif
   215 #endif
   216 
   216 
   217 	return true;
   217 	return true;
   280 				bool b = LoadNextSprite(start, file_index);
   280 				bool b = LoadNextSprite(start, file_index);
   281 				assert(b);
   281 				assert(b);
   282 			} while (++start <= end);
   282 			} while (++start <= end);
   283 		}
   283 		}
   284 	}
   284 	}
   285 }	
   285 }
   286 
   286 
   287 typedef size_t CDECL fread_t(void*,size_t,size_t,FILE*);
   287 typedef size_t CDECL fread_t(void*,size_t,size_t,FILE*);
   288 
   288 
   289 static bool HandleCachedSpriteHeaders(const char *filename, bool read)
   289 static bool HandleCachedSpriteHeaders(const char *filename, bool read)
   290 {
   290 {
   396 static void CompactSpriteCache()
   396 static void CompactSpriteCache()
   397 {
   397 {
   398 	byte *s, *t;
   398 	byte *s, *t;
   399 	size_t size, sizeb, cur_size;
   399 	size_t size, sizeb, cur_size;
   400 	int i;
   400 	int i;
   401 	
   401 
   402 	DEBUG(spritecache, 2) ("compacting sprite cache, inuse=%d", GetSpriteCacheUsage());
   402 	DEBUG(spritecache, 2) ("compacting sprite cache, inuse=%d", GetSpriteCacheUsage());
   403 
   403 
   404 	s = _spritecache_ptr;
   404 	s = _spritecache_ptr;
   405 	
   405 
   406 	while (true) {
   406 	while (true) {
   407 		size = S_DATA(s);
   407 		size = S_DATA(s);
   408 		
   408 
   409 		// Only look for free blocks.
   409 		// Only look for free blocks.
   410 		if (size & S_FREE_MASK) {
   410 		if (size & S_FREE_MASK) {
   411 			size -= S_FREE_MASK;
   411 			size -= S_FREE_MASK;
   412 			// Since free blocks are automatically coalesced, this should hold true.
   412 			// Since free blocks are automatically coalesced, this should hold true.
   413 			assert(!(S_DATA(s+size) & S_FREE_MASK));
   413 			assert(!(S_DATA(s+size) & S_FREE_MASK));
   414 			
   414 
   415 			// If the next block is the sentinel block, we can safely return
   415 			// If the next block is the sentinel block, we can safely return
   416 			if ( (sizeb=S_DATA(s + size)) == 0)
   416 			if ( (sizeb=S_DATA(s + size)) == 0)
   417 				break;
   417 				break;
   418 
   418 
   419 			// Locate the sprite number belonging to the next pointer.
   419 			// Locate the sprite number belonging to the next pointer.
   425 #endif
   425 #endif
   426 
   426 
   427 				// Offset the sprite pointer by the size of the free block
   427 				// Offset the sprite pointer by the size of the free block
   428 				_sprite_ptr[i] -= size;
   428 				_sprite_ptr[i] -= size;
   429 
   429 
   430 				// Move the memory 
   430 				// Move the memory
   431 				memcpy_overlapping(s+S_HDRSIZE, s+S_HDRSIZE+size, sizeb - S_HDRSIZE );
   431 				memcpy_overlapping(s+S_HDRSIZE, s+S_HDRSIZE+size, sizeb - S_HDRSIZE );
   432 
   432 
   433 				// What we just did had the effect of swapping the allocated block with the free block, so we need to update
   433 				// What we just did had the effect of swapping the allocated block with the free block, so we need to update
   434 				//  the block pointers. First update the allocated one. It is in use.
   434 				//  the block pointers. First update the allocated one. It is in use.
   435 				S_DATA(s) = sizeb;
   435 				S_DATA(s) = sizeb;
   436 							
   436 
   437 				// Then coalesce the free ones that follow.
   437 				// Then coalesce the free ones that follow.
   438 				s += sizeb;
   438 				s += sizeb;
   439 				while ((cur_size = S_DATA(s+size)) & S_FREE_MASK)
   439 				while ((cur_size = S_DATA(s+size)) & S_FREE_MASK)
   440 					size += cur_size - S_FREE_MASK;
   440 					size += cur_size - S_FREE_MASK;
   441 				S_DATA(s) = size + S_FREE_MASK;
   441 				S_DATA(s) = size + S_FREE_MASK;
   483 #if defined(WANT_LOCKED)
   483 #if defined(WANT_LOCKED)
   484 				_sprite_locked[i] ||
   484 				_sprite_locked[i] ||
   485 #endif
   485 #endif
   486 				_sprite_lru[i] < cur_lru)
   486 				_sprite_lru[i] < cur_lru)
   487 					continue;
   487 					continue;
   488 		
   488 
   489 		// Found a sprite with a higher LRU value, then remember it.
   489 		// Found a sprite with a higher LRU value, then remember it.
   490 		if (_sprite_lru[i] != cur_lru) {
   490 		if (_sprite_lru[i] != cur_lru) {
   491 			cur_lru = _sprite_lru[i];
   491 			cur_lru = _sprite_lru[i];
   492 			best = i;
   492 			best = i;
   493 
   493 
   549 			cur_size -= S_FREE_MASK;
   549 			cur_size -= S_FREE_MASK;
   550 
   550 
   551 			// Now s points at a free block.
   551 			// Now s points at a free block.
   552 			// The block is exactly the size we need?
   552 			// The block is exactly the size we need?
   553 			if (cur_size != mem_req) {
   553 			if (cur_size != mem_req) {
   554 				
   554 
   555 				// No.. is it too small?
   555 				// No.. is it too small?
   556 				if (cur_size < mem_req + S_HDRSIZE)
   556 				if (cur_size < mem_req + S_HDRSIZE)
   557 					break;
   557 					break;
   558 
   558 
   559 				// Block was big enough, and we need to inject a free block too.
   559 				// Block was big enough, and we need to inject a free block too.
   565 
   565 
   566 			_sprite_ptr[sprite] = (s += S_HDRSIZE);
   566 			_sprite_ptr[sprite] = (s += S_HDRSIZE);
   567 
   567 
   568 			FioSeekToFile(_sprite_file_pos[sprite]);
   568 			FioSeekToFile(_sprite_file_pos[sprite]);
   569 			ReadSprite(_sprite_size[sprite], s);
   569 			ReadSprite(_sprite_size[sprite], s);
   570 			
   570 
   571 			// Patch the height to compensate for a TTD bug?
   571 			// Patch the height to compensate for a TTD bug?
   572 			if (sprite == 142) { s[1] = 10; }
   572 			if (sprite == 142) { s[1] = 10; }
   573 
   573 
   574 			// Return sprite ptr
   574 			// Return sprite ptr
   575 			return s;
   575 			return s;
   578 		// Reached sentinel, but no block found yet. Need to delete some old entries.
   578 		// Reached sentinel, but no block found yet. Need to delete some old entries.
   579 		if (cur_size == 0) {
   579 		if (cur_size == 0) {
   580 			DeleteEntryFromSpriteCache();
   580 			DeleteEntryFromSpriteCache();
   581 			goto restart;
   581 			goto restart;
   582 		}
   582 		}
   583 		
   583 
   584 		s += cur_size;
   584 		s += cur_size;
   585 	}
   585 	}
   586 }
   586 }
   587 
   587 
   588 #if defined(NEW_ROTATION)
   588 #if defined(NEW_ROTATION)
   626 	MAP(4120, 4125, _fence_map)
   626 	MAP(4120, 4125, _fence_map)
   627 	return s;
   627 	return s;
   628 }
   628 }
   629 #endif
   629 #endif
   630 
   630 
   631 byte *GetSpritePtr(uint sprite) 
   631 byte *GetSpritePtr(uint sprite)
   632 {
   632 {
   633 	byte *p;
   633 	byte *p;
   634 
   634 
   635 	assert(sprite < NUM_SPRITES);
   635 	assert(sprite < NUM_SPRITES);
   636 
   636 
   648 
   648 
   649 	// Check if the sprite is loaded already?
   649 	// Check if the sprite is loaded already?
   650 	p = _sprite_ptr[sprite];
   650 	p = _sprite_ptr[sprite];
   651 	if (p == NULL)
   651 	if (p == NULL)
   652 		p = LoadSpriteToMem(sprite);  // No, need to load it.
   652 		p = LoadSpriteToMem(sprite);  // No, need to load it.
   653 	return p;	
   653 	return p;
   654 }
   654 }
   655 
   655 
   656 byte _sprite_page_to_load = 0xFF;
   656 byte _sprite_page_to_load = 0xFF;
   657 
   657 
   658 static const char * const _cached_filenames[4] = {
   658 static const char * const _cached_filenames[4] = {
   678 
   678 
   679 static void LoadSpriteTables()
   679 static void LoadSpriteTables()
   680 {
   680 {
   681 	int i,j;
   681 	int i,j;
   682 
   682 
   683 	/* load initial sprites */
   683 	/*
       
   684 	 * Note for developers:
       
   685 	 *   Keep in mind that when you add a LoadGrfIndexed in the 'if'-section below
       
   686 	 *   that you should also add the corresponding FioOpenFile to the 'else'-section
       
   687 	 *   below.
       
   688 	 */
       
   689 
       
   690 	// Try to load the sprites from cache
   684 	if (!HandleCachedSpriteHeaders(_cached_filenames[_opt.landscape], true)) {
   691 	if (!HandleCachedSpriteHeaders(_cached_filenames[_opt.landscape], true)) {
   685 		
   692 		// We do not have the sprites in cache yet, or cache is disabled
       
   693 		// So just load all files from disk..
       
   694 
   686 		int load_index = 0;
   695 		int load_index = 0;
   687 		for(i=0; _filename_list[i] != NULL; i++) {
   696 		for(i=0; _filename_list[i] != NULL; i++) {
   688 			load_index += LoadGrfFile(_filename_list[i], load_index, (byte)i);
   697 			load_index += LoadGrfFile(_filename_list[i], load_index, (byte)i);
   689 		}
   698 		}
   690 
   699 
   691 		LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++);
   700 		LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++);
   692 
   701 
   693 		{
   702 		if (_sprite_page_to_load != 0)
   694 			int l;
   703 			LoadGrfIndexed(_landscape_filenames[_sprite_page_to_load-1], _landscape_spriteindexes[_sprite_page_to_load-1], i++);
   695 			if ((l=_sprite_page_to_load) != 0)
   704 
   696 				LoadGrfIndexed(_landscape_filenames[l-1], _landscape_spriteindexes[l-1], i++); 
       
   697 		}
       
   698 		
       
   699 		LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
   705 		LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
   700 
   706 
   701 		load_index = SPR_CANALS_BASE;
   707 		load_index = SPR_CANALS_BASE;
   702 		load_index += LoadGrfFile("canalsw.grf", load_index, i++);
   708 		load_index += LoadGrfFile("canalsw.grf", load_index, i++);
   703 		/* XXX: Only for debugging. Will be more generic. */
   709 
   704 
   710 		load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT + 1;
   705 		load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT+1;
       
   706 
   711 
   707 		for(j=0; j!=lengthof(_newgrf_files) && _newgrf_files[j]; j++)
   712 		for(j=0; j!=lengthof(_newgrf_files) && _newgrf_files[j]; j++)
   708 			load_index += LoadGrfFile(_newgrf_files[j], load_index, i++);
   713 			load_index += LoadGrfFile(_newgrf_files[j], load_index, i++);
   709 
   714 
   710 //		load_index += LoadGrfFile("arcticseto.grf", load_index, i++);
   715 		// If needed, save the cache to file
   711 //		load_index += LoadGrfFile("tempsetpo.grf", load_index, i++);
       
   712 //		load_index += LoadGrfFile("newshipso.grf", load_index, i++);
       
   713 		//load_index += LoadGrfFile("brseto.grf", load_index, i++);
       
   714 
       
   715 		HandleCachedSpriteHeaders(_cached_filenames[_opt.landscape], false);
   716 		HandleCachedSpriteHeaders(_cached_filenames[_opt.landscape], false);
   716 	} else {
   717 	} else {
       
   718 		// We have sprites cached. We just loaded the cached files
       
   719 		//  now we only have to open a file-pointer to all the original grf-files
       
   720 		// This is very important. Not all sprites are in the cache. So sometimes
       
   721 		//  the game needs to load the sprite from disk. When the file is not
       
   722 		//  open it can not read. So all files that are in the 'if'-section
       
   723 		//  above should also be in this 'else'-section.
       
   724 		//
       
   725 		// NOTE: the order of the files must be identical as in the section above!!
       
   726 
   717 		for(i=0; _filename_list[i] != NULL; i++)
   727 		for(i=0; _filename_list[i] != NULL; i++)
   718 			FioOpenFile(i,_filename_list[i]); 
   728 			FioOpenFile(i,_filename_list[i]);
   719 		
   729 
   720 		FioOpenFile(i, "openttd.grf");
   730 		FioOpenFile(i++, "openttd.grf");
   721 		FioOpenFile(i+1, "canalsw.grf");
   731 
   722 		
       
   723 		if (_sprite_page_to_load != 0)
   732 		if (_sprite_page_to_load != 0)
   724 			FioOpenFile(i+2, _landscape_filenames[_sprite_page_to_load-1]);
   733 			FioOpenFile(i++, _landscape_filenames[_sprite_page_to_load-1]);
       
   734 
       
   735 		FioOpenFile(i++, "trkfoundw.grf");
       
   736 		FioOpenFile(i++, "canalsw.grf");
       
   737 
       
   738 		// FIXME: if a user changes his newgrf's, the cached-sprites gets
       
   739 		//  invalid. We should have some kind of check for this.
       
   740 		// The best solution for this is to delete the cached-sprites.. but how
       
   741 		//  do we detect it?
       
   742 		for(j=0; j!=lengthof(_newgrf_files) && _newgrf_files[j]; j++)
       
   743 			FioOpenFile(i++, _newgrf_files[j]);
   725 	}
   744 	}
   726 
   745 
   727 	_compact_cache_counter = 0;
   746 	_compact_cache_counter = 0;
   728 }
   747 }
   729 
   748 
   742 }
   761 }
   743 
   762 
   744 
   763 
   745 void GfxLoadSprites() {
   764 void GfxLoadSprites() {
   746 	static byte *_sprite_mem;
   765 	static byte *_sprite_mem;
   747 	
   766 
   748 	// Need to reload the sprites only if the landscape changed
   767 	// Need to reload the sprites only if the landscape changed
   749 	if (_sprite_page_to_load != _opt.landscape) {
   768 	if (_sprite_page_to_load != _opt.landscape) {
   750 		_sprite_page_to_load = _opt.landscape;
   769 		_sprite_page_to_load = _opt.landscape;
   751 
   770 
   752 		// Sprite cache
   771 		// Sprite cache
   791 	sd->xsize = _sprite_xsize[sprite];
   810 	sd->xsize = _sprite_xsize[sprite];
   792 	sd->ysize = _sprite_ysize[sprite];
   811 	sd->ysize = _sprite_ysize[sprite];
   793 */
   812 */
   794 	return sd;
   813 	return sd;
   795 }
   814 }
   796  
   815