mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
3d preview to Heightmap editor (#329)
This commit is contained in:
parent
efd9159737
commit
0e308079aa
8 changed files with 51152 additions and 2 deletions
150
modules/ui/3dutils.js
Normal file
150
modules/ui/3dutils.js
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
var _3dheightMapExponent = null;
|
||||
var _3dmaxHeight = null;
|
||||
var _3dcolorLookup = null;
|
||||
|
||||
function _2dto1d(source) {
|
||||
var r = [];
|
||||
|
||||
var w = source[0].length;
|
||||
var h = source.length;
|
||||
|
||||
var i=0;
|
||||
for (var y=0; y < h; y++) {
|
||||
for (var x=0; x < w; x++) {
|
||||
r[i] = source[y][x];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
function _1dto2d(source, w, h) {
|
||||
|
||||
var r = [];
|
||||
|
||||
var i=0;
|
||||
for (var y=0; y < h; y++) {
|
||||
r[y] = [];
|
||||
for (var x=0; x < w; x++) {
|
||||
r[y][x] = source[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
function getSVGImage(type, width, height) {
|
||||
// clone svg
|
||||
const cloneEl = document.getElementById("map").cloneNode(true);
|
||||
cloneEl.id = "fantasyMap";
|
||||
document.getElementsByTagName("body")[0].appendChild(cloneEl);
|
||||
const clone = d3.select("#fantasyMap");
|
||||
|
||||
if (type === "svg") {
|
||||
clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
||||
}
|
||||
|
||||
clone.attr("width", width).attr("height", height);
|
||||
|
||||
// remove unused elements
|
||||
if (!clone.select("#terrain").selectAll("use").size()) clone.select("#defs-relief").remove();
|
||||
if (!clone.select("#prec").selectAll("circle").size()) clone.select("#prec").remove();
|
||||
if (!clone.select("#scaleBar").selectAll("use").size()) clone.select("#scaleBar").remove();
|
||||
|
||||
// default to water - on Firefox, ocean pattern appears as alternating blocks of ocean and water pattern
|
||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
if (isFirefox) {
|
||||
if (!clone.select("#oceanPattern").selectAll("use").size()) clone.select("#oceanPattern").remove();
|
||||
}
|
||||
|
||||
const removeEmptyGroups = function() {
|
||||
let empty = 0;
|
||||
clone.selectAll("g").each(function() {
|
||||
if (!this.hasChildNodes() || this.style.display === "none") {empty++; this.remove();}
|
||||
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
|
||||
});
|
||||
return empty;
|
||||
}
|
||||
while(removeEmptyGroups()) {removeEmptyGroups();}
|
||||
|
||||
// for each g element get inline style
|
||||
const emptyG = clone.append("g").node();
|
||||
const defaultStyles = window.getComputedStyle(emptyG);
|
||||
clone.selectAll("g, #ruler > g > *, #scaleBar > text").each(function(d) {
|
||||
const compStyle = window.getComputedStyle(this);
|
||||
let style = "";
|
||||
for (let i=0; i < compStyle.length; i++) {
|
||||
const key = compStyle[i];
|
||||
const value = compStyle.getPropertyValue(key);
|
||||
// Firefox mask hack
|
||||
if (key === "mask-image" && value !== defaultStyles.getPropertyValue(key)) {
|
||||
style += "mask-image: url('#land');";
|
||||
continue;
|
||||
}
|
||||
if (key === "cursor") continue; // cursor should be default
|
||||
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
|
||||
if (value === defaultStyles.getPropertyValue(key)) continue;
|
||||
style += key + ':' + value + ';';
|
||||
}
|
||||
if (style != "") this.setAttribute('style', style);
|
||||
});
|
||||
emptyG.remove();
|
||||
|
||||
// load fonts as dataURI so they will be available in downloaded svg/png
|
||||
const svg_xml = (new XMLSerializer()).serializeToString(clone.node());
|
||||
clone.remove();
|
||||
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
return url;
|
||||
}
|
||||
|
||||
function getHeightmap() {
|
||||
var mh = 0;
|
||||
grid.cells.h.forEach((height, i) => {
|
||||
h = grid.cells.h[i];
|
||||
|
||||
if (h > mh) mh = h;
|
||||
});
|
||||
if (mh > 82) { mh = 82; }
|
||||
|
||||
_3dheightMapExponent = heightExponentInput.value;
|
||||
// _3dmaxHeight = Math.pow(mh, _3dheightMapExponent);
|
||||
_3dmaxHeight = Math.pow(82, _3dheightMapExponent);
|
||||
|
||||
var heightMap = [];
|
||||
for (var y=0; y < grid.cellsY; y++) {
|
||||
heightMap[y] = [];
|
||||
}
|
||||
|
||||
var y = 0, x = 0;
|
||||
|
||||
// convert height from map heights to a linear height
|
||||
grid.cells.h.forEach((height, i) => {
|
||||
h = grid.cells.h[i];
|
||||
|
||||
// add heightmap exponent
|
||||
if (h >= 20) height = Math.pow(h - 18, _3dheightMapExponent);
|
||||
// else if (h > 0) height = (h - 20) / h * 50;
|
||||
else height = 0;
|
||||
|
||||
// get heightmap as a percentage
|
||||
let v = (height / _3dmaxHeight);
|
||||
|
||||
// convert to 0-255
|
||||
v = (v * 255);
|
||||
|
||||
heightMap[y][x] = Math.floor(v);
|
||||
x++;
|
||||
if (x >= grid.cellsX) { x = 0; y++ }
|
||||
});
|
||||
|
||||
var hm = _2dto1d(heightMap);
|
||||
|
||||
return hm;
|
||||
}
|
||||
|
||||
function getPreviewTexture(width, height) {
|
||||
return getSVGImage("svg", width, height);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue