├── .gitmodules ├── ASHIMA.md ├── LICENSE ├── README.md ├── glocd ├── .gitignore ├── Makefile ├── Stone1.jpg ├── abs.glsl ├── blend.glsl ├── demo.html ├── demo.js ├── engine ├── light.glsl ├── nplain.glsl ├── plain.glsl ├── sphere.glsl ├── tex.glsl └── vert.glsl └── pano ├── .gitignore ├── README.md ├── apollo ├── .gitignore ├── Makefile └── manifest.xml ├── atom.xsl ├── fs.xsl ├── gallery.xsl ├── lang └── en.xml ├── manifest.xml ├── manifest.xsl ├── mars ├── .gitignore ├── Makefile └── gallery.xml ├── pano.css ├── pano.html ├── pano.js ├── pano_ui.js ├── subpath.xsl └── xhtml.xsl /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pano/engine"] 2 | path = pano/engine 3 | url = git://github.com/ashima/webgl-engine.git 4 | [submodule "pano/demo-lib"] 5 | path = pano/demo-lib 6 | url = git://github.com/ashima/demo-lib.git 7 | [submodule "webgl-noise"] 8 | path = webgl-noise 9 | url = git@github.com:ashima/webgl-noise.git 10 | -------------------------------------------------------------------------------- /ASHIMA.md: -------------------------------------------------------------------------------- 1 | # Ashima webgl-demos 2 | 3 | webgl-demos is a collection of WebGL demonstrations from Ashima 4 | Group. The software is free and open source under the MIT Expat license 5 | which can be found in the LICENSE file. 6 | 7 | ###License 8 | [MIT Expat](http://ashimagroup.net/os/license/mit-expat) 9 | 10 | ###Tags 11 | [WebGL](http://ashimagroup.net/os/tag/webgl) 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011 Ashima Arts 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ashima webgl-demos 2 | 3 | webgl-demos is a collection of WebGL demonstrations from Ashima 4 | Group. The software is free and open source under the MIT Expat license 5 | which can be found in the LICENSE file. 6 | 7 | ## Usage 8 | 9 | Don't forget to 10 | ```git submodule update --init --recursive``` 11 | to clone dependencies! 12 | 13 | ## Demos 14 | 15 | - [Multiple Panorama Viewer](https://github.com/ashima/webgl-demos/tree/master/pano) 16 | -------------------------------------------------------------------------------- /glocd/.gitignore: -------------------------------------------------------------------------------- 1 | *.glo 2 | -------------------------------------------------------------------------------- /glocd/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all noise 2 | 3 | GLSL := $(wildcard *.glsl) 4 | GLO := $(GLSL:.glsl=.glo) 5 | 6 | all: ${GLO} noise 7 | 8 | noise: 9 | cd ../webgl-noise/src && make 10 | cp ../webgl-noise/src/noise.glo . 11 | 12 | %.glo: %.glsl 13 | gloc -c --dissolve $*.glsl -o $*.glo 14 | -------------------------------------------------------------------------------- /glocd/Stone1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashima/webgl-demos/a63f8a19ea74c89abca2f6eac6b876a35dd01aa7/glocd/Stone1.jpg -------------------------------------------------------------------------------- /glocd/abs.glsl: -------------------------------------------------------------------------------- 1 | vec4 abs_(vec2 xy) { 2 | return vec4(abs(xy),1.0,1.0); 3 | } 4 | 5 | vec4 abs_noise(vec2 xy) { 6 | float t = time/1000.; 7 | return vec4((0.2+snoise(vec3(xy,t)))/1.2, 8 | (0.2+snoise(vec3(xy.y,t,xy.x)))/1.2, 9 | (0.2+snoise(vec3(t,xy)))/1.2,1.0); 10 | } 11 | -------------------------------------------------------------------------------- /glocd/blend.glsl: -------------------------------------------------------------------------------- 1 | const float ipi = 1.0 / 3.1415926535897932384626433832795029; 2 | uniform sampler2D tex0; 3 | uniform float time; 4 | uniform float mixf; 5 | 6 | varying vec2 texCoord; 7 | varying vec4 normal; 8 | varying vec4 pointLightingDirection; 9 | 10 | uniform vec4 ambientColor; 11 | uniform vec4 directionalColor; 12 | uniform vec4 lightingDirection; 13 | uniform vec4 pointLightingColor; 14 | 15 | void main(void) { 16 | vec4 lt_att = light(vec4(0.)); 17 | gl_FragColor = lt_att * mix(blenda(texCoord),blendb(texCoord),mixf); 18 | } 19 | -------------------------------------------------------------------------------- /glocd/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WebGL glo Demo 4 | 23 | 24 | 25 |
26 | Loading ... 27 |
28 | 29 |
30 |
V F
31 |
32 | 33 | 34 | 36 | 37 | 38 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /glocd/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Ashima Arts All rights reserved. 3 | * License: MIT expat <../LICENSE> 4 | * Author: Ian McEwan, Ashima Arts 5 | * Author: David Sheets, Ashima Arts 6 | * Description: A gloc demo module 7 | */ 8 | 9 | function ashimaGlocDemo(onprogress, onprogchange) { 10 | var D = this; 11 | var awe = ashimaWebGLEngine0; 12 | var epoch = (new Date()).getTime(); 13 | 14 | var vcycle = ["map2Rs","map2Rpp","map2Rnp","map2Rns"]; 15 | var fcycle = ["tex_","abs_","abs_noise","tex_noise"]; 16 | var vtrans = 7000.; 17 | var ftrans = 3000.; 18 | var currentvi = 0, currentfi = 0; 19 | function ready_for_switch() { 20 | var now = (new Date()).getTime() - epoch; 21 | var vi = Math.floor((now/vtrans) % vcycle.length); 22 | var fi = Math.floor((now/ftrans) % fcycle.length); 23 | var ovi = currentvi, ofi = currentfi; 24 | currentvi=vi; currentfi=fi; 25 | return (ovi != vi) || (ofi != fi); 26 | } 27 | var prog_cache = {}; 28 | function make_progs(callback) { 29 | var total = vcycle.length * fcycle.length; 30 | var complete = 0; 31 | for (var vi = 0; vi < vcycle.length; vi++) { 32 | for (var fi = 0; fi < fcycle.length; fi++) { 33 | (function() { 34 | var av, bv, af, bf; 35 | av = vcycle[vi]; bv = vcycle[(vi + 1) % vcycle.length]; 36 | af = fcycle[fi]; bf = fcycle[(fi + 1) % fcycle.length]; 37 | get_glo(["vert.glo", 38 | make_blend(av,bv), 39 | "sphere.glo", 40 | "plain.glo", 41 | "nplain.glo", 42 | "noise.glo"], 43 | ["blend.glo", 44 | make_blend(af,bf), 45 | make_light(["point_light","ambient_light"]), 46 | "abs.glo", 47 | "tex.glo", 48 | "light.glo", 49 | "noise.glo"], 50 | function (vglom, fglom) { 51 | if (!( av in prog_cache)) prog_cache[av] = {}; 52 | prog_cache[av][af] = link_prog(vglom,fglom); 53 | complete++; 54 | onprogress(complete,av,af); 55 | if (total == complete) callback(); 56 | }); 57 | })(); 58 | } 59 | } 60 | } 61 | function get_prog() { 62 | var now = (new Date()).getTime() - epoch; 63 | var vi = Math.floor((now/vtrans) % vcycle.length); 64 | var fi = Math.floor((now/ftrans) % fcycle.length); 65 | onprogchange(vi,fi); 66 | return prog_cache[vcycle[vi]][fcycle[fi]]; 67 | } 68 | 69 | //var gl, prog, verts, tris; 70 | var pi = 3.1415926535897932384626433832795029 ; 71 | var elemDemo, elemRoot, elemCanvas; 72 | var curW , curH ; 73 | //var mvMatrix, pMatrix; 74 | 75 | theta = 0.; 76 | phi = 0.; 77 | function makePerspective(fovy, aspect, near, far) 78 | { // swipped from somewhere! 79 | var tp = near * Math.tan(fovy * Math.PI / 360.0); 80 | var bt = -tp; 81 | var lt = bt * aspect; 82 | var rt = tp * aspect; 83 | 84 | var X = 2*near/(rt-lt); 85 | var Y = 2*near/(tp-bt); 86 | var A = (rt+lt)/(rt-lt); 87 | var B = (tp+bt)/(tp-bt); 88 | var C = -(far+near)/(far-near); 89 | var D = -2*far*near/(far-near); 90 | 91 | return [X, 0, 0, 0, 92 | 0, Y, 0, 0, 93 | A, B, C, -1, 94 | 0, 0, D, 0 ] ; 95 | } 96 | 97 | var precdecl = "#ifdef GL_ES\nprecision highp float;\n#endif\n"; 98 | var glol = new GLOL(); 99 | 100 | function link_prog(vglom,fglom) { 101 | var vs; 102 | try { vs = glol.link(precdecl,[],vglom) } 103 | catch(e) { console.log(e); }; 104 | var fs; 105 | try { fs = glol.link(precdecl,[],fglom) } 106 | catch(e) { console.log(e); }; 107 | 108 | r = awe.compileAndLink(vs,fs); 109 | return r; 110 | } 111 | 112 | function use_prog() { 113 | prog.aweUse(); 114 | demoTex.aweSet(0, prog.aweSym['tex0'] ); 115 | verts.aweSetVertexAttPtr(prog.aweSym["position2D"]); 116 | } 117 | 118 | function make_blend(a,b) { 119 | return [a+"2"+b, 120 | {"glo": [1,0,0], 121 | "target": ["webgl",[1,0,0]], 122 | "units":[ 123 | {"insym": [a], 124 | "outmac": ["blenda"], 125 | "source":"#define blenda "+a}, 126 | {"insym": [b], 127 | "outmac": ["blendb"], 128 | "source":"#define blendb "+b} 129 | ] 130 | } 131 | ]; 132 | } 133 | function make_light(a) { 134 | var compose = a.join("(")+"(c"+a.map(function(k){ return ""; }).join(")")+")"; 135 | return [a.join("_"), 136 | {"glo": [1,0,0], 137 | "target": ["webgl",[1,0,0]], 138 | "units":[ 139 | {"insym": a, 140 | "outmac": ["light"], 141 | "source":"#define light(c) "+compose } 142 | ] 143 | } 144 | ]; 145 | } 146 | 147 | var glo_cache = {}; 148 | 149 | function get_glo(vpaths,fpaths,callback) { 150 | var complete = vpaths.length+fpaths.length; 151 | var progress = 0; 152 | function error() { 153 | throw ("Error requesting '"+path+"'."); 154 | } 155 | function got_glo(path,set_path) { 156 | progress++; 157 | set_path(path,[path,glo_cache[path]]); 158 | if (progress == complete) { callback(vpaths,fpaths); } 159 | } 160 | function request_path(path,set_path) { 161 | if ( Object.prototype.toString.call(path) === "[object Array]") { 162 | glo_cache[path[0]] = path[1]; 163 | got_glo(path[0],set_path); 164 | return; 165 | } 166 | if (path in glo_cache) { got_glo(path,set_path); return; } 167 | var req = new XMLHttpRequest(); 168 | 169 | req.onerror = req.onabort = error; 170 | 171 | req.onreadystatechange = function() { 172 | if (req.readyState == 4) { 173 | if (req.responseText == null) error(); 174 | else { 175 | glo_cache[path] = JSON.parse(req.responseText); 176 | got_glo(path,set_path); 177 | } 178 | } 179 | }; 180 | req.open("GET",path); 181 | 182 | try { req.send(); } 183 | catch (x) { 184 | throw ("File exception caught requesting "+s+" :\n'"+x.toString()+"'"); 185 | return true; 186 | } 187 | } 188 | 189 | vpaths.forEach(function (path) { 190 | request_path(path, 191 | function(p,v) { 192 | vpaths[vpaths.indexOf(p)] = v; 193 | }); 194 | }); 195 | fpaths.forEach(function (path) { 196 | request_path(path, 197 | function(p,v) { 198 | fpaths[fpaths.indexOf(p)] = v; 199 | }); 200 | }); 201 | } 202 | 203 | function glinit() { 204 | gl = awe.getGlContext(elemCanvas,{"warningsAsErrors":true}); 205 | 206 | if (!gl) throw "No webgl here"; 207 | 208 | var num = 20; 209 | var step = 2 / (num-1); 210 | jverts = new Array; 211 | for (var j = 0; j < num; j++ ) 212 | for (var i = 0; i < num; i++ ) 213 | { 214 | jverts[(j*num+i)*2+0] = i * step - 1.0; 215 | jverts[(j*num+i)*2+1] = j * step - 1.0; 216 | } 217 | jtris = new Array; 218 | for (var j = 0; j < num-1 ; j++ ) 219 | for (var i = 0; i < num-1 ; i++ ) 220 | { 221 | jtris[ (j*(num-1)+i)*6 +0] = (j+0)*num+(i+0) ; 222 | jtris[ (j*(num-1)+i)*6 +1] = (j+0)*num+(i+1) ; 223 | jtris[ (j*(num-1)+i)*6 +2] = (j+1)*num+(i+0) ; 224 | 225 | jtris[ (j*(num-1)+i)*6 +3] = (j+0)*num+(i+1) ; 226 | jtris[ (j*(num-1)+i)*6 +4] = (j+1)*num+(i+1) ; 227 | jtris[ (j*(num-1)+i)*6 +5] = (j+1)*num+(i+0) ; 228 | } 229 | verts = awe.makeBuffer(gl.ARRAY_BUFFER,gl.FLOAT,2,gl.STATIC_DRAW,jverts ); 230 | tris = awe.makeBuffer(gl.ELEMENT_ARRAY_BUFFER,gl.UNSIGNED_SHORT,3,gl.STATIC_DRAW,jtris ); 231 | 232 | pMatrix = new Float32Array(makePerspective( 120, 1, 0.1, 10. )); 233 | mvMatrix = new Float32Array([0.5,0.5,0,0, -0.5,0.5,0,0, 0,0,1,0, 0,0,0,1]); 234 | } 235 | 236 | var demoTex, demoImg; 237 | function renderinit() 238 | { 239 | demoTex = awe.textureCreate(); 240 | demoImg = new Image ; 241 | demoImg.onload = function() { 242 | demoTex.aweFromElem(demoImg); 243 | demoTex.aweParams( gl.LINEAR, gl.LINEAR, 244 | gl.REPEAT, gl.REPEAT, false); 245 | } 246 | demoImg.onerror = function(e) { console.log(e); }; 247 | demoImg.src = "Stone1.jpg"; 248 | } 249 | 250 | function updateCanvasSize() { 251 | curW = elemRoot.clientWidth; 252 | curH = elemRoot.clientHeight; 253 | pMatrix = new Float32Array(makePerspective(45, curW/curH, 2, 10.)); 254 | gl.viewport(0, 0, 255 | gl.viewportWidth = elemCanvas.width = curW, 256 | gl.viewportHeight = elemCanvas.height = curH ); 257 | } 258 | 259 | function resizeNow() 260 | { 261 | updateCanvasSize(); 262 | D.animator.play(); 263 | } 264 | 265 | function clearFrame() 266 | { 267 | gl.clearColor(0.0,0.0,0.0,1.0); 268 | gl.clearDepth(100.0); 269 | gl.enable(gl.DEPTH_TEST); 270 | gl.disable(gl.BLEND); 271 | gl.enable(gl.CULL_FACE); 272 | gl.depthFunc(gl.LEQUAL); 273 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 274 | } 275 | 276 | function render() { 277 | var w = elemRoot.clientWidth; 278 | var h = elemRoot.clientHeight; 279 | var now = (new Date()).getTime()-epoch; 280 | 281 | phi += pi / 240; 282 | if (w != curW || h != curH) { 283 | D.animator.pause(); 284 | setTimeout(resizeNow,200); 285 | } 286 | else { 287 | ct = Math.cos(theta); st = Math.sin(theta); 288 | cp = Math.cos(phi); sp = Math.sin(phi); 289 | 290 | mvMatrix = new Float32Array([ cp, -sp, 0, 0, 291 | ct*sp, ct*cp, -st, 0, 292 | st*sp, st*cp, ct, 0, 293 | 0, 0, 0, 1.0]); 294 | 295 | if (ready_for_switch()) 296 | prog = get_prog(); 297 | 298 | use_prog(); 299 | clearFrame(); 300 | gl.uniformMatrix4fv(prog.aweSym["pMatrix"], false, pMatrix); 301 | gl.uniformMatrix4fv(prog.aweSym["mvMatrix"], false, mvMatrix); 302 | gl.uniform1f(prog.aweSym["time"], now); 303 | var sv = (now % vtrans) / vtrans; 304 | var sf = (now % ftrans) / ftrans; 305 | gl.uniform1f(prog.aweSym["mixv"], 3*Math.pow(sv,2) - 2*Math.pow(sv,3)); 306 | gl.uniform1f(prog.aweSym["mixf"], 3*Math.pow(sf,2) - 2*Math.pow(sf,3)); 307 | 308 | gl.uniform4fv(prog.aweSym["ambientColor"], [0.1,0.1,0.1,1.0]); 309 | gl.uniform4fv(prog.aweSym["directionalColor"], [0.9,0.9,0.9,1.0]); 310 | gl.uniform4fv(prog.aweSym["lightingDirection"], 311 | [sp*cp+cp*sp,1.0,cp*cp-sp*sp,1.0]); 312 | gl.uniform4fv(prog.aweSym["pointLightingColor"], [0.9,0.9,0.9,1.]); 313 | gl.uniform4fv(prog.aweSym["pointLightingLocation"], [10.0,10.0,10.0,1.0]); 314 | 315 | tris.drawElements(gl.TRIANGLES); 316 | } 317 | } 318 | D.updateCanvasSize = updateCanvasSize; 319 | //D.updateElems = updateElems; 320 | 321 | D.init = function(p, callback) { 322 | elemRoot = p; 323 | 324 | elemCanvas = document.createElement("canvas"); 325 | elemCanvas.style.zIndex = -1; 326 | elemCanvas.style.position = "absolute"; 327 | elemDemo = document.createElement("div"); 328 | elemDemo.style.zIndex = 1; 329 | elemDemo.appendChild(elemCanvas); 330 | elemRoot.appendChild(elemDemo); 331 | 332 | glinit(); 333 | renderinit(); 334 | make_progs(function() { prog = get_prog(); callback(); } ); 335 | D.animator = awe.animationStart(render,gl.canvas,1000/60,true); 336 | theta = -1.0; 337 | phi = 0; 338 | } 339 | }; 340 | 341 | 342 | -------------------------------------------------------------------------------- /glocd/engine: -------------------------------------------------------------------------------- 1 | ../pano/engine/ -------------------------------------------------------------------------------- /glocd/light.glsl: -------------------------------------------------------------------------------- 1 | vec4 ambient_light(vec4 c) { 2 | return c + ambientColor; 3 | } 4 | 5 | vec4 diffuse_light(vec4 c) { 6 | return c + directionalColor * max(dot(normal, lightingDirection),0.); 7 | } 8 | 9 | vec4 point_light(vec4 c) { 10 | return c + pointLightingColor * max(dot(normal, pointLightingDirection),0.); 11 | } 12 | 13 | vec4 null_light(vec4 c) { 14 | return vec4(1.0); 15 | } 16 | -------------------------------------------------------------------------------- /glocd/nplain.glsl: -------------------------------------------------------------------------------- 1 | void map2Rnp(out vec4 P, out vec4 N, vec2 v) { /* plain */ 2 | P = vec4(v.x,v.y,-1.0-snoise(vec3(v,time/1000.))/10.,1.); 3 | N = vec4(0.,0.,1.,1.); 4 | } 5 | -------------------------------------------------------------------------------- /glocd/plain.glsl: -------------------------------------------------------------------------------- 1 | void map2Rpp(out vec4 P, out vec4 N, vec2 v) { /* plain */ 2 | P = vec4(v.x,v.y,0.,1.); 3 | N = vec4(0.,0.,1.,1.); 4 | } 5 | -------------------------------------------------------------------------------- /glocd/sphere.glsl: -------------------------------------------------------------------------------- 1 | void map2Rs(out vec4 P, out vec4 N, vec2 v) { /* sphere */ 2 | v *= pi; 3 | P = vec4(cos(v.x)*sin(v.y),sin(v.x)*sin(v.y), cos(v.y),1.0); 4 | N = normalize(P); 5 | } 6 | 7 | void map2Rns(out vec4 P, out vec4 N, vec2 v) { 8 | v *= pi; 9 | float t = time/1000.; 10 | vec3 s = vec3(cos(v.x)*sin(v.y),sin(v.x)*sin(v.y),cos(v.y)); 11 | P = vec4((2.+snoise(vec3(v,t)))*s/2.5,1.0); 12 | N = normalize(P); 13 | } 14 | -------------------------------------------------------------------------------- /glocd/tex.glsl: -------------------------------------------------------------------------------- 1 | vec4 tex_(vec2 xy) { 2 | return texture2D(tex0, xy); 3 | } 4 | 5 | vec4 tex_noise(vec2 xy) { 6 | float t = time/1000.; 7 | vec4 tf = texture2D(tex0, xy); 8 | return vec4(tf.r*(0.2+snoise(vec3(xy,t)))/1.2, 9 | tf.g*(0.2+snoise(vec3(xy.y,t,xy.x)))/1.2, 10 | tf.b*(0.2+snoise(vec3(t,xy)))/1.2, 1.0); 11 | } 12 | -------------------------------------------------------------------------------- /glocd/vert.glsl: -------------------------------------------------------------------------------- 1 | const float pi = 3.1415926535897932384626433832795029; 2 | 3 | attribute vec2 Rxy; 4 | attribute vec2 position2D; 5 | vec4 P,N; 6 | 7 | uniform mat4 pMatrix; 8 | uniform mat4 mvMatrix; 9 | uniform vec4 pointLightingLocation; 10 | 11 | uniform float time; 12 | uniform float mixv; 13 | 14 | varying vec4 normal; 15 | varying vec2 texCoord; 16 | varying vec4 pointLightingDirection; 17 | 18 | void main(void) { 19 | vec4 position4; 20 | vec4 Pa, Na, Pb, Nb; 21 | blenda(Pa, Na, position2D); 22 | blendb(Pb, Nb, position2D); 23 | P = mix(Pa,Pb,mixv); 24 | N = mix(Na,Nb,mixv); 25 | 26 | texCoord = position2D; 27 | normal = N*mvMatrix; 28 | 29 | position4 = P*mvMatrix - vec4(0.,0.,4.,0.); 30 | position4 /= position4.w; 31 | pointLightingDirection = vec4( 32 | normalize( pointLightingLocation.xyz - position4.xyz ), 0. ); 33 | gl_Position = pMatrix * position4; 34 | } 35 | -------------------------------------------------------------------------------- /pano/.gitignore: -------------------------------------------------------------------------------- 1 | img/ 2 | panos/ 3 | mars/index.html 4 | mars/static-manifest.xml 5 | mars/panos/ 6 | -------------------------------------------------------------------------------- /pano/README.md: -------------------------------------------------------------------------------- 1 | # Ashima webgl-demos 2 | ## Multiple Panorama Viewer 3 | ### Requirements 4 | 5 | To automatically fetch assets or wrap the demo in 6 | [webgl-diagnostic](https://github.com/ashima/webgl-diagnostic), you will 7 | need **make**, **xsltproc**, and **wget**. 8 | 9 | ### Assets 10 | 11 | To automatically fetch the large, binary panorama images, run *make* 12 | *static* in this directory. 13 | 14 | ### Demo Wrapping 15 | 16 | To wrap the Mars demo in 17 | [webgl-diagnostic](https://github.com/ashima/webgl-diagnostic) and 18 | prepare for publication, run *make* in *mars/*. 19 | 20 | -------------------------------------------------------------------------------- /pano/apollo/.gitignore: -------------------------------------------------------------------------------- 1 | index.html 2 | static-manifest.xml 3 | -------------------------------------------------------------------------------- /pano/apollo/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all static clean 2 | 3 | all: index.html static 4 | 5 | static-manifest.xml: manifest.xml 6 | xsltproc ../demo-lib/static-manifest.xsl manifest.xml > static-manifest.xml 7 | 8 | index.html: static-manifest.xml 9 | xsltproc ../gallery.xsl static-manifest.xml > index.html 10 | 11 | static: static-manifest.xml 12 | xsltproc ../demo-lib/local-assets.xsl static-manifest.xml | uniq | sh 13 | 14 | clean: 15 | rm static-manifest.xml index.html -------------------------------------------------------------------------------- /pano/apollo/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /pano/atom.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <xsl:apply-templates select="title" /> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <xsl:apply-templates select="title" /> 67 | 68 | 69 | 70 | 71 |
72 | 73 |
74 |
75 |
76 |
77 | 78 |
79 | -------------------------------------------------------------------------------- /pano/fs.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | #!/bin/sh 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | mkdir -p 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ln -fs 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | xsltproc --stringparam host 51 | 52 | --param subfeed 53 | 54 | ../atom.xsl gallery.xml > 55 | 56 | /index.atom 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | rm -rfv 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /pano/gallery.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pano/lang/en.xml: -------------------------------------------------------------------------------- 1 | 2 | View Gallery 3 | Try Viewing Gallery Anyway 4 | 5 | An Ashima WebGL Demonstration 6 | 7 | Downloading 8 | Download Error 9 | 10 | -------------------------------------------------------------------------------- /pano/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pano/manifest.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /pano/mars/.gitignore: -------------------------------------------------------------------------------- 1 | css/ 2 | engine/ 3 | gallery.xhtml 4 | index.atom 5 | js/ 6 | manifest.xml 7 | mer/ 8 | mpf/ 9 | msl/ 10 | pano.css 11 | pano.js 12 | pano_ui.js 13 | phx/ 14 | webgl-diagnostic/ 15 | -------------------------------------------------------------------------------- /pano/mars/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all dev static fs clean 2 | 3 | OBJS := manifest.xml static-manifest.xml gallery.xhtml index.html index.atom 4 | 5 | all: dev 6 | 7 | manifest.xml: gallery.xml ../manifest.xsl 8 | xsltproc ../manifest.xsl gallery.xml > manifest.xml 9 | 10 | static-manifest.xml: manifest.xml 11 | xsltproc --param rooted true\(\) \ 12 | ../demo-lib/static-manifest.xsl manifest.xml > static-manifest.xml 13 | 14 | gallery.xhtml: gallery.xml ../xhtml.xsl 15 | xsltproc ../xhtml.xsl gallery.xml > gallery.xhtml 16 | 17 | index.html: static-manifest.xml gallery.xhtml ../gallery.xsl 18 | xsltproc ../gallery.xsl static-manifest.xml > index.html 19 | 20 | index.atom: gallery.xml ../atom.xsl 21 | xsltproc ../atom.xsl gallery.xml > index.atom 22 | 23 | fs: gallery.xml ../fs.xsl 24 | xsltproc ../fs.xsl gallery.xml | sh 25 | 26 | dev: fs static-manifest.xml index.html index.atom 27 | xsltproc --stringparam profile dev \ 28 | ../demo-lib/local-assets.xsl static-manifest.xml | uniq | sh 29 | 30 | static: fs static-manifest.xml index.html index.atom 31 | xsltproc --stringparam profile static \ 32 | ../demo-lib/local-assets.xsl static-manifest.xml | uniq | sh 33 | 34 | clean: static-manifest.xml 35 | xsltproc --stringparam action delete \ 36 | ../demo-lib/local-assets.xsl static-manifest.xml | uniq | sh 37 | xsltproc --stringparam action delete \ 38 | ../fs.xsl gallery.xml | sh 39 | rm -f ${OBJS} 40 | 41 | -------------------------------------------------------------------------------- /pano/mars/gallery.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | Mars Panorama Archive 6 | 7 | This is the Ashima Group Mars Panorama Archive. These panoramic 8 | images were captured by NASA/JPL robots on the surface of Mars. 9 | 10 | 11 |
12 | Mars Science Laboratory 13 | The Mars 15 | Science Laboratory is a currently ongoing (as of Aug. 28, 16 | 2012) NASA mission which landed a rover, Curiosity, 17 | in Gale 18 | Crater on Aug. 6, 2012. 19 | 20 | 21 | Curiosity NavCam Full 2012 22 | 2012-09-03T14:06:41-07:00 23 | Captured: 2012 24 | 25 | 26 | Curiosity First Color Pan 2012 27 | 2012-09-03T14:08:41-07:00 28 | Captured: 2012 29 | 30 | 31 | First Curiosity Pan 2012 32 | 2012-09-03T14:10:41-07:00 33 | Captured: 2012 34 | 35 |
36 | 37 |
38 | <term>Phoenix</term> Lander 39 | The Phoenix 41 | Lander descended to the surface of Mars on May 25, 2008. 42 | 43 | 44 | PHX 2008 45 | 2012-08-01T12:00:01-07:00 46 | Captured: 2008 47 | 48 |
49 | 50 |
51 | Mars Exploration Rover 52 | 56 | MER-B 2012 57 | 2012-08-27T13:00:00-07:00 58 | Captured: 2012 59 | 60 | 61 | The Mars 63 | Exploration Rover mission involved two rovers, 64 | Spirit and Opportunity. The rovers 65 | were launched in June and July 2003 and landed successfully in 66 | January 2004. 67 | 68 | 69 | MER-B 2004 70 | 2012-08-01T13:00:00-07:00 71 | Captured: 2004 72 | 73 | 74 | MER-A 2004 75 | 2012-08-01T13:00:01-07:00 76 | Captured: 2004 77 | 78 | 79 | MER-A 2009 80 | 2012-08-01T13:00:02-07:00 81 | Captured: 2009 82 | 83 | 84 | MER-B 2008 85 | 2012-08-01T13:00:03-07:00 86 | Captured: 2008 87 | 88 | 89 | MER-B 2006 90 | 2012-08-01T13:00:04-07:00 91 | Captured: 2006 92 | 93 |
94 | 95 |
96 | Mars Pathfinder 97 | The Mars 99 | Pathfinder mission landed a stationary base station, 100 | Carl Sagan Memorial Station, and a 10.6 kg rover, 101 | Sojourner. 102 | 103 | MPF 1997 104 | 2012-08-01T12:00:00-07:00 105 | Captured: 1997 106 | 107 |
108 |
109 | -------------------------------------------------------------------------------- /pano/pano.css: -------------------------------------------------------------------------------- 1 | /* 2 | ************************************* 3 | WebGL Panorama 4 | Created: 26 sep 2011 5 | Updated: 11 oct 2011 6 | ************************************* 7 | */ 8 | 9 | 10 | body { 11 | font:12px/18px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", helvetica, arial, verdana, sans-serif; 12 | color:#000; 13 | margin:0; 14 | padding:0; 15 | } 16 | 17 | article h1 { font-size: 2em; font-weight: bold; margin: 0.5em 0em; } 18 | article ul { padding-left: 2em; } 19 | nav h1 { font-size: 1.1em; margin: 0; } 20 | 21 | #pano-container { 22 | height:100%; 23 | width:100%; 24 | margin:auto; 25 | display: -moz-box; 26 | display: -webkit-box; 27 | display: box; 28 | } 29 | 30 | nav.gallery-nav { 31 | background-color:#fff; 32 | background:-webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFFFFF), to(#bbb)); 33 | background:-moz-linear-gradient(0% 0% 270deg,#FFFFFF, #bbb); 34 | background: -webkit-linear-gradient(#fff, #bbb); 35 | width:172px; 36 | height:100%; 37 | border-left:1px solid #aaa; 38 | overflow-y: auto; 39 | } 40 | 41 | ul { 42 | list-style:none; 43 | } 44 | 45 | .index ul { 46 | list-style:circle; 47 | } 48 | 49 | .isResizable { 50 | display:block; 51 | -moz-box-flex: 1; 52 | -webkit-box-flex: 1; 53 | box-flex: 1; 54 | clear:both; 55 | background: rgba(0, 0, 0, 0.0); 56 | overflow: scroll; 57 | resize: both; 58 | padding:0; 59 | margin:0; 60 | height:100%; 61 | width:100%; 62 | } 63 | 64 | #zoom { 65 | width:93px; 66 | height:34px; 67 | padding-top:15px; 68 | padding-left:34px; 69 | } 70 | 71 | .zoomin, .zoomout { 72 | width:39px; 73 | height:34px; 74 | float:left; 75 | position:block; 76 | cursor:pointer; 77 | } 78 | 79 | .zoomin { 80 | background:url("img/zoom_more.png") no-repeat scroll top right transparent; 81 | margin-right:15px; 82 | } 83 | 84 | .zoomout { 85 | background:url("img/zoom_less.png") no-repeat scroll top right transparent; 86 | } 87 | 88 | .rss { 89 | width: 34px; height: 34px; 90 | background:url("img/rss.png") no-repeat scroll top right transparent; 91 | } 92 | 93 | .rss:hover { 94 | width: 34px; height:34px; 95 | background:url("img/rss_orange.png") no-repeat scroll top right transparent; 96 | } 97 | 98 | div#navcat { 99 | margin:0 auto; 100 | padding-top:15px; 101 | width:82px; 102 | } 103 | 104 | .status { 105 | display:none; 106 | } 107 | 108 | .pano { 109 | color: #000; 110 | border:1px solid #999; 111 | text-align:center; 112 | margin-bottom:10px; 113 | } 114 | 115 | .pano img { 116 | min-width: 80; 117 | min-height: 40; 118 | max-width: 80; 119 | max-height: 40; 120 | width: 80; 121 | height: 40; 122 | margin-bottom:2px; 123 | cursor:pointer; 124 | } 125 | 126 | .panoInAct { 127 | opacity:0.7; 128 | } 129 | 130 | .panoAct, .pano:hover { 131 | opacity:1.0; 132 | } 133 | 134 | .index { display: none; } 135 | .infoOverlay { 136 | display: block; 137 | position: absolute; 138 | opacity: 0.8; background-color: #bbb; padding: 1em; padding-top: 0; 139 | top: 30px; left: 30px; width: 30%; 140 | } 141 | 142 | .infoOverlay.status { 143 | display: block; 144 | position: absolute; 145 | top: 45%; opacity: 1.0; 146 | left: 30%; right: 40%; 147 | background-color: #bbb; padding: 0.5em; 148 | font-size: 1.5em; 149 | overflow: hidden; 150 | } 151 | 152 | #caption { 153 | position: absolute; 154 | bottom: 2em; left: 1em; 155 | color: white; 156 | opacity: 0.8; 157 | font-size: 2em; 158 | } 159 | -------------------------------------------------------------------------------- /pano/pano.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Multiple Panorama Viewer 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 18 | 19 | 21 | 22 | 24 | 25 | 29 | 30 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 | 118 | 119 | 120 | 121 |
122 | 123 | 124 | -------------------------------------------------------------------------------- /pano/pano.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Description : Simple Panorama Viewing module. 3 | * Author : Ian McEwan, Ashima Arts. 4 | * License : Copyright (C) 2011 Ashima Arts. All rights reserved. 5 | * Distributed under the MIT License. See LICENSE file. 6 | */ 7 | 8 | function ashimaPanoViewer() { 9 | var P = this; 10 | var awe = ashimaWebGLEngine0; 11 | 12 | var gl, prog, verts, panoTex, panoStopTimer; 13 | var pi = 3.1415926535897932384626433832795029 ; 14 | var elemPan, elemRoot, elemCanvas; 15 | var zoom = 1.0; 16 | var saspect = 8 /2; 17 | var panoStopDelay = 500; 18 | 19 | function glinit() { 20 | gl = awe.getGlContext(elemCanvas,{}); 21 | 22 | if (!gl) 23 | throw "No webgl here"; 24 | 25 | var vs = "\ 26 | attribute vec2 p; \ 27 | uniform vec3 z; \ 28 | varying vec3 fpos; \ 29 | void main(void) { \ 30 | fpos = vec3(p*z.z, z.x); \ 31 | fpos.y *= z.y; \ 32 | gl_Position = vec4(p.x,p.y,z.x,1.0); \ 33 | }"; 34 | 35 | var fs = "#ifdef GL_ES\nprecision highp float;\n#endif\n\ 36 | const float ipi = 1.0 / 3.1415926535897932384626433832795029 ; \ 37 | uniform sampler2D pan; \ 38 | uniform mat3 trans; \ 39 | uniform vec2 sas; \ 40 | varying vec3 fpos; \ 41 | void main(void) { \ 42 | vec3 q = normalize(fpos) * trans ; \ 43 | vec2 l = vec2( atan(q.z,q.x) * 0.5, sas.y-asin(q.y)*sas.x) * ipi ; \ 44 | l.y += 0.5; \ 45 | gl_FragColor = texture2D(pan, l.xy ); \ 46 | }"; 47 | 48 | 49 | prog = awe.compileAndLink(vs, fs); 50 | 51 | verts = awe.makeBuffer(gl.ARRAY_BUFFER,gl.FLOAT,2,gl.STATIC_DRAW, 52 | [ -1.,-1., 1.,-1., -1.,1., 1.,1. ] ); 53 | 54 | } 55 | 56 | function renderinit() 57 | { 58 | panoTex = awe.textureCreate(); 59 | panoTex.aweParams( gl.LINEAR, gl.LINEAR, gl.REPEAT, gl.CLAMP_TO_EDGE, false); 60 | gl.disable(gl.DEPTH_TEST); 61 | gl.disable(gl.BLEND); 62 | 63 | prog.aweUse(); 64 | panoTex.aweSet(0, prog.aweSym['pan'] ); 65 | verts.aweSetVertexAttPtr(prog.aweSym["p"]); 66 | } 67 | 68 | var el = 0; 69 | var az = 0; 70 | var prev_el = null; 71 | var prev_az = null; 72 | curW = 0; 73 | curH = 0; 74 | wrap = 4; 75 | function updateElems() { 76 | curW = elemRoot.clientWidth; 77 | curH = elemRoot.clientHeight; 78 | 79 | elemPan.style.width = curW * 2/ zoom + wrap ; 80 | elemPan.style.height = curH * 2/(zoom *saspect); 81 | elemRoot.scrollLeft = az * (elemPan.offsetWidth - curW-wrap) / (2*pi)+wrap/2; 82 | elemRoot.scrollTop = (-el*saspect / pi + 0.5) * (elemPan.offsetHeight - curH) ; 83 | } 84 | 85 | function updateCanvasSize() { 86 | gl.viewport(0, 0, 87 | gl.viewportWidth = elemCanvas.width = curW, 88 | gl.viewportHeight = elemCanvas.height = curH ); 89 | } 90 | 91 | function resizeNow() 92 | { 93 | updateElems(); 94 | updateCanvasSize(); 95 | P.animator.play(); 96 | } 97 | 98 | function render() { 99 | var w = elemRoot.clientWidth; 100 | var h = elemRoot.clientHeight; 101 | 102 | az = 2* pi * ( elemRoot.scrollLeft-wrap/2)/(elemPan.offsetWidth - w - wrap); 103 | el = (1/saspect)* -pi * (elemRoot.scrollTop/(elemPan.offsetHeight - h)-0.5); 104 | if (az > 2*pi) { 105 | az -= 2*pi; 106 | updateElems(); 107 | } 108 | 109 | if (az < 0) { 110 | az += 2*pi; 111 | updateElems(); 112 | } 113 | if (w != curW || h != curH) { 114 | P.animator.pause(); 115 | setTimeout(resizeNow,200); 116 | } 117 | else if (el != prev_el || az != prev_az) 118 | { 119 | var ce = Math.cos(el), se = Math.sin(el); 120 | var ca = Math.cos(az), sa = Math.sin(az); 121 | 122 | var trans = [ ca, -sa*se, sa*ce, 0, ce, se, sa, se*ca, -ca*ce ]; 123 | 124 | var z_dist = 1.0; 125 | 126 | gl.uniform3f(prog.aweSym["z"], z_dist, h/w, zoom); 127 | gl.uniform2f(prog.aweSym["sas"], saspect, 0); 128 | gl.uniformMatrix3fv(prog.aweSym["trans"], false,trans); 129 | gl.drawArrays(gl.TRIANGLE_STRIP,0,verts.aweNumItems); 130 | 131 | prev_el = el; prev_az = az; 132 | clearTimeout(panoStopTimer); 133 | panoStopTimer = setTimeout(P.onPanoStop,panoStopDelay,az,el,zoom); 134 | } 135 | } 136 | 137 | P.updateCanvasSize = updateCanvasSize; 138 | P.updateElems = updateElems; 139 | 140 | P.init = function(p) { 141 | elemRoot = p; 142 | 143 | elemCanvas = document.createElement("canvas"); 144 | elemCanvas.style.zIndex = -1; 145 | elemCanvas.style.position = "absolute"; 146 | elemPan = document.createElement("div"); 147 | elemPan.style.zIndex = 1; 148 | elemPan.appendChild(elemCanvas); 149 | elemRoot.appendChild(elemPan); 150 | 151 | glinit(); 152 | renderinit(); 153 | updateElems(); 154 | updateCanvasSize(); 155 | P.animator = awe.animationStart(render,gl.canvas,1000/30,true); 156 | }; 157 | 158 | P.setImage = function(i) { 159 | var iw = i.naturalWidth, 160 | ih = i.naturalHeight; 161 | saspect = (iw / ih) *0.5 ; 162 | panoTex.aweFromElem(i); 163 | zoom = 1 / saspect; 164 | prev_el = prev_az = null; 165 | resizeNow(); 166 | }; 167 | P.setZoom = function(_z) { 168 | zoom = _z; 169 | updateElems(); 170 | }; 171 | P.setView = function(az_,el_) { 172 | el = el_; 173 | az = az_; 174 | }; 175 | P.onPanoStop = function(az,el,z) { } 176 | }; 177 | -------------------------------------------------------------------------------- /pano/pano_ui.js: -------------------------------------------------------------------------------- 1 | var run_main = false; 2 | var main_pause = function() { // namespace 3 | 4 | var path_prefix = document.querySelector('nav').attributes['data-base-uri'].value; 5 | 6 | var gif1x1 = "data:image/gif;base64,R0lGODlhAQABAJEAAP/Mmf/Mmf4BAgAAACH5BAQUAP8ALAAAAAABAAEAAAICRAEAOw=="; 7 | 8 | var zoomDelta = (1-1/16); 9 | var zoom = 1.0; 10 | 11 | var apv = new ashimaPanoViewer(); 12 | 13 | var addEvent = (document.addEventListener) 14 | ? function (e, v, f, c) { e.addEventListener(v,f,c); } 15 | : function (e, v, f) { e.attachEvent("on"+v,f); } 16 | 17 | var panos = document.querySelectorAll('.pano'); 18 | var subpath_els = document.querySelectorAll('*[data-uri]'); 19 | 20 | function showInfoOverlay(el) { 21 | var div = document.getElementById("panodiv"); 22 | var info = el.cloneNode(true); 23 | info.className += " infoOverlay"; 24 | var internal_links = info.querySelectorAll("a.internal"); 25 | for (var i = 0; i < internal_links.length; i++) { 26 | addEvent(internal_links[i],"click",function(e) { 27 | e.preventDefault(); 28 | pushPath(subpath_of_path(this.pathname+this.hash))(); 29 | },false); 30 | } 31 | div.appendChild(info); 32 | 33 | return info; 34 | } 35 | 36 | function hideInfoOverlay() { 37 | var div = document.getElementById("panodiv"); 38 | var infos = div.querySelectorAll(".infoOverlay"); 39 | if (infos) for (var i = 0; i < infos.length; i++) { 40 | div.removeChild(infos[i]); 41 | } 42 | } 43 | 44 | function showErrorStatus() { 45 | showInfoOverlay(document.getElementById("errormsg")); 46 | } 47 | 48 | function showLoadStatus() { 49 | var loader = showInfoOverlay(document.getElementById("loadmsg")); 50 | var timer = setInterval(function() { 51 | loader.innerText += "."; 52 | }, 200); // TODO: test spinner 53 | return {finish:function() { 54 | clearInterval(timer); 55 | loader.parentNode.removeChild(loader); 56 | }}; 57 | } 58 | 59 | apv.onPanoStop = function(az, el, z) { 60 | var zs = ""; 61 | if (z!=1) zs = "&z="+z; 62 | if (az!=0 || el!=0) 63 | history.replaceState({webgl:1},"","#?az="+az+"&el="+el+zs); 64 | } 65 | 66 | function normHash(h) { 67 | var hfqp = {az: 0, el: 0, z: 1}; 68 | var q = h.substr(2); 69 | var kvp = q.split("&"); 70 | if ("#?" == h.substr(0,2)) { 71 | for (var i = 0; i < kvp.length; i++) { 72 | kvp[i] = kvp[i].split("="); 73 | hfqp[kvp[i][0]] = parseFloat(kvp[i][1]); 74 | } 75 | 76 | apv.onPanoStop(hfqp.az,hfqp.el,hfqp.z); 77 | } 78 | return hfqp; 79 | } 80 | 81 | function showPano(i,subpath) { 82 | var caption = document.getElementById("caption"); 83 | var link = document.getElementById(subpath); 84 | var href = link.attributes['href'].value; 85 | var img = new Image; 86 | var error = false; 87 | img.src = gif1x1; 88 | return function() { 89 | for (var j = 0; j < panos.length; j++) { 90 | panos[j].className = "pano panoInAct"; 91 | } 92 | subpath_els[i].className = "pano panoAct"; 93 | 94 | var spinner = showLoadStatus(); 95 | img.onload = function(e) { 96 | var panoCoord = normHash(window.location.hash); 97 | spinner.finish(); 98 | 99 | apv.setView(panoCoord.az,panoCoord.el); 100 | zoom = 1.0; 101 | apv.setImage(img); 102 | zoom = tryZoom(panoCoord.z); 103 | 104 | caption.innerText = subpath_els[i].querySelector(".thumb").attributes['title'].value; 105 | 106 | // preload the next pano 107 | setTimeout(function () { 108 | var link; 109 | if (subpath_els[i+1].className.indexOf("pano") != -1) { 110 | link = document.getElementById(constructPath(subpath_els[i+1],"")); 111 | (new Image).src = link.attributes['href'].value; 112 | } 113 | },0); 114 | }; 115 | img.onerror = function() { 116 | spinner.finish(); 117 | showErrorStatus(); 118 | error = true; 119 | }; 120 | var a_uri = document.createElement("a"); 121 | a_uri.href = img.src; 122 | if (a_uri.pathname==href && !error) img.onload(); 123 | else if (error) img.onerror(); 124 | else img.src = href; 125 | }; 126 | } 127 | 128 | function showSection(i,subpath) { 129 | return function() { // TODO: check 130 | loadPath(constructPath(subpath_els[i].querySelector(".pano"),"")); 131 | showInfoOverlay(subpath_els[i].querySelector(".index")); 132 | }; 133 | } 134 | 135 | function showIndex() { 136 | return function() { 137 | loadPath(constructPath(document.querySelector(".pano"),"")); 138 | showInfoOverlay(document.querySelector(".index")); 139 | }; 140 | } 141 | 142 | function constructPath(el, path_suffix) { 143 | var attr = el.attributes['data-uri']; 144 | if (attr) { 145 | return constructPath(el.parentNode,attr.value+"/"+path_suffix); 146 | } else { 147 | return path_suffix; 148 | } 149 | } 150 | 151 | var subpaths = {}; 152 | var subpath; 153 | for (var i = 0; i < subpath_els.length; i++) { 154 | subpath = constructPath(subpath_els[i],""); 155 | subpaths[subpath] = { 156 | "section": function() { return showSection(i,subpath); }, 157 | "pano": function() { return showPano(i,subpath); } 158 | }[subpath_els[i].className](); 159 | } 160 | 161 | function loadPath(subpath) { 162 | hideInfoOverlay(); 163 | 164 | if (subpath === "") showIndex()(); 165 | else if (!(subpath in subpaths)) window.location = path_prefix; 166 | else subpaths[subpath](); 167 | } 168 | 169 | function pushPath(subpath) { 170 | return function() { 171 | loadPath(subpath); 172 | history.pushState({webgl:1},"",path_prefix+subpath); 173 | }; 174 | } 175 | 176 | function subpath_of_path(path) { 177 | var subpath_requested = ""; 178 | for (var i = 0; i < path.length; i++) { 179 | if (i >= path_prefix.length || path[i] !== path_prefix[i]) 180 | subpath_requested += path[i]; 181 | } 182 | return subpath_requested; 183 | } 184 | 185 | function tryZoom(z) { 186 | if (z < 1.9) { apv.setZoom(z); return z; } 187 | else return zoom; 188 | } 189 | function zoomIn() { zoom = tryZoom( zoom * zoomDelta) } 190 | function zoomOut() { zoom = tryZoom( zoom / zoomDelta) } 191 | 192 | return [function() { // main 193 | if (!run_main) { 194 | var label,f,img; 195 | apv.init( document.getElementById("panodiv") ); 196 | 197 | for (var i = 0; i < panos.length; i++) { 198 | var pano_path = constructPath(panos[i],""); 199 | addEvent(panos[i], "click", pushPath(pano_path), false); 200 | 201 | label = document.createTextNode(panos[i].querySelector('img').attributes['title'].value); 202 | panos[i].appendChild(label); 203 | } 204 | 205 | function zoomButton(e,f,dt) { 206 | var t = 0; 207 | function clear() { 208 | if (t) { 209 | clearTimeout(t); t = 0; 210 | } 211 | } 212 | addEvent( e, "mousedown", function() { t = setInterval(f,dt); f(); }, false); 213 | addEvent( e, "mouseup", clear, false); 214 | addEvent( e, "mouseout", clear, false); 215 | addEvent( e, "mouseleave", clear, false); 216 | addEvent( e, "blur", clear, false); 217 | } 218 | 219 | zoomButton( document.getElementById("bZoomIn"), zoomIn, 33 ) ; 220 | zoomButton( document.getElementById("bZoomOut"), zoomOut, 33 ) ; 221 | 222 | loadPath(subpath_of_path(window.location.pathname)); 223 | history.replaceState({webgl:1},""); 224 | 225 | run_main = true; 226 | } else { 227 | loadPath(subpath_of_path(window.location.pathname)); 228 | apv.updateElems(); 229 | apv.animator.play(); 230 | } 231 | }, 232 | function() { // pause 233 | apv.animator.pause(); 234 | }]; 235 | }(); 236 | 237 | main = main_pause[0]; 238 | pause = main_pause[1]; 239 | -------------------------------------------------------------------------------- /pano/subpath.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | \'\' 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /pano/xhtml.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <xsl:apply-templates select="title" /> 15 | 19 | 20 | 21 |
22 |
23 |
24 |
25 | 41 | 42 | 43 | 44 |
45 | 46 | 47 |
48 | 49 | 50 | 51 |

52 |
53 | 54 | 55 |
56 | 57 | 58 | 59 | 60 |
61 |
62 | 63 | 64 |
65 | 66 |
67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 |

80 |

81 | 82 |

83 | 93 | 94 |
95 | 96 |
97 | 98 | 99 | 100 | --------------------------------------------------------------------------------