Modular webgl2 drawer: fix small bugs. Add drawer IDs to demo page urls to allow refreshing/direct running

This commit is contained in:
Aiosa 2023-09-26 15:31:43 +02:00
parent e07745d790
commit e3024deb46
8 changed files with 156 additions and 64 deletions

View File

@ -114,6 +114,30 @@ $.WebGL = class WebGL extends OpenSeadragon.DrawerBase {
engine.init(size.x, size.y);
this.viewer.addHandler("resize", this._resizeRenderer.bind(this));
this.renderer = engine;
this.renderer.setDataBlendingEnabled(true);
// const gl = this.renderer.gl;
// this._renderToTexture = gl.createTexture();
// gl.activeTexture(gl.TEXTURE0);
// gl.bindTexture(gl.TEXTURE_2D, this._renderToTexture);
// gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size.x, size.y, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
//
// // set up the framebuffer for render-to-texture
// this._glFrameBuffer = gl.createFramebuffer();
// gl.bindFramebuffer(gl.FRAMEBUFFER, this._glFrameBuffer);
// gl.framebufferTexture2D(
// gl.FRAMEBUFFER,
// gl.COLOR_ATTACHMENT0, // attach texture as COLOR_ATTACHMENT0
// gl.TEXTURE_2D, // attach a 2D texture
// this._renderToTexture, // the texture to attach
// 0
// );
// gl.bindFramebuffer(gl.FRAMEBUFFER, this._glFrameBuffer);
// gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._renderToTexture, 0);
return engine.canvas;
}
@ -136,23 +160,19 @@ $.WebGL = class WebGL extends OpenSeadragon.DrawerBase {
let rotMatrix = $.Mat3.makeRotation(-viewport.rotation);
let viewMatrix = scaleMatrix.multiply(rotMatrix).multiply(posMatrix);
this.renderer.clear();
this.renderer.setDataBlendingEnabled(false);
// const gl = this.renderer.gl;
// gl.bindFramebuffer(gl.FRAMEBUFFER, this._glFrameBuffer);
// clear the buffer to draw a new image
// gl.clear(gl.COLOR_BUFFER_BIT);
//iterate over tiled images and draw each one using a two-pass rendering pipeline if needed
let drawn = 0;
for (const tiledImage of tiledImages) {
console.log("START TILED IMAGE");
let tilesToDraw = tiledImage.getTilesToDraw();
if (tilesToDraw.length === 0) {
break;
}
if (drawn === 1) {
this.renderer.setDataBlendingEnabled(true);
}
// if (tilesToDraw.length === 0) {
// break;
// }
let overallMatrix = viewMatrix;
let imageRotation = tiledImage.getRotation(true);
@ -168,12 +188,15 @@ $.WebGL = class WebGL extends OpenSeadragon.DrawerBase {
overallMatrix = viewMatrix.multiply(localMatrix);
}
//todo better access to the rendering context
const shader = this.renderer.specification(0).shaders.renderShader._renderContext;
// iterate over tiles and add data for each one to the buffers
for (let tileIndex = 0; tileIndex < tilesToDraw.length; tileIndex++){
const tile = tilesToDraw[tileIndex].tile;
console.log("TILE " + tile.level + "-" + tile.x + "_" + tile.y);
const matrix = this._getTileMatrix(tile, tiledImage, overallMatrix);
shader.opacity.set(tile.opacity * tiledImage.opacity);
@ -205,8 +228,6 @@ $.WebGL = class WebGL extends OpenSeadragon.DrawerBase {
tiles: tilesToDraw.map(info => info.tile),
});
}
drawn++;
}
}

View File

