/** * @author mrdoob / http://mrdoob.com/ */ three.spritecanvasmaterial = function ( parameters ) { three.material.call( this ); this.type = 'spritecanvasmaterial'; this.color = new three.color( 0xffffff ); this.program = function ( context, color ) {}; this.setvalues( parameters ); }; three.spritecanvasmaterial.prototype = object.create( three.material.prototype ); three.spritecanvasmaterial.prototype.constructor = three.spritecanvasmaterial; three.spritecanvasmaterial.prototype.clone = function () { var material = new three.spritecanvasmaterial(); three.material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.program = this.program; return material; }; // three.canvasrenderer = function ( parameters ) { console.log( 'three.canvasrenderer', three.revision ); var smoothstep = three.math.smoothstep; parameters = parameters || {}; var _this = this, _renderdata, _elements, _lights, _projector = new three.projector(), _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createelement( 'canvas' ), _canvaswidth = _canvas.width, _canvasheight = _canvas.height, _canvaswidthhalf = math.floor( _canvaswidth / 2 ), _canvasheighthalf = math.floor( _canvasheight / 2 ), _viewportx = 0, _viewporty = 0, _viewportwidth = _canvaswidth, _viewportheight = _canvasheight, pixelratio = 1, _context = _canvas.getcontext( '2d', { alpha: parameters.alpha === true } ), _clearcolor = new three.color( 0x000000 ), _clearalpha = parameters.alpha === true ? 0 : 1, _contextglobalalpha = 1, _contextglobalcompositeoperation = 0, _contextstrokestyle = null, _contextfillstyle = null, _contextlinewidth = null, _contextlinecap = null, _contextlinejoin = null, _contextlinedash = [], _camera, _v1, _v2, _v3, _v4, _v5 = new three.renderablevertex(), _v6 = new three.renderablevertex(), _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, _color = new three.color(), _color1 = new three.color(), _color2 = new three.color(), _color3 = new three.color(), _color4 = new three.color(), _diffusecolor = new three.color(), _emissivecolor = new three.color(), _lightcolor = new three.color(), _patterns = {}, _image, _uvs, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, _clipbox = new three.box2(), _clearbox = new three.box2(), _elembox = new three.box2(), _ambientlight = new three.color(), _directionallights = new three.color(), _pointlights = new three.color(), _vector3 = new three.vector3(), // needed for pointlight _centroid = new three.vector3(), _normal = new three.vector3(), _normalviewmatrix = new three.matrix3(); // dash+gap fallbacks for firefox and everything else if ( _context.setlinedash === undefined ) { _context.setlinedash = function () {} } this.domelement = _canvas; this.autoclear = true; this.sortobjects = true; this.sortelements = true; this.info = { render: { vertices: 0, faces: 0 } } // webglrenderer compatibility this.supportsvertextextures = function () {}; this.setfaceculling = function () {}; // this.getpixelratio = function () { return pixelratio; }; this.setpixelratio = function ( value ) { pixelratio = value; }; this.setsize = function ( width, height, updatestyle ) { _canvaswidth = width * pixelratio; _canvasheight = height * pixelratio; _canvas.width = _canvaswidth; _canvas.height = _canvasheight; _canvaswidthhalf = math.floor( _canvaswidth / 2 ); _canvasheighthalf = math.floor( _canvasheight / 2 ); if ( updatestyle !== false ) { _canvas.style.width = width + 'px'; _canvas.style.height = height + 'px'; } _clipbox.min.set( -_canvaswidthhalf, -_canvasheighthalf ), _clipbox.max.set( _canvaswidthhalf, _canvasheighthalf ); _clearbox.min.set( - _canvaswidthhalf, - _canvasheighthalf ); _clearbox.max.set( _canvaswidthhalf, _canvasheighthalf ); _contextglobalalpha = 1; _contextglobalcompositeoperation = 0; _contextstrokestyle = null; _contextfillstyle = null; _contextlinewidth = null; _contextlinecap = null; _contextlinejoin = null; this.setviewport( 0, 0, width, height ); }; this.setviewport = function ( x, y, width, height ) { _viewportx = x * pixelratio; _viewporty = y * pixelratio; _viewportwidth = width * pixelratio; _viewportheight = height * pixelratio; }; this.setscissor = function () {}; this.enablescissortest = function () {}; this.setclearcolor = function ( color, alpha ) { _clearcolor.set( color ); _clearalpha = alpha !== undefined ? alpha : 1; _clearbox.min.set( - _canvaswidthhalf, - _canvasheighthalf ); _clearbox.max.set( _canvaswidthhalf, _canvasheighthalf ); }; this.setclearcolorhex = function ( hex, alpha ) { console.warn( 'three.canvasrenderer: .setclearcolorhex() is being removed. use .setclearcolor() instead.' ); this.setclearcolor( hex, alpha ); }; this.getclearcolor = function () { return _clearcolor; }; this.getclearalpha = function () { return _clearalpha; }; this.getmaxanisotropy = function () { return 0; }; this.clear = function () { if ( _clearbox.empty() === false ) { _clearbox.intersect( _clipbox ); _clearbox.expandbyscalar( 2 ); _clearbox.min.x = _clearbox.min.x + _canvaswidthhalf; _clearbox.min.y = - _clearbox.min.y + _canvasheighthalf; // higher y value ! _clearbox.max.x = _clearbox.max.x + _canvaswidthhalf; _clearbox.max.y = - _clearbox.max.y + _canvasheighthalf; // lower y value ! if ( _clearalpha < 1 ) { _context.clearrect( _clearbox.min.x | 0, _clearbox.max.y | 0, ( _clearbox.max.x - _clearbox.min.x ) | 0, ( _clearbox.min.y - _clearbox.max.y ) | 0 ); } if ( _clearalpha > 0 ) { setblending( three.normalblending ); setopacity( 1 ); setfillstyle( 'rgba(' + math.floor( _clearcolor.r * 255 ) + ',' + math.floor( _clearcolor.g * 255 ) + ',' + math.floor( _clearcolor.b * 255 ) + ',' + _clearalpha + ')' ); _context.fillrect( _clearbox.min.x | 0, _clearbox.max.y | 0, ( _clearbox.max.x - _clearbox.min.x ) | 0, ( _clearbox.min.y - _clearbox.max.y ) | 0 ); } _clearbox.makeempty(); } }; // compatibility this.clearcolor = function () {}; this.cleardepth = function () {}; this.clearstencil = function () {}; this.render = function ( scene, camera ) { if ( camera instanceof three.camera === false ) { console.error( 'three.canvasrenderer.render: camera is not an instance of three.camera.' ); return; } if ( this.autoclear === true ) this.clear(); _this.info.render.vertices = 0; _this.info.render.faces = 0; _context.settransform( _viewportwidth / _canvaswidth, 0, 0, - _viewportheight / _canvasheight, _viewportx, _canvasheight - _viewporty ); _context.translate( _canvaswidthhalf, _canvasheighthalf ); _renderdata = _projector.projectscene( scene, camera, this.sortobjects, this.sortelements ); _elements = _renderdata.elements; _lights = _renderdata.lights; _camera = camera; _normalviewmatrix.getnormalmatrix( camera.matrixworldinverse ); /* debug setfillstyle( 'rgba( 0, 255, 255, 0.5 )' ); _context.fillrect( _clipbox.min.x, _clipbox.min.y, _clipbox.max.x - _clipbox.min.x, _clipbox.max.y - _clipbox.min.y ); */ calculatelights(); for ( var e = 0, el = _elements.length; e < el; e ++ ) { var element = _elements[ e ]; var material = element.material; if ( material === undefined || material.opacity === 0 ) continue; _elembox.makeempty(); if ( element instanceof three.renderablesprite ) { _v1 = element; _v1.x *= _canvaswidthhalf; _v1.y *= _canvasheighthalf; rendersprite( _v1, element, material ); } else if ( element instanceof three.renderableline ) { _v1 = element.v1; _v2 = element.v2; _v1.positionscreen.x *= _canvaswidthhalf; _v1.positionscreen.y *= _canvasheighthalf; _v2.positionscreen.x *= _canvaswidthhalf; _v2.positionscreen.y *= _canvasheighthalf; _elembox.setfrompoints( [ _v1.positionscreen, _v2.positionscreen ] ); if ( _clipbox.isintersectionbox( _elembox ) === true ) { renderline( _v1, _v2, element, material ); } } else if ( element instanceof three.renderableface ) { _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; if ( _v1.positionscreen.z < - 1 || _v1.positionscreen.z > 1 ) continue; if ( _v2.positionscreen.z < - 1 || _v2.positionscreen.z > 1 ) continue; if ( _v3.positionscreen.z < - 1 || _v3.positionscreen.z > 1 ) continue; _v1.positionscreen.x *= _canvaswidthhalf; _v1.positionscreen.y *= _canvasheighthalf; _v2.positionscreen.x *= _canvaswidthhalf; _v2.positionscreen.y *= _canvasheighthalf; _v3.positionscreen.x *= _canvaswidthhalf; _v3.positionscreen.y *= _canvasheighthalf; if ( material.overdraw > 0 ) { expand( _v1.positionscreen, _v2.positionscreen, material.overdraw ); expand( _v2.positionscreen, _v3.positionscreen, material.overdraw ); expand( _v3.positionscreen, _v1.positionscreen, material.overdraw ); } _elembox.setfrompoints( [ _v1.positionscreen, _v2.positionscreen, _v3.positionscreen ] ); if ( _clipbox.isintersectionbox( _elembox ) === true ) { renderface3( _v1, _v2, _v3, 0, 1, 2, element, material ); } } /* debug setlinewidth( 1 ); setstrokestyle( 'rgba( 0, 255, 0, 0.5 )' ); _context.strokerect( _elembox.min.x, _elembox.min.y, _elembox.max.x - _elembox.min.x, _elembox.max.y - _elembox.min.y ); */ _clearbox.union( _elembox ); } /* debug setlinewidth( 1 ); setstrokestyle( 'rgba( 255, 0, 0, 0.5 )' ); _context.strokerect( _clearbox.min.x, _clearbox.min.y, _clearbox.max.x - _clearbox.min.x, _clearbox.max.y - _clearbox.min.y ); */ _context.settransform( 1, 0, 0, 1, 0, 0 ); }; // function calculatelights() { _ambientlight.setrgb( 0, 0, 0 ); _directionallights.setrgb( 0, 0, 0 ); _pointlights.setrgb( 0, 0, 0 ); for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { var light = _lights[ l ]; var lightcolor = light.color; if ( light instanceof three.ambientlight ) { _ambientlight.add( lightcolor ); } else if ( light instanceof three.directionallight ) { // for sprites _directionallights.add( lightcolor ); } else if ( light instanceof three.pointlight ) { // for sprites _pointlights.add( lightcolor ); } } } function calculatelight( position, normal, color ) { for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { var light = _lights[ l ]; _lightcolor.copy( light.color ); if ( light instanceof three.directionallight ) { var lightposition = _vector3.setfrommatrixposition( light.matrixworld ).normalize(); var amount = normal.dot( lightposition ); if ( amount <= 0 ) continue; amount *= light.intensity; color.add( _lightcolor.multiplyscalar( amount ) ); } else if ( light instanceof three.pointlight ) { var lightposition = _vector3.setfrommatrixposition( light.matrixworld ); var amount = normal.dot( _vector3.subvectors( lightposition, position ).normalize() ); if ( amount <= 0 ) continue; amount *= light.distance == 0 ? 1 : 1 - math.min( position.distanceto( lightposition ) / light.distance, 1 ); if ( amount == 0 ) continue; amount *= light.intensity; color.add( _lightcolor.multiplyscalar( amount ) ); } } } function rendersprite( v1, element, material ) { setopacity( material.opacity ); setblending( material.blending ); var scalex = element.scale.x * _canvaswidthhalf; var scaley = element.scale.y * _canvasheighthalf; var dist = 0.5 * math.sqrt( scalex * scalex + scaley * scaley ); // allow for rotated sprite _elembox.min.set( v1.x - dist, v1.y - dist ); _elembox.max.set( v1.x + dist, v1.y + dist ); if ( material instanceof three.spritematerial ) { var texture = material.map; if ( texture !== null && texture.image !== undefined ) { if ( texture.haseventlistener( 'update', ontextureupdate ) === false ) { if ( texture.image.width > 0 ) { texturetopattern( texture ); } texture.addeventlistener( 'update', ontextureupdate ); } var pattern = _patterns[ texture.id ]; if ( pattern !== undefined ) { setfillstyle( pattern ); } else { setfillstyle( 'rgba( 0, 0, 0, 1 )' ); } // var bitmap = texture.image; var ox = bitmap.width * texture.offset.x; var oy = bitmap.height * texture.offset.y; var sx = bitmap.width * texture.repeat.x; var sy = bitmap.height * texture.repeat.y; var cx = scalex / sx; var cy = scaley / sy; _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.translate( - scalex / 2, - scaley / 2 ); _context.scale( cx, cy ); _context.translate( - ox, - oy ); _context.fillrect( ox, oy, sx, sy ); _context.restore(); } else { // no texture setfillstyle( material.color.getstyle() ); _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.scale( scalex, - scaley ); _context.fillrect( - 0.5, - 0.5, 1, 1 ); _context.restore(); } } else if ( material instanceof three.spritecanvasmaterial ) { setstrokestyle( material.color.getstyle() ); setfillstyle( material.color.getstyle() ); _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.scale( scalex, scaley ); material.program( _context ); _context.restore(); } /* debug setstrokestyle( 'rgb(255,255,0)' ); _context.beginpath(); _context.moveto( v1.x - 10, v1.y ); _context.lineto( v1.x + 10, v1.y ); _context.moveto( v1.x, v1.y - 10 ); _context.lineto( v1.x, v1.y + 10 ); _context.stroke(); */ } function renderline( v1, v2, element, material ) { setopacity( material.opacity ); setblending( material.blending ); _context.beginpath(); _context.moveto( v1.positionscreen.x, v1.positionscreen.y ); _context.lineto( v2.positionscreen.x, v2.positionscreen.y ); if ( material instanceof three.linebasicmaterial ) { setlinewidth( material.linewidth ); setlinecap( material.linecap ); setlinejoin( material.linejoin ); if ( material.vertexcolors !== three.vertexcolors ) { setstrokestyle( material.color.getstyle() ); } else { var colorstyle1 = element.vertexcolors[ 0 ].getstyle(); var colorstyle2 = element.vertexcolors[ 1 ].getstyle(); if ( colorstyle1 === colorstyle2 ) { setstrokestyle( colorstyle1 ); } else { try { var grad = _context.createlineargradient( v1.positionscreen.x, v1.positionscreen.y, v2.positionscreen.x, v2.positionscreen.y ); grad.addcolorstop( 0, colorstyle1 ); grad.addcolorstop( 1, colorstyle2 ); } catch ( exception ) { grad = colorstyle1; } setstrokestyle( grad ); } } _context.stroke(); _elembox.expandbyscalar( material.linewidth * 2 ); } else if ( material instanceof three.linedashedmaterial ) { setlinewidth( material.linewidth ); setlinecap( material.linecap ); setlinejoin( material.linejoin ); setstrokestyle( material.color.getstyle() ); setlinedash( [ material.dashsize, material.gapsize ] ); _context.stroke(); _elembox.expandbyscalar( material.linewidth * 2 ); setlinedash( [] ); } } function renderface3( v1, v2, v3, uv1, uv2, uv3, element, material ) { _this.info.render.vertices += 3; _this.info.render.faces ++; setopacity( material.opacity ); setblending( material.blending ); _v1x = v1.positionscreen.x; _v1y = v1.positionscreen.y; _v2x = v2.positionscreen.x; _v2y = v2.positionscreen.y; _v3x = v3.positionscreen.x; _v3y = v3.positionscreen.y; drawtriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); if ( ( material instanceof three.meshlambertmaterial || material instanceof three.meshphongmaterial ) && material.map === null ) { _diffusecolor.copy( material.color ); _emissivecolor.copy( material.emissive ); if ( material.vertexcolors === three.facecolors ) { _diffusecolor.multiply( element.color ); } _color.copy( _ambientlight ); _centroid.copy( v1.positionworld ).add( v2.positionworld ).add( v3.positionworld ).dividescalar( 3 ); calculatelight( _centroid, element.normalmodel, _color ); _color.multiply( _diffusecolor ).add( _emissivecolor ); material.wireframe === true ? strokepath( _color, material.wireframelinewidth, material.wireframelinecap, material.wireframelinejoin ) : fillpath( _color ); } else if ( material instanceof three.meshbasicmaterial || material instanceof three.meshlambertmaterial || material instanceof three.meshphongmaterial ) { if ( material.map !== null ) { var mapping = material.map.mapping; if ( mapping === three.uvmapping ) { _uvs = element.uvs; patternpath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); } } else if ( material.envmap !== null ) { if ( material.envmap.mapping === three.sphericalreflectionmapping ) { _normal.copy( element.vertexnormalsmodel[ uv1 ] ).applymatrix3( _normalviewmatrix ); _uv1x = 0.5 * _normal.x + 0.5; _uv1y = 0.5 * _normal.y + 0.5; _normal.copy( element.vertexnormalsmodel[ uv2 ] ).applymatrix3( _normalviewmatrix ); _uv2x = 0.5 * _normal.x + 0.5; _uv2y = 0.5 * _normal.y + 0.5; _normal.copy( element.vertexnormalsmodel[ uv3 ] ).applymatrix3( _normalviewmatrix ); _uv3x = 0.5 * _normal.x + 0.5; _uv3y = 0.5 * _normal.y + 0.5; patternpath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envmap ); } } else { _color.copy( material.color ); if ( material.vertexcolors === three.facecolors ) { _color.multiply( element.color ); } material.wireframe === true ? strokepath( _color, material.wireframelinewidth, material.wireframelinecap, material.wireframelinejoin ) : fillpath( _color ); } } else if ( material instanceof three.meshdepthmaterial ) { _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionscreen.z * v1.positionscreen.w, _camera.near, _camera.far ); material.wireframe === true ? strokepath( _color, material.wireframelinewidth, material.wireframelinecap, material.wireframelinejoin ) : fillpath( _color ); } else if ( material instanceof three.meshnormalmaterial ) { _normal.copy( element.normalmodel ).applymatrix3( _normalviewmatrix ); _color.setrgb( _normal.x, _normal.y, _normal.z ).multiplyscalar( 0.5 ).addscalar( 0.5 ); material.wireframe === true ? strokepath( _color, material.wireframelinewidth, material.wireframelinecap, material.wireframelinejoin ) : fillpath( _color ); } else { _color.setrgb( 1, 1, 1 ); material.wireframe === true ? strokepath( _color, material.wireframelinewidth, material.wireframelinecap, material.wireframelinejoin ) : fillpath( _color ); } } // function drawtriangle( x0, y0, x1, y1, x2, y2 ) { _context.beginpath(); _context.moveto( x0, y0 ); _context.lineto( x1, y1 ); _context.lineto( x2, y2 ); _context.closepath(); } function strokepath( color, linewidth, linecap, linejoin ) { setlinewidth( linewidth ); setlinecap( linecap ); setlinejoin( linejoin ); setstrokestyle( color.getstyle() ); _context.stroke(); _elembox.expandbyscalar( linewidth * 2 ); } function fillpath( color ) { setfillstyle( color.getstyle() ); _context.fill(); } function ontextureupdate ( event ) { texturetopattern( event.target ); } function texturetopattern( texture ) { if ( texture instanceof three.compressedtexture ) return; var repeatx = texture.wraps === three.repeatwrapping; var repeaty = texture.wrapt === three.repeatwrapping; var image = texture.image; var canvas = document.createelement( 'canvas' ); canvas.width = image.width; canvas.height = image.height; var context = canvas.getcontext( '2d' ); context.settransform( 1, 0, 0, - 1, 0, image.height ); context.drawimage( image, 0, 0 ); _patterns[ texture.id ] = _context.createpattern( canvas, repeatx === true && repeaty === true ? 'repeat' : repeatx === true && repeaty === false ? 'repeat-x' : repeatx === false && repeaty === true ? 'repeat-y' : 'no-repeat' ); } function patternpath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { if ( texture instanceof three.datatexture ) return; if ( texture.haseventlistener( 'update', ontextureupdate ) === false ) { if ( texture.image !== undefined && texture.image.width > 0 ) { texturetopattern( texture ); } texture.addeventlistener( 'update', ontextureupdate ); } var pattern = _patterns[ texture.id ]; if ( pattern !== undefined ) { setfillstyle( pattern ); } else { setfillstyle( 'rgba(0,0,0,1)' ); _context.fill(); return; } // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, offsetx = texture.offset.x / texture.repeat.x, offsety = texture.offset.y / texture.repeat.y, width = texture.image.width * texture.repeat.x, height = texture.image.height * texture.repeat.y; u0 = ( u0 + offsetx ) * width; v0 = ( v0 + offsety ) * height; u1 = ( u1 + offsetx ) * width; v1 = ( v1 + offsety ) * height; u2 = ( u2 + offsetx ) * width; v2 = ( v2 + offsety ) * height; x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0; u1 -= u0; v1 -= v0; u2 -= u0; v2 -= v0; det = u1 * v2 - u2 * v1; if ( det === 0 ) return; idet = 1 / det; a = ( v2 * x1 - v1 * x2 ) * idet; b = ( v2 * y1 - v1 * y2 ) * idet; c = ( u1 * x2 - u2 * x1 ) * idet; d = ( u1 * y2 - u2 * y1 ) * idet; e = x0 - a * u0 - c * v0; f = y0 - b * u0 - d * v0; _context.save(); _context.transform( a, b, c, d, e, f ); _context.fill(); _context.restore(); } function clipimage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, width = image.width - 1, height = image.height - 1; u0 *= width; v0 *= height; u1 *= width; v1 *= height; u2 *= width; v2 *= height; x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0; u1 -= u0; v1 -= v0; u2 -= u0; v2 -= v0; det = u1 * v2 - u2 * v1; idet = 1 / det; a = ( v2 * x1 - v1 * x2 ) * idet; b = ( v2 * y1 - v1 * y2 ) * idet; c = ( u1 * x2 - u2 * x1 ) * idet; d = ( u1 * y2 - u2 * y1 ) * idet; e = x0 - a * u0 - c * v0; f = y0 - b * u0 - d * v0; _context.save(); _context.transform( a, b, c, d, e, f ); _context.clip(); _context.drawimage( image, 0, 0 ); _context.restore(); } // hide anti-alias gaps function expand( v1, v2, pixels ) { var x = v2.x - v1.x, y = v2.y - v1.y, det = x * x + y * y, idet; if ( det === 0 ) return; idet = pixels / math.sqrt( det ); x *= idet; y *= idet; v2.x += x; v2.y += y; v1.x -= x; v1.y -= y; } // context cached methods. function setopacity( value ) { if ( _contextglobalalpha !== value ) { _context.globalalpha = value; _contextglobalalpha = value; } } function setblending( value ) { if ( _contextglobalcompositeoperation !== value ) { if ( value === three.normalblending ) { _context.globalcompositeoperation = 'source-over'; } else if ( value === three.additiveblending ) { _context.globalcompositeoperation = 'lighter'; } else if ( value === three.subtractiveblending ) { _context.globalcompositeoperation = 'darker'; } _contextglobalcompositeoperation = value; } } function setlinewidth( value ) { if ( _contextlinewidth !== value ) { _context.linewidth = value; _contextlinewidth = value; } } function setlinecap( value ) { // "butt", "round", "square" if ( _contextlinecap !== value ) { _context.linecap = value; _contextlinecap = value; } } function setlinejoin( value ) { // "round", "bevel", "miter" if ( _contextlinejoin !== value ) { _context.linejoin = value; _contextlinejoin = value; } } function setstrokestyle( value ) { if ( _contextstrokestyle !== value ) { _context.strokestyle = value; _contextstrokestyle = value; } } function setfillstyle( value ) { if ( _contextfillstyle !== value ) { _context.fillstyle = value; _contextfillstyle = value; } } function setlinedash( value ) { if ( _contextlinedash.length !== value.length ) { _context.setlinedash( value ); _contextlinedash = value; } } };