Add meshnode drawtype.

This commit is contained in:
RealBadAngel 2014-10-15 04:13:53 +02:00
parent d1ccc64e1e
commit 0066bd77d2
11 changed files with 374 additions and 6 deletions

@ -103,6 +103,7 @@ mods
| |-- screenshot.png | |-- screenshot.png
| |-- description.txt | |-- description.txt
| |-- init.lua | |-- init.lua
| |-- models
| |-- textures | |-- textures
| | |-- modname_stuff.png | | |-- modname_stuff.png
| | `-- modname_something_else.png | | `-- modname_something_else.png
@ -137,6 +138,9 @@ init.lua:
minetest.setting_get(name) and minetest.setting_getbool(name) can be used minetest.setting_get(name) and minetest.setting_getbool(name) can be used
to read custom or existing settings at load time, if necessary. to read custom or existing settings at load time, if necessary.
models:
Models for entities or meshnodes.
textures, sounds, media: textures, sounds, media:
Media files (textures, sounds, whatever) that will be transferred to the Media files (textures, sounds, whatever) that will be transferred to the
client and will be available for use by the mod. client and will be available for use by the mod.
@ -430,6 +434,7 @@ Look for examples in games/minimal or games/minetest_game.
- fencelike - fencelike
- raillike - raillike
- nodebox -- See below. EXPERIMENTAL - nodebox -- See below. EXPERIMENTAL
- mesh -- use models for nodes
*_optional drawtypes need less rendering time if deactivated (always client side) *_optional drawtypes need less rendering time if deactivated (always client side)
@ -469,6 +474,12 @@ A box of a regular node would look like:
type = "leveled" is same as "fixed", but y2 will be automatically set to level from param2 type = "leveled" is same as "fixed", but y2 will be automatically set to level from param2
Meshes
-----------
If drawtype "mesh" is used tiles should hold model materials textures.
Only static meshes are implemented.
For supported model formats see Irrlicht engine documentation.
Ore types Ore types
--------------- ---------------
These tell in what manner the ore is generated. These tell in what manner the ore is generated.
@ -2405,7 +2416,7 @@ Node definition (register_node)
drawtype = "normal", -- See "Node drawtypes" drawtype = "normal", -- See "Node drawtypes"
visual_scale = 1.0, visual_scale = 1.0,
^ Supported for drawtypes "plantlike", "signlike", "torchlike". ^ Supported for drawtypes "plantlike", "signlike", "torchlike", "mesh".
^ For plantlike, the image will start at the bottom of the node; for the ^ For plantlike, the image will start at the bottom of the node; for the
^ other drawtypes, the image will be centered on the node. ^ other drawtypes, the image will be centered on the node.
^ Note that positioning for "torchlike" may still change. ^ Note that positioning for "torchlike" may still change.
@ -2439,6 +2450,7 @@ Node definition (register_node)
light_source = 0, -- Amount of light emitted by node light_source = 0, -- Amount of light emitted by node
damage_per_second = 0, -- If player is inside node, this damage is caused damage_per_second = 0, -- If player is inside node, this damage is caused
node_box = {type="regular"}, -- See "Node boxes" node_box = {type="regular"}, -- See "Node boxes"
mesh = "model",
selection_box = {type="regular"}, -- See "Node boxes" selection_box = {type="regular"}, -- See "Node boxes"
^ If drawtype "nodebox" is used and selection_box is nil, then node_box is used ^ If drawtype "nodebox" is used and selection_box is nil, then node_box is used
legacy_facedir_simple = false, -- Support maps made in and before January 2012 legacy_facedir_simple = false, -- Support maps made in and before January 2012

@ -2678,7 +2678,7 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
// Update node textures and assign shaders to each tile // Update node textures and assign shaders to each tile
infostream<<"- Updating node textures"<<std::endl; infostream<<"- Updating node textures"<<std::endl;
m_nodedef->updateTextures(m_tsrc, m_shsrc); m_nodedef->updateTextures(this);
// Preload item textures and meshes if configured to // Preload item textures and meshes if configured to
if(g_settings->getBool("preload_item_visuals")) if(g_settings->getBool("preload_item_visuals"))

