From 61dfa912f5f37f435e41b3c7d8cdb6244562e597 Mon Sep 17 00:00:00 2001
From: kwolekr <kwolekr@minetest.net>
Date: Sun, 28 Dec 2014 21:17:12 -0500
Subject: [PATCH] Ore: Add Vein ore type

---
 doc/lua_api.txt                 | 28 +++++++++++++--
 src/mg_ore.cpp                  | 60 ++++++++++++++++++++++++++++++---
 src/mg_ore.h                    | 24 ++++++++-----
 src/script/lua_api/l_mapgen.cpp | 13 +++++--
 4 files changed, 106 insertions(+), 19 deletions(-)

diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 8f491f5a8..7474c2bf4 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -563,9 +563,27 @@ All default ores are of the uniformly-distributed scatter type.
     clust_scarcity and clust_num_ores are ignored.
     This is essentially an improved version of the so-called "stratus" ore seen in some unofficial mods.
  - blob
-    Creates a roundish blob of ore according to 3d perlin noise described by noise_params. The maximum
-    size of the blob is clust_size, and clust_scarcity has the same meaning as with scatter type.
-
+    Creates a deformed sphere blobs of ore according to 3d perlin noise described by noise_params. The
+    maximum size of the blob is clust_size, and clust_scarcity has the same meaning as with scatter type.
+ - vein
+    Creates veins of ore varying in density by according to the intersection of two instances 3d perlin
+    noise with diffferent seeds both described by noise_params.  random_factor varies the influence random
+    chance has on placement of an ore inside the vein, which is 1 by default.  Note that modifying this
+    parameter may require adjusting noise_threshhold.  The parameters clust_scarcity, clust_num_ores, and
+    clust_size are ignored by this ore type.  This ore type is difficult to control since it is sensitive
+    to small changes.  The following is a decent set of parameters to work from:
+    noise_params = {
+        offset  = 0,
+        scale   = 3,
+        spread  = {x=200, y=200, z=200},
+        seed    = 5390,
+        octaves = 4,
+        persist = 0.5,
+        flags = "eased",
+    },
+    noise_threshhold = 1.6
+    WARNING:  Use this ore type *very* sparingly since it is ~200x more computationally expensive than
+    any other ore.
 
 Ore attributes
 -------------------
@@ -2717,6 +2735,10 @@ Ore definition (register_ore)
     noise_params = {offset=0, scale=1, spread={x=100, y=100, z=100}, seed=23, octaves=3, persist=0.70}
     ^ NoiseParams structure describing the perlin noise used for ore distribution.
     ^ Needed for sheet ore_type.  Omit from scatter ore_type for a uniform ore distribution
+    random_factor = 1.0,
+    ^ Multiplier of the randomness contribution to the noise value at any given point to
+    ^ decide if ore should be placed.  Set to 0 for solid veins. This parameter is only valid
+    ^ for ore_type == "vein".
 }
 
 Decoration definition (register_decoration)
diff --git a/src/mg_ore.cpp b/src/mg_ore.cpp
index 2c5712da7..95bc02f4f 100644
--- a/src/mg_ore.cpp
+++ b/src/mg_ore.cpp
@@ -27,10 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 const char *OreManager::ELEMENT_TITLE = "ore";
 
 FlagDesc flagdesc_ore[] = {
-	{"absheight",            OREFLAG_ABSHEIGHT},
-	{"scatter_noisedensity", OREFLAG_DENSITY},
-	{"claylike_nodeisnt",    OREFLAG_NODEISNT},
-	{NULL,                   0}
+	{"absheight", OREFLAG_ABSHEIGHT},
+	{NULL,        0}
 };
 
 
