forked from MagicBane/Server
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
5.4 KiB
164 lines
5.4 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
package engine.InterestManagement; |
|
|
|
import engine.gameManager.ZoneManager; |
|
import engine.math.Vector2f; |
|
import engine.math.Vector3fImmutable; |
|
import engine.objects.Zone; |
|
import org.pmw.tinylog.Logger; |
|
|
|
import java.util.HashMap; |
|
|
|
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 int heightmap; |
|
|
|
public Terrain(Zone zone) { |
|
|
|
this.zone = zone; |
|
|
|
this.heightmap = this.zone.terrain_image; |
|
|
|
// Configure PLANAR |
|
|
|
if (this.zone.terrain_type.equals("PLANAR")) |
|
this.heightmap = 1006300; |
|
|
|
this.terrain_size.x = this.zone.major_radius * 2; |
|
this.terrain_size.y = this.zone.minor_radius * 2; |
|
|
|
this.terrain_pixel_data = Terrain._heightmap_pixel_cache.get(heightmap); |
|
|
|
if (terrain_pixel_data == null) |
|
Logger.error("Pixel map empty for zone: " + zone.getObjectUUID() + ":" + zone.zoneName); |
|
|
|
this.cell_count.x = this.terrain_pixel_data.length - 1; |
|
this.cell_count.y = this.terrain_pixel_data[0].length - 1; |
|
|
|
this.cell_size.x = terrain_size.x / this.cell_count.x; |
|
this.cell_size.y = terrain_size.y / this.cell_count.y; |
|
|
|
this.terrain_scale = this.zone.terrain_max_y / 255f; |
|
|
|
} |
|
|
|
public static Zone getNextZoneWithTerrain(Zone zone) { |
|
|
|
Zone terrain_zone = zone; |
|
|
|
if (zone == null) |
|
return ZoneManager.getSeaFloor(); |
|
|
|
if (zone.terrain != null) |
|
return zone; |
|
|
|
if (zone.equals(ZoneManager.getSeaFloor())) |
|
return zone; |
|
|
|
while (terrain_zone.terrain == null) |
|
terrain_zone = terrain_zone.parent; |
|
|
|
return terrain_zone; |
|
} |
|
|
|
public static float getWorldHeight(Zone currentZone, Vector3fImmutable worldLoc) { |
|
|
|
Zone terrainZone; |
|
|
|
// 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); |
|
|
|
// Transform world loc into zone space coordinate system |
|
|
|
Vector2f terrainLoc = ZoneManager.worldToZoneSpace(worldLoc, terrainZone); |
|
|
|
// Interpolate height for this position using pixel array. |
|
|
|
float interpolatedTerrainHeight = terrainZone.terrain.getInterpolatedTerrainHeight(terrainLoc); |
|
interpolatedTerrainHeight += terrainZone.worldAltitude; |
|
|
|
return interpolatedTerrainHeight; |
|
|
|
} |
|
|
|
public static float getWorldHeight(Vector3fImmutable worldLoc) { |
|
|
|
Zone currentZone = ZoneManager.findSmallestZone(worldLoc); |
|
|
|
if (currentZone == null) |
|
return 0; |
|
|
|
return getWorldHeight(currentZone, worldLoc); |
|
|
|
} |
|
|
|
public Vector2f getTerrainCell(Vector2f terrainLoc) { |
|
|
|
Vector2f terrain_cell = new Vector2f(terrainLoc.x / this.cell_size.x, terrainLoc.y / this.cell_size.y); |
|
|
|
// Clamp values when standing directly on max pole |
|
|
|
if (terrain_cell.x >= this.cell_count.x) |
|
terrain_cell.x = terrain_cell.x - 1; |
|
|
|
if (terrain_cell.x >= this.cell_count.y) |
|
terrain_cell.y = terrain_cell.y - 1; |
|
|
|
return terrain_cell; |
|
} |
|
|
|
public float getInterpolatedTerrainHeight(Vector2f terrainLoc) { |
|
|
|
float interpolatedHeight; |
|
|
|
Vector2f terrain_cell = getTerrainCell(terrainLoc); |
|
|
|
int gridX = (int) Math.floor(terrain_cell.x); |
|
int gridY = (int) Math.floor(terrain_cell.y); |
|
|
|
float offsetX = terrain_cell.x % 1; |
|
float offsetY = terrain_cell.y % 1; |
|
|
|
//get 4 surrounding vertices from the pixel array. |
|
|
|
float topLeftHeight; |
|
float topRightHeight; |
|
float bottomLeftHeight; |
|
float bottomRightHeight; |
|
|
|
topLeftHeight = terrain_pixel_data[gridX][gridY]; |
|
topRightHeight = terrain_pixel_data[gridX + 1][gridY]; |
|
bottomLeftHeight = terrain_pixel_data[gridX][gridY + 1]; |
|
bottomRightHeight = terrain_pixel_data[gridX + 1][gridY + 1]; |
|
|
|
// Interpolate between the 4 vertices |
|
|
|
interpolatedHeight = topRightHeight * (1 - offsetY) * (offsetX); |
|
interpolatedHeight += (bottomRightHeight * offsetY * offsetX); |
|
interpolatedHeight += (bottomLeftHeight * (1 - offsetX) * offsetY); |
|
interpolatedHeight += (topLeftHeight * (1 - offsetX) * (1 - offsetY)); |
|
|
|
interpolatedHeight *= this.terrain_scale; // Scale height |
|
|
|
return interpolatedHeight; |
|
} |
|
}
|
|
|