From 2c3bca6ad9af3ef5f886e6ce74d93d330f58859f Mon Sep 17 00:00:00 2001 From: michi_cc Date: Sat, 4 Feb 2012 22:18:57 +0000 Subject: (svn r23897) -Feature: [NewGRF] 32bpp sprites in GRFs. --- src/spritecache.cpp | 10 ++++- src/spriteloader/grf.cpp | 90 +++++++++++++++++++++++++++------------ src/spriteloader/grf.hpp | 2 +- src/spriteloader/png.cpp | 4 +- src/spriteloader/png.hpp | 2 +- src/spriteloader/spriteloader.hpp | 3 +- 6 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/spritecache.cpp b/src/spritecache.cpp index 75e402bed..59b04a4d7 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -391,7 +391,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty /* Try loading 32bpp graphics in case we are 32bpp output */ SpriteLoaderPNG sprite_loader; - sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, sc->id, sprite_type); + sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, sc->id, sprite_type, true); if (sprite_avail != 0) { if (ResizeSprites(sprite, sprite_avail, file_slot, sc->id)) { @@ -409,7 +409,13 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty } SpriteLoaderGrf sprite_loader(sc->container_ver); - sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type); + if (sprite_type != ST_MAPGEN && BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 32) { + /* Try for 32bpp sprites first. */ + sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, true); + } + if (sprite_avail == 0) { + sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, false); + } if (sprite_avail == 0) { if (sprite_type == ST_MAPGEN) return NULL; diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp index da4902049..2de58dc6f 100644 --- a/src/spriteloader/grf.cpp +++ b/src/spriteloader/grf.cpp @@ -61,10 +61,11 @@ static bool WarnCorruptSprite(uint8 file_slot, size_t file_pos, int line) * @param num Size of the decompressed sprite. * @param type Type of the encoded sprite. * @param zoom_lvl Requested zoom level. + * @param colour_fmt Colour format of the sprite. * @param container_format Container format of the GRF this sprite is in. * @return True if the sprite was successfully loaded. */ -bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, int64 num, byte type, ZoomLevel zoom_lvl, byte container_format) +bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, int64 num, byte type, ZoomLevel zoom_lvl, byte colour_fmt, byte container_format) { AutoFreePtr dest_orig(MallocT(num)); byte *dest = dest_orig; @@ -101,6 +102,12 @@ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t fi sprite->AllocateData(zoom_lvl, sprite->width * sprite->height); + /* Convert colour depth to pixel size. */ + int bpp = 0; + if (colour_fmt & SCC_RGB) bpp += 3; // Has RGB data. + if (colour_fmt & SCC_ALPHA) bpp++; // Has alpha data. + if (colour_fmt & SCC_PAL) bpp++; // Has palette data. + /* When there are transparency pixels, this format has another trick.. decode it */ if (type & 0x08) { for (int y = 0; y < sprite->height; y++) { @@ -143,53 +150,74 @@ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t fi data = &sprite->data[y * sprite->width + skip]; - if (skip + length > sprite->width || dest + length > dest_orig + dest_size) { + if (skip + length > sprite->width || dest + length * bpp > dest_orig + dest_size) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } for (int x = 0; x < length; x++) { - switch (sprite_type) { - case ST_NORMAL: data->m = _palette_remap_grf[file_slot] ? _palmap_w2d[*dest] : *dest; break; - case ST_FONT: data->m = min(*dest, 2u); break; - default: data->m = *dest; break; + if (colour_fmt & SCC_RGB) { + data->r = *dest++; + data->g = *dest++; + data->b = *dest++; + } + data->a = (colour_fmt & SCC_ALPHA) ? *dest++ : 0xFF; + if (colour_fmt & SCC_PAL) { + switch (sprite_type) { + case ST_NORMAL: data->m = _palette_remap_grf[file_slot] ? _palmap_w2d[*dest] : *dest; break; + case ST_FONT: data->m = min(*dest, 2u); break; + default: data->m = *dest; break; + } + /* Magic blue. */ + if (colour_fmt == SCC_PAL && *dest == 0) data->a = 0x00; + dest++; } - dest++; data++; } } while (!last_item); } } else { - if (dest_size < sprite->width * sprite->height) { + if (dest_size < sprite->width * sprite->height * bpp) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } - if (dest_size > sprite->width * sprite->height) { + if (dest_size > sprite->width * sprite->height * bpp) { static byte warning_level = 0; - DEBUG(sprite, warning_level, "Ignoring " OTTD_PRINTF64 " unused extra bytes from the sprite from %s at position %i", dest_size - sprite->width * sprite->height, FioGetFilename(file_slot), (int)file_pos); + DEBUG(sprite, warning_level, "Ignoring " OTTD_PRINTF64 " unused extra bytes from the sprite from %s at position %i", dest_size - sprite->width * sprite->height * bpp, FioGetFilename(file_slot), (int)file_pos); warning_level = 6; } dest = dest_orig; for (int i = 0; i < sprite->width * sprite->height; i++) { - switch (sprite_type) { - case ST_NORMAL: sprite->data[i].m = _palette_remap_grf[file_slot] ? _palmap_w2d[dest[i]] : dest[i]; break; - case ST_FONT: sprite->data[i].m = min(dest[i], 2u); break; - default: sprite->data[i].m = dest[i]; break; + byte *pixel = &dest[i * bpp]; + + if (colour_fmt & SCC_RGB) { + sprite->data[i].r = *pixel++; + sprite->data[i].g = *pixel++; + sprite->data[i].b = *pixel++; + } + sprite->data[i].a = (colour_fmt & SCC_ALPHA) ? *pixel++ : 0xFF; + if (colour_fmt & SCC_PAL) { + switch (sprite_type) { + case ST_NORMAL: sprite->data[i].m = _palette_remap_grf[file_slot] ? _palmap_w2d[*pixel] : *pixel; break; + case ST_FONT: sprite->data[i].m = min(*pixel, 2u); break; + default: sprite->data[i].m = *pixel; break; + } + /* Magic blue. */ + if (colour_fmt == SCC_PAL && *pixel == 0) sprite->data[i].a = 0x00; + pixel++; } } } - /* Make sure to mark all transparent pixels transparent on the alpha channel too */ - for (int i = 0; i < sprite->width * sprite->height; i++) { - if (sprite->data[i].m != 0) sprite->data[i].a = 0xFF; - } - return true; } -uint8 LoadSpriteV1(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +uint8 LoadSpriteV1(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { + /* Check the requested colour depth. */ + if (load_32bpp) return 0; + /* Open the right file and go to the correct position */ FioSeekToFile(file_slot, file_pos); @@ -211,12 +239,12 @@ uint8 LoadSpriteV1(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_po * In case it is uncompressed, the size is 'num' - 8 (header-size). */ num = (type & 0x02) ? sprite[zoom_lvl].width * sprite[zoom_lvl].height : num - 8; - if (DecodeSingleSprite(&sprite[zoom_lvl], file_slot, file_pos, sprite_type, num, type, zoom_lvl, 1)) return 1 << zoom_lvl; + if (DecodeSingleSprite(&sprite[zoom_lvl], file_slot, file_pos, sprite_type, num, type, zoom_lvl, SCC_PAL, 1)) return 1 << zoom_lvl; return 0; } -uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { static const ZoomLevel zoom_lvl_map[6] = {ZOOM_LVL_OUT_4X, ZOOM_LVL_NORMAL, ZOOM_LVL_OUT_2X, ZOOM_LVL_OUT_8X, ZOOM_LVL_OUT_16X, ZOOM_LVL_OUT_32X}; @@ -240,7 +268,7 @@ uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_po byte colour = type & SCC_MASK; byte zoom = FioReadByte(); - if (colour == SCC_PAL && (sprite_type == ST_NORMAL ? zoom < lengthof(zoom_lvl_map) : zoom == 0)) { + if (colour != 0 && (load_32bpp ? colour != SCC_PAL : colour == SCC_PAL) && (sprite_type == ST_NORMAL ? zoom < lengthof(zoom_lvl_map) : zoom == 0)) { ZoomLevel zoom_lvl = (sprite_type == ST_NORMAL) ? zoom_lvl_map[zoom] : ZOOM_LVL_NORMAL; if (HasBit(loaded_sprites, zoom_lvl)) { @@ -258,11 +286,17 @@ uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_po /* Mask out colour information. */ type = type & ~SCC_MASK; + /* Convert colour depth to pixel size. */ + int bpp = 0; + if (colour & SCC_RGB) bpp += 3; // Has RGB data. + if (colour & SCC_ALPHA) bpp++; // Has alpha data. + if (colour & SCC_PAL) bpp++; // Has palette data. + /* For chunked encoding we store the decompressed size in the file, * otherwise we can calculate it from the image dimensions. */ - uint decomp_size = (type & 0x08) ? FioReadDword() : sprite[zoom_lvl].width * sprite[zoom_lvl].height; + uint decomp_size = (type & 0x08) ? FioReadDword() : sprite[zoom_lvl].width * sprite[zoom_lvl].height * bpp; - bool valid = DecodeSingleSprite(&sprite[zoom_lvl], file_slot, file_pos, sprite_type, decomp_size, type, zoom_lvl, 2); + bool valid = DecodeSingleSprite(&sprite[zoom_lvl], file_slot, file_pos, sprite_type, decomp_size, type, zoom_lvl, colour, 2); if (FioGetPos() != start_pos + num) { WarnCorruptSprite(file_slot, file_pos, __LINE__); return 0; @@ -279,11 +313,11 @@ uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_po return loaded_sprites; } -uint8 SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +uint8 SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { if (this->container_ver >= 2) { - return LoadSpriteV2(sprite, file_slot, file_pos, sprite_type); + return LoadSpriteV2(sprite, file_slot, file_pos, sprite_type, load_32bpp); } else { - return LoadSpriteV1(sprite, file_slot, file_pos, sprite_type); + return LoadSpriteV1(sprite, file_slot, file_pos, sprite_type, load_32bpp); } } diff --git a/src/spriteloader/grf.hpp b/src/spriteloader/grf.hpp index e33033f6f..4081a9f33 100644 --- a/src/spriteloader/grf.hpp +++ b/src/spriteloader/grf.hpp @@ -19,7 +19,7 @@ class SpriteLoaderGrf : public SpriteLoader { byte container_ver; public: SpriteLoaderGrf(byte container_ver) : container_ver(container_ver) {} - uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type); + uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp); }; #endif /* SPRITELOADER_GRF_HPP */ diff --git a/src/spriteloader/png.cpp b/src/spriteloader/png.cpp index 73403f520..0c65ffc6f 100644 --- a/src/spriteloader/png.cpp +++ b/src/spriteloader/png.cpp @@ -206,8 +206,10 @@ static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 i return true; } -uint8 SpriteLoaderPNG::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +uint8 SpriteLoaderPNG::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { + if (!load_32bpp) return 0; + ZoomLevel zoom_lvl = (sprite_type == ST_NORMAL) ? ZOOM_LVL_OUT_4X : ZOOM_LVL_NORMAL; const char *filename = FioGetFilename(file_slot); diff --git a/src/spriteloader/png.hpp b/src/spriteloader/png.hpp index 92d152e0f..425904af6 100644 --- a/src/spriteloader/png.hpp +++ b/src/spriteloader/png.hpp @@ -17,7 +17,7 @@ /** Sprite loader for graphics coming from a PNG image. */ class SpriteLoaderPNG : public SpriteLoader { public: - uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type); + uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp); }; #endif /* SPRITELOADER_PNG_HPP */ diff --git a/src/spriteloader/spriteloader.hpp b/src/spriteloader/spriteloader.hpp index 030eb1850..060e72d16 100644 --- a/src/spriteloader/spriteloader.hpp +++ b/src/spriteloader/spriteloader.hpp @@ -58,9 +58,10 @@ public: * @param file_slot The file "descriptor" of the file we read from. * @param file_pos The position within the file the image begins. * @param sprite_type The type of sprite we're trying to load. + * @param load_32bpp True if 32bpp sprites should be loaded, false for a 8bpp sprite. * @return Bit mask of the zoom levels successfully loaded or 0 if no sprite could be loaded. */ - virtual uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) = 0; + virtual uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) = 0; virtual ~SpriteLoader() { } }; -- cgit v1.2.3-54-g00ecf