├── .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 | 
11 | 
12 | 
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 |
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 |
15 |
16 |
Rendering large terrains in WebGL
17 |
Felix Palmer | @pheeelicks | www.pheelicks.com
18 |

19 |
23 |
41 |
42 |
43 |
Talk overview
44 |
45 | - Crash course on WebGL shaders
46 | - Basic approach to problem
47 | - Using a recursive tile pattern
48 | - Using a dynamic mesh
49 | - Questions? Feel free to ask during talk too!
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 | - Geometry is defined in JavaScript and sent to GPU
61 | - Vertex shader is invoked on every vertex, allowing it to be moved
62 | - Fragment (pixel) shader is invoked on each pixel to be drawn
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 |
78 |
79 | - Cons:
80 |
81 | - Not enough detail in the foreground
82 | - Too much detail in in the background
83 |
84 |
85 |
86 |
87 |
90 |
91 |
Arrange tiles in concentric shells
92 |

93 |
94 |
95 |
Arrange tiles in concentric shells
96 |

97 |
98 |
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 |
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 |
--------------------------------------------------------------------------------
/presentation/shower/themes/bright/images/grid-4x3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |
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 |
33 |
34 |
35 |
Lists in English typography
36 |
37 | - Ennui keffiyeh thundercats
38 | - Jean shorts biodiesel
39 | - Terry richardson, swag blog
40 |
41 | - Locavore umami vegan helvetica
42 | - Fingerstache kale chips
43 | - Keytar sriracha gluten-free
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 | - Locavore umami vegan helvetica
57 | - Fingerstache kale chips
58 | - Keytar sriracha gluten-free
59 |
60 |
61 | - Before they sold out master
62 |
63 |
64 |
65 |
Lists in English typography
66 |
67 | - Locavore umami vegan helvetica
68 | - Fingerstache kale chips
69 | - Keytar sriracha gluten-free
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 | Locavore |
92 | Umami |
93 | Helvetica |
94 | Vegan |
95 |
96 |
97 | Fingerstache |
98 | Kale |
99 | Chips |
100 | Keytar |
101 |
102 |
103 | Sriracha |
104 | Gluten-free |
105 | Ennui |
106 | Keffiyeh |
107 |
108 |
109 | Thundercats |
110 | Jean |
111 | Shorts |
112 | Biodiesel |
113 |
114 |
115 | Terry |
116 | Richardson |
117 | Swag |
118 | Blog |
119 |
120 |
121 |
Typewriter etsy messenger bag fingerstache.
122 |
123 |
124 |
Numbered code listing
125 |
126 | <html lang="en">
127 | <head>
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>
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 |
153 |
154 |
157 |
158 |
Sliding Right
159 |
160 |
163 |
164 |

165 |
166 |
167 |

168 |
169 |
170 |

171 |
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 | - Ennui keffiyeh thundercats
200 | - Jean shorts biodiesel
201 | - Terry richardson, swag blog
202 | - Locavore umami vegan helvetica
203 | - Fingerstache kale chips
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 |
--------------------------------------------------------------------------------
/presentation/shower/themes/ribbon/images/grid-4x3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
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 |
33 |
34 |
35 |
Lists in English typography
36 |
37 | - Ennui keffiyeh thundercats
38 | - Jean shorts biodiesel
39 | - Terry richardson, swag blog
40 |
41 | - Locavore umami vegan helvetica
42 | - Fingerstache kale chips
43 | - Keytar sriracha gluten-free
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 | - Locavore umami vegan helvetica
57 | - Fingerstache kale chips
58 | - Keytar sriracha gluten-free
59 |
60 |
61 | - Before they sold out master
62 |
63 |
64 |
65 |
Lists in English typography
66 |
67 | - Locavore umami vegan helvetica
68 | - Fingerstache kale chips
69 | - Keytar sriracha gluten-free
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 | Locavore |
92 | Umami |
93 | Helvetica |
94 | Vegan |
95 |
96 |
97 | Fingerstache |
98 | Kale |
99 | Chips |
100 | Keytar |
101 |
102 |
103 | Sriracha |
104 | Gluten-free |
105 | Ennui |
106 | Keffiyeh |
107 |
108 |
109 | Thundercats |
110 | Jean |
111 | Shorts |
112 | Biodiesel |
113 |
114 |
115 | Terry |
116 | Richardson |
117 | Swag |
118 | Blog |
119 |
120 |
121 |
Typewriter etsy messenger bag fingerstache.
122 |
123 |
124 |
Numbered code listing
125 |
126 | <html lang="en">
127 | <head>
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>
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 |
153 |
154 |
157 |
158 |
Growing Shout
159 |
160 |
161 |
Shrinking Shout
162 |
163 |
164 |

165 |
166 |
167 |

168 |
169 |
170 |

171 |
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 | - Ennui keffiyeh thundercats
200 | - Jean shorts biodiesel
201 | - Terry richardson, swag blog
202 | - Locavore umami vegan helvetica
203 | - Fingerstache kale chips
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 |
--------------------------------------------------------------------------------