diff --git a/src/engine/InterestManagement/Terrain.java b/src/engine/InterestManagement/Terrain.java index cd5423d7..21ea9849 100644 --- a/src/engine/InterestManagement/Terrain.java +++ b/src/engine/InterestManagement/Terrain.java @@ -16,18 +16,22 @@ import org.pmw.tinylog.Logger; import java.util.HashMap; +import static java.lang.Math.PI; + public class Terrain { // Class variables public static final HashMap _heightmap_pixel_cache = new HashMap<>(); - Zone zone; public short[][] terrain_pixel_data; public Vector2f terrain_size = new Vector2f(); public Vector2f cell_size = new Vector2f(); public Vector2f cell_count = new Vector2f(); public float terrain_scale; + public float min_blend; + public float max_blend; public int heightmap; + Zone zone; public Terrain(Zone zone) { @@ -54,6 +58,9 @@ public class Terrain { this.cell_size.x = terrain_size.x / this.cell_count.x; this.cell_size.y = terrain_size.y / this.cell_count.y; + this.max_blend = this.zone.max_blend / this.zone.major_radius; + this.min_blend = this.zone.min_blend / this.zone.minor_radius; + this.terrain_scale = this.zone.terrain_max_y / 255f; } @@ -80,22 +87,34 @@ public class Terrain { public static float getWorldHeight(Zone currentZone, Vector3fImmutable worldLoc) { Zone terrainZone; + Zone parentZone; // Retrieve the next zone with a heightmap attached. // Zones without a heightmap use the next zone up the // tree to calculate heights from. terrainZone = getNextZoneWithTerrain(currentZone); + parentZone = getNextZoneWithTerrain(currentZone.parent); // Transform world loc into zone space coordinate system Vector2f terrainLoc = ZoneManager.worldToZoneSpace(worldLoc, terrainZone); + Vector2f parentLoc = ZoneManager.worldToZoneSpace(worldLoc, parentZone); - // Interpolate height for this position using pixel array. + // Interpolate height for this position in terrain float interpolatedTerrainHeight = terrainZone.terrain.getInterpolatedTerrainHeight(terrainLoc); interpolatedTerrainHeight += terrainZone.worldAltitude; + // Interpolate height for this position in parent + + float interpolatedParentTerrainHeight = parentZone.terrain.getInterpolatedTerrainHeight(parentLoc); + interpolatedParentTerrainHeight += parentZone.worldAltitude; + + // Blend between heights + + interpolatedTerrainHeight = interpolatedTerrainHeight + interpolatedParentTerrainHeight * (1 - terrainZone.terrain.heightBlend(terrainLoc)); + return interpolatedTerrainHeight; } @@ -161,4 +180,47 @@ public class Terrain { return interpolatedHeight; } + + public float heightBlend(Vector2f terrainLoc) { + + // Normalize terrain loc + + Vector2f normalizedLoc = new Vector2f(terrainLoc.x / this.terrain_size.x, + terrainLoc.y / terrain_size.y); + + float minp = this.zone.min_blend / this.zone.major_radius; + float maxp = this.zone.max_blend / this.zone.major_radius; + + float xval; + + if (minp > 0.4f) + xval = minp; + else + xval = Math.min(maxp, 0.4f); + + float minpy = this.zone.min_blend / this.zone.minor_radius; + float maxpy = this.zone.max_blend / this.zone.minor_radius; + + float yval; + + if (minpy > 0.4f) + yval = minpy; + else + yval = Math.min(maxpy, 0.4f); + + float value; + + if (normalizedLoc.x <= 1 - xval || normalizedLoc.x <= normalizedLoc.y) { + + if (normalizedLoc.x < 1 - yval) + return 1; + + value = (normalizedLoc.y - (1 - yval)) / yval; + } else + value = (normalizedLoc.x - (1 - xval)) / xval; + + value = (float) Math.atan((0.5f - value) * PI); + + return (value + 1) * 0.5f; + } }