Add alpha transparency ability for blocks

This commit is contained in:
Sfan5 2014-04-03 20:32:48 +02:00
parent 6897ef85c7
commit 84d46ab8eb
7 changed files with 115 additions and 36 deletions

@ -11,11 +11,13 @@
#define PIXELATTRIBUTES_H_ADZ35GYF #define PIXELATTRIBUTES_H_ADZ35GYF
#include <limits> #include <limits>
#include <stdint.h>
#include "config.h" #include "config.h"
struct PixelAttribute { struct PixelAttribute {
PixelAttribute(): height(std::numeric_limits<int>::min()) {}; PixelAttribute(): height(std::numeric_limits<int>::min()), thicken(0) {};
int height; int height;
uint8_t thicken;
inline bool valid_height() { inline bool valid_height() {
return height != std::numeric_limits<int>::min(); return height != std::numeric_limits<int>::min();
} }

@ -53,6 +53,9 @@ drawplayers:
draworigin: draworigin:
Draw origin indicator, `--draworigin` Draw origin indicator, `--draworigin`
drawalpha:
Allow blocks to be drawn with transparency, `--drawalpha`
noshading: noshading:
Don't draw shading on nodes, `--noshading` Don't draw shading on nodes, `--noshading`

@ -54,9 +54,14 @@ static inline uint16_t readU16(const unsigned char *data)
return data[0] << 8 | data[1]; 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) 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(): TileGenerator::TileGenerator():
m_bgColor(255, 255, 255), m_bgColor(255, 255, 255),
m_scaleColor(0, 0, 0), m_scaleColor(0, 0, 0),
@ -101,6 +119,7 @@ TileGenerator::TileGenerator():
m_drawOrigin(false), m_drawOrigin(false),
m_drawPlayers(false), m_drawPlayers(false),
m_drawScale(false), m_drawScale(false),
m_drawAlpha(false),
m_shading(true), m_shading(true),
m_border(0), m_border(0),
m_backend("sqlite3"), 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) void TileGenerator::setShading(bool shading)
{ {
m_shading = shading; m_shading = shading;
@ -268,7 +292,7 @@ void TileGenerator::parseColorsStream(std::istream &in)
{ {
while (in.good()) { while (in.good()) {
string name; string name;
Color color; ColorEntry color;
in >> name; in >> name;
if (name[0] == '#') { if (name[0] == '#') {
in.ignore(65536, '\n'); in.ignore(65536, '\n');
@ -277,14 +301,20 @@ void TileGenerator::parseColorsStream(std::istream &in)
while (name == "\n" && in.good()) { while (name == "\n" && in.good()) {
in >> name; in >> name;
} }
int r, g, b; int r, g, b, a, t;
in >> r; in >> r;
in >> g; in >> g;
in >> b; in >> b;
if(in.peek() != '\n') {
in >> a;
if(in.peek() != '\n')
in >> t;
else
t = 0;
} else
a = 0xFF;
if (in.good()) { if (in.good()) {
color.r = r; color = ColorEntry(r,g,b,a,t);
color.g = g;
color.b = b;
m_colors[name] = color; m_colors[name] = color;
} }
} }
@ -352,7 +382,7 @@ void TileGenerator::createImage()
m_image = gdImageCreateTrueColor(m_mapWidth + m_border, m_mapHeight + m_border); m_image = gdImageCreateTrueColor(m_mapWidth + m_border, m_mapHeight + m_border);
m_blockPixelAttributes.setWidth(m_mapWidth); m_blockPixelAttributes.setWidth(m_mapWidth);
// Background // 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<int, TileGenerator::BlockList> TileGenerator::getBlocksOnZ(int zPos) std::map<int, TileGenerator::BlockList> TileGenerator::getBlocksOnZ(int zPos)
@ -496,6 +526,8 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const
const unsigned char *mapData = mapBlock.c_str(); const unsigned char *mapData = mapBlock.c_str();
int minY = (pos.y * 16 > m_yMin) ? 0 : m_yMin - pos.y * 16; 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; 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) { for (int z = 0; z < 16; ++z) {
int imageY = getImageY(zBegin + 15 - z); int imageY = getImageY(zBegin + 15 - z);
for (int x = 0; x < 16; ++x) { for (int x = 0; x < 16; ++x) {
@ -503,6 +535,10 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const
continue; continue;
} }
int imageX = getImageX(xBegin + x); int imageX = getImageX(xBegin + x);
if(m_drawAlpha) {
col = Color(0,0,0,0);
th = 0;
}
for (int y = maxY; y >= minY; --y) { for (int y = maxY; y >= minY; --y) {
int position = x + (y << 4) + (z << 8); int position = x + (y << 4) + (z << 8);
@ -511,20 +547,33 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const
continue; continue;
} }
std::map<int, std::string>::iterator blockName = m_nameMap.find(content); std::map<int, std::string>::iterator blockName = m_nameMap.find(content);
if (blockName != m_nameMap.end()) { if (blockName == m_nameMap.end())
const string &name = blockName->second; continue;
ColorMap::const_iterator color = m_colors.find(name); const string &name = blockName->second;
if (color != m_colors.end()) { ColorMap::const_iterator color = m_colors.find(name);
const Color &c = color->second; if (color != m_colors.end()) {
m_image->tpixels[imageY][imageX] = rgb2int(c.r, c.g, c.b); const Color c = color->second.to_color();
m_readedPixels[z] |= (1 << x); if (m_drawAlpha) {
m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y; if (col.a == 0)
} else { col = c;
m_unknownNodes.insert(name); else
continue; col = mixColors(col, c);
} if(col.a == 0xFF) {
break; 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) { if (d > 36) {
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 sourceColor = m_image->tpixels[imageY][getImageX(x)] & 0xffffff;
int r = (sourceColor & 0xff0000) >> 16; uint8_t r = (sourceColor & 0xff0000) >> 16;
int g = (sourceColor & 0x00ff00) >> 8; uint8_t g = (sourceColor & 0x00ff00) >> 8;
int b = (sourceColor & 0x0000ff); uint8_t b = (sourceColor & 0x0000ff);
r = colorSafeBounds(r + d); r = colorSafeBounds(r + d);
g = colorSafeBounds(g + d); g = colorSafeBounds(g + d);
b = colorSafeBounds(b + d); b = colorSafeBounds(b + d);
m_image->tpixels[imageY][getImageX(x)] = rgb2int(r, g, b); m_image->tpixels[imageY][getImageX(x)] = rgb2int(r, g, b);
} }
} }
@ -565,7 +617,7 @@ inline void TileGenerator::renderShading(int zPos)
void TileGenerator::renderScale() 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<unsigned char *>(const_cast<char *>("X")), color); gdImageString(m_image, gdFontGetMediumBold(), 24, 0, reinterpret_cast<unsigned char *>(const_cast<char *>("X")), color);
gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast<unsigned char *>(const_cast<char *>("Z")), color); gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast<unsigned char *>(const_cast<char *>("Z")), color);
@ -596,12 +648,12 @@ void TileGenerator::renderOrigin()
{ {
int imageX = -m_xMin * 16 + m_border; int imageX = -m_xMin * 16 + m_border;
int imageY = m_mapHeight - m_zMin * -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) 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); PlayerAttributes players(inputPath);
for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) { for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) {

@ -21,13 +21,27 @@
#include "db.h" #include "db.h"
struct Color { struct Color {
Color(): r(255), g(255), b(255) {}; 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) {}; 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 r;
uint8_t g; uint8_t g;
uint8_t b; 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 { struct BlockPos {
int x; int x;
int y; int y;
@ -61,7 +75,7 @@ class TileGenerator
{ {
private: private:
typedef std::basic_string<unsigned char> unsigned_string; typedef std::basic_string<unsigned char> unsigned_string;
typedef std::map<std::string, Color> ColorMap; typedef std::map<std::string, ColorEntry> ColorMap;
typedef std::pair<BlockPos, unsigned_string> Block; typedef std::pair<BlockPos, unsigned_string> Block;
typedef std::list<Block> BlockList; typedef std::list<Block> BlockList;
@ -75,6 +89,7 @@ public:
void setDrawOrigin(bool drawOrigin); void setDrawOrigin(bool drawOrigin);
void setDrawPlayers(bool drawPlayers); void setDrawPlayers(bool drawPlayers);
void setDrawScale(bool drawScale); void setDrawScale(bool drawScale);
void setDrawAlpha(bool drawAlpha);
void setShading(bool shading); void setShading(bool shading);
void setGeometry(int x, int y, int w, int h); void setGeometry(int x, int y, int w, int h);
void setMinY(int y); void setMinY(int y);
@ -110,6 +125,7 @@ private:
bool m_drawOrigin; bool m_drawOrigin;
bool m_drawPlayers; bool m_drawPlayers;
bool m_drawScale; bool m_drawScale;
bool m_drawAlpha;
bool m_shading; bool m_shading;
int m_border; int m_border;
std::string m_backend; std::string m_backend;

@ -90,8 +90,9 @@ while read -r p; do
fi fi
done < nodes.txt > colors.txt done < nodes.txt > colors.txt
# Use nicer colors for water and lava # 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: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== ==INSTRUCTIONS==
1) Make sure avgcolors.py outputs the usage instructions 1) Make sure avgcolors.py outputs the usage instructions
2) Add the dumpnodes mod to Minetest 2) Add the dumpnodes mod to Minetest

@ -1466,15 +1466,15 @@ mesecons_lightstone:lightstone_yellow_off 222 220 72
mesecons_walllever:wall_lever_on 136 136 136 mesecons_walllever:wall_lever_on 136 136 136
mesecons_walllever:wall_lever_off 136 136 136 mesecons_walllever:wall_lever_off 136 136 136
bones:bones 74 74 74 bones:bones 74 74 74
default:glass 192 192 227 default:glass 192 192 227 64 16
default:water_flowing 39 66 106 default:water_flowing 39 66 106 128 224
default:junglesapling 37 34 14 default:junglesapling 37 34 14
default:sandstonebrick 160 144 108 default:sandstonebrick 160 144 108
default:furnace_active 97 93 91 default:furnace_active 97 93 91
default:sign_wall 163 141 106 default:sign_wall 163 141 106
default:lava_source 255 100 0 default:lava_source 255 100 0
default:goldblock 126 116 35 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:stone_with_copper 91 88 87
default:grass_1 72 109 32 default:grass_1 72 109 32
default:papyrus 98 173 32 default:papyrus 98 173 32
@ -1505,7 +1505,7 @@ default:desert_stone 122 74 57
default:tree 66 52 35 default:tree 66 52 35
default:jungletree 120 106 78 default:jungletree 120 106 78
default:cactus 132 143 108 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:mese 200 202 0
default:stone_with_coal 91 88 87 default:stone_with_coal 91 88 87
default:nyancat 38 16 66 default:nyancat 38 16 66

@ -30,6 +30,7 @@ void usage()
" --drawscale\n" " --drawscale\n"
" --drawplayers\n" " --drawplayers\n"
" --draworigin\n" " --draworigin\n"
" --drawalpha\n"
" --noshading\n" " --noshading\n"
" --min-y <y>\n" " --min-y <y>\n"
" --max-y <y>\n" " --max-y <y>\n"
@ -53,6 +54,7 @@ int main(int argc, char *argv[])
{"draworigin", no_argument, 0, 'R'}, {"draworigin", no_argument, 0, 'R'},
{"drawplayers", no_argument, 0, 'P'}, {"drawplayers", no_argument, 0, 'P'},
{"drawscale", no_argument, 0, 'S'}, {"drawscale", no_argument, 0, 'S'},
{"drawalpha", no_argument, 0, 'e'},
{"noshading", no_argument, 0, 'H'}, {"noshading", no_argument, 0, 'H'},
{"geometry", required_argument, 0, 'g'}, {"geometry", required_argument, 0, 'g'},
{"min-y", required_argument, 0, 'a'}, {"min-y", required_argument, 0, 'a'},
@ -108,6 +110,9 @@ int main(int argc, char *argv[])
case 'S': case 'S':
generator.setDrawScale(true); generator.setDrawScale(true);
break; break;
case 'e':
generator.setDrawAlpha(true);
break;
case 'H': case 'H':
generator.setShading(false); generator.setShading(false);
break; break;