Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add embedded PNG texture modifier (#11498)
  • Loading branch information
hecktest committed Oct 13, 2021
1 parent fe5cb2c commit 02292e0
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 35 deletions.
17 changes: 17 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -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
-----------------

Expand Down
31 changes: 31 additions & 0 deletions games/devtest/mods/testnodes/textures.lua
Expand Up @@ -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),
Expand Down Expand Up @@ -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 },
})
113 changes: 78 additions & 35 deletions src/client/tile.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 "
Expand Down

0 comments on commit 02292e0

Please sign in to comment.