summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDániel Juhász <juhdanad@gmail.com>2017-03-10 18:25:58 +0100
committerAuke Kok <sofar@foo-projects.org>2017-04-08 18:39:15 -0700
commit58d83a7bb2f992194c3df304b1dcbb81f98f78c0 (patch)
tree4beedb69ac8b9b74352ef52c3a1d27004e77bc1d
parentd4e9dd4643607192f5adebeecda86f25074f02cd (diff)
downloadminetest-58d83a7bb2f992194c3df304b1dcbb81f98f78c0.tar.gz
minetest-58d83a7bb2f992194c3df304b1dcbb81f98f78c0.tar.bz2
minetest-58d83a7bb2f992194c3df304b1dcbb81f98f78c0.zip
Hardware coloring for itemstacks
Adds the possibility to colorize item stacks based on their metadata. In the item/node definition you can specify palette (an image file) and color (fallback color if the item has no palette or metadata). Then you can add palette_index to the metadata. Dropped itemstacks with different colors do not merge.
-rw-r--r--builtin/game/item_entity.lua31
-rw-r--r--doc/lua_api.txt18
-rw-r--r--src/camera.cpp3
-rw-r--r--src/client/tile.cpp69
-rw-r--r--src/client/tile.h15
-rw-r--r--src/content_cao.cpp39
-rw-r--r--src/hud.cpp20
-rw-r--r--src/itemdef.cpp55
-rw-r--r--src/itemdef.h18
-rw-r--r--src/nodedef.cpp82
-rw-r--r--src/object_properties.cpp2
-rw-r--r--src/object_properties.h2
-rw-r--r--src/script/common/c_content.cpp14
-rw-r--r--src/script/common/c_content.h3
-rw-r--r--src/script/cpp_api/s_entity.cpp5
-rw-r--r--src/script/lua_api/l_itemstackmeta.cpp5
-rw-r--r--src/script/lua_api/l_metadata.cpp14
-rw-r--r--src/script/lua_api/l_metadata.h3
-rw-r--r--src/script/lua_api/l_nodemeta.cpp5
-rw-r--r--src/script/lua_api/l_object.cpp2
-rw-r--r--src/script/lua_api/l_storage.cpp5
-rw-r--r--src/wieldmesh.cpp19
-rw-r--r--src/wieldmesh.h18
23 files changed, 308 insertions, 139 deletions
diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua
index be158c119..7b8247116 100644
--- a/builtin/game/item_entity.lua
+++ b/builtin/game/item_entity.lua
@@ -53,6 +53,8 @@ core.register_entity(":__builtin:item", {
if itemtable then
itemname = stack:to_table().name
end
+ -- Backwards compatibility: old clients use the texture
+ -- to get the type of the item
local item_texture = nil
local item_type = ""
if core.registered_items[itemname] then
@@ -66,6 +68,7 @@ core.register_entity(":__builtin:item", {
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c},
automatic_rotate = math.pi * 0.5,
+ wield_item = itemstring,
}
self.object:set_properties(prop)
end,
@@ -101,31 +104,39 @@ core.register_entity(":__builtin:item", {
self:set_item(self.itemstring)
end,
+ -- moves items from this stack to an other stack
try_merge_with = function(self, own_stack, object, obj)
+ -- other item's stack
local stack = ItemStack(obj.itemstring)
- if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then
+ -- only merge if items are the same
+ if own_stack:get_name() == stack:get_name() and
+ own_stack:get_meta() == stack:get_meta() and
+ own_stack:get_wear() == stack:get_wear() and
+ stack:get_free_space() > 0 then
local overflow = false
local count = stack:get_count() + own_stack:get_count()
local max_count = stack:get_stack_max()
if count > max_count then
overflow = true
+ stack:set_count(max_count)
count = count - max_count
+ own_stack:set_count(count)
else
self.itemstring = ''
+ stack:set_count(count)
end
local pos = object:getpos()
pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15
object:moveto(pos, false)
local s, c
- local max_count = stack:get_stack_max()
- local name = stack:get_name()
if not overflow then
- obj.itemstring = name .. " " .. count
+ obj.itemstring = stack:to_string()
s = 0.2 + 0.1 * (count / max_count)
c = s
object:set_properties({
visual_size = {x = s, y = s},
- collisionbox = {-c, -c, -c, c, c, c}
+ collisionbox = {-c, -c, -c, c, c, c},
+ wield_item = obj.itemstring
})
self.object:remove()
-- merging succeeded
@@ -133,18 +144,20 @@ core.register_entity(":__builtin:item", {
else
s = 0.4
c = 0.3
+ obj.itemstring = stack:to_string()
object:set_properties({
visual_size = {x = s, y = s},
- collisionbox = {-c, -c, -c, c, c, c}
+ collisionbox = {-c, -c, -c, c, c, c},
+ wield_item = obj.itemstring
})
- obj.itemstring = name .. " " .. max_count
s = 0.2 + 0.1 * (count / max_count)
c = s
+ self.itemstring = own_stack:to_string()
self.object:set_properties({
visual_size = {x = s, y = s},
- collisionbox = {-c, -c, -c, c, c, c}
+ collisionbox = {-c, -c, -c, c, c, c},
+ wield_item = self.itemstring
})
- self.itemstring = name .. " " .. count
end
end
-- merging didn't succeed
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index ca1b5d14c..721f5448a 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -1480,6 +1480,9 @@ Item metadata only contains a key-value store.
Some of the values in the key-value store are handled specially:
* `description`: Set the itemstack's description. Defaults to idef.description
+* `color`: A `ColorString`, which sets the stack's color.
+* `palette_index`: If the item has a palette, this is used to get the
+ current color from the palette.
Example stuff:
@@ -2855,6 +2858,8 @@ See `StorageRef`, `NodeMetaRef` and `ItemStackMetaRef`.
* Any non-table value will clear the metadata
* See "Node Metadata" for an example
* returns `true` on success
+* `equals(other)`
+ * returns `true` if this metadata has the same key-value pairs as `other`
### `NodeMetaRef`
Node metadata: reference extra data and functionality stored in a node.
@@ -3735,6 +3740,19 @@ Definition tables
{hard = 1, metal = 1, spikes = 1}
inventory_image = "default_tool_steelaxe.png",
wield_image = "",
+ palette = "",
+ --[[
+ ^ An image file containing the palette of a node.
+ ^ You can set the currently used color as the
+ ^ "palette_index" field of the item stack metadata.
+ ^ The palette is always stretched to fit indices
+ ^ between 0 and 255, to ensure compatibility with
+ ^ "colorfacedir" and "colorwallmounted" nodes.
+ ]]
+ color = "0xFFFFFFFF",
+ --[[
+ ^ The color of the item. The palette overrides this.
+ ]]
wield_scale = {x = 1, y = 1, z = 1},
stack_max = 99,
range = 4.0,
diff --git a/src/camera.cpp b/src/camera.cpp
index d5c337fe8..7e83dadeb 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -501,7 +501,8 @@ void Camera::setDigging(s32 button)
void Camera::wield(const ItemStack &item)
{
- if (item.name != m_wield_item_next.name) {
+ if (item.name != m_wield_item_next.name ||
+ item.metadata != m_wield_item_next.metadata) {
m_wield_item_next = item;
if (m_wield_change_timer > 0)
m_wield_change_timer = -m_wield_change_timer;
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 86ca7d422..0aa06980c 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -341,6 +341,8 @@ public:
*/
video::ITexture* getTextureForMesh(const std::string &name, u32 *id);
+ virtual Palette* getPalette(const std::string &name);
+
// Returns a pointer to the irrlicht device
virtual IrrlichtDevice* getDevice()
{
@@ -377,8 +379,6 @@ public:
video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params);
- video::IImage* generateImage(const std::string &name);
-
video::ITexture* getNormalTexture(const std::string &name);
video::SColor getTextureAverageColor(const std::string &name);
video::ITexture *getShaderFlagsTexture(bool normamap_present);
@@ -401,6 +401,13 @@ private:
// if baseimg is NULL, it is created. Otherwise stuff is made on it.
bool generateImagePart(std::string part_of_name, video::IImage *& baseimg);
+ /*! Generates an image from a full string like
+ * "stone.png^mineral_coal.png^[crack:1:0".
+ * Shall be called from the main thread.
+ * The returned Image should be dropped.
+ */
+ video::IImage* generateImage(const std::string &name);
+
// Thread-safe cache of what source images are known (true = known)
MutexedMap<std::string, bool> m_source_image_existence;
@@ -419,6 +426,9 @@ private:
// but can't be deleted because the ITexture* might still be used
std::vector<video::ITexture*> m_texture_trash;
+ // Maps image file names to loaded palettes.
+ UNORDERED_MAP<std::string, Palette> m_palettes;
+
// Cached settings needed for making textures from meshes
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
@@ -682,6 +692,61 @@ video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *
return getTexture(name + "^[applyfiltersformesh", id);
}
+Palette* TextureSource::getPalette(const std::string &name)
+{
+ // Only the main thread may load images
+ sanity_check(thr_is_current_thread(m_main_thread));
+
+ if (name == "")
+ return NULL;
+
+ UNORDERED_MAP<std::string, Palette>::iterator it = m_palettes.find(name);
+ if (it == m_palettes.end()) {
+ // Create palette
+ video::IImage *img = generateImage(name);
+ if (!img) {
+ warningstream << "TextureSource::getPalette(): palette \"" << name
+ << "\" could not be loaded." << std::endl;
+ return NULL;
+ }
+ Palette new_palette;
+ u32 w = img->getDimension().Width;
+ u32 h = img->getDimension().Height;
+ // Real area of the image
+ u32 area = h * w;
+ if (area == 0)
+ return NULL;
+ if (area > 256) {
+ warningstream << "TextureSource::getPalette(): the specified"
+ << " palette image \"" << name << "\" is larger than 256"
+ << " pixels, using the first 256." << std::endl;
+ area = 256;
+ } else if (256 % area != 0)
+ warningstream << "TextureSource::getPalette(): the "
+ << "specified palette image \"" << name << "\" does not "
+ << "contain power of two pixels." << std::endl;
+ // We stretch the palette so it will fit 256 values
+ // This many param2 values will have the same color
+ u32 step = 256 / area;
+ // For each pixel in the image
+ for (u32 i = 0; i < area; i++) {
+ video::SColor c = img->getPixel(i % w, i / w);
+ // Fill in palette with 'step' colors
+ for (u32 j = 0; j < step; j++)
+ new_palette.push_back(c);
+ }
+ img->drop();
+ // Fill in remaining elements
+ while (new_palette.size() < 256)
+ new_palette.push_back(video::SColor(0xFFFFFFFF));
+ m_palettes[name] = new_palette;
+ it = m_palettes.find(name);
+ }
+ if (it != m_palettes.end())
+ return &((*it).second);
+ return NULL;
+}
+
void TextureSource::processQueue()
{
/*
diff --git a/src/client/tile.h b/src/client/tile.h
index d04ab918a..5eec0f2ea 100644
--- a/src/client/tile.h
+++ b/src/client/tile.h
@@ -33,6 +33,8 @@ class IGameDef;
struct TileSpec;
struct TileDef;
+typedef std::vector<video::SColor> Palette;
+
/*
tile.{h,cpp}: Texture handling stuff.
*/
@@ -106,14 +108,15 @@ public:
const std::string &name, u32 *id = NULL)=0;
virtual video::ITexture* getTextureForMesh(
const std::string &name, u32 *id = NULL) = 0;
+ /*!
+ * Returns a palette from the given texture name.
+ * The pointer is valid until the texture source is
+ * destructed.
+ * Should be called from the main thread.
+ */
+ virtual Palette* getPalette(const std::string &name) = 0;
virtual IrrlichtDevice* getDevice()=0;
virtual bool isKnownSourceImage(const std::string &name)=0;
- /*! Generates an image from a full string like
- * "stone.png^mineral_coal.png^[crack:1:0".
- * Shall be called from the main thread.
- * The returned Image should be dropped.
- */
- virtual video::IImage* generateImage(const std::string &name)=0;
virtual video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params)=0;
virtual video::ITexture* getNormalTexture(const std::string &name)=0;
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index e0b1c4cd2..84f198b75 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -933,23 +933,30 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr,
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
}
else if(m_prop.visual == "wielditem") {
- infostream<<"GenericCAO::addToScene(): wielditem"<<std::endl;
- infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
- if(m_prop.textures.size() >= 1){
- infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
- IItemDefManager *idef = m_client->idef();
- ItemStack item(m_prop.textures[0], 1, 0, idef);
-
- m_wield_meshnode = new WieldMeshSceneNode(
- smgr->getRootSceneNode(), smgr, -1);
- m_wield_meshnode->setItem(item, m_client);
-
- m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
- m_prop.visual_size.Y/2,
- m_prop.visual_size.X/2));
- u8 li = m_last_light;
- m_wield_meshnode->setColor(video::SColor(255,li,li,li));
+ ItemStack item;
+ infostream << "GenericCAO::addToScene(): wielditem" << std::endl;
+ if (m_prop.wield_item == "") {
+ // Old format, only textures are specified.
+ infostream << "textures: " << m_prop.textures.size() << std::endl;
+ if (m_prop.textures.size() >= 1) {
+ infostream << "textures[0]: " << m_prop.textures[0]
+ << std::endl;
+ IItemDefManager *idef = m_client->idef();
+ item = ItemStack(m_prop.textures[0], 1, 0, idef);
+ }
+ } else {
+ infostream << "serialized form: " << m_prop.wield_item << std::endl;
+ item.deSerialize(m_prop.wield_item, m_client->idef());
}
+ m_wield_meshnode = new WieldMeshSceneNode(smgr->getRootSceneNode(),
+ smgr, -1);
+ m_wield_meshnode->setItem(item, m_client);
+
+ m_wield_meshnode->setScale(
+ v3f(m_prop.visual_size.X / 2, m_prop.visual_size.Y / 2,
+ m_prop.visual_size.X / 2));
+ u8 li = m_last_light;
+ m_wield_meshnode->setColor(video::SColor(255, li, li, li));
} else {
infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
<<"\" not supported"<<std::endl;
diff --git a/src/hud.cpp b/src/hud.cpp
index a602125e3..f558acf1e 100644
--- a/src/hud.cpp
+++ b/src/hud.cpp
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "fontengine.h"
#include "guiscalingfilter.h"
#include "mesh.h"
+#include "wieldmesh.h"
#include <IGUIStaticText.h>
#ifdef HAVE_TOUCHSCREENGUI
@@ -642,9 +643,10 @@ void drawItemStack(video::IVideoDriver *driver,
}
const ItemDefinition &def = item.getDefinition(client->idef());
- scene::IMesh* mesh = client->idef()->getWieldMesh(def.name, client);
+ ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
- if (mesh) {
+ if (imesh && imesh->mesh) {
+ scene::IMesh *mesh = imesh->mesh;
driver->clearZBuffer();
s32 delta = 0;
if (rotation_kind < IT_ROT_NONE) {
@@ -667,16 +669,28 @@ void drawItemStack(video::IVideoDriver *driver,
matrix.makeIdentity();
if (enable_animations) {
- float timer_f = (float)delta / 5000.0;
+ float timer_f = (float) delta / 5000.0;
matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
}
driver->setTransform(video::ETS_WORLD, matrix);
driver->setViewPort(rect);
+ video::SColor basecolor =
+ client->idef()->getItemstackColor(item, client);
+
u32 mc = mesh->getMeshBufferCount();
for (u32 j = 0; j < mc; ++j) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ // we can modify vertices relatively fast,
+ // because these meshes are not buffered.
+ assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
+ video::SColor c = basecolor;
+ if (imesh->buffer_colors.size() > j) {
+ std::pair<bool, video::SColor> p = imesh->buffer_colors[j];
+ c = p.first ? p.second : basecolor;
+ }
+ colorizeMeshBuffer(buf, &c);
video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.Lighting = false;
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 627ad1b6c..51d8f1d5d 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -82,6 +82,8 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
sound_place = def.sound_place;
sound_place_failed = def.sound_place_failed;
range = def.range;
+ palette_image = def.palette_image;
+ color = def.color;
return *this;
}
@@ -104,6 +106,8 @@ void ItemDefinition::reset()
description = "";
inventory_image = "";
wield_image = "";
+ palette_image = "";
+ color = video::SColor(0xFFFFFFFF);
wield_scale = v3f(1.0, 1.0, 1.0);
stack_max = 99;
usable = false;
@@ -153,6 +157,8 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
writeF1000(os, range);
os << serializeString(sound_place_failed.name);
writeF1000(os, sound_place_failed.gain);
+ os << serializeString(palette_image);
+ writeU32(os, color.color);
}
void ItemDefinition::deSerialize(std::istream &is)
@@ -209,6 +215,8 @@ void ItemDefinition::deSerialize(std::istream &is)
try {
sound_place_failed.name = deSerializeString(is);
sound_place_failed.gain = readF1000(is);
+ palette_image = deSerializeString(is);
+ color.set(readU32(is));
} catch(SerializationError &e) {};
}
@@ -224,11 +232,13 @@ class CItemDefManager: public IWritableItemDefManager
struct ClientCached
{
video::ITexture *inventory_texture;
- scene::IMesh *wield_mesh;
+ ItemMesh wield_mesh;
+ Palette *palette;
ClientCached():
inventory_texture(NULL),
- wield_mesh(NULL)
+ wield_mesh(),
+ palette(NULL)
{}
};
#endif
@@ -250,8 +260,8 @@ public:
i = values.begin(); i != values.end(); ++i)
{
ClientCached *cc = *i;
- if (cc->wield_mesh)
- cc->wield_mesh->drop();
+ if (cc->wield_mesh.mesh)
+ cc->wield_mesh.mesh->drop();
delete cc;
}
@@ -335,8 +345,9 @@ public:
ItemStack item = ItemStack();
item.name = def.name;
- scene::IMesh *mesh = getItemMesh(client, item);
- cc->wield_mesh = mesh;
+ getItemMesh(client, item, &(cc->wield_mesh));
+
+ cc->palette = tsrc->getPalette(def.palette_image);
// Put in cache
m_clientcached.set(name, cc);
@@ -390,13 +401,41 @@ public:
return cc->inventory_texture;
}
// Get item wield mesh
- virtual scene::IMesh* getWieldMesh(const std::string &name,
+ virtual ItemMesh* getWieldMesh(const std::string &name,
Client *client) const
{
ClientCached *cc = getClientCached(name, client);
if(!cc)
return NULL;
- return cc->wield_mesh;
+ return &(cc->wield_mesh);
+ }
+
+ // Get item palette
+ virtual Palette* getPalette(const std::string &name,
+ Client *client) const
+ {
+ ClientCached *cc = getClientCached(name, client);
+ if(!cc)
+ return NULL;
+ return cc->palette;
+ }
+
+ virtual video::SColor getItemstackColor(const ItemStack &stack,
+ Client *client) const
+ {
+ // Look for direct color definition
+ const std::string &colorstring = stack.metadata.getString("color", 0);
+ video::SColor directcolor;
+ if ((colorstring != "")
+ && parseColorString(colorstring, directcolor, true))
+ return directcolor;
+ // See if there is a palette
+ Palette *palette = getPalette(stack.name, client);
+ const std::string &index = stack.metadata.getString("palette_index", 0);
+ if ((palette != NULL) && (index != ""))
+ return (*palette)[mystoi(index, 0, 255)];
+ // Fallback color
+ return get(stack.name).color;
}
#endif
void clear()
diff --git a/src/itemdef.h b/src/itemdef.h
index 01ec4fa2f..2d7ff570d 100644
--- a/src/itemdef.h
+++ b/src/itemdef.h
@@ -30,6 +30,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class IGameDef;
class Client;
struct ToolCapabilities;
+#ifndef SERVER
+#include "client/tile.h"
+struct ItemMesh;
+struct ItemStack;
+#endif
/*
Base item definition
@@ -57,6 +62,8 @@ struct ItemDefinition
*/
std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
+ 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;
/*
@@ -110,8 +117,15 @@ public:
virtual video::ITexture* getInventoryTexture(const std::string &name,
Client *client) const=0;
// Get item wield mesh
- virtual scene::IMesh* getWieldMesh(const std::string &name,
+ virtual ItemMesh* getWieldMesh(const std::string &name,
Client *client) const=0;
+ // Get item palette
+ virtual Palette* getPalette(const std::string &name,
+ Client *client) const = 0;
+ // Returns the base color of an item stack: the color of all
+ // tiles that do not define their own color.
+ virtual video::SColor getItemstackColor(const ItemStack &stack,
+ Client *client) const = 0;
#endif
virtual void serialize(std::ostream &os, u16 protocol_version)=0;
@@ -136,7 +150,7 @@ public:
virtual video::ITexture* getInventoryTexture(const std::string &name,
Client *client) const=0;
// Get item wield mesh
- virtual scene::IMesh* getWieldMesh(const std::string &name,
+ virtual ItemMesh* getWieldMesh(const std::string &name,
Client *client) const=0;
#endif
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 2745a45e8..558acafd6 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -786,6 +786,8 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
tiledef_special[j].backface_culling, material_type);
}
+ palette = tsrc->getPalette(palette_name);
+
if ((drawtype == NDT_MESH) && (mesh != "")) {
// Meshnode drawtype
// Read the mesh and apply scale
@@ -859,9 +861,6 @@ public:
virtual void removeNode(const std::string &name);
virtual void updateAliases(IItemDefManager *idef);
virtual void applyTextureOverrides(const std::string &override_filepath);
- //! Returns a palette or NULL if not found. Only on client.
- std::vector<video::SColor> *getPalette(const ContentFeatures &f,
- const IGameDef *gamedef);
virtual void updateTextures(IGameDef *gamedef,
void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
void *progress_cbk_args);
@@ -910,9 +909,6 @@ private:
// Next possibly free id
content_t m_next_id;
- // Maps image file names to loaded palettes.
- UNORDERED_MAP<std::string, std::vector<video::SColor> > m_palettes;
-
// NodeResolvers to callback once node registration has ended
std::vector<NodeResolver *> m_pending_resolve_callbacks;
@@ -1401,78 +1397,6 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath
}
}
-std::vector<video::SColor> *CNodeDefManager::getPalette(
- const ContentFeatures &f, const IGameDef *gamedef)
-{
-#ifndef SERVER
- // This works because colors always use the most significant bits
- // of param2. If you add a new colored type which uses param2
- // in a more advanced way, you should change this code, too.
- u32 palette_pixels = 0;
- switch (f.param_type_2) {
- case CPT2_COLOR:
- palette_pixels = 256;
- break;
- case CPT2_COLORED_FACEDIR:
- palette_pixels = 8;
- break;
- case CPT2_COLORED_WALLMOUNTED:
- palette_pixels = 32;
- break;
- default:
- return NULL;
- }
- // This many param2 values will have the same color
- u32 step = 256 / palette_pixels;
- const std::string &name = f.palette_name;
- if (name == "")
- return NULL;
- Client *client = (Client *) gamedef;
- ITextureSource *tsrc = client->tsrc();
-
- UNORDERED_MAP<std::string, std::vector<video::SColor> >::iterator it =
- m_palettes.find(name);
- if (it == m_palettes.end()) {
- // Create palette
- if (!tsrc->isKnownSourceImage(name)) {
- warningstream << "CNodeDefManager::getPalette(): palette \"" << name
- << "\" could not be loaded." << std::endl;
- return NULL;
- }
- video::IImage *img = tsrc->generateImage(name);
- std::vector<video::SColor> new_palette;
- u32 w = img->getDimension().Width;
- u32 h = img->getDimension().Height;
- // Real area of the image
- u32 area = h * w;
- if (area != palette_pixels)
- warningstream << "CNodeDefManager::getPalette(): the "
- << "specified palette image \"" << name << "\" does not "
- << "contain exactly " << palette_pixels
- << " pixels." << std::endl;
- if (area > palette_pixels)
- area = palette_pixels;
- // For each pixel in the image
- for (u32 i = 0; i < area; i++) {
- video::SColor c = img->getPixel(i % w, i / w);
- // Fill in palette with 'step' colors
- for (u32 j = 0; j < step; j++)
- new_palette.push_back(c);
- }
- img->drop();
- // Fill in remaining elements
- while (new_palette.size() < 256)
- new_palette.push_back(video::SColor(0xFFFFFFFF));
- m_palettes[name] = new_palette;
- it = m_palettes.find(name);
- }
- if (it != m_palettes.end())
- return &((*it).second);
-
-#endif
- return NULL;
-}
-
void CNodeDefManager::updateTextures(IGameDef *gamedef,
void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
void *progress_callback_args)
@@ -1489,12 +1413,10 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
TextureSettings tsettings;
tsettings.readSettings();
- m_palettes.clear();
u32 size = m_content_features.size();
for (u32 i = 0; i < size; i++) {
ContentFeatures *f = &(m_content_features[i]);
- f->palette = getPalette(*f, gamedef);
f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
progress_callback(progress_callback_args, i, size);
}
diff --git a/src/object_properties.cpp b/src/object_properties.cpp
index f4e4953ba..a77368151 100644
--- a/src/object_properties.cpp
+++ b/src/object_properties.cpp
@@ -117,6 +117,7 @@ void ObjectProperties::serialize(std::ostream &os) const
writeARGB8(os, nametag_color);
writeF1000(os, automatic_face_movement_max_rotation_per_sec);
os << serializeString(infotext);
+ os << serializeString(wield_item);
// Add stuff only at the bottom.
// Never remove anything, because we don't want new versions of this
@@ -159,6 +160,7 @@ void ObjectProperties::deSerialize(std::istream &is)
nametag_color = readARGB8(is);
automatic_face_movement_max_rotation_per_sec = readF1000(is);
infotext = deSerializeString(is);
+ wield_item = deSerializeString(is);
}catch(SerializationError &e){}
}
else
diff --git a/src/object_properties.h b/src/object_properties.h
index 082d9a529..908757a64 100644
--- a/src/object_properties.h
+++ b/src/object_properties.h
@@ -52,6 +52,8 @@ struct ObjectProperties
video::SColor nametag_color;
f32 automatic_face_movement_max_rotation_per_sec;
std::string infotext;
+ //! For dropped items, this contains item information.
+ std::string wield_item;
ObjectProperties();
std::string dump();
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 99e12cd82..bcae874b9 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -58,6 +58,12 @@ ItemDefinition read_item_definition(lua_State* L,int index,
getstringfield(L, index, "description", def.description);
getstringfield(L, index, "inventory_image", def.inventory_image);
getstringfield(L, index, "wield_image", def.wield_image);
+ getstringfield(L, index, "palette", def.palette_image);
+
+ // Read item color.
+ lua_getfield(L, index, "color");
+ read_color(L, -1, &def.color);
+ lua_pop(L, 1);
lua_getfield(L, index, "wield_scale");
if(lua_istable(L, -1)){
@@ -118,7 +124,7 @@ ItemDefinition read_item_definition(lua_State* L,int index,
/******************************************************************************/
void read_object_properties(lua_State *L, int index,
- ObjectProperties *prop)
+ ObjectProperties *prop, IItemDefManager *idef)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
@@ -216,6 +222,10 @@ void read_object_properties(lua_State *L, int index,
}
lua_pop(L, 1);
getstringfield(L, -1, "infotext", prop->infotext);
+ lua_getfield(L, -1, "wield_item");
+ if (!lua_isnil(L, -1))
+ prop->wield_item = read_item(L, -1, idef).getItemString();
+ lua_pop(L, 1);
}
/******************************************************************************/
@@ -284,6 +294,8 @@ void push_object_properties(lua_State *L, ObjectProperties *prop)
lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
lua_setfield(L, -2, "infotext");
+ lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size());
+ lua_setfield(L, -2, "wield_item");
}
/******************************************************************************/
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 10cccbb01..949b136eb 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -89,7 +89,8 @@ void push_tool_capabilities (lua_State *L,
ItemDefinition read_item_definition (lua_State *L, int index,
ItemDefinition default_def);
void read_object_properties (lua_State *L, int index,
- ObjectProperties *prop);
+ ObjectProperties *prop,
+ IItemDefManager *idef);
void push_object_properties (lua_State *L,
ObjectProperties *prop);
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index 9e2193970..2e1d277e4 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "object_properties.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "server.h"
bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
{
@@ -187,11 +188,11 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id,
getstringfield(L, -1, "mesh", prop->mesh);
// Deprecated: read object properties directly
- read_object_properties(L, -1, prop);
+ read_object_properties(L, -1, prop, getServer()->idef());
// Read initial_properties
lua_getfield(L, -1, "initial_properties");
- read_object_properties(L, -1, prop);
+ read_object_properties(L, -1, prop, getServer()->idef());
lua_pop(L, 1);
}
diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp
index efdd77b51..c37a82116 100644
--- a/src/script/lua_api/l_itemstackmeta.cpp
+++ b/src/script/lua_api/l_itemstackmeta.cpp
@@ -92,6 +92,10 @@ void ItemStackMetaRef::Register(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
+ lua_pushliteral(L, "__eq");
+ lua_pushcfunction(L, l_equals);
+ lua_settable(L, metatable);
+
lua_pop(L, 1); // drop metatable
luaL_openlib(L, 0, methods, 0); // fill methodtable
@@ -111,5 +115,6 @@ const luaL_Reg ItemStackMetaRef::methods[] = {
luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
+ luamethod(MetaDataRef, equals),
{0,0}
};
diff --git a/src/script/lua_api/l_metadata.cpp b/src/script/lua_api/l_metadata.cpp
index b54005bac..5f4e984cb 100644
--- a/src/script/lua_api/l_metadata.cpp
+++ b/src/script/lua_api/l_metadata.cpp
@@ -250,3 +250,17 @@ bool MetaDataRef::handleFromTable(lua_State *L, int table, Metadata *meta)
return true;
}
+
+// equals(self, other)
+int MetaDataRef::l_equals(lua_State *L)
+{
+ MetaDataRef *ref1 = checkobject(L, 1);
+ Metadata *data1 = ref1->getmeta(false);
+ MetaDataRef *ref2 = checkobject(L, 2);
+ Metadata *data2 = ref2->getmeta(false);
+ if (data1 == NULL || data2 == NULL)
+ lua_pushboolean(L, data1 == data2);
+ else
+ lua_pushboolean(L, *data1 == *data2);
+ return 1;
+}
diff --git a/src/script/lua_api/l_metadata.h b/src/script/lua_api/l_metadata.h
index be31d95ad..a4d8214d3 100644
--- a/src/script/lua_api/l_metadata.h
+++ b/src/script/lua_api/l_metadata.h
@@ -67,6 +67,9 @@ protected:
// from_table(self, table)
static int l_from_table(lua_State *L);
+
+ // equals(self, other)
+ static int l_equals(lua_State *L);
};
#endif /* L_NODEMETA_H_ */
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 55d11fc13..c65d56f14 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -204,6 +204,10 @@ void NodeMetaRef::RegisterCommon(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
+ lua_pushliteral(L, "__eq");
+ lua_pushcfunction(L, l_equals);
+ lua_settable(L, metatable);
+
lua_pop(L, 1); // drop metatable
}
@@ -225,6 +229,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = {
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
luamethod(NodeMetaRef, get_inventory),
+ luamethod(MetaDataRef, equals),
{0,0}
};
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index f9d2754e7..0699705cb 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -737,7 +737,7 @@ int ObjectRef::l_set_properties(lua_State *L)
ObjectProperties *prop = co->accessObjectProperties();
if (!prop)
return 0;
- read_object_properties(L, 2, prop);
+ read_object_properties(L, 2, prop, getServer(L)->idef());
co->notifyObjectPropertiesModified();
return 0;
}
diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp
index 59906dda5..4c6b2a182 100644
--- a/src/script/lua_api/l_storage.cpp
+++ b/src/script/lua_api/l_storage.cpp
@@ -98,6 +98,10 @@ void StorageRef::Register(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
+ lua_pushliteral(L, "__eq");
+ lua_pushcfunction(L, l_equals);
+ lua_settable(L, metatable);
+
lua_pop(L, 1); // drop metatable
luaL_openlib(L, 0, methods, 0); // fill methodtable
@@ -138,5 +142,6 @@ const luaL_Reg StorageRef::methods[] = {
luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
+ luamethod(MetaDataRef, equals),
{0,0}
};
diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp
index 089a67f33..40af0be5f 100644
--- a/src/wieldmesh.cpp
+++ b/src/wieldmesh.cpp
@@ -318,11 +318,15 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
u32 shader_id = shdrsrc->getShader("wielded_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
m_material_type = shdrsrc->getShaderInfo(shader_id).material;
}
+
+ // Color-related
m_colors.clear();
+ video::SColor basecolor = idef->getItemstackColor(item, client);
// If wield_image is defined, it overrides everything else
if (def.wield_image != "") {
setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
+ m_colors.push_back(basecolor);
return;
}
// Handle nodes
@@ -371,7 +375,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
} else {
material.setTexture(0, tile->texture);
}
- m_colors.push_back(tile->color);
+ m_colors.push_back(tile->has_color ? tile->color : basecolor);
material.MaterialType = m_material_type;
if (m_enable_shaders) {
if (tile->normal_texture) {
@@ -389,6 +393,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
}
else if (def.inventory_image != "") {
setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
+ m_colors.push_back(basecolor);
return;
}
@@ -455,7 +460,7 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
m_meshnode->setVisible(true);
}
-scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
+void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
{
ITextureSource *tsrc = client->getTextureSource();
IItemDefManager *idef = client->getItemDefManager();
@@ -475,12 +480,13 @@ scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
// If inventory_image is defined, it overrides everything else
if (def.inventory_image != "") {
mesh = getExtrudedMesh(tsrc, def.inventory_image);
- return mesh;
+ result->mesh = mesh;
+ result->buffer_colors.push_back(
+ std::pair<bool, video::SColor>(false, video::SColor(0xFFFFFFFF)));
} 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));
- setMeshColor(mesh, video::SColor (255, 255, 255, 255));
} else if (f.drawtype == NDT_PLANTLIKE) {
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(f.tiles[0].texture_id));
@@ -515,6 +521,8 @@ scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
for (u32 i = 0; i < mc; ++i) {
const TileSpec *tile = &(f.tiles[i]);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
+ result->buffer_colors.push_back(
+ std::pair<bool, video::SColor>(tile->has_color, tile->color));
colorizeMeshBuffer(buf, &tile->color);
video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -532,9 +540,8 @@ scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
rotateMeshXZby(mesh, -45);
rotateMeshYZby(mesh, -30);
- return mesh;
+ result->mesh = mesh;
}
- return NULL;
}
scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
diff --git a/src/wieldmesh.h b/src/wieldmesh.h
index 200587058..94edb1de6 100644
--- a/src/wieldmesh.h
+++ b/src/wieldmesh.h
@@ -28,6 +28,22 @@ class Client;
class ITextureSource;
struct TileSpec;
+struct ItemMesh
+{
+ scene::IMesh* mesh;
+ /*!
+ * Stores the color of each mesh buffer.
+ * If the boolean is true, the color is fixed, else
+ * palettes can modify it.
+ */
+ std::vector<std::pair<bool, video::SColor> > buffer_colors;
+
+ ItemMesh():
+ mesh(NULL),
+ buffer_colors()
+ {}
+};
+
/*
Wield item scene node, renders the wield mesh of some item
*/
@@ -79,7 +95,7 @@ private:
aabb3f m_bounding_box;
};
-scene::IMesh *getItemMesh(Client *client, const ItemStack &item);
+void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
scene::IMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename);
#endif