Skip to content
Permalink
Browse files

Add meshnode drawtype.

  • Loading branch information
RealBadAngel committed Oct 18, 2014
1 parent d1ccc64 commit 0066bd77d25793b76fdaa9a62755cca934f0121d
Showing with 374 additions and 6 deletions.
  1. +13 −1 doc/lua_api.txt
  2. +1 −1 src/client.cpp
  3. +12 −0 src/content_mapblock.cpp
  4. +51 −0 src/mapblock_mesh.cpp
  5. +4 −0 src/mapblock_mesh.h
  6. +216 −0 src/mesh.cpp
  7. +21 −0 src/mesh.h
  8. +46 −2 src/nodedef.cpp
  9. +6 −2 src/nodedef.h
  10. +3 −0 src/script/common/c_content.cpp
  11. +1 −0 src/script/cpp_api/s_node.cpp
@@ -103,6 +103,7 @@ mods
| |-- screenshot.png
| |-- description.txt
| |-- init.lua
| |-- models
| |-- textures
| | |-- modname_stuff.png
| | `-- modname_something_else.png
@@ -137,6 +138,9 @@ init.lua:
minetest.setting_get(name) and minetest.setting_getbool(name) can be used
to read custom or existing settings at load time, if necessary.

models:
Models for entities or meshnodes.

textures, sounds, media:
Media files (textures, sounds, whatever) that will be transferred to the
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
- raillike
- nodebox -- See below. EXPERIMENTAL
- mesh -- use models for nodes

*_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

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
---------------
These tell in what manner the ore is generated.
@@ -2405,7 +2416,7 @@ Node definition (register_node)

drawtype = "normal", -- See "Node drawtypes"
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
^ other drawtypes, the image will be centered on the node.
^ 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
damage_per_second = 0, -- If player is inside node, this damage is caused
node_box = {type="regular"}, -- See "Node boxes"
mesh = "model",
selection_box = {type="regular"}, -- See "Node boxes"
^ 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
@@ -2678,7 +2678,7 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)

// Update node textures and assign shaders to each tile
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
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);
}
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]);
}
}

/*
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,
const video::S3DVertex *vertices, u32 numVertices,
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
@@ -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;
}

12 comments on commit 0066bd7

@4aiman

This comment has been minimized.

Copy link
Contributor

@4aiman 4aiman replied Oct 31, 2014

So, this enables me to convert some weird complex nodeboxes to some static meshes which can use less vertexes/edges/faces. And that was intended to speedup the game.
Am I right or do I miss something about it?

@Calinou

This comment has been minimized.

Copy link
Member

@Calinou Calinou replied Nov 2, 2014

So, this enables me to convert some weird complex nodeboxes to some static meshes which can use less vertexes/edges/faces. And that was intended to speedup the game.
Am I right or do I miss something about it?

Yes, you are right, but the vertex/triangle count stays the same. No mesh optimization or duplicate removals are done.

@4aiman

This comment has been minimized.

Copy link
Contributor

@4aiman 4aiman replied Nov 5, 2014

@Calinou
It seems you've got me wrong.
What I meant was:
Statement: I Can I create a model of a triangular pyramid and use it instead of a nodebox.
Question: Will there be only 4 vertexes or MT will try to "convert" my model to a nodebox thus making thousands of vertexes (like in more blocks mod)?

@Jordach

This comment has been minimized.

Copy link
Contributor

@Jordach Jordach replied Nov 5, 2014

@4aiman

This comment has been minimized.

Copy link
Contributor

@4aiman 4aiman replied Nov 5, 2014

@Jordach
Did you try to use this feature?
I've tried but MT draws a cube instead an acyual model.
I've used *.x and *.3ds formats...

@NathanSalapat

This comment has been minimized.

Copy link
Contributor

@NathanSalapat NathanSalapat replied Nov 5, 2014

@4aiman I'm sure you are, but are you using a fresh version? I've been using the daily PPA for Ubuntu and have had the meshes working for a while. I'm using OBJ format on my models.

@Calinou

This comment has been minimized.

Copy link
Member

@Calinou Calinou replied Nov 5, 2014

Will there be only 4 vertexes or MT will try to "convert" my model to a nodebox thus making thousands of vertexes (like in more blocks mod)?

I am using VanessaE's slopes in the More Blocks branch, which are 3D models in .obj format.

@4aiman

This comment has been minimized.

Copy link
Contributor

@4aiman 4aiman replied Nov 7, 2014

@Calinou, does that count as an answer to you? :)
I've asked about the engine's behaviour. You've told me what you're using.
Or was that 'yes' for the first part of my message? :)

@NathanSalapat
I thought I was using the 2-days-old build. Turned out I was wrong.
But now I have a different problem: models are too big. Is there any way to control that?

@Calinou where can I find that moreblocks of Vanessa to find out about meshnode drawtype more?

@NathanSalapat

This comment has been minimized.

Copy link
Contributor

@NathanSalapat NathanSalapat replied Nov 7, 2014

I'm not sure if you can control the scale in the lua, but a cube 1x1x1 in Blender is the same size as a block in minetest.

This might be the moreblock thing @Calinou is referencing. https://forum.minetest.net/viewtopic.php?f=9&t=10428

@RHRhino

This comment has been minimized.

Copy link

@RHRhino RHRhino replied Nov 8, 2014

@4aiman: Meshes are useing .obj, not .x or .3ds. In Minetest your "triangular pyramid" Tetrahedron? will also have just 4 vertices like in Blender. This is the new of this commit. You can scale the mesh in blender or in your mod with visual_scale like every other node. Check out VanessaE's slope_test mod.
@NathanSalapat: 1 Blender unit = 0.1 Minetest unit. The Blender Default Cube has 2x2x2 blender units.

@4aiman

This comment has been minimized.

Copy link
Contributor

@4aiman 4aiman replied Nov 8, 2014

@RHRhino: Meshes CAN use all of those - tested and working. Also, please, if you suggest looking for smth, then provide a link to it - just like NathanSalapat did :)
Blender unit = 0.1 minetest unit? Are you serious? Try to export to b3d and see the difference. Please, don't say what you just did without pointing out that there are at least 3 types of units in blender and that some exporterter still treat 1BU as a 1m.

@NathanSalapat: Thanks a lot!

@ShadowNinja

This comment has been minimized.

Copy link
Member

@ShadowNinja ShadowNinja replied Nov 9, 2014

@RHRhino: 1 blender unit is scaled to one Minetest unit now.
Unfortunately I don't think this scaling is done for entity meshes.

Please sign in to comment.