Overlays for wield and inventory images (#6107)
authorDániel Juhász <juhdanad@gmail.com>
Fri, 25 Aug 2017 11:20:53 +0000 (11:20 +0000)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Fri, 25 Aug 2017 11:20:53 +0000 (13:20 +0200)
* Overlays for wield and inventory images

doc/lua_api.txt
src/itemdef.cpp
src/itemdef.h
src/script/common/c_content.cpp
src/wieldmesh.cpp
src/wieldmesh.h

index 20c3e5a9288bc1c36e24d9e68693e562a2b120c3..5b071d626330ac59ef9bfd65b36aa0374fa77ad5 100644 (file)
@@ -588,7 +588,11 @@ other. This allows different hardware coloring, but also means that
 tiles with overlays are drawn slower. Using too much overlays might
 cause FPS loss.
 
-To define an overlay, simply set the `overlay_tiles` field of the node
+For inventory and wield images you can specify overlays which
+hardware coloring does not modify. You have to set `inventory_overlay`
+and `wield_overlay` fields to an image name.
+
+To define a node overlay, simply set the `overlay_tiles` field of the node
 definition. These tiles are defined in the same way as plain tiles:
 they can have a texture name, color etc.
 To skip one face, set that overlay tile to an empty string.
@@ -4146,7 +4150,9 @@ Definition tables
                             {bendy = 2, snappy = 1},
                             {hard = 1, metal = 1, spikes = 1}
         inventory_image = "default_tool_steelaxe.png",
+        inventory_overlay = "overlay.png", -- an overlay which does not get colorized
         wield_image = "",
+        wield_overlay = "",
         palette = "",
         --[[
         ^ An image file containing the palette of a node.
index 5ad9764509f3ba77163593bcdff84497eefa25f0..3d8116bf642085b0bf6d5a8123a62961ce94fe1f 100644 (file)
@@ -67,7 +67,9 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
        name = def.name;
        description = def.description;
        inventory_image = def.inventory_image;
+       inventory_overlay = def.inventory_overlay;
        wield_image = def.wield_image;
+       wield_overlay = def.wield_overlay;
        wield_scale = def.wield_scale;
        stack_max = def.stack_max;
        usable = def.usable;
@@ -105,7 +107,9 @@ void ItemDefinition::reset()
        name = "";
        description = "";
        inventory_image = "";
+       inventory_overlay = "";
        wield_image = "";
+       wield_overlay = "";
        palette_image = "";
        color = video::SColor(0xFFFFFFFF);
        wield_scale = v3f(1.0, 1.0, 1.0);
@@ -159,6 +163,8 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
        if (version >= 4) {
                writeF1000(os, sound_place.pitch);
                writeF1000(os, sound_place_failed.pitch);
+               os << serializeString(inventory_overlay);
+               os << serializeString(wield_overlay);
        }
 }
 
@@ -222,6 +228,8 @@ void ItemDefinition::deSerialize(std::istream &is)
                if (version >= 4) {
                        sound_place.pitch = readF1000(is);
                        sound_place_failed.pitch = readF1000(is);
+                       inventory_overlay = deSerializeString(is);
+                       wield_overlay = deSerializeString(is);
                }
        } catch(SerializationError &e) {};
 }
index bca922d3a8ba2b1cc6eb8b0aac2d91cc494d6ff3..45cff582a218096028f28689c04695bfe66bdee4 100644 (file)
@@ -60,7 +60,9 @@ struct ItemDefinition
                Visual properties
        */
        std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
+       std::string inventory_overlay; // Overlay of inventory_image.
        std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
+       std::string wield_overlay; // Overlay of wield_image.
        std::string palette_image; // If specified, the item will be colorized based on this
        video::SColor color; // The fallback color of the node.
        v3f wield_scale;
