From 4140bf87417f4aa99780fc3d6c0438d4d469a53a Mon Sep 17 00:00:00 2001 From: Michael Meeks Date: Sat, 6 Nov 2021 11:11:13 +0000 Subject: [PATCH] Bring back the delta application JS from the 6.4 branch. Change-Id: I13329e1e7ceeb1fc611193ccaa78fc4e799e1869 Signed-off-by: Michael Meeks --- browser/src/core/Socket.js | 9 ++ browser/src/layer/tile/CanvasTileLayer.js | 113 ++++++++++++++++++++-- 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/browser/src/core/Socket.js b/browser/src/core/Socket.js index 58fc2b7951..bb811682e5 100644 --- a/browser/src/core/Socket.js +++ b/browser/src/core/Socket.js @@ -454,6 +454,15 @@ app.definitions.Socket = L.Class.extend({ if (e.textMsg.indexOf(' nopng') !== -1) return; + // pass deltas through quickly. + if (e.imgBytes && e.imgBytes[e.imgIndex] === 68 /* D */) + { + window.app.console.log('Passed through delta object'); + e.image = e.imgBytes.subarray(e.imgIndex); + e.imageIsComplete = true; + return; + } + var that = this; var img = this._extractImage(e); e.image = new Image(); diff --git a/browser/src/layer/tile/CanvasTileLayer.js b/browser/src/layer/tile/CanvasTileLayer.js index fb613c15b1..a070d43d05 100644 --- a/browser/src/layer/tile/CanvasTileLayer.js +++ b/browser/src/layer/tile/CanvasTileLayer.js @@ -3,7 +3,7 @@ * L.CanvasTileLayer is a layer with canvas based rendering. */ -/* global app L CanvasSectionContainer CanvasOverlay CDarkOverlay CSplitterLine CStyleData $ _ isAnyVexDialogActive CPointSet CPolyUtil CPolygon Cursor CCellCursor CCellSelection PathGroupType UNOKey UNOModifier */ +/* global app L CanvasSectionContainer CanvasOverlay CDarkOverlay CSplitterLine CStyleData $ _ isAnyVexDialogActive CPointSet CPolyUtil CPolygon Cursor CCellCursor CCellSelection PathGroupType UNOKey UNOModifier Uint8ClampedArray Uint8Array */ /*eslint no-extend-native:0*/ if (typeof String.prototype.startsWith !== 'function') { @@ -12,6 +12,19 @@ if (typeof String.prototype.startsWith !== 'function') { }; } +// debugging aid. +function hex2string(inData) +{ + var hexified = []; + var data = new Uint8Array(inData); + for (var i = 0; i < data.length; i++) { + var hex = data[i].toString(16); + var paddedHex = ('00' + hex).slice(-2); + hexified.push(paddedHex); + } + return hexified.join(''); +} + // CStyleData is used to obtain CSS property values from style data // stored in DOM elements in the form of custom CSS properties/variables. var CStyleData = L.Class.extend({ @@ -6433,6 +6446,91 @@ L.CanvasTileLayer = L.Layer.extend({ } }, + _applyDelta: function(tile, delta) { + // 'Uint8Array' delta + var canvas = document.createElement('canvas'); + canvas.width = window.tileSize; + canvas.height = window.tileSize; + var ctx = canvas.getContext('2d'); + + var oldImg = new Image(); + oldImg.src = tile.el.src; + ctx.drawImage(oldImg, 0, 0); + + // FIXME; can we operate directly on the image ? + var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); + var oldData = new Uint8ClampedArray(imgData.data); + + var pixSize = canvas.width * canvas.height * 4; + var offset = 0; + + console.log('Applying a delta of length ' + delta.length + ' pix size: ' + pixSize + '\nhex: ' + hex2string(delta)); + + // Green-tinge the old-Data ... + if (0) + { + for (var i = 0; i < pixSize; ++i) + oldData[i*4 + 1] = 128; + } + + // wipe to grey. + if (0) + { + for (var i = 0; i < pixSize * 4; ++i) + imgData.data[i] = 128; + } + + // Apply delta. + for (var i = 1; i < delta.length;) + { + switch (delta[i]) + { + case 99: // 'c': // copy row + var count = delta[i+1]; + var srcRow = delta[i+2]; + var destRow = delta[i+3]; + i+= 4; + console.log('copy ' + count + ' row(s) ' + srcRow + ' to ' + destRow); + for (var cnt = 0; cnt < count; ++cnt) + { + var src = (srcRow + cnt) * canvas.width * 4; + var dest = (destRow + cnt) * canvas.width * 4; + for (var j = 0; j < canvas.width * 4; ++j) + { + imgData.data[dest + j] = oldData[src + j]; + } + } + break; + case 100: // 'd': // new run + destRow = delta[i+1]; + var destCol = delta[i+2]; + var span = delta[i+3]; + offset = destRow * canvas.width * 4 + destCol * 4; + i += 4; + console.log('apply new span of size ' + span + ' at pos ' + destCol + ', ' + destRow + ' into delta at byte: ' + offset); + span *= 4; + imgData.data[offset + 1] = 256; // debug - greener start + while (span-- > 0) { + imgData.data[offset++] = delta[i++]; + } + imgData.data[offset - 2] = 256; // debug - blue terminator + break; + default: + console.log('ERROR: Unknown code ' + delta[i] + + ' at offset ' + i); + i = delta.length; + break; + } + } + + ctx.putImageData(imgData, 0, 0); + // FIXME: grim ... can we take as BMP ? as a URL ? + // keep as getImageData instead ? and composite ? + tile.el.src = canvas.toDataURL('image/png'); + + console.log('set new image'); + }, + _onTileMsgFileBasedView: function (textMsg, img) { var tileMsgObj = app.socket.parseServerCmd(textMsg); var coords = this._tileMsgToCoords(tileMsgObj); @@ -6524,13 +6622,16 @@ L.CanvasTileLayer = L.Layer.extend({ tile.wireId = tileMsgObj.wireId; if (this._map._canvasDevicePixelGrid) - // browser/test/pixel-test.png + // browser/test/pixel-test.png - debugging pixel alignment. tile.el.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5QEIChoQ0oROpwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACfklEQVR42u3dO67CQBBFwbnI+9/yJbCQLDIkPsZdFRAQjjiv3S8YZ63VNsl6aLvgop5+6vFzZ3QP/uQz2c0RIAAQAAzcASwAmAAgABAACAAEAAIAAYAAQAAgABAACAAEAAIAAYAAQAAgABAACADGBnC8iQ5MABAACAB+zsVYjLZ9dOvd3zzg/QOYADByB/BvUCzBIAAQAFiCwQQAAYAAQAAgABAACAAEAAIAAYAAQAAgABAACAAEAAIAAYAAQAAwIgAXb2ECgABAAPDaI7SLsZhs+79kvX8AEwDsAM8DASzBIAAQAFiCwQQAAYAAQAAgABAAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAI4LSSOAQBgABAAPDVR9C2ToGxNkfww623bZL98/ilUzIBwA4wbCAgABAACAAswWACgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAAAjAESAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgAPiaJAEAAIAB48yNWW6fAWJsj4LRbb9sk++fxSxMA7AAMGwgCAAGAAMASDCYACAAEAAIAAYAAQAAgABAACAAEAAIAASAAR4AAQAAgABAACAAEANeW9e675sAEAAGAAODUO4AFgMnu7t9h2ahA0pgAAAAASUVORK5CYII='; - else { + + else if (tile && img && !img.src) + this._applyDelta(tile, img); + + else tile.el = img; - tile.loaded = true; - this._tileReady(coords, null /* err */, tile); - } + tile.loaded = true; + this._tileReady(coords, null /* err */, tile); } L.Log.log(textMsg, 'INCOMING', key);