mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-21 20:56:09 +03:00
Merge pull request #3 from Aiosa/rotation-seams
Exposing matrix implementation, automatic drawer recognition Thanks, @Aiosa!
This commit is contained in:
commit
d912ff3196
13
Gruntfile.js
13
Gruntfile.js
@ -28,6 +28,7 @@ module.exports = function(grunt) {
|
||||
coverageDir = 'coverage/' + dateFormat(new Date(), 'yyyymmdd-HHMMss'),
|
||||
sources = [
|
||||
"src/openseadragon.js",
|
||||
"src/matrix.js",
|
||||
"src/fullscreen.js",
|
||||
"src/eventsource.js",
|
||||
"src/mousetracker.js",
|
||||
@ -64,7 +65,15 @@ module.exports = function(grunt) {
|
||||
"src/viewport.js",
|
||||
"src/tiledimage.js",
|
||||
"src/tilecache.js",
|
||||
"src/world.js"
|
||||
"src/world.js",
|
||||
|
||||
// Aiosa's webgl drawer - needs optimization, polishing, trimming
|
||||
// "src/webgl/webGLWrapper.js",
|
||||
// "src/webgl/visualisationLayer.js",
|
||||
// "src/webgl/dataLoader.js",
|
||||
// "src/webgl/webGLContext.js",
|
||||
// "src/webgl/drawer.js",
|
||||
// "src/webgl/plainShader.js",
|
||||
];
|
||||
|
||||
var banner = "//! <%= pkg.name %> <%= pkg.version %>\n" +
|
||||
@ -195,7 +204,7 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: [ "Gruntfile.js", "src/*.js", "images/*" ],
|
||||
files: [ "Gruntfile.js", "src/*.js", "images/*" /*, "src/webgl/*.js" */ ],
|
||||
tasks: "watchTask"
|
||||
},
|
||||
eslint: {
|
||||
|
@ -108,9 +108,7 @@ $.DrawerBase = class DrawerBase{
|
||||
|
||||
this._checkForAPIOverrides();
|
||||
}
|
||||
get isOpenSeadragonDrawer(){
|
||||
return true;
|
||||
}
|
||||
|
||||
get canvas(){
|
||||
if(!this._renderingTarget){
|
||||
this._renderingTarget = this.createDrawingElement();
|
||||
|
123
src/matrix.js
Normal file
123
src/matrix.js
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* OpenSeadragon - Mat3
|
||||
*
|
||||
* Modified from https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html
|
||||
* Copyright (C) 2010-2023 webglfundamentals.org and OpenSeadragon contributors
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of CodePlex Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
(function( $ ){
|
||||
|
||||
/**
|
||||
* Matrix left-to-right system representation
|
||||
*/
|
||||
$.Mat3 = class Mat3 {
|
||||
constructor(values){
|
||||
if(!values) {
|
||||
values = [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0
|
||||
];
|
||||
}
|
||||
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
static makeIdentity(){
|
||||
return new Mat3([
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1
|
||||
]);
|
||||
}
|
||||
|
||||
static makeTranslation(tx, ty) {
|
||||
return new Mat3([
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
tx, ty, 1,
|
||||
]);
|
||||
}
|
||||
|
||||
static makeRotation(angleInRadians) {
|
||||
var c = Math.cos(angleInRadians);
|
||||
var s = Math.sin(angleInRadians);
|
||||
return new Mat3([
|
||||
c, -s, 0,
|
||||
s, c, 0,
|
||||
0, 0, 1,
|
||||
]);
|
||||
}
|
||||
|
||||
static makeScaling(sx, sy) {
|
||||
return new Mat3([
|
||||
sx, 0, 0,
|
||||
0, sy, 0,
|
||||
0, 0, 1,
|
||||
]);
|
||||
}
|
||||
|
||||
multiply(other) {
|
||||
let a = this.values;
|
||||
let b = other.values;
|
||||
|
||||
var a00 = a[0 * 3 + 0];
|
||||
var a01 = a[0 * 3 + 1];
|
||||
var a02 = a[0 * 3 + 2];
|
||||
var a10 = a[1 * 3 + 0];
|
||||
var a11 = a[1 * 3 + 1];
|
||||
var a12 = a[1 * 3 + 2];
|
||||
var a20 = a[2 * 3 + 0];
|
||||
var a21 = a[2 * 3 + 1];
|
||||
var a22 = a[2 * 3 + 2];
|
||||
var b00 = b[0 * 3 + 0];
|
||||
var b01 = b[0 * 3 + 1];
|
||||
var b02 = b[0 * 3 + 2];
|
||||
var b10 = b[1 * 3 + 0];
|
||||
var b11 = b[1 * 3 + 1];
|
||||
var b12 = b[1 * 3 + 2];
|
||||
var b20 = b[2 * 3 + 0];
|
||||
var b21 = b[2 * 3 + 1];
|
||||
var b22 = b[2 * 3 + 2];
|
||||
return new Mat3([
|
||||
b00 * a00 + b01 * a10 + b02 * a20,
|
||||
b00 * a01 + b01 * a11 + b02 * a21,
|
||||
b00 * a02 + b01 * a12 + b02 * a22,
|
||||
b10 * a00 + b11 * a10 + b12 * a20,
|
||||
b10 * a01 + b11 * a11 + b12 * a21,
|
||||
b10 * a02 + b11 * a12 + b12 * a22,
|
||||
b20 * a00 + b21 * a10 + b22 * a20,
|
||||
b20 * a01 + b21 * a11 + b22 * a21,
|
||||
b20 * a02 + b21 * a12 + b22 * a22,
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
}( OpenSeadragon ));
|
@ -1473,7 +1473,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
* @param {Number} levelOpacity
|
||||
* @param {Number} currentTime
|
||||
* @param {Boolean} lowestLevel
|
||||
* @returns {Boolean} whether the opacity of this tile has changed
|
||||
* @returns {Boolean} true if blending did not yet finish
|
||||
*/
|
||||
_blendTile: function(tile, x, y, level, levelOpacity, currentTime, lowestLevel ){
|
||||
let blendTimeMillis = 1000 * this.blendTime,
|
||||
|
@ -445,33 +445,30 @@ $.Viewer = function( options ) {
|
||||
|
||||
delete this.drawerOptions.useCanvas;
|
||||
}
|
||||
let drawerPriority = Array.isArray(this.drawer) ? this.drawer : [this.drawer];
|
||||
let drawersToTry = drawerPriority.filter(d => ['webgl', 'canvas', 'html'].includes(d) || (d.prototype && d.prototype.isOpenSeadragonDrawer) );
|
||||
if(drawerPriority.length !== drawersToTry.length){
|
||||
$.console.error('An invalid drawer was requested.');
|
||||
}
|
||||
if(drawersToTry.length === 0){
|
||||
drawersToTry = [$.DEFAULT_SETTINGS.drawer].flat(); // ensure it is a list
|
||||
let drawerCandidates = Array.isArray(this.drawer) ? this.drawer : [this.drawer];
|
||||
if (drawerCandidates.length === 0){
|
||||
drawerCandidates = [$.DEFAULT_SETTINGS.drawer].flat(); // ensure it is a list
|
||||
$.console.warn('No valid drawers were selected. Using the default value.');
|
||||
}
|
||||
// extend the drawerOptions object with additional properties to pass to the Drawer implementation
|
||||
this.drawer = null; // TO DO: how to deal with the possibility that none of the requested drawers are supported?
|
||||
for(let i = 0; i < drawersToTry.length; i++){
|
||||
let Drawer = drawersToTry[i];
|
||||
let optsKey = null;
|
||||
// replace text-based option with appropriate constructor
|
||||
if (Drawer === 'canvas'){
|
||||
Drawer = $.CanvasDrawer;
|
||||
optsKey = 'canvas';
|
||||
} else if (Drawer === 'html'){
|
||||
Drawer = $.HTMLDrawer;
|
||||
optsKey = 'html';
|
||||
} else if (Drawer === 'webgl'){
|
||||
Drawer = $.WebGLDrawer;
|
||||
optsKey = 'webgl';
|
||||
// TODO: how to deal with the possibility that none of the requested drawers are supported?
|
||||
this.drawer = null;
|
||||
for (let i = 0; i < drawerCandidates.length; i++) {
|
||||
|
||||
let drawerCandidate = drawerCandidates[i];
|
||||
let Drawer = null;
|
||||
|
||||
//if inherits from a drawer base, use it
|
||||
if (drawerCandidate && drawerCandidate.prototype instanceof $.DrawerBase) {
|
||||
Drawer = drawerCandidate;
|
||||
drawerCandidate = 'custom';
|
||||
} else if (typeof drawerCandidate === "string") {
|
||||
Drawer = $.determineDrawer(drawerCandidate);
|
||||
} else {
|
||||
optsKey = 'custom';
|
||||
$.console.warn('Unsupported drawer! Drawer must be an existing string type, or a class that extends OpenSeadragon.DrawerBase.');
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the drawer is supported, create it and break the loop
|
||||
if (Drawer.isSupported()) {
|
||||
this.drawer = new Drawer({
|
||||
@ -479,13 +476,13 @@ $.Viewer = function( options ) {
|
||||
viewport: this.viewport,
|
||||
element: this.canvas,
|
||||
debugGridColor: this.debugGridColor,
|
||||
options: this.drawerOptions[optsKey],
|
||||
options: this.drawerOptions[drawerCandidate],
|
||||
});
|
||||
this.drawerOptions.constructor = Drawer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(this.drawer === null){
|
||||
if (!this.drawer){
|
||||
$.console.error('No drawer could be created!');
|
||||
throw('Error with creating the selected drawer(s)');
|
||||
}
|
||||
@ -4002,4 +3999,22 @@ function onFlip() {
|
||||
this.viewport.toggleFlip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find drawer
|
||||
*/
|
||||
$.determineDrawer = function( id ){
|
||||
for (let property in OpenSeadragon) {
|
||||
const drawer = OpenSeadragon[ property ],
|
||||
proto = drawer.prototype;
|
||||
if( proto &&
|
||||
proto instanceof OpenSeadragon.DrawerBase &&
|
||||
$.isFunction( proto.getType ) &&
|
||||
proto.getType.call( drawer ) === id
|
||||
){
|
||||
return drawer;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
}( OpenSeadragon ));
|
||||
|
@ -35,92 +35,6 @@
|
||||
|
||||
(function( $ ){
|
||||
|
||||
// internal class Mat3: implements matrix operations
|
||||
// Modified from https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html
|
||||
class Mat3{
|
||||
constructor(values){
|
||||
if(!values) {
|
||||
values = [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0
|
||||
];
|
||||
}
|
||||
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
static makeIdentity(){
|
||||
return new Mat3([
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1
|
||||
]);
|
||||
}
|
||||
|
||||
static makeTranslation(tx, ty) {
|
||||
return new Mat3([
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
tx, ty, 1,
|
||||
]);
|
||||
}
|
||||
|
||||
static makeRotation(angleInRadians) {
|
||||
var c = Math.cos(angleInRadians);
|
||||
var s = Math.sin(angleInRadians);
|
||||
return new Mat3([
|
||||
c, -s, 0,
|
||||
s, c, 0,
|
||||
0, 0, 1,
|
||||
]);
|
||||
}
|
||||
|
||||
static makeScaling(sx, sy) {
|
||||
return new Mat3([
|
||||
sx, 0, 0,
|
||||
0, sy, 0,
|
||||
0, 0, 1,
|
||||
]);
|
||||
}
|
||||
|
||||
multiply(other) {
|
||||
let a = this.values;
|
||||
let b = other.values;
|
||||
|
||||
var a00 = a[0 * 3 + 0];
|
||||
var a01 = a[0 * 3 + 1];
|
||||
var a02 = a[0 * 3 + 2];
|
||||
var a10 = a[1 * 3 + 0];
|
||||
var a11 = a[1 * 3 + 1];
|
||||
var a12 = a[1 * 3 + 2];
|
||||
var a20 = a[2 * 3 + 0];
|
||||
var a21 = a[2 * 3 + 1];
|
||||
var a22 = a[2 * 3 + 2];
|
||||
var b00 = b[0 * 3 + 0];
|
||||
var b01 = b[0 * 3 + 1];
|
||||
var b02 = b[0 * 3 + 2];
|
||||
var b10 = b[1 * 3 + 0];
|
||||
var b11 = b[1 * 3 + 1];
|
||||
var b12 = b[1 * 3 + 2];
|
||||
var b20 = b[2 * 3 + 0];
|
||||
var b21 = b[2 * 3 + 1];
|
||||
var b22 = b[2 * 3 + 2];
|
||||
return new Mat3([
|
||||
b00 * a00 + b01 * a10 + b02 * a20,
|
||||
b00 * a01 + b01 * a11 + b02 * a21,
|
||||
b00 * a02 + b01 * a12 + b02 * a22,
|
||||
b10 * a00 + b11 * a10 + b12 * a20,
|
||||
b10 * a01 + b11 * a11 + b12 * a21,
|
||||
b10 * a02 + b11 * a12 + b12 * a22,
|
||||
b20 * a00 + b21 * a10 + b22 * a20,
|
||||
b20 * a01 + b21 * a11 + b22 * a21,
|
||||
b20 * a02 + b21 * a12 + b22 * a22,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @class WebGLDrawer
|
||||
* @memberof OpenSeadragon
|
||||
@ -277,9 +191,9 @@
|
||||
|
||||
let flipMultiplier = this.viewport.flipped ? -1 : 1;
|
||||
// calculate view matrix for viewer
|
||||
let posMatrix = Mat3.makeTranslation(-viewport.center.x, -viewport.center.y);
|
||||
let scaleMatrix = Mat3.makeScaling(2 / viewport.bounds.width * flipMultiplier, -2 / viewport.bounds.height);
|
||||
let rotMatrix = Mat3.makeRotation(-viewport.rotation);
|
||||
let posMatrix = $.Mat3.makeTranslation(-viewport.center.x, -viewport.center.y);
|
||||
let scaleMatrix = $.Mat3.makeScaling(2 / viewport.bounds.width * flipMultiplier, -2 / viewport.bounds.height);
|
||||
let rotMatrix = $.Mat3.makeRotation(-viewport.rotation);
|
||||
let viewMatrix = scaleMatrix.multiply(rotMatrix).multiply(posMatrix);
|
||||
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
@ -343,10 +257,10 @@
|
||||
let imageRotation = tiledImage.getRotation(true);
|
||||
// if needed, handle the tiledImage being rotated
|
||||
if( imageRotation % 360 !== 0){
|
||||
let imageRotationMatrix = Mat3.makeRotation(-imageRotation * Math.PI / 180);
|
||||
let imageRotationMatrix = $.Mat3.makeRotation(-imageRotation * Math.PI / 180);
|
||||
let imageCenter = tiledImage.getBoundsNoRotate(true).getCenter();
|
||||
let t1 = Mat3.makeTranslation(imageCenter.x, imageCenter.y);
|
||||
let t2 = Mat3.makeTranslation(-imageCenter.x, -imageCenter.y);
|
||||
let t1 = $.Mat3.makeTranslation(imageCenter.x, imageCenter.y);
|
||||
let t2 = $.Mat3.makeTranslation(-imageCenter.x, -imageCenter.y);
|
||||
|
||||
// update the view matrix to account for this image's rotation
|
||||
let localMatrix = t1.multiply(imageRotationMatrix).multiply(t2);
|
||||
@ -572,7 +486,7 @@
|
||||
let w = right - x;
|
||||
let h = bottom - y;
|
||||
|
||||
let matrix = new Mat3([
|
||||
let matrix = new $.Mat3([
|
||||
w, 0, 0,
|
||||
0, h, 0,
|
||||
x, y, 1,
|
||||
@ -580,11 +494,11 @@
|
||||
|
||||
if(tile.flipped){
|
||||
// flip the tile around the center of the unit quad
|
||||
let t1 = Mat3.makeTranslation(0.5, 0);
|
||||
let t2 = Mat3.makeTranslation(-0.5, 0);
|
||||
let t1 = $.Mat3.makeTranslation(0.5, 0);
|
||||
let t2 = $.Mat3.makeTranslation(-0.5, 0);
|
||||
|
||||
// update the view matrix to account for this image's rotation
|
||||
let localMatrix = t1.multiply(Mat3.makeScaling(-1, 1)).multiply(t2);
|
||||
let localMatrix = t1.multiply($.Mat3.makeScaling(-1, 1)).multiply(t2);
|
||||
matrix = matrix.multiply(localMatrix);
|
||||
}
|
||||
|
||||
@ -798,7 +712,7 @@
|
||||
gl.enableVertexAttribArray(this._secondPass.aTexturePosition);
|
||||
|
||||
// set the matrix that transforms the framebuffer to clip space
|
||||
let matrix = Mat3.makeScaling(2, 2).multiply(Mat3.makeTranslation(-0.5, -0.5));
|
||||
let matrix = $.Mat3.makeScaling(2, 2).multiply($.Mat3.makeTranslation(-0.5, -0.5));
|
||||
gl.uniformMatrix3fv(this._secondPass.uMatrix, false, matrix.values);
|
||||
}
|
||||
|
||||
@ -957,8 +871,6 @@
|
||||
} catch (e){
|
||||
$.console.error('Error uploading image data to WebGL', e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
_imageUnloadedHandler(event){
|
||||
|
@ -30,7 +30,10 @@ let viewer;
|
||||
$('#create-drawer').on('click',function(){
|
||||
let drawerType = $('#select-drawer').val();
|
||||
let num = Math.floor($('#input-number').val());
|
||||
run(drawerType, num);
|
||||
});
|
||||
|
||||
function run(drawerType, num) {
|
||||
if(viewer){
|
||||
viewer.destroy();
|
||||
}
|
||||
@ -57,8 +60,7 @@ $('#create-drawer').on('click',function(){
|
||||
viewer.viewport.panBy(new OpenSeadragon.Point( dist * m/2, 0));
|
||||
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function makeViewer(drawerType){
|
||||
let viewer = OpenSeadragon({
|
||||
|
@ -302,8 +302,8 @@
|
||||
tiledImage._croppingPolygons ||
|
||||
tiledImage.debugMode
|
||||
);
|
||||
let useTwoPassRendering = useContext2dPipeline || (tiledImage.opacity < 1); // TO DO: check hasTransparency in addition to opacity
|
||||
|
||||
let useTwoPassRendering = useContext2dPipeline ||(tiledImage.opacity < 1); // TODO: check hasTransparency in addition to opacity
|
||||
|
||||
let tilesToDraw = tiledImage.getTilesToDraw();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user