index 4360f63bbb715d126118dcca7fef95a33e365e06..f746ce76601d419f9f6e1530443df3c826e07468 100644 (file)
@@ -56,7 +56,9 @@ void read_item_definition(lua_State* L, int index,
        getstringfield(L, index, "name", def.name);
        getstringfield(L, index, "description", def.description);
        getstringfield(L, index, "inventory_image", def.inventory_image);
+       getstringfield(L, index, "inventory_overlay", def.inventory_overlay);
        getstringfield(L, index, "wield_image", def.wield_image);
+       getstringfield(L, index, "wield_overlay", def.wield_overlay);
        getstringfield(L, index, "palette", def.palette_image);
 
        // Read item color.
@@ -142,8 +144,12 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
        lua_setfield(L, -2, "type");
        lua_pushstring(L, i.inventory_image.c_str());
        lua_setfield(L, -2, "inventory_image");
+       lua_pushstring(L, i.inventory_overlay.c_str());
+       lua_setfield(L, -2, "inventory_overlay");
        lua_pushstring(L, i.wield_image.c_str());
        lua_setfield(L, -2, "wield_image");
+       lua_pushstring(L, i.wield_overlay.c_str());
+       lua_setfield(L, -2, "wield_overlay");
        lua_pushstring(L, i.palette_image.c_str());
        lua_setfield(L, -2, "palette_image");
        push_ARGB8(L, i.color);
index df23dc433cc72765b843cd1cbcf73f58cbd0ad79..0394cc9eadd1e8761af042049ccb3ef3343342f5 100644 (file)
@@ -240,13 +240,16 @@ void WieldMeshSceneNode::setCube(const ContentFeatures &f,
 }
 
 void WieldMeshSceneNode::setExtruded(const std::string &imagename,
-               v3f wield_scale, ITextureSource *tsrc, u8 num_frames)
+       const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
+       u8 num_frames)
 {
        video::ITexture *texture = tsrc->getTexture(imagename);
        if (!texture) {
                changeToMesh(nullptr);
                return;
        }
+       video::ITexture *overlay_texture =
+               overlay_name.empty() ? NULL : tsrc->getTexture(overlay_name);
 
        core::dimension2d<u32> dim = texture->getSize();
        // Detect animation texture and pull off top frame instead of using entire thing
@@ -254,36 +257,46 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
                u32 frame_height = dim.Height / num_frames;
                dim = core::dimension2d<u32>(dim.Width, frame_height);
        }
-       scene::IMesh *mesh = g_extrusion_mesh_cache->create(dim);
-       scene::SMesh *copy = cloneMesh(mesh);
+       scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
+       scene::SMesh *mesh = cloneMesh(original);
+       original->drop();
+       //set texture
+       mesh->getMeshBuffer(0)->getMaterial().setTexture(0,
+               tsrc->getTexture(imagename));
+       if (overlay_texture) {
+               scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));
+               copy->getMaterial().setTexture(0, overlay_texture);
+               mesh->addMeshBuffer(copy);
+               copy->drop();
+       }
+       changeToMesh(mesh);
        mesh->drop();
-       changeToMesh(copy);
-       copy->drop();
 
        m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR_EXTRUDED);
 
-       // Customize material
-       video::SMaterial &material = m_meshnode->getMaterial(0);
-       material.setTexture(0, tsrc->getTextureForMesh(imagename));
-       material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
-       material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
-       material.MaterialType = m_material_type;
-       material.setFlag(video::EMF_BACK_FACE_CULLING, true);
-       // Enable bi/trilinear filtering only for high resolution textures
-       if (dim.Width > 32) {
-               material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
-               material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
-       } else {
-               material.setFlag(video::EMF_BILINEAR_FILTER, false);
-               material.setFlag(video::EMF_TRILINEAR_FILTER, false);
-       }
-       material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter);
-       // mipmaps cause "thin black line" artifacts
+       // Customize materials
+       for (u32 layer = 0; layer < m_meshnode->getMaterialCount(); layer++) {
+               video::SMaterial &material = m_meshnode->getMaterial(layer);
+               material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
+               material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
+               material.MaterialType = m_material_type;
+               material.setFlag(video::EMF_BACK_FACE_CULLING, true);
+               // Enable bi/trilinear filtering only for high resolution textures
+               if (dim.Width > 32) {
+                       material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
+                       material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
+               } else {
+                       material.setFlag(video::EMF_BILINEAR_FILTER, false);
+                       material.setFlag(video::EMF_TRILINEAR_FILTER, false);
+               }
+               material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter);
+               // mipmaps cause "thin black line" artifacts
 #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
