CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/assets/threejs/r73/CanvasRenderer.js
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/**
7
* @author mrdoob / http://mrdoob.com/
8
*/
9
10
THREE.SpriteCanvasMaterial = function ( parameters ) {
11
12
THREE.Material.call( this );
13
14
this.type = 'SpriteCanvasMaterial';
15
16
this.color = new THREE.Color( 0xffffff );
17
this.program = function ( context, color ) {};
18
19
this.setValues( parameters );
20
21
};
22
23
THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
24
THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
25
26
THREE.SpriteCanvasMaterial.prototype.clone = function () {
27
28
var material = new THREE.SpriteCanvasMaterial();
29
30
material.copy( this );
31
material.color.copy( this.color );
32
material.program = this.program;
33
34
return material;
35
36
};
37
38
//
39
40
THREE.CanvasRenderer = function ( parameters ) {
41
42
console.log( 'THREE.CanvasRenderer', THREE.REVISION );
43
44
parameters = parameters || {};
45
46
var _this = this,
47
_renderData, _elements, _lights,
48
_projector = new THREE.Projector(),
49
50
_canvas = parameters.canvas !== undefined
51
? parameters.canvas
52
: document.createElement( 'canvas' ),
53
54
_canvasWidth = _canvas.width,
55
_canvasHeight = _canvas.height,
56
_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
57
_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
58
59
_viewportX = 0,
60
_viewportY = 0,
61
_viewportWidth = _canvasWidth,
62
_viewportHeight = _canvasHeight,
63
64
pixelRatio = 1,
65
66
_context = _canvas.getContext( '2d', {
67
alpha: parameters.alpha === true
68
} ),
69
70
_clearColor = new THREE.Color( 0x000000 ),
71
_clearAlpha = parameters.alpha === true ? 0 : 1,
72
73
_contextGlobalAlpha = 1,
74
_contextGlobalCompositeOperation = 0,
75
_contextStrokeStyle = null,
76
_contextFillStyle = null,
77
_contextLineWidth = null,
78
_contextLineCap = null,
79
_contextLineJoin = null,
80
_contextLineDash = [],
81
82
_camera,
83
84
_v1, _v2, _v3, _v4,
85
_v5 = new THREE.RenderableVertex(),
86
_v6 = new THREE.RenderableVertex(),
87
88
_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
89
_v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
90
91
_color = new THREE.Color(),
92
_color1 = new THREE.Color(),
93
_color2 = new THREE.Color(),
94
_color3 = new THREE.Color(),
95
_color4 = new THREE.Color(),
96
97
_diffuseColor = new THREE.Color(),
98
_emissiveColor = new THREE.Color(),
99
100
_lightColor = new THREE.Color(),
101
102
_patterns = {},
103
104
_image, _uvs,
105
_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
106
107
_clipBox = new THREE.Box2(),
108
_clearBox = new THREE.Box2(),
109
_elemBox = new THREE.Box2(),
110
111
_ambientLight = new THREE.Color(),
112
_directionalLights = new THREE.Color(),
113
_pointLights = new THREE.Color(),
114
115
_vector3 = new THREE.Vector3(), // Needed for PointLight
116
_centroid = new THREE.Vector3(),
117
_normal = new THREE.Vector3(),
118
_normalViewMatrix = new THREE.Matrix3();
119
120
// dash+gap fallbacks for Firefox and everything else
121
122
if ( _context.setLineDash === undefined ) {
123
124
_context.setLineDash = function () {};
125
126
}
127
128
this.domElement = _canvas;
129
130
this.autoClear = true;
131
this.sortObjects = true;
132
this.sortElements = true;
133
134
this.info = {
135
136
render: {
137
138
vertices: 0,
139
faces: 0
140
141
}
142
143
};
144
145
// WebGLRenderer compatibility
146
147
this.supportsVertexTextures = function () {};
148
this.setFaceCulling = function () {};
149
150
// API
151
152
this.getContext = function () {
153
154
return _context;
155
156
};
157
158
this.getContextAttributes = function () {
159
160
return _context.getContextAttributes();
161
162
};
163
164
this.getPixelRatio = function () {
165
166
return pixelRatio;
167
168
};
169
170
this.setPixelRatio = function ( value ) {
171
172
if ( value !== undefined ) pixelRatio = value;
173
174
};
175
176
this.setSize = function ( width, height, updateStyle ) {
177
178
_canvasWidth = width * pixelRatio;
179
_canvasHeight = height * pixelRatio;
180
181
_canvas.width = _canvasWidth;
182
_canvas.height = _canvasHeight;
183
184
_canvasWidthHalf = Math.floor( _canvasWidth / 2 );
185
_canvasHeightHalf = Math.floor( _canvasHeight / 2 );
186
187
if ( updateStyle !== false ) {
188
189
_canvas.style.width = width + 'px';
190
_canvas.style.height = height + 'px';
191
192
}
193
194
_clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
195
_clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
196
197
_clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
198
_clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
199
200
_contextGlobalAlpha = 1;
201
_contextGlobalCompositeOperation = 0;
202
_contextStrokeStyle = null;
203
_contextFillStyle = null;
204
_contextLineWidth = null;
205
_contextLineCap = null;
206
_contextLineJoin = null;
207
208
this.setViewport( 0, 0, width, height );
209
210
};
211
212
this.setViewport = function ( x, y, width, height ) {
213
214
_viewportX = x * pixelRatio;
215
_viewportY = y * pixelRatio;
216
217
_viewportWidth = width * pixelRatio;
218
_viewportHeight = height * pixelRatio;
219
220
};
221
222
this.setScissor = function () {};
223
this.enableScissorTest = function () {};
224
225
this.setClearColor = function ( color, alpha ) {
226
227
_clearColor.set( color );
228
_clearAlpha = alpha !== undefined ? alpha : 1;
229
230
_clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
231
_clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
232
233
};
234
235
this.setClearColorHex = function ( hex, alpha ) {
236
237
console.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
238
this.setClearColor( hex, alpha );
239
240
};
241
242
this.getClearColor = function () {
243
244
return _clearColor;
245
246
};
247
248
this.getClearAlpha = function () {
249
250
return _clearAlpha;
251
252
};
253
254
this.getMaxAnisotropy = function () {
255
256
return 0;
257
258
};
259
260
this.clear = function () {
261
262
if ( _clearBox.empty() === false ) {
263
264
_clearBox.intersect( _clipBox );
265
_clearBox.expandByScalar( 2 );
266
267
_clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;
268
_clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value !
269
_clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
270
_clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value !
271
272
if ( _clearAlpha < 1 ) {
273
274
_context.clearRect(
275
_clearBox.min.x | 0,
276
_clearBox.max.y | 0,
277
( _clearBox.max.x - _clearBox.min.x ) | 0,
278
( _clearBox.min.y - _clearBox.max.y ) | 0
279
);
280
281
}
282
283
if ( _clearAlpha > 0 ) {
284
285
setBlending( THREE.NormalBlending );
286
setOpacity( 1 );
287
288
setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );
289
290
_context.fillRect(
291
_clearBox.min.x | 0,
292
_clearBox.max.y | 0,
293
( _clearBox.max.x - _clearBox.min.x ) | 0,
294
( _clearBox.min.y - _clearBox.max.y ) | 0
295
);
296
297
}
298
299
_clearBox.makeEmpty();
300
301
}
302
303
};
304
305
// compatibility
306
307
this.clearColor = function () {};
308
this.clearDepth = function () {};
309
this.clearStencil = function () {};
310
311
this.render = function ( scene, camera ) {
312
313
if ( camera instanceof THREE.Camera === false ) {
314
315
console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
316
return;
317
318
}
319
320
if ( this.autoClear === true ) this.clear();
321
322
_this.info.render.vertices = 0;
323
_this.info.render.faces = 0;
324
325
_context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY );
326
_context.translate( _canvasWidthHalf, _canvasHeightHalf );
327
328
_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
329
_elements = _renderData.elements;
330
_lights = _renderData.lights;
331
_camera = camera;
332
333
_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
334
335
/* DEBUG
336
setFillStyle( 'rgba( 0, 255, 255, 0.5 )' );
337
_context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y );
338
*/
339
340
calculateLights();
341
342
for ( var e = 0, el = _elements.length; e < el; e ++ ) {
343
344
var element = _elements[ e ];
345
346
var material = element.material;
347
348
if ( material === undefined || material.opacity === 0 ) continue;
349
350
_elemBox.makeEmpty();
351
352
if ( element instanceof THREE.RenderableSprite ) {
353
354
_v1 = element;
355
_v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;
356
357
renderSprite( _v1, element, material );
358
359
} else if ( element instanceof THREE.RenderableLine ) {
360
361
_v1 = element.v1; _v2 = element.v2;
362
363
_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
364
_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
365
366
_elemBox.setFromPoints( [
367
_v1.positionScreen,
368
_v2.positionScreen
369
] );
370
371
if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
372
373
renderLine( _v1, _v2, element, material );
374
375
}
376
377
} else if ( element instanceof THREE.RenderableFace ) {
378
379
_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
380
381
if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;
382
if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;
383
if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;
384
385
_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
386
_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
387
_v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
388
389
if ( material.overdraw > 0 ) {
390
391
expand( _v1.positionScreen, _v2.positionScreen, material.overdraw );
392
expand( _v2.positionScreen, _v3.positionScreen, material.overdraw );
393
expand( _v3.positionScreen, _v1.positionScreen, material.overdraw );
394
395
}
396
397
_elemBox.setFromPoints( [
398
_v1.positionScreen,
399
_v2.positionScreen,
400
_v3.positionScreen
401
] );
402
403
if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
404
405
renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material );
406
407
}
408
409
}
410
411
/* DEBUG
412
setLineWidth( 1 );
413
setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' );
414
_context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y );
415
*/
416
417
_clearBox.union( _elemBox );
418
419
}
420
421
/* DEBUG
422
setLineWidth( 1 );
423
setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' );
424
_context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y );
425
*/
426
427
_context.setTransform( 1, 0, 0, 1, 0, 0 );
428
429
};
430
431
//
432
433
function calculateLights() {
434
435
_ambientLight.setRGB( 0, 0, 0 );
436
_directionalLights.setRGB( 0, 0, 0 );
437
_pointLights.setRGB( 0, 0, 0 );
438
439
for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
440
441
var light = _lights[ l ];
442
var lightColor = light.color;
443
444
if ( light instanceof THREE.AmbientLight ) {
445
446
_ambientLight.add( lightColor );
447
448
} else if ( light instanceof THREE.DirectionalLight ) {
449
450
// for sprites
451
452
_directionalLights.add( lightColor );
453
454
} else if ( light instanceof THREE.PointLight ) {
455
456
// for sprites
457
458
_pointLights.add( lightColor );
459
460
}
461
462
}
463
464
}
465
466
function calculateLight( position, normal, color ) {
467
468
for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
469
470
var light = _lights[ l ];
471
472
_lightColor.copy( light.color );
473
474
if ( light instanceof THREE.DirectionalLight ) {
475
476
var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
477
478
var amount = normal.dot( lightPosition );
479
480
if ( amount <= 0 ) continue;
481
482
amount *= light.intensity;
483
484
color.add( _lightColor.multiplyScalar( amount ) );
485
486
} else if ( light instanceof THREE.PointLight ) {
487
488
var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
489
490
var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
491
492
if ( amount <= 0 ) continue;
493
494
amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
495
496
if ( amount == 0 ) continue;
497
498
amount *= light.intensity;
499
500
color.add( _lightColor.multiplyScalar( amount ) );
501
502
}
503
504
}
505
506
}
507
508
function renderSprite( v1, element, material ) {
509
510
setOpacity( material.opacity );
511
setBlending( material.blending );
512
513
var scaleX = element.scale.x * _canvasWidthHalf;
514
var scaleY = element.scale.y * _canvasHeightHalf;
515
516
var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite
517
_elemBox.min.set( v1.x - dist, v1.y - dist );
518
_elemBox.max.set( v1.x + dist, v1.y + dist );
519
520
if ( material instanceof THREE.SpriteMaterial ) {
521
522
var texture = material.map;
523
524
if ( texture !== null ) {
525
526
var pattern = _patterns[ texture.id ];
527
528
if ( pattern === undefined || pattern.version !== texture.version ) {
529
530
pattern = textureToPattern( texture );
531
_patterns[ texture.id ] = pattern;
532
533
}
534
535
if ( pattern.canvas !== undefined ) {
536
537
setFillStyle( pattern.canvas );
538
539
var bitmap = texture.image;
540
541
var ox = bitmap.width * texture.offset.x;
542
var oy = bitmap.height * texture.offset.y;
543
544
var sx = bitmap.width * texture.repeat.x;
545
var sy = bitmap.height * texture.repeat.y;
546
547
var cx = scaleX / sx;
548
var cy = scaleY / sy;
549
550
_context.save();
551
_context.translate( v1.x, v1.y );
552
if ( material.rotation !== 0 ) _context.rotate( material.rotation );
553
_context.translate( - scaleX / 2, - scaleY / 2 );
554
_context.scale( cx, cy );
555
_context.translate( - ox, - oy );
556
_context.fillRect( ox, oy, sx, sy );
557
_context.restore();
558
559
}
560
561
} else {
562
563
// no texture
564
565
setFillStyle( material.color.getStyle() );
566
567
_context.save();
568
_context.translate( v1.x, v1.y );
569
if ( material.rotation !== 0 ) _context.rotate( material.rotation );
570
_context.scale( scaleX, - scaleY );
571
_context.fillRect( - 0.5, - 0.5, 1, 1 );
572
_context.restore();
573
574
}
575
576
} else if ( material instanceof THREE.SpriteCanvasMaterial ) {
577
578
setStrokeStyle( material.color.getStyle() );
579
setFillStyle( material.color.getStyle() );
580
581
_context.save();
582
_context.translate( v1.x, v1.y );
583
if ( material.rotation !== 0 ) _context.rotate( material.rotation );
584
_context.scale( scaleX, scaleY );
585
586
material.program( _context );
587
588
_context.restore();
589
590
}
591
592
/* DEBUG
593
setStrokeStyle( 'rgb(255,255,0)' );
594
_context.beginPath();
595
_context.moveTo( v1.x - 10, v1.y );
596
_context.lineTo( v1.x + 10, v1.y );
597
_context.moveTo( v1.x, v1.y - 10 );
598
_context.lineTo( v1.x, v1.y + 10 );
599
_context.stroke();
600
*/
601
602
}
603
604
function renderLine( v1, v2, element, material ) {
605
606
setOpacity( material.opacity );
607
setBlending( material.blending );
608
609
_context.beginPath();
610
_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
611
_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
612
613
if ( material instanceof THREE.LineBasicMaterial ) {
614
615
setLineWidth( material.linewidth );
616
setLineCap( material.linecap );
617
setLineJoin( material.linejoin );
618
619
if ( material.vertexColors !== THREE.VertexColors ) {
620
621
setStrokeStyle( material.color.getStyle() );
622
623
} else {
624
625
var colorStyle1 = element.vertexColors[ 0 ].getStyle();
626
var colorStyle2 = element.vertexColors[ 1 ].getStyle();
627
628
if ( colorStyle1 === colorStyle2 ) {
629
630
setStrokeStyle( colorStyle1 );
631
632
} else {
633
634
try {
635
636
var grad = _context.createLinearGradient(
637
v1.positionScreen.x,
638
v1.positionScreen.y,
639
v2.positionScreen.x,
640
v2.positionScreen.y
641
);
642
grad.addColorStop( 0, colorStyle1 );
643
grad.addColorStop( 1, colorStyle2 );
644
645
} catch ( exception ) {
646
647
grad = colorStyle1;
648
649
}
650
651
setStrokeStyle( grad );
652
653
}
654
655
}
656
657
_context.stroke();
658
_elemBox.expandByScalar( material.linewidth * 2 );
659
660
} else if ( material instanceof THREE.LineDashedMaterial ) {
661
662
setLineWidth( material.linewidth );
663
setLineCap( material.linecap );
664
setLineJoin( material.linejoin );
665
setStrokeStyle( material.color.getStyle() );
666
setLineDash( [ material.dashSize, material.gapSize ] );
667
668
_context.stroke();
669
670
_elemBox.expandByScalar( material.linewidth * 2 );
671
672
setLineDash( [] );
673
674
}
675
676
}
677
678
function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) {
679
680
_this.info.render.vertices += 3;
681
_this.info.render.faces ++;
682
683
setOpacity( material.opacity );
684
setBlending( material.blending );
685
686
_v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
687
_v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
688
_v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
689
690
drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
691
692
if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
693
694
_diffuseColor.copy( material.color );
695
_emissiveColor.copy( material.emissive );
696
697
if ( material.vertexColors === THREE.FaceColors ) {
698
699
_diffuseColor.multiply( element.color );
700
701
}
702
703
_color.copy( _ambientLight );
704
705
_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
706
707
calculateLight( _centroid, element.normalModel, _color );
708
709
_color.multiply( _diffuseColor ).add( _emissiveColor );
710
711
material.wireframe === true
712
? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
713
: fillPath( _color );
714
715
} else if ( material instanceof THREE.MeshBasicMaterial ||
716
material instanceof THREE.MeshLambertMaterial ||
717
material instanceof THREE.MeshPhongMaterial ) {
718
719
if ( material.map !== null ) {
720
721
var mapping = material.map.mapping;
722
723
if ( mapping === THREE.UVMapping ) {
724
725
_uvs = element.uvs;
726
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 );
727
728
}
729
730
} else if ( material.envMap !== null ) {
731
732
if ( material.envMap.mapping === THREE.SphericalReflectionMapping ) {
733
734
_normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix );
735
_uv1x = 0.5 * _normal.x + 0.5;
736
_uv1y = 0.5 * _normal.y + 0.5;
737
738
_normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix );
739
_uv2x = 0.5 * _normal.x + 0.5;
740
_uv2y = 0.5 * _normal.y + 0.5;
741
742
_normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix );
743
_uv3x = 0.5 * _normal.x + 0.5;
744
_uv3y = 0.5 * _normal.y + 0.5;
745
746
patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
747
748
}
749
750
} else {
751
752
_color.copy( material.color );
753
754
if ( material.vertexColors === THREE.FaceColors ) {
755
756
_color.multiply( element.color );
757
758
}
759
760
material.wireframe === true
761
? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
762
: fillPath( _color );
763
764
}
765
766
} else if ( material instanceof THREE.MeshNormalMaterial ) {
767
768
_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
769
770
_color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
771
772
material.wireframe === true
773
? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
774
: fillPath( _color );
775
776
} else {
777
778
_color.setRGB( 1, 1, 1 );
779
780
material.wireframe === true
781
? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
782
: fillPath( _color );
783
784
}
785
786
}
787
788
//
789
790
function drawTriangle( x0, y0, x1, y1, x2, y2 ) {
791
792
_context.beginPath();
793
_context.moveTo( x0, y0 );
794
_context.lineTo( x1, y1 );
795
_context.lineTo( x2, y2 );
796
_context.closePath();
797
798
}
799
800
function strokePath( color, linewidth, linecap, linejoin ) {
801
802
setLineWidth( linewidth );
803
setLineCap( linecap );
804
setLineJoin( linejoin );
805
setStrokeStyle( color.getStyle() );
806
807
_context.stroke();
808
809
_elemBox.expandByScalar( linewidth * 2 );
810
811
}
812
813
function fillPath( color ) {
814
815
setFillStyle( color.getStyle() );
816
_context.fill();
817
818
}
819
820
function textureToPattern( texture ) {
821
822
if ( texture.version === 0 ||
823
texture instanceof THREE.CompressedTexture ||
824
texture instanceof THREE.DataTexture ) {
825
826
return {
827
canvas: undefined,
828
version: texture.version
829
}
830
831
}
832
833
var image = texture.image;
834
835
var canvas = document.createElement( 'canvas' );
836
canvas.width = image.width;
837
canvas.height = image.height;
838
839
var context = canvas.getContext( '2d' );
840
context.setTransform( 1, 0, 0, - 1, 0, image.height );
841
context.drawImage( image, 0, 0 );
842
843
var repeatX = texture.wrapS === THREE.RepeatWrapping;
844
var repeatY = texture.wrapT === THREE.RepeatWrapping;
845
846
var repeat = 'no-repeat';
847
848
if ( repeatX === true && repeatY === true ) {
849
850
repeat = 'repeat';
851
852
} else if ( repeatX === true ) {
853
854
repeat = 'repeat-x';
855
856
} else if ( repeatY === true ) {
857
858
repeat = 'repeat-y';
859
860
}
861
862
return {
863
canvas: _context.createPattern( canvas, repeat ),
864
version: texture.version
865
}
866
867
}
868
869
function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {
870
871
var pattern = _patterns[ texture.id ];
872
873
if ( pattern === undefined || pattern.version !== texture.version ) {
874
875
pattern = textureToPattern( texture );
876
_patterns[ texture.id ] = pattern;
877
878
}
879
880
if ( pattern.canvas !== undefined ) {
881
882
setFillStyle( pattern.canvas );
883
884
} else {
885
886
setFillStyle( 'rgba( 0, 0, 0, 1)' );
887
_context.fill();
888
return;
889
890
}
891
892
// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
893
894
var a, b, c, d, e, f, det, idet,
895
offsetX = texture.offset.x / texture.repeat.x,
896
offsetY = texture.offset.y / texture.repeat.y,
897
width = texture.image.width * texture.repeat.x,
898
height = texture.image.height * texture.repeat.y;
899
900
u0 = ( u0 + offsetX ) * width;
901
v0 = ( v0 + offsetY ) * height;
902
903
u1 = ( u1 + offsetX ) * width;
904
v1 = ( v1 + offsetY ) * height;
905
906
u2 = ( u2 + offsetX ) * width;
907
v2 = ( v2 + offsetY ) * height;
908
909
x1 -= x0; y1 -= y0;
910
x2 -= x0; y2 -= y0;
911
912
u1 -= u0; v1 -= v0;
913
u2 -= u0; v2 -= v0;
914
915
det = u1 * v2 - u2 * v1;
916
917
if ( det === 0 ) return;
918
919
idet = 1 / det;
920
921
a = ( v2 * x1 - v1 * x2 ) * idet;
922
b = ( v2 * y1 - v1 * y2 ) * idet;
923
c = ( u1 * x2 - u2 * x1 ) * idet;
924
d = ( u1 * y2 - u2 * y1 ) * idet;
925
926
e = x0 - a * u0 - c * v0;
927
f = y0 - b * u0 - d * v0;
928
929
_context.save();
930
_context.transform( a, b, c, d, e, f );
931
_context.fill();
932
_context.restore();
933
934
}
935
936
function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
937
938
// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
939
940
var a, b, c, d, e, f, det, idet,
941
width = image.width - 1,
942
height = image.height - 1;
943
944
u0 *= width; v0 *= height;
945
u1 *= width; v1 *= height;
946
u2 *= width; v2 *= height;
947
948
x1 -= x0; y1 -= y0;
949
x2 -= x0; y2 -= y0;
950
951
u1 -= u0; v1 -= v0;
952
u2 -= u0; v2 -= v0;
953
954
det = u1 * v2 - u2 * v1;
955
956
idet = 1 / det;
957
958
a = ( v2 * x1 - v1 * x2 ) * idet;
959
b = ( v2 * y1 - v1 * y2 ) * idet;
960
c = ( u1 * x2 - u2 * x1 ) * idet;
961
d = ( u1 * y2 - u2 * y1 ) * idet;
962
963
e = x0 - a * u0 - c * v0;
964
f = y0 - b * u0 - d * v0;
965
966
_context.save();
967
_context.transform( a, b, c, d, e, f );
968
_context.clip();
969
_context.drawImage( image, 0, 0 );
970
_context.restore();
971
972
}
973
974
// Hide anti-alias gaps
975
976
function expand( v1, v2, pixels ) {
977
978
var x = v2.x - v1.x, y = v2.y - v1.y,
979
det = x * x + y * y, idet;
980
981
if ( det === 0 ) return;
982
983
idet = pixels / Math.sqrt( det );
984
985
x *= idet; y *= idet;
986
987
v2.x += x; v2.y += y;
988
v1.x -= x; v1.y -= y;
989
990
}
991
992
// Context cached methods.
993
994
function setOpacity( value ) {
995
996
if ( _contextGlobalAlpha !== value ) {
997
998
_context.globalAlpha = value;
999
_contextGlobalAlpha = value;
1000
1001
}
1002
1003
}
1004
1005
function setBlending( value ) {
1006
1007
if ( _contextGlobalCompositeOperation !== value ) {
1008
1009
if ( value === THREE.NormalBlending ) {
1010
1011
_context.globalCompositeOperation = 'source-over';
1012
1013
} else if ( value === THREE.AdditiveBlending ) {
1014
1015
_context.globalCompositeOperation = 'lighter';
1016
1017
} else if ( value === THREE.SubtractiveBlending ) {
1018
1019
_context.globalCompositeOperation = 'darker';
1020
1021
}
1022
1023
_contextGlobalCompositeOperation = value;
1024
1025
}
1026
1027
}
1028
1029
function setLineWidth( value ) {
1030
1031
if ( _contextLineWidth !== value ) {
1032
1033
_context.lineWidth = value;
1034
_contextLineWidth = value;
1035
1036
}
1037
1038
}
1039
1040
function setLineCap( value ) {
1041
1042
// "butt", "round", "square"
1043
1044
if ( _contextLineCap !== value ) {
1045
1046
_context.lineCap = value;
1047
_contextLineCap = value;
1048
1049
}
1050
1051
}
1052
1053
function setLineJoin( value ) {
1054
1055
// "round", "bevel", "miter"
1056
1057
if ( _contextLineJoin !== value ) {
1058
1059
_context.lineJoin = value;
1060
_contextLineJoin = value;
1061
1062
}
1063
1064
}
1065
1066
function setStrokeStyle( value ) {
1067
1068
if ( _contextStrokeStyle !== value ) {
1069
1070
_context.strokeStyle = value;
1071
_contextStrokeStyle = value;
1072
1073
}
1074
1075
}
1076
1077
function setFillStyle( value ) {
1078
1079
if ( _contextFillStyle !== value ) {
1080
1081
_context.fillStyle = value;
1082
_contextFillStyle = value;
1083
1084
}
1085
1086
}
1087
1088
function setLineDash( value ) {
1089
1090
if ( _contextLineDash.length !== value.length ) {
1091
1092
_context.setLineDash( value );
1093
_contextLineDash = value;
1094
1095
}
1096
1097
}
1098
1099
};
1100
1101