Wizcorp / Ejecta-X

A Fast, Open Source JavaScript, Canvas & Audio Implementation
http://wizcorp.github.io/Ejecta-X
185 stars 50 forks source link

Added support for canvas patterns and drawing with pattern fills. #82

Closed timothyt closed 9 years ago

timothyt commented 9 years ago

Replaced fixed function calls in EJPath with EGL 2 calls.

aogilvie commented 9 years ago

Sample code

changed the sample animate function

var animate = function() {
    // Clear the screen - note that .globalAlpha is still honored,
    // so this will only "darken" the screen a bit

    ctx.globalCompositeOperation = 'source-over';
    ctx.fillRect(0,0,w,h);

    // Use the additive blend mode to draw the bezier curves
    ctx.globalCompositeOperation = 'lighter';

    // Calculate curve positions and draw
    for( var i = 0; i < maxCurves; i++ ) {
        var curve = curves[i];
        curve.current += curve.inc;
        for( var j = 0; j < p.length; j+=2 ) {
            var a = Math.sin( curve.current * (j+3) * 373 * 0.0001 );
            var b = Math.sin( curve.current * (j+5) * 927 * 0.0002 );
            var c = Math.sin( curve.current * (j+5) * 573 * 0.0001 );
            p[j] = (a * a * b + c * a + b) * w * c + w2;
            p[j+1] = (a * b * b + c - a * b *c) * h2 + h2;
        }

        ctx.beginPath();
        ctx.moveTo( p[0], p[1] );
        ctx.bezierCurveTo( p[2], p[3], p[4], p[5], p[6], p[7] );
        ctx.strokeStyle = curve.color;
        ctx.stroke();
    }
    if(window.pos_x>200)window.pos_x=0;
    if(window.pos_y>200)window.pos_y=0;
    window.pos_x++;
    window.pos_y++;

    if (img) { 
        var pat = ctx.createPattern(img, "repeat");
        ctx.rect(0, 0, 300, 500);
        ctx.fillStyle = pat;
        ctx.fill();
    }

    ctx.save();

    ctx.globalAlpha = 1;

    // if(img)ctx.drawImage(img, window.pos_x, window.pos_y);

    ctx.restore();

};

gives:

screenshot_2014-07-14-12-36-42

The pattern should be expected to only fill: 300 x 500...

Is this createPattern bug or fillRect? Samsung Galaxy S3

timothyt commented 9 years ago

Sorry, my test case used fillRect and not rect and then fill. I'ved updated EJPath::drawPolygonsToContext to match Ejecta 1.4 which properly handles patterned fills. Also I think the code should be more like

var animate = function() {
    // Clear the screen - note that .globalAlpha is still honored,
    // so this will only "darken" the screen a bit

    ctx.globalCompositeOperation = 'source-over';
    ctx.fillStyle = '#000000';
    ctx.globalAlpha = 1.0;
    ctx.fillRect(0,0,w,h);

    // Use the additive blend mode to draw the bezier curves
    ctx.globalCompositeOperation = 'lighter';

    // Calculate curve positions and draw
    for( var i = 0; i < maxCurves; i++ ) {
        var curve = curves[i];
        curve.current += curve.inc;
        for( var j = 0; j < p.length; j+=2 ) {
            var a = Math.sin( curve.current * (j+3) * 373 * 0.0001 );
            var b = Math.sin( curve.current * (j+5) * 927 * 0.0002 );
            var c = Math.sin( curve.current * (j+5) * 573 * 0.0001 );
            p[j] = (a * a * b + c * a + b) * w * c + w2;
            p[j+1] = (a * b * b + c - a * b *c) * h2 + h2;
        }

        ctx.beginPath();
        ctx.moveTo( p[0], p[1] );
        ctx.bezierCurveTo( p[2], p[3], p[4], p[5], p[6], p[7] );
        ctx.strokeStyle = curve.color;
        ctx.stroke();
    }
    if(window.pos_x>200)window.pos_x=0;
    if(window.pos_y>200)window.pos_y=0;
    window.pos_x++;
    window.pos_y++;

    if (img) { 
        var pat = ctx.createPattern(img, "repeat");
        ctx.beginPath();
        ctx.rect(0, 0, 300, 500);
        ctx.fillStyle = pat;
        ctx.fill();
    }

    ctx.save();

    ctx.globalAlpha = 1;

    // if(img)ctx.drawImage(img, window.pos_x, window.pos_y);

    ctx.restore();

};

If you don't reset the fillStyle before doing the fillRect to erase the screen, it'll use the pattern the second time through. And then you need to do ctx.beginPath before drawing the patterned fill to create a new path otherwise you're appending onto the last curve path drawn.

Seperately I made the clear screen an opaque draw. There seems to be an issue with some devices where the framebuffer seems to get trashed after a swapbuffers. I did some investigation using Tracer for opengl es as well as the Adreno Profiler and the opengl api calls are all correct and the captured framebuffers don't show any corruption so I'm not sure what the issue is. You're supposed to do a glclear anyway immediately after binding to the framebuffer for performance reasons eg. https://wiki.mozilla.org/Platform/GFX/MobileGPUs#Always_call_glClear_immediately_after_glBindFramebuffer . I could put this clear in the EJCanvasContextScreen::present() perhaps?

aogilvie commented 9 years ago

I could put this clear in the EJCanvasContextScreen::present() perhaps?

Give it a try. It would be interesting to note any performance differences with Adreno Profiler.

aogilvie commented 9 years ago

Tested with sample code :fork_and_knife: