diff --git a/src/tiledimage.js b/src/tiledimage.js
index 21fb1e13..7992ee57 100644
--- a/src/tiledimage.js
+++ b/src/tiledimage.js
@@ -303,6 +303,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
this._tileCache.clearTilesFor(this);
this.lastResetTime = $.now();
this._needsDraw = true;
+ this._fullyLoaded = false;
},
/**
diff --git a/test/demo/basic2.html b/test/demo/basic2.html
deleted file mode 100644
index bcfdb78b..00000000
--- a/test/demo/basic2.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
- OpenSeadragon maxTilesPerFrame Demo
-
-
-
-
-
-
- Simple demo page to show an OpenSeadragon viewer with a higher maxTilesPerFrame.
-
-
-
-
-
diff --git a/test/demo/old-plugins/filtering/index.html b/test/demo/old-plugins/filtering/index.html
new file mode 100644
index 00000000..2a2265bc
--- /dev/null
+++ b/test/demo/old-plugins/filtering/index.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+ OpenSeadragon Filtering
+
+
+
+
+
+
+
+
+
+
+ OpenSeadragon filtering plugin demo.
+
+
+
+
+ Demo of the OpenSeadragon filtering plugin.
+ Code and documentation are available on
+ GitHub.
+
+
+ Add/remove filters to visualize the effects.
+
+
+
+
+
+
+
+
+
Available filters
+
+
+
Selected filters
+
+
+
Drag and drop the selected filters to set their order.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/demo/old-plugins/filtering/style.css b/test/demo/old-plugins/filtering/style.css
new file mode 100644
index 00000000..5e91cd26
--- /dev/null
+++ b/test/demo/old-plugins/filtering/style.css
@@ -0,0 +1,83 @@
+/*
+This software was developed at the National Institute of Standards and
+Technology by employees of the Federal Government in the course of
+their official duties. Pursuant to title 17 Section 105 of the United
+States Code this software is not subject to copyright protection and is
+in the public domain. This software is an experimental system. NIST assumes
+no responsibility whatsoever for its use by other parties, and makes no
+guarantees, expressed or implied, about its quality, reliability, or
+any other characteristic. We would appreciate acknowledgement if the
+software is used.
+*/
+.demo {
+ line-height: normal;
+}
+
+.demo h3 {
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+#openseadragon {
+ width: 100%;
+ height: 700px;
+ background-color: black;
+}
+
+.wdzt-table-layout {
+ display: table;
+}
+
+.wdzt-row-layout {
+ display: table-row;
+}
+
+.wdzt-cell-layout {
+ display: table-cell;
+}
+
+.wdzt-full-width {
+ width: 100%;
+}
+
+.wdzt-menu-slider {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.column-2 {
+ width: 50%;
+ vertical-align: top;
+ padding: 3px;
+}
+
+#available {
+ list-style-type: none;
+}
+
+ul {
+ padding: 0;
+ border: 1px solid black;
+ min-height: 25px;
+}
+
+li {
+ padding: 3px;
+}
+
+#selected {
+ list-style-type: none;
+}
+
+.button {
+ cursor: pointer;
+ vertical-align: text-top;
+}
+
+.filterLabel {
+ min-width: 120px;
+}
+
+#selected .filterLabel {
+ cursor: move;
+}
diff --git a/test/demo/old-plugins/via-webgl/fs.glsl b/test/demo/old-plugins/via-webgl/fs.glsl
new file mode 100644
index 00000000..3d3019af
--- /dev/null
+++ b/test/demo/old-plugins/via-webgl/fs.glsl
@@ -0,0 +1,71 @@
+precision mediump float;
+uniform sampler2D u_tile;
+uniform vec2 u_tile_size;
+varying vec2 v_tile_pos;
+
+// Sum a vector
+float sum3(vec3 v) {
+ return dot(v,vec3(1));
+}
+
+// Weight of a matrix
+float weigh3(mat3 m) {
+ return sum3(m[0])+sum3(m[1])+sum3(m[2]);
+}
+
+// Take the outer product
+mat3 outer3(vec3 c, vec3 r) {
+ mat3 goal;
+ for (int i =0; i<3; i++) {
+ goal[i] = r*c[i];
+ }
+ return goal;
+}
+
+//*~*~*~*~*~*~*~*~*~*~*~*~*~
+// Now for the Sobel Program
+//*~
+
+// Sample the color at offset
+vec3 color(float dx, float dy) {
+ // calculate the color of sampler at an offset from position
+ return texture2D(u_tile, v_tile_pos+vec2(dx,dy)).rgb;
+}
+
+float sobel(mat3 kernel, vec3 near_in[9]) {
+
+ // nearest pixels
+ mat3 near_out[3];
+
+ // Get all near_in pixels
+ for (int i = 0; i < 3; i++) {
+ near_out[i][0] = kernel[0]*vec3(near_in[0][i],near_in[1][i],near_in[2][i]);
+ near_out[i][1] = kernel[1]*vec3(near_in[3][i],near_in[4][i],near_in[5][i]);
+ near_out[i][2] = kernel[2]*vec3(near_in[6][i],near_in[7][i],near_in[8][i]);
+ }
+
+ // convolve the kernel with the nearest pixels
+ return length(vec3(weigh3(near_out[0]),weigh3(near_out[1]),weigh3(near_out[2])));
+}
+
+void main() {
+ // Prep work
+ vec3 near_in[9];
+ vec3 mean = vec3(1,2,1);
+ vec3 slope = vec3(-1,0,1);
+ mat3 sobelX = outer3(mean,slope);
+ mat3 sobelY = outer3(slope,mean);
+ vec2 u = vec2(1./u_tile_size.x, 1./u_tile_size.y);
+ // Calculate coordinates of nearest points
+ for (int i = 0; i < 9; i++) {
+ near_in[i] = color(mod(float(i),3.)*u.x, float(i/3-1)*u.y);
+ }
+
+ // Show the mixed XY contrast
+ float edgeX = sobel(sobelX, near_in);
+ float edgeY = sobel(sobelY, near_in);
+ float mixed = length(vec2(edgeX,edgeY));
+// mixed = (max(mixed,0.5)-0.5);
+
+ gl_FragColor = vec4(vec3(mixed),1);
+}
diff --git a/test/demo/old-plugins/via-webgl/index.html b/test/demo/old-plugins/via-webgl/index.html
new file mode 100644
index 00000000..893a9245
--- /dev/null
+++ b/test/demo/old-plugins/via-webgl/index.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+ GLSL shaders for zoomable DZI images: openSeadragonGL
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/demo/old-plugins/via-webgl/osd-gl.js b/test/demo/old-plugins/via-webgl/osd-gl.js
new file mode 100644
index 00000000..cefd2bdc
--- /dev/null
+++ b/test/demo/old-plugins/via-webgl/osd-gl.js
@@ -0,0 +1,102 @@
+/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
+/* openSeadragonGL - Set Shaders in OpenSeaDragon with viaWebGL
+*/
+openSeadragonGL = function(openSD) {
+
+ /* OpenSeaDragon API calls
+ ~*~*~*~*~*~*~*~*~*~*~*~*/
+ this.interface = {
+ 'tile-loaded': function(e) {
+ // Set the imageSource as a data URL and then complete
+ var output = this.viaGL.toCanvas(e.image);
+ e.image.onload = e.getCompletionCallback();
+ e.image.src = output.toDataURL();
+ },
+ 'tile-drawing': function(e) {
+ // Render a webGL canvas to an input canvas
+ var input = e.rendered.canvas;
+ e.rendered.drawImage(this.viaGL.toCanvas(input), 0, 0, input.width, input.height);
+ }
+ };
+ this.defaults = {
+ 'tile-loaded': function(callback, e) {
+ callback(e);
+ },
+ 'tile-drawing': function(callback, e) {
+ if (e.tile.loaded !==1) {
+ e.tile.loaded = 1;
+ callback(e);
+ }
+ }
+ };
+ this.openSD = openSD;
+ this.viaGL = new ViaWebGL();
+};
+
+openSeadragonGL.prototype = {
+ // Map to viaWebGL and openSeadragon
+ init: function() {
+ var open = this.merger.bind(this);
+ this.openSD.addHandler('open',open);
+ return this;
+ },
+ // User adds events
+ addHandler: function(key,custom) {
+ if (key in this.defaults){
+ this[key] = this.defaults[key];
+ }
+ if (typeof custom == 'function') {
+ this[key] = custom;
+ }
+ },
+ // Merge with viaGL
+ merger: function(e) {
+ // Take GL height and width from OpenSeaDragon
+ this.width = this.openSD.source.getTileWidth();
+ this.height = this.openSD.source.getTileHeight();
+ // Add all viaWebGL properties
+ for (var key of this.and(this.viaGL)) {
+ this.viaGL[key] = this[key];
+ }
+ this.viaGL.init().then(this.adder.bind(this));
+ },
+ // Add all seadragon properties
+ adder: function(e) {
+ for (var key of this.and(this.defaults)) {
+ var handler = this[key].bind(this);
+ var interface = this.interface[key].bind(this);
+ // Add all openSeadragon event handlers
+ this.openSD.addHandler(key, function(e) {
+ handler.call(this, interface, e);
+ });
+ }
+ },
+ // Joint keys
+ and: function(obj) {
+ return Object.keys(obj).filter(Object.hasOwnProperty,this);
+ },
+ // Add your own button to OSD controls
+ button: function(terms) {
+
+ var name = terms.name || 'tool';
+ var prefix = terms.prefix || this.openSD.prefixUrl;
+ if (!terms.hasOwnProperty('onClick')){
+ terms.onClick = this.shade;
+ }
+ terms.onClick = terms.onClick.bind(this);
+ terms.srcRest = terms.srcRest || prefix+name+'_rest.png';
+ terms.srcHover = terms.srcHover || prefix+name+'_hover.png';
+ terms.srcDown = terms.srcDown || prefix+name+'_pressed.png';
+ terms.srcGroup = terms.srcGroup || prefix+name+'_grouphover.png';
+ // Replace the current controls with the same controls plus a new button
+ this.openSD.clearControls().buttons.buttons.push(new OpenSeadragon.Button(terms));
+ var toolbar = new OpenSeadragon.ButtonGroup({buttons: this.openSD.buttons.buttons});
+ this.openSD.addControl(toolbar.element,{anchor: OpenSeadragon.ControlAnchor.TOP_LEFT});
+ },
+ // Switch Shaders on or off
+ shade: function() {
+
+ this.viaGL.on++;
+ this.openSD.world.resetItems();
+ }
+}
diff --git a/test/demo/old-plugins/via-webgl/viawebgl.js b/test/demo/old-plugins/via-webgl/viawebgl.js
new file mode 100644
index 00000000..17c99adb
--- /dev/null
+++ b/test/demo/old-plugins/via-webgl/viawebgl.js
@@ -0,0 +1,201 @@
+/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
+/* viaWebGL
+/* Set shaders on Image or Canvas with WebGL
+/* Built on 2016-9-9
+/* http://via.hoff.in
+*/
+ViaWebGL = function(incoming) {
+
+ /* Custom WebGL API calls
+ ~*~*~*~*~*~*~*~*~*~*~*~*/
+ this['gl-drawing'] = function(e) { return e; };
+ this['gl-loaded'] = function(e) { return e; };
+ this.ready = function(e) { return e; };
+
+ var gl = this.maker();
+ this.flat = document.createElement('canvas').getContext('2d');
+ this.tile_size = 'u_tile_size';
+ this.vShader = 'vShader.glsl';
+ this.fShader = 'fShader.glsl';
+ this.wrap = gl.CLAMP_TO_EDGE;
+ this.tile_pos = 'a_tile_pos';
+ this.filter = gl.NEAREST;
+ this.pos = 'a_pos';
+ this.height = 128;
+ this.width = 128;
+ this.on = 0;
+ this.gl = gl;
+ // Assign from incoming terms
+ for (var key in incoming) {
+ this[key] = incoming[key];
+ }
+};
+
+ViaWebGL.prototype = {
+
+ init: function(source) {
+ var ready = this.ready;
+ // Allow for mouse actions on click
+ if (this.hasOwnProperty('container') && this.hasOwnProperty('onclick')) {
+ this.container.onclick = this[this.onclick].bind(this);
+ }
+ if (source && source.height && source.width) {
+ this.ready = this.toCanvas.bind(this,source);
+ this.height = source.height;
+ this.width = source.width;
+ }
+ this.source = source;
+ this.gl.canvas.width = this.width;
+ this.gl.canvas.height = this.height;
+ this.gl.viewport(0, 0, this.width, this.height);
+ // Load the shaders when ready and return the promise
+ var step = [[this.vShader, this.fShader].map(this.getter)];
+ step.push(this.toProgram.bind(this), this.toBuffers.bind(this));
+ return Promise.all(step[0]).then(step[1]).then(step[2]).then(this.ready);
+
+ },
+ // Make a canvas
+ maker: function(options){
+ return this.context(document.createElement('canvas'));
+ },
+ context: function(a){
+ return a.getContext('experimental-webgl') || a.getContext('webgl');
+ },
+ // Get a file as a promise
+ getter: function(where) {
+ return new Promise(function(done){
+ // Return if not a valid filename
+ if (where.slice(-4) != 'glsl') {
+ return done(where);
+ }
+ var bid = new XMLHttpRequest();
+ var win = function(){
+ if (bid.status == 200) {
+ return done(bid.response);
+ }
+ return done(where);
+ };
+ bid.open('GET', where, true);
+ bid.onerror = bid.onload = win;
+ bid.send();
+ });
+ },
+ // Link shaders from strings
+ toProgram: function(files) {
+ var gl = this.gl;
+ var program = gl.createProgram();
+ var ok = function(kind,status,value,sh) {
+ if (!gl['get'+kind+'Parameter'](value, gl[status+'_STATUS'])){
+ console.log((sh||'LINK')+':\n'+gl['get'+kind+'InfoLog'](value));
+ }
+ return value;
+ }
+ // 1st is vertex; 2nd is fragment
+ files.map(function(given,i) {
+ var sh = ['VERTEX_SHADER', 'FRAGMENT_SHADER'][i];
+ var shader = gl.createShader(gl[sh]);
+ gl.shaderSource(shader, given);
+ gl.compileShader(shader);
+ gl.attachShader(program, shader);
+ ok('Shader','COMPILE',shader,sh);
+ });
+ gl.linkProgram(program);
+ return ok('Program','LINK',program);
+ },
+ // Load data to the buffers
+ toBuffers: function(program) {
+
+ // Allow for custom loading
+ this.gl.useProgram(program);
+ this['gl-loaded'].call(this, program);
+
+ // Unchangeable square array buffer fills viewport with texture
+ var boxes = [[-1, 1,-1,-1, 1, 1, 1,-1], [0, 1, 0, 0, 1, 1, 1, 0]];
+ var buffer = new Float32Array([].concat.apply([], boxes));
+ var bytes = buffer.BYTES_PER_ELEMENT;
+ var gl = this.gl;
+ var count = 4;
+
+ // Get uniform term
+ var tile_size = gl.getUniformLocation(program, this.tile_size);
+ gl.uniform2f(tile_size, gl.canvas.height, gl.canvas.width);
+
+ // Get attribute terms
+ this.att = [this.pos, this.tile_pos].map(function(name, number) {
+
+ var index = Math.min(number, boxes.length-1);
+ var vec = Math.floor(boxes[index].length/count);
+ var vertex = gl.getAttribLocation(program, name);
+
+ return [vertex, vec, gl.FLOAT, 0, vec*bytes, count*index*vec*bytes];
+ });
+ // Get texture
+ this.tex = {
+ texParameteri: [
+ [gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrap],
+ [gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrap],
+ [gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.filter],
+ [gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.filter]
+ ],
+ texImage2D: [gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE],
+ bindTexture: [gl.TEXTURE_2D, gl.createTexture()],
+ drawArrays: [gl.TRIANGLE_STRIP, 0, count],
+ pixelStorei: [gl.UNPACK_FLIP_Y_WEBGL, 1]
+ };
+ // Build the position and texture buffer
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+ gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
+ },
+ // Turns image or canvas into a rendered canvas
+ toCanvas: function(tile) {
+ // Stop Rendering
+ if (this.on%2 !== 0) {
+ if(tile.nodeName == 'IMG') {
+ this.flat.canvas.width = tile.width;
+ this.flat.canvas.height = tile.height;
+ this.flat.drawImage(tile,0,0,tile.width,tile.height);
+ return this.flat.canvas;
+ }
+ return tile;
+ }
+
+ // Allow for custom drawing in webGL
+ this['gl-drawing'].call(this,tile);
+ var gl = this.gl;
+
+ // Set Attributes for GLSL
+ this.att.map(function(x){
+
+ gl.enableVertexAttribArray(x.slice(0,1));
+ gl.vertexAttribPointer.apply(gl, x);
+ });
+
+ // Set Texture for GLSL
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture.apply(gl, this.tex.bindTexture);
+ gl.pixelStorei.apply(gl, this.tex.pixelStorei);
+
+ // Apply texture parameters
+ this.tex.texParameteri.map(function(x){
+ gl.texParameteri.apply(gl, x);
+ });
+ // Send the tile into the texture.
+ var output = this.tex.texImage2D.concat([tile]);
+ gl.texImage2D.apply(gl, output);
+
+ // Draw everything needed to canvas
+ gl.drawArrays.apply(gl, this.tex.drawArrays);
+
+ // Apply to container if needed
+ if (this.container) {
+ this.container.appendChild(this.gl.canvas);
+ }
+ return this.gl.canvas;
+ },
+ toggle: function() {
+ this.on ++;
+ this.container.innerHTML = '';
+ this.container.appendChild(this.toCanvas(this.source));
+
+ }
+}
diff --git a/test/demo/old-plugins/via-webgl/vs.glsl b/test/demo/old-plugins/via-webgl/vs.glsl
new file mode 100644
index 00000000..1d42f156
--- /dev/null
+++ b/test/demo/old-plugins/via-webgl/vs.glsl
@@ -0,0 +1,9 @@
+attribute vec4 a_pos;
+attribute vec2 a_tile_pos;
+varying vec2 v_tile_pos;
+
+void main() {
+ // Pass the overlay tiles
+ v_tile_pos = a_tile_pos;
+ gl_Position = a_pos;
+}