Allow configuring leaf radius and tree height independently.

fixes #519
This commit is contained in:
IntegratedQuantum 2024-07-02 10:23:31 +02:00
parent 02fff0fd4c
commit d2bc6e6428
6 changed files with 142 additions and 102 deletions

View File

@ -22,9 +22,11 @@
"log" : "cubyz:oak_log",
"top" : "cubyz:oak_top",
"chance" : 0.01,
"type" : "bush",
"height" : 4,
"height_variation" : 6
"type" : "round",
"height" : 1,
"height_variation" : 1,
"leafRadius" : 2,
"leafRadius_variation" : 1,
},
{
"id" : "cubyz:ground_patch",

View File

@ -34,8 +34,10 @@
"top" : "cubyz:birch_top",
"chance" : 0.01,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3.5,
"leafRadius_variation" : 1.5
},
{
"id" : "cubyz:fallen_tree",

View File

@ -22,8 +22,10 @@
"top" : "cubyz:chalk/aqua",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -32,8 +34,10 @@
"top" : "cubyz:chalk/black",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -42,8 +46,10 @@
"top" : "cubyz:chalk/blue",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -52,8 +58,10 @@
"top" : "cubyz:chalk/brown",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -62,8 +70,10 @@
"top" : "cubyz:chalk/crimson",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -72,8 +82,10 @@
"top" : "cubyz:chalk/cyan",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -82,8 +94,10 @@
"top" : "cubyz:chalk/dark_grey",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -92,8 +106,10 @@
"top" : "cubyz:chalk/green",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -102,8 +118,10 @@
"top" : "cubyz:chalk/grey",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -112,8 +130,10 @@
"top" : "cubyz:chalk/indigo",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -122,8 +142,10 @@
"top" : "cubyz:chalk/lime",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -132,8 +154,10 @@
"top" : "cubyz:chalk/magenta",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -142,8 +166,10 @@
"top" : "cubyz:chalk/orange",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -152,8 +178,10 @@
"top" : "cubyz:chalk/pink",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -162,8 +190,10 @@
"top" : "cubyz:chalk/purple",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -172,8 +202,10 @@
"top" : "cubyz:chalk/red",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -182,8 +214,10 @@
"top" : "cubyz:chalk/violet",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -192,8 +226,10 @@
"top" : "cubyz:chalk/viridian",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -202,8 +238,10 @@
"top" : "cubyz:chalk/white",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -212,8 +250,10 @@
"top" : "cubyz:chalk/yellow",
"chance" : 0.0005,
"type" : "round",
"height" : 6,
"height_variation" : 3
"height" : 10,
"height_variation" : 5,
"leafRadius" : 3,
"leafRadius_variation" : 3
},
]
}

View File

@ -23,7 +23,9 @@
"chance" : 0.001,
"type" : "round",
"height" : 12,
"height_variation" : 10
"height_variation" : 10,
"leafRadius" : 5,
"leafRadius_variation" : 6
}
],

View File

@ -35,9 +35,11 @@
"log" : "cubyz:fog/red",
"top" : "cubyz:fog/red",
"chance" : 0.01,
"type" : "bush",
"height" : 32,
"height_variation" : 3
"type" : "round",
"height" : 0,
"height_variation" : 0,
"leafRadius" : 16,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -45,9 +47,11 @@
"log" : "cubyz:fog/green",
"top" : "cubyz:fog/green",
"chance" : 0.01,
"type" : "bush",
"height" : 32,
"height_variation" : 3
"type" : "round",
"height" : 0,
"height_variation" : 0,
"leafRadius" : 16,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -55,9 +59,11 @@
"log" : "cubyz:fog/blue",
"top" : "cubyz:fog/blue",
"chance" : 0.01,
"type" : "bush",
"height" : 32,
"height_variation" : 3
"type" : "round",
"height" : 0,
"height_variation" : 0,
"leafRadius" : 16,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -65,9 +71,11 @@
"log" : "cubyz:fog/yellow",
"top" : "cubyz:fog/yellow",
"chance" : 0.01,
"type" : "bush",
"height" : 32,
"height_variation" : 3
"type" : "round",
"height" : 0,
"height_variation" : 0,
"leafRadius" : 16,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -75,9 +83,11 @@
"log" : "cubyz:fog/cyan",
"top" : "cubyz:fog/cyan",
"chance" : 0.01,
"type" : "bush",
"height" : 32,
"height_variation" : 3
"type" : "round",
"height" : 0,
"height_variation" : 0,
"leafRadius" : 16,
"leafRadius_variation" : 3
},
{
"id" : "cubyz:simple_tree",
@ -85,9 +95,11 @@
"log" : "cubyz:fog/magenta",
"top" : "cubyz:fog/magenta",
"chance" : 0.01,
"type" : "bush",
"height" : 32,
"height_variation" : 3
"type" : "round",
"height" : 0,
"height_variation" : 0,
"leafRadius" : 16,
"leafRadius_variation" : 3
},
]
}

View File

@ -18,7 +18,6 @@ const SimpleTreeModel = @This();
const Type = enum {
pyramid,
round,
bush,
};
typ: Type,
@ -27,17 +26,24 @@ woodBlock: u16,
topWoodBlock: u16,
height0: i32,
deltaHeight: u31,
leafRadius: f32,
deltaLeafRadius: f32,
branched: bool,
pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: JsonElement) *SimpleTreeModel {
const self = arenaAllocator.create(SimpleTreeModel);
self.* = .{
.typ = std.meta.stringToEnum(Type, parameters.get([]const u8, "type", "")) orelse .round,
.typ = std.meta.stringToEnum(Type, parameters.get([]const u8, "type", "")) orelse blk: {
if(parameters.get(?[]const u8, "type", null)) |typ| std.log.err("Unknown tree type \"{s}\"", .{typ});
break :blk .round;
},
.leavesBlock = main.blocks.getByID(parameters.get([]const u8, "leaves", "cubyz:oak_leaves")),
.woodBlock = main.blocks.getByID(parameters.get([]const u8, "log", "cubyz:oak_log")),
.topWoodBlock = main.blocks.getByID(parameters.get([]const u8, "top", "cubyz:oak_top")),
.height0 = parameters.get(i32, "height", 6),
.deltaHeight = parameters.get(u31, "height_variation", 3),
.leafRadius = parameters.get(f32, "leafRadius", (1 + parameters.get(f32, "height", 6))/2),
.deltaLeafRadius = parameters.get(f32, "leafRadius_variation", parameters.get(f32, "height_variation", 3)/2),
.branched = parameters.get(bool, "branched", true),
};
return self;
@ -78,7 +84,9 @@ pub fn generateBranch(self: *SimpleTreeModel, x: i32, y: i32, z: i32, d: u32, ch
}
pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void {
var height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight);
const factor = random.nextFloat(seed);
var height = self.height0 + @as(i32, @intFromFloat(factor*@as(f32, @floatFromInt(self.deltaHeight))));
const leafRadius = self.leafRadius + factor*self.deltaLeafRadius;
if(z + height >= caveMap.findTerrainChangeAbove(x, y, z)) // Space is too small.Allocator
return;
@ -116,17 +124,16 @@ pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chu
.round => {
self.generateStem(x, y, z, height, chunk, seed);
const leafRadius = 1 + @divFloor(height, 2);
const floatLeafRadius = @as(f32, @floatFromInt(leafRadius)) - random.nextFloat(seed);
const radiusSqr: i32 = @intFromFloat(floatLeafRadius*floatLeafRadius);
const randomRadiusSqr: i32 = @intFromFloat((floatLeafRadius - 0.25)*(floatLeafRadius - 0.25));
const ceilRadius: i32 = @intFromFloat(@ceil(leafRadius));
const radiusSqr: i32 = @intFromFloat(leafRadius*leafRadius);
const randomRadiusSqr: i32 = @intFromFloat((leafRadius - 0.25)*(leafRadius - 0.25));
const center = z + height;
var pz = chunk.startIndex(center - leafRadius);
while(pz < center + leafRadius) : (pz += chunk.super.pos.voxelSize) {
var px = chunk.startIndex(x - leafRadius);
while(px < x + leafRadius) : (px += chunk.super.pos.voxelSize) {
var py = chunk.startIndex(y - leafRadius);
while(py < y + leafRadius) : (py += chunk.super.pos.voxelSize) {
var pz = chunk.startIndex(center - ceilRadius);
while(pz < center + ceilRadius) : (pz += chunk.super.pos.voxelSize) {
var px = chunk.startIndex(x - ceilRadius);
while(px < x + ceilRadius) : (px += chunk.super.pos.voxelSize) {
var py = chunk.startIndex(y - ceilRadius);
while(py < y + ceilRadius) : (py += chunk.super.pos.voxelSize) {
const distSqr = (pz - center)*(pz - center) + (px - x)*(px - x) + (py - y)*(py - y);
if(chunk.liesInChunk(px, py, pz) and distSqr < radiusSqr and (distSqr < randomRadiusSqr or random.nextInt(u1, seed) != 0)) { // TODO: Use another seed to make this more reliable!
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
@ -135,30 +142,5 @@ pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chu
}
}
},
.bush => {
const oldHeight = height;
height = @min(2, height); // Make sure the stem of the bush stays small.
self.generateStem(x, y, z, height, chunk, seed);
const leafRadius = 1 + @divFloor(oldHeight, 2);
const floatLeafRadius = @as(f32, @floatFromInt(leafRadius)) - random.nextFloat(seed);
const radiusSqr: i32 = @intFromFloat(floatLeafRadius*floatLeafRadius);
const randomRadiusSqr: i32 = @intFromFloat((floatLeafRadius - 0.25)*(floatLeafRadius - 0.25));
const center = z + height;
var pz = chunk.startIndex(center - leafRadius);
while(pz < center + leafRadius) : (pz += chunk.super.pos.voxelSize) {
var px = chunk.startIndex(x - leafRadius);
while(px < x + leafRadius) : (px += chunk.super.pos.voxelSize) {
var py = chunk.startIndex(y - leafRadius);
while(py < y + leafRadius) : (py += chunk.super.pos.voxelSize) {
const distSqr = (pz - center)*(pz - center) + (px - x)*(px - x) + (py - y)*(py - y);
if(chunk.liesInChunk(px, py, pz) and distSqr < radiusSqr and (distSqr < randomRadiusSqr or random.nextInt(u1, seed) != 0)) { // TODO: Use another seed to make this more reliable!
chunk.updateBlockIfDegradable(px, py, pz, .{.typ = self.leavesBlock, .data = 0}); // TODO: Natural standard.
}
}
}
}
}
}
}