mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Client: Extend [combine modifier with optional width parameter
This addition makes it possible to combine textures easily without needing to take care of the texture pack size e.g. by resizing every texture before combining. This feature automates such labour.
This commit is contained in:
parent
c175046d30
commit
f13144a15d
3 changed files with 90 additions and 22 deletions
|
@ -562,17 +562,22 @@ Example:
|
|||
|
||||
default_cobble.png^[crack:10:1
|
||||
|
||||
#### `[combine:<w>x<h>:<x1>,<y1>=<file1>:<x2>,<y2>=<file2>:...`
|
||||
|
||||
* `<w>`: width
|
||||
* `<h>`: height
|
||||
* `<x>`: x position, negative numbers allowed
|
||||
* `<y>`: y position, negative numbers allowed
|
||||
* `<file>`: texture to combine
|
||||
#### `[combine:<w>x<h>:<x1>,<y1>,<w1>=<file1>:<x2>,<y2>,<w2>=<file2>:...`
|
||||
|
||||
Creates a texture of size `<w>` times `<h>` and blits the listed files to their
|
||||
specified coordinates.
|
||||
|
||||
Note: the output texture size may vary if one or more of `<wN>` is provided.
|
||||
The aspect ratio is preserved.
|
||||
|
||||
* `<xN>`: X offset of insertion, negative numbers allowed
|
||||
* `<yN>`: Y offset of insertion, negative numbers allowed
|
||||
* `<wN>` (optional): Expected texture width
|
||||
* Scales the output image if `<wN> != input texture width` to perform lossless blit.
|
||||
* Supported since protocol version 46.
|
||||
* `<file>`: texture to combine
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
[combine:16x32:0,0=default_cobble.png:0,16=default_wood.png
|
||||
|
|
|
@ -1118,21 +1118,78 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
|||
{
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
// grid size
|
||||
u32 w0 = stoi(sf.next("x"));
|
||||
u32 h0 = stoi(sf.next(":"));
|
||||
|
||||
struct ImagePart {
|
||||
v2s32 offset;
|
||||
std::string filename;
|
||||
video::IImage *img = nullptr;
|
||||
int expected_width = 0;
|
||||
|
||||
~ImagePart()
|
||||
{
|
||||
if (img)
|
||||
img->drop();
|
||||
}
|
||||
};
|
||||
std::list<ImagePart> image_parts;
|
||||
|
||||
// fixed point precision to allow textures smaller than the grid size
|
||||
constexpr int FX_FACTOR = 1024;
|
||||
// By how much to scale (w0, h0) for the resulting image
|
||||
u32 scale = 0; // includes FX_FACTOR
|
||||
|
||||
while (!sf.at_end()) {
|
||||
// X,Y(,W)=image_esc(:X,Y...)
|
||||
|
||||
auto &it = image_parts.emplace_back();
|
||||
|
||||
auto parts = str_split(sf.next("="), ',');
|
||||
if (parts.size() >= 1)
|
||||
it.offset.X = stoi(parts[0]);
|
||||
if (parts.size() >= 2)
|
||||
it.offset.Y = stoi(parts[1]);
|
||||
if (parts.size() >= 3)
|
||||
it.expected_width = stoi(parts[2]);
|
||||
|
||||
it.filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||
it.img = generateImage(it.filename, source_image_names);
|
||||
if (!it.img) {
|
||||
errorstream << "generateImagePart(): Failed to load image \""
|
||||
<< it.filename << "\" for [combine" << std::endl;
|
||||
image_parts.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto dim = it.img->getDimension();
|
||||
if (it.expected_width <= 0) {
|
||||
// Parameter not specified -> do not scale
|
||||
it.expected_width = dim.Width;
|
||||
}
|
||||
|
||||
scale = std::max<u32>(scale, FX_FACTOR * dim.Width / it.expected_width);
|
||||
}
|
||||
|
||||
if (!baseimg) {
|
||||
if (scale > 0) {
|
||||
w0 = w0 * scale / FX_FACTOR;
|
||||
h0 = h0 * scale / FX_FACTOR;
|
||||
}
|
||||
CHECK_DIM(w0, h0);
|
||||
|
||||
// create desired
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, {w0, h0});
|
||||
baseimg->fill(video::SColor(0,0,0,0));
|
||||
}
|
||||
|
||||
while (!sf.at_end()) {
|
||||
v2s32 pos_base;
|
||||
pos_base.X = stoi(sf.next(","));
|
||||
pos_base.Y = stoi(sf.next("="));
|
||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||
const auto basedim = baseimg->getDimension();
|
||||
for (ImagePart &it : image_parts) {
|
||||
// Shift insertion offset by the same factor as we scaled `baseimg`
|
||||
const v2s32 pos_base = it.offset * scale / FX_FACTOR;
|
||||
const std::string &filename = it.filename;
|
||||
|
||||
auto basedim = baseimg->getDimension();
|
||||
if (pos_base.X > (s32)basedim.Width || pos_base.Y > (s32)basedim.Height) {
|
||||
warningstream << "generateImagePart(): Skipping \""
|
||||
<< filename << "\" as it's out-of-bounds " << pos_base
|
||||
|
@ -1142,23 +1199,28 @@ bool ImageSource::generateImagePart(std::string_view part_of_name,
|
|||
infostream << "Adding \"" << filename<< "\" to combined "
|
||||
<< pos_base << std::endl;
|
||||
|
||||
video::IImage *img = generateImage(filename, source_image_names);
|
||||
if (!img) {
|
||||
errorstream << "generateImagePart(): Failed to load image \""
|
||||
<< filename << "\" for [combine" << std::endl;
|
||||
continue;
|
||||
auto dim = it.img->getDimension();
|
||||
u32 wanted_width = it.expected_width * scale / FX_FACTOR;
|
||||
if (dim.Width != wanted_width) {
|
||||
// needs resize
|
||||
video::IImage *newimg = driver->createImage(
|
||||
baseimg->getColorFormat(),
|
||||
{ wanted_width, (dim.Height * wanted_width) / dim.Width }
|
||||
);
|
||||
it.img->copyToScaling(newimg);
|
||||
it.img->drop();
|
||||
it.img = newimg;
|
||||
dim = it.img->getDimension();
|
||||
}
|
||||
const auto dim = img->getDimension();
|
||||
|
||||
if (pos_base.X + dim.Width <= 0 || pos_base.Y + dim.Height <= 0) {
|
||||
warningstream << "generateImagePart(): Skipping \""
|
||||
<< filename << "\" as it's out-of-bounds " << pos_base
|
||||
<< " for [combine" << std::endl;
|
||||
img->drop();
|
||||
continue;
|
||||
}
|
||||
|
||||
blit_with_alpha(img, baseimg, pos_base, dim);
|
||||
img->drop();
|
||||
blit_with_alpha(it.img, baseimg, pos_base, dim);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
[scheduled bump for 5.10.0]
|
||||
PROTOCOL VERSION 47
|
||||
Add particle blend mode "clip"
|
||||
"[combine:WxH:x1,y1,w1=" 3rd parameter extension
|
||||
[scheduled bump for 5.11.0]
|
||||
*/
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue