Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../stdafx.h"
00013 #include "../gfx_func.h"
00014 #include "../fileio_func.h"
00015 #include "../debug.h"
00016 #include "../strings_func.h"
00017 #include "table/strings.h"
00018 #include "../gui.h"
00019 #include "../core/math_func.hpp"
00020 #include "grf.hpp"
00021
00022 extern const byte _palmap_w2d[];
00023
00032 static bool WarnCorruptSprite(uint8 file_slot, size_t file_pos, int line)
00033 {
00034 static byte warning_level = 0;
00035 if (warning_level == 0) {
00036 SetDParamStr(0, FioGetFilename(file_slot));
00037 ShowErrorMessage(STR_NEWGRF_ERROR_CORRUPT_SPRITE, INVALID_STRING_ID, WL_ERROR);
00038 }
00039 DEBUG(sprite, warning_level, "[%i] Loading corrupted sprite from %s at position %i", line, FioGetFilename(file_slot), (int)file_pos);
00040 warning_level = 6;
00041 return false;
00042 }
00043
00044 bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type)
00045 {
00046
00047 FioSeekToFile(file_slot, file_pos);
00048
00049
00050 int num = FioReadWord();
00051 byte type = FioReadByte();
00052
00053
00054 if (type == 0xFF) return false;
00055
00056 sprite->height = FioReadByte();
00057 sprite->width = FioReadWord();
00058 sprite->x_offs = FioReadWord();
00059 sprite->y_offs = FioReadWord();
00060
00061
00062
00063 num = (type & 0x02) ? sprite->width * sprite->height : num - 8;
00064
00065 byte *dest_orig = AllocaM(byte, num);
00066 byte *dest = dest_orig;
00067 const int dest_size = num;
00068
00069
00070 while (num > 0) {
00071 int8 code = FioReadByte();
00072
00073 if (code >= 0) {
00074
00075 int size = (code == 0) ? 0x80 : code;
00076 num -= size;
00077 if (num < 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00078 for (; size > 0; size--) {
00079 *dest = FioReadByte();
00080 dest++;
00081 }
00082 } else {
00083
00084 const uint data_offset = ((code & 7) << 8) | FioReadByte();
00085 if (dest - data_offset < dest_orig) return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00086 int size = -(code >> 3);
00087 num -= size;
00088 if (num < 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00089 for (; size > 0; size--) {
00090 *dest = *(dest - data_offset);
00091 dest++;
00092 }
00093 }
00094 }
00095
00096 if (num != 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00097
00098 sprite->AllocateData(sprite->width * sprite->height * ZOOM_LVL_BASE * ZOOM_LVL_BASE);
00099
00100
00101 if (type & 0x08) {
00102 for (int y = 0; y < sprite->height; y++) {
00103 bool last_item = false;
00104
00105 int offset = (dest_orig[y * 2 + 1] << 8) | dest_orig[y * 2];
00106
00107
00108 dest = dest_orig + offset;
00109
00110 do {
00111 if (dest + 2 > dest_orig + dest_size) {
00112 return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00113 }
00114
00115 SpriteLoader::CommonPixel *data;
00116
00117
00118
00119
00120 last_item = ((*dest) & 0x80) != 0;
00121 int length = (*dest++) & 0x7F;
00122 int skip = *dest++;
00123
00124 data = &sprite->data[y * sprite->width + skip];
00125
00126 if (skip + length > sprite->width || dest + length > dest_orig + dest_size) {
00127 return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00128 }
00129
00130 for (int x = 0; x < length; x++) {
00131 switch (sprite_type) {
00132 case ST_NORMAL: data->m = _palette_remap_grf[file_slot] ? _palmap_w2d[*dest] : *dest; break;
00133 case ST_FONT: data->m = min(*dest, 2u); break;
00134 default: data->m = *dest; break;
00135 }
00136 dest++;
00137 data++;
00138 }
00139 } while (!last_item);
00140 }
00141 } else {
00142 if (dest_size < sprite->width * sprite->height) {
00143 return WarnCorruptSprite(file_slot, file_pos, __LINE__);
00144 }
00145
00146 if (dest_size > sprite->width * sprite->height) {
00147 static byte warning_level = 0;
00148 DEBUG(sprite, warning_level, "Ignoring %i unused extra bytes from the sprite from %s at position %i", dest_size - sprite->width * sprite->height, FioGetFilename(file_slot), (int)file_pos);
00149 warning_level = 6;
00150 }
00151
00152 dest = dest_orig;
00153
00154 for (int i = 0; i < sprite->width * sprite->height; i++) {
00155 switch (sprite_type) {
00156 case ST_NORMAL: sprite->data[i].m = _palette_remap_grf[file_slot] ? _palmap_w2d[dest[i]] : dest[i]; break;
00157 case ST_FONT: sprite->data[i].m = min(dest[i], 2u); break;
00158 default: sprite->data[i].m = dest[i]; break;
00159 }
00160 }
00161 }
00162
00163 if (ZOOM_LVL_BASE != 1 && sprite_type == ST_NORMAL) {
00164
00165 int width = sprite->width * ZOOM_LVL_BASE;
00166 int height = sprite->height * ZOOM_LVL_BASE;
00167 for (int y = height - 1; y >= 0; y--) {
00168 for (int x = width - 1; x >= 0; x--) {
00169 sprite->data[y * width + x] = sprite->data[y / ZOOM_LVL_BASE * sprite->width + x / ZOOM_LVL_BASE];
00170 }
00171 }
00172
00173 sprite->width *= ZOOM_LVL_BASE;
00174 sprite->height *= ZOOM_LVL_BASE;
00175 sprite->x_offs *= ZOOM_LVL_BASE;
00176 sprite->y_offs *= ZOOM_LVL_BASE;
00177 }
00178
00179
00180 for (int i = 0; i < sprite->width * sprite->height; i++) {
00181 if (sprite->data[i].m != 0) sprite->data[i].a = 0xFF;
00182 }
00183
00184 return true;
00185 }