Drawing content from another canvas onto c2canvas

For developers using the Construct 2 Javascript SDK

Post » Wed Apr 02, 2014 4:38 am

I'm trying to make a plugin to use three.js for 3D rendering with construct 2.

Right now i have everything working so that i can render onto a separate canvas element on the page, and copy that content onto a texture construct can use.

Because the way construct draws is pretty undocumented and i'm new to javascript i'm having difficulty understanding how i can efficiently pass the texture from the other canvas onto the "c2canvas" without significant slowdown.

right now i'm using:

this.webGL_texture = this.runtime.glwrap.loadTexture(MYCANVAS, true, this.runtime.linearSampling, this.texture_pixelformat); etc.

and rendering webGL_texture using glw.quad(). All this stuff is currently working as intended but it's very slow to copy a screen sized image into memory every frame, and it's not a usable solution.

The problem im having is that i don't know a more efficient way to do this. Using three.js i'm able to render to a texture as well, but the method of doing this produces an object defined by three.js that contains the texture which is also pretty undocumented, and i have no clue how to get this texture to a form construct can use.

some information on how construct 2 handles webGL textures so i can interface the two systems might prove insightful, or perhaps a better way to transfer the contents of the other canvas to a texture for construct to render.

Would i be better off just laying my three.js canvas below the c2canvas, and save the overhead of passing anything? Maybe i'm doing things right but something is going wrong somewhere? i've been looking at @R0j0hound 's paster to see how he grabbed the content of sprites but it seems hes just calling their draw function.

I'd be grateful for any insight as im just scratching my head with this right now.
B
77
S
13
G
8
Posts: 1,974
Reputation: 9,893

Post » Wed Apr 02, 2014 6:11 am

I did about the same thing in my canvas plugin to get a webgl texture and had the same effect of being slow.

If you look in the text object it uses a function from Glwrap that just copies the pixels from a canvas to a webgl texture instead of loading a new texture each time. I haven't used it yet but it should be a bit faster especially since it should give less for the gc to collect.

That sounds interesting that three.js can render directly to a texture. As far as I'm aware c2 uses just a standard webgl texture handle. I'll try to investigate furthur when I get to my PC.
B
92
S
32
G
109
Posts: 5,294
Reputation: 70,999

Post » Wed Apr 02, 2014 6:36 am

Nice! Looking forward to when you have it working! :)
Moderator
B
95
S
34
G
33
Posts: 3,006
Reputation: 27,874

Post » Wed Apr 02, 2014 1:14 pm

'loadTexture' is the wrong function to use! It will allocate a whole new texture every call which will kill performance and leak memory.

Call glw.createEmptyTexture(w, h, linearsampling) to create an empty texture, and update its contents with glw.videoToTexture(canvas, texture). Despite the name it can also copy a canvas to a texture. This may still be a bottleneck; on some system's WebGL implementations it could do a slow CPU-readback-and-upload, but efficient implementations should be able to do a GPU copy. If it turns out it's still slow, consider just having a separate canvas underlay as you already considered.

In canvas2d mode you should just be able to drawImage() the canvas directly.
Scirra Founder
B
398
S
236
G
88
Posts: 24,433
Reputation: 194,635

Post » Wed Apr 02, 2014 3:07 pm

ah thanks for all the help, that looks like exactly what I've been looking for, ill try it later!

I'd also like to know if maybe i can directly pass a webgl texture handle somehow like r0j0 mentioned, because im sure three.js is using the same webGL calls for textures at some level. I'd be able to circumvent rendering it to a separate canvas completely if this were the case at least in webGL mode.

EDIT:

I tried using videototexture, seems to be working very well in chrome (slow in ie11 but what can you do). There might be a minor issue with the function as its copying the texture upside down(?). i just had to draw my quad inverted but seems like this is a bug.
B
77
S
13
G
8
Posts: 1,974
Reputation: 9,893

Post » Wed Apr 02, 2014 4:54 pm

@QuaziGNRLnose
Ok, I found where the webgl texture handle is in the __webglTexture attribute of WebGLRenderTarget.
Code: Select all
var rendertexture = new THREE.WebGLRenderTarget(100,100 );
//texture to use with setTexture()
rendertexture.__webglTexture


The problem that I've found after that is the texture still won't work since by default textures aren't shared between different contexts. But there is a way to share it:
http://www.khronos.org/webgl/wiki/SharedResouces

From that page I found this tidbit of code that shows what needs to be done to share textures:
Code: Select all
var gl1 = someCanvas.getContext('webgl');
var sg1 = someCanvas.getExtension("WEBGL_shared_resources");
var gl2 = someOtherCanvas.getContext('webgl', {
    shareGroup: gl1.shareGroup
});
var sg2 = someOtherCanvas.getExtension("WEBGL_shared_resources");
var tex = gl1.createTexture();
sg1.releaseSharedResource(tex);
sg2.acquireSharedResource(tex, gl.READ_ONLY, function() {
   gl2.bindTexture(gl.TEXTURE_2D, tex);
});


I'm still working out the details for getting it working but a few points I have so far.
1. The first context doesn't need to be created, we can get it from this.runtime.gl.
2. For the second context it seems we have to create the canvas and context for WebGLRenderer first and then pass them as parameters like this:
Code: Select all
var renderer = new WebGLRenderer({"canvas":mycanvas, "context":mycontext});
The context creation can likely be copied basically from what threejs already does plus the shareGroup stuff.
3. The bindtexture() function should be replaceable by the set Texture() function.

I hope to have it more ironed out later.

Edit:
Well it seems that resource sharing isn't implemented as of yet...

Edit2:
After further testing the idea won't work. I also tried making threejs use the same canvas and context as c2 but it's giving errors, probably due to conflicts in gl states from the two. So Ashley's solution is probably the best you can get at the moment.
B
92
S
32
G
109
Posts: 5,294
Reputation: 70,999

Post » Wed Apr 02, 2014 8:00 pm

Yeah, I doubt you could get it to render directly to the same canvas, both C2 and Three.js will be constantly clobbering the WebGL state that each tries to set.
Scirra Founder
B
398
S
236
G
88
Posts: 24,433
Reputation: 194,635

Post » Wed Apr 02, 2014 8:35 pm

alright so for now ill use videototexture, and provide an option to just place the three.js canvas below the c2canvas since this is fastest if you have no reason to pass the texture to construct, and just want construct to render 2D stuff for a ui etc. Thanks for all the help guys!
B
77
S
13
G
8
Posts: 1,974
Reputation: 9,893

Post » Wed Apr 02, 2014 9:31 pm

I tried writing a set of plugins for three.js a year ago, but it became rapidely cumbersome.
I tried two designs:
1. everything in one plugin. But you have to handle references to every objects by tagging them... it was a pain. Also the ACE started to get very long
2. one plugin per three.js type of object. So I had a renderer plugin, a camera plugin, geometry plugin, material plugin, light plugin, etc etc etc..

In both case I wasn't really satisfied. But it worked:
https://dl.dropboxusercontent.com/u/23551572/C2-Games/3DMaze/index.html made with the first design
https://dl.dropboxusercontent.com/u/23551572/C2-Games/3DTest/index.html made with the second.
B
66
S
22
G
14
Posts: 1,484
Reputation: 16,511

Post » Wed Apr 02, 2014 10:22 pm

I'm leaning towards doing something similar to what you were doing with your first design.
B
77
S
13
G
8
Posts: 1,974
Reputation: 9,893

Next

Return to Javascript SDK

Who is online

Users browsing this forum: No registered users and 0 guests