@ -1715,6 +1715,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
makeCuboid(&collector, box, tiles, 6, c, txc); makeCuboid(&collector, box, tiles, 6, c, txc);
} }
break;} break;}
case NDT_MESH:
{
v3f pos = intToFloat(p, BS);
video::SColor c = MapBlock_LightColor(255, getInteriorLight(n, 1, nodedef), f.light_source);
u8 facedir = n.getFaceDir(nodedef);
for(u16 j = 0; j < f.mesh_ptr[facedir]->getMeshBufferCount(); j++) {
scene::IMeshBuffer *buf = f.mesh_ptr[facedir]->getMeshBuffer(j);
collector.append(getNodeTileN(n, p, j, data),
(video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
buf->getIndices(), buf->getIndexCount(), pos, c);
}
break;}
} }
} }
} }

@ -1428,3 +1428,54 @@ void MeshCollector::append(const TileSpec &tile,
p->vertices.push_back(vertices[i]); p->vertices.push_back(vertices[i]);
} }
} }
/*
MeshCollector - for meshnodes and converted drawtypes.
*/
void MeshCollector::append(const TileSpec &tile,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
v3f pos, video::SColor c)
{
if(numIndices > 65535)
{
dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
return;
}
PreMeshBuffer *p = NULL;
for(u32 i=0; i<prebuffers.size(); i++)
{
PreMeshBuffer &pp = prebuffers[i];
if(pp.tile != tile)
continue;
if(pp.indices.size() + numIndices > 65535)
continue;
p = &pp;
break;
}
if(p == NULL)
{
PreMeshBuffer pp;
pp.tile = tile;
prebuffers.push_back(pp);
p = &prebuffers[prebuffers.size()-1];
}
u32 vertex_count = p->vertices.size();
for(u32 i=0; i<numIndices; i++)
{
u32 j = indices[i] + vertex_count;
p->indices.push_back(j);
}
for(u32 i=0; i<numVertices; i++)
{
video::S3DVertex vert = vertices[i];
vert.Pos += pos;
vert.Color = c;
p->vertices.push_back(vert);
}
}

@ -174,6 +174,10 @@ struct MeshCollector
void append(const TileSpec &material, void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices, const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices); const u16 *indices, u32 numIndices);
void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
v3f pos, video::SColor c);
}; };
// This encodes // This encodes

