]> git.lizzy.rs Git - minetest.git/commitdiff
Add embedded PNG texture modifier (#11498)
authorhecks <42101236+hecktest@users.noreply.github.com>
Wed, 13 Oct 2021 15:51:37 +0000 (17:51 +0200)
committerGitHub <noreply@github.com>
Wed, 13 Oct 2021 15:51:37 +0000 (17:51 +0200)
doc/lua_api.txt
games/devtest/mods/testnodes/textures.lua
src/client/tile.cpp

index e6cabb68e2fb97cb7b799bcc4c166727127461a2..69ac554936cef8ebd8f2e48d7e33111be8a74699 100644 (file)
@@ -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
 -----------------
 
index 4652007d941a330122a4d48fd5913c27d54f4848..dc581b0c77862cb90b3512c8350e5c3024ef18d8 100644 (file)
@@ -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 },
+})
index 091e546c69ef275f78758f6f388bdd1a30d3dad9..2f57503d38884f4bd3d331689765a543f48f06f2 100644 (file)
@@ -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 "