@@ -217,7 +215,7 @@ void OreBlob::generate(ManualMapVoxelManipulator *vm, int seed, u32 blockseed,
 	int volume = (nmax.X - nmin.X + 1) *
 				 (nmax.Y - nmin.Y + 1) *
 				 (nmax.Z - nmin.Z + 1);
-	int csize     = clust_size;
+	int csize  = clust_size;
 	int nblobs = volume / clust_scarcity;
 
 	if (!noise)
@@ -261,3 +259,55 @@ void OreBlob::generate(ManualMapVoxelManipulator *vm, int seed, u32 blockseed,
 		}
 	}
 }
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+OreVein::~OreVein()
+{
+	delete noise2;
+}
+
+
+void OreVein::generate(ManualMapVoxelManipulator *vm, int seed, u32 blockseed,
+	v3s16 nmin, v3s16 nmax)
+{
+	PseudoRandom pr(blockseed + 520);
+	MapNode n_ore(c_ore, 0, ore_param2);
+
+	if (!noise) {
+		int sx = nmax.X - nmin.X + 1;
+		int sy = nmax.Y - nmin.Y + 1;
+		int sz = nmax.Z - nmin.Z + 1;
+		noise  = new Noise(&np, seed, sx, sy, sz);
+		noise2 = new Noise(&np, seed + 436, sx, sy, sz);
+	}
+	bool noise_generated = false;
+
+	size_t index = 0;
+	for (int z = nmin.Z; z <= nmax.Z; z++)
+	for (int y = nmin.Y; y <= nmax.Y; y++)
+	for (int x = nmin.X; x <= nmax.X; x++, index++) {
+		u32 i = vm->m_area.index(x, y, z);
+		if (!vm->m_area.contains(i))
+			continue;
+		if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
+			continue;
+
+		// Same lazy generation optimization as in OreBlob
+		if (!noise_generated) {
+			noise_generated = true;
+			noise->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
+			noise2->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
+		}
+
+		// randval ranges from -1..1
+		float randval   = (float)pr.next() / (PSEUDORANDOM_MAX / 2) - 1.f;
+		float noiseval  = contour(noise->result[index]);
+		float noiseval2 = contour(noise2->result[index]);
+		if (noiseval * noiseval2 + randval * random_factor < nthresh)
+			continue;
+
+		vm->m_data[i] = n_ore;
+	}
+}
diff --git a/src/mg_ore.h b/src/mg_ore.h
index a20aeefe0..bd81a63fb 100644
--- a/src/mg_ore.h
+++ b/src/mg_ore.h
@@ -32,14 +32,6 @@ class ManualMapVoxelManipulator;
 
 // Use absolute value of height to determine ore placement
 #define OREFLAG_ABSHEIGHT 0x01
-
-// Use 3d noise to get density of ore placement, instead of just the position
-#define OREFLAG_DENSITY   0x02 // not yet implemented
-
-// For claylike ore types, place ore if the number of surrounding
-// nodes isn't the specified node
-#define OREFLAG_NODEISNT  0x04 // not yet implemented
-
 #define OREFLAG_USE_NOISE 0x08
 
 #define ORE_RANGE_ACTUAL 1
@@ -50,6 +42,7 @@ enum OreType {
 	ORE_TYPE_SCATTER,
 	ORE_TYPE_SHEET,
 	ORE_TYPE_BLOB,
+	ORE_TYPE_VEIN,
 };
 
 extern FlagDesc flagdesc_ore[];
@@ -105,6 +98,19 @@ class OreBlob : public Ore {
 		u32 blockseed, v3s16 nmin, v3s16 nmax);
 };
 
+class OreVein : public Ore {
+public:
+	static const bool NEEDS_NOISE = true;
+
+	float random_factor;
+	Noise *noise2;
+
+	virtual ~OreVein();
+
+	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
+		u32 blockseed, v3s16 nmin, v3s16 nmax);
+};
+
 class OreManager : public GenElementManager {
 public:
 	static const char *ELEMENT_TITLE;
@@ -122,6 +128,8 @@ class OreManager : public GenElementManager {
 			return new OreSheet;
 		case ORE_TYPE_BLOB:
 			return new OreBlob;
+		case ORE_TYPE_VEIN:
+			return new OreVein;
 		default:
 			return NULL;
 		}
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index 8c81412b1..c0a58305b 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -68,9 +68,10 @@ struct EnumString ModApiMapgen::es_MapgenObject[] =
 
 struct EnumString ModApiMapgen::es_OreType[] =
 {
-	{ORE_TYPE_SCATTER,  "scatter"},
-	{ORE_TYPE_SHEET,    "sheet"},
-	{ORE_TYPE_BLOB,     "blob"},
+	{ORE_TYPE_SCATTER, "scatter"},
+	{ORE_TYPE_SHEET,   "sheet"},
+	{ORE_TYPE_BLOB,    "blob"},
+	{ORE_TYPE_VEIN,    "vein"},
 	{0, NULL},
 };
 
@@ -680,6 +681,12 @@ int ModApiMapgen::l_register_ore(lua_State *L)
 	}
 	lua_pop(L, 1);
 
+	if (oretype == ORE_TYPE_VEIN) {
+		OreVein *orevein = (OreVein *)ore;
+		orevein->random_factor = getfloatfield_default(L, index,
+			"random_factor", 1.f);
+	}
+
 	u32 id = oremgr->add(ore);
 	if (id == (u32)-1) {
 		delete ore;
-- 
GitLab