diff --git a/src/extensions/renderer/canvas/drawing-redraw.js b/src/extensions/renderer/canvas/drawing-redraw.js index ff00873ac..dc9c83673 100644 --- a/src/extensions/renderer/canvas/drawing-redraw.js +++ b/src/extensions/renderer/canvas/drawing-redraw.js @@ -1,5 +1,6 @@ import * as util from '../../../util'; import * as math from '../../../math'; +import * as eleTextureCache from './ele-texture-cache'; var CRp = {}; @@ -260,13 +261,31 @@ CRp.renderTo = function( cxt, zoom, pan, pxRatio ){ } ); }; +CRp.clearCanvas = function(){ + var r = this; + var data = r.data; + function clear(context) { + context.clearRect(0, 0, r.canvasWidth, r.canvasHeight); + }; + clear(data.contexts[ r.NODE ]); + clear(data.contexts[ r.DRAG ]); +}; + + CRp.render = function( options ){ var r = this; options = options || util.staticEmptyObject(); + var cy = r.cy; + if( r.webgl ){ - r.renderWebgl( options ); - return; + if( cy.zoom() > eleTextureCache.maxZoom ) { + r.clearWebgl(); + } else { + r.clearCanvas(); + r.renderWebgl( options ); + return; + } } var forcedContext = options.forcedContext; @@ -275,7 +294,6 @@ CRp.render = function( options ){ var forcedZoom = options.forcedZoom; var forcedPan = options.forcedPan; var pixelRatio = options.forcedPxRatio === undefined ? this.getPixelRatio() : options.forcedPxRatio; - var cy = r.cy; var data = r.data; var needDraw = data.canvasNeedsRedraw; var textureDraw = r.textureOnViewport && !forcedContext && (r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming); diff --git a/src/extensions/renderer/canvas/ele-texture-cache.js b/src/extensions/renderer/canvas/ele-texture-cache.js index 8eaa4c80b..ef47d07fd 100644 --- a/src/extensions/renderer/canvas/ele-texture-cache.js +++ b/src/extensions/renderer/canvas/ele-texture-cache.js @@ -7,8 +7,8 @@ import ElementTextureCacheLookup from './ele-texture-cache-lookup'; const minTxrH = 25; // the size of the texture cache for small height eles (special case) const txrStepH = 50; // the min size of the regular cache, and the size it increases with each step up const minLvl = -4; // when scaling smaller than that we don't need to re-render -const maxLvl = 3; // when larger than this scale just render directly (caching is not helpful) -const maxZoom = 7.99; // beyond this zoom level, layered textures are not used +export const maxLvl = 3; // when larger than this scale just render directly (caching is not helpful) +export const maxZoom = 7.99; // beyond this zoom level, layered textures are not used const eleTxrSpacing = 8; // spacing between elements on textures to avoid blitting overlaps const defTxrWidth = 1024; // default/minimum texture width const maxTxrW = 1024; // the maximum width of a texture diff --git a/src/extensions/renderer/canvas/webgl/drawing-redraw-webgl.js b/src/extensions/renderer/canvas/webgl/drawing-redraw-webgl.js index 7f3d23828..4e4348c0a 100644 --- a/src/extensions/renderer/canvas/webgl/drawing-redraw-webgl.js +++ b/src/extensions/renderer/canvas/webgl/drawing-redraw-webgl.js @@ -1,4 +1,5 @@ import * as mat from './matrix'; +import * as eleTextureCache from '../ele-texture-cache'; const CRp = {}; @@ -28,6 +29,12 @@ CRp.initWebgl = function(options) { }); } +CRp.clearWebgl = function() { + const r = this; + const gl = r.data.contexts[r.WEBGL]; + gl.clear(gl.COLOR_BUFFER_BIT); +}; + function createVertexArrays(eles) { const nodeVertexArray = []; @@ -264,29 +271,33 @@ function bufferNodeData(r, gl, program, vertices) { // texture(s) const layers = 2; - const textures = []; - const node = vertices.nodes[0]; + const textures = new Array(layers); + const node = vertices.nodes[0]; // TODO temp for(let layer = 0; layer < layers; layer++) { const eleCache = getTextureForNode(r, node, layer); const texture = gl.createTexture(); - + textures[layer] = texture; gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, eleCache.width, eleCache.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, eleCache.texture.canvas); - textures.push(texture); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); - gl.generateMipmap(gl.TEXTURE_2D); + if(eleCache) { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, eleCache.width, eleCache.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, eleCache.texture.canvas); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); + gl.generateMipmap(gl.TEXTURE_2D); + } else { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0])); + } gl.bindTexture(gl.TEXTURE_2D, null); } const bind = () => { gl.bindVertexArray(vao); for(let layer = 0; layer < layers; layer++) { - gl.activeTexture(gl.TEXTURE0 + layer); - gl.bindTexture(gl.TEXTURE_2D, textures[layer]); - gl.uniform1i(program.layerUniforms[layer], layer); // texture unit + if(textures[layer]) { + gl.activeTexture(gl.TEXTURE0 + layer); + gl.bindTexture(gl.TEXTURE_2D, textures[layer]); + gl.uniform1i(program.layerUniforms[layer], layer); // texture unit + } } }; const unbind = () => { @@ -305,10 +316,10 @@ function getTextureForNode(r, node, layer) { const { pixelRatio } = r; const cache = layer === 0 ? r.data.eleTxrCache : r.data.lblTxrCache; const reason = 'highQuality'; // what does this mean? - const lvl = Math.ceil(Math.log2(r.cy.zoom() * pixelRatio)); // not sure how to pick the lvl + const lvl = eleTextureCache.maxLvl; const bb = cache.getBoundingBox(node); const eleCache = cache.getElement(node, bb, pixelRatio, lvl, reason); - return eleCache; + return eleCache; // may be null } function createTestTextureCanvas(r) {