Index: binaries/data/mods/public/maps/random/rmgen/painter/DunePainter.js =================================================================== --- binaries/data/mods/public/maps/random/rmgen/painter/DunePainter.js +++ binaries/data/mods/public/maps/random/rmgen/painter/DunePainter.js @@ -0,0 +1,48 @@ +/* +@param {Bool} type - ELEVATION_MODIFY or ELEVATION_SET +@param {Float} scale - global scale of dune size ( width and height) - higher values make dunes bigger +@param {Float} vertical_scale - scale of dune height - higher makes dunes taller +*/ +function DunePainter(type=ELEVATION_MODIFY, scale=1, vertical_scale=1){ + this.type = type; + this.scale = scale; + this.vertical_scale = vertical_scale; +} +/* +Dune base shape +@param {Float} - x [0,1] value +@param {Float} - xm [0,1] position of the dune crest +@param {Bool} - d true for dune false for dome +*/ +DunePainter.prototype.dune = function(x,crest_x=0.75,dune=true){ + if( x < crest_x ){ return (1.0-Math.cos(Math.PI*x/crest_x))*0.5; } + else{ if(dune){ return (1.0-Math.cos(Math.PI*(x-1.0)/(crest_x-1.0)))*0.5; } + else{ return 1.0-Math.cos(Math.PI*(x-1.0)/(crest_x-1.0)*0.5); } + } +} +DunePainter.prototype.paint = function(area){ + const points = area.getPoints(); + const length = points.length; + //1st dune layer + const h1_1 = perlin_noise(points,6,2,1,1.1,true); + const h1_2 = perlin_noise(points,3,2,1,1,true); + const L1 = 17.0*this.scale; + //2on dune layer + const h2_1 = perlin_noise(points,8,1,2,2,true); + const h2_2 = perlin_noise(points,4,2,2,2,true); + const L2 = 14.0*this.scale; + //loop all the points + for (var i = 0; i < length; i++){ + const X = points[i].x; + const Y = points[i].y; + //main dunes creation + const v1 = ((X+h1_1[i]*13+Y*0.1)%L1)/L1; + const h1 = this.dune(v1,0.60,false)*9*0.9 + h1_1[i]*h1_2[i]*150*0.1; + //secondary dunes + const v2 = ((X+h2_1[i]*13+Y*0.1)%L2)/L2; + const h2 = this.dune(v2,0.60,false)*9*0.9 + h2_2[i]*50*0.1; + const h = (h1*0.8 + h2*0.2)*this.vertical_scale*this.scale; + //add or set height + this.type ? g_Map.setHeight(points[i],g_Map.getHeight(points[i])+h) : g_Map.setHeight(points[i],h); + } +} \ No newline at end of file Index: binaries/data/mods/public/maps/random/rmgen/painter/PerlinPainter.js =================================================================== --- binaries/data/mods/public/maps/random/rmgen/painter/PerlinPainter.js +++ binaries/data/mods/public/maps/random/rmgen/painter/PerlinPainter.js @@ -0,0 +1,27 @@ +/* +@param {Bool} type - ELEVATION_MODIFY or ELEVATION_SET +@param {Array of Vector2D} points - Points +@param {Float >= 1} frequency - Noise size, higher value make noise more compact +@param {Int >= 1} octaves - Sub noise levels, higher the value gives noise more definition **can be as high as desired while the original frequcny doesng reach <1 +@param {Float} scale - Scale size of the perlin noise (in the three axis) +@param {Float} vertical_scale - Scale sizze of the perlin noise (in the vertical axis) +@param {Boolean} positive - Returns only on the range of [0,1] (in the case of default paremeters) +*/ +function PerlinPainter(type=ELEVATION_MODIFY, frequency = 25, octaves = 10, scale = 1, vertical_scale = 2, positive = true ){ + this.type = type; + this.frequency = frequency; + this.octaves = octaves; + this.scale = scale; + this.vertical_scale = vertical_scale; + this.positive = positive; +} +PerlinPainter.prototype.paint = function(area){ + const points = area.getPoints(); + const length = points.length; + const perlinHeights = perlin_noise(points,this.frequency,this.octaves,this.scale,this.vertical_scale,this.positive); + for (var i = 0; i < length; i++) + { + const h = perlinHeights[i]; + this.type ? g_Map.setHeight(points[i],g_Map.getHeight(points[i])+h) : g_Map.setHeight(points[i],h); + } +} \ No newline at end of file Index: binaries/data/mods/public/maps/random/rmgen/perlin_noise.js =================================================================== --- binaries/data/mods/public/maps/random/rmgen/perlin_noise.js +++ binaries/data/mods/public/maps/random/rmgen/perlin_noise.js @@ -0,0 +1,95 @@ + +/* +Perlin noise. Returns 1D array list of heights for each point given. With default paramenters returns in the range of [-1,1] +@param {Array of Vector2D} points - Points +@param {Float >= 1} frequency - Noise size, higher value make noise more compact +@param {Int >= 1} octaves - Sub noise levels, higher the value gives noise more definition **can be as high as desired while the original frequcny doesng reach <1 +@param {Float} scale - Scale size of the perlin noise (in the three axis) +@param {Float} vertical_scale - Scale sizze of the perlin noise (in the vertical axis) +@param {Boolean} positive - Returns only on the range of [0,1] (in the case of default paremeters) +@return {Array of floats} +*/ +function perlin_noise(points, frequency = 10 , octaves = 1, scale = 1, vertical_scale = 1, positive = false) +{ + const size = points.length; + let heights = Array(size).fill(0) + frequency /= scale + let weight = 1.0; + const frequency_multiplier = 1.333333; + const weight_multiplier = 0.75; + + for( let octave = 0; octave < octaves; octave++ ) + { + let noise2D = new Noise2D(frequency); + for (let i = 0; i < size; i++ ) + { + const ix = (points[i].x/256.0) % 1.0; + const iy = (points[i].y/256.0) % 1.0; + //noise2D gives values between [0.15,0.85] + //give range [-1,1] + let val = (noise2D.get(ix, iy) - 0.15)/0.7*2.0 - 1.0; + heights[i] += val*weight; + } + frequency *= frequency_multiplier; + weight *= weight_multiplier; + } + heights.forEach( (v,i,a) => { a[i] *= scale*vertical_scale } ) + + if(positive) + { + const hdisp = vertical_scale*scale*Array(octaves).fill().map( (e,i) => Math.pow(weight_multiplier,i+1) ).reduce( (a,b) => a+b ); + heights.forEach( (v,i,a) => { a[i] = (a[i]+hdisp)*0.5 } ) + } + + return heights +} + +/* +Perlin noise for individual points +*/ +function perlin_noise_point(frequency = 10 , octaves = 1, scale = 1, vertical_scale = 1, positive = false) +{ + this.frequency = frequency/scale + this.octaves = octaves + this.scale = scale + this.vertical_scale = vertical_scale + this.positive = positive + this.frequency_multiplier = 1.333333 + this.weight_multiplier = 0.75 + let frequency_i = this.frequency + let weight_i = 1.0 + + this.noise2D = [] + this.weights = [] + for( let octave = 0; octave < this.octaves; octave++ ) + { + this.noise2D.push( new Noise2D(frequency_i) ) + this.weights.push( weight_i ) + frequency_i *= this.frequency_multiplier + weight_i *= this.weight_multiplier + } + + this.hdisp = this.vertical_scale*this.scale*Array(this.octaves).fill().map( (e,i) => Math.pow(this.weight_multiplier,i+1) ).reduce( (a,b) => a+b ) +} + +perlin_noise_point.prototype.get = function(point) +{ + let height = 0; + for( let i = 0; i < this.octaves; i++ ) + { + const x = (point.x/256.0) % 1.0 + const y = (point.y/256.0) % 1.0 + //noise2D gives values between [0.15,0.85] + let val = this.noise2D[i].get(x,y) + //give range [-1,1] + val = ( val - 0.15 )/0.7*2.0 - 1.0 + height += val*this.weights[i]; + } + height *= this.scale*this.vertical_scale + + if(this.positive) + { + height = (height+this.hdisp)*0.5 + } + return height +} Index: binaries/data/mods/public/maps/random/rmgen/placer/noncentered/PolygonPlacer.js =================================================================== --- binaries/data/mods/public/maps/random/rmgen/placer/noncentered/PolygonPlacer.js +++ binaries/data/mods/public/maps/random/rmgen/placer/noncentered/PolygonPlacer.js @@ -0,0 +1,60 @@ +/* +Fills the inside of any polygon given 3 or more points - filling also works with degenerated and overlapping sections +*/ +function PolygonPlacer(points) +{ + this.points = points; + this.horiLine = function(p1,p2) + { + this.dy = p2.y-p1.y; + this.dx = p2.x-p1.x; + if(this.dy != 0){ this.idy = 1.0/this.dy; } + this.py = p1.y; + this.px = p1.x; + this.minx = Math.min(p1.x,p2.x); + } + this.horiLine.prototype.cross = function(p) + { + if(this.dy==0){ return false; } + if( p.x < this.minx){ return false; } + //0.000000000001131979327 added to fix a unknow artifact (doesn't crash but doesn't paint well if not added, unkown reason) + const t = (p.y-this.py)*this.idy+0.000000000001131979327; + const x = this.px + t*this.dx; + return p.x>=x && t>=0 && t<= 1; + } +}; +PolygonPlacer.prototype.isOdd = function(num){ return num%2; } +PolygonPlacer.prototype.place = function(constraint) +{ + //bounding box + let plength = this.points.length; + let xlist = this.points.map((v) => v.x).sort((a,b) => a-b); + let ylist = this.points.map((v) => v.y).sort((a,b) => a-b); + const minx = Math.floor( xlist[0] ); + const miny = Math.floor( ylist[0] ); + const maxx = Math.ceil( xlist[plength-1] ); + const maxy = Math.ceil( ylist[plength-1] ); + //make lines + let lines = []; + for (let i = 0; i < plength; i++) + { + lines.push( new this.horiLine(this.points[i%plength],this.points[(i+1)%plength]) ) + } + //check every possible point + let inpoints = []; + for (let x=minx; x v.cross(p)).length) ) + { + inpoints.push(p); + } + } + } + } + return inpoints; +}; \ No newline at end of file Index: binaries/data/mods/public/simulation/templates/special/filter/disableGarrisonHolder.xml =================================================================== --- binaries/data/mods/public/simulation/templates/special/filter/disableGarrisonHolder.xml +++ binaries/data/mods/public/simulation/templates/special/filter/disableGarrisonHolder.xml @@ -0,0 +1,4 @@ + + + +