aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lua_api.txt17
-rw-r--r--games/devtest/mods/testnodes/textures.lua31
-rw-r--r--src/client/tile.cpp113
3 files changed, 126 insertions, 35 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index e6cabb68e..69ac55493 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -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
-----------------
diff --git a/games/devtest/mods/testnodes/textures.lua b/games/devtest/mods/testnodes/textures.lua
index 4652007d9..dc581b0c7 100644
--- a/games/devtest/mods/testnodes/textures.lua
+++ b/games/devtest/mods/testnodes/textures.lua
@@ -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 },
+})
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 091e546c6..2f57503d3 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -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 "