Make plantlike drawtype more fun
authorAuke Kok <sofar@foo-projects.org>
Fri, 11 Dec 2015 06:58:11 +0000 (22:58 -0800)
committerparamat <mat.gregory@virginmedia.com>
Fri, 26 Aug 2016 04:26:08 +0000 (05:26 +0100)
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)

doc/lua_api.txt
src/content_mapblock.cpp
src/network/networkprotocol.h
src/nodedef.cpp
src/nodedef.h
src/script/cpp_api/s_node.cpp

index 38f19aadc44e019fd7dcdec17c0b1a6fb3fb9ada..440edd963f3b298177e2465c3c848481781823f0 100644 (file)
@@ -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 = {
index 6a83bd8f3821b47c260fd052ffd58f5348dccbbd..b86b97822bcb81ade36de635bb51c940224768d7 100644 (file)
@@ -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.
@@ -1104,6 +1105,8 @@ 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;
 
@@ -1111,9 +1114,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                        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),
@@ -1121,28 +1133,146 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                        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) {
+                                       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:
index 3a9483efbfa15c0fd8a34845ed2319aef1da5398..e3fcae0c68710ddaaefdac20302a7c088fcc4aa4 100644 (file)
@@ -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
index 764203efcf4ee9c65119a059e88dc649ce1d16fd..646375575d5483946feffe719c3fd9490855ce29 100644 (file)
@@ -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);
index 1c2f792d8a2a841d4488cbfd1829caebae53b9d6..f17c53727a6393e5a36688f4fcef795e9267bc9b 100644 (file)
@@ -65,6 +65,8 @@ enum ContentParamType2
        CPT2_LEVELED,
        // 2D rotation for things like plants
        CPT2_DEGROTATE,
+       // Mesh options for plants
+       CPT2_MESHOPTIONS
 };
 
 enum LiquidType
index 17f0f0dac3be395ba7b0cd049351534ad2dcaf17..379ed773f3b69c692d2cddf086ffd73da8b4d021 100644 (file)
@@ -58,6 +58,7 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
                {CPT2_WALLMOUNTED, "wallmounted"},
                {CPT2_LEVELED, "leveled"},
                {CPT2_DEGROTATE, "degrotate"},
+               {CPT2_MESHOPTIONS, "meshoptions"},
                {0, NULL},
        };