forked from Mirrorlandia_minetest/minetest
Handle some edge cases in tile images
This commit is contained in:
parent
a46fe79939
commit
8927e7caf6
@ -703,7 +703,7 @@ video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *
|
|||||||
const bool filter_needed =
|
const bool filter_needed =
|
||||||
m_setting_mipmap || m_setting_trilinear_filter ||
|
m_setting_mipmap || m_setting_trilinear_filter ||
|
||||||
m_setting_bilinear_filter || m_setting_anisotropic_filter;
|
m_setting_bilinear_filter || m_setting_anisotropic_filter;
|
||||||
if (filter_needed)
|
if (filter_needed && !name.empty())
|
||||||
return getTexture(name + "^[applyfiltersformesh", id);
|
return getTexture(name + "^[applyfiltersformesh", id);
|
||||||
return getTexture(name, id);
|
return getTexture(name, id);
|
||||||
}
|
}
|
||||||
@ -1062,6 +1062,12 @@ video::IImage* TextureSource::generateImage(const std::string &name, std::set<st
|
|||||||
if (baseimg == NULL) {
|
if (baseimg == NULL) {
|
||||||
errorstream << "generateImage(): baseimg is NULL (attempted to"
|
errorstream << "generateImage(): baseimg is NULL (attempted to"
|
||||||
" create texture \"" << name << "\")" << std::endl;
|
" create texture \"" << name << "\")" << std::endl;
|
||||||
|
} else if (baseimg->getDimension().Width == 0 ||
|
||||||
|
baseimg->getDimension().Height == 0) {
|
||||||
|
errorstream << "generateImage(): zero-sized image was created?! "
|
||||||
|
"(attempted to create texture \"" << name << "\")" << std::endl;
|
||||||
|
baseimg->drop();
|
||||||
|
baseimg = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseimg;
|
return baseimg;
|
||||||
@ -1173,20 +1179,25 @@ void blitBaseImage(video::IImage* &src, video::IImage* &dst)
|
|||||||
#define CHECK_BASEIMG() \
|
#define CHECK_BASEIMG() \
|
||||||
do { \
|
do { \
|
||||||
if (!baseimg) { \
|
if (!baseimg) { \
|
||||||
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; \
|
||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
#define COMPLAIN_INVALID(description) \
|
||||||
|
do { \
|
||||||
|
errorstream << "generateImagePart(): invalid " << (description) \
|
||||||
|
<< " for part_of_name=\"" << part_of_name \
|
||||||
|
<< "\", cancelling." << std::endl; \
|
||||||
|
return false; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define CHECK_DIM(w, h) \
|
#define CHECK_DIM(w, h) \
|
||||||
do { \
|
do { \
|
||||||
if ((w) <= 0 || (h) <= 0 || (w) >= 0xffff || (h) >= 0xffff) { \
|
if ((w) <= 0 || (h) <= 0 || (w) >= 0xffff || (h) >= 0xffff) { \
|
||||||
errorstream << "generateImagePart(): invalid width or height " \
|
COMPLAIN_INVALID("width or height"); \
|
||||||
<< "for part_of_name=\"" << part_of_name \
|
|
||||||
<< "\", cancelling." << std::endl; \
|
|
||||||
return false; \
|
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
@ -1197,26 +1208,34 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
sanity_check(driver);
|
sanity_check(driver);
|
||||||
|
|
||||||
|
if (baseimg && (baseimg->getDimension().Width == 0 ||
|
||||||
|
baseimg->getDimension().Height == 0)) {
|
||||||
|
errorstream << "generateImagePart(): baseimg is zero-sized?!"
|
||||||
|
<< std::endl;
|
||||||
|
baseimg->drop();
|
||||||
|
baseimg = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Stuff starting with [ are special commands
|
// Stuff starting with [ are special commands
|
||||||
if (part_of_name.empty() || part_of_name[0] != '[') {
|
if (part_of_name.empty() || part_of_name[0] != '[') {
|
||||||
source_image_names.insert(part_of_name);
|
source_image_names.insert(part_of_name);
|
||||||
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
||||||
if (image == NULL) {
|
if (!image) {
|
||||||
if (!part_of_name.empty()) {
|
// Do not create the dummy texture
|
||||||
|
if (part_of_name.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
// Do not create normalmap dummies
|
// Do not create normalmap dummies
|
||||||
if (part_of_name.find("_normal.png") != std::string::npos) {
|
if (str_ends_with(part_of_name, "_normal.png")) {
|
||||||
warningstream << "generateImage(): Could not load normal map \""
|
warningstream << "generateImagePart(): Could not load normal map \""
|
||||||
<< part_of_name << "\"" << std::endl;
|
<< part_of_name << "\"" << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorstream << "generateImage(): Could not load image \""
|
errorstream << "generateImagePart(): Could not load image \""
|
||||||
<< part_of_name << "\" while building texture; "
|
<< part_of_name << "\" while building texture; "
|
||||||
"Creating a dummy image" << std::endl;
|
"Creating a dummy image" << std::endl;
|
||||||
}
|
|
||||||
|
|
||||||
// Just create a dummy image
|
|
||||||
core::dimension2d<u32> dim(1,1);
|
core::dimension2d<u32> dim(1,1);
|
||||||
image = driver->createImage(video::ECF_A8R8G8B8, dim);
|
image = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
sanity_check(image != NULL);
|
sanity_check(image != NULL);
|
||||||
@ -1314,9 +1333,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
u32 x = stoi(sf.next(","));
|
u32 x = stoi(sf.next(","));
|
||||||
u32 y = stoi(sf.next("="));
|
u32 y = stoi(sf.next("="));
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||||
|
|
||||||
|
if (x >= w0 || y >= h0)
|
||||||
|
COMPLAIN_INVALID("X or Y offset");
|
||||||
infostream<<"Adding \""<<filename
|
infostream<<"Adding \""<<filename
|
||||||
<<"\" to combined ("<<x<<","<<y<<")"
|
<<"\" to combined ("<<x<<","<<y<<")"
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
video::IImage *img = generateImage(filename, source_image_names);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img) {
|
if (img) {
|
||||||
core::dimension2d<u32> dim = img->getDimension();
|
core::dimension2d<u32> dim = img->getDimension();
|
||||||
@ -1341,8 +1364,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[fill"))
|
else if (str_starts_with(part_of_name, "[fill"))
|
||||||
{
|
{
|
||||||
s32 x = 0;
|
u32 x = 0;
|
||||||
s32 y = 0;
|
u32 y = 0;
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
@ -1362,6 +1385,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
core::dimension2d<u32> dim(width, height);
|
core::dimension2d<u32> dim(width, height);
|
||||||
|
|
||||||
CHECK_DIM(dim.Width, dim.Height);
|
CHECK_DIM(dim.Width, dim.Height);
|
||||||
|
if (baseimg) {
|
||||||
|
auto basedim = baseimg->getDimension();
|
||||||
|
if (x >= basedim.Width || y >= basedim.Height)
|
||||||
|
COMPLAIN_INVALID("X or Y offset");
|
||||||
|
}
|
||||||
|
|
||||||
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
|
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
img->fill(color);
|
img->fill(color);
|
||||||
|
|
||||||
@ -1497,8 +1526,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
errorstream << "generateImagePart(): Failed to create textures"
|
errorstream << "generateImagePart(): Failed to create textures"
|
||||||
<< " for inventorycube \"" << part_of_name << "\""
|
<< " for inventorycube \"" << part_of_name << "\""
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
baseimg = generateImage(imagename_top, source_image_names);
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
baseimg = createInventoryCubeImage(img_top, img_left, img_right);
|
baseimg = createInventoryCubeImage(img_top, img_left, img_right);
|
||||||
@ -1518,30 +1546,26 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
{
|
{
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
u32 percent = stoi(sf.next(":"));
|
u32 percent = stoi(sf.next(":"), 0, 100);
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||||
|
|
||||||
if (baseimg == NULL)
|
|
||||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
|
|
||||||
video::IImage *img = generateImage(filename, source_image_names);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img)
|
if (img) {
|
||||||
{
|
|
||||||
core::dimension2d<u32> dim = img->getDimension();
|
core::dimension2d<u32> dim = img->getDimension();
|
||||||
|
if (!baseimg)
|
||||||
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
|
|
||||||
core::position2d<s32> pos_base(0, 0);
|
core::position2d<s32> pos_base(0, 0);
|
||||||
video::IImage *img2 =
|
|
||||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
|
||||||
img->copyTo(img2);
|
|
||||||
img->drop();
|
|
||||||
core::position2d<s32> clippos(0, 0);
|
core::position2d<s32> clippos(0, 0);
|
||||||
clippos.Y = dim.Height * (100-percent) / 100;
|
clippos.Y = dim.Height * (100-percent) / 100;
|
||||||
core::dimension2d<u32> clipdim = dim;
|
core::dimension2d<u32> clipdim = dim;
|
||||||
clipdim.Height = clipdim.Height * percent / 100 + 1;
|
clipdim.Height = clipdim.Height * percent / 100 + 1;
|
||||||
core::rect<s32> cliprect(clippos, clipdim);
|
core::rect<s32> cliprect(clippos, clipdim);
|
||||||
img2->copyToWithAlpha(baseimg, pos_base,
|
img->copyToWithAlpha(baseimg, pos_base,
|
||||||
core::rect<s32>(v2s32(0,0), dim),
|
core::rect<s32>(v2s32(0,0), dim),
|
||||||
video::SColor(255,255,255,255),
|
video::SColor(255,255,255,255),
|
||||||
&cliprect);
|
&cliprect);
|
||||||
img2->drop();
|
img->drop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1564,6 +1588,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
<< "\", using frame_count = 1 instead." << std::endl;
|
<< "\", using frame_count = 1 instead." << std::endl;
|
||||||
frame_count = 1;
|
frame_count = 1;
|
||||||
}
|
}
|
||||||
|
if (frame_index >= frame_count)
|
||||||
|
frame_index = frame_count - 1;
|
||||||
|
|
||||||
v2u32 frame_size = baseimg->getDimension();
|
v2u32 frame_size = baseimg->getDimension();
|
||||||
frame_size.Y /= frame_count;
|
frame_size.Y /= frame_count;
|
||||||
@ -1603,8 +1629,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
img->getDimension());
|
img->getDimension());
|
||||||
img->drop();
|
img->drop();
|
||||||
} else {
|
} else {
|
||||||
errorstream << "generateImage(): Failed to load \""
|
errorstream << "generateImagePart(): Failed to load image \""
|
||||||
<< filename << "\".";
|
<< filename << "\" for [mask" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1696,7 +1722,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
* equal to the target minimum. If e.g. this is a vertical frames
|
* equal to the target minimum. If e.g. this is a vertical frames
|
||||||
* animation, the short dimension will be the real size.
|
* animation, the short dimension will be the real size.
|
||||||
*/
|
*/
|
||||||
CHECK_DIM(dim.Width, dim.Height);
|
|
||||||
u32 xscale = scaleto / dim.Width;
|
u32 xscale = scaleto / dim.Width;
|
||||||
u32 yscale = scaleto / dim.Height;
|
u32 yscale = scaleto / dim.Height;
|
||||||
const s32 scale = std::max(xscale, yscale);
|
const s32 scale = std::max(xscale, yscale);
|
||||||
@ -1728,7 +1753,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
u32 height = stoi(sf.next(""));
|
u32 height = stoi(sf.next(""));
|
||||||
CHECK_DIM(width, height);
|
CHECK_DIM(width, height);
|
||||||
|
|
||||||
video::IImage *image = RenderingEngine::get_video_driver()->
|
video::IImage *image = driver->
|
||||||
createImage(video::ECF_A8R8G8B8, {width, height});
|
createImage(video::ECF_A8R8G8B8, {width, height});
|
||||||
baseimg->copyToScaling(image);
|
baseimg->copyToScaling(image);
|
||||||
baseimg->drop();
|
baseimg->drop();
|
||||||
@ -1810,14 +1835,20 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
u32 y0 = stoi(sf.next(":"));
|
u32 y0 = stoi(sf.next(":"));
|
||||||
|
|
||||||
CHECK_DIM(w0, h0);
|
CHECK_DIM(w0, h0);
|
||||||
|
if (x0 >= w0 || y0 >= h0)
|
||||||
|
COMPLAIN_INVALID("tile position (X,Y)");
|
||||||
|
|
||||||
core::dimension2d<u32> img_dim = baseimg->getDimension();
|
core::dimension2d<u32> img_dim = baseimg->getDimension();
|
||||||
core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0));
|
core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0));
|
||||||
|
if (tile_dim.Width == 0)
|
||||||
|
tile_dim.Width = 1;
|
||||||
|
if (tile_dim.Height == 0)
|
||||||
|
tile_dim.Height = 1;
|
||||||
|
|
||||||
video::IImage *img = driver->createImage(
|
video::IImage *img = driver->createImage(
|
||||||
video::ECF_A8R8G8B8, tile_dim);
|
video::ECF_A8R8G8B8, tile_dim);
|
||||||
|
|
||||||
img->fill(video::SColor(0,0,0,0));
|
img->fill(video::SColor(0,0,0,0));
|
||||||
|
|
||||||
v2u32 vdim(tile_dim);
|
v2u32 vdim(tile_dim);
|
||||||
core::rect<s32> rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim);
|
core::rect<s32> rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim);
|
||||||
baseimg->copyToWithAlpha(img, v2s32(0), rect,
|
baseimg->copyToWithAlpha(img, v2s32(0), rect,
|
||||||
@ -1834,15 +1865,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
to produce a valid string.
|
to produce a valid string.
|
||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[png:")) {
|
else if (str_starts_with(part_of_name, "[png:")) {
|
||||||
Strfnd sf(part_of_name);
|
|
||||||
sf.next(":");
|
|
||||||
std::string png;
|
std::string png;
|
||||||
{
|
{
|
||||||
std::string blob = sf.next("");
|
std::string blob = part_of_name.substr(5);
|
||||||
if (!base64_is_valid(blob)) {
|
if (!base64_is_valid(blob)) {
|
||||||
errorstream << "generateImagePart(): "
|
errorstream << "generateImagePart(): "
|
||||||
<< "malformed base64 in '[png'"
|
<< "malformed base64 in [png" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
png = base64_decode(blob);
|
png = base64_decode(blob);
|
||||||
@ -1939,8 +1967,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
img->getDimension(), hardlight);
|
img->getDimension(), hardlight);
|
||||||
img->drop();
|
img->drop();
|
||||||
} else {
|
} else {
|
||||||
errorstream << "generateImage(): Failed to load \""
|
errorstream << "generateImage(): Failed to load image \""
|
||||||
<< filename << "\".";
|
<< filename << "\" for [overlay or [hardlight" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1974,6 +2002,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CHECK_BASEIMG
|
||||||
|
|
||||||
|
#undef COMPLAIN_INVALID
|
||||||
|
|
||||||
|
#undef CHECK_DIM
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the color of a single pixel drawn on top of another pixel.
|
Calculate the color of a single pixel drawn on top of another pixel.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user