Skip to content

hitTest (→mousedown) fails on webgl cached DisplayObject #977

@adabru

Description

@adabru

Using examples/WebGL/Filters_GL-GL.html from master branch (commit c7b6035) and adding the line bmp.hitTest(0,0) leads to following error (Ubuntu 16.04, Chrome 69.0.3497.42 beta 64-bit):

Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'
    at BitmapCache.p.draw (easeljs-NEXT.js:15625)
    at Bitmap.p.draw (easeljs-NEXT.js:6705)
    at Bitmap.p.draw (easeljs-NEXT.js:11883)
    at Bitmap.p.hitTest (easeljs-NEXT.js:7016)
    at Image.handleImageLoad (Filters_GL-GL.html:68)

The provided value metioned in the error message is of type WebGLTexture instead. bmp.on('mousedown', ()=>{}) plus clicking causes the same error for same reason.

The general problem as I see it is that currently for the hitTest a 1x1-sized canvas is created, its '2d' context is acquired, the object is drawn on it and the pixel for the test is queried with ctx.getImageData(0,0,1,1), as can be seen in the following code references:

var canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); // prevent errors on load in browsers without canvas.
if (canvas.getContext) {
DisplayObject._hitTestCanvas = canvas;
DisplayObject._hitTestContext = canvas.getContext("2d");
canvas.width = canvas.height = 1;
}

p.hitTest = function(x, y) {
var ctx = DisplayObject._hitTestContext;
ctx.setTransform(1, 0, 0, 1, -x, -y);
this.draw(ctx);
var hit = this._testHit(ctx);

p._testHit = function(ctx) {
try {
var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1;
} catch (e) {

I guess the problem with webgl-cache is that it is stored on the gpu and not as easy accessible as a getImageData. I'm basing my guess solely on the following comment:

* When "options.useGL" is set to the parent stage of the target and WebGL, performance is increased by using
* "RenderTextures" instead of canvas elements. These are internal Textures on the graphics card stored in the GPU.
* Because they are no longer canvases you cannot perform operations you could with a regular canvas. The benefit
* is that this avoids the slowdown of copying the texture back and forth from the GPU to a Canvas element.
* This means "stage" is the recommended option when available.

I don't know a solution, imo a solution depends on hitTest's use cases. For my case, as a workaround, I'm planning to override the DisplayObject's hitTest with a custom function that either uses a context2d-duplicate to do the hitTest or simply checks for the object's bounds in this function.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions