Tiled Kaleidoscope

Here is the relevant part of the code:


function render( image, radius, imageScale, imageAngle )
{
    var PI2 = 2.0 * Math.PI;

    // the radius at the edge
    var radiusInner = radius >> 0;

    // the radius at the vertex
    var radiusOuter = radiusInner * Math.sqrt( 3 ) >> 1;

    var numRows = 1 + ( _height * 0.5 / radiusInner ) >> 0;
    var numCols = 1 + ( _width * 0.5 / ( radiusInner * 3 ) ) >> 0;

    var mirror = -1;

    _context.save();
    _context.translate( 0.5 * _width, 0.5 * _height );
    _context.fillStyle = _context.createPattern( image, "repeat" );

    for( var row = -numRows; row <= numRows; ++row )
    {
        _context.save();
        _context.translate( ( row % 2 ) ? 0 : radiusInner * 1.5, radiusOuter * row );

        for( var col = -numCols; col <= numCols; ++col )
        {
            _context.save();
            _context.translate( radiusInner * col * 3, 0 );

            //render hexagon sides
            for( var i = 0; i < 6; ++i )
            {
                _context.save();

                _context.rotate( i * PI2 / 6 );
                _context.scale( mirror, 1 );

                _context.beginPath();
                _context.moveTo( 0, 0 );
                _context.lineTo( -radiusInner * .5, radiusOuter );
                _context.lineTo( radiusInner * .5, radiusOuter );
                _context.closePath();

                // render pattern start
                _context.save();

                _context.scale( imageScale, imageScale );
                _context.rotate( imageAngle * PI2 );
                _context.translate( -0.5 * image.width, -0.5 * image.height );
                _context.fill();

                _context.restore();
                // render pattern end

                mirror *= -1;

                _context.restore();
            }

            _context.restore();
        }

        _context.restore();
    }

    _context.restore();
}