/**
* Copies the given heightmap to the given area.
* Scales the horizontal plane proportionally and applies bicubic interpolation.
* The heightrange is either scaled proportionally or mapped to the given heightrange.
*
* @param {Uint16Array} heightmap - One dimensional array of vertex heights.
* @param {number} [normalMinHeight] - The minimum height the elevation grid of 320 tiles would have.
* @param {number} [normalMaxHeight] - The maximum height the elevation grid of 320 tiles would have.
*/
function HeightmapPainter(heightmap, normalMinHeight = undefined, normalMaxHeight = undefined)
{
this.heightmap = heightmap;
this.bicubicInterpolation = bicubicInterpolation;
this.verticesPerSide = heightmap.length;
this.normalMinHeight = normalMinHeight;
this.normalMaxHeight = normalMaxHeight;
}
HeightmapPainter.prototype.getScale = function()
{
return this.verticesPerSide / (g_Map.getSize() + 1);
};
HeightmapPainter.prototype.scaleHeight = function(height)
{
if (this.normalMinHeight === undefined || this.normalMaxHeight === undefined)
return height / this.getScale() / HEIGHT_UNITS_PER_METRE;
let minHeight = this.normalMinHeight * (g_Map.getSize() + 1) / 321;
let maxHeight = this.normalMaxHeight * (g_Map.getSize() + 1) / 321;
return minHeight + (maxHeight - minHeight) * height / 0xFFFF;
};
HeightmapPainter.prototype.paint = function(area)
{
let scale = this.getScale();
let leftBottom = new Vector2D(0, 0);
let rightTop = new Vector2D(this.verticesPerSide, this.verticesPerSide);
let brushSize = new Vector2D(3, 3);
let brushCenter = new Vector2D(1, 1);
// Additional complexity to process all 4 vertices of each tile, i.e the last row too
let seen = new Array(g_Map.height.length).fill(0).map(zero => new Uint8Array(g_Map.height.length).fill(0));
for (let point of area.getPoints())
for (let vertex of g_TileVertices)
{
let vertexPos = Vector2D.add(point, vertex);
if (!g_Map.validHeight(vertexPos) || seen[vertexPos.x][vertexPos.y])
continue;
seen[vertexPos.x][vertexPos.y] = 1;
let sourcePos = Vector2D.mult(vertexPos, scale);
let sourceTilePos = sourcePos.clone().floor();
let brushPosition = Vector2D.max(
leftBottom,
Vector2D.min(
Vector2D.sub(sourceTilePos, brushCenter),
Vector2D.sub(rightTop, brushSize).sub(brushCenter)));
g_Map.setHeight(vertexPos, bicubicInterpolation(
Vector2D.sub(sourcePos, brushPosition).sub(brushCenter),
...getPointsInBoundingBox(getBoundingBox([brushPosition, Vector2D.add(brushPosition, brushSize)])).map(pos =>
this.scaleHeight(this.heightmap[pos.x][pos.y]))));
}
};