From 8e7449e09253e138716d8dbad6a2ab5c6e089e28 Mon Sep 17 00:00:00 2001 From: Ner'zhul Date: Mon, 9 Jan 2017 20:39:22 +0100 Subject: Environment & IGameDef code refactoring (#4985) * Environment code refactoring * Cleanup includes & class declarations in client & server environment to improve build speed * ServerEnvironment::m_gamedef is now a pointer to Server instead of IGameDef, permitting to cleanup many casts. * Cleanup IGameDef * Move ITextureSource* IGameDef::getTextureSource() to Client only. * Also move ITextureSource *IGameDef::tsrc() helper * drop getShaderSource, getSceneManager, getSoundManager & getCamera abstract call * drop unused emerge() call * cleanup server unused functions (mentionned before) * Drop one unused parameter from ContentFeatures::updateTextures * move checkLocalPrivilege to Client * Remove some unnecessary casts * create_formspec_menu: remove IWritableTextureSource pointer, as client already knows it * Fix some comments * Change required IGameDef to Server/Client pointers * Previous change that game.cpp sometimes calls functions with Client + InventoryManager + IGameDef in same functions but it's the same objects * Remove duplicate Client pointer in GUIFormSpecMenu::GUIFormSpecMenu * drop ClientMap::sectorWasDrawn which is unused --- src/itemdef.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/itemdef.h') diff --git a/src/itemdef.h b/src/itemdef.h index dcb98e8a9..2ade6116a 100644 --- a/src/itemdef.h +++ b/src/itemdef.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemgroup.h" #include "sound.h" class IGameDef; +class Client; struct ToolCapabilities; /* @@ -107,10 +108,10 @@ public: #ifndef SERVER // Get item inventory texture virtual video::ITexture* getInventoryTexture(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; // Get item wield mesh virtual scene::IMesh* getWieldMesh(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; #endif virtual void serialize(std::ostream &os, u16 protocol_version)=0; @@ -133,10 +134,10 @@ public: #ifndef SERVER // Get item inventory texture virtual video::ITexture* getInventoryTexture(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; // Get item wield mesh virtual scene::IMesh* getWieldMesh(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; #endif // Remove all registered item and node definitions and aliases -- cgit v1.2.3 From 072bbba69aa2528c309b76aaec288bdba52e119c Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Wed, 22 Mar 2017 21:41:02 +0100 Subject: Some performance optimizations (#5424) * Some performance optimizations This is globally removing some memory useless copy * use a const ref return on std::string Settings::get to prevent data copy on getters which doesn't need to copy it * pass some stack created strings to static const as they are not modified anywhere * Camera: return nametags per const ref instead of a list pointer, we only need to read it * INodeDefManager: getAll should be a result ref writer instead of a return copy * INodeDefManager: getAlias should return a const std::string ref * Minimap: unroll a Scolor creation in blitMinimapPixersToImageRadar to prvent many variable construct/destruct which are unneeded (we rewrite the content in the loop) * CNodeDefManager::updateAliases: prevent a idef getall copy * Profiler: constness * rollback_interface: create real_name later, and use const ref * MapBlockMesh updateFastFaceRow: unroll TileSpec next_tile, which has a cost of 1.8% CPU due to variable allocation/destruction, * MapBlockMesh updateFastFaceRow: copy next_tile to tile only if it's a different tilespec * MapBlockMesh updateFastFaceRow: use memcpy to copy next_lights to lights to do it in a single cpu operation --- src/camera.h | 3 +-- src/client/clientlauncher.cpp | 2 +- src/client/tile.cpp | 12 +++++------ src/drawscene.cpp | 2 +- src/game.cpp | 2 +- src/itemdef.cpp | 7 +++---- src/itemdef.h | 8 ++++---- src/mapblock_mesh.cpp | 48 ++++++++++--------------------------------- src/minimap.cpp | 30 ++++++++++++++------------- src/nodedef.cpp | 9 ++++---- src/profiler.h | 33 +++++++++++++---------------- src/remoteplayer.cpp | 4 ++-- src/rollback_interface.cpp | 5 +++-- src/settings.cpp | 29 +------------------------- src/settings.h | 4 +--- src/sky.h | 15 ++++++++------ 16 files changed, 79 insertions(+), 134 deletions(-) (limited to 'src/itemdef.h') diff --git a/src/camera.h b/src/camera.h index b5be26718..f57efdf10 100644 --- a/src/camera.h +++ b/src/camera.h @@ -172,8 +172,7 @@ public: void removeNametag(Nametag *nametag); - std::list *getNametags() - { return &m_nametags; } + const std::list &getNametags() { return m_nametags; } void drawNametags(); diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 2adac53c2..bdd16205f 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -530,7 +530,7 @@ bool ClientLauncher::create_engine_device() // Determine driver video::E_DRIVER_TYPE driverType = video::EDT_OPENGL; - std::string driverstring = g_settings->get("video_driver"); + const std::string &driverstring = g_settings->get("video_driver"); std::vector drivers = porting::getSupportedVideoDrivers(); u32 i; diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 000c766d0..85d388d6e 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -134,9 +134,8 @@ std::string getTexturePath(const std::string &filename) /* Check from texture_path */ - std::string texture_path = g_settings->get("texture_path"); - if (texture_path != "") - { + const std::string &texture_path = g_settings->get("texture_path"); + if (texture_path != "") { std::string testpath = texture_path + DIR_DELIM + filename; // Check all filename extensions. Returns "" if not found. fullpath = getImagePath(testpath); @@ -1854,7 +1853,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, for (u32 x = 0; x < dim.Width; x++) { video::SColor c = baseimg->getPixel(x, y); - c.color ^= mask; + c.color ^= mask; baseimg->setPixel(x, y, c); } } @@ -2266,7 +2265,8 @@ video::ITexture* TextureSource::getNormalTexture(const std::string &name) if (isKnownSourceImage("override_normal.png")) return getTexture("override_normal.png"); std::string fname_base = name; - std::string normal_ext = "_normal.png"; + static const char *normal_ext = "_normal.png"; + static const uint32_t normal_ext_size = strlen(normal_ext); size_t pos = fname_base.find("."); std::string fname_normal = fname_base.substr(0, pos) + normal_ext; if (isKnownSourceImage(fname_normal)) { @@ -2274,7 +2274,7 @@ video::ITexture* TextureSource::getNormalTexture(const std::string &name) size_t i = 0; while ((i = fname_base.find(".", i)) != std::string::npos) { fname_base.replace(i, 4, normal_ext); - i += normal_ext.length(); + i += normal_ext_size; } return getTexture(fname_base); } diff --git a/src/drawscene.cpp b/src/drawscene.cpp index 3a03743ee..663c8828c 100644 --- a/src/drawscene.cpp +++ b/src/drawscene.cpp @@ -494,7 +494,7 @@ void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr, catch(SettingNotFoundException) {} #endif - std::string draw_mode = g_settings->get("3d_mode"); + const std::string &draw_mode = g_settings->get("3d_mode"); smgr->drawAll(); diff --git a/src/game.cpp b/src/game.cpp index 5b49d34c0..9d52e4326 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -4094,7 +4094,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, Drawing begins */ - video::SColor skycolor = sky->getSkyColor(); + const video::SColor &skycolor = sky->getSkyColor(); TimeTaker tt_draw("mainloop: draw"); driver->beginScene(true, true, skycolor); diff --git a/src/itemdef.cpp b/src/itemdef.cpp index f43e5c970..627ad1b6c 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -275,16 +275,16 @@ public: assert(i != m_item_definitions.end()); return *(i->second); } - virtual std::string getAlias(const std::string &name) const + virtual const std::string &getAlias(const std::string &name) const { StringMap::const_iterator it = m_aliases.find(name); if (it != m_aliases.end()) return it->second; return name; } - virtual std::set getAll() const + virtual void getAll(std::set &result) const { - std::set result; + result.clear(); for(std::map::const_iterator it = m_item_definitions.begin(); it != m_item_definitions.end(); ++it) { @@ -295,7 +295,6 @@ public: it != m_aliases.end(); ++it) { result.insert(it->first); } - return result; } virtual bool isKnown(const std::string &name_) const { diff --git a/src/itemdef.h b/src/itemdef.h index 2ade6116a..01ec4fa2f 100644 --- a/src/itemdef.h +++ b/src/itemdef.h @@ -100,9 +100,9 @@ public: // Get item definition virtual const ItemDefinition& get(const std::string &name) const=0; // Get alias definition - virtual std::string getAlias(const std::string &name) const=0; + virtual const std::string &getAlias(const std::string &name) const=0; // Get set of all defined item names and aliases - virtual std::set getAll() const=0; + virtual void getAll(std::set &result) const=0; // Check if item is known virtual bool isKnown(const std::string &name) const=0; #ifndef SERVER @@ -126,9 +126,9 @@ public: // Get item definition virtual const ItemDefinition& get(const std::string &name) const=0; // Get alias definition - virtual std::string getAlias(const std::string &name) const=0; + virtual const std::string &getAlias(const std::string &name) const=0; // Get set of all defined item names and aliases - virtual std::set getAll() const=0; + virtual void getAll(std::set &result) const=0; // Check if item is known virtual bool isKnown(const std::string &name) const=0; #ifndef SERVER diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index f76033ea8..eddb061b4 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -855,8 +855,9 @@ static void updateFastFaceRow( makes_face, p_corrected, face_dir_corrected, lights, tile); - for(u16 j=0; jadd("Meshgen: diff: next_makes_face != makes_face", - next_makes_face != makes_face ? 1 : 0); - g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir", - (next_p_corrected != p_corrected + translate_dir) ? 1 : 0); - g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr", - next_face_dir_corrected != face_dir_corrected ? 1 : 0); - g_profiler->add("Meshgen: diff: next_lights[] != lights[]", - (next_lights[0] != lights[0] || - next_lights[0] != lights[0] || - next_lights[0] != lights[0] || - next_lights[0] != lights[0]) ? 1 : 0); - g_profiler->add("Meshgen: diff: !(next_tile == tile)", - !(next_tile == tile) ? 1 : 0); - }*/ } - /*g_profiler->add("Meshgen: Total faces checked", 1); - if(makes_face) - g_profiler->add("Meshgen: Total makes_face checked", 1);*/ - } else { - /*if(makes_face) - g_profiler->add("Meshgen: diff: last position", 1);*/ } - if(next_is_different) - { + if (next_is_different) { /* Create a face if there should be one */ - if(makes_face) - { + if (makes_face) { // Floating point conversion of the position vector v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z); // Center point of face (kind of) @@ -957,11 +933,9 @@ static void updateFastFaceRow( makes_face = next_makes_face; p_corrected = next_p_corrected; face_dir_corrected = next_face_dir_corrected; - lights[0] = next_lights[0]; - lights[1] = next_lights[1]; - lights[2] = next_lights[2]; - lights[3] = next_lights[3]; - tile = next_tile; + std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16)); + if (next_is_different) + tile = next_tile; p = p_next; } } diff --git a/src/minimap.cpp b/src/minimap.cpp index ee29c58ba..a7f4822c9 100644 --- a/src/minimap.cpp +++ b/src/minimap.cpp @@ -105,7 +105,7 @@ void MinimapUpdateThread::doUpdate() // Swap two values in the map using single lookup std::pair::iterator, bool> result = m_blocks_cache.insert(std::make_pair(update.pos, update.data)); - if (result.second == false) { + if (!result.second) { delete result.first->second; result.first->second = update.data; } @@ -322,13 +322,15 @@ void Minimap::setAngle(f32 angle) void Minimap::blitMinimapPixelsToImageRadar(video::IImage *map_image) { + video::SColor c(240, 0, 0, 0); for (s16 x = 0; x < data->map_size; x++) for (s16 z = 0; z < data->map_size; z++) { MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size]; - video::SColor c(240, 0, 0, 0); if (mmpixel->air_count > 0) c.setGreen(core::clamp(core::round32(32 + mmpixel->air_count * 8), 0, 255)); + else + c.setGreen(0); map_image->setPixel(x, data->map_size - z - 1, c); } @@ -337,21 +339,23 @@ void Minimap::blitMinimapPixelsToImageRadar(video::IImage *map_image) void Minimap::blitMinimapPixelsToImageSurface( video::IImage *map_image, video::IImage *heightmap_image) { + // This variable creation/destruction has a 1% cost on rendering minimap + video::SColor tilecolor; for (s16 x = 0; x < data->map_size; x++) for (s16 z = 0; z < data->map_size; z++) { MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size]; const ContentFeatures &f = m_ndef->get(mmpixel->n); const TileDef *tile = &f.tiledef[0]; + // Color of the 0th tile (mostly this is the topmost) - video::SColor tilecolor; if(tile->has_color) tilecolor = tile->color; else mmpixel->n.getColor(f, &tilecolor); + tilecolor.setRed(tilecolor.getRed() * f.minimap_color.getRed() / 255); - tilecolor.setGreen(tilecolor.getGreen() * f.minimap_color.getGreen() - / 255); + tilecolor.setGreen(tilecolor.getGreen() * f.minimap_color.getGreen() / 255); tilecolor.setBlue(tilecolor.getBlue() * f.minimap_color.getBlue() / 255); tilecolor.setAlpha(240); @@ -391,7 +395,7 @@ video::ITexture *Minimap::getMinimapTexture() if (minimap_mask) { for (s16 y = 0; y < MINIMAP_MAX_SY; y++) for (s16 x = 0; x < MINIMAP_MAX_SX; x++) { - video::SColor mask_col = minimap_mask->getPixel(x, y); + const video::SColor &mask_col = minimap_mask->getPixel(x, y); if (!mask_col.getAlpha()) minimap_image->setPixel(x, y, video::SColor(0,0,0,0)); } @@ -430,7 +434,7 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer() scene::SMeshBuffer *buf = new scene::SMeshBuffer(); buf->Vertices.set_used(4); buf->Indices.set_used(6); - video::SColor c(255, 255, 255, 255); + static const video::SColor c(255, 255, 255, 255); buf->Vertices[0] = video::S3DVertex(-1, -1, 0, 0, 0, 1, c, 0, 1); buf->Vertices[1] = video::S3DVertex(-1, 1, 0, 0, 0, 1, c, 0, 0); @@ -550,15 +554,13 @@ void Minimap::updateActiveMarkers() video::IImage *minimap_mask = data->minimap_shape_round ? data->minimap_mask_round : data->minimap_mask_square; - std::list *nametags = client->getCamera()->getNametags(); + const std::list &nametags = client->getCamera()->getNametags(); m_active_markers.clear(); - for (std::list::const_iterator - i = nametags->begin(); - i != nametags->end(); ++i) { - Nametag *nametag = *i; - v3s16 pos = floatToInt(nametag->parent_node->getPosition() + + for (std::list::const_iterator i = nametags.begin(); + i != nametags.end(); ++i) { + v3s16 pos = floatToInt((*i)->parent_node->getPosition() + intToFloat(client->getCamera()->getOffset(), BS), BS); pos -= data->pos - v3s16(data->map_size / 2, data->scan_height / 2, @@ -570,7 +572,7 @@ void Minimap::updateActiveMarkers() } pos.X = ((float)pos.X / data->map_size) * MINIMAP_MAX_SX; pos.Z = ((float)pos.Z / data->map_size) * MINIMAP_MAX_SY; - video::SColor mask_col = minimap_mask->getPixel(pos.X, pos.Z); + const video::SColor &mask_col = minimap_mask->getPixel(pos.X, pos.Z); if (!mask_col.getAlpha()) { continue; } diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 3532eea1e..2745a45e8 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1332,12 +1332,13 @@ void CNodeDefManager::removeNode(const std::string &name) void CNodeDefManager::updateAliases(IItemDefManager *idef) { - std::set all = idef->getAll(); + std::set all; + idef->getAll(all); m_name_id_mapping_with_aliases.clear(); - for (std::set::iterator + for (std::set::const_iterator i = all.begin(); i != all.end(); ++i) { - std::string name = *i; - std::string convert_to = idef->getAlias(name); + const std::string &name = *i; + const std::string &convert_to = idef->getAlias(name); content_t id; if (m_name_id_mapping.getId(convert_to, id)) { m_name_id_mapping_with_aliases.insert( diff --git a/src/profiler.h b/src/profiler.h index e8eac86b1..6da115972 100644 --- a/src/profiler.h +++ b/src/profiler.h @@ -119,39 +119,34 @@ public: u32 minindex, maxindex; paging(m_data.size(), page, pagecount, minindex, maxindex); - for(std::map::iterator - i = m_data.begin(); - i != m_data.end(); ++i) - { - if(maxindex == 0) + for (std::map::const_iterator i = m_data.begin(); + i != m_data.end(); ++i) { + if (maxindex == 0) break; maxindex--; - if(minindex != 0) - { + if (minindex != 0) { minindex--; continue; } - std::string name = i->first; int avgcount = 1; - std::map::iterator n = m_avgcounts.find(name); - if(n != m_avgcounts.end()){ + std::map::const_iterator n = m_avgcounts.find(i->first); + if (n != m_avgcounts.end()) { if(n->second >= 1) avgcount = n->second; } - o<<" "<first << ": "; s32 clampsize = 40; - s32 space = clampsize - name.size(); - for(s32 j=0; jfirst.size(); + for(s32 j = 0; j < space; j++) { + if (j % 2 == 0 && j < space - 1) + o << "-"; else - o<<" "; + o << " "; } - o<<(i->second / avgcount); - o<second / avgcount); + o << std::endl; } } diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index 0a4591410..c8e5b9132 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -141,7 +141,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername, m_dirty = true; //args.getS32("version"); // Version field value not used - std::string name = args.get("name"); + const std::string &name = args.get("name"); strlcpy(m_name, name.c_str(), PLAYERNAME_SIZE); if (sao) { @@ -167,7 +167,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername, } catch (SettingNotFoundException &e) {} try { - std::string extended_attributes = args.get("extended_attributes"); + const std::string &extended_attributes = args.get("extended_attributes"); Json::Reader reader; Json::Value attr_root; reader.parse(extended_attributes, attr_root); diff --git a/src/rollback_interface.cpp b/src/rollback_interface.cpp index 7345c4a7d..40a33a51d 100644 --- a/src/rollback_interface.cpp +++ b/src/rollback_interface.cpp @@ -190,7 +190,6 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam case TYPE_MODIFY_INVENTORY_STACK: { InventoryLocation loc; loc.deSerialize(inventory_location); - std::string real_name = gamedef->idef()->getAlias(inventory_stack.name); Inventory *inv = imgr->getInventory(loc); if (!inv) { infostream << "RollbackAction::applyRevert(): Could not get " @@ -211,10 +210,12 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam << inventory_location << std::endl; return false; } + // If item was added, take away item, otherwise add removed item if (inventory_add) { // Silently ignore different current item - if (list->getItem(inventory_index).name != real_name) + if (list->getItem(inventory_index).name != + gamedef->idef()->getAlias(inventory_stack.name)) return false; list->takeItem(inventory_index, inventory_stack.count); } else { diff --git a/src/settings.cpp b/src/settings.cpp index c4c3c9073..b4083264e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -90,33 +90,6 @@ bool Settings::checkValueValid(const std::string &value) return true; } - -std::string Settings::sanitizeName(const std::string &name) -{ - std::string n = trim(name); - - for (const char *s = "=\"{}#"; *s; s++) - n.erase(std::remove(n.begin(), n.end(), *s), n.end()); - - return n; -} - - -std::string Settings::sanitizeValue(const std::string &value) -{ - std::string v(value); - size_t p = 0; - - if (v.substr(0, 3) == "\"\"\"") - v.erase(0, 3); - - while ((p = v.find("\n\"\"\"")) != std::string::npos) - v.erase(p, 4); - - return v; -} - - std::string Settings::getMultiline(std::istream &is, size_t *num_lines) { size_t lines = 1; @@ -398,7 +371,7 @@ Settings *Settings::getGroup(const std::string &name) const } -std::string Settings::get(const std::string &name) const +const std::string &Settings::get(const std::string &name) const { const SettingsEntry &entry = getEntry(name); if (entry.is_group) diff --git a/src/settings.h b/src/settings.h index b19733514..777d0eff5 100644 --- a/src/settings.h +++ b/src/settings.h @@ -129,8 +129,6 @@ public: static bool checkNameValid(const std::string &name); static bool checkValueValid(const std::string &value); - static std::string sanitizeName(const std::string &name); - static std::string sanitizeValue(const std::string &value); static std::string getMultiline(std::istream &is, size_t *num_lines=NULL); static void printEntry(std::ostream &os, const std::string &name, const SettingsEntry &entry, u32 tab_depth=0); @@ -141,7 +139,7 @@ public: const SettingsEntry &getEntry(const std::string &name) const; Settings *getGroup(const std::string &name) const; - std::string get(const std::string &name) const; + const std::string &get(const std::string &name) const; bool getBool(const std::string &name) const; u16 getU16(const std::string &name) const; s16 getS16(const std::string &name) const; diff --git a/src/sky.h b/src/sky.h index f19891773..17d6c5f73 100644 --- a/src/sky.h +++ b/src/sky.h @@ -56,18 +56,21 @@ public: void update(float m_time_of_day, float time_brightness, float direct_brightness, bool sunlight_seen, CameraMode cam_mode, float yaw, float pitch); - + float getBrightness(){ return m_brightness; } - video::SColor getBgColor(){ + const video::SColor &getBgColor() const + { return m_visible ? m_bgcolor : m_fallback_bg_color; } - video::SColor getSkyColor(){ + + const video::SColor &getSkyColor() const + { return m_visible ? m_skycolor : m_fallback_bg_color; } - - bool getCloudsVisible(){ return m_clouds_visible && m_visible; } - video::SColorf getCloudColor(){ return m_cloudcolor_f; } + + bool getCloudsVisible() { return m_clouds_visible && m_visible; } + const video::SColorf &getCloudColor() { return m_cloudcolor_f; } void setVisible(bool visible){ m_visible = visible; } void setFallbackBgColor(const video::SColor &fallback_bg_color){ -- cgit v1.2.3 From 58d83a7bb2f992194c3df304b1dcbb81f98f78c0 Mon Sep 17 00:00:00 2001 From: Dániel Juhász Date: Fri, 10 Mar 2017 18:25:58 +0100 Subject: 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. --- builtin/game/item_entity.lua | 31 +++++++++---- doc/lua_api.txt | 18 ++++++++ src/camera.cpp | 3 +- src/client/tile.cpp | 69 +++++++++++++++++++++++++++- src/client/tile.h | 15 ++++--- src/content_cao.cpp | 39 +++++++++------- src/hud.cpp | 20 +++++++-- src/itemdef.cpp | 55 +++++++++++++++++++---- src/itemdef.h | 18 +++++++- src/nodedef.cpp | 82 +--------------------------------- src/object_properties.cpp | 2 + src/object_properties.h | 2 + src/script/common/c_content.cpp | 14 +++++- src/script/common/c_content.h | 3 +- src/script/cpp_api/s_entity.cpp | 5 ++- src/script/lua_api/l_itemstackmeta.cpp | 5 +++ src/script/lua_api/l_metadata.cpp | 14 ++++++ src/script/lua_api/l_metadata.h | 3 ++ src/script/lua_api/l_nodemeta.cpp | 5 +++ src/script/lua_api/l_object.cpp | 2 +- src/script/lua_api/l_storage.cpp | 5 +++ src/wieldmesh.cpp | 19 +++++--- src/wieldmesh.h | 18 +++++++- 23 files changed, 308 insertions(+), 139 deletions(-) (limited to 'src/itemdef.h') 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 ¶ms); - 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 m_source_image_existence; @@ -419,6 +426,9 @@ private: // but can't be deleted because the ITexture* might still be used std::vector m_texture_trash; + // Maps image file names to loaded palettes. + UNORDERED_MAP 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::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 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 ¶ms)=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 "<= 1){ - infostream<<"textures[0]: "<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(): \""< #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 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 *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 > m_palettes; - // NodeResolvers to callback once node registration has ended std::vector m_pending_resolve_callbacks; @@ -1401,78 +1397,6 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath } } -std::vector *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 >::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 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(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(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 > 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 -- cgit v1.2.3