├── .eslintrc.js ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── build ├── procedural-gl.js ├── procedural-gl.min.js └── procedural-gl.module.js ├── docs ├── CNAME ├── build-docs.sh ├── docdash │ ├── .gitignore │ ├── LICENSE.md │ ├── README.md │ ├── conf.json │ ├── fixtures │ │ ├── base │ │ │ ├── chains.js │ │ │ └── index.js │ │ ├── documents │ │ │ ├── binder.js │ │ │ ├── collector.js │ │ │ ├── model.js │ │ │ ├── probe.js │ │ │ └── schema.js │ │ ├── fixtures.conf.json │ │ ├── mixins │ │ │ ├── bussable.js │ │ │ └── signalable.js │ │ ├── strings │ │ │ └── format.js │ │ ├── tutorials │ │ │ ├── Brush Teeth.md │ │ │ ├── Drive Car.md │ │ │ └── Fence Test.md │ │ └── utils │ │ │ └── logger.js │ ├── package.json │ ├── publish.js │ ├── static │ │ ├── scripts │ │ │ ├── linenumber.js │ │ │ └── prettify │ │ │ │ ├── Apache-License-2.0.txt │ │ │ │ ├── lang-css.js │ │ │ │ └── prettify.js │ │ └── styles │ │ │ ├── jsdoc.css │ │ │ └── prettify.css │ └── tmpl │ │ ├── augments.tmpl │ │ ├── container.tmpl │ │ ├── details.tmpl │ │ ├── example.tmpl │ │ ├── examples.tmpl │ │ ├── exceptions.tmpl │ │ ├── layout.tmpl │ │ ├── mainpage.tmpl │ │ ├── members.tmpl │ │ ├── method.tmpl │ │ ├── params.tmpl │ │ ├── properties.tmpl │ │ ├── returns.tmpl │ │ ├── source.tmpl │ │ ├── tutorial.tmpl │ │ └── type.tmpl ├── examples.json ├── examples │ ├── Lines │ │ ├── Basic Line.json │ │ ├── Line alpha.json │ │ ├── Line color.json │ │ ├── Line multicolor.json │ │ ├── Line outline.json │ │ └── Line thickness.json │ ├── Markers - Basics │ │ ├── Defaults.json │ │ ├── Icon+Text Marker.json │ │ ├── Image Marker.json │ │ ├── Multiple Markers.json │ │ ├── Single Marker.json │ │ └── Text Marker.json │ ├── Markers - Examples │ │ ├── Collapsing Pin.json │ │ ├── Icon with Popup.json │ │ └── Image Pin.json │ ├── Markers - Styling │ │ ├── Border Radius.json │ │ ├── Border Width.json │ │ ├── Colors.json │ │ ├── Font Size.json │ │ ├── Highlight Opacity.json │ │ ├── Not Selectable.json │ │ └── Padding.json │ ├── Markers - Visibility │ │ ├── Anchor (Basic).json │ │ ├── Anchor (Explicit).json │ │ ├── Anchor (Offset).json │ │ ├── Clipping.json │ │ ├── Collapse Distance.json │ │ └── Fade Distance.json │ ├── Other │ │ └── Empty Overlay.json │ └── combine_examples.py ├── img │ ├── blue-dot.png │ ├── lake.jpg │ ├── rock.jpg │ ├── screenshot.jpg │ ├── sun.jpg │ └── sunset.jpg ├── index.html ├── map │ └── index.html ├── module-Camera.html ├── module-Controls.html ├── module-Core.html ├── module-Environment.html ├── module-Environments.html ├── module-Features.html ├── module-Location.html ├── module-Procedural.html ├── module-Rendering.html ├── module-UI.html ├── overlays.html ├── scripts │ ├── codemirror.js │ ├── geojsonhint.js │ ├── javascript.js │ ├── linenumber.js │ ├── overlays.js │ ├── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js │ └── turf-bbox.js ├── static │ ├── ProceduralMap.js │ └── ProceduralMap.native.js └── styles │ ├── blackboard.css │ ├── codemirror.css │ ├── jsdoc.css │ ├── overlays.css │ └── prettify.css ├── index.dev.html ├── index.html ├── index.module.html ├── lib ├── alt.min.js ├── dat.gui.min.js ├── lodash.min.js ├── preact.umd.min.js ├── proj4.js ├── react-compat.js ├── three.js ├── three.module.js └── tilebelt.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── screenshots ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg └── title.jpg ├── shaders ├── .gitignore ├── beacon.frag ├── beacon.vert ├── fog.glsl ├── getHeight.glsl ├── lengthNormalize.glsl ├── line.frag ├── line.vert ├── marker.frag ├── marker.vert ├── minify.sh ├── picker.frag ├── picker.vert ├── positionFromTangent.glsl ├── postprocess.frag ├── quad.vert ├── quad_uv.vert ├── raycast.frag ├── raycast.vert ├── readTexVirtual.glsl ├── saturate.glsl ├── sky.frag ├── sky.vert ├── skyColor.glsl ├── skySpheremap.frag ├── skybox.frag ├── skyboxColor.glsl ├── terrain.frag ├── terrain.vert ├── terrainPicker.frag ├── terrainPicker.vert ├── tonemap.glsl └── vertexDiscard.glsl ├── src ├── actions │ ├── config.js │ ├── currentLocation.js │ ├── geodata.js │ ├── render.js │ └── user.js ├── adapters │ ├── osm.js │ └── overlay.js ├── alt.js ├── api │ └── geodata.js ├── app.js ├── atlas.js ├── camera.js ├── composer.js ├── constants.js ├── controls │ └── OrbitControls.js ├── currentLocation.js ├── data │ ├── line.js │ └── marker.js ├── datasources │ ├── base.js │ ├── elevation.js │ └── imagery.js ├── empty.js ├── envParams.js ├── export │ ├── camera.js │ ├── capabilities.js │ ├── controls.js │ ├── core.js │ ├── displayLocation.js │ ├── environments.js │ ├── features.js │ ├── location.js │ ├── pause.js │ └── userInterface.js ├── geometry │ ├── bufferMerge.js │ ├── line.js │ └── mapTile.js ├── geoproject.js ├── gl.js ├── glUtils.js ├── gui.js ├── heightAt.js ├── index.js ├── lineCurve.js ├── lines.js ├── linesBase.js ├── log.js ├── logo.svg ├── mapTile.js ├── markers.js ├── material.js ├── normalAt.js ├── patched │ └── Color.js ├── picker.js ├── picking.js ├── postprocessing │ ├── CopyShader.js │ ├── EffectComposer.js │ ├── Pass.js │ ├── RenderPass.js │ ├── SavePass.js │ └── ShaderPass.js ├── renderer.js ├── rollup-plugin-shader.js ├── scene.js ├── sky.js ├── skyBox.js ├── stores │ ├── animation.js │ ├── app.js │ ├── camera.js │ ├── container.js │ ├── currentLocation.js │ ├── engine.js │ ├── environment.js │ ├── error.js │ ├── features.js │ ├── geoproject.js │ ├── places.js │ ├── render.js │ ├── userInput.js │ └── userInterface.js ├── templates │ └── default.js ├── terrain.js ├── track.js ├── uniforms │ ├── depth.js │ ├── fog.js │ ├── height.js │ ├── line.js │ ├── marker.js │ ├── picker.js │ ├── postprocess.js │ ├── sky.js │ ├── skyBox.js │ ├── tag.js │ ├── tilepicker.js │ └── tonemap.js ├── utils │ ├── ImageLoader.js │ ├── IntegerPool.js │ ├── RGBABuffer.js │ ├── TextureArray.js │ ├── anchorForName.js │ ├── api.js │ ├── bindToVisible.js │ ├── clippingForName.js │ ├── dataToHeight.js │ ├── defer.js │ ├── feature.js │ ├── glyphForIcon.js │ ├── pushList.js │ ├── setterStore.js │ ├── shader.js │ ├── skyColor.js │ ├── store.js │ ├── tonemap.js │ ├── uiFont.js │ └── workQueue.js ├── views │ ├── button.jsx │ ├── buttonRow.jsx │ ├── compass.jsx │ ├── container.jsx │ ├── credits.jsx │ ├── engine.jsx │ ├── engineControlsBottom.jsx │ ├── engineControlsTop.jsx │ ├── logo.jsx │ ├── logoStyle.css │ ├── poweredBy.jsx │ └── root.jsx └── webgl.js └── webserver.sh /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'env': { 3 | 'browser': true, 4 | 'es2020': true 5 | }, 6 | 'extends': 'eslint-config-mdcs', 7 | 'globals': { 8 | '__dev__': true 9 | }, 10 | 'parserOptions': { 11 | 'ecmaVersion': 11, 12 | 'sourceType': 'module' 13 | }, 14 | 'rules': { 15 | 'indent': [ 'error', 2 ], 16 | 'padded-blocks': ['error', { 17 | 'blocks': 'never', 18 | 'switches': 'never', 19 | 'classes': 'never' 20 | }], 21 | 'space-unary-ops': [ 'error', { 22 | 'words': true, 'nonwords': false 23 | }] 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: felixpalmer 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | _Please bear in mind that I have a limited amount of time, and as such may not be able to address your issue right away. If you find the library useful, please consider [Sponsoring the project](https://github.com/sponsors/felixpalmer). Bugs & feature requests from Sponsors will be treated with priority._ 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Desktop (please complete the following information):** 29 | - OS: [e.g. iOS] 30 | - Browser [e.g. chrome, safari] 31 | - Version [e.g. 22] 32 | 33 | **Smartphone (please complete the following information):** 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **WebGL information** 40 | 41 | WebGL is complex and support varies across devices. To best help identify the issue, please visit https://webglreport.com/ and include the output from that page here. _Note include the WebGL1 data, **not** the WebGL2 data_ 42 | 43 | **Additional context** 44 | Add any other context about the problem here. 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Other issues 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | _Please bear in mind that I have a limited amount of time, and as such may not be able to address your issue right away. If you find the library useful, please consider Sponsoring the project. Bugs & feature requests from Sponsors will be treated with priority._ 11 | 12 | If you are reporting a bug or asking for a feature, please use the **Bug report** or **Feature request** templates. Failure to do so may result in your issue being closed and you will be asked to fill in the relevant template. 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please bear in mind that I have a limited amount of time, and as such may not be able to address your issue right away. If you find the library useful, please consider Sponsoring the project. Bugs & feature requests from Sponsors will be treated with priority. 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/*map 3 | build/procedural-gl.dev.js 4 | stats.html 5 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | www.procedural.eu -------------------------------------------------------------------------------- /docs/build-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Generating documentation..." 3 | EXPORT_DIR=../src/export/ 4 | jsdoc -t docdash \ 5 | --configure docdash/conf.json \ 6 | --destination . \ 7 | --readme ../README.md \ 8 | $EXPORT_DIR/camera.js \ 9 | $EXPORT_DIR/controls.js \ 10 | $EXPORT_DIR/core.js \ 11 | $EXPORT_DIR/displayLocation.js \ 12 | $EXPORT_DIR/environments.js \ 13 | $EXPORT_DIR/features.js \ 14 | $EXPORT_DIR/location.js \ 15 | $EXPORT_DIR/pause.js \ 16 | $EXPORT_DIR/userInterface.js 17 | 18 | echo "Combining examples..." 19 | cd examples 20 | ./combine_examples.py 21 | cd - 22 | -------------------------------------------------------------------------------- /docs/docdash/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.sublime-project 3 | *.sublime-workspace 4 | .DS_Store 5 | .DS_Store? 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | ehthumbs.db 10 | Thumbs.db 11 | logs 12 | *.log 13 | jspm_packages 14 | .npm 15 | -------------------------------------------------------------------------------- /docs/docdash/README.md: -------------------------------------------------------------------------------- 1 | # Docdash 2 | [![npm package](https://img.shields.io/npm/v/docdash.svg)](https://www.npmjs.com/package/docdash) [![license](https://img.shields.io/npm/l/docdash.svg)](LICENSE.md) 3 | 4 | A clean, responsive documentation template theme for JSDoc 3. 5 | 6 | ![docdash-screenshot](https://cloud.githubusercontent.com/assets/447956/13398144/4dde7f36-defd-11e5-8909-1a9013302cb9.png) 7 | 8 | ![docdash-screenshot-2](https://cloud.githubusercontent.com/assets/447956/13401057/e30effd8-df0a-11e5-9f51-66257ac38e94.jpg) 9 | 10 | ## Example 11 | See http://clenemt.github.io/docdash/ for a sample demo. :rocket: 12 | 13 | ## Install 14 | 15 | ```bash 16 | $ npm install docdash 17 | ``` 18 | 19 | ## Usage 20 | Clone repository to your designated `jsdoc` template directory, then: 21 | 22 | ```bash 23 | $ jsdoc entry-file.js -t path/to/docdash 24 | ``` 25 | 26 | ## Usage (npm) 27 | In your projects `package.json` file add a new script: 28 | 29 | ```json 30 | "script": { 31 | "generate-docs": "node_modules/.bin/jsdoc -c jsdoc.json" 32 | } 33 | ``` 34 | 35 | In your `jsdoc.json` file, add a template option. 36 | 37 | ```json 38 | "opts": { 39 | "template": "node_modules/docdash" 40 | } 41 | ``` 42 | 43 | ## Sample `jsdoc.json` 44 | See the config file for the [fixtures](fixtures/fixtures.conf.json) or the sample below. 45 | 46 | ```json 47 | { 48 | "tags": { 49 | "allowUnknownTags": false 50 | }, 51 | "source": { 52 | "include": "../js", 53 | "includePattern": ".js$", 54 | "excludePattern": "(node_modules/|docs)" 55 | }, 56 | "plugins": [ 57 | "plugins/markdown" 58 | ], 59 | "opts": { 60 | "template": "assets/template/docdash/", 61 | "encoding": "utf8", 62 | "destination": "docs/", 63 | "recurse": true, 64 | "verbose": true 65 | }, 66 | "templates": { 67 | "cleverLinks": false, 68 | "monospaceLinks": false 69 | } 70 | } 71 | ``` 72 | 73 | ## Options 74 | Docdash supports the following options: 75 | 76 | ``` 77 | { 78 | "docdash": { 79 | "static": [false|true], // Display the static members inside the navbar 80 | "sort": [false|true] // Sort the methods in the navbar 81 | } 82 | } 83 | ``` 84 | 85 | Place them anywhere inside your `jsdoc.json` file. 86 | 87 | ## Thanks 88 | Thanks to [lodash](https://lodash.com) and [minami](https://github.com/nijikokun/minami). 89 | 90 | ## License 91 | Licensed under the Apache License, version 2.0. (see [Apache-2.0](LICENSE.md)). 92 | -------------------------------------------------------------------------------- /docs/docdash/conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "templates": { 3 | "default": { 4 | "outputSourceFiles": false, 5 | "includeDate": false 6 | } 7 | }, 8 | "docdash": { 9 | "static": true, 10 | "sort": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /docs/docdash/fixtures/fixtures.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "source": { 6 | "include": [ 7 | "fixtures/", 8 | "./README.md" 9 | ] 10 | }, 11 | "plugins": ["plugins/markdown"], 12 | "opts": { 13 | "encoding": "utf8", 14 | "template": "../", 15 | "destination": "../fixtures-doc/", 16 | "recurse": true, 17 | "verbose": true 18 | }, 19 | "markdown": { 20 | "parser": "gfm", 21 | "hardwrap": true 22 | }, 23 | "templates": { 24 | "cleverLinks": false, 25 | "monospaceLinks": false, 26 | "default": { 27 | "outputSourceFiles": true, 28 | "includeDate": false 29 | } 30 | }, 31 | "docdash": { 32 | "static": false, 33 | "sort": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/docdash/fixtures/strings/format.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview String helper methods 4 | * 5 | * @module strings/format 6 | */ 7 | 8 | /** 9 | * Format a string quickly and easily using .net style format strings 10 | * @param {string} format A string format like "Hello {0}, now take off your {1}!" 11 | * @param {...?} args One argument per `{}` in the string, positionally replaced 12 | * @returns {string} 13 | * 14 | * @example 15 | * var strings = require("papyrus/strings"); 16 | * var s = strings.format("Hello {0}", "Madame Vastra"); 17 | * // s = "Hello Madame Vastra" 18 | * 19 | * @example {@lang xml} 20 | * 21 | * <%= strings.format("Hello {0}", "Madame Vastra") %> 22 | * 23 | */ 24 | module.exports = function ( format ) { 25 | var args = Array.prototype.slice.call( arguments, 1 ); 26 | return format.replace( /{(\d+)}/g, function ( match, number ) { 27 | return typeof args[number] != 'undefined' 28 | ? args[number] 29 | : match 30 | ; 31 | } ); 32 | }; 33 | -------------------------------------------------------------------------------- /docs/docdash/fixtures/tutorials/Drive Car.md: -------------------------------------------------------------------------------- 1 | #Lorem ipsum dolor sit amet 2 | 3 | Curabitur est mi, fermentum lacinia tincidunt vitae, mattis sit amet neque. Quisque diam nisl, accumsan ac porta tincidunt, iaculis facilisis ipsum. Nulla facilisi. Aenean a metus tortor. Pellentesque congue, mauris vitae viverra varius, elit nunc dictum nisl, rhoncus ultrices nulla sapien at leo. Duis ultricies porttitor diam. Nulla facilisi. Nullam elementum, lorem eu imperdiet laoreet, est turpis sollicitudin velit, in porttitor justo dolor vel urna. Mauris in ante magna. Curabitur vitae lacus in magna mollis commodo. 4 | 5 | ##Fusce lacinia, mauris ac aliquam consequat 6 | Fusce molestie blandit velit, sit amet dictum eros pharetra vitae. In erat urna, condimentum ac feugiat id, rutrum et nisi. Cras ac velit lorem. Nulla facilisi. Maecenas dignissim nulla in turpis tempus sed rhoncus augue dapibus. Nulla feugiat, urna non sagittis laoreet, dolor metus rhoncus justo, sed semper ante lacus eget quam. Sed ac ligula magna. Sed tincidunt pulvinar neque in porta. Nullam quis lacus orci. Pellentesque ornare viverra lacus, id aliquam magna venenatis a. 7 | 8 | Sed id tristique lorem. Ut sodales turpis nec mauris gravida interdum. Cras pellentesque, purus at suscipit euismod, elit nunc cursus nisi, ut venenatis metus sapien id velit. Sed lectus orci, pharetra non pulvinar vel, ullamcorper id lorem. Donec vulputate tincidunt ipsum, ut lacinia tortor sollicitudin id. Nunc nec nibh ut felis venenatis egestas. Proin risus mauris, eleifend eget interdum in, venenatis sed velit. Praesent sodales elit ut odio viverra posuere. Donec sapien lorem, molestie in egestas eget, vulputate sed orci. Aenean elit sapien, pellentesque vitae tempor sit amet, sagittis et ligula. Mauris aliquam sapien sit amet lacus ultrices rutrum. Curabitur nec dolor sed elit varius dignissim a a lacus. Aliquam ac convallis enim. 9 | 10 | Suspendisse orci massa, hendrerit sagittis lacinia consectetur, sagittis vitae purus. Aliquam id eros diam, eget elementum turpis. Nullam tellus magna, mollis in molestie id, venenatis rhoncus est. Proin id diam justo. Nunc tempus gravida justo at lobortis. Nam vitae venenatis nisi. Donec vel odio massa. Quisque interdum metus sit amet est iaculis tincidunt. Donec bibendum blandit purus, id semper orci aliquam quis. Nam tincidunt dolor eu felis ultricies tempor. Nulla non consectetur erat. 11 | -------------------------------------------------------------------------------- /docs/docdash/fixtures/tutorials/Fence Test.md: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non libero tristique, interdum quam in, fermentum massa. Aenean vestibulum velit eu massa faucibus accumsan. Aenean tempus quam ornare ligula gravida adipiscing. Suspendisse vestibulum diam quis quam lacinia convallis. Nunc rhoncus a elit ut dictum. Maecenas porta mi et risus convallis commodo. In hac habitasse platea dictumst. Morbi placerat sem nec eleifend hendrerit. Donec hendrerit pulvinar tristique. Pellentesque at nunc blandit, fringilla elit nec, dignissim arcu. Quisque sit amet enim urna. Nunc adipiscing lacinia justo. Pellentesque euismod nisi id elit auctor porttitor. Phasellus rutrum viverra felis, ac cursus ante vulputate ut. Donec laoreet felis ac risus vulputate sodales. 2 | 3 | Mauris sit amet risus non ligula lacinia iaculis. Sed ornare tellus velit, vel elementum quam porttitor tempus. Duis vestibulum augue eu diam malesuada auctor. Maecenas dignissim odio ut elit fermentum, id mollis leo mattis. Phasellus posuere augue sed interdum vestibulum. Etiam ac pharetra est. Integer tortor ligula, pharetra ac nisi nec, faucibus laoreet dolor. Nunc vehicula, enim et cursus tincidunt, nulla purus mollis urna, vel ultricies nisl mi a risus. Vestibulum sed urna sodales, pretium nisi sed, pretium sapien. Vivamus et massa tincidunt, semper nibh nec, eleifend urna. Integer auctor, eros at pharetra blandit, erat nibh mattis turpis, rhoncus elementum nisi mi vitae purus. 4 | 5 | Quisque elementum sapien id neque volutpat cursus non mattis velit. 6 | 7 | 8 | ``` 9 | $mod : function ( qu, value ) { 10 | var operands = sys.flatten( qu.operands ); 11 | if ( operands.length !== 2 ) { 12 | throw new Error( "$mod requires two operands" ); 13 | } 14 | var mod = operands[0]; 15 | var rem = operands[1]; 16 | return value % mod === rem; 17 | }, 18 | 19 | ``` 20 | 21 | 22 | ``` 23 | {@lang bash} 24 | #!/bin/bash 25 | echo Please, enter your firstname and lastname 26 | read FN LN 27 | echo "Hi! $LN, $FN !" 28 | ``` 29 | 30 | ```bash 31 | #!/bin/bash 32 | echo Please, enter your firstname and lastname 33 | read FN LN 34 | echo "Hi! $LN, $FN !" 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /docs/docdash/fixtures/utils/logger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @fileOverview The logging system for papyrus is based on [http://pimterry.github.io/loglevel/](loglevel) and slightly decorated 4 | * @module utils/logger 5 | * @requires dcl 6 | * @requires loglevel 7 | */ 8 | 9 | var dcl = require( "dcl" ); 10 | var log = require( 'loglevel' ); 11 | 12 | /** 13 | * A logger class that you can mix into your classes to handle logging settings and state at an object level. 14 | * See {@link utils/logger} for the members of this class 15 | * 16 | * @exports utils/logger.Logger 17 | * @class 18 | * @see utils/logger 19 | */ 20 | var Logger = dcl( null, /** @lends utils/logger.Logger# */{ 21 | declaredClass : "utils/Logger", 22 | 23 | /** 24 | * Turn off all logging. If you log something, it will not error, but will not do anything either 25 | * and the cycles are minimal. 26 | * 27 | */ 28 | silent : function () { 29 | log.disableAll(); 30 | }, 31 | /** 32 | * Turns on all logging levels 33 | * 34 | */ 35 | all : function () { 36 | log.enableAll(); 37 | }, 38 | /** 39 | * Sets the logging level to one of `trace`, `debug`, `info`, `warn`, `error`. 40 | * @param {string} lvl The level to set it to. Can be one of `trace`, `debug`, `info`, `warn`, `error`. 41 | * 42 | */ 43 | level : function ( lvl ) { 44 | if ( lvl.toLowerCase() === "none" ) { 45 | log.disableAll(); 46 | } else { 47 | log.setLevel( lvl ); 48 | } 49 | }, 50 | /** 51 | * Log a `trace` call 52 | * @method 53 | * @param {string} The value to log 54 | */ 55 | trace : log.trace, 56 | /** 57 | * Log a `debug` call 58 | * @method 59 | * @param {string} The value to log 60 | */ 61 | debug : log.debug, 62 | /** 63 | * Log a `info` call 64 | * @method 65 | * @param {string} The value to log 66 | */ 67 | info : log.info, 68 | /** 69 | * Log a `warn` call 70 | * @method 71 | * @param {string} The value to log 72 | */ 73 | warn : log.warn, 74 | /** 75 | * Log a `error` call 76 | * @method 77 | * @param {string} The value to log 78 | */ 79 | error : log.error 80 | } ); 81 | 82 | module.exports = new Logger(); 83 | /** 84 | * The system global, cross-platform logger 85 | * @name utils/logger 86 | * @static 87 | * @type {utils/logger.Logger} 88 | */ 89 | module.exports.Logger = Logger; 90 | -------------------------------------------------------------------------------- /docs/docdash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docdash", 3 | "version": "0.4.1", 4 | "description": "A clean, responsive documentation template theme for JSDoc 3 inspired by lodash and minami", 5 | "main": "publish.js", 6 | "scripts": { 7 | "test": "jsdoc -c fixtures/fixtures.conf.json", 8 | "sync": "browser-sync start -s ../fixtures-doc -f ../fixtures-doc --reload-delay 1000 --no-ui --no-notify", 9 | "watch": "watch-run -d 1000 -p tmpl/**,static/** \"npm run test\"" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/clenemt/docdash.git" 14 | }, 15 | "devDependencies": { 16 | "jsdoc": "latest", 17 | "browser-sync": "latest", 18 | "watch-run": "latest" 19 | }, 20 | "author": "Clement Moron ", 21 | "license": "Apache-2.0", 22 | "keywords": [ 23 | "jsdoc", 24 | "template" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /docs/docdash/static/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/docdash/static/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/docdash/static/styles/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #ddd; 3 | } 4 | 5 | /* string content */ 6 | .str { 7 | color: #61ce3c; 8 | } 9 | 10 | /* a keyword */ 11 | .kwd { 12 | color: #fbde2d; 13 | } 14 | 15 | /* a comment */ 16 | .com { 17 | color: #aeaeae; 18 | } 19 | 20 | /* a type name */ 21 | .typ { 22 | color: #8da6ce; 23 | } 24 | 25 | /* a literal value */ 26 | .lit { 27 | color: #fbde2d; 28 | } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #ddd; 33 | } 34 | 35 | /* lisp open bracket */ 36 | .opn { 37 | color: #000000; 38 | } 39 | 40 | /* lisp close bracket */ 41 | .clo { 42 | color: #000000; 43 | } 44 | 45 | /* a markup tag name */ 46 | .tag { 47 | color: #8da6ce; 48 | } 49 | 50 | /* a markup attribute name */ 51 | .atn { 52 | color: #fbde2d; 53 | } 54 | 55 | /* a markup attribute value */ 56 | .atv { 57 | color: #ddd; 58 | } 59 | 60 | /* a declaration */ 61 | .dec { 62 | color: #EF5050; 63 | } 64 | 65 | /* a variable name */ 66 | .var { 67 | color: #c82829; 68 | } 69 | 70 | /* a function name */ 71 | .fun { 72 | color: #4271ae; 73 | } 74 | 75 | /* Specify class=linenums on a pre to get line numbering */ 76 | ol.linenums { 77 | margin-top: 0; 78 | margin-bottom: 0; 79 | } 80 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/augments.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/example.tmpl: -------------------------------------------------------------------------------- 1 | 2 |
3 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/examples.tmpl: -------------------------------------------------------------------------------- 1 | 8 |

9 | 10 |
11 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/exceptions.tmpl: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 |
14 |
15 | Type 16 |
17 |
18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/layout.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?js= title ?> - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 28 | 29 |
30 | 31 |

32 | 33 | 34 | 35 |
36 | 37 |
38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/mainpage.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 |
8 |
9 |
10 | 11 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/members.tmpl: -------------------------------------------------------------------------------- 1 | 5 |

6 | 7 | 8 |

9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 |
Type:
21 | 26 | 27 | 28 | 29 |
Fires:
30 | 33 | 34 | 35 | 36 |
Example 1? 's':'' ?>
37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/returns.tmpl: -------------------------------------------------------------------------------- 1 | 5 |
6 | 7 |
8 | 9 | 10 | 11 |
12 |
13 | Type 14 |
15 |
16 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/source.tmpl: -------------------------------------------------------------------------------- 1 | 4 |
5 |
6 |
7 |
8 |
-------------------------------------------------------------------------------- /docs/docdash/tmpl/tutorial.tmpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 0) { ?> 5 |
    8 |
  • 9 |
10 | 11 | 12 |

13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 | -------------------------------------------------------------------------------- /docs/docdash/tmpl/type.tmpl: -------------------------------------------------------------------------------- 1 | 5 | 6 | | 7 | -------------------------------------------------------------------------------- /docs/examples/Lines/Basic Line.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "id": 0, 6 | "type": "Feature", 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | 13.55, 12 | 47.25 13 | ], 14 | [ 15 | 13.56, 16 | 47.26 17 | ] 18 | ] 19 | }, 20 | "properties": { 21 | "color": "#f30e32" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /docs/examples/Lines/Line alpha.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "LineString", 6 | "coordinates": [ 7 | [ 13.55, 47.21 ], 8 | [ 13.55, 47.224 ] 9 | ] 10 | }, 11 | "type": "Feature", 12 | "id": 0, 13 | "properties": { 14 | "color": "rgba(41,99, 233, 1)", 15 | "thickness": 4 16 | } 17 | }, 18 | { 19 | "geometry": { 20 | "type": "LineString", 21 | "coordinates": [ 22 | [ 13.549, 47.21 ], 23 | [ 13.549, 47.224 ] 24 | ] 25 | }, 26 | "type": "Feature", 27 | "id": 1, 28 | "properties": { 29 | "color": "rgba(41,99, 233, 0.8)", 30 | "thickness": 4 31 | } 32 | }, 33 | { 34 | "geometry": { 35 | "type": "LineString", 36 | "coordinates": [ 37 | [ 13.548, 47.21 ], 38 | [ 13.548, 47.224 ] 39 | ] 40 | }, 41 | "type": "Feature", 42 | "id": 2, 43 | "properties": { 44 | "color": "rgba(41,99, 233, 0.6)", 45 | "thickness": 4 46 | } 47 | }, 48 | { 49 | "geometry": { 50 | "type": "LineString", 51 | "coordinates": [ 52 | [ 13.547, 47.21 ], 53 | [ 13.547, 47.224 ] 54 | ] 55 | }, 56 | "type": "Feature", 57 | "id": 3, 58 | "properties": { 59 | "color": "rgba(41,99, 233, 0.4)", 60 | "thickness": 4 61 | } 62 | }, 63 | { 64 | "geometry": { 65 | "type": "LineString", 66 | "coordinates": [ 67 | [ 13.546, 47.21 ], 68 | [ 13.546, 47.224 ] 69 | ] 70 | }, 71 | "type": "Feature", 72 | "id": 4, 73 | "properties": { 74 | "color": "rgba(41,99, 233, 0.2)", 75 | "thickness": 4 76 | } 77 | } 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /docs/examples/Lines/Line color.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "id": 0, 6 | "type": "Feature", 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | 13.49, 12 | 47.21 13 | ], 14 | [ 15 | 13.475, 16 | 47.224 17 | ], 18 | [ 19 | 13.481, 20 | 47.23 21 | ], 22 | [ 23 | 13.51, 24 | 47.222 25 | ] 26 | ] 27 | }, 28 | "properties": { 29 | "color": "#f30e32" 30 | } 31 | }, 32 | { 33 | "id": 1, 34 | "type": "Feature", 35 | "geometry": { 36 | "type": "LineString", 37 | "coordinates": [ 38 | [ 39 | 13.51, 40 | 47.222 41 | ], 42 | [ 43 | 13.52, 44 | 47.222 45 | ], 46 | [ 47 | 13.525, 48 | 47.227 49 | ], 50 | [ 51 | 13.52, 52 | 47.252 53 | ] 54 | ] 55 | }, 56 | "properties": { 57 | "color": "#3205f1" 58 | } 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /docs/examples/Lines/Line multicolor.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "LineString", 6 | "coordinates": [ 7 | [ 13.457, 47.2315 ], 8 | [ 13.47, 47.22 ], 9 | [ 13.481, 47.23 ], 10 | [ 13.4901, 47.227 ] 11 | ], 12 | "colors": [ 13 | "#ff3121", 14 | "#ef2161", 15 | "#df0191", 16 | "#bf01d1" 17 | ] 18 | }, 19 | "type": "Feature", 20 | "id": 0, 21 | "properties": { 22 | "color": "#f30e32", 23 | "thickness": 4 24 | } 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /docs/examples/Lines/Line outline.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "LineString", 6 | "coordinates": [ 7 | [ 13.545, 47.255 ], 8 | [ 13.55, 47.255 ], 9 | [ 13.55, 47.25 ], 10 | [ 13.545, 47.25 ], 11 | [ 13.545, 47.253 ], 12 | [ 13.548, 47.253 ], 13 | [ 13.548, 47.252 ], 14 | [ 13.547, 47.251 ] 15 | ] 16 | }, 17 | "type": "Feature", 18 | "id": 0, 19 | "properties": { 20 | } 21 | } 22 | ], 23 | "defaults": { 24 | "properties": { 25 | "color": "crimson", 26 | "outlineColor": "white", 27 | "thickness": 6 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/examples/Lines/Line thickness.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "id": 0, 6 | "type": "Feature", 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | 13.454, 12 | 47.219 13 | ], 14 | [ 15 | 13.435, 16 | 47.214 17 | ], 18 | [ 19 | 13.451, 20 | 47.23 21 | ], 22 | [ 23 | 13.48, 24 | 47.213 25 | ] 26 | ] 27 | }, 28 | "properties": { 29 | "color": "#f30e32" 30 | } 31 | }, 32 | { 33 | "id": 1, 34 | "type": "Feature", 35 | "geometry": { 36 | "type": "LineString", 37 | "coordinates": [ 38 | [ 39 | 13.48, 40 | 47.213 41 | ], 42 | [ 43 | 13.454, 44 | 47.219 45 | ] 46 | ] 47 | }, 48 | "properties": { 49 | "color": "#12133d", 50 | "thickness": 5 51 | } 52 | } 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /docs/examples/Markers - Basics/Defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.567, 9 | 47.25 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "name": "Default color and background" 16 | } 17 | }, 18 | { 19 | "geometry": { 20 | "type": "Point", 21 | "coordinates": [ 22 | 13.567, 23 | 47.249 24 | ] 25 | }, 26 | "type": "Feature", 27 | "id": 1, 28 | "properties": { 29 | "name": "Color overridden", 30 | "color": "blue" 31 | } 32 | }, 33 | { 34 | "geometry": { 35 | "type": "Point", 36 | "coordinates": [ 37 | 13.567, 38 | 47.248 39 | ] 40 | }, 41 | "type": "Feature", 42 | "id": 2, 43 | "properties": { 44 | "name": "Background overridden", 45 | "background": "green" 46 | } 47 | } 48 | ], 49 | "defaults": { 50 | "properties": { 51 | "color": "white", 52 | "background": "black", 53 | "padding": 10, 54 | "clipping": "object" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /docs/examples/Markers - Basics/Icon+Text Marker.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.55, 9 | 47.27 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "color": "white", 16 | "padding": 10, 17 | "name": "Example", 18 | "icon": "star", 19 | "background": "green" 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /docs/examples/Markers - Basics/Image Marker.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.6, 9 | 47.23, 10 | 2500 11 | ] 12 | }, 13 | "type": "Feature", 14 | "id": 0, 15 | "properties": { 16 | "image": "img/blue-dot.png" 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /docs/examples/Markers - Basics/Multiple Markers.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "defaults": { 4 | "properties": { 5 | "color": "white", 6 | "padding": 10 7 | } 8 | }, 9 | "features": [ 10 | { 11 | "geometry": { 12 | "type": "Point", 13 | "coordinates": [ 14 | 13.56, 15 | 47.25 16 | ] 17 | }, 18 | "type": "Feature", 19 | "id": 0, 20 | "properties": { 21 | "background": "black", 22 | "icon": "info" 23 | } 24 | }, 25 | { 26 | "geometry": { 27 | "type": "Point", 28 | "coordinates": [ 29 | 13.557, 30 | 47.25 31 | ] 32 | }, 33 | "type": "Feature", 34 | "id": 1, 35 | "properties": { 36 | "background": "red", 37 | "icon": "bus" 38 | } 39 | }, 40 | { 41 | "geometry": { 42 | "type": "Point", 43 | "coordinates": [ 44 | 13.561, 45 | 47.2505 46 | ] 47 | }, 48 | "type": "Feature", 49 | "id": 2, 50 | "properties": { 51 | "background": "blue", 52 | "icon": "coffee" 53 | } 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /docs/examples/Markers - Basics/Single Marker.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.56, 9 | 47.25 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "background": "black", 16 | "color": "white", 17 | "padding": 10, 18 | "icon": "info" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /docs/examples/Markers - Basics/Text Marker.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.54, 9 | 47.27 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "color": "white", 16 | "padding": 10, 17 | "background": "black", 18 | "name": "Example" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /docs/examples/Markers - Examples/Collapsing Pin.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "Point", 6 | "coordinates": [ 13.544, 47.25343 ] 7 | }, 8 | "type": "Feature", 9 | "id": 0, 10 | "properties": { 11 | "name": "Hotel", 12 | "borderRadius": 25, 13 | "padding": 10, 14 | "borderWidth": 2, 15 | "background": "blue", 16 | "anchorOffset": { 17 | "y": 70, 18 | "x": 0 19 | }, 20 | "icon": "hotel" 21 | } 22 | }, 23 | { 24 | "geometry": { 25 | "type": "Point", 26 | "coordinates": [ 13.544, 47.25343 ] 27 | }, 28 | "type": "Feature", 29 | "id": 0, 30 | "properties": { 31 | "color": "#ddd", 32 | "fontSize": 11, 33 | "anchor": "center", 34 | "icon": "circle-o" 35 | } 36 | }, 37 | { 38 | "geometry": { 39 | "type": "Point", 40 | "coordinates": [ 13.544, 47.25343 ] 41 | }, 42 | "type": "Feature", 43 | "id": 0, 44 | "properties": { 45 | "color": "#ddd", 46 | "fontSize": 40, 47 | "name": "|", 48 | "anchor": "bottom", 49 | "anchorOffset": { 50 | "y": 3, 51 | "x": 0 52 | } 53 | } 54 | } 55 | ], 56 | "defaults": { 57 | "properties": { 58 | "color": "white", 59 | "collapseDistance": 3000, 60 | "fadeDistance": 5000 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Border Radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "defaults": { 4 | "properties": { 5 | "color": "blue", 6 | "padding": 10, 7 | "background": "white" 8 | } 9 | }, 10 | "features": [ 11 | { 12 | "geometry": { 13 | "type": "Point", 14 | "coordinates": [ 15 | 13.56, 16 | 47.25 17 | ] 18 | }, 19 | "type": "Feature", 20 | "id": 0, 21 | "properties": { 22 | "borderRadius": 0, 23 | "icon": "info" 24 | } 25 | }, 26 | { 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | 13.559, 31 | 47.25 32 | ] 33 | }, 34 | "type": "Feature", 35 | "id": 1, 36 | "properties": { 37 | "borderRadius": 4, 38 | "icon": "info" 39 | } 40 | }, 41 | { 42 | "geometry": { 43 | "type": "Point", 44 | "coordinates": [ 45 | 13.558, 46 | 47.25 47 | ] 48 | }, 49 | "type": "Feature", 50 | "id": 2, 51 | "properties": { 52 | "borderRadius": 100, 53 | "icon": "info" 54 | } 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Border Width.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "defaults": { 4 | "properties": { 5 | "color": "white", 6 | "padding": 10 7 | } 8 | }, 9 | "features": [ 10 | { 11 | "geometry": { 12 | "type": "Point", 13 | "coordinates": [ 14 | 13.547, 15 | 47.239 16 | ] 17 | }, 18 | "type": "Feature", 19 | "id": 0, 20 | "properties": { 21 | "name": "None", 22 | "background": "red" 23 | } 24 | }, 25 | { 26 | "geometry": { 27 | "type": "Point", 28 | "coordinates": [ 29 | 13.55, 30 | 47.239 31 | ] 32 | }, 33 | "type": "Feature", 34 | "id": 1, 35 | "properties": { 36 | "borderWidth": 2, 37 | "background": "blue", 38 | "name": "Normal" 39 | } 40 | }, 41 | { 42 | "geometry": { 43 | "type": "Point", 44 | "coordinates": [ 45 | 13.553, 46 | 47.239 47 | ] 48 | }, 49 | "type": "Feature", 50 | "id": 2, 51 | "properties": { 52 | "borderWidth": 5, 53 | "background": "green", 54 | "name": "Thick" 55 | } 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.54, 9 | 47.252 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "name": "Hex value: '#6719f3'", 16 | "background": "#6719f3" 17 | } 18 | }, 19 | { 20 | "geometry": { 21 | "type": "Point", 22 | "coordinates": [ 23 | 13.54, 24 | 47.254 25 | ] 26 | }, 27 | "type": "Feature", 28 | "id": 1, 29 | "properties": { 30 | "name": "Named color: 'crimson'", 31 | "background": "crimson" 32 | } 33 | }, 34 | { 35 | "geometry": { 36 | "type": "Point", 37 | "coordinates": [ 38 | 13.543, 39 | 47.252 40 | ] 41 | }, 42 | "type": "Feature", 43 | "id": 2, 44 | "properties": { 45 | "name": "RGB: 'rgb(101, 32, 77)'", 46 | "background": "rgb(101, 32, 77)" 47 | } 48 | }, 49 | { 50 | "geometry": { 51 | "type": "Point", 52 | "coordinates": [ 53 | 13.543, 54 | 47.254 55 | ] 56 | }, 57 | "type": "Feature", 58 | "id": 3, 59 | "properties": { 60 | "name": "RGBA: 'rgba(44, 244, 11, 0.2)'", 61 | "background": "rgba(44, 244, 11, 0.2)" 62 | } 63 | } 64 | ], 65 | "defaults": { 66 | "properties": { 67 | "padding": 10, 68 | "clipping": "object" 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Font Size.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "Point", 6 | "coordinates": [ 13.53, 47.253 ] 7 | }, 8 | "type": "Feature", 9 | "id": 0, 10 | "properties": { 11 | "name": "Text size 10", 12 | "fontSize": 10 13 | } 14 | }, 15 | { 16 | "geometry": { 17 | "type": "Point", 18 | "coordinates": [ 13.53, 47.2545 ] 19 | }, 20 | "type": "Feature", 21 | "id": 1, 22 | "properties": { 23 | "fontSize": 14, 24 | "name": "Text size 14" 25 | } 26 | }, 27 | { 28 | "geometry": { 29 | "type": "Point", 30 | "coordinates": [ 13.53, 47.257 ] 31 | }, 32 | "type": "Feature", 33 | "id": 2, 34 | "properties": { 35 | "fontSize": 20, 36 | "name": "Text size 20" 37 | } 38 | } 39 | ], 40 | "defaults": { 41 | "properties": { 42 | "color": "purple", 43 | "background": "cornsilk", 44 | "padding": 5 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Highlight Opacity.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "Point", 6 | "coordinates": [ 13.55, 47.24 ] 7 | }, 8 | "type": "Feature", 9 | "id": 0, 10 | "properties": { 11 | "highlightOpacity": 0, 12 | "name": "highlightOpacity 0" 13 | } 14 | }, { 15 | "geometry": { 16 | "type": "Point", 17 | "coordinates": [ 13.55, 47.241 ] 18 | }, 19 | "type": "Feature", 20 | "id": 1, 21 | "properties": { 22 | "name": "highlightOpacity 0.2 (default)" 23 | } 24 | }, { 25 | "geometry": { 26 | "type": "Point", 27 | "coordinates": [ 13.55, 47.242 ] 28 | }, 29 | "type": "Feature", 30 | "id": 2, 31 | "properties": { 32 | "highlightOpacity": 0.5, 33 | "name": "highlightOpacity 0.5" 34 | } 35 | }, { 36 | "geometry": { 37 | "type": "Point", 38 | "coordinates": [ 13.55, 47.243 ] 39 | }, 40 | "type": "Feature", 41 | "id": 3, 42 | "properties": { 43 | "highlightOpacity": 1, 44 | "name": "highlightOpacity 1" 45 | } 46 | } 47 | ], 48 | "defaults": { 49 | "properties": { 50 | "color": "white", 51 | "background": "crimson", 52 | "borderRadius": 25, 53 | "padding": 10, 54 | "icon": "star", 55 | "anchor": "left", 56 | "fadeDistance": 5000 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Not Selectable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ { 4 | "geometry": { 5 | "type": "Point", 6 | "coordinates": [ 13.542, 47.24 ] 7 | }, 8 | "type": "Feature", 9 | "id": 0, 10 | "properties": { 11 | "name": "selectable (default)", 12 | "icon": "check" 13 | } 14 | }, 15 | { 16 | "geometry": { 17 | "type": "Point", 18 | "coordinates": [ 13.542, 47.241 ] 19 | }, 20 | "type": "Feature", 21 | "id": 1, 22 | "properties": { 23 | "name": "not selectable", 24 | "selectable": false, 25 | "icon": "close" 26 | } 27 | } 28 | ], 29 | "defaults": { 30 | "properties": { 31 | "color": "white", 32 | "padding": 10, 33 | "borderRadius": 25, 34 | "background": "chocolate", 35 | "anchor": "left", 36 | "fadeDistance": 5000 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/examples/Markers - Styling/Padding.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "defaults": { 4 | "properties": { 5 | "color": "green" 6 | } 7 | }, 8 | "features": [ 9 | { 10 | "geometry": { 11 | "type": "Point", 12 | "coordinates": [ 13 | 13.56, 14 | 47.25 15 | ] 16 | }, 17 | "type": "Feature", 18 | "id": 0, 19 | "properties": { 20 | "padding": 0, 21 | "name": "small", 22 | "background": "#fff" 23 | } 24 | }, 25 | { 26 | "geometry": { 27 | "type": "Point", 28 | "coordinates": [ 29 | 13.559, 30 | 47.25 31 | ] 32 | }, 33 | "type": "Feature", 34 | "id": 1, 35 | "properties": { 36 | "padding": 10, 37 | "name": "medium", 38 | "background": "#ccc" 39 | } 40 | }, 41 | { 42 | "geometry": { 43 | "type": "Point", 44 | "coordinates": [ 45 | 13.558, 46 | 47.25 47 | ] 48 | }, 49 | "type": "Feature", 50 | "id": 2, 51 | "properties": { 52 | "padding": 20, 53 | "name": "large", 54 | "background": "#999" 55 | } 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /docs/examples/Markers - Visibility/Anchor (Explicit).json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.53, 9 | 47.2715 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "anchor": {"x": 1, "y": 0}, 16 | "name": "{x: 1, y:0}" 17 | } 18 | }, 19 | { 20 | "geometry": { 21 | "type": "Point", 22 | "coordinates": [ 23 | 13.54, 24 | 47.2515 25 | ] 26 | }, 27 | "type": "Feature", 28 | "id": 1, 29 | "properties": { 30 | "anchor": {"x": 0, "y": 1}, 31 | "name": "{x: 0, y: 1}" 32 | } 33 | }, 34 | { 35 | "geometry": { 36 | "type": "Point", 37 | "coordinates": [ 38 | 13.56, 39 | 47.2615 40 | ] 41 | }, 42 | "type": "Feature", 43 | "id": 2, 44 | "properties": { 45 | "anchor": {"x": 0, "y": 1.5}, 46 | "name": "{x: 0, y: 1.5}" 47 | } 48 | }, 49 | { 50 | "geometry": { 51 | "type": "Point", 52 | "coordinates": [ 53 | 13.53, 54 | 47.2715 55 | ] 56 | }, 57 | "type": "Feature", 58 | "id": 0, 59 | "properties": { 60 | "padding": 0, 61 | "borderWidth": 0, 62 | "icon": "circle" 63 | } 64 | }, 65 | { 66 | "geometry": { 67 | "type": "Point", 68 | "coordinates": [ 69 | 13.54, 70 | 47.2515 71 | ] 72 | }, 73 | "type": "Feature", 74 | "id": 1, 75 | "properties": { 76 | "padding": 0, 77 | "borderWidth": 0, 78 | "icon": "circle" 79 | } 80 | }, 81 | { 82 | "geometry": { 83 | "type": "Point", 84 | "coordinates": [ 85 | 13.56, 86 | 47.2615 87 | ] 88 | }, 89 | "type": "Feature", 90 | "id": 2, 91 | "properties": { 92 | "padding": 0, 93 | "borderWidth": 0, 94 | "icon": "circle" 95 | } 96 | } 97 | ], 98 | "defaults": { 99 | "properties": { 100 | "anchor": "center", 101 | "color": "white", 102 | "padding": 30, 103 | "clipping": "object", 104 | "borderWidth": 2 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /docs/examples/Markers - Visibility/Clipping.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "defaults": { 4 | "properties": { 5 | "color": "green", 6 | "padding": 20, 7 | "background": "white" 8 | } 9 | }, 10 | "features": [ 11 | { 12 | "geometry": { 13 | "type": "Point", 14 | "coordinates": [ 15 | 13.55, 16 | 47.233 17 | ] 18 | }, 19 | "type": "Feature", 20 | "id": 0, 21 | "properties": { 22 | "clipping": "pixel", 23 | "name": "Visibility calculated per pixel - (default)" 24 | } 25 | }, 26 | { 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | 13.55, 31 | 47.237 32 | ] 33 | }, 34 | "type": "Feature", 35 | "id": 1, 36 | "properties": { 37 | "clipping": "object", 38 | "name": "Visibility based on anchor point" 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /docs/examples/Markers - Visibility/Collapse Distance.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.55, 9 | 47.25 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "collapseDistance": 500, 16 | "fadeDistance": 2000, 17 | "name": "collapses at 500m, fades at 2km", 18 | "background": "blue" 19 | } 20 | }, 21 | { 22 | "geometry": { 23 | "type": "Point", 24 | "coordinates": [ 25 | 13.55, 26 | 47.251 27 | ] 28 | }, 29 | "type": "Feature", 30 | "id": 1, 31 | "properties": { 32 | "collapseDistance": 1000, 33 | "fadeDistance": 2000, 34 | "name": "collapses at 1km, fades at 2km", 35 | "background": "green" 36 | } 37 | }, 38 | { 39 | "geometry": { 40 | "type": "Point", 41 | "coordinates": [ 42 | 13.55, 43 | 47.252 44 | ] 45 | }, 46 | "type": "Feature", 47 | "id": 2, 48 | "properties": { 49 | "collapseDistance": 5000, 50 | "name": "collapses at 5km", 51 | "background": "red" 52 | } 53 | } 54 | ], 55 | "defaults": { 56 | "properties": { 57 | "color": "white", 58 | "padding": 10, 59 | "icon": "eye", 60 | "clipping": "object", 61 | "anchor": "left", 62 | "borderRadius": 10, 63 | "borderWidth": 1 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /docs/examples/Markers - Visibility/Fade Distance.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "geometry": { 6 | "type": "Point", 7 | "coordinates": [ 8 | 13.55, 9 | 47.25 10 | ] 11 | }, 12 | "type": "Feature", 13 | "id": 0, 14 | "properties": { 15 | "fadeDistance": 1000, 16 | "name": "fades at 1km", 17 | "background": "blue" 18 | } 19 | }, 20 | { 21 | "geometry": { 22 | "type": "Point", 23 | "coordinates": [ 24 | 13.55, 25 | 47.251 26 | ] 27 | }, 28 | "type": "Feature", 29 | "id": 1, 30 | "properties": { 31 | "fadeDistance": 2000, 32 | "name": "fades at 2km", 33 | "background": "green" 34 | } 35 | }, 36 | { 37 | "geometry": { 38 | "type": "Point", 39 | "coordinates": [ 40 | 13.55, 41 | 47.252 42 | ] 43 | }, 44 | "type": "Feature", 45 | "id": 2, 46 | "properties": { 47 | "fadeDistance": 5000, 48 | "name": "fades at 5km", 49 | "background": "red" 50 | } 51 | } 52 | ], 53 | "defaults": { 54 | "properties": { 55 | "clipping": "object", 56 | "color": "white", 57 | "padding": 10, 58 | "borderRadius": 10, 59 | "borderWidth": 1, 60 | "anchor": "left", 61 | "icon": "eye" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /docs/examples/Other/Empty Overlay.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [] 4 | } 5 | -------------------------------------------------------------------------------- /docs/examples/combine_examples.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from glob import glob 3 | import json 4 | import os 5 | 6 | 7 | def get_immediate_subdirectories(a_dir): 8 | return [name for name in os.listdir(a_dir) 9 | if os.path.isdir(os.path.join(a_dir, name))] 10 | 11 | 12 | # Combine all json examples into one 13 | out = [] 14 | directories = sorted(get_immediate_subdirectories('.')) 15 | for directory in directories: 16 | # Create group 17 | group = { 18 | "group": directory, 19 | "items": [] 20 | } 21 | 22 | # Add all examples 23 | examples = sorted(glob(os.path.join(directory, '*.json'))) 24 | for example in examples: 25 | with open(example, 'r') as f: 26 | name = example.split('/')[1].split('.')[0] 27 | group["items"].append({ 28 | "name": name, 29 | "value": json.load(f) 30 | }) 31 | 32 | out.append(group) 33 | 34 | 35 | with open('../examples.json', 'w') as f: 36 | json.dump(out, f) 37 | -------------------------------------------------------------------------------- /docs/img/blue-dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/docs/img/blue-dot.png -------------------------------------------------------------------------------- /docs/img/lake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/docs/img/lake.jpg -------------------------------------------------------------------------------- /docs/img/rock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/docs/img/rock.jpg -------------------------------------------------------------------------------- /docs/img/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/docs/img/screenshot.jpg -------------------------------------------------------------------------------- /docs/img/sun.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/docs/img/sun.jpg -------------------------------------------------------------------------------- /docs/img/sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/docs/img/sunset.jpg -------------------------------------------------------------------------------- /docs/overlays.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Overlay Editor 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 35 | 36 |
37 |
38 |
39 |

40 |
41 |
42 |
43 |
    44 |
  • Update
  • 45 |
  • Clear
  • 46 |
47 |
48 |
49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/styles/blackboard.css: -------------------------------------------------------------------------------- 1 | /* Port of TextMate's Blackboard theme */ 2 | 3 | .cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; } 4 | .cm-s-blackboard div.CodeMirror-selected { background: #253B76; } 5 | .cm-s-blackboard .CodeMirror-line::selection, .cm-s-blackboard .CodeMirror-line > span::selection, .cm-s-blackboard .CodeMirror-line > span > span::selection { background: rgba(37, 59, 118, .99); } 6 | .cm-s-blackboard .CodeMirror-line::-moz-selection, .cm-s-blackboard .CodeMirror-line > span::-moz-selection, .cm-s-blackboard .CodeMirror-line > span > span::-moz-selection { background: rgba(37, 59, 118, .99); } 7 | .cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; } 8 | .cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; } 9 | .cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; } 10 | .cm-s-blackboard .CodeMirror-linenumber { color: #888; } 11 | .cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7; } 12 | 13 | .cm-s-blackboard .cm-keyword { color: #FBDE2D; } 14 | .cm-s-blackboard .cm-atom { color: #D8FA3C; } 15 | .cm-s-blackboard .cm-number { color: #D8FA3C; } 16 | .cm-s-blackboard .cm-def { color: #8DA6CE; } 17 | .cm-s-blackboard .cm-variable { color: #FF6400; } 18 | .cm-s-blackboard .cm-operator { color: #FBDE2D; } 19 | .cm-s-blackboard .cm-comment { color: #AEAEAE; } 20 | .cm-s-blackboard .cm-string { color: #61CE3C; } 21 | .cm-s-blackboard .cm-string-2 { color: #61CE3C; } 22 | .cm-s-blackboard .cm-meta { color: #D8FA3C; } 23 | .cm-s-blackboard .cm-builtin { color: #8DA6CE; } 24 | .cm-s-blackboard .cm-tag { color: #8DA6CE; } 25 | .cm-s-blackboard .cm-attribute { color: #8DA6CE; } 26 | .cm-s-blackboard .cm-header { color: #FF6400; } 27 | .cm-s-blackboard .cm-hr { color: #AEAEAE; } 28 | .cm-s-blackboard .cm-link { color: #8DA6CE; } 29 | .cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; } 30 | 31 | .cm-s-blackboard .CodeMirror-activeline-background { background: #3C3636; } 32 | .cm-s-blackboard .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; } 33 | -------------------------------------------------------------------------------- /docs/styles/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #ddd; 3 | } 4 | 5 | /* string content */ 6 | .str { 7 | color: #61ce3c; 8 | } 9 | 10 | /* a keyword */ 11 | .kwd { 12 | color: #fbde2d; 13 | } 14 | 15 | /* a comment */ 16 | .com { 17 | color: #aeaeae; 18 | } 19 | 20 | /* a type name */ 21 | .typ { 22 | color: #8da6ce; 23 | } 24 | 25 | /* a literal value */ 26 | .lit { 27 | color: #fbde2d; 28 | } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #ddd; 33 | } 34 | 35 | /* lisp open bracket */ 36 | .opn { 37 | color: #000000; 38 | } 39 | 40 | /* lisp close bracket */ 41 | .clo { 42 | color: #000000; 43 | } 44 | 45 | /* a markup tag name */ 46 | .tag { 47 | color: #8da6ce; 48 | } 49 | 50 | /* a markup attribute name */ 51 | .atn { 52 | color: #fbde2d; 53 | } 54 | 55 | /* a markup attribute value */ 56 | .atv { 57 | color: #ddd; 58 | } 59 | 60 | /* a declaration */ 61 | .dec { 62 | color: #EF5050; 63 | } 64 | 65 | /* a variable name */ 66 | .var { 67 | color: #c82829; 68 | } 69 | 70 | /* a function name */ 71 | .fun { 72 | color: #4271ae; 73 | } 74 | 75 | /* Specify class=linenums on a pre to get line numbering */ 76 | ol.linenums { 77 | margin-top: 0; 78 | margin-bottom: 0; 79 | } 80 | -------------------------------------------------------------------------------- /lib/react-compat.js: -------------------------------------------------------------------------------- 1 | import Preact from 'preact.umd.min'; 2 | // Keep compat layer minimal so we can more easily 3 | // track the differences 4 | var AUTOBIND_BLACKLIST = { 5 | constructor: 1, 6 | render: 1, 7 | shouldComponentUpdate: 1, 8 | componentWillReceiveProps: 1, 9 | componentWillUpdate: 1, 10 | componentDidUpdate: 1, 11 | componentWillMount: 1, 12 | componentDidMount: 1, 13 | componentWillUnmount: 1, 14 | componentDidUnmount: 1 15 | }; 16 | function bindAll(ctx) { 17 | for (var i in ctx) { 18 | var v = ctx[i]; 19 | if (typeof v === 'function' && !v.__bound && !AUTOBIND_BLACKLIST.hasOwnProperty(i)) { 20 | (ctx[i] = v.bind(ctx)).__bound = true; 21 | } 22 | } 23 | } 24 | 25 | var React = Preact; 26 | React.createClass = function ( obj ) { 27 | function F(props, context) { 28 | bindAll(this); 29 | Preact.Component.call( this, props, context ); 30 | } 31 | 32 | var p = F.prototype = new Preact.Component; 33 | // copy our skeleton into the prototype: 34 | for ( var i in obj ) { p[i] = obj[i]; } 35 | // restore constructor: 36 | return p.constructor = F; 37 | } 38 | 39 | var _render = React.render; 40 | React.render = function ( obj, el ) { 41 | el.innerHTML = null; 42 | _render( obj, el ); 43 | } 44 | 45 | export default React; 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "procedural-gl", 3 | "version": "1.0.19", 4 | "description": "3D mapping engine for the web", 5 | "main": "build/procedural-gl.js", 6 | "module": "build/procedural-gl.module.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "npm run compile && npm run uglify", 10 | "build-dev": "rollup -c --environment DEV", 11 | "compile": "cd shaders && ./minify.sh && cd - && rollup -c", 12 | "dev": "find src lib shaders -type f \\( -iname \\*js -o -iname \\*jsx -o -iname \\*vert -o -iname \\*frag -o -iname \\*glsl \\) | entr npm run build-dev", 13 | "lint": "eslint src --ext js --fix", 14 | "uglify": "uglifyjs build/procedural-gl.js -o build/procedural-gl.min.js -c -m" 15 | }, 16 | "files": [ 17 | "build/procedural-gl.js", 18 | "build/procedural-gl.min.js", 19 | "build/procedural-gl.module.js", 20 | "LICENSE", 21 | "package.json", 22 | "README.md" 23 | ], 24 | "dependencies": {}, 25 | "devDependencies": { 26 | "eslint": "^7.7.0", 27 | "eslint-config-mdcs": "^5.0.0", 28 | "@rollup/plugin-alias": "^3.1.0", 29 | "@rollup/plugin-commonjs": "^11.1.0", 30 | "@rollup/plugin-node-resolve": "^7.0.0", 31 | "@rollup/plugin-replace": "^2.3.2", 32 | "@rollup/plugin-sucrase": "^3.0.1", 33 | "rollup": "^1.14.6", 34 | "rollup-plugin-root-import": "^1.0.0", 35 | "rollup-plugin-string": "^3.0.0", 36 | "rollup-plugin-visualizer": "^4.0.4", 37 | "uglify-es": "^3.3.9" 38 | }, 39 | "repository": { 40 | "type": "git", 41 | "url": "git+https://github.com/felixpalmer/procedural-gl-js.git" 42 | }, 43 | "keywords": [ 44 | "javascript", 45 | "3d", 46 | "webgl", 47 | "map", 48 | "dataviz", 49 | "canvas", 50 | "html5", 51 | "gis", 52 | "geospatial", 53 | "three.js" 54 | ], 55 | "author": "felixpalmer", 56 | "license": "MPL-2.0", 57 | "bugs": { 58 | "url": "https://github.com/felixpalmer/procedural-gl-js/issues" 59 | }, 60 | "homepage": "https://github.com/felixpalmer/procedural-gl-js#readme" 61 | } 62 | -------------------------------------------------------------------------------- /screenshots/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/screenshots/1.jpg -------------------------------------------------------------------------------- /screenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/screenshots/2.jpg -------------------------------------------------------------------------------- /screenshots/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/screenshots/3.jpg -------------------------------------------------------------------------------- /screenshots/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/screenshots/4.jpg -------------------------------------------------------------------------------- /screenshots/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/screenshots/5.jpg -------------------------------------------------------------------------------- /screenshots/title.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/procedural-gl-js/1ff6e97313da000e677947cc03ab8375738ea9ab/screenshots/title.jpg -------------------------------------------------------------------------------- /shaders/.gitignore: -------------------------------------------------------------------------------- 1 | min/ 2 | *.full.frag 3 | *.full.vert 4 | -------------------------------------------------------------------------------- /shaders/beacon.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | uniform float uTime; 12 | 13 | varying vec3 vPosition; 14 | varying vec3 vCenter; 15 | varying float vRingRadius; 16 | 17 | const vec4 white = vec4( 1.0, 1.0, 1.0, 0.9 ); 18 | 19 | void main() { 20 | float fractionalR = distance( vPosition.xy, vCenter.xy ) / vRingRadius; 21 | vec3 baseColor = mix( vec3( 0.0, 0.0, 1.0 ), vec3( 0.0, 0.5, 1.0 ), 0.2 * fractionalR ); 22 | vec4 color = vec4( baseColor * sin( uTime ), 0.5 ); 23 | 24 | // White ring 25 | color = mix( color, white, smoothstep( 0.75, 0.8, fractionalR ) ); 26 | color = mix( color, vec4( baseColor.rgb, 0.15 ), smoothstep( 1.0, 1.05, fractionalR ) ); 27 | 28 | // Gamma 29 | color.rgb = pow( abs( color.rgb ), vec3( 0.4545 ) ); 30 | 31 | gl_FragColor = color; 32 | } 33 | -------------------------------------------------------------------------------- /shaders/beacon.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | uniform mat4 modelMatrix; 10 | uniform mat4 viewMatrix; 11 | uniform mat4 projectionMatrix; 12 | uniform vec3 cameraPosition; 13 | 14 | attribute vec3 position; 15 | attribute vec3 normal; 16 | 17 | uniform float uAccuracy; 18 | 19 | varying vec3 vPosition; 20 | varying vec3 vCenter; // Center of beacon 21 | varying float vRingRadius; // Radius to draw inner ring at 22 | 23 | // Radius of beacon geometry, as defined in JS 24 | #define BEACON_RADIUS 50.0 25 | 26 | #include saturate.glsl 27 | #include getHeight.glsl 28 | 29 | void main() { 30 | vCenter = position - BEACON_RADIUS * normal; 31 | vec4 c4 = modelMatrix * vec4( vCenter, 1.0 ); 32 | vec3 worldCenter = c4.xyz / c4.w; 33 | vCenter = worldCenter; 34 | 35 | // Get distance to camera, and scale so that all beacon has constant screen size 36 | float D = abs( ( viewMatrix * vec4( worldCenter, 1.0 ) ).z ); 37 | vRingRadius = 25.0 * clamp( D / 1000.0, 0.01, 10.0 ); // Cap size at so don't get artifacts when zooming 38 | 39 | // Now have the minimum visible radius for beacon, adjust if smaller than accuracy 40 | float radius = max( vRingRadius, uAccuracy ); 41 | 42 | vPosition = vCenter + radius * normal; 43 | 44 | // Correct height 45 | float height = getHeight( vPosition.xy ); 46 | 47 | // Place at correct height (flattening sphere in process) 48 | float delta = height - vPosition.z + D / 1000.0 - 0.3 * radius; // Lift up at large distance so terrain doesn't swallow us & sink into ground 49 | vPosition.z = height; 50 | 51 | 52 | // To ensure beacon appears on top of forests & pistes, move towards camera 53 | vec3 view = cameraPosition - vPosition; 54 | float d = length( view ); 55 | view = normalize( view ); 56 | // Do not apply if too close, as it screws up geometry too much 57 | float scale = 230.0 * smoothstep( 50.0, 250.0, d ); 58 | 59 | gl_Position = projectionMatrix * viewMatrix * vec4( vPosition + scale * view, 1.0 ); 60 | } 61 | -------------------------------------------------------------------------------- /shaders/fog.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | uniform float uFogDropoff; 9 | uniform float uFogIntensity; 10 | uniform vec3 uFogColor; 11 | 12 | float fogFactor( in float dist ) { 13 | float fog = uFogIntensity * ( 1.0 - exp( -dist * uFogDropoff ) ); 14 | return clamp( fog, 0.0, 1.0 ); 15 | } 16 | 17 | float fogFactor( in vec3 camera, in vec3 pos ) { 18 | float dist = distance( camera, pos ); 19 | return fogFactor( dist ); 20 | } 21 | -------------------------------------------------------------------------------- /shaders/lengthNormalize.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // Normalized the input vector in place at the same 9 | // time as finding its lengt 10 | // Doesn't appear to be faster than length() & normalize() (same speed) 11 | float lengthNormalize( inout vec3 v ) { 12 | float lengthSquared = dot( v, v ); 13 | float rcpLength = inversesqrt( lengthSquared ); 14 | v = rcpLength * v; // Normalized vector 15 | return lengthSquared * rcpLength; // Vector length 16 | } 17 | -------------------------------------------------------------------------------- /shaders/line.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | uniform float uCutoff; 12 | uniform vec4 uOutlineColor; 13 | 14 | varying vec4 vColor; 15 | varying float vAlpha; 16 | 17 | void main() { 18 | // Smoothly interpolate between: 19 | // x: line color and edge color 20 | // y: line alpha and transparent antialiased edge 21 | vec2 f = smoothstep( 22 | vec2( 0.4, 1.0 ) * uCutoff, 23 | vec2( 0.5, 1.0 ), 24 | abs( vec2( vAlpha ) ) ); 25 | 26 | // Multiply application of edge line with alpha 27 | f.x *= uOutlineColor.a; 28 | 29 | gl_FragColor = mix( 30 | vColor, 31 | vec4( uOutlineColor.rgb, 0.0 ), 32 | f.xxxy ); 33 | } 34 | -------------------------------------------------------------------------------- /shaders/line.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | uniform vec3 cameraPosition; 14 | 15 | attribute vec3 tag; 16 | attribute vec4 tangent; 17 | attribute vec3 position; 18 | attribute vec4 color; 19 | 20 | uniform float uThickness; 21 | uniform vec3 uSelectedTag; 22 | 23 | varying vec4 vColor; 24 | varying float vAlpha; 25 | 26 | #include positionFromTangent.glsl 27 | #include getHeight.glsl 28 | 29 | void main() { 30 | // Vertices are placed based on tangent, to give constant width on screen 31 | vec3 center = position; 32 | center.z += getHeight( center.xy ); 33 | gl_Position = positionFromTangent( center, uThickness ); 34 | 35 | vColor = color; 36 | 37 | // Is line selected? 38 | float selected = step( distance( tag, uSelectedTag ), 0.0 ); 39 | gl_Position.z -= 0.5 + 0.01 * selected; 40 | vColor.rgb = mix( vColor.rgb, vec3( 1.0 ), 0.8 * selected ); 41 | 42 | // Safe way to identify side of line 43 | vAlpha = sign( tangent.w ); 44 | 45 | // Dashed line 46 | // float D = ( viewMatrix * vec4( position, 1.0 ) ).z; 47 | // Round to log values 48 | // D = pow( 2.0, floor( log2( D ) ) ); 49 | // Modulate distance along line by depth 50 | // float dash = position.w * D; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /shaders/picker.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | varying vec4 vTag; 12 | 13 | void main() { 14 | gl_FragColor = vTag; 15 | // For testing draw more visible colors 16 | //gl_FragColor.rgb = mod( 10000.0 * vTag.rgb, vec3( 1.0 ) ); 17 | //gl_FragColor.a = 1.0; 18 | } 19 | -------------------------------------------------------------------------------- /shaders/positionFromTangent.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | uniform vec2 uViewportInverse; 9 | 10 | // Calculate our position from the center and tangent of line 11 | vec4 positionFromTangent( const in vec3 center, 12 | const in float thickness ) { 13 | // Get clipspace positions of center and center + tangent 14 | vec4 p = vec4( center, 1.0 ); 15 | vec4 c4 = projectionMatrix * viewMatrix * p; 16 | 17 | p.xyz += tangent.xyz; 18 | vec4 cplust4 = projectionMatrix * viewMatrix * p; 19 | 20 | // Tangent vector in clipspace (normalizing by w!) 21 | vec2 t4 = cplust4.xy / cplust4.w - c4.xy / c4.w; 22 | 23 | // Issue here when line is going towards screen, up and 24 | // then down. The tangent will then flip from up to down 25 | // and the line normal will also switch sides, leading 26 | // to a fold in the quads forming the line 27 | // Not really clear how to overcome this... 28 | 29 | // Get normal in clipspace by crossing with vec3(0, 0, 1) 30 | vec2 delt = t4.yx * vec2( 1.0, -1.0 ); // Move one side one way, the other the other way (tangent is opposite for vertices in pair) 31 | delt = thickness * c4.w * normalize( delt ) * uViewportInverse; 32 | 33 | c4.xy += delt; 34 | return c4; 35 | } 36 | -------------------------------------------------------------------------------- /shaders/quad.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | attribute vec3 position; 10 | 11 | void main() { 12 | // Do not need any matrix multiplications as positions already in clip 13 | // space 14 | gl_Position = vec4( position, 1.0 ); 15 | } 16 | -------------------------------------------------------------------------------- /shaders/quad_uv.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | attribute vec3 position; 10 | attribute vec2 uv; 11 | 12 | // Quad vertex shader that also passes through uv coordinate 13 | varying vec2 vUv; 14 | 15 | void main() { 16 | vUv = uv; 17 | // Do not need any matrix multiplications as positions already in clip 18 | // space 19 | gl_Position = vec4( position, 1.0 ); 20 | } 21 | -------------------------------------------------------------------------------- /shaders/raycast.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | varying vec2 vPosition; 12 | 13 | void main() { 14 | // Pack position xy into RGBA 15 | gl_FragColor = vec4( mod( vPosition.xy, 256.0 ), 16 | floor( vPosition.xy / 256.0 ) ) / 255.0; 17 | } 18 | -------------------------------------------------------------------------------- /shaders/raycast.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | attribute vec4 position; 15 | 16 | uniform vec4 uOffset; 17 | 18 | varying vec2 vPosition; 19 | 20 | #include getHeight.glsl 21 | 22 | // TODO, not yet working, but shader should look something like this 23 | void main() { 24 | // Move into place by shifting instanced position by tile offset 25 | vec4 p = vec4( position.xy, 0.0, 1.0 ); 26 | p.xy *= uOffset.z; // Scale 27 | p.xy += uOffset.xy; // Shift 28 | 29 | vPosition = p.xy + vec2( 32768.0 ); 30 | p.z = getHeight( p.xy ); 31 | gl_Position = projectionMatrix * viewMatrix * p; 32 | } 33 | -------------------------------------------------------------------------------- /shaders/readTexVirtual.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // On iOS standard texture linear filtering has 9 | // artifacts, so use this manual replacement. 10 | // It also doesn't work for FLOAT textures 11 | #define TEX_SIZE (VIRTUAL_TEXTURE_ARRAY_SIZE * VIRTUAL_TEXTURE_ARRAY_BLOCKS) 12 | const vec2 texelSize = vec2( 1.0 / TEX_SIZE, 0.0 ); 13 | vec4 texture2D_bilinear( const in sampler2D t, in vec2 uv ) 14 | { 15 | // Calculate pixels to sample and interpolating factor 16 | uv -= 0.5 * texelSize.xx; 17 | vec2 f = fract( uv * TEX_SIZE ); 18 | // Snap to corner of texel and then move to center 19 | vec2 uvSnapped = uv - texelSize.xx * f + 0.5 * texelSize.xx; 20 | 21 | #ifdef HEIGHT_LOOKUP_BIAS 22 | // As we are sampling snapped pixels need to override 23 | // the mip-map selection by selecting a large negative 24 | // bias. Otherwise at boundaries the gradient of 25 | // uvSnapped is large and an incorrect mip-level is used 26 | // leading to artifacts 27 | vec4 tl = texture2D(t, uvSnapped, -10.0); 28 | vec4 tr = texture2D(t, uvSnapped + texelSize, -10.0 ); 29 | vec4 bl = texture2D(t, uvSnapped + texelSize.yx, -10.0 ); 30 | vec4 br = texture2D(t, uvSnapped + texelSize.xx, -10.0 ); 31 | #else 32 | vec4 tl = texture2D(t, uvSnapped); 33 | vec4 tr = texture2D(t, uvSnapped + texelSize); 34 | vec4 bl = texture2D(t, uvSnapped + texelSize.yx); 35 | vec4 br = texture2D(t, uvSnapped + texelSize.xx); 36 | #endif 37 | vec4 tA = mix( tl, tr, f.x ); 38 | vec4 tB = mix( bl, br, f.x ); 39 | return mix( tA, tB, f.y ); 40 | } 41 | 42 | // Virtual texture array lookup (WebGL1 fallback) 43 | vec4 readTex( in sampler2D tex, in vec2 uv, in float index ) { 44 | // Convert index into spatial offset 45 | vec2 offset = vec2( 46 | mod( float( index ), VIRTUAL_TEXTURE_ARRAY_BLOCKS ), 47 | floor( float( index ) / VIRTUAL_TEXTURE_ARRAY_BLOCKS ) 48 | ); 49 | 50 | // Don't bleed across to next texture 51 | const float padding = 0.5; 52 | vec2 limits = vec2( padding, VIRTUAL_TEXTURE_ARRAY_SIZE - padding ) / VIRTUAL_TEXTURE_ARRAY_SIZE; 53 | 54 | // Calculate uv for lookup 55 | vec2 scaledUv = ( clamp( uv, limits.x, limits.y ) + offset ) / VIRTUAL_TEXTURE_ARRAY_BLOCKS; 56 | #ifdef MANUAL_TEXTURE_BILINEAR 57 | return texture2D_bilinear( tex, scaledUv ); 58 | #else 59 | return texture2D( tex, scaledUv ); 60 | #endif 61 | } 62 | -------------------------------------------------------------------------------- /shaders/saturate.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | float saturate( float t ) { return clamp( t, 0.0, 1.0 ); } 9 | vec2 saturate( vec2 t ) { return clamp( t, 0.0, 1.0 ); } 10 | vec3 saturate( vec3 t ) { return clamp( t, 0.0, 1.0 ); } 11 | vec4 saturate( vec4 t ) { return clamp( t, 0.0, 1.0 ); } 12 | -------------------------------------------------------------------------------- /shaders/sky.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | varying vec3 vPosition; 12 | 13 | // Not including sun disk for now as we rarely see it anyway 14 | #include skyColor.glsl 15 | 16 | void main() { 17 | vec3 direction = normalize( vPosition ); 18 | vec3 color = skyColor( direction ); 19 | // Stars 20 | //float r = 500.0; 21 | //vec3 rounded = floor( 0.4999999 + r * direction ) / r; 22 | //float hash = fract( sin( 21041.4 * rounded.x ) + sin( 317041.4 * rounded.z ) + sin( 210041.4 * rounded.x ) + sin( 217041.4 * rounded.y )); 23 | //float star = distance( rounded, direction ); 24 | //star = smoothstep( 0.5 / r, 0.0, star ); 25 | //color += vec3( star * smoothstep( 0.97, 1.0, hash ) * smoothstep( 0.01, 0.05, direction.y) ); 26 | gl_FragColor = vec4( color, 1.0 ); 27 | } 28 | -------------------------------------------------------------------------------- /shaders/sky.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 projectionMatrix; 11 | uniform vec3 cameraPosition; 12 | 13 | attribute vec3 position; 14 | 15 | varying vec3 vPosition; 16 | 17 | void main() { 18 | // vPosition is the ray direction for sky shader 19 | vPosition = position.xzy; 20 | vPosition.y = max( 0.0, vPosition.y ); 21 | 22 | // Shift entire sky dome with camera 23 | vec3 p = position; 24 | p.xy += cameraPosition.xy; 25 | gl_Position = projectionMatrix * modelViewMatrix * vec4( p, 1.0 ); 26 | } 27 | -------------------------------------------------------------------------------- /shaders/skyColor.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // Derived uniforms 9 | uniform vec3 sunDirection; 10 | uniform vec3 betaRM; 11 | uniform vec3 betaRnorm; 12 | uniform vec3 betaMnorm; 13 | uniform vec4 constants; // sunE, hgPhaseA, hgPhaseB & LinWeight 14 | uniform float gamma; 15 | uniform float tonemapScale; 16 | 17 | // Safe functions 18 | float spow( const float x, const float y ) { 19 | return pow( abs( x ), y ); 20 | } 21 | 22 | vec3 spow( const vec3 x, const vec3 y ) { 23 | return pow( abs( x ), y ); 24 | } 25 | 26 | vec3 ssqrt( const vec3 x ) { 27 | return sqrt( abs( x ) ); 28 | } 29 | 30 | #include tonemap.glsl 31 | 32 | vec3 skyColor( vec3 direction ) { 33 | float cosZenithAngle = max( 0.0, direction.y ); 34 | // Approximate acos( x ) by pi/2 - x 35 | // This allows us to simplify and error is only large when looking up 36 | float denom = cosZenithAngle + spow( 17.6579343808112 + cosZenithAngle * 260.41830500372932, -1.253 ); 37 | 38 | // combined extinction factor 39 | vec3 Fex = exp( -betaRM / denom ); 40 | 41 | // in scattering 42 | float cosTheta = dot( direction, sunDirection ); 43 | float rPhase = cosTheta + 1.0; 44 | vec3 betaRTheta = betaRnorm * ( 4.0 + rPhase * rPhase ); 45 | vec3 betaMTheta = betaMnorm * spow( constants.y * cosTheta + constants.z, -1.5 ); 46 | 47 | vec3 tmp = betaRTheta + betaMTheta; 48 | vec3 Lin = spow( tmp * ( 1.0 - Fex ), vec3( 1.5 ) ); 49 | Lin *= mix( vec3( 1.0 ), ssqrt( tmp * Fex ), constants.w ); 50 | 51 | // nightsky 52 | vec3 L0 = 0.1 * Fex; 53 | 54 | #ifdef SUN_DISK 55 | L0 += constants.x * Fex * smoothstep( 0.9999566769, 0.9999766769, cosTheta ); 56 | #endif 57 | 58 | // Combine all components 59 | vec3 color = 0.04 * ( Lin + L0 ) + vec3( 0.0, 0.0003, 0.00075 ); 60 | color = Tonemap( tonemapScale * color ); 61 | return spow( color, vec3( gamma ) ); 62 | } 63 | -------------------------------------------------------------------------------- /shaders/skySpheremap.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | #define SUN_DISK 12 | #include skyColor.glsl 13 | 14 | // 1 / 2048.0 (texture width) 15 | #define STEP 0.00048828125 16 | 17 | void main() { 18 | // Map to sphere normal direction 19 | vec2 uv = gl_FragCoord.xy * STEP; 20 | vec3 direction = 2.0 * vec3( uv - 0.5, 0.0 ); // Switch to polar coordaintes 21 | float r = min( 0.99999, length( direction ) ); // Limit to unit length 22 | r = sin( 1.5707963267949 * r ); // store linear in polar angle 23 | direction = r * normalize( direction ); 24 | direction.z = sqrt( max( 0.0, 1.0 - dot( direction, direction ) ) ); // Get z-coordinate from Pythagorus 25 | vec3 color = skyColor( normalize( direction.xzy ) ); 26 | gl_FragColor = vec4( color, 1.0 ); 27 | } 28 | -------------------------------------------------------------------------------- /shaders/skybox.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | varying vec3 vPosition; 9 | 10 | #include skyboxColor.glsl 11 | 12 | void main() { 13 | vec3 direction = normalize( vPosition ); 14 | vec3 color = skyColor( direction ); 15 | gl_FragColor = vec4( color, 1.0 ); 16 | } 17 | -------------------------------------------------------------------------------- /shaders/skyboxColor.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | uniform sampler2D uSkybox; 9 | // Only works for 0 < f < 1.0 10 | // Saves 6 instructions? (12->6) relative to asin() 11 | float asin_lowp( float f ) { 12 | float x = clamp( f, 0.0, 1.0 ); 13 | float result = 0.2120531 * x - 1.57073; 14 | result *= sqrt( 1.0 - x ) - 1.57073; 15 | return result; 16 | } 17 | 18 | #include lengthNormalize.glsl 19 | 20 | vec3 skyboxColor( vec2 st ) { 21 | return texture2D( uSkybox, st ).rgb; 22 | } 23 | 24 | vec3 skyColor( vec3 direction ) { 25 | direction.y = 0.0; 26 | float r = lengthNormalize( direction ); 27 | r = 0.63661977236758 * asin( r ); // convert to standard polar 28 | vec2 st = vec2( 0.5 ) + 0.5 * r * direction.xz; 29 | return skyboxColor( st ); 30 | } 31 | -------------------------------------------------------------------------------- /shaders/terrain.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | //#extension GL_OES_standard_derivatives : enable 10 | precision highp float; 11 | 12 | uniform vec4 uImageryUvOffset; 13 | 14 | varying vec4 vUV; // xy: scaled for imagery lookup, zw: actual uv across tile 15 | 16 | varying float D; 17 | 18 | uniform lowp sampler2D imageryArray; 19 | 20 | #include fog.glsl 21 | 22 | #define VIRTUAL_TEXTURE_ARRAY_BLOCKS 16.0 23 | #define VIRTUAL_TEXTURE_ARRAY_SIZE 256.0 24 | #include readTexVirtual.glsl 25 | 26 | void main() { 27 | vec3 color = readTex( imageryArray, vUV.xy, uImageryUvOffset.w ).rgb; 28 | 29 | float fogAmount = fogFactor( D ); 30 | color = mix( color, uFogColor, fogAmount ); 31 | 32 | gl_FragColor = vec4( color, 1.0 ); 33 | 34 | //// Edge debug 35 | //gl_FragColor.r *= 1.0 - dot( vec2( 1.0 ), step( vUV.xy, vec2( 0.01 ) ) ); 36 | //gl_FragColor.g *= 1.0 - dot( vec2( 1.0 ), step( vUV.zw, vec2( 0.01 ) ) ); 37 | 38 | // Error calc (mimics picker shader) 39 | //vec4 error = dFdx( vUV ); 40 | //error *= 256.0; 41 | //float E = log2( length( error.zw ) ) - 0.75; 42 | //float cap = 0.75; // Value to cap error display at 43 | //vec3 errorColor = mix( vec3( 1.0 ), vec3( 1.0, 0.0, 0.0 ), 44 | // max( 0.0, E / cap ) ); 45 | //errorColor = mix( errorColor, vec3( 0.0, 1.0, 0.0 ), 46 | // max( 0.0, -E / cap ) ); 47 | 48 | //// Tile outlines 49 | //vec4 wire = smoothstep( 50 | // 0.48, 0.49, 51 | // fract( vec4( 1.0, -1.0, 1.0, -1.0 ) * 2.0 * vUV.zzww + vec4( 0.5 ) ) ); 52 | //float wireframe = min( 1.0, wire.x * wire.y + wire.z * wire.w ); 53 | //gl_FragColor.rgb = mix( gl_FragColor.rgb, errorColor, wireframe ); 54 | } 55 | -------------------------------------------------------------------------------- /shaders/terrain.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | uniform vec3 cameraPosition; 14 | 15 | attribute vec4 position; 16 | 17 | uniform vec4 uOffset; 18 | uniform vec4 uImageryUvOffset; 19 | 20 | varying vec4 vUV; 21 | varying float D; 22 | 23 | #include getHeight.glsl 24 | 25 | void main() { 26 | // Move into place by shifting instanced position by tile offset 27 | vec4 p = vec4( position.xy, 0.0, 1.0 ); 28 | p.xy *= uOffset.z; // Scale 29 | p.xy += uOffset.xy; // Shift 30 | 31 | // Extract the height (for skirting from the uv) 32 | vec2 skirt = 10.0 * floor( position.zw / 10.0 ); 33 | vec2 uv = position.zw - skirt; 34 | 35 | p.z = getHeight( p.xy ); 36 | 37 | // Pull down skirt vertices 38 | p.z -= 0.01 * uOffset.z * skirt.x; 39 | 40 | // Scale image uv lookup for fragment shader 41 | vUV.xy = uImageryUvOffset.z * uv.xy + uImageryUvOffset.xy; 42 | vUV.zw = uv.xy; 43 | 44 | // Distance for fog 45 | D = distance( cameraPosition, p.xyz ); 46 | 47 | gl_Position = projectionMatrix * viewMatrix * p; 48 | } 49 | -------------------------------------------------------------------------------- /shaders/terrainPicker.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | #extension GL_OES_standard_derivatives : enable 10 | precision highp float; 11 | 12 | uniform vec3 uScaling; // xy: center pixel, z: downScaling 13 | 14 | varying vec4 vUV; // xy: actual uv across tile, zw: encodedTileId 15 | 16 | void main() { 17 | // Assess our screen space error, both for tile size and texture blur 18 | // For now not actually using the texture blur error, as it is best to 19 | // fetch just based on the tile geometry, makes things more stable 20 | vec2 deltaUV = dFdx( vUV.xy ); 21 | 22 | float err = log2( length( deltaUV ) ); 23 | 24 | vec2 encodedTileId = vUV.zw; 25 | 26 | // TODO perhaps we could encode this the same way we encode Z 27 | // and save some instructions 28 | // Store error clamped to range -5 > 5 (log encoded) 29 | float encodedError = 0.1 * err + 0.5; 30 | 31 | // Scale to fill 0->1 to 16bit capacity 32 | float scaledZ = 256.0 * 255.0 * gl_FragCoord.z; 33 | vec2 encodedZ = vec2( 34 | floor( scaledZ / 256.0 ), 35 | mod( scaledZ, 256.0 ) 36 | ) / 255.0; 37 | float isCenter = step( distance( gl_FragCoord.xy, uScaling.xy ), 4.0 ); 38 | 39 | vec4 standard = vec4( encodedTileId, 0.0, encodedError ); 40 | vec4 centerPixels = vec4( 0.0, 0.0, encodedZ ); 41 | gl_FragColor = mix( standard, centerPixels, isCenter ); 42 | } 43 | -------------------------------------------------------------------------------- /shaders/terrainPicker.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // RawShader 9 | precision highp float; 10 | 11 | uniform mat4 viewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | attribute vec4 position; 15 | 16 | uniform vec4 uOffset; 17 | uniform vec4 uImageryUvOffset; 18 | uniform vec3 uScaling; // xy: center pixel, z: downScaling 19 | 20 | varying vec4 vUV; 21 | 22 | #define MANUAL_TEXTURE_BILINEAR 1 23 | #include getHeight.glsl 24 | 25 | void main() { 26 | // Move into place by shifting instanced position by tile offset 27 | vec4 p = vec4( position.xy, 0.0, 1.0 ); 28 | p.xy *= uOffset.z; // Scale 29 | p.xy += uOffset.xy; // Shift 30 | 31 | // Extract the height (for skirting from the uv) 32 | vec2 skirt = 10.0 * floor( position.zw / 10.0 ); 33 | vec2 uv = position.zw - skirt; 34 | 35 | p.z = getHeight( p.xy ); 36 | 37 | // Pull down skirt vertices 38 | p.z -= 0.01 * uOffset.z * skirt.x; 39 | 40 | // Pass values through to fragment shader 41 | float tileId = uOffset.w; 42 | vec2 encodedTileId = vec2( 43 | floor( tileId / 256.0 ) / 256.0, 44 | fract( tileId / 256.0 ) 45 | ) * ( 256.0 / 255.0 ); 46 | 47 | // Scale error to texture width 48 | vUV.xy = uv.xy * uScaling.z; 49 | vUV.zw = encodedTileId; 50 | 51 | gl_Position = projectionMatrix * viewMatrix * p; 52 | } 53 | -------------------------------------------------------------------------------- /shaders/tonemap.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | const float A = 0.15; 9 | const float B = 0.50; 10 | const float C = 0.10; 11 | const float D = 0.20; 12 | const float E = 0.02; 13 | const float F = 0.30; 14 | 15 | uniform float uTonemapExposureBias; 16 | uniform float uTonemapWhiteScale; 17 | 18 | vec3 RawTonemap( vec3 x ) 19 | { 20 | return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; 21 | } 22 | 23 | vec3 Tonemap( vec3 color ) { 24 | return uTonemapExposureBias * RawTonemap( uTonemapWhiteScale * color ); 25 | } 26 | -------------------------------------------------------------------------------- /shaders/vertexDiscard.glsl: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // Function to cull triangles in vertex shader by reducing their 9 | // size to zero (degenerate), which means the fragment shader 10 | // will not be invoked on them 11 | // As we cannot operate on primitives (triangles) directly, 12 | // we discard vertices by collapsing them onto a point. 13 | // The collapse will drag geometry down below the terrain, 14 | // without making it apparent the triangles are being stretched 15 | void vertexDiscard( in float D, in float cutoff ) { 16 | gl_Position = mix( vec4( 0.0, -1.0, 1.0, 0.0 ), gl_Position, step( D, cutoff ) ); 17 | } 18 | -------------------------------------------------------------------------------- /src/actions/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | 10 | export default alt.generateActions( 11 | 'configureCamera', 12 | 'configureElevationDatasource', 13 | 'configureImageryDatasource', 14 | 'setAppContainer', 15 | 'setCameraModeControlVisible', 16 | 'setCompassVisible', 17 | 'setDisplayErrors', 18 | 'setLayersControlVisible', 19 | 'setResourceUrl', 20 | 'setRotationControlVisible', 21 | 'setSeasonControlVisible', 22 | 'setUserLocationControlVisible', 23 | 'setZoomControlVisible' 24 | ); 25 | -------------------------------------------------------------------------------- /src/actions/currentLocation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | 10 | export default alt.generateActions( 11 | 'panToPosition', 12 | 'setPosition', 13 | 'toggleTracking' 14 | ); 15 | -------------------------------------------------------------------------------- /src/actions/geodata.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | 10 | export default alt.generateActions( 11 | 'addBuiltinOverlay', 12 | 'addOverlay', 13 | 'elevationBigProgress', 14 | 'elevationProgress', 15 | 'featuresProgress', 16 | 'imageryBigProgress', 17 | 'imageryProgress', 18 | 'removeOverlay', 19 | 'setElevation', 20 | 'setElevationBig', 21 | 'setFeatures', 22 | 'setHeightOffset', 23 | 'setHeightOffsetBig', 24 | 'setImagery', 25 | 'setImageryBig', 26 | 'setLiabilityUsed', 27 | 'setOSMUsed', 28 | 'setSRTMUsed', 29 | 'setTerrainMesh', 30 | 'updateHeightMap', 31 | 'updateOverlay' 32 | ); 33 | -------------------------------------------------------------------------------- /src/actions/render.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | 10 | export default alt.generateActions( 11 | 'containerMounted', 12 | 'containerResized', 13 | 'fatalError', 14 | 'featureCreated', 15 | 'fontsLoaded', 16 | 'forceHD', 17 | 'onBoundsFocused', 18 | 'onLocationFocused', 19 | 'overlayDisplayed', 20 | 'needsRender', 21 | 'pause', 22 | 'play', 23 | 'renderedFeatureDisplayed', 24 | 'renderedFeatureRegister', 25 | 'setFieldOfView', 26 | 'setHD', 27 | 'setSize' 28 | ); 29 | -------------------------------------------------------------------------------- /src/actions/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | 10 | export default alt.generateActions( 11 | 'animateAlongFeature', 12 | 'doubleTapZoom', 13 | 'featureClicked', 14 | 'featureSelected', 15 | 'focusOnBounds', 16 | 'focusOnFeature', 17 | 'focusOnLocation', 18 | 'focusOnTarget', 19 | 'inputEnded', 20 | 'inputStarted', 21 | 'orbitTarget', 22 | 'panToPosition', 23 | 'rotateLeft', 24 | 'rotateRight', 25 | 'selectFeatures', 26 | 'setCamera', 27 | 'setCameraMode', 28 | 'setCameraPosition', 29 | 'setCameraTarget', 30 | 'setCurrentPlace', 31 | 'setEnvironment', 32 | 'setGeography', 33 | 'setSecondaryParams', 34 | 'setTerrainEffectContours', 35 | 'setTerrainEffectFlats', 36 | 'setTerrainEffectGrade', 37 | 'setTerrainEffectHeight', 38 | 'setTerrainEffectNone', 39 | 'startFlyover', 40 | 'toggleWidgets', 41 | 'zoomIn', 42 | 'zoomOut' 43 | ); 44 | -------------------------------------------------------------------------------- /src/alt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import Alt from 'alt.min'; 9 | var alt = new Alt(); 10 | alt.serialize = function () { return '' }; 11 | 12 | alt.deserialize = function () { return '' }; 13 | 14 | export default alt; 15 | -------------------------------------------------------------------------------- /src/api/geodata.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import AppStore from '/stores/app'; 10 | import GeodataActions from '/actions/geodata'; 11 | import log from '/log'; 12 | import RenderActions from '/actions/render'; 13 | import track from '/track'; 14 | var GeodataAPI = function () { 15 | this.loader = new THREE.FileLoader(); 16 | this.baseUrl = null; 17 | var self = this; 18 | 19 | // TODO this implicitly relies on the resourceUrl being configured before 20 | // any requests are fired. Could be more robust. 21 | AppStore.listen( function ( state ) { 22 | if ( state.resourceUrl !== null ) { self.baseUrl = state.resourceUrl } 23 | } ); 24 | }; 25 | 26 | GeodataAPI.prototype.onNetworkError = function () { 27 | if ( navigator.onLine ) { 28 | RenderActions.fatalError( 'Failed to download geodata. ' + 29 | 'Please check your internet connection and try again.' ); 30 | } else { 31 | RenderActions.fatalError( 'No internet connection. ' + 32 | 'This area is not available offline, please connect ' + 33 | 'to the internet and try again.' ); 34 | } 35 | }; 36 | 37 | GeodataAPI.prototype.loadFeatures = function ( place ) { 38 | var startTime = track.now(); 39 | var features = place.features ? 40 | place.features.replace( /[^a-z-]/gi, '' ) : 41 | 'features'; 42 | var url = this.baseUrl + features + '/' + place.name + '.geojson'; 43 | this.loader.load( url, function ( result ) { 44 | var time = track.now() - startTime; 45 | track.timing( 'geodata', 'load', place.name, time ); 46 | 47 | // Parse result 48 | startTime = track.now(); 49 | var data = JSON.parse( result ); 50 | time = track.now() - startTime; 51 | track.timing( 'geodata', 'json_parse', place.name, time ); 52 | if ( data.type !== 'FeatureCollection' ) { 53 | log( 'Error - expected FeatureCollection' ); 54 | log( data ); 55 | return; 56 | } 57 | 58 | GeodataActions.setFeatures( data ); 59 | }, GeodataActions.featuresProgress, function () { 60 | log( 'Error - failed to download feature data' ); 61 | GeodataActions.setFeatures( { features: [] } ); 62 | } ); 63 | }; 64 | 65 | export default new GeodataAPI(); 66 | -------------------------------------------------------------------------------- /src/camera.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import ContainerStore from '/stores/container'; 10 | // Changing the far parameter makes little difference, 11 | // the key one is near, as we start losing depth 12 | // precision based on that 13 | // http://www.reedbeta.com/blog/depth-precision-visualized/ 14 | var camera = new THREE.PerspectiveCamera( 15 | 45, // fov 16 | 1, // aspect 17 | 200, // near 18 | 2000000 // far 19 | ); 20 | 21 | ContainerStore.listen( function ( state ) { 22 | camera.aspect = state.aspect; 23 | camera.fov = state.fov / Math.max( camera.aspect, 1.0 ); 24 | camera.updateProjectionMatrix(); 25 | } ); 26 | 27 | export default camera; 28 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | let params = new URLSearchParams( window.location.search.slice( 1 ) ); 9 | 10 | // TODO could support non-square POT textures also 11 | let elevationPoolSize = 8 * 8; 12 | let imageryPoolSize = 16 * 16; 13 | if ( params.has( 'elevationPoolSize' ) ) { 14 | elevationPoolSize = Number.parseInt( params.get( 'elevationPoolSize' ) ); 15 | } 16 | 17 | if ( params.has( 'imageryPoolSize' ) ) { 18 | imageryPoolSize = Number.parseInt( params.get( 'imageryPoolSize' ) ); 19 | } 20 | 21 | export const ELEVATION_POOL_SIZE = elevationPoolSize; 22 | export const ELEVATION_TILE_SIZE = 512; 23 | export const IMAGERY_POOL_SIZE = imageryPoolSize; 24 | export const IMAGERY_TILE_SIZE = 256; 25 | export const INTERPOLATE_FLOAT = params.has( 'interpolateFloat' ); 26 | 27 | // Different formats for encoding pixel data in elevation PNGs 28 | export const PIXEL_ENCODING_NASADEM = 'nasadem'; 29 | export const PIXEL_ENCODING_TERRARIUM = 'terrarium'; 30 | export const PIXEL_ENCODING_TERRAIN_RGB = 'terrain-rgb'; 31 | -------------------------------------------------------------------------------- /src/currentLocation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import CurrentLocationStore from '/stores/currentLocation'; 10 | import geoproject from '/geoproject'; 11 | import material from '/material'; 12 | import RenderStore from '/stores/render'; 13 | import scene from '/scene'; 14 | var CurrentLocation = function ( ) { 15 | THREE.Object3D.call( this ); 16 | this.sphere = new THREE.Mesh( 17 | new THREE.SphereBufferGeometry( 50, 32, 15 ), 18 | material.beacon ); 19 | this.add( this.sphere ); 20 | this.visible = false; 21 | scene.add( this ); 22 | 23 | CurrentLocationStore.listen( this.update.bind( this ) ); 24 | RenderStore.listen( this.tick.bind( this ) ); 25 | }; 26 | 27 | CurrentLocation.prototype = Object.create( THREE.Object3D.prototype ); 28 | 29 | CurrentLocation.prototype.update = function () { 30 | var state = CurrentLocationStore.getState(); 31 | if ( !state.longitude || !state.latitude || state.tooFar ) { 32 | this.visible = false; 33 | return; 34 | } else { 35 | this.visible = true; 36 | } 37 | 38 | var latest = geoproject.project( [ state.longitude, state.latitude ] ); 39 | this.position.copy( latest ); 40 | this.sphere.material.uniforms.uAccuracy.value = state.accuracy || 0; 41 | }; 42 | 43 | CurrentLocation.prototype.tick = function ( state ) { 44 | this.sphere.material.uniforms.uTime.value = state.clock.elapsedTime; 45 | }; 46 | 47 | export default new CurrentLocation(); 48 | -------------------------------------------------------------------------------- /src/data/line.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import _ from 'lodash'; 9 | import alt from '/alt'; 10 | import GeodataActions from '/actions/geodata'; 11 | import OverlayAdapter from '/adapters/overlay'; 12 | import picker from '/picker'; 13 | import UserActions from '/actions/user'; 14 | // Data for showing lines, inside 3D world 15 | function LineData() { 16 | this.data = {}; 17 | 18 | this.bindListeners( { 19 | clearFeatures: UserActions.setCurrentPlace, 20 | addOverlay: [ GeodataActions.addOverlay, GeodataActions.removeOverlay ] 21 | } ); 22 | } 23 | 24 | LineData.prototype.clearFeatures = function () { 25 | this.data = []; 26 | return false; 27 | }; 28 | 29 | LineData.prototype.addOverlay = function () { 30 | this.waitFor( OverlayAdapter ); 31 | var lines = OverlayAdapter.getState().lines; 32 | if ( _.isEqual( this.data, lines ) ) { 33 | // Do not broadcast if data is unchanged 34 | return false; 35 | } 36 | 37 | this.data = lines.concat(); 38 | picker.registerStore( this ); 39 | }; 40 | 41 | LineData.displayName = 'LineData'; 42 | 43 | export default alt.createStore( LineData ); 44 | -------------------------------------------------------------------------------- /src/data/marker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import _ from 'lodash'; 10 | import GeodataActions from '/actions/geodata'; 11 | import OverlayAdapter from '/adapters/overlay'; 12 | import picker from '/picker'; 13 | import RenderActions from '/actions/render'; 14 | import UserActions from '/actions/user'; 15 | function MarkerData() { 16 | this.data = []; 17 | this.haveFonts = false; 18 | this.isUpdate = false; 19 | 20 | this.bindListeners( { 21 | clearFeatures: UserActions.setCurrentPlace, 22 | fontsLoaded: RenderActions.fontsLoaded, 23 | addOverlay: [ 24 | GeodataActions.addBuiltinOverlay, 25 | GeodataActions.addOverlay, 26 | GeodataActions.setFeatures, 27 | GeodataActions.removeOverlay 28 | ], 29 | updateOverlay: GeodataActions.updateOverlay 30 | } ); 31 | } 32 | 33 | MarkerData.prototype.clearFeatures = function () { 34 | this.data = []; 35 | return true; 36 | }; 37 | 38 | MarkerData.prototype.isReady = function () { 39 | return this.haveFonts; 40 | }; 41 | 42 | MarkerData.prototype.fontsLoaded = function () { 43 | // Markers need fonts to be drawn to wait for them to arrive 44 | this.haveFonts = true; 45 | return this.isReady(); 46 | }; 47 | 48 | MarkerData.prototype.addOverlay = function () { 49 | this.waitFor( OverlayAdapter ); 50 | var markers = OverlayAdapter.getState().markers; 51 | if ( _.isEqual( this.data, markers ) ) { 52 | // Do not broadcast if data is unchanged 53 | return false; 54 | } 55 | 56 | this.data = markers.concat(); 57 | picker.registerStore( this ); 58 | this.isUpdate = false; 59 | return this.isReady(); 60 | }; 61 | 62 | MarkerData.prototype.updateOverlay = function () { 63 | this.waitFor( OverlayAdapter ); 64 | var markers = OverlayAdapter.getState().markers; 65 | this.data = markers.concat(); 66 | this.isUpdate = true; 67 | return this.isReady(); 68 | }; 69 | 70 | MarkerData.displayName = 'MarkerData'; 71 | 72 | export default alt.createStore( MarkerData ); 73 | -------------------------------------------------------------------------------- /src/datasources/elevation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import AppStore from '/stores/app'; 9 | import BaseDatasource from './base'; 10 | import { ELEVATION_TILE_SIZE, ELEVATION_POOL_SIZE, 11 | PIXEL_ENCODING_NASADEM } from '/constants'; 12 | 13 | const ElevationDatasource = new BaseDatasource( { 14 | urlFormat: 'https://www.nasadem.xyz/api/v1/dem/{z}/{x}/{y}.png?key={apiKey}', 15 | textureSize: ELEVATION_TILE_SIZE, 16 | maxZoom: 12, 17 | pixelEncoding: PIXEL_ENCODING_NASADEM, 18 | poolSize: ELEVATION_POOL_SIZE, 19 | useFloat: true 20 | } ); 21 | 22 | AppStore.listen( ( { datasource } ) => { 23 | if ( datasource.elevation ) { 24 | for ( let key of [ 'apiKey', 'maxZoom', 'pixelEncoding', 'urlFormat' ] ) { 25 | const value = datasource.elevation[ key ]; 26 | if ( value ) { ElevationDatasource[ key ] = value } 27 | } 28 | } 29 | } ); 30 | 31 | export default ElevationDatasource; 32 | -------------------------------------------------------------------------------- /src/datasources/imagery.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import AppStore from '/stores/app'; 9 | import BaseDatasource from './base'; 10 | import { IMAGERY_TILE_SIZE, IMAGERY_POOL_SIZE } from '/constants'; 11 | 12 | const ImageryDatasource = new BaseDatasource( { 13 | maxZoom: 18, 14 | textureSize: IMAGERY_TILE_SIZE, 15 | poolSize: IMAGERY_POOL_SIZE 16 | } ); 17 | 18 | AppStore.listen( ( { datasource } ) => { 19 | if ( datasource.imagery ) { 20 | for ( let key of [ 'apiKey', 'maxZoom', 'urlFormat' ] ) { 21 | const value = datasource.imagery[ key ]; 22 | if ( value ) { ImageryDatasource[ key ] = value } 23 | } 24 | } 25 | } ); 26 | 27 | export default ImageryDatasource; 28 | -------------------------------------------------------------------------------- /src/empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | export default null; 9 | -------------------------------------------------------------------------------- /src/export/capabilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import Procedural from '/export/core'; 9 | import webgl from '/webgl'; 10 | // External API to engine, listing webgl capabilites 11 | // Expose state of WebGL support 12 | Procedural.missingCapabilities = []; 13 | if ( !webgl.supported || webgl.missing.length > 0 ) { 14 | Procedural.deviceCapable = false; 15 | if ( !webgl.supported ) { 16 | Procedural.missingCapabilities.push( 'WebGL not supported' ); 17 | } 18 | 19 | for ( var i in webgl.missing ) { 20 | if ( webgl.missing.hasOwnProperty( i ) ) { 21 | Procedural.missingCapabilities.push( 'Missing required WebGL extension: ' + webgl.missing[ i ] ); 22 | } 23 | } 24 | } else { 25 | Procedural.deviceCapable = true; 26 | } 27 | 28 | // Signal Procedural API is ready in case where we are not 29 | // capable so that client knows we can proceed 30 | if ( !Procedural.deviceCapable ) { 31 | if ( typeof Procedural.onReady === 'function' ) { Procedural.onReady() } 32 | } 33 | 34 | export default Procedural; 35 | -------------------------------------------------------------------------------- /src/export/controls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import ConfigActions from '/actions/config'; 9 | 10 | const Procedural = {}; 11 | 12 | /** 13 | * @exports Procedural 14 | * @name Controls 15 | * @description Use the Controls API methods to configure 16 | * how the user can interact with the scene 17 | */ 18 | 19 | /** 20 | * @name configureControls 21 | * @memberof module:Controls 22 | * @function 23 | * @description Pass configuration to set parameters for controls 24 | * @param {Object} configuration An Object specifying the configuration 25 | * @example 26 | * // All parameters are optional 27 | * var configuration = { 28 | * // Minimum distance camera can approach scene 29 | * minDistance: 1000, 30 | * // Maximum distance camera can move from scene 31 | * maxDistance: 5000, 32 | * // Maximum distance camera target can move from scene 33 | * maxBounds: 7500, 34 | * // Minimum polar angle of camera 35 | * minPolarAngle: 0.25 * Math.PI, 36 | * // Maximum polar angle of camera 37 | * maxPolarAngle: 0.8 * Math.PI, 38 | * // Set to true to disable panning 39 | * noPan: true, 40 | * // Set to true to disable rotating 41 | * noRotate: false, 42 | * // Set to true to disable zooming 43 | * noZoom: false 44 | * }; 45 | * Procedural.configureControls( configuration ); 46 | */ 47 | Procedural.configureControls = function ( config ) { 48 | if ( !config ) { 49 | console.log( 'No configuration passed' ); 50 | return; 51 | } 52 | 53 | var filtered = {}; 54 | var keys = [ 55 | 'minDistance', 'maxBounds', 'maxDistance', 56 | 'minPolarAngle', 'maxPolarAngle', 57 | 'noPan', 'noRotate', 'noZoom' 58 | ]; 59 | for ( var k in keys ) { 60 | var key = keys[ k ]; 61 | if ( config.hasOwnProperty( key ) ) { filtered[ key ] = config[ key ] } 62 | } 63 | 64 | setTimeout( function () { ConfigActions.configureCamera( filtered ) }, 0 ); 65 | }; 66 | 67 | export default Procedural; 68 | -------------------------------------------------------------------------------- /src/export/environments.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import gui from '/gui'; 9 | import UserActions from '/actions/user'; 10 | 11 | const Procedural = {}; 12 | 13 | /** 14 | * @exports Procedural 15 | * @name Environment 16 | * @description Environments describe how the scene is rendered, 17 | * for example the color of the lighting, or the position of the 18 | * sun. 19 | * 20 | * To interactively adjust the values of the environment 21 | * you can use the editor, launched using: 22 | * [Procedural.environmentEditor]{@link module:Environment.environmentEditor} 23 | */ 24 | 25 | /** 26 | * @name setEnvironment 27 | * @memberof module:Environment 28 | * @function 29 | * @param {Object} environment 30 | * @description Update the engine's environment to the environment 31 | * configuration passed. 32 | * @example 33 | * var environment = { 34 | * title: 'custom', 35 | * parameters: { 36 | * inclination: 0.6, 37 | * fogDropoff: 0.0002 38 | * } 39 | * }; 40 | * Procedural.setEnvironment( environment ) 41 | */ 42 | Procedural.setEnvironment = function ( environment ) { 43 | setTimeout( function () { UserActions.setEnvironment( environment ) }, 0 ); 44 | }; 45 | 46 | /** 47 | * @name environmentEditor 48 | * @memberof module:Environment 49 | * @function 50 | * @description Launches the environment editor 51 | */ 52 | Procedural.environmentEditor = function () { gui.initEnv() }; 53 | 54 | export default Procedural; 55 | -------------------------------------------------------------------------------- /src/export/location.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import CurrentLocationActions from '/actions/currentLocation'; 9 | 10 | const Procedural = {}; 11 | 12 | /** 13 | * @exports Procedural 14 | * @name Location 15 | * @description The Location API methods enable 16 | * a marker indicating where the user is located in the world 17 | */ 18 | 19 | /** 20 | * @name setUserLocation 21 | * @memberof module:Location 22 | * @function 23 | * @description Tells the engine where the current user is located, which 24 | * displays a marker in the 3D world 25 | * @param {Object} position An Object of the format produced by the HTML5 Geolocation API 26 | * @example 27 | * // Manually construct object, can also use navigator.geolocation.watchPosition 28 | * // to obtain 29 | * var position = { 30 | * coords: { 31 | * latitude: 46.46695, 32 | * longitude: 7.52151, 33 | * accuracy: 50 34 | * } 35 | * }; 36 | * 37 | * Procedural.setUserLocation( position ); 38 | */ 39 | Procedural.setUserLocation = function ( position ) { 40 | // Detect object not in coords format and wrap 41 | var p; 42 | if ( position.latitude !== undefined && 43 | position.longitude !== undefined ) { 44 | p = { coords: position }; 45 | } else { 46 | p = position; 47 | } 48 | 49 | setTimeout( function () { CurrentLocationActions.panToPosition( p ) }, 0 ); 50 | }; 51 | 52 | /** 53 | * @name toggleUserLocationTracking 54 | * @memberof module:Location 55 | * @function 56 | * @description Toggles whether the camera automatically follows the user 57 | * when a new location update is sent using [Procedural.setUserLocation]{@link module:Location.setUserLocation}. Initially tracking is disabled. 58 | * Note tracking is automatically disabled when the user manipulates the camera 59 | */ 60 | Procedural.toggleUserLocationTracking = function () { 61 | setTimeout( function () { CurrentLocationActions.toggleTracking() }, 0 ); 62 | }; 63 | 64 | export default Procedural; 65 | -------------------------------------------------------------------------------- /src/export/pause.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import RenderActions from '/actions/render'; 9 | 10 | const Procedural = {}; 11 | 12 | /** 13 | * @exports Procedural 14 | * @name Rendering 15 | * @description The engine will only re-render the scene when 16 | * needed, and automatically pause rendering when appropriate, 17 | * e.g. when the containing browser tab is in the background. 18 | * 19 | * Using the [play]{@link module:Rendering.play} and [pause]{@link module:Rendering.pause} methods the engine can also be paused manually. This can 20 | * be used to pause the engine when the containing element scrolls 21 | * off the page. 22 | */ 23 | 24 | /** 25 | * @name play 26 | * @memberof module:Rendering 27 | * @function 28 | * @description Resumes the engine. See also [Rendering.pause]{@link module:Rendering.pause} 29 | */ 30 | Procedural.play = function () { 31 | setTimeout( function () { RenderActions.play() }, 0 ); 32 | }; 33 | 34 | /** 35 | * @name pause 36 | * @memberof module:Rendering 37 | * @function 38 | * @description Pauses the engine. See also [Rendering.play]{@link module:Rendering.play} 39 | */ 40 | Procedural.pause = function () { 41 | setTimeout( function () { RenderActions.pause() }, 0 ); 42 | }; 43 | 44 | export default Procedural; 45 | -------------------------------------------------------------------------------- /src/export/userInterface.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import ConfigActions from '/actions/config'; 9 | 10 | const Procedural = {}; 11 | 12 | /** 13 | * @exports Procedural 14 | * @name UI 15 | * @description User interface elements can be optionally shown 16 | * on top of the map 17 | */ 18 | 19 | /** 20 | * @name setCameraModeControlVisible 21 | * @memberof module:UI 22 | * @function 23 | * @param {Boolean} value pass true to show control, false to hide 24 | * @description Show/hide the camera mode control 25 | */ 26 | Procedural.setCameraModeControlVisible = function ( value ) { 27 | setTimeout( function () { ConfigActions.setCameraModeControlVisible( value ) }, 0 ); 28 | }; 29 | 30 | /** 31 | * @name setCompassVisible 32 | * @memberof module:UI 33 | * @function 34 | * @param {Boolean} value pass true to show control, false to hide 35 | * @description Show/hide the compass control 36 | */ 37 | Procedural.setCompassVisible = function ( value ) { 38 | setTimeout( function () { ConfigActions.setCompassVisible( value ) }, 0 ); 39 | }; 40 | 41 | /** 42 | * @name setRotationControlVisible 43 | * @memberof module:UI 44 | * @function 45 | * @param {Boolean} value pass true to show control, false to hide 46 | * @description Show/hide the camera rotation control 47 | */ 48 | Procedural.setRotationControlVisible = function ( value ) { 49 | setTimeout( function () { ConfigActions.setRotationControlVisible( value ) }, 0 ); 50 | }; 51 | 52 | /** 53 | * @name setUserLocationControlVisible 54 | * @memberof module:UI 55 | * @function 56 | * @param {Boolean} value pass true to show control, false to hide 57 | * @description Show/hide the user location control. If GPS location is 58 | * not available the control will not be shown. 59 | */ 60 | Procedural.setUserLocationControlVisible = function ( value ) { 61 | setTimeout( function () { ConfigActions.setUserLocationControlVisible( value ) }, 0 ); 62 | }; 63 | 64 | /** 65 | * @name setZoomControlVisible 66 | * @memberof module:UI 67 | * @function 68 | * @param {Boolean} value pass true to show control, false to hide 69 | * @description Show/hide the camera zoom control 70 | */ 71 | Procedural.setZoomControlVisible = function ( value ) { 72 | setTimeout( function () { ConfigActions.setZoomControlVisible( value ) }, 0 ); 73 | }; 74 | 75 | export default Procedural; 76 | -------------------------------------------------------------------------------- /src/gl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var canvas = document.createElement( 'canvas' ); 9 | var gl = canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ); 10 | canvas = undefined; 11 | export default gl; 12 | -------------------------------------------------------------------------------- /src/glUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import gl from '/gl'; 9 | var createShader = function ( type, src ) { 10 | // Create and compile shader 11 | var shader = gl.createShader( type ); 12 | gl.shaderSource( shader, src ); 13 | gl.compileShader( shader ); 14 | 15 | // Check for errors 16 | var status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); 17 | if ( !status ) { 18 | var error = gl.getShaderInfoLog( shader ); 19 | console.error( 'Error compiling shader:\n\n', src, error ); 20 | return null; 21 | } 22 | 23 | return shader; 24 | }; 25 | 26 | var createProgram = function ( vertShader, fragShader ) { 27 | // Create and link program 28 | var program = gl.createProgram(); 29 | var vs = gl.attachShader( program, createShader( gl.VERTEX_SHADER, vertShader ) ); 30 | var fs = gl.attachShader( program, createShader( gl.FRAGMENT_SHADER, fragShader ) ); 31 | gl.linkProgram( program ); 32 | 33 | // Check for errors 34 | var status = gl.getProgramParameter( program, gl.LINK_STATUS ); 35 | if ( !status ) { 36 | var error = gl.getProgramInfoLog( program ); 37 | console.error( 'Error linking program', program, error ); 38 | return null; 39 | } 40 | 41 | // Clean up 42 | gl.deleteShader( vs ); 43 | gl.deleteShader( fs ); 44 | return program; 45 | }; 46 | 47 | export default { 48 | createProgram: createProgram 49 | }; 50 | -------------------------------------------------------------------------------- /src/gui.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import dat from 'dat'; 9 | import envParams from '/envParams'; 10 | import RenderActions from '/actions/render'; 11 | var out = { 12 | gui: null, 13 | onChange: null, 14 | initEnv: function () { 15 | if ( out.envGui ) { return } 16 | 17 | var guiChanged = function () { 18 | envParams.update(); 19 | RenderActions.needsRender( { env: true } ); 20 | if ( out.onChange ) { out.onChange() } 21 | }; 22 | 23 | var envGui = new dat.GUI(); 24 | out.envGui = envGui; 25 | envGui.remember( envParams ); 26 | 27 | var guiSky = envGui.addFolder( 'Sky' ); 28 | guiSky.add( envParams, 'turbidity', 1.0, 20.0 ).onChange( guiChanged ); 29 | guiSky.add( envParams, 'reileigh', 0.0, 4 ).onChange( guiChanged ); 30 | guiSky.add( envParams, 'mieCoefficient', 0.0, 0.1 ).onChange( guiChanged ); 31 | guiSky.add( envParams, 'mieDirectionalG', 0.0, 1 ).onChange( guiChanged ); 32 | guiSky.add( envParams, 'luminance', 0.0, 2 ).onChange( guiChanged ); 33 | guiSky.add( envParams, 'inclination', 0.4, 1 ).onChange( guiChanged ); 34 | guiSky.add( envParams, 'azimuth', 0, 1 ).onChange( guiChanged ); 35 | 36 | var guiFog = envGui.addFolder( 'Fog' ); 37 | guiFog.add( envParams, 'fogDropoff', 0, 0.0001 ).onChange( guiChanged ); 38 | guiFog.add( envParams, 'fogIntensity', 0, 2.5 ).onChange( guiChanged ); 39 | 40 | var guiScene = envGui.addFolder( 'Scene' ); 41 | guiScene.add( envParams, 'exposureBias', 0.1, 10 ).onChange( guiChanged ); 42 | guiScene.add( envParams, 'whitePoint', 0.1, 30 ).onChange( guiChanged ); 43 | }, 44 | }; 45 | 46 | // Quick display of GUI 47 | window.letMePlay = function () { 48 | out.initEnv(); 49 | }; 50 | 51 | export default out; 52 | -------------------------------------------------------------------------------- /src/heightAt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | /// Looks up height at specific location in height dataset 9 | import tilebelt from "@mapbox/tilebelt"; 10 | 11 | import GeoprojectStore from '/stores/geoproject'; 12 | import ElevationDatasource from '/datasources/elevation'; 13 | 14 | import dataToHeight from '/utils/dataToHeight'; 15 | 16 | const earthScale = 0.0008176665341588574; 17 | function heightScale( p ) { 18 | const sceneScale = GeoprojectStore.getState().sceneScale; 19 | let tile; 20 | if ( p.longitude ) { 21 | tile = tilebelt.pointToTile( p.longitude, p.latitude, 10 ); 22 | } else { 23 | tile = GeoprojectStore.positionToTileFraction( p, 10 ); 24 | } 25 | 26 | const n = 3.141592653589793 - 0.006135923151542565 * tile[ 1 ]; 27 | return Math.cosh( n ) / ( earthScale * sceneScale ); 28 | } 29 | 30 | // Simplified height lookup, doesn't interpolate between points 31 | // just picks the nearest pixel 32 | function heightAt( p, callback ) { 33 | const data = ElevationDatasource.dataAtPoint( p ); 34 | if ( !data ) { 35 | if ( typeof callback === 'function' ) { 36 | const listener = () => { 37 | // Now that data has updated, try again to fetch 38 | const data = ElevationDatasource.dataAtPoint( p ); 39 | if ( data ) { 40 | ElevationDatasource.removeListener( listener ); 41 | callback( dataToHeight( data, ElevationDatasource.pixelEncoding ) * heightScale( p ) ); 42 | } 43 | }; 44 | 45 | // Don't have data yet, but want to register for callback 46 | // once available 47 | ElevationDatasource.addListener( listener ); 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | const H = dataToHeight( data, ElevationDatasource.pixelEncoding ) * heightScale( p ); 54 | if ( typeof callback === 'function' ) { callback( H ) } 55 | 56 | return H; 57 | } 58 | 59 | export default heightAt; 60 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import CameraExport from '/export/camera'; 9 | import ControlsExport from '/export/controls'; 10 | import CoreExport from '/export/core'; 11 | import DisplayLocationExport from '/export/displayLocation'; 12 | import EnvironmentsExport from '/export/environments'; 13 | import FeaturesExport from '/export/features'; 14 | import PauseExport from '/export/pause'; 15 | import LocationExport from '/export/location'; 16 | import UserInterfaceExport from '/export/userInterface'; 17 | 18 | // Entry point into app 19 | import '/views/root.jsx'; 20 | /*global __buildVersion__*/ 21 | console.log( 'Procedural v' + __buildVersion__ ); 22 | 23 | // Re-export public API 24 | const Procedural = { 25 | ...CameraExport, 26 | ...ControlsExport, 27 | ...CoreExport, 28 | ...DisplayLocationExport, 29 | ...EnvironmentsExport, 30 | ...FeaturesExport, 31 | ...PauseExport, 32 | ...LocationExport, 33 | ...UserInterfaceExport 34 | }; 35 | 36 | // Proxy through setters as destructing won't pass these through 37 | let listeners = [ 38 | 'onFeatureClicked', 39 | 'onFeatureSelected', 40 | 'onOverlayAdded' 41 | ]; 42 | for ( let l of listeners ) { 43 | Object.defineProperty( Procedural, l, { 44 | set: fn => FeaturesExport[ l ] = fn 45 | } ); 46 | } 47 | 48 | listeners = [ 49 | 'onCameraChange' 50 | ]; 51 | for ( let l of listeners ) { 52 | Object.defineProperty( Procedural, l, { 53 | set: fn => CameraExport[ l ] = fn 54 | } ); 55 | } 56 | 57 | listeners = [ 58 | 'onBoundsFocused', 59 | 'onLocationError', 60 | 'onLocationFocused', 61 | 'onLocationLoaded', 62 | 'onUserInteraction' 63 | ]; 64 | for ( let l of listeners ) { 65 | Object.defineProperty( Procedural, l, { 66 | set: fn => CoreExport[ l ] = fn 67 | } ); 68 | } 69 | 70 | export default Procedural; 71 | -------------------------------------------------------------------------------- /src/lines.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import LinesBase from '/linesBase'; 9 | import material from '/material'; 10 | import LineData from '/data/line'; 11 | import RenderActions from '/actions/render'; 12 | import scene from '/scene'; 13 | var Lines = function () { 14 | LinesBase.call( this ); 15 | 16 | LineData.listen( this.onNewData.bind( this ) ); 17 | scene.pickerScene.add( this ); 18 | 19 | this.material = material.line; 20 | this.name = 'lines'; 21 | RenderActions.renderedFeatureRegister( this.name ); 22 | 23 | this.constantWidth = true; 24 | }; 25 | 26 | Lines.prototype = Object.create( LinesBase.prototype ); 27 | 28 | export default new Lines(); 29 | -------------------------------------------------------------------------------- /src/log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | let log; 9 | if ( __dev__ ) { 10 | log = function () { 11 | if ( arguments.length ) { 12 | console.log.apply( console, arguments ); 13 | } 14 | }; 15 | } else { 16 | log = () => {}; // Disable logging 17 | } 18 | 19 | export default log; 20 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | url("data:image/svg+xml,") 2 | -------------------------------------------------------------------------------- /src/normalAt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | /// Looks up normal at specific location in height dataset 9 | /// Looks up normal at specific location in height dataset 10 | import THREE from 'three'; 11 | 12 | import heightAt from '/heightAt'; 13 | var p1 = new THREE.Vector3( 0, 0, 0 ); 14 | var p2 = new THREE.Vector3( 0, 0, 0 ); 15 | var addNormal = function ( normal, origin, delta1, delta2 ) { 16 | p1.addVectors( origin, delta1 ); 17 | delta1.z = heightAt( p1 ) - origin.z; 18 | 19 | p2.addVectors( origin, delta2 ); 20 | delta2.z = heightAt( p2 ) - origin.z; 21 | 22 | delta1.cross( delta2 ); 23 | delta1.normalize(); 24 | normal.add( delta1 ); 25 | }; 26 | 27 | var n = 1, i; // Just keep it simple and only compute one normal 28 | var theta = 2 * Math.PI / n; 29 | var origin = new THREE.Vector3(); 30 | var defaultStep = 25; 31 | var normal = new THREE.Vector3( 0, 0, 1 ); 32 | var d1 = new THREE.Vector3( 0, 0, 0 ); 33 | var d2 = new THREE.Vector3( 0, 0, 0 ); 34 | var normalAt = function ( p, step ) { 35 | step = step ? step : defaultStep; 36 | 37 | origin.copy( p ); 38 | origin.z = heightAt( origin ); 39 | normal.set( 0, 0, 0 ); 40 | for ( i = 0; i < n; i++ ) { 41 | d1.x = step * Math.cos( i * theta ); 42 | d1.y = step * Math.sin( i * theta ); 43 | d2.x = -d1.y; 44 | d2.y = d1.x; 45 | addNormal( normal, origin, d1, d2 ); 46 | } 47 | 48 | normal.normalize(); 49 | return normal; 50 | }; 51 | 52 | export default normalAt; 53 | -------------------------------------------------------------------------------- /src/picking.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import renderer from '/renderer'; 10 | import ContainerStore from '/stores/container'; 11 | import tilepickerUniforms from '/uniforms/tilepicker'; 12 | 13 | // Picking 14 | const canvas = renderer.domElement; 15 | const TilePicker = { 16 | data: new Uint8Array( 4 * canvas.width * canvas.height ), 17 | target: new THREE.WebGLRenderTarget( canvas.width, canvas.height ), 18 | } 19 | 20 | // Make independent target for picking to not intefere with terrain 21 | const FeaturePicker = { 22 | data: new Uint8Array( 4 * canvas.width * canvas.height ), 23 | target: new THREE.WebGLRenderTarget( canvas.width, canvas.height ), 24 | } 25 | 26 | function updateSize( { width, height, renderRatio } ) { 27 | // Want to scale down so that resulting canvas is 500 pixels 28 | // This means 500 pixels total not 500 wide!!! 29 | let downScale = Math.sqrt( ( width * height ) / 500 ); 30 | let w = 2 * Math.round( 0.5 * width / downScale ); 31 | let h = 2 * Math.round( 0.5 * height / downScale ); 32 | if ( !TilePicker.target || 33 | w !== TilePicker.target.width || 34 | h !== TilePicker.target.height ) { 35 | TilePicker.target = new THREE.WebGLRenderTarget( w, h ); 36 | TilePicker.data = new Uint8Array( 4 * TilePicker.target.width * TilePicker.target.height ); 37 | 38 | // 16X picker to be improve click accuracy 39 | FeaturePicker.target = new THREE.WebGLRenderTarget( 16 * w, 16 * h ); 40 | FeaturePicker.data = new Uint8Array( 4 * FeaturePicker.target.width * FeaturePicker.target.height ); 41 | 42 | // Update shaders 43 | tilepickerUniforms.uScaling.value.set( 44 | 0.5 * w, 0.5 * h, // Location of center pixel 45 | 256 / ( renderRatio * downScale ) // Scaling factor for uv error to compensate downScale 46 | ); 47 | } 48 | } 49 | 50 | ContainerStore.listen( updateSize ); 51 | 52 | export { 53 | TilePicker, FeaturePicker 54 | } 55 | -------------------------------------------------------------------------------- /src/postprocessing/CopyShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Full-screen textured quad shader 5 | */ 6 | 7 | 8 | 9 | var CopyShader = { 10 | 11 | uniforms: { 12 | 13 | "tDiffuse": { value: null }, 14 | "opacity": { value: 1.0 } 15 | 16 | }, 17 | 18 | vertexShader: [ 19 | "precision highp float;", 20 | 21 | "uniform mat4 modelViewMatrix;", 22 | "uniform mat4 projectionMatrix;", 23 | 24 | "attribute vec3 position;", 25 | "attribute vec2 uv;", 26 | 27 | "varying vec2 vUv;", 28 | 29 | "void main() {", 30 | 31 | " vUv = uv;", 32 | " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 33 | 34 | "}" 35 | 36 | ].join( "\n" ), 37 | 38 | fragmentShader: [ 39 | 40 | "precision highp float;", 41 | 42 | "uniform float opacity;", 43 | 44 | "uniform sampler2D tDiffuse;", 45 | 46 | "varying vec2 vUv;", 47 | 48 | "void main() {", 49 | 50 | " vec4 texel = texture2D( tDiffuse, vUv );", 51 | " gl_FragColor = opacity * texel;", 52 | 53 | "}" 54 | 55 | ].join( "\n" ) 56 | 57 | }; 58 | 59 | export { CopyShader }; 60 | -------------------------------------------------------------------------------- /src/postprocessing/Pass.js: -------------------------------------------------------------------------------- 1 | import { 2 | OrthographicCamera, 3 | PlaneBufferGeometry, 4 | Mesh 5 | } from "three.lib"; 6 | 7 | function Pass() { 8 | 9 | // if set to true, the pass is processed by the composer 10 | this.enabled = true; 11 | 12 | // if set to true, the pass indicates to swap read and write buffer after rendering 13 | this.needsSwap = true; 14 | 15 | // if set to true, the pass clears its buffer before rendering 16 | this.clear = false; 17 | 18 | // if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer. 19 | this.renderToScreen = false; 20 | 21 | } 22 | 23 | Object.assign( Pass.prototype, { 24 | 25 | setSize: function ( /* width, height */ ) {}, 26 | 27 | render: function ( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) { 28 | 29 | console.error( 'THREE.Pass: .render() must be implemented in derived pass.' ); 30 | 31 | } 32 | 33 | } ); 34 | 35 | // Helper for passes that need to fill the viewport with a single quad. 36 | 37 | Pass.FullScreenQuad = ( function () { 38 | 39 | var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); 40 | var geometry = new PlaneBufferGeometry( 2, 2 ); 41 | 42 | var FullScreenQuad = function ( material ) { 43 | 44 | this._mesh = new Mesh( geometry, material ); 45 | this._camera = camera; 46 | 47 | }; 48 | 49 | Object.defineProperty( FullScreenQuad.prototype, 'material', { 50 | 51 | get: function () { 52 | 53 | return this._mesh.material; 54 | 55 | }, 56 | 57 | set: function ( value ) { 58 | 59 | this._mesh.material = value; 60 | 61 | } 62 | 63 | } ); 64 | 65 | Object.assign( FullScreenQuad.prototype, { 66 | 67 | dispose: function () { 68 | 69 | this._mesh.geometry.dispose(); 70 | 71 | }, 72 | 73 | render: function ( renderer ) { 74 | 75 | renderer.render( this._mesh, camera ); 76 | 77 | } 78 | } ); 79 | 80 | return FullScreenQuad; 81 | 82 | } )(); 83 | 84 | export { Pass }; 85 | -------------------------------------------------------------------------------- /src/postprocessing/SavePass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | import { 6 | LinearFilter, 7 | RGBFormat, 8 | ShaderMaterial, 9 | UniformsUtils, 10 | WebGLRenderTarget 11 | } from "three.lib"; 12 | import { Pass } from "../postprocessing/Pass.js"; 13 | import { CopyShader } from "../postprocessing/CopyShader.js"; 14 | 15 | var SavePass = function ( renderTarget ) { 16 | 17 | Pass.call( this ); 18 | 19 | if ( CopyShader === undefined ) 20 | console.error( "SavePass relies on CopyShader" ); 21 | 22 | var shader = CopyShader; 23 | 24 | this.textureID = "tDiffuse"; 25 | 26 | this.uniforms = UniformsUtils.clone( shader.uniforms ); 27 | 28 | this.material = new ShaderMaterial( { 29 | 30 | uniforms: this.uniforms, 31 | vertexShader: shader.vertexShader, 32 | fragmentShader: shader.fragmentShader 33 | 34 | } ); 35 | 36 | this.renderTarget = renderTarget; 37 | 38 | if ( this.renderTarget === undefined ) { 39 | 40 | this.renderTarget = new WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBFormat, stencilBuffer: false } ); 41 | this.renderTarget.texture.name = "SavePass.rt"; 42 | 43 | } 44 | 45 | this.needsSwap = false; 46 | 47 | this.fsQuad = new Pass.FullScreenQuad( this.material ); 48 | 49 | }; 50 | 51 | SavePass.prototype = Object.assign( Object.create( Pass.prototype ), { 52 | 53 | constructor: SavePass, 54 | 55 | render: function ( renderer, writeBuffer, readBuffer ) { 56 | 57 | if ( this.uniforms[ this.textureID ] ) { 58 | 59 | this.uniforms[ this.textureID ].value = readBuffer.texture; 60 | 61 | } 62 | 63 | renderer.setRenderTarget( this.renderTarget ); 64 | if ( this.clear ) renderer.clear(); 65 | this.fsQuad.render( renderer ); 66 | 67 | } 68 | 69 | } ); 70 | 71 | export { SavePass }; 72 | -------------------------------------------------------------------------------- /src/renderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import ContainerStore from '/stores/container'; 10 | var renderer = new THREE.WebGLRenderer( { 11 | alpha: true, 12 | antialias: false, 13 | clearColor: 0x000000, 14 | logarithmicDepthBuffer: false 15 | } ); 16 | renderer.sortObjects = true; 17 | 18 | // Don't clear buffers we know will be overwritten 19 | renderer.autoClear = false; 20 | renderer.autoClearColor = false; 21 | renderer.autoClearDepth = true; 22 | renderer.autoClearStencil = false; 23 | renderer.domElement.selectable = false; 24 | // We do our own tonemapping, so disable otherwise get shader errors 25 | renderer.toneMapping = THREE.NoToneMapping; 26 | 27 | var state = ContainerStore.getState(); 28 | renderer.setPixelRatio( state.pixelRatio ); 29 | renderer.setSize( state.width, state.height ); 30 | ContainerStore.listen( function ( state ) { 31 | renderer.setPixelRatio( state.pixelRatio ); 32 | renderer.setSize( state.width, state.height ); 33 | } ); 34 | 35 | export default renderer; 36 | -------------------------------------------------------------------------------- /src/rollup-plugin-shader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 'use strict'; 9 | 10 | function _interopDefault( ex ) { return ( ex && ( typeof ex === 'object' ) && 'default' in ex ) ? ex[ 'default' ] : ex } 11 | 12 | const { readFileSync } = require( 'fs' ); 13 | const { dirname } = require( 'path' ); 14 | var rollupPluginutils = require( 'rollup-pluginutils' ); 15 | var MagicString = _interopDefault( require( 'magic-string' ) ); 16 | 17 | // Loads #includes into passed shader 18 | function loadIncludes( source, id ) { 19 | // First, search for any include statements 20 | var matches = []; 21 | source.replace( /#include (.*)/g, function ( match, includeFile ) { 22 | matches.push( includeFile ); 23 | } ); 24 | if ( matches.length === 0 ) { return source } 25 | 26 | var pathName = dirname( id ); 27 | for ( var m = 0; m < matches.length; m++ ) { 28 | var includeFile = matches[ m ]; 29 | var includeShader = readFileSync( 30 | `${pathName}/${includeFile}`, { encoding: 'utf8' } ); 31 | var regexp = new RegExp( "#include " + includeFile, "g" ); 32 | source = source.replace( regexp, includeShader ); 33 | } 34 | 35 | return loadIncludes( source, id ); 36 | } 37 | 38 | // Plugin to load shader files and return them wrapped in Shader class 39 | function shader( options ) { 40 | if ( options === void 0 ) options = {}; 41 | 42 | var filter = rollupPluginutils.createFilter( 43 | options.include, options.exclude ); 44 | 45 | return { 46 | name: 'shader', 47 | 48 | transform: function transform( source, id ) { 49 | if ( !filter( id ) ) return; 50 | 51 | // TODO perhaps could be nice to sourcemap this also? 52 | source = loadIncludes( source, id ); 53 | 54 | var s = new MagicString( source.replace( /`/g, '\\`' ) ); 55 | s.prepend( 'import Shader from "/utils/shader"; export default new Shader(`' ) 56 | .append( '`);' ); 57 | var code = s.toString(); 58 | 59 | var result = { code }; 60 | result.map = s.generateMap( { hires: true } ); 61 | return result; 62 | } 63 | }; 64 | } 65 | 66 | export default shader; 67 | -------------------------------------------------------------------------------- /src/scene.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | var scene = new THREE.Scene(); 10 | scene.hd = new THREE.Scene(); 11 | scene.tilepickerScene = new THREE.Scene(); 12 | scene.pickerScene = new THREE.Scene(); 13 | export default scene; 14 | -------------------------------------------------------------------------------- /src/sky.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | 10 | import camera from '/camera'; 11 | import material from '/material'; 12 | import scene from '/scene'; 13 | 14 | const hemisphere = new THREE.SphereBufferGeometry( 0.8 * camera.far , 32, 6, 0, 2 * Math.PI, 0, 0.6 * Math.PI ); 15 | const m = new THREE.Matrix4(); 16 | m.makeRotationX( Math.PI / 2 ); 17 | hemisphere.applyMatrix4( m ); 18 | 19 | const mesh = new THREE.Mesh( hemisphere, material.sky ); 20 | mesh.geometry.computeBoundingBox(); 21 | mesh.renderOrder = 10000; // Render sky last as often obscured 22 | scene.add( mesh ); 23 | export default mesh; 24 | -------------------------------------------------------------------------------- /src/skyBox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import _ from 'lodash'; 10 | import renderer from '/renderer'; 11 | import skyUniforms from '/uniforms/sky'; 12 | import skyBoxUniforms from '/uniforms/skyBox'; 13 | import skySpheremapFragment from 'shader/skySpheremap.frag'; 14 | import tonemapUniforms from '/uniforms/tonemap'; 15 | import quadVertex from 'shader/quad.vert'; 16 | import RenderStore from '/stores/render'; 17 | import webgl from '/webgl'; 18 | // Renders sky onto plane render target 19 | var skyBox = { 20 | camera: null, 21 | enabled: true, 22 | renderTarget: null, 23 | scene: new THREE.Scene(), 24 | init: function () { 25 | var parameters = { 26 | format: THREE.RGBFormat, 27 | type: ( webgl.render565 ? THREE.UnsignedShort565Type : 28 | THREE.UnsignedByteType ), 29 | depthBuffer: false, 30 | stencilBuffer: false, 31 | wrapS: THREE.ClampToEdgeWrapping, 32 | wrapT: THREE.ClampToEdgeWrapping 33 | }; 34 | 35 | // Render quad orthographically 36 | skyBox.width = 256; // 256KB of memory (if just using for fog do not need accuracy) 37 | skyBox.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 10000 ); 38 | skyBox.scene.add( skyBox.camera ); 39 | skyBox.camera.position.z = 10; 40 | skyBox.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); // Look up at sky! 41 | skyBox.renderTarget = new THREE.WebGLRenderTarget( skyBox.width, skyBox.width, parameters ); 42 | skyBoxUniforms.uSkybox.value = skyBox.renderTarget.texture; 43 | 44 | var plane = new THREE.PlaneBufferGeometry( 2, 2 ); 45 | skySpheremapFragment.define( 'STEP', ( 1.0 / skyBox.width ).toExponential() ); 46 | var material = new THREE.RawShaderMaterial( { 47 | name: 'skybox', 48 | uniforms: _.assign( {}, 49 | skyUniforms, 50 | tonemapUniforms 51 | ), 52 | vertexShader: quadVertex.value, 53 | fragmentShader: skySpheremapFragment.value 54 | } ); 55 | var quad = new THREE.Mesh( plane, material ); 56 | skyBox.scene.add( quad ); 57 | 58 | // Trigger renders 59 | RenderStore.listen( function ( state ) { 60 | if ( state.env ) { skyBox.process() } 61 | } ); 62 | }, 63 | process: function () { 64 | renderer.setRenderTarget( skyBox.renderTarget ); 65 | renderer.render( skyBox.scene, skyBox.camera ); 66 | } 67 | }; 68 | 69 | skyBox.init(); 70 | 71 | export default skyBox; 72 | -------------------------------------------------------------------------------- /src/stores/animation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | 10 | import RenderActions from '/actions/render'; 11 | // In order to provide frame based animation, wrap requestAnimationFrame 12 | // in a Store, so we can emit evens the rest of the app can listen to 13 | // This allows us to have multiple syncronized animations, but only one RaF 14 | function AnimationStore() { 15 | this.paused = false; 16 | this.time = 0; 17 | this.bindListeners( { 18 | play: RenderActions.play, 19 | pause: RenderActions.pause 20 | } ); 21 | 22 | // Setup syncronizing RaF 23 | const tick = time => { 24 | window.requestAnimationFrame( tick ); 25 | if ( !this.paused ) { 26 | this.time = time; 27 | this.emitChange(); 28 | } 29 | }; 30 | 31 | window.requestAnimationFrame( tick ); 32 | } 33 | 34 | AnimationStore.prototype.play = function () { 35 | this.paused = false; 36 | return false; 37 | }; 38 | 39 | AnimationStore.prototype.pause = function () { 40 | this.paused = true; 41 | return false; 42 | }; 43 | 44 | AnimationStore.displayName = 'AnimationStore'; 45 | 46 | export default alt.createStore( AnimationStore ); 47 | -------------------------------------------------------------------------------- /src/stores/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import ConfigActions from '/actions/config'; 10 | import RenderActions from '/actions/render'; 11 | function AppStore() { 12 | this.appContainer = null; 13 | this.datasource = {}; 14 | this.fatalError = false; 15 | this.initialized = false; 16 | this.resourceUrl = null; 17 | this.bindListeners( { 18 | configureElevationDatasource: ConfigActions.configureElevationDatasource, 19 | configureImageryDatasource: ConfigActions.configureImageryDatasource, 20 | setAppContainer: ConfigActions.setAppContainer, 21 | setFatalError: RenderActions.fatalError, 22 | setResourceUrl: ConfigActions.setResourceUrl 23 | } ); 24 | } 25 | 26 | AppStore.prototype.checkInitialized = function () { 27 | this.initialized = ( this.appContainer !== null ) && 28 | ( this.resourceUrl !== null ); 29 | }; 30 | 31 | AppStore.prototype.configureElevationDatasource = function ( elevation ) { 32 | this.datasource.elevation = elevation; 33 | }; 34 | 35 | AppStore.prototype.configureImageryDatasource = function ( imagery ) { 36 | this.datasource.imagery = imagery; 37 | }; 38 | 39 | AppStore.prototype.setFatalError = function () { 40 | this.fatalError = true; 41 | }; 42 | 43 | AppStore.prototype.setAppContainer = function ( container ) { 44 | this.appContainer = container; 45 | this.checkInitialized(); 46 | }; 47 | 48 | AppStore.prototype.setResourceUrl = function ( url ) { 49 | this.resourceUrl = url; 50 | this.checkInitialized(); 51 | }; 52 | 53 | AppStore.displayName = 'AppStore'; 54 | export default alt.createStore( AppStore ); 55 | -------------------------------------------------------------------------------- /src/stores/environment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import SetterStore from '/utils/setterStore'; 10 | import UserActions from '/actions/user'; 11 | var EnvironmentStore = SetterStore( [ 12 | [ UserActions.setEnvironment, {} ] 13 | ] ); 14 | EnvironmentStore.displayName = 'EnvironmentStore'; 15 | export default alt.createStore( EnvironmentStore ); 16 | -------------------------------------------------------------------------------- /src/stores/error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import ConfigActions from '/actions/config'; 10 | import RenderActions from '/actions/render'; 11 | import UserActions from '/actions/user'; 12 | function ErrorStore() { 13 | this.message = null; 14 | this.displayErrors = true; 15 | this.bindListeners( { 16 | clearError: UserActions.setCurrentPlace, 17 | fatalError: RenderActions.fatalError, 18 | setDisplayErrors: ConfigActions.setDisplayErrors 19 | } ); 20 | } 21 | 22 | ErrorStore.prototype.clearError = function () { 23 | this.message = null; 24 | }; 25 | 26 | ErrorStore.prototype.fatalError = function ( message ) { 27 | this.message = message; 28 | }; 29 | 30 | ErrorStore.prototype.setDisplayErrors = function ( value ) { 31 | this.displayErrors = value; 32 | }; 33 | 34 | ErrorStore.displayName = 'ErrorStore'; 35 | export default alt.createStore( ErrorStore ); 36 | -------------------------------------------------------------------------------- /src/stores/features.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import UserActions from '/actions/user'; 10 | function FeaturesStore() { 11 | this.selected = null; 12 | 13 | this.bindListeners( { 14 | animateAlongFeature: UserActions.animateAlongFeature, 15 | onFeatureSelected: UserActions.featureSelected 16 | } ); 17 | } 18 | 19 | 20 | FeaturesStore.prototype.animateAlongFeature = function () { 21 | this.selected = null; 22 | }; 23 | 24 | FeaturesStore.prototype.onFeatureSelected = function ( feature ) { 25 | this.selected = feature; 26 | }; 27 | 28 | FeaturesStore.displayName = 'FeaturesStore'; 29 | export default alt.createStore( FeaturesStore ); 30 | -------------------------------------------------------------------------------- /src/stores/places.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import SetterStore from '/utils/setterStore'; 10 | import UserActions from '/actions/user'; 11 | var PlacesStore = SetterStore( [ 12 | [ UserActions.setCurrentPlace, {} ] 13 | ] ); 14 | PlacesStore.displayName = 'PlacesStore'; 15 | export default alt.createStore( PlacesStore ); 16 | -------------------------------------------------------------------------------- /src/stores/userInput.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import alt from '/alt'; 10 | import CurrentLocationActions from '/actions/currentLocation'; 11 | import UserActions from '/actions/user'; 12 | // Special store to trigger on any user input 13 | // Primarily used for cancelling transitions (see `utils/store`) 14 | function UserInputStore() { 15 | this.clock = new THREE.Clock(); 16 | this.lastInput = this.clock.getElapsedTime(); 17 | this.interacting = false; 18 | 19 | // Any action in this list will cause a running transition be cancelled 20 | this.bindListeners( { 21 | onInput: [ 22 | CurrentLocationActions.toggleTracking, 23 | UserActions.animateAlongFeature, 24 | UserActions.doubleTapZoom, 25 | UserActions.focusOnFeature, 26 | UserActions.focusOnLocation, 27 | UserActions.focusOnTarget, 28 | UserActions.inputStarted, 29 | UserActions.inputEnded, 30 | UserActions.rotateLeft, 31 | UserActions.rotateRight, 32 | UserActions.featureClicked, 33 | UserActions.setCurrentPlace, 34 | UserActions.startFlyover, 35 | UserActions.zoomIn, 36 | UserActions.zoomOut 37 | ], 38 | inputStarted: UserActions.inputStarted, 39 | inputEnded: UserActions.inputEnded 40 | } ); 41 | } 42 | 43 | UserInputStore.prototype.onInput = function () { 44 | this.lastInput = this.clock.getElapsedTime(); 45 | }; 46 | 47 | UserInputStore.prototype.inputStarted = function () { 48 | this.interacting = true; 49 | }; 50 | 51 | UserInputStore.prototype.inputEnded = function () { 52 | this.interacting = false; 53 | this.onInput(); 54 | }; 55 | 56 | UserInputStore.displayName = 'UserInputStore'; 57 | export default alt.createStore( UserInputStore ); 58 | -------------------------------------------------------------------------------- /src/stores/userInterface.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import alt from '/alt'; 9 | import ConfigActions from '/actions/config'; 10 | import SetterStore from '/utils/setterStore'; 11 | import UserActions from '/actions/user'; 12 | var UserInterfaceStore = SetterStore( [ 13 | [ ConfigActions.setCameraModeControlVisible ], 14 | [ ConfigActions.setCompassVisible ], 15 | [ ConfigActions.setLayersControlVisible ], 16 | [ ConfigActions.setRotationControlVisible ], 17 | [ ConfigActions.setSeasonControlVisible ], 18 | [ UserActions.setSecondaryParams ], 19 | [ ConfigActions.setUserLocationControlVisible ], 20 | [ ConfigActions.setZoomControlVisible ] 21 | ] ); 22 | UserInterfaceStore.displayName = 'UserInterfaceStore'; 23 | export default alt.createStore( UserInterfaceStore ); 24 | -------------------------------------------------------------------------------- /src/templates/default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | export default { 9 | "env": { 10 | "turbidity": 2.928118393234672, 11 | "reileigh": 0.631430584918957, 12 | "mieCoefficient": 0.006765327695560254, 13 | "mieDirectionalG": 0.9020436927413672, 14 | "luminance": 0.7892882311486963, 15 | "inclination": 0.6376744186046512, 16 | "azimuth": 0.881, 17 | "sun": false, 18 | "fogDropoff": 0.0000065, 19 | "fogIntensity": 1, 20 | "exposureBias": 1.25, 21 | "whitePoint": 2.5, 22 | "ambientColor": "#2d3034", 23 | "diffuseColor": "#aeafa4", 24 | "backscatterColor": "#181d20", 25 | "ambientOcclusion": 1.17 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/track.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | /*global performance*/ 9 | import log from '/log'; 10 | let timeSource = performance || Date; 11 | let track; 12 | 13 | if ( __dev__ ) { 14 | track = { 15 | raw: function () { 16 | // Parse out object for display 17 | // At the moment we do not collect analytics, but keeping 18 | // format in case we want to change in future 19 | var tag = arguments[ 1 ].toUpperCase(); 20 | var args = [ tag ]; 21 | var obj = arguments[ 2 ]; 22 | var labels = [ 23 | 'eventCategory', 'eventAction', 'eventLabel', 'eventValue', 24 | 'timingCategory', 'timingVar', 'timingLabel', 'timingValue' 25 | ]; 26 | labels.forEach( function ( label ) { 27 | if ( obj[ label ] !== undefined ) { 28 | if ( label === 'timingValue' ) { 29 | args.push( obj[ label ].toFixed( 0 ) + 'ms' ); 30 | } else { 31 | args.push( obj[ label ] ); 32 | } 33 | } 34 | } ); 35 | log.apply( window, args ); 36 | }, 37 | event: function ( category, action, label, value ) { 38 | var obj = {}; 39 | if ( category ) { obj.eventCategory = category } 40 | 41 | if ( action ) { obj.eventAction = action } 42 | 43 | if ( label ) { obj.eventLabel = label } 44 | 45 | if ( value ) { obj.eventValue = value } 46 | 47 | track.raw( 'send', 'event', obj ); 48 | }, 49 | timing: function ( category, variable, label, value ) { 50 | var obj = {}; 51 | if ( category ) { obj.timingCategory = category } 52 | 53 | if ( variable ) { obj.timingVar = variable } 54 | 55 | if ( label ) { obj.timingLabel = label } 56 | 57 | if ( value ) { obj.timingValue = Math.round( value ) } 58 | 59 | track.raw( 'send', 'timing', obj ); 60 | }, 61 | onload: null, 62 | now: function () { return timeSource.now() } 63 | }; 64 | setTimeout( function () { 65 | if ( track.onload ) { track.onload() } 66 | } ); 67 | } else { 68 | // Mock out in production build 69 | track = { 70 | event: () => {}, 71 | timing: () => {}, 72 | onload: null, 73 | now: () => 0 74 | }; 75 | } 76 | 77 | export default track; 78 | -------------------------------------------------------------------------------- /src/uniforms/depth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import CameraStore from '/stores/camera'; 9 | import composer from '/composer'; 10 | import webgl from '/webgl'; 11 | var depthUniforms = {}; 12 | if ( webgl.depthTexture ) { 13 | depthUniforms.uDepth = { type: 't', value: composer.renderTarget2.depthTexture }; 14 | } 15 | 16 | depthUniforms.uReadDepthOverride = { type: 'f', value: 1.0 }; 17 | 18 | CameraStore.listen( function ( state ) { 19 | depthUniforms.uReadDepthOverride.value = 20 | state.controls.lock2D ? 0.0 : 1.0; 21 | } ); 22 | 23 | export default depthUniforms; 24 | -------------------------------------------------------------------------------- /src/uniforms/fog.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import CameraStore from '/stores/camera'; 10 | import skyColor from '/utils/skyColor'; 11 | var direction = new THREE.Vector3(); 12 | var lastDirection = new THREE.Vector3(); 13 | var forceUpdate = false; 14 | 15 | // Uniforms required where drawing basic fog 16 | var fogUniforms = { 17 | uFogDropoff: { type: 'f', value: 0.0006 }, 18 | uFogIntensity: { type: 'f', value: 0.1 }, 19 | uFogColor: { type: 'c', value: new THREE.Color() }, 20 | update: function ( state ) { 21 | forceUpdate = !state; 22 | state = state || CameraStore.getState(); 23 | 24 | // Sky uses different coordinate system 25 | direction.copy( state.target ).sub( state.position ); 26 | 27 | direction.z = direction.y; 28 | 29 | // Flatten y component to look at horizon 30 | direction.y = 0.0; 31 | direction.normalize(); 32 | 33 | if ( forceUpdate || direction.distanceToSquared( lastDirection ) > 0.01 ) { 34 | fogUniforms.uFogColor.value.copy( skyColor( direction ) ); 35 | lastDirection.copy( direction ); 36 | } 37 | } 38 | }; 39 | 40 | CameraStore.listen( fogUniforms.update ); 41 | export default fogUniforms; 42 | -------------------------------------------------------------------------------- /src/uniforms/height.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import AppStore from '/stores/app'; 10 | import ElevationDatasource from '/datasources/elevation'; 11 | import GeoprojectStore from '/stores/geoproject'; 12 | 13 | // Uniforms for shaders that lookup height 14 | const heightUniforms = { 15 | elevationArray: { value: ElevationDatasource.textureArray }, 16 | indirectionTexture: { value: ElevationDatasource.indirectionTexture }, 17 | uGlobalOffset: { type: 'v2', value: new THREE.Vector2() }, 18 | uSceneScale: { type: 'v3', value: new THREE.Vector3( 19 | 1, // sceneScale 20 | 1, // earthScale 21 | 1 // tileScale 22 | ) } 23 | }; 24 | 25 | function updateSceneScale () { 26 | const sceneScale = GeoprojectStore.getState()[ 'sceneScale' ]; 27 | const maxZoom = ElevationDatasource.maxZoom; 28 | 29 | // Compute compound values to ease work in shader and improve 30 | // accuracy 31 | const zoomScale = Math.pow( 2, 15 - maxZoom ); 32 | const earthScale = 40075016.686 / ( sceneScale * Math.pow( 2, 15 ) ); 33 | const earthShift = -6.283185307179586 / Math.pow( 2.0, maxZoom ); 34 | const tileScale = 1 / ( sceneScale * zoomScale ); 35 | heightUniforms.uSceneScale.value.set( 36 | earthShift, earthScale, tileScale ); 37 | } 38 | 39 | AppStore.listen( () => { updateSceneScale() } ); 40 | 41 | GeoprojectStore.listen( ( { globalOffset, sceneScale } ) => { 42 | heightUniforms.uGlobalOffset.value.copy( globalOffset ); 43 | updateSceneScale(); 44 | } ); 45 | 46 | export default heightUniforms; 47 | -------------------------------------------------------------------------------- /src/uniforms/line.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import ContainerStore from '/stores/container'; 10 | 11 | const lineUniforms = { 12 | uViewportInverse: { type: 'v2', value: new THREE.Vector2( 1.0, 1.0 ) }, 13 | }; 14 | 15 | ContainerStore.listen( ( { height, width } ) => { 16 | lineUniforms.uViewportInverse.value.set( 1.0 / width, 1.0 / height ); 17 | } ); 18 | 19 | export default lineUniforms; 20 | -------------------------------------------------------------------------------- /src/uniforms/marker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import ContainerStore from '/stores/container'; 10 | 11 | const markerUniforms = { 12 | uMap: { type: 't', value: null }, 13 | uPixelRatio: { type: 'f', value: 1.0 }, 14 | uViewportCanvasInverse: { type: 'v2', value: new THREE.Vector2( 1.0, 1.0 ) } 15 | }; 16 | 17 | ContainerStore.listen( ( { canvasHeight, pixelRatio, canvasWidth } ) => { 18 | markerUniforms.uViewportCanvasInverse.value.set( 19 | 1.0 / canvasWidth, 1.0 / canvasHeight ); 20 | markerUniforms.uPixelRatio.value = pixelRatio; 21 | } ); 22 | 23 | export default markerUniforms; 24 | -------------------------------------------------------------------------------- /src/uniforms/picker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import ContainerStore from '/stores/container'; 10 | 11 | const pickerUniforms = { 12 | uPixelRatio: { type: 'f', value: 1.0 }, 13 | uViewportCanvasInverse: { type: 'v2', value: new THREE.Vector2( 1.0, 1.0 ) }, 14 | uViewportInverse: { type: 'v2', value: new THREE.Vector2( 1.0, 1.0 ) }, 15 | }; 16 | 17 | ContainerStore.listen( ( { canvasHeight, canvasWidth, 18 | height, width, pixelRatio } ) => { 19 | pickerUniforms.uViewportCanvasInverse.value.set( 20 | 1.0 / canvasWidth, 1.0 / canvasHeight ); 21 | pickerUniforms.uViewportInverse.value.set( 1.0 / width, 1.0 / height ); 22 | pickerUniforms.uPixelRatio.value = pixelRatio; 23 | } ); 24 | 25 | export default pickerUniforms; 26 | -------------------------------------------------------------------------------- /src/uniforms/postprocess.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | var postprocessUniforms = { 10 | tDiffuse: { type: 't', value: null }, 11 | uResolution: { type: 'v2', value: new THREE.Vector2( 1.0, 1.0 ) } 12 | }; 13 | 14 | export default postprocessUniforms; 15 | -------------------------------------------------------------------------------- /src/uniforms/skyBox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | export default { 9 | uSkybox: { type: 't', value: null } 10 | }; 11 | -------------------------------------------------------------------------------- /src/uniforms/tag.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | import FeaturesStore from '/stores/features'; 10 | 11 | // Tag is used to identify the hovered over feature 12 | const tagUniforms = { 13 | uSelectedTag: { type: 'c', value: new THREE.Color() } 14 | }; 15 | 16 | FeaturesStore.listen( ( { selected } ) => { 17 | var id = selected && selected.tag ? selected.tag : 65536; 18 | tagUniforms.selectedTag.value.set( id ); 19 | } ); 20 | 21 | export default tagUniforms; 22 | -------------------------------------------------------------------------------- /src/uniforms/tilepicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | 10 | const tilepickerUniforms = { 11 | // Combine center pixel location (xy) and uv downscaling (z) into one 12 | // Update happens in tilepicker.js 13 | uScaling: { value: new THREE.Vector3() } 14 | }; 15 | 16 | export default tilepickerUniforms; 17 | -------------------------------------------------------------------------------- /src/uniforms/tonemap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import Tonemap from '/utils/tonemap'; 9 | var tonemapUniforms = { 10 | exposureBias: { type: 'f', value: 1 }, 11 | whitePoint: { type: 'f', value: 11.2 }, 12 | 13 | // Calculate the white scale from the white point 14 | uTonemapExposureBias: { type: 'f', value: 1 }, 15 | uTonemapWhiteScale: { type: 'f', value: 1 }, 16 | update: function () { 17 | tonemapUniforms.uTonemapExposureBias.value = 18 | tonemapUniforms.exposureBias.value; 19 | tonemapUniforms.uTonemapWhiteScale.value = 20 | 1.0 / Tonemap( tonemapUniforms.whitePoint.value ); 21 | } 22 | }; 23 | 24 | export default tonemapUniforms; 25 | -------------------------------------------------------------------------------- /src/utils/ImageLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import THREE from 'three'; 9 | const ImageLoader = ( typeof createImageBitmap === 'undefined' ) ? 10 | THREE.ImageLoader : THREE.ImageBitmapLoader; 11 | 12 | export default new ImageLoader(); 13 | -------------------------------------------------------------------------------- /src/utils/IntegerPool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // Class for managing a set of indices 9 | // `next()` returns a integer 10 | class IntegerPool { 11 | constructor( capacity ) { 12 | this.capacity = capacity; 13 | this.index = 0; 14 | this.items = []; 15 | } 16 | 17 | next() { 18 | let i; 19 | // Once we hit capacity, start re-using stale entries 20 | if ( this.index >= this.capacity ) { 21 | i = this.items.splice( 0, 1 )[ 0 ]; 22 | } else { 23 | // ...otherwise allocate sequentially 24 | i = this.index++; 25 | } 26 | 27 | this.items.push( i ); 28 | return i; 29 | } 30 | 31 | // Method to keep element alive 32 | tap( item ) { 33 | let i = this.items.indexOf( item ); 34 | if ( i !== -1 ) { 35 | this.items.splice( i, 1 ); 36 | this.items.push( item ); 37 | } 38 | } 39 | } 40 | 41 | export default IntegerPool; 42 | -------------------------------------------------------------------------------- /src/utils/RGBABuffer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | // Class for managing a Float32Array which is expected to be 9 | // read torioidally - that is data which is written beyond 10 | // one edge, appears on the other. 11 | // This class is useful for preparing an buffer for writing 12 | // to an RGBA square floating point texture. 13 | // It expects that values are to be set in groups of 4, 14 | // corresponding to the 4 channels 15 | // The main benefit it offers is quickly filling square 16 | // regions with the same value 17 | class RGBABuffer { 18 | constructor( size ) { 19 | this.size = size; 20 | this.data = new Float32Array( 4 * size * size ); 21 | } 22 | 23 | // Sets a single RGBA "pixel" 24 | set( p, r, g, b, a ) { 25 | this.data[ 4 * p ] = r; 26 | this.data[ 4 * p + 1 ] = g; 27 | this.data[ 4 * p + 2 ] = b; 28 | this.data[ 4 * p + 3 ] = a; 29 | } 30 | 31 | // Fills a region with a RGBA "pixel" value 32 | fillRect( p, width, height, r, g, b, a ) { 33 | if ( ( width <= 0 ) || ( height <= 0 ) ) { 34 | return; 35 | } 36 | 37 | if ( ( width === this.size ) || ( height === this.size ) ) { 38 | this.fill( r, g, b, a ); 39 | return; 40 | } 41 | 42 | // First set top-left pixel to correct value 43 | this.set( p, r, g, b, a ); 44 | 45 | // Next copy across row, doubling up each time 46 | // As we are copying within the same Float32Array 47 | // this is fast 48 | for ( let i = 1; i < width; i *= 2 ) { 49 | let offset = p + i; // Destination pixel 50 | 51 | // Number of pixels to copy (cap at width for non-POT copy) 52 | let count = Math.min( i, width - i ); 53 | this.data.set( 54 | this.data.subarray( 4 * p, 4 * ( p + count ) ), 55 | 4 * offset ); 56 | } 57 | 58 | // Now copy row itself 59 | const row = this.data.subarray( 4 * p, 4 * ( p + width ) ); 60 | for ( let j = 1; j < height; j++ ) { 61 | let offset = p + this.size * j; // Destination row 62 | this.data.set( row, 4 * offset ); 63 | } 64 | } 65 | 66 | // Fills entire buffer 67 | // Allows even faster copying than `fillRect` 68 | fill( r, g, b, a ) { 69 | this.set( 0, r, g, b, a ); 70 | for ( let i = 1, il = this.size * this.size; i < il; i *= 2 ) { 71 | this.data.set( this.data.subarray( 0, 4 * i ), 4 * i ); 72 | } 73 | } 74 | } 75 | 76 | export default RGBABuffer; 77 | -------------------------------------------------------------------------------- /src/utils/anchorForName.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var mapping = { 9 | 'top-left': { x: 1, y: -1 }, 10 | 'top': { x: 0, y: -1 }, 11 | 'top-right': { x: -1, y: -1 }, 12 | 'left': { x: 1, y: 0 }, 13 | 'center': { x: 0, y: 0 }, 14 | 'right': { x: -1, y: 0 }, 15 | 'bottom-left': { x: 1, y: 1 }, 16 | 'bottom': { x: 0, y: 1 }, 17 | 'bottom-right': { x: -1, y: 1 } 18 | }; 19 | 20 | export default function ( name ) { 21 | if ( name !== undefined && !isNaN( name.x ) && !isNaN( name.y ) ) { 22 | // If we just have coordinates, e.g. {x: 0.5, y: 0.1} just return 23 | return name; 24 | } 25 | 26 | return mapping[ name ] || mapping.bottom; 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var spacing = 0.05; 9 | 10 | var ApiUtils = { 11 | snap: function ( n ) { 12 | return Math.round( n / spacing ) * spacing; 13 | }, 14 | datafileForLocation: function ( lon, lat ) { 15 | lon = ApiUtils.snap( lon ); 16 | lat = ApiUtils.snap( lat ); 17 | 18 | // Calculate NS and EW 19 | var ns = lat > 0 ? 'N' : 'S'; 20 | var ew = lon > 0 ? 'E' : 'W'; 21 | lon = Math.abs( lon ); 22 | lat = Math.abs( lat ); 23 | 24 | // Display same number of decimal places as spacing 25 | var decimalPlaces = spacing.toPrecision().split( '.' )[ 1 ]; 26 | decimalPlaces = decimalPlaces ? decimalPlaces.length : 0; 27 | lon = lon.toFixed( decimalPlaces ); 28 | lat = lat.toFixed( decimalPlaces ); 29 | 30 | // Construct name of datafile 31 | return ns + lat + ew + lon; 32 | } 33 | }; 34 | 35 | export default ApiUtils; 36 | -------------------------------------------------------------------------------- /src/utils/bindToVisible.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | export default function ( parameter ) { 9 | return function ( state ) { 10 | this.setState( { visible: state[ parameter ] } ); 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/clippingForName.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var mapping = { 9 | 'none': { x: 0, y: 0 }, 10 | 'object': { x: 1, y: 0 }, 11 | 'pixel': { x: 0, y: 1 } 12 | }; 13 | 14 | export default function ( name ) { 15 | if ( name !== undefined && !isNaN( name.x ) && !isNaN( name.y ) ) { 16 | // If we just have coordinates, e.g. {x: 0.5, y: 0.1} just return 17 | return name; 18 | } 19 | 20 | return mapping[ name ] || mapping.pixel; 21 | } 22 | -------------------------------------------------------------------------------- /src/utils/dataToHeight.js: -------------------------------------------------------------------------------- 1 | import { ELEVATION_TILE_SIZE, 2 | PIXEL_ENCODING_NASADEM, PIXEL_ENCODING_TERRARIUM, PIXEL_ENCODING_TERRAIN_RGB } from '/constants'; 3 | 4 | const MULTIPLIER_TERRARIUM = [ 256, 1, 1 / 256, -32768 ]; 5 | const MULTIPLIER_TERRAIN_RGB = [ 0.1 * 256 * 256, 0.1 * 256, 0.1, -10000 ]; 6 | 7 | function dataToHeight( data, pixelEncoding ) { 8 | if ( data[ 0 ] === 0 && data[ 1 ] === 0 ) { 9 | // NODATA values return 0 10 | return 0; 11 | } 12 | 13 | let m; 14 | if ( pixelEncoding === PIXEL_ENCODING_TERRARIUM || 15 | pixelEncoding === PIXEL_ENCODING_NASADEM ) { 16 | m = MULTIPLIER_TERRARIUM; 17 | } else if ( pixelEncoding === PIXEL_ENCODING_TERRAIN_RGB ) { 18 | m = MULTIPLIER_TERRAIN_RGB; 19 | } 20 | 21 | return m[ 0 ] * data[ 0 ] + 22 | m[ 1 ] * data[ 1 ] + 23 | m[ 2 ] * data[ 2 ] + 24 | // This is correct, we don't want to multiply by data[ 3 ] 25 | m[ 3 ]; 26 | } 27 | 28 | export default dataToHeight; 29 | -------------------------------------------------------------------------------- /src/utils/defer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var queue = []; 9 | var processNext = function () { queue.shift()() }; 10 | 11 | var enqueue = function ( fn ) { 12 | if ( typeof fn !== 'function' ) { 13 | console.error( 'Tried to enqueue non-function' ); 14 | return; 15 | } 16 | 17 | queue.push( fn ); 18 | setTimeout( processNext, 0 ); 19 | }; 20 | 21 | export default enqueue; 22 | -------------------------------------------------------------------------------- /src/utils/glyphForIcon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import _ from 'lodash'; 9 | // Extract the glpyh for a FontAwesome icon 10 | var iconElement = document.createElement( 'i' ); 11 | var wrapper = document.createElement( 'div' ); 12 | wrapper.style.position = 'absolute'; 13 | wrapper.style.left = '-999px'; 14 | wrapper.style.top = '-999px'; 15 | wrapper.appendChild( iconElement ); 16 | wrapper.style.display = 'none'; 17 | document.body.appendChild( wrapper ); 18 | 19 | var glyph; 20 | 21 | export default _.memoize( function ( icon ) { 22 | wrapper.style.display = 'block'; 23 | iconElement.className = 'fa fa-' + icon; 24 | glyph = window.getComputedStyle( iconElement, ':before' ) 25 | .getPropertyValue( 'content' ); 26 | glyph = glyph.replace( /['"]/g, '' ); 27 | wrapper.style.display = 'none'; 28 | return glyph; 29 | } ); 30 | -------------------------------------------------------------------------------- /src/utils/pushList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import _ from 'lodash'; 9 | // Sugar around array, that let's us determine 10 | // if it only contains duplicates of a set of 11 | // values. Useful to build a buffer for an attribute 12 | // and if it is all the same, use a defaultAttributeValue 13 | // instead 14 | var PushList = function () { 15 | this.defaultValue = Array.prototype.slice.call( arguments ); 16 | if ( this.defaultValue.length === 0 ) { 17 | console.error( 'Need to provide default value(s)' ); 18 | } 19 | 20 | this.array = []; 21 | this.firstValue = null; 22 | this.onlyDuplicates = true; 23 | }; 24 | 25 | // Push and keep track of whether the array only contains 26 | // duplicates 27 | PushList.prototype.push = function () { 28 | var value = Array.prototype.slice.call( arguments ); 29 | if ( this.defaultValue.length !== value.length ) { 30 | console.error( 'Pushed item with incorrect length to PushList' ); 31 | } 32 | 33 | if ( this.firstValue === null ) { 34 | this.firstValue = value; 35 | } else if ( this.onlyDuplicates && !_.isEqual( this.firstValue, value ) ) { 36 | this.onlyDuplicates = false; 37 | } 38 | 39 | this.array.push.apply( this.array, value ); 40 | }; 41 | 42 | PushList.prototype.pushDefault = function () { 43 | this.push.apply( this, this.defaultValue ); 44 | }; 45 | 46 | export default PushList; 47 | -------------------------------------------------------------------------------- /src/utils/setterStore.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var v, vl, item, action, actionName, defaultValue; 9 | var extractKey = function ( actionName ) { 10 | if ( actionName.slice( 0, 3 ) !== 'set' ) { 11 | throw new Error( 'Action must be called setX' ); 12 | } 13 | 14 | return actionName.charAt( 3 ).toLowerCase() + 15 | actionName.slice( 4 ); 16 | }; 17 | 18 | export default function ( config ) { 19 | // Extract listeners and method names 20 | function SetterStore() { 21 | var listeners = {}; 22 | 23 | // Set defaults 24 | for ( v = 0, vl = config.length; v < vl; v++ ) { 25 | item = config[ v ]; 26 | action = item[ 0 ]; 27 | defaultValue = item[ 1 ]; 28 | actionName = action.data.name; 29 | this[ extractKey( actionName ) ] = defaultValue; 30 | 31 | // Configure binding between action and function 32 | listeners[ actionName ] = action; 33 | } 34 | 35 | this.bindListeners( listeners ); 36 | } 37 | 38 | // Define handler functions to set values 39 | for ( v = 0, vl = config.length; v < vl; v++ ) { 40 | item = config[ v ]; 41 | action = item[ 0 ]; 42 | actionName = action.data.name; 43 | SetterStore.prototype[ actionName ] = function ( key ) { 44 | return function ( value ) { this[ key ] = value }; 45 | }( extractKey( actionName ) ); 46 | } 47 | 48 | return SetterStore; 49 | } 50 | -------------------------------------------------------------------------------- /src/utils/shader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | const Shader = function ( value ) { 9 | this.value = value; 10 | }; 11 | 12 | Shader.prototype.define = function ( define, value ) { 13 | var regexp = new RegExp( "#define " + define + " .*", "g" ); 14 | var newDefine = "#define " + define + ( value ? " " + value : "" ); 15 | if ( this.value.match( regexp ) ) { 16 | // #define already exists, update its value 17 | this.value = this.value.replace( regexp, newDefine ); 18 | } else { 19 | // New #define, prepend to start of file 20 | this.value = newDefine + "\n" + this.value; 21 | } 22 | }; 23 | 24 | Shader.prototype.clone = function () { 25 | return new Shader( this.value ); 26 | }; 27 | 28 | export default Shader; 29 | -------------------------------------------------------------------------------- /src/utils/tonemap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | var A = 0.15; 9 | var B = 0.50; 10 | var C = 0.10; 11 | var D = 0.20; 12 | var E = 0.02; 13 | var F = 0.30; 14 | 15 | var RawTonemap = function ( x ) { 16 | return ( ( x * ( A * x + C * B ) + D * E ) / ( x * ( A * x + B ) + D * F ) ) - E / F; 17 | }; 18 | 19 | export default RawTonemap; 20 | -------------------------------------------------------------------------------- /src/utils/uiFont.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | export default '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'; 9 | -------------------------------------------------------------------------------- /src/views/button.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import React from 'react'; 9 | var defaultStyle = { 10 | border: '1px solid white', 11 | margin: 4, 12 | color: 'white', 13 | width: 36, 14 | height: 36, 15 | lineHeight: '32px', 16 | textAlign: 'center', 17 | padding: 0, 18 | borderRadius: 18, 19 | backgroundColor: '#333542', 20 | outline: 'none', 21 | WebkitTransition: 'background-color 0.5s', 22 | transition: 'background-color 0.5s', 23 | cursor: 'pointer', 24 | }; 25 | var hoverStyle = { 26 | backgroundColor: 'rgba(97, 97, 97, 0.5)' 27 | }; 28 | 29 | var Button = React.createClass( { 30 | getInitialState: function () { return { hover: false }; }, 31 | mouseOver: function () { this.setState( { hover: true } ); }, 32 | mouseOut: function () { this.setState( { hover: false } ); }, 33 | render: function () { 34 | var style = Object.assign( {}, 35 | defaultStyle, 36 | this.state.hover ? hoverStyle : undefined, 37 | this.props.style 38 | ); 39 | return ( 40 | 45 | ); 46 | } 47 | } ); 48 | 49 | export default Button; 50 | -------------------------------------------------------------------------------- /src/views/buttonRow.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 (c) Felix Palmer 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | import React from 'react'; 9 | import Button from '/views/button.jsx'; 10 | import UserActions from '/actions/user'; 11 | var ButtonRow = React.createClass( { 12 | render: function () { 13 | var buttons = this.props.buttons.map( function ( b ) { 14 | return