Diep.IO 3D

Turns diep.io into real 3D

目前为 2021-09-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Diep.IO 3D
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.0.6
  5. // @description Turns diep.io into real 3D
  6. // @author Zertalious (Zert)
  7. // @match *://diep.io/*
  8. // @icon https://www.google.com/s2/favicons?domain=diep.io
  9. // @grant none
  10. // @require https://unpkg.com/three@latest/build/three.min.js
  11. // @require https://unpkg.com/three@latest/examples/js/controls/OrbitControls.js
  12. // ==/UserScript==
  13.  
  14. const OUTLINE_LAYER = 0;
  15. const MAIN_LAYER = 1;
  16.  
  17. let renderer, scene, camera, canvas;
  18. let ortho;
  19.  
  20. let currentCamera;
  21.  
  22. init();
  23.  
  24. const tempObject = new THREE.Object3D();
  25. const tempColor = new THREE.Color();
  26.  
  27. const materialParams = { transparent: true };
  28.  
  29. let materialIndex = 0;
  30.  
  31. const outlineMaterial = new THREE.MeshBasicMaterial( materialParams );
  32.  
  33. const materials = [
  34. new THREE.MeshToonMaterial( materialParams ),
  35. new THREE.MeshLambertMaterial( materialParams ),
  36. new THREE.MeshPhongMaterial( materialParams ),
  37. outlineMaterial
  38. ];
  39.  
  40. function onBeforeCompile( shader ) {
  41.  
  42. shader.vertexShader = shader.vertexShader.replace( 'void', `
  43.  
  44. attribute vec2 scale;
  45. attribute float alpha;
  46.  
  47. varying float vAlpha;
  48.  
  49. void` ).replace( '<begin_vertex>', `<begin_vertex>
  50.  
  51. if ( scale.x != 0.0 && scale.y != 0.0 ) {
  52.  
  53. if ( transformed.x == 1.0 || transformed.x == 0.5 ) {
  54.  
  55. transformed.yz *= scale.x;
  56.  
  57. } else if ( transformed.x == - 1.0 || transformed.x == - 0.5 ) {
  58.  
  59. transformed.yz *= scale.y;
  60.  
  61. }
  62.  
  63. }
  64.  
  65. vAlpha = alpha;
  66.  
  67. ` );
  68.  
  69. shader.fragmentShader = shader.fragmentShader.replace( 'void', `
  70.  
  71. varying float vAlpha;
  72.  
  73. void` ).replace( '}', `
  74.  
  75. gl_FragColor.a *= vAlpha;
  76.  
  77. }` );
  78.  
  79. }
  80.  
  81. for ( let i = 0; i < materials.length; i ++ ) {
  82.  
  83. materials[ i ].onBeforeCompile = onBeforeCompile;
  84.  
  85. }
  86.  
  87. const instances = {};
  88.  
  89. const array = [ {
  90. name: 'sphere',
  91. geometry: new THREE.SphereGeometry( 1, 16 ),
  92. count: 150
  93. }, {
  94. name: 'cylinder',
  95. geometry: new THREE.CylinderGeometry( 0.5, 0.5, 1, 16 ).rotateZ( Math.PI / 2 ),
  96. count: 75,
  97. hasScaling: true
  98. }, {
  99. name: 'poly3',
  100. geometry: new THREE.CylinderGeometry( 1, 1, 1, 3, 1, false, - Math.PI / 6 ).rotateX( Math.PI / 2 ),
  101. count: 75
  102. }, {
  103. name: 'poly4',
  104. geometry: new THREE.BoxGeometry( 1, 1, 1 ),
  105. count: 75
  106. }, {
  107. name: 'poly5',
  108. geometry: new THREE.CylinderGeometry( 1, 1, 1, 5, 1, false, Math.PI / 10 ).rotateX( Math.PI / 2 ),
  109. count: 40
  110. }, {
  111. name: 'poly6',
  112. geometry: new THREE.CylinderGeometry( 1, 1, 1, 6, 1, false, - Math.PI / 12 ).rotateX( Math.PI / 2 ),
  113. count: 10
  114. } ];
  115.  
  116. for ( let i = 0; i < array.length; i ++ ) {
  117.  
  118. const { name, geometry, count, hasScaling } = array[ i ];
  119.  
  120. if ( hasScaling ) {
  121.  
  122. geometry.setAttribute( 'scale', new THREE.InstancedBufferAttribute( new Float32Array( count * 2 ), 2 ) );
  123.  
  124. }
  125.  
  126. geometry.setAttribute( 'alpha', new THREE.InstancedBufferAttribute( new Float32Array( count ), 1 ) );
  127.  
  128. const main = new THREE.InstancedMesh( geometry, materials[ materialIndex ], count );
  129. main.layers.set( MAIN_LAYER );
  130. scene.add( main );
  131.  
  132. const outline = new THREE.InstancedMesh( geometry, outlineMaterial, count );
  133. outline.layers.set( OUTLINE_LAYER );
  134. scene.add( outline );
  135.  
  136. main.setColorAt( 0, tempColor );
  137. outline.setColorAt( 0, tempColor );
  138.  
  139. instances[ name ] = {
  140. main,
  141. outline,
  142. count,
  143. hasScaling,
  144. index: 0
  145. };
  146.  
  147. }
  148.  
  149. const stack = [];
  150.  
  151. function getStack( index ) {
  152.  
  153. const result = stack[ stack.length - 1 - index ];
  154.  
  155. if ( result ) {
  156.  
  157. return result;
  158.  
  159. }
  160.  
  161. return { name: 'none' };
  162.  
  163. }
  164.  
  165. function setObject( name, x, y, z, sx, sy, sz, angle, color, alpha = 1, scaleX = 1, scaleY = 1 ) {
  166.  
  167. tempObject.position.set( x, y, z );
  168. tempObject.scale.set( sx, sy, sz );
  169. tempObject.rotation.set( 0, 0, angle );
  170.  
  171. tempObject.updateMatrix();
  172.  
  173. tempColor.set( color );
  174.  
  175. const instance = instances[ name ];
  176.  
  177. instance.main.setMatrixAt( instance.index, tempObject.matrix );
  178. instance.main.setColorAt( instance.index, tempColor );
  179.  
  180. instance.main.geometry.attributes.alpha.setX( instance.index, alpha );
  181. instance.outline.geometry.attributes.alpha.setX( instance.index, alpha );
  182.  
  183. const outlineSize = 4 / window.innerHeight * ( name === 'sphere' ? 0.7 : 1 );
  184.  
  185. if ( instance.hasScaling ) {
  186.  
  187. tempObject.scale.x += outlineSize;
  188. tempObject.scale.y += outlineSize / scaleY;
  189. tempObject.scale.z += outlineSize / scaleY;
  190.  
  191. } else {
  192.  
  193. tempObject.scale.addScalar( outlineSize );
  194.  
  195. }
  196.  
  197. tempObject.updateMatrix();
  198.  
  199. tempColor.multiplyScalar( 0.6 );
  200.  
  201. instance.outline.setMatrixAt( instance.index, tempObject.matrix );
  202. instance.outline.setColorAt( instance.index, tempColor );
  203.  
  204. if ( instance.hasScaling ) {
  205.  
  206. instance.main.geometry.attributes.scale.setXY( instance.index, scaleX, scaleY );
  207. instance.outline.geometry.attributes.scale.setXY( instance.index, scaleX, scaleY );
  208.  
  209. }
  210.  
  211. instance.index ++;
  212.  
  213. stack.push( { name, x, y, z, sx, sy, sz, angle, color, outlineSize, alpha } );
  214.  
  215. }
  216.  
  217. function init() {
  218.  
  219. canvas = document.getElementById( 'canvas' );
  220.  
  221. renderer = new THREE.WebGLRenderer( {
  222. antialias: true,
  223. alpha: true
  224. } );
  225.  
  226. renderer.autoClear = false;
  227.  
  228. renderer.setPixelRatio( window.devicePixelRatio );
  229. renderer.setSize( canvas.width, canvas.height, false );
  230.  
  231. renderer.domElement.style.position = 'absolute';
  232. renderer.domElement.style.left = '0';
  233. renderer.domElement.style.top = '0';
  234. renderer.domElement.style.width = '100%';
  235. renderer.domElement.style.height = '100%';
  236. renderer.domElement.style.pointerEvents = 'none';
  237.  
  238. canvas.parentNode.insertBefore( renderer.domElement, canvas.nextSibling );
  239.  
  240. scene = new THREE.Scene();
  241.  
  242. camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
  243.  
  244. ortho = new THREE.OrthographicCamera( - camera.aspect / 2, camera.aspect / 2, 0.5, - 0.5, 0, 1000 );
  245.  
  246. currentCamera = camera;
  247.  
  248. const oldZ = Math.sin( Math.PI / 3 );
  249. camera.position.z = ortho.position.z = oldZ;
  250.  
  251. const ambLight = new THREE.AmbientLight( 0xffffff, 0.5 );
  252. ambLight.layers.set( MAIN_LAYER );
  253. scene.add( ambLight );
  254.  
  255. const dirLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
  256. dirLight.layers.set( MAIN_LAYER );
  257. dirLight.position.z = 1;
  258. scene.add( dirLight );
  259.  
  260. const controls = new THREE.OrbitControls( camera, canvas );
  261.  
  262. controls.enabled = false;
  263.  
  264. window.addEventListener( 'keyup', function ( event ) {
  265.  
  266. const key = String.fromCharCode( event.keyCode );
  267.  
  268. if ( key === 'V' ) {
  269.  
  270. controls.enabled = ! controls.enabled;
  271.  
  272. if ( ! controls.enabled ) {
  273.  
  274. camera.position.set( 0, 0, oldZ );
  275. camera.rotation.set( 0, 0, 0 );
  276.  
  277. controls.target.set( 0, 0, 0 );
  278.  
  279. ortho.position.set( 0, 0, oldZ );
  280. ortho.rotation.set( 0, 0, 0 );
  281.  
  282. ortho.zoom = 1;
  283.  
  284. }
  285.  
  286. } else if ( key === 'P' ) {
  287.  
  288. currentCamera = currentCamera === camera ? ortho : camera;
  289.  
  290. currentCamera.position.copy( controls.object.position );
  291. currentCamera.rotation.copy( controls.object.rotation );
  292.  
  293. controls.object = currentCamera;
  294.  
  295. } else if ( key === 'B' ) {
  296.  
  297. materialIndex = ( materialIndex + 1 ) % materials.length;
  298.  
  299. for ( let key in instances ) {
  300.  
  301. instances[ key ].main.material = materials[ materialIndex ];
  302.  
  303. }
  304.  
  305. }
  306.  
  307. } );
  308.  
  309. window.addEventListener( 'resize', onWindowResize );
  310.  
  311. }
  312.  
  313. function onWindowResize() {
  314.  
  315. renderer.setSize( canvas.width, canvas.height, false );
  316. camera.aspect = canvas.width / canvas.height;
  317. camera.updateProjectionMatrix();
  318.  
  319. ortho.left = - camera.aspect / 2;
  320. ortho.right = camera.aspect / 2;
  321. ortho.updateProjectionMatrix();
  322.  
  323. }
  324.  
  325. window.requestAnimationFrame = new Proxy( window.requestAnimationFrame, {
  326. apply( target, thisArgs, args ) {
  327.  
  328. args[ 0 ] = new Proxy( args[ 0 ], {
  329. apply( target, thisArgs, args ) {
  330.  
  331. stack.length = 0;
  332.  
  333. tempObject.position.setScalar( 0 );
  334. tempObject.scale.setScalar( 0 );
  335. tempObject.rotation.set( 0, 0, 0 );
  336.  
  337. tempObject.updateMatrix();
  338.  
  339. tempColor.setRGB( 0, 0, 0 );
  340.  
  341. for ( let key in instances ) {
  342.  
  343. const { main, outline, count, hasScaling } = instances[ key ];
  344.  
  345. for ( let i = 0; i < count; i ++ ) {
  346.  
  347. main.setMatrixAt( i, tempObject.matrix );
  348. outline.setMatrixAt( i, tempObject.matrix );
  349.  
  350. }
  351.  
  352. main.instanceMatrix.needsUpdate = true;
  353. main.instanceColor.needsUpdate = true;
  354.  
  355. outline.instanceMatrix.needsUpdate = true;
  356. outline.instanceColor.needsUpdate = true;
  357.  
  358. if ( hasScaling ) {
  359.  
  360. main.geometry.attributes.scale.needsUpdate = true;
  361. outline.geometry.attributes.scale.needsUpdate = true;
  362.  
  363. }
  364.  
  365. main.geometry.attributes.alpha.needsUpdate = true;
  366. outline.geometry.attributes.alpha.needsUpdate = true;
  367.  
  368. instances[ key ].index = 0;
  369.  
  370. }
  371.  
  372. arcCounter = 0;
  373.  
  374. Reflect.apply( ...arguments );
  375.  
  376. renderer.clear();
  377.  
  378. currentCamera.layers.set( OUTLINE_LAYER );
  379.  
  380. renderer.render( scene, currentCamera );
  381.  
  382. renderer.clearDepth();
  383.  
  384. currentCamera.layers.set( MAIN_LAYER );
  385.  
  386. renderer.render( scene, currentCamera );
  387.  
  388. }
  389. } );
  390.  
  391. return Reflect.apply( ...arguments );
  392.  
  393. }
  394. } );
  395.  
  396. const Context2D = CanvasRenderingContext2D.prototype;
  397.  
  398. let arcCounter = 0;
  399.  
  400. Context2D.arc = new Proxy( Context2D.arc, {
  401. apply( target, thisArgs, args ) {
  402.  
  403. if ( args[ 4 ] === Math.PI * 2 ) {
  404.  
  405. if ( arcCounter === 0 ) {
  406.  
  407. const matrix = thisArgs.getTransform();
  408.  
  409. const r = matrix.a / canvas.height;
  410.  
  411. const x = ( matrix.e / canvas.width - 0.5 ) * camera.aspect;
  412. const y = 0.5 - matrix.f / canvas.height;
  413.  
  414. let z = 0;
  415.  
  416. const s0 = getStack( 0 );
  417. const s1 = getStack( 1 );
  418.  
  419. if ( s0.name === 'cylinder' && s1.name === 'sphere' && Math.hypot( x - s1.x, y - s1.y ) < 0.001 ) {
  420.  
  421. z = s1.sz;
  422.  
  423. const index = ( instances.cylinder.index - 1 ) * 16 + 14;
  424.  
  425. const newDepth = z + r - s0.sz / 2;
  426.  
  427. instances.cylinder.main.instanceMatrix.array[ index ] = newDepth;
  428. instances.cylinder.outline.instanceMatrix.array[ index ] = newDepth;
  429.  
  430. } else myBlock: {
  431.  
  432. if ( getStack( 0 ).name === 'cylinder' &&
  433. getStack( 1 ).name === 'sphere' &&
  434. getStack( 2 ).name === 'cylinder' &&
  435. getStack( 3 ).name === 'sphere' &&
  436. getStack( 4 ).name === 'cylinder' &&
  437. getStack( 5 ).name === 'poly3' &&
  438. getStack( 6 ).name === 'cylinder' ) {
  439.  
  440. z = getStack( 5 ).sz / 2;
  441.  
  442. const tr = getStack( 2 ).sz;
  443.  
  444. for ( let i = 0; i < 3; i ++ ) {
  445.  
  446. const index = ( instances.cylinder.index - 1 - i ) * 16 + 14;
  447.  
  448. const newDepth = z + r - tr / 2;
  449.  
  450. instances.cylinder.main.instanceMatrix.array[ index ] = newDepth;
  451. instances.cylinder.outline.instanceMatrix.array[ index ] = newDepth;
  452.  
  453. }
  454.  
  455. for ( let i = 0; i < 2; i ++ ) {
  456.  
  457. const index = ( instances.sphere.index - 1 - i ) * 16 + 14;
  458.  
  459. instances.sphere.main.instanceMatrix.array[ index ] = z;
  460. instances.sphere.outline.instanceMatrix.array[ index ] = z;
  461.  
  462. }
  463.  
  464. break myBlock;
  465.  
  466. }
  467.  
  468. for ( let i = 0; i < 5; i ++ ) {
  469.  
  470. if ( getStack( i ).name !== 'cylinder' ) {
  471.  
  472. break myBlock;
  473.  
  474. }
  475.  
  476. }
  477.  
  478. if ( getStack( 0 ).angle !== getStack( 2 ).angle ) {
  479.  
  480. break myBlock;
  481.  
  482. }
  483.  
  484. const a = r - getStack( 0 ).sy;
  485.  
  486. for ( let i = 0; i < 5; i ++ ) {
  487.  
  488. const index = ( instances.cylinder.index - 1 - i ) * 16 + 14;
  489.  
  490. const newDepth = a - a * 2 * i / 4;
  491.  
  492. instances.cylinder.main.instanceMatrix.array[ index ] = newDepth;
  493. instances.cylinder.outline.instanceMatrix.array[ index ] = newDepth;
  494.  
  495. }
  496.  
  497. }
  498.  
  499. checkIfIsMainCanvas( thisArgs, 'sphere' );
  500.  
  501. setObject(
  502. 'sphere',
  503. x,
  504. y,
  505. z,
  506. r,
  507. r,
  508. r,
  509. 0,
  510. thisArgs.fillStyle,
  511. thisArgs.globalAlpha
  512. );
  513.  
  514. } else if ( arcCounter === 1 ) {
  515.  
  516. tempColor.set( thisArgs.fillStyle );
  517. instances.sphere.main.setColorAt( instances.sphere.index - 1, tempColor );
  518.  
  519. tempColor.multiplyScalar( 0.6 );
  520. instances.sphere.outline.setColorAt( instances.sphere.index - 1, tempColor );
  521.  
  522. }
  523.  
  524. arcCounter = ( arcCounter + 1 ) % 3;
  525.  
  526. }
  527.  
  528. return Reflect.apply( ...arguments );
  529.  
  530. }
  531. } );
  532.  
  533. Context2D.rect = new Proxy( Context2D.rect, {
  534. apply( target, thisArgs, args ) {
  535.  
  536. const matrix = thisArgs.getTransform();
  537.  
  538. const isTurret = matrix.b !== 0 && matrix.c !== 0;
  539.  
  540. if ( isTurret || ( thisArgs.canvas === canvas && Math.hypot( matrix.c, matrix.d ) > 100 && thisArgs.globalAlpha === 1 ) ) {
  541.  
  542. const center = new DOMPoint( 0.5, 0.5 ).matrixTransform( matrix );
  543.  
  544. const scaleYZ = Math.hypot( matrix.c, matrix.d ) / canvas.height;
  545.  
  546. const name = isTurret ? 'cylinder' : 'poly4';
  547.  
  548. checkIfIsMainCanvas( thisArgs, name );
  549.  
  550. setObject(
  551. name,
  552. ( center.x / canvas.width - 0.5 ) * camera.aspect,
  553. 0.5 - center.y / canvas.height,
  554. isTurret ? 0 : 0.05,
  555. Math.hypot( matrix.a, matrix.b ) / canvas.height,
  556. scaleYZ,
  557. isTurret ? scaleYZ : 0.1,
  558. Math.atan2( matrix.c, matrix.d ),
  559. thisArgs.fillStyle,
  560. thisArgs.globalAlpha
  561. );
  562.  
  563. }
  564.  
  565. return Reflect.apply( ...arguments );
  566.  
  567. }
  568. } );
  569.  
  570. const points = [];
  571. let hasCurve = true;
  572.  
  573. Context2D.beginPath = new Proxy( Context2D.beginPath, {
  574. apply( target, thisArgs, args ) {
  575.  
  576. points.length = 0;
  577. hasCurve = false;
  578.  
  579. return Reflect.apply( ...arguments );
  580.  
  581. }
  582. } );
  583.  
  584. const addPoint = {
  585. apply( target, thisArgs, [ x, y ] ) {
  586.  
  587. points.push( new DOMPoint( x, y ).matrixTransform( thisArgs.getTransform() ) );
  588.  
  589. return Reflect.apply( ...arguments );
  590.  
  591. }
  592. };
  593.  
  594. Context2D.moveTo = new Proxy( Context2D.moveTo, addPoint );
  595. Context2D.lineTo = new Proxy( Context2D.lineTo, addPoint );
  596.  
  597. Context2D.arc = new Proxy( Context2D.arc, {
  598. apply( target, thisArgs, args ) {
  599.  
  600. hasCurve = true;
  601.  
  602. return Reflect.apply( ...arguments );
  603.  
  604. }
  605. } );
  606.  
  607. Context2D.fill = new Proxy( Context2D.fill, {
  608. apply( target, thisArgs, args ) {
  609.  
  610. if ( ! hasCurve ) {
  611.  
  612. if ( points.length > 2 && points.length < 7 ) myBlock: {
  613.  
  614. const center = { x: 0, y: 0 };
  615.  
  616. const count = points.length;
  617.  
  618. for ( let i = 0; i < count; i ++ ) {
  619.  
  620. center.x += points[ i ].x;
  621. center.y += points[ i ].y;
  622.  
  623. }
  624.  
  625. center.x /= count;
  626. center.y /= count;
  627.  
  628. if ( points.length === 6 ) {
  629.  
  630. const d1 = Math.hypot( points[ 0 ].x - center.x, points[ 0 ].y - center.y );
  631. const d2 = Math.hypot( points[ 1 ].x - center.x, points[ 1 ].y - center.y );
  632.  
  633. if ( Math.abs( d1 - d2 ) > 0.01 ) {
  634.  
  635. break myBlock;
  636.  
  637. }
  638.  
  639. }
  640.  
  641. let s, sx, angle, scaleX, scaleY;
  642.  
  643. let name = 'poly' + points.length;
  644.  
  645. if ( points.length === 4 ) {
  646.  
  647. const [ p0, p1, p2 ] = points;
  648. const pl = points[ points.length - 1 ];
  649.  
  650. scaleX = Math.hypot( p1.x - p2.x, p1.y - p2.y ) / canvas.height;
  651. scaleY = Math.hypot( p0.x - pl.x, p0.y - pl.y ) / canvas.height;
  652.  
  653. const dx = ( p1.x + p2.x ) / 2 - ( p0.x + pl.x ) / 2;
  654. const dy = ( p1.y + p2.y ) / 2 - ( p0.y + pl.y ) / 2;
  655.  
  656. sx = Math.hypot( dx, dy ) / canvas.height;
  657. angle = Math.atan2( dx, dy ) - Math.PI / 2;
  658.  
  659. if ( Math.abs( scaleX - scaleY ) > 0.001 ) {
  660.  
  661. s = 1;
  662. name = 'cylinder';
  663.  
  664. } else {
  665.  
  666. s = sx = scaleY;
  667.  
  668. }
  669.  
  670. } else {
  671.  
  672. s = sx = Math.hypot( points[ 0 ].x - center.x, points[ 0 ].y - center.y ) / canvas.height;
  673.  
  674. angle = - Math.atan2( points[ 0 ].y - center.y, points[ 0 ].x - center.x );
  675.  
  676. }
  677.  
  678. checkIfIsMainCanvas( thisArgs, name );
  679.  
  680. setObject(
  681. name,
  682. ( center.x / canvas.width - 0.5 ) * camera.aspect,
  683. 0.5 - center.y / canvas.height,
  684. 0,
  685. sx,
  686. s,
  687. s,
  688. angle,
  689. thisArgs.fillStyle,
  690. thisArgs.globalAlpha,
  691. scaleX,
  692. scaleY
  693. );
  694.  
  695. }
  696.  
  697. }
  698.  
  699. return Reflect.apply( ...arguments );
  700.  
  701. }
  702. } );
  703.  
  704. Context2D.drawImage = new Proxy( Context2D.drawImage, {
  705. apply( target, thisArgs, args ) {
  706.  
  707. if ( thisArgs.canvas === canvas && args[ 0 ].objects ) {
  708.  
  709. const matrix = thisArgs.getTransform();
  710.  
  711. const x = matrix.e / canvas.width;
  712. const y = matrix.f / canvas.height;
  713.  
  714. const sx = Math.hypot( matrix.a, matrix.b );
  715. const sy = Math.hypot( matrix.c, matrix.d );
  716.  
  717. for ( let i = 0; i < args[ 0 ].objects.length; i ++ ) {
  718.  
  719. const { name, index } = args[ 0 ].objects[ i ];
  720.  
  721. const instance = instances[ name ];
  722.  
  723. const ma = instance.main.instanceMatrix.array;
  724. const oa = instance.outline.instanceMatrix.array;
  725.  
  726. const idx = index * 16;
  727.  
  728. const ox = ma[ idx + 12 ] / camera.aspect + 0.5;
  729. const oy = - ma[ idx + 13 ] + 0.5;
  730.  
  731. const outlineOldSx = Math.hypot( oa[ idx + 0 ], oa[ idx + 1 ] );
  732. const outlineOldSy = Math.hypot( oa[ idx + 4 ], oa[ idx + 5 ] );
  733.  
  734. const outlineSizeX = outlineOldSx - Math.hypot( ma[ idx + 0 ], ma[ idx + 1 ] );
  735. const outlineSizeY = outlineOldSy - Math.hypot( ma[ idx + 4 ], ma[ idx + 5 ] );
  736.  
  737. ma[ idx + 0 ] *= sx;
  738. ma[ idx + 1 ] *= sx;
  739. ma[ idx + 4 ] *= sy;
  740. ma[ idx + 5 ] *= sy;
  741. ma[ idx + 10 ] *= sy;
  742.  
  743. const nsx = Math.hypot( ma[ idx + 0 ], ma[ idx + 1 ] ) + outlineSizeX;
  744. const nsy = Math.hypot( ma[ idx + 4 ], ma[ idx + 5 ] ) + outlineSizeY;
  745.  
  746. oa[ idx + 0 ] *= nsx / outlineOldSx;
  747. oa[ idx + 1 ] *= nsx / outlineOldSx;
  748. oa[ idx + 4 ] *= nsy / outlineOldSy;
  749. oa[ idx + 5 ] *= nsy / outlineOldSy;
  750. oa[ idx + 10 ] *= sy;
  751.  
  752. ma[ idx + 12 ] = oa[ idx + 12 ] = ( ( ox * sx + x ) - 0.5 ) * camera.aspect;
  753. ma[ idx + 13 ] = oa[ idx + 13 ] = 0.5 - ( oy * sy + y );
  754.  
  755. instance.main.geometry.attributes.alpha.array[ index ] = thisArgs.globalAlpha;
  756. instance.outline.geometry.attributes.alpha.array[ index ] = thisArgs.globalAlpha;
  757.  
  758. }
  759.  
  760. delete args[ 0 ][ 'objects' ];
  761.  
  762. }
  763.  
  764. return Reflect.apply( ...arguments );
  765.  
  766. }
  767. } );
  768.  
  769. function checkIfIsMainCanvas( ctx, name ) {
  770.  
  771. if ( ctx.canvas !== canvas ) {
  772.  
  773. const { index } = instances[ name ];
  774.  
  775. if ( ctx.canvas.objects ) {
  776.  
  777. ctx.canvas.objects.push( { name, index } );
  778.  
  779. } else {
  780.  
  781. ctx.canvas.objects = [ { name, index } ];
  782.  
  783. }
  784.  
  785. }
  786.  
  787. }