diff --git a/src/environment.cpp b/src/environment.cpp index 0ad96c0..6dc599b 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -983,7 +983,7 @@ void ServerEnvironment::step(float dtime) block->incNodeTicks(p0); MapNode n = block->getNodeNoEx(p0); - if (!has_spawned && active_object_count_wider < 20 && content_mob_spawn(this,p,active_object_count_wider)) { + if (!has_spawned && active_object_count_wider < 10 && content_mob_spawn(this,p,active_object_count_wider)) { has_spawned = true; active_object_count_wider++; } diff --git a/src/hex.h b/src/hex.h index 87a6aec..6f00a79 100644 --- a/src/hex.h +++ b/src/hex.h @@ -46,4 +46,17 @@ static inline std::string hex_encode(const std::string &data) return hex_encode(data.c_str(), data.size()); } +static inline bool hex_digit_decode(char hexdigit, unsigned char &value) +{ + if(hexdigit >= '0' && hexdigit <= '9') + value = hexdigit - '0'; + else if(hexdigit >= 'A' && hexdigit <= 'F') + value = hexdigit - 'A' + 10; + else if(hexdigit >= 'a' && hexdigit <= 'f') + value = hexdigit - 'a' + 10; + else + return false; + return true; +} + #endif diff --git a/src/tile.cpp b/src/tile.cpp index 44a9dcf..9a81cdc 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "utility.h" #include "settings.h" #include "mesh.h" +#include "hex.h" #include #include "log.h" #include "mapnode.h" // For texture atlas making @@ -96,21 +97,16 @@ u32 TextureSource::getTextureId(const std::string &name) JMutexAutoLock lock(m_atlaspointer_cache_mutex); core::map::Node *n; n = m_name_to_id.find(name); - if(n != NULL) - { + if (n != NULL) return n->getValue(); - } } /* Get texture */ - if(get_current_thread_id() == m_main_thread) - { + if (get_current_thread_id() == m_main_thread) { return getTextureIdDirect(name); - } - else - { + }else{ infostream<<"getTextureId(): Queued: name=\""< result = result_queue.pop_front(1000); @@ -132,9 +127,7 @@ u32 TextureSource::getTextureId(const std::string &name) assert(result.key == name); return result.item; - } - catch(ItemNotFoundException &e) - { + }catch(ItemNotFoundException &e) { infostream<<"Waiting for texture timed out."<::Node *n; n = m_name_to_id.find(name); - if(n != NULL) - { - infostream<<"getTextureIdDirect(): \""<getValue(); } } @@ -222,10 +212,8 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) // Find last meta separator in name s32 last_separator_position = -1; - for(s32 i=name.size()-1; i>=0; i--) - { - if(name[i] == separator) - { + for (s32 i=name.size()-1; i>=0; i--) { + if (name[i] == separator) { last_separator_position = i; break; } @@ -235,8 +223,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) base image using a recursive call */ std::string base_image_name; - if(last_separator_position != -1) - { + if (last_separator_position != -1) { // Construct base name base_image_name = name.substr(0, last_separator_position); /*infostream<<"getTextureIdDirect(): Calling itself recursively" @@ -258,22 +245,18 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) video::IImage *baseimg = NULL; // If a base image was found, copy it to baseimg - if(base_image_id != 0) - { + if (base_image_id != 0) { JMutexAutoLock lock(m_atlaspointer_cache_mutex); SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id]; video::IImage *image = ap.atlas_img; - if(image == NULL) - { + if (image == NULL) { infostream<<"getTextureIdDirect(): NULL image in " <<"cache: \""< dim = ap.intsize; baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); @@ -282,9 +265,9 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) core::position2d pos_from = ap.intpos; image->copyTo( - baseimg, // target - v2s32(0,0), // position in target - core::rect(pos_from, dim) // from + baseimg, // target + v2s32(0,0), // position in target + core::rect(pos_from, dim) // from ); /*infostream<<"getTextureIdDirect(): Loaded \"" @@ -302,22 +285,19 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) //infostream<<"last_part_of_name=\""<addTexture(name.c_str(), baseimg); } @@ -335,7 +315,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) ap.size = v2f(1,1); ap.tiled = 0; core::dimension2d baseimg_dim(0,0); - if(baseimg) + if (baseimg) baseimg_dim = baseimg->getDimension(); SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim); m_atlaspointer_cache.push_back(nap); @@ -631,6 +611,275 @@ void TextureSource::buildMainAtlas() driver->writeImageToFile(atlas_img, atlaspath.c_str());*/ } +static bool parseHexColorString(const std::string &value, video::SColor &color) +{ + unsigned char components[] = { 0x00, 0x00, 0x00, 0xff }; // R,G,B,A + + if (value[0] != '#') + return false; + + size_t len = value.size(); + bool short_form; + + if (len == 9 || len == 7) // #RRGGBBAA or #RRGGBB + short_form = false; + else if (len == 5 || len == 4) // #RGBA or #RGB + short_form = true; + else + return false; + + bool success = true; + + for (size_t pos = 1, cc = 0; pos < len; pos++, cc++) { + assert(cc < sizeof components / sizeof components[0]); + if (short_form) { + unsigned char d; + if (!hex_digit_decode(value[pos], d)) { + success = false; + break; + } + components[cc] = (d & 0xf) << 4 | (d & 0xf); + } else { + unsigned char d1, d2; + if (!hex_digit_decode(value[pos], d1) || + !hex_digit_decode(value[pos+1], d2)) { + success = false; + break; + } + components[cc] = (d1 & 0xf) << 4 | (d2 & 0xf); + pos++; // skip the second digit -- it's already used + } + } + + if (success) { + color.setRed(components[0]); + color.setGreen(components[1]); + color.setBlue(components[2]); + color.setAlpha(components[3]); + } + + return success; +} + +struct ColorContainer { + ColorContainer(); + std::map colors; +}; + +ColorContainer::ColorContainer() +{ + colors["aliceblue"] = 0xf0f8ff; + colors["antiquewhite"] = 0xfaebd7; + colors["aqua"] = 0x00ffff; + colors["aquamarine"] = 0x7fffd4; + colors["azure"] = 0xf0ffff; + colors["beige"] = 0xf5f5dc; + colors["bisque"] = 0xffe4c4; + colors["black"] = 00000000; + colors["blanchedalmond"] = 0xffebcd; + colors["blue"] = 0x0000ff; + colors["blueviolet"] = 0x8a2be2; + colors["brown"] = 0xa52a2a; + colors["burlywood"] = 0xdeb887; + colors["cadetblue"] = 0x5f9ea0; + colors["chartreuse"] = 0x7fff00; + colors["chocolate"] = 0xd2691e; + colors["coral"] = 0xff7f50; + colors["cornflowerblue"] = 0x6495ed; + colors["cornsilk"] = 0xfff8dc; + colors["crimson"] = 0xdc143c; + colors["cyan"] = 0x00ffff; + colors["darkblue"] = 0x00008b; + colors["darkcyan"] = 0x008b8b; + colors["darkgoldenrod"] = 0xb8860b; + colors["darkgray"] = 0xa9a9a9; + colors["darkgreen"] = 0x006400; + colors["darkkhaki"] = 0xbdb76b; + colors["darkmagenta"] = 0x8b008b; + colors["darkolivegreen"] = 0x556b2f; + colors["darkorange"] = 0xff8c00; + colors["darkorchid"] = 0x9932cc; + colors["darkred"] = 0x8b0000; + colors["darksalmon"] = 0xe9967a; + colors["darkseagreen"] = 0x8fbc8f; + colors["darkslateblue"] = 0x483d8b; + colors["darkslategray"] = 0x2f4f4f; + colors["darkturquoise"] = 0x00ced1; + colors["darkviolet"] = 0x9400d3; + colors["deeppink"] = 0xff1493; + colors["deepskyblue"] = 0x00bfff; + colors["dimgray"] = 0x696969; + colors["dodgerblue"] = 0x1e90ff; + colors["firebrick"] = 0xb22222; + colors["floralwhite"] = 0xfffaf0; + colors["forestgreen"] = 0x228b22; + colors["fuchsia"] = 0xff00ff; + colors["gainsboro"] = 0xdcdcdc; + colors["ghostwhite"] = 0xf8f8ff; + colors["gold"] = 0xffd700; + colors["goldenrod"] = 0xdaa520; + colors["gray"] = 0x808080; + colors["green"] = 0x008000; + colors["greenyellow"] = 0xadff2f; + colors["honeydew"] = 0xf0fff0; + colors["hotpink"] = 0xff69b4; + colors["indianred "] = 0xcd5c5c; + colors["indigo "] = 0x4b0082; + colors["ivory"] = 0xfffff0; + colors["khaki"] = 0xf0e68c; + colors["lavender"] = 0xe6e6fa; + colors["lavenderblush"] = 0xfff0f5; + colors["lawngreen"] = 0x7cfc00; + colors["lemonchiffon"] = 0xfffacd; + colors["lightblue"] = 0xadd8e6; + colors["lightcoral"] = 0xf08080; + colors["lightcyan"] = 0xe0ffff; + colors["lightgoldenrodyellow"] = 0xfafad2; + colors["lightgray"] = 0xd3d3d3; + colors["lightgreen"] = 0x90ee90; + colors["lightpink"] = 0xffb6c1; + colors["lightsalmon"] = 0xffa07a; + colors["lightseagreen"] = 0x20b2aa; + colors["lightskyblue"] = 0x87cefa; + colors["lightslategray"] = 0x778899; + colors["lightsteelblue"] = 0xb0c4de; + colors["lightyellow"] = 0xffffe0; + colors["lime"] = 0x00ff00; + colors["limegreen"] = 0x32cd32; + colors["linen"] = 0xfaf0e6; + colors["magenta"] = 0xff00ff; + colors["maroon"] = 0x800000; + colors["mediumaquamarine"] = 0x66cdaa; + colors["mediumblue"] = 0x0000cd; + colors["mediumorchid"] = 0xba55d3; + colors["mediumpurple"] = 0x9370db; + colors["mediumseagreen"] = 0x3cb371; + colors["mediumslateblue"] = 0x7b68ee; + colors["mediumspringgreen"] = 0x00fa9a; + colors["mediumturquoise"] = 0x48d1cc; + colors["mediumvioletred"] = 0xc71585; + colors["midnightblue"] = 0x191970; + colors["mintcream"] = 0xf5fffa; + colors["mistyrose"] = 0xffe4e1; + colors["moccasin"] = 0xffe4b5; + colors["navajowhite"] = 0xffdead; + colors["navy"] = 0x000080; + colors["oldlace"] = 0xfdf5e6; + colors["olive"] = 0x808000; + colors["olivedrab"] = 0x6b8e23; + colors["orange"] = 0xffa500; + colors["orangered"] = 0xff4500; + colors["orchid"] = 0xda70d6; + colors["palegoldenrod"] = 0xeee8aa; + colors["palegreen"] = 0x98fb98; + colors["paleturquoise"] = 0xafeeee; + colors["palevioletred"] = 0xdb7093; + colors["papayawhip"] = 0xffefd5; + colors["peachpuff"] = 0xffdab9; + colors["peru"] = 0xcd853f; + colors["pink"] = 0xffc0cb; + colors["plum"] = 0xdda0dd; + colors["powderblue"] = 0xb0e0e6; + colors["purple"] = 0x800080; + colors["red"] = 0xff0000; + colors["rosybrown"] = 0xbc8f8f; + colors["royalblue"] = 0x4169e1; + colors["saddlebrown"] = 0x8b4513; + colors["salmon"] = 0xfa8072; + colors["sandybrown"] = 0xf4a460; + colors["seagreen"] = 0x2e8b57; + colors["seashell"] = 0xfff5ee; + colors["sienna"] = 0xa0522d; + colors["silver"] = 0xc0c0c0; + colors["skyblue"] = 0x87ceeb; + colors["slateblue"] = 0x6a5acd; + colors["slategray"] = 0x708090; + colors["snow"] = 0xfffafa; + colors["springgreen"] = 0x00ff7f; + colors["steelblue"] = 0x4682b4; + colors["tan"] = 0xd2b48c; + colors["teal"] = 0x008080; + colors["thistle"] = 0xd8bfd8; + colors["tomato"] = 0xff6347; + colors["turquoise"] = 0x40e0d0; + colors["violet"] = 0xee82ee; + colors["wheat"] = 0xf5deb3; + colors["white"] = 0xffffff; + colors["whitesmoke"] = 0xf5f5f5; + colors["yellow"] = 0xffff00; + colors["yellowgreen"] = 0x9acd32; + +} + +static const ColorContainer named_colors; + +static bool parseNamedColorString(const std::string &value, video::SColor &color) +{ + std::string color_name; + std::string alpha_string; + + /* If the string has a # in it, assume this is the start of a specified + * alpha value (if it isn't the string is invalid and the error will be + * caught later on, either because the color name won't be found or the + * alpha value will fail conversion) + */ + size_t alpha_pos = value.find('#'); + if (alpha_pos != std::string::npos) { + color_name = value.substr(0, alpha_pos); + alpha_string = value.substr(alpha_pos + 1); + } else { + color_name = value; + } + + color_name = lowercase(value); + + std::map::const_iterator it; + it = named_colors.colors.find(color_name); + if (it == named_colors.colors.end()) + return false; + + u32 color_temp = it->second; + + /* An empty string for alpha is ok (none of the color table entries + * have an alpha value either). Color strings without an alpha specified + * are interpreted as fully opaque + * + * For named colors the supplied alpha string (representing a hex value) + * must be exactly two digits. For example: colorname#08 + */ + if (!alpha_string.empty()) { + if (alpha_string.length() != 2) + return false; + + unsigned char d1, d2; + if (!hex_digit_decode(alpha_string.at(0), d1) + || !hex_digit_decode(alpha_string.at(1), d2)) + return false; + color_temp |= ((d1 & 0xf) << 4 | (d2 & 0xf)) << 24; + } else { + color_temp |= 0xff << 24; // Fully opaque + } + + color = video::SColor(color_temp); + + return true; +} + +bool parseColorString(const std::string &value, video::SColor &color, bool quiet) +{ + bool success; + + if (value[0] == '#') + success = parseHexColorString(value, color); + else + success = parseNamedColorString(value, color); + + if (!success && !quiet) + errorstream << "Invalid color: \"" << value << "\"" << std::endl; + + return success; +} + video::IImage* generate_image_from_scratch(std::string name, IrrlichtDevice *device) { @@ -1379,6 +1628,42 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, image->drop(); } } + /* + [colorize:color + Overlays image with given color + color = color as ColorString + */ + else if (part_of_name.substr(0,10) == "[colorize:") { + Strfnd sf(part_of_name); + sf.next(":"); + std::string color_str = sf.next(":"); + + if (baseimg == NULL) { + errorstream << "generateImagePart(): baseimg != NULL " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + video::SColor color; + if (!parseColorString(color_str, color, false)) + return false; + + core::dimension2d dim = baseimg->getDimension(); + video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim); + + if (!img) { + errorstream << "generateImagePart(): Could not create image " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + img->fill(video::SColor(color)); + // Overlay the colored image + blit_with_alpha_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim); + img->drop(); + } else { infostream<<"generate_image(): Invalid " @@ -1569,3 +1854,27 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst) } } +/* + Draw an image on top of an another one, using the alpha channel of the + source image; only modify fully opaque pixels in destinaion +*/ +static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst, + v2s32 src_pos, v2s32 dst_pos, v2u32 size) +{ + for(u32 y0=0; y0getPixel(src_x, src_y); + video::SColor dst_c = dst->getPixel(dst_x, dst_y); + if(dst_c.getAlpha() == 255 && src_c.getAlpha() != 0) + { + dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f); + dst->setPixel(dst_x, dst_y, dst_c); + } + } +} +