mirror of
https://github.com/minetest/minetest.git
synced 2024-11-23 08:03:45 +01:00
Add embedded PNG texture modifier (#11498)
This commit is contained in:
parent
fe5cb2cdfb
commit
02292e03e4
@ -628,6 +628,23 @@ Result is more like what you'd expect if you put a color on top of another
|
||||
color, meaning white surfaces get a lot of your new color while black parts
|
||||
don't change very much.
|
||||
|
||||
#### `[png:<base64>`
|
||||
|
||||
Embed a base64 encoded PNG image in the texture string.
|
||||
You can produce a valid string for this by calling
|
||||
`minetest.encode_base64(minetest.encode_png(tex))`,
|
||||
refer to the documentation of these functions for details.
|
||||
You can use this to send disposable images such as captchas
|
||||
to individual clients, or render things that would be too
|
||||
expensive to compose with `[combine:`.
|
||||
|
||||
IMPORTANT: Avoid sending large images this way.
|
||||
This is not a replacement for asset files, do not use it to do anything
|
||||
that you could instead achieve by just using a file.
|
||||
In particular consider `minetest.dynamic_add_media` and test whether
|
||||
using other texture modifiers could result in a shorter string than
|
||||
embedding a whole image, this may vary by use case.
|
||||
|
||||
Hardware coloring
|
||||
-----------------
|
||||
|
||||
|
@ -102,12 +102,22 @@ local function gen_checkers(w, h, tile)
|
||||
end
|
||||
|
||||
local fractal = mandelbrot(512, 512, 128)
|
||||
local frac_emb = mandelbrot(64, 64, 64)
|
||||
local checker = gen_checkers(512, 512, 32)
|
||||
|
||||
local floor = math.floor
|
||||
local abs = math.abs
|
||||
local data_emb = {}
|
||||
local data_mb = {}
|
||||
local data_ck = {}
|
||||
for i=1, #frac_emb do
|
||||
data_emb[i] = {
|
||||
r = floor(abs(frac_emb[i] * 2 - 1) * 255),
|
||||
g = floor(abs(1 - frac_emb[i]) * 255),
|
||||
b = floor(frac_emb[i] * 255),
|
||||
a = frac_emb[i] < 0.95 and 255 or 0,
|
||||
}
|
||||
end
|
||||
for i=1, #fractal do
|
||||
data_mb[i] = {
|
||||
r = floor(fractal[i] * 255),
|
||||
@ -140,3 +150,24 @@ minetest.register_node("testnodes:generated_png_ck", {
|
||||
|
||||
groups = { dig_immediate = 2 },
|
||||
})
|
||||
|
||||
local png_emb = "[png:" .. minetest.encode_base64(minetest.encode_png(64,64,data_emb))
|
||||
|
||||
minetest.register_node("testnodes:generated_png_emb", {
|
||||
description = S("Generated In-Band Mandelbrot PNG Test Node"),
|
||||
tiles = { png_emb },
|
||||
|
||||
groups = { dig_immediate = 2 },
|
||||
})
|
||||
minetest.register_node("testnodes:generated_png_src_emb", {
|
||||
description = S("Generated In-Band Source Blit Mandelbrot PNG Test Node"),
|
||||
tiles = { png_emb .. "^testnodes_damage_neg.png" },
|
||||
|
||||
groups = { dig_immediate = 2 },
|
||||
})
|
||||
minetest.register_node("testnodes:generated_png_dst_emb", {
|
||||
description = S("Generated In-Band Dest Blit Mandelbrot PNG Test Node"),
|
||||
tiles = { "testnodes_generated_ck.png^" .. png_emb },
|
||||
|
||||
groups = { dig_immediate = 2 },
|
||||
})
|
||||
|
@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "imagefilters.h"
|
||||
#include "guiscalingfilter.h"
|
||||
#include "renderingengine.h"
|
||||
#include "util/base64.h"
|
||||
|
||||
/*
|
||||
A cache from texture name to texture path
|
||||
@ -1059,6 +1060,45 @@ static std::string unescape_string(const std::string &str, const char esc = '\\'
|
||||
return out;
|
||||
}
|
||||
|
||||
void blitBaseImage(video::IImage* &src, video::IImage* &dst)
|
||||
{
|
||||
//infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
|
||||
// Size of the copied area
|
||||
core::dimension2d<u32> dim = src->getDimension();
|
||||
//core::dimension2d<u32> dim(16,16);
|
||||
// Position to copy the blitted to in the base image
|
||||
core::position2d<s32> pos_to(0,0);
|
||||
// Position to copy the blitted from in the blitted image
|
||||
core::position2d<s32> pos_from(0,0);
|
||||
// Blit
|
||||
/*image->copyToWithAlpha(baseimg, pos_to,
|
||||
core::rect<s32>(pos_from, dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);*/
|
||||
|
||||
core::dimension2d<u32> dim_dst = dst->getDimension();
|
||||
if (dim == dim_dst) {
|
||||
blit_with_alpha(src, dst, pos_from, pos_to, dim);
|
||||
} else if (dim.Width * dim.Height < dim_dst.Width * dim_dst.Height) {
|
||||
// Upscale overlying image
|
||||
video::IImage *scaled_image = RenderingEngine::get_video_driver()->
|
||||
createImage(video::ECF_A8R8G8B8, dim_dst);
|
||||
src->copyToScaling(scaled_image);
|
||||
|
||||
blit_with_alpha(scaled_image, dst, pos_from, pos_to, dim_dst);
|
||||
scaled_image->drop();
|
||||
} else {
|
||||
// Upscale base image
|
||||
video::IImage *scaled_base = RenderingEngine::get_video_driver()->
|
||||
createImage(video::ECF_A8R8G8B8, dim);
|
||||
dst->copyToScaling(scaled_base);
|
||||
dst->drop();
|
||||
dst = scaled_base;
|
||||
|
||||
blit_with_alpha(src, dst, pos_from, pos_to, dim);
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
video::IImage *& baseimg)
|
||||
{
|
||||
@ -1122,41 +1162,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
// Else blit on base.
|
||||
else
|
||||
{
|
||||
//infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
|
||||
// Size of the copied area
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
//core::dimension2d<u32> dim(16,16);
|
||||
// Position to copy the blitted to in the base image
|
||||
core::position2d<s32> pos_to(0,0);
|
||||
// Position to copy the blitted from in the blitted image
|
||||
core::position2d<s32> pos_from(0,0);
|
||||
// Blit
|
||||
/*image->copyToWithAlpha(baseimg, pos_to,
|
||||
core::rect<s32>(pos_from, dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);*/
|
||||
|
||||
core::dimension2d<u32> dim_dst = baseimg->getDimension();
|
||||
if (dim == dim_dst) {
|
||||
blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
|
||||
} else if (dim.Width * dim.Height < dim_dst.Width * dim_dst.Height) {
|
||||
// Upscale overlying image
|
||||
video::IImage *scaled_image = RenderingEngine::get_video_driver()->
|
||||
createImage(video::ECF_A8R8G8B8, dim_dst);
|
||||
image->copyToScaling(scaled_image);
|
||||
|
||||
blit_with_alpha(scaled_image, baseimg, pos_from, pos_to, dim_dst);
|
||||
scaled_image->drop();
|
||||
} else {
|
||||
// Upscale base image
|
||||
video::IImage *scaled_base = RenderingEngine::get_video_driver()->
|
||||
createImage(video::ECF_A8R8G8B8, dim);
|
||||
baseimg->copyToScaling(scaled_base);
|
||||
baseimg->drop();
|
||||
baseimg = scaled_base;
|
||||
|
||||
blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
|
||||
}
|
||||
blitBaseImage(image, baseimg);
|
||||
}
|
||||
//cleanup
|
||||
image->drop();
|
||||
@ -1784,6 +1790,43 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
baseimg->drop();
|
||||
baseimg = img;
|
||||
}
|
||||
/*
|
||||
[png:base64
|
||||
Decodes a PNG image in base64 form.
|
||||
Use minetest.encode_png and minetest.encode_base64
|
||||
to produce a valid string.
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[png:")) {
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
std::string png;
|
||||
{
|
||||
std::string blob = sf.next("");
|
||||
if (!base64_is_valid(blob)) {
|
||||
errorstream << "generateImagePart(): "
|
||||
<< "malformed base64 in '[png'"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
png = base64_decode(blob);
|
||||
}
|
||||
|
||||
auto *device = RenderingEngine::get_raw_device();
|
||||
auto *fs = device->getFileSystem();
|
||||
auto *vd = device->getVideoDriver();
|
||||
auto *memfile = fs->createMemoryReadFile(png.data(), png.size(), "__temp_png");
|
||||
video::IImage* pngimg = vd->createImageFromFile(memfile);
|
||||
memfile->drop();
|
||||
|
||||
if (baseimg) {
|
||||
blitBaseImage(pngimg, baseimg);
|
||||
} else {
|
||||
core::dimension2d<u32> dim = pngimg->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
pngimg->copyTo(baseimg);
|
||||
}
|
||||
pngimg->drop();
|
||||
}
|
||||
else
|
||||
{
|
||||
errorstream << "generateImagePart(): Invalid "
|
||||
|
Loading…
Reference in New Issue
Block a user