X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnodedef.cpp;h=e392f477ab2c3ad9db1881574585e861773c6902;hb=ba15c98e4d5d7f4bc515e351d6af1a084d46092e;hp=5735ef91465406dc99919c6c485b8ece14b61688;hpb=e5652cb75cd891895fab50ce46eb34ab9734d160;p=oweals%2Fminetest.git diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 5735ef914..e392f477a 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -19,11 +19,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" -#include "main.h" // For g_settings #include "itemdef.h" #ifndef SERVER -#include "tile.h" +#include "client/tile.h" #include "mesh.h" +#include #endif #include "log.h" #include "settings.h" @@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "debug.h" #include "gamedef.h" +#include // Used in applyTextureOverrides() /* NodeBox @@ -201,6 +202,7 @@ void ContentFeatures::reset() #ifndef SERVER for(u32 i = 0; i < 24; i++) mesh_ptr[i] = NULL; + minimap_color = video::SColor(0, 0, 0, 0); #endif visual_scale = 1.0; for(u32 i = 0; i < 6; i++) @@ -226,7 +228,6 @@ void ContentFeatures::reset() liquid_alternative_source = ""; liquid_viscosity = 0; liquid_renewable = true; - freezemelt = ""; liquid_range = LIQUID_LEVEL_MAX+1; drowning = 0; light_source = 0; @@ -242,7 +243,7 @@ void ContentFeatures::reset() sound_dug = SimpleSoundSpec(); } -void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) +void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const { if(protocol_version < 24){ serializeOld(os, protocol_version); @@ -388,8 +389,8 @@ public: virtual ~CNodeDefManager(); void clear(); virtual IWritableNodeDefManager *clone(); - virtual const ContentFeatures& get(content_t c) const; - virtual const ContentFeatures& get(const MapNode &n) const; + inline virtual const ContentFeatures& get(content_t c) const; + inline virtual const ContentFeatures& get(const MapNode &n) const; virtual bool getId(const std::string &name, content_t &result) const; virtual content_t getId(const std::string &name) const; virtual void getIds(const std::string &name, std::set &result) const; @@ -398,10 +399,21 @@ public: virtual content_t set(const std::string &name, const ContentFeatures &def); virtual content_t allocateDummy(const std::string &name); virtual void updateAliases(IItemDefManager *idef); - virtual void updateTextures(IGameDef *gamedef); - void serialize(std::ostream &os, u16 protocol_version); + virtual void applyTextureOverrides(const std::string &override_filepath); + virtual void updateTextures(IGameDef *gamedef, + void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress), + void *progress_cbk_args); + void serialize(std::ostream &os, u16 protocol_version) const; void deSerialize(std::istream &is); + inline virtual bool getNodeRegistrationStatus() const; + inline virtual void setNodeRegistrationStatus(bool completed); + + virtual void pendNodeResolve(NodeResolver *nr); + virtual bool cancelNodeResolveCallback(NodeResolver *nr); + virtual void runNodeResolveCallbacks(); + virtual void resetNodeResolveState(); + private: void addNameIdMapping(content_t i, std::string name); #ifndef SERVER @@ -429,6 +441,12 @@ private: // Next possibly free id content_t m_next_id; + + // NodeResolvers to callback once node registration has ended + std::vector m_pending_resolve_callbacks; + + // True when all nodes have been registered + bool m_node_registration_complete; }; @@ -440,6 +458,15 @@ CNodeDefManager::CNodeDefManager() CNodeDefManager::~CNodeDefManager() { +#ifndef SERVER + for (u32 i = 0; i < m_content_features.size(); i++) { + ContentFeatures *f = &m_content_features[i]; + for (u32 j = 0; j < 24; j++) { + if (f->mesh_ptr[j]) + f->mesh_ptr[j]->drop(); + } + } +#endif } @@ -451,6 +478,8 @@ void CNodeDefManager::clear() m_group_to_items.clear(); m_next_id = 0; + resetNodeResolveState(); + u32 initial_length = 0; initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1); initial_length = MYMAX(initial_length, CONTENT_AIR + 1); @@ -515,16 +544,14 @@ IWritableNodeDefManager *CNodeDefManager::clone() } -const ContentFeatures& CNodeDefManager::get(content_t c) const +inline const ContentFeatures& CNodeDefManager::get(content_t c) const { - if (c < m_content_features.size()) - return m_content_features[c]; - else - return m_content_features[CONTENT_UNKNOWN]; + return c < m_content_features.size() + ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN]; } -const ContentFeatures& CNodeDefManager::get(const MapNode &n) const +inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const { return get(n.getContent()); } @@ -608,6 +635,7 @@ content_t CNodeDefManager::allocateId() // IWritableNodeDefManager content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def) { + // Pre-conditions assert(name != ""); assert(name == def.name); @@ -645,7 +673,7 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d j = m_group_to_items.find(group_name); if (j == m_group_to_items.end()) { m_group_to_items[group_name].push_back( - std::make_pair(id, i->second)); + std::make_pair(id, i->second)); } else { GroupItems &items = j->second; items.push_back(std::make_pair(id, i->second)); @@ -657,7 +685,7 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d content_t CNodeDefManager::allocateDummy(const std::string &name) { - assert(name != ""); + assert(name != ""); // Pre-condition ContentFeatures f; f.name = name; return set(name, f); @@ -675,20 +703,81 @@ void CNodeDefManager::updateAliases(IItemDefManager *idef) content_t id; if (m_name_id_mapping.getId(convert_to, id)) { m_name_id_mapping_with_aliases.insert( - std::make_pair(name, id)); + std::make_pair(name, id)); } } } +void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath) +{ + infostream << "CNodeDefManager::applyTextureOverrides(): Applying " + "overrides to textures from " << override_filepath << std::endl; + + std::ifstream infile(override_filepath.c_str()); + std::string line; + int line_c = 0; + while (std::getline(infile, line)) { + line_c++; + if (trim(line) == "") + continue; + std::vector splitted = str_split(line, ' '); + if (splitted.size() != 3) { + errorstream << override_filepath + << ":" << line_c << " Could not apply texture override \"" + << line << "\": Syntax error" << std::endl; + continue; + } + + content_t id; + if (!getId(splitted[0], id)) { + errorstream << override_filepath + << ":" << line_c << " Could not apply texture override \"" + << line << "\": Unknown node \"" + << splitted[0] << "\"" << std::endl; + continue; + } + + ContentFeatures &nodedef = m_content_features[id]; + + if (splitted[1] == "top") + nodedef.tiledef[0].name = splitted[2]; + else if (splitted[1] == "bottom") + nodedef.tiledef[1].name = splitted[2]; + else if (splitted[1] == "right") + nodedef.tiledef[2].name = splitted[2]; + else if (splitted[1] == "left") + nodedef.tiledef[3].name = splitted[2]; + else if (splitted[1] == "back") + nodedef.tiledef[4].name = splitted[2]; + else if (splitted[1] == "front") + nodedef.tiledef[5].name = splitted[2]; + else if (splitted[1] == "all" || splitted[1] == "*") + for (int i = 0; i < 6; i++) + nodedef.tiledef[i].name = splitted[2]; + else if (splitted[1] == "sides") + for (int i = 2; i < 6; i++) + nodedef.tiledef[i].name = splitted[2]; + else { + errorstream << override_filepath + << ":" << line_c << " Could not apply texture override \"" + << line << "\": Unknown node side \"" + << splitted[1] << "\"" << std::endl; + continue; + } + } +} -void CNodeDefManager::updateTextures(IGameDef *gamedef) +void CNodeDefManager::updateTextures(IGameDef *gamedef, + void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress), + void *progress_callback_args) { #ifndef SERVER infostream << "CNodeDefManager::updateTextures(): Updating " "textures in node definitions" << std::endl; - ITextureSource *tsrc = gamedef->tsrc(); IShaderSource *shdsrc = gamedef->getShaderSource(); + scene::ISceneManager* smgr = gamedef->getSceneManager(); + scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator(); bool new_style_water = g_settings->getBool("new_style_water"); bool new_style_leaves = g_settings->getBool("new_style_leaves"); @@ -697,13 +786,21 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef) bool enable_shaders = g_settings->getBool("enable_shaders"); bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping"); bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion"); + bool enable_mesh_cache = g_settings->getBool("enable_mesh_cache"); + bool enable_minimap = g_settings->getBool("enable_minimap"); bool use_normal_texture = enable_shaders && (enable_bumpmapping || enable_parallax_occlusion); - for (u32 i = 0; i < m_content_features.size(); i++) { + u32 size = m_content_features.size(); + + for (u32 i = 0; i < size; i++) { ContentFeatures *f = &m_content_features[i]; + // minimap pixel color - the average color of a texture + if (enable_minimap && f->tiledef[0].name != "") + f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name); + // Figure out the actual tiles to use TileDef tiledef[6]; for (u32 j = 0; j < 6; j++) { @@ -830,33 +927,52 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef) f->tiledef_special[j].backface_culling, f->alpha, material_type); } - // Meshnode drawtype - // Read the mesh and apply scale if ((f->drawtype == NDT_MESH) && (f->mesh != "")) { + // Meshnode drawtype + // Read the mesh and apply scale f->mesh_ptr[0] = gamedef->getMesh(f->mesh); - scaleMesh(f->mesh_ptr[0], v3f(f->visual_scale,f->visual_scale,f->visual_scale)); - recalculateBoundingBox(f->mesh_ptr[0]); - } - - //Convert regular nodebox nodes to meshnodes - //Change the drawtype and apply scale - if ((f->drawtype == NDT_NODEBOX) && - ((f->node_box.type == NODEBOX_REGULAR) || (f->node_box.type == NODEBOX_FIXED)) && + if (f->mesh_ptr[0]){ + v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale; + scaleMesh(f->mesh_ptr[0], scale); + recalculateBoundingBox(f->mesh_ptr[0]); + meshmanip->recalculateNormals(f->mesh_ptr[0], true, false); + } + } else if ((f->drawtype == NDT_NODEBOX) && + ((f->node_box.type == NODEBOX_REGULAR) || + (f->node_box.type == NODEBOX_FIXED)) && (!f->node_box.fixed.empty())) { + //Convert regular nodebox nodes to meshnodes + //Change the drawtype and apply scale f->drawtype = NDT_MESH; f->mesh_ptr[0] = convertNodeboxNodeToMesh(f); - scaleMesh(f->mesh_ptr[0], v3f(f->visual_scale,f->visual_scale,f->visual_scale)); + v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale; + scaleMesh(f->mesh_ptr[0], scale); recalculateBoundingBox(f->mesh_ptr[0]); + meshmanip->recalculateNormals(f->mesh_ptr[0], true, false); } - //Cache 6dfacedir rotated clones of meshes - if (f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) { - for (u16 j = 1; j < 24; j++) { - f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]); - rotateMeshBy6dFacedir(f->mesh_ptr[j], j); - recalculateBoundingBox(f->mesh_ptr[j]); - } + //Cache 6dfacedir and wallmounted rotated clones of meshes + if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) { + for (u16 j = 1; j < 24; j++) { + f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]); + rotateMeshBy6dFacedir(f->mesh_ptr[j], j); + recalculateBoundingBox(f->mesh_ptr[j]); + meshmanip->recalculateNormals(f->mesh_ptr[j], true, false); } + } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) { + static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2}; + for (u16 j = 1; j < 6; j++) { + f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]); + rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]); + recalculateBoundingBox(f->mesh_ptr[j]); + meshmanip->recalculateNormals(f->mesh_ptr[j], true, false); + } + rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]); + recalculateBoundingBox(f->mesh_ptr[0]); + meshmanip->recalculateNormals(f->mesh_ptr[0], true, false); + } + + progress_callback(progress_callback_args, i, size); } #endif } @@ -868,7 +984,7 @@ void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, bool backface_culling, u8 alpha, u8 material_type) { tile->shader_id = shader_id; - tile->texture = tsrc->getTexture(tiledef->name, &tile->texture_id); + tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id); tile->alpha = alpha; tile->material_type = material_type; @@ -901,14 +1017,17 @@ void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES; } else { std::ostringstream os(std::ios::binary); + tile->frames.resize(frame_count); + for (int i = 0; i < frame_count; i++) { + FrameSpec frame; os.str(""); os << tiledef->name << "^[verticalframe:" << frame_count << ":" << i; - frame.texture = tsrc->getTexture(os.str(), &frame.texture_id); + frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id); if (tile->normal_texture) frame.normal_texture = tsrc->getNormalTexture(os.str()); tile->frames[i] = frame; @@ -918,7 +1037,7 @@ void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, #endif -void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) +void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const { writeU8(os, 1); // version u16 count = 0; @@ -927,7 +1046,7 @@ void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) continue; - ContentFeatures *f = &m_content_features[i]; + const ContentFeatures *f = &m_content_features[i]; if (f->name == "") continue; writeU16(os2, i); @@ -937,7 +1056,9 @@ void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) f->serialize(wrapper_os, protocol_version); os2< count); // must not overflow + // must not overflow + u16 next = count + 1; + FATAL_ERROR_IF(next < count, "Overflow"); count++; } writeU16(os, count); @@ -1006,7 +1127,7 @@ IWritableNodeDefManager *createNodeDefManager() //// Serialization of old ContentFeatures formats -void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) +void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const { if (protocol_version == 13) { @@ -1109,7 +1230,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) writeU8(os, drowning); writeU8(os, leveled); writeU8(os, liquid_range); - } else + } else throw SerializationError("ContentFeatures::serialize(): " "Unsupported version requested"); } @@ -1224,3 +1345,168 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version) throw SerializationError("unsupported ContentFeatures version"); } } + + +inline bool CNodeDefManager::getNodeRegistrationStatus() const +{ + return m_node_registration_complete; +} + + +inline void CNodeDefManager::setNodeRegistrationStatus(bool completed) +{ + m_node_registration_complete = completed; +} + + +void CNodeDefManager::pendNodeResolve(NodeResolver *nr) +{ + nr->m_ndef = this; + if (m_node_registration_complete) + nr->nodeResolveInternal(); + else + m_pending_resolve_callbacks.push_back(nr); +} + + +bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr) +{ + size_t len = m_pending_resolve_callbacks.size(); + for (size_t i = 0; i != len; i++) { + if (nr != m_pending_resolve_callbacks[i]) + continue; + + len--; + m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len]; + m_pending_resolve_callbacks.resize(len); + return true; + } + + return false; +} + + +void CNodeDefManager::runNodeResolveCallbacks() +{ + for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) { + NodeResolver *nr = m_pending_resolve_callbacks[i]; + nr->nodeResolveInternal(); + } + + m_pending_resolve_callbacks.clear(); +} + + +void CNodeDefManager::resetNodeResolveState() +{ + m_node_registration_complete = false; + m_pending_resolve_callbacks.clear(); +} + + +//// +//// NodeResolver +//// + +NodeResolver::NodeResolver() +{ + m_ndef = NULL; + m_nodenames_idx = 0; + m_nnlistsizes_idx = 0; + m_resolve_done = false; + + m_nodenames.reserve(16); + m_nnlistsizes.reserve(4); +} + + +NodeResolver::~NodeResolver() +{ + if (!m_resolve_done && m_ndef) + m_ndef->cancelNodeResolveCallback(this); +} + + +void NodeResolver::nodeResolveInternal() +{ + m_nodenames_idx = 0; + m_nnlistsizes_idx = 0; + + resolveNodeNames(); + m_resolve_done = true; + + m_nodenames.clear(); + m_nnlistsizes.clear(); +} + + +bool NodeResolver::getIdFromNrBacklog(content_t *result_out, + const std::string &node_alt, content_t c_fallback) +{ + if (m_nodenames_idx == m_nodenames.size()) { + *result_out = c_fallback; + errorstream << "NodeResolver: no more nodes in list" << std::endl; + return false; + } + + content_t c; + std::string name = m_nodenames[m_nodenames_idx++]; + + bool success = m_ndef->getId(name, c); + if (!success && node_alt != "") { + name = node_alt; + success = m_ndef->getId(name, c); + } + + if (!success) { + errorstream << "NodeResolver: failed to resolve node name '" << name + << "'." << std::endl; + c = c_fallback; + } + + *result_out = c; + return success; +} + + +bool NodeResolver::getIdsFromNrBacklog(std::vector *result_out, + bool all_required, content_t c_fallback) +{ + bool success = true; + + if (m_nnlistsizes_idx == m_nnlistsizes.size()) { + errorstream << "NodeResolver: no more node lists" << std::endl; + return false; + } + + size_t length = m_nnlistsizes[m_nnlistsizes_idx++]; + + while (length--) { + if (m_nodenames_idx == m_nodenames.size()) { + errorstream << "NodeResolver: no more nodes in list" << std::endl; + return false; + } + + content_t c; + std::string &name = m_nodenames[m_nodenames_idx++]; + + if (name.substr(0,6) != "group:") { + if (m_ndef->getId(name, c)) { + result_out->push_back(c); + } else if (all_required) { + errorstream << "NodeResolver: failed to resolve node name '" + << name << "'." << std::endl; + result_out->push_back(c_fallback); + success = false; + } + } else { + std::set cids; + std::set::iterator it; + m_ndef->getIds(name, cids); + for (it = cids.begin(); it != cids.end(); ++it) + result_out->push_back(*it); + } + } + + return success; +}