Copyright (C) 2010-2011 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 General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GNU Lesser General Public License for more details.
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#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
// 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;
// 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
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()
const ContentFeatures &f = ndef->get(j);
for(u32 i=0; i<6; i++)
{
- std::string name = f.tname_tiles[i];
+ std::string name = f.tiledef[i].name;
sourcelist[name] = true;
}
}
src_x = pos_in_atlas.X;
}
s32 y = y0 + pos_in_atlas.Y;
- s32 src_y = MYMAX(pos_in_atlas.Y, MYMIN(pos_in_atlas.Y + dim.Height - 1, y));
+ s32 src_y = MYMAX((int)pos_in_atlas.Y, MYMIN((int)pos_in_atlas.Y + (int)dim.Height - 1, y));
s32 dst_y = y;
video::SColor c = atlas_img->getPixel(src_x, src_y);
atlas_img->setPixel(dst_x,dst_y,c);
// 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
img2->drop();
}
}
+ /*
+ [verticalframe:N:I
+ Crops a frame of a vertical animation.
+ N = frame count, I = frame index
+ */
+ else if(part_of_name.substr(0,15) == "[verticalframe:")
+ {
+ Strfnd sf(part_of_name);
+ sf.next(":");
+ u32 frame_count = stoi(sf.next(":"));
+ u32 frame_index = stoi(sf.next(":"));
+
+ if(baseimg == NULL){
+ errorstream<<"generate_image(): baseimg!=NULL "
+ <<"for part_of_name=\""<<part_of_name
+ <<"\", cancelling."<<std::endl;
+ return false;
+ }
+
+ v2u32 frame_size = baseimg->getDimension();
+ frame_size.Y /= frame_count;
+
+ video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
+ frame_size);
+ if(!img){
+ errorstream<<"generate_image(): Could not create image "
+ <<"for part_of_name=\""<<part_of_name
+ <<"\", cancelling."<<std::endl;
+ 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);
+ baseimg->copyToWithAlpha(img, pos_dst,
+ core::rect<s32>(pos_src, dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ // Replace baseimg
+ baseimg->drop();
+ baseimg = img;
+ }
else
{
errorstream<<"generate_image(): Invalid "
}
}
+/*
+ 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)