Line data Source code
1 : /** 2 : * Copies the given heightmap to the given area. 3 : * Scales the horizontal plane proportionally and applies bicubic interpolation. 4 : * The heightrange is either scaled proportionally or mapped to the given heightrange. 5 : * 6 : * @param {Uint16Array} heightmap - One dimensional array of vertex heights. 7 : * @param {number} [normalMinHeight] - The minimum height the elevation grid of 320 tiles would have. 8 : * @param {number} [normalMaxHeight] - The maximum height the elevation grid of 320 tiles would have. 9 : */ 10 : function HeightmapPainter(heightmap, normalMinHeight = undefined, normalMaxHeight = undefined) 11 : { 12 0 : this.heightmap = heightmap; 13 0 : this.bicubicInterpolation = bicubicInterpolation; 14 0 : this.verticesPerSide = heightmap.length; 15 0 : this.normalMinHeight = normalMinHeight; 16 0 : this.normalMaxHeight = normalMaxHeight; 17 : } 18 : 19 6 : HeightmapPainter.prototype.getScale = function() 20 : { 21 0 : return this.verticesPerSide / (g_Map.getSize() + 1); 22 : }; 23 : 24 6 : HeightmapPainter.prototype.scaleHeight = function(height) 25 : { 26 0 : if (this.normalMinHeight === undefined || this.normalMaxHeight === undefined) 27 0 : return height / this.getScale() / HEIGHT_UNITS_PER_METRE; 28 : 29 0 : let minHeight = this.normalMinHeight * (g_Map.getSize() + 1) / 321; 30 0 : let maxHeight = this.normalMaxHeight * (g_Map.getSize() + 1) / 321; 31 : 32 0 : return minHeight + (maxHeight - minHeight) * height / 0xFFFF; 33 : }; 34 : 35 6 : HeightmapPainter.prototype.paint = function(area) 36 : { 37 0 : let scale = this.getScale(); 38 0 : let leftBottom = new Vector2D(0, 0); 39 0 : let rightTop = new Vector2D(this.verticesPerSide, this.verticesPerSide); 40 0 : let brushSize = new Vector2D(3, 3); 41 0 : let brushCenter = new Vector2D(1, 1); 42 : 43 : // Additional complexity to process all 4 vertices of each tile, i.e the last row too 44 0 : let seen = new Array(g_Map.height.length).fill(0).map(zero => new Uint8Array(g_Map.height.length).fill(0)); 45 : 46 0 : for (let point of area.getPoints()) 47 0 : for (let vertex of g_TileVertices) 48 : { 49 0 : let vertexPos = Vector2D.add(point, vertex); 50 : 51 0 : if (!g_Map.validHeight(vertexPos) || seen[vertexPos.x][vertexPos.y]) 52 0 : continue; 53 : 54 0 : seen[vertexPos.x][vertexPos.y] = 1; 55 : 56 0 : let sourcePos = Vector2D.mult(vertexPos, scale); 57 0 : let sourceTilePos = sourcePos.clone().floor(); 58 : 59 0 : let brushPosition = Vector2D.max( 60 : leftBottom, 61 : Vector2D.min( 62 : Vector2D.sub(sourceTilePos, brushCenter), 63 : Vector2D.sub(rightTop, brushSize).sub(brushCenter))); 64 : 65 0 : g_Map.setHeight(vertexPos, bicubicInterpolation( 66 : Vector2D.sub(sourcePos, brushPosition).sub(brushCenter), 67 : ...getPointsInBoundingBox(getBoundingBox([brushPosition, Vector2D.add(brushPosition, brushSize)])).map(pos => 68 0 : this.scaleHeight(this.heightmap[pos.x][pos.y])))); 69 : } 70 : };