@ -144,7 +144,7 @@ $.WebGLModule = class extends $.EventSource {
const options = {
wrap: readGlProp("wrap", "MIRRORED_REPEAT"),
magFilter: readGlProp("magFilter", "LINEAR"),
minFilter: readGlProp("minFilter", "NEAREST"),
minFilter: readGlProp("minFilter", "LINEAR"),
dataLoader: contextOpts.dataLoader || "TEXTURE_2D"
};
this.webglContext = new Context(this, glContext, options);
@ -592,9 +592,11 @@ $.WebGLModule = class extends $.EventSource {
setDataBlendingEnabled(enabled) {
if (enabled) {
// this.gl.enable(this.gl.BLEND);
// this.gl.blendEquation(this.gl.FUNC_ADD);
// this.gl.blendFuncSeparate(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, this.gl.ONE, this.gl.ONE);
this.gl.enable(this.gl.BLEND);
this.gl.blendEquation(this.gl.FUNC_ADD);
this.gl.blendFuncSeparate(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, this.gl.ONE, this.gl.ONE);
this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
} else {
this.gl.disable(this.gl.BLEND);
}

View File

@ -185,7 +185,7 @@ $.WebGLModule.WebGL20 = class extends $.WebGLModule.WebGLImplementation {
}
static create(canvas) {
return canvas.getContext('webgl2', { premultipliedAlpha: false, alpha: true });
return canvas.getContext('webgl2', { premultipliedAlpha: true, alpha: true });
}
//todo try to implement on the global scope version-independntly
@ -263,6 +263,7 @@ vec4 lid_${layer._index}_xo() {
return `#version 300 es
precision mediump float;
precision mediump sampler2DArray;
precision mediump sampler2D;
${this.texture.declare(shaderDataIndexToGlobalDataIndex)}
uniform float pixel_size_in_fragments;
@ -283,17 +284,7 @@ void show(vec4 color) {
vec4 fg = _last_rendered_color;
_last_rendered_color = color;
vec4 pre_fg = vec4(fg.rgb * fg.a, fg.a);
final_color = pre_fg + final_color * (1.0-fg.a);
}
void finalize() {
show(vec4(.0));
if (close(final_color.a, 0.0)) {
final_color = vec4(0.);
} else {
final_color = vec4(final_color.rgb/final_color.a, final_color.a);
}
final_color = pre_fg + final_color;
}
vec4 blend_equation(in vec4 foreground, in vec4 background) {
@ -317,7 +308,8 @@ ${definition}
void main() {
${execution}
finalize();
//blend last level
show(vec4(.0));
}`;
}

View File

@ -20,12 +20,23 @@
<div id="contentDiv" class="openseadragon1"></div>
<script type="text/javascript">
const url = new URL(window.location.href);
let drawer = url.searchParams.get("drawer");
if (!drawer) {
drawer = 'canvas';
url.searchParams.set('drawer', drawer);
if ("undefined" !== typeof history.replaceState) {
history.replaceState(null, window.location.title, url.toString());
}
}
var viewer = OpenSeadragon({
// debugMode: true,
id: "contentDiv",
prefixUrl: "../../build/openseadragon/images/",
tileSources: "../data/testpattern.dzi",
showNavigator: true
showNavigator: true,
drawer:drawer,
});
</script>
</body>

View File

@ -65,12 +65,12 @@
<h2>Compare behavior of <strong>Context2d</strong> and <strong>WebGL</strong> drawers</h2>
<div class="mirrored">
<div>
<h3>Context2d drawer (default in OSD &lt;= 4.1.0)</h3>
<h3 id="title-w1">Loading...</h3>
<div id="canvasdrawer" class="viewer-container"></div>
</div>
<div>
<h3>New WebGL drawer</h3>
<h3 id="title-w2">Loading...</h3>
<div id="webgl" class="viewer-container"></div>
</div>
</div>

View File

@ -13,6 +13,19 @@ const labels = {
bblue: 'Blue B',
duomo: 'Duomo',
}
const drawers = {
canvas: "Context2d drawer (default in OSD &lt;= 4.1.0)",
webgl: "New WebGL drawer",
universal_webgl: "New WebGL (Modular)"
}
//Support drawer type from the url
const url = new URL(window.location.href);
const drawer1 = url.searchParams.get("left") || 'canvas';
const drawer2 = url.searchParams.get("right") || 'webgl';
$("#title-w1").html(drawers[drawer1]);
$("#title-w2").html(drawers[drawer2]);
//Double viewer setup for comparison - CanvasDrawer and WebGLDrawer
// viewer1: canvas drawer
@ -25,7 +38,7 @@ let viewer1 = window.viewer1 = OpenSeadragon({
crossOriginPolicy: 'Anonymous',
ajaxWithCredentials: false,
// maxImageCacheCount: 30,
drawer:'canvas',
drawer:drawer1,
blendTime:0
});
@ -39,25 +52,23 @@ let viewer2 = window.viewer2 = OpenSeadragon({
crossOriginPolicy: 'Anonymous',
ajaxWithCredentials: false,
// maxImageCacheCount: 30,
drawer:'webgl',
drawer:drawer2,
blendTime:0,
});
// viewer3: html drawer
var viewer3 = window.viewer3 = OpenSeadragon({
id: "htmldrawer",
drawer:'html',
blendTime:2,
prefixUrl: "../../build/openseadragon/images/",
minZoomImageRatio:0.01,
customDrawer: OpenSeadragon.HTMLDrawer,
tileSources: [sources['leaves'], sources['rainbow'], sources['duomo']],
sequenceMode: true,
crossOriginPolicy: 'Anonymous',
ajaxWithCredentials: false
});
// // viewer3: html drawer, unused
// var viewer3 = window.viewer3 = OpenSeadragon({
// id: "htmldrawer",
// drawer:'html',
// blendTime:2,
// prefixUrl: "../../build/openseadragon/images/",
// minZoomImageRatio:0.01,
// customDrawer: OpenSeadragon.HTMLDrawer,
// tileSources: [sources['leaves'], sources['rainbow'], sources['duomo']],
// sequenceMode: true,
// crossOriginPolicy: 'Anonymous',
// ajaxWithCredentials: false
// });
// Sync navigation of viewer1 and viewer 2
@ -126,6 +137,8 @@ Object.keys(sources).forEach((key, index)=>{
}
})
$('#image-picker').append(makeComparisonSwitcher());
$('#image-picker input.toggle').on('change',function(){
let data = $(this).data();
if(this.checked){
@ -288,6 +301,30 @@ function addTileSource(viewer, image, checkbox){
}
}
function getAvailableDrawerSelect(name, selectedDrawer) {
return `
<select name="${name}">
${Object.entries(drawers).map(([k, v]) => {
const selected = selectedDrawer === k ? "selected" : "";
return `<option value="${k}" ${selected}>${v}</option>`;
}).join("\n")}
</select>`;
}
function makeComparisonSwitcher() {
const left = getAvailableDrawerSelect("left", drawer1),
right = getAvailableDrawerSelect("right", drawer2);
return `
<div>
Note: you can run the comparison with desired drawers like this: drawercomparison.html?left=[type]&right=[type]
<form method="get">
${left}
${right}
<button>Submit</button>
</form>
</div>`;
}
function makeImagePickerElement(key, label){
return $(`<div class="image-options">
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
@ -306,7 +343,6 @@ function makeImagePickerElement(key, label){
<label>Composite: <select data-image="" data-field="composite"></select></label>
<label>Wrap: <select data-image="" data-field="wrapping"></select></label>
</div>
</div>`.replaceAll('data-image=""', `data-image="${key}"`).replace('__title__', label));
}

View File

@ -27,9 +27,7 @@
<div>
<label>Select a drawer: </label>
<select id="select-drawer">
<option value="canvas">Canvas</option>
<option value="webgl">WebGL</option>
<option value="html">HTML</option>
</select>
<label>Num images: </label>
<input id="input-number" type="number" value="1" min="1" step="1">

View File

@ -13,6 +13,14 @@ const labels = {
bblue: 'Blue B',
duomo: 'Duomo',
}
const drawers = {
canvas: "Context2d drawer (default in OSD &lt;= 4.1.0)",
webgl: "New WebGL drawer",
universal_webgl: "New WebGL (Modular)",
html: ""
}
let viewer;
( function () {
@ -408,6 +416,10 @@ function rStats ( settings ) {
_base = document.createElement( 'div' );
_base.className = 'rs-base';
_base.style.bottom = '0px';
_base.style.right = '0px';
_base.style.top = 'initial';
_base.style.left = 'initial';
_div = document.createElement( 'div' );
_div.className = 'rs-container';
_div.style.height = 'auto';
@ -509,6 +521,8 @@ function rStats ( settings ) {
}
var glStats = function() {
var _rS = null;
@ -898,16 +912,9 @@ Stats.Panel = function ( name, fg, bg ) {
// })();
$('#create-drawer').on('click',function(){
let drawerType = $('#select-drawer').val();
let num = Math.floor($('#input-number').val());
rS('other').start();
run(drawerType, num);
});
function run(drawerType, num) {
rS('other').start();
if(viewer){
viewer.destroy();
}
@ -969,3 +976,28 @@ function makeTileSources(num){
}
const url = new URL(window.location.href);
const drawer = url.searchParams.get("drawer");
const numberOfSources = Number.parseInt(url.searchParams.get("sources")) || 1;
$('#create-drawer').on('click',function(){
const drawer = $('#select-drawer').val();
let num = Math.floor($('#input-number').val());
url.searchParams.set("drawer", drawer);
url.searchParams.set("sources", num);
if ("undefined" !== typeof history.replaceState) {
history.replaceState(null, window.location.title, url.toString());
}
run(drawer, num);
});
$('#input-number').val(numberOfSources);
$("#select-drawer").html(Object.entries(drawers).map(([k, v]) => {
const selected = drawer === k ? "selected" : "";
return `<option value="${k}" ${selected}>${v}</option>`;
}).join("\n"));
if (drawer) {
run(drawer, numberOfSources);
}