From cea7f095bb921ac963e5a01a9c20bece84468ace Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 10 May 2019 22:42:50 +1000 Subject: [PATCH] If non-alex area of skin arms are completely black, treat as alex skin This fixes skins saved by services that lose transparency --- src/Entity.c | 8 ++++---- src/Game.c | 2 +- src/Utils.c | 23 ++++++++++++++++++++--- src/Utils.h | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Entity.c b/src/Entity.c index b1ddd90ff..d1088eb3d 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -660,13 +660,13 @@ static void Player_ClearHat(Bitmap* bmp, uint8_t skinType) { } /* only perform filtering when the entire hat is opaque */ - uint32_t fullWhite = PackedCol_ARGB(255, 255, 255, 255); - uint32_t fullBlack = PackedCol_ARGB(0, 0, 0, 255); + uint32_t white = PackedCol_ARGB(255, 255, 255, 255); + uint32_t black = PackedCol_ARGB(0, 0, 0, 255); for (y = 0; y < sizeY; y++) { uint32_t* row = Bitmap_RawRow(bmp, y) + sizeX; for (x = 0; x < sizeX; x++) { uint32_t pixel = row[x]; - if (pixel == fullWhite || pixel == fullBlack) row[x] = 0; + if (pixel == white || pixel == black) row[x] = 0; } } } @@ -730,7 +730,7 @@ static void Player_CheckSkin(struct Player* p) { Gfx_DeleteTexture(&e->TextureId); Player_SetSkinAll(p, true); Player_EnsurePow2(p, &bmp); - e->SkinType = Utils_GetSkinType(&bmp); + e->SkinType = Utils_CalcSkinType(&bmp); if (bmp.Width > Gfx.MaxTexWidth || bmp.Height > Gfx.MaxTexHeight) { Chat_Add1("&cSkin %s is too large", &skin); diff --git a/src/Game.c b/src/Game.c index 5c986f32b..c9d4c39da 100644 --- a/src/Game.c +++ b/src/Game.c @@ -237,7 +237,7 @@ bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, const String* success = !res && Game_ValidateBitmap(file, &bmp); if (success) { Gfx_DeleteTexture(texId); - if (skinType) { *skinType = Utils_GetSkinType(&bmp); } + if (skinType) { *skinType = Utils_CalcSkinType(&bmp); } *texId = Gfx_CreateTexture(&bmp, true, false); } diff --git a/src/Utils.c b/src/Utils.c index c6701d044..d7f8dc2f9 100644 --- a/src/Utils.c +++ b/src/Utils.c @@ -140,14 +140,31 @@ int Utils_AccumulateWheelDelta(float* accumulator, float delta) { return steps; } -uint8_t Utils_GetSkinType(const Bitmap* bmp) { +/* Checks if an area is completely black, so Alex skins edited with Microsoft Paint are still treated as Alex */ +static bool Utils_IsAllBlack(const Bitmap* bmp, int x1, int y1, int width, int height) { + uint32_t black = PackedCol_ARGB(0, 0, 0, 255); + int x, y; + for (y = y1; y < y1 + height; y++) { + uint32_t* row = Bitmap_RawRow(bmp, y); + + for (x = x1; x < x1 + width; x++) { + if (row[x] != black) return false; + } + } + return true; +} + +uint8_t Utils_CalcSkinType(const Bitmap* bmp) { int scale; if (bmp->Width == bmp->Height * 2) return SKIN_64x32; if (bmp->Width != bmp->Height) return SKIN_INVALID; - /* Minecraft alex skins have this particular pixel with alpha of 0 */ scale = bmp->Width / 64; - return Bitmap_GetPixel(bmp, 54 * scale, 20 * scale).A >= 127 ? SKIN_64x64 : SKIN_64x64_SLIM; + /* Minecraft alex skins have this particular pixel with alpha of 0 */ + if (Bitmap_GetPixel(bmp, 54 * scale, 20 * scale).A < 128) return SKIN_64x64_SLIM; + + return Utils_IsAllBlack(bmp, 54 * scale, 20 * scale, 2 * scale, 12 * scale) + && Utils_IsAllBlack(bmp, 50 * scale, 16 * scale, 2 * scale, 4 * scale) ? SKIN_64x64_SLIM : SKIN_64x64; } uint32_t Utils_CRC32(const uint8_t* data, uint32_t length) { diff --git a/src/Utils.h b/src/Utils.h index dfcb774ff..7564e127a 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -40,7 +40,7 @@ void Utils_UNSAFE_GetFilename(STRING_REF String* path); int Utils_AccumulateWheelDelta(float* accumulator, float delta); #define Utils_AdjViewDist(value) ((int)(1.4142135f * (value))) -uint8_t Utils_GetSkinType(const Bitmap* bmp); +uint8_t Utils_CalcSkinType(const Bitmap* bmp); uint32_t Utils_CRC32(const uint8_t* data, uint32_t length); /* CRC32 lookup table, for faster CRC32 calculations. */ /* NOTE: This cannot be just indexed by byte value - see Utils_CRC32 implementation. */