diff --git a/biome-ui.js b/biome-ui.js index eefd3da..96d5c7d 100644 --- a/biome-ui.js +++ b/biome-ui.js @@ -36,14 +36,17 @@ const cellColors = [ ]; // Min. and max. mathematically possible values for heat and humidity -let limit_min, limit_max; +let limit_heat_min, limit_heat_max; +let limit_humidity_min, limit_humidity_max; // Draw area. Slightly larger than the value area to avoid // ugly edge rendering problems const DRAW_OFFSET = 10 -let draw_min, draw_max; +let draw_heat_min, draw_heat_max; +let draw_humidity_min, draw_humidity_max; // The point that is considered the middle of heat/humidity; // mathematically this value is the most probable. -let midpoint; +let midpoint_heat; +let midpoint_humidity; // Biome noise settings const NOISE_OFFSET_DEFAULT = 50; @@ -51,25 +54,41 @@ const NOISE_SCALE_DEFAULT = 50; const NOISE_PERSISTENCE_DEFAULT = 0.5; const NOISE_OCTAVES_DEFAULT = 3; const NOISE_ABSVALUE_DEFAULT = false; -let noiseOffset = NOISE_OFFSET_DEFAULT; -let noiseScale = NOISE_SCALE_DEFAULT; -let noiseOctaves = NOISE_OCTAVES_DEFAULT; -let noisePersistence = NOISE_PERSISTENCE_DEFAULT; -let noiseAbsvalue = NOISE_ABSVALUE_DEFAULT; -function updateAreaVars() { - let is_absolute = noiseAbsvalue === true +let noises = { + heat: { + offset: NOISE_OFFSET_DEFAULT, + scale: NOISE_SCALE_DEFAULT, + octaves: NOISE_OCTAVES_DEFAULT, + persistence: NOISE_PERSISTENCE_DEFAULT, + absvalue: NOISE_ABSVALUE_DEFAULT, + }, + humidity: { + offset: NOISE_OFFSET_DEFAULT, + scale: NOISE_SCALE_DEFAULT, + octaves: NOISE_OCTAVES_DEFAULT, + persistence: NOISE_PERSISTENCE_DEFAULT, + absvalue: NOISE_ABSVALUE_DEFAULT, + }, + +}; + +function updateAreaVarsFor(noiseType) { + console.log("noiseType "+noiseType) + let noise = noises[noiseType]; + + let is_absolute = noise.absvalue === true // Calculate min. and max. possible values // Octaves let [o_min, o_max] = [0, 0] - for (let o=1; o<=noiseOctaves; o++) { + for (let o=1; o<=noise.octaves; o++) { let exp = o-1 // Calculate the two possible extreme values // with the octave value being either at 1 or -1. - let limit1 = (1 * noisePersistence ** exp) + let limit1 = (1 * noise.persistence ** exp) let limit2 if (!is_absolute) { - limit2 = (-1 * noisePersistence ** exp) + limit2 = (-1 * noise.persistence ** exp) } else { // If absvalue is set, one of the // limits is always 0 because we @@ -92,8 +111,8 @@ function updateAreaVars() { } } // Add offset and scale to min/max value (final step) - let min_value = noiseOffset + noiseScale * o_min - let max_value = noiseOffset + noiseScale * o_max + let min_value = noise.offset + noise.scale * o_min + let max_value = noise.offset + noise.scale * o_max // Bring the 2 values in the correct order // (min_value might be bigger for negative scale) @@ -102,16 +121,34 @@ function updateAreaVars() { } // Update globals - limit_min = min_value; - limit_max = max_value; - console.log("limit_min = "+limit_min); - console.log("limit_max = "+limit_max); - draw_min = limit_min - DRAW_OFFSET - draw_max = limit_max + DRAW_OFFSET - midpoint = min_value + (max_value - min_value) / 2 - + let limit_min = min_value; + let limit_max = max_value; + let draw_min = limit_min - DRAW_OFFSET + let draw_max = limit_max + DRAW_OFFSET + let midpoint = min_value + (max_value - min_value) / 2 + if (noiseType === "heat") { + limit_heat_min = limit_min; + limit_heat_max = limit_max; + draw_heat_min = draw_min; + draw_heat_max = draw_max; + midpoint_heat = midpoint; + console.log("Heat= "+limit_heat_min+" - "+limit_heat_max); + } else if (noiseType === "humidity") { + limit_humidity_min = limit_min; + limit_humidity_max = limit_max; + draw_humidity_min = draw_min; + draw_humidity_max = draw_max; + midpoint_humidity = midpoint; + } else { + console.log("ERROR! updateAreaVars() called with wrong noise_type!") + } +} +function updateAreaVars() { + updateAreaVarsFor("heat"); + updateAreaVarsFor("humidity"); // Update element - statsInfo.innerText = "Value range: ["+(+limit_min)+", "+(+limit_max)+"]" + statsInfo.innerText = "Heat value range: ["+(+limit_heat_min)+", "+(+limit_heat_max)+"]; " + + "humidity value range: ["+(+limit_humidity_min)+", "+(+limit_humidity_max)+"]"; } updateAreaVars(); @@ -136,7 +173,7 @@ function addBiome(biomeDef) { } // Add a default biome at the midpoint -addBiome({name: generateBiomeName(midpoint, midpoint), heat:midpoint, humidity:midpoint, min_y: MIN_Y_DEFAULT, max_y: MAX_Y_DEFAULT}) +addBiome({name: generateBiomeName(midpoint_heat, midpoint_humidity), heat:midpoint_heat, humidity:midpoint_humidity, min_y: MIN_Y_DEFAULT, max_y: MAX_Y_DEFAULT}) function getViewY() { if (!inputViewY) { @@ -176,17 +213,17 @@ function voronoiPointToBiomePoint(point) { function putPointName(context, point) { let x = point.heat let y = point.humidity - 1 - if (x < limit_min || x > limit_max || y < limit_min || y > limit_max) { + if (x < limit_heat_min || x > limit_heat_max || y < limit_humidity_min || y > limit_humidity_max) { return; } - if (x > midpoint) { + if (x > midpoint_heat) { context.textAlign = "right"; x = x-2; } else { context.textAlign = "left"; x = x+2; } - if (y < midpoint) { + if (y < midpoint_humidity) { context.textBaseline = "top"; } else { context.textBaseline = "alphabetic"; @@ -200,62 +237,62 @@ function putPoint(context, point) { let x = point.heat let y = point.humidity // Point is out of bounds: Draw an arrow at the border - if (x < limit_min || x > limit_max || y < limit_min || y > limit_max) { + if (x < limit_heat_min || x > limit_heat_max || y < limit_humidity_min || y > limit_humidity_max) { context.beginPath(); // top left corner - if (x < limit_min && y < limit_min) { - context.moveTo(limit_min, limit_min); - context.lineTo(limit_min + ARROW_SIZE_CORNER, limit_min); - context.lineTo(limit_min, limit_min + ARROW_SIZE_CORNER); + if (x < limit_heat_min && y < limit_humidity_min) { + context.moveTo(limit_heat_min, limit_humidity_min); + context.lineTo(limit_heat_min + ARROW_SIZE_CORNER, limit_humidity_min); + context.lineTo(limit_heat_min, limit_humidity_min + ARROW_SIZE_CORNER); context.closePath(); context.fill(); // top right corner - } else if (x > limit_max && y < limit_min) { - context.moveTo(limit_max, limit_min); - context.lineTo(limit_max - ARROW_SIZE_CORNER, limit_min); - context.lineTo(limit_max, limit_min + ARROW_SIZE_CORNER); + } else if (x > limit_heat_max && y < limit_humidity_min) { + context.moveTo(limit_heat_max, limit_humidity_min); + context.lineTo(limit_heat_max - ARROW_SIZE_CORNER, limit_humidity_min); + context.lineTo(limit_heat_max, limit_humidity_min + ARROW_SIZE_CORNER); context.closePath(); context.fill(); // bottom left corner - } else if (x < limit_min && y > limit_max) { - context.moveTo(limit_min, limit_max); - context.lineTo(limit_min + ARROW_SIZE_CORNER, limit_max); - context.lineTo(limit_min, limit_max - ARROW_SIZE_CORNER); + } else if (x < limit_heat_min && y > limit_humidity_max) { + context.moveTo(limit_heat_min, limit_humidity_max); + context.lineTo(limit_heat_min + ARROW_SIZE_CORNER, limit_humidity_max); + context.lineTo(limit_heat_min, limit_humidity_max - ARROW_SIZE_CORNER); context.closePath(); context.fill(); // top right corner - } else if (x > limit_max && y > limit_max) { - context.moveTo(limit_max, limit_max); - context.lineTo(limit_max - ARROW_SIZE_CORNER, limit_max); - context.lineTo(limit_max, limit_max - ARROW_SIZE_CORNER); + } else if (x > limit_heat_max && y > limit_humidity_max) { + context.moveTo(limit_heat_max, limit_humidity_max); + context.lineTo(limit_heat_max - ARROW_SIZE_CORNER, limit_humidity_max); + context.lineTo(limit_heat_max, limit_humidity_max - ARROW_SIZE_CORNER); context.closePath(); context.fill(); // left side - } else if (x < limit_min) { - context.moveTo(limit_min, y); - context.lineTo(limit_min + ARROW_SIZE_SIDE, y + ARROW_SIZE_SIDE); - context.lineTo(limit_min + ARROW_SIZE_SIDE, y - ARROW_SIZE_SIDE); + } else if (x < limit_heat_min) { + context.moveTo(limit_heat_min, y); + context.lineTo(limit_heat_min + ARROW_SIZE_SIDE, y + ARROW_SIZE_SIDE); + context.lineTo(limit_heat_min + ARROW_SIZE_SIDE, y - ARROW_SIZE_SIDE); context.closePath(); context.fill(); // right side - } else if (x > limit_max) { - context.moveTo(limit_max, y); - context.lineTo(limit_max - ARROW_SIZE_SIDE, y + ARROW_SIZE_SIDE); - context.lineTo(limit_max - ARROW_SIZE_SIDE, y - ARROW_SIZE_SIDE); + } else if (x > limit_heat_max) { + context.moveTo(limit_heat_max, y); + context.lineTo(limit_heat_max - ARROW_SIZE_SIDE, y + ARROW_SIZE_SIDE); + context.lineTo(limit_heat_max - ARROW_SIZE_SIDE, y - ARROW_SIZE_SIDE); context.closePath(); context.fill(); // top side - } else if (y < limit_min) { - context.moveTo(x, limit_min); - context.lineTo(x - ARROW_SIZE_SIDE, limit_min + ARROW_SIZE_SIDE); - context.lineTo(x + ARROW_SIZE_SIDE, limit_min + ARROW_SIZE_SIDE); + } else if (y < limit_humidity_min) { + context.moveTo(x, limit_humidity_min); + context.lineTo(x - ARROW_SIZE_SIDE, limit_humidity_min + ARROW_SIZE_SIDE); + context.lineTo(x + ARROW_SIZE_SIDE, limit_humidity_min + ARROW_SIZE_SIDE); context.closePath(); context.fill(); // bottom side - } else if (y > limit_max) { - context.moveTo(x, limit_max); - context.lineTo(x - ARROW_SIZE_SIDE, limit_max - ARROW_SIZE_SIDE); - context.lineTo(x + ARROW_SIZE_SIDE, limit_max - ARROW_SIZE_SIDE); + } else if (y > limit_humidity_max) { + context.moveTo(x, limit_humidity_max); + context.lineTo(x - ARROW_SIZE_SIDE, limit_humidity_max - ARROW_SIZE_SIDE); + context.lineTo(x + ARROW_SIZE_SIDE, limit_humidity_max - ARROW_SIZE_SIDE); context.closePath(); context.fill(); } @@ -272,28 +309,28 @@ function putPoint(context, point) { function putGrid(context) { context.lineWidth = 0.5; context.strokeStyle = gridColor; - for (let x=0; x<=limit_max; x+=GRID_STEP) { + for (let x=0; x<=limit_heat_max; x+=GRID_STEP) { context.beginPath(); - context.moveTo(x, limit_min); - context.lineTo(x, limit_max); + context.moveTo(x, limit_humidity_min); + context.lineTo(x, limit_humidity_max); context.stroke(); } - for (let x=-GRID_STEP; x>=limit_min; x-=GRID_STEP) { + for (let x=-GRID_STEP; x>=limit_heat_min; x-=GRID_STEP) { context.beginPath(); - context.moveTo(x, limit_min); - context.lineTo(x, limit_max); + context.moveTo(x, limit_humidity_min); + context.lineTo(x, limit_humidity_max); context.stroke(); } - for (let y=0; y<=limit_max; y+=GRID_STEP) { + for (let y=0; y<=limit_humidity_max; y+=GRID_STEP) { context.beginPath(); - context.moveTo(limit_min, y); - context.lineTo(limit_max, y); + context.moveTo(limit_heat_min, y); + context.lineTo(limit_heat_max, y); context.stroke(); } - for (let y=-GRID_STEP; y>=limit_min; y-=GRID_STEP) { + for (let y=-GRID_STEP; y>=limit_humidity_min; y-=GRID_STEP) { context.beginPath(); - context.moveTo(limit_min, y); - context.lineTo(limit_max, y); + context.moveTo(limit_heat_min, y); + context.lineTo(limit_heat_max, y); context.stroke(); } } @@ -303,7 +340,7 @@ let cachedVoronoiDiagram = null; function getVoronoiDiagram(points, recalculate) { if ((cachedVoronoiDiagram === null) || recalculate) { - let vbbox = {xl: limit_min, xr: limit_max, yt: limit_min, yb: limit_max}; + let vbbox = {xl: limit_heat_min, xr: limit_heat_max, yt: limit_humidity_min, yb: limit_humidity_max}; let sites = [] for (let p of points) { sites.push(biomePointToVoronoiPoint(p)); @@ -335,30 +372,9 @@ function clear(context) { context = getDrawContext(); } context.fillStyle = clearColor; - context.fillRect(draw_min, draw_min, draw_max-draw_min, draw_max-draw_min); + context.fillRect(draw_heat_min, draw_humidity_min, draw_heat_max-draw_heat_min, draw_humidity_max-draw_humidity_min); } -function drawInit(contextRestore) { - /* - let context = getDrawContext(); - if (contextRestore) { - context.restore(); - } - context.save(); - - // Clear area - clear(context); - - // Don't scale and translate if value range is tiny; an error message will be triggered in draw() - if (limit_max - limit_min < 0.01) { - return; - } - - // New range - context.scale(voronoiCanvas.width/(limit_max-limit_min), voronoiCanvas.height/(limit_max-limit_min)); - context.translate(-limit_min, -limit_min); - */ -} function getRenderedPoints(y) { let points = []; for (let p=0; p 0) { @@ -549,10 +565,14 @@ function updateWidgetStates() { inputMaxY.value = point.max_y; } } - inputNoiseOffset.value = noiseOffset; - inputNoiseScale.value = noiseScale; - inputNoiseOctaves.value = noiseOctaves; - inputNoisePersistence.value = noisePersistence; + inputNoiseHeatOffset.value = noises.heat.offset; + inputNoiseHeatScale.value = noises.heat.scale; + inputNoiseHeatOctaves.value = noises.heat.octaves; + inputNoiseHeatPersistence.value = noises.heat.persistence; + inputNoiseHumidityOffset.value = noises.humidity.offset; + inputNoiseHumidityScale.value = noises.humidity.scale; + inputNoiseHumidityOctaves.value = noises.humidity.octaves; + inputNoiseHumidityPersistence.value = noises.humidity.persistence; } biomeSelector.onchange = function() { @@ -603,15 +623,15 @@ inputViewY.onchange = function() { } addBiomeButton.onclick = function() { - let he = Math.round(limit_min + Math.random() * (limit_max - limit_min)); - let hu = Math.round(limit_min + Math.random() * (limit_max - limit_min)); + let he = Math.round(limit_heat_min + Math.random() * (limit_heat_max - limit_heat_min)); + let hu = Math.round(limit_humidity_min + Math.random() * (limit_humidity_max - limit_humidity_min)); let newPoint = { id: lastBiomeID, name: generateBiomeName(he, hu), heat: he, + humidity: hu, min_y: MIN_Y_DEFAULT, max_y: MAX_Y_DEFAULT, - humidity: hu, }; biomePoints.push(newPoint); let num = biomePoints.length @@ -684,17 +704,17 @@ function getDistance(x1, y1, x2, y2) { return Math.sqrt((x2 - x1)**2 + (y2 - y1)**2); } function canvasPixelCoordsToBiomeCoords(x, y) { - let w = (voronoiCanvas.width/(limit_max-limit_min)); - let h = (voronoiCanvas.height/(limit_max-limit_min)); - let heat = Math.round((x + limit_min * w) / w); - let humidity = Math.round((y + limit_min * w) / w); + let w = (voronoiCanvas.width/(limit_heat_max-limit_heat_min)); + let h = (voronoiCanvas.height/(limit_humidity_max-limit_humidity_min)); + let heat = Math.round((x + limit_heat_min * w) / w); + let humidity = Math.round((y + limit_humidity_min * w) / w); return [heat, humidity]; } function biomeCoordsToCanvasPixelCoords(heat, humidity) { - let w = (voronoiCanvas.width/(limit_max-limit_min)); - let h = (voronoiCanvas.height/(limit_max-limit_min)); - let pixelX = heat * w - limit_min * w; - let pixelY = humidity * h - limit_min * h; + let w = (voronoiCanvas.width/(limit_heat_max-limit_heat_min)); + let h = (voronoiCanvas.height/(limit_humidity_max-limit_humidity_min)); + let pixelX = heat * w - limit_heat_min * w; + let pixelY = humidity * h - limit_humidity_min * h; return [pixelX, pixelY]; } @@ -827,47 +847,77 @@ inputCheckboxGrid.onchange = function() { showGrid = this.checked; draw(getViewY(), true); } -inputNoiseScale.onchange = function() { - noiseScale = +this.value; +inputNoiseHeatScale.onchange = function() { + noises.heat.scale = +this.value; clear(); updateAreaVars(); - drawInit(true); draw(getViewY(), true); } -inputNoiseOffset.onchange = function() { - noiseOffset = +this.value; +inputNoiseHeatOffset.onchange = function() { + noises.heat.offset = +this.value; clear(); updateAreaVars(); - drawInit(true); draw(getViewY(), true); } -inputNoisePersistence.onchange = function() { - noisePersistence = +this.value; +inputNoiseHeatPersistence.onchange = function() { + noises.heat.persistence = +this.value; clear(); updateAreaVars(); - drawInit(true); draw(getViewY(), true); } -inputNoiseOctaves.onchange = function() { - noiseOctaves = +this.value; +inputNoiseHeatOctaves.onchange = function() { + noises.heat.octaves = +this.value; + clear(); + updateAreaVars(); + draw(getViewY(), true); +} +inputNoiseHumidityScale.onchange = function() { + noises.humidity.scale = +this.value; + clear(); + updateAreaVars(); + draw(getViewY(), true); +} +inputNoiseHumidityOffset.onchange = function() { + noises.humidity.offset = +this.value; + clear(); + updateAreaVars(); + draw(getViewY(), true); +} +inputNoiseHumidityPersistence.onchange = function() { + noises.humidity.persistence = +this.value; + clear(); + updateAreaVars(); + draw(getViewY(), true); +} +inputNoiseHumidityOctaves.onchange = function() { + noises.humidity.octaves = +this.value; clear(); updateAreaVars(); - drawInit(true); draw(getViewY(), true); } inputNoiseReset.onclick = function() { - noiseOffset = NOISE_OFFSET_DEFAULT; - noiseScale = NOISE_SCALE_DEFAULT; - noiseOctaves = NOISE_OCTAVES_DEFAULT; - noisePersistence = NOISE_PERSISTENCE_DEFAULT; - noiseAbsvalue = NOISE_ABSVALUE_DEFAULT; - inputNoiseOffset.value = noiseOffset; - inputNoiseScale.value = noiseScale; - inputNoiseOctaves.value = noiseOctaves; - inputNoisePersistence.value = noisePersistence; + noises.heat.offset = NOISE_OFFSET_DEFAULT; + noises.heat.scale = NOISE_SCALE_DEFAULT; + noises.heat.octaves = NOISE_OCTAVES_DEFAULT; + noises.heat.persistence = NOISE_PERSISTENCE_DEFAULT; + noises.heat.absvalue = NOISE_ABSVALUE_DEFAULT; + inputNoiseHeatOffset.value = noises.heat.offset; + inputNoiseHeatScale.value = noises.heat.scale; + inputNoiseHeatOctaves.value = noises.heat.octaves; + inputNoiseHeatPersistence.value = noises.heat.persistence; + + noises.humidity.offset = NOISE_OFFSET_DEFAULT; + noises.humidity.scale = NOISE_SCALE_DEFAULT; + noises.humidity.octaves = NOISE_OCTAVES_DEFAULT; + noises.humidity.persistence = NOISE_PERSISTENCE_DEFAULT; + noises.humidity.absvalue = NOISE_ABSVALUE_DEFAULT; + inputNoiseHumidityOffset.value = noises.humidity.offset; + inputNoiseHumidityScale.value = noises.humidity.scale; + inputNoiseHumidityOctaves.value = noises.humidity.octaves; + inputNoiseHumidityPersistence.value = noises.humidity.persistence; + clear(); updateAreaVars(); - drawInit(true); draw(getViewY(), true); } @@ -879,7 +929,6 @@ function checkboxVarsInit() { } window.addEventListener("load", checkboxVarsInit); -window.addEventListener("load", drawInit); window.addEventListener("load", function() { draw(getViewY(), true); }) diff --git a/index.html b/index.html index bc188ae..80931b6 100644 --- a/index.html +++ b/index.html @@ -78,21 +78,34 @@ A voronoi diagram is supposed to be here but for some reason it cannot be displa
-

Heat/humidity noise parameters

+

Noise parameters

- - - - - - - - - - - - +

Heat

+ + + + + + + + + + + + +

Humidity

+ + + + + + + + + + +