29 static int _skip_specials; |
29 static int _skip_specials; |
30 uint16 _custom_sprites_base; |
30 uint16 _custom_sprites_base; |
31 static Sprite _cur_sprite; |
31 static Sprite _cur_sprite; |
32 |
32 |
33 |
33 |
34 static byte *_sprite_ptr[NUM_SPRITES]; |
34 static void* _sprite_ptr[NUM_SPRITES]; |
35 static uint16 _sprite_size[NUM_SPRITES]; |
35 static uint16 _sprite_size[NUM_SPRITES]; |
36 static uint32 _sprite_file_pos[NUM_SPRITES]; |
36 static uint32 _sprite_file_pos[NUM_SPRITES]; |
37 |
37 |
38 // This one is probably not needed. |
38 // This one is probably not needed. |
39 #if defined(WANT_LOCKED) |
39 #if defined(WANT_LOCKED) |
146 } |
146 } |
147 } |
147 } |
148 } |
148 } |
149 } |
149 } |
150 |
150 |
151 static void ReadSprite(SpriteID id, void *buffer) |
151 static void* AllocSprite(size_t); |
|
152 |
|
153 static void* ReadSprite(SpriteID id) |
152 { |
154 { |
153 uint num = _sprite_size[id]; |
155 uint num = _sprite_size[id]; |
154 byte type; |
156 byte type; |
155 byte* dest; |
157 |
|
158 DEBUG(spritecache, 9) ("load sprite %d", id); |
156 |
159 |
157 if (_sprite_file_pos[id] == 0) { |
160 if (_sprite_file_pos[id] == 0) { |
158 error( |
161 error( |
159 "Tried to load non-existing sprite #%d.\n" |
162 "Tried to load non-existing sprite #%d.\n" |
160 "Probable cause: Wrong/missing NewGRFs", |
163 "Probable cause: Wrong/missing NewGRFs", |
163 } |
166 } |
164 |
167 |
165 FioSeekToFile(_sprite_file_pos[id]); |
168 FioSeekToFile(_sprite_file_pos[id]); |
166 |
169 |
167 type = FioReadByte(); |
170 type = FioReadByte(); |
168 /* We've decoded special sprites when reading headers. */ |
171 if (type == 0xFF) { |
169 if (type != 0xFF) { |
172 byte* dest = AllocSprite(num); |
170 /* read sprite hdr */ |
173 |
171 Sprite* sprite = buffer; |
174 _sprite_ptr[id] = dest; |
172 sprite->info = type; |
175 FioReadBlock(dest, num); |
173 sprite->height = FioReadByte(); |
176 |
174 if (id == 142) sprite->height = 10; // Compensate for a TTD bug |
177 return dest; |
175 sprite->width = FioReadWord(); |
178 } else { |
|
179 uint height = FioReadByte(); |
|
180 uint width = FioReadWord(); |
|
181 Sprite* sprite; |
|
182 byte* dest; |
|
183 |
|
184 num = (type & 0x02) ? width * height : num - 8; |
|
185 sprite = AllocSprite(sizeof(*sprite) + num); |
|
186 _sprite_ptr[id] = sprite; |
|
187 sprite->info = type; |
|
188 sprite->height = (id != 142) ? height : 10; |
|
189 sprite->width = width; |
176 sprite->x_offs = FioReadWord(); |
190 sprite->x_offs = FioReadWord(); |
177 sprite->y_offs = FioReadWord(); |
191 sprite->y_offs = FioReadWord(); |
|
192 |
178 dest = sprite->data; |
193 dest = sprite->data; |
179 num -= 8; |
|
180 } else { |
|
181 dest = buffer; |
|
182 } |
|
183 |
|
184 if (type & 2) { |
|
185 for (; num > 0; --num) |
|
186 *dest++ = FioReadByte(); |
|
187 } else { |
|
188 while (num > 0) { |
194 while (num > 0) { |
189 int8 i = FioReadByte(); |
195 int8 i = FioReadByte(); |
190 |
196 |
191 if (i >= 0) { |
197 if (i >= 0) { |
192 num -= i; |
198 num -= i; |
193 for (; i > 0; --i) |
199 for (; i > 0; --i) *dest++ = FioReadByte(); |
194 *dest++ = FioReadByte(); |
|
195 } else { |
200 } else { |
196 const byte* rel = dest - (((i & 7) << 8) | FioReadByte()); |
201 const byte* rel = dest - (((i & 7) << 8) | FioReadByte()); |
197 |
202 |
198 i = -(i >> 3); |
203 i = -(i >> 3); |
199 num -= i; |
204 num -= i; |
200 |
205 |
201 for (; i > 0; --i) |
206 for (; i > 0; --i) *dest++ = *rel++; |
202 *dest++ = *rel++; |
|
203 } |
207 } |
204 } |
208 } |
|
209 |
|
210 return sprite; |
205 } |
211 } |
206 } |
212 } |
207 |
213 |
208 |
214 |
209 static bool LoadNextSprite(int load_index, byte file_index) |
215 static bool LoadNextSprite(int load_index, byte file_index) |
497 |
503 |
498 for (s = _spritecache_ptr; s->size != 0;) { |
504 for (s = _spritecache_ptr; s->size != 0;) { |
499 if (s->size & S_FREE_MASK) { |
505 if (s->size & S_FREE_MASK) { |
500 MemBlock* next = NextBlock(s); |
506 MemBlock* next = NextBlock(s); |
501 MemBlock temp; |
507 MemBlock temp; |
502 byte** i; |
508 void** i; |
503 |
509 |
504 // Since free blocks are automatically coalesced, this should hold true. |
510 // Since free blocks are automatically coalesced, this should hold true. |
505 assert(!(next->size & S_FREE_MASK)); |
511 assert(!(next->size & S_FREE_MASK)); |
506 |
512 |
507 // If the next block is the sentinel block, we can safely return |
513 // If the next block is the sentinel block, we can safely return |
604 } |
610 } |
605 } |
611 } |
606 } |
612 } |
607 } |
613 } |
608 |
614 |
609 static byte *LoadSpriteToMem(SpriteID sprite) |
615 static void* AllocSprite(size_t mem_req) |
610 { |
616 { |
611 size_t mem_req; |
617 mem_req += sizeof(MemBlock); |
612 |
|
613 DEBUG(spritecache, 9) ("load sprite %d", sprite); |
|
614 |
|
615 // Number of needed bytes |
|
616 mem_req = sizeof(MemBlock) + _sprite_size[sprite]; |
|
617 |
618 |
618 /* Align this to an uint32 boundary. This also makes sure that the 2 least |
619 /* Align this to an uint32 boundary. This also makes sure that the 2 least |
619 * bits are not used, so we could use those for other things. */ |
620 * bits are not used, so we could use those for other things. */ |
620 mem_req = (mem_req + sizeof(uint32) - 1) & ~(sizeof(uint32) - 1); |
621 mem_req = (mem_req + sizeof(uint32) - 1) & ~(sizeof(uint32) - 1); |
621 |
622 |
712 #else |
708 #else |
713 _sprite_lru_cur[sprite] = ++_sprite_lru_counter; |
709 _sprite_lru_cur[sprite] = ++_sprite_lru_counter; |
714 _sprite_lru[sprite] = 0; |
710 _sprite_lru[sprite] = 0; |
715 #endif |
711 #endif |
716 |
712 |
717 // Check if the sprite is loaded already? |
|
718 p = _sprite_ptr[sprite]; |
713 p = _sprite_ptr[sprite]; |
719 if (p == NULL) |
714 // Load the sprite, if it is not loaded, yet |
720 p = LoadSpriteToMem(sprite); // No, need to load it. |
715 if (p == NULL) p = ReadSprite(sprite); |
721 return p; |
716 return p; |
722 } |
717 } |
723 |
718 |
724 byte _sprite_page_to_load = 0xFF; |
719 byte _sprite_page_to_load = 0xFF; |
725 |
720 |