-       material.setFlag(video::EMF_USE_MIP_MAPS, false);
+               material.setFlag(video::EMF_USE_MIP_MAPS, false);
 #endif
-       if (m_enable_shaders) {
-               material.setTexture(2, tsrc->getShaderFlagsTexture(false));
+               if (m_enable_shaders) {
+                       material.setTexture(2, tsrc->getShaderFlagsTexture(false));
+               }
        }
 }
 
@@ -308,8 +321,11 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
 
        // If wield_image is defined, it overrides everything else
        if (!def.wield_image.empty()) {
-               setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
+               setExtruded(def.wield_image, def.wield_overlay, def.wield_scale, tsrc,
+                       1);
                m_colors.emplace_back();
+               // overlay is white, if present
+               m_colors.emplace_back(true, video::SColor(0xFFFFFFFF));
                return;
        }
 
@@ -335,14 +351,23 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
                                }
                                case NDT_PLANTLIKE: {
                                        setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
+                                               tsrc->getTextureName(f.tiles[0].layers[1].texture_id),
                                                def.wield_scale, tsrc,
                                                f.tiles[0].layers[0].animation_frame_count);
+                                       // Add color
+                                       const TileLayer &l0 = f.tiles[0].layers[0];
+                                       m_colors.emplace_back(l0.has_color, l0.color);
+                                       const TileLayer &l1 = f.tiles[0].layers[1];
+                                       m_colors.emplace_back(l1.has_color, l1.color);
                                        break;
                                }
                                case NDT_PLANTLIKE_ROOTED: {
                                        setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id),
-                                               def.wield_scale, tsrc,
+                                               "", def.wield_scale, tsrc,
                                                f.special_tiles[0].layers[0].animation_frame_count);
+                                       // Add color
+                                       const TileLayer &l0 = f.special_tiles[0].layers[0];
+                                       m_colors.emplace_back(l0.has_color, l0.color);
                                        break;
                                }
                                case NDT_NORMAL:
@@ -376,10 +401,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
                }
                return;
        }
-
-       if (!def.inventory_image.empty()) {
-               setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
+       else if (!def.inventory_image.empty()) {
+               setExtruded(def.inventory_image, def.inventory_overlay, def.wield_scale,
+                       tsrc, 1);
                m_colors.emplace_back();
+               // overlay is white, if present
+               m_colors.emplace_back(true, video::SColor(0xFFFFFFFF));
                return;
        }
 
@@ -456,24 +483,38 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
 
        // If inventory_image is defined, it overrides everything else
        if (!def.inventory_image.empty()) {
-               mesh = getExtrudedMesh(tsrc, def.inventory_image);
+               mesh = getExtrudedMesh(tsrc, def.inventory_image,
+                       def.inventory_overlay);
                result->buffer_colors.emplace_back();
+               // overlay is white, if present
+               result->buffer_colors.emplace_back(true, video::SColor(0xFFFFFFFF));
                // Items with inventory images do not need shading
                result->needs_shading = false;
        } else if (def.type == ITEM_NODE) {
                if (f.mesh_ptr[0]) {
                        mesh = cloneMesh(f.mesh_ptr[0]);
                        scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
+                       postProcessNodeMesh(mesh, f, false, false, nullptr,
+                               &result->buffer_colors);
                } else {
                        switch (f.drawtype) {
                                case NDT_PLANTLIKE: {
                                        mesh = getExtrudedMesh(tsrc,
-                                               tsrc->getTextureName(f.tiles[0].layers[0].texture_id));
+                                               tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
+                                               tsrc->getTextureName(f.tiles[0].layers[1].texture_id));
+                                       // Add color
+                                       const TileLayer &l0 = f.tiles[0].layers[0];
+                                       result->buffer_colors.emplace_back(l0.has_color, l0.color);
+                                       const TileLayer &l1 = f.tiles[0].layers[1];
+                                       result->buffer_colors.emplace_back(l1.has_color, l1.color);
                                        break;
                                }
                                case NDT_PLANTLIKE_ROOTED: {
                                        mesh = getExtrudedMesh(tsrc,
-                                               tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id));
+                                               tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
+                                       // Add color
+                                       const TileLayer &l0 = f.special_tiles[0].layers[0];
+                                       result->buffer_colors.emplace_back(l0.has_color, l0.color);
                                        break;
                                }
                                case NDT_NORMAL:
@@ -484,6 +525,9 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
                                        mesh = cloneMesh(cube);
                                        cube->drop();
                                        scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
+                                       // add overlays
+                                       postProcessNodeMesh(mesh, f, false, false, nullptr,
+                                               &result->buffer_colors);
                                        break;
                                }
                                default: {
@@ -507,6 +551,10 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
                                                material1.setTexture(3, material2.getTexture(3));
                                                material1.MaterialType = material2.MaterialType;
                                        }
+                                       // add overlays (since getMesh() returns
+                                       // the base layer only)
+                                       postProcessNodeMesh(mesh, f, false, false, nullptr,
+                                               &result->buffer_colors);
                                }
                        }
                }
