Added ratio argument to colorize, removed the weird alpha-based ratio.

This commit is contained in:
TriBlade9 2015-01-19 14:15:20 +08:00 committed by Craig Robbins
parent 60d745126f
commit db481e7232
2 changed files with 137 additions and 98 deletions

View File

@ -337,9 +337,11 @@ Apply a mask to the base image.
The mask is applied using binary AND. The mask is applied using binary AND.
#### `[colorize:<color>` #### `[colorize:<color>:<ratio>`
Colorize the textures with the given color. Colorize the textures with the given color.
`<color>` is specified as a `ColorString`. `<color>` is specified as a `ColorString`.
`<ratio>` is an int ranging from 0 to 255, and specifies how much of the
color to apply. If ommitted, the alpha will be used.
Sounds Sounds
------ ------
@ -3259,4 +3261,3 @@ Definition tables
playername = "singleplayer" playername = "singleplayer"
-- ^ Playername is optional, if specified spawns particle only on the player's client -- ^ Playername is optional, if specified spawns particle only on the player's client
} }

View File

@ -54,23 +54,23 @@ MutexedMap<std::string, std::string> g_texturename_to_path_cache;
*/ */
static bool replace_ext(std::string &path, const char *ext) static bool replace_ext(std::string &path, const char *ext)
{ {
if(ext == NULL) if (ext == NULL)
return false; return false;
// Find place of last dot, fail if \ or / found. // Find place of last dot, fail if \ or / found.
s32 last_dot_i = -1; s32 last_dot_i = -1;
for(s32 i=path.size()-1; i>=0; i--) for (s32 i=path.size()-1; i>=0; i--)
{ {
if(path[i] == '.') if (path[i] == '.')
{ {
last_dot_i = i; last_dot_i = i;
break; break;
} }
if(path[i] == '\\' || path[i] == '/') if (path[i] == '\\' || path[i] == '/')
break; break;
} }
// If not found, return an empty string // If not found, return an empty string
if(last_dot_i == -1) if (last_dot_i == -1)
return false; return false;
// Else make the new path // Else make the new path
path = path.substr(0, last_dot_i+1) + ext; path = path.substr(0, last_dot_i+1) + ext;
@ -92,15 +92,15 @@ std::string getImagePath(std::string path)
NULL NULL
}; };
// If there is no extension, add one // If there is no extension, add one
if(removeStringEnd(path, extensions) == "") if (removeStringEnd(path, extensions) == "")
path = path + ".png"; path = path + ".png";
// Check paths until something is found to exist // Check paths until something is found to exist
const char **ext = extensions; const char **ext = extensions;
do{ do{
bool r = replace_ext(path, *ext); bool r = replace_ext(path, *ext);
if(r == false) if (r == false)
return ""; return "";
if(fs::PathExists(path)) if (fs::PathExists(path))
return path; return path;
} }
while((++ext) != NULL); while((++ext) != NULL);
@ -125,14 +125,14 @@ std::string getTexturePath(const std::string &filename)
Check from cache Check from cache
*/ */
bool incache = g_texturename_to_path_cache.get(filename, &fullpath); bool incache = g_texturename_to_path_cache.get(filename, &fullpath);
if(incache) if (incache)
return fullpath; return fullpath;
/* /*
Check from texture_path Check from texture_path
*/ */
std::string texture_path = g_settings->get("texture_path"); std::string texture_path = g_settings->get("texture_path");
if(texture_path != "") if (texture_path != "")
{ {
std::string testpath = texture_path + DIR_DELIM + filename; std::string testpath = texture_path + DIR_DELIM + filename;
// Check all filename extensions. Returns "" if not found. // Check all filename extensions. Returns "" if not found.
@ -142,7 +142,7 @@ std::string getTexturePath(const std::string &filename)
/* /*
Check from default data directory Check from default data directory
*/ */
if(fullpath == "") if (fullpath == "")
{ {
std::string base_path = porting::path_share + DIR_DELIM + "textures" std::string base_path = porting::path_share + DIR_DELIM + "textures"
+ DIR_DELIM + "base" + DIR_DELIM + "pack"; + DIR_DELIM + "base" + DIR_DELIM + "pack";
@ -190,7 +190,7 @@ class SourceImageCache
{ {
public: public:
~SourceImageCache() { ~SourceImageCache() {
for(std::map<std::string, video::IImage*>::iterator iter = m_images.begin(); for (std::map<std::string, video::IImage*>::iterator iter = m_images.begin();
iter != m_images.end(); iter++) { iter != m_images.end(); iter++) {
iter->second->drop(); iter->second->drop();
} }
@ -203,8 +203,8 @@ public:
// Remove old image // Remove old image
std::map<std::string, video::IImage*>::iterator n; std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name); n = m_images.find(name);
if(n != m_images.end()){ if (n != m_images.end()){
if(n->second) if (n->second)
n->second->drop(); n->second->drop();
} }
@ -212,11 +212,11 @@ public:
bool need_to_grab = true; bool need_to_grab = true;
// Try to use local texture instead if asked to // Try to use local texture instead if asked to
if(prefer_local){ if (prefer_local){
std::string path = getTexturePath(name); std::string path = getTexturePath(name);
if(path != ""){ if (path != ""){
video::IImage *img2 = driver->createImageFromFile(path.c_str()); video::IImage *img2 = driver->createImageFromFile(path.c_str());
if(img2){ if (img2){
toadd = img2; toadd = img2;
need_to_grab = false; need_to_grab = false;
} }
@ -231,7 +231,7 @@ public:
{ {
std::map<std::string, video::IImage*>::iterator n; std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name); n = m_images.find(name);
if(n != m_images.end()) if (n != m_images.end())
return n->second; return n->second;
return NULL; return NULL;
} }
@ -240,13 +240,13 @@ public:
{ {
std::map<std::string, video::IImage*>::iterator n; std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name); n = m_images.find(name);
if(n != m_images.end()){ if (n != m_images.end()){
n->second->grab(); // Grab for caller n->second->grab(); // Grab for caller
return n->second; return n->second;
} }
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
std::string path = getTexturePath(name); std::string path = getTexturePath(name);
if(path == ""){ if (path == ""){
infostream<<"SourceImageCache::getOrLoad(): No path found for \"" infostream<<"SourceImageCache::getOrLoad(): No path found for \""
<<name<<"\""<<std::endl; <<name<<"\""<<std::endl;
return NULL; return NULL;
@ -255,7 +255,7 @@ public:
<<"\""<<std::endl; <<"\""<<std::endl;
video::IImage *img = driver->createImageFromFile(path.c_str()); video::IImage *img = driver->createImageFromFile(path.c_str());
if(img){ if (img){
m_images[name] = img; m_images[name] = img;
img->grab(); // Grab for caller img->grab(); // Grab for caller
} }
@ -341,7 +341,7 @@ public:
{ {
bool is_known = false; bool is_known = false;
bool cache_found = m_source_image_existence.get(name, &is_known); bool cache_found = m_source_image_existence.get(name, &is_known);
if(cache_found) if (cache_found)
return is_known; return is_known;
// Not found in cache; find out if a local file exists // Not found in cache; find out if a local file exists
is_known = (getTexturePath(name) != ""); is_known = (getTexturePath(name) != "");
@ -480,7 +480,7 @@ u32 TextureSource::getTextureId(const std::string &name)
JMutexAutoLock lock(m_textureinfo_cache_mutex); JMutexAutoLock lock(m_textureinfo_cache_mutex);
std::map<std::string, u32>::iterator n; std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name); n = m_name_to_id.find(name);
if(n != m_name_to_id.end()) if (n != m_name_to_id.end())
{ {
return n->second; return n->second;
} }
@ -489,7 +489,7 @@ u32 TextureSource::getTextureId(const std::string &name)
/* /*
Get texture Get texture
*/ */
if(get_current_thread_id() == m_main_thread) if (get_current_thread_id() == m_main_thread)
{ {
return generateTexture(name); return generateTexture(name);
} }
@ -540,6 +540,11 @@ static void blit_with_alpha(video::IImage *src, video::IImage *dst,
static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst, static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
v2s32 src_pos, v2s32 dst_pos, v2u32 size); v2s32 src_pos, v2s32 dst_pos, v2u32 size);
// Like blit_with_alpha overlay, but uses an int to calculate the ratio
// and modifies any destination pixels that are not fully transparent
static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst,
v2s32 src_pos, v2s32 dst_pos, v2u32 size, int ratio);
// Apply a mask to an image // Apply a mask to an image
static void apply_mask(video::IImage *mask, video::IImage *dst, static void apply_mask(video::IImage *mask, video::IImage *dst,
v2s32 mask_pos, v2s32 dst_pos, v2u32 size); v2s32 mask_pos, v2s32 dst_pos, v2u32 size);
@ -626,7 +631,7 @@ std::string TextureSource::getTextureName(u32 id)
{ {
JMutexAutoLock lock(m_textureinfo_cache_mutex); JMutexAutoLock lock(m_textureinfo_cache_mutex);
if(id >= m_textureinfo_cache.size()) if (id >= m_textureinfo_cache.size())
{ {
errorstream<<"TextureSource::getTextureName(): id="<<id errorstream<<"TextureSource::getTextureName(): id="<<id
<<" >= m_textureinfo_cache.size()=" <<" >= m_textureinfo_cache.size()="
@ -641,7 +646,7 @@ video::ITexture* TextureSource::getTexture(u32 id)
{ {
JMutexAutoLock lock(m_textureinfo_cache_mutex); JMutexAutoLock lock(m_textureinfo_cache_mutex);
if(id >= m_textureinfo_cache.size()) if (id >= m_textureinfo_cache.size())
return NULL; return NULL;
return m_textureinfo_cache[id].texture; return m_textureinfo_cache[id].texture;
@ -650,7 +655,7 @@ video::ITexture* TextureSource::getTexture(u32 id)
video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id) video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id)
{ {
u32 actual_id = getTextureId(name); u32 actual_id = getTextureId(name);
if(id){ if (id){
*id = actual_id; *id = actual_id;
} }
return getTexture(actual_id); return getTexture(actual_id);
@ -662,7 +667,7 @@ void TextureSource::processQueue()
Fetch textures Fetch textures
*/ */
//NOTE this is only thread safe for ONE consumer thread! //NOTE this is only thread safe for ONE consumer thread!
if(!m_get_texture_queue.empty()) if (!m_get_texture_queue.empty())
{ {
GetRequest<std::string, u32, u8, u8> GetRequest<std::string, u32, u8, u8>
request = m_get_texture_queue.pop(); request = m_get_texture_queue.pop();
@ -694,7 +699,7 @@ void TextureSource::rebuildImagesAndTextures()
assert(driver != 0); assert(driver != 0);
// Recreate textures // Recreate textures
for(u32 i=0; i<m_textureinfo_cache.size(); i++){ for (u32 i=0; i<m_textureinfo_cache.size(); i++){
TextureInfo *ti = &m_textureinfo_cache[i]; TextureInfo *ti = &m_textureinfo_cache[i];
video::IImage *img = generateImage(ti->name); video::IImage *img = generateImage(ti->name);
#ifdef __ANDROID__ #ifdef __ANDROID__
@ -836,17 +841,17 @@ video::ITexture* TextureSource::generateTextureFromMesh(
driver->makeColorKeyTexture(rtt, v2s32(0,0)); driver->makeColorKeyTexture(rtt, v2s32(0,0));
if(params.delete_texture_on_shutdown) if (params.delete_texture_on_shutdown)
m_texture_trash.push_back(rtt); m_texture_trash.push_back(rtt);
return rtt; return rtt;
} }
#endif #endif
if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false) if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
{ {
static bool warned = false; static bool warned = false;
if(!warned) if (!warned)
{ {
errorstream<<"TextureSource::generateTextureFromMesh(): " errorstream<<"TextureSource::generateTextureFromMesh(): "
<<"EVDF_RENDER_TO_TARGET not supported."<<std::endl; <<"EVDF_RENDER_TO_TARGET not supported."<<std::endl;
@ -859,7 +864,7 @@ video::ITexture* TextureSource::generateTextureFromMesh(
video::ITexture *rtt = driver->addRenderTargetTexture( video::ITexture *rtt = driver->addRenderTargetTexture(
params.dim, params.rtt_texture_name.c_str(), params.dim, params.rtt_texture_name.c_str(),
video::ECF_A8R8G8B8); video::ECF_A8R8G8B8);
if(rtt == NULL) if (rtt == NULL)
{ {
errorstream<<"TextureSource::generateTextureFromMesh(): " errorstream<<"TextureSource::generateTextureFromMesh(): "
<<"addRenderTargetTexture returned NULL."<<std::endl; <<"addRenderTargetTexture returned NULL."<<std::endl;
@ -911,7 +916,7 @@ video::ITexture* TextureSource::generateTextureFromMesh(
// Unset render target // Unset render target
driver->setRenderTarget(0, false, true, 0); driver->setRenderTarget(0, false, true, 0);
if(params.delete_texture_on_shutdown) if (params.delete_texture_on_shutdown)
m_texture_trash.push_back(rtt); m_texture_trash.push_back(rtt);
return rtt; return rtt;
@ -930,7 +935,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
// Find last separator in the name // Find last separator in the name
s32 last_separator_pos = -1; s32 last_separator_pos = -1;
u8 paren_bal = 0; u8 paren_bal = 0;
for(s32 i = name.size() - 1; i >= 0; i--) { for (s32 i = name.size() - 1; i >= 0; i--) {
switch(name[i]) { switch(name[i]) {
case separator: case separator:
if (paren_bal == 0) { if (paren_bal == 0) {
@ -1030,7 +1035,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
video::IImage * Align2Npot2(video::IImage * image, video::IImage * Align2Npot2(video::IImage * image,
video::IVideoDriver* driver) video::IVideoDriver* driver)
{ {
if(image == NULL) { if (image == NULL) {
return image; return image;
} }
@ -1077,7 +1082,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
assert(driver); assert(driver);
// Stuff starting with [ are special commands // Stuff starting with [ are special commands
if(part_of_name.size() == 0 || part_of_name[0] != '[') if (part_of_name.size() == 0 || part_of_name[0] != '[')
{ {
video::IImage *image = m_sourcecache.getOrLoad(part_of_name, m_device); video::IImage *image = m_sourcecache.getOrLoad(part_of_name, m_device);
#ifdef __ANDROID__ #ifdef __ANDROID__
@ -1118,7 +1123,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
// If base image is NULL, load as base. // If base image is NULL, load as base.
if(baseimg == NULL) if (baseimg == NULL)
{ {
//infostream<<"Setting "<<part_of_name<<" as base"<<std::endl; //infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
/* /*
@ -1165,7 +1170,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Adds a cracking texture Adds a cracking texture
N = animation frame count, P = crack progression N = animation frame count, P = crack progression
*/ */
if(part_of_name.substr(0,6) == "[crack") if (part_of_name.substr(0,6) == "[crack")
{ {
if (baseimg == NULL) { if (baseimg == NULL) {
errorstream<<"generateImagePart(): baseimg == NULL " errorstream<<"generateImagePart(): baseimg == NULL "
@ -1190,7 +1195,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
video::IImage *img_crack = m_sourcecache.getOrLoad( video::IImage *img_crack = m_sourcecache.getOrLoad(
"crack_anylength.png", m_device); "crack_anylength.png", m_device);
if(img_crack && progression >= 0) if (img_crack && progression >= 0)
{ {
draw_crack(img_crack, baseimg, draw_crack(img_crack, baseimg,
use_overlay, frame_count, use_overlay, frame_count,
@ -1202,7 +1207,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
[combine:WxH:X,Y=filename:X,Y=filename2 [combine:WxH:X,Y=filename:X,Y=filename2
Creates a bigger texture from an amount of smaller ones Creates a bigger texture from an amount of smaller ones
*/ */
else if(part_of_name.substr(0,8) == "[combine") else if (part_of_name.substr(0,8) == "[combine")
{ {
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); sf.next(":");
@ -1246,7 +1251,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
/* /*
"[brighten" "[brighten"
*/ */
else if(part_of_name.substr(0,9) == "[brighten") else if (part_of_name.substr(0,9) == "[brighten")
{ {
if (baseimg == NULL) { if (baseimg == NULL) {
errorstream<<"generateImagePart(): baseimg==NULL " errorstream<<"generateImagePart(): baseimg==NULL "
@ -1264,7 +1269,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
that the transparent parts don't look completely black that the transparent parts don't look completely black
when simple alpha channel is used for rendering. when simple alpha channel is used for rendering.
*/ */
else if(part_of_name.substr(0,8) == "[noalpha") else if (part_of_name.substr(0,8) == "[noalpha")
{ {
if (baseimg == NULL){ if (baseimg == NULL){
errorstream<<"generateImagePart(): baseimg==NULL " errorstream<<"generateImagePart(): baseimg==NULL "
@ -1276,8 +1281,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
core::dimension2d<u32> dim = baseimg->getDimension(); core::dimension2d<u32> dim = baseimg->getDimension();
// Set alpha to full // Set alpha to full
for(u32 y=0; y<dim.Height; y++) for (u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++) for (u32 x=0; x<dim.Width; x++)
{ {
video::SColor c = baseimg->getPixel(x,y); video::SColor c = baseimg->getPixel(x,y);
c.setAlpha(255); c.setAlpha(255);
@ -1288,7 +1293,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
"[makealpha:R,G,B" "[makealpha:R,G,B"
Convert one color to transparent. Convert one color to transparent.
*/ */
else if(part_of_name.substr(0,11) == "[makealpha:") else if (part_of_name.substr(0,11) == "[makealpha:")
{ {
if (baseimg == NULL) { if (baseimg == NULL) {
errorstream<<"generateImagePart(): baseimg == NULL " errorstream<<"generateImagePart(): baseimg == NULL "
@ -1311,14 +1316,14 @@ bool TextureSource::generateImagePart(std::string part_of_name,
oldbaseimg->drop();*/ oldbaseimg->drop();*/
// Set alpha to full // Set alpha to full
for(u32 y=0; y<dim.Height; y++) for (u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++) for (u32 x=0; x<dim.Width; x++)
{ {
video::SColor c = baseimg->getPixel(x,y); video::SColor c = baseimg->getPixel(x,y);
u32 r = c.getRed(); u32 r = c.getRed();
u32 g = c.getGreen(); u32 g = c.getGreen();
u32 b = c.getBlue(); u32 b = c.getBlue();
if(!(r == r1 && g == g1 && b == b1)) if (!(r == r1 && g == g1 && b == b1))
continue; continue;
c.setAlpha(0); c.setAlpha(0);
baseimg->setPixel(x,y,c); baseimg->setPixel(x,y,c);
@ -1344,7 +1349,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
The resulting transform will be equivalent to one of the The resulting transform will be equivalent to one of the
eight existing ones, though (see: dihedral group). eight existing ones, though (see: dihedral group).
*/ */
else if(part_of_name.substr(0,10) == "[transform") else if (part_of_name.substr(0,10) == "[transform")
{ {
if (baseimg == NULL) { if (baseimg == NULL) {
errorstream<<"generateImagePart(): baseimg == NULL " errorstream<<"generateImagePart(): baseimg == NULL "
@ -1371,7 +1376,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Example (a grass block (not actually used in game): Example (a grass block (not actually used in game):
"[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png" "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
*/ */
else if(part_of_name.substr(0,14) == "[inventorycube") else if (part_of_name.substr(0,14) == "[inventorycube")
{ {
if (baseimg != NULL){ if (baseimg != NULL){
errorstream<<"generateImagePart(): baseimg != NULL " errorstream<<"generateImagePart(): baseimg != NULL "
@ -1488,7 +1493,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
[lowpart:percent:filename [lowpart:percent:filename
Adds the lower part of a texture Adds the lower part of a texture
*/ */
else if(part_of_name.substr(0,9) == "[lowpart:") else if (part_of_name.substr(0,9) == "[lowpart:")
{ {
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); sf.next(":");
@ -1496,10 +1501,10 @@ bool TextureSource::generateImagePart(std::string part_of_name,
std::string filename = sf.next(":"); std::string filename = sf.next(":");
//infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl; //infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl;
if(baseimg == NULL) if (baseimg == NULL)
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16)); baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
video::IImage *img = m_sourcecache.getOrLoad(filename, m_device); video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
if(img) if (img)
{ {
core::dimension2d<u32> dim = img->getDimension(); core::dimension2d<u32> dim = img->getDimension();
core::position2d<s32> pos_base(0, 0); core::position2d<s32> pos_base(0, 0);
@ -1524,14 +1529,14 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Crops a frame of a vertical animation. Crops a frame of a vertical animation.
N = frame count, I = frame index N = frame count, I = frame index
*/ */
else if(part_of_name.substr(0,15) == "[verticalframe:") else if (part_of_name.substr(0,15) == "[verticalframe:")
{ {
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); sf.next(":");
u32 frame_count = stoi(sf.next(":")); u32 frame_count = stoi(sf.next(":"));
u32 frame_index = stoi(sf.next(":")); u32 frame_index = stoi(sf.next(":"));
if(baseimg == NULL){ if (baseimg == NULL){
errorstream<<"generateImagePart(): baseimg != NULL " errorstream<<"generateImagePart(): baseimg != NULL "
<<"for part_of_name=\""<<part_of_name <<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl; <<"\", cancelling."<<std::endl;
@ -1543,7 +1548,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
frame_size); frame_size);
if(!img){ if (!img){
errorstream<<"generateImagePart(): Could not create image " errorstream<<"generateImagePart(): Could not create image "
<<"for part_of_name=\""<<part_of_name <<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl; <<"\", cancelling."<<std::endl;
@ -1568,7 +1573,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
[mask:filename [mask:filename
Applies a mask to an image Applies a mask to an image
*/ */
else if(part_of_name.substr(0,6) == "[mask:") else if (part_of_name.substr(0,6) == "[mask:")
{ {
if (baseimg == NULL) { if (baseimg == NULL) {
errorstream << "generateImage(): baseimg == NULL " errorstream << "generateImage(): baseimg == NULL "
@ -1598,6 +1603,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); sf.next(":");
std::string color_str = sf.next(":"); std::string color_str = sf.next(":");
std::string ratio_str = sf.next(":");
if (baseimg == NULL) { if (baseimg == NULL) {
errorstream << "generateImagePart(): baseimg != NULL " errorstream << "generateImagePart(): baseimg != NULL "
@ -1607,9 +1613,14 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
video::SColor color; video::SColor color;
int ratio = -1;
if (!parseColorString(color_str, color, false)) if (!parseColorString(color_str, color, false))
return false; return false;
if (is_number(ratio_str))
ratio = mystoi(ratio_str, 0, 255);
core::dimension2d<u32> dim = baseimg->getDimension(); core::dimension2d<u32> dim = baseimg->getDimension();
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim); video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
@ -1622,7 +1633,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
img->fill(video::SColor(color)); img->fill(video::SColor(color));
// Overlay the colored image // Overlay the colored image
blit_with_alpha_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim); blit_with_interpolate_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim, ratio);
img->drop(); img->drop();
} }
else else
@ -1645,8 +1656,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
static void blit_with_alpha(video::IImage *src, video::IImage *dst, static void blit_with_alpha(video::IImage *src, video::IImage *dst,
v2s32 src_pos, v2s32 dst_pos, v2u32 size) v2s32 src_pos, v2s32 dst_pos, v2u32 size)
{ {
for(u32 y0=0; y0<size.Y; y0++) for (u32 y0=0; y0<size.Y; y0++)
for(u32 x0=0; x0<size.X; x0++) for (u32 x0=0; x0<size.X; x0++)
{ {
s32 src_x = src_pos.X + x0; s32 src_x = src_pos.X + x0;
s32 src_y = src_pos.Y + y0; s32 src_y = src_pos.Y + y0;
@ -1666,8 +1677,8 @@ static void blit_with_alpha(video::IImage *src, video::IImage *dst,
static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst, static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
v2s32 src_pos, v2s32 dst_pos, v2u32 size) v2s32 src_pos, v2s32 dst_pos, v2u32 size)
{ {
for(u32 y0=0; y0<size.Y; y0++) for (u32 y0=0; y0<size.Y; y0++)
for(u32 x0=0; x0<size.X; x0++) for (u32 x0=0; x0<size.X; x0++)
{ {
s32 src_x = src_pos.X + x0; s32 src_x = src_pos.X + x0;
s32 src_y = src_pos.Y + y0; s32 src_y = src_pos.Y + y0;
@ -1675,7 +1686,7 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
s32 dst_y = dst_pos.Y + y0; s32 dst_y = dst_pos.Y + y0;
video::SColor src_c = src->getPixel(src_x, src_y); video::SColor src_c = src->getPixel(src_x, src_y);
video::SColor dst_c = dst->getPixel(dst_x, dst_y); video::SColor dst_c = dst->getPixel(dst_x, dst_y);
if(dst_c.getAlpha() == 255 && src_c.getAlpha() != 0) if (dst_c.getAlpha() == 255 && src_c.getAlpha() != 0)
{ {
dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f); dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
dst->setPixel(dst_x, dst_y, dst_c); dst->setPixel(dst_x, dst_y, dst_c);
@ -1683,14 +1694,41 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
} }
} }
/*
Draw an image on top of an another one, using the specified ratio
modify all partially-opaque pixels in the destination.
*/
static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst,
v2s32 src_pos, v2s32 dst_pos, v2u32 size, int ratio)
{
for (u32 y0 = 0; y0 < size.Y; y0++)
for (u32 x0 = 0; x0 < size.X; x0++)
{
s32 src_x = src_pos.X + x0;
s32 src_y = src_pos.Y + y0;
s32 dst_x = dst_pos.X + x0;
s32 dst_y = dst_pos.Y + y0;
video::SColor src_c = src->getPixel(src_x, src_y);
video::SColor dst_c = dst->getPixel(dst_x, dst_y);
if (dst_c.getAlpha() > 0 && src_c.getAlpha() != 0)
{
if (ratio == -1)
dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
else
dst_c = src_c.getInterpolated(dst_c, (float)ratio/255.0f);
dst->setPixel(dst_x, dst_y, dst_c);
}
}
}
/* /*
Apply mask to destination Apply mask to destination
*/ */
static void apply_mask(video::IImage *mask, video::IImage *dst, static void apply_mask(video::IImage *mask, video::IImage *dst,
v2s32 mask_pos, v2s32 dst_pos, v2u32 size) v2s32 mask_pos, v2s32 dst_pos, v2u32 size)
{ {
for(u32 y0 = 0; y0 < size.Y; y0++) { for (u32 y0 = 0; y0 < size.Y; y0++) {
for(u32 x0 = 0; x0 < size.X; x0++) { for (u32 x0 = 0; x0 < size.X; x0++) {
s32 mask_x = x0 + mask_pos.X; s32 mask_x = x0 + mask_pos.X;
s32 mask_y = y0 + mask_pos.Y; s32 mask_y = y0 + mask_pos.Y;
s32 dst_x = x0 + dst_pos.X; s32 dst_x = x0 + dst_pos.X;
@ -1714,12 +1752,12 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
// Count of crack stages // Count of crack stages
s32 crack_count = dim_crack.Height / dim_crack.Width; s32 crack_count = dim_crack.Height / dim_crack.Width;
// Limit frame_count // Limit frame_count
if(frame_count > (s32) dim_dst.Height) if (frame_count > (s32) dim_dst.Height)
frame_count = dim_dst.Height; frame_count = dim_dst.Height;
if(frame_count < 1) if (frame_count < 1)
frame_count = 1; frame_count = 1;
// Limit progression // Limit progression
if(progression > crack_count-1) if (progression > crack_count-1)
progression = crack_count-1; progression = crack_count-1;
// Dimension of a single crack stage // Dimension of a single crack stage
core::dimension2d<u32> dim_crack_cropped( core::dimension2d<u32> dim_crack_cropped(
@ -1738,7 +1776,7 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
video::IImage *crack_scaled = driver->createImage( video::IImage *crack_scaled = driver->createImage(
video::ECF_A8R8G8B8, dim_crack_scaled); video::ECF_A8R8G8B8, dim_crack_scaled);
if(crack_cropped && crack_scaled) if (crack_cropped && crack_scaled)
{ {
// Crop crack image // Crop crack image
v2s32 pos_crack(0, progression*dim_crack.Width); v2s32 pos_crack(0, progression*dim_crack.Width);
@ -1748,10 +1786,10 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
// Scale crack image by copying // Scale crack image by copying
crack_cropped->copyToScaling(crack_scaled); crack_cropped->copyToScaling(crack_scaled);
// Copy or overlay crack image onto each frame // Copy or overlay crack image onto each frame
for(s32 i = 0; i < frame_count; ++i) for (s32 i = 0; i < frame_count; ++i)
{ {
v2s32 dst_pos(0, dim_crack_scaled.Height * i); v2s32 dst_pos(0, dim_crack_scaled.Height * i);
if(use_overlay) if (use_overlay)
{ {
blit_with_alpha_overlay(crack_scaled, dst, blit_with_alpha_overlay(crack_scaled, dst,
v2s32(0,0), dst_pos, v2s32(0,0), dst_pos,
@ -1766,22 +1804,22 @@ static void draw_crack(video::IImage *crack, video::IImage *dst,
} }
} }
if(crack_scaled) if (crack_scaled)
crack_scaled->drop(); crack_scaled->drop();
if(crack_cropped) if (crack_cropped)
crack_cropped->drop(); crack_cropped->drop();
} }
void brighten(video::IImage *image) void brighten(video::IImage *image)
{ {
if(image == NULL) if (image == NULL)
return; return;
core::dimension2d<u32> dim = image->getDimension(); core::dimension2d<u32> dim = image->getDimension();
for(u32 y=0; y<dim.Height; y++) for (u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++) for (u32 x=0; x<dim.Width; x++)
{ {
video::SColor c = image->getPixel(x,y); video::SColor c = image->getPixel(x,y);
c.setRed(0.5 * 255 + 0.5 * (float)c.getRed()); c.setRed(0.5 * 255 + 0.5 * (float)c.getRed());
@ -1807,17 +1845,17 @@ u32 parseImageTransform(const std::string& s)
while(pos < s.size()) while(pos < s.size())
{ {
int transform = -1; int transform = -1;
for(int i = 0; i <= 7; ++i) for (int i = 0; i <= 7; ++i)
{ {
const std::string &name_i = transform_names[i]; const std::string &name_i = transform_names[i];
if(s[pos] == ('0' + i)) if (s[pos] == ('0' + i))
{ {
transform = i; transform = i;
pos++; pos++;
break; break;
} }
else if(!(name_i.empty()) && else if (!(name_i.empty()) &&
lowercase(s.substr(pos, name_i.size())) == name_i) lowercase(s.substr(pos, name_i.size())) == name_i)
{ {
transform = i; transform = i;
@ -1825,16 +1863,16 @@ u32 parseImageTransform(const std::string& s)
break; break;
} }
} }
if(transform < 0) if (transform < 0)
break; break;
// Multiply total_transform and transform in the group D4 // Multiply total_transform and transform in the group D4
int new_total = 0; int new_total = 0;
if(transform < 4) if (transform < 4)
new_total = (transform + total_transform) % 4; new_total = (transform + total_transform) % 4;
else else
new_total = (transform - total_transform + 8) % 4; new_total = (transform - total_transform + 8) % 4;
if((transform >= 4) ^ (total_transform >= 4)) if ((transform >= 4) ^ (total_transform >= 4))
new_total += 4; new_total += 4;
total_transform = new_total; total_transform = new_total;
@ -1844,7 +1882,7 @@ u32 parseImageTransform(const std::string& s)
core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim) core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim)
{ {
if(transform % 2 == 0) if (transform % 2 == 0)
return dim; return dim;
else else
return core::dimension2d<u32>(dim.Height, dim.Width); return core::dimension2d<u32>(dim.Height, dim.Width);
@ -1852,7 +1890,7 @@ core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst) void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
{ {
if(src == NULL || dst == NULL) if (src == NULL || dst == NULL)
return; return;
core::dimension2d<u32> srcdim = src->getDimension(); core::dimension2d<u32> srcdim = src->getDimension();
@ -1867,25 +1905,25 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
*/ */
int sxn = 0; int sxn = 0;
int syn = 2; int syn = 2;
if(transform == 0) // identity if (transform == 0) // identity
sxn = 0, syn = 2; // sx = dx, sy = dy sxn = 0, syn = 2; // sx = dx, sy = dy
else if(transform == 1) // rotate by 90 degrees ccw else if (transform == 1) // rotate by 90 degrees ccw
sxn = 3, syn = 0; // sx = (H-1) - dy, sy = dx sxn = 3, syn = 0; // sx = (H-1) - dy, sy = dx
else if(transform == 2) // rotate by 180 degrees else if (transform == 2) // rotate by 180 degrees
sxn = 1, syn = 3; // sx = (W-1) - dx, sy = (H-1) - dy sxn = 1, syn = 3; // sx = (W-1) - dx, sy = (H-1) - dy
else if(transform == 3) // rotate by 270 degrees ccw else if (transform == 3) // rotate by 270 degrees ccw
sxn = 2, syn = 1; // sx = dy, sy = (W-1) - dx sxn = 2, syn = 1; // sx = dy, sy = (W-1) - dx
else if(transform == 4) // flip x else if (transform == 4) // flip x
sxn = 1, syn = 2; // sx = (W-1) - dx, sy = dy sxn = 1, syn = 2; // sx = (W-1) - dx, sy = dy
else if(transform == 5) // flip x then rotate by 90 degrees ccw else if (transform == 5) // flip x then rotate by 90 degrees ccw
sxn = 2, syn = 0; // sx = dy, sy = dx sxn = 2, syn = 0; // sx = dy, sy = dx
else if(transform == 6) // flip y else if (transform == 6) // flip y
sxn = 0, syn = 3; // sx = dx, sy = (H-1) - dy sxn = 0, syn = 3; // sx = dx, sy = (H-1) - dy
else if(transform == 7) // flip y then rotate by 90 degrees ccw else if (transform == 7) // flip y then rotate by 90 degrees ccw
sxn = 3, syn = 1; // sx = (H-1) - dy, sy = (W-1) - dx sxn = 3, syn = 1; // sx = (H-1) - dy, sy = (W-1) - dx
for(u32 dy=0; dy<dstdim.Height; dy++) for (u32 dy=0; dy<dstdim.Height; dy++)
for(u32 dx=0; dx<dstdim.Width; dx++) for (u32 dx=0; dx<dstdim.Width; dx++)
{ {
u32 entries[4] = {dx, dstdim.Width-1-dx, dy, dstdim.Height-1-dy}; u32 entries[4] = {dx, dstdim.Width-1-dx, dy, dstdim.Height-1-dy};
u32 sx = entries[sxn]; u32 sx = entries[sxn];