/*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
#include "debug.h"
#include "main.h" // for g_settings
#include "filesys.h"
-#include "utility.h"
#include "settings.h"
#include "mesh.h"
#include <ICameraSceneNode.h>
#include "mapnode.h" // For texture atlas making
#include "nodedef.h" // For texture atlas making
#include "gamedef.h"
-#include "utility_string.h"
+#include "util/string.h"
+#include "util/container.h"
+#include "util/thread.h"
+#include "util/numeric.h"
/*
A cache from texture name to texture path
{
assert(img);
// Remove old image
- core::map<std::string, video::IImage*>::Node *n;
+ std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
- if(n){
- video::IImage *oldimg = n->getValue();
+ if(n != m_images.end()){
+ video::IImage *oldimg = n->second;
if(oldimg)
oldimg->drop();
}
}
video::IImage* get(const std::string &name)
{
- core::map<std::string, video::IImage*>::Node *n;
+ std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
- if(n)
- return n->getValue();
+ if(n != m_images.end())
+ return n->second;
return NULL;
}
// Primarily fetches from cache, secondarily tries to read from filesystem
video::IImage* getOrLoad(const std::string &name, IrrlichtDevice *device)
{
- core::map<std::string, video::IImage*>::Node *n;
+ std::map<std::string, video::IImage*>::iterator n;
n = m_images.find(name);
- if(n){
- n->getValue()->grab(); // Grab for caller
- return n->getValue();
+ if(n != m_images.end()){
+ n->second->grab(); // Grab for caller
+ return n->second;
}
video::IVideoDriver* driver = device->getVideoDriver();
std::string path = getTexturePath(name.c_str());
return img;
}
private:
- core::map<std::string, video::IImage*> m_images;
+ std::map<std::string, video::IImage*> m_images;
};
/*
// Update new texture pointer and texture coordinates to an
// AtlasPointer based on it's texture id
void updateAP(AtlasPointer &ap);
+
+ bool isKnownSourceImage(const std::string &name)
+ {
+ bool is_known = false;
+ bool cache_found = m_source_image_existence.get(name, &is_known);
+ if(cache_found)
+ return is_known;
+ // Not found in cache; find out if a local file exists
+ is_known = (getTexturePath(name) != "");
+ m_source_image_existence.set(name, is_known);
+ return is_known;
+ }
// Processes queued texture requests from other threads.
// Shall be called from the main thread.
// This should be only accessed from the main thread
SourceImageCache m_sourcecache;
+ // Thread-safe cache of what source images are known (true = known)
+ MutexedMap<std::string, bool> m_source_image_existence;
+
// A texture id is index in this array.
// The first position contains a NULL texture.
- core::array<SourceAtlasPointer> m_atlaspointer_cache;
+ std::vector<SourceAtlasPointer> m_atlaspointer_cache;
// Maps a texture name to an index in the former.
- core::map<std::string, u32> m_name_to_id;
+ std::map<std::string, u32> m_name_to_id;
// The two former containers are behind this mutex
JMutex m_atlaspointer_cache_mutex;
See if texture already exists
*/
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL)
+ if(n != m_name_to_id.end())
{
- return n->getValue();
+ return n->second;
}
}
// Overlay image on top of another image (used for cracks)
void overlay(video::IImage *image, video::IImage *overlay);
+// Draw an image on top of an another one, using the alpha channel of the
+// source image
+static void blit_with_alpha(video::IImage *src, video::IImage *dst,
+ v2s32 src_pos, v2s32 dst_pos, v2u32 size);
+
// Brighten image
void brighten(video::IImage *image);
// Parse a transform name
{
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL)
+ if(n != m_name_to_id.end())
{
/*infostream<<"getTextureIdDirect(): \""<<name
<<"\" found in cache"<<std::endl;*/
- return n->getValue();
+ return n->second;
}
}
baseimg_dim = baseimg->getDimension();
SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
m_atlaspointer_cache.push_back(nap);
- m_name_to_id.insert(name, id);
+ m_name_to_id[name] = id;
/*infostream<<"getTextureIdDirect(): "
<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
/*
Fetch textures
*/
- if(m_get_texture_queue.size() > 0)
+ if(!m_get_texture_queue.empty())
{
GetRequest<std::string, u32, u8, u8>
request = m_get_texture_queue.pop();
assert(get_current_thread_id() == m_main_thread);
m_sourcecache.insert(name, img, true, m_device->getVideoDriver());
+ m_source_image_existence.set(name, true);
}
void TextureSource::rebuildImagesAndTextures()
main content features
*/
- core::map<std::string, bool> sourcelist;
+ std::set<std::string> sourcelist;
for(u16 j=0; j<MAX_CONTENT+1; j++)
{
for(u32 i=0; i<6; i++)
{
std::string name = f.tiledef[i].name;
- sourcelist[name] = true;
+ sourcelist.insert(name);
}
}
infostream<<"Creating texture atlas out of textures: ";
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
+ for(std::set<std::string>::iterator
+ i = sourcelist.begin();
+ i != sourcelist.end(); ++i)
{
- std::string name = i.getNode()->getKey();
+ std::string name = *i;
infostream<<"\""<<name<<"\" ";
}
infostream<<std::endl;
pos_in_atlas.X = column_padding;
pos_in_atlas.Y = padding;
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
+ for(std::set<std::string>::iterator
+ i = sourcelist.begin();
+ i != sourcelist.end(); ++i)
{
- std::string name = i.getNode()->getKey();
+ std::string name = *i;
// Generate image by name
video::IImage *img2 = generate_image_from_scratch(name, m_device,
bool reuse_old_id = false;
u32 id = m_atlaspointer_cache.size();
// Check old id without fetching a texture
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
// If it exists, we will replace the old definition
- if(n){
- id = n->getValue();
+ if(n != m_name_to_id.end()){
+ id = n->second;
reuse_old_id = true;
/*infostream<<"TextureSource::buildMainAtlas(): "
<<"Replacing old AtlasPointer"<<std::endl;*/
/*
Second pass: set texture pointer in generated AtlasPointers
*/
- for(core::map<std::string, bool>::Iterator
- i = sourcelist.getIterator();
- i.atEnd() == false; i++)
+ for(std::set<std::string>::iterator
+ i = sourcelist.begin();
+ i != sourcelist.end(); ++i)
{
- std::string name = i.getNode()->getKey();
- if(m_name_to_id.find(name) == NULL)
+ std::string name = *i;
+ if(m_name_to_id.find(name) == m_name_to_id.end())
continue;
u32 id = m_name_to_id[name];
//infostream<<"id of name "<<name<<" is "<<id<<std::endl;
// Position to copy the blitted from in the blitted image
core::position2d<s32> pos_from(0,0);
// Blit
- image->copyToWithAlpha(baseimg, pos_to,
+ /*image->copyToWithAlpha(baseimg, pos_to,
core::rect<s32>(pos_from, dim),
video::SColor(255,255,255,255),
- NULL);
+ NULL);*/
+ blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
// Drop image
image->drop();
}
It is an image with a number of cracking stages
horizontally tiled.
*/
- video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
+ video::IImage *img_crack = sourcecache->getOrLoad(
+ "crack_anylength.png", device);
if(img_crack && progression >= 0)
{
}
else
{
- img_crack_scaled->copyToWithAlpha(
+ /*img_crack_scaled->copyToWithAlpha(
baseimg,
v2s32(0,0),
core::rect<s32>(v2s32(0,0), dim_base),
- video::SColor(255,255,255,255));
+ video::SColor(255,255,255,255));*/
+ blit_with_alpha(img_crack_scaled, baseimg,
+ v2s32(0,0), v2s32(0,0), dim_base);
}
}
u32 h0 = stoi(sf.next(":"));
infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
core::dimension2d<u32> dim(w0,h0);
- baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ if(baseimg == NULL)
+ {
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ baseimg->fill(video::SColor(0,0,0,0));
+ }
while(sf.atend() == false)
{
u32 x = stoi(sf.next(","));
driver->createImage(video::ECF_A8R8G8B8, dim);
img->copyTo(img2);
img->drop();
- img2->copyToWithAlpha(baseimg, pos_base,
+ /*img2->copyToWithAlpha(baseimg, pos_base,
core::rect<s32>(v2s32(0,0), dim),
video::SColor(255,255,255,255),
- NULL);
+ NULL);*/
+ blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
img2->drop();
}
else
return false;
}
+ // Fill target image with transparency
+ img->fill(video::SColor(0,0,0,0));
+
core::dimension2d<u32> dim = frame_size;
core::position2d<s32> pos_dst(0, 0);
core::position2d<s32> pos_src(0, frame_index * frame_size.Y);
}
}
+/*
+ Draw an image on top of an another one, using the alpha channel of the
+ source image
+
+ This exists because IImage::copyToWithAlpha() doesn't seem to always
+ work.
+*/
+static void blit_with_alpha(video::IImage *src, video::IImage *dst,
+ v2s32 src_pos, v2s32 dst_pos, v2u32 size)
+{
+ 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);
+ dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
+ dst->setPixel(dst_x, dst_y, dst_c);
+ }
+}
+
void brighten(video::IImage *image)
{
if(image == NULL)