From 84d46ab8eb3205d47605817e390b529398a72ff5 Mon Sep 17 00:00:00 2001 From: Sfan5 Date: Thu, 3 Apr 2014 20:32:48 +0200 Subject: [PATCH] Add alpha transparency ability for blocks --- PixelAttributes.h | 4 +- README.rst | 3 ++ TileGenerator.cpp | 106 ++++++++++++++++++++++++++++---------- TileGenerator.h | 22 ++++++-- autogenerating-colors.txt | 3 +- colors.txt | 8 +-- mapper.cpp | 5 ++ 7 files changed, 115 insertions(+), 36 deletions(-) diff --git a/PixelAttributes.h b/PixelAttributes.h index 1e84215..64068f7 100644 --- a/PixelAttributes.h +++ b/PixelAttributes.h @@ -11,11 +11,13 @@ #define PIXELATTRIBUTES_H_ADZ35GYF #include +#include #include "config.h" struct PixelAttribute { - PixelAttribute(): height(std::numeric_limits::min()) {}; + PixelAttribute(): height(std::numeric_limits::min()), thicken(0) {}; int height; + uint8_t thicken; inline bool valid_height() { return height != std::numeric_limits::min(); } diff --git a/README.rst b/README.rst index 063cf56..dab6687 100644 --- a/README.rst +++ b/README.rst @@ -53,6 +53,9 @@ drawplayers: draworigin: Draw origin indicator, `--draworigin` +drawalpha: + Allow blocks to be drawn with transparency, `--drawalpha` + noshading: Don't draw shading on nodes, `--noshading` diff --git a/TileGenerator.cpp b/TileGenerator.cpp index fc76a43..82c45de 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -54,9 +54,14 @@ static inline uint16_t readU16(const unsigned char *data) return data[0] << 8 | data[1]; } -static inline int rgb2int(uint8_t r, uint8_t g, uint8_t b) +static inline int rgb2int(uint8_t r, uint8_t g, uint8_t b, uint8_t a=0xFF) { - return (r << 16) + (g << 8) + b; + return (a << 24) + (r << 16) + (g << 8) + b; +} + +static inline int color2int(Color c) +{ + return rgb2int(c.r, c.g, c.b, c.a); } static inline int readBlockContent(const unsigned char *mapData, int version, int datapos) @@ -93,6 +98,19 @@ static inline int colorSafeBounds(int color) } } +static inline Color mixColors(Color a, Color b) +{ + Color result; + double a1 = a.a / 255.0; + double a2 = b.a / 255.0; + + result.r = (int) (a1 * a.r + a2 * (1 - a1) * b.r); + result.g = (int) (a1 * a.g + a2 * (1 - a1) * b.g); + result.b = (int) (a1 * a.b + a2 * (1 - a1) * b.b); + result.a = (int) (255 * (a1 + a2 * (1 - a1))); + return result; +} + TileGenerator::TileGenerator(): m_bgColor(255, 255, 255), m_scaleColor(0, 0, 0), @@ -101,6 +119,7 @@ TileGenerator::TileGenerator(): m_drawOrigin(false), m_drawPlayers(false), m_drawScale(false), + m_drawAlpha(false), m_shading(true), m_border(0), m_backend("sqlite3"), @@ -178,6 +197,11 @@ void TileGenerator::setDrawScale(bool drawScale) } } +void TileGenerator::setDrawAlpha(bool drawAlpha) +{ + m_drawAlpha = drawAlpha; +} + void TileGenerator::setShading(bool shading) { m_shading = shading; @@ -268,7 +292,7 @@ void TileGenerator::parseColorsStream(std::istream &in) { while (in.good()) { string name; - Color color; + ColorEntry color; in >> name; if (name[0] == '#') { in.ignore(65536, '\n'); @@ -277,14 +301,20 @@ void TileGenerator::parseColorsStream(std::istream &in) while (name == "\n" && in.good()) { in >> name; } - int r, g, b; + int r, g, b, a, t; in >> r; in >> g; in >> b; + if(in.peek() != '\n') { + in >> a; + if(in.peek() != '\n') + in >> t; + else + t = 0; + } else + a = 0xFF; if (in.good()) { - color.r = r; - color.g = g; - color.b = b; + color = ColorEntry(r,g,b,a,t); m_colors[name] = color; } } @@ -352,7 +382,7 @@ void TileGenerator::createImage() m_image = gdImageCreateTrueColor(m_mapWidth + m_border, m_mapHeight + m_border); m_blockPixelAttributes.setWidth(m_mapWidth); // Background - gdImageFilledRectangle(m_image, 0, 0, m_mapWidth + m_border - 1, m_mapHeight + m_border -1, rgb2int(m_bgColor.r, m_bgColor.g, m_bgColor.b)); + gdImageFilledRectangle(m_image, 0, 0, m_mapWidth + m_border - 1, m_mapHeight + m_border -1, color2int(m_bgColor)); } std::map TileGenerator::getBlocksOnZ(int zPos) @@ -496,6 +526,8 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const const unsigned char *mapData = mapBlock.c_str(); int minY = (pos.y * 16 > m_yMin) ? 0 : m_yMin - pos.y * 16; int maxY = (pos.y * 16 < m_yMax) ? 15 : m_yMax - pos.y * 16; + Color col; + uint8_t th; for (int z = 0; z < 16; ++z) { int imageY = getImageY(zBegin + 15 - z); for (int x = 0; x < 16; ++x) { @@ -503,6 +535,10 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const continue; } int imageX = getImageX(xBegin + x); + if(m_drawAlpha) { + col = Color(0,0,0,0); + th = 0; + } for (int y = maxY; y >= minY; --y) { int position = x + (y << 4) + (z << 8); @@ -511,20 +547,33 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const continue; } std::map::iterator blockName = m_nameMap.find(content); - if (blockName != m_nameMap.end()) { - const string &name = blockName->second; - ColorMap::const_iterator color = m_colors.find(name); - if (color != m_colors.end()) { - const Color &c = color->second; - m_image->tpixels[imageY][imageX] = rgb2int(c.r, c.g, c.b); - m_readedPixels[z] |= (1 << x); - m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y; - } else { - m_unknownNodes.insert(name); - continue; - } - break; + if (blockName == m_nameMap.end()) + continue; + const string &name = blockName->second; + ColorMap::const_iterator color = m_colors.find(name); + if (color != m_colors.end()) { + const Color c = color->second.to_color(); + if (m_drawAlpha) { + if (col.a == 0) + col = c; + else + col = mixColors(col, c); + if(col.a == 0xFF) { + m_image->tpixels[imageY][imageX] = color2int(col); + m_blockPixelAttributes.attribute(15 - z, xBegin + x).thicken = th; + } else { + th = (th + color->second.t) / 2.0; + continue; + } + } else + m_image->tpixels[imageY][imageX] = color2int(c); + m_readedPixels[z] |= (1 << x); + m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y; + } else { + m_unknownNodes.insert(name); + continue; } + break; } } } @@ -550,13 +599,16 @@ inline void TileGenerator::renderShading(int zPos) if (d > 36) { d = 36; } + if (m_drawAlpha) + d = d * ((0xFF - m_blockPixelAttributes.attribute(z, x).thicken) / 255.0); int sourceColor = m_image->tpixels[imageY][getImageX(x)] & 0xffffff; - int r = (sourceColor & 0xff0000) >> 16; - int g = (sourceColor & 0x00ff00) >> 8; - int b = (sourceColor & 0x0000ff); + uint8_t r = (sourceColor & 0xff0000) >> 16; + uint8_t g = (sourceColor & 0x00ff00) >> 8; + uint8_t b = (sourceColor & 0x0000ff); r = colorSafeBounds(r + d); g = colorSafeBounds(g + d); b = colorSafeBounds(b + d); + m_image->tpixels[imageY][getImageX(x)] = rgb2int(r, g, b); } } @@ -565,7 +617,7 @@ inline void TileGenerator::renderShading(int zPos) void TileGenerator::renderScale() { - int color = rgb2int(m_scaleColor.r, m_scaleColor.g, m_scaleColor.b); + int color = color2int(m_scaleColor); gdImageString(m_image, gdFontGetMediumBold(), 24, 0, reinterpret_cast(const_cast("X")), color); gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast(const_cast("Z")), color); @@ -596,12 +648,12 @@ void TileGenerator::renderOrigin() { int imageX = -m_xMin * 16 + m_border; int imageY = m_mapHeight - m_zMin * -16 + m_border; - gdImageArc(m_image, imageX, imageY, 12, 12, 0, 360, rgb2int(m_originColor.r, m_originColor.g, m_originColor.b)); + gdImageArc(m_image, imageX, imageY, 12, 12, 0, 360, color2int(m_originColor)); } void TileGenerator::renderPlayers(const std::string &inputPath) { - int color = rgb2int(m_playerColor.r, m_playerColor.g, m_playerColor.b); + int color = color2int(m_playerColor); PlayerAttributes players(inputPath); for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) { diff --git a/TileGenerator.h b/TileGenerator.h index 905f636..5295442 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -21,13 +21,27 @@ #include "db.h" struct Color { - Color(): r(255), g(255), b(255) {}; - Color(uint8_t r, uint8_t g, uint8_t b): r(r), g(g), b(b) {}; + Color(): r(0xFF), g(0xFF), b(0xFF), a(0) {}; + Color(uint8_t r, uint8_t g, uint8_t b): r(r), g(g), b(b), a(0xFF) {}; + Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a): r(r), g(g), b(b), a(a) {}; uint8_t r; uint8_t g; uint8_t b; + uint8_t a; }; +struct ColorEntry { + ColorEntry(): r(0), g(0), b(0), a(0), t(0) {}; + ColorEntry(uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t t): r(r), g(g), b(b), a(a), t(t) {}; + inline Color to_color() const { return Color(r, g, b, a); } + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + uint8_t t; +}; + + struct BlockPos { int x; int y; @@ -61,7 +75,7 @@ class TileGenerator { private: typedef std::basic_string unsigned_string; - typedef std::map ColorMap; + typedef std::map ColorMap; typedef std::pair Block; typedef std::list BlockList; @@ -75,6 +89,7 @@ public: void setDrawOrigin(bool drawOrigin); void setDrawPlayers(bool drawPlayers); void setDrawScale(bool drawScale); + void setDrawAlpha(bool drawAlpha); void setShading(bool shading); void setGeometry(int x, int y, int w, int h); void setMinY(int y); @@ -110,6 +125,7 @@ private: bool m_drawOrigin; bool m_drawPlayers; bool m_drawScale; + bool m_drawAlpha; bool m_shading; int m_border; std::string m_backend; diff --git a/autogenerating-colors.txt b/autogenerating-colors.txt index 9479246..2791dc3 100644 --- a/autogenerating-colors.txt +++ b/autogenerating-colors.txt @@ -90,8 +90,9 @@ while read -r p; do fi done < nodes.txt > colors.txt # Use nicer colors for water and lava -sed -re 's/^default:water_([a-z]+) [0-9 ]+$/default:water_\1 39 66 106/' < colors.txt > tmp$$ && mv tmp$$ colors.txt +sed -re 's/^default:water_([a-z]+) [0-9 ]+$/default:water_\1 39 66 106 128 224/' < colors.txt > tmp$$ && mv tmp$$ colors.txt sed -re 's/^default:lava_([a-z]+) [0-9 ]+$/default:lava_\1 255 100 0/' < colors.txt > tmp$$ && mv tmp$$ colors.txt +sed -re 's/^default:([a-z_]*)glass ([0-9 ]+)$/default:\1glass \2 64 16/' < colors.txt > tmp$$ && mv tmp$$ colors.txt ==INSTRUCTIONS== 1) Make sure avgcolors.py outputs the usage instructions 2) Add the dumpnodes mod to Minetest diff --git a/colors.txt b/colors.txt index dc04a49..baf9db9 100644 --- a/colors.txt +++ b/colors.txt @@ -1466,15 +1466,15 @@ mesecons_lightstone:lightstone_yellow_off 222 220 72 mesecons_walllever:wall_lever_on 136 136 136 mesecons_walllever:wall_lever_off 136 136 136 bones:bones 74 74 74 -default:glass 192 192 227 -default:water_flowing 39 66 106 +default:glass 192 192 227 64 16 +default:water_flowing 39 66 106 128 224 default:junglesapling 37 34 14 default:sandstonebrick 160 144 108 default:furnace_active 97 93 91 default:sign_wall 163 141 106 default:lava_source 255 100 0 default:goldblock 126 116 35 -default:obsidian_glass 16 17 17 +default:obsidian_glass 16 17 17 64 16 default:stone_with_copper 91 88 87 default:grass_1 72 109 32 default:papyrus 98 173 32 @@ -1505,7 +1505,7 @@ default:desert_stone 122 74 57 default:tree 66 52 35 default:jungletree 120 106 78 default:cactus 132 143 108 -default:water_source 39 66 106 +default:water_source 39 66 106 128 224 default:mese 200 202 0 default:stone_with_coal 91 88 87 default:nyancat 38 16 66 diff --git a/mapper.cpp b/mapper.cpp index 57da7b5..0382ff4 100644 --- a/mapper.cpp +++ b/mapper.cpp @@ -30,6 +30,7 @@ void usage() " --drawscale\n" " --drawplayers\n" " --draworigin\n" + " --drawalpha\n" " --noshading\n" " --min-y \n" " --max-y \n" @@ -53,6 +54,7 @@ int main(int argc, char *argv[]) {"draworigin", no_argument, 0, 'R'}, {"drawplayers", no_argument, 0, 'P'}, {"drawscale", no_argument, 0, 'S'}, + {"drawalpha", no_argument, 0, 'e'}, {"noshading", no_argument, 0, 'H'}, {"geometry", required_argument, 0, 'g'}, {"min-y", required_argument, 0, 'a'}, @@ -108,6 +110,9 @@ int main(int argc, char *argv[]) case 'S': generator.setDrawScale(true); break; + case 'e': + generator.setDrawAlpha(true); + break; case 'H': generator.setShading(false); break;