@@ -524,36 +572,49 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
 
                rotateMeshXZby(mesh, -45);
                rotateMeshYZby(mesh, -30);
-
-               postProcessNodeMesh(mesh, f, false, false, nullptr, &result->buffer_colors);
        }
        result->mesh = mesh;
 }
 
 
 
-scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename)
+scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
+       const std::string &imagename, const std::string &overlay_name)
 {
+       // check textures
        video::ITexture *texture = tsrc->getTextureForMesh(imagename);
        if (!texture) {
-               return nullptr;
+               return NULL;
        }
+       video::ITexture *overlay_texture =
+               (overlay_name.empty()) ? NULL : tsrc->getTexture(overlay_name);
 
+       // get mesh
        core::dimension2d<u32> dim = texture->getSize();
        scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
        scene::SMesh *mesh = cloneMesh(original);
        original->drop();
 
-       // Customize material
-       video::SMaterial &material = mesh->getMeshBuffer(0)->getMaterial();
-       material.setTexture(0, tsrc->getTexture(imagename));
-       material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
-       material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
-       material.setFlag(video::EMF_BILINEAR_FILTER, false);
-       material.setFlag(video::EMF_TRILINEAR_FILTER, false);
-       material.setFlag(video::EMF_BACK_FACE_CULLING, true);
-       material.setFlag(video::EMF_LIGHTING, false);
-       material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+       //set texture
+       mesh->getMeshBuffer(0)->getMaterial().setTexture(0,
+               tsrc->getTexture(imagename));
+       if (overlay_texture) {
+               scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));
+               copy->getMaterial().setTexture(0, overlay_texture);
+               mesh->addMeshBuffer(copy);
+               copy->drop();
+       }
+       // Customize materials
+       for (u32 layer = 0; layer < mesh->getMeshBufferCount(); layer++) {
+               video::SMaterial &material = mesh->getMeshBuffer(layer)->getMaterial();
+               material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
+               material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
+               material.setFlag(video::EMF_BILINEAR_FILTER, false);
+               material.setFlag(video::EMF_TRILINEAR_FILTER, false);
+               material.setFlag(video::EMF_BACK_FACE_CULLING, true);
+               material.setFlag(video::EMF_LIGHTING, false);
+               material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+       }
        scaleMesh(mesh, v3f(2.0, 2.0, 2.0));
 
        return mesh;
index 828625075726a6cdc2ba06355e4b0af5f0433d1e..23e3abf2984f2f87d16d8a69feef48642d420e3f 100644 (file)
@@ -78,8 +78,8 @@ public:
        virtual ~WieldMeshSceneNode();
 
        void setCube(const ContentFeatures &f, v3f wield_scale);
-       void setExtruded(const std::string &imagename, v3f wield_scale,
-                       ITextureSource *tsrc, u8 num_frames);
+       void setExtruded(const std::string &imagename, const std::string &overlay_image,
+                       v3f wield_scale, ITextureSource *tsrc, u8 num_frames);
        void setItem(const ItemStack &item, Client *client);
 
        // Sets the vertex color of the wield mesh.
@@ -125,7 +125,8 @@ private:
 
 void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
 
-scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename);
+scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
+               const std::string &overlay_name);
 
 /*!
  * Applies overlays, textures and optionally materials to the given mesh and