├── .gitignore ├── LICENSE ├── README.md ├── css └── style.css ├── index.html ├── js ├── app │ ├── app.js │ ├── camera.js │ ├── container.js │ ├── geometry.js │ ├── light.js │ ├── material.js │ ├── noise.js │ ├── renderer.js │ ├── scene.js │ ├── terrain.js │ └── texture.js ├── config.js ├── lib │ ├── Detector.js │ ├── ImprovedNoise.js │ ├── controls │ │ └── TrackballControls.js │ ├── shader.js │ ├── stats.min.js │ ├── text.js │ ├── three.js │ └── three.min.js ├── main.js ├── require.js ├── shaders │ ├── atmosphere.frag │ ├── atmosphere.vert │ ├── colorScale.glsl │ ├── edgemorph.glsl │ ├── shift.glsl │ ├── terrain.frag │ ├── terrain.vert │ ├── terrainSnow.frag │ └── terrainToon.frag └── textures │ ├── README.md │ ├── rock.jpg │ └── sky.png ├── presentation ├── License.md ├── Readme.md ├── index.html ├── pictures │ ├── cover.png │ ├── lod_terrain_close.png │ ├── lod_terrain_final.png │ ├── lod_terrain_intro.png │ ├── lod_terrain_lod.png │ ├── lod_terrain_morph.png │ ├── lod_terrain_seams.png │ ├── lod_terrain_shells.png │ └── lod_terrain_shells_perspective.png └── shower │ ├── License.md │ ├── Readme.md │ ├── shower.min.js │ └── themes │ ├── bright │ ├── License.md │ ├── Readme.md │ ├── fonts │ │ ├── Anka.Coder.Italic.woff │ │ ├── Anka.Coder.woff │ │ ├── OpenSans.Bold.Italic.woff │ │ ├── OpenSans.Bold.woff │ │ ├── OpenSans.Italic.woff │ │ ├── OpenSans.Light.woff │ │ └── OpenSans.woff │ ├── images │ │ ├── grid-16x10.svg │ │ └── grid-4x3.svg │ ├── index.html │ ├── pictures │ │ ├── exact.png │ │ ├── square.png │ │ ├── tall.png │ │ └── wide.png │ └── styles │ │ └── screen.css │ └── ribbon │ ├── License.md │ ├── Readme.md │ ├── fonts │ ├── PTMono.woff │ ├── PTSans.Bold.Italic.woff │ ├── PTSans.Bold.woff │ ├── PTSans.Italic.woff │ ├── PTSans.Narrow.Bold.woff │ └── PTSans.woff │ ├── images │ ├── grid-16x10.svg │ ├── grid-4x3.svg │ ├── linen.png │ ├── linen@2x.png │ └── ribbon.svg │ ├── index.html │ ├── pictures │ ├── exact.png │ ├── square.png │ ├── tall.png │ └── wide.png │ └── styles │ └── screen.css ├── screenshots ├── screenshot1.png ├── screenshot2.png ├── screenshot3.png ├── screenshot4.png ├── screenshot5.png └── screenshot6.png └── webserver.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *swo 2 | *swp 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Felix Palmer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LOD Terrain 2 | =========== 3 | 4 | LOD Terrain is an example of how to render a terrain with a variable level of detail (LOD), based on the distance from the camera. The approach taken is based on [CD-LOD](http://www.vertexasylum.com/downloads/cdlod/cdlod_latest.pdf). 5 | 6 | * [Accompanying blog post](http://www.pheelicks.com/2014/03/rendering-large-terrains/) 7 | * [Slides](http://felixpalmer.github.io/lod-terrain/presentation) 8 | 9 | [Try out the live demo here](http://felixpalmer.github.io/lod-terrain) 10 | ![](https://github.com/felixpalmer/lod-terrain/raw/master/screenshots/screenshot1.png) 11 | ![](https://github.com/felixpalmer/lod-terrain/raw/master/screenshots/screenshot4.png) 12 | ![](https://github.com/felixpalmer/lod-terrain/raw/master/screenshots/screenshot5.png) 13 | 14 | Height calculations 15 | =================== 16 | 17 | Currently the detail distribution isn't as per the paper, namely it assumes the most detailed region is the point above which the camera currently resides, rather than taking into account the height of the terrain. 18 | 19 | Running 20 | ======= 21 | 22 | Just host this directory with a webserver of your choice. You can also use the `webserver.sh` script included (provided you have Python) to set up a simple development server. 23 | 24 | Then visit http://localhost:8000 in your browser. Or try the [online demo](http://felixpalmer.github.io/lod-terrain). 25 | 26 | Structure 27 | ========= 28 | 29 | This project is based on [amd-three.js](https://github.com/felixpalmer/amd-three.js/). Please see there for details of project structure. 30 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /* base styles */ 2 | 3 | html { 4 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 5 | font-size: 20px; 6 | line-height: 1.2; 7 | color: #fff; 8 | } 9 | 10 | html, body, #container { 11 | height: 100%; 12 | width: 100%; 13 | margin: 0; 14 | } 15 | 16 | p { 17 | margin: 0 0 10px 0; 18 | } 19 | 20 | #share-container { 21 | position: absolute; 22 | top: 0; 23 | background: #000; 24 | opacity: 0.8; 25 | color: #fff; 26 | padding: 10px; 27 | padding-left: 20px; 28 | height: 120px; 29 | width: 100%; 30 | } 31 | 32 | #share-container h1 { 33 | float: left; 34 | margin: 0 auto; 35 | padding-right: 30px; 36 | } 37 | 38 | #share-container p { 39 | padding-top: 6px; 40 | font-size: 12px; 41 | } 42 | 43 | #threejs-container { 44 | background: #000; 45 | color: #666; 46 | height: 100%; 47 | width: 100%; 48 | } 49 | 50 | #threejs-container canvas { 51 | position: absolute; 52 | left: 0; 53 | top: 0; 54 | right: 0; 55 | bottom: 0; 56 | } 57 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LOD terrain 5 | 6 | 7 | 8 | 9 | 10 |
11 |
Loading...
12 |
13 |

LOD terrain

14 |
15 | 16 |
17 | 18 | 25 |
26 | How does this work? 27 |

Use mouse to adjust camera, click to switch mode

28 |
29 | 30 | Fork me on GitHub 31 | 32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /js/app/app.js: -------------------------------------------------------------------------------- 1 | define( ["three", "camera", "container", "geometry", "material", "noise", "renderer", "scene", "terrain"], 2 | function ( THREE, camera, container, geometry, material, noise, renderer, scene, Terrain ) { 3 | var app = { 4 | clock: new THREE.Clock(), 5 | mouse: { x: 0, y: 0 }, 6 | smoothMouse: { x: 0, y: 0 }, 7 | init: function () { 8 | // Terrain( heightdata, worldWidth, levels of detail, tile resolution ) 9 | app.terrain = new Terrain( noise, 1024, 4, 64 ); 10 | scene.add( app.terrain ); 11 | 12 | // Add sky 13 | app.sky = new THREE.Mesh( geometry.sky, material.sky ); 14 | app.sky.position.z = 250; 15 | app.sky.visible = false; 16 | scene.add( app.sky ); 17 | 18 | /// Add sky2 19 | app.sky2 = new THREE.Mesh( geometry.sky2, material.atmosphere ); 20 | app.sky2.position.z = -1000; 21 | scene.add( app.sky2 ); 22 | 23 | // Mouse input 24 | container.addEventListener( 'mousemove', function( e ) { 25 | app.mouse = { 26 | x: e.clientX - container.offsetWidth / 2, 27 | // Square to give more sensitivity at bottom of screen 28 | y: Math.pow( container.offsetHeight - e.clientY, 2 ) / container.offsetHeight 29 | }; 30 | } ); 31 | 32 | container.addEventListener( 'click', function() { 33 | // Switch between different frag shaders 34 | var s = app.terrain.cycleShader(); 35 | if ( s === 0 ) { 36 | app.sky.visible = true; 37 | app.sky2.visible = false; 38 | } else { 39 | app.sky.visible = false; 40 | app.sky2.visible = true; 41 | if ( s === 1 ) { 42 | material.atmosphere.uniforms.uHorizonColor.value = new THREE.Color( 0xfff1d8 ); 43 | material.atmosphere.uniforms.uSkyColor.value = new THREE.Color( 0xf9f9ff ); 44 | } else { 45 | material.atmosphere.uniforms.uHorizonColor.value = new THREE.Color( 0xffffff ); 46 | material.atmosphere.uniforms.uSkyColor.value = new THREE.Color( 0x55b9ff ); 47 | } 48 | } 49 | } ); 50 | }, 51 | // height: function() { 52 | // var i = Math.floor( camera.position.x % 1024 ); 53 | // var j = 1023 - Math.floor( camera.position.y % 1024 ); 54 | // //var h = 1024 * noise.image.data[ 13 ]; 55 | // var h = 1024 * noise.image.data[i + 1024 * j] / 255; 56 | // return h * h / 2000 + 20; 57 | // }, 58 | center: new THREE.Vector3( 205, 135, 0 ), 59 | animate: function () { 60 | window.requestAnimationFrame( app.animate ); 61 | 62 | // Smooth mouse position 63 | var smooth = 0.02; 64 | app.smoothMouse.x += smooth * ( app.mouse.x - app.smoothMouse.x ); 65 | app.smoothMouse.y += smooth * ( app.mouse.y - app.smoothMouse.y ); 66 | 67 | var time = 0.5 * app.clock.getElapsedTime(); 68 | camera.position.x = 450 * Math.cos( time / 3 ) + app.center.x; 69 | camera.position.y = 250 * Math.sin( time / 4 ) + app.center.y + 500; 70 | camera.position.z = Math.min( app.smoothMouse.y / 2 + 5, 500 ); 71 | //camera.position.z = 30 + 260 * Math.pow( Math.sin( time ), 4 ); 72 | camera.up = new THREE.Vector3( 0, 0, 1 ); 73 | camera.lookAt( app.center ); 74 | 75 | // Look left right 76 | var look = app.center.clone(); 77 | look.sub( camera.position ); 78 | look.normalize(); 79 | look.multiplyScalar( 50 ); 80 | var across = new THREE.Vector3().crossVectors( look, camera.up ); 81 | across.multiplyScalar( app.smoothMouse.x / 333 ); 82 | camera.position.add( across ); 83 | //camera.up = new THREE.Vector3( 1, 0, 1 ); 84 | camera.up.add( across.multiplyScalar( -0.005 ) ); 85 | camera.lookAt( app.center ); 86 | 87 | app.terrain.offset.x = camera.position.x; 88 | app.terrain.offset.y = camera.position.y; 89 | renderer.render( scene, camera ); 90 | } 91 | }; 92 | return app; 93 | } ); 94 | -------------------------------------------------------------------------------- /js/app/camera.js: -------------------------------------------------------------------------------- 1 | define( ["three", "container"], function ( THREE, container ) { 2 | var camera = new THREE.PerspectiveCamera( 70, 1, 1, 5000 ); 3 | camera.position.z = 80; 4 | camera.up = new THREE.Vector3( 0, 0, 1 ); 5 | 6 | var updateSize = function () { 7 | camera.aspect = container.offsetWidth / container.offsetHeight; 8 | camera.updateProjectionMatrix(); 9 | }; 10 | window.addEventListener( 'resize', updateSize, false ); 11 | updateSize(); 12 | 13 | return camera; 14 | } ); 15 | -------------------------------------------------------------------------------- /js/app/container.js: -------------------------------------------------------------------------------- 1 | define( [], function () { 2 | return document.getElementById( 'threejs-container' ); 3 | } ); 4 | -------------------------------------------------------------------------------- /js/app/geometry.js: -------------------------------------------------------------------------------- 1 | define( ["three"], function ( THREE ) { 2 | return { 3 | cube: new THREE.CubeGeometry( 200, 200, 200 ), 4 | sky: new THREE.PlaneGeometry( 1600, 1600 ), 5 | sky2: new THREE.SphereGeometry( 3000, 64, 64 ) 6 | }; 7 | } ); 8 | -------------------------------------------------------------------------------- /js/app/light.js: -------------------------------------------------------------------------------- 1 | define( ["three", "scene"], function ( THREE, scene ) { 2 | var light = new THREE.DirectionalLight( 0xff3bff ); 3 | light.position.set( 0, 0, 300 ); 4 | scene.add( light ); 5 | return light; 6 | } ); 7 | -------------------------------------------------------------------------------- /js/app/material.js: -------------------------------------------------------------------------------- 1 | define( ["three", "shader!atmosphere.vert", "shader!atmosphere.frag", "texture"], 2 | function ( THREE, atmosphereVert, atmosphereFrag, texture ) { 3 | return { 4 | atmosphere: new THREE.ShaderMaterial( { 5 | uniforms: { 6 | uHorizonColor: { type: "c", value: new THREE.Color( 0xfff1d8 ) }, 7 | //uSkyColor: { type: "c", value: new THREE.Color( 0xd1e3f1 ) } 8 | uSkyColor: { type: "c", value: new THREE.Color( 0xf9f9ff ) } 9 | }, 10 | vertexShader: atmosphereVert.value, 11 | fragmentShader: atmosphereFrag.value, 12 | side: THREE.BackSide 13 | } ), 14 | sky: new THREE.MeshBasicMaterial( { 15 | map: texture.sky, 16 | side: THREE.BackSide 17 | } ) 18 | }; 19 | } ); 20 | -------------------------------------------------------------------------------- /js/app/noise.js: -------------------------------------------------------------------------------- 1 | define( ["three", "ImprovedNoise"], function ( THREE, ImprovedNoise ) { 2 | // Create noise and save it to texture 3 | var width = 1024; 4 | var size = width * width; 5 | var data = new Uint8Array( size ); 6 | 7 | // Zero out height data 8 | for ( var i = 0; i < size; i ++ ) { 9 | data[i] = 0; 10 | } 11 | 12 | var perlin = new ImprovedNoise(); 13 | var quality = 1; 14 | var z = Math.random() * 100; 15 | 16 | // Do several passes to get more detail 17 | for ( var iteration = 0; iteration < 4; iteration++ ) { 18 | for ( var i = 0; i < size; i ++ ) { 19 | var x = i % width; 20 | var y = Math.floor( i / width ); 21 | data[i] += Math.abs( perlin.noise( x / quality, y / quality, z ) * quality ); 22 | } 23 | quality *= 5; 24 | } 25 | 26 | var noise = new THREE.DataTexture( data, width, width, THREE.AlphaFormat ); 27 | noise.wrapS = THREE.MirroredRepeatWrapping; 28 | noise.wrapT = THREE.MirroredRepeatWrapping; 29 | noise.magFilter = THREE.LinearFilter; 30 | noise.minFilter = THREE.LinearMipMapLinearFilter; 31 | noise.generateMipmaps = true; 32 | noise.needsUpdate = true; 33 | return noise; 34 | } ); 35 | -------------------------------------------------------------------------------- /js/app/renderer.js: -------------------------------------------------------------------------------- 1 | define( ["three", "container"], function ( THREE, container ) { 2 | container.innerHTML = ""; 3 | var renderer = new THREE.WebGLRenderer( { clearColor: 0x000000 } ); 4 | renderer.sortObjects = false; 5 | renderer.autoClear = false; 6 | container.appendChild( renderer.domElement ); 7 | 8 | var updateSize = function () { 9 | renderer.setSize( container.offsetWidth, container.offsetHeight ); 10 | 11 | // For a smoother render double the pixel ratio 12 | renderer.setPixelRatio( 2 ); 13 | }; 14 | window.addEventListener( 'resize', updateSize, false ); 15 | updateSize(); 16 | 17 | return renderer; 18 | } ); 19 | -------------------------------------------------------------------------------- /js/app/scene.js: -------------------------------------------------------------------------------- 1 | define( ["three"], function ( THREE ) { 2 | var scene = new THREE.Scene(); 3 | scene.fog = new THREE.Fog( 0x000000, 200, 1000 ); 4 | return scene; 5 | } ); 6 | -------------------------------------------------------------------------------- /js/app/terrain.js: -------------------------------------------------------------------------------- 1 | define( ["three", "geometry", "shader!terrain.vert", "shader!terrain.frag", "shader!terrainSnow.frag", "shader!terrainToon.frag", "texture"], function ( THREE, geometry, terrainVert, terrainFrag, terrainSnowFrag, terrainToonFrag, texture ) { 2 | // Tiles that sit next to a tile of a greater scale need to have their edges morphed to avoid 3 | // edges. Mark which edges need morphing using flags. These flags are then read by the vertex 4 | // shader which performs the actual morph 5 | var Edge = { 6 | NONE: 0, 7 | TOP: 1, 8 | LEFT: 2, 9 | BOTTOM: 4, 10 | RIGHT: 8 11 | }; 12 | 13 | // Terrain is an extension of Object3D and thus can be added directly to the stage 14 | var Terrain = function( heightData, worldWidth, levels, resolution ) { 15 | THREE.Object3D.call( this ); 16 | 17 | this.worldWidth = ( worldWidth !== undefined ) ? worldWidth : 1024; 18 | this.levels = ( levels !== undefined ) ? levels : 6; 19 | this.resolution = ( resolution !== undefined ) ? resolution : 128; 20 | this.heightData = heightData; 21 | 22 | // Offset is used to re-center the terrain, this way we get the greates detail 23 | // nearest to the camera. In the future, should calculate required detail level per tile 24 | this.offset = new THREE.Vector3( 0, 0, 0 ); 25 | 26 | // Which shader should be used for rendering 27 | this.fragShaders = [terrainFrag, terrainSnowFrag, terrainToonFrag]; 28 | this.fragShader = terrainSnowFrag; 29 | 30 | // Create geometry that we'll use for each tile, just a standard plane 31 | this.tileGeometry = new THREE.PlaneGeometry( 1, 1, this.resolution, this.resolution ); 32 | // Place origin at bottom left corner, rather than center 33 | var m = new THREE.Matrix4(); 34 | m.makeTranslation( 0.5, 0.5, 0 ); 35 | this.tileGeometry.applyMatrix( m ); 36 | 37 | // Create collection of tiles to fill required space 38 | /*jslint bitwise: true */ 39 | var initialScale = this.worldWidth / Math.pow( 2, levels ); 40 | 41 | // Create center layer first 42 | // +---+---+ 43 | // | O | O | 44 | // +---+---+ 45 | // | O | O | 46 | // +---+---+ 47 | this.createTile( -initialScale, -initialScale, initialScale, Edge.NONE ); 48 | this.createTile( -initialScale, 0, initialScale, Edge.NONE ); 49 | this.createTile( 0, 0, initialScale, Edge.NONE ); 50 | this.createTile( 0, -initialScale, initialScale, Edge.NONE ); 51 | 52 | // Create "quadtree" of tiles, with smallest in center 53 | // Each added layer consists of the following tiles (marked 'A'), with the tiles 54 | // in the middle being created in previous layers 55 | // +---+---+---+---+ 56 | // | A | A | A | A | 57 | // +---+---+---+---+ 58 | // | A | | | A | 59 | // +---+---+---+---+ 60 | // | A | | | A | 61 | // +---+---+---+---+ 62 | // | A | A | A | A | 63 | // +---+---+---+---+ 64 | for ( var scale = initialScale; scale < worldWidth; scale *= 2 ) { 65 | this.createTile( -2 * scale, -2 * scale, scale, Edge.BOTTOM | Edge.LEFT ); 66 | this.createTile( -2 * scale, -scale, scale, Edge.LEFT ); 67 | this.createTile( -2 * scale, 0, scale, Edge.LEFT ); 68 | this.createTile( -2 * scale, scale, scale, Edge.TOP | Edge.LEFT ); 69 | 70 | this.createTile( -scale, -2 * scale, scale, Edge.BOTTOM ); 71 | // 2 tiles 'missing' here are in previous layer 72 | this.createTile( -scale, scale, scale, Edge.TOP ); 73 | 74 | this.createTile( 0, -2 * scale, scale, Edge.BOTTOM ); 75 | // 2 tiles 'missing' here are in previous layer 76 | this.createTile( 0, scale, scale, Edge.TOP ); 77 | 78 | this.createTile( scale, -2 * scale, scale, Edge.BOTTOM | Edge.RIGHT ); 79 | this.createTile( scale, -scale, scale, Edge.RIGHT ); 80 | this.createTile( scale, 0, scale, Edge.RIGHT ); 81 | this.createTile( scale, scale, scale, Edge.TOP | Edge.RIGHT ); 82 | } 83 | /*jslint bitwise: false */ 84 | }; 85 | 86 | Terrain.prototype = Object.create( THREE.Object3D.prototype ); 87 | 88 | Terrain.prototype.createTile = function ( x, y, scale, edgeMorph ) { 89 | var terrainMaterial = this.createTerrainMaterial( this.heightData, 90 | this.offset, 91 | new THREE.Vector2( x, y ), 92 | scale, 93 | this.resolution, 94 | edgeMorph ); 95 | var plane = new THREE.Mesh( this.tileGeometry, terrainMaterial ); 96 | this.add( plane ); 97 | }; 98 | 99 | Terrain.prototype.createTerrainMaterial = function( heightData, globalOffset, offset, scale, resolution, edgeMorph ) { 100 | // Is it bad to change this for every tile? 101 | terrainVert.define( "TILE_RESOLUTION", resolution.toFixed(1) ); 102 | return new THREE.ShaderMaterial( { 103 | uniforms: { 104 | uEdgeMorph: { type: "i", value: edgeMorph }, 105 | uGlobalOffset: { type: "v3", value: globalOffset }, 106 | uHeightData: { type: "t", value: heightData }, 107 | //uGrass: { type: "t", value: texture.grass }, 108 | uRock: { type: "t", value: texture.rock }, 109 | //uSnow: { type: "t", value: texture.snow }, 110 | uTileOffset: { type: "v2", value: offset }, 111 | uScale: { type: "f", value: scale } 112 | }, 113 | vertexShader: terrainVert.value, 114 | fragmentShader: this.fragShader.value, 115 | transparent: true 116 | } ); 117 | }; 118 | 119 | Terrain.prototype.cycleShader = function() { 120 | // Swap between different terrains 121 | var f = this.fragShaders.indexOf( this.fragShader ); 122 | f = ( f + 1 ) % this.fragShaders.length; 123 | this.fragShader = this.fragShaders[f]; 124 | 125 | // Update all tiles 126 | for ( var c in this.children ) { 127 | var tile = this.children[c]; 128 | tile.material.fragmentShader = this.fragShader.value; 129 | tile.material.needsUpdate = true; 130 | } 131 | 132 | return f; 133 | }; 134 | 135 | return Terrain; 136 | } ); 137 | -------------------------------------------------------------------------------- /js/app/texture.js: -------------------------------------------------------------------------------- 1 | define( ["three"], function ( THREE ) { 2 | var texturePath = "js/textures/"; 3 | var sky = THREE.ImageUtils.loadTexture( texturePath + "sky.png" ); 4 | 5 | var textures = { 6 | sky: sky, 7 | grass: THREE.ImageUtils.loadTexture( texturePath + "grass.jpg" ), 8 | rock: THREE.ImageUtils.loadTexture( texturePath + "rock.jpg" ), 9 | snow: THREE.ImageUtils.loadTexture( texturePath + "snow.jpg" ) 10 | }; 11 | 12 | for ( var t in textures ) { 13 | if ( textures.hasOwnProperty( t ) ) { 14 | textures[t].wrapS = textures[t].wrapT = THREE.RepeatWrapping; 15 | } 16 | } 17 | sky.wrapS = sky.wrapT = THREE.MirroredRepeatWrapping; 18 | sky.repeat.set( 2, 2 ); 19 | 20 | return textures; 21 | } ); 22 | -------------------------------------------------------------------------------- /js/config.js: -------------------------------------------------------------------------------- 1 | // Configure Require.js 2 | var require = { 3 | // Default load path for js files 4 | baseUrl: 'js/app', 5 | shim: { 6 | // --- Use shim to mix together all THREE.js subcomponents 7 | 'threeCore': { exports: 'THREE' }, 8 | // --- end THREE sub-components 9 | 'ImprovedNoise': { exports: 'ImprovedNoise' }, 10 | 'detector': { exports: 'Detector' }, 11 | 'stats': { exports: 'Stats' } 12 | }, 13 | // Third party code lives in js/lib 14 | paths: { 15 | // --- start THREE sub-components 16 | three: '../lib/three', 17 | threeCore: '../lib/three.min', 18 | ImprovedNoise: '../lib/ImprovedNoise', 19 | // --- end THREE sub-components 20 | detector: '../lib/Detector', 21 | stats: '../lib/stats.min', 22 | // Require.js plugins 23 | text: '../lib/text', 24 | shader: '../lib/shader', 25 | // Where to look for shader files 26 | shaders: '../shaders' 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /js/lib/Detector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @author mr.doob / http://mrdoob.com/ 4 | */ 5 | 6 | var Detector = { 7 | 8 | canvas: !! window.CanvasRenderingContext2D, 9 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), 10 | workers: !! window.Worker, 11 | fileapi: window.File && window.FileReader && window.FileList && window.Blob, 12 | 13 | getWebGLErrorMessage: function () { 14 | 15 | var element = document.createElement( 'div' ); 16 | element.id = 'webgl-error-message'; 17 | element.style.fontFamily = 'monospace'; 18 | element.style.fontSize = '13px'; 19 | element.style.fontWeight = 'normal'; 20 | element.style.textAlign = 'center'; 21 | element.style.background = '#fff'; 22 | element.style.color = '#000'; 23 | element.style.padding = '1.5em'; 24 | element.style.width = '400px'; 25 | element.style.margin = '5em auto 0'; 26 | 27 | if ( ! this.webgl ) { 28 | 29 | element.innerHTML = window.WebGLRenderingContext ? [ 30 | 'Your graphics card does not seem to support WebGL.
', 31 | 'Find out how to get it here.' 32 | ].join( '\n' ) : [ 33 | 'Your browser does not seem to support WebGL.
', 34 | 'Find out how to get it here.' 35 | ].join( '\n' ); 36 | 37 | } 38 | 39 | return element; 40 | 41 | }, 42 | 43 | addGetWebGLMessage: function ( parameters ) { 44 | 45 | var parent, id, element; 46 | 47 | parameters = parameters || {}; 48 | 49 | parent = parameters.parent !== undefined ? parameters.parent : document.body; 50 | id = parameters.id !== undefined ? parameters.id : 'oldie'; 51 | 52 | element = Detector.getWebGLErrorMessage(); 53 | element.id = id; 54 | 55 | parent.appendChild( element ); 56 | 57 | } 58 | 59 | }; 60 | -------------------------------------------------------------------------------- /js/lib/ImprovedNoise.js: -------------------------------------------------------------------------------- 1 | // http://mrl.nyu.edu/~perlin/noise/ 2 | 3 | var ImprovedNoise = function () { 4 | 5 | var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10, 6 | 23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87, 7 | 174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211, 8 | 133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208, 9 | 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5, 10 | 202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119, 11 | 248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232, 12 | 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249, 13 | 14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205, 14 | 93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]; 15 | 16 | for (var i=0; i < 256 ; i++) { 17 | 18 | p[256+i] = p[i]; 19 | 20 | } 21 | 22 | function fade(t) { 23 | 24 | return t * t * t * (t * (t * 6 - 15) + 10); 25 | 26 | } 27 | 28 | function lerp(t, a, b) { 29 | 30 | return a + t * (b - a); 31 | 32 | } 33 | 34 | function grad(hash, x, y, z) { 35 | 36 | var h = hash & 15; 37 | var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z; 38 | return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); 39 | 40 | } 41 | 42 | return { 43 | 44 | noise: function (x, y, z) { 45 | 46 | var floorX = ~~x, floorY = ~~y, floorZ = ~~z; 47 | 48 | var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255; 49 | 50 | x -= floorX; 51 | y -= floorY; 52 | z -= floorZ; 53 | 54 | var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1; 55 | 56 | var u = fade(x), v = fade(y), w = fade(z); 57 | 58 | var A = p[X]+Y, AA = p[A]+Z, AB = p[A+1]+Z, B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; 59 | 60 | return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), 61 | grad(p[BA], xMinus1, y, z)), 62 | lerp(u, grad(p[AB], x, yMinus1, z), 63 | grad(p[BB], xMinus1, yMinus1, z))), 64 | lerp(v, lerp(u, grad(p[AA+1], x, y, zMinus1), 65 | grad(p[BA+1], xMinus1, y, z-1)), 66 | lerp(u, grad(p[AB+1], x, yMinus1, zMinus1), 67 | grad(p[BB+1], xMinus1, yMinus1, zMinus1)))); 68 | 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /js/lib/controls/TrackballControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Eberhard Graether / http://egraether.com/ 3 | */ 4 | 5 | THREE.TrackballControls = function ( object, domElement ) { 6 | 7 | var _this = this; 8 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 }; 9 | 10 | this.object = object; 11 | this.domElement = ( domElement !== undefined ) ? domElement : document; 12 | 13 | // API 14 | 15 | this.enabled = true; 16 | 17 | this.screen = { left: 0, top: 0, width: 0, height: 0 }; 18 | 19 | this.rotateSpeed = 1.0; 20 | this.zoomSpeed = 1.2; 21 | this.panSpeed = 0.3; 22 | 23 | this.noRotate = false; 24 | this.noZoom = false; 25 | this.noPan = false; 26 | this.noRoll = false; 27 | 28 | this.staticMoving = false; 29 | this.dynamicDampingFactor = 0.2; 30 | 31 | this.minDistance = 0; 32 | this.maxDistance = Infinity; 33 | 34 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 35 | 36 | // internals 37 | 38 | this.target = new THREE.Vector3(); 39 | 40 | var lastPosition = new THREE.Vector3(); 41 | 42 | var _state = STATE.NONE, 43 | _prevState = STATE.NONE, 44 | 45 | _eye = new THREE.Vector3(), 46 | 47 | _rotateStart = new THREE.Vector3(), 48 | _rotateEnd = new THREE.Vector3(), 49 | 50 | _zoomStart = new THREE.Vector2(), 51 | _zoomEnd = new THREE.Vector2(), 52 | 53 | _touchZoomDistanceStart = 0, 54 | _touchZoomDistanceEnd = 0, 55 | 56 | _panStart = new THREE.Vector2(), 57 | _panEnd = new THREE.Vector2(); 58 | 59 | // for reset 60 | 61 | this.target0 = this.target.clone(); 62 | this.position0 = this.object.position.clone(); 63 | this.up0 = this.object.up.clone(); 64 | 65 | // events 66 | 67 | var changeEvent = { type: 'change' }; 68 | 69 | 70 | // methods 71 | 72 | this.handleResize = function () { 73 | 74 | if ( this.domElement === document ) { 75 | 76 | this.screen.left = 0; 77 | this.screen.top = 0; 78 | this.screen.width = window.innerWidth; 79 | this.screen.height = window.innerHeight; 80 | 81 | } else { 82 | 83 | this.screen = this.domElement.getBoundingClientRect(); 84 | 85 | } 86 | 87 | }; 88 | 89 | this.handleEvent = function ( event ) { 90 | 91 | if ( typeof this[ event.type ] == 'function' ) { 92 | 93 | this[ event.type ]( event ); 94 | 95 | } 96 | 97 | }; 98 | 99 | this.getMouseOnScreen = function ( clientX, clientY ) { 100 | 101 | return new THREE.Vector2( 102 | ( clientX - _this.screen.left ) / _this.screen.width, 103 | ( clientY - _this.screen.top ) / _this.screen.height 104 | ); 105 | 106 | }; 107 | 108 | this.getMouseProjectionOnBall = function ( clientX, clientY ) { 109 | 110 | var mouseOnBall = new THREE.Vector3( 111 | ( clientX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5), 112 | ( _this.screen.height * 0.5 + _this.screen.top - clientY ) / (_this.screen.height*.5), 113 | 0.0 114 | ); 115 | 116 | var length = mouseOnBall.length(); 117 | 118 | if ( _this.noRoll ) { 119 | 120 | if ( length < Math.SQRT1_2 ) { 121 | 122 | mouseOnBall.z = Math.sqrt( 1.0 - length*length ); 123 | 124 | } else { 125 | 126 | mouseOnBall.z = .5 / length; 127 | 128 | } 129 | 130 | } else if ( length > 1.0 ) { 131 | 132 | mouseOnBall.normalize(); 133 | 134 | } else { 135 | 136 | mouseOnBall.z = Math.sqrt( 1.0 - length * length ); 137 | 138 | } 139 | 140 | _eye.copy( _this.object.position ).sub( _this.target ); 141 | 142 | var projection = _this.object.up.clone().setLength( mouseOnBall.y ); 143 | projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) ); 144 | projection.add( _eye.setLength( mouseOnBall.z ) ); 145 | 146 | return projection; 147 | 148 | }; 149 | 150 | this.rotateCamera = function () { 151 | 152 | var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); 153 | 154 | if ( angle ) { 155 | 156 | var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(), 157 | quaternion = new THREE.Quaternion(); 158 | 159 | angle *= _this.rotateSpeed; 160 | 161 | quaternion.setFromAxisAngle( axis, -angle ); 162 | 163 | _eye.applyQuaternion( quaternion ); 164 | _this.object.up.applyQuaternion( quaternion ); 165 | 166 | _rotateEnd.applyQuaternion( quaternion ); 167 | 168 | if ( _this.staticMoving ) { 169 | 170 | _rotateStart.copy( _rotateEnd ); 171 | 172 | } else { 173 | 174 | quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); 175 | _rotateStart.applyQuaternion( quaternion ); 176 | 177 | } 178 | 179 | } 180 | 181 | }; 182 | 183 | this.zoomCamera = function () { 184 | 185 | if ( _state === STATE.TOUCH_ZOOM ) { 186 | 187 | var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; 188 | _touchZoomDistanceStart = _touchZoomDistanceEnd; 189 | _eye.multiplyScalar( factor ); 190 | 191 | } else { 192 | 193 | var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; 194 | 195 | if ( factor !== 1.0 && factor > 0.0 ) { 196 | 197 | _eye.multiplyScalar( factor ); 198 | 199 | if ( _this.staticMoving ) { 200 | 201 | _zoomStart.copy( _zoomEnd ); 202 | 203 | } else { 204 | 205 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 206 | 207 | } 208 | 209 | } 210 | 211 | } 212 | 213 | }; 214 | 215 | this.panCamera = function () { 216 | 217 | var mouseChange = _panEnd.clone().sub( _panStart ); 218 | 219 | if ( mouseChange.lengthSq() ) { 220 | 221 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); 222 | 223 | var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x ); 224 | pan.add( _this.object.up.clone().setLength( mouseChange.y ) ); 225 | 226 | _this.object.position.add( pan ); 227 | _this.target.add( pan ); 228 | 229 | if ( _this.staticMoving ) { 230 | 231 | _panStart = _panEnd; 232 | 233 | } else { 234 | 235 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); 236 | 237 | } 238 | 239 | } 240 | 241 | }; 242 | 243 | this.checkDistances = function () { 244 | 245 | if ( !_this.noZoom || !_this.noPan ) { 246 | 247 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) { 248 | 249 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) ); 250 | 251 | } 252 | 253 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { 254 | 255 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); 256 | 257 | } 258 | 259 | } 260 | 261 | }; 262 | 263 | this.update = function () { 264 | 265 | _eye.subVectors( _this.object.position, _this.target ); 266 | 267 | if ( !_this.noRotate ) { 268 | 269 | _this.rotateCamera(); 270 | 271 | } 272 | 273 | if ( !_this.noZoom ) { 274 | 275 | _this.zoomCamera(); 276 | 277 | } 278 | 279 | if ( !_this.noPan ) { 280 | 281 | _this.panCamera(); 282 | 283 | } 284 | 285 | _this.object.position.addVectors( _this.target, _eye ); 286 | 287 | _this.checkDistances(); 288 | 289 | _this.object.lookAt( _this.target ); 290 | 291 | if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) { 292 | 293 | _this.dispatchEvent( changeEvent ); 294 | 295 | lastPosition.copy( _this.object.position ); 296 | 297 | } 298 | 299 | }; 300 | 301 | this.reset = function () { 302 | 303 | _state = STATE.NONE; 304 | _prevState = STATE.NONE; 305 | 306 | _this.target.copy( _this.target0 ); 307 | _this.object.position.copy( _this.position0 ); 308 | _this.object.up.copy( _this.up0 ); 309 | 310 | _eye.subVectors( _this.object.position, _this.target ); 311 | 312 | _this.object.lookAt( _this.target ); 313 | 314 | _this.dispatchEvent( changeEvent ); 315 | 316 | lastPosition.copy( _this.object.position ); 317 | 318 | }; 319 | 320 | // listeners 321 | 322 | function keydown( event ) { 323 | 324 | if ( _this.enabled === false ) return; 325 | 326 | window.removeEventListener( 'keydown', keydown ); 327 | 328 | _prevState = _state; 329 | 330 | if ( _state !== STATE.NONE ) { 331 | 332 | return; 333 | 334 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) { 335 | 336 | _state = STATE.ROTATE; 337 | 338 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) { 339 | 340 | _state = STATE.ZOOM; 341 | 342 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) { 343 | 344 | _state = STATE.PAN; 345 | 346 | } 347 | 348 | } 349 | 350 | function keyup( event ) { 351 | 352 | if ( _this.enabled === false ) return; 353 | 354 | _state = _prevState; 355 | 356 | window.addEventListener( 'keydown', keydown, false ); 357 | 358 | } 359 | 360 | function mousedown( event ) { 361 | 362 | if ( _this.enabled === false ) return; 363 | 364 | event.preventDefault(); 365 | event.stopPropagation(); 366 | 367 | if ( _state === STATE.NONE ) { 368 | 369 | _state = event.button; 370 | 371 | } 372 | 373 | if ( _state === STATE.ROTATE && !_this.noRotate ) { 374 | 375 | _rotateStart = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); 376 | _rotateEnd.copy(_rotateStart) 377 | 378 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) { 379 | 380 | _zoomStart = _this.getMouseOnScreen( event.clientX, event.clientY ); 381 | _zoomEnd.copy(_zoomStart); 382 | 383 | } else if ( _state === STATE.PAN && !_this.noPan ) { 384 | 385 | _panStart = _this.getMouseOnScreen( event.clientX, event.clientY ); 386 | _panEnd.copy(_panStart) 387 | 388 | } 389 | 390 | document.addEventListener( 'mousemove', mousemove, false ); 391 | document.addEventListener( 'mouseup', mouseup, false ); 392 | 393 | } 394 | 395 | function mousemove( event ) { 396 | 397 | if ( _this.enabled === false ) return; 398 | 399 | event.preventDefault(); 400 | event.stopPropagation(); 401 | 402 | if ( _state === STATE.ROTATE && !_this.noRotate ) { 403 | 404 | _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); 405 | 406 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) { 407 | 408 | _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); 409 | 410 | } else if ( _state === STATE.PAN && !_this.noPan ) { 411 | 412 | _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); 413 | 414 | } 415 | 416 | } 417 | 418 | function mouseup( event ) { 419 | 420 | if ( _this.enabled === false ) return; 421 | 422 | event.preventDefault(); 423 | event.stopPropagation(); 424 | 425 | _state = STATE.NONE; 426 | 427 | document.removeEventListener( 'mousemove', mousemove ); 428 | document.removeEventListener( 'mouseup', mouseup ); 429 | 430 | } 431 | 432 | function mousewheel( event ) { 433 | 434 | if ( _this.enabled === false ) return; 435 | 436 | event.preventDefault(); 437 | event.stopPropagation(); 438 | 439 | var delta = 0; 440 | 441 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 442 | 443 | delta = event.wheelDelta / 40; 444 | 445 | } else if ( event.detail ) { // Firefox 446 | 447 | delta = - event.detail / 3; 448 | 449 | } 450 | 451 | _zoomStart.y += delta * 0.01; 452 | 453 | } 454 | 455 | function touchstart( event ) { 456 | 457 | if ( _this.enabled === false ) return; 458 | 459 | switch ( event.touches.length ) { 460 | 461 | case 1: 462 | _state = STATE.TOUCH_ROTATE; 463 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 464 | break; 465 | 466 | case 2: 467 | _state = STATE.TOUCH_ZOOM; 468 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 469 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 470 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 471 | break; 472 | 473 | case 3: 474 | _state = STATE.TOUCH_PAN; 475 | _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 476 | break; 477 | 478 | default: 479 | _state = STATE.NONE; 480 | 481 | } 482 | 483 | } 484 | 485 | function touchmove( event ) { 486 | 487 | if ( _this.enabled === false ) return; 488 | 489 | event.preventDefault(); 490 | event.stopPropagation(); 491 | 492 | switch ( event.touches.length ) { 493 | 494 | case 1: 495 | _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 496 | break; 497 | 498 | case 2: 499 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 500 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 501 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ) 502 | break; 503 | 504 | case 3: 505 | _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 506 | break; 507 | 508 | default: 509 | _state = STATE.NONE; 510 | 511 | } 512 | 513 | } 514 | 515 | function touchend( event ) { 516 | 517 | if ( _this.enabled === false ) return; 518 | 519 | switch ( event.touches.length ) { 520 | 521 | case 1: 522 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 523 | break; 524 | 525 | case 2: 526 | _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; 527 | break; 528 | 529 | case 3: 530 | _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 531 | break; 532 | 533 | } 534 | 535 | _state = STATE.NONE; 536 | 537 | } 538 | 539 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); 540 | 541 | this.domElement.addEventListener( 'mousedown', mousedown, false ); 542 | 543 | this.domElement.addEventListener( 'mousewheel', mousewheel, false ); 544 | this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox 545 | 546 | this.domElement.addEventListener( 'touchstart', touchstart, false ); 547 | this.domElement.addEventListener( 'touchend', touchend, false ); 548 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 549 | 550 | window.addEventListener( 'keydown', keydown, false ); 551 | window.addEventListener( 'keyup', keyup, false ); 552 | 553 | this.handleResize(); 554 | 555 | }; 556 | 557 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 558 | -------------------------------------------------------------------------------- /js/lib/shader.js: -------------------------------------------------------------------------------- 1 | // Extension of the 'text' plugin specially for loading shaders 2 | // Features 3 | // - Supports #include statements to combine shaders 4 | // - Can use the define function to change the value of #define statments in the shader 5 | // - Expects shaders to be in `shaders` directory, which can be configured in the require.js config 6 | define( { 7 | load: function ( name, req, onload, config ) { 8 | if ( config.isBuild ) { 9 | onload(); 10 | return; 11 | } 12 | 13 | var Shader = function ( value ) { 14 | this.value = value; 15 | }; 16 | 17 | // Replace the value of a #define within the shader 18 | Shader.prototype.define = function ( define, value ) { 19 | var regexp = new RegExp("#define " + define + " .*", "g"); 20 | var newDefine = "#define " + define + ( value ? " " + value : "" ); 21 | if ( this.value.match( regexp ) ) { 22 | // #define already exists, update its value 23 | this.value = this.value.replace( regexp, newDefine ); 24 | } else { 25 | // New #define, prepend to start of file 26 | this.value = newDefine + "\n" + this.value; 27 | } 28 | }; 29 | 30 | req( ["text!shaders/" + name], function ( shaderContents ) { 31 | var shader = new Shader( shaderContents ); 32 | var matches = []; 33 | shaderContents.replace( /#include (.*)/g, function ( match, includeFile ) { 34 | matches.push( includeFile ); 35 | } ); 36 | 37 | if ( matches.length === 0 ) { 38 | // No includes, just return straight away 39 | onload( shader ); 40 | } else { 41 | // Load included shaders and replace them in the code 42 | var loaded = 0; 43 | for ( var m = 0; m < matches.length; m++ ) { 44 | ( function ( includeFile ) { 45 | req(["shader!" + includeFile], function ( includeShader ) { 46 | var regexp = new RegExp("#include " + includeFile, "g"); 47 | shader.value = shader.value.replace( regexp, includeShader.value ); 48 | loaded++; 49 | 50 | if ( loaded === matches.length ) { 51 | // All shaders have been loaded, return result 52 | onload( shader ); 53 | } 54 | }); 55 | })( matches[m] ); 56 | } 57 | } 58 | }); 59 | } 60 | }); 61 | -------------------------------------------------------------------------------- /js/lib/stats.min.js: -------------------------------------------------------------------------------- 1 | // stats.js - http://github.com/mrdoob/stats.js 2 | var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; 3 | i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); 4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= 5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= 6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}}; 7 | -------------------------------------------------------------------------------- /js/lib/text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. 3 | * Available via the MIT or new BSD license. 4 | * see: http://github.com/requirejs/text for details 5 | */ 6 | /*jslint regexp: true */ 7 | /*global require, XMLHttpRequest, ActiveXObject, 8 | define, window, process, Packages, 9 | java, location, Components, FileUtils */ 10 | 11 | define(['module'], function (module) { 12 | 'use strict'; 13 | 14 | var text, fs, Cc, Ci, xpcIsWindows, 15 | progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], 16 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, 17 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, 18 | hasLocation = typeof location !== 'undefined' && location.href, 19 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), 20 | defaultHostName = hasLocation && location.hostname, 21 | defaultPort = hasLocation && (location.port || undefined), 22 | buildMap = {}, 23 | masterConfig = (module.config && module.config()) || {}; 24 | 25 | text = { 26 | version: '2.0.10', 27 | 28 | strip: function (content) { 29 | //Strips declarations so that external SVG and XML 30 | //documents can be added to a document without worry. Also, if the string 31 | //is an HTML document, only the part inside the body tag is returned. 32 | if (content) { 33 | content = content.replace(xmlRegExp, ""); 34 | var matches = content.match(bodyRegExp); 35 | if (matches) { 36 | content = matches[1]; 37 | } 38 | } else { 39 | content = ""; 40 | } 41 | return content; 42 | }, 43 | 44 | jsEscape: function (content) { 45 | return content.replace(/(['\\])/g, '\\$1') 46 | .replace(/[\f]/g, "\\f") 47 | .replace(/[\b]/g, "\\b") 48 | .replace(/[\n]/g, "\\n") 49 | .replace(/[\t]/g, "\\t") 50 | .replace(/[\r]/g, "\\r") 51 | .replace(/[\u2028]/g, "\\u2028") 52 | .replace(/[\u2029]/g, "\\u2029"); 53 | }, 54 | 55 | createXhr: masterConfig.createXhr || function () { 56 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first. 57 | var xhr, i, progId; 58 | if (typeof XMLHttpRequest !== "undefined") { 59 | return new XMLHttpRequest(); 60 | } else if (typeof ActiveXObject !== "undefined") { 61 | for (i = 0; i < 3; i += 1) { 62 | progId = progIds[i]; 63 | try { 64 | xhr = new ActiveXObject(progId); 65 | } catch (e) {} 66 | 67 | if (xhr) { 68 | progIds = [progId]; // so faster next time 69 | break; 70 | } 71 | } 72 | } 73 | 74 | return xhr; 75 | }, 76 | 77 | /** 78 | * Parses a resource name into its component parts. Resource names 79 | * look like: module/name.ext!strip, where the !strip part is 80 | * optional. 81 | * @param {String} name the resource name 82 | * @returns {Object} with properties "moduleName", "ext" and "strip" 83 | * where strip is a boolean. 84 | */ 85 | parseName: function (name) { 86 | var modName, ext, temp, 87 | strip = false, 88 | index = name.indexOf("."), 89 | isRelative = name.indexOf('./') === 0 || 90 | name.indexOf('../') === 0; 91 | 92 | if (index !== -1 && (!isRelative || index > 1)) { 93 | modName = name.substring(0, index); 94 | ext = name.substring(index + 1, name.length); 95 | } else { 96 | modName = name; 97 | } 98 | 99 | temp = ext || modName; 100 | index = temp.indexOf("!"); 101 | if (index !== -1) { 102 | //Pull off the strip arg. 103 | strip = temp.substring(index + 1) === "strip"; 104 | temp = temp.substring(0, index); 105 | if (ext) { 106 | ext = temp; 107 | } else { 108 | modName = temp; 109 | } 110 | } 111 | 112 | return { 113 | moduleName: modName, 114 | ext: ext, 115 | strip: strip 116 | }; 117 | }, 118 | 119 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, 120 | 121 | /** 122 | * Is an URL on another domain. Only works for browser use, returns 123 | * false in non-browser environments. Only used to know if an 124 | * optimized .js version of a text resource should be loaded 125 | * instead. 126 | * @param {String} url 127 | * @returns Boolean 128 | */ 129 | useXhr: function (url, protocol, hostname, port) { 130 | var uProtocol, uHostName, uPort, 131 | match = text.xdRegExp.exec(url); 132 | if (!match) { 133 | return true; 134 | } 135 | uProtocol = match[2]; 136 | uHostName = match[3]; 137 | 138 | uHostName = uHostName.split(':'); 139 | uPort = uHostName[1]; 140 | uHostName = uHostName[0]; 141 | 142 | return (!uProtocol || uProtocol === protocol) && 143 | (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && 144 | ((!uPort && !uHostName) || uPort === port); 145 | }, 146 | 147 | finishLoad: function (name, strip, content, onLoad) { 148 | content = strip ? text.strip(content) : content; 149 | if (masterConfig.isBuild) { 150 | buildMap[name] = content; 151 | } 152 | onLoad(content); 153 | }, 154 | 155 | load: function (name, req, onLoad, config) { 156 | //Name has format: some.module.filext!strip 157 | //The strip part is optional. 158 | //if strip is present, then that means only get the string contents 159 | //inside a body tag in an HTML string. For XML/SVG content it means 160 | //removing the declarations so the content can be inserted 161 | //into the current doc without problems. 162 | 163 | // Do not bother with the work if a build and text will 164 | // not be inlined. 165 | if (config.isBuild && !config.inlineText) { 166 | onLoad(); 167 | return; 168 | } 169 | 170 | masterConfig.isBuild = config.isBuild; 171 | 172 | var parsed = text.parseName(name), 173 | nonStripName = parsed.moduleName + 174 | (parsed.ext ? '.' + parsed.ext : ''), 175 | url = req.toUrl(nonStripName), 176 | useXhr = (masterConfig.useXhr) || 177 | text.useXhr; 178 | 179 | // Do not load if it is an empty: url 180 | if (url.indexOf('empty:') === 0) { 181 | onLoad(); 182 | return; 183 | } 184 | 185 | //Load the text. Use XHR if possible and in a browser. 186 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { 187 | text.get(url, function (content) { 188 | text.finishLoad(name, parsed.strip, content, onLoad); 189 | }, function (err) { 190 | if (onLoad.error) { 191 | onLoad.error(err); 192 | } 193 | }); 194 | } else { 195 | //Need to fetch the resource across domains. Assume 196 | //the resource has been optimized into a JS module. Fetch 197 | //by the module name + extension, but do not include the 198 | //!strip part to avoid file system issues. 199 | req([nonStripName], function (content) { 200 | text.finishLoad(parsed.moduleName + '.' + parsed.ext, 201 | parsed.strip, content, onLoad); 202 | }); 203 | } 204 | }, 205 | 206 | write: function (pluginName, moduleName, write, config) { 207 | if (buildMap.hasOwnProperty(moduleName)) { 208 | var content = text.jsEscape(buildMap[moduleName]); 209 | write.asModule(pluginName + "!" + moduleName, 210 | "define(function () { return '" + 211 | content + 212 | "';});\n"); 213 | } 214 | }, 215 | 216 | writeFile: function (pluginName, moduleName, req, write, config) { 217 | var parsed = text.parseName(moduleName), 218 | extPart = parsed.ext ? '.' + parsed.ext : '', 219 | nonStripName = parsed.moduleName + extPart, 220 | //Use a '.js' file name so that it indicates it is a 221 | //script that can be loaded across domains. 222 | fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; 223 | 224 | //Leverage own load() method to load plugin value, but only 225 | //write out values that do not have the strip argument, 226 | //to avoid any potential issues with ! in file names. 227 | text.load(nonStripName, req, function (value) { 228 | //Use own write() method to construct full module value. 229 | //But need to create shell that translates writeFile's 230 | //write() to the right interface. 231 | var textWrite = function (contents) { 232 | return write(fileName, contents); 233 | }; 234 | textWrite.asModule = function (moduleName, contents) { 235 | return write.asModule(moduleName, fileName, contents); 236 | }; 237 | 238 | text.write(pluginName, nonStripName, textWrite, config); 239 | }, config); 240 | } 241 | }; 242 | 243 | if (masterConfig.env === 'node' || (!masterConfig.env && 244 | typeof process !== "undefined" && 245 | process.versions && 246 | !!process.versions.node && 247 | !process.versions['node-webkit'])) { 248 | //Using special require.nodeRequire, something added by r.js. 249 | fs = require.nodeRequire('fs'); 250 | 251 | text.get = function (url, callback, errback) { 252 | try { 253 | var file = fs.readFileSync(url, 'utf8'); 254 | //Remove BOM (Byte Mark Order) from utf8 files if it is there. 255 | if (file.indexOf('\uFEFF') === 0) { 256 | file = file.substring(1); 257 | } 258 | callback(file); 259 | } catch (e) { 260 | errback(e); 261 | } 262 | }; 263 | } else if (masterConfig.env === 'xhr' || (!masterConfig.env && 264 | text.createXhr())) { 265 | text.get = function (url, callback, errback, headers) { 266 | var xhr = text.createXhr(), header; 267 | xhr.open('GET', url, true); 268 | 269 | //Allow plugins direct access to xhr headers 270 | if (headers) { 271 | for (header in headers) { 272 | if (headers.hasOwnProperty(header)) { 273 | xhr.setRequestHeader(header.toLowerCase(), headers[header]); 274 | } 275 | } 276 | } 277 | 278 | //Allow overrides specified in config 279 | if (masterConfig.onXhr) { 280 | masterConfig.onXhr(xhr, url); 281 | } 282 | 283 | xhr.onreadystatechange = function (evt) { 284 | var status, err; 285 | //Do not explicitly handle errors, those should be 286 | //visible via console output in the browser. 287 | if (xhr.readyState === 4) { 288 | status = xhr.status; 289 | if (status > 399 && status < 600) { 290 | //An http 4xx or 5xx error. Signal an error. 291 | err = new Error(url + ' HTTP status: ' + status); 292 | err.xhr = xhr; 293 | errback(err); 294 | } else { 295 | callback(xhr.responseText); 296 | } 297 | 298 | if (masterConfig.onXhrComplete) { 299 | masterConfig.onXhrComplete(xhr, url); 300 | } 301 | } 302 | }; 303 | xhr.send(null); 304 | }; 305 | } else if (masterConfig.env === 'rhino' || (!masterConfig.env && 306 | typeof Packages !== 'undefined' && typeof java !== 'undefined')) { 307 | //Why Java, why is this so awkward? 308 | text.get = function (url, callback) { 309 | var stringBuffer, line, 310 | encoding = "utf-8", 311 | file = new java.io.File(url), 312 | lineSeparator = java.lang.System.getProperty("line.separator"), 313 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), 314 | content = ''; 315 | try { 316 | stringBuffer = new java.lang.StringBuffer(); 317 | line = input.readLine(); 318 | 319 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 320 | // http://www.unicode.org/faq/utf_bom.html 321 | 322 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: 323 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 324 | if (line && line.length() && line.charAt(0) === 0xfeff) { 325 | // Eat the BOM, since we've already found the encoding on this file, 326 | // and we plan to concatenating this buffer with others; the BOM should 327 | // only appear at the top of a file. 328 | line = line.substring(1); 329 | } 330 | 331 | if (line !== null) { 332 | stringBuffer.append(line); 333 | } 334 | 335 | while ((line = input.readLine()) !== null) { 336 | stringBuffer.append(lineSeparator); 337 | stringBuffer.append(line); 338 | } 339 | //Make sure we return a JavaScript string and not a Java string. 340 | content = String(stringBuffer.toString()); //String 341 | } finally { 342 | input.close(); 343 | } 344 | callback(content); 345 | }; 346 | } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && 347 | typeof Components !== 'undefined' && Components.classes && 348 | Components.interfaces)) { 349 | //Avert your gaze! 350 | Cc = Components.classes, 351 | Ci = Components.interfaces; 352 | Components.utils['import']('resource://gre/modules/FileUtils.jsm'); 353 | xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); 354 | 355 | text.get = function (url, callback) { 356 | var inStream, convertStream, fileObj, 357 | readData = {}; 358 | 359 | if (xpcIsWindows) { 360 | url = url.replace(/\//g, '\\'); 361 | } 362 | 363 | fileObj = new FileUtils.File(url); 364 | 365 | //XPCOM, you so crazy 366 | try { 367 | inStream = Cc['@mozilla.org/network/file-input-stream;1'] 368 | .createInstance(Ci.nsIFileInputStream); 369 | inStream.init(fileObj, 1, 0, false); 370 | 371 | convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] 372 | .createInstance(Ci.nsIConverterInputStream); 373 | convertStream.init(inStream, "utf-8", inStream.available(), 374 | Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); 375 | 376 | convertStream.readString(inStream.available(), readData); 377 | convertStream.close(); 378 | inStream.close(); 379 | callback(readData.value); 380 | } catch (e) { 381 | throw new Error((fileObj && fileObj.path || '') + ': ' + e); 382 | } 383 | }; 384 | } 385 | return text; 386 | }); 387 | -------------------------------------------------------------------------------- /js/lib/three.js: -------------------------------------------------------------------------------- 1 | // As THREE.js comes with many addons/plugins mix them all into one three object here 2 | define( ["threeCore"], function( threeCore ) { 3 | return threeCore; 4 | } ); 5 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | // Start the app 2 | require( ['detector', 'app', 'container'], function ( Detector, app, container ) { 3 | if ( ! Detector.webgl ) { 4 | Detector.addGetWebGLMessage(); 5 | container.innerHTML = ""; 6 | } 7 | 8 | // Initialize our app and start the animation loop (animate is expected to call itself) 9 | app.init(); 10 | app.animate(); 11 | } ); 12 | -------------------------------------------------------------------------------- /js/require.js: -------------------------------------------------------------------------------- 1 | /* 2 | RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. 3 | Available via the MIT or new BSD license. 4 | see: http://github.com/jrburke/requirejs for details 5 | */ 6 | var requirejs,require,define; 7 | (function(Z){function H(b){return"[object Function]"===L.call(b)}function I(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var e;for(e=0;ethis.depCount&&!this.defined){if(H(m)){if(this.events.error&&this.map.isDefine||j.onError!==aa)try{d=i.execCb(c,m,b,d)}catch(e){a=e}else d=i.execCb(c,m,b,d);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!== 19 | this.exports?d=b.exports:void 0===d&&this.usingExports&&(d=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",v(this.error=a)}else d=m;this.exports=d;if(this.map.isDefine&&!this.ignore&&(r[c]=d,j.onResourceLoad))j.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete= 20 | !0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,e=n(a.prefix);this.depMaps.push(e);s(e,"defined",u(this,function(d){var m,e;e=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(d.normalize&&(e=d.normalize(e,function(a){return c(a,g,!0)})||""),d=n(a.prefix+"!"+e,this.map.parentMap),s(d,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})), 21 | e=l(p,d.id)){this.depMaps.push(d);if(this.events.error)e.on("error",u(this,function(a){this.emit("error",a)}));e.enable()}}else m=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),m.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];F(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),m.fromText=u(this,function(d,c){var e=a.name,g=n(e),B=O;c&&(d=c);B&&(O=!1);q(g);t(k.config,b)&&(k.config[e]=k.config[b]);try{j.exec(d)}catch(ca){return v(A("fromtexteval", 22 | "fromText eval for "+b+" failed: "+ca,ca,[b]))}B&&(O=!0);this.depMaps.push(g);i.completeLoad(e);h([e],m)}),d.load(a.name,h,m,k)}));i.enable(e,this);this.pluginMaps[e.id]=e},enable:function(){T[this.map.id]=this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,d;if("string"===typeof a){a=n(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=l(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;s(a,"defined",u(this,function(a){this.defineDep(b, 23 | a);this.check()}));this.errback&&s(a,"error",u(this,this.errback))}c=a.id;d=p[c];!t(N,c)&&(d&&!d.enabled)&&i.enable(a,this)}));F(this.pluginMaps,u(this,function(a){var b=l(p,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:r,urlFetched:S,defQueue:G,Module:X,makeModuleMap:n, 24 | nextTick:j.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,d={paths:!0,config:!0,map:!0};F(a,function(a,b){d[b]?"map"===b?(k.map||(k.map={}),Q(k[b],a,!0,!0)):Q(k[b],a,!0):k[b]=a});a.shim&&(F(a.shim,function(a,b){I(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name, 25 | location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);F(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=n(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(Z,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function h(d,c,e){var g,k;f.enableBuildCallback&&(c&&H(c))&&(c.__requireJsBuild=!0);if("string"===typeof d){if(H(c))return v(A("requireargs", 26 | "Invalid require call"),e);if(a&&t(N,d))return N[d](p[a.id]);if(j.get)return j.get(i,d,a,h);g=n(d,a,!1,!0);g=g.id;return!t(r,g)?v(A("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[g]}K();i.nextTick(function(){K();k=q(n(null,a));k.skipMap=f.skipMap;k.init(d,c,e,{enabled:!0});C()});return h}f=f||{};Q(h,{isBrowser:z,toUrl:function(b){var f,e=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==e&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!W?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error", 34 | b.onScriptError,!1)),h.src=e,K=h,C?x.insertBefore(h,C):x.appendChild(h),K=null,h;if(da)try{importScripts(e),b.completeLoad(c)}catch(l){b.onError(A("importscripts","importScripts failed for "+c+" at "+e,l,[c]))}};z&&!s.skipDataMain&&M(document.getElementsByTagName("script"),function(b){x||(x=b.parentNode);if(J=b.getAttribute("data-main"))return q=J,s.baseUrl||(D=q.split("/"),q=D.pop(),fa=D.length?D.join("/")+"/":"./",s.baseUrl=fa),q=q.replace(ea,""),j.jsExtRegExp.test(q)&&(q=J),s.deps=s.deps?s.deps.concat(q): 35 | [q],!0});define=function(b,c,e){var h,j;"string"!==typeof b&&(e=c,c=b,b=null);I(c)||(e=c,c=null);!c&&H(e)&&(c=[],e.length&&(e.toString().replace(la,"").replace(ma,function(b,e){c.push(e)}),c=(1===e.length?["require"]:["require","exports","module"]).concat(c)));if(O){if(!(h=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),h=P;h&&(b||(b=h.getAttribute("data-requiremodule")),j=E[h.getAttribute("data-requirecontext")])}(j? 36 | j.defQueue:R).push([b,c,e])};define.amd={jQuery:!0};j.exec=function(b){return eval(b)};j(s)}})(this); 37 | -------------------------------------------------------------------------------- /js/shaders/atmosphere.frag: -------------------------------------------------------------------------------- 1 | uniform vec3 uHorizonColor; 2 | uniform vec3 uSkyColor; 3 | 4 | varying float vDistance; 5 | 6 | void main() { 7 | // Not the best gradient effect.... 8 | float blend = smoothstep( 500.0, 1500.0, gl_FragCoord.y ); 9 | vec3 color = mix( uHorizonColor, uSkyColor, blend ); 10 | gl_FragColor = vec4( color, 1.0 ); 11 | } 12 | -------------------------------------------------------------------------------- /js/shaders/atmosphere.vert: -------------------------------------------------------------------------------- 1 | varying float vDistance; 2 | 3 | void main() { 4 | vDistance = distance( cameraPosition, position ); 5 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 6 | } 7 | -------------------------------------------------------------------------------- /js/shaders/colorScale.glsl: -------------------------------------------------------------------------------- 1 | vec3 colorForScale(float scale) { 2 | if ( scale > 32.0 ) { 3 | scale /= 32.0; 4 | } 5 | if ( scale <= 1.0 ) { 6 | return vec3(1.0, 0, 0); 7 | } else if ( scale <= 2.0 ) { 8 | return vec3(0, 1.0, 0); 9 | } else if ( scale <= 4.0 ) { 10 | return vec3(0, 0, 1.0); 11 | } else if ( scale <= 8.0 ) { 12 | return vec3(1.0, 1.0, 0); 13 | } else if ( scale <= 16.0 ) { 14 | return vec3(1.0, 0, 1.0); 15 | } else if ( scale <= 32.0 ) { 16 | return vec3(1.0, 1.0, 1.0); 17 | } 18 | 19 | // Shouldn't happen 20 | return vec3(0, 0, 0); 21 | } 22 | -------------------------------------------------------------------------------- /js/shaders/edgemorph.glsl: -------------------------------------------------------------------------------- 1 | uniform int uEdgeMorph; 2 | 3 | #define EGDE_MORPH_TOP 1 4 | #define EGDE_MORPH_LEFT 2 5 | #define EGDE_MORPH_BOTTOM 4 6 | #define EGDE_MORPH_RIGHT 8 7 | 8 | // Poor man's bitwise & 9 | bool edgePresent(int edge) { 10 | int e = uEdgeMorph / edge; 11 | return 2 * ( e / 2 ) != e; 12 | } 13 | 14 | #define MORPH_REGION 0.3 15 | 16 | // At the edges of tiles morph the vertices, if they are joining onto a higher layer 17 | float calculateMorph(vec3 p) { 18 | float morphFactor = 0.0; 19 | if( edgePresent(EGDE_MORPH_TOP) && p.y >= 1.0 - MORPH_REGION ) { 20 | float m = 1.0 - clamp((1.0 - p.y) / MORPH_REGION, 0.0, 1.0); 21 | morphFactor = max(m, morphFactor); 22 | } 23 | if( edgePresent(EGDE_MORPH_LEFT) && p.x <= MORPH_REGION ) { 24 | float m = 1.0 - clamp(p.x / MORPH_REGION, 0.0, 1.0); 25 | morphFactor = max(m, morphFactor); 26 | } 27 | if( edgePresent(EGDE_MORPH_BOTTOM) && p.y <= MORPH_REGION ) { 28 | float m = 1.0 - clamp(p.y / MORPH_REGION, 0.0, 1.0); 29 | morphFactor = max(m, morphFactor); 30 | } 31 | if( edgePresent(EGDE_MORPH_RIGHT) && p.x >= 1.0 - MORPH_REGION ) { 32 | float m = 1.0 - clamp((1.0 - p.x) / MORPH_REGION, 0.0, 1.0); 33 | morphFactor = max(m, morphFactor); 34 | } 35 | 36 | return morphFactor; 37 | } 38 | -------------------------------------------------------------------------------- /js/shaders/shift.glsl: -------------------------------------------------------------------------------- 1 | // shift() will translate a vertex by 500 units in the x direction 2 | vec3 shift(vec3 p) { 3 | return p + vec3(500.0, 0, 0); 4 | } 5 | -------------------------------------------------------------------------------- /js/shaders/terrain.frag: -------------------------------------------------------------------------------- 1 | #extension GL_OES_standard_derivatives : enable 2 | uniform float uScale; 3 | uniform sampler2D uHeightData; 4 | 5 | varying float vMorphFactor; 6 | varying vec3 vNormal; 7 | varying vec3 vPosition; 8 | 9 | #include colorScale.glsl 10 | 11 | float getHeight(vec3 p) { 12 | // Assume a 1024x1024 world 13 | vec2 st = p.xy / 1024.0; 14 | 15 | // Sample multiple times to get more detail out of map 16 | float h = 1024.0 * texture2D(uHeightData, st).a; 17 | h += 64.0 * texture2D(uHeightData, 16.0 * st).a; 18 | h += 4.0 * texture2D(uHeightData, 256.0 * st).a; 19 | 20 | // Square the height, leads to more rocky looking terrain 21 | return h * h / 2000.0; 22 | } 23 | 24 | vec3 getNormal() { 25 | // Differentiate the position vector (this will give us two vectors perpendicular to the surface) 26 | // Before differentiating, add the displacement based on the height from the height map. By doing this 27 | // calculation here, rather than in the vertex shader, we get a per-fragment calculated normal, rather 28 | // than a per-vertex normal. This improves the look of distant low-vertex terrain. 29 | float height = getHeight( vPosition ); 30 | vec3 p = vec3( vPosition.xy, height ); 31 | vec3 dPositiondx = dFdx(p); 32 | vec3 dPositiondy = dFdy(p); 33 | 34 | // The normal is the cross product of the differentials 35 | return normalize(cross(dPositiondx, dPositiondy)); 36 | } 37 | 38 | void main() { 39 | // Base color 40 | vec3 light = vec3(80.0, 150.0, 50.0); 41 | //vec3 color = colorForScale(uScale); 42 | vec3 color = vec3(0.27, 0.27, 0.17); 43 | //color = vec3(vMorphFactor); 44 | 45 | vec3 normal = getNormal(); 46 | 47 | // Incident light 48 | float incidence = dot(normalize(light - vPosition), normal); 49 | incidence = clamp(incidence, 0.0, 1.0); 50 | incidence = pow(incidence, 0.02); 51 | color = mix(vec3(0, 0, 0), color, incidence); 52 | 53 | // Mix in specular light 54 | vec3 halfVector = normalize(normalize(cameraPosition - vPosition) + normalize(light - vPosition)); 55 | float specular = dot(normal, halfVector); 56 | specular = max(0.0, specular); 57 | specular = pow(specular, 25.0); 58 | color = mix(color, vec3(0, 1.0, 1.0), 0.5 * specular); 59 | 60 | // Add more specular light for fun 61 | vec3 light2 = vec3(420.0, 510.0, 30.0); 62 | halfVector = normalize(normalize(cameraPosition - vPosition) + normalize(light2 - vPosition)); 63 | specular = dot(normal, halfVector); 64 | specular = max(0.0, specular); 65 | specular = pow(specular, 3.0); 66 | color = mix(color, vec3(1.0, 0.3, 0), 0.5 * specular); 67 | 68 | vec3 light3 = vec3(0.0, 0.0, 1000.0); 69 | halfVector = normalize(normalize(cameraPosition - vPosition) + normalize(light3 - vPosition)); 70 | specular = dot(normal, halfVector); 71 | specular = max(0.0, specular); 72 | specular = pow(specular, 130.0); 73 | color = mix(color, vec3(1.0, 0.5, 0), specular); 74 | 75 | // Add height fog 76 | float fogFactor = clamp( 1.0 - vPosition.z / 25.0, 0.0, 1.0 ); 77 | fogFactor = pow( fogFactor, 5.4 ); 78 | color = mix( color, vec3( 1.0, 0.9, 0.8 ), fogFactor ); 79 | 80 | // Add distance fog 81 | float depth = gl_FragCoord.z / gl_FragCoord.w; 82 | fogFactor = smoothstep( 300.0, 1000.0, depth ); 83 | //fogFactor = fogFactor * ( 1.0 - clamp( ( camH - 5.0 ) / 8.0, 0.0, 1.0 ) ); 84 | color = mix( color, vec3( 0, 0, 0 ), fogFactor ); 85 | 86 | gl_FragColor = vec4(color, 1.0); 87 | } 88 | -------------------------------------------------------------------------------- /js/shaders/terrain.vert: -------------------------------------------------------------------------------- 1 | uniform vec3 uGlobalOffset; 2 | uniform sampler2D uHeightData; 3 | uniform vec2 uTileOffset; 4 | uniform float uScale; 5 | 6 | varying vec3 vNormal; 7 | varying vec3 vPosition; 8 | varying float vMorphFactor; 9 | 10 | // Number of vertices along edge of tile 11 | #define TILE_RESOLUTION 128.0 12 | 13 | float getHeight(vec3 p) { 14 | // Assume a 1024x1024 world 15 | float lod = 0.0;//log2(uScale) - 6.0; 16 | vec2 st = p.xy / 1024.0; 17 | 18 | // Sample multiple times to get more detail out of map 19 | float h = 1024.0 * texture2DLod(uHeightData, st, lod).a; 20 | h += 64.0 * texture2DLod(uHeightData, 16.0 * st, lod).a; 21 | h += 4.0 * texture2DLod(uHeightData, 256.0 * st, lod).a; 22 | 23 | // Square the height, leads to more rocky looking terrain 24 | return h * h / 2000.0; 25 | //return h / 10.0; 26 | } 27 | 28 | vec3 getNormal() { 29 | // Get 2 vectors perpendicular to the unperturbed normal, and create at point at each (relative to position) 30 | //float delta = 1024.0 / 4.0; 31 | float delta = (vMorphFactor + 1.0) * uScale / TILE_RESOLUTION; 32 | vec3 dA = delta * normalize(cross(normal.yzx, normal)); 33 | vec3 dB = delta * normalize(cross(dA, normal)); 34 | vec3 p = vPosition; 35 | vec3 pA = vPosition + dA; 36 | vec3 pB = vPosition + dB; 37 | 38 | // Now get the height at those points 39 | float h = getHeight(vPosition); 40 | float hA = getHeight(pA); 41 | float hB = getHeight(pB); 42 | 43 | // Update the points with their correct heights and calculate true normal 44 | p += normal * h; 45 | pA += normal * hA; 46 | pB += normal * hB; 47 | return normalize(cross(pB - p, pA - p)); 48 | } 49 | 50 | #include edgemorph.glsl 51 | 52 | void main() { 53 | // Morph factor tells us how close we are to next level. 54 | // 0.0 is this level 55 | // 1.0 is next level 56 | vMorphFactor = calculateMorph(position); 57 | 58 | // Move into correct place 59 | vPosition = uScale * position + vec3(uTileOffset, 0.0) + uGlobalOffset; 60 | 61 | // Snap to grid 62 | float grid = uScale / TILE_RESOLUTION; 63 | vPosition = floor(vPosition / grid) * grid; 64 | 65 | // Morph between zoom layers 66 | if( vMorphFactor > 0.0 ) { 67 | // Get position that we would have if we were on higher level grid 68 | grid = 2.0 * grid; 69 | vec3 position2 = floor(vPosition / grid) * grid; 70 | 71 | // Linearly interpolate the two, depending on morph factor 72 | vPosition = mix(vPosition, position2, vMorphFactor); 73 | } 74 | 75 | // Get height and calculate normal 76 | vPosition = vPosition + normal * getHeight(vPosition); 77 | vNormal = getNormal(); 78 | //vNormal = normal; 79 | gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1.0); 80 | } 81 | -------------------------------------------------------------------------------- /js/shaders/terrainSnow.frag: -------------------------------------------------------------------------------- 1 | #extension GL_OES_standard_derivatives : enable 2 | uniform float uScale; 3 | uniform sampler2D uHeightData; 4 | 5 | uniform sampler2D uGrass; 6 | uniform sampler2D uRock; 7 | uniform sampler2D uSnow; 8 | 9 | varying float vMorphFactor; 10 | varying vec3 vNormal; 11 | varying vec3 vPosition; 12 | 13 | #include colorScale.glsl 14 | 15 | float getHeight( vec3 p ) { 16 | // Assume a 1024x1024 world 17 | vec2 st = p.xy / 1024.0; 18 | 19 | // Sample multiple times to get more detail out of map 20 | float h = 1024.0 * texture2D(uHeightData, st).a; 21 | h += 64.0 * texture2D(uHeightData, 16.0 * st).a; 22 | //h += 4.0 * texture2D(uHeightData, 256.0 * st).a; 23 | 24 | // Square the height, leads to more rocky looking terrain 25 | return h * h / 2000.0; 26 | } 27 | 28 | vec3 getNormal() { 29 | // Differentiate the position vector (this will give us two vectors perpendicular to the surface) 30 | // Before differentiating, add the displacement based on the height from the height map. By doing this 31 | // calculation here, rather than in the vertex shader, we get a per-fragment calculated normal, rather 32 | // than a per-vertex normal. This improves the look of distant low-vertex terrain. 33 | float height = getHeight( vPosition ); 34 | vec3 p = vec3(vPosition.xy, height); 35 | vec3 dPositiondx = dFdx(p); 36 | vec3 dPositiondy = dFdy(p); 37 | 38 | // The normal is the cross product of the differentials 39 | return normalize(cross(dPositiondx, dPositiondy)); 40 | } 41 | 42 | void main() { 43 | // Base color 44 | vec3 light = vec3(0.0, 850.0, 50.0); 45 | //vec3 color = colorForScale(uScale); 46 | vec3 normal = getNormal(); 47 | 48 | // Combine textures based on height and normal (use rougher normal from vertex shader) 49 | float texScale = 0.03; 50 | 51 | // Snow stick determines effect of normal on presence of snow 52 | float snowStick = dot( vec3( 0, 0, 1.0 ), normal ); 53 | snowStick = pow( snowStick, 3.0 ); 54 | snowStick = step( 0.2, snowStick ); 55 | float snowAlt = 20.0; 56 | 57 | vec3 grass = texture2D( uGrass, texScale * vPosition.xy ).rgb; 58 | vec3 rock = texture2D( uRock, texScale * vPosition.xy ).rgb; 59 | //vec3 snow = texture2D( uSnow, texScale * vPosition.xy ).rgb; 60 | vec3 snow = vec3( 0.93, 0.97, 1.0 ); 61 | //vec3 color = mix( grass, rock, smoothstep( 7.0, 14.0, vPosition.z ) ); 62 | //vec3 color = mix( rock, snow, smoothstep( snowAlt, snowAlt + 10.0, snowAlt + snowStick * ( vPosition.z - snowAlt ) ) ); 63 | vec3 color = mix( rock, snow, snowStick ); 64 | //color = vec3(vMorphFactor); 65 | 66 | 67 | // Incident light (generate shadows and highlights) 68 | float incidence = dot(normalize(light - vPosition), vNormal); 69 | incidence = clamp(incidence, 0.0, 1.0); 70 | float shadowFactor = pow(incidence, 0.72); 71 | shadowFactor = 0.03 + 0.97 * shadowFactor; 72 | color = mix( vec3( 0, 0, 0 ), color, shadowFactor ); 73 | color = mix( color, vec3( 0.81, 0.9, 1.0 ), 0.2 * shadowFactor ); 74 | 75 | // Fade out based on distance 76 | //color = mix( color, vec3( 0, 0, 0 ), smoothstep( 350.0, 500.0, distance( light, vPosition ) ) ); 77 | 78 | // Mix in specular light 79 | vec3 halfVector = normalize(normalize(cameraPosition - vPosition) + normalize(light - vPosition)); 80 | float specular = dot(normal, halfVector); 81 | specular = max(0.0, specular); 82 | specular = pow(specular, 25.0); 83 | //color = mix(color, vec3(0.1, 0.8, 1.0), 0.5 * specular); 84 | 85 | // Add height fog 86 | float fogFactor = clamp( 1.0 - vPosition.z / 155.0, 0.0, 1.0 ); 87 | fogFactor = 0.96 * pow( fogFactor, 5.4 ); 88 | float fogAngle = dot( normalize( cameraPosition - vPosition ), normalize( vPosition - light ) ); 89 | fogAngle = smoothstep( 0.0, 1.0, fogAngle ); 90 | //vec3 fogColor = mix( vec3( 0.86, 0.95, 1.0 ), vec3( 0.98, 0.77, 0.33), fogAngle ); 91 | vec3 fogColor = vec3( 0.86, 0.95, 1.0 ); 92 | color = mix( color, fogColor, fogFactor ); 93 | 94 | // Add distance fog 95 | float depth = gl_FragCoord.z / gl_FragCoord.w; 96 | fogFactor = smoothstep( 300.0, 1000.0, depth ); 97 | //fogFactor = fogFactor * ( 1.0 - clamp( ( camH - 5.0 ) / 8.0, 0.0, 1.0 ) ); 98 | fogColor = mix( vec3( 1.0, 0.945, 0.847 ), vec3( 0.98, 0.77, 0.33), fogAngle ); 99 | color = mix( color, fogColor, fogFactor ); 100 | 101 | gl_FragColor = vec4(color, 1.0 - fogFactor); 102 | } 103 | -------------------------------------------------------------------------------- /js/shaders/terrainToon.frag: -------------------------------------------------------------------------------- 1 | #extension GL_OES_standard_derivatives : enable 2 | uniform float uScale; 3 | uniform sampler2D uHeightData; 4 | 5 | varying float vMorphFactor; 6 | varying vec3 vNormal; 7 | varying vec3 vPosition; 8 | 9 | #include colorScale.glsl 10 | 11 | float getHeight( vec3 p ) { 12 | // Assume a 1024x1024 world 13 | vec2 st = p.xy / 1024.0; 14 | 15 | // Sample multiple times to get more detail out of map 16 | float h = 1024.0 * texture2D(uHeightData, st).a; 17 | h += 64.0 * texture2D(uHeightData, 16.0 * st).a; 18 | //h += 4.0 * texture2D(uHeightData, 256.0 * st).a; 19 | 20 | // Square the height, leads to more rocky looking terrain 21 | return h * h / 2000.0; 22 | } 23 | 24 | void main() { 25 | // Base color 26 | vec3 light = vec3( 400.0, 850.0, 50.0 ); 27 | //vec3 color = colorForScale(uScale); 28 | 29 | // Combine textures based on height and normal (use rougher normal from vertex shader) 30 | float texScale = 0.03; 31 | 32 | // Grass stick determines effect of normal on presence of grass 33 | float grassStick = dot( vec3( 0, 0, 1.0 ), vNormal ); 34 | grassStick = pow( grassStick, 3.0 ); 35 | grassStick = step( 0.2, grassStick ); 36 | 37 | vec3 water = vec3( 0.23, 0.08, 0.345 ); 38 | vec3 grass = vec3( 0.12, 0.87, 0.14 ); 39 | vec3 rock = vec3( 0.31, 0.11, 0.09 ); 40 | vec3 color = mix( water, grass, smoothstep( 7.0, 14.0, vPosition.z ) ); 41 | color = mix( rock, color, grassStick ); 42 | 43 | // Incident light (generate shadows and highlights) 44 | float incidence = dot(normalize(light - vPosition), vNormal); 45 | incidence = clamp(incidence, 0.0, 1.0); 46 | float shadowFactor = pow(incidence, 0.01); // use 0.02 for cartoony shadows 47 | shadowFactor = 0.03 + 0.97 * shadowFactor; 48 | color = mix( vec3( 0, 0, 0 ), color, shadowFactor ); 49 | color = mix( color, vec3( 0.81, 0.9, 1.0 ), 0.2 * shadowFactor ); 50 | 51 | // Add height fog 52 | float fogFactor = smoothstep( 10.0, 8.0, vPosition.z ); 53 | fogFactor = 0.93 * pow( fogFactor, 1.4 ); 54 | //vec3 fogColor = mix( vec3( 0.86, 0.95, 1.0 ), vec3( 0.98, 0.77, 0.33), fogAngle ); 55 | vec3 fogColor = vec3( 0.0, 0.6 + 0.4 * smoothstep( 3.0, 10.0, vPosition.z ), 0.935 ); 56 | color = mix( color, fogColor, fogFactor ); 57 | 58 | // Add distance fog 59 | float depth = gl_FragCoord.z / gl_FragCoord.w; 60 | fogFactor = smoothstep( 500.0, 1200.0, depth ); 61 | fogColor = vec3( 0.8, 0.945, 1.0 ); 62 | color = mix( color, fogColor, fogFactor ); 63 | 64 | gl_FragColor = vec4(color, 1.0 - fogFactor); 65 | } 66 | -------------------------------------------------------------------------------- /js/textures/README.md: -------------------------------------------------------------------------------- 1 | rock.jpg texture taken from http://opengameart.org/content/terrain-textures-pack-from-stunt-rally-23 (CC0 - Public domain) 2 | -------------------------------------------------------------------------------- /js/textures/rock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/js/textures/rock.jpg -------------------------------------------------------------------------------- /js/textures/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/js/textures/sky.png -------------------------------------------------------------------------------- /presentation/License.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright © 2010–2014 Vadim Makeev, http://pepelsbey.net/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | --- 12 | 13 | # Лицензия MIT 14 | 15 | Copyright © 2010–2014 Вадим Макеев, http://pepelsbey.net/ 16 | 17 | Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, также как и лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий: 18 | 19 | Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения. 20 | 21 | ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. -------------------------------------------------------------------------------- /presentation/Readme.md: -------------------------------------------------------------------------------- 1 | # Shower HTML presentation engine 2 | 3 | Follow [@shower_me](https://twitter.com/shower_me) for support and updates 4 | 5 | To see Shower in action: 6 | 7 | - Open [shwr.me](http://shwr.me/) 8 | - Click any slide to enter presentation mode 9 | - Use arrow keys or presenter remote to navigate 10 | - Press `Esc` to exit presentation mode 11 | 12 | See [Wiki](https://github.com/shower/shower/wiki) for more information how to use Shower. 13 | 14 | ## Using Shower 15 | 16 | There are two ways of making presentation using Shower: you can just download an archive with all you need or you can install needed Shower modules using [npm](https://www.npmjs.org) or [bower](http://bower.io). 17 | 18 | ### Simple Way 19 | 20 | In a simple way you just download the latest Shower version with built-in themes and use it. 21 | 22 | 1. Download and unarchive [shower.zip](http://shwr.me/shower.zip) 23 | 2. Open `index.html` in any code or text editor, edit your slides in HTML 24 | 3. Use `pictures` folder for pictures used in presentation 25 | 4. Once finished, open `index.html` in a browser, enter full screen and start presenting 26 | 27 | ### Advanced Way 28 | 29 | Advanced way allows you to manually install needed Shower packages and requires [Node.js](http://nodejs.org/) installed together with package managment system: `npm` or `bower`. 30 | 31 | 1. Run `npm install shower-core shower-ribbon` 32 | 2. Link core and theme files in `node_modules` folder to your presentation file 33 | 3. You’re probably know what to do next, it’s an advanced way. 34 | 35 | **Note:** you can use `bower` instead of `npm` or `shower-bright` instead of `shower-ribbon` in command above to install Shower using Bower or get Bright theme. 36 | 37 | ## Usage examples 38 | 39 | - [Clear and Sharp](http://pepelsbey.net/pres/clear-and-sharp/) 40 | - [CSS Management](http://pepelsbey.net/pres/knife-train/) 41 | - [Push it!](http://pepelsbey.net/pres/push-it/) 42 | - [Pre-fixes](http://pepelsbey.net/pres/pre-fixes/) 43 | - [Web In Curves](http://pepelsbey.net/pres/web-in-curves/) 44 | - [Sense Coding](http://pepelsbey.net/pres/sense-coding/) 45 | 46 | ## Browser support 47 | 48 | Latest stable versions of Chrome, Internet Explorer, Firefox, Opera and Safari are supported. 49 | 50 | ## Contributing 51 | 52 | You’re always welcome to contibute. Fork project, make changes and send it as pull request. But it’s better to file an [issue](https://github.com/shower/shower/issues) with your idea first. Read [contributing rules](https://github.com/shower/shower/blob/master/Contributing.md) for more details. 53 | 54 | Main contributors: [pepelsbey](https://github.com/pepelsbey), [jahson](https://github.com/jahson), [miripiruni](https://github.com/miripiruni), [kizu](https://github.com/kizu), [artpolikarpov](https://github.com/artpolikarpov), [tonyganch](https://github.com/tonyganch). 55 | 56 | --- 57 | Licensed under [MIT License](http://en.wikipedia.org/wiki/MIT_License), see [license page](https://github.com/shower/shower/wiki/MIT-License) for details. -------------------------------------------------------------------------------- /presentation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rendering large terrains in WebGL 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Rendering large terrains in WebGL

13 |

Felix Palmer - @pheeelicks

14 |
15 |
16 |

Rendering large terrains in WebGL

17 |

Felix Palmer | @pheeelicks | www.pheelicks.com

18 | 19 | 23 | 41 |
42 |
43 |

Talk overview

44 |
    45 |
  1. Crash course on WebGL shaders
  2. 46 |
  3. Basic approach to problem
  4. 47 |
  5. Using a recursive tile pattern
  6. 48 |
  7. Using a dynamic mesh
  8. 49 |
  9. Questions? Feel free to ask during talk too!
  10. 50 |
51 |

Talk is based on blog post that can be found on www.pheelicks.com

52 |
53 |
54 |

DEMO

55 |

felixpalmer.github.io/lod-terrain/

56 |
57 |
58 |

WebGL graphics pipeline

59 |
    60 |
  1. Geometry is defined in JavaScript and sent to GPU
  2. 61 |
  3. Vertex shader is invoked on every vertex, allowing it to be moved
  4. 62 |
  5. Fragment (pixel) shader is invoked on each pixel to be drawn
  6. 63 |
64 |

In this talk we'll be looking at the geometry and the vertex shader

65 |
66 |
67 | 68 |

Let the graphics card do the work!

69 |
70 |
71 |

Simple grid approach

72 |
    73 |
  • Just have a uniform grid of points across the entire map
  • 74 |
  • Pros: 75 |
      76 |
    • Simple
    • 77 |
    78 |
  • 79 |
  • Cons: 80 |
      81 |
    • Not enough detail in the foreground
    • 82 |
    • Too much detail in in the background
    • 83 |
    84 |
  • 85 |
86 |
87 |
88 |

DEMO

89 |
90 |
91 |

Arrange tiles in concentric shells

92 | 93 |
94 |
95 |

Arrange tiles in concentric shells

96 | 97 |
98 |
99 |

DEMO

100 |
101 |
102 |

Moving around the terrain

103 |
    104 |
  • Terrain geometry is static relative to camera
  • 105 |
  • Data underlying visulazation is changing
  • 106 |
  • Terrain data is "flowing" through the vertices
  • 107 |
  • If we do not have enough vertices, terrain will "shake"
  • 108 |
109 |
110 |
111 |

DEMO

112 |
113 |
114 |

How to fix shaking

115 |
    116 |
  • Snap each vertex to a grid, such that the grid spacing is equal to the vertex spacing
  • 117 |
  • Snapping will be inperceptable as vertices are equally spaced
  • 118 |
  • There's just one problem...
  • 119 |
120 |
121 |
122 |

Seams between layers

123 |
    124 |
  • By fixing the shaking we've introduced seams between the layers
  • 125 |
  • Seams appear because each shell is snapping to a grid of different resolution
  • 126 |
  • How to fix?
  • 127 |
128 |
129 |
130 |

DEMO

131 | 132 |
133 |
134 |

Morphing grid snapping between layers

135 |
    136 |
  • Over a short distance between shells, gradually morph the grid to snap to
  • 137 |
138 |
139 |
140 |

DEMO

141 | 142 |
143 |
144 |

Questions?

145 |

http://www.github.com/felixpalmer/lod-terrain

146 |

http://felixpalmer.github.io/lod-terrain/

147 |

Felix Palmer | @pheeelicks | www.pheelicks.com

148 |
149 |
150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /presentation/pictures/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/cover.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_close.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_final.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_intro.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_lod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_lod.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_morph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_morph.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_seams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_seams.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_shells.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_shells.png -------------------------------------------------------------------------------- /presentation/pictures/lod_terrain_shells_perspective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/pictures/lod_terrain_shells_perspective.png -------------------------------------------------------------------------------- /presentation/shower/License.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright © 2010–2014 Vadim Makeev, http://pepelsbey.net/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | --- 12 | 13 | # Лицензия MIT 14 | 15 | Copyright © 2010–2014 Вадим Макеев, http://pepelsbey.net/ 16 | 17 | Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, также как и лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий: 18 | 19 | Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения. 20 | 21 | ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. -------------------------------------------------------------------------------- /presentation/shower/Readme.md: -------------------------------------------------------------------------------- 1 | # Core for Shower HTML presentation engine 2 | 3 | Follow [@shower_me](https://twitter.com/shower_me) for support and updates 4 | 5 | To see Shower in action: 6 | 7 | - Open [shwr.me](http://shwr.me/) 8 | - Click any slide to enter presentation mode 9 | - Use arrow keys or presenter remote to navigate 10 | - Press `Esc` to exit presentation mode 11 | 12 | Part of [Shower presentation template](https://github.com/shower/shower/). See [Wiki](https://github.com/shower/shower/wiki) for more information how to use Shower. 13 | 14 | --- 15 | Licensed under [MIT License](http://en.wikipedia.org/wiki/MIT_License), see [license page](https://github.com/shower/shower/wiki/MIT-License) for details. -------------------------------------------------------------------------------- /presentation/shower/shower.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Shower HTML presentation engine: github.com/shower/shower 3 | * @copyright 2010–2014 Vadim Makeev, pepelsbey.net 4 | * @license MIT license: github.com/shower/shower/wiki/MIT-License 5 | */ 6 | window.shower&&window.shower.init||(window.shower=function(a,b,c){function d(a){for(var b in a)a.hasOwnProperty(b)&&(this[b]=a[b])}var e,f={},g=a.location,h=b.body,i=[],j=[],k=!(!a.history||!a.history.pushState);return d.prototype={getSlideNumber:function(){return this.number},isLast:function(){return f.slideList.length===this.number+1},isFinished:function(){return this.innerComplete>=this.innerLength},process:function(a){return this.timing?(this.initTimer(a),this):(this.next(a),this)},initTimer:function(a){var b=this;return b.timing?(b.stopTimer(),e=b.isFinished()?setInterval(function(){b.stopTimer(),a.next()},b.timing*(b.innerLength||1)):setInterval(function(){b.isFinished()?(b.stopTimer(),a.next()):b.next(a)},b.timing),this):!1},stopTimer:function(){return e&&(clearInterval(e),e=!1),this},prev:function(a){var c,d=this;return!d.hasInnerNavigation||d.isFinished()||0===d.innerComplete?(a.prev(),!1):(c=b.getElementById(d.id).querySelectorAll(".next.active"),!c||c.length<1?!1:(d.innerComplete>0?(d.innerComplete--,c[c.length-1].classList.remove("active")):a.prev(),this))},next:function(a){var c,d=this;return!d.hasInnerNavigation||d.isFinished()?(a.next(),!1):(d.isFinished()||(c=b.getElementById(d.id).querySelectorAll(".next:not(.active)"),c[0].classList.add("active"),d.innerComplete++),this)}},f._getData=function(a,b){return a.dataset?a.dataset[b]:a.getAttribute("data-"+b)},f.slideList=[],f.init=function(a,c){var e;a=a||".slide",c=c||"div.progress div",i=b.querySelectorAll(a),j=b.querySelector(c);for(var g=0;ga&&(a=0),a>=f.slideList.length&&(a=f.slideList.length-1),a},f._getSlideIdByEl=function(a){for(;"BODY"!==a.nodeName&&"HTML"!==a.nodeName;){if(a.classList.contains("slide"))return a.id;a=a.parentNode}return""},f._checkInteractiveElement=function(a){return"A"===a.target.nodeName},f.getSlideNumber=function(a){var b,c=f.slideList.length-1;for(""===a&&(b=0);c>=0;--c)if(a===f.slideList[c].id){b=c;break}return b},f.go=function(a,b){var c;if(!f._isNumber(a))throw new Error("Gimme slide number as Number, baby!");return f.slideList[a]?(g.hash=f.getSlideHash(a),f.updateProgress(a),f.updateActiveAndVisitedSlides(a),f.isSlideMode()&&(f.showPresenterNotes(a),c=f.slideList[a],c.timing&&c.initTimer(f)),"function"==typeof b&&b(),a):!1},f.next=function(a){var b=f.getCurrentSlideNumber(),c=f.slideList[b+1];return c?(f.go(b+1),"function"==typeof a&&a(),this):!1},f._turnNextSlide=function(a){var b=f.getCurrentSlideNumber(),c=f.slideList[b];f.isSlideMode()?(c.stopTimer(),c.next(f)):f.go(b+1),"function"==typeof a&&a()},f.prev=f.previous=function(a){var b=f.getCurrentSlideNumber();return 1>b?!1:(f.go(b-1),"function"==typeof a&&a(),!0)},f._turnPreviousSlide=function(a){var b=f.getCurrentSlideNumber(),c=f.slideList[b];return c.stopTimer(),f.isSlideMode()?c.prev(f):f.go(b-1),"function"==typeof a&&a(),!0},f.first=function(a){var b=f.slideList[f.getCurrentSlideNumber()];b&&b.timing&&b.stopTimer(),f.go(0),"function"==typeof a&&a()},f.last=function(a){var b=f.slideList[f.getCurrentSlideNumber()];b&&b.timing&&b.stopTimer(),f.go(f.slideList.length-1),"function"==typeof a&&a()},f.enterSlideMode=function(a){var b=f.getCurrentSlideNumber();return h.classList.remove("list"),h.classList.add("full"),f.isListMode()&&k&&history.pushState(null,null,g.pathname+"?full"+f.getSlideHash(b)),f._applyTransform(f._getTransform()),"function"==typeof a&&a(),!0},f.enterListMode=function(a){var b;return h.classList.remove("full"),h.classList.add("list"),f.clearPresenterNotes(),f._applyTransform("none"),f.isListMode()?!1:(b=f.getCurrentSlideNumber(),f.slideList[b].stopTimer(),f.isSlideMode()&&k&&history.pushState(null,null,g.pathname+f.getSlideHash(b)),f.scrollToSlide(b),"function"==typeof a&&a(),!0)},f.toggleMode=function(a){return f.isListMode()?f.enterSlideMode():f.enterListMode(),"function"==typeof a&&a(),!0},f.getCurrentSlideNumber=function(){var a=f.slideList.length-1,b=g.hash.substr(1);if(""===b)return-1;for(;a>=0;--a)if(b===f.slideList[a].id)return a;return 0},f.scrollToSlide=function(c){var d,e=!1;if(!f._isNumber(c))throw new Error("Gimme slide number as Number, baby!");if(f.isSlideMode())throw new Error("You can't scroll to because you in slide mode. Please, switch to list mode.");if(-1===c)return e;if(!f.slideList[c])throw new Error("There is no slide with number "+c);return d=b.getElementById(f.slideList[c].id),a.scrollTo(0,d.offsetTop),e=!0,e},f.isListMode=function(){return k?!/^full.*/.test(g.search.substr(1)):h.classList.contains("list")},f.isSlideMode=function(){return k?/^full.*/.test(g.search.substr(1)):h.classList.contains("full")},f.updateProgress=function(a){if(null===j)return!1;if(!f._isNumber(a))throw new Error("Gimme slide number as Number, baby!");return j.style.width=(100/(f.slideList.length-1)*f._normalizeSlideNumber(a)).toFixed(2)+"%",!0},f.updateActiveAndVisitedSlides=function(a){var c,d,e=f.slideList.length;if(a=f._normalizeSlideNumber(a),!f._isNumber(a))throw new Error("Gimme slide number as Number, baby!");for(c=0;e>c;++c)d=b.getElementById(f.slideList[c].id),a>c?(d.classList.remove("active"),d.classList.add("visited")):c>a?(d.classList.remove("visited"),d.classList.remove("active")):(d.classList.remove("visited"),d.classList.add("active"));return!0},f.clearPresenterNotes=function(){f.isSlideMode()&&a.console&&a.console.clear&&console.clear()},f.showPresenterNotes=function(c){if(f.clearPresenterNotes(),a.console){c=f._normalizeSlideNumber(c);var d=f.slideList[c].id,e=f.slideList[c+1]?f.slideList[c+1].id:null,g=b.getElementById(d).querySelector("footer");if(g&&g.innerHTML&&console.info(g.innerHTML.replace(/\n\s+/g,"\n")),e){var h=b.getElementById(e).querySelector("h2");h&&(h=h.innerHTML.replace(/^\s+|<[^>]+>/g,""),console.info("NEXT: "+h))}}},f.getSlideHash=function(a){if(!f._isNumber(a))throw new Error("Gimme slide number as Number, baby!");return a=f._normalizeSlideNumber(a),"#"+f.slideList[a].id},f.wheel=function(a){var d,e=b.querySelector("body"),g="locked"===e.getAttribute("data-scroll");g||f.isListMode()||(e.setAttribute("data-scroll","locked"),d=a.deltaY===c?a.detail?a.wheelDeltaY/a.detail/120*a.detail>0?1:-1:a.wheelDeltaY/10:-a.deltaY,0>d?f._turnNextSlide():f._turnPreviousSlide(),setTimeout(function(){e.setAttribute("data-scroll","unlocked")},Math.abs(d)>3?200:800))},a.addEventListener("DOMContentLoaded",function(){var a=f.getCurrentSlideNumber(),b=h.classList.contains("full")||f.isSlideMode();-1===a&&b?f.go(0):(0===a||b)&&f.go(a),b&&f.enterSlideMode()},!1),a.addEventListener("popstate",function(){var a=f.getCurrentSlideNumber();-1!==a&&f.go(a),f.isListMode()?f.enterListMode():f.enterSlideMode()},!1),a.addEventListener("resize",function(){f.isSlideMode()&&f._applyTransform(f._getTransform())},!1),b.addEventListener("keydown",function(a){var b,c=f.getCurrentSlideNumber(),d=f.slideList[-1!==c?c:0];switch(a.which){case 80:f.isListMode()&&a.altKey&&a.metaKey&&(a.preventDefault(),b=d.number,f.go(b),f.enterSlideMode(),f.showPresenterNotes(b),d.timing&&d.initTimer(f));break;case 116:a.preventDefault(),f.isListMode()?(b=a.shiftKey?d.number:0,f.go(b),f.enterSlideMode(),f.showPresenterNotes(b),d.timing&&d.initTimer(f)):f.enterListMode();break;case 13:f.isListMode()&&-1!==c&&(a.preventDefault(),f.enterSlideMode(),f.showPresenterNotes(c),d.timing&&d.initTimer(f));break;case 27:f.isSlideMode()&&(a.preventDefault(),f.enterListMode());break;case 33:case 38:case 37:case 72:case 75:if(a.altKey||a.ctrlKey||a.metaKey)return;a.preventDefault(),f._turnPreviousSlide();break;case 34:case 40:case 39:case 76:case 74:if(a.altKey||a.ctrlKey||a.metaKey)return;a.preventDefault(),f._turnNextSlide();break;case 36:a.preventDefault(),f.first();break;case 35:a.preventDefault(),f.last();break;case 9:case 32:a.preventDefault(),f[a.shiftKey?"_turnPreviousSlide":"_turnNextSlide"]()}},!1),f.init(),b.addEventListener("click",function(a){var b,c,d=f._getSlideIdByEl(a.target);d&&f.isListMode()&&(b=f.getSlideNumber(d),f.go(b),f.enterSlideMode(),f.showPresenterNotes(b),c=f.slideList[b],c.timing&&c.initTimer(f))},!1),b.addEventListener("touchstart",function(b){var c,d,e,g=f._getSlideIdByEl(b.target);g&&(f.isSlideMode()&&!f._checkInteractiveElement(b)&&(e=b.touches[0].pageX,e>a.innerWidth/2?f._turnNextSlide():f._turnPreviousSlide()),f.isListMode()&&(c=f.getSlideNumber(g),f.go(c),f.enterSlideMode(),f.showPresenterNotes(c),d=f.slideList[c],d.timing&&d.initTimer(f)))},!1),b.addEventListener("touchmove",function(a){f.isSlideMode()&&a.preventDefault()},!1),b.addEventListener("wheel",f.wheel,!1),b.addEventListener("mousewheel",f.wheel,!1),f}(this,this.document)); -------------------------------------------------------------------------------- /presentation/shower/themes/bright/License.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright © 2010–2014 Vadim Makeev, http://pepelsbey.net/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | --- 12 | 13 | # Лицензия MIT 14 | 15 | Copyright © 2010–2014 Вадим Макеев, http://pepelsbey.net/ 16 | 17 | Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, также как и лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий: 18 | 19 | Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения. 20 | 21 | ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. -------------------------------------------------------------------------------- /presentation/shower/themes/bright/Readme.md: -------------------------------------------------------------------------------- 1 | # Bright theme for Shower HTML presentation engine 2 | 3 | Follow [@shower_me](https://twitter.com/shower_me) for support and updates 4 | 5 | To see Bright theme for Shower in action: 6 | 7 | - Open [shwr.me/shower/themes/bright](http://shwr.me/shower/themes/bright/) 8 | - Click any slide to enter presentation mode 9 | - Use arrow keys or presenter remote to navigate 10 | - Press `Esc` to exit presentation mode 11 | 12 | Part of [Shower presentation template](https://github.com/shower/shower/). See [Wiki](https://github.com/shower/shower/wiki) for more information how to use Shower. 13 | 14 | --- 15 | Licensed under [MIT License](http://en.wikipedia.org/wiki/MIT_License), see [license page](https://github.com/shower/shower/wiki/MIT-License) for details. 16 | -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/Anka.Coder.Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/Anka.Coder.Italic.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/Anka.Coder.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/Anka.Coder.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/OpenSans.Bold.Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/OpenSans.Bold.Italic.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/OpenSans.Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/OpenSans.Bold.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/OpenSans.Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/OpenSans.Italic.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/OpenSans.Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/OpenSans.Light.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/fonts/OpenSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/fonts/OpenSans.woff -------------------------------------------------------------------------------- /presentation/shower/themes/bright/images/grid-16x10.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /presentation/shower/themes/bright/images/grid-4x3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /presentation/shower/themes/bright/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bright theme for Shower 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 |
16 |

Presentation Title

17 |

Yours Truly, Famous Inc.

18 |
19 |
20 |

Header

21 |

Typewriter etsy messenger bag fingerstache, aesthetic vinyl semiotics twee DIY forage chillwave. Thundercats ennui messenger bag, squid carles chillwave shoreditch pickled cliche letterpress. DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub1 kale H20 chips. Ennui keffiyeh thundercats jean shorts biodiesel. Terry richardson, swag blog locavore umami vegan helvetica. Fingerstache kale chips.

22 |
23 | Typewriter etsy messenger bag fingerstache. 24 |
25 |
26 |
27 |

Header

28 |

DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub kale chips. Ennui keffiyeh thundercats jean shorts biodiesel.

29 |

Typewriter etsy messenger bag fingerstache, aesthetic vinyl semiotics twee DIY forage chillwave. Thundercats ennui messenger bag, squid carles chillwave shoreditch pickled cliche letterpress.

30 |
31 | DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub kale chips. Ennui keffiyeh thundercats jean shorts biodiesel. 32 |
33 |
34 |
35 |

Lists in English typography

36 |
    37 |
  • Ennui keffiyeh thundercats
  • 38 |
  • Jean shorts biodiesel
  • 39 |
  • Terry richardson, swag blog 40 |
      41 |
    1. Locavore umami vegan helvetica
    2. 42 |
    3. Fingerstache kale chips
    4. 43 |
    5. Keytar sriracha gluten-free
    6. 44 |
    45 |
  • 46 |
  • Before they sold out master
  • 47 |
48 |
49 |
50 |

Lists in Russian typography

51 |
    52 |
  • Ennui keffiyeh thundercats
  • 53 |
  • Jean shorts biodiesel
  • 54 |
  • Terry richardson, swag blog 55 |
      56 |
    1. Locavore umami vegan helvetica
    2. 57 |
    3. Fingerstache kale chips
    4. 58 |
    5. Keytar sriracha gluten-free
    6. 59 |
    60 |
  • 61 |
  • Before they sold out master
  • 62 |
63 |
64 |
65 |

Lists in English typography

66 |
    67 |
  1. Locavore umami vegan helvetica
  2. 68 |
  3. Fingerstache kale chips
  4. 69 |
  5. Keytar sriracha gluten-free
  6. 70 |
71 |
    72 |
  • Ennui keffiyeh thundercats
  • 73 |
  • Jean shorts biodiesel
  • 74 |
  • Terry richardson, swag blog
  • 75 |
76 |
77 |
78 |

Quote

79 |
80 |
81 |

Typewriter etsy messenger bag fingerstache, aesthetic vinyl semiotics twee DIY forage chillwave. Thundercats ennui messenger bag, squid carles chillwave shoreditch pickled cliche letterpress.

82 |
83 |
Author Name
84 |
85 |

DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub kale chips.

86 |
87 |
88 |

Table

89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
LocavoreUmamiHelveticaVegan
FingerstacheKaleChipsKeytar
SrirachaGluten-freeEnnuiKeffiyeh
ThundercatsJeanShortsBiodiesel
TerryRichardsonSwagBlog
121 |

Typewriter etsy messenger bag fingerstache.

122 |
123 |
124 |

Numbered code listing

125 |
126 | 			<html lang="en">
127 | 			<head> <!--Comment-->
128 | 			    <title>Shower</title>
129 | 			    <meta charset="UTF-8">
130 | 			    <link rel="stylesheet" href="s/screen.css">
131 | 			    <script src="j/jquery.js"></script>
132 | 			</head>
133 | 		
134 |
135 |
136 |

Plain code listing

137 |
<html lang="en">
138 | <head> <!--Comment-->
139 | 	<title>Shower</title>
140 | 	<meta charset="UTF-8">
141 | 	<link rel="stylesheet" href="s/screen.css">
142 | 	<script src="j/jquery.js"></script>
143 | </head>
144 |
145 |
146 |

147 | You Can
148 | Shout This Way 149 |

150 |
151 | Typewriter etsy messenger bag fingerstache. 152 |
153 |
154 |
155 |

Linked Shout

156 |
157 |
158 |

Sliding Right

159 |
160 |
161 |

Sliding Up

162 |
163 |
164 | 165 |
166 |
167 | 168 |
169 |
170 | 171 |
172 | Typewriter etsy messenger bag fingerstache. 173 |
174 |
175 |
176 | 177 |
178 |
179 | 180 |
181 |
182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 |
192 |
193 |

Timer

194 |

Three seconds to go.

195 |
196 |
197 |

List navigation

198 |
    199 |
  1. Ennui keffiyeh thundercats
  2. 200 | 201 | 202 | 203 | 204 |
205 |

Before they sold out master

206 |
207 |

Fork me on Github

208 | 212 |
213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /presentation/shower/themes/bright/pictures/exact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/pictures/exact.png -------------------------------------------------------------------------------- /presentation/shower/themes/bright/pictures/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/pictures/square.png -------------------------------------------------------------------------------- /presentation/shower/themes/bright/pictures/tall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/pictures/tall.png -------------------------------------------------------------------------------- /presentation/shower/themes/bright/pictures/wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/bright/pictures/wide.png -------------------------------------------------------------------------------- /presentation/shower/themes/bright/styles/screen.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Bright theme for Shower HTML presentation engine: github.com/shower/bright 3 | * Copyright © 2010–2014 Vadim Makeev, pepelsbey.net 4 | * Licensed under MIT license: github.com/shower/shower/wiki/MIT-License 5 | */ 6 | @font-face{font-family:'Open Sans';src:url(../fonts/OpenSans.woff) format("woff")}@font-face{font-weight:700;font-family:'Open Sans';src:url(../fonts/OpenSans.Bold.woff) format("woff")}@font-face{font-style:italic;font-family:'Open Sans';src:url(../fonts/OpenSans.Italic.woff) format("woff")}@font-face{font-style:italic;font-weight:700;font-family:'Open Sans';src:url(../fonts/OpenSans.Bold.Italic.woff) format("woff")}@font-face{font-family:'Open Sans Light';src:url(../fonts/OpenSans.Light.woff) format("woff")}@font-face{font-family:'Anka Coder';src:url(../fonts/Anka.Coder.woff) format("woff")}@font-face{font-style:italic;font-family:'Anka Coder';src:url(../fonts/Anka.Coder.Italic.woff) format("woff")}html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0}body{counter-reset:slide;font:24px/2 'Open Sans',sans-serif}a{color:#52a2df;background:-webkit-gradient(linear,left bottom,left top,from(currentColor),color-stop(.09em,currentColor),color-stop(.09em,transparent),to(transparent))repeat-x;background:-webkit-linear-gradient(bottom,currentColor,currentColor .09em,transparent .09em,transparent)repeat-x;background:linear-gradient(to top,currentColor,currentColor .09em,transparent .09em,transparent)repeat-x;text-decoration:none}.caption{display:none;margin:0 0 60px;padding:0 50px 0 0;color:#555}.caption h1{font:50px 'Open Sans Light',sans-serif}.badge{position:absolute;top:0;right:0;display:none;overflow:hidden;visibility:hidden;width:11em;height:11em;line-height:2.5;font-size:15px}.badge a{position:absolute;bottom:50%;right:-50%;left:-50%;visibility:visible;background:#52a2df;color:#FFF;text-align:center;-webkit-transform-origin:50% 100%;-ms-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transform:rotate(45deg)translateY(-1em);-ms-transform:rotate(45deg)translateY(-1em);transform:rotate(45deg)translateY(-1em)}.slide{position:relative;width:1024px;height:640px;background:#FFF;color:#000;-webkit-print-color-adjust:exact;-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none}.slide:after{position:absolute;right:0;bottom:45px;left:0;color:#AAA;counter-increment:slide;content:counter(slide);text-align:center;line-height:1}.slide>div{position:absolute;top:0;left:0;overflow:hidden;padding:100px 96px 0 128px;width:800px;height:540px}.slide h2{margin:0 0 58px;font:48px/1 'Open Sans Light',sans-serif}.slide p{margin:0 0 48px}.slide a{color:#52a2df}.slide b,.slide strong{font-weight:700}.slide i,.slide em{font-style:italic}.slide kbd,.slide code,.slide samp{padding:2px 7px;background:rgba(0,0,0,.1);-moz-tab-size:4;-o-tab-size:4;tab-size:4;line-height:1;font-family:'Anka Coder',monospace}.slide sub,.slide sup{position:relative;line-height:0;font-size:75%}.slide sub{bottom:-.25em}.slide sup{top:-.5em}.slide blockquote{font-style:italic}.slide blockquote:before{position:absolute;margin:-50px 0 0 -100px;color:#DDD;content:'\201C';line-height:1;font-size:200px}.slide blockquote+figcaption{margin:-48px 0 48px;font-style:italic;font-weight:700}.slide ol,.slide ul{margin:0 0 48px;counter-reset:list}.slide ol li,.slide ul li{text-indent:-2em}.slide ol li:before,.slide ul li:before{display:inline-block;width:2em;color:#AAA;text-align:right}.slide ol ol,.slide ol ul,.slide ul ol,.slide ul ul{margin:0 0 0 2em}.slide ul>li:before{content:'\2022\00A0\00A0\2009'}.slide ul>li:lang(ru):before{content:'\2014\00A0\2009'}.slide ol>li:before{counter-increment:list;content:counter(list)".\00A0\2009"}.slide pre{margin:0 0 45px;padding:3px 0 0;counter-reset:code;white-space:normal}.slide pre code{display:block;padding:0;background:0 0;white-space:pre;line-height:2}.slide pre code:before{position:absolute;margin-left:-50px;color:#AAA;counter-increment:code;content:counter(code,decimal-leading-zero)"."}.slide pre code:only-child:before{content:''}.slide pre mark{background:0 0;color:#52a2df;font-style:normal}.slide pre mark.important{padding:3px 7px 0;background:#52a2df;color:#FFF}.slide pre mark.comment{color:#AAA}.slide table{margin:0 0 50px;width:100%;border-collapse:collapse;border-spacing:0}.slide table th,.slide table td{background:url("data:image/gif;base64,R0lGODdhAQABAPAAAFKi3wAAACH/C1hNUCBEYXRhWE1QAz94cAAsAAAAAAEAAQBAAgJEAQA7") 0 100% repeat-x}.slide table th{text-align:left;font-weight:700}.slide table.striped tr:nth-child(even){background:#f1f7fc}.slide.cover,.slide.shout{z-index:1}.slide.cover:after,.slide.shout:after{content:''}.slide.cover{background:#000}.slide.cover img,.slide.cover svg,.slide.cover video,.slide.cover object,.slide.cover canvas,.slide.cover iframe{position:absolute;top:0;left:0;z-index:-1}.slide.cover.w img,.slide.cover.w svg,.slide.cover.w video,.slide.cover.w object,.slide.cover.w canvas,.slide.cover.w iframe{top:50%;width:100%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.slide.cover.h img,.slide.cover.h svg,.slide.cover.h video,.slide.cover.h object,.slide.cover.h canvas,.slide.cover.h iframe{left:50%;height:100%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.slide.cover.w.h img,.slide.cover.w.h svg,.slide.cover.w.h video,.slide.cover.w.h object,.slide.cover.w.h canvas,.slide.cover.w.h iframe{top:0;left:0;-webkit-transform:none;-ms-transform:none;transform:none}.slide.shout{background:#52a2df}.slide.shout h2{position:absolute;top:50%;left:128px;right:96px;color:#FFF;font-size:100px;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.slide.shout h2 a{background:-webkit-gradient(linear,left bottom,left top,from(currentColor),color-stop(.055em,currentColor),color-stop(.055em,transparent),to(transparent))repeat-x;background:-webkit-linear-gradient(bottom,currentColor,currentColor .055em,transparent .055em,transparent)repeat-x;background:linear-gradient(to top,currentColor,currentColor .055em,transparent .055em,transparent)repeat-x;color:#FFF}.slide .place{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.slide .place.t.l,.slide .place.t.r,.slide .place.b.r,.slide .place.b.l{-webkit-transform:none;-ms-transform:none;transform:none}.slide .place.t,.slide .place.b{-webkit-transform:translate(-50%,0);-ms-transform:translate(-50%,0);transform:translate(-50%,0)}.slide .place.l,.slide .place.r{-webkit-transform:translate(0,-50%);-ms-transform:translate(0,-50%);transform:translate(0,-50%)}.slide .place.t,.slide .place.t.l,.slide .place.t.r{top:0}.slide .place.r{right:0;left:auto}.slide .place.b,.slide .place.b.r,.slide .place.b.l{top:auto;bottom:0}.slide .place.l{left:0}.slide footer{position:absolute;left:0;right:0;bottom:-640px;z-index:1;display:none;padding:20px 96px 20px 128px;background:#fafac4;-webkit-box-shadow:0 0 0 2px rgba(0,0,0,.05);box-shadow:0 0 0 2px rgba(0,0,0,.05);-webkit-transition:bottom .3s;transition:bottom .3s}.slide:hover footer{bottom:0}@media screen{.list{position:absolute;clip:rect(0,auto,auto,0);padding:50px 0 50px 50px;background:#e3e5e7;text-align:center}.list .caption,.list .badge{display:block}.list .slide{position:relative;top:270px;display:inline-block;margin:-270px -462px 0 0;text-align:left;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}}@media screen and (max-width:1180px){.list .slide{top:430px;margin:-430px -718px 0 0;-webkit-transform:scale(.25);-ms-transform:scale(.25);transform:scale(.25)}}@media screen{.list .slide:before{position:absolute;top:0;left:0;z-index:-1;width:512px;height:320px;-webkit-box-shadow:0 0 0 1px #DDD;box-shadow:0 0 0 1px #DDD;content:'';-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scale(2);-ms-transform:scale(2);transform:scale(2)}}@media screen and (max-width:1180px){.list .slide:before{width:256px;height:160px;-webkit-transform:scale(4);-ms-transform:scale(4);transform:scale(4)}}@media screen{.list .slide:after{top:100%;bottom:auto;padding-top:50px}}@media screen and (max-width:1180px){.list .slide:after{width:512px;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scale(2);-ms-transform:scale(2);transform:scale(2)}}@media screen{.list .slide:hover:before{-webkit-box-shadow:0 0 0 1px #eee,0 0 0 12px rgba(255,255,255,.5);box-shadow:0 0 0 1px #eee,0 0 0 12px rgba(255,255,255,.5)}.list .slide:target:before{-webkit-box-shadow:0 0 10px 0 #3c96db,0 0 0 12px #52a2df;box-shadow:0 0 10px 0 #3c96db,0 0 0 12px #52a2df}.list .slide:target:after{color:#52a2df}.list .slide>div:before{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;content:''}.list .slide.cover:after,.list .slide.shout:after{content:counter(slide)}.list .slide footer{display:block}.full{position:absolute;top:50%;left:50%;overflow:hidden;margin:-320px 0 0 -512px;width:1024px;height:640px;background:#000}.full.debug:after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;background:url(../images/grid-16x10.svg) no-repeat;content:''}.full .slide{position:absolute;top:0;left:0;margin-left:150%}.full .slide .next{visibility:hidden}.full .slide .next.active{visibility:visible}.full .slide:target{margin:0}.full .slide.shout.right h2,.full .slide.shout.up h2{opacity:0;-webkit-transition:all .4s ease-out;transition:all .4s ease-out}.full .slide.shout.right:target h2,.full .slide.shout.up:target h2{opacity:1;-webkit-transform:translateX(0)translateY(-50%);-ms-transform:translateX(0)translateY(-50%);transform:translateX(0)translateY(-50%)}.full .slide.shout.right h2{-webkit-transform:translateX(-100%)translateY(-50%);-ms-transform:translateX(-100%)translateY(-50%);transform:translateX(-100%)translateY(-50%)}.full .slide.shout.up h2{-webkit-transform:translateX(0)translateY(100%);-ms-transform:translateX(0)translateY(100%);transform:translateX(0)translateY(100%)}.full .progress{position:absolute;right:0;bottom:0;left:0;z-index:1}.full .progress div{position:absolute;left:0;bottom:0;width:0;height:8px;background:#52a2df;-webkit-transition:width .2s linear;transition:width .2s linear}}@page{margin:0;size:1024px 640px} -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/License.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright © 2010–2014 Vadim Makeev, http://pepelsbey.net/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | --- 12 | 13 | # Лицензия MIT 14 | 15 | Copyright © 2010–2014 Вадим Макеев, http://pepelsbey.net/ 16 | 17 | Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, также как и лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий: 18 | 19 | Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения. 20 | 21 | ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/Readme.md: -------------------------------------------------------------------------------- 1 | # Ribbon theme for Shower HTML presentation engine 2 | 3 | Follow [@shower_me](https://twitter.com/shower_me) for support and updates 4 | 5 | To see Ribbon theme for Shower in action: 6 | 7 | - Open [shwr.me/shower/themes/ribbon](http://shwr.me/shower/themes/ribbon/) 8 | - Click any slide to enter presentation mode 9 | - Use arrow keys or presenter remote to navigate 10 | - Press `Esc` to exit presentation mode 11 | 12 | Part of [Shower presentation template](https://github.com/shower/shower/). See [Wiki](https://github.com/shower/shower/wiki) for more information how to use Shower. 13 | 14 | --- 15 | Licensed under [MIT License](http://en.wikipedia.org/wiki/MIT_License), see [license page](https://github.com/shower/shower/wiki/MIT-License) for details. -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/fonts/PTMono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/fonts/PTMono.woff -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/fonts/PTSans.Bold.Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/fonts/PTSans.Bold.Italic.woff -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/fonts/PTSans.Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/fonts/PTSans.Bold.woff -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/fonts/PTSans.Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/fonts/PTSans.Italic.woff -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/fonts/PTSans.Narrow.Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/fonts/PTSans.Narrow.Bold.woff -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/fonts/PTSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/fonts/PTSans.woff -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/images/grid-16x10.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/images/grid-4x3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/images/linen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/images/linen.png -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/images/linen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/images/linen@2x.png -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/images/ribbon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ribbon theme for Shower 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 |
16 |

Presentation Title

17 |

Yours Truly, Famous Inc.

18 |
19 |
20 |

Header

21 |

Typewriter etsy messenger bag fingerstache, aesthetic vinyl semiotics twee DIY forage chillwave. Thundercats ennui messenger bag, squid carles chillwave shoreditch pickled cliche letterpress. DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub1 kale H20 chips. Ennui keffiyeh thundercats jean shorts biodiesel. Terry richardson, swag blog locavore umami vegan helvetica. Fingerstache kale chips.

22 |
23 | Typewriter etsy messenger bag fingerstache. 24 |
25 |
26 |
27 |

Header

28 |

Thundercats ennui messenger bag, squid carles chillwave shoreditch pickled cliche letterpress. DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub kale chips. Ennui keffiyeh thundercats jean shorts biodiesel. Terry richardson, swag blog locavore umami vegan helvetica. Fingerstache kale chips.

29 |

Typewriter etsy messenger bag fingerstache.

30 |
31 | DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub kale chips. Ennui keffiyeh thundercats jean shorts biodiesel. 32 |
33 |
34 |
35 |

Lists in English typography

36 |
    37 |
  • Ennui keffiyeh thundercats
  • 38 |
  • Jean shorts biodiesel
  • 39 |
  • Terry richardson, swag blog 40 |
      41 |
    1. Locavore umami vegan helvetica
    2. 42 |
    3. Fingerstache kale chips
    4. 43 |
    5. Keytar sriracha gluten-free
    6. 44 |
    45 |
  • 46 |
  • Before they sold out master
  • 47 |
48 |
49 |
50 |

Lists in Russian typography

51 |
    52 |
  • Ennui keffiyeh thundercats
  • 53 |
  • Jean shorts biodiesel
  • 54 |
  • Terry richardson, swag blog 55 |
      56 |
    1. Locavore umami vegan helvetica
    2. 57 |
    3. Fingerstache kale chips
    4. 58 |
    5. Keytar sriracha gluten-free
    6. 59 |
    60 |
  • 61 |
  • Before they sold out master
  • 62 |
63 |
64 |
65 |

Lists in English typography

66 |
    67 |
  1. Locavore umami vegan helvetica
  2. 68 |
  3. Fingerstache kale chips
  4. 69 |
  5. Keytar sriracha gluten-free
  6. 70 |
71 |
    72 |
  • Ennui keffiyeh thundercats
  • 73 |
  • Jean shorts biodiesel
  • 74 |
  • Terry richardson, swag blog
  • 75 |
76 |
77 |
78 |

Quote

79 |
80 |
81 |

Typewriter etsy messenger bag fingerstache, aesthetic vinyl semiotics twee DIY forage chillwave. Thundercats ennui messenger bag, squid carles chillwave shoreditch pickled cliche letterpress.

82 |
83 |
Author Name
84 |
85 |

DIY beard locavore occupy salvia, whatever single-origin coffee fanny pack 3 wolf moon typewriter gastropub kale chips.

86 |
87 |
88 |

Table

89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
LocavoreUmamiHelveticaVegan
FingerstacheKaleChipsKeytar
SrirachaGluten-freeEnnuiKeffiyeh
ThundercatsJeanShortsBiodiesel
TerryRichardsonSwagBlog
121 |

Typewriter etsy messenger bag fingerstache.

122 |
123 |
124 |

Numbered code listing

125 |
126 | 			<html lang="en">
127 | 			<head> <!--Comment-->
128 | 			    <title>Shower</title>
129 | 			    <meta charset="UTF-8">
130 | 			    <link rel="stylesheet" href="s/screen.css">
131 | 			    <script src="j/jquery.js"></script>
132 | 			</head>
133 | 		
134 |
135 |
136 |

Plain code listing

137 |
<html lang="en">
138 | <head> <!--Comment-->
139 | 	<title>Shower</title>
140 | 	<meta charset="UTF-8">
141 | 	<link rel="stylesheet" href="s/screen.css">
142 | 	<script src="j/jquery.js"></script>
143 | </head>
144 |
145 |
146 |

147 | You Can
148 | Shout This Way 149 |

150 |
151 | Typewriter etsy messenger bag fingerstache. 152 |
153 |
154 |
155 |

Linked Shout

156 |
157 |
158 |

Growing Shout

159 |
160 |
161 |

Shrinking Shout

162 |
163 |
164 | 165 |
166 |
167 | 168 |
169 |
170 | 171 |
172 | Typewriter etsy messenger bag fingerstache. 173 |
174 |
175 |
176 | 177 |
178 |
179 | 180 |
181 |
182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 |
192 |
193 |

Timer

194 |

Three seconds to go.

195 |
196 |
197 |

List navigation

198 |
    199 |
  1. Ennui keffiyeh thundercats
  2. 200 | 201 | 202 | 203 | 204 |
205 |

Before they sold out master

206 |
207 |

Fork me on Github

208 | 212 |
213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/pictures/exact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/pictures/exact.png -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/pictures/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/pictures/square.png -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/pictures/tall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/pictures/tall.png -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/pictures/wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/presentation/shower/themes/ribbon/pictures/wide.png -------------------------------------------------------------------------------- /presentation/shower/themes/ribbon/styles/screen.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Ribbon theme for Shower HTML presentation engine: github.com/shower/ribbon 3 | * Copyright © 2010–2014 Vadim Makeev, pepelsbey.net 4 | * Licensed under MIT license: github.com/shower/shower/wiki/MIT-License 5 | */ 6 | @font-face{font-family:'PT Sans';src:url(../fonts/PTSans.woff) format("woff")}@font-face{font-weight:700;font-family:'PT Sans';src:url(../fonts/PTSans.Bold.woff) format("woff")}@font-face{font-style:italic;font-family:'PT Sans';src:url(../fonts/PTSans.Italic.woff) format("woff")}@font-face{font-style:italic;font-weight:700;font-family:'PT Sans';src:url(../fonts/PTSans.Bold.Italic.woff) format("woff")}@font-face{font-family:'PT Sans Narrow';font-weight:700;src:url(../fonts/PTSans.Narrow.Bold.woff) format("woff")}@font-face{font-family:'PT Mono';src:url(../fonts/PTMono.woff) format("woff")}html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0}body{counter-reset:slide;font:25px/2 'PT Sans',sans-serif}a{color:#4b86c2;background:-webkit-gradient(linear,left bottom,left top,from(currentColor),color-stop(.09em,currentColor),color-stop(.09em,transparent),to(transparent))repeat-x;background:-webkit-linear-gradient(bottom,currentColor,currentColor .09em,transparent .09em,transparent)repeat-x;background:linear-gradient(to top,currentColor,currentColor .09em,transparent .09em,transparent)repeat-x;text-decoration:none}.caption{display:none;margin:0 0 50px;color:#3C3D40;text-shadow:0 1px 1px #8D8E90}.caption h1{font:700 50px/1 'PT Sans Narrow',sans-serif}.caption a{text-shadow:0 -1px 1px #1F3F60;background:0 0}.caption a:hover{color:#5e93c8}.badge{position:absolute;top:0;right:0;display:none;overflow:hidden;visibility:hidden;width:11em;height:11em;line-height:2.5;font-size:15px}.badge a{position:absolute;bottom:50%;right:-50%;left:-50%;visibility:visible;background:#4b86c2;-webkit-box-shadow:0 0 1em rgba(0,0,0,.3);box-shadow:0 0 1em rgba(0,0,0,.3);color:#FFF;text-decoration:none;text-align:center;-webkit-transform-origin:50% 100%;-ms-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transform:rotate(45deg)translateY(-1em);-ms-transform:rotate(45deg)translateY(-1em);transform:rotate(45deg)translateY(-1em)}.badge a:hover{background:#568ec6}.slide{position:relative;width:1024px;height:640px;background:#FFF;color:#000;-webkit-print-color-adjust:exact;-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none}.slide:after{position:absolute;top:0;right:119px;padding:20px 0 0;width:50px;height:80px;background:url(../images/ribbon.svg) no-repeat;color:#FFF;counter-increment:slide;content:counter(slide);text-align:center;font-size:20px}.slide>div{position:absolute;top:0;left:0;overflow:hidden;padding:105px 120px 0;width:784px;height:535px}.slide h2{margin:0 0 37px;color:#666;font:700 50px/1 'PT Sans Narrow',sans-serif}.slide p{margin:0 0 50px}.slide p.note{color:#999}.slide b,.slide strong{font-weight:700}.slide i,.slide em{font-style:italic}.slide kbd,.slide code,.slide samp{padding:3px 8px;border-radius:8px;background:#fafaa2;color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;line-height:1;font-family:'PT Mono',monospace}.slide sub,.slide sup{position:relative;line-height:0;font-size:75%}.slide sub{bottom:-.25em}.slide sup{top:-.5em}.slide blockquote{font-style:italic}.slide blockquote:before{position:absolute;margin:-16px 0 0 -80px;color:#CCC;font:200px/1 'PT Sans',sans-serif;content:'\201C'}.slide blockquote+figcaption{margin:-50px 0 50px;font-style:italic;font-weight:700}.slide ol,.slide ul{margin:0 0 50px;counter-reset:list}.slide ol li,.slide ul li{text-indent:-2em}.slide ol li:before,.slide ul li:before{display:inline-block;width:2em;color:#BBB;text-align:right}.slide ol ol,.slide ol ul,.slide ul ol,.slide ul ul{margin:0 0 0 2em}.slide ul>li:before{content:'\2022\00A0\00A0'}.slide ul>li:lang(ru):before{content:'\2014\00A0\00A0'}.slide ol>li:before{counter-increment:list;content:counter(list)".\00A0"}.slide pre{margin:0 0 49px;padding:1px 0 0;counter-reset:code;white-space:normal}.slide pre code{display:block;padding:0;background:0 0;white-space:pre;line-height:50px}.slide pre code:before{position:absolute;margin:0 0 0 -110px;width:100px;color:#BBB;text-align:right;counter-increment:code;content:counter(code,decimal-leading-zero)"."}.slide pre code:only-child:before{content:''}.slide pre mark{padding:3px 8px;border-radius:8px;background:#F7FCA0;color:#000;font-style:normal}.slide pre mark.important{background:#C00;color:#FFF;font-weight:400}.slide pre mark.comment{padding:0;background:0 0;color:#999}.slide table{margin:0 0 50px;width:100%;border-collapse:collapse;border-spacing:0}.slide table th,.slide table td{background:url("data:image/gif;base64,R0lGODdhAQABAPAAAJmZmQAAACH/C1hNUCBEYXRhWE1QAj94ACwAAAAAAQABAAACAkQBADs=") 0 100% repeat-x}.slide table th{text-align:left;font-weight:700}.slide table.striped tr:nth-child(even){background:#EEE}.slide.cover,.slide.shout{z-index:1}.slide.cover:after,.slide.shout:after{visibility:hidden}.slide.cover{background:#000}.slide.cover img,.slide.cover svg,.slide.cover video,.slide.cover object,.slide.cover canvas,.slide.cover iframe{position:absolute;top:0;left:0;z-index:-1}.slide.cover.w img,.slide.cover.w svg,.slide.cover.w video,.slide.cover.w object,.slide.cover.w canvas,.slide.cover.w iframe{top:50%;width:100%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.slide.cover.h img,.slide.cover.h svg,.slide.cover.h video,.slide.cover.h object,.slide.cover.h canvas,.slide.cover.h iframe{left:50%;height:100%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.slide.cover.w.h img,.slide.cover.w.h svg,.slide.cover.w.h video,.slide.cover.w.h object,.slide.cover.w.h canvas,.slide.cover.w.h iframe{top:0;left:0;-webkit-transform:none;-ms-transform:none;transform:none}.slide.shout h2{position:absolute;top:50%;left:0;width:100%;text-align:center;line-height:1;font-size:150px;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.slide.shout h2 a{background:-webkit-gradient(linear,left bottom,left top,from(currentColor),color-stop(.11em,currentColor),color-stop(.11em,transparent),to(transparent))repeat-x;background:-webkit-linear-gradient(bottom,currentColor,currentColor .11em,transparent .11em,transparent)repeat-x;background:linear-gradient(to top,currentColor,currentColor .11em,transparent .11em,transparent)repeat-x}.slide .place{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.slide .place.t.l,.slide .place.t.r,.slide .place.b.r,.slide .place.b.l{-webkit-transform:none;-ms-transform:none;transform:none}.slide .place.t,.slide .place.b{-webkit-transform:translate(-50%,0);-ms-transform:translate(-50%,0);transform:translate(-50%,0)}.slide .place.l,.slide .place.r{-webkit-transform:translate(0,-50%);-ms-transform:translate(0,-50%);transform:translate(0,-50%)}.slide .place.t,.slide .place.t.l,.slide .place.t.r{top:0}.slide .place.r{right:0;left:auto}.slide .place.b,.slide .place.b.r,.slide .place.b.l{top:auto;bottom:0}.slide .place.l{left:0}.slide footer{position:absolute;left:0;right:0;bottom:-640px;z-index:1;display:none;padding:20px 120px;background:#fafaa2;-webkit-box-shadow:0 0 0 2px #f0f0ac inset;box-shadow:0 0 0 2px #f0f0ac inset;-webkit-transition:bottom .3s;transition:bottom .3s}.slide:hover footer{bottom:0}@media screen{.list{position:absolute;clip:rect(0,auto,auto,0);padding:80px 0 40px 100px;background:#585a5e url(../images/linen.png)}}@media screen and (-webkit-min-device-pixel-ratio:2),screen and (min-resolution:192dpi){.list{background-image:url(../images/linen@2x.png);-webkit-background-size:256px;background-size:256px}}@media screen{.list .caption,.list .badge{display:block}.list .slide{float:left;margin:0 -412px -220px 0;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}}@media screen and (max-width:1324px){.list .slide{margin:0 -688px -400px 0;-webkit-transform:scale(.25);-ms-transform:scale(.25);transform:scale(.25)}}@media screen{.list .slide:before{position:absolute;top:0;left:0;z-index:-1;width:512px;height:320px;-webkit-box-shadow:0 0 30px rgba(0,0,0,.005),0 20px 50px rgba(42,43,45,.6);box-shadow:0 0 30px rgba(0,0,0,.005),0 20px 50px rgba(42,43,45,.6);border-radius:2px;content:'';-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scale(2);-ms-transform:scale(2);transform:scale(2)}}@media screen and (max-width:1324px){.list .slide:before{width:256px;height:160px;-webkit-transform:scale(4);-ms-transform:scale(4);transform:scale(4)}}@media screen{.list .slide:after{top:auto;right:auto;bottom:-80px;left:120px;padding:0;width:auto;height:auto;background:0 0;color:#3C3D40;text-shadow:0 1px 1px #8D8E90;font-weight:700;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scale(2);-ms-transform:scale(2);transform:scale(2)}}@media screen and (max-width:1324px){.list .slide:after{bottom:-104px;-webkit-transform:scale(4);-ms-transform:scale(4);transform:scale(4)}}@media screen{.list .slide:hover:before{-webkit-box-shadow:0 0 0 10px rgba(42,43,45,.3),0 20px 50px rgba(42,43,45,.6);box-shadow:0 0 0 10px rgba(42,43,45,.3),0 20px 50px rgba(42,43,45,.6)}.list .slide:target:before{-webkit-box-shadow:0 0 0 1px #376da3,0 0 0 10px #4b86c2,0 20px 50px rgba(42,43,45,.6);box-shadow:0 0 0 1px #376da3,0 0 0 10px #4b86c2,0 20px 50px rgba(42,43,45,.6)}}@media screen and (max-width:1324px){.list .slide:target:before{-webkit-box-shadow:0 0 0 1px #376da3,0 0 0 10px #4b86c2,0 20px 50px rgba(42,43,45,.6);box-shadow:0 0 0 1px #376da3,0 0 0 10px #4b86c2,0 20px 50px rgba(42,43,45,.6)}}@media screen{.list .slide:target:after{text-shadow:0 1px 1px rgba(42,43,45,.6);color:#4b86c2}.list .slide>div:before{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;content:''}.list .slide.cover:after,.list .slide.shout:after{visibility:visible}.list .slide footer{display:block}.full{position:absolute;top:50%;left:50%;overflow:hidden;margin:-320px 0 0 -512px;width:1024px;height:640px;background:#000}.full.debug:after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;background:url(../images/grid-16x10.svg) no-repeat;content:''}.full .slide{position:absolute;top:0;left:0;margin-left:150%}.full .slide .next{visibility:hidden}.full .slide .next.active{visibility:visible}.full .slide:target{margin:0}.full .slide.shout.grow h2,.full .slide.shout.shrink h2{opacity:0;-webkit-transition:all .4s ease-out;transition:all .4s ease-out}.full .slide.shout.grow:target h2,.full .slide.shout.shrink:target h2{opacity:1;-webkit-transform:scale(1)translateY(-50%);-ms-transform:scale(1)translateY(-50%);transform:scale(1)translateY(-50%)}.full .slide.shout.grow h2{-webkit-transform:scale(.1)translateY(-50%);-ms-transform:scale(.1)translateY(-50%);transform:scale(.1)translateY(-50%)}.full .slide.shout.shrink h2{-webkit-transform:scale(10)translateY(-50%);-ms-transform:scale(10)translateY(-50%);transform:scale(10)translateY(-50%)}.full .progress{position:absolute;right:0;bottom:0;left:0;overflow:hidden;height:10px;z-index:1}.full .progress div{position:absolute;left:-20px;top:-10px;width:0;height:0;border:10px solid transparent;border-bottom-color:#4b86c2;-webkit-transition:width .2s linear;transition:width .2s linear}.full .progress div[style$='100%;']{padding-left:10px}}@page{margin:0;size:1024px 640px} -------------------------------------------------------------------------------- /screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/screenshots/screenshot1.png -------------------------------------------------------------------------------- /screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/screenshots/screenshot2.png -------------------------------------------------------------------------------- /screenshots/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/screenshots/screenshot3.png -------------------------------------------------------------------------------- /screenshots/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/screenshots/screenshot4.png -------------------------------------------------------------------------------- /screenshots/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/screenshots/screenshot5.png -------------------------------------------------------------------------------- /screenshots/screenshot6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixpalmer/lod-terrain/4f8db08c1385d59f05a5b4e720d9705e666fc4b4/screenshots/screenshot6.png -------------------------------------------------------------------------------- /webserver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import SimpleHTTPServer 3 | 4 | # Simple web server with caching disabled (useful for development) 5 | class MyHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 6 | def end_headers(self): 7 | self.send_my_headers() 8 | SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) 9 | 10 | def send_my_headers(self): 11 | self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") 12 | self.send_header("Pragma", "no-cache") 13 | self.send_header("Expires", "0") 14 | 15 | 16 | if __name__ == '__main__': 17 | SimpleHTTPServer.test(HandlerClass=MyHTTPRequestHandler) 18 | --------------------------------------------------------------------------------