Skip to content

Commit

Permalink
Make plantlike drawtype more fun
Browse files Browse the repository at this point in the history
Adds several new ways that the plantlike drawtype mesh can be changed.

This requires paramtype2 = "meshoptions" to be set in the node
definition. The drawtype for these nodes should be "plantlike".

These modifications are all done using param2. This field is now
a complex bitfield that allows some or more of the combinations to
be chosen, and the mesh draw code will choose the options based as
neeeded for each plantlike node.

bit layout:
bits 0, 1 and 2 (values 0x1 through 0x7) are for choosing the plant
mesh shape:
  0 - ordinary plantlike plant ("x" shaped)
  1 - ordinary plant, but rotated 45 degrees ("+" shaped)
  2 - a plant with 3 faces ("*" shaped)
  3 - a plant with 4 faces ("#" shaped)
  4 - a plant with 4 faces ("#" shaped, leaning outwards)
  5 through 7 are unused and reserved for future mesh shapes.

bit 3 (0x8) causes the plant to be randomly offset in the x,z
plane. The plant should fall within the 1x1x1 nodebox if regularly
sized.

bit 4 (0x10) causes the plant mesh to grow by sqrt(2), and will cause
the plant mesh to fill out 1x1x1, and appear slightly larger. Texture
makers will want to make their plant texture 23x16 pixels to have the
best visual fit in 1x1x1 size.

bit 5 (0x20) causes each face of the plant to have a slight negative
Y offset in position, descending up to 0.125 downwards into the node
below. Because this is per face, this causes the plant model to be
less symmetric.

bit 6 (0x40) through bit 7 (0x80) are unused and reserved for
future use.

!(https://youtu.be/qWuI664krsI)
  • Loading branch information
sofar authored and paramat committed Aug 26, 2016
1 parent d767f02 commit e58a55a
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 13 deletions.
16 changes: 16 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -578,6 +578,22 @@ node definition:
^ The rotation of this node is stored in param2. Plants are rotated this way.
Values range 0 - 179. The value stored in param2 is multiplied by two to
get the actual rotation of the node.
paramtype2 == "meshoptions"
^ Only valid for "plantlike". The value of param2 becomes a bitfield which can
be used to change how the client draws plantlike nodes. Bits 0, 1 and 2 form
a mesh selector. Currently the following meshes are choosable:
0 = a "x" shaped plant (ordinary plant)
1 = a "+" shaped plant (just rotated 45 degrees)
2 = a "*" shaped plant with 3 faces instead of 2
3 = a "#" shaped plant with 4 faces instead of 2
4 = a "#" shaped plant with 4 faces that lean outwards
5-7 are unused and reserved for future meshes.
Bits 3 through 7 are optional flags that can be combined and give these
effects:
bit 3 (0x08) - Makes the plant slightly vary placement horizontally
bit 4 (0x10) - Makes the plant mesh 1.4x larger
bit 5 (0x20) - Moves each face randomly a small bit down (1/8 max)
bits 6-7 are reserved for future use.
collision_box = {
type = "fixed",
fixed = {
Expand Down
152 changes: 141 additions & 11 deletions src/content_mapblock.cpp
Expand Up @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IMeshManipulator.h>
#include "gamedef.h"
#include "log.h"
#include "noise.h"


// Create a cuboid.
Expand Down Expand Up @@ -1104,45 +1105,174 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
break;}
case NDT_PLANTLIKE:
{
PseudoRandom rng(x<<8 | z | y<<16);

TileSpec tile = getNodeTileN(n, p, 0, data);
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;

u16 l = getInteriorLight(n, 1, nodedef);
video::SColor c = MapBlock_LightColor(255, l, f.light_source);

float s = BS / 2 * f.visual_scale;
// add sqrt(2) visual scale
if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x10) != 0))
s *= 1.41421;

float random_offset_X = .0;
float random_offset_Z = .0;
if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) {
random_offset_X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
random_offset_Z = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
}

