├── LICENSE ├── README.md ├── decoder.html ├── decoder.js ├── img ├── LitSphere_test_02.jpg ├── RadialGradient.png ├── bars.jpg ├── checkers.jpg ├── checkers2.jpg ├── color1 ├── color1.jpg ├── color2.jpg ├── color3.jpg ├── color_wheel.jpg ├── decoder.png ├── elevation0.png ├── env1bg.jpg ├── env2bg.jpg ├── env3bg.jpg ├── env4bg.jpg ├── gradient-ocean.png ├── gradient.png ├── hypsometric01.png ├── imhof.psd ├── imhof5.jpg ├── mad-pano.jpg ├── mad-pano1-blur.jpg ├── mad-pano1-blur2.jpg ├── mad-pano1.jpg ├── matball01.jpg ├── office-pano1-blur.jpg ├── office-pano1.jpg ├── rings.jpg ├── rings2.jpg ├── shade1.png ├── skylight.jpg ├── sunrise.jpg ├── sunrise2.jpg ├── sunrise3.jpg ├── sunset.jpg └── wheel.png ├── index.html ├── kernel.glsl ├── lib ├── dat.gui.min.js ├── key.js ├── leaflet-hash.js ├── tangram.debug.js └── tangram.min.js ├── main.js └── styles ├── blurred-normal.yaml ├── combo.yaml ├── contours.yaml ├── contours2.yaml ├── elevation-difference.yaml ├── elevation-extrude.yaml ├── elevation-tiles.yaml ├── elevation-zoom-adjust.yaml ├── environment-map1.yaml ├── grayscale.yaml ├── green-avg.yaml ├── green-selectiveblur.yaml ├── green-stdev-adjusted.yaml ├── green-stdev-opt.yaml ├── green-stdev.yaml ├── green.yaml ├── heightmap.yaml ├── hypsometric-adjusted.yaml ├── hypsometric-spheremap.yaml ├── hypsometric-spheremap2.yaml ├── hypsometric-texture.yaml ├── hypsometric.yaml ├── imhof.yaml ├── imhof2.yaml ├── kinkade-style.yaml ├── median-normal.yaml ├── median.yaml ├── metal.yaml ├── normal-alpha-elevation.yaml ├── normals-averaged.yaml ├── normals-manual.yaml ├── normals-tiles.yaml ├── raster-normal.yaml ├── reference-elevation.yaml ├── sharpen-normals.yaml ├── sharpened.yaml ├── single-light.yaml ├── slope.yaml ├── sunrise.yaml ├── sunset.yaml ├── terrarium-elevation.yaml ├── three-lights.yaml ├── two-lights.yaml └── weighted-average.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mapzen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terrain-demos 2 | 3 | Ways to manipulate heightmap data in [Tangram](http://github.com/tangrams/tangram) as seen in the [Mapping Mountains](https://mapzen.com/blog/mapping-mountains/) post on the [Mapzen blog](http://mapzen.com/blog). 4 | 5 | terrain demo 6 | 7 | ## Style gallery 8 | 9 | - elevation tiles: http://tangrams.github.io/terrain-demos/?url=styles/elevation-tiles.yaml 10 | - basic green: http://tangrams.github.io/terrain-demos/?url=styles/green.yaml 11 | - animated contours: http://tangrams.github.io/terrain-demos/?url=styles/contours.yaml 12 | - grayscale hypsometric: http://tangrams.github.io/terrain-demos/?url=styles/grayscale.yaml 13 | - classic hypsometric: http://tangrams.github.io/terrain-demos/?url=styles/hypsometric.yaml 14 | - slopemap: http://tangrams.github.io/terrain-demos/?url=styles/slope.yaml 15 | - heightmap: http://tangrams.github.io/terrain-demos/?url=styles/heightmap.yaml 16 | - manual normal derivation: http://tangrams.github.io/terrain-demos/?url=styles/normals-manual.yaml 17 | - normal tiles: http://tangrams.github.io/terrain-demos/?url=styles/normals-tiles.yaml 18 | - single light: http://tangrams.github.io/terrain-demos/?url=styles/single-light.yaml 19 | - two lights: http://tangrams.github.io/terrain-demos/?url=styles/two-lights.yaml 20 | - three lights: http://tangrams.github.io/terrain-demos/?url=styles/three-lights.yaml 21 | - environment map: http://tangrams.github.io/terrain-demos/?url=styles/environment-map1.yaml 22 | - metal spheremap: http://tangrams.github.io/terrain-demos/?url=styles/metal.yaml 23 | - sunrise spheremap: http://tangrams.github.io/terrain-demos/?url=styles/sunrise.yaml 24 | - sunset spheremap: http://tangrams.github.io/terrain-demos/?url=styles/sunset.yaml 25 | - swiss style: http://tangrams.github.io/terrain-demos/?url=styles/imhof.yaml 26 | 27 | Check out the source code for these and more examples in the [styles directory](https://github.com/tangrams/terrain-demos/tree/gh-pages/styles). 28 | 29 | ### Elevation tiles vs. Normal tiles alpha elevation 30 | 31 | Mapzen offers two sources of elevation data: the ["terrarium" elevation tiles](https://mapzen.com/documentation/terrain-tiles/formats/#terrarium), and also the [alpha channel of the normal tiles](https://mapzen.com/documentation/terrain-tiles/formats/#normal). Most of the examples in this repo are based on the elevation tiles, but some of them (such as normal-alpha-elevation.yaml) use the alpha channel of the normal tiles. This source is a bit trickier to use, but if you don't need the 24-bit resolution of the elevation tiles, and are already loading the normal tiles, it will make your styles faster. 32 | 33 | The elevation tiles use a relatively simple linear encoding, but the normal tiles alpha channel is quantized, non-linear, and 8-bit. (More information about this encoding can be found in [the documentation for our elevation datasource](https://mapzen.com/documentation/terrain-tiles/formats/#normal).) 34 | 35 | To make this source simpler to interpret, we're using a "[decoder ring](https://wikipedia.org/wiki/Secret_decoder_ring)" image which maps the quantized range to the unquantized range as best it can. This image is generated with [a piece of JavaScript](decoder.js) which runs the quantize function in reverse, and creates a new image in a canvas element with the decoded output values for each input value. [You can run this script here](tangrams.github.io/terrain-demos/decoder.html). This image has also been pregenerated for your convenience, and is stored in this repo as [decoder.png](https://github.com/tangrams/terrain-demos/blob/master/img/decoder.png). It looks like this: 36 | 37 | ![decoder ring image](https://github.com/tangrams/terrain-demos/blob/master/img/decoder.png) 38 | 39 | This image can be used as a texture in a heightmap shader, for easier decoding. 40 | 41 | ### To run locally: 42 | 43 | Start a web server in the repo's directory: 44 | 45 | python -m SimpleHTTPServer 8000 46 | 47 | If that doesn't work, try: 48 | 49 | python -m http.server 8000 50 | 51 | Then navigate to, eg: [http://localhost:8000/?url=styles/contours.yaml](http://localhost:8000/?url=styles/contours.yaml) 52 | -------------------------------------------------------------------------------- /decoder.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /decoder.js: -------------------------------------------------------------------------------- 1 | // wait until the page loads to run the script 2 | // (otherwise there won't be a document to write to) 3 | window.onload = function() { 4 | table = []; 5 | for (i = 0; i < 11; i++) { 6 | table.push(-11000 + i * 1000); 7 | } 8 | table.push(-100) 9 | table.push( -50) 10 | table.push( -20) 11 | table.push( -10) 12 | table.push( -1) 13 | for (i = 0; i < 150; i++) { 14 | table.push(20 * i); 15 | } 16 | for (i = 0; i < 60; i++) { 17 | table.push(3000 + 50 * i); 18 | } 19 | for (i = 0; i < 29; i++) { 20 | table.push(6000 + 100 * i); 21 | } 22 | console.log(table); 23 | 24 | function bisectLeft (array, x) { 25 | for (var i = 0; i < array.length; i++) { 26 | if (array[i] >= x) return i; 27 | } 28 | return array.length; 29 | } 30 | 31 | // make a new canvas element to draw into 32 | var canvas = document.createElement('canvas'); 33 | canvas.id = "canvas"; 34 | canvas.width = 255; 35 | canvas.height = 10; 36 | 37 | var ctx=canvas.getContext("2d"); 38 | var imgData=ctx.createImageData(255,1); 39 | 40 | // all 10 rows are identical, just to make it easier to see 41 | for (j=0; j< 10; j++){ 42 | // save data in the columns 43 | for (i = 0; i < 255; i++) { 44 | v = table[i]; 45 | console.log('starting value:', v); 46 | // o = offset 47 | o = v + 11000; 48 | // r = red channel 49 | r = o % 256; 50 | g = Math.floor(o / 256); 51 | console.log('r:', r, 'g:', g); 52 | console.log('reconstructed, r + g*256 - 11000:', (r+g*256)-11000); 53 | 54 | // build each pixel's color value 55 | id = i * 4; 56 | { 57 | imgData.data[id+0]=r; 58 | imgData.data[id+1]=g; 59 | imgData.data[id+2]=0; // don't use b channel 60 | imgData.data[id+3]=255; // solid alpha 61 | } 62 | } 63 | ctx.putImageData(imgData,0,j); 64 | } 65 | // grab the contents of the otherwise invisible canvas 66 | var d=canvas.toDataURL("image/png"); 67 | // add a new image with the contents of the canvas to the document 68 | document.write("from canvas"); 69 | } 70 | -------------------------------------------------------------------------------- /img/LitSphere_test_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/LitSphere_test_02.jpg -------------------------------------------------------------------------------- /img/RadialGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/RadialGradient.png -------------------------------------------------------------------------------- /img/bars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/bars.jpg -------------------------------------------------------------------------------- /img/checkers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/checkers.jpg -------------------------------------------------------------------------------- /img/checkers2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/checkers2.jpg -------------------------------------------------------------------------------- /img/color1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/color1 -------------------------------------------------------------------------------- /img/color1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/color1.jpg -------------------------------------------------------------------------------- /img/color2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/color2.jpg -------------------------------------------------------------------------------- /img/color3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/color3.jpg -------------------------------------------------------------------------------- /img/color_wheel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/color_wheel.jpg -------------------------------------------------------------------------------- /img/decoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/decoder.png -------------------------------------------------------------------------------- /img/elevation0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/elevation0.png -------------------------------------------------------------------------------- /img/env1bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/env1bg.jpg -------------------------------------------------------------------------------- /img/env2bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/env2bg.jpg -------------------------------------------------------------------------------- /img/env3bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/env3bg.jpg -------------------------------------------------------------------------------- /img/env4bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/env4bg.jpg -------------------------------------------------------------------------------- /img/gradient-ocean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/gradient-ocean.png -------------------------------------------------------------------------------- /img/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/gradient.png -------------------------------------------------------------------------------- /img/hypsometric01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/hypsometric01.png -------------------------------------------------------------------------------- /img/imhof.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/imhof.psd -------------------------------------------------------------------------------- /img/imhof5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/imhof5.jpg -------------------------------------------------------------------------------- /img/mad-pano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/mad-pano.jpg -------------------------------------------------------------------------------- /img/mad-pano1-blur.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/mad-pano1-blur.jpg -------------------------------------------------------------------------------- /img/mad-pano1-blur2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/mad-pano1-blur2.jpg -------------------------------------------------------------------------------- /img/mad-pano1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/mad-pano1.jpg -------------------------------------------------------------------------------- /img/matball01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/matball01.jpg -------------------------------------------------------------------------------- /img/office-pano1-blur.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/office-pano1-blur.jpg -------------------------------------------------------------------------------- /img/office-pano1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/office-pano1.jpg -------------------------------------------------------------------------------- /img/rings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/rings.jpg -------------------------------------------------------------------------------- /img/rings2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/rings2.jpg -------------------------------------------------------------------------------- /img/shade1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/shade1.png -------------------------------------------------------------------------------- /img/skylight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/skylight.jpg -------------------------------------------------------------------------------- /img/sunrise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/sunrise.jpg -------------------------------------------------------------------------------- /img/sunrise2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/sunrise2.jpg -------------------------------------------------------------------------------- /img/sunrise3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/sunrise3.jpg -------------------------------------------------------------------------------- /img/sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/sunset.jpg -------------------------------------------------------------------------------- /img/wheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/terrain-demos/9de91d85b1279512b7cd3b2944f484b9c513fb1e/img/wheel.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | Tangram 14 | 15 | 16 | 17 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /kernel.glsl: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision mediump float; 3 | #endif 4 | 5 | float normpdf(in float x, in float sigma) 6 | { 7 | return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma; 8 | } 9 | 10 | 11 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 12 | { 13 | //declare stuff 14 | const int mSize = 11; 15 | const int kSize = (mSize-1)/2; 16 | float kernel[mSize]; 17 | vec3 final_colour = vec3(0.0); 18 | 19 | //create the 1-D kernel 20 | float sigma = 7.0; 21 | float Z = 0.0; 22 | for (int j = 0; j <= kSize; ++j) 23 | { 24 | kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma); 25 | } 26 | 27 | //get the normalization factor (as the gaussian has been clamped) 28 | for (int j = 0; j < mSize; ++j) 29 | { 30 | Z += kernel[j]; 31 | } 32 | 33 | //read out the texels 34 | for (int i=-kSize; i <= kSize; ++i) 35 | { 36 | for (int j=-kSize; j <= kSize; ++j) 37 | { 38 | final_colour += kernel[kSize+j]*kernel[kSize+i]*texture2D(iChannel0, (fragCoord.xy+vec2(float(i),float(j))) / iResolution.xy).rgb; 39 | 40 | } 41 | } 42 | 43 | fragColor = vec4(final_colour/(Z*Z), 1.0); 44 | } -------------------------------------------------------------------------------- /lib/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(e,a){a=a||document;var b=a.createElement("link");b.type="text/css";b.rel="stylesheet";b.href=e;a.getElementsByTagName("head")[0].appendChild(b)},inject:function(e,a){a=a||document;var b=document.createElement("style");b.type="text/css";b.innerHTML=e;a.getElementsByTagName("head")[0].appendChild(b)}}}(); 2 | dat.utils.common=function(){var e=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(b){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(a[f])||(b[f]=a[f])},this);return b},defaults:function(b){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(b[f])&&(b[f]=a[f])},this);return b},compose:function(){var b=a.call(arguments);return function(){for(var d=a.call(arguments),f=b.length-1;0<=f;f--)d=[b[f].apply(this,d)];return d[0]}}, 3 | each:function(a,d,f){if(e&&a.forEach===e)a.forEach(d,f);else if(a.length===a.length+0)for(var c=0,p=a.length;cthis.__max&&(a=this.__max);void 0!==this.__step&&0!=a%this.__step&&(a=Math.round(a/this.__step)*this.__step);return b.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__step=a;return this}});return b}(dat.controllers.Controller,dat.utils.common); 17 | dat.controllers.NumberControllerBox=function(e,a,b){var d=function(f,c,e){function k(){var a=parseFloat(n.__input.value);b.isNaN(a)||n.setValue(a)}function l(a){var c=r-a.clientY;n.setValue(n.getValue()+c*n.__impliedStep);r=a.clientY}function q(){a.unbind(window,"mousemove",l);a.unbind(window,"mouseup",q)}this.__truncationSuspended=!1;d.superclass.call(this,f,c,e);var n=this,r;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",k);a.bind(this.__input, 18 | "blur",function(){k();n.__onFinishChange&&n.__onFinishChange.call(n,n.getValue())});a.bind(this.__input,"mousedown",function(c){a.bind(window,"mousemove",l);a.bind(window,"mouseup",q);r=c.clientY});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&(n.__truncationSuspended=!0,this.blur(),n.__truncationSuspended=!1)});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;b.extend(d.prototype,e.prototype,{updateDisplay:function(){var a=this.__input,c;if(this.__truncationSuspended)c= 19 | this.getValue();else{c=this.getValue();var b=Math.pow(10,this.__precision);c=Math.round(c*b)/b}a.value=c;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common); 20 | dat.controllers.NumberControllerSlider=function(e,a,b,d,f){function c(a,c,d,b,f){return b+(a-c)/(d-c)*(f-b)}var p=function(d,b,f,e,r){function y(d){d.preventDefault();var b=a.getOffset(h.__background),f=a.getWidth(h.__background);h.setValue(c(d.clientX,b.left,b.left+f,h.__min,h.__max));return!1}function g(){a.unbind(window,"mousemove",y);a.unbind(window,"mouseup",g);h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}p.superclass.call(this,d,b,{min:f,max:e,step:r});var h=this;this.__background= 21 | document.createElement("div");this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(c){a.bind(window,"mousemove",y);a.bind(window,"mouseup",g);y(c)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};p.superclass=e;p.useDefaultStyles=function(){b.inject(f)};d.extend(p.prototype,e.prototype,{updateDisplay:function(){var a= 22 | (this.getValue()-this.__min)/(this.__max-this.__min);this.__foreground.style.width=100*a+"%";return p.superclass.prototype.updateDisplay.call(this)}});return p}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,"/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n.slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}"); 23 | dat.controllers.FunctionController=function(e,a,b){var d=function(b,c,e){d.superclass.call(this,b,c);var k=this;this.__button=document.createElement("div");this.__button.innerHTML=void 0===e?"Fire":e;a.bind(this.__button,"click",function(a){a.preventDefault();k.fire();return!1});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};d.superclass=e;b.extend(d.prototype,e.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.__onFinishChange&&this.__onFinishChange.call(this, 24 | this.getValue());this.getValue().call(this.object)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); 25 | dat.controllers.BooleanController=function(e,a,b){var d=function(b,c){d.superclass.call(this,b,c);var e=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){e.setValue(!e.__prev)},!1);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};d.superclass=e;b.extend(d.prototype,e.prototype,{setValue:function(a){a=d.superclass.prototype.setValue.call(this,a);this.__onFinishChange&& 26 | this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){!0===this.getValue()?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=!0):this.__checkbox.checked=!1;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common); 27 | dat.color.toString=function(e){return function(a){if(1==a.a||e.isUndefined(a.a)){for(a=a.hex.toString(16);6>a.length;)a="0"+a;return"#"+a}return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common); 28 | dat.color.interpret=function(e,a){var b,d,f=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:e},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:e},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); 29 | return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:e},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:e}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return 3!= 30 | a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return 4!=a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(c){return a.isNumber(c.r)&&a.isNumber(c.g)&&a.isNumber(c.b)&&a.isNumber(c.a)?{space:"RGB",r:c.r,g:c.g,b:c.b,a:c.a}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(c){return a.isNumber(c.r)&& 31 | a.isNumber(c.g)&&a.isNumber(c.b)?{space:"RGB",r:c.r,g:c.g,b:c.b}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(c){return a.isNumber(c.h)&&a.isNumber(c.s)&&a.isNumber(c.v)&&a.isNumber(c.a)?{space:"HSV",h:c.h,s:c.s,v:c.v,a:c.a}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(d){return a.isNumber(d.h)&&a.isNumber(d.s)&&a.isNumber(d.v)?{space:"HSV",h:d.h,s:d.s,v:d.v}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){d=!1; 32 | var c=1\n\n Here\'s the new load parameter for your GUI\'s constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI\'s constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n', 59 | ".dg {\n /** Clear list styles */\n /* Auto-place container */\n /* Auto-placed GUI's */\n /* Line items that don't contain folders. */\n /** Folder names */\n /** Hides closed items */\n /** Controller row */\n /** Name-half (left) */\n /** Controller-half (right) */\n /** Controller placement */\n /** Shorter number boxes when slider is present. */\n /** Ensure the entire boolean and function row shows a hand */ }\n .dg ul {\n list-style: none;\n margin: 0;\n padding: 0;\n width: 100%;\n clear: both; }\n .dg.ac {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 0;\n z-index: 0; }\n .dg:not(.ac) .main {\n /** Exclude mains in ac so that we don't hide close button */\n overflow: hidden; }\n .dg.main {\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear; }\n .dg.main.taller-than-window {\n overflow-y: auto; }\n .dg.main.taller-than-window .close-button {\n opacity: 1;\n /* TODO, these are style notes */\n margin-top: -1px;\n border-top: 1px solid #2c2c2c; }\n .dg.main ul.closed .close-button {\n opacity: 1 !important; }\n .dg.main:hover .close-button,\n .dg.main .close-button.drag {\n opacity: 1; }\n .dg.main .close-button {\n /*opacity: 0;*/\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear;\n border: 0;\n position: absolute;\n line-height: 19px;\n height: 20px;\n /* TODO, these are style notes */\n cursor: pointer;\n text-align: center;\n background-color: #000; }\n .dg.main .close-button:hover {\n background-color: #111; }\n .dg.a {\n float: right;\n margin-right: 15px;\n overflow-x: hidden; }\n .dg.a.has-save > ul {\n margin-top: 27px; }\n .dg.a.has-save > ul.closed {\n margin-top: 0; }\n .dg.a .save-row {\n position: fixed;\n top: 0;\n z-index: 1002; }\n .dg li {\n -webkit-transition: height 0.1s ease-out;\n -o-transition: height 0.1s ease-out;\n -moz-transition: height 0.1s ease-out;\n transition: height 0.1s ease-out; }\n .dg li:not(.folder) {\n cursor: auto;\n height: 27px;\n line-height: 27px;\n overflow: hidden;\n padding: 0 4px 0 5px; }\n .dg li.folder {\n padding: 0;\n border-left: 4px solid rgba(0, 0, 0, 0); }\n .dg li.title {\n cursor: pointer;\n margin-left: -4px; }\n .dg .closed li:not(.title),\n .dg .closed ul li,\n .dg .closed ul li > * {\n height: 0;\n overflow: hidden;\n border: 0; }\n .dg .cr {\n clear: both;\n padding-left: 3px;\n height: 27px; }\n .dg .property-name {\n cursor: default;\n float: left;\n clear: left;\n width: 40%;\n overflow: hidden;\n text-overflow: ellipsis; }\n .dg .c {\n float: left;\n width: 60%; }\n .dg .c input[type=text] {\n border: 0;\n margin-top: 4px;\n padding: 3px;\n width: 100%;\n float: right; }\n .dg .has-slider input[type=text] {\n width: 30%;\n /*display: none;*/\n margin-left: 0; }\n .dg .slider {\n float: left;\n width: 66%;\n margin-left: -5px;\n margin-right: 0;\n height: 19px;\n margin-top: 4px; }\n .dg .slider-fg {\n height: 100%; }\n .dg .c input[type=checkbox] {\n margin-top: 9px; }\n .dg .c select {\n margin-top: 5px; }\n .dg .cr.function,\n .dg .cr.function .property-name,\n .dg .cr.function *,\n .dg .cr.boolean,\n .dg .cr.boolean * {\n cursor: pointer; }\n .dg .selector {\n display: none;\n position: absolute;\n margin-left: -9px;\n margin-top: 23px;\n z-index: 10; }\n .dg .c:hover .selector,\n .dg .selector.drag {\n display: block; }\n .dg li.save-row {\n padding: 0; }\n .dg li.save-row .button {\n display: inline-block;\n padding: 0px 6px; }\n .dg.dialogue {\n background-color: #222;\n width: 460px;\n padding: 15px;\n font-size: 13px;\n line-height: 15px; }\n\n/* TODO Separate style and structure */\n#dg-new-constructor {\n padding: 10px;\n color: #222;\n font-family: Monaco, monospace;\n font-size: 10px;\n border: 0;\n resize: none;\n box-shadow: inset 1px 1px 1px #888;\n word-wrap: break-word;\n margin: 12px 0;\n display: block;\n width: 440px;\n overflow-y: scroll;\n height: 100px;\n position: relative; }\n\n#dg-local-explain {\n display: none;\n font-size: 11px;\n line-height: 17px;\n border-radius: 3px;\n background-color: #333;\n padding: 8px;\n margin-top: 10px; }\n #dg-local-explain code {\n font-size: 10px; }\n\n#dat-gui-save-locally {\n display: none; }\n\n/** Main type */\n.dg {\n color: #eee;\n font: 11px 'Lucida Grande', sans-serif;\n text-shadow: 0 -1px 0 #111;\n /** Auto place */\n /* Controller row,
  • */\n /** Controllers */ }\n .dg.main {\n /** Scrollbar */ }\n .dg.main::-webkit-scrollbar {\n width: 5px;\n background: #1a1a1a; }\n .dg.main::-webkit-scrollbar-corner {\n height: 0;\n display: none; }\n .dg.main::-webkit-scrollbar-thumb {\n border-radius: 5px;\n background: #676767; }\n .dg li:not(.folder) {\n background: #1a1a1a;\n border-bottom: 1px solid #2c2c2c; }\n .dg li.save-row {\n line-height: 25px;\n background: #dad5cb;\n border: 0; }\n .dg li.save-row select {\n margin-left: 5px;\n width: 108px; }\n .dg li.save-row .button {\n margin-left: 5px;\n margin-top: 1px;\n border-radius: 2px;\n font-size: 9px;\n line-height: 7px;\n padding: 4px 4px 5px 4px;\n background: #c5bdad;\n color: #fff;\n text-shadow: 0 1px 0 #b0a58f;\n box-shadow: 0 -1px 0 #b0a58f;\n cursor: pointer; }\n .dg li.save-row .button.gears {\n background: #c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;\n height: 7px;\n width: 8px; }\n .dg li.save-row .button:hover {\n background-color: #bab19e;\n box-shadow: 0 -1px 0 #b0a58f; }\n .dg li.folder {\n border-bottom: 0; }\n .dg li.title {\n padding-left: 16px;\n background: black url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;\n cursor: pointer;\n border-bottom: 1px solid rgba(255, 255, 255, 0.2); }\n .dg .closed li.title {\n background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); }\n .dg .cr.boolean {\n border-left: 3px solid #806787; }\n .dg .cr.function {\n border-left: 3px solid #e61d5f; }\n .dg .cr.number {\n border-left: 3px solid #2fa1d6; }\n .dg .cr.number input[type=text] {\n color: #2fa1d6; }\n .dg .cr.string {\n border-left: 3px solid #1ed36f; }\n .dg .cr.string input[type=text] {\n color: #1ed36f; }\n .dg .cr.function:hover, .dg .cr.boolean:hover {\n background: #111; }\n .dg .c input[type=text] {\n background: #303030;\n outline: none; }\n .dg .c input[type=text]:hover {\n background: #3c3c3c; }\n .dg .c input[type=text]:focus {\n background: #494949;\n color: #fff; }\n .dg .c .slider {\n background: #303030;\n cursor: ew-resize; }\n .dg .c .slider-fg {\n background: #2fa1d6; }\n .dg .c .slider:hover {\n background: #3c3c3c; }\n .dg .c .slider:hover .slider-fg {\n background: #44abda; }\n", 60 | dat.controllers.factory=function(e,a,b,d,f,c,p){return function(k,l,q,n){var r=k[l];if(p.isArray(q)||p.isObject(q))return new e(k,l,q);if(p.isNumber(r))return p.isNumber(q)&&p.isNumber(n)?new b(k,l,q,n):new a(k,l,{min:q,max:n});if(p.isString(r))return new d(k,l);if(p.isFunction(r))return new f(k,l,"");if(p.isBoolean(r))return new c(k,l)}}(dat.controllers.OptionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.StringController=function(e,a,b){var d= 61 | function(b,c){function e(){k.setValue(k.__input.value)}d.superclass.call(this,b,c);var k=this;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"keyup",e);a.bind(this.__input,"change",e);a.bind(this.__input,"blur",function(){k.__onFinishChange&&k.__onFinishChange.call(k,k.getValue())});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&this.blur()});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;b.extend(d.prototype, 62 | e.prototype,{updateDisplay:function(){a.isActive(this.__input)||(this.__input.value=this.getValue());return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common),dat.controllers.FunctionController,dat.controllers.BooleanController,dat.utils.common),dat.controllers.Controller,dat.controllers.BooleanController,dat.controllers.FunctionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.OptionController, 63 | dat.controllers.ColorController=function(e,a,b,d,f){function c(a,b,d,c){a.style.background="";f.each(l,function(e){a.style.cssText+="background: "+e+"linear-gradient("+b+", "+d+" 0%, "+c+" 100%); "})}function p(a){a.style.background="";a.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);";a.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; 64 | a.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}var k=function(e,n){function r(b){t(b);a.bind(window,"mousemove",t);a.bind(window, 65 | "mouseup",l)}function l(){a.unbind(window,"mousemove",t);a.unbind(window,"mouseup",l)}function g(){var a=d(this.value);!1!==a?(s.__color.__state=a,s.setValue(s.__color.toOriginal())):this.value=s.__color.toString()}function h(){a.unbind(window,"mousemove",u);a.unbind(window,"mouseup",h)}function t(b){b.preventDefault();var d=a.getWidth(s.__saturation_field),c=a.getOffset(s.__saturation_field),e=(b.clientX-c.left+document.body.scrollLeft)/d;b=1-(b.clientY-c.top+document.body.scrollTop)/d;1 66 | b&&(b=0);1e&&(e=0);s.__color.v=b;s.__color.s=e;s.setValue(s.__color.toOriginal());return!1}function u(b){b.preventDefault();var d=a.getHeight(s.__hue_field),c=a.getOffset(s.__hue_field);b=1-(b.clientY-c.top+document.body.scrollTop)/d;1b&&(b=0);s.__color.h=360*b;s.setValue(s.__color.toOriginal());return!1}k.superclass.call(this,e,n);this.__color=new b(this.getValue());this.__temp=new b(0);var s=this;this.domElement=document.createElement("div");a.makeSelectable(this.domElement,!1); 67 | this.__selector=document.createElement("div");this.__selector.className="selector";this.__saturation_field=document.createElement("div");this.__saturation_field.className="saturation-field";this.__field_knob=document.createElement("div");this.__field_knob.className="field-knob";this.__field_knob_border="2px solid ";this.__hue_knob=document.createElement("div");this.__hue_knob.className="hue-knob";this.__hue_field=document.createElement("div");this.__hue_field.className="hue-field";this.__input=document.createElement("input"); 68 | this.__input.type="text";this.__input_textShadow="0 1px 1px ";a.bind(this.__input,"keydown",function(a){13===a.keyCode&&g.call(this)});a.bind(this.__input,"blur",g);a.bind(this.__selector,"mousedown",function(b){a.addClass(this,"drag").bind(window,"mouseup",function(b){a.removeClass(s.__selector,"drag")})});var v=document.createElement("div");f.extend(this.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"});f.extend(this.__field_knob.style, 69 | {position:"absolute",width:"12px",height:"12px",border:this.__field_knob_border+(0.5>this.__color.v?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1});f.extend(this.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1});f.extend(this.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"});f.extend(v.style,{width:"100%",height:"100%", 70 | background:"none"});c(v,"top","rgba(0,0,0,0)","#000");f.extend(this.__hue_field.style,{width:"15px",height:"100px",display:"inline-block",border:"1px solid #555",cursor:"ns-resize"});p(this.__hue_field);f.extend(this.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:this.__input_textShadow+"rgba(0,0,0,0.7)"});a.bind(this.__saturation_field,"mousedown",r);a.bind(this.__field_knob,"mousedown",r);a.bind(this.__hue_field,"mousedown",function(b){u(b);a.bind(window, 71 | "mousemove",u);a.bind(window,"mouseup",h)});this.__saturation_field.appendChild(v);this.__selector.appendChild(this.__field_knob);this.__selector.appendChild(this.__saturation_field);this.__selector.appendChild(this.__hue_field);this.__hue_field.appendChild(this.__hue_knob);this.domElement.appendChild(this.__input);this.domElement.appendChild(this.__selector);this.updateDisplay()};k.superclass=e;f.extend(k.prototype,e.prototype,{updateDisplay:function(){var a=d(this.getValue());if(!1!==a){var e=!1; 72 | f.each(b.COMPONENTS,function(b){if(!f.isUndefined(a[b])&&!f.isUndefined(this.__color.__state[b])&&a[b]!==this.__color.__state[b])return e=!0,{}},this);e&&f.extend(this.__color.__state,a)}f.extend(this.__temp.__state,this.__color.__state);this.__temp.a=1;var k=0.5>this.__color.v||0.5a&&(a+=1);return{h:360*a,s:e/c,v:c/255}},rgb_to_hex:function(a,b,d){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,b);return a=this.hex_with_component(a,0,d)},component_from_hex:function(a,b){return a>>8*b&255},hex_with_component:function(a,b,d){return d<<(e=8*b)|a&~(255<Tangram | © OSM contributors | Nextzen' 51 | }); 52 | 53 | if (query.quiet) { 54 | layer.options.attribution = ""; 55 | map.attributionControl.setPrefix(''); 56 | window.addEventListener("load", function() { 57 | var div = document.getElementById("mz-bug"); 58 | if (div != null) {div.style.display = "none";} 59 | div = document.getElementById("mz-citysearch"); 60 | if (div != null) {div.style.display = "none";} 61 | div = document.getElementById("mz-geolocator"); 62 | if (div != null) {div.style.display = "none";} 63 | }); 64 | } 65 | 66 | if (query.noscroll) { 67 | map.scrollWheelZoom.disable(); 68 | } 69 | 70 | window.layer = layer; 71 | var scene = layer.scene; 72 | window.scene = scene; 73 | 74 | // setView expects format ([lat, long], zoom) 75 | map.setView(map_start_location.slice(0, 3), map_start_location[2]); 76 | 77 | var hash = new L.Hash(map); 78 | 79 | // wait to add map until window is loaded, to avoid race condition with API key replacement 80 | window.addEventListener('load', function () { 81 | layer.addTo(map); 82 | }); 83 | 84 | return map; 85 | 86 | }()); 87 | -------------------------------------------------------------------------------- /styles/blurred-normal.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | raster: normal 20 | shaders: 21 | blocks: 22 | normal: | 23 | // box blur 24 | const int mSize = 5; // kernel width 25 | const int kSize = (mSize-1)/2; 26 | 27 | // loop over the kernel 28 | vec3 final = vec3(0.0); 29 | for (int i=-kSize; i <= kSize; ++i) { 30 | for (int j=-kSize; j <= kSize; ++j) { 31 | final += sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 32 | } 33 | } 34 | // find the mean of the sampled values (a simple box blur) 35 | vec3 mean = final / vec3(mSize*mSize); 36 | 37 | normal = mean; 38 | // normalize it 39 | normal = normalize(normal); 40 | 41 | layers: 42 | terrain: 43 | data: { source: normals, layer: _default } 44 | draw: 45 | hillshade: 46 | order: 0 47 | -------------------------------------------------------------------------------- /styles/combo.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | normals: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | rasters: [elevation] 15 | elevation: 16 | type: Raster 17 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 18 | url_params: 19 | api_key: your-nextzen-api-key 20 | max_zoom: 14 21 | 22 | lights: 23 | light2: 24 | type: directional 25 | direction: [0,0,-1] 26 | diffuse: 1. 27 | 28 | styles: 29 | hillshade: 30 | base: raster 31 | raster: custom 32 | shaders: 33 | uniforms: 34 | mult: 8 35 | blocks: 36 | normal: | 37 | normal = sampleRaster(0).rgb * mult - (mult - 1.); 38 | color: | 39 | color.rgb = 1.0 - sampleRaster(0).aaa; 40 | color.rgb = color.rgb * 10.; 41 | color.a = 1.0; 42 | 43 | 44 | layers: 45 | terrain: 46 | data: { source: normals, layer: _default } 47 | draw: 48 | hillshade: 49 | order: 0 50 | color: white 51 | 52 | water: 53 | data: { source: nextzen } 54 | filter: {boundary: true} 55 | draw: 56 | lines: 57 | order: 2 58 | color: [.3, .3, .3] 59 | width: 1px 60 | 61 | places: 62 | data: { source: nextzen } 63 | filter: 64 | kind: [city] 65 | draw: 66 | text: 67 | font: 68 | fill: white 69 | size: 16px 70 | stroke: { color: '#444', width: 4px} 71 | -------------------------------------------------------------------------------- /styles/contours.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | elevation: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | hillshade: 17 | base: raster 18 | animated: true 19 | lighting: false 20 | texcoords: true 21 | shaders: 22 | blocks: 23 | global: | 24 | float unpack(vec4 h) { 25 | // GPU reads each 0-255 channel as range 0-1, right where we want it 26 | // assemble to get height 27 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 28 | } 29 | color: | 30 | // Normal from heightmap 31 | // adapted from 32 | // http://stackoverflow.com/questions/5281261/generating-a-normal-map-from-a-height-map 33 | // http://stackoverflow.com/questions/15178225/normal-map-from-height-map-artifact 34 | float px = 1.; 35 | vec3 off = vec3(-px, 0, px); 36 | 37 | float h = unpack(color); 38 | 39 | // Sample heightmap at center, left, right, above, below 40 | float h01 = unpack(sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + off.xy))); 41 | float h21 = unpack(sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + off.zy))); 42 | float h10 = unpack(sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + off.yx))); 43 | float h12 = unpack(sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + off.yz))); 44 | 45 | // left/right + up/down kernel (softer) 46 | vec3 va = normalize(vec3(off.xy/-2./rasterPixelSize(0),h21-h01)); 47 | vec3 vb = normalize(vec3(off.yx/-2./rasterPixelSize(0),h12-h10)); 48 | 49 | normal = normalize(cross(va, vb)); 50 | 51 | // adjust width of line based on normals to produce thinner line on flatter surfaces 52 | float adj = (1. / normal.z) * 1. - .9999; 53 | float w = 1.5 * adj * (1.5 - fract(u_map_position.z)); 54 | float val = fract(h * (250. * (1. + fract(u_time * .001)))); 55 | float triangle = abs(1. * val - 1.0); 56 | float square = smoothstep(.0, w, triangle); 57 | square *= smoothstep(w, w+w, val); 58 | color.rgb = vec3(square); 59 | 60 | val = fract(h * (1000. * (1. + fract(u_time * .001)))); 61 | triangle = abs(1. * val - 1.0); 62 | square = smoothstep(.0, w, triangle); 63 | square *= smoothstep(w, w+w, val); 64 | color.rgb *= vec3(square); 65 | 66 | layers: 67 | terrain: 68 | data: { source: elevation, layer: _default } 69 | draw: 70 | hillshade: 71 | order: 0 72 | 73 | water: 74 | data: { source: nextzen } 75 | filter: 76 | - boundary: true 77 | draw: 78 | lines: 79 | order: 2 80 | color: [.3, .3, .3] 81 | width: 1px 82 | 83 | places: 84 | data: { source: nextzen } 85 | filter: 86 | kind: [city] 87 | draw: 88 | text: 89 | font: 90 | fill: white 91 | size: 16px 92 | stroke: { color: '#444', width: 4px} 93 | -------------------------------------------------------------------------------- /styles/contours2.yaml: -------------------------------------------------------------------------------- 1 | scene: 2 | animated: false 3 | background: 4 | color: white 5 | 6 | sources: 7 | nextzen: 8 | type: MVT 9 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 10 | url_params: 11 | api_key: your-nextzen-api-key 12 | max_zoom: 8 13 | rasters: [heightmap, normals] 14 | heightmap: 15 | type: Raster 16 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 17 | url_params: 18 | api_key: your-nextzen-api-key 19 | max_zoom: 14 20 | rasters: [normals] 21 | normals: 22 | type: Raster 23 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 24 | url_params: 25 | api_key: your-nextzen-api-key 26 | max_zoom: 14 27 | 28 | styles: 29 | hillshade: 30 | base: raster 31 | lighting: false 32 | # texcoords: true 33 | raster: custom 34 | shaders: 35 | blocks: 36 | global: | 37 | float unpack(vec4 h) { 38 | // GPU reads each 0-255 channel as range 0-1, right where we want it 39 | // assemble to get height 40 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 41 | } 42 | color: | 43 | // sample elevation 44 | float h = unpack(sampleRaster(0)); 45 | // sample normals 46 | vec3 normals = normalize(sampleRaster(1).xyz * 2. - 1.); 47 | 48 | // adjust width of line based on normals to produce thinner line on flatter surfaces 49 | float adj = (1. / normals.z) - 1.; 50 | // width 51 | float w = .05 * pow(2., 20. - u_tile_origin.z) * adj; 52 | // spacing 53 | float zoom_power = 20. - u_tile_origin.z; 54 | float power = pow(2., zoom_power); 55 | float scale = 100000.; 56 | float val = fract(h * scale / power); 57 | float triangle = abs(1. * val - 1.0); 58 | float square = smoothstep(.0, w, triangle); 59 | square *= smoothstep(w, w+w, val); 60 | color.rgb = vec3(square) + vec3(.8); 61 | 62 | val = fract(h * 10000.); 63 | triangle = abs(1. * val - 1.0); 64 | square = smoothstep(.0, w, triangle); 65 | square *= smoothstep(w, w+w, val); 66 | color.rgb *= vec3(square); 67 | color.a = 1.; 68 | 69 | layers: 70 | earth: 71 | data: { source: nextzen } 72 | draw: 73 | hillshade: 74 | order: 1 75 | water: 76 | data: { source: nextzen } 77 | filter: { kind: [lakes], boundary: true } 78 | draw: 79 | lines: 80 | order: 2 81 | color: [.3, .3, .3] 82 | width: 1px 83 | polygons: 84 | order: 4 85 | color: white 86 | -------------------------------------------------------------------------------- /styles/elevation-difference.yaml: -------------------------------------------------------------------------------- 1 | 2 | # hypsometric map 3 | 4 | 5 | sources: 6 | nextzen: 7 | type: MVT 8 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 9 | url_params: 10 | api_key: your-nextzen-api-key 11 | max_zoom: 8 12 | rasters: [normals, elevation] 13 | normals: 14 | type: Raster 15 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 16 | url_params: 17 | api_key: your-nextzen-api-key 18 | max_zoom: 14 19 | rasters: [elevation] 20 | elevation: 21 | type: Raster 22 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 23 | url_params: 24 | api_key: your-nextzen-api-key 25 | max_zoom: 14 26 | 27 | textures: 28 | hypsometric: 29 | url: ../img/gradient.png 30 | # filtering: nearest 31 | spheremap: 32 | url: ../img/shade1.png 33 | # filtering: nearest 34 | decoder: 35 | url: ../img/decoder.png 36 | 37 | 38 | styles: 39 | combo: 40 | base: raster 41 | raster: custom 42 | shaders: 43 | uniforms: 44 | u_scale: 3 45 | u_decoder: decoder 46 | u_palette: hypsometric 47 | blocks: 48 | global: | 49 | float unpack(vec4 h) { 50 | // GPU reads each 0-255 channel as range 0-1, right where we want it 51 | // assemble to get un-normalized height 52 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 53 | } 54 | color: | 55 | // elevation from elevation tiles 56 | vec4 elevation = sampleRaster(1); 57 | float height1 = unpack(elevation); 58 | // normalize to 0 - 1 59 | height1 = (height1 - 0.3321533203125)/(0.635833740234375 - 0.3321533203125); 60 | 61 | // elevation from normal tile alpha 62 | float height2 = 1.0 - sampleRaster(0).a; 63 | 64 | // check height against decoder ring image to un-quantize it 65 | vec3 ring = texture2D(u_decoder, vec2(height2,0.5)).rgb; 66 | ring.r *= 256.; 67 | ring.g *= 256. * 256.; 68 | height2 = (ring.r + ring.g); 69 | // range is now 0 - 19900, squish into 0 - 1: 70 | height2 /= 19900.; 71 | 72 | // height from elevation tiles 73 | color.rgb = vec3(height1); 74 | // height from normal alpha 75 | color.rgb = vec3(height2); 76 | 77 | //// exaggerate 78 | // color.rgb = color.rgb * u_scale - (u_scale - 1.); 79 | 80 | // hypsometric gradient from texture 81 | color.rgb = texture2D(u_palette, vec2(color.r,0.5)).rgb; 82 | 83 | // difference between the two sources: 84 | color.rgb = vec3(height1-height2)*150.; 85 | 86 | layers: 87 | terrain: 88 | data: { source: normals, layer: _default } 89 | draw: 90 | combo: 91 | order: 0 92 | water: 93 | data: { source: nextzen} 94 | draw: 95 | polygons: 96 | order: 4 97 | color: lightblue 98 | -------------------------------------------------------------------------------- /styles/elevation-extrude.yaml: -------------------------------------------------------------------------------- 1 | 2 | # hypsometric map 3 | 4 | camera: 5 | type: isometric 6 | axis: [0, 1] 7 | sources: 8 | nextzen: 9 | type: MVT 10 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 8 14 | rasters: [elevation] 15 | elevation: 16 | type: Raster 17 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 18 | url_params: 19 | api_key: your-nextzen-api-key 20 | max_zoom: 14 21 | 22 | textures: 23 | decoder: 24 | url: ../img/decoder.png 25 | 26 | 27 | 28 | styles: 29 | extrude: 30 | base: polygons 31 | raster: custom 32 | shaders: 33 | uniforms: 34 | u_scale: 3 35 | u_decoder: decoder 36 | blocks: 37 | global: | 38 | float unpack(vec4 h) { 39 | // GPU reads each 0-255 channel as range 0-1, right where we want it 40 | // assemble to get un-normalized height 41 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 42 | } 43 | position: | 44 | // elevation from elevation tiles 45 | vec4 elevation = sampleRaster(0); 46 | float height = unpack(elevation); 47 | // normalize to 0 - 1 48 | height = (height - 0.3321533203125)/(0.635833740234375 - 0.3321533203125); 49 | 50 | // height from elevation tiles 51 | //color.rgb = vec3(height); 52 | 53 | position.z *= height * 100.; 54 | 55 | layers: 56 | terrain: 57 | data: { source: normals, layer: _default } 58 | draw: 59 | combo: 60 | order: 0 61 | water: 62 | data: { source: nextzen} 63 | draw: 64 | extrude: 65 | order: 4 66 | color: lightblue 67 | -------------------------------------------------------------------------------- /styles/elevation-tiles.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | elevation: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | hillshade: 17 | base: raster 18 | lighting: false 19 | 20 | layers: 21 | terrain: 22 | data: { source: elevation, layer: _default } 23 | draw: 24 | hillshade: 25 | order: 0 26 | 27 | water: 28 | data: { source: nextzen } 29 | filter: { boundary: true } 30 | draw: 31 | lines: 32 | order: 2 33 | color: [.3, .3, .3] 34 | width: 1px 35 | 36 | places: 37 | data: { source: nextzen } 38 | filter: 39 | kind: [city] 40 | draw: 41 | text: 42 | font: 43 | fill: white 44 | size: 16px 45 | stroke: { color: '#444', width: 4px} 46 | -------------------------------------------------------------------------------- /styles/elevation-zoom-adjust.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | rasters: [normals] 9 | normals: 10 | type: Raster 11 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 12 | url_params: 13 | api_key: your-nextzen-api-key 14 | max_zoom: 14 15 | 16 | textures: 17 | hypsometric: 18 | url: ../img/gradient.png 19 | # filtering: nearest 20 | spheremap: 21 | url: ../img/shade1.png 22 | # filtering: nearest 23 | decoder: 24 | url: ../img/decoder.png 25 | 26 | 27 | styles: 28 | # combination of hypsometric and spheremap, using two separate textures 29 | combo: 30 | base: raster 31 | lighting: false 32 | raster: color 33 | shaders: 34 | defines: 35 | SCALE: 4. 36 | uniforms: 37 | u_contrast: 1. 38 | u_brightness: 1. 39 | u_scale: 8. 40 | u_palette: hypsometric 41 | u_envmap: spheremap 42 | u_decoder: decoder 43 | u_zoom_scale: 3.5 44 | blocks: 45 | global: | 46 | // Simplified view-independent environment map 47 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal, in float scale) { 48 | _normal.z *= scale; 49 | return texture2D(_tex, .5*(normalize(_normal).xy + 1.)); 50 | } 51 | float unpack(vec4 h) { 52 | // GPU reads each 0-255 channel as range 0-1, right where we want it 53 | // assemble to get un-normalized height 54 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 55 | } 56 | color: | 57 | // spheremap 58 | normal = color.rgb; 59 | normal.z *= u_scale; 60 | normal = normalize(normal); 61 | 62 | // turn terrain exaggeration up/down 63 | // fade out spheremap normals with a function 64 | float scale1 = 20./(u_map_position.z) + 1.5; 65 | float m = u_zoom_scale * (u_map_position.z - 0.8) * exp(u_map_position.z * -.29); 66 | m = clamp(m, 0., 1.5); 67 | 68 | // color = vec4(1., 0, 0, 1); 69 | // color = applyEnvmap(u_envmap, normal, 1./scale1); 70 | // vec3 spheremap = applyEnvmap(u_envmap, normal).rgb * 3. - 2.; 71 | // vec3 spheremap = applyEnvmap(u_envmap, normal).rgb * 1.; 72 | 73 | // apply contrast and brightness 74 | // color -= .1; 75 | // float contrast = m; 76 | // color.rgb = ((color.rgb - 0.5) * max(contrast, 0.)) + 0.5; 77 | // float brightness = .5 - m * .5; 78 | // color.rgb += brightness; 79 | 80 | // add hypsometric 81 | vec4 elevation = sampleRaster(1); 82 | float height1 = unpack(elevation); 83 | // normalize to 0 - 1 84 | height1 = (height1 - 0.3321533203125)/(0.635833740234375 - 0.3321533203125); 85 | // scale range by lifting lower end 86 | // float height1 = unpack(elevation) * SCALE - (SCALE - 1.)/2.; 87 | // // color = vec4(1.0); 88 | // height to color from palette LUT 89 | color = texture2D(u_palette, vec2(clamp(height1,0.0,1.0),.5)); 90 | // color = texture2D(u_palette, vec2(height1,.5)); 91 | 92 | // elevation from normal tile 93 | float height = 1.0 - sampleRaster(0).a; 94 | 95 | // check height against decoder ring to un-quantize it 96 | vec3 ring = texture2D(u_decoder, vec2(height,0.5)).rgb; 97 | ring.r *= 256.; 98 | ring.g *= 256. * 256.; 99 | // range is now 0 - 100 | height = (ring.r + ring.g); 101 | height /= 19900.; 102 | // height = 10000.; 103 | 104 | 105 | vec3 hypsometric = texture2D(u_palette, vec2(height,0.5)).rgb; 106 | // // color.rgb = hypsometric * spheremap; 107 | // color.rgb *= hypsometric; 108 | // color = vec4(1.); 109 | // color.rgb *= height; 110 | // color.rgb = test; 111 | color.rgb = hypsometric; 112 | color.rgb = vec3(height); 113 | // color.rgb = vec3(height1); 114 | // color.rgb = vec3(height-height1)*50.; 115 | // color.rgb *= spheremap * 1.; 116 | 117 | hypsometric: 118 | base: raster 119 | lighting: false 120 | shaders: 121 | blocks: 122 | global: | 123 | color: | 124 | 125 | 126 | layers: 127 | terrain: 128 | data: { source: normals, layer: _default } 129 | draw: 130 | combo: 131 | order: 0 132 | color: white 133 | roads: 134 | data: { source: nextzen} 135 | draw: 136 | lines: 137 | order: 5 138 | color: [.8, .3, .3] 139 | width: 2px 140 | 141 | water: 142 | data: { source: nextzen} 143 | enabled: false 144 | draw: 145 | polygons: 146 | order: 4 147 | color: lightblue 148 | // width: 2px 149 | lines: 150 | order: 5 151 | color: [.2, .2, .8] 152 | width: .5px 153 | landuse: 154 | data: { source: nextzen} 155 | filter: { kind: [forest, park, conservation, nature_reserve, national_park] } 156 | draw: 157 | # polygons: 158 | # order: 1 159 | # color: green 160 | # width: 2px 161 | # lines: 162 | # style: textured-lines 163 | # order: 200 164 | # color: blue 165 | # width: 10px 166 | -------------------------------------------------------------------------------- /styles/environment-map1.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | normals: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | terrain-envmap: 17 | base: raster 18 | lighting: false 19 | raster: normal 20 | shaders: 21 | uniforms: 22 | u_scale: .5 23 | u_envmap: ../img/matball01.jpg 24 | blocks: 25 | global: | 26 | // Simplified view-independent environment map 27 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 28 | vec2 uv = 0.5 * _normal.xy + 0.5; 29 | return texture2D(_tex, uv); 30 | } 31 | color: | 32 | normal.z *= u_scale; 33 | normal = normalize(normal); 34 | color = applyEnvmap(u_envmap, normal); 35 | 36 | layers: 37 | terrain: 38 | data: { source: normals, layer: _default } 39 | draw: 40 | terrain-envmap: 41 | order: 0 42 | 43 | water: 44 | data: { source: nextzen } 45 | filter: 46 | - boundary: true 47 | - kind: [river, stream] 48 | draw: 49 | lines: 50 | order: 2 51 | color: [.3, .3, .3] 52 | width: 1px 53 | 54 | places: 55 | data: { source: nextzen } 56 | filter: 57 | kind: [city] 58 | draw: 59 | text: 60 | font: 61 | fill: white 62 | size: 16px 63 | stroke: { color: '#444', width: 4px} 64 | -------------------------------------------------------------------------------- /styles/grayscale.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | elevation: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | hillshade: 17 | base: raster 18 | lighting: false 19 | shaders: 20 | blocks: 21 | global: | 22 | float unpack(vec4 h) { 23 | // GPU reads each 0-255 channel as range 0-1, right where we want it 24 | // assemble to get height 25 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 26 | } 27 | color: | 28 | float height = unpack(color); 29 | color = vec4(1.0); 30 | 31 | // Color ramps 32 | vec3 colors[5]; 33 | colors[0] = vec3(0.); 34 | colors[1] = vec3(1.); 35 | 36 | color.rgb = mix(colors[0], colors[1], height * 50. - 25.); 37 | 38 | 39 | layers: 40 | terrain: 41 | data: { source: elevation, layer: _default } 42 | draw: 43 | hillshade: 44 | order: 0 45 | -------------------------------------------------------------------------------- /styles/green-avg.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | raster: normal 20 | shaders: 21 | blocks: 22 | global: | 23 | float normpdf(in float x, in float sigma) { 24 | return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma; 25 | } 26 | 27 | normal: | 28 | //declare stuff 29 | const int mSize = 17; 30 | const int kSize = (mSize-1)/2; 31 | float kernel[mSize]; 32 | vec3 final_colour = vec3(0.0); 33 | 34 | //create the 1-D kernel 35 | float sigma = 7.0; 36 | float Z = 0.0; 37 | for (int j = 0; j <= kSize; ++j) { 38 | kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma); 39 | } 40 | 41 | //get the normalization factor (as the gaussian has been clamped) 42 | for (int j = 0; j < mSize; ++j) { 43 | Z += kernel[j]; 44 | } 45 | 46 | //read out the texels 47 | for (int i=-kSize; i <= kSize; ++i) { 48 | for (int j=-kSize; j <= kSize; ++j) { 49 | final_colour += kernel[kSize+j]*kernel[kSize+i]*sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 50 | } 51 | } 52 | 53 | // if (dot(final_colour, normal) < 0.24) { 54 | // normal = vec3(final_colour/(Z*Z)); 55 | // normal = vec3(final_colour * (1.-dot(final_colour, normal))/(Z*Z) ); 56 | // normal = vec3(final_colour/(Z*Z) * 1.-dot(final_colour, normal)); 57 | // } 58 | // normal = vec3(final_colour/(Z*Z) ) * ( 1. - dot(final_colour, normal)); 59 | normal = vec3(final_colour/(Z*Z) ) *dot(final_colour, normal); 60 | normal.z *= 1./((.05 * float(mSize) - .23)); 61 | 62 | layers: 63 | terrain: 64 | data: { source: normals, layer: _default } 65 | draw: 66 | hillshade: 67 | order: 0 68 | -------------------------------------------------------------------------------- /styles/green-selectiveblur.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | raster: normal 20 | shaders: 21 | blocks: 22 | normal: | 23 | // box blur masked with a standard deviation 24 | // adapted from https://www.shadertoy.com/view/XdfGDH 25 | const int mSize = 5; // kernel width 26 | const int kSize = (mSize-1)/2; 27 | 28 | // loop over the kernel 29 | vec3 final = vec3(0.0); 30 | for (int i=-kSize; i <= kSize; ++i) { 31 | for (int j=-kSize; j <= kSize; ++j) { 32 | final += sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 33 | } 34 | } 35 | // find the mean of the sampled values (a simple box blur) 36 | vec3 mean = final / vec3(mSize*mSize); 37 | 38 | // loop over the kernel again, summing the squares of (samples - mean) 39 | vec3 squares = vec3(0.0); 40 | for (int i=-kSize; i <= kSize; ++i) { 41 | for (int j=-kSize; j <= kSize; ++j) { 42 | vec3 sample = sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 43 | vec3 difference = sample - mean; 44 | squares += difference*difference; 45 | } 46 | } 47 | // find the mean of the squares 48 | squares /= vec3(mSize*mSize); 49 | // take the square root of the mean 50 | vec3 stdev = vec3(sqrt(squares)); 51 | // finally, take the magnitude of the vector standard deviation 52 | stdev = vec3(length(stdev)); 53 | // scale to taste 54 | stdev *= 8.; 55 | // mix between the blurred and unblurred normals, using stdev as a mask 56 | normal = mix(mean, normal, stdev); 57 | // normalize it 58 | normal = normalize(normal); 59 | 60 | // debugging - uncomment to see the mask 61 | // normal = stdev; 62 | 63 | layers: 64 | terrain: 65 | data: { source: normals, layer: _default } 66 | draw: 67 | hillshade: 68 | order: 0 69 | -------------------------------------------------------------------------------- /styles/green-stdev-adjusted.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | raster: normal 20 | shaders: 21 | blocks: 22 | normal: | 23 | // box blur masked with a standard deviation 24 | 25 | // blur adapted from https://www.shadertoy.com/view/XdfGDH 26 | const int mSize = 5; // kernel width 27 | const int kSize = (mSize-1)/2; 28 | 29 | // this version samples in screen space instead of texture space, 30 | // to minimize the artifacts across zoom boundaries 31 | float fract = clamp(u_map_position.z - u_tile_origin.z, 0., 1.); 32 | float zoom = 1. - fract * .5; 33 | 34 | // loop over the kernel 35 | vec3 final = vec3(0.0); 36 | for (int i=-kSize; i <= kSize; ++i) { 37 | for (int j=-kSize; j <= kSize; ++j) { 38 | final += sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i)*zoom,float(j)*zoom))).rgb; 39 | } 40 | } 41 | // find the mean of the sampled values (a simple box blur) 42 | vec3 mean = final / vec3(mSize*mSize); 43 | 44 | // loop over the kernel again, summing the squares of (samples - mean) 45 | vec3 squares = vec3(0.0); 46 | for (int i=-kSize; i <= kSize; ++i) { 47 | for (int j=-kSize; j <= kSize; ++j) { 48 | vec3 sample = sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i)*zoom,float(j)*zoom))).rgb; 49 | vec3 difference = sample - mean; 50 | squares += difference*difference; 51 | } 52 | } 53 | // find the mean of the squares 54 | squares /= vec3(mSize*mSize); 55 | // take the square root of the mean 56 | vec3 stdev = vec3(sqrt(squares)); 57 | // finally, take the magnitude of the vector standard deviation 58 | stdev = vec3(dot(stdev,stdev)); 59 | // scale to taste 60 | 61 | // account for brightness differences across a single zoom level 62 | float scale = 80.; 63 | stdev *= scale - (scale/2. - fract * scale/2.); 64 | 65 | // mix between the blurred and unblurred normals, using stdev as a mask 66 | normal = mix(mean, normal, stdev); // hide this to see the original 67 | // normalize it 68 | normal = normalize(normal); 69 | 70 | // debugging 71 | // normal = mean; // unhide this to see the blurred version 72 | // normal = stdev; // unhide this to see the mask 73 | 74 | layers: 75 | terrain: 76 | data: { source: normals, layer: _default } 77 | draw: 78 | hillshade: 79 | order: 0 80 | -------------------------------------------------------------------------------- /styles/green-stdev-opt.yaml: -------------------------------------------------------------------------------- 1 | # with optimization assistance from Patricio Gonzalez Vivo 2 | sources: 3 | normals: 4 | type: Raster 5 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 6 | url_params: 7 | api_key: your-nextzen-api-key 8 | max_zoom: 14 9 | 10 | lights: 11 | directional1: 12 | type: directional 13 | direction: [0.5,-0.7,-0.5] 14 | diffuse: [1, 1.000, 0.75] 15 | ambient: [0.2, 0.3, 0.3] 16 | 17 | styles: 18 | hillshade: 19 | base: raster 20 | raster: normal 21 | shaders: 22 | blocks: 23 | normal: | 24 | // box blur masked with standard deviation 25 | // adapted from https://www.shadertoy.com/view/XdfGDH 26 | 27 | // set some constants, to reduce math operations later 28 | const int mSize = 5; // kernel width 29 | const int kSize = (mSize-1)/2; // 2 30 | const int mSize2 = mSize*mSize; // 25 31 | // store the reciprocal for later (multiplications are faster than divisions in glsl) 32 | const float mSize2reciprocal = 1./float(mSize2); // .25 33 | 34 | // loop over the kernel 35 | vec3 final = vec3(0.0); 36 | for (int i=-kSize; i <= kSize; ++i) { 37 | for (int j=-kSize; j <= kSize; ++j) { 38 | final += sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 39 | } 40 | } 41 | // find the mean of the sampled values (a simple box blur) 42 | // by dividing by the number of samples 43 | // aka multiplying by the reciprocal of the kernel width squared 44 | vec3 mean = final * mSize2reciprocal; 45 | 46 | // loop over the kernel again, summing the squares of (samples - mean) 47 | vec3 squares = vec3(0.0); 48 | for (int i=-kSize; i <= kSize; ++i) { 49 | for (int j=-kSize; j <= kSize; ++j) { 50 | vec3 sample = sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 51 | vec3 difference = sample - mean; 52 | squares += difference*difference; 53 | } 54 | } 55 | // find the mean of the squares by dividing by the number of samples 56 | // aka multiplying by the reciprocal of the kernel width squared 57 | squares *= mSize2reciprocal; 58 | 59 | // take the square root of the mean 60 | vec3 stdev = vec3(0.); 61 | stdev = vec3(sqrt(squares)); 62 | 63 | // finally, find the magnitude^2 of the standard deviation with dot() 64 | stdev = vec3(dot(stdev,stdev)); 65 | 66 | // scale to taste 67 | stdev *= 80.; 68 | // clamp range to 0-1 (only matters with extreme stdev scales) 69 | stdev = clamp(stdev, 0., 1.); 70 | 71 | // mix between the blurred and unblurred normals, using stdev as a mask 72 | normal = mix(mean, normal, stdev); // comment this out to disable the effect 73 | // normalize it 74 | normal = normalize(normal); 75 | 76 | // uncomment this to see the mask 77 | // normal = stdev; 78 | 79 | layers: 80 | terrain: 81 | data: { source: normals, layer: _default } 82 | draw: 83 | hillshade: 84 | order: 0 85 | -------------------------------------------------------------------------------- /styles/green-stdev.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | raster: normal 20 | shaders: 21 | blocks: 22 | normal: | 23 | // box blur masked with a standard deviation 24 | // adapted from https://www.shadertoy.com/view/XdfGDH 25 | const int mSize = 5; // kernel width 26 | const int kSize = (mSize-1)/2; 27 | 28 | // loop over the kernel 29 | vec3 final = vec3(0.0); 30 | for (int i=-kSize; i <= kSize; ++i) { 31 | for (int j=-kSize; j <= kSize; ++j) { 32 | final += sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 33 | } 34 | } 35 | // find the mean of the sampled values (a simple box blur) 36 | vec3 mean = final / vec3(mSize*mSize); 37 | 38 | // loop over the kernel again, summing the squares of (samples - mean) 39 | vec3 squares = vec3(0.0); 40 | for (int i=-kSize; i <= kSize; ++i) { 41 | for (int j=-kSize; j <= kSize; ++j) { 42 | vec3 sample = sampleRasterAtPixel(0, vec2(currentRasterPixel(0) + vec2(float(i),float(j)))).rgb; 43 | vec3 difference = sample - mean; 44 | squares += difference*difference; 45 | } 46 | } 47 | // find the mean of the squares 48 | squares /= vec3(mSize*mSize); 49 | // take the square root of the mean 50 | vec3 stdev = vec3(sqrt(squares)); 51 | // finally, take the magnitude of the vector standard deviation 52 | stdev = vec3(length(stdev)); 53 | // scale to taste 54 | stdev *= 8.; 55 | // mix between the blurred and unblurred normals, using stdev as a mask 56 | normal = mix(mean, normal, stdev); 57 | // normalize it 58 | normal = normalize(normal); 59 | 60 | // debugging - uncomment to see the mask 61 | normal = stdev; 62 | 63 | layers: 64 | terrain: 65 | data: { source: normals, layer: _default } 66 | draw: 67 | hillshade: 68 | order: 0 69 | -------------------------------------------------------------------------------- /styles/green.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | raster: normal 20 | 21 | layers: 22 | terrain: 23 | data: { source: normals, layer: _default } 24 | draw: 25 | hillshade: 26 | order: 0 27 | -------------------------------------------------------------------------------- /styles/heightmap.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | normals: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | hillshade: 17 | base: raster 18 | lighting: false 19 | shaders: 20 | blocks: 21 | color: | 22 | color.rgb = 1.0 - color.aaa; 23 | color.a = 1.0; 24 | 25 | layers: 26 | terrain: 27 | data: { source: normals, layer: _default } 28 | draw: 29 | hillshade: 30 | order: 0 31 | -------------------------------------------------------------------------------- /styles/hypsometric-adjusted.yaml: -------------------------------------------------------------------------------- 1 | 2 | # this is a hypsometric map adjusted using a low-resolution global heightmap as 3 | # a reference image to pull up lower mountain ranges so they all mostly use the 4 | # same range in the hypsometric gradient. 5 | 6 | # After the adjustment, the map is no longer a true hypsometric – elevation and 7 | # color are no longer directly corellated. Instead, a degree of *relative* 8 | # elevation is factored in. 9 | 10 | # A separate, plain hypsometric gradient is used for bathymetric coloring. 11 | 12 | sources: 13 | nextzen: 14 | type: MVT 15 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 16 | url_params: 17 | api_key: your-nextzen-api-key 18 | max_zoom: 8 19 | rasters: [elevation, ref] 20 | elevation: 21 | type: Raster 22 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 23 | url_params: 24 | api_key: your-nextzen-api-key 25 | max_zoom: 14 26 | ref: 27 | type: Raster 28 | url: ../img/elevation0.png?{x}{y}{z} 29 | max_zoom: 0 30 | 31 | textures: 32 | palette: 33 | url: ../img/gradient.png 34 | ocean: 35 | url: ../img/gradient-ocean.png 36 | 37 | styles: 38 | land: 39 | base: raster 40 | raster: custom 41 | lighting: false 42 | shaders: 43 | uniforms: 44 | u_palette: palette 45 | blocks: 46 | global: | 47 | float unpack(vec4 h) { 48 | // GPU reads each 0-255 channel as range 0-1 49 | // assemble to get un-normalized height 50 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 51 | } 52 | color: | 53 | // elevation from elevation tiles 54 | float height = unpack(sampleRaster(0)); 55 | // normalize to 0 - 1 56 | height = (height - 0.3321533203125)/(0.635833740234375 - 0.3321533203125); 57 | 58 | // reference image is monochromatic so we only need one channel 59 | float ref = sampleRaster(1).r; 60 | 61 | float limit = .55; 62 | float range = .05; 63 | float mask = smoothstep(limit, limit + range, ref); 64 | 65 | float offset = (1. - ref) / 5.; 66 | offset *= mask; 67 | 68 | //// set offset to 0 to see un-adjusted hypsometric 69 | // offset = 0.; 70 | 71 | color = texture2D(u_palette, vec2(height + offset,0.5)); 72 | 73 | //// debugging 74 | //color.rgb = vec3(offset)*10.; 75 | //color.rgb = vec3(ref); 76 | //color.rgb = vec3(mask); 77 | ocean: 78 | base: raster 79 | raster: custom 80 | lighting: false 81 | shaders: 82 | defines: 83 | SCALE: 4 84 | uniforms: 85 | u_palette: ocean 86 | blocks: 87 | global: | 88 | float unpack(vec4 h) { 89 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 90 | } 91 | color: | 92 | float height = unpack(sampleRaster(0)) * SCALE - (SCALE - 1.)/2.; 93 | float offset = 0.; 94 | color = texture2D(u_palette, vec2(height + offset,0.5)); 95 | 96 | layers: 97 | earth: 98 | data: { source: nextzen} 99 | draw: 100 | land: 101 | order: 0 102 | water: 103 | data: { source: nextzen} 104 | draw: 105 | ocean: 106 | order: 1 107 | -------------------------------------------------------------------------------- /styles/hypsometric-spheremap.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | normals: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | rasters: [elevation] 15 | elevation: 16 | type: Raster 17 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 18 | url_params: 19 | api_key: your-nextzen-api-key 20 | max_zoom: 14 21 | 22 | textures: 23 | hypsometric: 24 | # url: ../img/hypsometric01.png 25 | url: https://raw.githubusercontent.com/tangrams/terrain-demos/master/img/hypsometric01.png 26 | # filtering: nearest 27 | spheremap: 28 | # url: ../img/imhof.jpg 29 | # url: https://rawgit.com/tangrams/terrain-demos/master/img/imhof5.jpg 30 | url: https://raw.githubusercontent.com/tangrams/terrain-demos/master/img/shade1.png 31 | # url: http://localhost:8080/img/shade1.png 32 | # filtering: nearest 33 | 34 | styles: 35 | # combination of hypsometric and spheremap, using two separate textures 36 | combo: 37 | base: raster 38 | lighting: false 39 | raster: custom 40 | shaders: 41 | defines: 42 | SCALE: 4. 43 | uniforms: 44 | u_scale: 3. 45 | u_palette: hypsometric 46 | u_envmap: spheremap 47 | blocks: 48 | global: | 49 | // Simplified view-independent environment map 50 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 51 | vec2 uv = 0.5 * _normal.xy + 0.5; 52 | return texture2D(_tex, uv); 53 | } 54 | float unpack(vec4 h) { 55 | // GPU reads each 0-255 channel as range 0-1, right where we want it 56 | // assemble to get height 57 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 58 | } 59 | color: | 60 | // spheremap 61 | normal = sampleRaster(0).xyz; 62 | normal.z *= u_scale; 63 | normal = normalize(normal); 64 | vec3 spheremap = applyEnvmap(u_envmap, normal).rgb * 3. - 2.; 65 | // vec3 spheremap = applyEnvmap(u_envmap, normal).rgb * 1.; 66 | 67 | // add hypsometric 68 | vec4 elevation = sampleRaster(1); 69 | // compress range by raising lowest level 70 | float height = unpack(elevation) * SCALE - (SCALE - 1.)/2.; 71 | 72 | // height to color from palette LUT 73 | // color = texture2D(u_palette, vec2(clamp(height,0.0,1.0),.5)); 74 | height = 1.0 - sampleRaster(0).a; 75 | vec3 hypsometric = texture2D(u_palette, vec2(height,0.5)).rgb; 76 | color.rgb = hypsometric * spheremap; 77 | 78 | //// debugging 79 | // color.rgb = hypsometric * 1.; 80 | // color.rgb = spheremap * 1.; 81 | // color.rgb = mix(hypsometric, spheremap, .5); 82 | hypsometric: 83 | base: raster 84 | lighting: false 85 | shaders: 86 | blocks: 87 | global: | 88 | color: | 89 | 90 | 91 | layers: 92 | terrain: 93 | data: { source: normals, layer: _default } 94 | draw: 95 | combo: 96 | order: 0 97 | water: 98 | data: { source: nextzen} 99 | draw: 100 | polygons: 101 | order: 1 102 | color: lightblue 103 | -------------------------------------------------------------------------------- /styles/hypsometric-spheremap2.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | normals: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | rasters: [elevation] 15 | elevation: 16 | type: Raster 17 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 18 | url_params: 19 | api_key: your-nextzen-api-key 20 | max_zoom: 14 21 | 22 | textures: 23 | hypsometric: 24 | # url: ../img/hypsometric01.png 25 | url: https://rawgit.com/tangrams/terrain-demos/master/img/hypsometric01.png 26 | # filtering: nearest 27 | spheremap: 28 | # url: ../img/imhof.jpg 29 | # url: https://rawgit.com/tangrams/terrain-demos/master/img/imhof5.jpg 30 | url: https://rawgit.com/tangrams/terrain-demos/master/img/shade1.png 31 | # url: http://localhost:8080/img/shade1.png 32 | # filtering: nearest 33 | 34 | styles: 35 | # combination of hypsometric and spheremap, using two separate textures 36 | combo: 37 | base: raster 38 | lighting: false 39 | raster: normal 40 | shaders: 41 | defines: 42 | SCALE: 4. 43 | uniforms: 44 | u_scale: .2 45 | u_palette: hypsometric 46 | u_envmap: spheremap 47 | blocks: 48 | global: | 49 | // Simplified view-independent environment map 50 | // vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 51 | // vec2 uv = 0.5 * _normal.xy + 0.5; 52 | // return texture2D(_tex, uv); 53 | // } 54 | float unpack(vec4 h) { 55 | // GPU reads each 0-255 channel as range 0-1, right where we want it 56 | // assemble to get height 57 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 58 | } 59 | 60 | // Simplified view-independent environment map 61 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 62 | const vec3 eye = vec3(0.,0.,-1.); 63 | vec3 r = reflect(eye, _normal); 64 | r.z += 1.0; 65 | float m = 2. * length(r); 66 | vec2 uv = r.xy / m + .5; 67 | return texture2D(_tex, uv); 68 | } 69 | color: | 70 | // spheremap 71 | // normal = sampleRaster(0).xyz * 2. - .5; 72 | float scale2 = 1./exp2(u_scale)-1.; 73 | normal.z *= scale2 * -1.; 74 | // normal = normalize(normal); 75 | // normal.z *= u_scale; 76 | // vec3 spheremap = applyEnvmap(u_envmap, normal).rgb * SCALE - (SCALE - 1.)/2.; 77 | // color = applyEnvmap(u_envmap, normal); 78 | // vec3 spheremap = applyEnvmap(u_envmap, normal).rgb * 1.; 79 | vec3 spheremap = applyEnvmap(u_envmap, normal).rgb; 80 | 81 | // add hypsometric 82 | vec4 elevation = sampleRaster(1); 83 | // compress range by raising lowest level 84 | float height = unpack(elevation) * SCALE - (SCALE - 1.)/2.; 85 | 86 | // height to color from palette LUT 87 | // color = texture2D(u_palette, vec2(clamp(height,0.0,1.0),.5)); 88 | height = 1.0 - sampleRaster(0).a; 89 | vec3 hypsometric = texture2D(u_palette, vec2(height,0.5)).rgb; 90 | color.rgb = hypsometric * spheremap; 91 | 92 | //// debugging 93 | // color.rgb = hypsometric * 1.; 94 | color.rgb = spheremap * 1.; 95 | // color.rgb = mix(hypsometric, spheremap, .5); 96 | hypsometric: 97 | base: raster 98 | lighting: false 99 | shaders: 100 | blocks: 101 | global: | 102 | color: | 103 | 104 | 105 | layers: 106 | terrain: 107 | data: { source: normals, layer: _default } 108 | draw: 109 | combo: 110 | order: 0 111 | water: 112 | data: { source: nextzen} 113 | draw: 114 | polygons: 115 | order: 1 116 | color: lightblue 117 | -------------------------------------------------------------------------------- /styles/hypsometric-texture.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | elevation: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | textures: 16 | palette: 17 | url: ../img/hypsometric01.png 18 | # url: https://rawgit.com/tangrams/terrain-demos/master/img/hypsometric01.png 19 | # filtering: nearest 20 | 21 | styles: 22 | hypsometric: 23 | base: raster 24 | lighting: false 25 | shaders: 26 | defines: 27 | SCALE: 4. 28 | uniforms: 29 | u_palette: palette 30 | blocks: 31 | global: | 32 | float unpack(vec4 h) { 33 | // GPU reads each 0-255 channel as range 0-1, right where we want it 34 | // assemble to get height 35 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 36 | } 37 | color: | 38 | // compress levels by raising floor 39 | float height = unpack(color) * SCALE - (SCALE - 1.)/2.; 40 | color = vec4(1.0); 41 | // height to color from palette LUT 42 | // color = texture2D(u_palette, vec2(clamp(height,0.0,1.0),.5)); 43 | color = texture2D(u_palette, vec2(height,0.5)); 44 | 45 | 46 | layers: 47 | terrain: 48 | data: { source: elevation, layer: _default } 49 | draw: 50 | hypsometric: 51 | order: 0 52 | -------------------------------------------------------------------------------- /styles/hypsometric.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | elevation: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | hillshade: 17 | base: raster 18 | lighting: false 19 | shaders: 20 | blocks: 21 | global: | 22 | float unpack(vec4 h) { 23 | // GPU reads each 0-255 channel as range 0-1, right where we want it 24 | // assemble to get height 25 | return (h.r * 1. + h.g / 256. + h.b / 65536.); 26 | } 27 | color: | 28 | float height = unpack(color); 29 | color = vec4(1.0); 30 | 31 | // Color ramps 32 | vec3 colors[5]; 33 | colors[0] = vec3(0.); 34 | colors[1] = vec3(.4, .55, .3); 35 | colors[2] = vec3(.9, .9, .6); 36 | colors[3] = vec3(.6, .4, .3); 37 | colors[4] = vec3(1., 1., 1.); 38 | 39 | float step1 = 0.5015; // bottom 40 | float step2 = 0.503; 41 | float step3 = 0.505; 42 | float step4 = 0.51; 43 | float step5 = 0.52; // top 44 | 45 | color.rgb = mix(colors[0], colors[1], smoothstep(step1, step2, height)); 46 | color.rgb = mix(color.rgb, colors[2], smoothstep(step2, step3, height)); 47 | color.rgb = mix(color.rgb, colors[3], smoothstep(step3, step4, height)); 48 | color.rgb = mix(color.rgb, colors[4], smoothstep(step4, step5, height)); 49 | 50 | 51 | layers: 52 | terrain: 53 | data: { source: elevation, layer: _default } 54 | draw: 55 | hillshade: 56 | order: 0 57 | -------------------------------------------------------------------------------- /styles/imhof.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | normals: 9 | type: Raster 10 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 11 | url_params: 12 | api_key: your-nextzen-api-key 13 | max_zoom: 14 14 | 15 | styles: 16 | terrain-envmap: 17 | base: raster 18 | lighting: false 19 | raster: normal 20 | shaders: 21 | uniforms: 22 | u_scale: .15 23 | u_envmap: ../img/imhof5.jpg 24 | blocks: 25 | global: | 26 | // Simplified view-independent environment map 27 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 28 | vec2 uv = 0.5 * _normal.xy + 0.5; 29 | return texture2D(_tex, uv); 30 | } 31 | color: | 32 | normal.z *= u_scale; 33 | normal = normalize(normal); 34 | color = applyEnvmap(u_envmap, normal); 35 | 36 | layers: 37 | terrain: 38 | data: { source: normals, layer: _default } 39 | draw: 40 | terrain-envmap: 41 | order: 0 42 | 43 | water: 44 | data: { source: nextzen } 45 | filter: {boundary: true, kind: ocean} 46 | draw: 47 | lines: 48 | order: 2 49 | color: [.3, .3, .3] 50 | width: 1px 51 | 52 | places: 53 | data: { source: nextzen } 54 | filter: 55 | kind: [city] 56 | draw: 57 | text: 58 | font: 59 | fill: white 60 | size: 16px 61 | stroke: { color: '#444', width: 4px} 62 | -------------------------------------------------------------------------------- /styles/imhof2.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | rasters: [normals] 9 | normals: 10 | type: Raster 11 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 12 | url_params: 13 | api_key: your-nextzen-api-key 14 | max_zoom: 14 15 | 16 | styles: 17 | terrain-envmap: 18 | base: raster 19 | raster: normal 20 | lighting: false 21 | shaders: 22 | uniforms: 23 | u_scale: .15 24 | u_envmap: https://raw.githubusercontent.com/tangrams/terrain-demos/master/img/imhof5.jpg 25 | blocks: 26 | global: | 27 | // Simplified view-independent environment map 28 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 29 | vec2 uv = 0.5 * _normal.xy + 0.5; 30 | return texture2D(_tex, uv); 31 | } 32 | color: | 33 | normal.z *= u_scale; 34 | normal = normalize(normal); 35 | color = applyEnvmap(u_envmap, normal); 36 | dots: 37 | base: lines 38 | dash: [1, 2] 39 | fadelines: 40 | base: lines 41 | blend: multiply 42 | fadetext: 43 | base: text 44 | blend: overlay 45 | fadepolys: 46 | base: raster 47 | mix: terrain-envmap 48 | shaders: 49 | blocks: 50 | color: | 51 | color *= vec4(1.2); 52 | layers: 53 | terrain: 54 | data: { source: normals, layer: _default } 55 | draw: 56 | terrain-envmap: 57 | order: 0 58 | 59 | places: 60 | data: { source: nextzen } 61 | filter: 62 | kind: [city] 63 | draw: 64 | text: 65 | font: 66 | fill: white 67 | size: 10px 68 | stroke: { color: '#444', width: 4px} 69 | boundaries: 70 | data: { source: nextzen } 71 | draw: 72 | dots: 73 | color: [.75, .75, .75] 74 | width: 1px 75 | water: 76 | data: { source: nextzen } 77 | lines: 78 | filter: {boundary: true} 79 | draw: 80 | lines: 81 | order: 5 82 | color: [.3, .3, .3] 83 | width: .3px 84 | water-terrain: 85 | data: { source: nextzen, layer: water } 86 | draw: 87 | fadepolys: 88 | order: 4 89 | 90 | roads: 91 | data: { source: nextzen } 92 | draw: 93 | fadelines: 94 | order: 3 95 | color: [[10, [.9, .9, .9]], [18, white]] 96 | width: [[13, 1.5px], [15, 5]] 97 | labels: 98 | filter: {$zoom: {min: 10}} 99 | draw: 100 | fadetext: 101 | buffer: 10px 102 | font: 103 | size: 10px 104 | family: Lucida Grande 105 | fill: function() {return [1, 1, 1, $zoom/15.];} 106 | stroke: 107 | color: function() {return [0, 0, 0, $zoom/15.];} 108 | width: 1px 109 | places: 110 | data: { source: nextzen } 111 | filter: { not: { kind: [neighbourhood] } } 112 | countries: 113 | filter: { kind: country } 114 | draw: 115 | text: 116 | font: 117 | transform: uppercase 118 | size: 10px 119 | family: Lucida Grande 120 | fill: white 121 | stroke: 122 | color: black 123 | width: 2px 124 | cities: 125 | filter: { not: { kind: [country, state] } } 126 | also: 127 | filter: 128 | any: 129 | - $zoom: { min: 6, max: 8 } 130 | - { labelrank: {min: 5}, $zoom: { max: 6 }} 131 | - { population: { min: 100000 } , $zoom: {min: 8 } } 132 | - { population: { min: 50000 } , $zoom: {min: 12 } } 133 | draw: 134 | text: 135 | optional: false 136 | font: 137 | size: 10px 138 | family: Lucida Grande 139 | fill: white 140 | stroke: 141 | color: black 142 | width: 2px 143 | states: 144 | filter: 145 | - kind: state 146 | $zoom: { min: 6 } 147 | draw: 148 | text: 149 | priority: 3 150 | font: 151 | transform: uppercase 152 | size: 10px 153 | family: Lucida Grande 154 | fill: white 155 | stroke: 156 | color: black 157 | width: 2px 158 | buildings: 159 | data: {source: nextzen } 160 | draw: 161 | fadelines: 162 | order: 10 163 | color: [.95, .95, .95] 164 | width: 2px 165 | -------------------------------------------------------------------------------- /styles/kinkade-style.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | nextzen: 3 | type: MVT 4 | url: https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 8 8 | rasters: [normals] 9 | normals: 10 | type: Raster 11 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 12 | url_params: 13 | api_key: your-nextzen-api-key 14 | max_zoom: 14 15 | 16 | scene: 17 | background: 18 | color: white 19 | 20 | textures: 21 | spheremap: 22 | # element: "#kcanvas" 23 | url: https://tangrams.github.io/terrain-demos/img/shade1.png 24 | 25 | global: 26 | lines: true 27 | water: true 28 | labels: true 29 | 30 | styles: 31 | hillshade: 32 | base: polygons 33 | raster: normal 34 | lighting: false 35 | shaders: 36 | uniforms: 37 | u_scale: 5. 38 | u_envmap: spheremap 39 | blocks: 40 | global: | 41 | // Simplified view-independent environment map 42 | vec4 applyEnvmap (in sampler2D _tex, in vec3 _normal) { 43 | return texture2D(_tex, .5*(_normal.xy + 1.)); 44 | } 45 | color: | 46 | float scale = 1./(exp2(u_scale)-1.); 47 | normal.z *= scale; 48 | normal = normalize(normal); 49 | color = applyEnvmap(u_envmap, normal); 50 | 51 | dots: 52 | base: lines 53 | dash: [1, 2] 54 | dashes: 55 | base: lines 56 | dash: [1, 3] 57 | 58 | layers: 59 | earth: 60 | data: { source: nextzen } 61 | draw: 62 | hillshade: 63 | order: 0 64 | water: 65 | data: { source: nextzen } 66 | draw: 67 | polygons: 68 | visible: global.water 69 | order: 4 70 | color: white 71 | hillshade: 72 | order: 3 73 | lines: 74 | visible: global.lines 75 | order: 3 76 | color: [.3, .3, .3] 77 | width: .3px 78 | places: 79 | data: { source: nextzen } 80 | filter: { not: { kind: [neighbourhood] } } 81 | countries: 82 | filter: { kind: country } 83 | draw: 84 | points: 85 | visible: global.labels 86 | priority: 1 87 | color: [0, 0, 0, 0] 88 | size: 80px 89 | text: 90 | collide: false 91 | anchor: center 92 | visible: global.labels 93 | font: 94 | transform: uppercase 95 | size: 10pt 96 | family: Lucida Grande 97 | fill: white 98 | stroke: 99 | color: black 100 | width: 2px 101 | cities: 102 | filter: { not: { kind_detail: [country, state] } } 103 | also: 104 | filter: 105 | any: 106 | - $zoom: { min: 6, max: 8 } 107 | - { labelrank: {min: 5}, $zoom: { max: 6 }} 108 | - { population: { min: 100000 } , $zoom: {min: 8 } } 109 | - { population: { min: 50000 } , $zoom: {min: 12 } } 110 | draw: 111 | points: 112 | visible: global.labels 113 | priority: 2 114 | color: '#aaa' 115 | size: 8px 116 | text: 117 | optional: false 118 | font: 119 | size: 8pt 120 | family: Lucida Grande 121 | fill: white 122 | stroke: 123 | color: black 124 | width: 2px 125 | states: 126 | filter: 127 | - kind_detail: state 128 | $zoom: { min: 6 } 129 | draw: 130 | text: 131 | visible: global.labels 132 | priority: 3 133 | font: 134 | transform: uppercase 135 | size: 10pt 136 | family: Lucida Grande 137 | fill: white 138 | stroke: 139 | color: black 140 | width: 2px 141 | boundaries: 142 | data: { source: nextzen } 143 | draw: 144 | dots: 145 | order: 5 146 | visible: global.lines 147 | color: [.75, .75, .75] 148 | width: 1px 149 | roads: 150 | data: { source: nextzen } 151 | draw: 152 | dashes: 153 | order: 6 154 | visible: global.lines 155 | color: [.5, .5, .5] 156 | width: 1px 157 | -------------------------------------------------------------------------------- /styles/median-normal.yaml: -------------------------------------------------------------------------------- 1 | sources: 2 | normals: 3 | type: Raster 4 | url: https://tile.nextzen.org/tilezen/terrain/v1/256/normal/{z}/{x}/{y}.png 5 | url_params: 6 | api_key: your-nextzen-api-key 7 | max_zoom: 14 8 | 9 | lights: 10 | directional1: 11 | type: directional 12 | direction: [0.5,-0.7,-0.5] 13 | diffuse: [1, 1.000, 0.75] 14 | ambient: [0.2, 0.3, 0.3] 15 | 16 | styles: 17 | hillshade: 18 | base: raster 19 | lighting: false 20 | raster: normal 21 | shaders: 22 | defines: 23 | SORT_SIZE: int(8) 24 | SWAP(sort,a,b): t = max(sort[a],sort[b]); sort[a] = min(sort[a],sort[b]); sort[b] = t; 25 | 26 | SORT8: SWAP(sort,0, 1); SWAP(sort,2, 3); SWAP(sort,0, 2); SWAP(sort,1, 3); SWAP(sort,1, 2); SWAP(sort,4, 5); SWAP(sort,6, 7); SWAP(sort,4, 6); SWAP(sort,5, 7); SWAP(sort,5, 6); SWAP(sort,0, 4); SWAP(sort,1, 5); SWAP(sort,1, 4); SWAP(sort,2, 6); SWAP(sort,3, 7); SWAP(sort,3, 6); SWAP(sort,2, 4); SWAP(sort,3, 5); SWAP(sort,3, 4); 27 | 28 | SORT16: SWAP(sort,0, 1); SWAP(sort,2, 3); SWAP(sort,4, 5); SWAP(sort,6, 7); SWAP(sort,8, 9); SWAP(sort,10, 11); SWAP(sort,12, 13); SWAP(sort,14, 15); SWAP(sort,0, 2); SWAP(sort,4, 6); SWAP(sort,8, 10); SWAP(sort,12, 14); SWAP(sort,1, 3); SWAP(sort,5, 7); SWAP(sort,9, 11); SWAP(sort,13, 15); SWAP(sort,0, 4); SWAP(sort,8, 12); SWAP(sort,1, 5); SWAP(sort,9, 13); SWAP(sort,2, 6); SWAP(sort,10, 14); SWAP(sort,3, 7); SWAP(sort,11, 15); SWAP(sort,0, 8); SWAP(sort,1, 9); SWAP(sort,2, 10); SWAP(sort,3, 11); SWAP(sort,4, 12); SWAP(sort,5, 13); SWAP(sort,6, 14); SWAP(sort,7, 15); SWAP(sort,5, 10); SWAP(sort,6, 9); SWAP(sort,3, 12); SWAP(sort,13, 14); SWAP(sort,7, 11); SWAP(sort,1, 2); SWAP(sort,4, 8); SWAP(sort,1, 4); SWAP(sort,7, 13); SWAP(sort,2, 8); SWAP(sort,11, 14); SWAP(sort,2, 4); SWAP(sort,5, 6); SWAP(sort,9, 10); SWAP(sort,11, 13); SWAP(sort,3, 8); SWAP(sort,7, 12); SWAP(sort,6, 8); SWAP(sort,10, 12); SWAP(sort,3, 5); SWAP(sort,7, 9); SWAP(sort,3, 4); SWAP(sort,5, 6); SWAP(sort,7, 8); SWAP(sort,9, 10); SWAP(sort,11, 12); SWAP(sort,6, 7); SWAP(sort,8, 9); 29 | 30 | blocks: 31 | global: | 32 | float t; 33 | float sort[SORT_SIZE]; 34 | float quant(float x) { 35 | x = clamp(x,0.,1.); 36 | return floor(x*255.); 37 | } 38 | // pack a vec3 into a scalar for sorting 39 | float pack(vec3 c) { 40 | float lum = (c.x+c.y+c.z)*(1./3.); 41 | // sort by pseudo-luminance – put that in MSB and quantize everything to 8 bit 42 | // since floats represent 24 bit ints you get 3 channels and only have to sort a scalar value 43 | return quant(c.x) + quant(c.y)*256. + quant(lum) * 65536.; 44 | } 45 | // unpack a scalar back into a vec3 46 | vec3 unpack(float x) { 47 | float lum = floor(x * (1./65536.)) * (1./255.); 48 | vec3 c; 49 | c.x = floor(mod(x,256.)) * (1./255.); 50 | c.y = floor(mod(x*(1./256.),256.)) * (1./255.); 51 | c.z = lum * 3. - c.y - c.x; 52 | return c; 53 | } 54 | void Sort() { 55 | // change this and the SORT_SIZE value to 16 to use a larger kernel 56 | SORT8; 57 | // SOT16; 58 | } 59 | 60 | normal: | 61 | float medians[SORT_SIZE]; 62 | //do a bunch of 1D sorts on X 63 | for (int j=0; j