Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 6 additions & 43 deletions modules/world-worldgen/src/biome_selector.zig
Original file line number Diff line number Diff line change
Expand Up @@ -258,49 +258,12 @@ pub fn selectBiomeWithConstraintsAndRiver(climate: ClimateParams, structural: St
// LOD-optimized Biome Functions (Issue #114)
// ============================================================================

/// Simplified biome selection for LOD2+ (no structural constraints).
/// Simplified biome selection for LOD2+ paths that only have climate params.
///
/// Intentionally excludes transition micro-biomes (foothills, marsh, dry_plains,
/// coastal_plains), special biomes (mushroom_fields, mangrove_swamp), beach,
/// and mountain variants. These are either rare, narrow-band, or structurally
/// dependent biomes that don't significantly affect distant terrain silhouette.
/// The full Voronoi selection handles them when chunks enter LOD0/LOD1 range.
/// Keep this aligned with the full registry scoring path so distant biome color
/// and material choices use the same climate, elevation, continentalness,
/// ruggedness, and ridge signals as LOD0 where structural height/slope filters
/// are not available.
pub fn selectBiomeSimple(climate: ClimateParams) BiomeId {
const heat = climate.temperature * 100.0;
const humidity = climate.humidity * 100.0;
const continental = climate.continentalness;

// Ocean check
if (continental < 0.35) {
if (heat <= 15) return .frozen_ocean;
if (heat <= 30) return .cold_ocean;
if (continental < 0.20) return .deep_ocean;
if (heat > 75 and humidity > 55) return .warm_ocean;
return .ocean;
}

if (continental < 0.48 and heat > 85 and humidity > 70) return .tropical;

// Simple land biome selection based on heat/humidity
if (heat < 20) {
return if (humidity > 50) .taiga else .snow_tundra;
} else if (heat < 40) {
return if (humidity > 60) .taiga else .plains;
} else if (heat < 60) {
return if (humidity > 70) .forest else .plains;
} else if (heat < 80) {
if (humidity > 70) {
return if (humidity > 85) .bamboo_jungle else .jungle;
}
if (humidity > 30) return if (climate.elevation > 0.55) .savanna_plateau else .savanna;
return .desert;
} else {
if (humidity > 85) return .bamboo_jungle;
if (humidity > 70) return .jungle;
if (humidity > 50) return .sparse_jungle;
if (humidity > 15 and humidity <= 30 and climate.elevation > 0.55) return .windswept_savanna;
if (humidity > 25) return .wooded_badlands;
if (humidity > 10) return .badlands;
return .desert;
}
return selectBiome(climate);
}
46 changes: 46 additions & 0 deletions modules/world-worldgen/src/biome_selector_tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,52 @@ test "selectBiomeSimple hot humid returns non-desert" {
try testing.expect(biome != .ocean);
}

test "selectBiomeSimple matches constrained selector for LOD-compatible samples" {
const Case = struct {
name: []const u8,
climate: ClimateParams,
structural: StructuralParams,
};

const cases = [_]Case{
.{
.name = "deep ocean",
.climate = .{ .temperature = 0.5, .humidity = 0.5, .elevation = 0.2, .continentalness = 0.10, .ruggedness = 0.1 },
.structural = .{ .height = 48, .slope = 1, .continentalness = 0.10, .ridge_mask = 0.0 },
},
.{
.name = "plains",
.climate = .{ .temperature = 0.5, .humidity = 0.45, .elevation = 0.35, .continentalness = 0.60, .ruggedness = 0.1 },
.structural = .{ .height = 70, .slope = 2, .continentalness = 0.60, .ridge_mask = 0.1 },
},
.{
.name = "jagged peaks",
.climate = .{ .temperature = 0.32, .humidity = 0.45, .elevation = 0.85, .continentalness = 0.85, .ruggedness = 0.85, .ridge_mask = 0.7 },
.structural = .{ .height = 150, .slope = 18, .continentalness = 0.85, .ridge_mask = 0.7 },
},
};

for (cases) |case| {
errdefer std.debug.print("failed LOD selector consistency case: {s}\n", .{case.name});
try testing.expectEqual(selectBiomeWithConstraints(case.climate, case.structural), selectBiomeSimple(case.climate));
}
}

test "selectBiomeSimple uses terrain signals beyond heat and humidity" {
const warm_dry = ClimateParams{
.temperature = 0.82,
.humidity = 0.25,
.elevation = 0.40,
.continentalness = 0.80,
.ruggedness = 0.10,
};
var rugged = warm_dry;
rugged.ruggedness = 0.75;

try testing.expectEqual(BiomeId.savanna, selectBiomeSimple(warm_dry));
try testing.expectEqual(BiomeId.badlands, selectBiomeSimple(rugged));
}

// ============================================================================
// BiomeSelection Structure Tests
// ============================================================================
Expand Down
4 changes: 2 additions & 2 deletions src/worldgen_tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -986,13 +986,13 @@ test "BiomeSource selectBiomeSimplified returns valid biome" {
const climate2 = biome_mod.ClimateParams{
.temperature = 0.5,
.humidity = 0.5,
.elevation = 0.4,
.elevation = 0.2,
.continentalness = 0.1,
.ruggedness = 0.2,
};

const result2 = source.selectBiomeSimplified(climate2);
try testing.expectEqual(result2, BiomeId.deep_ocean);
try testing.expectEqual(BiomeId.deep_ocean, result2);
}

test "BiomeSource getColor returns valid packed RGB" {
Expand Down
Loading