for (int j = 0; j < 2; j++)
{
for (int j = 0; j < 4; j++) {
video::S3DVertex vertices[4] =
{
video::S3DVertex(-s,-BS/2, 0, 0,0,0, c, 0,1),
video::S3DVertex( s,-BS/2, 0, 0,0,0, c, 1,1),
video::S3DVertex( s,-BS/2 + s*2,0, 0,0,0, c, 1,0),
video::S3DVertex(-s,-BS/2 + s*2,0, 0,0,0, c, 0,0),
};

float rotate_degree = 0;
u8 p2mesh = 0;
if (f.param_type_2 == CPT2_DEGROTATE)
rotate_degree = n.param2 * 2;

if (j == 0) {
for(u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(46 + rotate_degree);
} else if (j == 1) {
for(u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(-44 + rotate_degree);
else if (f.param_type_2 != CPT2_MESHOPTIONS) {

This comment has been minimized.

Copy link
@HybridDog

HybridDog Sep 1, 2016

Contributor

@sofar degrotate is broken now:
screenshot_20160901_135009
l assume here shouldn't be an else

This comment has been minimized.

Copy link
@sofar

sofar Sep 7, 2016

Author Contributor

quite likely, yes, I'll see if that is the fix.

This comment has been minimized.

Copy link
@HybridDog

HybridDog Sep 8, 2016

Contributor

thanks

if (j == 0) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(46 + rotate_degree);
} else if (j == 1) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(-44 + rotate_degree);
}
} else {
p2mesh = n.param2 & 0x7;
switch (p2mesh) {
case 0:
// x
if (j == 0) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(46);
} else if (j == 1) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(-44);
}
break;
case 1:
// +
if (j == 0) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(91);
} else if (j == 1) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(1);
}
break;
case 2:
// *
if (j == 0) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(121);
} else if (j == 1) {
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(241);
} else { // (j == 2)
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(1);
}
break;
case 3:
// #
switch (j) {
case 0:
for (u16 i = 0; i < 4; i++) {
vertices[i].Pos.rotateXZBy(1);
vertices[i].Pos.Z += BS / 4;
}
break;
case 1:
for (u16 i = 0; i < 4; i++) {
vertices[i].Pos.rotateXZBy(91);
vertices[i].Pos.X += BS / 4;
}
break;
case 2:
for (u16 i = 0; i < 4; i++) {
vertices[i].Pos.rotateXZBy(181);
vertices[i].Pos.Z -= BS / 4;
}
break;
case 3:
for (u16 i = 0; i < 4; i++) {
vertices[i].Pos.rotateXZBy(271);
vertices[i].Pos.X -= BS / 4;
}
break;
}
break;
case 4:
// outward leaning #-like
switch (j) {
case 0:
for (u16 i = 2; i < 4; i++)
vertices[i].Pos.Z -= BS / 2;
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(1);
break;
case 1:
for (u16 i = 2; i < 4; i++)
vertices[i].Pos.Z -= BS / 2;
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(91);
break;
case 2:
for (u16 i = 2; i < 4; i++)
vertices[i].Pos.Z -= BS / 2;
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(181);
break;
case 3:
for (u16 i = 2; i < 4; i++)
vertices[i].Pos.Z -= BS / 2;
for (u16 i = 0; i < 4; i++)
vertices[i].Pos.rotateXZBy(271);
break;
}
break;
}
}

for (int i = 0; i < 4; i++)
{
for (int i = 0; i < 4; i++) {
vertices[i].Pos *= f.visual_scale;
vertices[i].Pos.Y += BS/2 * (f.visual_scale - 1);
vertices[i].Pos += intToFloat(p, BS);
// move to a random spot to avoid moire
if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) {
vertices[i].Pos.X += random_offset_X;
vertices[i].Pos.Z += random_offset_Z;
}
// randomly move each face up/down
if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x20) != 0)) {
PseudoRandom yrng(j | x<<16 | z<<8 | y<<24 );
vertices[i].Pos.Y -= BS * ((yrng.next() % 16 / 16.0) * 0.125);
}
}

u16 indices[] = {0, 1, 2, 2, 3, 0};
// Add to mesh collector
collector.append(tile, vertices, 4, indices, 6);

// stop adding faces for meshes with less than 4 faces
if (f.param_type_2 == CPT2_MESHOPTIONS) {
if (((p2mesh == 0) || (p2mesh == 1)) && (j == 1))
break;
else if ((p2mesh == 2) && (j == 2))
break;
} else if (j == 1) {
break;
}

}
break;}
case NDT_FIRELIKE:
Expand Down
4 changes: 3 additions & 1 deletion src/network/networkprotocol.h
Expand Up @@ -136,9 +136,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
backface_culling: backwards compatibility for playing with
newer client on pre-27 servers.
Add nodedef v3 - connected nodeboxes
PROTOCOL_VERSION 28:
CPT2_MESHOPTIONS
*/

#define LATEST_PROTOCOL_VERSION 27
#define LATEST_PROTOCOL_VERSION 28

// Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13
Expand Down
5 changes: 4 additions & 1 deletion src/nodedef.cpp
Expand Up @@ -387,7 +387,10 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
writeU8(os, param_type_2);
if ((protocol_version < 28) && (param_type_2 == CPT2_MESHOPTIONS))
writeU8(os, CPT2_NONE);
else
writeU8(os, param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
Expand Down
2 changes: 2 additions & 0 deletions src/nodedef.h
Expand Up @@ -65,6 +65,8 @@ enum ContentParamType2
CPT2_LEVELED,
// 2D rotation for things like plants
CPT2_DEGROTATE,
// Mesh options for plants
CPT2_MESHOPTIONS
};

enum LiquidType
Expand Down
1 change: 1 addition & 0 deletions src/script/cpp_api/s_node.cpp
Expand Up @@ -58,6 +58,7 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
{CPT2_WALLMOUNTED, "wallmounted"},
{CPT2_LEVELED, "leveled"},
{CPT2_DEGROTATE, "degrotate"},
{CPT2_MESHOPTIONS, "meshoptions"},
{0, NULL},
};

Expand Down

0 comments on commit e58a55a

Please sign in to comment.