@ -408,3 +408,219 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
} }
} }
} }
void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir)
{
int axisdir = facedir>>2;
facedir &= 0x03;
u16 mc = mesh->getMeshBufferCount();
for(u16 j = 0; j < mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
switch (axisdir)
{
case 0:
if(facedir == 1)
vertices[i].Pos.rotateXZBy(-90);
else if(facedir == 2)
vertices[i].Pos.rotateXZBy(180);
else if(facedir == 3)
vertices[i].Pos.rotateXZBy(90);
break;
case 1: // z+
vertices[i].Pos.rotateYZBy(90);
if(facedir == 1)
vertices[i].Pos.rotateXYBy(90);
else if(facedir == 2)
vertices[i].Pos.rotateXYBy(180);
else if(facedir == 3)
vertices[i].Pos.rotateXYBy(-90);
break;
case 2: //z-
vertices[i].Pos.rotateYZBy(-90);
if(facedir == 1)
vertices[i].Pos.rotateXYBy(-90);
else if(facedir == 2)
vertices[i].Pos.rotateXYBy(180);
else if(facedir == 3)
vertices[i].Pos.rotateXYBy(90);
break;
case 3: //x+
vertices[i].Pos.rotateXYBy(-90);
if(facedir == 1)
vertices[i].Pos.rotateYZBy(90);
else if(facedir == 2)
vertices[i].Pos.rotateYZBy(180);
else if(facedir == 3)
vertices[i].Pos.rotateYZBy(-90);
break;
case 4: //x-
vertices[i].Pos.rotateXYBy(90);
if(facedir == 1)
vertices[i].Pos.rotateYZBy(-90);
else if(facedir == 2)
vertices[i].Pos.rotateYZBy(180);
else if(facedir == 3)
vertices[i].Pos.rotateYZBy(90);
break;
case 5:
vertices[i].Pos.rotateXYBy(-180);
if(facedir == 1)
vertices[i].Pos.rotateXZBy(90);
else if(facedir == 2)
vertices[i].Pos.rotateXZBy(180);
else if(facedir == 3)
vertices[i].Pos.rotateXZBy(-90);
break;
default:
break;
}
}
}
}
void recalculateBoundingBox(scene::IMesh *src_mesh)
{
core::aabbox3d<f32> bbox;
bbox.reset(0,0,0);
for(u16 j = 0; j < src_mesh->getMeshBufferCount(); j++)
{
scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
buf->recalculateBoundingBox();
if(j == 0)
bbox = buf->getBoundingBox();
else
bbox.addInternalBox(buf->getBoundingBox());
}
src_mesh->setBoundingBox(bbox);
}
scene::IMesh* cloneMesh(scene::IMesh *src_mesh)
{
scene::SMesh* dst_mesh = new scene::SMesh();
for(u16 j = 0; j < src_mesh->getMeshBufferCount(); j++)
{
scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 *indices = (u16*)buf->getIndices();
scene::SMeshBuffer *temp_buf = new scene::SMeshBuffer();
temp_buf->append(vertices, buf->getVertexCount(),
indices, buf->getIndexCount());
dst_mesh->addMeshBuffer(temp_buf);
temp_buf->drop();
}
return dst_mesh;
}
scene::IMesh* convertNodeboxNodeToMesh(ContentFeatures *f)
{
scene::SMesh* dst_mesh = new scene::SMesh();
for (u16 j = 0; j < 6; j++)
{
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
dst_mesh->addMeshBuffer(buf);
buf->drop();
}
video::SColor c(255,255,255,255);
std::vector<aabb3f> boxes = f->node_box.fixed;
for(std::vector<aabb3f>::iterator
i = boxes.begin();
i != boxes.end(); i++)
{
aabb3f box = *i;
f32 temp;
if (box.MinEdge.X > box.MaxEdge.X)
{
temp=box.MinEdge.X;
box.MinEdge.X=box.MaxEdge.X;
box.MaxEdge.X=temp;
}
if (box.MinEdge.Y > box.MaxEdge.Y)
{
temp=box.MinEdge.Y;
box.MinEdge.Y=box.MaxEdge.Y;
box.MaxEdge.Y=temp;
}
if (box.MinEdge.Z > box.MaxEdge.Z)
{
temp=box.MinEdge.Z;
box.MinEdge.Z=box.MaxEdge.Z;
box.MaxEdge.Z=temp;
}
// Compute texture coords
f32 tx1 = (box.MinEdge.X/BS)+0.5;
f32 ty1 = (box.MinEdge.Y/BS)+0.5;
f32 tz1 = (box.MinEdge.Z/BS)+0.5;
f32 tx2 = (box.MaxEdge.X/BS)+0.5;
f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
f32 txc[24] = {
// up
tx1, 1-tz2, tx2, 1-tz1,
// down
tx1, tz1, tx2, tz2,
// right
tz1, 1-ty2, tz2, 1-ty1,
// left
1-tz2, 1-ty2, 1-tz1, 1-ty1,
// back
1-tx2, 1-ty2, 1-tx1, 1-ty1,
// front
tx1, 1-ty2, tx2, 1-ty1,
};
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
video::S3DVertex vertices[24] =
{
// up
video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
// down
video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
// right
video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
// left
video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
// back
video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
// front
video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
};
u16 indices[] = {0,1,2,2,3,0};
for(u16 j = 0; j < 24; j += 4)
{
scene::IMeshBuffer *buf = dst_mesh->getMeshBuffer(j / 4);
buf->append(vertices + j, 4, indices, 6);
}
}
return dst_mesh;
}

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MESH_HEADER #define MESH_HEADER
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "nodedef.h"
#include <string> #include <string>
/* /*
@ -68,5 +69,25 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
const video::SColor &colorX, const video::SColor &colorX,
const video::SColor &colorY, const video::SColor &colorY,
const video::SColor &colorZ); const video::SColor &colorZ);
/*
Rotate the mesh by 6d facedir value.
Method only for meshnodes, not suitable for entities.
*/
void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir);
/*
Clone the mesh.
*/
scene::IMesh* cloneMesh(scene::IMesh *src_mesh);
/*
Convert nodebox drawtype node to mesh.
*/
scene::IMesh* convertNodeboxNodeToMesh(ContentFeatures *f);
/*
Update bounding box for a mesh.
*/
void recalculateBoundingBox(scene::IMesh *src_mesh);
#endif #endif

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemdef.h" #include "itemdef.h"
#ifndef SERVER #ifndef SERVER
#include "tile.h" #include "tile.h"
#include "mesh.h"
#endif #endif
#include "log.h" #include "log.h"
#include "settings.h" #include "settings.h"
@ -31,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h" #include "util/serialize.h"
#include "exceptions.h" #include "exceptions.h"
#include "debug.h" #include "debug.h"
#include "gamedef.h"
/* /*
NodeBox NodeBox
@ -195,6 +197,11 @@ void ContentFeatures::reset()
// Unknown nodes can be dug // Unknown nodes can be dug
groups["dig_immediate"] = 2; groups["dig_immediate"] = 2;
drawtype = NDT_NORMAL; drawtype = NDT_NORMAL;
mesh = "";
#ifndef SERVER
for(u32 i = 0; i < 24; i++)
mesh_ptr[i] = NULL;
#endif
visual_scale = 1.0; visual_scale = 1.0;
for(u32 i = 0; i < 6; i++) for(u32 i = 0; i < 6; i++)
tiledef[i] = TileDef(); tiledef[i] = TileDef();
@ -295,6 +302,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version)
writeU8(os, waving); writeU8(os, waving);
// Stuff below should be moved to correct place in a version that otherwise changes // Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version // the protocol version
os<<serializeString(mesh);
} }
void ContentFeatures::deSerialize(std::istream &is) void ContentFeatures::deSerialize(std::istream &is)
@ -363,6 +371,7 @@ void ContentFeatures::deSerialize(std::istream &is)
try{ try{
// Stuff below should be moved to correct place in a version that // Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version // otherwise changes the protocol version
mesh = deSerializeString(is);
}catch(SerializationError &e) {}; }catch(SerializationError &e) {};
} }
@ -386,7 +395,7 @@ public:
virtual content_t set(const std::string &name, const ContentFeatures &def); virtual content_t set(const std::string &name, const ContentFeatures &def);
virtual content_t allocateDummy(const std::string &name); virtual content_t allocateDummy(const std::string &name);
virtual void updateAliases(IItemDefManager *idef); 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 serialize(std::ostream &os, u16 protocol_version);
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
@ -669,12 +678,15 @@ void CNodeDefManager::updateAliases(IItemDefManager *idef)
} }
void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc) void CNodeDefManager::updateTextures(IGameDef *gamedef)
{ {
#ifndef SERVER #ifndef SERVER
infostream << "CNodeDefManager::updateTextures(): Updating " infostream << "CNodeDefManager::updateTextures(): Updating "
"textures in node definitions" << std::endl; "textures in node definitions" << std::endl;
ITextureSource *tsrc = gamedef->tsrc();
IShaderSource *shdsrc = gamedef->getShaderSource();
bool new_style_water = g_settings->getBool("new_style_water"); bool new_style_water = g_settings->getBool("new_style_water");
bool new_style_leaves = g_settings->getBool("new_style_leaves"); bool new_style_leaves = g_settings->getBool("new_style_leaves");
bool connected_glass = g_settings->getBool("connected_glass"); bool connected_glass = g_settings->getBool("connected_glass");
@ -771,6 +783,10 @@ void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
f->backface_culling = false; f->backface_culling = false;
f->solidness = 0; f->solidness = 0;
break; break;
case NDT_MESH:
f->solidness = 0;
f->backface_culling = false;
break;
case NDT_TORCHLIKE: case NDT_TORCHLIKE:
case NDT_SIGNLIKE: case NDT_SIGNLIKE:
case NDT_FENCELIKE: case NDT_FENCELIKE:
@ -810,6 +826,34 @@ void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
tile_shader[j], use_normal_texture, tile_shader[j], use_normal_texture,
f->tiledef_special[j].backface_culling, f->alpha, material_type); 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 != "")) {
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)) &&
(!f->node_box.fixed.empty())) {
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));
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]);
}
}
} }
#endif #endif
} }

@ -152,6 +152,7 @@ enum NodeDrawType
NDT_FIRELIKE, // Draw faces slightly rotated and only on connecting nodes, NDT_FIRELIKE, // Draw faces slightly rotated and only on connecting nodes,
NDT_GLASSLIKE_FRAMED_OPTIONAL, // enabled -> connected, disabled -> Glass-like NDT_GLASSLIKE_FRAMED_OPTIONAL, // enabled -> connected, disabled -> Glass-like
// uses 2 textures, one for frames, second for faces // uses 2 textures, one for frames, second for faces
NDT_MESH, // Uses static meshes
}; };
#define CF_SPECIAL_COUNT 6 #define CF_SPECIAL_COUNT 6
@ -187,6 +188,10 @@ struct ContentFeatures
// Visual definition // Visual definition
enum NodeDrawType drawtype; enum NodeDrawType drawtype;
std::string mesh;
#ifndef SERVER
scene::IMesh *mesh_ptr[24];
#endif
float visual_scale; // Misc. scale parameter float visual_scale; // Misc. scale parameter
TileDef tiledef[6]; TileDef tiledef[6];
TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid
@ -328,8 +333,7 @@ public:
/* /*
Update tile textures to latest return values of TextueSource. Update tile textures to latest return values of TextueSource.
*/ */
virtual void updateTextures(ITextureSource *tsrc, virtual void updateTextures(IGameDef *gamedef)=0;
IShaderSource *shdsrc)=0;
virtual void serialize(std::ostream &os, u16 protocol_version)=0; virtual void serialize(std::ostream &os, u16 protocol_version)=0;
virtual void deSerialize(std::istream &is)=0; virtual void deSerialize(std::istream &is)=0;

@ -281,6 +281,9 @@ ContentFeatures read_content_features(lua_State *L, int index)
ScriptApiNode::es_DrawType,NDT_NORMAL); ScriptApiNode::es_DrawType,NDT_NORMAL);
getfloatfield(L, index, "visual_scale", f.visual_scale); getfloatfield(L, index, "visual_scale", f.visual_scale);
/* Meshnode model filename */
getstringfield(L, index, "mesh", f.mesh);
// tiles = {} // tiles = {}
lua_getfield(L, index, "tiles"); lua_getfield(L, index, "tiles");
// If nil, try the deprecated name "tile_images" instead // If nil, try the deprecated name "tile_images" instead

@ -45,6 +45,7 @@ struct EnumString ScriptApiNode::es_DrawType[] =
{NDT_FENCELIKE, "fencelike"}, {NDT_FENCELIKE, "fencelike"},
{NDT_RAILLIKE, "raillike"}, {NDT_RAILLIKE, "raillike"},
{NDT_NODEBOX, "nodebox"}, {NDT_NODEBOX, "nodebox"},
{NDT_MESH, "mesh"},
{0, NULL}, {0, NULL},
}; };