#include "itemdef.h"
#ifndef SERVER
#include "tile.h"
+#include "mesh.h"
+#include <IMeshManipulator.h>
#endif
#include "log.h"
#include "settings.h"
#include "util/serialize.h"
#include "exceptions.h"
#include "debug.h"
+#include "gamedef.h"
/*
NodeBox
// Unknown nodes can be dug
groups["dig_immediate"] = 2;
drawtype = NDT_NORMAL;
+ mesh = "";
+#ifndef SERVER
+ for(u32 i = 0; i < 24; i++)
+ mesh_ptr[i] = NULL;
+#endif
visual_scale = 1.0;
for(u32 i = 0; i < 6; i++)
tiledef[i] = TileDef();
damage_per_second = 0;
node_box = NodeBox();
selection_box = NodeBox();
+ collision_box = NodeBox();
waving = 0;
legacy_facedir_simple = false;
legacy_wallmounted = false;
writeU8(os, waving);
// Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version
+ os<<serializeString(mesh);
+ collision_box.serialize(os, protocol_version);
}
void ContentFeatures::deSerialize(std::istream &is)
try{
// Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version
+ mesh = deSerializeString(is);
+ collision_box.deSerialize(is);
}catch(SerializationError &e) {};
}
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<content_t> &result) const;
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(ITextureSource *tsrc, IShaderSource *shdsrc);
+ virtual void updateTextures(IGameDef *gamedef);
void serialize(std::ostream &os, u16 protocol_version);
void deSerialize(std::istream &is);
+ virtual void pendNodeResolve(NodeResolveInfo *nri);
+ virtual void cancelNodeResolve(NodeResolver *resolver);
+ virtual void runNodeResolverCallbacks();
+
+ virtual bool getIdFromResolveInfo(NodeResolveInfo *nri,
+ const std::string &node_alt, content_t c_fallback, content_t &result);
+ virtual bool getIdsFromResolveInfo(NodeResolveInfo *nri,
+ std::vector<content_t> &result);
+
private:
void addNameIdMapping(content_t i, std::string name);
#ifndef SERVER
// Next possibly free id
content_t m_next_id;
+
+ // List of node strings and node resolver callbacks to perform
+ std::list<NodeResolveInfo *> m_pending_node_lookups;
};
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
}
}
-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());
}
}
-void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc)
+void CNodeDefManager::updateTextures(IGameDef *gamedef)
{
#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");
bool connected_glass = g_settings->getBool("connected_glass");
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 use_normal_texture = enable_shaders &&
(enable_bumpmapping || enable_parallax_occlusion);
f->backface_culling = false;
f->solidness = 0;
break;
+ case NDT_MESH:
+ f->solidness = 0;
+ f->backface_culling = false;
+ break;
case NDT_TORCHLIKE:
case NDT_SIGNLIKE:
case NDT_FENCELIKE:
tile_shader[j], use_normal_texture,
f->tiledef_special[j].backface_culling, f->alpha, material_type);
}
+
+ if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
+ // Meshnode drawtype
+ // Read the mesh and apply scale
+ f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
+ 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);
+ 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 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);
+ }
}
#endif
}
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("");
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
- } else
+ } else
throw SerializationError("ContentFeatures::serialize(): "
"Unsupported version requested");
}
throw SerializationError("unsupported ContentFeatures version");
}
}
+
+
+void CNodeDefManager::pendNodeResolve(NodeResolveInfo *nri)
+{
+ nri->resolver->m_ndef = this;
+ m_pending_node_lookups.push_back(nri);
+}
+
+
+void CNodeDefManager::cancelNodeResolve(NodeResolver *resolver)
+{
+ for (std::list<NodeResolveInfo *>::iterator
+ it = m_pending_node_lookups.begin();
+ it != m_pending_node_lookups.end();
+ ++it) {
+ NodeResolveInfo *nri = *it;
+ if (resolver == nri->resolver) {
+ it = m_pending_node_lookups.erase(it);
+ delete nri;
+ }
+ }
+}
+
+
+void CNodeDefManager::runNodeResolverCallbacks()
+{
+ while (!m_pending_node_lookups.empty()) {
+ NodeResolveInfo *nri = m_pending_node_lookups.front();
+ m_pending_node_lookups.pop_front();
+ nri->resolver->resolveNodeNames(nri);
+ nri->resolver->m_lookup_done = true;
+ delete nri;
+ }
+}
+
+
+bool CNodeDefManager::getIdFromResolveInfo(NodeResolveInfo *nri,
+ const std::string &node_alt, content_t c_fallback, content_t &result)
+{
+ if (nri->nodenames.empty()) {
+ result = c_fallback;
+ errorstream << "Resolver empty nodename list" << std::endl;
+ return false;
+ }
+
+ content_t c;
+ std::string name = nri->nodenames.front();
+ nri->nodenames.pop_front();
+
+ bool success = getId(name, c);
+ if (!success && node_alt != "") {
+ name = node_alt;
+ success = getId(name, c);
+ }
+
+ if (!success) {
+ errorstream << "Resolver: Failed to resolve node name '" << name
+ << "'." << std::endl;
+ c = c_fallback;
+ }
+
+ result = c;
+ return success;
+}
+
+
+bool CNodeDefManager::getIdsFromResolveInfo(NodeResolveInfo *nri,
+ std::vector<content_t> &result)
+{
+ bool success = true;
+
+ if (nri->nodelistinfo.empty()) {
+ errorstream << "Resolver: Empty nodelistinfo list" << std::endl;
+ return false;
+ }
+
+ NodeListInfo listinfo = nri->nodelistinfo.front();
+ nri->nodelistinfo.pop_front();
+
+ while (listinfo.length--) {
+ if (nri->nodenames.empty()) {
+ errorstream << "Resolver: Empty nodename list" << std::endl;
+ return false;
+ }
+
+ content_t c;
+ std::string name = nri->nodenames.front();
+ nri->nodenames.pop_front();
+
+ if (getId(name, c)) {
+ result.push_back(c);
+ } else if (listinfo.all_required) {
+ errorstream << "Resolver: Failed to resolve node name '" << name
+ << "'." << std::endl;
+ result.push_back(listinfo.c_fallback);
+ success = false;
+ }
+ }
+
+ return success;
+}