|
|
|
@ -16,18 +16,22 @@ import org.pmw.tinylog.Logger;
@@ -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<Integer, short[][]> _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 {
@@ -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 {
@@ -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 {
@@ -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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|