#ifndef SERVER
#include "tile.h"
#include "mesh.h"
+#include <IMeshManipulator.h>
#endif
#include "log.h"
#include "settings.h"
ContentFeatures::~ContentFeatures()
{
-#ifndef SERVER
- for (u32 i = 0; i < 24; i++) {
- if (mesh_ptr[i])
- mesh_ptr[i]->drop();
- }
-#endif
}
void ContentFeatures::reset()
virtual void updateTextures(IGameDef *gamedef);
void serialize(std::ostream &os, u16 protocol_version);
void deSerialize(std::istream &is);
+ virtual NodeResolver *getResolver();
private:
void addNameIdMapping(content_t i, std::string name);
// Next possibly free id
content_t m_next_id;
+
+ // NodeResolver to queue pending node resolutions
+ NodeResolver m_resolver;
};
-CNodeDefManager::CNodeDefManager()
+CNodeDefManager::CNodeDefManager() :
+ m_resolver(this)
{
clear();
}
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
}
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 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->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]);
+ }
+ } 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]);
}
- //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, 12, 8, 4};
+ 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
}
}
+NodeResolver *CNodeDefManager::getResolver()
+{
+ return &m_resolver;
+}
+
+
IWritableNodeDefManager *createNodeDefManager()
{
return new CNodeDefManager();
throw SerializationError("unsupported ContentFeatures version");
}
}
+
+/*
+ NodeResolver
+*/
+
+NodeResolver::NodeResolver(INodeDefManager *ndef)
+{
+ m_ndef = ndef;
+ m_is_node_registration_complete = false;
+}
+
+
+NodeResolver::~NodeResolver()
+{
+ while (!m_pending_contents.empty()) {
+ NodeResolveInfo *nri = m_pending_contents.front();
+ m_pending_contents.pop_front();
+ delete nri;
+ }
+}
+
+
+int NodeResolver::addNode(std::string n_wanted, std::string n_alt,
+ content_t c_fallback, content_t *content)
+{
+ if (m_is_node_registration_complete) {
+ if (m_ndef->getId(n_wanted, *content))
+ return NR_STATUS_SUCCESS;
+
+ if (n_alt == "" || !m_ndef->getId(n_alt, *content)) {
+ *content = c_fallback;
+ return NR_STATUS_FAILURE;
+ }
+
+ return NR_STATUS_SUCCESS;
+ } else {
+ NodeResolveInfo *nfi = new NodeResolveInfo;
+ nfi->n_wanted = n_wanted;
+ nfi->n_alt = n_alt;
+ nfi->c_fallback = c_fallback;
+ nfi->output = content;
+
+ m_pending_contents.push_back(nfi);
+
+ return NR_STATUS_PENDING;
+ }
+}
+
+
+int NodeResolver::addNodeList(const char *nodename,
+ std::vector<content_t> *content_vec)
+{
+ if (m_is_node_registration_complete) {
+ std::set<content_t> idset;
+ std::set<content_t>::iterator it;
+
+ m_ndef->getIds(nodename, idset);
+ for (it = idset.begin(); it != idset.end(); ++it)
+ content_vec->push_back(*it);
+
+ return idset.size() ? NR_STATUS_SUCCESS : NR_STATUS_FAILURE;
+ } else {
+ m_pending_content_vecs.push_back(
+ std::make_pair(std::string(nodename), content_vec));
+ return NR_STATUS_PENDING;
+ }
+}
+
+
+bool NodeResolver::cancelNode(content_t *content)
+{
+ bool found = false;
+
+ std::list<NodeResolveInfo *>::iterator it = m_pending_contents.begin();
+ while (it != m_pending_contents.end()) {
+ NodeResolveInfo *nfi = *it;
+ if (nfi->output == content) {
+ it = m_pending_contents.erase(it);
+ delete nfi;
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+
+int NodeResolver::cancelNodeList(std::vector<content_t> *content_vec)
+{
+ int num_canceled = 0;
+
+ std::list<std::pair<std::string, std::vector<content_t> *> >::iterator it;
+ it = m_pending_content_vecs.begin();
+ while (it != m_pending_content_vecs.end()) {
+ if (it->second == content_vec) {
+ it = m_pending_content_vecs.erase(it);
+ num_canceled++;
+ }
+ }
+
+ return num_canceled;
+}
+
+
+int NodeResolver::resolveNodes()
+{
+ int num_failed = 0;
+
+ //// Resolve pending single node name -> content ID mappings
+ while (!m_pending_contents.empty()) {
+ NodeResolveInfo *nri = m_pending_contents.front();
+ m_pending_contents.pop_front();
+
+ bool success = true;
+ if (!m_ndef->getId(nri->n_wanted, *nri->output)) {
+ success = (nri->n_alt != "") ?
+ m_ndef->getId(nri->n_alt, *nri->output) : false;
+ }
+
+ if (!success) {
+ *nri->output = nri->c_fallback;
+ num_failed++;
+ errorstream << "NodeResolver::resolveNodes(): Failed to "
+ "resolve '" << nri->n_wanted;
+ if (nri->n_alt != "")
+ errorstream << "' and '" << nri->n_alt;
+ errorstream << "'" << std::endl;
+ }
+
+ delete nri;
+ }
+
+ //// Resolve pending node names and add to content_t vector
+ while (!m_pending_content_vecs.empty()) {
+ std::pair<std::string, std::vector<content_t> *> item =
+ m_pending_content_vecs.front();
+ m_pending_content_vecs.pop_front();
+
+ std::string &name = item.first;
+ std::vector<content_t> *output = item.second;
+
+ std::set<content_t> idset;
+ std::set<content_t>::iterator it;
+
+ m_ndef->getIds(name, idset);
+ for (it = idset.begin(); it != idset.end(); ++it)
+ output->push_back(*it);
+
+ if (idset.size() == 0) {
+ num_failed++;
+ errorstream << "NodeResolver::resolveNodes(): Failed to "
+ "resolve '" << name << "'" << std::endl;
+ }
+ }
+
+ //// Mark node registration as complete so future resolve
+ //// requests are satisfied immediately
+ m_is_node_registration_complete = true;
+
+ return num_failed;
+}