Line data Source code
1 : /** 2 : * Applies smoothing to the given area using Inverse-Distance-Weighting / Shepard's method. 3 : * 4 : * @param {Number} size - Determines the number of neighboring heights to interpolate. The area is a square with the length twice this size. 5 : * @param {Number} strength - Between 0 (no effect) and 1 (only neighbor heights count). This parameter has the lowest performance impact. 6 : * @param {Number} iterations - How often the process should be repeated. Typically 1. Can be used to gain even more smoothing. 7 : */ 8 : function SmoothingPainter(size, strength, iterations) 9 : { 10 1 : if (size < 1) 11 0 : throw new Error("Invalid size: " + size); 12 : 13 1 : if (strength <= 0 || strength > 1) 14 0 : throw new Error("Invalid strength: " + strength); 15 : 16 1 : if (iterations <= 0) 17 0 : throw new Error("Invalid iterations: " + iterations); 18 : 19 1 : this.size = Math.floor(size); 20 1 : this.strength = strength; 21 1 : this.iterations = iterations; 22 : } 23 : 24 6 : SmoothingPainter.prototype.paint = function(area) 25 : { 26 1 : let brushPoints = getPointsInBoundingBox(getBoundingBox( 27 2 : new Array(2).fill(0).map((zero, i) => new Vector2D(1, 1).mult(this.size).mult(i ? 1 : -1)))); 28 : 29 1 : for (let i = 0; i < this.iterations; ++i) 30 : { 31 1 : let heightmap = clone(g_Map.height); 32 : 33 : // Additional complexity to process all 4 vertices of each tile, i.e the last row too 34 513 : let seen = new Array(heightmap.length).fill(0).map(zero => new Uint8Array(heightmap.length).fill(0)); 35 : 36 1 : for (let point of area.getPoints()) 37 9 : for (let tileVertex of g_TileVertices) 38 : { 39 36 : let vertex = Vector2D.add(point, tileVertex); 40 36 : if (!g_Map.validHeight(vertex) || seen[vertex.x][vertex.y]) 41 20 : continue; 42 : 43 16 : seen[vertex.x][vertex.y] = 1; 44 : 45 16 : let sumWeightedHeights = 0; 46 16 : let sumWeights = 0; 47 : 48 16 : for (let brushPoint of brushPoints) 49 : { 50 400 : let position = Vector2D.add(vertex, brushPoint); 51 400 : let distance = Math.abs(brushPoint.x) + Math.abs(brushPoint.y); 52 400 : if (!distance || !g_Map.validHeight(position)) 53 16 : continue; 54 : 55 384 : sumWeightedHeights += g_Map.getHeight(position) / distance; 56 384 : sumWeights += 1 / distance; 57 : } 58 : 59 16 : g_Map.setHeight( 60 : vertex, 61 : this.strength * sumWeightedHeights / sumWeights + 62 : (1 - this.strength) * g_Map.getHeight(vertex)); 63 : } 64 : } 65 : };