PageSourceSearch

https://www.amalphi.de/wp-content/plugins/interactive-globes-premi…/js/public/globe-pro.min.js?ver=2.0.3

js amalphi.de collected 2026-10-05 19:10:18 UTC 978,701 bytes, 34,006 lines download raw bytes

1/**
2 * Prepares safe url
3 * @param string str url to prepare
4 * @returns string prepared URL
5 */
6const globe_ut_prepareURL = function (str) {
7
8	if (typeof str !== "string") {
9		return str;
10	}
11
12	// parse html entities
13	str = str.replace(/&/gi, '&');
14	str.replace(/&#(\d+);/g, function (match, dec) {
15		return String.fromCharCode(dec);
16	});
17
18	// check if allowed url
19	var url, protocols;
20	try {
21		url = new URL(str);
22	} catch (_) {
23		url = false;
24	}
25
26	// check if valid url. If string it might be a anchor or relative path, so keep going
27	if (url) {
28		// acepted protocols
29		protocols = [null, "http:", "https:", "mailto:", "tel:"];
30		if (!protocols.includes(url.protocol)) {
31			console.log('URL protocol not allowed');
32			return '';
33		}
34	}
35
36	return str;
37
38};
39
40/** Prepare data to be used. Set defaults and other operations */
41const globe_ut_prepareData = function ( data ) {
42
43	if ( ! data.hasOwnProperty( 'dotLabels' ) || ! data.dotLabels ) {
44		data['dotlabels'] = [];
45	}
46	if ( ! data.hasOwnProperty( 'points' ) || ! data.points ) {
47		data['points'] = [];
48	}
49
50	// set preview defaults
51	let defaults = {
52		'showGraticules': false,
53		'backgroundColor': 'transparent',
54		'atmosphere': {
55			'enabled': false,
56			'atmosphereColor': null,
57			'atmosphereAltitude': null
58		},
59		'globeImage': 'earth-day.jpg'
60	};
61
62	// merge data with defaults
63	if ( Object.keys(data).length === 0 || data.emptyPreview ) {
64		Object.assign(data, defaults);
65	}
66
67	// set point of view
68	data.pointOfView = {
69		lat: 0,
70		lng: 0,
71		altitude: 1.5
72	};
73
74	if ( ! data.centerCoordinates ) {
75		data.centerCoordinates = {
76			latitude: 0,
77			lat: 0,
78			longitude: 0,
79			lng: 0
80		};
81	}
82	if (data.centerCoordinates) {
83		let altitude = typeof data.altitudeOptions !== 'undefined' ? data.altitudeOptions.altitude : data.altitude;
84		data.pointOfView.lat      = globe_ut_float(data.centerCoordinates.latitude);
85		data.pointOfView.lng      = globe_ut_float(data.centerCoordinates.longitude);
86		const floatAltitude = globe_ut_float(altitude);
87		data.pointOfView.altitude = (altitude !== '' && typeof altitude !== 'undefined') ? floatAltitude : 1.7;
88	}
89
90	return data;
91};
92
93const globe_ut_prepareProData = function ( data ) {
94
95	if ( ! data.hasOwnProperty( 'arcLines' ) || ! data.arcLines ) {
96		data['arcLines'] = [];
97	}
98	if ( ! data.hasOwnProperty( 'regions' ) || ! data.arcLines ) {
99		data['regions'] = [];
100	}
101	if ( ! data.hasOwnProperty( 'html' ) || ! data.html ) {
102		data['html'] = [];
103	}
104
105	return data;
106};
107
108
109const globe_ut_setupData = function ( data, dataTypes ) {
110
111	data.centerCoordinates.lat = parseFloat( data.centerCoordinates.lat );
112	data.centerCoordinates.lng = parseFloat( data.centerCoordinates.lng );
113
114	for (const key in dataTypes) {
115		let defaults = dataTypes[key];
116		if ( data[key] && Array.isArray( data[key] ) ) {
117			data[key].map(function (entry) {
118				// add defaults data type
119				if ( typeof entry.useCustom === "undefined" ||
120					( typeof entry.useCustom !== "undefined" && ! globe_ut_bool( entry.useCustom ) ) ) {
121					Object.assign(entry, data[defaults]);
122				}
123
124				if(Array.isArray(entry.action)){
125					entry.action = entry.action[0];
126				}
127
128				// if it's using default action
129				if ( data[defaults] && entry.action && entry.action === 'default') {
130					entry.action = data[defaults]['action'];
131				}
132			});
133		}
134	}
135};
136
137/**
138 * Prepare viewport and globe
139 * @param DOM element container
140 * @param object data
141 * @param Globe Object thisGlobe
142 */
143const globe_ut_prepareViewport = function ( container, data ) {
144	var aspRatioContainer = container.closest(".itt_globe_aspect_ratio");
145
146	// container size adjustment
147	// if mobile
148	if (window.innerWidth <= 780 && typeof data.paddingTop !== 'undefined' && data.paddingTop !== '') {
149		aspRatioContainer.style.paddingTop = String(data.paddingTopMobile) + '%';
150	} else {
151		aspRatioContainer.style.paddingTop = String(data.paddingTop) + '%';
152	}
153};
154
155/**
156 * Returns float, even if not a number
157 * @param {string} string to get float from
158 * @returns int float number
159 */
160const globe_ut_float = function (string) {
161	var float = parseFloat(string);
162	if (isNaN(float)) {
163		return 0;
164	}
165	return float;
166};
167
168/**
169 * Returns boolean value of a string or number
170 * @param {*} string
171 * @returns boolen
172 */
173const globe_ut_bool = function (string) {
174	var bool = Number(string) === 0 || string === "false" || typeof string === "undefined" ? false : true;
175	return bool;
176};
177
178const globe_ut_prepare_coordinates = function( type, marker ){
179
180	if( typeof marker.coordinates !== 'undefined' && marker.coordinates[type] ){
181		return parseFloat( marker.coordinates[type] );
182	}
183
184	if( typeof marker[type] !== 'undefined' ){
185		return parseFloat( marker[type] );
186	}
187	return false;
188};
189
190/**
191 * Sanitizes HTML string using a whitelist approach to prevent XSS.
192 * Allows basic formatting tags but removes unsafe tags and attributes.
193 * @param {string} htmlString
194 * @returns {string} Safe HTML string
195 */
196const globe_ut_sanitize = function(htmlString) {
197	if (!htmlString || typeof htmlString !== 'string') {
198		return '';
199	}
200
201	// Create a detached element to parse HTML
202	const parser = new DOMParser();
203	const doc = parser.parseFromString(htmlString, 'text/html');
204	const body = doc.body;
205
206	// Allowed tags
207	const allowedTags = [
208		'DIV', 'SPAN', 'B', 'STRONG', 'I', 'EM', 'U', 'P', 'BR', 'UL', 'OL', 'LI', 'IMG', 'A',
209		'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'TABLE', 'THEAD', 'TBODY', 'TR', 'TD', 'TH', 'BLOCKQUOTE', 'BODY'
210	];
211
212	// Allowed attributes
213	const allowedAttributes = [
214		'id', 'class', 'title', 'src', 'alt', 'href', 'target', 'width', 'height', 'rel'
215	];
216
217	// Recursive sanitization function
218	function sanitizeNode(node) {
219		const children = Array.from(node.childNodes);
220		for (const child of children) {
221			sanitizeNode(child);
222		}
223
224		// Remove disallowed tags
225		if (node.nodeType === 1) { // Element node
226			if (!allowedTags.includes(node.tagName)) {
227				// Replace with text content if it's not script/style, otherwise remove entirely
228				if (['SCRIPT', 'STYLE', 'IFRAME', 'OBJECT', 'EMBED', 'LINK', 'META'].includes(node.tagName)) {
229					node.remove();
230				} else {
231					// Unwrap safe text content for other unknown tags
232					while (node.firstChild) {
233						node.parentNode.insertBefore(node.firstChild, node);
234					}
235					node.remove();
236				}
237			} else {
238				// Sanitize attributes
239				const attributes = Array.from(node.attributes);
240				for (const attr of attributes) {
241					// Remove attributes not in whitelist
242					if (!allowedAttributes.includes(attr.name.toLowerCase())) {
243						node.removeAttribute(attr.name);
244						continue;
245					}
246
247					// Special checks
248					// Block javascript: protocols in href and src
249					if (['href', 'src'].includes(attr.name.toLowerCase())) {
250						// Remove control characters (00-31 and 127) before checking to prevent bypasses
251						const val = attr.value.replace(/[\x00-\x1F\x7F]+/g, '').trim().toLowerCase();
252						if ( val.startsWith('javascript:') || val.startsWith('vbscript:') || (val.startsWith('data:') && !val.startsWith('data:image/')) ) {
253							node.removeAttribute(attr.name);
254						}
255					}
256					// Block event handlers (on*) just in case they slipped through whitelist (though not in allowedAttributes)
257					if (attr.name.toLowerCase().startsWith('on')) {
258						node.removeAttribute(attr.name);
259					}
260					// Prevent tabnabbing
261					if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {
262						node.setAttribute('rel', 'noopener noreferrer');
263					}
264				}
265			}
266		}
267	}
268
269	sanitizeNode(body);
270	return body.innerHTML;
271};
272
273/** Setup tooltip for element */
274function setupTooltip( element, template ) {
275
276	let tooltip = element.tooltipContent ?? '';
277	if( typeof template !== 'undefined' && template !== '{tooltipContent}' && template.length > 0 ){
278
279		tooltip = template.replace(/\{([^}]+)\}/g, function(match, key) {
280			// Split the key by dot notation
281			const keys = key.split('.');
282			let value = element;
283
284			// Traverse the object using the keys
285			for (let i = 0; i < keys.length; i++) {
286				value = value ? value[keys[i]] : undefined;
287			}
288
289			// If the value is undefined, replace it with an empty string or handle as necessary
290			return value !== undefined ? String(value) : '';
291		});
292	}
293
294	// Sanitize the final result to ensure both template and values are safe
295	tooltip = globe_ut_sanitize(tooltip);
296
297	if ( tooltip !== '') {
298		tooltip = '<div class="itt_globe_' + element.globe_id + ' itt_globe_tooltip">' + tooltip + '</div>';
299	}
300	return tooltip;
301}
302
303/** Setup click events for element */
304function setupClickEvent$1( thisGlobe, GlobeData, element ) {
305
306	let layerDataTypes = {
307		'arcLines': 'arcLineDefaults',
308		'points': 'pointDefaults',
309		'dotLabels': 'labelDefaults',
310		'regions': 'regionDefaults',
311		'html': 'htmlDefaults',
312	};
313
314	if(element.type === 'flag' || element.type === 'marker' || element.type === 'cylinder' || element.type === 'pin'){
315		element.type = 'points';
316	}
317
318	if(element.type === 'regions' && element.properties){
319		element = { ...element.properties };
320	}
321
322	if (new URLSearchParams(window.location.search).has('debug')) {
323		console.debug(element);
324	}
325
326	// if we arrive here and it's still set as default, we need to set it to the default action for that layer
327	if( element.action === 'default' ){
328		element.action = GlobeData[layerDataTypes[element.type]].action;
329	}
330
331	if (element.action === "none") {
332		// do nothing
333		return;
334	}
335
336	const clickAction = element.action;
337	if (clickAction && typeof window.ittGlobes.clickActions[clickAction] === 'function') {
338		window.ittGlobes.clickActions[clickAction]( thisGlobe, GlobeData, element );
339	}
340	if ( ittGlobeData.isAdmin ) {
341		return;
342	}
343
344	// check urls
345	if (element.action === "open_url" || element.action === "open_url_new") {
346		element.content = globe_ut_prepareURL(element.content);
347	}
348	// open new url
349	if (element.action === "open_url" && element.content !== "") {
350		document.location = element.content;
351	} else if (element.action === "open_url_new" && element.content !== "") {
352		window.open(element.content);
353	}
354}
355
356/** Setup hover events for element */
357function setupHoverEvent$1(thisGlobe, element, prevElement, type) {
358	
359	let GlobeData = thisGlobe.meta;
360	
361	if (type === 'regions') {
362
363		//pause/resume animation
364		if (
365			typeof GlobeData.rotate !== 'undefined' &&
366			globe_ut_bool(GlobeData.rotate.enabled)
367		) {
368			// Pause auto-rotation when hovering over a region, resume when not hovering
369			thisGlobe.controls().autoRotate = !element;
370		}
371
372		
373		thisGlobe.polygonCapColor(function (region) {
374			// when hovering the globe itself, element doesn't exist or doesn't have properties
375			if (
376				typeof element === 'undefined' ||
377				(element && typeof element.properties === 'undefined' && typeof element.originalId === 'undefined')
378			) {
379				// Return original color when hovering over empty space or invalid element
380				return region.properties.color
381					? region.properties.color
382					: GlobeData.regionDefaults.inactive;
383			}
384			// change hover color if being hovered or part of same group
385			else if (region === element) {
386				// Apply hover color to the specific region being hovered
387				return region.properties.hover;
388			} 
389			// Handle case where element itself contains properties (like originalId)
390			else if (
391				element &&
392				element.originalId &&
393				Array.isArray(element.originalId) &&
394				region.properties.originalId &&
395				Array.isArray(region.properties.originalId) &&
396				element.originalId.some(id => region.properties.originalId.includes(id))
397			) {
398				console.log('triggered case where element itself contains properties (like originalId)');
399				// Apply hover color to regions that match the element's originalId
400				return element.hover || region.properties.hover;
401			}
402			// Handle case where element has properties but we're checking against region properties
403			else if (
404				region.properties.originalId &&
405				element &&
406				element.properties &&
407				element.properties.id &&
408				region.properties.originalId.includes(element.properties.id)
409			) {
410				// Apply hover color to regions that share the same original ID (grouped regions)
411				return region.properties.hover;
412			} else if (
413				region.properties.originalId &&
414				element &&
415				element.properties &&
416				Array.isArray(element.properties.id) &&
417				element.properties.id.includes(region.properties.id)
418			) {
419				// Apply hover color to regions that are part of an array of IDs (multi-selection)
420				return region.properties.hover;
421			}
422			// we actually don't need the previous I think, we can reset the value for the rest of the entries
423			// Return original color for all other regions (not being hovered or grouped)
424			return region.properties.color
425				? region.properties.color
426				: GlobeData.regionDefaults.inactive;
427		});
428	} 
429
430	else if (type === 'pin' || type === 'marker') {
431		if (element) {
432			// Convert hex color to integer
433			const hoverColor = parseInt(element.hover.replace('#', '0x'), 16);
434			parseInt(element.color.replace('#', '0x'), 16);
435
436			let threeObj = element.__threeObjObject ? element.__threeObjObject : element.__threeObj;
437
438			if (type === 'pin' ) {
439				threeObj.children[0].children.forEach((element) => {
440					element.material.color.setHex(hoverColor);
441				});
442			} else if (type === 'marker') {
443				threeObj.children[0].material.color.setHex(hoverColor);
444			}
445		}
446
447		if (prevElement && prevElement !== element) {
448			const originalColor = parseInt(prevElement.color.replace('#', '0x'), 16);
449			let threeObj = prevElement.__threeObjObject ? prevElement.__threeObjObject : prevElement.__threeObj;
450			
451			if (type === 'pin') {
452				threeObj.children[0].children.forEach((element) => {
453					element.material.color.setHex(originalColor);
454				});
455			} else if (type === 'marker' && prevElement.type === 'marker') {
456				threeObj.children[0].material.color.setHex(originalColor);
457			}
458		}
459		
460
461		//pause/resume animation
462		if (
463			typeof GlobeData.rotate !== 'undefined' &&
464			globe_ut_bool(GlobeData.rotate.enabled)
465		) {
466			thisGlobe.controls().autoRotate = !element;
467		}
468
469	} 
470	
471	else { // for default points and labels
472		thisGlobe.labelColor(function (el) {
473			return element && el.id === element.id ? el.hover : el.color;
474		});
475
476		thisGlobe.pointColor(function (el) {
477			return element && el.id === element.id ? el.hover : el.color;
478		});
479
480		//pause/resume animation
481		if (
482			typeof GlobeData.rotate !== 'undefined' &&
483			globe_ut_bool(GlobeData.rotate.enabled)
484		) {
485			thisGlobe.controls().autoRotate = !element;
486		}
487	}
488
489	return thisGlobe;
490}
491
492/** Add Points Layer to Globe */
493function addPointsLayer(thisGlobe, GlobeData) {
494	thisGlobe.pointsData( GlobeData.points )
495		.pointLat(p => globe_ut_prepare_coordinates('latitude', p) )
496		.pointLng(p => globe_ut_prepare_coordinates('longitude', p) )
497		.pointRadius(p => p.radius / 10)
498		.pointAltitude(p => p.altitude / 100)
499		.pointColor(p => p.color)
500		.pointResolution(20);
501
502	// tooltip
503	thisGlobe.pointLabel(function (label) {
504
505		let pointsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}';
506		if( GlobeData.pointsTooltipTemplate ){
507			pointsTooltipTemplate = GlobeData.pointsTooltipTemplate;
508		}
509		return setupTooltip(label, pointsTooltipTemplate );
510
511	});
512
513	// click events
514	thisGlobe.onPointClick(function ( element ) {
515		setupClickEvent$1( thisGlobe, GlobeData, element );
516	});
517
518	// hover events
519	thisGlobe.onPointHover(function (label) {
520		setupHoverEvent$1( thisGlobe, label, 'point' );
521	});
522
523	// click events
524	thisGlobe.onObjectClick(function ( element ) {
525		setupClickEvent$1( thisGlobe, GlobeData, element );
526	});
527}
528
529/** Add Labels Layer to Globe */
530function addLabelsLayer( thisGlobe, GlobeData ) {
531
532	thisGlobe.labelsData( GlobeData.dotLabels )
533		.labelLat(l => globe_ut_prepare_coordinates('latitude', l))
534		.labelLng(l => globe_ut_prepare_coordinates('longitude', l))
535		.labelText(l => l.title ? (l.title.trim() ? l.title : '_') : '_')
536		.labelAltitude(l => l.altitude / 100)
537		.labelSize(l => l.size / 10)
538		.labelColor(l => l.color)
539		.labelResolution(20)
540		.labelIncludeDot(l => globe_ut_bool(l.includeDot))
541		.labelDotRadius(l => l.radius / 10)
542		.labelDotOrientation(l => l.dotOrientation);
543
544	// font
545	if (GlobeData.labelFont && GlobeData.labelFont !== 'default') {
546
547		let url = ittGlobeData.assetsUrl + 'fonts/' + GlobeData.labelFont + '.json';
548
549		fetch(url)
550			.then(res => res.json())
551			.then( labelfont => { thisGlobe.labelTypeFace(labelfont); } )
552			.catch(error => {
553				console.error('Fetch error:', error);
554			});
555	}
556
557	// tooltip
558	thisGlobe.labelLabel(function (label) {
559
560		let dotLabelsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}';
561		if( GlobeData.dotLabelsTooltipTemplate ){
562			dotLabelsTooltipTemplate = GlobeData.dotLabelsTooltipTemplate;
563		}
564		return setupTooltip(label, dotLabelsTooltipTemplate );
565	});
566
567	// click events
568	thisGlobe.onLabelClick(function (label, event, coordinates) {
569		setupClickEvent$1( thisGlobe, GlobeData, label );
570	});
571
572	// hover events
573	thisGlobe.onLabelHover(function (label) {
574		setupHoverEvent$1( thisGlobe, label, 'label' );
575	});
576}
577
578/** Setup click events for element */
579function setupResizeEvent( thisGlobe, container, data ) {
580
581	var aspRatioContainer = container.closest(".itt_globe_aspect_ratio");
582
583	window.addEventListener('resize', function () {
584		if (window.innerWidth <= 780 && typeof data.paddingTop !== 'undefined' && data.paddingTop !== '') {
585			aspRatioContainer.style.paddingTop = String(data.paddingTopMobile) + '%';
586		} else {
587			aspRatioContainer.style.paddingTop = String(data.paddingTop) + '%';
588		}
589
590		// Here should go the code to rebuild globe with new size in a more performant way
591		// check for size changes, etc..
592		if (thisGlobe.width() !== container.offsetWidth) {
593			thisGlobe
594				.width(container.offsetWidth)
595				.height(container.offsetHeight);
596		}
597	});
598}
599
600/**
601 * Controls globe interactions
602 * @param {*} thisGlobe
603 * @param {*} data
604 */
605function setupInteractions( thisGlobe, data ) {
606		// interactions
607		if( typeof data.interactions !== 'undefined' ) {
608			thisGlobe.controls().enableZoom   = globe_ut_bool( data.interactions.zoom );
609			thisGlobe.controls().enablePan    = globe_ut_bool( data.interactions.pan );
610			thisGlobe.controls().enableRotate = globe_ut_bool( data.interactions.pan );
611		}
612
613		if( typeof data.interactions === 'undefined' || globe_ut_bool( data.interactions.zoom ) ) {
614
615			let lastClickTime = 0;
616			const doubleClickDelay = 300; // milliseconds
617
618			thisGlobe.onGlobeClick(function(coordinates, event) {
619
620				const currentTime = new Date().getTime();
621				const timeDiff = currentTime - lastClickTime;
622
623				if (timeDiff < doubleClickDelay) {
624					// Double click detected - zoom in
625					let zoomTo = thisGlobe.pointOfView();
626					zoomTo.altitude = zoomTo.altitude * 0.6;
627					zoomTo.lat = coordinates.lat;
628					zoomTo.lng = coordinates.lng;
629					thisGlobe.pointOfView(zoomTo, 800);
630				}
631
632				lastClickTime = currentTime;
633			});
634		}
635}
636
637let ittGlobes$1 = {
638    'globes': [],
639    'globesIndex': {},
640    'clickActions': {},
641};
642
643window.ittGlobes = ittGlobes$1;
644
645function addArcLines(globe, data) {
646	// Create GeoJSON features from arc lines
647	const features = data.arcLines.map((line, index) => {
648		// Line properties have already been processed, so use them directly
649		const lineProps = line;
650		// Get the layer ID and globe ID
651		let layerId = line._layerId ? line._layerId : line.globe_id;
652		let globeId = line.globe_id;
653
654		// If no layer ID is set, try to find the layer this line belongs to
655		if (!layerId && data.layers) {
656			const matchingLayer = data.layers.find(layer =>
657				layer.arcLines && layer.arcLines.some(l => l === line)
658			);
659			if (matchingLayer) {
660				layerId = matchingLayer.id;
661				globeId = matchingLayer.globe_id;
662			}
663		}
664
665		// If still no globe ID, use the base map ID
666		if (!globeId) {
667			globeId = data.id;
668		}
669
670		let feature = {
671			type: 'Feature',
672			id: index,
673			properties: {
674				stroke: lineProps.stroke || '#000000',
675				strokeWidth: parseInt(lineProps.strokeWidth || 5, 10),
676				globe_id: globeId,
677				layer_id: layerId,
678				isActive: true
679			},
680			geometry: {
681				type: 'LineString',
682				coordinates: line.line.map(point => [
683					point.coordinates.longitude,
684					point.coordinates.latitude
685				])
686			}
687		};
688
689		return feature;
690	});
691
692	// Add source
693	globe.addSource('lines', {
694		type: 'geojson',
695		data: {
696			type: 'FeatureCollection',
697			features: features
698		}
699	});
700
701	// Get all layers and find the last region border layer
702	const styleLayers = globe.getStyle().layers;
703	const borderLayerIndices = styleLayers
704		.map((layer, index) => layer.id.endsWith('-borders') ? index : -1)
705		.filter(index => index !== -1);
706
707	// If we found any border layers, add lines after the last one
708	// If no border layers found, add at the very end
709	const lastBorderIndex = borderLayerIndices.length > 0
710		? Math.max(...borderLayerIndices)
711		: styleLayers.length - 1;
712
713	styleLayers[Math.min(lastBorderIndex + 1, styleLayers.length - 1)].id;
714
715	// Add layer with high z-index to ensure it's on top
716	globe.addLayer({
717		id: 'lines',
718		type: 'line',
719		source: 'lines',
720		layout: {
721			'line-join': 'round',
722			'line-cap': 'round'
723		},
724		paint: {
725			'line-color': ['get', 'stroke'],
726			'line-width': ['get', 'strokeWidth'],
727			'line-opacity': [
728				'case',
729				['boolean', ['feature-state', 'visible'], false],
730				1,
731				0
732			]
733		}
734	}); // if provided, it will Insert the layer beneath the first symbol layer.
735	// so by not passing the second parameter, it places on top.
736
737	// Set initial feature states for lines
738	features.forEach(feature => {
739
740		if (feature.id !== undefined) {
741			// Check if we have a default layer set and keepBase is disabled
742			const hasDefaultLayer = data.liveFilter?.enabled === '1' && data.liveFilter?.default;
743			const keepBaseDisabled = data.liveFilter?.keepBase !== '1';
744			const defaultGlobeId = data.liveFilter?.default;
745			const featureGlobeId = feature.properties.globe_id;
746
747			// Determine initial visibility - FIXED: Don't hide lines by default
748			let shouldBeVisible = true;
749
750			if (hasDefaultLayer && keepBaseDisabled) {
751				// If we have a default layer and keepBase is disabled,
752				// only show lines that match the default layer's globe ID
753				shouldBeVisible = String(featureGlobeId) === String(defaultGlobeId);
754			}
755			// REMOVED: else if (keepBaseDisabled) { shouldBeVisible = false; }
756			// This was causing lines to be hidden by default when keepBase was disabled
757
758			globe.setFeatureState(
759				{ source: 'lines', id: feature.id },
760				{
761					visible: shouldBeVisible,
762					hover: false
763				}
764			);
765
766		}
767	});
768}
769
770// Handle resize events to prevent rendering artifacts
771function setupResizeListener(globe) {
772	const handleResize = () => {
773		globe.resize();
774	};
775
776	// Use ResizeObserver to detect container size changes
777	const container = globe.getContainer();
778	const resizeObserver = new ResizeObserver(() => {
779		handleResize();
780	});
781
782	if (container) {
783		resizeObserver.observe(container);
784	}
785
786	window.addEventListener('resize', handleResize);
787
788	// Return cleanup function
789	return () => {
790		if (container) {
791			resizeObserver.unobserve(container);
792		}
793		resizeObserver.disconnect();
794		window.removeEventListener('resize', handleResize);
795	};
796}
797// Add methods to the globe object for programmatic control
798
799// Method to trigger click events programmatically
800function setupClickEvent(globe, globeData, element) {
801
802	// If element exists, call the imported setupClickEvent function
803	if (element) {
804		// Directly call the setupClickEvent function that's imported from click.js
805		setupClickEvent$1(globe, globeData, element);
806	}
807}
808// Method to trigger hover events programmatically
809function setupHoverEvent(globe, element, prevElement, type) {
810
811	// Handle hover event based on element type
812	if (!element) return;
813
814	const zoomLevel = element.zoomLevel || 4;
815	const animationDuration = 1500;
816	// Normalize type - use element.type if provided, or fallback to the passed type
817	const elementType = element.type || type || 'point';
818
819	// Check if it's a marker (points, objects, dotLabels, html)
820	if (elementType !== 'regions' && element._marker) {
821		// For markers, trigger mouseenter event on the marker element
822		const markerElement = element._marker.getElement();
823
824		// Remove hover from previous element if provided
825		if (prevElement && prevElement._marker) {
826			const prevMarkerElement = prevElement._marker.getElement();
827			const mouseLeaveEvent = new MouseEvent('mouseleave');
828			prevMarkerElement.dispatchEvent(mouseLeaveEvent);
829		}
830
831		// Trigger hover on current element
832		const mouseEnterEvent = new MouseEvent('mouseenter');
833		markerElement.dispatchEvent(mouseEnterEvent);
834
835		// Show popup with tooltip content if available
836		if (element.tooltipContent ||
837			(elementType === 'point' && (globe.meta.pointsTooltipTemplate || globe.meta.tooltipTemplate)) ||
838			(elementType === 'dotLabel' && (globe.meta.dotLabelsTooltipTemplate || globe.meta.tooltipTemplate))) {
839
840			const coordinates = element.coordinates ?
841				[element.coordinates.longitude, element.coordinates.latitude] :
842				[element.longitude || element.lng || 0, element.latitude || element.lat || 0];
843
844			// Process tooltip content using the same method as in the hover handler
845			let template = '';
846			switch(elementType) {
847				case 'point':
848				case 'marker':
849					template = globe.meta.pointsTooltipTemplate || globe.meta.tooltipTemplate;
850					break;
851				case 'dotLabel':
852					template = globe.meta.dotLabelsTooltipTemplate || globe.meta.tooltipTemplate;
853					break;
854				case 'htmlMarker':
855					template = globe.meta.htmlTooltipTemplate || globe.meta.tooltipTemplate;
856					break;
857				default:
858					template = globe.meta.tooltipTemplate;
859			}
860
861			let processedContent = element.tooltipContent || '';
862			if (template) {
863				processedContent = template;
864				// Replace all placeholders with their values
865				Object.keys(element).forEach(key => {
866					const placeholder = `{${key}}`;
867					const value = element[key] || '';
868					processedContent = processedContent.replace(new RegExp(placeholder, 'g'), value);
869				});
870			}
871
872			globe.popup.setLngLat(coordinates)
873				.setHTML(processedContent)
874				.addTo(globe);
875		}
876	}
877	// Check if it's a region
878	else if (elementType === 'regions' && globe.getSource('regions')) {
879		// Handle region - it could have an ID as array or string
880		const regionId = Array.isArray(element.id) ? element.id[0] : element.id;
881
882		if (!regionId) {
883			return;
884		}
885
886		// If not a known region, proceed with feature-based calculation
887		const regionFeatures = globe.querySourceFeatures('regions', {
888			filter: ['==', ['get', 'id'], regionId]
889		});
890
891		if (regionFeatures.length > 0) {
892			// Create a bounds object to encompass ALL parts of the region
893			const bounds = new maplibregl.LngLatBounds();
894			let hasValidCoords = false;
895
896			try {
897				// Process all features that match this region ID
898				regionFeatures.forEach(feature => {
899					if (feature.geometry.type === 'Polygon') {
900						// For polygons, process all rings (first is outer, rest are holes)
901						feature.geometry.coordinates.forEach((ring, ringIndex) => {
902							// Only process outer ring (index 0) for bounds
903							if (ringIndex === 0) {
904								ring.forEach(coord => {
905									if (Array.isArray(coord) && coord.length >= 2) {
906										bounds.extend(coord);
907										hasValidCoords = true;
908									}
909								});
910							}
911						});
912					}
913					else if (feature.geometry.type === 'MultiPolygon') {
914						// For multi-polygons, process each polygon's outer ring
915						feature.geometry.coordinates.forEach(polygon => {
916							if (Array.isArray(polygon) && polygon.length > 0) {
917								// Get the outer ring of this polygon (index 0)
918								const outerRing = polygon[0];
919								if (Array.isArray(outerRing)) {
920									outerRing.forEach(coord => {
921										if (Array.isArray(coord) && coord.length >= 2) {
922											bounds.extend(coord);
923											hasValidCoords = true;
924										}
925									});
926								}
927							}
928						});
929					}
930				});
931
932				if (hasValidCoords) {
933					// Fit the map to the bounds of the entire region
934					globe.fitBounds(bounds, {
935						padding: {top: 10, bottom: 10, left: 10, right: 10}, // More flexible padding
936						duration: animationDuration,
937						maxZoom: zoomLevel
938					});
939				} else {
940					throw new Error('No valid coordinates found in any region geometry');
941				}
942			} catch (error) {
943				// Silently handle error
944			}
945		}
946	}
947}
948
949// Add filter interaction logic for maplibre maps
950const setupMaplibreFilters = () => {
951	const filterContainers = document.querySelectorAll(
952		'.itt_globe_filter_menu_container[data-library="maplibre"] .itt_globe_filter_menu, .itt_globe_filter_menu_container[data-library="maplibre"] .itt_globe_toggle_menu'
953	);
954	document.querySelectorAll(
955		'.itt_globe_filter_menu_container[data-library="maplibre"] .itt_globe_filter_dropdown'
956	);
957
958	// Menu & toggle
959	if (filterContainers.length > 0) {
960		filterContainers.forEach((container) => {
961			const type = container.classList.contains('itt_globe_filter_menu')
962				? 'filter'
963				: 'toggle';
964			const containerId = container.getAttribute('data-globe-id');
965			const globe = ittGlobes.globesIndex[containerId];
966			const globeData = globe.meta;
967			const filterItems = container.querySelectorAll('.itt_globe_filter_item');
968
969			// Function to handle filter click
970			const handleFilterClick = function() {
971				const globeId = parseInt(this.getAttribute('data-globe-id'));
972				// Get the data from the globe's meta property
973				const globeData = globe.meta;
974
975				// Handle active class based on filter type
976				if (type === 'filter') {
977					// Remove active class from all items in the same container
978					filterItems.forEach(otherItem => {
979						otherItem.classList.remove('itt_globe_filter_item_active');
980					});
981					// Add active class to clicked item
982					this.classList.add('itt_globe_filter_item_active');
983				} else if (type === 'toggle') {
984					// Toggle the active class
985					this.classList.toggle('itt_globe_filter_item_active');
986				}
987
988				// Process base data
989				processEntries(globe, globeId, globeData, type, true);
990
991				// Process layer data
992				if (globeData.layers && Array.isArray(globeData.layers)) {
993					globeData.layers.forEach(layer => {
994						processEntries( globe, globeId, layer, type, false);
995					});
996				}
997			};
998
999			// Add click event listeners to filter items
1000			filterItems.forEach((item) => {
1001				item.addEventListener('click', handleFilterClick);
1002			});
1003
1004			// Check for default filter and trigger it if needed
1005			if (globeData.liveFilter?.enabled === '1' && globeData.liveFilter?.default) {
1006				const defaultGlobeId = globeData.liveFilter.default;
1007				const defaultFilterItem = Array.from(filterItems).find(item =>
1008					item.getAttribute('data-globe-id') === defaultGlobeId
1009				);
1010
1011				if (defaultFilterItem) {
1012					// Create and dispatch a click event
1013					const clickEvent = new MouseEvent('click', {
1014						bubbles: true,
1015						cancelable: true,
1016						view: window
1017					});
1018					defaultFilterItem.dispatchEvent(clickEvent);
1019				}
1020			}
1021		});
1022	}
1023};
1024
1025
1026
1027// Function to process entries from a data object
1028const processEntries = ( globe, globeId, data, type, isBaseData = false) => {
1029	if (!data) return;
1030	// Get all entries from the globe that match the globeId
1031	const matchingEntries = [];
1032	const keepBaseValue = data.liveFilter && data.liveFilter.keepBase ? data.liveFilter.keepBase : '0';
1033
1034	/**
1035	 * Determines if an entry should be visible based on various conditions:
1036	 * 1. Base map entries with matching keepBase ID
1037	 * 2. Base map filter selection (globeId matches base map ID)
1038	 * 3. Filter/toggle type and active state
1039	 *
1040	 * @param {Object} entry - The entry to check visibility for
1041	 * @returns {boolean} - Whether the entry should be visible
1042	 */
1043	const shouldBeVisible = (entry) => {
1044
1045		// If this is the base map filter (globeId matches base map ID), show all entries
1046		if (globeId === parseInt(data.id)) {
1047			return true;
1048		}
1049
1050		if ( globe.meta.id === globeId ) {
1051			return true;
1052		}
1053
1054		// If keepBase is set and this is a base map region, keep it visible
1055		if (keepBaseValue === '1' && entry.globe_id === parseInt(data.id)) {
1056			return true;
1057		}
1058
1059		// For filter type, show only matching entries
1060		if (type === 'filter') {
1061			const isVisible = entry.globe_id === globeId;
1062			return isVisible;
1063		}
1064		// For toggle type, show based on active state
1065		// simplified this, but maybe its too simplistic
1066		return entry.globe_id === globeId;
1067	};
1068
1069	// Check points
1070	if (data.points) {
1071		const matchingPoints = data.points.filter(point => point.globe_id === globeId);
1072		matchingEntries.push(...matchingPoints);
1073		// Show/hide markers
1074		data.points.forEach(point => {
1075			if (point._marker) {
1076				point._marker.getElement().style.display = shouldBeVisible(point) ? 'block' : 'none';
1077			}
1078		});
1079	}
1080
1081	// Check objects
1082	if (data.objects) {
1083		const matchingObjects = data.objects.filter(object => object.globe_id === globeId);
1084		matchingEntries.push(...matchingObjects);
1085		// Show/hide markers
1086		data.objects.forEach(object => {
1087			if (object._marker) {
1088				object._marker.getElement().style.display = shouldBeVisible(object) ? 'block' : 'none';
1089			}
1090		});
1091	}
1092
1093	// Check dotLabels
1094	if (data.dotLabels) {
1095		const matchingDotLabels = data.dotLabels.filter(label => label.globe_id === globeId);
1096		matchingEntries.push(...matchingDotLabels);
1097		// Show/hide markers
1098		data.dotLabels.forEach(label => {
1099			if (label._marker) {
1100				label._marker.getElement().style.display = shouldBeVisible(label) ? 'block' : 'none';
1101			}
1102		});
1103	}
1104
1105	// Check html markers
1106	if (data.html) {
1107		const matchingHtml = data.html.filter(html => html.globe_id === globeId);
1108		matchingEntries.push(...matchingHtml);
1109		// Show/hide markers
1110		data.html.forEach(html => {
1111			if (html._marker) {
1112				html._marker.getElement().style.display = shouldBeVisible(html) ? 'block' : 'none';
1113			}
1114		});
1115	}
1116
1117	// Check regions
1118	if (data.regions) {
1119		const matchingRegions = data.regions.filter(region => region.globe_id === globeId);
1120		matchingEntries.push(...matchingRegions);
1121
1122		// Show/hide regions using feature state for all region sources
1123		const regionSources = globe.getStyle().sources;
1124		Object.keys(regionSources).forEach(sourceId => {
1125			if (sourceId.startsWith('regions')) {
1126				const features = globe.querySourceFeatures(sourceId);
1127				features.forEach(feature => {
1128					if (feature.id !== undefined) {
1129						const isActive = shouldBeVisible(feature.properties);
1130
1131						try {
1132							globe.setFeatureState(
1133								{ source: sourceId, id: feature.id },
1134								{
1135									visible: isActive,
1136									hover: false
1137								}
1138							);
1139
1140						} catch (error) {
1141							console.error('Error setting feature state:', error);
1142						}
1143					}
1144				});
1145			}
1146		});
1147	}
1148
1149	// Check arcLines
1150	if (data.arcLines) {
1151
1152		const matchingArcLines = data.arcLines.filter(line => line.globe_id === globeId);
1153		matchingEntries.push(...matchingArcLines);
1154
1155		// Show/hide lines using feature state
1156		if (globe.getSource('lines')) {
1157			const features = globe.querySourceFeatures('lines');
1158
1159
1160			features.forEach(feature => {
1161				if (feature.id !== undefined) {
1162					const isActive = shouldBeVisible(feature.properties);
1163
1164
1165					try {
1166						globe.setFeatureState(
1167							{ source: 'lines', id: feature.id },
1168							{
1169								visible: isActive,
1170								hover: false
1171							}
1172						);
1173
1174					} catch (error) {
1175						console.error('Error setting line feature state:', error);
1176					}
1177				}
1178			});
1179		}
1180	}
1181
1182	return matchingEntries;
1183};
1184
1185// Helper function to get coordinates from an object, [ longitude, latitude ]
1186const getCoordinates = (obj) => {
1187	// Try different possible coordinate property names
1188	if (obj.coordinates?.longitude !== undefined && obj.coordinates?.latitude !== undefined) {
1189		return [obj.coordinates.longitude, obj.coordinates.latitude];
1190	}
1191	if (obj.coordinates?.long !== undefined && obj.coordinates?.lat !== undefined) {
1192		return [obj.coordinates.long, obj.coordinates.lat];
1193	}
1194	if (obj.longitude !== undefined && obj.latitude !== undefined) {
1195		return [obj.longitude, obj.latitude];
1196	}
1197	if (obj.long !== undefined && obj.lat !== undefined) {
1198		return [obj.long, obj.lat];
1199	}
1200	if (obj.lng !== undefined && obj.lat !== undefined) {
1201		return [obj.lng, obj.lat];
1202	}
1203	console.warn('Could not find valid coordinates in object:', obj);
1204	return [0, 0]; // Fallback to [0,0] if no valid coordinates found
1205};
1206
1207const isAdmin = typeof ittGlobeData !== 'undefined' && ittGlobeData.isAdmin === true;
1208
1209// Function to check if a specific select element already has an option with a specific value
1210const hasOption = function(selectElement, valueToCheck) {
1211	// Get all options of the select element
1212	const options = selectElement.options;
1213	if ( options === undefined ){
1214		return false;
1215	}
1216
1217	// Loop through all options
1218	for (let i = 0; i < options.length; i++) {
1219		// Check if the value of the current option matches the value we are checking for
1220		if (options[i].value === valueToCheck) {
1221			// If a match is found, return true
1222			return true;
1223		}
1224	}
1225
1226	// If no match is found, return false
1227	return false;
1228};
1229
1230
1231
1232/**
1233 * Truncate to 3 decimal places
1234 */
1235const truncateTo3Decimals = function(number) {
1236	const truncated = Math.trunc(number * 1000) / 1000;
1237	return truncated.toFixed(3);
1238};
1239
1240
1241
1242const getGeojsonUrlVal = function(){
1243	let geojsonUrlSelect = document.getElementsByName( 'globe_info[regionCustomSourceURL]' );
1244
1245	if ( typeof geojsonUrlSelect === 'undefined' || geojsonUrlSelect.length == 0 ) {
1246		return;
1247	}
1248
1249	geojsonUrlSelect = geojsonUrlSelect[0];
1250	if ( typeof geojsonUrlSelect === 'undefined' ) {
1251		return;
1252	}
1253
1254	return geojsonUrlSelect.value;
1255};
1256
1257const getGeojsonVal = function(){
1258	let geojsonSelect = document.getElementsByName( 'globe_info[regionSource]' );
1259	if ( typeof geojsonSelect === 'undefined' || geojsonSelect.length == 0 ) {
1260		return;
1261	}
1262
1263	geojsonSelect = geojsonSelect[0];
1264	if ( typeof geojsonSelect === 'undefined' ) {
1265		return;
1266	}
1267
1268	return geojsonSelect.value;
1269};
1270
1271
1272
1273const updatePreviewUI = ( dataset, element ) => {
1274
1275	// prevent unnecessary DOM queries and logic from running when the preview UI is not present.
1276	const previewContainer = document.querySelector('#itt_globe_preview_data_clicked');
1277	if ( ! previewContainer ) {
1278		return;
1279	}
1280	// ripple click
1281	// TODO ripple click
1282	let addNewButton = previewContainer.querySelector('.itt_globe_preview_action_add_new');
1283
1284	// if is inactive , show add new button
1285	if( dataset.isActive === false ){
1286		if ( ! addNewButton) {
1287			return;
1288		}
1289		// remove any previous dataset keys used by this feature
1290		Object.keys( dataset ).forEach(key => {
1291			delete addNewButton.dataset[key];
1292		});
1293
1294		// set previous
1295		addNewButton.dataset.prevlatitude  = addNewButton.dataset.latitude;
1296		addNewButton.dataset.prevlongitude = addNewButton.dataset.longitude;
1297
1298		// add to the dropdown
1299		if( ! hasOption( addNewButton, element.post_type ) ){
1300			let newOption = new Option( element.type, element.post_type );
1301			addNewButton.add( newOption, undefined );
1302		}
1303		let editButton = previewContainer.querySelector('.itt_globe_preview_action_edit');
1304		if ( editButton ) {
1305			editButton.style.display = "none";
1306		}
1307
1308		// set dataset values to carry on to add new url
1309
1310		// set new coordinates
1311		addNewButton.dataset.latitude  = truncateTo3Decimals( element.coordinates.latitude );
1312		addNewButton.dataset.longitude = truncateTo3Decimals( element.coordinates.longitude );
1313
1314
1315		// set new values (ensure strings)
1316		Object.entries( dataset ).forEach(([key, val]) => {
1317			addNewButton.dataset[key] = (val === null || typeof val === 'undefined') ? '' : String(val);
1318		});
1319
1320		addNewButton.style.display = "inline-block";
1321		let title = previewContainer.querySelector('.itt_globe_preview_title');
1322		if ( title ) {
1323			title.textContent = 'Clicked ' + element.text + ' : ' + element.title;
1324		}
1325	}
1326	if( dataset.isActive === true ){
1327		// edit stuff
1328		if ( (
1329				element.post_type === 'itt_globe_point' ||
1330				element.post_type === 'itt_globe_dotlabel' ||
1331				element.post_type === 'itt_globe_region' ||
1332				element.post_type === 'itt_globe_html'
1333			) ||
1334			typeof element.post_id !== 'undefined' ){
1335
1336			if ( addNewButton ) {
1337				addNewButton.style.display = "none";
1338			}
1339			// show edit button
1340			let editButton = previewContainer.querySelector('.itt_globe_preview_action_edit');
1341			if ( editButton ) {
1342				editButton.dataset.id = element.post_id ? element.post_id : element.id;
1343				editButton.dataset.post_type = element.post_type;
1344				editButton.style.display = "inline-block";
1345			}
1346		}
1347
1348		let title = previewContainer.querySelector('.itt_globe_preview_title');
1349		if ( title ) {
1350			title.textContent = 'Clicked ' + element.text + ' : ' + element.title;
1351		}
1352	}
1353
1354	// common update info
1355	let clicked = previewContainer.querySelector('.inside .itt_globe_preview_data');
1356	if ( ! clicked ) {
1357		return;
1358	}
1359	let clickedTemplate =
1360		'<div class="coordinate-block lat-block">' +
1361			'<div class="coordinate-label info--unselectable ">Lat: </div>' +
1362			'<div class="coordinate-value">' + truncateTo3Decimals(element.coordinates.latitude) + '</div>' +
1363		'</div>' +
1364		'<div class="coordinate-block lng-block">' +
1365			'<div class="coordinate-label info--unselectable">Lng: </div>' +
1366			'<div class="coordinate-value">' + truncateTo3Decimals(element.coordinates.longitude) + '</div>' +
1367		'</div>';
1368	clicked.innerHTML   = clickedTemplate;
1369};
1370
1371// Function to process tooltip template
1372	const processTooltipTemplate = (template, properties = {}) => {
1373		// If no template, return tooltipContent or empty string
1374		if (!template) return properties.tooltipContent || '';
1375
1376		let processedContent = template;
1377
1378		// Replace all placeholders with their values
1379		Object.keys(properties).forEach(key => {
1380			const placeholder = `{${key}}`;
1381			const value = properties[key] || '';
1382			processedContent = processedContent.replace(new RegExp(placeholder, 'g'), value);
1383		});
1384
1385		return processedContent;
1386	};
1387
1388	// Function to get the appropriate template
1389	const getTooltipTemplate = (type, properties = {}, data ) => {
1390		// Check for specific template first
1391		let template = '';
1392		switch(type) {
1393			case 'point':
1394				template = data.pointsTooltipTemplate || data.tooltipTemplate;
1395				break;
1396			case 'region':
1397				template = data.regionsTooltipTemplate || data.tooltipTemplate;
1398				break;
1399			case 'dotLabel':
1400				template = data.dotLabelsTooltipTemplate || data.tooltipTemplate;
1401				break;
1402			default:
1403				template = data.tooltipTemplate;
1404		}
1405
1406		// If we have a template, process it regardless of tooltipContent
1407		if (template) {
1408			return processTooltipTemplate(template, properties);
1409		}
1410
1411		// If no template, return tooltipContent or empty string
1412		return properties.tooltipContent || '';
1413	};
1414
1415
1416	// Function to apply tooltip styles
1417	const applyTooltipStyles = (popupElement, globeId, data ) => {
1418		if (!data.tooltip) return;
1419
1420		const tooltipSettings = data.tooltip;
1421		const className = `itt-tooltip-${globeId}`;
1422
1423		// Create style element if it doesn't exist
1424		let styleElement = document.getElementById(`itt-tooltip-styles-${globeId}`);
1425		if (!styleElement) {
1426			styleElement = document.createElement('style');
1427			styleElement.globeId = `itt-tooltip-styles-${globeId}`;
1428			document.head.appendChild(styleElement);
1429		}
1430
1431		// Generate CSS
1432		const css = `
1433			.maplibregl-popup.${className} {
1434				background: none;
1435				padding: 0;
1436				box-shadow: none;
1437				border: none;
1438				pointer-events: none;
1439			}
1440
1441			.maplibregl-popup.${className} .maplibregl-popup-content {
1442				pointer-events: none;
1443				min-width: 40px;
1444				background-color: ${tooltipSettings.backgroundColor};
1445				font-family: ${tooltipSettings.fontFamily};
1446				font-weight: ${tooltipSettings.font['font-weight']};
1447				font-style: ${tooltipSettings.font['font-style']};
1448				text-align: ${tooltipSettings.font['text-align']};
1449				font-size: ${tooltipSettings.font['font-size']}${tooltipSettings.font.unit};
1450				color: ${tooltipSettings.font.color};
1451				border-radius: ${tooltipSettings.cornerRadius}px;
1452				border: ${tooltipSettings.border.all}px ${tooltipSettings.border.style} ${tooltipSettings.border.color};
1453				padding: ${tooltipSettings.padding.top}${tooltipSettings.padding.unit} ${tooltipSettings.padding.right}${tooltipSettings.padding.unit} ${tooltipSettings.padding.bottom}${tooltipSettings.padding.unit} ${tooltipSettings.padding.left}${tooltipSettings.padding.unit};
1454				max-width: ${tooltipSettings.maxWidth}px;
1455				margin: 0;
1456				position: relative;
1457			}
1458
1459
1460
1461			.maplibregl-popup.${className} .maplibregl-popup-tip {
1462				display: none;
1463			}
1464		`;
1465
1466		// Update styles
1467		styleElement.textContent = css;
1468
1469		// Apply class to popup
1470		popupElement.classList.add(className);
1471	};
1472
1473
1474const addTooltipStylesToPopup = function( globe, globeId, data ) {
1475
1476	// Apply styles when popup is added to the map
1477	globe.popup.on('open', () => {
1478		const popupElement = globe.popup.getElement();
1479		applyTooltipStyles(popupElement, globeId, data );
1480	});
1481};
1482
1483// Function to calculate optimal anchor position for tooltip
1484const calculateOptimalAnchor = ( globe, coordinates, markerElement) => {
1485	// Get the marker's position in the viewport
1486	const markerRect = markerElement.getBoundingClientRect();
1487	const mapRect = globe.getContainer().getBoundingClientRect();
1488
1489	// Calculate distances to viewport edges
1490	const distanceToTop = markerRect.top - mapRect.top;
1491	mapRect.bottom - markerRect.bottom;
1492	const distanceToLeft = markerRect.left - mapRect.left;
1493	const distanceToRight = mapRect.right - markerRect.right;
1494
1495	// Determine vertical anchor
1496	let verticalAnchor = 'bottom';
1497	if (distanceToTop < 100) { // If less than 100px from top
1498		verticalAnchor = 'top';
1499	}
1500
1501	// Determine horizontal anchor
1502	let horizontalAnchor = 'center';
1503	if (distanceToLeft < 100) { // If less than 100px from left
1504		horizontalAnchor = 'left';
1505	} else if (distanceToRight < 100) { // If less than 100px from right
1506		horizontalAnchor = 'right';
1507	}
1508
1509	return `${verticalAnchor}-${horizontalAnchor}`;
1510};
1511
1512// Helper function to get point property with fallback to defaults
1513const getPointProperty = ( point, propertyName, data ) => {
1514	// Special case for type property
1515	if (propertyName === 'type') {
1516		return point.type;
1517	}
1518
1519	// If point has custom settings enabled, return the point's property
1520	if (globe_ut_bool(point.useCustom)) {
1521		return point[propertyName];
1522	}
1523
1524	// If point has a layer ID, use that layer's defaults
1525	if (point._layerId && data.layers) {
1526		const layer = data.layers.find(l => l.id === point._layerId || l.id === `layer_${point._layerId}`);
1527		if (layer) {
1528			// Get the appropriate defaults based on point type
1529			let layerDefaults;
1530			switch (point.type) {
1531				case 'dotLabel':
1532					layerDefaults = layer.labelDefaults;
1533					break;
1534				case 'htmlMarker':
1535					layerDefaults = layer.htmlDefaults;
1536					break;
1537				case 'objects':
1538					layerDefaults = layer.pointDefaults;
1539					break;
1540				default:
1541					layerDefaults = layer.pointDefaults;
1542			}
1543			if (layerDefaults && layerDefaults[propertyName] !== undefined) {
1544				return layerDefaults[propertyName];
1545			}
1546		}
1547	}
1548
1549	// Fallback to base map defaults
1550	let defaults;
1551	switch (point.type) {
1552		case 'dotLabel':
1553			defaults = data.labelDefaults;
1554			break;
1555		case 'htmlMarker':
1556			defaults = data.htmlDefaults;
1557			break;
1558		case 'objects':
1559			defaults = data.pointDefaults;
1560			break;
1561		default:
1562			defaults = data.pointDefaults;
1563	}
1564
1565	return defaults[propertyName];
1566};
1567const addMarkers = function( globe, data ) {
1568	// Process base data first (without layer ID)
1569	if (data.points && data.points.length > 0) {
1570		data.points.forEach(point => {
1571			const coordinates = getCoordinates(point);
1572			const marker = createMarker$1(point, data )
1573				.setLngLat(coordinates)
1574				.addTo(globe);
1575
1576			// Store marker reference
1577			point._marker = marker;
1578
1579			// Add click event listener
1580			marker.getElement().addEventListener('click', () => {
1581				setupClickEvent$1(globe, data, point);
1582
1583				// update ui
1584				point.post_type = 'itt_globe_point';
1585				if ( isAdmin ) {
1586					updateUIforMarker( point, coordinates );
1587				}
1588			});
1589
1590			// Check for either tooltipContent or template
1591			if (point.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) {
1592				handleMarkerHover(
1593					globe,
1594					data,
1595					marker,
1596					point.tooltipContent,
1597					coordinates,
1598					'point',
1599					point
1600				);
1601			}
1602
1603		});
1604	}
1605
1606	// Add markers from objects array
1607	if (data.objects && data.objects.length > 0) {
1608		data.objects.forEach(object => {
1609			const coordinates = getCoordinates(object);
1610			const marker = createMarker$1(object, data )
1611				.setLngLat(coordinates)
1612				.addTo(globe);
1613
1614			// Store marker reference
1615			object._marker = marker;
1616
1617			// Add click event listener
1618			marker.getElement().addEventListener('click', () => {
1619				setupClickEvent$1(globe, data, object);
1620
1621				object.post_type = 'itt_globe_point';
1622				if ( isAdmin ) {
1623					updateUIforMarker( object, coordinates );
1624				}
1625			});
1626
1627			// Check for either tooltipContent or template
1628			if (object.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) {
1629				handleMarkerHover(
1630					globe,
1631					data,
1632					marker,
1633					object.tooltipContent,
1634					coordinates,
1635					'point',
1636					object
1637				);
1638			}
1639		});
1640	}
1641
1642	// Add dot labels from dotLabels array
1643	if (data.dotLabels && data.dotLabels.length > 0) {
1644		data.dotLabels.forEach(dotlabel => {
1645			dotlabel.type = 'dotLabel';
1646			const coordinates = getCoordinates(dotlabel);
1647			const marker = createMarker$1(dotlabel, data )
1648				.setLngLat(coordinates)
1649				.addTo(globe);
1650
1651			// Store marker reference
1652			dotlabel._marker = marker;
1653
1654			// Add click event listener
1655			marker.getElement().addEventListener('click', () => {
1656
1657				setupClickEvent$1(globe, data, dotlabel);
1658
1659				dotlabel.post_type = 'itt_globe_dotlabel';
1660				if ( isAdmin ) {
1661					updateUIforMarker( dotlabel, coordinates );
1662				}
1663			});
1664
1665			// Check for either tooltipContent or template
1666			if (dotlabel.tooltipContent || data.dotLabelsTooltipTemplate || data.tooltipTemplate) {
1667				handleMarkerHover(
1668					globe,
1669					data,
1670					marker,
1671					dotlabel.tooltipContent,
1672					coordinates,
1673					'dotLabel',
1674					dotlabel
1675				);
1676			}
1677		});
1678	}
1679
1680	// add html labels from htmlLabels array
1681	if (data.html && data.html.length > 0) {
1682		data.html.forEach(htmlMarker => {
1683			htmlMarker.type = 'htmlMarker';
1684			const coordinates = getCoordinates(htmlMarker);
1685			const marker = createMarker$1(htmlMarker, data )
1686				.setLngLat(coordinates)
1687				.addTo(globe);
1688
1689			// Store marker reference
1690			htmlMarker._marker = marker;
1691
1692			// Add click event listener
1693			marker.getElement().addEventListener('click', () => {
1694				setupClickEvent$1(globe, data, htmlMarker);
1695
1696				htmlMarker.post_type = 'itt_globe_html';
1697				if ( isAdmin ) {
1698					updateUIforMarker( htmlMarker, coordinates );
1699				}
1700			});
1701
1702			// Check for either tooltipContent or template
1703			if (htmlMarker.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) {
1704				handleMarkerHover(
1705					globe,
1706					data,
1707					marker,
1708					htmlMarker.tooltipContent,
1709					coordinates,
1710					'point',
1711					htmlMarker
1712				);
1713			}
1714		});
1715	}
1716
1717};
1718// Helper function to handle marker hover
1719const handleMarkerHover = ( globe, data, marker, content, coordinates, type, originalProperties) => {
1720	const element = marker.getElement();
1721
1722	// Show popup on hover
1723	element.addEventListener('mouseenter', (e) => {
1724		e.stopPropagation();
1725
1726		// Close any existing popup
1727		if (globe.popup.isOpen()) {
1728			globe.popup.remove();
1729		}
1730
1731		// Check if marker is effectively hidden
1732		const opacity = window.getComputedStyle(element).opacity;
1733		if (parseFloat(opacity) === 0) {
1734			return; // Skip showing tooltip
1735		}
1736
1737		// Calculate optimal anchor position
1738		const anchor = calculateOptimalAnchor( globe, coordinates, element);
1739
1740		// Calculate offset based on anchor position
1741		let offset = [0, 0];
1742		if (anchor.startsWith('top')) {
1743			offset[1] = 10; // Offset below marker
1744		} else {
1745			offset[1] = -10; // Offset above marker
1746		}
1747
1748		// Adjust horizontal offset based on anchor
1749		if (anchor.endsWith('left')) {
1750			offset[0] = 10;
1751		} else if (anchor.endsWith('right')) {
1752			offset[0] = -10;
1753		}
1754
1755		// Show new popup with calculated offset
1756		const processedContent = getTooltipTemplate(type, originalProperties, data );
1757		globe.popup.setLngLat(coordinates)
1758			.setOffset(offset)
1759			.setHTML(processedContent)
1760			.addTo(globe);
1761	});
1762
1763	element.addEventListener('mouseleave', () => {
1764		globe.popup.remove();
1765	});
1766
1767	// Hide popup when mouse leaves the map
1768	globe.getCanvas().addEventListener('mouseleave', () => {
1769		globe.popup.remove();
1770	});
1771};
1772
1773
1774// Add markers from points and objects arrays
1775const createMarker$1 = ( point, data ) => {
1776	let markerElement;
1777	const type = getPointProperty(point, 'type', data );
1778	const color = getPointProperty(point, 'color', data);
1779	const hover = getPointProperty(point, 'hover', data);
1780	const radius = getPointProperty(point, 'radius', data);
1781	const image = getPointProperty(point, 'image', data);
1782
1783	switch(type) {
1784		case 'htmlMarker':
1785			let template = getPointProperty(point,'htmlTemplate', data );
1786
1787			// now replace all {placeholders} with the point properties
1788			Object.keys(point).forEach(key => {
1789				template = template.replace(`{${key}}`, point[key]);
1790			});
1791
1792			markerElement = document.createElement('div');
1793			markerElement.className = 'custom-marker html-marker';
1794			markerElement.innerHTML = template || '';
1795			markerElement.style.color = color;
1796			markerElement.style.fontSize = point.size + 'px';
1797			markerElement.style.transition = 'color 0.3s ease';
1798
1799			markerElement.addEventListener('mouseenter', () => {
1800				markerElement.style.color = hover;
1801			});
1802			markerElement.addEventListener('mouseleave', () => {
1803				markerElement.style.color = color;
1804			});
1805			break;
1806
1807		case 'cylinder':
1808			markerElement = document.createElement('div');
1809			markerElement.className = 'custom-marker cylinder-marker';
1810			markerElement.style.width = radius + 'px';
1811			markerElement.style.height = radius + 'px';
1812			markerElement.style.backgroundColor = color;
1813			markerElement.style.border = '1px solid #e0e0e0';
1814			markerElement.style.borderRadius = '50%';
1815			markerElement.style.transition = 'background-color 0.3s ease';
1816
1817			markerElement.addEventListener('mouseenter', () => {
1818				markerElement.style.backgroundColor = hover;
1819			});
1820			markerElement.addEventListener('mouseleave', () => {
1821				markerElement.style.backgroundColor = color;
1822			});
1823			break;
1824
1825		case 'pin':
1826			markerElement = document.createElement('div');
1827			markerElement.className = 'custom-marker pin-marker';
1828			markerElement.style.filter = 'drop-shadow(0 2px 4px rgba(0,0,0,0.2))';
1829
1830			const pinHead = document.createElement('div');
1831			pinHead.className = 'pin-head';
1832			pinHead.style.width = radius + 'px';
1833			pinHead.style.height = radius + 'px';
1834			pinHead.style.backgroundColor = color;
1835			pinHead.style.borderRadius = '50%';
1836			pinHead.style.boxShadow = 'inset -2px -2px 4px rgba(0,0,0,0.2)';
1837
1838			const pinLine = document.createElement('div');
1839			pinLine.className = 'pin-line';
1840			pinLine.style.width = '6px'; // Wider at the bottom
1841			pinLine.style.height = (radius * 0.5 + (point.altitude * 2)) + 'px';
1842			pinLine.style.background = `linear-gradient(to right, ${color} 0%, ${color} 50%, transparent 100%)`;
1843			pinLine.style.marginLeft = 'auto';
1844			pinLine.style.marginRight = 'auto';
1845			pinLine.style.clipPath = 'polygon(0 0, 100% 0, 50% 100%)';
1846			pinLine.style.transformOrigin = 'top center';
1847			pinLine.style.transform = 'scaleY(1)';
1848			pinLine.style.boxShadow = '0 1px 2px rgba(0,0,0,0.1)';
1849
1850			markerElement.appendChild(pinHead);
1851			markerElement.appendChild(pinLine);
1852
1853			// Add hover color change and tooltip to the entire marker
1854			markerElement.addEventListener('mouseenter', () => {
1855				pinHead.style.backgroundColor = hover;
1856				pinLine.style.background = `linear-gradient(to right, ${hover} 0%, ${hover} 50%, transparent 100%)`;
1857			});
1858			markerElement.addEventListener('mouseleave', () => {
1859				pinHead.style.backgroundColor = color;
1860				pinLine.style.background = `linear-gradient(to right, ${color} 0%, ${color} 50%, transparent 100%)`;
1861			});
1862
1863			// Return the marker with the element
1864			return new maplibregl.Marker({
1865				element: markerElement,
1866				opacityWhenCovered: 0,
1867				anchor: 'bottom'
1868			});
1869
1870		case 'dotLabel':
1871			markerElement = document.createElement('div');
1872			markerElement.className = 'custom-marker dot-label-marker';
1873
1874			const label = document.createElement('div');
1875			label.className = 'dot-label-text';
1876			label.textContent = point.title;
1877			label.style.color = color;
1878			label.style.fontSize = point.size + 'px';
1879			label.style.textAlign = 'center';
1880
1881			if (globe_ut_bool(point.includeDot)) {
1882				const dot = document.createElement('div');
1883				dot.className = 'dot-label-dot';
1884				dot.style.width = radius + 'px';
1885				dot.style.height = radius + 'px';
1886				dot.style.backgroundColor = color;
1887				dot.style.borderRadius = '50%';
1888
1889				// Handle dot orientation (which is actually the label side)
1890				const orientation = point.dotOrientation || 'above';
1891				const orientationString = Array.isArray(orientation) ? orientation[0] : orientation;
1892
1893				switch(orientationString.toLowerCase()) {
1894					case 'bottom':
1895						dot.style.margin = '0 auto 5px auto';
1896						markerElement.appendChild(dot);
1897						markerElement.appendChild(label);
1898						break;
1899					case 'top':
1900						dot.style.margin = '5px auto 0 auto';
1901						markerElement.appendChild(label);
1902						markerElement.appendChild(dot);
1903						break;
1904					case 'right':
1905						markerElement.style.display = 'flex';
1906						markerElement.style.alignItems = 'center';
1907						markerElement.style.flexDirection = 'row';
1908						dot.style.margin = '0 5px 0 0';
1909						markerElement.appendChild(dot);
1910						markerElement.appendChild(label);
1911						break;
1912					default: // default to above
1913						dot.style.margin = '0 auto 5px auto';
1914						markerElement.appendChild(dot);
1915						markerElement.appendChild(label);
1916				}
1917			} else {
1918				markerElement.appendChild(label);
1919			}
1920
1921			markerElement.addEventListener('mouseenter', () => {
1922				if (globe_ut_bool(point.includeDot)) {
1923					markerElement.querySelector('.dot-label-dot').style.backgroundColor = hover;
1924				}
1925				label.style.color = hover;
1926			});
1927
1928			markerElement.addEventListener('mouseleave', () => {
1929				if (globe_ut_bool(point.includeDot)) {
1930					markerElement.querySelector('.dot-label-dot').style.backgroundColor = color;
1931				}
1932				label.style.color = color;
1933			});
1934			break;
1935
1936		case 'image':
1937			if (image?.url) {
1938				markerElement = document.createElement('div');
1939				markerElement.className = 'custom-marker image-marker';
1940				const img = document.createElement('img');
1941				img.src = image.url;
1942				img.style.width = radius + 'px';
1943				img.style.height = 'auto';
1944				markerElement.appendChild(img);
1945			}
1946			break;
1947
1948		case 'flag':
1949			markerElement = document.createElement('div');
1950			markerElement.className = 'custom-marker flag-marker';
1951
1952			// Create flag pole
1953			const flagPole = document.createElement('div');
1954			flagPole.className = 'flag-pole';
1955			flagPole.style.width = '2px';
1956			// Calculate pole height based on altitude, with a minimum height
1957			const baseHeight = radius * 0.5;
1958			const altitude = point.altitude || 0;
1959			const scaledHeight = baseHeight + (altitude * 2); // Scale factor of 2 for better visibility
1960			flagPole.style.height = Math.max(baseHeight, scaledHeight) + 'px';
1961			flagPole.style.backgroundColor = '#666';
1962			flagPole.style.position = 'absolute';
1963			flagPole.style.left = '0';
1964			flagPole.style.bottom = '0';
1965			flagPole.style.zIndex = '1';
1966
1967			// Create flag container
1968			const flagContainer = document.createElement('div');
1969			flagContainer.className = 'flag-container';
1970			flagContainer.style.width = (radius * 1.5) + 'px';
1971			flagContainer.style.height = radius + 'px';
1972			flagContainer.style.position = 'absolute';
1973			flagContainer.style.left = '2px';
1974			flagContainer.style.bottom = (Math.max(baseHeight, scaledHeight) - radius) + 'px'; // Align with top of pole
1975			flagContainer.style.overflow = 'hidden';
1976			flagContainer.style.zIndex = '2';
1977
1978			if (image?.url) {
1979				// If image is provided, use it as the flag
1980				const flagImage = document.createElement('img');
1981				flagImage.src = image.url;
1982				flagImage.style.width = '100%';
1983				flagImage.style.height = '100%';
1984				flagImage.style.objectFit = 'cover';
1985				flagContainer.appendChild(flagImage);
1986			} else {
1987				// If no image, use a colored rectangle
1988				const flagColor = document.createElement('div');
1989				flagColor.style.width = '100%';
1990				flagColor.style.height = '100%';
1991				flagColor.style.backgroundColor = color;
1992				flagContainer.appendChild(flagColor);
1993			}
1994
1995			markerElement.appendChild(flagPole);
1996			markerElement.appendChild(flagContainer);
1997
1998			return new maplibregl.Marker({
1999				element: markerElement,
2000				anchor: 'bottom',
2001				offset: [-2, 0], // Offset to align with pole base
2002				rotationAlignment: 'map',
2003				pitchAlignment: 'map',
2004				opacityWhenCovered: 0,
2005			});
2006
2007		case 'marker':
2008		default:
2009			// Use default MapLibre marker with custom color
2010			const defaultMarker = new maplibregl.Marker({
2011				color: color,
2012				scale: radius / 30,
2013				rotationAlignment: 'map',
2014				pitchAlignment: 'map',
2015				opacityWhenCovered: 0,
2016			});
2017
2018			// Add hover color change
2019			const defaultMarkerElement = defaultMarker.getElement();
2020			defaultMarkerElement.addEventListener('mouseenter', () => {
2021				defaultMarkerElement.querySelector('path').style.fill = hover;
2022			});
2023			defaultMarkerElement.addEventListener('mouseleave', () => {
2024				defaultMarkerElement.querySelector('path').style.fill = color;
2025			});
2026
2027			return defaultMarker;
2028	}
2029
2030	// Return custom marker if element was created
2031	if (markerElement) {
2032		return new maplibregl.Marker({
2033			element: markerElement,
2034			anchor: type === 'pin' ? 'center' : 'center',
2035			rotationAlignment: 'map',
2036			pitchAlignment: 'map',
2037			opacityWhenCovered: 0,
2038		});
2039	}
2040
2041	// Fallback to default marker
2042	return new maplibregl.Marker({
2043		color: color,
2044		scale: radius / 30,
2045		rotationAlignment: 'map',
2046		pitchAlignment: 'map',
2047		opacityWhenCovered: 0,
2048	});
2049};
2050
2051
2052
2053const updateUIforMarker = ( marker, coordinates ) => {
2054	coordinates.latitude  = truncateTo3Decimals( coordinates[1] );
2055	coordinates.longitude = truncateTo3Decimals( coordinates[0] );
2056
2057	marker.coordinates = coordinates;
2058
2059
2060	// if clicked empty region, set title
2061	if( typeof marker.title === 'undefined' ){
2062		marker.title = marker.name || marker.id;
2063	}
2064
2065	let preview = {};
2066	preview.clickedDataset = {
2067		marker_id : marker.id || marker.id,
2068		title : marker.name,
2069		isActive: true
2070	};
2071
2072	preview.clickedElement = Object.assign({}, marker );
2073	preview.clickedElement.text = 'Marker';
2074	preview.clickedElement.type = 'Marker';
2075	preview.clickedElement.post_type = marker.post_type;
2076
2077
2078	updatePreviewUI( preview.clickedDataset, preview.clickedElement );
2079};
2080
2081// Add filter interaction logic for maplibre maps
2082const setupMaplibreLayers = (globe, data ) => {
2083	data.layers.forEach((layer, index) => {
2084		// Use layer.id if available, otherwise generate one
2085		const layerId = layer.id || `layer_${index}`;
2086
2087		processLayer( globe, data, layer, layerId);
2088	});
2089};
2090
2091
2092// Function to process a single layer's data
2093
2094// todo add extra param to calls
2095const processLayer = (globe, data, layerData, layerId) => {
2096	// Process points
2097	if (layerData.points && layerData.points.length > 0) {
2098		layerData.points.forEach((point, index) => {
2099			// Add layer ID to the point
2100			point._layerId = layerId;
2101
2102			// Inherit defaults from layer if not specified
2103			if (!point.useCustom) {
2104				// Update the original object instead of creating a new one
2105				Object.assign(point, {
2106					...layerData.pointDefaults,
2107					color: point.color || layerData.pointDefaults?.color,
2108					hover: point.hover || layerData.pointDefaults?.hover
2109				});
2110			}
2111
2112			const coordinates = getCoordinates(point);
2113			const marker = createMarker$1(point, data )
2114				.setLngLat(coordinates)
2115				.addTo(globe);
2116
2117			// Store marker reference - this will now work correctly
2118			point._marker = marker;
2119
2120			// Add click event listener
2121			marker.getElement().addEventListener('click', () => {
2122				// Ensure we have all necessary data for the click event
2123				const clickData = {
2124					...point,
2125					action: point.action || layerData.action || data.action,
2126					actionTarget: point.actionTarget || layerData.actionTarget || data.actionTarget,
2127					actionValue: point.actionValue || layerData.actionValue || data.actionValue,
2128					globe_id: point.globe_id || layerData.globe_id || data.id
2129				};
2130				globe.setupClickEvent(globe, data, clickData);
2131			});
2132
2133			// Add hover effects if needed
2134			if (point.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) {
2135				handleMarkerHover(
2136					globe,
2137					data,
2138					marker,
2139					point.tooltipContent,
2140					coordinates,
2141					'point',
2142					point
2143				);
2144			}
2145		});
2146	}
2147
2148	// Process objects
2149	if (layerData.objects && layerData.objects.length > 0) {
2150		layerData.objects.forEach(object => {
2151			// Add layer ID to the object
2152			object._layerId = layerId;
2153			// Inherit defaults from layer if not specified
2154			if (!globe_ut_bool(object.useCustom)) {
2155				Object.assign(object, {
2156					...layerData.pointDefaults,
2157					color: object.color || layerData.pointDefaults?.color,
2158					hover: object.hover || layerData.pointDefaults?.hover
2159				});
2160			}
2161			const coordinates = getCoordinates(object);
2162			const marker = createMarker$1(object, data )
2163				.setLngLat(coordinates)
2164				.addTo(globe);
2165
2166			// Store marker reference
2167			object._marker = marker;
2168
2169			// Add click event listener
2170			marker.getElement().addEventListener('click', () => {
2171				// Ensure we have all necessary data for the click event
2172				const clickData = {
2173					...object,
2174					action: object.action || layerData.action || data.action,
2175					actionTarget: object.actionTarget || layerData.actionTarget || data.actionTarget,
2176					actionValue: object.actionValue || layerData.actionValue || data.actionValue,
2177					globe_id: object.globe_id || layerData.globe_id || data.id
2178				};
2179				globe.setupClickEvent(globe, data, clickData);
2180			});
2181
2182			// Add hover effects if needed
2183			if (object.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) {
2184				handleMarkerHover(
2185					globe,
2186					data,
2187					marker,
2188					object.tooltipContent,
2189					coordinates,
2190					'point',
2191					object
2192				);
2193			}
2194		});
2195	}
2196
2197	// Process dot labels
2198	if (layerData.dotLabels && layerData.dotLabels.length > 0) {
2199		layerData.dotLabels.forEach(label => {
2200			// Add layer ID to the label
2201			label._layerId = layerId;
2202			label.type = 'dotLabel';
2203			// Inherit defaults from layer if not specified
2204			if (!globe_ut_bool(label.useCustom)) {
2205				Object.assign(label, {
2206					...layerData.labelDefaults,
2207					color: label.color || layerData.labelDefaults?.color,
2208					hover: label.hover || layerData.labelDefaults?.hover
2209				});
2210			}
2211			const coordinates = getCoordinates(label);
2212			const marker = createMarker$1(label, data )
2213				.setLngLat(coordinates)
2214				.addTo(globe);
2215
2216			// Store marker reference
2217			label._marker = marker;
2218
2219			// Add click event listener
2220			marker.getElement().addEventListener('click', () => {
2221				// Ensure we have all necessary data for the click event
2222				const clickData = {
2223					...label,
2224					action: label.action || layerData.action || data.action,
2225					actionTarget: label.actionTarget || layerData.actionTarget || data.actionTarget,
2226					actionValue: label.actionValue || layerData.actionValue || data.actionValue,
2227					globe_id: label.globe_id || layerData.globe_id || data.id
2228				};
2229				globe.setupClickEvent(globe, data, clickData);
2230			});
2231
2232			// Add hover effects if needed
2233			if (label.tooltipContent || data.dotLabelsTooltipTemplate || data.tooltipTemplate) {
2234				handleMarkerHover(
2235					globe,
2236					data,
2237					marker,
2238					label.tooltipContent,
2239					coordinates,
2240					'dotLabel',
2241					label
2242				);
2243			}
2244		});
2245	}
2246
2247	// Process HTML markers
2248	if (layerData.html && layerData.html.length > 0) {
2249		layerData.html.forEach(htmlMarker => {
2250			// Add layer ID to the HTML marker
2251			htmlMarker._layerId = layerId;
2252			htmlMarker.type = 'htmlMarker';
2253			// Inherit defaults from layer if not specified
2254			if (!globe_ut_bool(htmlMarker.useCustom)) {
2255				Object.assign(htmlMarker, {
2256					...layerData.htmlDefaults,
2257					color: htmlMarker.color || layerData.htmlDefaults?.color,
2258					hover: htmlMarker.hover || layerData.htmlDefaults?.hover
2259				});
2260			}
2261			const coordinates = getCoordinates(htmlMarker);
2262			const marker = createMarker$1(htmlMarker, data )
2263				.setLngLat(coordinates)
2264				.addTo(globe);
2265
2266			// Store marker reference
2267			htmlMarker._marker = marker;
2268
2269			// Add click event listener
2270			marker.getElement().addEventListener('click', () => {
2271				// Ensure we have all necessary data for the click event
2272				const clickData = {
2273					...htmlMarker,
2274					action: htmlMarker.action || layerData.action || data.action,
2275					actionTarget: htmlMarker.actionTarget || layerData.actionTarget || data.actionTarget,
2276					actionValue: htmlMarker.actionValue || layerData.actionValue || data.actionValue,
2277					globe_id: htmlMarker.globe_id || layerData.globe_id || data.id
2278				};
2279				globe.setupClickEvent(globe, data, clickData);
2280			});
2281
2282			// Add hover effects if needed
2283			if (htmlMarker.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) {
2284				handleMarkerHover(
2285					globe,
2286					data,
2287					marker,
2288					htmlMarker.tooltipContent,
2289					coordinates,
2290					'point',
2291					htmlMarker
2292				);
2293			}
2294		});
2295	}
2296
2297	// Process regions
2298	if (layerData.regions && layerData.regions.length > 0) {
2299		// Add regions to the main regions array with layer ID
2300
2301		layerData.regions.forEach(region => {
2302			region._layerId = layerId;
2303			// Inherit defaults from layer if not specified
2304			if (!globe_ut_bool(region.useCustom)) {
2305				Object.assign(region, {
2306					...layerData.regionDefaults,
2307					color: region.color || layerData.regionDefaults?.color,
2308					hover: region.hover || layerData.regionDefaults?.hover
2309				});
2310			}
2311			// Add to the main data.regions array
2312			if (!data.regions) data.regions = [];
2313			data.regions.push(region);
2314		});
2315	}
2316
2317	// Process lines
2318	if (layerData.arcLines && layerData.arcLines.length > 0) {
2319		// Add lines to the main arcLines array with layer ID
2320		layerData.arcLines.forEach(line => {
2321			line._layerId = layerId;
2322
2323			// Add to the main data.arcLines array
2324			if (!data.arcLines) data.arcLines = [];
2325			data.arcLines.push(line);
2326		});
2327	}
2328};
2329
2330const getRegionProperty = (region, propertyName, data, fallback ) => {
2331	if (globe_ut_bool(region.useCustom)) {
2332		return region[propertyName];
2333	}
2334	// If region has a layer ID, use that layer's defaults
2335	if (region.sourceId && data.layers) {
2336		const layer = data.layers.find(l => l.id === region.sourceId);
2337		if (layer && layer.regionDefaults) {
2338			return layer.regionDefaults[propertyName];
2339		}
2340	}
2341	// Fallback to base map defaults
2342	return data.regionDefaults?.[propertyName] || fallback;
2343};
2344
2345const normalizeRegion = (region, data ) => ({
2346	...region,
2347	color: getRegionProperty(region, 'color', data, '#c9c9c9'),
2348	hover: getRegionProperty(region, 'hover', data, '#a0a0a0'),
2349	strokeColor: getRegionProperty(region, 'strokeColor', data, '#f0f
23490f0'),
2350	tooltipContent: region.tooltipContent
2351});
2352
2353const isDictEmpty = (obj) => {
2354	for (let key in obj) {
2355		if (obj.hasOwnProperty(key)) {
2356			return false;
2357		}
2358	}
2359	return true;
2360};
2361
2362const findFeature = (regionFeatures, regionIdOrList, lookupId ) => {
2363	// Try direct lookup
2364
2365	if (Array.isArray(regionIdOrList)) {
2366		return regionIdOrList.map(element =>
2367			findFeature(regionFeatures, element, lookupId)
2368		);
2369	}
2370	let feature = regionFeatures[regionIdOrList];
2371	if (feature) return feature;
2372
2373	// Search by dynamic property
2374	return Object.values(regionFeatures).find(f =>
2375		f.properties?.[lookupId] === regionIdOrList
2376	) || null;
2377};
2378
2379const pointOfView = (globe, data, element, transitionMs ) => {
2380	if (!element) return;
2381
2382	// Define zoom level and animation options
2383	const zoomLevel = element.zoomLevel || 4;
2384	const animationDuration = 1500;
2385
2386	// For markers (points, objects, dotLabels, html)
2387	if (element.coordinates || element.longitude || element.lat) {
2388		const coordinates = element.coordinates ?
2389			[element.coordinates.longitude, element.coordinates.latitude] :
2390			[element.longitude || element.lng || 0, element.latitude || element.lat || 0];
2391
2392		// Fly to the coordinates
2393		globe.flyTo({
2394			center: coordinates,
2395			//zoom: zoomLevel, // where does this come from
2396			duration: animationDuration,
2397			essential: true
2398		});
2399	}
2400	// For regions
2401	else if (element.type === 'regions' && globe.getSource('regions')) {
2402		// Handle region ID that might be an array and might be in different locations
2403		// First check element.id (original format)
2404		let regionIdOrList;
2405
2406		if (element.id) {
2407			regionIdOrList = element.id;
2408		}
2409		// Then check element.properties.id (format from some event handlers)
2410		else if (element.properties && element.properties.id) {
2411			regionIdOrList = element.properties.id;
2412		}
2413		if (!regionIdOrList) {
2414			return;
2415		}
2416		let regionFirstId = regionIdOrList;
2417		if( Array.isArray( regionIdOrList ) ) {
2418			regionFirstId = regionIdOrList[0];
2419		}
2420
2421
2422		// Define known region centers for common regions
2423		const knownRegionCenters = {
2424			'asia': { center: [100, 30], zoom: 2.5 },
2425			'africa': { center: [20, 0], zoom: 2.5 },
2426			'europe': { center: [15, 50], zoom: 3 },
2427			'northAmerica': { center: [-100, 40], zoom: 2.5 },
2428			'southAmerica': { center: [-60, -20], zoom: 2.5 },
2429			'australia': { center: [135, -25], zoom: 3 },
2430			'antarctica': { center: [0, -90], zoom: 2 },
2431			'oceania': { center: [150, -10], zoom: 3 }
2432		};
2433
2434		// Check if this is a known region - normalize the ID for comparison
2435		const normalizedId = regionFirstId.toLowerCase().replace(/\s+/g, '-');
2436
2437		// If it's a known region, use predefined center and zoom
2438		if (knownRegionCenters[normalizedId]) {
2439			const regionConfig = knownRegionCenters[normalizedId];
2440
2441			globe.flyTo({
2442				center: regionConfig.center,
2443				zoom: regionConfig.zoom || (zoomLevel - 1), // Use predefined zoom or default
2444				duration: animationDuration,
2445				essential: true
2446			});
2447			return;
2448		}
2449
2450		let lookupId = 'id';
2451		const isRegionOtherSourceEnabled = data.regionsDataSource?.enabled || false;
2452		if ( isRegionOtherSourceEnabled != 0 ) {
2453			lookupId = data.regionsDataSource?.json_id || 'id';
2454		}
2455
2456		setTimeout(() => {
2457			// Wait a bit for tiles to load
2458			const allRegionFeatures = globe.allRegionsLookup;
2459			if ( isDictEmpty( allRegionFeatures ) ) {
2460				console.debug('the Lookup is empty' );
2461				return;
2462			}
2463
2464			const availableRegions = findFeature( allRegionFeatures, regionIdOrList, lookupId );
2465			if ( ! availableRegions ) {
2466				console.error('No Region found with ID:', regionIdOrList );
2467				return;
2468			}
2469
2470			// Create a bounds object to encompass ALL parts of the region
2471			const bounds = new maplibregl.LngLatBounds();
2472			let hasValidCoords = false;
2473
2474			try {
2475				// Process all features that match this region ID
2476				// for each availableRegion find the bounds:
2477				availableRegions.forEach( feature => {
2478
2479					if (feature.geometry.type === 'Polygon') {
2480						// For polygons, process all rings (first is outer, rest are holes)
2481						feature.geometry.coordinates.forEach((ring, ringIndex) => {
2482							// Only process outer ring (index 0) for bounds
2483							if (ringIndex === 0) {
2484								ring.forEach(coord => {
2485									if (Array.isArray(coord) && coord.length >= 2) {
2486										bounds.extend(coord);
2487										hasValidCoords = true;
2488									}
2489								});
2490							}
2491						});
2492					}
2493					else if (feature.geometry.type === 'MultiPolygon') {
2494						// For multi-polygons, process each polygon's outer ring
2495						feature.geometry.coordinates.forEach(polygon => {
2496							if (Array.isArray(polygon) && polygon.length > 0) {
2497								// Get the outer ring of this polygon (index 0)
2498								const outerRing = polygon[0];
2499								if (Array.isArray(outerRing)) {
2500									outerRing.forEach(coord => {
2501										if (Array.isArray(coord) && coord.length >= 2) {
2502											bounds.extend(coord);
2503											hasValidCoords = true;
2504										}
2505									});
2506								}
2507							}
2508						});
2509					}
2510				});
2511
2512				if (hasValidCoords) {
2513
2514					// Fit the map to the bounds of the entire region
2515					globe.fitBounds(bounds, {
2516						padding: {top: 10, bottom: 10, left: 10, right: 10}, // More flexible padding
2517						duration: animationDuration,
2518						maxZoom: zoomLevel
2519					});
2520				} else {
2521					throw new Error('No valid coordinates found in any region geometry');
2522				}
2523			} catch (error) {
2524				console.error('Error fitting region to view:', error);
2525			}
2526		}, 100);
2527	}
2528};
2529
2530// Add hover effects for regions
2531let hoveredRegionId = null;
2532let hoveredSourceId = null;
2533
2534/**
2535 * Adds geojson regions layer
2536 * @param {*} globe
2537 * @param {*} data
2538 */
2539
2540const addRegions = async function( globe, data, regionDataLookup = {} ) {
2541
2542	let allRegions = Object.create(null);
2543	// Get keepBase value from data.liveFilter at the start of the function
2544	data.liveFilter && data.liveFilter.keepBase ? data.liveFilter.keepBase : '0';
2545
2546
2547	// Process base map regions if enabled
2548	if (data.regionSource !== 'disabled' && data.regionSource && data.regions) {
2549		let fullpath;
2550		if (data.regionSource !== 'custom') {
2551			let geojson_source = data.regionSource;
2552			if (!geojson_source.includes('.geojson') && !geojson_source.includes('.json')) {
2553				geojson_source += '.json';
2554			}
2555			fullpath = ittGlobeData.assetsUrl + 'geojson/' + geojson_source;
2556		} else {
2557			fullpath = data.regionCustomSourceURL;
2558		}
2559
2560		const baseGeoJSONData = await loadGeoJSONData(fullpath);
2561		if (baseGeoJSONData) {
2562			// Get keepBase value from the filter container
2563			const baseRegions = await processRegionsData(globe, data, baseGeoJSONData, regionDataLookup, 'regions' );
2564			allRegions = { ...allRegions, ...baseRegions };
2565		}
2566	}
2567
2568	// Process regions from layers independently
2569	if (data.layers && Array.isArray(data.layers)) {
2570
2571		let layerRegions = {};
2572		for (const layer of data.layers) {
2573			if (layer.regions && layer.regions.length > 0 && layer.regionSource) {
2574				let layerFullpath;
2575				if (layer.regionSource !== 'custom') {
2576					let layerGeojsonSource = layer.regionSource;
2577					if (!layerGeojsonSource.includes('.geojson') && !layerGeojsonSource.includes('.json')) {
2578						layerGeojsonSource += '.json';
2579					}
2580					layerFullpath = ittGlobeData.assetsUrl + 'geojson/' + layerGeojsonSource;
2581				} else {
2582					layerFullpath = layer.regionCustomSourceURL;
2583				}
2584
2585				const layerGeoJSONData = await loadGeoJSONData(layerFullpath);
2586				if (layerGeoJSONData) {
2587					const sourceId = `regions-${layer.id || layer.name || Math.random().toString(36).substr(2, 9)}`;
2588					const layerRegionsDict = prepareDataRegions( layer, sourceId ) || {};
2589					// Create a context object with layer regions to ensure correct active IDs calculation
2590					// Merge layer properties to respect layer-specific settings
2591					// Force onlyActiveRegions to true to accumulate active regions without obscuring underlying layers with inactive ones
2592					const layerData = {
2593						...data,
2594						...layer,
2595						onlyActiveRegions: true
2596					};
2597
2598					layerRegions = await processRegionsData( globe, layerData, layerGeoJSONData, layerRegionsDict, sourceId );
2599					allRegions = { ...allRegions, ...layerRegions };
2600				}
2601			}
2602		}
2603	}
2604
2605
2606	// Add hover and click events to all region elements ( libremap calls it layers )
2607	const regionElements = globe.getStyle().layers
2608		.filter(layer => layer.id.endsWith('-fills'))
2609		.map(layer => layer.id);
2610
2611	regionElements.forEach(layerId => {
2612		globe.on('mousemove', layerId, createGlobeHandler(mapLibreHandleHoverEvent, globe, data ));
2613		globe.on('mouseleave', layerId, () => {
2614			if (hoveredRegionId && hoveredSourceId) {
2615				globe.setFeatureState(
2616					{ source: hoveredSourceId, id: hoveredRegionId },
2617					{ hover: false }
2618				);
2619			}
2620			hoveredRegionId = null;
2621			hoveredSourceId = null;
2622			globe.popup.remove();
2623		});
2624		globe.on('click', layerId, createGlobeHandler(mapLibreHandleRegionClick, globe, data ));
2625	});
2626
2627	return allRegions;
2628};
2629
2630
2631// Function to load and process GeoJSON data
2632const loadGeoJSONData = async (sourceUrl) => {
2633	try {
2634		const response = await fetch(sourceUrl);
2635		return await response.json();
2636	} catch (error) {
2637		console.error('Error loading GeoJSON:', error);
2638		return null;
2639	}
2640};
2641
2642const createGlobeHandler = (handler, globe, data ) => {
2643	return (e) => handler(globe, data, e );
2644};
2645const mapLibreHandleRegionClick = (globe, data, e ) => {
2646
2647	if (e.originalEvent.target.classList.contains('maplibregl-marker')
2648		|| e.originalEvent.target.classList.contains('itt_globe_html')
2649		|| e.originalEvent.target.classList.contains('itt_globe_dot_label')
2650		|| e.originalEvent.target.classList.contains('itt_globe_point')
2651		|| e.originalEvent.target.classList.contains('pin-head')
2652		|| e.originalEvent.target.classList.contains('dot-label-dot')
2653		|| e.originalEvent.target.classList.contains('dot-label-marker')
2654		|| e.originalEvent.target.classList.contains('itt_globe_line')
2655		|| e.originalEvent.target.classList.contains('itt_globe_html_marker')
2656		|| e.originalEvent.target.tagName.toLowerCase() === 'img'
2657		|| e.originalEvent.target.tagName.toLowerCase() === 'path') {
2658
2659		return // Click target was a marker so do nothing…
2660	}
2661	// update
2662	if (e && e.features && e.features.length > 0) {
2663		const region = e.features[0];
2664		setupClickEvent$1(globe, data, region.properties);
2665		// update the prview UI
2666		if ( isAdmin ) {
2667			updateUIforRegion( e.features[0], e.lngLat );
2668		}
2669
2670	}
2671};
2672
2673
2674const updateUIforRegion = ( region, coordinates ) => {
2675	coordinates.latitude  = truncateTo3Decimals( coordinates.lat );
2676	coordinates.longitude = truncateTo3Decimals( coordinates.lng );
2677
2678	region.properties.coordinates = coordinates;
2679
2680
2681	// if clicked empty region, set title
2682	if( typeof region.properties.title === 'undefined' ){
2683		region.properties.title = region.properties.name || region.id;
2684	}
2685	let preview = {};
2686	preview.clickedDataset = {
2687		region_id : region.properties.id || region.id,
2688		title : region.properties.name,
2689		geojson : getGeojsonVal(),
2690		geojsonURL : getGeojsonUrlVal(),
2691		isActive: region.properties.isActive == 1 || region.properties.isActive === true
2692	};
2693
2694	preview.clickedElement = Object.assign({}, region.properties);
2695	preview.clickedElement.text = 'in a location in Region';
2696	preview.clickedElement.type = 'Region';
2697	preview.clickedElement.post_type = 'itt_globe_region';
2698
2699
2700	updatePreviewUI( preview.clickedDataset, preview.clickedElement );
2701};
2702
2703
2704// Add hover effects for all region layers
2705const mapLibreHandleHoverEvent = (globe, data, e) => {
2706
2707	if ( e.features.length > 0) {
2708		const region = e.features[0];
2709		const regionId = region.id;
2710		const isActive = region.properties.isActive;
2711		const sourceId = region.properties.sourceId;
2712
2713		// Get the current feature state to check visibility
2714		const featureState = globe.getFeatureState({ source: sourceId, id: regionId });
2715		const isVisible = featureState && featureState.visible;
2716
2717		// Only proceed if the region is active and visible
2718		if (isActive && isVisible) {
2719			if (hoveredRegionId !== regionId || hoveredSourceId !== sourceId) {
2720				// Clear previous hover state if it exists
2721				if (hoveredRegionId && hoveredSourceId) {
2722					globe.setFeatureState(
2723						{ source: hoveredSourceId, id: hoveredRegionId },
2724						{ hover: false }
2725					);
2726				}
2727
2728				// Set new hover state
2729				hoveredRegionId = regionId;
2730				hoveredSourceId = sourceId;
2731				globe.setFeatureState(
2732					{ source: sourceId, id: hoveredRegionId },
2733					{ hover: true }
2734				);
2735
2736				// Show tooltip if available and not hovering a marker
2737				if (region.properties.tooltipContent) {
2738					const processedContent = getTooltipTemplate('region', region.properties, data );
2739					globe.popup.setLngLat(e.lngLat)
2740						.setHTML(processedContent)
2741						.addTo(globe);
2742				}
2743			}
2744		} else {
2745			// If region is not visible or not active, ensure hover state is cleared
2746			if (hoveredRegionId === regionId && hoveredSourceId === sourceId) {
2747				globe.setFeatureState(
2748					{ source: sourceId, id: regionId },
2749					{ hover: false }
2750				);
2751				hoveredRegionId = null;
2752				hoveredSourceId = null;
2753				globe.popup.remove();
2754			}
2755		}
2756	}
2757};
2758
2759const prepareDataRegions = function ( data, sourceId ){
2760	// foreach data.
2761	if (!data.regions || data.regions.length === 0) {
2762		return;
2763	}
2764	const selectedRegionsIndividually = data.regions.reduce((acc, region) => {
2765
2766		// save original id, to use for grouped hover
2767		region.originalId = region.id;
2768
2769		// Destructure the region to get all properties except ids
2770		const { id, ...regionProps } = region;
2771		if ( ! id ) {
2772			return acc;
2773		}
2774
2775		// Convert string id to array if needed
2776		if (typeof id === 'string') {
2777			id = id.includes(',') ? id.split(',').map(i => i.trim()) : [id];
2778		}
2779
2780		// Create new objects with all region properties and the individual id
2781		const idsWithProps = id.map(id => (
2782			{
2783				...regionProps,
2784				id: id,
2785				sourceId: sourceId, // Store the source ID in properties
2786			}));
2787		return acc.concat(idsWithProps);
2788	}, []);
2789
2790
2791	// Convert the selection of regions array to a dictionary for quick lookup
2792
2793	const regionsDict = selectedRegionsIndividually.reduce((acc, region) => {
2794		const ids = Array.isArray(region.id) ? region.id : [region.id];
2795		const normalized = normalizeRegion(region, data);
2796
2797		ids.forEach(id => {
2798			if (!id) {
2799				console.warn('Region missing ID:', region);
2800				return;
2801			}
2802			acc[String(id)] = normalized;
2803		});
2804
2805		// Optional: also store by title (for country name lookup)
2806		if (region.title) {
2807			acc[region.title] = normalized;
2808		}
2809		// Store by name as well (if different from title)
2810		if (region.name) {
2811			acc[region.name] = normalized;
2812		}
2813		return acc;
2814	}, Object.create(null)); // use null prototype for faster lookups
2815
2816	return regionsDict;
2817};
2818
2819
2820// Function to process regions data
2821const processRegionsData = (globe, data, geojsonData, regionDataLookup, sourceId ) => {
2822
2823	const allRegions = [];
2824	if ( ! geojsonData) {
2825		return allRegions;
2826	}
2827
2828	// todo: maybe replace with this regionDataLookup
2829	let activeRegionIds = [];
2830
2831	if ( data.regions?.length ) {
2832		activeRegionIds = data.regions.flatMap(region => Array.isArray(region.id) ? region.id : [region.id]);
2833	}
2834	// Only filter features if onlyActiveRegions is true
2835	const shouldFilterRegions = globe_ut_bool(data.onlyActiveRegions);
2836
2837	if (shouldFilterRegions) {
2838		geojsonData.features = geojsonData.features.filter(feature => {
2839			return activeRegionIds.includes(feature.properties.id);
2840		});
2841	}
2842	const keepBaseValue = data.liveFilter && data.liveFilter.keepBase ? data.liveFilter.keepBase : '0';
2843
2844
2845	const lookupjsonid = data.regionsDataSource?.json_id || 'id';
2846
2847	const features = geojsonData.features.map( (feature, index ) => {
2848		const originalId = feature.properties.id;
2849		const regionId = String(originalId);
2850
2851		const regionData = regionDataLookup[regionId] || {};
2852		const isActive = activeRegionIds.includes(regionId);
2853
2854		let search_term = originalId;
2855		const isRegionOtherSourceEnabled = data.regionsDataSource?.enabled || false;
2856		if ( isRegionOtherSourceEnabled != 0 ) {
2857			search_term = regionData?.[lookupjsonid];
2858		}
2859
2860		// Create a new feature with integer ID and original ID in properties
2861		return {
2862			...feature,
2863			id: index, // Assign unique integer ID
2864			properties: {
2865				...regionData,
2866				...feature.properties,
2867				originalId: originalId, // Store original ID in properties
2868				id: originalId, // Keep original ID in properties for compatibility
2869				searchTerm: search_term,
2870				isActive: isActive,
2871				sourceId: sourceId, // Store the source ID in properties
2872				globe_id: regionData.globe_id || data.id // Ensure globe_id is set
2873			}
2874		};
2875	});
2876
2877	// Add source ( all the data )
2878	globe.addSource(sourceId, {
2879		type: 'geojson',
2880		data: {
2881			...geojsonData,
2882			features: features
2883		}
2884	});
2885
2886	// Also create dict for lookups
2887	const featuresDict = features.reduce((acc, feature) => {
2888		const id = String(feature.properties.originalId);
2889		acc[id] = feature;
2890
2891		if (feature.properties.name) {
2892			acc[feature.properties.name] = feature;
2893		}
2894
2895		return acc;
2896	}, Object.create(null));
2897
2898	const hasRegions = Object.keys(regionDataLookup || {}).length > 0;
2899
2900	const hoverMatch = hasRegions ? [
2901		'match',
2902		['get', 'id'],
2903		...Object.entries(regionDataLookup).map(([id, props]) => [id, props.hover]).flat(),
2904		data.regionDefaults.hover || '#a0a0a0'
2905		]
2906	: data.regionDefaults.hover || '#a0a0a0';
2907
2908	const activeMatch = hasRegions ? [
2909		'match',
2910		['get', 'id'],
2911		...Object.entries(regionDataLookup).map(([id, props]) => [id, props.color]).flat(),
2912		data.regionDefaults.inactive || '#c9c9c9'
2913		]
2914	: data.regionDefaults.inactive || '#c9c9c9';
2915
2916	const regionsStrokeColor = data.regionDefaults?.strokeColor || '#f0f0f0';
2917	const strokeMatch = hasRegions ? [
2918		'match',
2919		['get', 'id'],
2920		...Object.entries(regionDataLookup).map(([id, props]) => [
2921			id,
2922			props.strokeColor ?? ( regionsStrokeColor )
2923		]).flat(),
2924		regionsStrokeColor
2925		]
2926	: regionsStrokeColor;
2927
2928	// Add regions style layer for Fill
2929	globe.addLayer({
2930		id: `${sourceId}-fills`,
2931		type: 'fill',
2932		source: sourceId,
2933		paint: {
2934			'fill-color': [
2935				'case',
2936				['all',
2937					['boolean', ['feature-state', 'hover'], false],
2938					['get', 'isActive']
2939				],
2940				hoverMatch,
2941				['get', 'isActive'],
2942				activeMatch,
2943				data.regionDefaults.inactive || '#c9c9c9'
2944			],
2945			'fill-opacity': [
2946				'case',
2947				['boolean', ['feature-state', 'visible'], false],
2948				0.9,
2949				0
2950			]
2951		}
2952	});
2953
2954	// Add regions style layer for borders
2955	globe.addLayer({
2956		id: `${sourceId}-borders`,
2957		type: 'line',
2958		source: sourceId,
2959		paint: {
2960			'line-color': [
2961				'case',
2962				['get', 'isActive'],
2963				strokeMatch,
2964				data.regionDefaults.strokeColor || '#f0f0f0'
2965			],
2966			'line-width': 0.5,
2967			'line-opacity': [
2968				'case',
2969				['boolean', ['feature-state', 'visible'], false],
2970				0.9,
2971				0
2972			]
2973		}
2974	});
2975
2976
2977	// Wait for the source to be loaded before setting feature states
2978	globe.on('sourcedata', (e) => {
2979		if (e.sourceId === sourceId && globe.isSourceLoaded(sourceId)) {
2980
2981			// Check if live filter is enabled and has a default value
2982			const hasLiveFilter = globe_ut_bool(data.liveFilter?.enabled);
2983			const defaultGlobeId = data.liveFilter?.default;
2984
2985
2986			const shouldFilterRegions = globe_ut_bool(data.onlyActiveRegions);
2987			features.forEach(feature => {
2988				if (feature.id !== undefined) {
2989					const isActive = feature.properties.isActive;
2990					const featureGlobeId = feature.properties.globe_id;
2991
2992					// Determine initial visibility based on live filter settings
2993					let shouldBeVisible = isActive || !shouldFilterRegions;
2994
2995					if (hasLiveFilter && defaultGlobeId) {
2996
2997						// Convert IDs to strings for comparison to avoid type mismatches
2998						const defaultGlobeIdStr = String(defaultGlobeId);
2999						const baseMapIdStr = String(data.id);
3000						const featureGlobeIdStr = String(featureGlobeId);
3001
3002						// If keepBase is enabled and this is a base map region, always show it
3003						if (keepBaseValue === '1' && featureGlobeIdStr === baseMapIdStr) {
3004							shouldBeVisible = isActive;
3005						}
3006						// If default is base map, show all active regions
3007						else if (defaultGlobeIdStr === baseMapIdStr) {
3008							shouldBeVisible = isActive;
3009						}
3010						// If default is this layer's globe_id, show this layer's regions
3011						else if (defaultGlobeIdStr === featureGlobeIdStr) {
3012							shouldBeVisible = isActive;
3013						}
3014						// If default is a different layer, hide this layer's regions unless it's base map with keepBase
3015						else {
3016							shouldBeVisible = keepBaseValue === '1' && featureGlobeIdStr === baseMapIdStr;
3017						}
3018					}
3019
3020
3021					try {
3022						// Set both visible and hover states
3023						globe.setFeatureState(
3024							{ source: sourceId, id: feature.id },
3025							{
3026								visible: shouldBeVisible,
3027								hover: false
3028							}
3029						);
3030
3031					} catch (error) {
3032						console.error('Error setting feature state:', error);
3033					}
3034				}
3035			});
3036		}
3037	});
3038	return featuresDict;
3039};
3040
3041const maybeRotateGlobe = function ( globe, data ) {
3042	// Add auto rotation if enabled
3043	if (globe_ut_bool(data.rotate?.enabled)) {
3044		let rotationSpeed = data.rotate?.speed ? parseFloat(data.rotate.speed)/4 : 1.5;
3045		let isRotating = true;
3046		let animationFrameId;
3047
3048		// Start a rotation animation around the globe (panning along equator)
3049		const rotateCamera = () => {
3050			if (isRotating) {
3051				const currentCenter = globe.getCenter();
3052				globe.setCenter([currentCenter.lng + rotationSpeed, currentCenter.lat], {
3053					duration: 0,
3054					easing: t => t
3055				});
3056				animationFrameId = requestAnimationFrame(rotateCamera);
3057			}
3058		};
3059
3060		const stopRotation = () => {
3061			isRotating = false;
3062			if (animationFrameId) {
3063				cancelAnimationFrame(animationFrameId);
3064			}
3065		};
3066
3067		const startRotation = () => {
3068			isRotating = true;
3069			rotateCamera();
3070		};
3071
3072		// Start initial rotation
3073		rotateCamera();
3074
3075		// Stop rotation on map hover
3076		globe.getCanvas().addEventListener('mouseenter', stopRotation);
3077
3078		// Resume rotation when mouse leaves the map
3079		globe.getCanvas().addEventListener('mouseleave', startRotation);
3080
3081		// Add hover handlers to all markers
3082		const addMarkerHoverHandlers = (marker) => {
3083			const element = marker.getElement();
3084			element.addEventListener('mouseenter', stopRotation);
3085			element.addEventListener('mouseleave', startRotation);
3086		};
3087
3088		// Add hover handlers to existing markers
3089		if (data.points) {
3090			data.points.forEach(point => addMarkerHoverHandlers(point._marker));
3091		}
3092		if (data.objects) {
3093			data.objects.forEach(object => addMarkerHoverHandlers(object._marker));
3094		}
3095		if (data.dotLabels) {
3096			data.dotLabels.forEach(label => addMarkerHoverHandlers(label._marker));
3097		}
3098		if (data.html) {
3099			data.html.forEach(html => addMarkerHoverHandlers(html._marker));
3100		}
3101	}
3102};
3103
3104const styles = {};
3105
3106	styles['default'] = {
3107		version: 8,
3108		sources: {
3109			satellite: {
3110				type: 'raster',
3111				tiles: ['https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'],
3112				tileSize: 256,
3113				attribution: 'Esri World Imagery'
3114			}
3115		},
3116		layers: [
3117			{
3118				id: 'satellite-layer',
3119				type: 'raster',
3120				source: 'satellite',
3121				minzoom: 0,
3122				maxzoom: 22
3123			}
3124		]
3125	};
3126	styles['terrain'] = {
3127		version: 8,
3128		sources: {
3129			opentopo: {
3130				type: 'raster',
3131				tiles: ['https://a.tile.opentopomap.org/{z}/{x}/{y}.png'],
3132				tileSize: 256
3133			}
3134		},
3135		layers: [
3136			{
3137				id: 'opentopo-tiles',
3138				type: 'raster',
3139				source: 'opentopo'
3140			}
3141		]
3142	};
3143
3144	styles['light'] = {
3145		version: 8,
3146		sources: {
3147			carto: {
3148				type: 'raster',
3149				tiles: ['https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png'],
3150				tileSize: 256
3151			}
3152		},
3153		layers: [
3154			{
3155				id: 'carto-tiles',
3156				type: 'raster',
3157				source: 'carto'
3158			}
3159		]
3160	};
3161
3162	styles['dark'] = {
3163		version: 8,
3164		sources: {
3165			carto: {
3166				type: 'raster',
3167				tiles: ['https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'],
3168				tileSize: 256
3169			}
3170		},
3171		layers: [
3172			{
3173				id: 'carto-tiles',
3174				type: 'raster',
3175				source: 'carto'
3176			}
3177		]
3178	};
3179
3180
3181
3182	styles['osm'] = {
3183		version: 8,
3184		sources: {
3185			osm: {
3186				type: 'raster',
3187				tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
3188				tileSize: 256
3189			}
3190		},
3191		layers: [
3192			{
3193				id: 'osm-tiles',
3194				type: 'raster',
3195				source: 'osm'
3196			}
3197		]
3198	};
3199
3200var create_maplibre = function ( id, data ) {
3201
3202	//data types - normal
3203	let dataTypes = {
3204		'points': 'pointDefaults',
3205		'dotLabels': 'labelDefaults',
3206		'html': 'htmlDefaults',
3207		'objects': 'pointDefaults',
3208		'regions': 'regionDefaults',
3209		'arcLines': 'arcLineDefaults',
3210	};
3211
3212	let container = document.getElementById( 'itt_globe_' + id );
3213
3214	globe_ut_prepareData( data );
3215	globe_ut_setupData( data, dataTypes );
3216	globe_ut_prepareViewport( container, data );
3217
3218	// Store the data in our data store
3219	({
3220		base: {
3221			points: data.points || [],
3222			objects: data.objects || [],
3223			dotLabels: data.dotLabels || [],
3224			html: data.html || [],
3225			regions: data.regions || [],
3226			arcLines: data.arcLines || []
3227		},
3228		layers: data.layers || [],
3229		baseMapId: data.id // Store the base map ID for reference
3230	});
3231
3232	// if there are layers, process the layers data also
3233	if(data.layers){
3234		for(let layer of data.layers){
3235			globe_ut_setupData(layer, dataTypes);
3236		}
3237	}
3238
3239	// Initialize a new MapLibre GL map instance with the specified configuration.
3240	// - `container`: The HTML element ID where the map will be rendered, prefixed with 'itt_globe_' and the given `id`.
3241	// - `style`: The map style to use, determined by the `maplibreStyle` property in the `data` object.
3242	// - `center`: The initial geographical center of the map, using longitude and latitude from `data.centerCoordinates`.
3243	// - `zoom`: The initial zoom level, defaulting to 2 if not specified in `data.zoomOptions`.
3244	// - `minZoom`: The minimum zoom level allowed, defaulting to 0, ensuring it's not negative.
3245	// - `maxZoom`: The maximum zoom level allowed, defaulting to 22, ensuring it doesn't exceed 22.
3246	// - `maplibreLogo`: Set to false to hide the MapLibre logo.
3247	// - `dragPan`: Enables or disables panning interaction based on `data.interactions.pan`.
3248	// - `scrollZoom`: Enables or disables zooming interaction based on `data.interactions.zoom`.
3249	// - `preserveDrawingBuffer`: Set to false, meaning the drawing buffer is not preserved.
3250	// - `renderWorldCopies`: Set to true to render multiple copies of the world map.
3251	const thisGlobe = new maplibregl.Map({
3252		container: 'itt_globe_' + id,
3253		style: styles[data.maplibreStyle],
3254		center: [data.centerCoordinates.longitude, data.centerCoordinates.latitude],
3255		zoom: (typeof data.zoomOptions?.initialZoom !== 'undefined' && data.zoomOptions.initialZoom !== '') ? parseFloat(data.zoomOptions.initialZoom) : 2,
3256		minZoom: data.zoomOptions?.minZoom ? Math.max(0, parseFloat(data.zoomOptions.minZoom)) : 0,
3257		maxZoom: data.zoomOptions?.maxZoom ? Math.min(22, parseFloat(data.zoomOptions.maxZoom)) : 22,
3258		maplibreLogo: false,
3259		dragPan: globe_ut_bool(data.interactions?.pan),
3260		scrollZoom: globe_ut_bool(data.interactions?.zoom),
3261		renderWorldCopies: true
3262	});
3263
3264	// Attach the wrapper - pre-bind globe and data
3265	thisGlobe.pointOfView = (pov, transitionMs) => {
3266		return pointOfView(thisGlobe, data, pov);
3267	};
3268
3269	// Create a single popup for all markers
3270	new maplibregl.Popup({
3271		offset: [0, -25], // Increased vertical offset
3272		closeButton: false,
3273		closeOnClick: true
3274	});
3275
3276	// to make it publically accessible
3277	thisGlobe.meta = data;
3278
3279	// Add screenshot capability
3280	thisGlobe.takeScreenshot = () => {
3281		return new Promise((resolve) => {
3282			thisGlobe.once("render", () => {
3283				resolve(thisGlobe.getCanvas().toDataURL());
3284			});
3285			/* trigger render */
3286			thisGlobe.setBearing(thisGlobe.getBearing());
3287		});
3288	};
3289
3290	// add object to be public
3291	ittGlobes$1.globes.push(thisGlobe);
3292	ittGlobes$1.globesIndex[id] = thisGlobe;
3293
3294
3295	// events
3296	thisGlobe.setupClickEvent = setupClickEvent;
3297	thisGlobe.setupHoverEvent = setupHoverEvent;
3298
3299	maybeRotateGlobe( thisGlobe, data );
3300
3301	thisGlobe.on('style.load', () => {
3302		thisGlobe.setProjection({
3303			type: 'globe'
3304		});
3305	});
3306
3307	thisGlobe.on('load', async () => {
3308		// Store popup reference for reuse
3309		thisGlobe.popup = new maplibregl.Popup({
3310			offset: [0, -25],
3311			closeButton: false,
3312			closeOnClick: true
3313		});
3314		addTooltipStylesToPopup( thisGlobe, id, data );
3315
3316		// setup settings
3317		// use later to empty memory used
3318		setupResizeListener(thisGlobe);
3319
3320		// Setup elements
3321		await addMarkers( thisGlobe, data );
3322
3323		// region Lookups
3324		const dataRegions = await prepareDataRegions( data, 'base' );
3325		const allRegions = await addRegions( thisGlobe, data, dataRegions );
3326		thisGlobe.allRegionsLookup = allRegions;
3327
3328		if (data.arcLines && data.arcLines.length > 0) {
3329			addArcLines( thisGlobe, data );
3330		}
3331
3332		// Only add navigation controls if zoom is enabled
3333		if (globe_ut_bool(data.interactions?.zoom)) {
3334			thisGlobe.addControl(new maplibregl.NavigationControl());
3335		}
3336
3337
3338		// Initialize filters after map is fully loaded
3339		setupMaplibreFilters();
3340		// Process layers if they exist
3341		if (data.layers && Array.isArray(data.layers)) {
3342			setupMaplibreLayers( thisGlobe, data );
3343		}
3344		// Trigger admin globe ready event if admin
3345		if (ittGlobeData.isAdmin) {
3346			const event = new Event("adminProGlobeReady");
3347			document.dispatchEvent(event);
3348		}
3349	});
3350
3351	return thisGlobe;
3352};
3353
3354function setupZoomEvent(globe) {
3355
3356	let GlobeData = globe.meta;
3357
3358	globe.onZoom(function(coordinates) {
3359		if (GlobeData.altitudeOptions) {
3360			// Clamp altitude between min and max values if values are set
3361			const minAlt = parseFloat(GlobeData.altitudeOptions.minAltitude);
3362			const maxAlt = parseFloat(GlobeData.altitudeOptions.maxAltitude);
3363
3364			if (!isNaN(minAlt) && minAlt !== 0 && coordinates.altitude < minAlt) {
3365				globe.pointOfView({
3366					...coordinates,
3367					altitude: minAlt
3368				});
3369			}
3370			else if (!isNaN(maxAlt) && maxAlt !== 0 && coordinates.altitude > maxAlt) {
3371				globe.pointOfView({
3372					...coordinates,
3373					altitude: maxAlt
3374				});
3375			}
3376		}
3377	});
3378}
3379
3380/** initialize globe */
3381ittGlobes$1.init = function () {
3382
3383	// code was running twice, so we check if it's already inited
3384	if ( typeof window.ittGlobes !== 'undefined' && typeof window.ittGlobes.inited !== 'undefined' ) {
3385		return;
3386	}
3387
3388	// check for globe container created by the shortcode
3389	let globe_render_container = document.getElementsByClassName( 'js-itt-globe-render' );
3390	for (const globe_container of globe_render_container) {
3391		if ( ! globe_container.dataset.hasOwnProperty('globe_id') ) {
3392			continue;
3393		}
3394		let globe_id = 0;
3395		try {
3396			globe_id = parseInt( JSON.parse(globe_container.dataset.globe_id ) );
3397		} catch (e) {
3398			continue;
3399		}
3400
3401		if ( ittGlobes$1.globesIndex[ globe_id ] !== undefined ) {
3402			continue;
3403		}
3404
3405		if ( ! globe_container.dataset.hasOwnProperty( 'globe_meta' ) ) {
3406			continue;
3407		}
3408
3409		let globe_meta = {};
3410		try {
3411			globe_meta = JSON.parse( globe_container.dataset.globe_meta );
3412		} catch (e) {
3413			globe_meta = {};
3414		}
3415
3416		if ( globe_meta.library === 'maplibre' ) {
3417			// return early if Maplibre Library didn't load properly
3418			if (typeof maplibregl === 'undefined') {
3419				console.error('Maplibre lib not loaded properly');
3420				return;
3421			}
3422
3423			// Store reference to map
3424			ittGlobes$1.globesIndex[globe_id] = create_maplibre( globe_id, globe_meta );
3425
3426			// we only set inited to true if library is maplibre, otherwise, it seems the globe needs to rerun to populate objects?
3427			ittGlobes$1.inited = true;
3428		}
3429		if ( globe_meta.library === 'globegl' || typeof globe_meta.library === 'undefined' ) {
3430			// return early if Globe.gl Library didn't load properly
3431			if (typeof Globe === 'undefined') {
3432				console.error('Globe lib not loaded properly');
3433				return;
3434			}
3435
3436			create_globe( globe_id, globe_meta );
3437		}
3438
3439
3440	}
3441};
3442
3443var create_globe = function ( id, data ) {
3444
3445	//data types - normal
3446	let dataTypes = {
3447		'points': 'pointDefaults',
3448		'dotLabels': 'labelDefaults',
3449	};
3450	let container = document.getElementById( 'itt_globe_' + id );
3451
3452	globe_ut_prepareData( data );
3453	globe_ut_setupData( data, dataTypes );
3454	globe_ut_prepareViewport( container, data );
3455
3456	let configOptions = {
3457		rendererConfig: { antialias: true, alpha: true },
3458		waitForGlobeReady: true,
3459		animateIn: typeof data.animateIn !== 'undefined' ? globe_ut_bool( data.animateIn ) : true,
3460	};
3461
3462	let thisGlobe = Globe( configOptions )
3463		(document.getElementById( 'itt_globe_' + id ));
3464
3465	// to make it publically accessible
3466	thisGlobe.meta = data;
3467
3468	// background colour
3469	if (data.backgroundColor === 'transparent') {
3470		data.backgroundColor = 'rgba(0,0,0,0)';
3471	}
3472
3473	// globe visuals
3474	if ( data.globeImage !== null && data.globeImage !== '' && data.globeImage !== 'earth-hollow' && data.globeImage !== 'noImage' && data.globeImage !== 'customImage' ) {
3475		thisGlobe.globeImageUrl( ittGlobeData.imagesUrl + data.globeImage );
3476	}
3477
3478	thisGlobe.backgroundColor(data.backgroundColor)
3479		.width(container.offsetWidth)
3480		.height(container.offsetHeight)
3481		.showGraticules( globe_ut_bool( data.showGraticules) && ! globe_ut_bool( data.graticules?.useLargeLinesGraticules ) )
3482		.showAtmosphere( globe_ut_bool(data.atmosphere.enabled))
3483		.atmosphereColor(data.atmosphere.atmosphereColor)
3484		.atmosphereAltitude(data.atmosphere.atmosphereAltitude)
3485		.pointOfView(data.pointOfView);
3486
3487	setupInteractions( thisGlobe, data );
3488	setupResizeEvent( thisGlobe, container, data );
3489	setupZoomEvent( thisGlobe );
3490	// if admin
3491	if ( ittGlobeData.isAdmin ) {
3492
3493		const existingOnGlobeReady = thisGlobe.onGlobeReady();
3494		thisGlobe.onGlobeReady(function () {
3495			if (existingOnGlobeReady) {
3496				existingOnGlobeReady();
3497			}
3498			const event = new Event("adminGlobeReady");
3499			document.dispatchEvent(event);
3500		});
3501	}
3502	// setup points
3503	if ( data.points ) {
3504		addPointsLayer( thisGlobe, data );
3505	}
3506
3507	// setup label points
3508	if ( data.dotLabels ) {
3509		addLabelsLayer( thisGlobe, data );
3510	}
3511
3512	// add click event function to be accesible globally
3513	thisGlobe.setupClickEvent = setupClickEvent$1;
3514	thisGlobe.setupHoverEvent = setupHoverEvent$1;
3515
3516	// add object to be public
3517	ittGlobes$1.globes.push( thisGlobe );
3518	ittGlobes$1.globesIndex[ id ] = thisGlobe;
3519
3520	// altitude options
3521	if ( data.altitudeOptions ) {
3522		thisGlobe.altitudeOptions = data.altitudeOptions;
3523	}
3524};
3525
3526ittGlobes$1.init();
3527
3528window.ittGlobes = ittGlobes$1;
3529
3530/** Add Arcs Layer to Globe - Pro */
3531function addArcsLayer( thisGlobe, data ) {
3532
3533	const segmented_lines = processLinesArray(data.arcLines);
3534
3535	thisGlobe.arcsData( segmented_lines )
3536		.arcStartLat(p => p.line[0].coordinates.latitude)
3537		.arcStartLng(p => p.line[0].coordinates.longitude)
3538		.arcEndLat(p => p.line[1].coordinates.latitude)
3539		.arcEndLng(p => p.line[1].coordinates.longitude)
3540		.arcColor( p => p.stroke )
3541		.arcStroke( p => p.strokeWidth )
3542		.arcDashLength( p => p.dashLength / 100 )
3543		.arcDashGap( p => p.dashGap / 100 )
3544		.arcDashAnimateTime( p => p.animate * 1000 )
3545		.arcAltitude(function (p) {
3546			if (isNaN(p.altitude) || p.altitude.trim() === '') {
3547				return null;
3548			}
3549			return p.altitude / 100;
3550		});
3551}
3552
3553function processLinesArray(lines) {
3554	const segmented_lines = [];
3555
3556	lines.forEach(entry => {
3557		const line_points = entry.line;
3558
3559		if ( line_points.length <= 2) {
3560			segmented_lines.push(entry);
3561			return;
3562		}
3563		// create copy for all properties
3564		const arc_data = { ...entry };
3565
3566		// replace the coordinates with a single line
3567		for (let i = 1; i < line_points.length; i++) {
3568			const new_arc_data = { ...arc_data };
3569			new_arc_data.line = [line_points[i - 1], line_points[i]];
3570			segmented_lines.push( new_arc_data );
3571		}
3572	});
3573
3574	return segmented_lines;
3575}
3576
3577/**
3578 * @license
3579 * Copyright 2010-2025 Three.js Authors
3580 * SPDX-License-Identifier: MIT
3581 */
3582const REVISION = '175';
3583
3584/**
3585 * Only front faces are rendered.
3586 *
3587 * @type {number}
3588 * @constant
3589 */
3590const FrontSide = 0;
3591
3592/**
3593 * Only back faces are rendered.
3594 *
3595 * @type {number}
3596 * @constant
3597 */
3598const BackSide = 1;
3599
3600/**
3601 * Both front and back faces are rendered.
3602 *
3603 * @type {number}
3604 * @constant
3605 */
3606const DoubleSide = 2;
3607
3608/**
3609 * The default blending.
3610 *
3611 * @type {number}
3612 * @constant
3613 */
3614const NormalBlending = 1;
3615
3616/**
3617 * A `source + destination` blending equation.
3618 *
3619 * @type {number}
3620 * @constant
3621 */
3622const AddEquation = 100;
3623
3624/**
3625 * Multiplies all colors by the source alpha value.
3626 *
3627 * @type {number}
3628 * @constant
3629 */
3630const SrcAlphaFactor = 204;
3631
3632/**
3633 * Multiplies all colors by 1 minus the source alpha value.
3634 *
3635 * @type {number}
3636 * @constant
3637 */
3638const OneMinusSrcAlphaFactor = 205;
3639
3640/**
3641 * Pass if the incoming value is less than or equal to the depth buffer value.
3642 *
3643 * @type {number}
3644 * @constant
3645 */
3646const LessEqualDepth = 3;
3647
3648/**
3649 * Multiplies the environment map color with the surface color.
3650 *
3651 * @type {number}
3652 * @constant
3653 */
3654const MultiplyOperation = 0;
3655
3656/**
3657 * Maps textures using the geometry's UV coordinates.
3658 *
3659 * @type {number}
3660 * @constant
3661 */
3662const UVMapping = 300;
3663
3664/**
3665 * The texture will simply repeat to infinity.
3666 *
3667 * @type {number}
3668 * @constant
3669 */
3670const RepeatWrapping = 1000;
3671
3672/**
3673 * The last pixel of the texture stretches to the edge of the mesh.
3674 *
3675 * @type {number}
3676 * @constant
3677 */
3678const ClampToEdgeWrapping = 1001;
3679
3680/**
3681 * The texture will repeats to infinity, mirroring on each repeat.
3682 *
3683 * @type {number}
3684 * @constant
3685 */
3686const MirroredRepeatWrapping = 1002;
3687
3688/**
3689 * Returns the weighted average of the four texture elements that are closest to the specified
3690 * texture coordinates, and can include items wrapped or repeated from other parts of a texture,
3691 * depending on the values of `wrapS` and `wrapT`, and on the exact mapping.
3692 *
3693 * @type {number}
3694 * @constant
3695 */
3696const LinearFilter = 1006;
3697
3698/**
3699 * Chooses the two mipmaps that most closely match the size of the pixel being textured and uses
3700 * the `LinearFilter` criterion to produce a texture value from each mipmap. The final texture value
3701 * is a weighted average of those two values.
3702 *
3703 * @type {number}
3704 * @constant
3705 */
3706const LinearMipmapLinearFilter = 1008;
3707
3708/**
3709 * An unsigned byte data type for textures.
3710 *
3711 * @type {number}
3712 * @constant
3713 */
3714const UnsignedByteType = 1009;
3715
3716/**
3717 * A float data type for textures.
3718 *
3719 * @type {number}
3720 * @constant
3721 */
3722const FloatType = 1015;
3723
3724/**
3725 * Reads the red, green, blue and alpha components.
3726 *
3727 * @type {number}
3728 * @constant
3729 */
3730const RGBAFormat = 1023;
3731
3732/**
3733 * Normal information is relative to the underlying surface.
3734 *
3735 * @type {number}
3736 * @constant
3737 */
3738const TangentSpaceNormalMap = 0;
3739
3740// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU n
vendor: 4,339 bytes, lines 3740-3947
3740ames where available.
3741
3742/**
3743 * No color space.
3744 *
3745 * @type {string}
3746 * @constant
3747 */
3748const NoColorSpace = '';
3749
3750/**
3751 * sRGB color space.
3752 *
3753 * @type {string}
3754 * @constant
3755 */
3756const SRGBColorSpace = 'srgb';
3757
3758/**
3759 * sRGB-linear color space.
3760 *
3761 * @type {string}
3762 * @constant
3763 */
3764const LinearSRGBColorSpace = 'srgb-linear';
3765
3766/**
3767 * Linear transfer function.
3768 *
3769 * @type {string}
3770 * @constant
3771 */
3772const LinearTransfer = 'linear';
3773
3774/**
3775 * sRGB transfer function.
3776 *
3777 * @type {string}
3778 * @constant
3779 */
3780const SRGBTransfer = 'srgb';
3781
3782/**
3783 * Keeps the current value.
3784 *
3785 * @type {number}
3786 * @constant
3787 */
3788const KeepStencilOp = 7680;
3789
3790/**
3791 * Will always return true.
3792 *
3793 * @type {number}
3794 * @constant
3795 */
3796const AlwaysStencilFunc = 519;
3797
3798/**
3799 * The contents are intended to be specified once by the application, and used many
3800 * times as the source for drawing and image specification commands.
3801 *
3802 * @type {number}
3803 * @constant
3804 */
3805const StaticDrawUsage = 35044;
3806
3807/**
3808 * WebGL coordinate system.
3809 *
3810 * @type {number}
3811 * @constant
3812 */
3813const WebGLCoordinateSystem = 2000;
3814
3815/**
3816 * WebGPU coordinate system.
3817 *
3818 * @type {number}
3819 * @constant
3820 */
3821const WebGPUCoordinateSystem = 2001;
3822
3823/**
3824 * This type represents mouse buttons and interaction types in context of controls.
3825 *
3826 * @typedef {Object} ConstantsMouse
3827 * @property {number} MIDDLE - The left mouse button.
3828 * @property {number} LEFT - The middle mouse button.
3829 * @property {number} RIGHT - The right mouse button.
3830 * @property {number} ROTATE - A rotate interaction.
3831 * @property {number} DOLLY - A dolly interaction.
3832 * @property {number} PAN - A pan interaction.
3833 **/
3834
3835/**
3836 * This type represents touch interaction types in context of controls.
3837 *
3838 * @typedef {Object} ConstantsTouch
3839 * @property {number} ROTATE - A rotate interaction.
3840 * @property {number} PAN - A pan interaction.
3841 * @property {number} DOLLY_PAN - The dolly-pan interaction.
3842 * @property {number} DOLLY_ROTATE - A dolly-rotate interaction.
3843 **/
3844
3845/**
3846 * This type represents the different timestamp query types.
3847 *
3848 * @typedef {Object} ConstantsTimestampQuery
3849 * @property {string} COMPUTE - A `compute` timestamp query.
3850 * @property {string} RENDER - A `render` timestamp query.
3851 **/
3852
3853/**
3854 * This modules allows to dispatch event objects on custom JavaScript objects.
3855 *
3856 * Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/}
3857 *
3858 * Code Example:
3859 * ```js
3860 * class Car extends EventDispatcher {
3861 * 	start() {
3862 *		this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } );
3863 *	}
3864 *};
3865 *
3866 * // Using events with the custom object
3867 * const car = new Car();
3868 * car.addEventListener( 'start', function ( event ) {
3869 * 	alert( event.message );
3870 * } );
3871 *
3872 * car.start();
3873 * ```
3874 */
3875class EventDispatcher {
3876
3877	/**
3878	 * Adds the given event listener to the given event type.
3879	 *
3880	 * @param {string} type - The type of event to listen to.
3881	 * @param {Function} listener - The function that gets called when the event is fired.
3882	 */
3883	addEventListener( type, listener ) {
3884
3885		if ( this._listeners === undefined ) this._listeners = {};
3886
3887		const listeners = this._listeners;
3888
3889		if ( listeners[ type ] === undefined ) {
3890
3891			listeners[ type ] = [];
3892
3893		}
3894
3895		if ( listeners[ type ].indexOf( listener ) === -1 ) {
3896
3897			listeners[ type ].push( listener );
3898
3899		}
3900
3901	}
3902
3903	/**
3904	 * Returns `true` if the given event listener has been added to the given event type.
3905	 *
3906	 * @param {string} type - The type of event.
3907	 * @param {Function} listener - The listener to check.
3908	 * @return {boolean} Whether the given event listener has been added to the given event type.
3909	 */
3910	hasEventListener( type, listener ) {
3911
3912		const listeners = this._listeners;
3913
3914		if ( listeners === undefined ) return false;
3915
3916		return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== -1;
3917
3918	}
3919
3920	/**
3921	 * Removes the given event listener from the given event type.
3922	 *
3923	 * @param {string} type - The type of event.
3924	 * @param {Function} listener - The listener to remove.
3925	 */
3926	removeEventListener( type, listener ) {
3927
3928		const listeners = this._listeners;
3929
3930		if ( listeners === undefined ) return;
3931
3932		const listenerArray = listeners[ type ];
3933
3934		if ( listenerArray !== undefined ) {
3935
3936			const index = listenerArray.indexOf( listener );
3937
3938			if ( index !== -1 ) {
3939
3940				listenerArray.splice( index, 1 );
3941
3942			}
3943
3944		}
3945
3946	}
3947
vendor: 12,364 bytes, lines 3948-4361
3948	/**
3949	 * Dispatches an event object.
3950	 *
3951	 * @param {Object} event - The event that gets fired.
3952	 */
3953	dispatchEvent( event ) {
3954
3955		const listeners = this._listeners;
3956
3957		if ( listeners === undefined ) return;
3958
3959		const listenerArray = listeners[ event.type ];
3960
3961		if ( listenerArray !== undefined ) {
3962
3963			event.target = this;
3964
3965			// Make a copy, in case listeners are removed while iterating.
3966			const array = listenerArray.slice( 0 );
3967
3968			for ( let i = 0, l = array.length; i < l; i ++ ) {
3969
3970				array[ i ].call( this, event );
3971
3972			}
3973
3974			event.target = null;
3975
3976		}
3977
3978	}
3979
3980}
3981
3982const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ];
3983
3984let _seed = 1234567;
3985
3986
3987const DEG2RAD = Math.PI / 180;
3988const RAD2DEG = 180 / Math.PI;
3989
3990/**
3991 * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier}
3992 * (universally unique identifier).
3993 *
3994 * @return {string} The UUID.
3995 */
3996function generateUUID() {
3997
3998	// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
3999
4000	const d0 = Math.random() * 0xffffffff | 0;
4001	const d1 = Math.random() * 0xffffffff | 0;
4002	const d2 = Math.random() * 0xffffffff | 0;
4003	const d3 = Math.random() * 0xffffffff | 0;
4004	const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
4005			_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
4006			_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
4007			_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
4008
4009	// .toLowerCase() here flattens concatenated strings to save heap memory space.
4010	return uuid.toLowerCase();
4011
4012}
4013
4014/**
4015 * Clamps the given value between min and max.
4016 *
4017 * @param {number} value - The value to clamp.
4018 * @param {number} min - The min value.
4019 * @param {number} max - The max value.
4020 * @return {number} The clamped value.
4021 */
4022function clamp( value, min, max ) {
4023
4024	return Math.max( min, Math.min( max, value ) );
4025
4026}
4027
4028/**
4029 * Computes the Euclidean modulo of the given parameters that
4030 * is `( ( n % m ) + m ) % m`.
4031 *
4032 * @param {number} n - The first parameter.
4033 * @param {number} m - The second parameter.
4034 * @return {number} The Euclidean modulo.
4035 */
4036function euclideanModulo( n, m ) {
4037
4038	// https://en.wikipedia.org/wiki/Modulo_operation
4039
4040	return ( ( n % m ) + m ) % m;
4041
4042}
4043
4044/**
4045 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>`
4046 * for the given value.
4047 *
4048 * @param {number} x - The value to be mapped.
4049 * @param {number} a1 - Minimum value for range A.
4050 * @param {number} a2 - Maximum value for range A.
4051 * @param {number} b1 - Minimum value for range B.
4052 * @param {number} b2 - Maximum value for range B.
4053 * @return {number} The mapped value.
4054 */
4055function mapLinear( x, a1, a2, b1, b2 ) {
4056
4057	return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
4058
4059}
4060
4061/**
4062 * Returns the percentage in the closed interval `[0, 1]` of the given value
4063 * between the start and end point.
4064 *
4065 * @param {number} x - The start point
4066 * @param {number} y - The end point.
4067 * @param {number} value - A value between start and end.
4068 * @return {number} The interpolation factor.
4069 */
4070function inverseLerp( x, y, value ) {
4071
4072	// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
4073
4074	if ( x !== y ) {
4075
4076		return ( value - x ) / ( y - x );
4077
4078	} else {
4079
4080		return 0;
4081
4082	}
4083
4084}
4085
4086/**
4087 * Returns a value linearly interpolated from two known points based on the given interval -
4088 * `t = 0` will return `x` and `t = 1` will return `y`.
4089 *
4090 * @param {number} x - The start point
4091 * @param {number} y - The end point.
4092 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
4093 * @return {number} The interpolated value.
4094 */
4095function lerp( x, y, t ) {
4096
4097	return ( 1 - t ) * x + t * y;
4098
4099}
4100
4101/**
4102 * Smoothly interpolate a number from `x` to `y` in  a spring-like manner using a delta
4103 * time to maintain frame rate independent movement. For details, see
4104 * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}.
4105 *
4106 * @param {number} x - The current point.
4107 * @param {number} y - The target point.
4108 * @param {number} lambda - A higher lambda value will make the movement more sudden,
4109 * and a lower value will make the movement more gradual.
4110 * @param {number} dt - Delta time in seconds.
4111 * @return {number} The interpolated value.
4112 */
4113function damp( x, y, lambda, dt ) {
4114
4115	return lerp( x, y, 1 - Math.exp( - lambda * dt ) );
4116
4117}
4118
4119/**
4120 * Returns a value that alternates between `0` and the given `length` parameter.
4121 *
4122 * @param {number} x - The value to pingpong.
4123 * @param {number} [length=1] - The positive value the function will pingpong to.
4124 * @return {number} The alternated value.
4125 */
4126function pingpong( x, length = 1 ) {
4127
4128	// https://www.desmos.com/calculator/vcsjnyz7x4
4129
4130	return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
4131
4132}
4133
4134/**
4135 * Returns a value in the range `[0,1]` that represents the percentage that `x` has
4136 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to
4137 * the `min` and `max`.
4138 *
4139 * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details.
4140 *
4141 * @param {number} x - The value to evaluate based on its position between min and max.
4142 * @param {number} min - The min value. Any x value below min will be `0`.
4143 * @param {number} max - The max value. Any x value above max will be `1`.
4144 * @return {number} The alternated value.
4145 */
4146function smoothstep( x, min, max ) {
4147
4148	if ( x <= min ) return 0;
4149	if ( x >= max ) return 1;
4150
4151	x = ( x - min ) / ( max - min );
4152
4153	return x * x * ( 3 - 2 * x );
4154
4155}
4156
4157/**
4158 * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations}
4159 * that has zero 1st and 2nd order derivatives at x=0 and x=1.
4160 *
4161 * @param {number} x - The value to evaluate based on its position between min and max.
4162 * @param {number} min - The min value. Any x value below min will be `0`.
4163 * @param {number} max - The max value. Any x value above max will be `1`.
4164 * @return {number} The alternated value.
4165 */
4166function smootherstep( x, min, max ) {
4167
4168	if ( x <= min ) return 0;
4169	if ( x >= max ) return 1;
4170
4171	x = ( x - min ) / ( max - min );
4172
4173	return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
4174
4175}
4176
4177/**
4178 * Returns a random integer from `<low, high>` interval.
4179 *
4180 * @param {number} low - The lower value boundary.
4181 * @param {number} high - The upper value boundary
4182 * @return {number} A random integer.
4183 */
4184function randInt( low, high ) {
4185
4186	return low + Math.floor( Math.random() * ( high - low + 1 ) );
4187
4188}
4189
4190/**
4191 * Returns a random float from `<low, high>` interval.
4192 *
4193 * @param {number} low - The lower value boundary.
4194 * @param {number} high - The upper value boundary
4195 * @return {number} A random float.
4196 */
4197function randFloat( low, high ) {
4198
4199	return low + Math.random() * ( high - low );
4200
4201}
4202
4203/**
4204 * Returns a random integer from `<-range/2, range/2>` interval.
4205 *
4206 * @param {number} range - Defines the value range.
4207 * @return {number} A random float.
4208 */
4209function randFloatSpread( range ) {
4210
4211	return range * ( 0.5 - Math.random() );
4212
4213}
4214
4215/**
4216 * Returns a deterministic pseudo-random float in the interval `[0, 1]`.
4217 *
4218 * @param {number} [s] - The integer seed.
4219 * @return {number} A random float.
4220 */
4221function seededRandom( s ) {
4222
4223	if ( s !== undefined ) _seed = s;
4224
4225	// Mulberry32 generator
4226
4227	let t = _seed += 0x6D2B79F5;
4228
4229	t = Math.imul( t ^ t >>> 15, t | 1 );
4230
4231	t ^= t + Math.imul( t ^ t >>> 7, t | 61 );
4232
4233	return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296;
4234
4235}
4236
4237/**
4238 * Converts degrees to radians.
4239 *
4240 * @param {number} degrees - A value in degrees.
4241 * @return {number} The converted value in radians.
4242 */
4243function degToRad( degrees ) {
4244
4245	return degrees * DEG2RAD;
4246
4247}
4248
4249/**
4250 * Converts radians to degrees.
4251 *
4252 * @param {number} radians - A value in radians.
4253 * @return {number} The converted value in degrees.
4254 */
4255function radToDeg( radians ) {
4256
4257	return radians * RAD2DEG;
4258
4259}
4260
4261/**
4262 * Returns `true` if the given number is a power of two.
4263 *
4264 * @param {number} value - The value to check.
4265 * @return {boolean} Whether the given number is a power of two or not.
4266 */
4267function isPowerOfTwo( value ) {
4268
4269	return ( value & ( value - 1 ) ) === 0 && value !== 0;
4270
4271}
4272
4273/**
4274 * Returns the smallest power of two that is greater than or equal to the given number.
4275 *
4276 * @param {number} value - The value to find a POT for.
4277 * @return {number} The smallest power of two that is greater than or equal to the given number.
4278 */
4279function ceilPowerOfTwo( value ) {
4280
4281	return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
4282
4283}
4284
4285/**
4286 * Returns the largest power of two that is less than or equal to the given number.
4287 *
4288 * @param {number} value - The value to find a POT for.
4289 * @return {number} The largest power of two that is less than or equal to the given number.
4290 */
4291function floorPowerOfTwo( value ) {
4292
4293	return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
4294
4295}
4296
4297/**
4298 * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles}
4299 * defined by the given angles and order.
4300 *
4301 * Rotations are applied to the axes in the order specified by order:
4302 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`.
4303 *
4304 * @param {Quaternion} q - The quaternion to set.
4305 * @param {number} a - The rotation applied to the first axis, in radians.
4306 * @param {number} b - The rotation applied to the second axis, in radians.
4307 * @param {number} c - The rotation applied to the third axis, in radians.
4308 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order.
4309 */
4310function setQuaternionFromProperEuler( q, a, b, c, order ) {
4311
4312	const cos = Math.cos;
4313	const sin = Math.sin;
4314
4315	const c2 = cos( b / 2 );
4316	const s2 = sin( b / 2 );
4317
4318	const c13 = cos( ( a + c ) / 2 );
4319	const s13 = sin( ( a + c ) / 2 );
4320
4321	const c1_3 = cos( ( a - c ) / 2 );
4322	const s1_3 = sin( ( a - c ) / 2 );
4323
4324	const c3_1 = cos( ( c - a ) / 2 );
4325	const s3_1 = sin( ( c - a ) / 2 );
4326
4327	switch ( order ) {
4328
4329		case 'XYX':
4330			q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
4331			break;
4332
4333		case 'YZY':
4334			q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
4335			break;
4336
4337		case 'ZXZ':
4338			q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
4339			break;
4340
4341		case 'XZX':
4342			q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
4343			break;
4344
4345		case 'YXY':
4346			q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
4347			break;
4348
4349		case 'ZYZ':
4350			q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
4351			break;
4352
4353		default:
4354			console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
4355
4356	}
4357
4358}
4359
4360/**
4361 * Denormalizes the given value according to the given typed array.
4362 *
4363 * @param {number} value - The value to denormalize.
4364 * @param {TypedArray} array - The typed array that defines the data type of the value.
4365 * @return {number} The denormalize (float) value in the range `[0,1]`.
4366 */
4367function denormalize( value, array ) {
4368
4369	switch ( array.constructor ) {
4370
4371		case Float32Array:
4372
4373			return value;
4374
4375		case Uint32Array:
4376
4377			return value / 4294967295.0;
4378
4379		case Uint16Array:
4380
4381			return value / 65535.0;
4382
4383		case Uint8Array:
4384
4385			return value / 255.0;
4386
4387		case Int32Array:
4388
4389			return Math.max( value / 2147483647.0, -1 );
4390
4391		case Int16Array:
4392
4393			return Math.max( value / 32767.0, -1 );
4394
4395		case Int8Array:
4396
4397			return Math.max( value / 127.0, -1 );
4398
4399		default:
4400
4401			throw new Error( 'Invalid component type.' );
4402
4403	}
4404
4405}
4406
4407/**
4408 * Normalizes the given value according to the given typed array.
4409 *
4410 * @param {number} value - The float value in the range `[0,1]` to normalize.
4411 * @param {TypedArray} array - The typed array that defines the data type of the value.
4412 * @return {number} The normalize value.
4413 */
4414function normalize( value, array ) {
4415
4416	switch ( array.constructor ) {
4417
4418		case Float32Array:
4419
4420			return value;
4421
4422		case Uint32Array:
4423
4424			return Math.round( value * 4294967295.0 );
4425
4426		case Uint16Array:
4427
4428			return Math.round( value * 65535.0 );
4429
4430		case Uint8Array:
4431
4432			return Math.round( value * 255.0 );
4433
4434		case Int32Array:
4435
4436			return Math.round( value * 2147483647.0 );
4437
4438		case Int16Array:
4439
4440			return Math.round( value * 32767.0 );
4441
4442		case Int8Array:
4443
4444			return Math.round( value * 127.0 );
4445
4446		default:
4447
4448			throw new Error( 'Invalid component type.' );
4449
4450	}
4451
4452}
4453
4454/**
4455 * @class
4456 * @classdesc A collection of math utility functions.
4457 * @hideconstructor
4458 */
4459const MathUtils = {
4460	DEG2RAD: DEG2RAD,
4461	RAD2DEG: RAD2DEG,
4462	/**
4463	 * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier}
4464	 * (universally unique identifier).
4465	 *
4466	 * @static
4467	 * @method
4468	 * @return {string} The UUID.
4469	 */
4470	generateUUID: generateUUID,
4471	/**
4472	 * Clamps the given value between min and max.
4473	 *
4474	 * @static
4475	 * @method
4476	 * @param {number} value - The value to clamp.
4477	 * @param {number} min - The min value.
4478	 * @param {number} max - The max value.
4479	 * @return {number} The clamped value.
4480	 */
4481	clamp: clamp,
4482	/**
4483	 * Computes the Euclidean modulo of the given parameters that
4484	 * is `( ( n % m ) + m ) % m`.
4485	 *
4486	 * @static
4487	 * @method
4488	 * @param {number} n - The first parameter.
4489	 * @param {number} m - The second parameter.
4490	 * @return {number} The Euclidean modulo.
4491	 */
4492	euclideanModulo: euclideanModulo,
4493	/**
4494	 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>`
4495	 * for the given value.
4496	 *
4497	 * @static
4498	 * @method
4499	 * @param {number} x - The value to be mapped.
4500	 * @param {number} a1 - Minimum value for range A.
4501	 * @param {number} a2 - Maximum value for range A.
4502	 * @param {number} b1 - Minimum value for range B.
4503	 * @param {number} b2 - Maximum value for range B.
4504	 * @return {number} The mapped value.
4505	 */
4506	mapLinear: mapLinear,
4507	/**
4508	 * Returns the percentage in the closed interval `[0, 1]` of the given value
4509	 * between the start and end point.
4510	 *
4511	 * @static
4512	 * @method
4513	 * @param {number} x - The start point
4514	 * @param {number} y - The end point.
4515	 * @param {number} value - A value between start and end.
4516	 * @return {number} The interpolation factor.
4517	 */
4518	inverseLerp: inverseLerp,
4519	/**
4520	 * Returns a value linearly interpolated from two known points based on the given interval -
4521	 * `t = 0` will return `x` and `t = 1` will return `y`.
4522	 *
4523	 * @static
4524	 * @method
4525	 * @param {number} x - The start point
4526	 * @param {number} y - The end point.
4527	 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
4528	 * @return {number} The interpolated value.
4529	 */
4530	lerp: lerp,
4531	/**
4532	 * Smoothly interpolate a number from `x` to `y` in  a spring-like manner using a delta
4533	 * time to maintain frame rate independent movement. For details, see
4534	 * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}.
4535	 *
4536	 * @static
4537	 * @method
4538	 * @param {number} x - The current point.
4539	 * @param {number} y - The target point.
4540	 * @param {number} lambda - A higher lambda value will make the movement more sudden,
4541	 * and a lower value will make the movement more gradual.
4542	 * @param {number} dt - Delta time in seconds.
4543	 * @return {number} The interpolated value.
4544	 */
4545	damp: damp,
4546	/**
4547	 * Returns a value that alternates between `0` and the given `length` parameter.
4548	 *
4549	 * @static
4550	 * @method
4551	 * @param {number} x - The value to pingpong.
4552	 * @param {number} [length=1] - The positive value the function will pingpong to.
4553	 * @return {number} The alternated value.
4554	 */
4555	pingpong: pingpong,
4556	/**
4557	 * Returns a value in the range `[0,1]` that represents the percentage that `x` has
4558	 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to
4559	 * the `min` and `max`.
4560	 *
4561	 * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details.
4562	 *
4563	 * @static
4564	 * @method
4565	 * @param {number} x - The value to evaluate based on its position between min and max.
4566	 * @param {number} min - The min value. Any x value below min will be `0`.
4567	 * @param {number} max - The max value. Any x value above max will be `1`.
4568	 * @return {number} The alternated value.
4569	 */
4570	smoothstep: smoothstep,
4571	/**
4572	 * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations}
4573	 * that has zero 1st and 2nd order derivatives at x=0 and x=1.
4574	 *
4575	 * @static
4576	 * @method
4577	 * @param {number} x - The value to evaluate based on its position between min and max.
4578	 * @param {number} min - The min value. Any x value below min will be `0`.
4579	 * @param {number} max - The max value. Any x value above max will be `1`.
4580	 * @return {number} The alternated value.
4581	 */
4582	smootherstep: smootherstep,
4583	/**
4584	 * Returns a random integer from `<low, high>` interval.
4585	 *
4586	 * @static
4587	 * @method
4588	 * @param {number} low - The lower value boundary.
4589	 * @param {number} high - The upper value boundary
4590	 * @return {number} A random integer.
4591	 */
4592	randInt: randInt,
4593	/**
4594	 * Returns a random float from `<low, high>` interval.
4595	 *
4596	 * @static
4597	 * @method
4598	 * @param {number} low - The lower value boundary.
4599	 * @param {number} high - The upper value boundary
4600	 * @return {number} A random float.
4601	 */
4602	randFloat: randFloat,
4603	/**
4604	 * Returns a random integer from `<-range/2, range/2>` interval.
4605	 *
4606	 * @static
4607	 * @method
4608	 * @param {number} range - Defines the value range.
4609	 * @return {number} A random float.
4610	 */
4611	randFloatSpread: randFloatSpread,
4612	/**
4613	 * Returns a deterministic pseudo-random float in the interval `[0, 1]`.
4614	 *
4615	 * @static
4616	 * @method
4617	 * @param {number} [s] - The integer seed.
4618	 * @return {number} A random float.
4619	 */
4620	seededRandom: seededRandom,
4621	/**
4622	 * Converts degrees to radians.
4623	 *
4624	 * @static
4625	 * @method
4626	 * @param {number} degrees - A value in degrees.
4627	 * @return {number} The converted value in radians.
4628	 */
4629	degToRad: degToRad,
4630	/**
4631	 * Converts radians to degrees.
4632	 *
4633	 * @static
4634	 * @method
4635	 * @param {number} radians - A value in radians.
4636	 * @return {number} The converted value in degrees.
4637	 */
4638	radToDeg: radToDeg,
4639	/**
4640	 * Returns `true` if the given number is a power of two.
4641	 *
4642	 * @static
4643	 * @method
4644	 * @param {number} value - The value to check.
4645	 * @return {boolean} Whether the given number is a power of two or not.
4646	 */
4647	isPowerOfTwo: isPowerOfTwo,
4648	/**
4649	 * Returns the smallest power of two that is greater than or equal to the given number.
4650	 *
4651	 * @static
4652	 * @method
4653	 * @param {number} value - The value to find a POT for.
4654	 * @return {number} The smallest power of two that is greater than or equal to the given number.
4655	 */
4656	ceilPowerOfTwo: ceilPowerOfTwo,
4657	/**
4658	 * Returns the largest power of two that is less than or equal to the given number.
4659	 *
4660	 * @static
4661	 * @method
4662	 * @param {number} value - The value to find a POT for.
4663	 * @return {number} The largest power of two that is less than or equal to the given number.
4664	 */
4665	floorPowerOfTwo: floorPowerOfTwo,
4666	/**
4667	 * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles}
vendor: 4,973 bytes, lines 4667-4895
4667
4668	 * defined by the given angles and order.
4669	 *
4670	 * Rotations are applied to the axes in the order specified by order:
4671	 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`.
4672	 *
4673	 * @static
4674	 * @method
4675	 * @param {Quaternion} q - The quaternion to set.
4676	 * @param {number} a - The rotation applied to the first axis, in radians.
4677	 * @param {number} b - The rotation applied to the second axis, in radians.
4678	 * @param {number} c - The rotation applied to the third axis, in radians.
4679	 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order.
4680	 */
4681	setQuaternionFromProperEuler: setQuaternionFromProperEuler,
4682	/**
4683	 * Normalizes the given value according to the given typed array.
4684	 *
4685	 * @static
4686	 * @method
4687	 * @param {number} value - The float value in the range `[0,1]` to normalize.
4688	 * @param {TypedArray} array - The typed array that defines the data type of the value.
4689	 * @return {number} The normalize value.
4690	 */
4691	normalize: normalize,
4692	/**
4693	 * Denormalizes the given value according to the given typed array.
4694	 *
4695	 * @static
4696	 * @method
4697	 * @param {number} value - The value to denormalize.
4698	 * @param {TypedArray} array - The typed array that defines the data type of the value.
4699	 * @return {number} The denormalize (float) value in the range `[0,1]`.
4700	 */
4701	denormalize: denormalize
4702};
4703
4704/**
4705 * Class representing a 2D vector. A 2D vector is an ordered pair of numbers
4706 * (labeled x and y), which can be used to represent a number of things, such as:
4707 *
4708 * - A point in 2D space (i.e. a position on a plane).
4709 * - A direction and length across a plane. In three.js the length will
4710 * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)`
4711 * and the direction is also measured from `(0, 0)` towards `(x, y)`.
4712 * - Any arbitrary ordered pair of numbers.
4713 *
4714 * There are other things a 2D vector can be used to represent, such as
4715 * momentum vectors, complex numbers and so on, however these are the most
4716 * common uses in three.js.
4717 *
4718 * Iterating through a vector instance will yield its components `(x, y)` in
4719 * the corresponding order.
4720 * ```js
4721 * const a = new THREE.Vector2( 0, 1 );
4722 *
4723 * //no arguments; will be initialised to (0, 0)
4724 * const b = new THREE.Vector2( );
4725 *
4726 * const d = a.distanceTo( b );
4727 * ```
4728 */
4729class Vector2 {
4730
4731	/**
4732	 * Constructs a new 2D vector.
4733	 *
4734	 * @param {number} [x=0] - The x value of this vector.
4735	 * @param {number} [y=0] - The y value of this vector.
4736	 */
4737	constructor( x = 0, y = 0 ) {
4738
4739		/**
4740		 * This flag can be used for type testing.
4741		 *
4742		 * @type {boolean}
4743		 * @readonly
4744		 * @default true
4745		 */
4746		Vector2.prototype.isVector2 = true;
4747
4748		/**
4749		 * The x value of this vector.
4750		 *
4751		 * @type {number}
4752		 */
4753		this.x = x;
4754
4755		/**
4756		 * The y value of this vector.
4757		 *
4758		 * @type {number}
4759		 */
4760		this.y = y;
4761
4762	}
4763
4764	/**
4765	 * Alias for {@link Vector2#x}.
4766	 *
4767	 * @type {number}
4768	 */
4769	get width() {
4770
4771		return this.x;
4772
4773	}
4774
4775	set width( value ) {
4776
4777		this.x = value;
4778
4779	}
4780
4781	/**
4782	 * Alias for {@link Vector2#y}.
4783	 *
4784	 * @type {number}
4785	 */
4786	get height() {
4787
4788		return this.y;
4789
4790	}
4791
4792	set height( value ) {
4793
4794		this.y = value;
4795
4796	}
4797
4798	/**
4799	 * Sets the vector components.
4800	 *
4801	 * @param {number} x - The value of the x component.
4802	 * @param {number} y - The value of the y component.
4803	 * @return {Vector2} A reference to this vector.
4804	 */
4805	set( x, y ) {
4806
4807		this.x = x;
4808		this.y = y;
4809
4810		return this;
4811
4812	}
4813
4814	/**
4815	 * Sets the vector components to the same value.
4816	 *
4817	 * @param {number} scalar - The value to set for all vector components.
4818	 * @return {Vector2} A reference to this vector.
4819	 */
4820	setScalar( scalar ) {
4821
4822		this.x = scalar;
4823		this.y = scalar;
4824
4825		return this;
4826
4827	}
4828
4829	/**
4830	 * Sets the vector's x component to the given value
4831	 *
4832	 * @param {number} x - The value to set.
4833	 * @return {Vector2} A reference to this vector.
4834	 */
4835	setX( x ) {
4836
4837		this.x = x;
4838
4839		return this;
4840
4841	}
4842
4843	/**
4844	 * Sets the vector's y component to the given value
4845	 *
4846	 * @param {number} y - The value to set.
4847	 * @return {Vector2} A reference to this vector.
4848	 */
4849	setY( y ) {
4850
4851		this.y = y;
4852
4853		return this;
4854
4855	}
4856
4857	/**
4858	 * Allows to set a vector component with an index.
4859	 *
4860	 * @param {number} index - The component index. `0` equals to x, `1` equals to y.
4861	 * @param {number} value - The value to set.
4862	 * @return {Vector2} A reference to this vector.
4863	 */
4864	setComponent( index, value ) {
4865
4866		switch ( index ) {
4867
4868			case 0: this.x = value; break;
4869			case 1: this.y = value; break;
4870			default: throw new Error( 'index is out of range: ' + index );
4871
4872		}
4873
4874		return this;
4875
4876	}
4877
4878	/**
4879	 * Returns the value of the vector component which matches the given index.
4880	 *
4881	 * @param {number} index - The component index. `0` equals to x, `1` equals to y.
4882	 * @return {number} A vector component value.
4883	 */
4884	getComponent( index ) {
4885
4886		switch ( index ) {
4887
4888			case 0: return this.x;
4889			case 1: return this.y;
4890			default: throw new Error( 'index is out of range: ' + index );
4891
4892		}
4893
4894	}
4895
vendor: 14,580 bytes, lines 4896-5568
4896	/**
4897	 * Returns a new vector with copied values from this instance.
4898	 *
4899	 * @return {Vector2} A clone of this instance.
4900	 */
4901	clone() {
4902
4903		return new this.constructor( this.x, this.y );
4904
4905	}
4906
4907	/**
4908	 * Copies the values of the given vector to this instance.
4909	 *
4910	 * @param {Vector2} v - The vector to copy.
4911	 * @return {Vector2} A reference to this vector.
4912	 */
4913	copy( v ) {
4914
4915		this.x = v.x;
4916		this.y = v.y;
4917
4918		return this;
4919
4920	}
4921
4922	/**
4923	 * Adds the given vector to this instance.
4924	 *
4925	 * @param {Vector2} v - The vector to add.
4926	 * @return {Vector2} A reference to this vector.
4927	 */
4928	add( v ) {
4929
4930		this.x += v.x;
4931		this.y += v.y;
4932
4933		return this;
4934
4935	}
4936
4937	/**
4938	 * Adds the given scalar value to all components of this instance.
4939	 *
4940	 * @param {number} s - The scalar to add.
4941	 * @return {Vector2} A reference to this vector.
4942	 */
4943	addScalar( s ) {
4944
4945		this.x += s;
4946		this.y += s;
4947
4948		return this;
4949
4950	}
4951
4952	/**
4953	 * Adds the given vectors and stores the result in this instance.
4954	 *
4955	 * @param {Vector2} a - The first vector.
4956	 * @param {Vector2} b - The second vector.
4957	 * @return {Vector2} A reference to this vector.
4958	 */
4959	addVectors( a, b ) {
4960
4961		this.x = a.x + b.x;
4962		this.y = a.y + b.y;
4963
4964		return this;
4965
4966	}
4967
4968	/**
4969	 * Adds the given vector scaled by the given factor to this instance.
4970	 *
4971	 * @param {Vector2} v - The vector.
4972	 * @param {number} s - The factor that scales `v`.
4973	 * @return {Vector2} A reference to this vector.
4974	 */
4975	addScaledVector( v, s ) {
4976
4977		this.x += v.x * s;
4978		this.y += v.y * s;
4979
4980		return this;
4981
4982	}
4983
4984	/**
4985	 * Subtracts the given vector from this instance.
4986	 *
4987	 * @param {Vector2} v - The vector to subtract.
4988	 * @return {Vector2} A reference to this vector.
4989	 */
4990	sub( v ) {
4991
4992		this.x -= v.x;
4993		this.y -= v.y;
4994
4995		return this;
4996
4997	}
4998
4999	/**
5000	 * Subtracts the given scalar value from all components of this instance.
5001	 *
5002	 * @param {number} s - The scalar to subtract.
5003	 * @return {Vector2} A reference to this vector.
5004	 */
5005	subScalar( s ) {
5006
5007		this.x -= s;
5008		this.y -= s;
5009
5010		return this;
5011
5012	}
5013
5014	/**
5015	 * Subtracts the given vectors and stores the result in this instance.
5016	 *
5017	 * @param {Vector2} a - The first vector.
5018	 * @param {Vector2} b - The second vector.
5019	 * @return {Vector2} A reference to this vector.
5020	 */
5021	subVectors( a, b ) {
5022
5023		this.x = a.x - b.x;
5024		this.y = a.y - b.y;
5025
5026		return this;
5027
5028	}
5029
5030	/**
5031	 * Multiplies the given vector with this instance.
5032	 *
5033	 * @param {Vector2} v - The vector to multiply.
5034	 * @return {Vector2} A reference to this vector.
5035	 */
5036	multiply( v ) {
5037
5038		this.x *= v.x;
5039		this.y *= v.y;
5040
5041		return this;
5042
5043	}
5044
5045	/**
5046	 * Multiplies the given scalar value with all components of this instance.
5047	 *
5048	 * @param {number} scalar - The scalar to multiply.
5049	 * @return {Vector2} A reference to this vector.
5050	 */
5051	multiplyScalar( scalar ) {
5052
5053		this.x *= scalar;
5054		this.y *= scalar;
5055
5056		return this;
5057
5058	}
5059
5060	/**
5061	 * Divides this instance by the given vector.
5062	 *
5063	 * @param {Vector2} v - The vector to divide.
5064	 * @return {Vector2} A reference to this vector.
5065	 */
5066	divide( v ) {
5067
5068		this.x /= v.x;
5069		this.y /= v.y;
5070
5071		return this;
5072
5073	}
5074
5075	/**
5076	 * Divides this vector by the given scalar.
5077	 *
5078	 * @param {number} scalar - The scalar to divide.
5079	 * @return {Vector2} A reference to this vector.
5080	 */
5081	divideScalar( scalar ) {
5082
5083		return this.multiplyScalar( 1 / scalar );
5084
5085	}
5086
5087	/**
5088	 * Multiplies this vector (with an implicit 1 as the 3rd component) by
5089	 * the given 3x3 matrix.
5090	 *
5091	 * @param {Matrix3} m - The matrix to apply.
5092	 * @return {Vector2} A reference to this vector.
5093	 */
5094	applyMatrix3( m ) {
5095
5096		const x = this.x, y = this.y;
5097		const e = m.elements;
5098
5099		this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
5100		this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
5101
5102		return this;
5103
5104	}
5105
5106	/**
5107	 * If this vector's x or y value is greater than the given vector's x or y
5108	 * value, replace that value with the corresponding min value.
5109	 *
5110	 * @param {Vector2} v - The vector.
5111	 * @return {Vector2} A reference to this vector.
5112	 */
5113	min( v ) {
5114
5115		this.x = Math.min( this.x, v.x );
5116		this.y = Math.min( this.y, v.y );
5117
5118		return this;
5119
5120	}
5121
5122	/**
5123	 * If this vector's x or y value is less than the given vector's x or y
5124	 * value, replace that value with the corresponding max value.
5125	 *
5126	 * @param {Vector2} v - The vector.
5127	 * @return {Vector2} A reference to this vector.
5128	 */
5129	max( v ) {
5130
5131		this.x = Math.max( this.x, v.x );
5132		this.y = Math.max( this.y, v.y );
5133
5134		return this;
5135
5136	}
5137
5138	/**
5139	 * If this vector's x or y value is greater than the max vector's x or y
5140	 * value, it is replaced by the corresponding value.
5141	 * If this vector's x or y value is less than the min vector's x or y value,
5142	 * it is replaced by the corresponding value.
5143	 *
5144	 * @param {Vector2} min - The minimum x and y values.
5145	 * @param {Vector2} max - The maximum x and y values in the desired range.
5146	 * @return {Vector2} A reference to this vector.
5147	 */
5148	clamp( min, max ) {
5149
5150		// assumes min < max, componentwise
5151
5152		this.x = clamp( this.x, min.x, max.x );
5153		this.y = clamp( this.y, min.y, max.y );
5154
5155		return this;
5156
5157	}
5158
5159	/**
5160	 * If this vector's x or y values are greater than the max value, they are
5161	 * replaced by the max value.
5162	 * If this vector's x or y values are less than the min value, they are
5163	 * replaced by the min value.
5164	 *
5165	 * @param {number} minVal - The minimum value the components will be clamped to.
5166	 * @param {number} maxVal - The maximum value the components will be clamped to.
5167	 * @return {Vector2} A reference to this vector.
5168	 */
5169	clampScalar( minVal, maxVal ) {
5170
5171		this.x = clamp( this.x, minVal, maxVal );
5172		this.y = clamp( this.y, minVal, maxVal );
5173
5174		return this;
5175
5176	}
5177
5178	/**
5179	 * If this vector's length is greater than the max value, it is replaced by
5180	 * the max value.
5181	 * If this vector's length is less than the min value, it is replaced by the
5182	 * min value.
5183	 *
5184	 * @param {number} min - The minimum value the vector length will be clamped to.
5185	 * @param {number} max - The maximum value the vector length will be clamped to.
5186	 * @return {Vector2} A reference to this vector.
5187	 */
5188	clampLength( min, max ) {
5189
5190		const length = this.length();
5191
5192		return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) );
5193
5194	}
5195
5196	/**
5197	 * The components of this vector are rounded down to the nearest integer value.
5198	 *
5199	 * @return {Vector2} A reference to this vector.
5200	 */
5201	floor() {
5202
5203		this.x = Math.floor( this.x );
5204		this.y = Math.floor( this.y );
5205
5206		return this;
5207
5208	}
5209
5210	/**
5211	 * The components of this vector are rounded up to the nearest integer value.
5212	 *
5213	 * @return {Vector2} A reference to this vector.
5214	 */
5215	ceil() {
5216
5217		this.x = Math.ceil( this.x );
5218		this.y = Math.ceil( this.y );
5219
5220		return this;
5221
5222	}
5223
5224	/**
5225	 * The components of this vector are rounded to the nearest integer value
5226	 *
5227	 * @return {Vector2} A reference to this vector.
5228	 */
5229	round() {
5230
5231		this.x = Math.round( this.x );
5232		this.y = Math.round( this.y );
5233
5234		return this;
5235
5236	}
5237
5238	/**
5239	 * The components of this vector are rounded towards zero (up if negative,
5240	 * down if positive) to an integer value.
5241	 *
5242	 * @return {Vector2} A reference to this vector.
5243	 */
5244	roundToZero() {
5245
5246		this.x = Math.trunc( this.x );
5247		this.y = Math.trunc( this.y );
5248
5249		return this;
5250
5251	}
5252
5253	/**
5254	 * Inverts this vector - i.e. sets x = -x and y = -y.
5255	 *
5256	 * @return {Vector2} A reference to this vector.
5257	 */
5258	negate() {
5259
5260		this.x = - this.x;
5261		this.y = - this.y;
5262
5263		return this;
5264
5265	}
5266
5267	/**
5268	 * Calculates the dot product of the given vector with this instance.
5269	 *
5270	 * @param {Vector2} v - The vector to compute the dot product with.
5271	 * @return {number} The result of the dot product.
5272	 */
5273	dot( v ) {
5274
5275		return this.x * v.x + this.y * v.y;
5276
5277	}
5278
5279	/**
5280	 * Calculates the cross product of the given vector with this instance.
5281	 *
5282	 * @param {Vector2} v - The vector to compute the cross product with.
5283	 * @return {number} The result of the cross product.
5284	 */
5285	cross( v ) {
5286
5287		return this.x * v.y - this.y * v.x;
5288
5289	}
5290
5291	/**
5292	 * Computes the square of the Euclidean length (straight-line length) from
5293	 * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should
5294	 * compare the length squared instead as it is slightly more efficient to calculate.
5295	 *
5296	 * @return {number} The square length of this vector.
5297	 */
5298	lengthSq() {
5299
5300		return this.x * this.x + this.y * this.y;
5301
5302	}
5303
5304	/**
5305	 * Computes the  Euclidean length (straight-line length) from (0, 0) to (x, y).
5306	 *
5307	 * @return {number} The length of this vector.
5308	 */
5309	length() {
5310
5311		return Math.sqrt( this.x * this.x + this.y * this.y );
5312
5313	}
5314
5315	/**
5316	 * Computes the Manhattan length of this vector.
5317	 *
5318	 * @return {number} The length of this vector.
5319	 */
5320	manhattanLength() {
5321
5322		return Math.abs( this.x ) + Math.abs( this.y );
5323
5324	}
5325
5326	/**
5327	 * Converts this vector to a unit vector - that is, sets it equal to a vector
5328	 * with the same direction as this one, but with a vector length of `1`.
5329	 *
5330	 * @return {Vector2} A reference to this vector.
5331	 */
5332	normalize() {
5333
5334		return this.divideScalar( this.length() || 1 );
5335
5336	}
5337
5338	/**
5339	 * Computes the angle in radians of this vector with respect to the positive x-axis.
5340	 *
5341	 * @return {number} The angle in radians.
5342	 */
5343	angle() {
5344
5345		const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
5346
5347		return angle;
5348
5349	}
5350
5351	/**
5352	 * Returns the angle between the given vector and this instance in radians.
5353	 *
5354	 * @param {Vector2} v - The vector to compute the angle with.
5355	 * @return {number} The angle in radians.
5356	 */
5357	angleTo( v ) {
5358
5359		const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
5360
5361		if ( denominator === 0 ) return Math.PI / 2;
5362
5363		const theta = this.dot( v ) / denominator;
5364
5365		// clamp, to handle numerical problems
5366
5367		return Math.acos( clamp( theta, -1, 1 ) );
5368
5369	}
5370
5371	/**
5372	 * Computes the distance from the given vector to this instance.
5373	 *
5374	 * @param {Vector2} v - The vector to compute the distance to.
5375	 * @return {number} The distance.
5376	 */
5377	distanceTo( v ) {
5378
5379		return Math.sqrt( this.distanceToSquared( v ) );
5380
5381	}
5382
5383	/**
5384	 * Computes the squared distance from the given vector to this instance.
5385	 * If you are just comparing the distance with another distance, you should compare
5386	 * the distance squared instead as it is slightly more efficient to calculate.
5387	 *
5388	 * @param {Vector2} v - The vector to compute the squared distance to.
5389	 * @return {number} The squared distance.
5390	 */
5391	distanceToSquared( v ) {
5392
5393		const dx = this.x - v.x, dy = this.y - v.y;
5394		return dx * dx + dy * dy;
5395
5396	}
5397
5398	/**
5399	 * Computes the Manhattan distance from the given vector to this instance.
5400	 *
5401	 * @param {Vector2} v - The vector to compute the Manhattan distance to.
5402	 * @return {number} The Manhattan distance.
5403	 */
5404	manhattanDistanceTo( v ) {
5405
5406		return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
5407
5408	}
5409
5410	/**
5411	 * Sets this vector to a vector with the same direction as this one, but
5412	 * with the specified length.
5413	 *
5414	 * @param {number} length - The new length of this vector.
5415	 * @return {Vector2} A reference to this vector.
5416	 */
5417	setLength( length ) {
5418
5419		return this.normalize().multiplyScalar( length );
5420
5421	}
5422
5423	/**
5424	 * Linearly interpolates between the given vector and this instance, where
5425	 * alpha is the percent distance along the line - alpha = 0 will be this
5426	 * vector, and alpha = 1 will be the given one.
5427	 *
5428	 * @param {Vector2} v - The vector to interpolate towards.
5429	 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
5430	 * @return {Vector2} A reference to this vector.
5431	 */
5432	lerp( v, alpha ) {
5433
5434		this.x += ( v.x - this.x ) * alpha;
5435		this.y += ( v.y - this.y ) * alpha;
5436
5437		return this;
5438
5439	}
5440
5441	/**
5442	 * Linearly interpolates between the given vectors, where alpha is the percent
5443	 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will
5444	 * be the second one. The result is stored in this instance.
5445	 *
5446	 * @param {Vector2} v1 - The first vector.
5447	 * @param {Vector2} v2 - The second vector.
5448	 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
5449	 * @return {Vector2} A reference to this vector.
5450	 */
5451	lerpVectors( v1, v2, alpha ) {
5452
5453		this.x = v1.x + ( v2.x - v1.x ) * alpha;
5454		this.y = v1.y + ( v2.y - v1.y ) * alpha;
5455
5456		return this;
5457
5458	}
5459
5460	/**
5461	 * Returns `true` if this vector is equal with the given one.
5462	 *
5463	 * @param {Vector2} v - The vector to test for equality.
5464	 * @return {boolean} Whether this vector is equal with the given one.
5465	 */
5466	equals( v ) {
5467
5468		return ( ( v.x === this.x ) && ( v.y === this.y ) );
5469
5470	}
5471
5472	/**
5473	 * Sets this vector's x value to be `array[ offset ]` and y
5474	 * value to be `array[ offset + 1 ]`.
5475	 *
5476	 * @param {Array<number>} array - An array holding the vector component values.
5477	 * @param {number} [offset=0] - The offset into the array.
5478	 * @return {Vector2} A reference to this vector.
5479	 */
5480	fromArray( array, offset = 0 ) {
5481
5482		this.x = array[ offset ];
5483		this.y = array[ offset + 1 ];
5484
5485		return this;
5486
5487	}
5488
5489	/**
5490	 * Writes the components of this vector to the given array. If no array is provided,
5491	 * the method returns a new instance.
5492	 *
5493	 * @param {Array<number>} [array=[]] - The target array holding the vector components.
5494	 * @param {number} [offset=0] - Index of the first element in the array.
5495	 * @return {Array<number>} The vector components.
5496	 */
5497	toArray( array = [], offset = 0 ) {
5498
5499		array[ offset ] = this.x;
5500		array[ offset + 1 ] = this.y;
5501
5502		return array;
5503
5504	}
5505
5506	/**
5507	 * Sets the components of this vector from the given buffer attribute.
5508	 *
5509	 * @param {BufferAttribute} attribute - The buffer attribute holding vector data.
5510	 * @param {number} index - The index into the attribute.
5511	 * @return {Vector2} A reference to this vector.
5512	 */
5513	fromBufferAttribute( attribute, index ) {
5514
5515		this.x = attribute.getX( index );
5516		this.y = attribute.getY( index );
5517
5518		return this;
5519
5520	}
5521
5522	/**
5523	 * Rotates this vector around the given center by the given angle.
5524	 *
5525	 * @param {Vector2} center - The point around which to rotate.
5526	 * @param {number} angle - The angle to rotate, in radians.
5527	 * @return {Vector2} A reference to this vector.
5528	 */
5529	rotateAround( center, angle ) {
5530
5531		const c = Math.cos( angle ), s = Math.sin( angle );
5532
5533		const x = this.x - center.x;
5534		const y = this.y - center.y;
5535
5536		this.x = x * c - y * s + center.x;
5537		this.y = x * s + y * c + center.y;
5538
5539		return this;
5540
5541	}
5542
5543	/**
5544	 * Sets each component of this vector to a pseudo-random value between `0` and
5545	 * `1`, excluding `1`.
5546	 *
5547	 * @return {Vector2} A reference to this vector.
5548	 */
5549	random() {
5550
5551		this.x = Math.random();
5552		this.y = Math.random();
5553
5554		return this;
5555
5556	}
5557
5558	*[ Symbol.iterator ]() {
5559
5560		yield this.x;
5561		yield this.y;
5562
5563	}
5564
5565}
5566
5567/**
5568 * 
5568Represents a 3x3 matrix.
5569 *
5570 * A Note on Row-Major and Column-Major Ordering:
5571 *
5572 * The constructor and {@link Matrix3#set} method take arguments in
5573 * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order}
5574 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order.
5575 * This means that calling:
5576 * ```js
5577 * const m = new THREE.Matrix();
5578 * m.set( 11, 12, 13,
5579 *        21, 22, 23,
5580 *        31, 32, 33 );
5581 * ```
5582 * will result in the elements array containing:
5583 * ```js
5584 * m.elements = [ 11, 21, 31,
5585 *                12, 22, 32,
5586 *                13, 23, 33 ];
5587 * ```
5588 * and internally all calculations are performed using column-major ordering.
5589 * However, as the actual ordering makes no difference mathematically and
5590 * most people are used to thinking about matrices in row-major order, the
5591 * three.js documentation shows matrices in row-major order. Just bear in
5592 * mind that if you are reading the source code, you'll have to take the
5593 * transpose of any matrices outlined here to make sense of the calculations.
5594 */
5595class Matrix3 {
5596
5597	/**
5598	 * Constructs a new 3x3 matrix. The arguments are supposed to be
5599	 * in row-major order. If no arguments are provided, the constructor
5600	 * initializes the matrix as an identity matrix.
5601	 *
5602	 * @param {number} [n11] - 1-1 matrix element.
5603	 * @param {number} [n12] - 1-2 matrix element.
5604	 * @param {number} [n13] - 1-3 matrix element.
5605	 * @param {number} [n21] - 2-1 matrix element.
5606	 * @param {number} [n22] - 2-2 matrix element.
5607	 * @param {number} [n23] - 2-3 matrix element.
5608	 * @param {number} [n31] - 3-1 matrix element.
5609	 * @param {number} [n32] - 3-2 matrix element.
5610	 * @param {number} [n33] - 3-3 matrix element.
5611	 */
5612	constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
5613
5614		/**
5615		 * This flag can be used for type testing.
5616		 *
5617		 * @type {boolean}
5618		 * @readonly
5619		 * @default true
5620		 */
5621		Matrix3.prototype.isMatrix3 = true;
5622
5623		/**
5624		 * A column-major list of matrix values.
5625		 *
5626		 * @type {Array<number>}
5627		 */
5628		this.elements = [
5629
5630			1, 0, 0,
5631			0, 1, 0,
5632			0, 0, 1
5633
5634		];
5635
5636		if ( n11 !== undefined ) {
5637
5638			this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );
5639
5640		}
5641
5642	}
5643
5644	/**
5645	 * Sets the elements of the matrix.The arguments are supposed to be
5646	 * in row-major order.
5647	 *
5648	 * @param {number} [n11] - 1-1 matrix element.
5649	 * @param {number} [n12] - 1-2 matrix element.
5650	 * @param {number} [n13] - 1-3 matrix element.
5651	 * @param {number} [n21] - 2-1 matrix element.
5652	 * @param {number} [n22] - 2-2 matrix element.
5653	 * @param {number} [n23] - 2-3 matrix element.
5654	 * @param {number} [n31] - 3-1 matrix element.
5655	 * @param {number} [n32] - 3-2 matrix element.
5656	 * @param {number} [n33] - 3-3 matrix element.
5657	 * @return {Matrix3} A reference to this matrix.
5658	 */
5659	set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
5660
5661		const te = this.elements;
5662
5663		te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
5664		te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
5665		te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
5666
5667		return this;
5668
5669	}
5670
vendor: 3,926 bytes, lines 5671-5847
5671	/**
5672	 * Sets this matrix to the 3x3 identity matrix.
5673	 *
5674	 * @return {Matrix3} A reference to this matrix.
5675	 */
5676	identity() {
5677
5678		this.set(
5679
5680			1, 0, 0,
5681			0, 1, 0,
5682			0, 0, 1
5683
5684		);
5685
5686		return this;
5687
5688	}
5689
5690	/**
5691	 * Copies the values of the given matrix to this instance.
5692	 *
5693	 * @param {Matrix3} m - The matrix to copy.
5694	 * @return {Matrix3} A reference to this matrix.
5695	 */
5696	copy( m ) {
5697
5698		const te = this.elements;
5699		const me = m.elements;
5700
5701		te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
5702		te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
5703		te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
5704
5705		return this;
5706
5707	}
5708
5709	/**
5710	 * Extracts the basis of this matrix into the three axis vectors provided.
5711	 *
5712	 * @param {Vector3} xAxis - The basis's x axis.
5713	 * @param {Vector3} yAxis - The basis's y axis.
5714	 * @param {Vector3} zAxis - The basis's z axis.
5715	 * @return {Matrix3} A reference to this matrix.
5716	 */
5717	extractBasis( xAxis, yAxis, zAxis ) {
5718
5719		xAxis.setFromMatrix3Column( this, 0 );
5720		yAxis.setFromMatrix3Column( this, 1 );
5721		zAxis.setFromMatrix3Column( this, 2 );
5722
5723		return this;
5724
5725	}
5726
5727	/**
5728	 * Set this matrix to the upper 3x3 matrix of the given 4x4 matrix.
5729	 *
5730	 * @param {Matrix4} m - The 4x4 matrix.
5731	 * @return {Matrix3} A reference to this matrix.
5732	 */
5733	setFromMatrix4( m ) {
5734
5735		const me = m.elements;
5736
5737		this.set(
5738
5739			me[ 0 ], me[ 4 ], me[ 8 ],
5740			me[ 1 ], me[ 5 ], me[ 9 ],
5741			me[ 2 ], me[ 6 ], me[ 10 ]
5742
5743		);
5744
5745		return this;
5746
5747	}
5748
5749	/**
5750	 * Post-multiplies this matrix by the given 3x3 matrix.
5751	 *
5752	 * @param {Matrix3} m - The matrix to multiply with.
5753	 * @return {Matrix3} A reference to this matrix.
5754	 */
5755	multiply( m ) {
5756
5757		return this.multiplyMatrices( this, m );
5758
5759	}
5760
5761	/**
5762	 * Pre-multiplies this matrix by the given 3x3 matrix.
5763	 *
5764	 * @param {Matrix3} m - The matrix to multiply with.
5765	 * @return {Matrix3} A reference to this matrix.
5766	 */
5767	premultiply( m ) {
5768
5769		return this.multiplyMatrices( m, this );
5770
5771	}
5772
5773	/**
5774	 * Multiples the given 3x3 matrices and stores the result
5775	 * in this matrix.
5776	 *
5777	 * @param {Matrix3} a - The first matrix.
5778	 * @param {Matrix3} b - The second matrix.
5779	 * @return {Matrix3} A reference to this matrix.
5780	 */
5781	multiplyMatrices( a, b ) {
5782
5783		const ae = a.elements;
5784		const be = b.elements;
5785		const te = this.elements;
5786
5787		const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
5788		const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
5789		const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
5790
5791		const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
5792		const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
5793		const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
5794
5795		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
5796		te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
5797		te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
5798
5799		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
5800		te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
5801		te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
5802
5803		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
5804		te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
5805		te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
5806
5807		return this;
5808
5809	}
5810
5811	/**
5812	 * Multiplies every component of the matrix by the given scalar.
5813	 *
5814	 * @param {number} s - The scalar.
5815	 * @return {Matrix3} A reference to this matrix.
5816	 */
5817	multiplyScalar( s ) {
5818
5819		const te = this.elements;
5820
5821		te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
5822		te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
5823		te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
5824
5825		return this;
5826
5827	}
5828
5829	/**
5830	 * Computes and returns the determinant of this matrix.
5831	 *
5832	 * @return {number} The determinant.
5833	 */
5834	determinant() {
5835
5836		const te = this.elements;
5837
5838		const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
5839			d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
5840			g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
5841
5842		return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
5843
5844	}
5845
5846	/**
5847	 * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}
vendor: 6,837 bytes, lines 5847-6178
5847.
5848	 * You can not invert with a determinant of zero. If you attempt this, the method produces
5849	 * a zero matrix instead.
5850	 *
5851	 * @return {Matrix3} A reference to this matrix.
5852	 */
5853	invert() {
5854
5855		const te = this.elements,
5856
5857			n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
5858			n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
5859			n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
5860
5861			t11 = n33 * n22 - n32 * n23,
5862			t12 = n32 * n13 - n33 * n12,
5863			t13 = n23 * n12 - n22 * n13,
5864
5865			det = n11 * t11 + n21 * t12 + n31 * t13;
5866
5867		if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
5868
5869		const detInv = 1 / det;
5870
5871		te[ 0 ] = t11 * detInv;
5872		te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
5873		te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
5874
5875		te[ 3 ] = t12 * detInv;
5876		te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
5877		te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
5878
5879		te[ 6 ] = t13 * detInv;
5880		te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
5881		te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
5882
5883		return this;
5884
5885	}
5886
5887	/**
5888	 * Transposes this matrix in place.
5889	 *
5890	 * @return {Matrix3} A reference to this matrix.
5891	 */
5892	transpose() {
5893
5894		let tmp;
5895		const m = this.elements;
5896
5897		tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
5898		tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
5899		tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
5900
5901		return this;
5902
5903	}
5904
5905	/**
5906	 * Computes the normal matrix which is the inverse transpose of the upper
5907	 * left 3x3 portion of the given 4x4 matrix.
5908	 *
5909	 * @param {Matrix4} matrix4 - The 4x4 matrix.
5910	 * @return {Matrix3} A reference to this matrix.
5911	 */
5912	getNormalMatrix( matrix4 ) {
5913
5914		return this.setFromMatrix4( matrix4 ).invert().transpose();
5915
5916	}
5917
5918	/**
5919	 * Transposes this matrix into the supplied array, and returns itself unchanged.
5920	 *
5921	 * @param {Array<number>} r - An array to store the transposed matrix elements.
5922	 * @return {Matrix3} A reference to this matrix.
5923	 */
5924	transposeIntoArray( r ) {
5925
5926		const m = this.elements;
5927
5928		r[ 0 ] = m[ 0 ];
5929		r[ 1 ] = m[ 3 ];
5930		r[ 2 ] = m[ 6 ];
5931		r[ 3 ] = m[ 1 ];
5932		r[ 4 ] = m[ 4 ];
5933		r[ 5 ] = m[ 7 ];
5934		r[ 6 ] = m[ 2 ];
5935		r[ 7 ] = m[ 5 ];
5936		r[ 8 ] = m[ 8 ];
5937
5938		return this;
5939
5940	}
5941
5942	/**
5943	 * Sets the UV transform matrix from offset, repeat, rotation, and center.
5944	 *
5945	 * @param {number} tx - Offset x.
5946	 * @param {number} ty - Offset y.
5947	 * @param {number} sx - Repeat x.
5948	 * @param {number} sy - Repeat y.
5949	 * @param {number} rotation - Rotation, in radians. Positive values rotate counterclockwise.
5950	 * @param {number} cx - Center x of rotation.
5951	 * @param {number} cy - Center y of rotation
5952	 * @return {Matrix3} A reference to this matrix.
5953	 */
5954	setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
5955
5956		const c = Math.cos( rotation );
5957		const s = Math.sin( rotation );
5958
5959		this.set(
5960			sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
5961			- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
5962			0, 0, 1
5963		);
5964
5965		return this;
5966
5967	}
5968
5969	/**
5970	 * Scales this matrix with the given scalar values.
5971	 *
5972	 * @param {number} sx - The amount to scale in the X axis.
5973	 * @param {number} sy - The amount to scale in the Y axis.
5974	 * @return {Matrix3} A reference to this matrix.
5975	 */
5976	scale( sx, sy ) {
5977
5978		this.premultiply( _m3.makeScale( sx, sy ) );
5979
5980		return this;
5981
5982	}
5983
5984	/**
5985	 * Rotates this matrix by the given angle.
5986	 *
5987	 * @param {number} theta - The rotation in radians.
5988	 * @return {Matrix3} A reference to this matrix.
5989	 */
5990	rotate( theta ) {
5991
5992		this.premultiply( _m3.makeRotation( - theta ) );
5993
5994		return this;
5995
5996	}
5997
5998	/**
5999	 * Translates this matrix by the given scalar values.
6000	 *
6001	 * @param {number} tx - The amount to translate in the X axis.
6002	 * @param {number} ty - The amount to translate in the Y axis.
6003	 * @return {Matrix3} A reference to this matrix.
6004	 */
6005	translate( tx, ty ) {
6006
6007		this.premultiply( _m3.makeTranslation( tx, ty ) );
6008
6009		return this;
6010
6011	}
6012
6013	// for 2D Transforms
6014
6015	/**
6016	 * Sets this matrix as a 2D translation transform.
6017	 *
6018	 * @param {number|Vector2} x - The amount to translate in the X axis or alternatively a translation vector.
6019	 * @param {number} y - The amount to translate in the Y axis.
6020	 * @return {Matrix3} A reference to this matrix.
6021	 */
6022	makeTranslation( x, y ) {
6023
6024		if ( x.isVector2 ) {
6025
6026			this.set(
6027
6028				1, 0, x.x,
6029				0, 1, x.y,
6030				0, 0, 1
6031
6032			);
6033
6034		} else {
6035
6036			this.set(
6037
6038				1, 0, x,
6039				0, 1, y,
6040				0, 0, 1
6041
6042			);
6043
6044		}
6045
6046		return this;
6047
6048	}
6049
6050	/**
6051	 * Sets this matrix as a 2D rotational transformation.
6052	 *
6053	 * @param {number} theta - The rotation in radians.
6054	 * @return {Matrix3} A reference to this matrix.
6055	 */
6056	makeRotation( theta ) {
6057
6058		// counterclockwise
6059
6060		const c = Math.cos( theta );
6061		const s = Math.sin( theta );
6062
6063		this.set(
6064
6065			c, - s, 0,
6066			s, c, 0,
6067			0, 0, 1
6068
6069		);
6070
6071		return this;
6072
6073	}
6074
6075	/**
6076	 * Sets this matrix as a 2D scale transform.
6077	 *
6078	 * @param {number} x - The amount to scale in the X axis.
6079	 * @param {number} y - The amount to scale in the Y axis.
6080	 * @return {Matrix3} A reference to this matrix.
6081	 */
6082	makeScale( x, y ) {
6083
6084		this.set(
6085
6086			x, 0, 0,
6087			0, y, 0,
6088			0, 0, 1
6089
6090		);
6091
6092		return this;
6093
6094	}
6095
6096	/**
6097	 * Returns `true` if this matrix is equal with the given one.
6098	 *
6099	 * @param {Matrix3} matrix - The matrix to test for equality.
6100	 * @return {boolean} Whether this matrix is equal with the given one.
6101	 */
6102	equals( matrix ) {
6103
6104		const te = this.elements;
6105		const me = matrix.elements;
6106
6107		for ( let i = 0; i < 9; i ++ ) {
6108
6109			if ( te[ i ] !== me[ i ] ) return false;
6110
6111		}
6112
6113		return true;
6114
6115	}
6116
6117	/**
6118	 * Sets the elements of the matrix from the given array.
6119	 *
6120	 * @param {Array<number>} array - The matrix elements in column-major order.
6121	 * @param {number} [offset=0] - Index of the first element in the array.
6122	 * @return {Matrix3} A reference to this matrix.
6123	 */
6124	fromArray( array, offset = 0 ) {
6125
6126		for ( let i = 0; i < 9; i ++ ) {
6127
6128			this.elements[ i ] = array[ i + offset ];
6129
6130		}
6131
6132		return this;
6133
6134	}
6135
6136	/**
6137	 * Writes the elements of this matrix to the given array. If no array is provided,
6138	 * the method returns a new instance.
6139	 *
6140	 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order.
6141	 * @param {number} [offset=0] - Index of the first element in the array.
6142	 * @return {Array<number>} The matrix elements in column-major order.
6143	 */
6144	toArray( array = [], offset = 0 ) {
6145
6146		const te = this.elements;
6147
6148		array[ offset ] = te[ 0 ];
6149		array[ offset + 1 ] = te[ 1 ];
6150		array[ offset + 2 ] = te[ 2 ];
6151
6152		array[ offset + 3 ] = te[ 3 ];
6153		array[ offset + 4 ] = te[ 4 ];
6154		array[ offset + 5 ] = te[ 5 ];
6155
6156		array[ offset + 6 ] = te[ 6 ];
6157		array[ offset + 7 ] = te[ 7 ];
6158		array[ offset + 8 ] = te[ 8 ];
6159
6160		return array;
6161
6162	}
6163
6164	/**
6165	 * Returns a matrix with copied values from this instance.
6166	 *
6167	 * @return {Matrix3} A clone of this instance.
6168	 */
6169	clone() {
6170
6171		return new this.constructor().fromArray( this.elements );
6172
6173	}
6174
6175}
6176
6177const _m3 = /*@__PURE__*/ new Matrix3();
6178
vendor: 4,073 bytes, lines 6179-6347
6179function arrayNeedsUint32( array ) {
6180
6181	// assumes larger values usually on last
6182
6183	for ( let i = array.length - 1; i >= 0; -- i ) {
6184
6185		if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
6186
6187	}
6188
6189	return false;
6190
6191}
6192
6193function createElementNS( name ) {
6194
6195	return document.createElementNS( 'http://www.w3.org/1999/xhtml', name );
6196
6197}
6198
6199const LINEAR_REC709_TO_XYZ = /*@__PURE__*/ new Matrix3().set(
6200	0.4123908, 0.3575843, 0.1804808,
6201	0.2126390, 0.7151687, 0.0721923,
6202	0.0193308, 0.1191948, 0.9505322
6203);
6204
6205const XYZ_TO_LINEAR_REC709 = /*@__PURE__*/ new Matrix3().set(
6206	3.2409699, -1.5373832, -0.4986108,
6207	-0.9692436, 1.8759675, 0.0415551,
6208	0.0556301, -0.203977, 1.0569715
6209);
6210
6211function createColorManagement() {
6212
6213	const ColorManagement = {
6214
6215		enabled: true,
6216
6217		workingColorSpace: LinearSRGBColorSpace,
6218
6219		/**
6220		 * Implementations of supported color spaces.
6221		 *
6222		 * Required:
6223		 *	- primaries: chromaticity coordinates [ rx ry gx gy bx by ]
6224		 *	- whitePoint: reference white [ x y ]
6225		 *	- transfer: transfer function (pre-defined)
6226		 *	- toXYZ: Matrix3 RGB to XYZ transform
6227		 *	- fromXYZ: Matrix3 XYZ to RGB transform
6228		 *	- luminanceCoefficients: RGB luminance coefficients
6229		 *
6230		 * Optional:
6231		 *  - outputColorSpaceConfig: { drawingBufferColorSpace: ColorSpace }
6232		 *  - workingColorSpaceConfig: { unpackColorSpace: ColorSpace }
6233		 *
6234		 * Reference:
6235		 * - https://www.russellcottrell.com/photo/matrixCalculator.htm
6236		 */
6237		spaces: {},
6238
6239		convert: function ( color, sourceColorSpace, targetColorSpace ) {
6240
6241			if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {
6242
6243				return color;
6244
6245			}
6246
6247			if ( this.spaces[ sourceColorSpace ].transfer === SRGBTransfer ) {
6248
6249				color.r = SRGBToLinear( color.r );
6250				color.g = SRGBToLinear( color.g );
6251				color.b = SRGBToLinear( color.b );
6252
6253			}
6254
6255			if ( this.spaces[ sourceColorSpace ].primaries !== this.spaces[ targetColorSpace ].primaries ) {
6256
6257				color.applyMatrix3( this.spaces[ sourceColorSpace ].toXYZ );
6258				color.applyMatrix3( this.spaces[ targetColorSpace ].fromXYZ );
6259
6260			}
6261
6262			if ( this.spaces[ targetColorSpace ].transfer === SRGBTransfer ) {
6263
6264				color.r = LinearToSRGB( color.r );
6265				color.g = LinearToSRGB( color.g );
6266				color.b = LinearToSRGB( color.b );
6267
6268			}
6269
6270			return color;
6271
6272		},
6273
6274		fromWorkingColorSpace: function ( color, targetColorSpace ) {
6275
6276			return this.convert( color, this.workingColorSpace, targetColorSpace );
6277
6278		},
6279
6280		toWorkingColorSpace: function ( color, sourceColorSpace ) {
6281
6282			return this.convert( color, sourceColorSpace, this.workingColorSpace );
6283
6284		},
6285
6286		getPrimaries: function ( colorSpace ) {
6287
6288			return this.spaces[ colorSpace ].primaries;
6289
6290		},
6291
6292		getTransfer: function ( colorSpace ) {
6293
6294			if ( colorSpace === NoColorSpace ) return LinearTransfer;
6295
6296			return this.spaces[ colorSpace ].transfer;
6297
6298		},
6299
6300		getLuminanceCoefficients: function ( target, colorSpace = this.workingColorSpace ) {
6301
6302			return target.fromArray( this.spaces[ colorSpace ].luminanceCoefficients );
6303
6304		},
6305
6306		define: function ( colorSpaces ) {
6307
6308			Object.assign( this.spaces, colorSpaces );
6309
6310		},
6311
6312		// Internal APIs
6313
6314		_getMatrix: function ( targetMatrix, sourceColorSpace, targetColorSpace ) {
6315
6316			return targetMatrix
6317				.copy( this.spaces[ sourceColorSpace ].toXYZ )
6318				.multiply( this.spaces[ targetColorSpace ].fromXYZ );
6319
6320		},
6321
6322		_getDrawingBufferColorSpace: function ( colorSpace ) {
6323
6324			return this.spaces[ colorSpace ].outputColorSpaceConfig.drawingBufferColorSpace;
6325
6326		},
6327
6328		_getUnpackColorSpace: function ( colorSpace = this.workingColorSpace ) {
6329
6330			return this.spaces[ colorSpace ].workingColorSpaceConfig.unpackColorSpace;
6331
6332		}
6333
6334	};
6335
6336	/******************************************************************************
6337	 * sRGB definitions
6338	 */
6339
6340	const REC709_PRIMARIES = [ 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 ];
6341	const REC709_LUMINANCE_COEFFICIENTS = [ 0.2126, 0.7152, 0.0722 ];
6342	const D65 = [ 0.3127, 0.3290 ];
6343
6344	ColorManagement.define( {
6345
6346		[ LinearSRGBColorSpace ]: {
6347			primaries: REC709_PRIMARIES,
vendor: 5,188 bytes, lines 6348-6591
6348			whitePoint: D65,
6349			transfer: LinearTransfer,
6350			toXYZ: LINEAR_REC709_TO_XYZ,
6351			fromXYZ: XYZ_TO_LINEAR_REC709,
6352			luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS,
6353			workingColorSpaceConfig: { unpackColorSpace: SRGBColorSpace },
6354			outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace }
6355		},
6356
6357		[ SRGBColorSpace ]: {
6358			primaries: REC709_PRIMARIES,
6359			whitePoint: D65,
6360			transfer: SRGBTransfer,
6361			toXYZ: LINEAR_REC709_TO_XYZ,
6362			fromXYZ: XYZ_TO_LINEAR_REC709,
6363			luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS,
6364			outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace }
6365		},
6366
6367	} );
6368
6369	return ColorManagement;
6370
6371}
6372
6373const ColorManagement = /*@__PURE__*/ createColorManagement();
6374
6375function SRGBToLinear( c ) {
6376
6377	return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
6378
6379}
6380
6381function LinearToSRGB( c ) {
6382
6383	return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
6384
6385}
6386
6387let _canvas;
6388
6389/**
6390 * A class containing utility functions for images.
6391 *
6392 * @hideconstructor
6393 */
6394class ImageUtils {
6395
6396	/**
6397	 * Returns a data URI containing a representation of the given image.
6398	 *
6399	 * @param {(HTMLImageElement|HTMLCanvasElement)} image - The image object.
6400	 * @param {string} [type='image/png'] - Indicates the image format.
6401	 * @return {string} The data URI.
6402	 */
6403	static getDataURL( image, type = 'image/png' ) {
6404
6405		if ( /^data:/i.test( image.src ) ) {
6406
6407			return image.src;
6408
6409		}
6410
6411		if ( typeof HTMLCanvasElement === 'undefined' ) {
6412
6413			return image.src;
6414
6415		}
6416
6417		let canvas;
6418
6419		if ( image instanceof HTMLCanvasElement ) {
6420
6421			canvas = image;
6422
6423		} else {
6424
6425			if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );
6426
6427			_canvas.width = image.width;
6428			_canvas.height = image.height;
6429
6430			const context = _canvas.getContext( '2d' );
6431
6432			if ( image instanceof ImageData ) {
6433
6434				context.putImageData( image, 0, 0 );
6435
6436			} else {
6437
6438				context.drawImage( image, 0, 0, image.width, image.height );
6439
6440			}
6441
6442			canvas = _canvas;
6443
6444		}
6445
6446		return canvas.toDataURL( type );
6447
6448	}
6449
6450	/**
6451	 * Converts the given sRGB image data to linear color space.
6452	 *
6453	 * @param {(HTMLImageElement|HTMLCanvasElement|ImageBitmap|Object)} image - The image object.
6454	 * @return {HTMLCanvasElement|Object} The converted image.
6455	 */
6456	static sRGBToLinear( image ) {
6457
6458		if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
6459			( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
6460			( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
6461
6462			const canvas = createElementNS( 'canvas' );
6463
6464			canvas.width = image.width;
6465			canvas.height = image.height;
6466
6467			const context = canvas.getContext( '2d' );
6468			context.drawImage( image, 0, 0, image.width, image.height );
6469
6470			const imageData = context.getImageData( 0, 0, image.width, image.height );
6471			const data = imageData.data;
6472
6473			for ( let i = 0; i < data.length; i ++ ) {
6474
6475				data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;
6476
6477			}
6478
6479			context.putImageData( imageData, 0, 0 );
6480
6481			return canvas;
6482
6483		} else if ( image.data ) {
6484
6485			const data = image.data.slice( 0 );
6486
6487			for ( let i = 0; i < data.length; i ++ ) {
6488
6489				if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {
6490
6491					data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );
6492
6493				} else {
6494
6495					// assuming float
6496
6497					data[ i ] = SRGBToLinear( data[ i ] );
6498
6499				}
6500
6501			}
6502
6503			return {
6504				data: data,
6505				width: image.width,
6506				height: image.height
6507			};
6508
6509		} else {
6510
6511			console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );
6512			return image;
6513
6514		}
6515
6516	}
6517
6518}
6519
6520let _sourceId = 0;
6521
6522/**
6523 * Represents the data source of a texture.
6524 *
6525 * The main purpose of this class is to decouple the data definition from the texture
6526 * definition so the same data can be used with multiple texture instances.
6527 */
6528class Source {
6529
6530	/**
6531	 * Constructs a new video texture.
6532	 *
6533	 * @param {any} [data=null] - The data definition of a texture.
6534	 */
6535	constructor( data = null ) {
6536
6537		/**
6538		 * This flag can be used for type testing.
6539		 *
6540		 * @type {boolean}
6541		 * @readonly
6542		 * @default true
6543		 */
6544		this.isSource = true;
6545
6546		/**
6547		 * The ID of the source.
6548		 *
6549		 * @name Source#id
6550		 * @type {number}
6551		 * @readonly
6552		 */
6553		Object.defineProperty( this, 'id', { value: _sourceId ++ } );
6554
6555		/**
6556		 * The UUID of the source.
6557		 *
6558		 * @type {string}
6559		 * @readonly
6560		 */
6561		this.uuid = generateUUID();
6562
6563		/**
6564		 * The data definition of a texture.
6565		 *
6566		 * @type {any}
6567		 */
6568		this.data = data;
6569
6570		/**
6571		 * This property is only relevant when {@link Source#needsUpdate} is set to `true` and
6572		 * provides more control on how texture data should be processed. When `dataReady` is set
6573		 * to `false`, the engine performs the memory allocation (if necessary) but does not transfer
6574		 * the data into the GPU memory.
6575		 *
6576		 * @type {boolean}
6577		 * @default true
6578		 */
6579		this.dataReady = true;
6580
6581		/**
6582		 * This starts at `0` and counts how many times {@link Source#needsUpdate} is set to `true`.
6583		 *
6584		 * @type {number}
6585		 * @readonly
6586		 * @default 0
6587		 */
6588		this.version = 0;
6589
6590	}
6591
vendor: 5,044 bytes, lines 6592-6811
6592	/**
6593	 * When the property is set to `true`, the engine allocates the memory
6594	 * for the texture (if necessary) and triggers the actual texture upload
6595	 * to the GPU next time the source is used.
6596	 *
6597	 * @type {boolean}
6598	 * @default false
6599	 * @param {boolean} value
6600	 */
6601	set needsUpdate( value ) {
6602
6603		if ( value === true ) this.version ++;
6604
6605	}
6606
6607	/**
6608	 * Serializes the source into JSON.
6609	 *
6610	 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
6611	 * @return {Object} A JSON object representing the serialized source.
6612	 * @see {@link ObjectLoader#parse}
6613	 */
6614	toJSON( meta ) {
6615
6616		const isRootObject = ( meta === undefined || typeof meta === 'string' );
6617
6618		if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) {
6619
6620			return meta.images[ this.uuid ];
6621
6622		}
6623
6624		const output = {
6625			uuid: this.uuid,
6626			url: ''
6627		};
6628
6629		const data = this.data;
6630
6631		if ( data !== null ) {
6632
6633			let url;
6634
6635			if ( Array.isArray( data ) ) {
6636
6637				// cube texture
6638
6639				url = [];
6640
6641				for ( let i = 0, l = data.length; i < l; i ++ ) {
6642
6643					if ( data[ i ].isDataTexture ) {
6644
6645						url.push( serializeImage( data[ i ].image ) );
6646
6647					} else {
6648
6649						url.push( serializeImage( data[ i ] ) );
6650
6651					}
6652
6653				}
6654
6655			} else {
6656
6657				// texture
6658
6659				url = serializeImage( data );
6660
6661			}
6662
6663			output.url = url;
6664
6665		}
6666
6667		if ( ! isRootObject ) {
6668
6669			meta.images[ this.uuid ] = output;
6670
6671		}
6672
6673		return output;
6674
6675	}
6676
6677}
6678
6679function serializeImage( image ) {
6680
6681	if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
6682		( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
6683		( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
6684
6685		// default images
6686
6687		return ImageUtils.getDataURL( image );
6688
6689	} else {
6690
6691		if ( image.data ) {
6692
6693			// images of DataTexture
6694
6695			return {
6696				data: Array.from( image.data ),
6697				width: image.width,
6698				height: image.height,
6699				type: image.data.constructor.name
6700			};
6701
6702		} else {
6703
6704			console.warn( 'THREE.Texture: Unable to serialize Texture.' );
6705			return {};
6706
6707		}
6708
6709	}
6710
6711}
6712
6713let _textureId = 0;
6714
6715/**
6716 * Base class for all textures.
6717 *
6718 * Note: After the initial use of a texture, its dimensions, format, and type
6719 * cannot be changed. Instead, call {@link Texture#dispose} on the texture and instantiate a new one.
6720 *
6721 * @augments EventDispatcher
6722 */
6723class Texture extends EventDispatcher {
6724
6725	/**
6726	 * Constructs a new texture.
6727	 *
6728	 * @param {?Object} [image=Texture.DEFAULT_IMAGE] - The image holding the texture data.
6729	 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping.
6730	 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value.
6731	 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value.
6732	 * @param {number} [magFilter=LinearFilter] - The mag filter value.
6733	 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value.
6734	 * @param {number} [format=RGBAFormat] - The texture format.
6735	 * @param {number} [type=UnsignedByteType] - The texture type.
6736	 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value.
6737	 * @param {string} [colorSpace=NoColorSpace] - The color space.
6738	 */
6739	constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) {
6740
6741		super();
6742
6743		/**
6744		 * This flag can be used for type testing.
6745		 *
6746		 * @type {boolean}
6747		 * @readonly
6748		 * @default true
6749		 */
6750		this.isTexture = true;
6751
6752		/**
6753		 * The ID of the texture.
6754		 *
6755		 * @name Texture#id
6756		 * @type {number}
6757		 * @readonly
6758		 */
6759		Object.defineProperty( this, 'id', { value: _textureId ++ } );
6760
6761		/**
6762		 * The UUID of the material.
6763		 *
6764		 * @type {string}
6765		 * @readonly
6766		 */
6767		this.uuid = generateUUID();
6768
6769		/**
6770		 * The name of the material.
6771		 *
6772		 * @type {string}
6773		 */
6774		this.name = '';
6775
6776		/**
6777		 * The data definition of a texture. A reference to the data source can be
6778		 * shared across textures. This is often useful in context of spritesheets
6779		 * where multiple textures render the same data but with different texture
6780		 * transformations.
6781		 *
6782		 * @type {Source}
6783		 */
6784		this.source = new Source( image );
6785
6786		/**
6787		 * An array holding user-defined mipmaps.
6788		 *
6789		 * @type {Array<Object>}
6790		 */
6791		this.mipmaps = [];
6792
6793		/**
6794		 * How the texture is applied to the object. The value `UVMapping`
6795		 * is the default, where texture or uv coordinates are used to apply the map.
6796		 *
6797		 * @type {(UVMapping|CubeReflectionMapping|CubeRefractionMapping|EquirectangularReflectionMapping|EquirectangularRefractionMapping|CubeUVReflectionMapping)}
6798		 * @default UVMapping
6799		*/
6800		this.mapping = mapping;
6801
6802		/**
6803		 * Lets you select the uv attribute to map the texture to. `0` for `uv`,
6804		 * `1` for `uv1`, `2` for `uv2` and `3` for `uv3`.
6805		 *
6806		 * @type {number}
6807		 * @default 0
6808		 */
6809		this.channel = 0;
6810
6811		/**
6812		 * This defines how the texture is wrapped horizontally and corresponds to
6813		 * *U* in UV mapping.
6814		 *
6815		 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)}
6816		 * @default ClampToEdgeWrapping
6817		 */
6818		this.wrapS = wrapS;
6819
6820		/**
6821		 * This defines how the texture is wrapped horizontally and corresponds to
6822		 * *V* in UV mapping.
6823		 *
6824		 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)}
6825		 * @default ClampToEdgeWrapping
6826		 */
6827		this.wrapT = wrapT;
6828
6829		/**
6830		 * How the texture is sampled when a texel covers more than one pixel.
6831		 *
6832		 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)}
6833		 * @default LinearFilter
6834		 */
6835		this.magFilter = magFilter;
6836
6837		/**
6838		 * How the texture is sampled when a texel covers less than one pixel.
6839		 *
6840		 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)}
6841		 * @default LinearMipmapLinearFilter
6842		 */
6843		this.minFilter = minFilter;
6844
6845		/**
6846		 * The number of samples taken along the axis through the pixel that has the
6847		 * highest density of texels. By default, this value is `1`. A higher value
6848		 * gives a less blurry result than a basic mipmap, at the cost of more
6849		 * texture samples being used.
6850		 *
6851		 * @type {number}
6852		 * @default 0
6853		 */
6854		this.anisotropy = anisotropy;
6855
6856		/**
6857		 * The format of the texture.
6858		 *
6859		 * @type {number}
6860		 * @default RGBAFormat
6861		 */
6862		this.format = format;
6863
6864		/**
6865		 * The default internal format is derived from {@link Texture#format} and {@link Texture#type} and
6866		 * defines how the texture data is going to be stored on the GPU.
6867		 *
6868		 * This property allows to overwrite the default format.
6869		 *
6870		 * @type {?string}
6871		 * @default null
6872		 */
6873		this.internalFormat = null;
6874
6875		/**
6876		 * The data type of the texture.
6877		 *
6878		 * @type {number}
6879		 * @default UnsignedByteType
6880		 */
6881		this.type = type;
6882
6883		/**
6884		 * How much a single repetition of the texture is offset from the beginning,
6885		 * in each direction U and V. Typical range is `0.0` to `1.0`.
6886		 *
6887		 * @type {Vector2}
6888		 * @default (0,0)
6889		 */
6890		this.offset = new Vector2( 0, 0 );
6891
6892		/**
6893		 * How many times the texture is repeated across the surface, in each
6894		 * direction U and V. If repeat is set greater than `1` in either direction,
6895		 * the corresponding wrap parameter should also be set to `RepeatWrapping`
6896		 * or `MirroredRepeatWrapping` to achieve the desired tiling effect.
6897		 *
6898		 * @type {Vector2}
6899		 * @default (1,1)
6900		 */
6901		this.repeat = new Vector2( 1, 1 );
6902
6903		/**
6904		 * The point around which rotation occurs. A value of `(0.5, 0.5)` corresponds
6905		 * to the center of the texture. Default is `(0, 0)`, the lower left.
6906		 *
6907		 * @type {Vector2}
6908		 * @default (0,0)
6909		 */
6910		this.center = new Vector2( 0, 0 );
6911
6912		/**
6913		 * How much the texture is rotated around the center point, in radians.
6914		 * Positive values are counter-clockwise.
6915		 *
6916		 * @type {number}
6917		 * @default 0
6918		 */
6919		this.rotation = 0;
6920
6921		/**
6922		 * Whether to update the texture's uv-transformation {@link Texture#matrix}
6923		 * from the properties {@link Texture#offset}, {@link Texture#repeat},
6924		 * {@link Texture#rotation}, and {@link Texture#center}.
6925		 *
6926		 * Set this to `false` if you are specifying the uv-transform matrix directly.
6927		 *
6928		 * @type {boolean}
6929		 * @default true
6930		 */
6931		this.matrixAutoUpdate = true;
6932
6933		/**
6934		 * The uv-transformation matrix of the texture.
6935		 *
6936		 * @type {Matrix3}
6937		 */
6938		this.matrix = new Matrix3();
6939
6940		/**
6941		 * Whether to generate mipmaps (if possible) for a texture.
6942		 *
6943		 * Set this to `false` if you are creating mipmaps manually.
6944		 *
6945		 * @type {boolean}
6946		 * @default true
6947		 */
6948		this.generateMipmaps = true;
6949
6950		/**
6951		 * If set to `true`, the alpha channel, if present, is multiplied into the
6952		 * color channels when the texture is uploaded to the GPU.
6953		 *
6954		 * Note that this property has no effect when using `ImageBitmap`. You need to
6955		 * configure premultiply alpha on bitmap creation instead.
6956		 *
6957		 * @type {boolean}
6958		 * @default false
6959		 */
6960		this.premultiplyAlpha = false;
6961
6962		/**
6963		 * If set to `true`, the texture is flipped along the vertical axis when
6964		 * uploaded to the GPU.
6965		 *
6966		 * Note that this property has no effect when using `ImageBitmap`. You need to
6967		 * configure the flip on bitmap creation instead.
6968		 *
6969		 * @type {boolean}
6970		 * @default true
6971		 */
6972		this.flipY = true;
6973
6974		/**
6975		 * Specifies the alignment requirements for the start of each pixel row in memory.
6976		 * The allowable values are `1` (byte-alignment), `2` (rows aligned to even-numbered bytes),
6977		 * `4` (word-alignment), and `8` (rows start on double-word boundaries).
6978		 *
6979		 * @type {number}
6980		 * @default 4
6981		 */
6982		this.unpackAlignment = 4;	// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
6983
6984		/**
6985		 * Textures containing color data should be annotated with `SRGBColorSpace` or `LinearSRGBColorSpace`.
6986		 *
6987		 * @type {string}
6988		 * @default NoColorSpace
6989		 */
6990		this.colorSpace = colorSpace;
6991
6992		/**
6993		 * An object that can be used to store custom data about the texture. It
6994		 * should not hold references to functions as these will not be cloned.
6995		 *
6996		 * @type {Object}
6997		 */
6998		this.userData = {};
6999
7000		/**
7001		 * This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`.
7002		 *
7003		 * @type {number}
7004		 * @readonly
7005		 * @default 0
7006		 */
7007		this.version = 0;
7008
7009		/**
7010		 * A callback function, called when the texture is updated (e.g., when
7011		 * {@link Texture#needsUpdate} has been set to true and then the texture is used).
7012		 *
7013		 * @type {?Function}
7014		 * @default null
7015		 */
7016		this.onUpdate = null;
7017
7018		/**
7019		 * An optional back reference to the textures render target.
7020		 *
7021		 * @type {?(RenderTarget|WebGLRenderTarget)}
7022		 * @default null
7023		 */
7024		this.renderTarget = null;
7025
7026		/**
7027		 * Indicates whether a texture belongs to a render target or not.
7028		 *
7029		 * @type {boolean}
7030		 * @readonly
7031		 * @default false
7032		 */
7033		this.isRenderTargetTexture = false;
7034
7035		/**
7036		 * Indicates whether this texture should be processed by `PMREMGenerator` or not
7037		 * (only relevant for render target textures).
7038		 *
7039		 * @type {number}
7040		 * @readonly
7041		 * @default 0
7042		 */
7043		this.pmremVersion = 0;
7044
7045	}
7046
7047	/**
7048	 * The image object holding the texture data.
7049	 *
7050	 * @type {?Object}
7051	 */
7052	get image() {
7053
7054		return this.source.data;
7055
7056	}
7057
7058	set image( value = null ) {
7059
7060		this.source.data = value;
7061
7062	}
7063
7064	/**
7065	 * Updates the texture transformation matrix from the from the properties {@link Texture#offset},
7066	 * {@link Texture#repeat}, {@link Texture#rotation}, and {@link Texture#center}.
7067	 */
7068	updateMatrix() {
7069
7070		this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
7071
7072	}
7073
7074	/**
7075	 * Returns a new texture with copied values from this instance.
7076	 *
7077	 * @return {Texture} A clone of this instance.
7078	 */
7079	clone() {
7080
7081		return new this.constructor().copy( this );
7082
7083	}
7084
7085	/**
7086	 * Copies the values of the given texture to this instance.
7087	 *
7088	 * @param {Texture} source - The texture to copy.
7089	 * @return {Texture} A reference to this instance.
7090	 */
7091	copy( source ) {
7092
7093		this.name = source.name;
7094
7095		this.source = source.source;
7096		this.mipmaps = source.mipmaps.slice( 0 );
7097
7098		this.mapping = source.mapping;
7099		this.channel = source.channel;
7100
7101		this.wrapS = source.wrapS;
7102		this.wrapT = source.wrapT;
7103
7104		this.magFilter = source.magFilter;
7105		this.minFilter = source.minFilter;
7106
7107		this.anisotropy = source.anisotropy;
7108
7109		this.format = source.format;
7110		this.internalFormat = source.internalFormat;
7111		this.type = source.type;
7112
7113		this.offset.copy( source.offset );
7114		this.repeat.copy( source.repeat );
7115		this.center.copy( source.center );
7116		this.rotation = source.rotation;
7117
7118		this.matrixAutoUpdate = source.matrixAutoUpdate;
7119		this.matrix.copy( source.matrix );
7120
7121		this.generateMipmaps = source.generateMipmaps;
7122		this.premultiplyAlpha = source.premultiplyAlpha;
7123		this.flipY = source.flipY;
7124		this.unpackAlignment = source.unpackAlignment;
7125		this.colorSpace = source.colorSpace;
7126
7127		this.renderTarget = source.renderTarget;
7128		this.isRenderTargetTexture = source.isRenderTargetTexture;
7129
7130		this.userData = JSON.parse( JSON.stringify( source.userData ) );
7131
7132		this.needsUpdate = true;
7133
7134		return this;
7135
7136	}
7137
vendor: 4,108 bytes, lines 7138-7376
7138	/**
7139	 * Serializes the texture into JSON.
7140	 *
7141	 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
7142	 * @return {Object} A JSON object representing the serialized texture.
7143	 * @see {@link ObjectLoader#parse}
7144	 */
7145	toJSON( meta ) {
7146
7147		const isRootObject = ( meta === undefined || typeof meta === 'string' );
7148
7149		if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
7150
7151			return meta.textures[ this.uuid ];
7152
7153		}
7154
7155		const output = {
7156
7157			metadata: {
7158				version: 4.6,
7159				type: 'Texture',
7160				generator: 'Texture.toJSON'
7161			},
7162
7163			uuid: this.uuid,
7164			name: this.name,
7165
7166			image: this.source.toJSON( meta ).uuid,
7167
7168			mapping: this.mapping,
7169			channel: this.channel,
7170
7171			repeat: [ this.repeat.x, this.repeat.y ],
7172			offset: [ this.offset.x, this.offset.y ],
7173			center: [ this.center.x, this.center.y ],
7174			rotation: this.rotation,
7175
7176			wrap: [ this.wrapS, this.wrapT ],
7177
7178			format: this.format,
7179			internalFormat: this.internalFormat,
7180			type: this.type,
7181			colorSpace: this.colorSpace,
7182
7183			minFilter: this.minFilter,
7184			magFilter: this.magFilter,
7185			anisotropy: this.anisotropy,
7186
7187			flipY: this.flipY,
7188
7189			generateMipmaps: this.generateMipmaps,
7190			premultiplyAlpha: this.premultiplyAlpha,
7191			unpackAlignment: this.unpackAlignment
7192
7193		};
7194
7195		if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;
7196
7197		if ( ! isRootObject ) {
7198
7199			meta.textures[ this.uuid ] = output;
7200
7201		}
7202
7203		return output;
7204
7205	}
7206
7207	/**
7208	 * Frees the GPU-related resources allocated by this instance. Call this
7209	 * method whenever this instance is no longer used in your app.
7210	 *
7211	 * @fires Texture#dispose
7212	 */
7213	dispose() {
7214
7215		/**
7216		 * Fires when the texture has been disposed of.
7217		 *
7218		 * @event Texture#dispose
7219		 * @type {Object}
7220		 */
7221		this.dispatchEvent( { type: 'dispose' } );
7222
7223	}
7224
7225	/**
7226	 * Transforms the given uv vector with the textures uv transformation matrix.
7227	 *
7228	 * @param {Vector2} uv - The uv vector.
7229	 * @return {Vector2} The transformed uv vector.
7230	 */
7231	transformUv( uv ) {
7232
7233		if ( this.mapping !== UVMapping ) return uv;
7234
7235		uv.applyMatrix3( this.matrix );
7236
7237		if ( uv.x < 0 || uv.x > 1 ) {
7238
7239			switch ( this.wrapS ) {
7240
7241				case RepeatWrapping:
7242
7243					uv.x = uv.x - Math.floor( uv.x );
7244					break;
7245
7246				case ClampToEdgeWrapping:
7247
7248					uv.x = uv.x < 0 ? 0 : 1;
7249					break;
7250
7251				case MirroredRepeatWrapping:
7252
7253					if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
7254
7255						uv.x = Math.ceil( uv.x ) - uv.x;
7256
7257					} else {
7258
7259						uv.x = uv.x - Math.floor( uv.x );
7260
7261					}
7262
7263					break;
7264
7265			}
7266
7267		}
7268
7269		if ( uv.y < 0 || uv.y > 1 ) {
7270
7271			switch ( this.wrapT ) {
7272
7273				case RepeatWrapping:
7274
7275					uv.y = uv.y - Math.floor( uv.y );
7276					break;
7277
7278				case ClampToEdgeWrapping:
7279
7280					uv.y = uv.y < 0 ? 0 : 1;
7281					break;
7282
7283				case MirroredRepeatWrapping:
7284
7285					if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
7286
7287						uv.y = Math.ceil( uv.y ) - uv.y;
7288
7289					} else {
7290
7291						uv.y = uv.y - Math.floor( uv.y );
7292
7293					}
7294
7295					break;
7296
7297			}
7298
7299		}
7300
7301		if ( this.flipY ) {
7302
7303			uv.y = 1 - uv.y;
7304
7305		}
7306
7307		return uv;
7308
7309	}
7310
7311	/**
7312	 * Setting this property to `true` indicates the engine the texture
7313	 * must be updated in the next render. This triggers a texture upload
7314	 * to the GPU and ensures correct texture parameter configuration.
7315	 *
7316	 * @type {boolean}
7317	 * @default false
7318	 * @param {boolean} value
7319	 */
7320	set needsUpdate( value ) {
7321
7322		if ( value === true ) {
7323
7324			this.version ++;
7325			this.source.needsUpdate = true;
7326
7327		}
7328
7329	}
7330
7331	/**
7332	 * Setting this property to `true` indicates the engine the PMREM
7333	 * must be regenerated.
7334	 *
7335	 * @type {boolean}
7336	 * @default false
7337	 * @param {boolean} value
7338	 */
7339	set needsPMREMUpdate( value ) {
7340
7341		if ( value === true ) {
7342
7343			this.pmremVersion ++;
7344
7345		}
7346
7347	}
7348
7349}
7350
7351/**
7352 * The default image for all textures.
7353 *
7354 * @static
7355 * @type {?Image}
7356 * @default null
7357 */
7358Texture.DEFAULT_IMAGE = null;
7359
7360/**
7361 * The default mapping for all textures.
7362 *
7363 * @static
7364 * @type {number}
7365 * @default UVMapping
7366 */
7367Texture.DEFAULT_MAPPING = UVMapping;
7368
7369/**
7370 * The default anisotropy value for all textures.
7371 *
7372 * @static
7373 * @type {number}
7374 * @default 1
7375 */
7376Texture
vendor: 14,502 bytes, lines 7376-8100
7376.DEFAULT_ANISOTROPY = 1;
7377
7378/**
7379 * Class representing a 4D vector. A 4D vector is an ordered quadruplet of numbers
7380 * (labeled x, y, z and w), which can be used to represent a number of things, such as:
7381 *
7382 * - A point in 4D space.
7383 * - A direction and length in 4D space. In three.js the length will
7384 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0, 0)` to `(x, y, z, w)`
7385 * and the direction is also measured from `(0, 0, 0, 0)` towards `(x, y, z, w)`.
7386 * - Any arbitrary ordered quadruplet of numbers.
7387 *
7388 * There are other things a 4D vector can be used to represent, however these
7389 * are the most common uses in *three.js*.
7390 *
7391 * Iterating through a vector instance will yield its components `(x, y, z, w)` in
7392 * the corresponding order.
7393 * ```js
7394 * const a = new THREE.Vector4( 0, 1, 0, 0 );
7395 *
7396 * //no arguments; will be initialised to (0, 0, 0, 1)
7397 * const b = new THREE.Vector4( );
7398 *
7399 * const d = a.dot( b );
7400 * ```
7401 */
7402class Vector4 {
7403
7404	/**
7405	 * Constructs a new 4D vector.
7406	 *
7407	 * @param {number} [x=0] - The x value of this vector.
7408	 * @param {number} [y=0] - The y value of this vector.
7409	 * @param {number} [z=0] - The z value of this vector.
7410	 * @param {number} [w=1] - The w value of this vector.
7411	 */
7412	constructor( x = 0, y = 0, z = 0, w = 1 ) {
7413
7414		/**
7415		 * This flag can be used for type testing.
7416		 *
7417		 * @type {boolean}
7418		 * @readonly
7419		 * @default true
7420		 */
7421		Vector4.prototype.isVector4 = true;
7422
7423		/**
7424		 * The x value of this vector.
7425		 *
7426		 * @type {number}
7427		 */
7428		this.x = x;
7429
7430		/**
7431		 * The y value of this vector.
7432		 *
7433		 * @type {number}
7434		 */
7435		this.y = y;
7436
7437		/**
7438		 * The z value of this vector.
7439		 *
7440		 * @type {number}
7441		 */
7442		this.z = z;
7443
7444		/**
7445		 * The w value of this vector.
7446		 *
7447		 * @type {number}
7448		 */
7449		this.w = w;
7450
7451	}
7452
7453	/**
7454	 * Alias for {@link Vector4#z}.
7455	 *
7456	 * @type {number}
7457	 */
7458	get width() {
7459
7460		return this.z;
7461
7462	}
7463
7464	set width( value ) {
7465
7466		this.z = value;
7467
7468	}
7469
7470	/**
7471	 * Alias for {@link Vector4#w}.
7472	 *
7473	 * @type {number}
7474	 */
7475	get height() {
7476
7477		return this.w;
7478
7479	}
7480
7481	set height( value ) {
7482
7483		this.w = value;
7484
7485	}
7486
7487	/**
7488	 * Sets the vector components.
7489	 *
7490	 * @param {number} x - The value of the x component.
7491	 * @param {number} y - The value of the y component.
7492	 * @param {number} z - The value of the z component.
7493	 * @param {number} w - The value of the w component.
7494	 * @return {Vector4} A reference to this vector.
7495	 */
7496	set( x, y, z, w ) {
7497
7498		this.x = x;
7499		this.y = y;
7500		this.z = z;
7501		this.w = w;
7502
7503		return this;
7504
7505	}
7506
7507	/**
7508	 * Sets the vector components to the same value.
7509	 *
7510	 * @param {number} scalar - The value to set for all vector components.
7511	 * @return {Vector4} A reference to this vector.
7512	 */
7513	setScalar( scalar ) {
7514
7515		this.x = scalar;
7516		this.y = scalar;
7517		this.z = scalar;
7518		this.w = scalar;
7519
7520		return this;
7521
7522	}
7523
7524	/**
7525	 * Sets the vector's x component to the given value
7526	 *
7527	 * @param {number} x - The value to set.
7528	 * @return {Vector4} A reference to this vector.
7529	 */
7530	setX( x ) {
7531
7532		this.x = x;
7533
7534		return this;
7535
7536	}
7537
7538	/**
7539	 * Sets the vector's y component to the given value
7540	 *
7541	 * @param {number} y - The value to set.
7542	 * @return {Vector4} A reference to this vector.
7543	 */
7544	setY( y ) {
7545
7546		this.y = y;
7547
7548		return this;
7549
7550	}
7551
7552	/**
7553	 * Sets the vector's z component to the given value
7554	 *
7555	 * @param {number} z - The value to set.
7556	 * @return {Vector4} A reference to this vector.
7557	 */
7558	setZ( z ) {
7559
7560		this.z = z;
7561
7562		return this;
7563
7564	}
7565
7566	/**
7567	 * Sets the vector's w component to the given value
7568	 *
7569	 * @param {number} w - The value to set.
7570	 * @return {Vector4} A reference to this vector.
7571	 */
7572	setW( w ) {
7573
7574		this.w = w;
7575
7576		return this;
7577
7578	}
7579
7580	/**
7581	 * Allows to set a vector component with an index.
7582	 *
7583	 * @param {number} index - The component index. `0` equals to x, `1` equals to y,
7584	 * `2` equals to z, `3` equals to w.
7585	 * @param {number} value - The value to set.
7586	 * @return {Vector4} A reference to this vector.
7587	 */
7588	setComponent( index, value ) {
7589
7590		switch ( index ) {
7591
7592			case 0: this.x = value; break;
7593			case 1: this.y = value; break;
7594			case 2: this.z = value; break;
7595			case 3: this.w = value; break;
7596			default: throw new Error( 'index is out of range: ' + index );
7597
7598		}
7599
7600		return this;
7601
7602	}
7603
7604	/**
7605	 * Returns the value of the vector component which matches the given index.
7606	 *
7607	 * @param {number} index - The component index. `0` equals to x, `1` equals to y,
7608	 * `2` equals to z, `3` equals to w.
7609	 * @return {number} A vector component value.
7610	 */
7611	getComponent( index ) {
7612
7613		switch ( index ) {
7614
7615			case 0: return this.x;
7616			case 1: return this.y;
7617			case 2: return this.z;
7618			case 3: return this.w;
7619			default: throw new Error( 'index is out of range: ' + index );
7620
7621		}
7622
7623	}
7624
7625	/**
7626	 * Returns a new vector with copied values from this instance.
7627	 *
7628	 * @return {Vector4} A clone of this instance.
7629	 */
7630	clone() {
7631
7632		return new this.constructor( this.x, this.y, this.z, this.w );
7633
7634	}
7635
7636	/**
7637	 * Copies the values of the given vector to this instance.
7638	 *
7639	 * @param {Vector3|Vector4} v - The vector to copy.
7640	 * @return {Vector4} A reference to this vector.
7641	 */
7642	copy( v ) {
7643
7644		this.x = v.x;
7645		this.y = v.y;
7646		this.z = v.z;
7647		this.w = ( v.w !== undefined ) ? v.w : 1;
7648
7649		return this;
7650
7651	}
7652
7653	/**
7654	 * Adds the given vector to this instance.
7655	 *
7656	 * @param {Vector4} v - The vector to add.
7657	 * @return {Vector4} A reference to this vector.
7658	 */
7659	add( v ) {
7660
7661		this.x += v.x;
7662		this.y += v.y;
7663		this.z += v.z;
7664		this.w += v.w;
7665
7666		return this;
7667
7668	}
7669
7670	/**
7671	 * Adds the given scalar value to all components of this instance.
7672	 *
7673	 * @param {number} s - The scalar to add.
7674	 * @return {Vector4} A reference to this vector.
7675	 */
7676	addScalar( s ) {
7677
7678		this.x += s;
7679		this.y += s;
7680		this.z += s;
7681		this.w += s;
7682
7683		return this;
7684
7685	}
7686
7687	/**
7688	 * Adds the given vectors and stores the result in this instance.
7689	 *
7690	 * @param {Vector4} a - The first vector.
7691	 * @param {Vector4} b - The second vector.
7692	 * @return {Vector4} A reference to this vector.
7693	 */
7694	addVectors( a, b ) {
7695
7696		this.x = a.x + b.x;
7697		this.y = a.y + b.y;
7698		this.z = a.z + b.z;
7699		this.w = a.w + b.w;
7700
7701		return this;
7702
7703	}
7704
7705	/**
7706	 * Adds the given vector scaled by the given factor to this instance.
7707	 *
7708	 * @param {Vector4} v - The vector.
7709	 * @param {number} s - The factor that scales `v`.
7710	 * @return {Vector4} A reference to this vector.
7711	 */
7712	addScaledVector( v, s ) {
7713
7714		this.x += v.x * s;
7715		this.y += v.y * s;
7716		this.z += v.z * s;
7717		this.w += v.w * s;
7718
7719		return this;
7720
7721	}
7722
7723	/**
7724	 * Subtracts the given vector from this instance.
7725	 *
7726	 * @param {Vector4} v - The vector to subtract.
7727	 * @return {Vector4} A reference to this vector.
7728	 */
7729	sub( v ) {
7730
7731		this.x -= v.x;
7732		this.y -= v.y;
7733		this.z -= v.z;
7734		this.w -= v.w;
7735
7736		return this;
7737
7738	}
7739
7740	/**
7741	 * Subtracts the given scalar value from all components of this instance.
7742	 *
7743	 * @param {number} s - The scalar to subtract.
7744	 * @return {Vector4} A reference to this vector.
7745	 */
7746	subScalar( s ) {
7747
7748		this.x -= s;
7749		this.y -= s;
7750		this.z -= s;
7751		this.w -= s;
7752
7753		return this;
7754
7755	}
7756
7757	/**
7758	 * Subtracts the given vectors and stores the result in this instance.
7759	 *
7760	 * @param {Vector4} a - The first vector.
7761	 * @param {Vector4} b - The second vector.
7762	 * @return {Vector4} A reference to this vector.
7763	 */
7764	subVectors( a, b ) {
7765
7766		this.x = a.x - b.x;
7767		this.y = a.y - b.y;
7768		this.z = a.z - b.z;
7769		this.w = a.w - b.w;
7770
7771		return this;
7772
7773	}
7774
7775	/**
7776	 * Multiplies the given vector with this instance.
7777	 *
7778	 * @param {Vector4} v - The vector to multiply.
7779	 * @return {Vector4} A reference to this vector.
7780	 */
7781	multiply( v ) {
7782
7783		this.x *= v.x;
7784		this.y *= v.y;
7785		this.z *= v.z;
7786		this.w *= v.w;
7787
7788		return this;
7789
7790	}
7791
7792	/**
7793	 * Multiplies the given scalar value with all components of this instance.
7794	 *
7795	 * @param {number} scalar - The scalar to multiply.
7796	 * @return {Vector4} A reference to this vector.
7797	 */
7798	multiplyScalar( scalar ) {
7799
7800		this.x *= scalar;
7801		this.y *= scalar;
7802		this.z *= scalar;
7803		this.w *= scalar;
7804
7805		return this;
7806
7807	}
7808
7809	/**
7810	 * Multiplies this vector with the given 4x4 matrix.
7811	 *
7812	 * @param {Matrix4} m - The 4x4 matrix.
7813	 * @return {Vector4} A reference to this vector.
7814	 */
7815	applyMatrix4( m ) {
7816
7817		const x = this.x, y = this.y, z = this.z, w = this.w;
7818		const e = m.elements;
7819
7820		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
7821		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
7822		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
7823		this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
7824
7825		return this;
7826
7827	}
7828
7829	/**
7830	 * Divides this instance by the given vector.
7831	 *
7832	 * @param {Vector4} v - The vector to divide.
7833	 * @return {Vector4} A reference to this vector.
7834	 */
7835	divide( v ) {
7836
7837		this.x /= v.x;
7838		this.y /= v.y;
7839		this.z /= v.z;
7840		this.w /= v.w;
7841
7842		return this;
7843
7844	}
7845
7846	/**
7847	 * Divides this vector by the given scalar.
7848	 *
7849	 * @param {number} scalar - The scalar to divide.
7850	 * @return {Vector4} A reference to this vector.
7851	 */
7852	divideScalar( scalar ) {
7853
7854		return this.multiplyScalar( 1 / scalar );
7855
7856	}
7857
7858	/**
7859	 * Sets the x, y and z components of this
7860	 * vector to the quaternion's axis and w to the angle.
7861	 *
7862	 * @param {Quaternion} q - The Quaternion to set.
7863	 * @return {Vector4} A reference to this vector.
7864	 */
7865	setAxisAngleFromQuaternion( q ) {
7866
7867		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
7868
7869		// q is assumed to be normalized
7870
7871		this.w = 2 * Math.acos( q.w );
7872
7873		const s = Math.sqrt( 1 - q.w * q.w );
7874
7875		if ( s < 0.0001 ) {
7876
7877			this.x = 1;
7878			this.y = 0;
7879			this.z = 0;
7880
7881		} else {
7882
7883			this.x = q.x / s;
7884			this.y = q.y / s;
7885			this.z = q.z / s;
7886
7887		}
7888
7889		return this;
7890
7891	}
7892
7893	/**
7894	 * Sets the x, y and z components of this
7895	 * vector to the axis of rotation and w to the angle.
7896	 *
7897	 * @param {Matrix4} m - A 4x4 matrix of which the upper left 3x3 matrix is a pure rotation matrix.
7898	 * @return {Vector4} A reference to this vector.
7899	 */
7900	setAxisAngleFromRotationMatrix( m ) {
7901
7902		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
7903
7904		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
7905
7906		let angle, x, y, z; // variables for result
7907		const epsilon = 0.01,		// margin to allow for rounding errors
7908			epsilon2 = 0.1,		// margin to distinguish between 0 and 180 degrees
7909
7910			te = m.elements,
7911
7912			m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
7913			m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
7914			m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
7915
7916		if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
7917		     ( Math.abs( m13 - m31 ) < epsilon ) &&
7918		     ( Math.abs( m23 - m32 ) < epsilon ) ) {
7919
7920			// singularity found
7921			// first check for identity matrix which must have +1 for all terms
7922			// in leading diagonal and zero in other terms
7923
7924			if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
7925			     ( Math.abs( m13 + m31 ) < epsilon2 ) &&
7926			     ( Math.abs( m23 + m32 ) < epsilon2 ) &&
7927			     ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
7928
7929				// this singularity is identity matrix so angle = 0
7930
7931				this.set( 1, 0, 0, 0 );
7932
7933				return this; // zero angle, arbitrary axis
7934
7935			}
7936
7937			// otherwise this singularity is angle = 180
7938
7939			angle = Math.PI;
7940
7941			const xx = ( m11 + 1 ) / 2;
7942			const yy = ( m22 + 1 ) / 2;
7943			const zz = ( m33 + 1 ) / 2;
7944			const xy = ( m12 + m21 ) / 4;
7945			const xz = ( m13 + m31 ) / 4;
7946			const yz = ( m23 + m32 ) / 4;
7947
7948			if ( ( xx > yy ) && ( xx > zz ) ) {
7949
7950				// m11 is the largest diagonal term
7951
7952				if ( xx < epsilon ) {
7953
7954					x = 0;
7955					y = 0.707106781;
7956					z = 0.707106781;
7957
7958				} else {
7959
7960					x = Math.sqrt( xx );
7961					y = xy / x;
7962					z = xz / x;
7963
7964				}
7965
7966			} else if ( yy > zz ) {
7967
7968				// m22 is the largest diagonal term
7969
7970				if ( yy < epsilon ) {
7971
7972					x = 0.707106781;
7973					y = 0;
7974					z = 0.707106781;
7975
7976				} else {
7977
7978					y = Math.sqrt( yy );
7979					x = xy / y;
7980					z = yz / y;
7981
7982				}
7983
7984			} else {
7985
7986				// m33 is the largest diagonal term so base result on this
7987
7988				if ( zz < epsilon ) {
7989
7990					x = 0.707106781;
7991					y = 0.707106781;
7992					z = 0;
7993
7994				} else {
7995
7996					z = Math.sqrt( zz );
7997					x = xz / z;
7998					y = yz / z;
7999
8000				}
8001
8002			}
8003
8004			this.set( x, y, z, angle );
8005
8006			return this; // return 180 deg rotation
8007
8008		}
8009
8010		// as we have reached here there are no singularities so we can handle normally
8011
8012		let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
8013			( m13 - m31 ) * ( m13 - m31 ) +
8014			( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
8015
8016		if ( Math.abs( s ) < 0.001 ) s = 1;
8017
8018		// prevent divide by zero, should not happen if matrix is orthogonal and should be
8019		// caught by singularity test above, but I've left it in just in case
8020
8021		this.x = ( m32 - m23 ) / s;
8022		this.y = ( m13 - m31 ) / s;
8023		this.z = ( m21 - m12 ) / s;
8024		this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
8025
8026		return this;
8027
8028	}
8029
8030	/**
8031	 * Sets the vector components to the position elements of the
8032	 * given transformation matrix.
8033	 *
8034	 * @param {Matrix4} m - The 4x4 matrix.
8035	 * @return {Vector4} A reference to this vector.
8036	 */
8037	setFromMatrixPosition( m ) {
8038
8039		const e = m.elements;
8040
8041		this.x = e[ 12 ];
8042		this.y = e[ 13 ];
8043		this.z = e[ 14 ];
8044		this.w = e[ 15 ];
8045
8046		return this;
8047
8048	}
8049
8050	/**
8051	 * If this vector's x, y, z or w value is greater than the given vector's x, y, z or w
8052	 * value, replace that value with the corresponding min value.
8053	 *
8054	 * @param {Vector4} v - The vector.
8055	 * @return {Vector4} A reference to this vector.
8056	 */
8057	min( v ) {
8058
8059		this.x = Math.min( this.x, v.x );
8060		this.y = Math.min( this.y, v.y );
8061		this.z = Math.min( this.z, v.z );
8062		this.w = Math.min( this.w, v.w );
8063
8064		return this;
8065
8066	}
8067
8068	/**
8069	 * If this vector's x, y, z or w value is less than the given vector's x, y, z or w
8070	 * value, replace that value with the corresponding max value.
8071	 *
8072	 * @param {Vector4} v - The vector.
8073	 * @return {Vector4} A reference to this vector.
8074	 */
8075	max( v ) {
8076
8077		this.x = Math.max( this.x, v.x );
8078		this.y = Math.max( this.y, v.y );
8079		this.z = Math.max( this.z, v.z );
8080		this.w = Math.max( this.w, v.w );
8081
8082		return this;
8083
8084	}
8085
8086	/**
8087	 * If this vector's x, y, z or w value is greater than the max vector's x, y, z or w
8088	 * value, it is replaced by the corresponding value.
8089	 * If this vector's x, y, z or w value is less than the min vector's x, y, z or w value,
8090	 * it is replaced by the corresponding value.
8091	 *
8092	 * @param {Vector4} min - The minimum x, y and z values.
8093	 * @param {Vector4} max - The maximum x, y and z values in the desired range.
8094	 * @return {Vector4} A reference to this vector.
8095	 */
8096	clamp( min, max ) {
8097
8098		// assumes min < max, componentwise
8099
8100		this.x = clamp
8100( this.x, min.x, max.x );
8101		this.y = clamp( this.y, min.y, max.y );
8102		this.z = clamp( this.z, min.z, max.z );
8103		this.w = clamp( this.w, min.w, max.w );
8104
8105		return this;
8106
8107	}
8108
vendor: 8,421 bytes, lines 8109-8443
8109	/**
8110	 * If this vector's x, y, z or w values are greater than the max value, they are
8111	 * replaced by the max value.
8112	 * If this vector's x, y, z or w values are less than the min value, they are
8113	 * replaced by the min value.
8114	 *
8115	 * @param {number} minVal - The minimum value the components will be clamped to.
8116	 * @param {number} maxVal - The maximum value the components will be clamped to.
8117	 * @return {Vector4} A reference to this vector.
8118	 */
8119	clampScalar( minVal, maxVal ) {
8120
8121		this.x = clamp( this.x, minVal, maxVal );
8122		this.y = clamp( this.y, minVal, maxVal );
8123		this.z = clamp( this.z, minVal, maxVal );
8124		this.w = clamp( this.w, minVal, maxVal );
8125
8126		return this;
8127
8128	}
8129
8130	/**
8131	 * If this vector's length is greater than the max value, it is replaced by
8132	 * the max value.
8133	 * If this vector's length is less than the min value, it is replaced by the
8134	 * min value.
8135	 *
8136	 * @param {number} min - The minimum value the vector length will be clamped to.
8137	 * @param {number} max - The maximum value the vector length will be clamped to.
8138	 * @return {Vector4} A reference to this vector.
8139	 */
8140	clampLength( min, max ) {
8141
8142		const length = this.length();
8143
8144		return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) );
8145
8146	}
8147
8148	/**
8149	 * The components of this vector are rounded down to the nearest integer value.
8150	 *
8151	 * @return {Vector4} A reference to this vector.
8152	 */
8153	floor() {
8154
8155		this.x = Math.floor( this.x );
8156		this.y = Math.floor( this.y );
8157		this.z = Math.floor( this.z );
8158		this.w = Math.floor( this.w );
8159
8160		return this;
8161
8162	}
8163
8164	/**
8165	 * The components of this vector are rounded up to the nearest integer value.
8166	 *
8167	 * @return {Vector4} A reference to this vector.
8168	 */
8169	ceil() {
8170
8171		this.x = Math.ceil( this.x );
8172		this.y = Math.ceil( this.y );
8173		this.z = Math.ceil( this.z );
8174		this.w = Math.ceil( this.w );
8175
8176		return this;
8177
8178	}
8179
8180	/**
8181	 * The components of this vector are rounded to the nearest integer value
8182	 *
8183	 * @return {Vector4} A reference to this vector.
8184	 */
8185	round() {
8186
8187		this.x = Math.round( this.x );
8188		this.y = Math.round( this.y );
8189		this.z = Math.round( this.z );
8190		this.w = Math.round( this.w );
8191
8192		return this;
8193
8194	}
8195
8196	/**
8197	 * The components of this vector are rounded towards zero (up if negative,
8198	 * down if positive) to an integer value.
8199	 *
8200	 * @return {Vector4} A reference to this vector.
8201	 */
8202	roundToZero() {
8203
8204		this.x = Math.trunc( this.x );
8205		this.y = Math.trunc( this.y );
8206		this.z = Math.trunc( this.z );
8207		this.w = Math.trunc( this.w );
8208
8209		return this;
8210
8211	}
8212
8213	/**
8214	 * Inverts this vector - i.e. sets x = -x, y = -y, z = -z, w = -w.
8215	 *
8216	 * @return {Vector4} A reference to this vector.
8217	 */
8218	negate() {
8219
8220		this.x = - this.x;
8221		this.y = - this.y;
8222		this.z = - this.z;
8223		this.w = - this.w;
8224
8225		return this;
8226
8227	}
8228
8229	/**
8230	 * Calculates the dot product of the given vector with this instance.
8231	 *
8232	 * @param {Vector4} v - The vector to compute the dot product with.
8233	 * @return {number} The result of the dot product.
8234	 */
8235	dot( v ) {
8236
8237		return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
8238
8239	}
8240
8241	/**
8242	 * Computes the square of the Euclidean length (straight-line length) from
8243	 * (0, 0, 0, 0) to (x, y, z, w). If you are comparing the lengths of vectors, you should
8244	 * compare the length squared instead as it is slightly more efficient to calculate.
8245	 *
8246	 * @return {number} The square length of this vector.
8247	 */
8248	lengthSq() {
8249
8250		return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
8251
8252	}
8253
8254	/**
8255	 * Computes the  Euclidean length (straight-line length) from (0, 0, 0, 0) to (x, y, z, w).
8256	 *
8257	 * @return {number} The length of this vector.
8258	 */
8259	length() {
8260
8261		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
8262
8263	}
8264
8265	/**
8266	 * Computes the Manhattan length of this vector.
8267	 *
8268	 * @return {number} The length of this vector.
8269	 */
8270	manhattanLength() {
8271
8272		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
8273
8274	}
8275
8276	/**
8277	 * Converts this vector to a unit vector - that is, sets it equal to a vector
8278	 * with the same direction as this one, but with a vector length of `1`.
8279	 *
8280	 * @return {Vector4} A reference to this vector.
8281	 */
8282	normalize() {
8283
8284		return this.divideScalar( this.length() || 1 );
8285
8286	}
8287
8288	/**
8289	 * Sets this vector to a vector with the same direction as this one, but
8290	 * with the specified length.
8291	 *
8292	 * @param {number} length - The new length of this vector.
8293	 * @return {Vector4} A reference to this vector.
8294	 */
8295	setLength( length ) {
8296
8297		return this.normalize().multiplyScalar( length );
8298
8299	}
8300
8301	/**
8302	 * Linearly interpolates between the given vector and this instance, where
8303	 * alpha is the percent distance along the line - alpha = 0 will be this
8304	 * vector, and alpha = 1 will be the given one.
8305	 *
8306	 * @param {Vector4} v - The vector to interpolate towards.
8307	 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
8308	 * @return {Vector4} A reference to this vector.
8309	 */
8310	lerp( v, alpha ) {
8311
8312		this.x += ( v.x - this.x ) * alpha;
8313		this.y += ( v.y - this.y ) * alpha;
8314		this.z += ( v.z - this.z ) * alpha;
8315		this.w += ( v.w - this.w ) * alpha;
8316
8317		return this;
8318
8319	}
8320
8321	/**
8322	 * Linearly interpolates between the given vectors, where alpha is the percent
8323	 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will
8324	 * be the second one. The result is stored in this instance.
8325	 *
8326	 * @param {Vector4} v1 - The first vector.
8327	 * @param {Vector4} v2 - The second vector.
8328	 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
8329	 * @return {Vector4} A reference to this vector.
8330	 */
8331	lerpVectors( v1, v2, alpha ) {
8332
8333		this.x = v1.x + ( v2.x - v1.x ) * alpha;
8334		this.y = v1.y + ( v2.y - v1.y ) * alpha;
8335		this.z = v1.z + ( v2.z - v1.z ) * alpha;
8336		this.w = v1.w + ( v2.w - v1.w ) * alpha;
8337
8338		return this;
8339
8340	}
8341
8342	/**
8343	 * Returns `true` if this vector is equal with the given one.
8344	 *
8345	 * @param {Vector4} v - The vector to test for equality.
8346	 * @return {boolean} Whether this vector is equal with the given one.
8347	 */
8348	equals( v ) {
8349
8350		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
8351
8352	}
8353
8354	/**
8355	 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]`,
8356	 * z value to be `array[ offset + 2 ]`, w value to be `array[ offset + 3 ]`.
8357	 *
8358	 * @param {Array<number>} array - An array holding the vector component values.
8359	 * @param {number} [offset=0] - The offset into the array.
8360	 * @return {Vector4} A reference to this vector.
8361	 */
8362	fromArray( array, offset = 0 ) {
8363
8364		this.x = array[ offset ];
8365		this.y = array[ offset + 1 ];
8366		this.z = array[ offset + 2 ];
8367		this.w = array[ offset + 3 ];
8368
8369		return this;
8370
8371	}
8372
8373	/**
8374	 * Writes the components of this vector to the given array. If no array is provided,
8375	 * the method returns a new instance.
8376	 *
8377	 * @param {Array<number>} [array=[]] - The target array holding the vector components.
8378	 * @param {number} [offset=0] - Index of the first element in the array.
8379	 * @return {Array<number>} The vector components.
8380	 */
8381	toArray( array = [], offset = 0 ) {
8382
8383		array[ offset ] = this.x;
8384		array[ offset + 1 ] = this.y;
8385		array[ offset + 2 ] = this.z;
8386		array[ offset + 3 ] = this.w;
8387
8388		return array;
8389
8390	}
8391
8392	/**
8393	 * Sets the components of this vector from the given buffer attribute.
8394	 *
8395	 * @param {BufferAttribute} attribute - The buffer attribute holding vector data.
8396	 * @param {number} index - The index into the attribute.
8397	 * @return {Vector4} A reference to this vector.
8398	 */
8399	fromBufferAttribute( attribute, index ) {
8400
8401		this.x = attribute.getX( index );
8402		this.y = attribute.getY( index );
8403		this.z = attribute.getZ( index );
8404		this.w = attribute.getW( index );
8405
8406		return this;
8407
8408	}
8409
8410	/**
8411	 * Sets each component of this vector to a pseudo-random value between `0` and
8412	 * `1`, excluding `1`.
8413	 *
8414	 * @return {Vector4} A reference to this vector.
8415	 */
8416	random() {
8417
8418		this.x = Math.random();
8419		this.y = Math.random();
8420		this.z = Math.random();
8421		this.w = Math.random();
8422
8423		return this;
8424
8425	}
8426
8427	*[ Symbol.iterator ]() {
8428
8429		yield this.x;
8430		yield this.y;
8431		yield this.z;
8432		yield this.w;
8433
8434	}
8435
8436}
8437
8438/**
8439 * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations.
8440 *
8441 * Iterating through a vector instance will yield its components `(x, y, z, w)` in
8442 * the corresponding order.
8443 *
vendor: 17,834 bytes, lines 8444-9225
8444 * Note that three.js expects Quaternions to be normalized.
8445 * ```js
8446 * const quaternion = new THREE.Quaternion();
8447 * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 );
8448 *
8449 * const vector = new THREE.Vector3( 1, 0, 0 );
8450 * vector.applyQuaternion( quaternion );
8451 * ```
8452 */
8453class Quaternion {
8454
8455	/**
8456	 * Constructs a new quaternion.
8457	 *
8458	 * @param {number} [x=0] - The x value of this quaternion.
8459	 * @param {number} [y=0] - The y value of this quaternion.
8460	 * @param {number} [z=0] - The z value of this quaternion.
8461	 * @param {number} [w=1] - The w value of this quaternion.
8462	 */
8463	constructor( x = 0, y = 0, z = 0, w = 1 ) {
8464
8465		/**
8466		 * This flag can be used for type testing.
8467		 *
8468		 * @type {boolean}
8469		 * @readonly
8470		 * @default true
8471		 */
8472		this.isQuaternion = true;
8473
8474		this._x = x;
8475		this._y = y;
8476		this._z = z;
8477		this._w = w;
8478
8479	}
8480
8481	/**
8482	 * Interpolates between two quaternions via SLERP. This implementation assumes the
8483	 * quaternion data are managed  in flat arrays.
8484	 *
8485	 * @param {Array<number>} dst - The destination array.
8486	 * @param {number} dstOffset - An offset into the destination array.
8487	 * @param {Array<number>} src0 - The source array of the first quaternion.
8488	 * @param {number} srcOffset0 - An offset into the first source array.
8489	 * @param {Array<number>} src1 -  The source array of the second quaternion.
8490	 * @param {number} srcOffset1 - An offset into the second source array.
8491	 * @param {number} t - The interpolation factor in the range `[0,1]`.
8492	 * @see {@link Quaternion#slerp}
8493	 */
8494	static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
8495
8496		// fuzz-free, array-based Quaternion SLERP operation
8497
8498		let x0 = src0[ srcOffset0 + 0 ],
8499			y0 = src0[ srcOffset0 + 1 ],
8500			z0 = src0[ srcOffset0 + 2 ],
8501			w0 = src0[ srcOffset0 + 3 ];
8502
8503		const x1 = src1[ srcOffset1 + 0 ],
8504			y1 = src1[ srcOffset1 + 1 ],
8505			z1 = src1[ srcOffset1 + 2 ],
8506			w1 = src1[ srcOffset1 + 3 ];
8507
8508		if ( t === 0 ) {
8509
8510			dst[ dstOffset + 0 ] = x0;
8511			dst[ dstOffset + 1 ] = y0;
8512			dst[ dstOffset + 2 ] = z0;
8513			dst[ dstOffset + 3 ] = w0;
8514			return;
8515
8516		}
8517
8518		if ( t === 1 ) {
8519
8520			dst[ dstOffset + 0 ] = x1;
8521			dst[ dstOffset + 1 ] = y1;
8522			dst[ dstOffset + 2 ] = z1;
8523			dst[ dstOffset + 3 ] = w1;
8524			return;
8525
8526		}
8527
8528		if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
8529
8530			let s = 1 - t;
8531			const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
8532				dir = ( cos >= 0 ? 1 : -1 ),
8533				sqrSin = 1 - cos * cos;
8534
8535			// Skip the Slerp for tiny steps to avoid numeric problems:
8536			if ( sqrSin > Number.EPSILON ) {
8537
8538				const sin = Math.sqrt( sqrSin ),
8539					len = Math.atan2( sin, cos * dir );
8540
8541				s = Math.sin( s * len ) / sin;
8542				t = Math.sin( t * len ) / sin;
8543
8544			}
8545
8546			const tDir = t * dir;
8547
8548			x0 = x0 * s + x1 * tDir;
8549			y0 = y0 * s + y1 * tDir;
8550			z0 = z0 * s + z1 * tDir;
8551			w0 = w0 * s + w1 * tDir;
8552
8553			// Normalize in case we just did a lerp:
8554			if ( s === 1 - t ) {
8555
8556				const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
8557
8558				x0 *= f;
8559				y0 *= f;
8560				z0 *= f;
8561				w0 *= f;
8562
8563			}
8564
8565		}
8566
8567		dst[ dstOffset ] = x0;
8568		dst[ dstOffset + 1 ] = y0;
8569		dst[ dstOffset + 2 ] = z0;
8570		dst[ dstOffset + 3 ] = w0;
8571
8572	}
8573
8574	/**
8575	 * Multiplies two quaternions. This implementation assumes the quaternion data are managed
8576	 * in flat arrays.
8577	 *
8578	 * @param {Array<number>} dst - The destination array.
8579	 * @param {number} dstOffset - An offset into the destination array.
8580	 * @param {Array<number>} src0 - The source array of the first quaternion.
8581	 * @param {number} srcOffset0 - An offset into the first source array.
8582	 * @param {Array<number>} src1 -  The source array of the second quaternion.
8583	 * @param {number} srcOffset1 - An offset into the second source array.
8584	 * @return {Array<number>} The destination array.
8585	 * @see {@link Quaternion#multiplyQuaternions}.
8586	 */
8587	static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
8588
8589		const x0 = src0[ srcOffset0 ];
8590		const y0 = src0[ srcOffset0 + 1 ];
8591		const z0 = src0[ srcOffset0 + 2 ];
8592		const w0 = src0[ srcOffset0 + 3 ];
8593
8594		const x1 = src1[ srcOffset1 ];
8595		const y1 = src1[ srcOffset1 + 1 ];
8596		const z1 = src1[ srcOffset1 + 2 ];
8597		const w1 = src1[ srcOffset1 + 3 ];
8598
8599		dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
8600		dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
8601		dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
8602		dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
8603
8604		return dst;
8605
8606	}
8607
8608	/**
8609	 * The x value of this quaternion.
8610	 *
8611	 * @type {number}
8612	 * @default 0
8613	 */
8614	get x() {
8615
8616		return this._x;
8617
8618	}
8619
8620	set x( value ) {
8621
8622		this._x = value;
8623		this._onChangeCallback();
8624
8625	}
8626
8627	/**
8628	 * The y value of this quaternion.
8629	 *
8630	 * @type {number}
8631	 * @default 0
8632	 */
8633	get y() {
8634
8635		return this._y;
8636
8637	}
8638
8639	set y( value ) {
8640
8641		this._y = value;
8642		this._onChangeCallback();
8643
8644	}
8645
8646	/**
8647	 * The z value of this quaternion.
8648	 *
8649	 * @type {number}
8650	 * @default 0
8651	 */
8652	get z() {
8653
8654		return this._z;
8655
8656	}
8657
8658	set z( value ) {
8659
8660		this._z = value;
8661		this._onChangeCallback();
8662
8663	}
8664
8665	/**
8666	 * The w value of this quaternion.
8667	 *
8668	 * @type {number}
8669	 * @default 1
8670	 */
8671	get w() {
8672
8673		return this._w;
8674
8675	}
8676
8677	set w( value ) {
8678
8679		this._w = value;
8680		this._onChangeCallback();
8681
8682	}
8683
8684	/**
8685	 * Sets the quaternion components.
8686	 *
8687	 * @param {number} x - The x value of this quaternion.
8688	 * @param {number} y - The y value of this quaternion.
8689	 * @param {number} z - The z value of this quaternion.
8690	 * @param {number} w - The w value of this quaternion.
8691	 * @return {Quaternion} A reference to this quaternion.
8692	 */
8693	set( x, y, z, w ) {
8694
8695		this._x = x;
8696		this._y = y;
8697		this._z = z;
8698		this._w = w;
8699
8700		this._onChangeCallback();
8701
8702		return this;
8703
8704	}
8705
8706	/**
8707	 * Returns a new quaternion with copied values from this instance.
8708	 *
8709	 * @return {Quaternion} A clone of this instance.
8710	 */
8711	clone() {
8712
8713		return new this.constructor( this._x, this._y, this._z, this._w );
8714
8715	}
8716
8717	/**
8718	 * Copies the values of the given quaternion to this instance.
8719	 *
8720	 * @param {Quaternion} quaternion - The quaternion to copy.
8721	 * @return {Quaternion} A reference to this quaternion.
8722	 */
8723	copy( quaternion ) {
8724
8725		this._x = quaternion.x;
8726		this._y = quaternion.y;
8727		this._z = quaternion.z;
8728		this._w = quaternion.w;
8729
8730		this._onChangeCallback();
8731
8732		return this;
8733
8734	}
8735
8736	/**
8737	 * Sets this quaternion from the rotation specified by the given
8738	 * Euler angles.
8739	 *
8740	 * @param {Euler} euler - The Euler angles.
8741	 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not.
8742	 * @return {Quaternion} A reference to this quaternion.
8743	 */
8744	setFromEuler( euler, update = true ) {
8745
8746		const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
8747
8748		// http://www.mathworks.com/matlabcentral/fileexchange/
8749		// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
8750		//	content/SpinCalc.m
8751
8752		const cos = Math.cos;
8753		const sin = Math.sin;
8754
8755		const c1 = cos( x / 2 );
8756		const c2 = cos( y / 2 );
8757		const c3 = cos( z / 2 );
8758
8759		const s1 = sin( x / 2 );
8760		const s2 = sin( y / 2 );
8761		const s3 = sin( z / 2 );
8762
8763		switch ( order ) {
8764
8765			case 'XYZ':
8766				this._x = s1 * c2 * c3 + c1 * s2 * s3;
8767				this._y = c1 * s2 * c3 - s1 * c2 * s3;
8768				this._z = c1 * c2 * s3 + s1 * s2 * c3;
8769				this._w = c1 * c2 * c3 - s1 * s2 * s3;
8770				break;
8771
8772			case 'YXZ':
8773				this._x = s1 * c2 * c3 + c1 * s2 * s3;
8774				this._y = c1 * s2 * c3 - s1 * c2 * s3;
8775				this._z = c1 * c2 * s3 - s1 * s2 * c3;
8776				this._w = c1 * c2 * c3 + s1 * s2 * s3;
8777				break;
8778
8779			case 'ZXY':
8780				this._x = s1 * c2 * c3 - c1 * s2 * s3;
8781				this._y = c1 * s2 * c3 + s1 * c2 * s3;
8782				this._z = c1 * c2 * s3 + s1 * s2 * c3;
8783				this._w = c1 * c2 * c3 - s1 * s2 * s3;
8784				break;
8785
8786			case 'ZYX':
8787				this._x = s1 * c2 * c3 - c1 * s2 * s3;
8788				this._y = c1 * s2 * c3 + s1 * c2 * s3;
8789				this._z = c1 * c2 * s3 - s1 * s2 * c3;
8790				this._w = c1 * c2 * c3 + s1 * s2 * s3;
8791				break;
8792
8793			case 'YZX':
8794				this._x = s1 * c2 * c3 + c1 * s2 * s3;
8795				this._y = c1 * s2 * c3 + s1 * c2 * s3;
8796				this._z = c1 * c2 * s3 - s1 * s2 * c3;
8797				this._w = c1 * c2 * c3 - s1 * s2 * s3;
8798				break;
8799
8800			case 'XZY':
8801				this._x = s1 * c2 * c3 - c1 * s2 * s3;
8802				this._y = c1 * s2 * c3 - s1 * c2 * s3;
8803				this._z = c1 * c2 * s3 + s1 * s2 * c3;
8804				this._w = c1 * c2 * c3 + s1 * s2 * s3;
8805				break;
8806
8807			default:
8808				console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
8809
8810		}
8811
8812		if ( update === true ) this._onChangeCallback();
8813
8814		return this;
8815
8816	}
8817
8818	/**
8819	 * Sets this quaternion from the given axis and angle.
8820	 *
8821	 * @param {Vector3} axis - The normalized axis.
8822	 * @param {number} angle - The angle in radians.
8823	 * @return {Quaternion} A reference to this quaternion.
8824	 */
8825	setFromAxisAngle( axis, angle ) {
8826
8827		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
8828
8829		const halfAngle = angle / 2, s = Math.sin( halfAngle );
8830
8831		this._x = axis.x * s;
8832		this._y = axis.y * s;
8833		this._z = axis.z * s;
8834		this._w = Math.cos( halfAngle );
8835
8836		this._onChangeCallback();
8837
8838		return this;
8839
8840	}
8841
8842	/**
8843	 * Sets this quaternion from the given rotation matrix.
8844	 *
8845	 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled).
8846	 * @return {Quaternion} A reference to this quaternion.
8847	 */
8848	setFromRotationMatrix( m ) {
8849
8850		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
8851
8852		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
8853
8854		const te = m.elements,
8855
8856			m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
8857			m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
8858			m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
8859
8860			trace = m11 + m22 + m33;
8861
8862		if ( trace > 0 ) {
8863
8864			const s = 0.5 / Math.sqrt( trace + 1.0 );
8865
8866			this._w = 0.25 / s;
8867			this._x = ( m32 - m23 ) * s;
8868			this._y = ( m13 - m31 ) * s;
8869			this._z = ( m21 - m12 ) * s;
8870
8871		} else if ( m11 > m22 && m11 > m33 ) {
8872
8873			const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
8874
8875			this._w = ( m32 - m23 ) / s;
8876			this._x = 0.25 * s;
8877			this._y = ( m12 + m21 ) / s;
8878			this._z = ( m13 + m31 ) / s;
8879
8880		} else if ( m22 > m33 ) {
8881
8882			const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
8883
8884			this._w = ( m13 - m31 ) / s;
8885			this._x = ( m12 + m21 ) / s;
8886			this._y = 0.25 * s;
8887			this._z = ( m23 + m32 ) / s;
8888
8889		} else {
8890
8891			const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
8892
8893			this._w = ( m21 - m12 ) / s;
8894			this._x = ( m13 + m31 ) / s;
8895			this._y = ( m23 + m32 ) / s;
8896			this._z = 0.25 * s;
8897
8898		}
8899
8900		this._onChangeCallback();
8901
8902		return this;
8903
8904	}
8905
8906	/**
8907	 * Sets this quaternion to the rotation required to rotate the direction vector
8908	 * `vFrom` to the direction vector `vTo`.
8909	 *
8910	 * @param {Vector3} vFrom - The first (normalized) direction vector.
8911	 * @param {Vector3} vTo - The second (normalized) direction vector.
8912	 * @return {Quaternion} A reference to this quaternion.
8913	 */
8914	setFromUnitVectors( vFrom, vTo ) {
8915
8916		// assumes direction vectors vFrom and vTo are normalized
8917
8918		let r = vFrom.dot( vTo ) + 1;
8919
8920		if ( r < Number.EPSILON ) {
8921
8922			// vFrom and vTo point in opposite directions
8923
8924			r = 0;
8925
8926			if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
8927
8928				this._x = - vFrom.y;
8929				this._y = vFrom.x;
8930				this._z = 0;
8931				this._w = r;
8932
8933			} else {
8934
8935				this._x = 0;
8936				this._y = - vFrom.z;
8937				this._z = vFrom.y;
8938				this._w = r;
8939
8940			}
8941
8942		} else {
8943
8944			// crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
8945
8946			this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
8947			this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
8948			this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
8949			this._w = r;
8950
8951		}
8952
8953		return this.normalize();
8954
8955	}
8956
8957	/**
8958	 * Returns the angle between this quaternion and the given one in radians.
8959	 *
8960	 * @param {Quaternion} q - The quaternion to compute the angle with.
8961	 * @return {number} The angle in radians.
8962	 */
8963	angleTo( q ) {
8964
8965		return 2 * Math.acos( Math.abs( clamp( this.dot( q ), -1, 1 ) ) );
8966
8967	}
8968
8969	/**
8970	 * Rotates this quaternion by a given angular step to the given quaternion.
8971	 * The method ensures that the final quaternion will not overshoot `q`.
8972	 *
8973	 * @param {Quaternion} q - The target quaternion.
8974	 * @param {number} step - The angular step in radians.
8975	 * @return {Quaternion} A reference to this quaternion.
8976	 */
8977	rotateTowards( q, step ) {
8978
8979		const angle = this.angleTo( q );
8980
8981		if ( angle === 0 ) return this;
8982
8983		const t = Math.min( 1, step / angle );
8984
8985		this.slerp( q, t );
8986
8987		return this;
8988
8989	}
8990
8991	/**
8992	 * Sets this quaternion to the identity quaternion; that is, to the
8993	 * quaternion that represents "no rotation".
8994	 *
8995	 * @return {Quaternion} A reference to this quaternion.
8996	 */
8997	identity() {
8998
8999		return this.set( 0, 0, 0, 1 );
9000
9001	}
9002
9003	/**
9004	 * Inverts this quaternion via {@link Quaternion#conjugate}. The
9005	 * quaternion is assumed to have unit length.
9006	 *
9007	 * @return {Quaternion} A reference to this quaternion.
9008	 */
9009	invert() {
9010
9011		return this.conjugate();
9012
9013	}
9014
9015	/**
9016	 * Returns the rotational conjugate of this quaternion. The conjugate of a
9017	 * quaternion represents the same rotation in the opposite direction about
9018	 * the rotational axis.
9019	 *
9020	 * @return {Quaternion} A reference to this quaternion.
9021	 */
9022	conjugate() {
9023
9024		this._x *= -1;
9025		this._y *= -1;
9026		this._z *= -1;
9027
9028		this._onChangeCallback();
9029
9030		return this;
9031
9032	}
9033
9034	/**
9035	 * Calculates the dot product of this quaternion and the given one.
9036	 *
9037	 * @param {Quaternion} v - The quaternion to compute the dot product with.
9038	 * @return {number} The result of the dot product.
9039	 */
9040	dot( v ) {
9041
9042		return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
9043
9044	}
9045
9046	/**
9047	 * Computes the squared Euclidean length (straight-line length) of this quaternion,
9048	 * considered as a 4 dimensional vector. This can be useful if you are comparing the
9049	 * lengths of two quaternions, as this is a slightly more efficient calculation than
9050	 * {@link Quaternion#length}.
9051	 *
9052	 * @return {number} The squared Euclidean length.
9053	 */
9054	lengthSq() {
9055
9056		return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
9057
9058	}
9059
9060	/**
9061	 * Computes the Euclidean length (straight-line length) of this quaternion,
9062	 * considered as a 4 dimensional vector.
9063	 *
9064	 * @return {number} The Euclidean length.
9065	 */
9066	length() {
9067
9068		return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
9069
9070	}
9071
9072	/**
9073	 * Normalizes this quaternion - that is, calculated the quaternion that performs
9074	 * the same rotation as this one, but has a length equal to `1`.
9075	 *
9076	 * @return {Quaternion} A reference to this quaternion.
9077	 */
9078	normalize() {
9079
9080		let l = this.length();
9081
9082		if ( l === 0 ) {
9083
9084			this._x = 0;
9085			this._y = 0;
9086			this._z = 0;
9087			this._w = 1;
9088
9089		} else {
9090
9091			l = 1 / l;
9092
9093			this._x = this._x * l;
9094			this._y = this._y * l;
9095			this._z = this._z * l;
9096			this._w = this._w * l;
9097
9098		}
9099
9100		this._onChangeCallback();
9101
9102		return this;
9103
9104	}
9105
9106	/**
9107	 * Multiplies this quaternion by the given one.
9108	 *
9109	 * @param {Quaternion} q - The quaternion.
9110	 * @return {Quaternion} A reference to this quaternion.
9111	 */
9112	multiply( q ) {
9113
9114		return this.multiplyQuaternions( this, q );
9115
9116	}
9117
9118	/**
9119	 * Pre-multiplies this quaternion by the given one.
9120	 *
9121	 * @param {Quaternion} q - The quaternion.
9122	 * @return {Quaternion} A reference to this quaternion.
9123	 */
9124	premultiply( q ) {
9125
9126		return this.multiplyQuaternions( q, this );
9127
9128	}
9129
9130	/**
9131	 * Multiplies the given quaternions and stores the result in this instance.
9132	 *
9133	 * @param {Quaternion} a - The first quaternion.
9134	 * @param {Quaternion} b - The second quaternion.
9135	 * @return {Quaternion} A reference to this quaternion.
9136	 */
9137	multiplyQuaternions( a, b ) {
9138
9139		// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
9140
9141		const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
9142		const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
9143
9144		this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
9145		this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
9146		this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
9147		this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
9148
9149		this._onChangeCallback();
9150
9151		return this;
9152
9153	}
9154
9155	/**
9156	 * Performs a spherical linear interpolation between quaternions.
9157	 *
9158	 * @param {Quaternion} qb - The target quaternion.
9159	 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
9160	 * @return {Quaternion} A reference to this quaternion.
9161	 */
9162	slerp( qb, t ) {
9163
9164		if ( t === 0 ) return this;
9165		if ( t === 1 ) return this.copy( qb );
9166
9167		const x = this._x, y = this._y, z = this._z, w = this._w;
9168
9169		// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
9170
9171		let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
9172
9173		if ( cosHalfTheta < 0 ) {
9174
9175			this._w = - qb._w;
9176			this._x = - qb._x;
9177			this._y = - qb._y;
9178			this._z = - qb._z;
9179
9180			cosHalfTheta = - cosHalfTheta;
9181
9182		} else {
9183
9184			this.copy( qb );
9185
9186		}
9187
9188		if ( cosHalfTheta >= 1.0 ) {
9189
9190			this._w = w;
9191			this._x = x;
9192			this._y = y;
9193			this._z = z;
9194
9195			return this;
9196
9197		}
9198
9199		const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
9200
9201		if ( sqrSinHalfTheta <= Number.EPSILON ) {
9202
9203			const s = 1 - t;
9204			this._w = s * w + t * this._w;
9205			this._x = s * x + t * this._x;
9206			this._y = s * y + t * this._y;
9207			this._z = s * z + t * this._z;
9208
9209			this.normalize(); // normalize calls _onChangeCallback()
9210
9211			return this;
9212
9213		}
9214
9215		const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
9216		const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
9217		const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
9218			ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
9219
9220		this._w = ( w * ratioA + this._w * ratioB );
9221		this._x = ( x * ratioA + this._x * ratioB );
9222		this._y = ( y * ratioA + this._y * ratioB );
9223		this._z = ( z * ratioA + this._z * ratioB );
9224
9225		this._onChangeCallback();
vendor: 4,515 bytes, lines 9225-9404
9225
9226
9227		return this;
9228
9229	}
9230
9231	/**
9232	 * Performs a spherical linear interpolation between the given quaternions
9233	 * and stores the result in this quaternion.
9234	 *
9235	 * @param {Quaternion} qa - The source quaternion.
9236	 * @param {Quaternion} qb - The target quaternion.
9237	 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
9238	 * @return {Quaternion} A reference to this quaternion.
9239	 */
9240	slerpQuaternions( qa, qb, t ) {
9241
9242		return this.copy( qa ).slerp( qb, t );
9243
9244	}
9245
9246	/**
9247	 * Sets this quaternion to a uniformly random, normalized quaternion.
9248	 *
9249	 * @return {Quaternion} A reference to this quaternion.
9250	 */
9251	random() {
9252
9253		// Ken Shoemake
9254		// Uniform random rotations
9255		// D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992.
9256
9257		const theta1 = 2 * Math.PI * Math.random();
9258		const theta2 = 2 * Math.PI * Math.random();
9259
9260		const x0 = Math.random();
9261		const r1 = Math.sqrt( 1 - x0 );
9262		const r2 = Math.sqrt( x0 );
9263
9264		return this.set(
9265			r1 * Math.sin( theta1 ),
9266			r1 * Math.cos( theta1 ),
9267			r2 * Math.sin( theta2 ),
9268			r2 * Math.cos( theta2 ),
9269		);
9270
9271	}
9272
9273	/**
9274	 * Returns `true` if this quaternion is equal with the given one.
9275	 *
9276	 * @param {Quaternion} quaternion - The quaternion to test for equality.
9277	 * @return {boolean} Whether this quaternion is equal with the given one.
9278	 */
9279	equals( quaternion ) {
9280
9281		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
9282
9283	}
9284
9285	/**
9286	 * Sets this quaternion's components from the given array.
9287	 *
9288	 * @param {Array<number>} array - An array holding the quaternion component values.
9289	 * @param {number} [offset=0] - The offset into the array.
9290	 * @return {Quaternion} A reference to this quaternion.
9291	 */
9292	fromArray( array, offset = 0 ) {
9293
9294		this._x = array[ offset ];
9295		this._y = array[ offset + 1 ];
9296		this._z = array[ offset + 2 ];
9297		this._w = array[ offset + 3 ];
9298
9299		this._onChangeCallback();
9300
9301		return this;
9302
9303	}
9304
9305	/**
9306	 * Writes the components of this quaternion to the given array. If no array is provided,
9307	 * the method returns a new instance.
9308	 *
9309	 * @param {Array<number>} [array=[]] - The target array holding the quaternion components.
9310	 * @param {number} [offset=0] - Index of the first element in the array.
9311	 * @return {Array<number>} The quaternion components.
9312	 */
9313	toArray( array = [], offset = 0 ) {
9314
9315		array[ offset ] = this._x;
9316		array[ offset + 1 ] = this._y;
9317		array[ offset + 2 ] = this._z;
9318		array[ offset + 3 ] = this._w;
9319
9320		return array;
9321
9322	}
9323
9324	/**
9325	 * Sets the components of this quaternion from the given buffer attribute.
9326	 *
9327	 * @param {BufferAttribute} attribute - The buffer attribute holding quaternion data.
9328	 * @param {number} index - The index into the attribute.
9329	 * @return {Quaternion} A reference to this quaternion.
9330	 */
9331	fromBufferAttribute( attribute, index ) {
9332
9333		this._x = attribute.getX( index );
9334		this._y = attribute.getY( index );
9335		this._z = attribute.getZ( index );
9336		this._w = attribute.getW( index );
9337
9338		this._onChangeCallback();
9339
9340		return this;
9341
9342	}
9343
9344	/**
9345	 * This methods defines the serialization result of this class. Returns the
9346	 * numerical elements of this quaternion in an array of format `[x, y, z, w]`.
9347	 *
9348	 * @return {Array<number>} The serialized quaternion.
9349	 */
9350	toJSON() {
9351
9352		return this.toArray();
9353
9354	}
9355
9356	_onChange( callback ) {
9357
9358		this._onChangeCallback = callback;
9359
9360		return this;
9361
9362	}
9363
9364	_onChangeCallback() {}
9365
9366	*[ Symbol.iterator ]() {
9367
9368		yield this._x;
9369		yield this._y;
9370		yield this._z;
9371		yield this._w;
9372
9373	}
9374
9375}
9376
9377/**
9378 * Class representing a 3D vector. A 3D vector is an ordered triplet of numbers
9379 * (labeled x, y and z), which can be used to represent a number of things, such as:
9380 *
9381 * - A point in 3D space.
9382 * - A direction and length in 3D space. In three.js the length will
9383 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0)` to `(x, y, z)`
9384 * and the direction is also measured from `(0, 0, 0)` towards `(x, y, z)`.
9385 * - Any arbitrary ordered triplet of numbers.
9386 *
9387 * There are other things a 3D vector can be used to represent, such as
9388 * momentum vectors and so on, however these are the most
9389 * common uses in three.js.
9390 *
9391 * Iterating through a vector instance will yield its components `(x, y, z)` in
9392 * the corresponding order.
9393 * ```js
9394 * const a = new THREE.Vector3( 0, 1, 0 );
9395 *
9396 * //no arguments; will be initialised to (0, 0, 0)
9397 * const b = new THREE.Vector3( );
9398 *
9399 * const d = a.distanceTo( b );
9400 * ```
9401 */
9402class Vector3 {
9403
9404	
vendor: 3,883 bytes, lines 9404-9622
9404/**
9405	 * Constructs a new 3D vector.
9406	 *
9407	 * @param {number} [x=0] - The x value of this vector.
9408	 * @param {number} [y=0] - The y value of this vector.
9409	 * @param {number} [z=0] - The z value of this vector.
9410	 */
9411	constructor( x = 0, y = 0, z = 0 ) {
9412
9413		/**
9414		 * This flag can be used for type testing.
9415		 *
9416		 * @type {boolean}
9417		 * @readonly
9418		 * @default true
9419		 */
9420		Vector3.prototype.isVector3 = true;
9421
9422		/**
9423		 * The x value of this vector.
9424		 *
9425		 * @type {number}
9426		 */
9427		this.x = x;
9428
9429		/**
9430		 * The y value of this vector.
9431		 *
9432		 * @type {number}
9433		 */
9434		this.y = y;
9435
9436		/**
9437		 * The z value of this vector.
9438		 *
9439		 * @type {number}
9440		 */
9441		this.z = z;
9442
9443	}
9444
9445	/**
9446	 * Sets the vector components.
9447	 *
9448	 * @param {number} x - The value of the x component.
9449	 * @param {number} y - The value of the y component.
9450	 * @param {number} z - The value of the z component.
9451	 * @return {Vector3} A reference to this vector.
9452	 */
9453	set( x, y, z ) {
9454
9455		if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
9456
9457		this.x = x;
9458		this.y = y;
9459		this.z = z;
9460
9461		return this;
9462
9463	}
9464
9465	/**
9466	 * Sets the vector components to the same value.
9467	 *
9468	 * @param {number} scalar - The value to set for all vector components.
9469	 * @return {Vector3} A reference to this vector.
9470	 */
9471	setScalar( scalar ) {
9472
9473		this.x = scalar;
9474		this.y = scalar;
9475		this.z = scalar;
9476
9477		return this;
9478
9479	}
9480
9481	/**
9482	 * Sets the vector's x component to the given value
9483	 *
9484	 * @param {number} x - The value to set.
9485	 * @return {Vector3} A reference to this vector.
9486	 */
9487	setX( x ) {
9488
9489		this.x = x;
9490
9491		return this;
9492
9493	}
9494
9495	/**
9496	 * Sets the vector's y component to the given value
9497	 *
9498	 * @param {number} y - The value to set.
9499	 * @return {Vector3} A reference to this vector.
9500	 */
9501	setY( y ) {
9502
9503		this.y = y;
9504
9505		return this;
9506
9507	}
9508
9509	/**
9510	 * Sets the vector's z component to the given value
9511	 *
9512	 * @param {number} z - The value to set.
9513	 * @return {Vector3} A reference to this vector.
9514	 */
9515	setZ( z ) {
9516
9517		this.z = z;
9518
9519		return this;
9520
9521	}
9522
9523	/**
9524	 * Allows to set a vector component with an index.
9525	 *
9526	 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z.
9527	 * @param {number} value - The value to set.
9528	 * @return {Vector3} A reference to this vector.
9529	 */
9530	setComponent( index, value ) {
9531
9532		switch ( index ) {
9533
9534			case 0: this.x = value; break;
9535			case 1: this.y = value; break;
9536			case 2: this.z = value; break;
9537			default: throw new Error( 'index is out of range: ' + index );
9538
9539		}
9540
9541		return this;
9542
9543	}
9544
9545	/**
9546	 * Returns the value of the vector component which matches the given index.
9547	 *
9548	 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z.
9549	 * @return {number} A vector component value.
9550	 */
9551	getComponent( index ) {
9552
9553		switch ( index ) {
9554
9555			case 0: return this.x;
9556			case 1: return this.y;
9557			case 2: return this.z;
9558			default: throw new Error( 'index is out of range: ' + index );
9559
9560		}
9561
9562	}
9563
9564	/**
9565	 * Returns a new vector with copied values from this instance.
9566	 *
9567	 * @return {Vector3} A clone of this instance.
9568	 */
9569	clone() {
9570
9571		return new this.constructor( this.x, this.y, this.z );
9572
9573	}
9574
9575	/**
9576	 * Copies the values of the given vector to this instance.
9577	 *
9578	 * @param {Vector3} v - The vector to copy.
9579	 * @return {Vector3} A reference to this vector.
9580	 */
9581	copy( v ) {
9582
9583		this.x = v.x;
9584		this.y = v.y;
9585		this.z = v.z;
9586
9587		return this;
9588
9589	}
9590
9591	/**
9592	 * Adds the given vector to this instance.
9593	 *
9594	 * @param {Vector3} v - The vector to add.
9595	 * @return {Vector3} A reference to this vector.
9596	 */
9597	add( v ) {
9598
9599		this.x += v.x;
9600		this.y += v.y;
9601		this.z += v.z;
9602
9603		return this;
9604
9605	}
9606
9607	/**
9608	 * Adds the given scalar value to all components of this instance.
9609	 *
9610	 * @param {number} s - The scalar to add.
9611	 * @return {Vector3} A reference to this vector.
9612	 */
9613	addScalar( s ) {
9614
9615		this.x += s;
9616		this.y += s;
9617		this.z += s;
9618
9619		return this;
9620
9621	}
9622
vendor: 11,109 bytes, lines 9623-10120
9623	/**
9624	 * Adds the given vectors and stores the result in this instance.
9625	 *
9626	 * @param {Vector3} a - The first vector.
9627	 * @param {Vector3} b - The second vector.
9628	 * @return {Vector3} A reference to this vector.
9629	 */
9630	addVectors( a, b ) {
9631
9632		this.x = a.x + b.x;
9633		this.y = a.y + b.y;
9634		this.z = a.z + b.z;
9635
9636		return this;
9637
9638	}
9639
9640	/**
9641	 * Adds the given vector scaled by the given factor to this instance.
9642	 *
9643	 * @param {Vector3|Vector4} v - The vector.
9644	 * @param {number} s - The factor that scales `v`.
9645	 * @return {Vector3} A reference to this vector.
9646	 */
9647	addScaledVector( v, s ) {
9648
9649		this.x += v.x * s;
9650		this.y += v.y * s;
9651		this.z += v.z * s;
9652
9653		return this;
9654
9655	}
9656
9657	/**
9658	 * Subtracts the given vector from this instance.
9659	 *
9660	 * @param {Vector3} v - The vector to subtract.
9661	 * @return {Vector3} A reference to this vector.
9662	 */
9663	sub( v ) {
9664
9665		this.x -= v.x;
9666		this.y -= v.y;
9667		this.z -= v.z;
9668
9669		return this;
9670
9671	}
9672
9673	/**
9674	 * Subtracts the given scalar value from all components of this instance.
9675	 *
9676	 * @param {number} s - The scalar to subtract.
9677	 * @return {Vector3} A reference to this vector.
9678	 */
9679	subScalar( s ) {
9680
9681		this.x -= s;
9682		this.y -= s;
9683		this.z -= s;
9684
9685		return this;
9686
9687	}
9688
9689	/**
9690	 * Subtracts the given vectors and stores the result in this instance.
9691	 *
9692	 * @param {Vector3} a - The first vector.
9693	 * @param {Vector3} b - The second vector.
9694	 * @return {Vector3} A reference to this vector.
9695	 */
9696	subVectors( a, b ) {
9697
9698		this.x = a.x - b.x;
9699		this.y = a.y - b.y;
9700		this.z = a.z - b.z;
9701
9702		return this;
9703
9704	}
9705
9706	/**
9707	 * Multiplies the given vector with this instance.
9708	 *
9709	 * @param {Vector3} v - The vector to multiply.
9710	 * @return {Vector3} A reference to this vector.
9711	 */
9712	multiply( v ) {
9713
9714		this.x *= v.x;
9715		this.y *= v.y;
9716		this.z *= v.z;
9717
9718		return this;
9719
9720	}
9721
9722	/**
9723	 * Multiplies the given scalar value with all components of this instance.
9724	 *
9725	 * @param {number} scalar - The scalar to multiply.
9726	 * @return {Vector3} A reference to this vector.
9727	 */
9728	multiplyScalar( scalar ) {
9729
9730		this.x *= scalar;
9731		this.y *= scalar;
9732		this.z *= scalar;
9733
9734		return this;
9735
9736	}
9737
9738	/**
9739	 * Multiplies the given vectors and stores the result in this instance.
9740	 *
9741	 * @param {Vector3} a - The first vector.
9742	 * @param {Vector3} b - The second vector.
9743	 * @return {Vector3} A reference to this vector.
9744	 */
9745	multiplyVectors( a, b ) {
9746
9747		this.x = a.x * b.x;
9748		this.y = a.y * b.y;
9749		this.z = a.z * b.z;
9750
9751		return this;
9752
9753	}
9754
9755	/**
9756	 * Applies the given Euler rotation to this vector.
9757	 *
9758	 * @param {Euler} euler - The Euler angles.
9759	 * @return {Vector3} A reference to this vector.
9760	 */
9761	applyEuler( euler ) {
9762
9763		return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) );
9764
9765	}
9766
9767	/**
9768	 * Applies a rotation specified by an axis and an angle to this vector.
9769	 *
9770	 * @param {Vector3} axis - A normalized vector representing the rotation axis.
9771	 * @param {number} angle - The angle in radians.
9772	 * @return {Vector3} A reference to this vector.
9773	 */
9774	applyAxisAngle( axis, angle ) {
9775
9776		return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) );
9777
9778	}
9779
9780	/**
9781	 * Multiplies this vector with the given 3x3 matrix.
9782	 *
9783	 * @param {Matrix3} m - The 3x3 matrix.
9784	 * @return {Vector3} A reference to this vector.
9785	 */
9786	applyMatrix3( m ) {
9787
9788		const x = this.x, y = this.y, z = this.z;
9789		const e = m.elements;
9790
9791		this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
9792		this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
9793		this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
9794
9795		return this;
9796
9797	}
9798
9799	/**
9800	 * Multiplies this vector by the given normal matrix and normalizes
9801	 * the result.
9802	 *
9803	 * @param {Matrix3} m - The normal matrix.
9804	 * @return {Vector3} A reference to this vector.
9805	 */
9806	applyNormalMatrix( m ) {
9807
9808		return this.applyMatrix3( m ).normalize();
9809
9810	}
9811
9812	/**
9813	 * Multiplies this vector (with an implicit 1 in the 4th dimension) by m, and
9814	 * divides by perspective.
9815	 *
9816	 * @param {Matrix4} m - The matrix to apply.
9817	 * @return {Vector3} A reference to this vector.
9818	 */
9819	applyMatrix4( m ) {
9820
9821		const x = this.x, y = this.y, z = this.z;
9822		const e = m.elements;
9823
9824		const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
9825
9826		this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
9827		this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
9828		this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
9829
9830		return this;
9831
9832	}
9833
9834	/**
9835	 * Applies the given Quaternion to this vector.
9836	 *
9837	 * @param {Quaternion} q - The Quaternion.
9838	 * @return {Vector3} A reference to this vector.
9839	 */
9840	applyQuaternion( q ) {
9841
9842		// quaternion q is assumed to have unit length
9843
9844		const vx = this.x, vy = this.y, vz = this.z;
9845		const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
9846
9847		// t = 2 * cross( q.xyz, v );
9848		const tx = 2 * ( qy * vz - qz * vy );
9849		const ty = 2 * ( qz * vx - qx * vz );
9850		const tz = 2 * ( qx * vy - qy * vx );
9851
9852		// v + q.w * t + cross( q.xyz, t );
9853		this.x = vx + qw * tx + qy * tz - qz * ty;
9854		this.y = vy + qw * ty + qz * tx - qx * tz;
9855		this.z = vz + qw * tz + qx * ty - qy * tx;
9856
9857		return this;
9858
9859	}
9860
9861	/**
9862	 * Projects this vector from world space into the camera's normalized
9863	 * device coordinate (NDC) space.
9864	 *
9865	 * @param {Camera} camera - The camera.
9866	 * @return {Vector3} A reference to this vector.
9867	 */
9868	project( camera ) {
9869
9870		return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
9871
9872	}
9873
9874	/**
9875	 * Unprojects this vector from the camera's normalized device coordinate (NDC)
9876	 * space into world space.
9877	 *
9878	 * @param {Camera} camera - The camera.
9879	 * @return {Vector3} A reference to this vector.
9880	 */
9881	unproject( camera ) {
9882
9883		return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
9884
9885	}
9886
9887	/**
9888	 * Transforms the direction of this vector by a matrix (the upper left 3 x 3
9889	 * subset of the given 4x4 matrix and then normalizes the result.
9890	 *
9891	 * @param {Matrix4} m - The matrix.
9892	 * @return {Vector3} A reference to this vector.
9893	 */
9894	transformDirection( m ) {
9895
9896		// input: THREE.Matrix4 affine matrix
9897		// vector interpreted as a direction
9898
9899		const x = this.x, y = this.y, z = this.z;
9900		const e = m.elements;
9901
9902		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
9903		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
9904		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
9905
9906		return this.normalize();
9907
9908	}
9909
9910	/**
9911	 * Divides this instance by the given vector.
9912	 *
9913	 * @param {Vector3} v - The vector to divide.
9914	 * @return {Vector3} A reference to this vector.
9915	 */
9916	divide( v ) {
9917
9918		this.x /= v.x;
9919		this.y /= v.y;
9920		this.z /= v.z;
9921
9922		return this;
9923
9924	}
9925
9926	/**
9927	 * Divides this vector by the given scalar.
9928	 *
9929	 * @param {number} scalar - The scalar to divide.
9930	 * @return {Vector3} A reference to this vector.
9931	 */
9932	divideScalar( scalar ) {
9933
9934		return this.multiplyScalar( 1 / scalar );
9935
9936	}
9937
9938	/**
9939	 * If this vector's x, y or z value is greater than the given vector's x, y or z
9940	 * value, replace that value with the corresponding min value.
9941	 *
9942	 * @param {Vector3} v - The vector.
9943	 * @return {Vector3} A reference to this vector.
9944	 */
9945	min( v ) {
9946
9947		this.x = Math.min( this.x, v.x );
9948		this.y = Math.min( this.y, v.y );
9949		this.z = Math.min( this.z, v.z );
9950
9951		return this;
9952
9953	}
9954
9955	/**
9956	 * If this vector's x, y or z value is less than the given vector's x, y or z
9957	 * value, replace that value with the corresponding max value.
9958	 *
9959	 * @param {Vector3} v - The vector.
9960	 * @return {Vector3} A reference to this vector.
9961	 */
9962	max( v ) {
9963
9964		this.x = Math.max( this.x, v.x );
9965		this.y = Math.max( this.y, v.y );
9966		this.z = Math.max( this.z, v.z );
9967
9968		return this;
9969
9970	}
9971
9972	/**
9973	 * If this vector's x, y or z value is greater than the max vector's x, y or z
9974	 * value, it is replaced by the corresponding value.
9975	 * If this vector's x, y or z value is less than the min vector's x, y or z value,
9976	 * it is replaced by the corresponding value.
9977	 *
9978	 * @param {Vector3} min - The minimum x, y and z values.
9979	 * @param {Vector3} max - The maximum x, y and z values in the desired range.
9980	 * @return {Vector3} A reference to this vector.
9981	 */
9982	clamp( min, max ) {
9983
9984		// assumes min < max, componentwise
9985
9986		this.x = clamp( this.x, min.x, max.x );
9987		this.y = clamp( this.y, min.y, max.y );
9988		this.z = clamp( this.z, min.z, max.z );
9989
9990		return this;
9991
9992	}
9993
9994	/**
9995	 * If this vector's x, y or z values are greater than the max value, they are
9996	 * replaced by the max value.
9997	 * If this vector's x, y or z values are less than the min value, they are
9998	 * replaced by the min value.
9999	 *
10000	 * @param {number} minVal - The minimum value the components will be clamped to.
10001	 * @param {number} maxVal - The maximum value the components will be clamped to.
10002	 * @return {Vector3} A reference to this vector.
10003	 */
10004	clampScalar( minVal, maxVal ) {
10005
10006		this.x = clamp( this.x, minVal, maxVal );
10007		this.y = clamp( this.y, minVal, maxVal );
10008		this.z = clamp( this.z, minVal, maxVal );
10009
10010		return this;
10011
10012	}
10013
10014	/**
10015	 * If this vector's length is greater than the max value, it is replaced by
10016	 * the max value.
10017	 * If this vector's length is less than the min value, it is replaced by the
10018	 * min value.
10019	 *
10020	 * @param {number} min - The minimum value the vector length will be clamped to.
10021	 * @param {number} max - The maximum value the vector length will be clamped to.
10022	 * @return {Vector3} A reference to this vector.
10023	 */
10024	clampLength( min, max ) {
10025
10026		const length = this.length();
10027
10028		return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) );
10029
10030	}
10031
10032	/**
10033	 * The components of this vector are rounded down to the nearest integer value.
10034	 *
10035	 * @return {Vector3} A reference to this vector.
10036	 */
10037	floor() {
10038
10039		this.x = Math.floor( this.x );
10040		this.y = Math.floor( this.y );
10041		this.z = Math.floor( this.z );
10042
10043		return this;
10044
10045	}
10046
10047	/**
10048	 * The components of this vector are rounded up to the nearest integer value.
10049	 *
10050	 * @return {Vector3} A reference to this vector.
10051	 */
10052	ceil() {
10053
10054		this.x = Math.ceil( this.x );
10055		this.y = Math.ceil( this.y );
10056		this.z = Math.ceil( this.z );
10057
10058		return this;
10059
10060	}
10061
10062	/**
10063	 * The components of this vector are rounded to the nearest integer value
10064	 *
10065	 * @return {Vector3} A reference to this vector.
10066	 */
10067	round() {
10068
10069		this.x = Math.round( this.x );
10070		this.y = Math.round( this.y );
10071		this.z = Math.round( this.z );
10072
10073		return this;
10074
10075	}
10076
10077	/**
10078	 * The components of this vector are rounded towards zero (up if negative,
10079	 * down if positive) to an integer value.
10080	 *
10081	 * @return {Vector3} A reference to this vector.
10082	 */
10083	roundToZero() {
10084
10085		this.x = Math.trunc( this.x );
10086		this.y = Math.trunc( this.y );
10087		this.z = Math.trunc( this.z );
10088
10089		return this;
10090
10091	}
10092
10093	/**
10094	 * Inverts this vector - i.e. sets x = -x, y = -y and z = -z.
10095	 *
10096	 * @return {Vector3} A reference to this vector.
10097	 */
10098	negate() {
10099
10100		this.x = - this.x;
10101		this.y = - this.y;
10102		this.z = - this.z;
10103
10104		return this;
10105
10106	}
10107
10108	/**
10109	 * Calculates the dot product of the given vector with this instance.
10110	 *
10111	 * @param {Vector3} v - The vector to compute the dot product with.
10112	 * @return {number} The result of the dot product.
10113	 */
10114	dot( v ) {
10115
10116		return this.x * v.x + this.y * v.y + this.z * v.z;
10117
10118	}
10119
10120	// TODO lengthSquared?
vendor: 12,137 bytes, lines 10120-10632
10120
10121
10122	/**
10123	 * Computes the square of the Euclidean length (straight-line length) from
10124	 * (0, 0, 0) to (x, y, z). If you are comparing the lengths of vectors, you should
10125	 * compare the length squared instead as it is slightly more efficient to calculate.
10126	 *
10127	 * @return {number} The square length of this vector.
10128	 */
10129	lengthSq() {
10130
10131		return this.x * this.x + this.y * this.y + this.z * this.z;
10132
10133	}
10134
10135	/**
10136	 * Computes the  Euclidean length (straight-line length) from (0, 0, 0) to (x, y, z).
10137	 *
10138	 * @return {number} The length of this vector.
10139	 */
10140	length() {
10141
10142		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
10143
10144	}
10145
10146	/**
10147	 * Computes the Manhattan length of this vector.
10148	 *
10149	 * @return {number} The length of this vector.
10150	 */
10151	manhattanLength() {
10152
10153		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
10154
10155	}
10156
10157	/**
10158	 * Converts this vector to a unit vector - that is, sets it equal to a vector
10159	 * with the same direction as this one, but with a vector length of `1`.
10160	 *
10161	 * @return {Vector3} A reference to this vector.
10162	 */
10163	normalize() {
10164
10165		return this.divideScalar( this.length() || 1 );
10166
10167	}
10168
10169	/**
10170	 * Sets this vector to a vector with the same direction as this one, but
10171	 * with the specified length.
10172	 *
10173	 * @param {number} length - The new length of this vector.
10174	 * @return {Vector3} A reference to this vector.
10175	 */
10176	setLength( length ) {
10177
10178		return this.normalize().multiplyScalar( length );
10179
10180	}
10181
10182	/**
10183	 * Linearly interpolates between the given vector and this instance, where
10184	 * alpha is the percent distance along the line - alpha = 0 will be this
10185	 * vector, and alpha = 1 will be the given one.
10186	 *
10187	 * @param {Vector3} v - The vector to interpolate towards.
10188	 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
10189	 * @return {Vector3} A reference to this vector.
10190	 */
10191	lerp( v, alpha ) {
10192
10193		this.x += ( v.x - this.x ) * alpha;
10194		this.y += ( v.y - this.y ) * alpha;
10195		this.z += ( v.z - this.z ) * alpha;
10196
10197		return this;
10198
10199	}
10200
10201	/**
10202	 * Linearly interpolates between the given vectors, where alpha is the percent
10203	 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will
10204	 * be the second one. The result is stored in this instance.
10205	 *
10206	 * @param {Vector3} v1 - The first vector.
10207	 * @param {Vector3} v2 - The second vector.
10208	 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
10209	 * @return {Vector3} A reference to this vector.
10210	 */
10211	lerpVectors( v1, v2, alpha ) {
10212
10213		this.x = v1.x + ( v2.x - v1.x ) * alpha;
10214		this.y = v1.y + ( v2.y - v1.y ) * alpha;
10215		this.z = v1.z + ( v2.z - v1.z ) * alpha;
10216
10217		return this;
10218
10219	}
10220
10221	/**
10222	 * Calculates the cross product of the given vector with this instance.
10223	 *
10224	 * @param {Vector3} v - The vector to compute the cross product with.
10225	 * @return {Vector3} The result of the cross product.
10226	 */
10227	cross( v ) {
10228
10229		return this.crossVectors( this, v );
10230
10231	}
10232
10233	/**
10234	 * Calculates the cross product of the given vectors and stores the result
10235	 * in this instance.
10236	 *
10237	 * @param {Vector3} a - The first vector.
10238	 * @param {Vector3} b - The second vector.
10239	 * @return {Vector3} A reference to this vector.
10240	 */
10241	crossVectors( a, b ) {
10242
10243		const ax = a.x, ay = a.y, az = a.z;
10244		const bx = b.x, by = b.y, bz = b.z;
10245
10246		this.x = ay * bz - az * by;
10247		this.y = az * bx - ax * bz;
10248		this.z = ax * by - ay * bx;
10249
10250		return this;
10251
10252	}
10253
10254	/**
10255	 * Projects this vector onto the given one.
10256	 *
10257	 * @param {Vector3} v - The vector to project to.
10258	 * @return {Vector3} A reference to this vector.
10259	 */
10260	projectOnVector( v ) {
10261
10262		const denominator = v.lengthSq();
10263
10264		if ( denominator === 0 ) return this.set( 0, 0, 0 );
10265
10266		const scalar = v.dot( this ) / denominator;
10267
10268		return this.copy( v ).multiplyScalar( scalar );
10269
10270	}
10271
10272	/**
10273	 * Projects this vector onto a plane by subtracting this
10274	 * vector projected onto the plane's normal from this vector.
10275	 *
10276	 * @param {Vector3} planeNormal - The plane normal.
10277	 * @return {Vector3} A reference to this vector.
10278	 */
10279	projectOnPlane( planeNormal ) {
10280
10281		_vector$c.copy( this ).projectOnVector( planeNormal );
10282
10283		return this.sub( _vector$c );
10284
10285	}
10286
10287	/**
10288	 * Reflects this vector off a plane orthogonal to the given normal vector.
10289	 *
10290	 * @param {Vector3} normal - The (normalized) normal vector.
10291	 * @return {Vector3} A reference to this vector.
10292	 */
10293	reflect( normal ) {
10294
10295		return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
10296
10297	}
10298	/**
10299	 * Returns the angle between the given vector and this instance in radians.
10300	 *
10301	 * @param {Vector3} v - The vector to compute the angle with.
10302	 * @return {number} The angle in radians.
10303	 */
10304	angleTo( v ) {
10305
10306		const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
10307
10308		if ( denominator === 0 ) return Math.PI / 2;
10309
10310		const theta = this.dot( v ) / denominator;
10311
10312		// clamp, to handle numerical problems
10313
10314		return Math.acos( clamp( theta, -1, 1 ) );
10315
10316	}
10317
10318	/**
10319	 * Computes the distance from the given vector to this instance.
10320	 *
10321	 * @param {Vector3} v - The vector to compute the distance to.
10322	 * @return {number} The distance.
10323	 */
10324	distanceTo( v ) {
10325
10326		return Math.sqrt( this.distanceToSquared( v ) );
10327
10328	}
10329
10330	/**
10331	 * Computes the squared distance from the given vector to this instance.
10332	 * If you are just comparing the distance with another distance, you should compare
10333	 * the distance squared instead as it is slightly more efficient to calculate.
10334	 *
10335	 * @param {Vector3} v - The vector to compute the squared distance to.
10336	 * @return {number} The squared distance.
10337	 */
10338	distanceToSquared( v ) {
10339
10340		const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
10341
10342		return dx * dx + dy * dy + dz * dz;
10343
10344	}
10345
10346	/**
10347	 * Computes the Manhattan distance from the given vector to this instance.
10348	 *
10349	 * @param {Vector3} v - The vector to compute the Manhattan distance to.
10350	 * @return {number} The Manhattan distance.
10351	 */
10352	manhattanDistanceTo( v ) {
10353
10354		return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
10355
10356	}
10357
10358	/**
10359	 * Sets the vector components from the given spherical coordinates.
10360	 *
10361	 * @param {Spherical} s - The spherical coordinates.
10362	 * @return {Vector3} A reference to this vector.
10363	 */
10364	setFromSpherical( s ) {
10365
10366		return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
10367
10368	}
10369
10370	/**
10371	 * Sets the vector components from the given spherical coordinates.
10372	 *
10373	 * @param {number} radius - The radius.
10374	 * @param {number} phi - The phi angle in radians.
10375	 * @param {number} theta - The theta angle in radians.
10376	 * @return {Vector3} A reference to this vector.
10377	 */
10378	setFromSphericalCoords( radius, phi, theta ) {
10379
10380		const sinPhiRadius = Math.sin( phi ) * radius;
10381
10382		this.x = sinPhiRadius * Math.sin( theta );
10383		this.y = Math.cos( phi ) * radius;
10384		this.z = sinPhiRadius * Math.cos( theta );
10385
10386		return this;
10387
10388	}
10389
10390	/**
10391	 * Sets the vector components from the given cylindrical coordinates.
10392	 *
10393	 * @param {Cylindrical} c - The cylindrical coordinates.
10394	 * @return {Vector3} A reference to this vector.
10395	 */
10396	setFromCylindrical( c ) {
10397
10398		return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
10399
10400	}
10401
10402	/**
10403	 * Sets the vector components from the given cylindrical coordinates.
10404	 *
10405	 * @param {number} radius - The radius.
10406	 * @param {number} theta - The theta angle in radians.
10407	 * @param {number} y - The y value.
10408	 * @return {Vector3} A reference to this vector.
10409	 */
10410	setFromCylindricalCoords( radius, theta, y ) {
10411
10412		this.x = radius * Math.sin( theta );
10413		this.y = y;
10414		this.z = radius * Math.cos( theta );
10415
10416		return this;
10417
10418	}
10419
10420	/**
10421	 * Sets the vector components to the position elements of the
10422	 * given transformation matrix.
10423	 *
10424	 * @param {Matrix4} m - The 4x4 matrix.
10425	 * @return {Vector3} A reference to this vector.
10426	 */
10427	setFromMatrixPosition( m ) {
10428
10429		const e = m.elements;
10430
10431		this.x = e[ 12 ];
10432		this.y = e[ 13 ];
10433		this.z = e[ 14 ];
10434
10435		return this;
10436
10437	}
10438
10439	/**
10440	 * Sets the vector components to the scale elements of the
10441	 * given transformation matrix.
10442	 *
10443	 * @param {Matrix4} m - The 4x4 matrix.
10444	 * @return {Vector3} A reference to this vector.
10445	 */
10446	setFromMatrixScale( m ) {
10447
10448		const sx = this.setFromMatrixColumn( m, 0 ).length();
10449		const sy = this.setFromMatrixColumn( m, 1 ).length();
10450		const sz = this.setFromMatrixColumn( m, 2 ).length();
10451
10452		this.x = sx;
10453		this.y = sy;
10454		this.z = sz;
10455
10456		return this;
10457
10458	}
10459
10460	/**
10461	 * Sets the vector components from the specified matrix column.
10462	 *
10463	 * @param {Matrix4} m - The 4x4 matrix.
10464	 * @param {number} index - The column index.
10465	 * @return {Vector3} A reference to this vector.
10466	 */
10467	setFromMatrixColumn( m, index ) {
10468
10469		return this.fromArray( m.elements, index * 4 );
10470
10471	}
10472
10473	/**
10474	 * Sets the vector components from the specified matrix column.
10475	 *
10476	 * @param {Matrix3} m - The 3x3 matrix.
10477	 * @param {number} index - The column index.
10478	 * @return {Vector3} A reference to this vector.
10479	 */
10480	setFromMatrix3Column( m, index ) {
10481
10482		return this.fromArray( m.elements, index * 3 );
10483
10484	}
10485
10486	/**
10487	 * Sets the vector components from the given Euler angles.
10488	 *
10489	 * @param {Euler} e - The Euler angles to set.
10490	 * @return {Vector3} A reference to this vector.
10491	 */
10492	setFromEuler( e ) {
10493
10494		this.x = e._x;
10495		this.y = e._y;
10496		this.z = e._z;
10497
10498		return this;
10499
10500	}
10501
10502	/**
10503	 * Sets the vector components from the RGB components of the
10504	 * given color.
10505	 *
10506	 * @param {Color} c - The color to set.
10507	 * @return {Vector3} A reference to this vector.
10508	 */
10509	setFromColor( c ) {
10510
10511		this.x = c.r;
10512		this.y = c.g;
10513		this.z = c.b;
10514
10515		return this;
10516
10517	}
10518
10519	/**
10520	 * Returns `true` if this vector is equal with the given one.
10521	 *
10522	 * @param {Vector3} v - The vector to test for equality.
10523	 * @return {boolean} Whether this vector is equal with the given one.
10524	 */
10525	equals( v ) {
10526
10527		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
10528
10529	}
10530
10531	/**
10532	 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]`
10533	 * and z value to be `array[ offset + 2 ]`.
10534	 *
10535	 * @param {Array<number>} array - An array holding the vector component values.
10536	 * @param {number} [offset=0] - The offset into the array.
10537	 * @return {Vector3} A reference to this vector.
10538	 */
10539	fromArray( array, offset = 0 ) {
10540
10541		this.x = array[ offset ];
10542		this.y = array[ offset + 1 ];
10543		this.z = array[ offset + 2 ];
10544
10545		return this;
10546
10547	}
10548
10549	/**
10550	 * Writes the components of this vector to the given array. If no array is provided,
10551	 * the method returns a new instance.
10552	 *
10553	 * @param {Array<number>} [array=[]] - The target array holding the vector components.
10554	 * @param {number} [offset=0] - Index of the first element in the array.
10555	 * @return {Array<number>} The vector components.
10556	 */
10557	toArray( array = [], offset = 0 ) {
10558
10559		array[ offset ] = this.x;
10560		array[ offset + 1 ] = this.y;
10561		array[ offset + 2 ] = this.z;
10562
10563		return array;
10564
10565	}
10566
10567	/**
10568	 * Sets the components of this vector from the given buffer attribute.
10569	 *
10570	 * @param {BufferAttribute} attribute - The buffer attribute holding vector data.
10571	 * @param {number} index - The index into the attribute.
10572	 * @return {Vector3} A reference to this vector.
10573	 */
10574	fromBufferAttribute( attribute, index ) {
10575
10576		this.x = attribute.getX( index );
10577		this.y = attribute.getY( index );
10578		this.z = attribute.getZ( index );
10579
10580		return this;
10581
10582	}
10583
10584	/**
10585	 * Sets each component of this vector to a pseudo-random value between `0` and
10586	 * `1`, excluding `1`.
10587	 *
10588	 * @return {Vector3} A reference to this vector.
10589	 */
10590	random() {
10591
10592		this.x = Math.random();
10593		this.y = Math.random();
10594		this.z = Math.random();
10595
10596		return this;
10597
10598	}
10599
10600	/**
10601	 * Sets this vector to a uniformly random point on a unit sphere.
10602	 *
10603	 * @return {Vector3} A reference to this vector.
10604	 */
10605	randomDirection() {
10606
10607		// https://mathworld.wolfram.com/SpherePointPicking.html
10608
10609		const theta = Math.random() * Math.PI * 2;
10610		const u = Math.random() * 2 - 1;
10611		const c = Math.sqrt( 1 - u * u );
10612
10613		this.x = c * Math.cos( theta );
10614		this.y = u;
10615		this.z = c * Math.sin( theta );
10616
10617		return this;
10618
10619	}
10620
10621	*[ Symbol.iterator ]() {
10622
10623		yield this.x;
10624		yield this.y;
10625		yield this.z;
10626
10627	}
10628
10629}
10630
10631const _vector$c = /*@__PURE__*/ new Vector3();
10632const _quaternion$
vendor: 15,977 bytes, lines 10632-11254
106324 = /*@__PURE__*/ new Quaternion();
10633
10634/**
10635 * Represents an axis-aligned bounding box (AABB) in 3D space.
10636 */
10637class Box3 {
10638
10639	/**
10640	 * Constructs a new bounding box.
10641	 *
10642	 * @param {Vector3} [min=(Infinity,Infinity,Infinity)] - A vector representing the lower boundary of the box.
10643	 * @param {Vector3} [max=(-Infinity,-Infinity,-Infinity)] - A vector representing the upper boundary of the box.
10644	 */
10645	constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {
10646
10647		/**
10648		 * This flag can be used for type testing.
10649		 *
10650		 * @type {boolean}
10651		 * @readonly
10652		 * @default true
10653		 */
10654		this.isBox3 = true;
10655
10656		/**
10657		 * The lower boundary of the box.
10658		 *
10659		 * @type {Vector3}
10660		 */
10661		this.min = min;
10662
10663		/**
10664		 * The upper boundary of the box.
10665		 *
10666		 * @type {Vector3}
10667		 */
10668		this.max = max;
10669
10670	}
10671
10672	/**
10673	 * Sets the lower and upper boundaries of this box.
10674	 * Please note that this method only copies the values from the given objects.
10675	 *
10676	 * @param {Vector3} min - The lower boundary of the box.
10677	 * @param {Vector3} max - The upper boundary of the box.
10678	 * @return {Box3} A reference to this bounding box.
10679	 */
10680	set( min, max ) {
10681
10682		this.min.copy( min );
10683		this.max.copy( max );
10684
10685		return this;
10686
10687	}
10688
10689	/**
10690	 * Sets the upper and lower bounds of this box so it encloses the position data
10691	 * in the given array.
10692	 *
10693	 * @param {Array<number>} array - An array holding 3D position data.
10694	 * @return {Box3} A reference to this bounding box.
10695	 */
10696	setFromArray( array ) {
10697
10698		this.makeEmpty();
10699
10700		for ( let i = 0, il = array.length; i < il; i += 3 ) {
10701
10702			this.expandByPoint( _vector$b.fromArray( array, i ) );
10703
10704		}
10705
10706		return this;
10707
10708	}
10709
10710	/**
10711	 * Sets the upper and lower bounds of this box so it encloses the position data
10712	 * in the given buffer attribute.
10713	 *
10714	 * @param {BufferAttribute} attribute - A buffer attribute holding 3D position data.
10715	 * @return {Box3} A reference to this bounding box.
10716	 */
10717	setFromBufferAttribute( attribute ) {
10718
10719		this.makeEmpty();
10720
10721		for ( let i = 0, il = attribute.count; i < il; i ++ ) {
10722
10723			this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) );
10724
10725		}
10726
10727		return this;
10728
10729	}
10730
10731	/**
10732	 * Sets the upper and lower bounds of this box so it encloses the position data
10733	 * in the given array.
10734	 *
10735	 * @param {Array<Vector3>} points - An array holding 3D position data as instances of {@link Vector3}.
10736	 * @return {Box3} A reference to this bounding box.
10737	 */
10738	setFromPoints( points ) {
10739
10740		this.makeEmpty();
10741
10742		for ( let i = 0, il = points.length; i < il; i ++ ) {
10743
10744			this.expandByPoint( points[ i ] );
10745
10746		}
10747
10748		return this;
10749
10750	}
10751
10752	/**
10753	 * Centers this box on the given center vector and sets this box's width, height and
10754	 * depth to the given size values.
10755	 *
10756	 * @param {Vector3} center - The center of the box.
10757	 * @param {Vector3} size - The x, y and z dimensions of the box.
10758	 * @return {Box3} A reference to this bounding box.
10759	 */
10760	setFromCenterAndSize( center, size ) {
10761
10762		const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 );
10763
10764		this.min.copy( center ).sub( halfSize );
10765		this.max.copy( center ).add( halfSize );
10766
10767		return this;
10768
10769	}
10770
10771	/**
10772	 * Computes the world-axis-aligned bounding box for the given 3D object
10773	 * (including its children), accounting for the object's, and children's,
10774	 * world transforms. The function may result in a larger box than strictly necessary.
10775	 *
10776	 * @param {Object3D} object - The 3D object to compute the bounding box for.
10777	 * @param {boolean} [precise=false] - If set to `true`, the method computes the smallest
10778	 * world-axis-aligned bounding box at the expense of more computation.
10779	 * @return {Box3} A reference to this bounding box.
10780	 */
10781	setFromObject( object, precise = false ) {
10782
10783		this.makeEmpty();
10784
10785		return this.expandByObject( object, precise );
10786
10787	}
10788
10789	/**
10790	 * Returns a new box with copied values from this instance.
10791	 *
10792	 * @return {Box3} A clone of this instance.
10793	 */
10794	clone() {
10795
10796		return new this.constructor().copy( this );
10797
10798	}
10799
10800	/**
10801	 * Copies the values of the given box to this instance.
10802	 *
10803	 * @param {Box3} box - The box to copy.
10804	 * @return {Box3} A reference to this bounding box.
10805	 */
10806	copy( box ) {
10807
10808		this.min.copy( box.min );
10809		this.max.copy( box.max );
10810
10811		return this;
10812
10813	}
10814
10815	/**
10816	 * Makes this box empty which means in encloses a zero space in 3D.
10817	 *
10818	 * @return {Box3} A reference to this bounding box.
10819	 */
10820	makeEmpty() {
10821
10822		this.min.x = this.min.y = this.min.z = + Infinity;
10823		this.max.x = this.max.y = this.max.z = - Infinity;
10824
10825		return this;
10826
10827	}
10828
10829	/**
10830	 * Returns true if this box includes zero points within its bounds.
10831	 * Note that a box with equal lower and upper bounds still includes one
10832	 * point, the one both bounds share.
10833	 *
10834	 * @return {boolean} Whether this box is empty or not.
10835	 */
10836	isEmpty() {
10837
10838		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
10839
10840		return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
10841
10842	}
10843
10844	/**
10845	 * Returns the center point of this box.
10846	 *
10847	 * @param {Vector3} target - The target vector that is used to store the method's result.
10848	 * @return {Vector3} The center point.
10849	 */
10850	getCenter( target ) {
10851
10852		return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
10853
10854	}
10855
10856	/**
10857	 * Returns the dimensions of this box.
10858	 *
10859	 * @param {Vector3} target - The target vector that is used to store the method's result.
10860	 * @return {Vector3} The size.
10861	 */
10862	getSize( target ) {
10863
10864		return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
10865
10866	}
10867
10868	/**
10869	 * Expands the boundaries of this box to include the given point.
10870	 *
10871	 * @param {Vector3} point - The point that should be included by the bounding box.
10872	 * @return {Box3} A reference to this bounding box.
10873	 */
10874	expandByPoint( point ) {
10875
10876		this.min.min( point );
10877		this.max.max( point );
10878
10879		return this;
10880
10881	}
10882
10883	/**
10884	 * Expands this box equilaterally by the given vector. The width of this
10885	 * box will be expanded by the x component of the vector in both
10886	 * directions. The height of this box will be expanded by the y component of
10887	 * the vector in both directions. The depth of this box will be
10888	 * expanded by the z component of the vector in both directions.
10889	 *
10890	 * @param {Vector3} vector - The vector that should expand the bounding box.
10891	 * @return {Box3} A reference to this bounding box.
10892	 */
10893	expandByVector( vector ) {
10894
10895		this.min.sub( vector );
10896		this.max.add( vector );
10897
10898		return this;
10899
10900	}
10901
10902	/**
10903	 * Expands each dimension of the box by the given scalar. If negative, the
10904	 * dimensions of the box will be contracted.
10905	 *
10906	 * @param {number} scalar - The scalar value that should expand the bounding box.
10907	 * @return {Box3} A reference to this bounding box.
10908	 */
10909	expandByScalar( scalar ) {
10910
10911		this.min.addScalar( - scalar );
10912		this.max.addScalar( scalar );
10913
10914		return this;
10915
10916	}
10917
10918	/**
10919	 * Expands the boundaries of this box to include the given 3D object and
10920	 * its children, accounting for the object's, and children's, world
10921	 * transforms. The function may result in a larger box than strictly
10922	 * necessary (unless the precise parameter is set to true).
10923	 *
10924	 * @param {Object3D} object - The 3D object that should expand the bounding box.
10925	 * @param {boolean} precise - If set to `true`, the method expands the bounding box
10926	 * as little as necessary at the expense of more computation.
10927	 * @return {Box3} A reference to this bounding box.
10928	 */
10929	expandByObject( object, precise = false ) {
10930
10931		// Computes the world-axis-aligned bounding box of an object (including its children),
10932		// accounting for both the object's, and children's, world transforms
10933
10934		object.updateWorldMatrix( false, false );
10935
10936		const geometry = object.geometry;
10937
10938		if ( geometry !== undefined ) {
10939
10940			const positionAttribute = geometry.getAttribute( 'position' );
10941
10942			// precise AABB computation based on vertex data requires at least a position attribute.
10943			// instancing isn't supported so far and uses the normal (conservative) code path.
10944
10945			if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {
10946
10947				for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
10948
10949					if ( object.isMesh === true ) {
10950
10951						object.getVertexPosition( i, _vector$b );
10952
10953					} else {
10954
10955						_vector$b.fromBufferAttribute( positionAttribute, i );
10956
10957					}
10958
10959					_vector$b.applyMatrix4( object.matrixWorld );
10960					this.expandByPoint( _vector$b );
10961
10962				}
10963
10964			} else {
10965
10966				if ( object.boundingBox !== undefined ) {
10967
10968					// object-level bounding box
10969
10970					if ( object.boundingBox === null ) {
10971
10972						object.computeBoundingBox();
10973
10974					}
10975
10976					_box$4.copy( object.boundingBox );
10977
10978
10979				} else {
10980
10981					// geometry-level bounding box
10982
10983					if ( geometry.boundingBox === null ) {
10984
10985						geometry.computeBoundingBox();
10986
10987					}
10988
10989					_box$4.copy( geometry.boundingBox );
10990
10991				}
10992
10993				_box$4.applyMatrix4( object.matrixWorld );
10994
10995				this.union( _box$4 );
10996
10997			}
10998
10999		}
11000
11001		const children = object.children;
11002
11003		for ( let i = 0, l = children.length; i < l; i ++ ) {
11004
11005			this.expandByObject( children[ i ], precise );
11006
11007		}
11008
11009		return this;
11010
11011	}
11012
11013	/**
11014	 * Returns `true` if the given point lies within or on the boundaries of this box.
11015	 *
11016	 * @param {Vector3} point - The point to test.
11017	 * @return {boolean} Whether the bounding box contains the given point or not.
11018	 */
11019	containsPoint( point ) {
11020
11021		return point.x >= this.min.x && point.x <= this.max.x &&
11022			point.y >= this.min.y && point.y <= this.max.y &&
11023			point.z >= this.min.z && point.z <= this.max.z;
11024
11025	}
11026
11027	/**
11028	 * Returns `true` if this bounding box includes the entirety of the given bounding box.
11029	 * If this box and the given one are identical, this function also returns `true`.
11030	 *
11031	 * @param {Box3} box - The bounding box to test.
11032	 * @return {boolean} Whether the bounding box contains the given bounding box or not.
11033	 */
11034	containsBox( box ) {
11035
11036		return this.min.x <= box.min.x && box.max.x <= this.max.x &&
11037			this.min.y <= box.min.y && box.max.y <= this.max.y &&
11038			this.min.z <= box.min.z && box.max.z <= this.max.z;
11039
11040	}
11041
11042	/**
11043	 * Returns a point as a proportion of this box's width, height and depth.
11044	 *
11045	 * @param {Vector3} point - A point in 3D space.
11046	 * @param {Vector3} target - The target vector that is used to store the method's result.
11047	 * @return {Vector3} A point as a proportion of this box's width, height and depth.
11048	 */
11049	getParameter( point, target ) {
11050
11051		// This can potentially have a divide by zero if the box
11052		// has a size dimension of 0.
11053
11054		return target.set(
11055			( point.x - this.min.x ) / ( this.max.x - this.min.x ),
11056			( point.y - this.min.y ) / ( this.max.y - this.min.y ),
11057			( point.z - this.min.z ) / ( this.max.z - this.min.z )
11058		);
11059
11060	}
11061
11062	/**
11063	 * Returns `true` if the given bounding box intersects with this bounding box.
11064	 *
11065	 * @param {Box3} box - The bounding box to test.
11066	 * @return {boolean} Whether the given bounding box intersects with this bounding box.
11067	 */
11068	intersectsBox( box ) {
11069
11070		// using 6 splitting planes to rule out intersections.
11071		return box.max.x >= this.min.x && box.min.x <= this.max.x &&
11072			box.max.y >= this.min.y && box.min.y <= this.max.y &&
11073			box.max.z >= this.min.z && box.min.z <= this.max.z;
11074
11075	}
11076
11077	/**
11078	 * Returns `true` if the given bounding sphere intersects with this bounding box.
11079	 *
11080	 * @param {Sphere} sphere - The bounding sphere to test.
11081	 * @return {boolean} Whether the given bounding sphere intersects with this bounding box.
11082	 */
11083	intersectsSphere( sphere ) {
11084
11085		// Find the point on the AABB closest to the sphere center.
11086		this.clampPoint( sphere.center, _vector$b );
11087
11088		// If that point is inside the sphere, the AABB and sphere intersect.
11089		return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
11090
11091	}
11092
11093	/**
11094	 * Returns `true` if the given plane intersects with this bounding box.
11095	 *
11096	 * @param {Plane} plane - The plane to test.
11097	 * @return {boolean} Whether the given plane intersects with this bounding box.
11098	 */
11099	intersectsPlane( plane ) {
11100
11101		// We compute the minimum and maximum dot product values. If those values
11102		// are on the same side (back or front) of the plane, then there is no intersection.
11103
11104		let min, max;
11105
11106		if ( plane.normal.x > 0 ) {
11107
11108			min = plane.normal.x * this.min.x;
11109			max = plane.normal.x * this.max.x;
11110
11111		} else {
11112
11113			min = plane.normal.x * this.max.x;
11114			max = plane.normal.x * this.min.x;
11115
11116		}
11117
11118		if ( plane.normal.y > 0 ) {
11119
11120			min += plane.normal.y * this.min.y;
11121			max += plane.normal.y * this.max.y;
11122
11123		} else {
11124
11125			min += plane.normal.y * this.max.y;
11126			max += plane.normal.y * this.min.y;
11127
11128		}
11129
11130		if ( plane.normal.z > 0 ) {
11131
11132			min += plane.normal.z * this.min.z;
11133			max += plane.normal.z * this.max.z;
11134
11135		} else {
11136
11137			min += plane.normal.z * this.max.z;
11138			max += plane.normal.z * this.min.z;
11139
11140		}
11141
11142		return ( min <= - plane.constant && max >= - plane.constant );
11143
11144	}
11145
11146	/**
11147	 * Returns `true` if the given triangle intersects with this bounding box.
11148	 *
11149	 * @param {Triangle} triangle - The triangle to test.
11150	 * @return {boolean} Whether the given triangle intersects with this bounding box.
11151	 */
11152	intersectsTriangle( triangle ) {
11153
11154		if ( this.isEmpty() ) {
11155
11156			return false;
11157
11158		}
11159
11160		// compute box center and extents
11161		this.getCenter( _center );
11162		_extents.subVectors( this.max, _center );
11163
11164		// translate triangle to aabb origin
11165		_v0$2.subVectors( triangle.a, _center );
11166		_v1$7.subVectors( triangle.b, _center );
11167		_v2$4.subVectors( triangle.c, _center );
11168
11169		// compute edge vectors for triangle
11170		_f0.subVectors( _v1$7, _v0$2 );
11171		_f1.subVectors( _v2$4, _v1$7 );
11172		_f2.subVectors( _v0$2, _v2$4 );
11173
11174		// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
11175		// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
11176		// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
11177		let axes = [
11178			0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
11179			_f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
11180			- _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
11181		];
11182		if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {
11183
11184			return false;
11185
11186		}
11187
11188		// test 3 face normals from the aabb
11189		axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
11190		if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {
11191
11192			return false;
11193
11194		}
11195
11196		// finally testing the face normal of the triangle
11197		// use already existing triangle edge vectors here
11198		_triangleNormal.crossVectors( _f0, _f1 );
11199		axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
11200
11201		return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents );
11202
11203	}
11204
11205	/**
11206	 * Clamps the given point within the bounds of this box.
11207	 *
11208	 * @param {Vector3} point - The point to clamp.
11209	 * @param {Vector3} target - The target vector that is used to store the method's result.
11210	 * @return {Vector3} The clamped point.
11211	 */
11212	clampPoint( point, target ) {
11213
11214		return target.copy( point ).clamp( this.min, this.max );
11215
11216	}
11217
11218	/**
11219	 * Returns the euclidean distance from any edge of this box to the specified point. If
11220	 * the given point lies inside of this box, the distance will be `0`.
11221	 *
11222	 * @param {Vector3} point - The point to compute the distance to.
11223	 * @return {number} The euclidean distance.
11224	 */
11225	distanceToPoint( point ) {
11226
11227		return this.clampPoint( point, _vector$b ).distanceTo( point );
11228
11229	}
11230
11231	/**
11232	 * Returns a bounding sphere that encloses this bounding box.
11233	 *
11234	 * @param {Sphere} target - The target sphere that is used to store the method's result.
11235	 * @return {Sphere} The bounding sphere that encloses this bounding box.
11236	 */
11237	getBoundingSphere( target ) {
11238
11239		if ( this.isEmpty() ) {
11240
11241			target.makeEmpty();
11242
11243		} else {
11244
11245			this.getCenter( target.center );
11246
11247			target.radius = this.getSize( _vector$b ).length() * 0.5;
11248
11249		}
11250
11251		return target;
11252
11253	}
11254
vendor: 8,977 bytes, lines 11255-11600
11255	/**
11256	 * Computes the intersection of this bounding box and the given one, setting the upper
11257	 * bound of this box to the lesser of the two boxes' upper bounds and the
11258	 * lower bound of this box to the greater of the two boxes' lower bounds. If
11259	 * there's no overlap, makes this box empty.
11260	 *
11261	 * @param {Box3} box - The bounding box to intersect with.
11262	 * @return {Box3} A reference to this bounding box.
11263	 */
11264	intersect( box ) {
11265
11266		this.min.max( box.min );
11267		this.max.min( box.max );
11268
11269		// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
11270		if ( this.isEmpty() ) this.makeEmpty();
11271
11272		return this;
11273
11274	}
11275
11276	/**
11277	 * Computes the union of this box and another and the given one, setting the upper
11278	 * bound of this box to the greater of the two boxes' upper bounds and the
11279	 * lower bound of this box to the lesser of the two boxes' lower bounds.
11280	 *
11281	 * @param {Box3} box - The bounding box that will be unioned with this instance.
11282	 * @return {Box3} A reference to this bounding box.
11283	 */
11284	union( box ) {
11285
11286		this.min.min( box.min );
11287		this.max.max( box.max );
11288
11289		return this;
11290
11291	}
11292
11293	/**
11294	 * Transforms this bounding box by the given 4x4 transformation matrix.
11295	 *
11296	 * @param {Matrix4} matrix - The transformation matrix.
11297	 * @return {Box3} A reference to this bounding box.
11298	 */
11299	applyMatrix4( matrix ) {
11300
11301		// transform of empty box is an empty box.
11302		if ( this.isEmpty() ) return this;
11303
11304		// NOTE: I am using a binary pattern to specify all 2^3 combinations below
11305		_points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
11306		_points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
11307		_points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
11308		_points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
11309		_points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
11310		_points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
11311		_points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
11312		_points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
11313
11314		this.setFromPoints( _points );
11315
11316		return this;
11317
11318	}
11319
11320	/**
11321	 * Adds the given offset to both the upper and lower bounds of this bounding box,
11322	 * effectively moving it in 3D space.
11323	 *
11324	 * @param {Vector3} offset - The offset that should be used to translate the bounding box.
11325	 * @return {Box3} A reference to this bounding box.
11326	 */
11327	translate( offset ) {
11328
11329		this.min.add( offset );
11330		this.max.add( offset );
11331
11332		return this;
11333
11334	}
11335
11336	/**
11337	 * Returns `true` if this bounding box is equal with the given one.
11338	 *
11339	 * @param {Box3} box - The box to test for equality.
11340	 * @return {boolean} Whether this bounding box is equal with the given one.
11341	 */
11342	equals( box ) {
11343
11344		return box.min.equals( this.min ) && box.max.equals( this.max );
11345
11346	}
11347
11348}
11349
11350const _points = [
11351	/*@__PURE__*/ new Vector3(),
11352	/*@__PURE__*/ new Vector3(),
11353	/*@__PURE__*/ new Vector3(),
11354	/*@__PURE__*/ new Vector3(),
11355	/*@__PURE__*/ new Vector3(),
11356	/*@__PURE__*/ new Vector3(),
11357	/*@__PURE__*/ new Vector3(),
11358	/*@__PURE__*/ new Vector3()
11359];
11360
11361const _vector$b = /*@__PURE__*/ new Vector3();
11362
11363const _box$4 = /*@__PURE__*/ new Box3();
11364
11365// triangle centered vertices
11366
11367const _v0$2 = /*@__PURE__*/ new Vector3();
11368const _v1$7 = /*@__PURE__*/ new Vector3();
11369const _v2$4 = /*@__PURE__*/ new Vector3();
11370
11371// triangle edge vectors
11372
11373const _f0 = /*@__PURE__*/ new Vector3();
11374const _f1 = /*@__PURE__*/ new Vector3();
11375const _f2 = /*@__PURE__*/ new Vector3();
11376
11377const _center = /*@__PURE__*/ new Vector3();
11378const _extents = /*@__PURE__*/ new Vector3();
11379const _triangleNormal = /*@__PURE__*/ new Vector3();
11380const _testAxis = /*@__PURE__*/ new Vector3();
11381
11382function satForAxes( axes, v0, v1, v2, extents ) {
11383
11384	for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
11385
11386		_testAxis.fromArray( axes, i );
11387		// project the aabb onto the separating axis
11388		const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
11389		// project all 3 vertices of the triangle onto the separating axis
11390		const p0 = v0.dot( _testAxis );
11391		const p1 = v1.dot( _testAxis );
11392		const p2 = v2.dot( _testAxis );
11393		// actual test, basically see if either of the most extreme of the triangle points intersects r
11394		if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
11395
11396			// points of the projected triangle are outside the projected half-length of the aabb
11397			// the axis is separating and we can exit
11398			return false;
11399
11400		}
11401
11402	}
11403
11404	return true;
11405
11406}
11407
11408const _box$3 = /*@__PURE__*/ new Box3();
11409const _v1$6 = /*@__PURE__*/ new Vector3();
11410const _v2$3 = /*@__PURE__*/ new Vector3();
11411
11412/**
11413 * An analytical 3D sphere defined by a center and radius. This class is mainly
11414 * used as a Bounding Sphere for 3D objects.
11415 */
11416class Sphere {
11417
11418	/**
11419	 * Constructs a new sphere.
11420	 *
11421	 * @param {Vector3} [center=(0,0,0)] - The center of the sphere
11422	 * @param {number} [radius=-1] - The radius of the sphere.
11423	 */
11424	constructor( center = new Vector3(), radius = -1 ) {
11425
11426		/**
11427		 * This flag can be used for type testing.
11428		 *
11429		 * @type {boolean}
11430		 * @readonly
11431		 * @default true
11432		 */
11433		this.isSphere = true;
11434
11435		/**
11436		 * The center of the sphere
11437		 *
11438		 * @type {Vector3}
11439		 */
11440		this.center = center;
11441
11442		/**
11443		 * The radius of the sphere.
11444		 *
11445		 * @type {number}
11446		 */
11447		this.radius = radius;
11448
11449	}
11450
11451	/**
11452	 * Sets the sphere's components by copying the given values.
11453	 *
11454	 * @param {Vector3} center - The center.
11455	 * @param {number} radius - The radius.
11456	 * @return {Sphere} A reference to this sphere.
11457	 */
11458	set( center, radius ) {
11459
11460		this.center.copy( center );
11461		this.radius = radius;
11462
11463		return this;
11464
11465	}
11466
11467	/**
11468	 * Computes the minimum bounding sphere for list of points.
11469	 * If the optional center point is given, it is used as the sphere's
11470	 * center. Otherwise, the center of the axis-aligned bounding box
11471	 * encompassing the points is calculated.
11472	 *
11473	 * @param {Array<Vector3>} points - A list of points in 3D space.
11474	 * @param {Vector3} [optionalCenter] - The center of the sphere.
11475	 * @return {Sphere} A reference to this sphere.
11476	 */
11477	setFromPoints( points, optionalCenter ) {
11478
11479		const center = this.center;
11480
11481		if ( optionalCenter !== undefined ) {
11482
11483			center.copy( optionalCenter );
11484
11485		} else {
11486
11487			_box$3.setFromPoints( points ).getCenter( center );
11488
11489		}
11490
11491		let maxRadiusSq = 0;
11492
11493		for ( let i = 0, il = points.length; i < il; i ++ ) {
11494
11495			maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
11496
11497		}
11498
11499		this.radius = Math.sqrt( maxRadiusSq );
11500
11501		return this;
11502
11503	}
11504
11505	/**
11506	 * Copies the values of the given sphere to this instance.
11507	 *
11508	 * @param {Sphere} sphere - The sphere to copy.
11509	 * @return {Sphere} A reference to this sphere.
11510	 */
11511	copy( sphere ) {
11512
11513		this.center.copy( sphere.center );
11514		this.radius = sphere.radius;
11515
11516		return this;
11517
11518	}
11519
11520	/**
11521	 * Returns `true` if the sphere is empty (the radius set to a negative number).
11522	 *
11523	 * Spheres with a radius of `0` contain only their center point and are not
11524	 * considered to be empty.
11525	 *
11526	 * @return {boolean} Whether this sphere is empty or not.
11527	 */
11528	isEmpty() {
11529
11530		return ( this.radius < 0 );
11531
11532	}
11533
11534	/**
11535	 * Makes this sphere empty which means in encloses a zero space in 3D.
11536	 *
11537	 * @return {Sphere} A reference to this sphere.
11538	 */
11539	makeEmpty() {
11540
11541		this.center.set( 0, 0, 0 );
11542		this.radius = -1;
11543
11544		return this;
11545
11546	}
11547
11548	/**
11549	 * Returns `true` if this sphere contains the given point inclusive of
11550	 * the surface of the sphere.
11551	 *
11552	 * @param {Vector3} point - The point to check.
11553	 * @return {boolean} Whether this sphere contains the given point or not.
11554	 */
11555	containsPoint( point ) {
11556
11557		return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
11558
11559	}
11560
11561	/**
11562	 * Returns the closest distance from the boundary of the sphere to the
11563	 * given point. If the sphere contains the point, the distance will
11564	 * be negative.
11565	 *
11566	 * @param {Vector3} point - The point to compute the distance to.
11567	 * @return {number} The distance to the point.
11568	 */
11569	distanceToPoint( point ) {
11570
11571		return ( point.distanceTo( this.center ) - this.radius );
11572
11573	}
11574
11575	/**
11576	 * Returns `true` if this sphere intersects with the given one.
11577	 *
11578	 * @param {Sphere} sphere - The sphere to test.
11579	 * @return {boolean} Whether this sphere intersects with the given one or not.
11580	 */
11581	intersectsSphere( sphere ) {
11582
11583		const radiusSum = this.radius + sphere.radius;
11584
11585		return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
11586
11587	}
11588
11589	/**
11590	 * Returns `true` if this sphere intersects with the given box.
11591	 *
11592	 * @param {Box3} box - The box to test.
11593	 * @return {boolean} Whether this sphere intersects with the given box or not.
11594	 */
11595	intersectsBox( box ) {
11596
11597		return box.intersectsSphere( this );
11598
11599	}
11600
vendor: 9,314 bytes, lines 11601-11991
11601	/**
11602	 * Returns `true` if this sphere intersects with the given plane.
11603	 *
11604	 * @param {Plane} plane - The plane to test.
11605	 * @return {boolean} Whether this sphere intersects with the given plane or not.
11606	 */
11607	intersectsPlane( plane ) {
11608
11609		return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
11610
11611	}
11612
11613	/**
11614	 * Clamps a point within the sphere. If the point is outside the sphere, it
11615	 * will clamp it to the closest point on the edge of the sphere. Points
11616	 * already inside the sphere will not be affected.
11617	 *
11618	 * @param {Vector3} point - The plane to clamp.
11619	 * @param {Vector3} target - The target vector that is used to store the method's result.
11620	 * @return {Vector3} The clamped point.
11621	 */
11622	clampPoint( point, target ) {
11623
11624		const deltaLengthSq = this.center.distanceToSquared( point );
11625
11626		target.copy( point );
11627
11628		if ( deltaLengthSq > ( this.radius * this.radius ) ) {
11629
11630			target.sub( this.center ).normalize();
11631			target.multiplyScalar( this.radius ).add( this.center );
11632
11633		}
11634
11635		return target;
11636
11637	}
11638
11639	/**
11640	 * Returns a bounding box that encloses this sphere.
11641	 *
11642	 * @param {Box3} target - The target box that is used to store the method's result.
11643	 * @return {Box3} The bounding box that encloses this sphere.
11644	 */
11645	getBoundingBox( target ) {
11646
11647		if ( this.isEmpty() ) {
11648
11649			// Empty sphere produces empty bounding box
11650			target.makeEmpty();
11651			return target;
11652
11653		}
11654
11655		target.set( this.center, this.center );
11656		target.expandByScalar( this.radius );
11657
11658		return target;
11659
11660	}
11661
11662	/**
11663	 * Transforms this sphere with the given 4x4 transformation matrix.
11664	 *
11665	 * @param {Matrix4} matrix - The transformation matrix.
11666	 * @return {Sphere} A reference to this sphere.
11667	 */
11668	applyMatrix4( matrix ) {
11669
11670		this.center.applyMatrix4( matrix );
11671		this.radius = this.radius * matrix.getMaxScaleOnAxis();
11672
11673		return this;
11674
11675	}
11676
11677	/**
11678	 * Translates the sphere's center by the given offset.
11679	 *
11680	 * @param {Vector3} offset - The offset.
11681	 * @return {Sphere} A reference to this sphere.
11682	 */
11683	translate( offset ) {
11684
11685		this.center.add( offset );
11686
11687		return this;
11688
11689	}
11690
11691	/**
11692	 * Expands the boundaries of this sphere to include the given point.
11693	 *
11694	 * @param {Vector3} point - The point to include.
11695	 * @return {Sphere} A reference to this sphere.
11696	 */
11697	expandByPoint( point ) {
11698
11699		if ( this.isEmpty() ) {
11700
11701			this.center.copy( point );
11702
11703			this.radius = 0;
11704
11705			return this;
11706
11707		}
11708
11709		_v1$6.subVectors( point, this.center );
11710
11711		const lengthSq = _v1$6.lengthSq();
11712
11713		if ( lengthSq > ( this.radius * this.radius ) ) {
11714
11715			// calculate the minimal sphere
11716
11717			const length = Math.sqrt( lengthSq );
11718
11719			const delta = ( length - this.radius ) * 0.5;
11720
11721			this.center.addScaledVector( _v1$6, delta / length );
11722
11723			this.radius += delta;
11724
11725		}
11726
11727		return this;
11728
11729	}
11730
11731	/**
11732	 * Expands this sphere to enclose both the original sphere and the given sphere.
11733	 *
11734	 * @param {Sphere} sphere - The sphere to include.
11735	 * @return {Sphere} A reference to this sphere.
11736	 */
11737	union( sphere ) {
11738
11739		if ( sphere.isEmpty() ) {
11740
11741			return this;
11742
11743		}
11744
11745		if ( this.isEmpty() ) {
11746
11747			this.copy( sphere );
11748
11749			return this;
11750
11751		}
11752
11753		if ( this.center.equals( sphere.center ) === true ) {
11754
11755			 this.radius = Math.max( this.radius, sphere.radius );
11756
11757		} else {
11758
11759			_v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius );
11760
11761			this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) );
11762
11763			this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) );
11764
11765		}
11766
11767		return this;
11768
11769	}
11770
11771	/**
11772	 * Returns `true` if this sphere is equal with the given one.
11773	 *
11774	 * @param {Sphere} sphere - The sphere to test for equality.
11775	 * @return {boolean} Whether this bounding sphere is equal with the given one.
11776	 */
11777	equals( sphere ) {
11778
11779		return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
11780
11781	}
11782
11783	/**
11784	 * Returns a new sphere with copied values from this instance.
11785	 *
11786	 * @return {Sphere} A clone of this instance.
11787	 */
11788	clone() {
11789
11790		return new this.constructor().copy( this );
11791
11792	}
11793
11794}
11795
11796const _vector$a = /*@__PURE__*/ new Vector3();
11797const _segCenter = /*@__PURE__*/ new Vector3();
11798const _segDir = /*@__PURE__*/ new Vector3();
11799const _diff = /*@__PURE__*/ new Vector3();
11800
11801const _edge1 = /*@__PURE__*/ new Vector3();
11802const _edge2 = /*@__PURE__*/ new Vector3();
11803const _normal$1 = /*@__PURE__*/ new Vector3();
11804
11805/**
11806 * A ray that emits from an origin in a certain direction. The class is used by
11807 * {@link Raycaster} to assist with raycasting. Raycasting is used for
11808 * mouse picking (working out what objects in the 3D space the mouse is over)
11809 * amongst other things.
11810 */
11811class Ray {
11812
11813	/**
11814	 * Constructs a new ray.
11815	 *
11816	 * @param {Vector3} [origin=(0,0,0)] - The origin of the ray.
11817	 * @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray.
11818	 */
11819	constructor( origin = new Vector3(), direction = new Vector3( 0, 0, -1 ) ) {
11820
11821		/**
11822		 * The origin of the ray.
11823		 *
11824		 * @type {Vector3}
11825		 */
11826		this.origin = origin;
11827
11828		/**
11829		 * The (normalized) direction of the ray.
11830		 *
11831		 * @type {Vector3}
11832		 */
11833		this.direction = direction;
11834
11835	}
11836
11837	/**
11838	 * Sets the ray's components by copying the given values.
11839	 *
11840	 * @param {Vector3} origin - The origin.
11841	 * @param {Vector3} direction - The direction.
11842	 * @return {Ray} A reference to this ray.
11843	 */
11844	set( origin, direction ) {
11845
11846		this.origin.copy( origin );
11847		this.direction.copy( direction );
11848
11849		return this;
11850
11851	}
11852
11853	/**
11854	 * Copies the values of the given ray to this instance.
11855	 *
11856	 * @param {Ray} ray - The ray to copy.
11857	 * @return {Ray} A reference to this ray.
11858	 */
11859	copy( ray ) {
11860
11861		this.origin.copy( ray.origin );
11862		this.direction.copy( ray.direction );
11863
11864		return this;
11865
11866	}
11867
11868	/**
11869	 * Returns a vector that is located at a given distance along this ray.
11870	 *
11871	 * @param {number} t - The distance along the ray to retrieve a position for.
11872	 * @param {Vector3} target - The target vector that is used to store the method's result.
11873	 * @return {Vector3} A position on the ray.
11874	 */
11875	at( t, target ) {
11876
11877		return target.copy( this.origin ).addScaledVector( this.direction, t );
11878
11879	}
11880
11881	/**
11882	 * Adjusts the direction of the ray to point at the given vector in world space.
11883	 *
11884	 * @param {Vector3} v - The target position.
11885	 * @return {Ray} A reference to this ray.
11886	 */
11887	lookAt( v ) {
11888
11889		this.direction.copy( v ).sub( this.origin ).normalize();
11890
11891		return this;
11892
11893	}
11894
11895	/**
11896	 * Shift the origin of this ray along its direction by the given distance.
11897	 *
11898	 * @param {number} t - The distance along the ray to interpolate.
11899	 * @return {Ray} A reference to this ray.
11900	 */
11901	recast( t ) {
11902
11903		this.origin.copy( this.at( t, _vector$a ) );
11904
11905		return this;
11906
11907	}
11908
11909	/**
11910	 * Returns the point along this ray that is closest to the given point.
11911	 *
11912	 * @param {Vector3} point - A point in 3D space to get the closet location on the ray for.
11913	 * @param {Vector3} target - The target vector that is used to store the method's result.
11914	 * @return {Vector3} The closest point on this ray.
11915	 */
11916	closestPointToPoint( point, target ) {
11917
11918		target.subVectors( point, this.origin );
11919
11920		const directionDistance = target.dot( this.direction );
11921
11922		if ( directionDistance < 0 ) {
11923
11924			return target.copy( this.origin );
11925
11926		}
11927
11928		return target.copy( this.origin ).addScaledVector( this.direction, directionDistance );
11929
11930	}
11931
11932	/**
11933	 * Returns the distance of the closest approach between this ray and the given point.
11934	 *
11935	 * @param {Vector3} point - A point in 3D space to compute the distance to.
11936	 * @return {number} The distance.
11937	 */
11938	distanceToPoint( point ) {
11939
11940		return Math.sqrt( this.distanceSqToPoint( point ) );
11941
11942	}
11943
11944	/**
11945	 * Returns the squared distance of the closest approach between this ray and the given point.
11946	 *
11947	 * @param {Vector3} point - A point in 3D space to compute the distance to.
11948	 * @return {number} The squared distance.
11949	 */
11950	distanceSqToPoint( point ) {
11951
11952		const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction );
11953
11954		// point behind the ray
11955
11956		if ( directionDistance < 0 ) {
11957
11958			return this.origin.distanceToSquared( point );
11959
11960		}
11961
11962		_vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance );
11963
11964		return _vector$a.distanceToSquared( point );
11965
11966	}
11967
11968	/**
11969	 * Returns the squared distance between this ray and the given line segment.
11970	 *
11971	 * @param {Vector3} v0 - The start point of the line segment.
11972	 * @param {Vector3} v1 - The end point of the line segment.
11973	 * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment.
11974	 * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray.
11975	 * @return {number} The squared distance.
11976	 */
11977	distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
11978
11979		// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h
11980		// It returns the min distance between the ray and the segment
11981		// defined by v0 and v1
11982		// It can also set two optional targets :
11983		// - The closest point on the ray
11984		// - The closest point on the segment
11985
11986		_segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
11987		_segDir.copy( v1 ).sub( v0 ).normalize();
11988		_diff.copy( this.origin ).sub( _segCenter );
11989
11990		const segExtent = v0.distanceTo( v1 ) * 0.5;
11991		const a01 = - this.direction.dot( _segDir );
vendor: 4,520 bytes, lines 11992-12179
11992		const b0 = _diff.dot( this.direction );
11993		const b1 = - _diff.dot( _segDir );
11994		const c = _diff.lengthSq();
11995		const det = Math.abs( 1 - a01 * a01 );
11996		let s0, s1, sqrDist, extDet;
11997
11998		if ( det > 0 ) {
11999
12000			// The ray and segment are not parallel.
12001
12002			s0 = a01 * b1 - b0;
12003			s1 = a01 * b0 - b1;
12004			extDet = segExtent * det;
12005
12006			if ( s0 >= 0 ) {
12007
12008				if ( s1 >= - extDet ) {
12009
12010					if ( s1 <= extDet ) {
12011
12012						// region 0
12013						// Minimum at interior points of ray and segment.
12014
12015						const invDet = 1 / det;
12016						s0 *= invDet;
12017						s1 *= invDet;
12018						sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
12019
12020					} else {
12021
12022						// region 1
12023
12024						s1 = segExtent;
12025						s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
12026						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
12027
12028					}
12029
12030				} else {
12031
12032					// region 5
12033
12034					s1 = - segExtent;
12035					s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
12036					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
12037
12038				}
12039
12040			} else {
12041
12042				if ( s1 <= - extDet ) {
12043
12044					// region 4
12045
12046					s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
12047					s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
12048					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
12049
12050				} else if ( s1 <= extDet ) {
12051
12052					// region 3
12053
12054					s0 = 0;
12055					s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
12056					sqrDist = s1 * ( s1 + 2 * b1 ) + c;
12057
12058				} else {
12059
12060					// region 2
12061
12062					s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
12063					s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
12064					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
12065
12066				}
12067
12068			}
12069
12070		} else {
12071
12072			// Ray and segment are parallel.
12073
12074			s1 = ( a01 > 0 ) ? - segExtent : segExtent;
12075			s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
12076			sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
12077
12078		}
12079
12080		if ( optionalPointOnRay ) {
12081
12082			optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );
12083
12084		}
12085
12086		if ( optionalPointOnSegment ) {
12087
12088			optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );
12089
12090		}
12091
12092		return sqrDist;
12093
12094	}
12095
12096	/**
12097	 * Intersects this ray with the given sphere, returning the intersection
12098	 * point or `null` if there is no intersection.
12099	 *
12100	 * @param {Sphere} sphere - The sphere to intersect.
12101	 * @param {Vector3} target - The target vector that is used to store the method's result.
12102	 * @return {?Vector3} The intersection point.
12103	 */
12104	intersectSphere( sphere, target ) {
12105
12106		_vector$a.subVectors( sphere.center, this.origin );
12107		const tca = _vector$a.dot( this.direction );
12108		const d2 = _vector$a.dot( _vector$a ) - tca * tca;
12109		const radius2 = sphere.radius * sphere.radius;
12110
12111		if ( d2 > radius2 ) return null;
12112
12113		const thc = Math.sqrt( radius2 - d2 );
12114
12115		// t0 = first intersect point - entrance on front of sphere
12116		const t0 = tca - thc;
12117
12118		// t1 = second intersect point - exit point on back of sphere
12119		const t1 = tca + thc;
12120
12121		// test to see if t1 is behind the ray - if so, return null
12122		if ( t1 < 0 ) return null;
12123
12124		// test to see if t0 is behind the ray:
12125		// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
12126		// in order to always return an intersect point that is in front of the ray.
12127		if ( t0 < 0 ) return this.at( t1, target );
12128
12129		// else t0 is in front of the ray, so return the first collision point scaled by t0
12130		return this.at( t0, target );
12131
12132	}
12133
12134	/**
12135	 * Returns `true` if this ray intersects with the given sphere.
12136	 *
12137	 * @param {Sphere} sphere - The sphere to intersect.
12138	 * @return {boolean} Whether this ray intersects with the given sphere or not.
12139	 */
12140	intersectsSphere( sphere ) {
12141
12142		return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
12143
12144	}
12145
12146	/**
12147	 * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray
12148	 * does not intersect with the plane.
12149	 *
12150	 * @param {Plane} plane - The plane to compute the distance to.
12151	 * @return {?number} Whether this ray intersects with the given sphere or not.
12152	 */
12153	distanceToPlane( plane ) {
12154
12155		const denominator = plane.normal.dot( this.direction );
12156
12157		if ( denominator === 0 ) {
12158
12159			// line is coplanar, return origin
12160			if ( plane.distanceToPoint( this.origin ) === 0 ) {
12161
12162				return 0;
12163
12164			}
12165
12166			// Null is preferable to undefined since undefined means.... it is undefined
12167
12168			return null;
12169
12170		}
12171
12172		const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
12173
12174		// Return if the ray never intersects the plane
12175
12176		return t >= 0 ? t : null;
12177
12178	}
12179
vendor: 4,941 bytes, lines 12180-12391
12180	/**
12181	 * Intersects this ray with the given plane, returning the intersection
12182	 * point or `null` if there is no intersection.
12183	 *
12184	 * @param {Plane} plane - The plane to intersect.
12185	 * @param {Vector3} target - The target vector that is used to store the method's result.
12186	 * @return {?Vector3} The intersection point.
12187	 */
12188	intersectPlane( plane, target ) {
12189
12190		const t = this.distanceToPlane( plane );
12191
12192		if ( t === null ) {
12193
12194			return null;
12195
12196		}
12197
12198		return this.at( t, target );
12199
12200	}
12201
12202	/**
12203	 * Returns `true` if this ray intersects with the given plane.
12204	 *
12205	 * @param {Plane} plane - The plane to intersect.
12206	 * @return {boolean} Whether this ray intersects with the given plane or not.
12207	 */
12208	intersectsPlane( plane ) {
12209
12210		// check if the ray lies on the plane first
12211
12212		const distToPoint = plane.distanceToPoint( this.origin );
12213
12214		if ( distToPoint === 0 ) {
12215
12216			return true;
12217
12218		}
12219
12220		const denominator = plane.normal.dot( this.direction );
12221
12222		if ( denominator * distToPoint < 0 ) {
12223
12224			return true;
12225
12226		}
12227
12228		// ray origin is behind the plane (and is pointing behind it)
12229
12230		return false;
12231
12232	}
12233
12234	/**
12235	 * Intersects this ray with the given bounding box, returning the intersection
12236	 * point or `null` if there is no intersection.
12237	 *
12238	 * @param {Box3} box - The box to intersect.
12239	 * @param {Vector3} target - The target vector that is used to store the method's result.
12240	 * @return {?Vector3} The intersection point.
12241	 */
12242	intersectBox( box, target ) {
12243
12244		let tmin, tmax, tymin, tymax, tzmin, tzmax;
12245
12246		const invdirx = 1 / this.direction.x,
12247			invdiry = 1 / this.direction.y,
12248			invdirz = 1 / this.direction.z;
12249
12250		const origin = this.origin;
12251
12252		if ( invdirx >= 0 ) {
12253
12254			tmin = ( box.min.x - origin.x ) * invdirx;
12255			tmax = ( box.max.x - origin.x ) * invdirx;
12256
12257		} else {
12258
12259			tmin = ( box.max.x - origin.x ) * invdirx;
12260			tmax = ( box.min.x - origin.x ) * invdirx;
12261
12262		}
12263
12264		if ( invdiry >= 0 ) {
12265
12266			tymin = ( box.min.y - origin.y ) * invdiry;
12267			tymax = ( box.max.y - origin.y ) * invdiry;
12268
12269		} else {
12270
12271			tymin = ( box.max.y - origin.y ) * invdiry;
12272			tymax = ( box.min.y - origin.y ) * invdiry;
12273
12274		}
12275
12276		if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
12277
12278		if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;
12279
12280		if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;
12281
12282		if ( invdirz >= 0 ) {
12283
12284			tzmin = ( box.min.z - origin.z ) * invdirz;
12285			tzmax = ( box.max.z - origin.z ) * invdirz;
12286
12287		} else {
12288
12289			tzmin = ( box.max.z - origin.z ) * invdirz;
12290			tzmax = ( box.min.z - origin.z ) * invdirz;
12291
12292		}
12293
12294		if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
12295
12296		if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
12297
12298		if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
12299
12300		//return point closest to the ray (positive side)
12301
12302		if ( tmax < 0 ) return null;
12303
12304		return this.at( tmin >= 0 ? tmin : tmax, target );
12305
12306	}
12307
12308	/**
12309	 * Returns `true` if this ray intersects with the given box.
12310	 *
12311	 * @param {Box3} box - The box to intersect.
12312	 * @return {boolean} Whether this ray intersects with the given box or not.
12313	 */
12314	intersectsBox( box ) {
12315
12316		return this.intersectBox( box, _vector$a ) !== null;
12317
12318	}
12319
12320	/**
12321	 * Intersects this ray with the given triangle, returning the intersection
12322	 * point or `null` if there is no intersection.
12323	 *
12324	 * @param {Vector3} a - The first vertex of the triangle.
12325	 * @param {Vector3} b - The second vertex of the triangle.
12326	 * @param {Vector3} c - The third vertex of the triangle.
12327	 * @param {boolean} backfaceCulling - Whether to use backface culling or not.
12328	 * @param {Vector3} target - The target vector that is used to store the method's result.
12329	 * @return {?Vector3} The intersection point.
12330	 */
12331	intersectTriangle( a, b, c, backfaceCulling, target ) {
12332
12333		// Compute the offset origin, edges, and normal.
12334
12335		// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
12336
12337		_edge1.subVectors( b, a );
12338		_edge2.subVectors( c, a );
12339		_normal$1.crossVectors( _edge1, _edge2 );
12340
12341		// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
12342		// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
12343		//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
12344		//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
12345		//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
12346		let DdN = this.direction.dot( _normal$1 );
12347		let sign;
12348
12349		if ( DdN > 0 ) {
12350
12351			if ( backfaceCulling ) return null;
12352			sign = 1;
12353
12354		} else if ( DdN < 0 ) {
12355
12356			sign = -1;
12357			DdN = - DdN;
12358
12359		} else {
12360
12361			return null;
12362
12363		}
12364
12365		_diff.subVectors( this.origin, a );
12366		const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
12367
12368		// b1 < 0, no intersection
12369		if ( DdQxE2 < 0 ) {
12370
12371			return null;
12372
12373		}
12374
12375		const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
12376
12377		// b2 < 0, no intersection
12378		if ( DdE1xQ < 0 ) {
12379
12380			return null;
12381
12382		}
12383
12384		// b1+b2 > 1, no intersection
12385		if ( DdQxE2 + DdE1xQ > DdN ) {
12386
12387			return null;
12388
12389		}
12390
12391		// Line intersects triangle, check if ray does.
vendor: 4,310 bytes, lines 12392-12540
12392		const QdN = - sign * _diff.dot( _normal$1 );
12393
12394		// t < 0, no intersection
12395		if ( QdN < 0 ) {
12396
12397			return null;
12398
12399		}
12400
12401		// Ray intersects triangle.
12402		return this.at( QdN / DdN, target );
12403
12404	}
12405
12406	/**
12407	 * Transforms this ray with the given 4x4 transformation matrix.
12408	 *
12409	 * @param {Matrix4} matrix4 - The transformation matrix.
12410	 * @return {Ray} A reference to this ray.
12411	 */
12412	applyMatrix4( matrix4 ) {
12413
12414		this.origin.applyMatrix4( matrix4 );
12415		this.direction.transformDirection( matrix4 );
12416
12417		return this;
12418
12419	}
12420
12421	/**
12422	 * Returns `true` if this ray is equal with the given one.
12423	 *
12424	 * @param {Ray} ray - The ray to test for equality.
12425	 * @return {boolean} Whether this ray is equal with the given one.
12426	 */
12427	equals( ray ) {
12428
12429		return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
12430
12431	}
12432
12433	/**
12434	 * Returns a new ray with copied values from this instance.
12435	 *
12436	 * @return {Ray} A clone of this instance.
12437	 */
12438	clone() {
12439
12440		return new this.constructor().copy( this );
12441
12442	}
12443
12444}
12445
12446/**
12447 * Represents a 4x4 matrix.
12448 *
12449 * The most common use of a 4x4 matrix in 3D computer graphics is as a transformation matrix.
12450 * For an introduction to transformation matrices as used in WebGL, check out [this tutorial]{@link https://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices}
12451 *
12452 * This allows a 3D vector representing a point in 3D space to undergo
12453 * transformations such as translation, rotation, shear, scale, reflection,
12454 * orthogonal or perspective projection and so on, by being multiplied by the
12455 * matrix. This is known as `applying` the matrix to the vector.
12456 *
12457 * A Note on Row-Major and Column-Major Ordering:
12458 *
12459 * The constructor and {@link Matrix3#set} method take arguments in
12460 * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order}
12461 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order.
12462 * This means that calling:
12463 * ```js
12464 * const m = new THREE.Matrix4();
12465 * m.set( 11, 12, 13, 14,
12466 *        21, 22, 23, 24,
12467 *        31, 32, 33, 34,
12468 *        41, 42, 43, 44 );
12469 * ```
12470 * will result in the elements array containing:
12471 * ```js
12472 * m.elements = [ 11, 21, 31, 41,
12473 *                12, 22, 32, 42,
12474 *                13, 23, 33, 43,
12475 *                14, 24, 34, 44 ];
12476 * ```
12477 * and internally all calculations are performed using column-major ordering.
12478 * However, as the actual ordering makes no difference mathematically and
12479 * most people are used to thinking about matrices in row-major order, the
12480 * three.js documentation shows matrices in row-major order. Just bear in
12481 * mind that if you are reading the source code, you'll have to take the
12482 * transpose of any matrices outlined here to make sense of the calculations.
12483 */
12484class Matrix4 {
12485
12486	/**
12487	 * Constructs a new 4x4 matrix. The arguments are supposed to be
12488	 * in row-major order. If no arguments are provided, the constructor
12489	 * initializes the matrix as an identity matrix.
12490	 *
12491	 * @param {number} [n11] - 1-1 matrix element.
12492	 * @param {number} [n12] - 1-2 matrix element.
12493	 * @param {number} [n13] - 1-3 matrix element.
12494	 * @param {number} [n14] - 1-4 matrix element.
12495	 * @param {number} [n21] - 2-1 matrix element.
12496	 * @param {number} [n22] - 2-2 matrix element.
12497	 * @param {number} [n23] - 2-3 matrix element.
12498	 * @param {number} [n24] - 2-4 matrix element.
12499	 * @param {number} [n31] - 3-1 matrix element.
12500	 * @param {number} [n32] - 3-2 matrix element.
12501	 * @param {number} [n33] - 3-3 matrix element.
12502	 * @param {number} [n34] - 3-4 matrix element.
12503	 * @param {number} [n41] - 4-1 matrix element.
12504	 * @param {number} [n42] - 4-2 matrix element.
12505	 * @param {number} [n43] - 4-3 matrix element.
12506	 * @param {number} [n44] - 4-4 matrix element.
12507	 */
12508	constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
12509
12510		/**
12511		 * This flag can be used for type testing.
12512		 *
12513		 * @type {boolean}
12514		 * @readonly
12515		 * @default true
12516		 */
12517		Matrix4.prototype.isMatrix4 = true;
12518
12519		/**
12520		 * A column-major list of matrix values.
12521		 *
12522		 * @type {Array<number>}
12523		 */
12524		this.elements = [
12525
12526			1, 0, 0, 0,
12527			0, 1, 0, 0,
12528			0, 0, 1, 0,
12529			0, 0, 0, 1
12530
12531		];
12532
12533		if ( n11 !== undefined ) {
12534
12535			this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 );
12536
12537		}
12538
12539	}
12540
vendor: 9,117 bytes, lines 12541-12951
12541	/**
12542	 * Sets the elements of the matrix.The arguments are supposed to be
12543	 * in row-major order.
12544	 *
12545	 * @param {number} [n11] - 1-1 matrix element.
12546	 * @param {number} [n12] - 1-2 matrix element.
12547	 * @param {number} [n13] - 1-3 matrix element.
12548	 * @param {number} [n14] - 1-4 matrix element.
12549	 * @param {number} [n21] - 2-1 matrix element.
12550	 * @param {number} [n22] - 2-2 matrix element.
12551	 * @param {number} [n23] - 2-3 matrix element.
12552	 * @param {number} [n24] - 2-4 matrix element.
12553	 * @param {number} [n31] - 3-1 matrix element.
12554	 * @param {number} [n32] - 3-2 matrix element.
12555	 * @param {number} [n33] - 3-3 matrix element.
12556	 * @param {number} [n34] - 3-4 matrix element.
12557	 * @param {number} [n41] - 4-1 matrix element.
12558	 * @param {number} [n42] - 4-2 matrix element.
12559	 * @param {number} [n43] - 4-3 matrix element.
12560	 * @param {number} [n44] - 4-4 matrix element.
12561	 * @return {Matrix4} A reference to this matrix.
12562	 */
12563	set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
12564
12565		const te = this.elements;
12566
12567		te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
12568		te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
12569		te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
12570		te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
12571
12572		return this;
12573
12574	}
12575
12576	/**
12577	 * Sets this matrix to the 4x4 identity matrix.
12578	 *
12579	 * @return {Matrix4} A reference to this matrix.
12580	 */
12581	identity() {
12582
12583		this.set(
12584
12585			1, 0, 0, 0,
12586			0, 1, 0, 0,
12587			0, 0, 1, 0,
12588			0, 0, 0, 1
12589
12590		);
12591
12592		return this;
12593
12594	}
12595
12596	/**
12597	 * Returns a matrix with copied values from this instance.
12598	 *
12599	 * @return {Matrix4} A clone of this instance.
12600	 */
12601	clone() {
12602
12603		return new Matrix4().fromArray( this.elements );
12604
12605	}
12606
12607	/**
12608	 * Copies the values of the given matrix to this instance.
12609	 *
12610	 * @param {Matrix4} m - The matrix to copy.
12611	 * @return {Matrix4} A reference to this matrix.
12612	 */
12613	copy( m ) {
12614
12615		const te = this.elements;
12616		const me = m.elements;
12617
12618		te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
12619		te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
12620		te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
12621		te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
12622
12623		return this;
12624
12625	}
12626
12627	/**
12628	 * Copies the translation component of the given matrix
12629	 * into this matrix's translation component.
12630	 *
12631	 * @param {Matrix4} m - The matrix to copy the translation component.
12632	 * @return {Matrix4} A reference to this matrix.
12633	 */
12634	copyPosition( m ) {
12635
12636		const te = this.elements, me = m.elements;
12637
12638		te[ 12 ] = me[ 12 ];
12639		te[ 13 ] = me[ 13 ];
12640		te[ 14 ] = me[ 14 ];
12641
12642		return this;
12643
12644	}
12645
12646	/**
12647	 * Set the upper 3x3 elements of this matrix to the values of given 3x3 matrix.
12648	 *
12649	 * @param {Matrix3} m - The 3x3 matrix.
12650	 * @return {Matrix4} A reference to this matrix.
12651	 */
12652	setFromMatrix3( m ) {
12653
12654		const me = m.elements;
12655
12656		this.set(
12657
12658			me[ 0 ], me[ 3 ], me[ 6 ], 0,
12659			me[ 1 ], me[ 4 ], me[ 7 ], 0,
12660			me[ 2 ], me[ 5 ], me[ 8 ], 0,
12661			0, 0, 0, 1
12662
12663		);
12664
12665		return this;
12666
12667	}
12668
12669	/**
12670	 * Extracts the basis of this matrix into the three axis vectors provided.
12671	 *
12672	 * @param {Vector3} xAxis - The basis's x axis.
12673	 * @param {Vector3} yAxis - The basis's y axis.
12674	 * @param {Vector3} zAxis - The basis's z axis.
12675	 * @return {Matrix4} A reference to this matrix.
12676	 */
12677	extractBasis( xAxis, yAxis, zAxis ) {
12678
12679		xAxis.setFromMatrixColumn( this, 0 );
12680		yAxis.setFromMatrixColumn( this, 1 );
12681		zAxis.setFromMatrixColumn( this, 2 );
12682
12683		return this;
12684
12685	}
12686
12687	/**
12688	 * Sets the given basis vectors to this matrix.
12689	 *
12690	 * @param {Vector3} xAxis - The basis's x axis.
12691	 * @param {Vector3} yAxis - The basis's y axis.
12692	 * @param {Vector3} zAxis - The basis's z axis.
12693	 * @return {Matrix4} A reference to this matrix.
12694	 */
12695	makeBasis( xAxis, yAxis, zAxis ) {
12696
12697		this.set(
12698			xAxis.x, yAxis.x, zAxis.x, 0,
12699			xAxis.y, yAxis.y, zAxis.y, 0,
12700			xAxis.z, yAxis.z, zAxis.z, 0,
12701			0, 0, 0, 1
12702		);
12703
12704		return this;
12705
12706	}
12707
12708	/**
12709	 * Extracts the rotation component of the given matrix
12710	 * into this matrix's rotation component.
12711	 *
12712	 * Note: This method does not support reflection matrices.
12713	 *
12714	 * @param {Matrix4} m - The matrix.
12715	 * @return {Matrix4} A reference to this matrix.
12716	 */
12717	extractRotation( m ) {
12718
12719		const te = this.elements;
12720		const me = m.elements;
12721
12722		const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length();
12723		const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length();
12724		const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length();
12725
12726		te[ 0 ] = me[ 0 ] * scaleX;
12727		te[ 1 ] = me[ 1 ] * scaleX;
12728		te[ 2 ] = me[ 2 ] * scaleX;
12729		te[ 3 ] = 0;
12730
12731		te[ 4 ] = me[ 4 ] * scaleY;
12732		te[ 5 ] = me[ 5 ] * scaleY;
12733		te[ 6 ] = me[ 6 ] * scaleY;
12734		te[ 7 ] = 0;
12735
12736		te[ 8 ] = me[ 8 ] * scaleZ;
12737		te[ 9 ] = me[ 9 ] * scaleZ;
12738		te[ 10 ] = me[ 10 ] * scaleZ;
12739		te[ 11 ] = 0;
12740
12741		te[ 12 ] = 0;
12742		te[ 13 ] = 0;
12743		te[ 14 ] = 0;
12744		te[ 15 ] = 1;
12745
12746		return this;
12747
12748	}
12749
12750	/**
12751	 * Sets the rotation component (the upper left 3x3 matrix) of this matrix to
12752	 * the rotation specified by the given Euler angles. The rest of
12753	 * the matrix is set to the identity. Depending on the {@link Euler#order},
12754	 * there are six possible outcomes. See [this page]{@link https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix}
12755	 * for a complete list.
12756	 *
12757	 * @param {Euler} euler - The Euler angles.
12758	 * @return {Matrix4} A reference to this matrix.
12759	 */
12760	makeRotationFromEuler( euler ) {
12761
12762		const te = this.elements;
12763
12764		const x = euler.x, y = euler.y, z = euler.z;
12765		const a = Math.cos( x ), b = Math.sin( x );
12766		const c = Math.cos( y ), d = Math.sin( y );
12767		const e = Math.cos( z ), f = Math.sin( z );
12768
12769		if ( euler.order === 'XYZ' ) {
12770
12771			const ae = a * e, af = a * f, be = b * e, bf = b * f;
12772
12773			te[ 0 ] = c * e;
12774			te[ 4 ] = - c * f;
12775			te[ 8 ] = d;
12776
12777			te[ 1 ] = af + be * d;
12778			te[ 5 ] = ae - bf * d;
12779			te[ 9 ] = - b * c;
12780
12781			te[ 2 ] = bf - ae * d;
12782			te[ 6 ] = be + af * d;
12783			te[ 10 ] = a * c;
12784
12785		} else if ( euler.order === 'YXZ' ) {
12786
12787			const ce = c * e, cf = c * f, de = d * e, df = d * f;
12788
12789			te[ 0 ] = ce + df * b;
12790			te[ 4 ] = de * b - cf;
12791			te[ 8 ] = a * d;
12792
12793			te[ 1 ] = a * f;
12794			te[ 5 ] = a * e;
12795			te[ 9 ] = - b;
12796
12797			te[ 2 ] = cf * b - de;
12798			te[ 6 ] = df + ce * b;
12799			te[ 10 ] = a * c;
12800
12801		} else if ( euler.order === 'ZXY' ) {
12802
12803			const ce = c * e, cf = c * f, de = d * e, df = d * f;
12804
12805			te[ 0 ] = ce - df * b;
12806			te[ 4 ] = - a * f;
12807			te[ 8 ] = de + cf * b;
12808
12809			te[ 1 ] = cf + de * b;
12810			te[ 5 ] = a * e;
12811			te[ 9 ] = df - ce * b;
12812
12813			te[ 2 ] = - a * d;
12814			te[ 6 ] = b;
12815			te[ 10 ] = a * c;
12816
12817		} else if ( euler.order === 'ZYX' ) {
12818
12819			const ae = a * e, af = a * f, be = b * e, bf = b * f;
12820
12821			te[ 0 ] = c * e;
12822			te[ 4 ] = be * d - af;
12823			te[ 8 ] = ae * d + bf;
12824
12825			te[ 1 ] = c * f;
12826			te[ 5 ] = bf * d + ae;
12827			te[ 9 ] = af * d - be;
12828
12829			te[ 2 ] = - d;
12830			te[ 6 ] = b * c;
12831			te[ 10 ] = a * c;
12832
12833		} else if ( euler.order === 'YZX' ) {
12834
12835			const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
12836
12837			te[ 0 ] = c * e;
12838			te[ 4 ] = bd - ac * f;
12839			te[ 8 ] = bc * f + ad;
12840
12841			te[ 1 ] = f;
12842			te[ 5 ] = a * e;
12843			te[ 9 ] = - b * e;
12844
12845			te[ 2 ] = - d * e;
12846			te[ 6 ] = ad * f + bc;
12847			te[ 10 ] = ac - bd * f;
12848
12849		} else if ( euler.order === 'XZY' ) {
12850
12851			const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
12852
12853			te[ 0 ] = c * e;
12854			te[ 4 ] = - f;
12855			te[ 8 ] = d * e;
12856
12857			te[ 1 ] = ac * f + bd;
12858			te[ 5 ] = a * e;
12859			te[ 9 ] = ad * f - bc;
12860
12861			te[ 2 ] = bc * f - ad;
12862			te[ 6 ] = b * e;
12863			te[ 10 ] = bd * f + ac;
12864
12865		}
12866
12867		// bottom row
12868		te[ 3 ] = 0;
12869		te[ 7 ] = 0;
12870		te[ 11 ] = 0;
12871
12872		// last column
12873		te[ 12 ] = 0;
12874		te[ 13 ] = 0;
12875		te[ 14 ] = 0;
12876		te[ 15 ] = 1;
12877
12878		return this;
12879
12880	}
12881
12882	/**
12883	 * Sets the rotation component of this matrix to the rotation specified by
12884	 * the given Quaternion as outlined [here]{@link https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion}
12885	 * The rest of the matrix is set to the identity.
12886	 *
12887	 * @param {Quaternion} q - The Quaternion.
12888	 * @return {Matrix4} A reference to this matrix.
12889	 */
12890	makeRotationFromQuaternion( q ) {
12891
12892		return this.compose( _zero, q, _one );
12893
12894	}
12895
12896	/**
12897	 * Sets the rotation component of the transformation matrix, looking from `eye` towards
12898	 * `target`, and oriented by the up-direction.
12899	 *
12900	 * @param {Vector3} eye - The eye vector.
12901	 * @param {Vector3} target - The target vector.
12902	 * @param {Vector3} up - The up vector.
12903	 * @return {Matrix4} A reference to this matrix.
12904	 */
12905	lookAt( eye, target, up ) {
12906
12907		const te = this.elements;
12908
12909		_z.subVectors( eye, target );
12910
12911		if ( _z.lengthSq() === 0 ) {
12912
12913			// eye and target are in the same position
12914
12915			_z.z = 1;
12916
12917		}
12918
12919		_z.normalize();
12920		_x.crossVectors( up, _z );
12921
12922		if ( _x.lengthSq() === 0 ) {
12923
12924			// up and z are parallel
12925
12926			if ( Math.abs( up.z ) === 1 ) {
12927
12928				_z.x += 0.0001;
12929
12930			} else {
12931
12932				_z.z += 0.0001;
12933
12934			}
12935
12936			_z.normalize();
12937			_x.crossVectors( up, _z );
12938
12939		}
12940
12941		_x.normalize();
12942		_y.crossVectors( _z, _x );
12943
12944		te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
12945		te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
12946		te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
12947
12948		return this;
12949
12950	}
12951
vendor: 4,574 bytes, lines 12952-13120
12952	/**
12953	 * Post-multiplies this matrix by the given 4x4 matrix.
12954	 *
12955	 * @param {Matrix4} m - The matrix to multiply with.
12956	 * @return {Matrix4} A reference to this matrix.
12957	 */
12958	multiply( m ) {
12959
12960		return this.multiplyMatrices( this, m );
12961
12962	}
12963
12964	/**
12965	 * Pre-multiplies this matrix by the given 4x4 matrix.
12966	 *
12967	 * @param {Matrix4} m - The matrix to multiply with.
12968	 * @return {Matrix4} A reference to this matrix.
12969	 */
12970	premultiply( m ) {
12971
12972		return this.multiplyMatrices( m, this );
12973
12974	}
12975
12976	/**
12977	 * Multiples the given 4x4 matrices and stores the result
12978	 * in this matrix.
12979	 *
12980	 * @param {Matrix4} a - The first matrix.
12981	 * @param {Matrix4} b - The second matrix.
12982	 * @return {Matrix4} A reference to this matrix.
12983	 */
12984	multiplyMatrices( a, b ) {
12985
12986		const ae = a.elements;
12987		const be = b.elements;
12988		const te = this.elements;
12989
12990		const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
12991		const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
12992		const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
12993		const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
12994
12995		const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
12996		const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
12997		const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
12998		const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
12999
13000		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
13001		te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
13002		te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
13003		te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
13004
13005		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
13006		te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
13007		te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
13008		te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
13009
13010		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
13011		te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
13012		te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
13013		te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
13014
13015		te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
13016		te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
13017		te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
13018		te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
13019
13020		return this;
13021
13022	}
13023
13024	/**
13025	 * Multiplies every component of the matrix by the given scalar.
13026	 *
13027	 * @param {number} s - The scalar.
13028	 * @return {Matrix4} A reference to this matrix.
13029	 */
13030	multiplyScalar( s ) {
13031
13032		const te = this.elements;
13033
13034		te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
13035		te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
13036		te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
13037		te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
13038
13039		return this;
13040
13041	}
13042
13043	/**
13044	 * Computes and returns the determinant of this matrix.
13045	 *
13046	 * Based on the method outlined [here]{@link http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html}.
13047	 *
13048	 * @return {number} The determinant.
13049	 */
13050	determinant() {
13051
13052		const te = this.elements;
13053
13054		const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
13055		const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
13056		const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
13057		const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
13058
13059		//TODO: make this more efficient
13060
13061		return (
13062			n41 * (
13063				+ n14 * n23 * n32
13064				 - n13 * n24 * n32
13065				 - n14 * n22 * n33
13066				 + n12 * n24 * n33
13067				 + n13 * n22 * n34
13068				 - n12 * n23 * n34
13069			) +
13070			n42 * (
13071				+ n11 * n23 * n34
13072				 - n11 * n24 * n33
13073				 + n14 * n21 * n33
13074				 - n13 * n21 * n34
13075				 + n13 * n24 * n31
13076				 - n14 * n23 * n31
13077			) +
13078			n43 * (
13079				+ n11 * n24 * n32
13080				 - n11 * n22 * n34
13081				 - n14 * n21 * n32
13082				 + n12 * n21 * n34
13083				 + n14 * n22 * n31
13084				 - n12 * n24 * n31
13085			) +
13086			n44 * (
13087				- n13 * n22 * n31
13088				 - n11 * n23 * n32
13089				 + n11 * n22 * n33
13090				 + n13 * n21 * n32
13091				 - n12 * n21 * n33
13092				 + n12 * n23 * n31
13093			)
13094
13095		);
13096
13097	}
13098
13099	/**
13100	 * Transposes this matrix in place.
13101	 *
13102	 * @return {Matrix4} A reference to this matrix.
13103	 */
13104	transpose() {
13105
13106		const te = this.elements;
13107		let tmp;
13108
13109		tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
13110		tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
13111		tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
13112
13113		tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
13114		tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
13115		tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
13116
13117		return this;
13118
13119	}
13120
vendor: 4,133 bytes, lines 13121-13223
13121	/**
13122	 * Sets the position component for this matrix from the given vector,
13123	 * without affecting the rest of the matrix.
13124	 *
13125	 * @param {number|Vector3} x - The x component of the vector or alternatively the vector object.
13126	 * @param {number} y - The y component of the vector.
13127	 * @param {number} z - The z component of the vector.
13128	 * @return {Matrix4} A reference to this matrix.
13129	 */
13130	setPosition( x, y, z ) {
13131
13132		const te = this.elements;
13133
13134		if ( x.isVector3 ) {
13135
13136			te[ 12 ] = x.x;
13137			te[ 13 ] = x.y;
13138			te[ 14 ] = x.z;
13139
13140		} else {
13141
13142			te[ 12 ] = x;
13143			te[ 13 ] = y;
13144			te[ 14 ] = z;
13145
13146		}
13147
13148		return this;
13149
13150	}
13151
13152	/**
13153	 * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}.
13154	 * You can not invert with a determinant of zero. If you attempt this, the method produces
13155	 * a zero matrix instead.
13156	 *
13157	 * @return {Matrix4} A reference to this matrix.
13158	 */
13159	invert() {
13160
13161		// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
13162		const te = this.elements,
13163
13164			n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
13165			n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
13166			n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
13167			n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
13168
13169			t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
13170			t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
13171			t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
13172			t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
13173
13174		const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
13175
13176		if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
13177
13178		const detInv = 1 / det;
13179
13180		te[ 0 ] = t11 * detInv;
13181		te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
13182		te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
13183		te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
13184
13185		te[ 4 ] = t12 * detInv;
13186		te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
13187		te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
13188		te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
13189
13190		te[ 8 ] = t13 * detInv;
13191		te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
13192		te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
13193		te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
13194
13195		te[ 12 ] = t14 * detInv;
13196		te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
13197		te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
13198		te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
13199
13200		return this;
13201
13202	}
13203
13204	/**
13205	 * Multiplies the columns of this matrix by the given vector.
13206	 *
13207	 * @param {Vector3} v - The scale vector.
13208	 * @return {Matrix4} A reference to this matrix.
13209	 */
13210	scale( v ) {
13211
13212		const te = this.elements;
13213		const x = v.x, y = v.y, z = v.z;
13214
13215		te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
13216		te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
13217		te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
13218		te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
13219
13220		return this;
13221
13222	}
13223
vendor: 4,266 bytes, lines 13224-13433
13224	/**
13225	 * Gets the maximum scale value of the three axes.
13226	 *
13227	 * @return {number} The maximum scale.
13228	 */
13229	getMaxScaleOnAxis() {
13230
13231		const te = this.elements;
13232
13233		const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
13234		const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
13235		const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
13236
13237		return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
13238
13239	}
13240
13241	/**
13242	 * Sets this matrix as a translation transform from the given vector.
13243	 *
13244	 * @param {number|Vector3} x - The amount to translate in the X axis or alternatively a translation vector.
13245	 * @param {number} y - The amount to translate in the Y axis.
13246	 * @param {number} z - The amount to translate in the z axis.
13247	 * @return {Matrix4} A reference to this matrix.
13248	 */
13249	makeTranslation( x, y, z ) {
13250
13251		if ( x.isVector3 ) {
13252
13253			this.set(
13254
13255				1, 0, 0, x.x,
13256				0, 1, 0, x.y,
13257				0, 0, 1, x.z,
13258				0, 0, 0, 1
13259
13260			);
13261
13262		} else {
13263
13264			this.set(
13265
13266				1, 0, 0, x,
13267				0, 1, 0, y,
13268				0, 0, 1, z,
13269				0, 0, 0, 1
13270
13271			);
13272
13273		}
13274
13275		return this;
13276
13277	}
13278
13279	/**
13280	 * Sets this matrix as a rotational transformation around the X axis by
13281	 * the given angle.
13282	 *
13283	 * @param {number} theta - The rotation in radians.
13284	 * @return {Matrix4} A reference to this matrix.
13285	 */
13286	makeRotationX( theta ) {
13287
13288		const c = Math.cos( theta ), s = Math.sin( theta );
13289
13290		this.set(
13291
13292			1, 0, 0, 0,
13293			0, c, - s, 0,
13294			0, s, c, 0,
13295			0, 0, 0, 1
13296
13297		);
13298
13299		return this;
13300
13301	}
13302
13303	/**
13304	 * Sets this matrix as a rotational transformation around the Y axis by
13305	 * the given angle.
13306	 *
13307	 * @param {number} theta - The rotation in radians.
13308	 * @return {Matrix4} A reference to this matrix.
13309	 */
13310	makeRotationY( theta ) {
13311
13312		const c = Math.cos( theta ), s = Math.sin( theta );
13313
13314		this.set(
13315
13316			 c, 0, s, 0,
13317			 0, 1, 0, 0,
13318			- s, 0, c, 0,
13319			 0, 0, 0, 1
13320
13321		);
13322
13323		return this;
13324
13325	}
13326
13327	/**
13328	 * Sets this matrix as a rotational transformation around the Z axis by
13329	 * the given angle.
13330	 *
13331	 * @param {number} theta - The rotation in radians.
13332	 * @return {Matrix4} A reference to this matrix.
13333	 */
13334	makeRotationZ( theta ) {
13335
13336		const c = Math.cos( theta ), s = Math.sin( theta );
13337
13338		this.set(
13339
13340			c, - s, 0, 0,
13341			s, c, 0, 0,
13342			0, 0, 1, 0,
13343			0, 0, 0, 1
13344
13345		);
13346
13347		return this;
13348
13349	}
13350
13351	/**
13352	 * Sets this matrix as a rotational transformation around the given axis by
13353	 * the given angle.
13354	 *
13355	 * This is a somewhat controversial but mathematically sound alternative to
13356	 * rotating via Quaternions. See the discussion [here]{@link https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199}.
13357	 *
13358	 * @param {Vector3} axis - The normalized rotation axis.
13359	 * @param {number} angle - The rotation in radians.
13360	 * @return {Matrix4} A reference to this matrix.
13361	 */
13362	makeRotationAxis( axis, angle ) {
13363
13364		// Based on http://www.gamedev.net/reference/articles/article1199.asp
13365
13366		const c = Math.cos( angle );
13367		const s = Math.sin( angle );
13368		const t = 1 - c;
13369		const x = axis.x, y = axis.y, z = axis.z;
13370		const tx = t * x, ty = t * y;
13371
13372		this.set(
13373
13374			tx * x + c, tx * y - s * z, tx * z + s * y, 0,
13375			tx * y + s * z, ty * y + c, ty * z - s * x, 0,
13376			tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
13377			0, 0, 0, 1
13378
13379		);
13380
13381		return this;
13382
13383	}
13384
13385	/**
13386	 * Sets this matrix as a scale transformation.
13387	 *
13388	 * @param {number} x - The amount to scale in the X axis.
13389	 * @param {number} y - The amount to scale in the Y axis.
13390	 * @param {number} z - The amount to scale in the Z axis.
13391	 * @return {Matrix4} A reference to this matrix.
13392	 */
13393	makeScale( x, y, z ) {
13394
13395		this.set(
13396
13397			x, 0, 0, 0,
13398			0, y, 0, 0,
13399			0, 0, z, 0,
13400			0, 0, 0, 1
13401
13402		);
13403
13404		return this;
13405
13406	}
13407
13408	/**
13409	 * Sets this matrix as a shear transformation.
13410	 *
13411	 * @param {number} xy - The amount to shear X by Y.
13412	 * @param {number} xz - The amount to shear X by Z.
13413	 * @param {number} yx - The amount to shear Y by X.
13414	 * @param {number} yz - The amount to shear Y by Z.
13415	 * @param {number} zx - The amount to shear Z by X.
13416	 * @param {number} zy - The amount to shear Z by Y.
13417	 * @return {Matrix4} A reference to this matrix.
13418	 */
13419	makeShear( xy, xz, yx, yz, zx, zy ) {
13420
13421		this.set(
13422
13423			1, yx, zx, 0,
13424			xy, 1, zy, 0,
13425			xz, yz, 1, 0,
13426			0, 0, 0, 1
13427
13428		);
13429
13430		return this;
13431
13432	}
13433
vendor: 14,176 bytes, lines 13434-14035
13434	/**
13435	 * Sets this matrix to the transformation composed of the given position,
13436	 * rotation (Quaternion) and scale.
13437	 *
13438	 * @param {Vector3} position - The position vector.
13439	 * @param {Quaternion} quaternion - The rotation as a Quaternion.
13440	 * @param {Vector3} scale - The scale vector.
13441	 * @return {Matrix4} A reference to this matrix.
13442	 */
13443	compose( position, quaternion, scale ) {
13444
13445		const te = this.elements;
13446
13447		const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
13448		const x2 = x + x,	y2 = y + y, z2 = z + z;
13449		const xx = x * x2, xy = x * y2, xz = x * z2;
13450		const yy = y * y2, yz = y * z2, zz = z * z2;
13451		const wx = w * x2, wy = w * y2, wz = w * z2;
13452
13453		const sx = scale.x, sy = scale.y, sz = scale.z;
13454
13455		te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
13456		te[ 1 ] = ( xy + wz ) * sx;
13457		te[ 2 ] = ( xz - wy ) * sx;
13458		te[ 3 ] = 0;
13459
13460		te[ 4 ] = ( xy - wz ) * sy;
13461		te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
13462		te[ 6 ] = ( yz + wx ) * sy;
13463		te[ 7 ] = 0;
13464
13465		te[ 8 ] = ( xz + wy ) * sz;
13466		te[ 9 ] = ( yz - wx ) * sz;
13467		te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
13468		te[ 11 ] = 0;
13469
13470		te[ 12 ] = position.x;
13471		te[ 13 ] = position.y;
13472		te[ 14 ] = position.z;
13473		te[ 15 ] = 1;
13474
13475		return this;
13476
13477	}
13478
13479	/**
13480	 * Decomposes this matrix into its position, rotation and scale components
13481	 * and provides the result in the given objects.
13482	 *
13483	 * Note: Not all matrices are decomposable in this way. For example, if an
13484	 * object has a non-uniformly scaled parent, then the object's world matrix
13485	 * may not be decomposable, and this method may not be appropriate.
13486	 *
13487	 * @param {Vector3} position - The position vector.
13488	 * @param {Quaternion} quaternion - The rotation as a Quaternion.
13489	 * @param {Vector3} scale - The scale vector.
13490	 * @return {Matrix4} A reference to this matrix.
13491	 */
13492	decompose( position, quaternion, scale ) {
13493
13494		const te = this.elements;
13495
13496		let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
13497		const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
13498		const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
13499
13500		// if determine is negative, we need to invert one scale
13501		const det = this.determinant();
13502		if ( det < 0 ) sx = - sx;
13503
13504		position.x = te[ 12 ];
13505		position.y = te[ 13 ];
13506		position.z = te[ 14 ];
13507
13508		// scale the rotation part
13509		_m1$2.copy( this );
13510
13511		const invSX = 1 / sx;
13512		const invSY = 1 / sy;
13513		const invSZ = 1 / sz;
13514
13515		_m1$2.elements[ 0 ] *= invSX;
13516		_m1$2.elements[ 1 ] *= invSX;
13517		_m1$2.elements[ 2 ] *= invSX;
13518
13519		_m1$2.elements[ 4 ] *= invSY;
13520		_m1$2.elements[ 5 ] *= invSY;
13521		_m1$2.elements[ 6 ] *= invSY;
13522
13523		_m1$2.elements[ 8 ] *= invSZ;
13524		_m1$2.elements[ 9 ] *= invSZ;
13525		_m1$2.elements[ 10 ] *= invSZ;
13526
13527		quaternion.setFromRotationMatrix( _m1$2 );
13528
13529		scale.x = sx;
13530		scale.y = sy;
13531		scale.z = sz;
13532
13533		return this;
13534
13535	}
13536
13537	/**
13538	 * Creates a perspective projection matrix. This is used internally by
13539	 * {@link PerspectiveCamera#updateProjectionMatrix}.
13540
13541	 * @param {number} left - Left boundary of the viewing frustum at the near plane.
13542	 * @param {number} right - Right boundary of the viewing frustum at the near plane.
13543	 * @param {number} top - Top boundary of the viewing frustum at the near plane.
13544	 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane.
13545	 * @param {number} near - The distance from the camera to the near plane.
13546	 * @param {number} far - The distance from the camera to the far plane.
13547	 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system.
13548	 * @return {Matrix4} A reference to this matrix.
13549	 */
13550	makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
13551
13552		const te = this.elements;
13553		const x = 2 * near / ( right - left );
13554		const y = 2 * near / ( top - bottom );
13555
13556		const a = ( right + left ) / ( right - left );
13557		const b = ( top + bottom ) / ( top - bottom );
13558
13559		let c, d;
13560
13561		if ( coordinateSystem === WebGLCoordinateSystem ) {
13562
13563			c = - ( far + near ) / ( far - near );
13564			d = ( -2 * far * near ) / ( far - near );
13565
13566		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
13567
13568			c = - far / ( far - near );
13569			d = ( - far * near ) / ( far - near );
13570
13571		} else {
13572
13573			throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem );
13574
13575		}
13576
13577		te[ 0 ] = x;	te[ 4 ] = 0;	te[ 8 ] = a; 	te[ 12 ] = 0;
13578		te[ 1 ] = 0;	te[ 5 ] = y;	te[ 9 ] = b; 	te[ 13 ] = 0;
13579		te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = c; 	te[ 14 ] = d;
13580		te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = -1;	te[ 15 ] = 0;
13581
13582		return this;
13583
13584	}
13585
13586	/**
13587	 * Creates a orthographic projection matrix. This is used internally by
13588	 * {@link OrthographicCamera#updateProjectionMatrix}.
13589
13590	 * @param {number} left - Left boundary of the viewing frustum at the near plane.
13591	 * @param {number} right - Right boundary of the viewing frustum at the near plane.
13592	 * @param {number} top - Top boundary of the viewing frustum at the near plane.
13593	 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane.
13594	 * @param {number} near - The distance from the camera to the near plane.
13595	 * @param {number} far - The distance from the camera to the far plane.
13596	 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system.
13597	 * @return {Matrix4} A reference to this matrix.
13598	 */
13599	makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
13600
13601		const te = this.elements;
13602		const w = 1.0 / ( right - left );
13603		const h = 1.0 / ( top - bottom );
13604		const p = 1.0 / ( far - near );
13605
13606		const x = ( right + left ) * w;
13607		const y = ( top + bottom ) * h;
13608
13609		let z, zInv;
13610
13611		if ( coordinateSystem === WebGLCoordinateSystem ) {
13612
13613			z = ( far + near ) * p;
13614			zInv = -2 * p;
13615
13616		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
13617
13618			z = near * p;
13619			zInv = -1 * p;
13620
13621		} else {
13622
13623			throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem );
13624
13625		}
13626
13627		te[ 0 ] = 2 * w;	te[ 4 ] = 0;		te[ 8 ] = 0; 		te[ 12 ] = - x;
13628		te[ 1 ] = 0; 		te[ 5 ] = 2 * h;	te[ 9 ] = 0; 		te[ 13 ] = - y;
13629		te[ 2 ] = 0; 		te[ 6 ] = 0;		te[ 10 ] = zInv;	te[ 14 ] = - z;
13630		te[ 3 ] = 0; 		te[ 7 ] = 0;		te[ 11 ] = 0;		te[ 15 ] = 1;
13631
13632		return this;
13633
13634	}
13635
13636	/**
13637	 * Returns `true` if this matrix is equal with the given one.
13638	 *
13639	 * @param {Matrix4} matrix - The matrix to test for equality.
13640	 * @return {boolean} Whether this matrix is equal with the given one.
13641	 */
13642	equals( matrix ) {
13643
13644		const te = this.elements;
13645		const me = matrix.elements;
13646
13647		for ( let i = 0; i < 16; i ++ ) {
13648
13649			if ( te[ i ] !== me[ i ] ) return false;
13650
13651		}
13652
13653		return true;
13654
13655	}
13656
13657	/**
13658	 * Sets the elements of the matrix from the given array.
13659	 *
13660	 * @param {Array<number>} array - The matrix elements in column-major order.
13661	 * @param {number} [offset=0] - Index of the first element in the array.
13662	 * @return {Matrix4} A reference to this matrix.
13663	 */
13664	fromArray( array, offset = 0 ) {
13665
13666		for ( let i = 0; i < 16; i ++ ) {
13667
13668			this.elements[ i ] = array[ i + offset ];
13669
13670		}
13671
13672		return this;
13673
13674	}
13675
13676	/**
13677	 * Writes the elements of this matrix to the given array. If no array is provided,
13678	 * the method returns a new instance.
13679	 *
13680	 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order.
13681	 * @param {number} [offset=0] - Index of the first element in the array.
13682	 * @return {Array<number>} The matrix elements in column-major order.
13683	 */
13684	toArray( array = [], offset = 0 ) {
13685
13686		const te = this.elements;
13687
13688		array[ offset ] = te[ 0 ];
13689		array[ offset + 1 ] = te[ 1 ];
13690		array[ offset + 2 ] = te[ 2 ];
13691		array[ offset + 3 ] = te[ 3 ];
13692
13693		array[ offset + 4 ] = te[ 4 ];
13694		array[ offset + 5 ] = te[ 5 ];
13695		array[ offset + 6 ] = te[ 6 ];
13696		array[ offset + 7 ] = te[ 7 ];
13697
13698		array[ offset + 8 ] = te[ 8 ];
13699		array[ offset + 9 ] = te[ 9 ];
13700		array[ offset + 10 ] = te[ 10 ];
13701		array[ offset + 11 ] = te[ 11 ];
13702
13703		array[ offset + 12 ] = te[ 12 ];
13704		array[ offset + 13 ] = te[ 13 ];
13705		array[ offset + 14 ] = te[ 14 ];
13706		array[ offset + 15 ] = te[ 15 ];
13707
13708		return array;
13709
13710	}
13711
13712}
13713
13714const _v1$5 = /*@__PURE__*/ new Vector3();
13715const _m1$2 = /*@__PURE__*/ new Matrix4();
13716const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
13717const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
13718const _x = /*@__PURE__*/ new Vector3();
13719const _y = /*@__PURE__*/ new Vector3();
13720const _z = /*@__PURE__*/ new Vector3();
13721
13722const _matrix$2 = /*@__PURE__*/ new Matrix4();
13723const _quaternion$3 = /*@__PURE__*/ new Quaternion();
13724
13725/**
13726 * A class representing Euler angles.
13727 *
13728 * Euler angles describe a rotational transformation by rotating an object on
13729 * its various axes in specified amounts per axis, and a specified axis
13730 * order.
13731 *
13732 * Iterating through an instance will yield its components (x, y, z,
13733 * order) in the corresponding order.
13734 *
13735 * ```js
13736 * const a = new THREE.Euler( 0, 1, 1.57, 'XYZ' );
13737 * const b = new THREE.Vector3( 1, 0, 1 );
13738 * b.applyEuler(a);
13739 * ```
13740 */
13741class Euler {
13742
13743	/**
13744	 * Constructs a new euler instance.
13745	 *
13746	 * @param {number} [x=0] - The angle of the x axis in radians.
13747	 * @param {number} [y=0] - The angle of the y axis in radians.
13748	 * @param {number} [z=0] - The angle of the z axis in radians.
13749	 * @param {string} [order=Euler.DEFAULT_ORDER] - A string representing the order that the rotations are applied.
13750	 */
13751	constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) {
13752
13753		/**
13754		 * This flag can be used for type testing.
13755		 *
13756		 * @type {boolean}
13757		 * @readonly
13758		 * @default true
13759		 */
13760		this.isEuler = true;
13761
13762		this._x = x;
13763		this._y = y;
13764		this._z = z;
13765		this._order = order;
13766
13767	}
13768
13769	/**
13770	 * The angle of the x axis in radians.
13771	 *
13772	 * @type {number}
13773	 * @default 0
13774	 */
13775	get x() {
13776
13777		return this._x;
13778
13779	}
13780
13781	set x( value ) {
13782
13783		this._x = value;
13784		this._onChangeCallback();
13785
13786	}
13787
13788	/**
13789	 * The angle of the y axis in radians.
13790	 *
13791	 * @type {number}
13792	 * @default 0
13793	 */
13794	get y() {
13795
13796		return this._y;
13797
13798	}
13799
13800	set y( value ) {
13801
13802		this._y = value;
13803		this._onChangeCallback();
13804
13805	}
13806
13807	/**
13808	 * The angle of the z axis in radians.
13809	 *
13810	 * @type {number}
13811	 * @default 0
13812	 */
13813	get z() {
13814
13815		return this._z;
13816
13817	}
13818
13819	set z( value ) {
13820
13821		this._z = value;
13822		this._onChangeCallback();
13823
13824	}
13825
13826	/**
13827	 * A string representing the order that the rotations are applied.
13828	 *
13829	 * @type {string}
13830	 * @default 'XYZ'
13831	 */
13832	get order() {
13833
13834		return this._order;
13835
13836	}
13837
13838	set order( value ) {
13839
13840		this._order = value;
13841		this._onChangeCallback();
13842
13843	}
13844
13845	/**
13846	 * Sets the Euler components.
13847	 *
13848	 * @param {number} x - The angle of the x axis in radians.
13849	 * @param {number} y - The angle of the y axis in radians.
13850	 * @param {number} z - The angle of the z axis in radians.
13851	 * @param {string} [order] - A string representing the order that the rotations are applied.
13852	 * @return {Euler} A reference to this Euler instance.
13853	 */
13854	set( x, y, z, order = this._order ) {
13855
13856		this._x = x;
13857		this._y = y;
13858		this._z = z;
13859		this._order = order;
13860
13861		this._onChangeCallback();
13862
13863		return this;
13864
13865	}
13866
13867	/**
13868	 * Returns a new Euler instance with copied values from this instance.
13869	 *
13870	 * @return {Euler} A clone of this instance.
13871	 */
13872	clone() {
13873
13874		return new this.constructor( this._x, this._y, this._z, this._order );
13875
13876	}
13877
13878	/**
13879	 * Copies the values of the given Euler instance to this instance.
13880	 *
13881	 * @param {Euler} euler - The Euler instance to copy.
13882	 * @return {Euler} A reference to this Euler instance.
13883	 */
13884	copy( euler ) {
13885
13886		this._x = euler._x;
13887		this._y = euler._y;
13888		this._z = euler._z;
13889		this._order = euler._order;
13890
13891		this._onChangeCallback();
13892
13893		return this;
13894
13895	}
13896
13897	/**
13898	 * Sets the angles of this Euler instance from a pure rotation matrix.
13899	 *
13900	 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled).
13901	 * @param {string} [order] - A string representing the order that the rotations are applied.
13902	 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not.
13903	 * @return {Euler} A reference to this Euler instance.
13904	 */
13905	setFromRotationMatrix( m, order = this._order, update = true ) {
13906
13907		const te = m.elements;
13908		const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
13909		const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
13910		const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
13911
13912		switch ( order ) {
13913
13914			case 'XYZ':
13915
13916				this._y = Math.asin( clamp( m13, -1, 1 ) );
13917
13918				if ( Math.abs( m13 ) < 0.9999999 ) {
13919
13920					this._x = Math.atan2( - m23, m33 );
13921					this._z = Math.atan2( - m12, m11 );
13922
13923				} else {
13924
13925					this._x = Math.atan2( m32, m22 );
13926					this._z = 0;
13927
13928				}
13929
13930				break;
13931
13932			case 'YXZ':
13933
13934				this._x = Math.asin( - clamp( m23, -1, 1 ) );
13935
13936				if ( Math.abs( m23 ) < 0.9999999 ) {
13937
13938					this._y = Math.atan2( m13, m33 );
13939					this._z = Math.atan2( m21, m22 );
13940
13941				} else {
13942
13943					this._y = Math.atan2( - m31, m11 );
13944					this._z = 0;
13945
13946				}
13947
13948				break;
13949
13950			case 'ZXY':
13951
13952				this._x = Math.asin( clamp( m32, -1, 1 ) );
13953
13954				if ( Math.abs( m32 ) < 0.9999999 ) {
13955
13956					this._y = Math.atan2( - m31, m33 );
13957					this._z = Math.atan2( - m12, m22 );
13958
13959				} else {
13960
13961					this._y = 0;
13962					this._z = Math.atan2( m21, m11 );
13963
13964				}
13965
13966				break;
13967
13968			case 'ZYX':
13969
13970				this._y = Math.asin( - clamp( m31, -1, 1 ) );
13971
13972				if ( Math.abs( m31 ) < 0.9999999 ) {
13973
13974					this._x = Math.atan2( m32, m33 );
13975					this._z = Math.atan2( m21, m11 );
13976
13977				} else {
13978
13979					this._x = 0;
13980					this._z = Math.atan2( - m12, m22 );
13981
13982				}
13983
13984				break;
13985
13986			case 'YZX':
13987
13988				this._z = Math.asin( clamp( m21, -1, 1 ) );
13989
13990				if ( Math.abs( m21 ) < 0.9999999 ) {
13991
13992					this._x = Math.atan2( - m23, m22 );
13993					this._y = Math.atan2( - m31, m11 );
13994
13995				} else {
13996
13997					this._x = 0;
13998					this._y = Math.atan2( m13, m33 );
13999
14000				}
14001
14002				break;
14003
14004			case 'XZY':
14005
14006				this._z = Math.asin( - clamp( m12, -1, 1 ) );
14007
14008				if ( Math.abs( m12 ) < 0.9999999 ) {
14009
14010					this._x = Math.atan2( m32, m22 );
14011					this._y = Math.atan2( m13, m11 );
14012
14013				} else {
14014
14015					this._x = Math.atan2( - m23, m33 );
14016					this._y = 0;
14017
14018				}
14019
14020				break;
14021
14022			default:
14023
14024				console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
14025
14026		}
14027
14028		this._order = order;
14029
14030		if ( update === true ) this._onChangeCallback();
14031
14032		return this;
14033
14034	}
14035
vendor: 11,401 bytes, lines 14036-14545
14036	/**
14037	 * Sets the angles of this Euler instance from a normalized quaternion.
14038	 *
14039	 * @param {Quaternion} q - A normalized Quaternion.
14040	 * @param {string} [order] - A string representing the order that the rotations are applied.
14041	 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not.
14042	 * @return {Euler} A reference to this Euler instance.
14043	 */
14044	setFromQuaternion( q, order, update ) {
14045
14046		_matrix$2.makeRotationFromQuaternion( q );
14047
14048		return this.setFromRotationMatrix( _matrix$2, order, update );
14049
14050	}
14051
14052	/**
14053	 * Sets the angles of this Euler instance from the given vector.
14054	 *
14055	 * @param {Vector3} v - The vector.
14056	 * @param {string} [order] - A string representing the order that the rotations are applied.
14057	 * @return {Euler} A reference to this Euler instance.
14058	 */
14059	setFromVector3( v, order = this._order ) {
14060
14061		return this.set( v.x, v.y, v.z, order );
14062
14063	}
14064
14065	/**
14066	 * Resets the euler angle with a new order by creating a quaternion from this
14067	 * euler angle and then setting this euler angle with the quaternion and the
14068	 * new order.
14069	 *
14070	 * Warning: This discards revolution information.
14071	 *
14072	 * @param {string} [newOrder] - A string representing the new order that the rotations are applied.
14073	 * @return {Euler} A reference to this Euler instance.
14074	 */
14075	reorder( newOrder ) {
14076
14077		_quaternion$3.setFromEuler( this );
14078
14079		return this.setFromQuaternion( _quaternion$3, newOrder );
14080
14081	}
14082
14083	/**
14084	 * Returns `true` if this Euler instance is equal with the given one.
14085	 *
14086	 * @param {Euler} euler - The Euler instance to test for equality.
14087	 * @return {boolean} Whether this Euler instance is equal with the given one.
14088	 */
14089	equals( euler ) {
14090
14091		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
14092
14093	}
14094
14095	/**
14096	 * Sets this Euler instance's components to values from the given array. The first three
14097	 * entries of the array are assign to the x,y and z components. An optional fourth entry
14098	 * defines the Euler order.
14099	 *
14100	 * @param {Array<number,number,number,?string>} array - An array holding the Euler component values.
14101	 * @return {Euler} A reference to this Euler instance.
14102	 */
14103	fromArray( array ) {
14104
14105		this._x = array[ 0 ];
14106		this._y = array[ 1 ];
14107		this._z = array[ 2 ];
14108		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
14109
14110		this._onChangeCallback();
14111
14112		return this;
14113
14114	}
14115
14116	/**
14117	 * Writes the components of this Euler instance to the given array. If no array is provided,
14118	 * the method returns a new instance.
14119	 *
14120	 * @param {Array<number,number,number,string>} [array=[]] - The target array holding the Euler components.
14121	 * @param {number} [offset=0] - Index of the first element in the array.
14122	 * @return {Array<number,number,number,string>} The Euler components.
14123	 */
14124	toArray( array = [], offset = 0 ) {
14125
14126		array[ offset ] = this._x;
14127		array[ offset + 1 ] = this._y;
14128		array[ offset + 2 ] = this._z;
14129		array[ offset + 3 ] = this._order;
14130
14131		return array;
14132
14133	}
14134
14135	_onChange( callback ) {
14136
14137		this._onChangeCallback = callback;
14138
14139		return this;
14140
14141	}
14142
14143	_onChangeCallback() {}
14144
14145	*[ Symbol.iterator ]() {
14146
14147		yield this._x;
14148		yield this._y;
14149		yield this._z;
14150		yield this._order;
14151
14152	}
14153
14154}
14155
14156/**
14157 * The default Euler angle order.
14158 *
14159 * @static
14160 * @type {string}
14161 * @default 'XYZ'
14162 */
14163Euler.DEFAULT_ORDER = 'XYZ';
14164
14165/**
14166 * A layers object assigns an 3D object to 1 or more of 32
14167 * layers numbered `0` to `31` - internally the layers are stored as a
14168 * bit mask], and by default all 3D objects are a member of layer `0`.
14169 *
14170 * This can be used to control visibility - an object must share a layer with
14171 * a camera to be visible when that camera's view is
14172 * rendered.
14173 *
14174 * All classes that inherit from {@link Object3D} have an `layers` property which
14175 * is an instance of this class.
14176 */
14177class Layers {
14178
14179	/**
14180	 * Constructs a new layers instance, with membership
14181	 * initially set to layer `0`.
14182	 */
14183	constructor() {
14184
14185		/**
14186		 * A bit mask storing which of the 32 layers this layers object is currently
14187		 * a member of.
14188		 *
14189		 * @type {number}
14190		 */
14191		this.mask = 1 | 0;
14192
14193	}
14194
14195	/**
14196	 * Sets membership to the given layer, and remove membership all other layers.
14197	 *
14198	 * @param {number} layer - The layer to set.
14199	 */
14200	set( layer ) {
14201
14202		this.mask = ( 1 << layer | 0 ) >>> 0;
14203
14204	}
14205
14206	/**
14207	 * Adds membership of the given layer.
14208	 *
14209	 * @param {number} layer - The layer to enable.
14210	 */
14211	enable( layer ) {
14212
14213		this.mask |= 1 << layer | 0;
14214
14215	}
14216
14217	/**
14218	 * Adds membership to all layers.
14219	 */
14220	enableAll() {
14221
14222		this.mask = 0xffffffff | 0;
14223
14224	}
14225
14226	/**
14227	 * Toggles the membership of the given layer.
14228	 *
14229	 * @param {number} layer - The layer to toggle.
14230	 */
14231	toggle( layer ) {
14232
14233		this.mask ^= 1 << layer | 0;
14234
14235	}
14236
14237	/**
14238	 * Removes membership of the given layer.
14239	 *
14240	 * @param {number} layer - The layer to enable.
14241	 */
14242	disable( layer ) {
14243
14244		this.mask &= ~ ( 1 << layer | 0 );
14245
14246	}
14247
14248	/**
14249	 * Removes the membership from all layers.
14250	 */
14251	disableAll() {
14252
14253		this.mask = 0;
14254
14255	}
14256
14257	/**
14258	 * Returns `true` if this and the given layers object have at least one
14259	 * layer in common.
14260	 *
14261	 * @param {Layers} layers - The layers to test.
14262	 * @return {boolean } Whether this and the given layers object have at least one layer in common or not.
14263	 */
14264	test( layers ) {
14265
14266		return ( this.mask & layers.mask ) !== 0;
14267
14268	}
14269
14270	/**
14271	 * Returns `true` if the given layer is enabled.
14272	 *
14273	 * @param {number} layer - The layer to test.
14274	 * @return {boolean } Whether the given layer is enabled or not.
14275	 */
14276	isEnabled( layer ) {
14277
14278		return ( this.mask & ( 1 << layer | 0 ) ) !== 0;
14279
14280	}
14281
14282}
14283
14284let _object3DId = 0;
14285
14286const _v1$4 = /*@__PURE__*/ new Vector3();
14287const _q1 = /*@__PURE__*/ new Quaternion();
14288const _m1$1 = /*@__PURE__*/ new Matrix4();
14289const _target = /*@__PURE__*/ new Vector3();
14290
14291const _position$3 = /*@__PURE__*/ new Vector3();
14292const _scale$2 = /*@__PURE__*/ new Vector3();
14293const _quaternion$2 = /*@__PURE__*/ new Quaternion();
14294
14295const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );
14296const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );
14297const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );
14298
14299/**
14300 * Fires when the object has been added to its parent object.
14301 *
14302 * @event Object3D#added
14303 * @type {Object}
14304 */
14305const _addedEvent = { type: 'added' };
14306
14307/**
14308 * Fires when the object has been removed from its parent object.
14309 *
14310 * @event Object3D#removed
14311 * @type {Object}
14312 */
14313const _removedEvent = { type: 'removed' };
14314
14315/**
14316 * Fires when a new child object has been added.
14317 *
14318 * @event Object3D#childadded
14319 * @type {Object}
14320 */
14321const _childaddedEvent = { type: 'childadded', child: null };
14322
14323/**
14324 * Fires when a new child object has been added.
14325 *
14326 * @event Object3D#childremoved
14327 * @type {Object}
14328 */
14329const _childremovedEvent = { type: 'childremoved', child: null };
14330
14331/**
14332 * This is the base class for most objects in three.js and provides a set of
14333 * properties and methods for manipulating objects in 3D space.
14334 *
14335 * @augments EventDispatcher
14336 */
14337class Object3D extends EventDispatcher {
14338
14339	/**
14340	 * Constructs a new 3D object.
14341	 */
14342	constructor() {
14343
14344		super();
14345
14346		/**
14347		 * This flag can be used for type testing.
14348		 *
14349		 * @type {boolean}
14350		 * @readonly
14351		 * @default true
14352		 */
14353		this.isObject3D = true;
14354
14355		/**
14356		 * The ID of the 3D object.
14357		 *
14358		 * @name Object3D#id
14359		 * @type {number}
14360		 * @readonly
14361		 */
14362		Object.defineProperty( this, 'id', { value: _object3DId ++ } );
14363
14364		/**
14365		 * The UUID of the 3D object.
14366		 *
14367		 * @type {string}
14368		 * @readonly
14369		 */
14370		this.uuid = generateUUID();
14371
14372		/**
14373		 * The name of the 3D object.
14374		 *
14375		 * @type {string}
14376		 */
14377		this.name = '';
14378
14379		/**
14380		 * The type property is used for detecting the object type
14381		 * in context of serialization/deserialization.
14382		 *
14383		 * @type {string}
14384		 * @readonly
14385		 */
14386		this.type = 'Object3D';
14387
14388		/**
14389		 * A reference to the parent object.
14390		 *
14391		 * @type {?Object3D}
14392		 * @default null
14393		 */
14394		this.parent = null;
14395
14396		/**
14397		 * An array holding the child 3D objects of this instance.
14398		 *
14399		 * @type {Array<Object3D>}
14400		 */
14401		this.children = [];
14402
14403		/**
14404		 * Defines the `up` direction of the 3D object which influences
14405		 * the orientation via methods like {@link Object3D#lookAt}.
14406		 *
14407		 * The default values for all 3D objects is defined by `Object3D.DEFAULT_UP`.
14408		 *
14409		 * @type {Vector3}
14410		 */
14411		this.up = Object3D.DEFAULT_UP.clone();
14412
14413		const position = new Vector3();
14414		const rotation = new Euler();
14415		const quaternion = new Quaternion();
14416		const scale = new Vector3( 1, 1, 1 );
14417
14418		function onRotationChange() {
14419
14420			quaternion.setFromEuler( rotation, false );
14421
14422		}
14423
14424		function onQuaternionChange() {
14425
14426			rotation.setFromQuaternion( quaternion, undefined, false );
14427
14428		}
14429
14430		rotation._onChange( onRotationChange );
14431		quaternion._onChange( onQuaternionChange );
14432
14433		Object.defineProperties( this, {
14434			/**
14435			 * Represents the object's local position.
14436			 *
14437			 * @name Object3D#position
14438			 * @type {Vector3}
14439			 * @default (0,0,0)
14440			 */
14441			position: {
14442				configurable: true,
14443				enumerable: true,
14444				value: position
14445			},
14446			/**
14447			 * Represents the object's local rotation as Euler angles, in radians.
14448			 *
14449			 * @name Object3D#rotation
14450			 * @type {Euler}
14451			 * @default (0,0,0)
14452			 */
14453			rotation: {
14454				configurable: true,
14455				enumerable: true,
14456				value: rotation
14457			},
14458			/**
14459			 * Represents the object's local rotation as Quaternions.
14460			 *
14461			 * @name Object3D#quaternion
14462			 * @type {Quaternion}
14463			 */
14464			quaternion: {
14465				configurable: true,
14466				enumerable: true,
14467				value: quaternion
14468			},
14469			/**
14470			 * Represents the object's local scale.
14471			 *
14472			 * @name Object3D#scale
14473			 * @type {Vector3}
14474			 * @default (1,1,1)
14475			 */
14476			scale: {
14477				configurable: true,
14478				enumerable: true,
14479				value: scale
14480			},
14481			/**
14482			 * Represents the object's model-view matrix.
14483			 *
14484			 * @name Object3D#modelViewMatrix
14485			 * @type {Matrix4}
14486			 */
14487			modelViewMatrix: {
14488				value: new Matrix4()
14489			},
14490			/**
14491			 * Represents the object's normal matrix.
14492			 *
14493			 * @name Object3D#normalMatrix
14494			 * @type {Matrix3}
14495			 */
14496			normalMatrix: {
14497				value: new Matrix3()
14498			}
14499		} );
14500
14501		/**
14502		 * Represents the object's transformation matrix in local space.
14503		 *
14504		 * @type {Matrix4}
14505		 */
14506		this.matrix = new Matrix4();
14507
14508		/**
14509		 * Represents the object's transformation matrix in world space.
14510		 * If the 3D object has no parent, then it's identical to the local transformation matrix
14511		 *
14512		 * @type {Matrix4}
14513		 */
14514		this.matrixWorld = new Matrix4();
14515
14516		/**
14517		 * When set to `true`, the engine automatically computes the local matrix from position,
14518		 * rotation and scale every frame.
14519		 *
14520		 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_AUTO_UPDATE`.
14521		 *
14522		 * @type {boolean}
14523		 * @default true
14524		 */
14525		this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
14526
14527		/**
14528		 * When set to `true`, the engine automatically computes the world matrix from the current local
14529		 * matrix and the object's transformation hierarchy.
14530		 *
14531		 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE`.
14532		 *
14533		 * @type {boolean}
14534		 * @default true
14535		 */
14536		this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer
14537
14538		/**
14539		 * When set to `true`, it calculates the world matrix in that frame and resets this property
14540		 * to `false`.
14541		 *
14542		 * @type {boolean}
14543		 * @default false
14544		 */
14545		this.matrixWorldNeedsUpdate = false;
14546
14547		/**
14548		 * The layer membership of the 3D object. The 3D object is only visible if it has
14549		 * at least one layer in common with the camera in use. This property can also be
14550		 * used to filter out unwanted objects in ray-intersection tests when using {@link Raycaster}.
14551		 *
14552		 * @type {Layers}
14553		 */
14554		this.layers = new Layers();
14555
14556		/**
14557		 * When set to `true`, the 3D object gets rendered.
14558		 *
14559		 * @type {boolean}
14560		 * @default true
14561		 */
14562		this.visible = true;
14563
14564		/**
14565		 * When set to `true`, the 3D object gets rendered into shadow maps.
14566		 *
14567		 * @type {boolean}
14568		 * @default false
14569		 */
14570		this.castShadow = false;
14571
14572		/**
14573		 * When set to `true`, the 3D object is affected by shadows in the scene.
14574		 *
14575		 * @type {boolean}
14576		 * @default false
14577		 */
14578		this.receiveShadow = false;
14579
14580		/**
14581		 * When set to `true`, the 3D object is honored by view frustum culling.
14582		 *
14583		 * @type {boolean}
14584		 * @default true
14585		 */
14586		this.frustumCulled = true;
14587
14588		/**
14589		 * This value allows the default rendering order of scene graph objects to be
14590		 * overridden although opaque and transparent objects remain sorted independently.
14591		 * When this property is set for an instance of {@link Group},all descendants
14592		 * objects will be sorted and rendered together. Sorting is from lowest to highest
14593		 * render order.
14594		 *
14595		 * @type {number}
14596		 * @default 0
14597		 */
14598		this.renderOrder = 0;
14599
14600		/**
14601		 * An array holding the animation clips of the 3D object.
14602		 *
14603		 * @type {Array<AnimationClip>}
14604		 */
14605		this.animations = [];
14606
14607		/**
14608		 * Custom depth material to be used when rendering to the depth map. Can only be used
14609		 * in context of meshes. When shadow-casting with a {@link DirectionalLight} or {@link SpotLight},
14610		 * if you are modifying vertex positions in the vertex shader you must specify a custom depth
14611		 * material for proper shadows.
14612		 *
14613		 * Only relevant in context of {@link WebGLRenderer}.
14614		 *
14615		 * @type {(Material|undefined)}
14616		 * @default undefined
14617		 */
14618		this.customDepthMaterial = undefined;
14619
14620		/**
14621		 * Same as {@link Object3D#customDepthMaterial}, but used with {@link PointLight}.
14622		 *
14623		 * Only relevant in context of {@link WebGLRenderer}.
14624		 *
14625		 * @type {(Material|undefined)}
14626		 * @default undefined
14627		 */
14628		this.customDistanceMaterial = undefined;
14629
14630		/**
14631		 * An object that can be used to store custom data about the 3D object. It
14632		 * should not hold references to functions as these will not be cloned.
14633		 *
14634		 * @type {Object}
14635		 */
14636		this.userData = {};
14637
14638	}
14639
14640	/**
14641	 * A callback that is executed immediately before a 3D object is rendered to a shadow map.
14642	 *
14643	 * @param {Renderer|WebGLRenderer} renderer - The renderer.
14644	 * @param {Object3D} object - The 3D object.
14645	 * @param {Camera} camera - The camera that is used to render the scene.
14646	 * @param {Camera} shadowCamera - The shadow camera.
14647	 * @param {BufferGeometry} geometry - The 3D object's geometry.
14648	 * @param {Material} depthMaterial - The depth material.
14649	 * @param {Object} group - The geometry group data.
14650	 */
14651	onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
14652
14653	/**
14654	 * A callback that is executed immediately after a 3D object is rendered to a shadow map.
14655	 *
14656	 * @param {Renderer|WebGLRenderer} renderer - The renderer.
14657	 * @param {Object3D} object - The 3D object.
14658	 * @param {Camera} camera - The camera that is used to render the scene.
14659	 * @param {Camera} shadowCamera - The shadow camera.
14660	 * @param {BufferGeometry} geometry - The 3D object's geometry.
14661	 * @param {Material} depthMaterial - The depth material.
14662	 * @param {Object} group - The geometry group data.
14663	 */
14664	onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
14665
14666	/**
14667	 * A callback that is executed immediately before a 3D object is rendered.
14668	 *
14669	 * @param {Renderer|WebGLRenderer} renderer - The renderer.
14670	 * @param {Object3D} object - The 3D object.
14671	 * @param {Camera} camera - The camera that is used to render the scene.
14672	 * @param {BufferGeometry} geometry - The 3D object's geometry.
14673	 * @param {Material} material - The 3D object's material.
14674	 * @param {Object} group - The geometry group data.
14675	 */
14676	onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
14677
14678	/**
14679	 * A callback that is executed immediately after a 3D object is rendered.
14680	 *
14681	 * @param {Renderer|WebGLRenderer} renderer - The renderer.
14682	 * @param {Object3D} object - The 3D object.
14683	 * @param {Camera} camera - The camera that is used to render the scene.
14684	 * @param {BufferGeometry} geometry - The 3D object's geometry.
14685	 * @param {Material} material - The 3D object's material.
14686	 * @param {Object} group - The geometry group data.
14687	 */
14688	onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
14689
14690	/**
14691	 * Applies the given transformation matrix to the object and updates the object's position,
14692	 * rotation and scale.
14693	 *
14694	 * @param {Matrix4} matrix - The transformation matrix.
14695	 */
14696	applyMatrix4( matrix ) {
14697
14698		if ( this.matrixAutoUpdate ) this.updateMatrix();
14699
14700		this.matrix.premultiply( matrix );
14701
14702		this.matrix.decompose( this.position, this.quaternion, this.scale );
14703
14704	}
14705
14706	/**
14707	 * Applies a rotation represented by given the quaternion to the 3D object.
14708	 *
14709	 * @param {Quaternion} q - The quaternion.
14710	 * @return {Object3D} A reference to this instance.
14711	 */
14712	applyQuaternion( q ) {
14713
14714		this.quaternion.premultiply( q );
14715
14716		return this;
14717
14718	}
14719
14720	/**
14721	 * Sets the given rotation represented as an axis/angle couple to the 3D object.
14722	 *
14723	 * @param {Vector3} axis - The (normalized) axis vector.
14724	 * @param {number} angle - The angle in radians.
14725	 */
14726	setRotationFromAxisAngle( axis, angle ) {
14727
14728		// assumes axis is normalized
14729
14730		this.quaternion.setFromAxisAngle( axis, angle );
14731
14732	}
14733
14734	/**
14735	 * Sets the given rotation represented as Euler angles to the 3D object.
14736	 *
14737	 * @param {Euler} euler - The Euler angles.
14738	 */
14739	setRotationFromEuler( euler ) {
14740
14741		this.quaternion.setFromEuler( euler, true );
14742
14743	}
14744
14745	/**
14746	 * Sets the given rotation represented as rotation matrix to the 3D object.
14747	 *
14748	 * @param {Matrix4} m - Although a 4x4 matrix is expected, the upper 3x3 portion must be
14749	 * a pure rotation matrix (i.e, unscaled).
14750	 */
14751	setRotationFromMatrix( m ) {
14752
14753		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
14754
14755		this.quaternion.setFromRotationMatrix( m );
14756
14757	}
14758
14759	/**
14760	 * Sets the given rotation represented as a Quaternion to the 3D object.
14761	 *
14762	 * @param {Quaternion} q - The Quaternion
14763	 */
14764	setRotationFromQuaternion( q ) {
14765
14766		// assumes q is normalized
14767
14768		this.quaternion.copy( q );
14769
14770	}
14771
14772	/**
14773	 * Rotates the 3D object along an axis in local space.
14774	 *
14775	 * @param {Vector3} axis - The (normalized) axis vector.
14776	 * @param {number} angle - The angle in radians.
14777	 * @return {Object3D} A reference to this instance.
14778	 */
14779	rotateOnAxis( axis, angle ) {
14780
14781		// rotate object on axis in object space
14782		// axis is assumed to be normalized
14783
14784		_q1.setFromAxisAngle( axis, angle );
14785
14786		this.quaternion.multiply( _q1 );
14787
14788		return this;
14789
14790	}
14791
14792	/**
14793	 * Rotates the 3D object along an axis in world space.
14794	 *
14795	 * @param {Vector3} axis - The (normalized) axis vector.
14796	 * @param {number} angle - The angle in radians.
14797	 * @return {Object3D} A reference to this instance.
14798	 */
14799	rotateOnWorldAxis( axis, angle ) {
14800
14801		// rotate object on axis in world space
14802		// axis is assumed to be normalized
14803		// method assumes no rotated parent
14804
14805		_q1.setFromAxisAngle( axis, angle );
14806
14807		this.quaternion.premultiply( _q1 );
14808
14809		return this;
14810
14811	}
14812
14813	/**
14814	 * Rotates the 3D object around its X axis in local space.
14815	 *
14816	 * @param {number} angle - The angle in radians.
14817	 * @return {Object3D} A reference to this instance.
14818	 */
14819	rotateX( angle ) {
14820
14821		return this.rotateOnAxis( _xAxis, angle );
14822
14823	}
14824
14825	/**
14826	 * Rotates the 3D object around its Y axis in local space.
14827	 *
14828	 * @param {number} angle - The angle in radians.
14829	 * @return {Object3D} A reference to this instance.
14830	 */
14831	rotateY( angle ) {
14832
14833		return this.rotateOnAxis( _yAxis, angle );
14834
14835	}
14836
14837	/**
14838	 * Rotates the 3D object around its Z axis in local space.
14839	 *
14840	 * @param {number} angle - The angle in radians.
14841	 * @return {Object3D} A reference to this instance.
14842	 */
14843	rotateZ( angle ) {
14844
14845		return this.rotateOnAxis( _zAxis, angle );
14846
14847	}
14848
14849	/**
14850	 * Translate the 3D object by a distance along the given axis in local space.
14851	 *
14852	 * @param {Vector3} axis - The (normalized) axis vector.
14853	 * @param {number} distance - The distance in world units.
14854	 * @return {Object3D} A reference to this instance.
14855	 */
14856	translateOnAxis( axis, distance ) {
14857
14858		// translate object by distance along axis in object space
14859		// axis is assumed to be normalized
14860
14861		_v1$4.copy( axis ).applyQuaternion( this.quaternion );
14862
14863		this.position.add( _v1$4.multiplyScalar( distance ) );
14864
14865		return this;
14866
14867	}
14868
vendor: 4,524 bytes, lines 14869-15078
14869	/**
14870	 * Translate the 3D object by a distance along its X-axis in local space.
14871	 *
14872	 * @param {number} distance - The distance in world units.
14873	 * @return {Object3D} A reference to this instance.
14874	 */
14875	translateX( distance ) {
14876
14877		return this.translateOnAxis( _xAxis, distance );
14878
14879	}
14880
14881	/**
14882	 * Translate the 3D object by a distance along its Y-axis in local space.
14883	 *
14884	 * @param {number} distance - The distance in world units.
14885	 * @return {Object3D} A reference to this instance.
14886	 */
14887	translateY( distance ) {
14888
14889		return this.translateOnAxis( _yAxis, distance );
14890
14891	}
14892
14893	/**
14894	 * Translate the 3D object by a distance along its Z-axis in local space.
14895	 *
14896	 * @param {number} distance - The distance in world units.
14897	 * @return {Object3D} A reference to this instance.
14898	 */
14899	translateZ( distance ) {
14900
14901		return this.translateOnAxis( _zAxis, distance );
14902
14903	}
14904
14905	/**
14906	 * Converts the given vector from this 3D object's local space to world space.
14907	 *
14908	 * @param {Vector3} vector - The vector to convert.
14909	 * @return {Vector3} The converted vector.
14910	 */
14911	localToWorld( vector ) {
14912
14913		this.updateWorldMatrix( true, false );
14914
14915		return vector.applyMatrix4( this.matrixWorld );
14916
14917	}
14918
14919	/**
14920	 * Converts the given vector from this 3D object's word space to local space.
14921	 *
14922	 * @param {Vector3} vector - The vector to convert.
14923	 * @return {Vector3} The converted vector.
14924	 */
14925	worldToLocal( vector ) {
14926
14927		this.updateWorldMatrix( true, false );
14928
14929		return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
14930
14931	}
14932
14933	/**
14934	 * Rotates the object to face a point in world space.
14935	 *
14936	 * This method does not support objects having non-uniformly-scaled parent(s).
14937	 *
14938	 * @param {number|Vector3} x - The x coordinate in world space. Alternatively, a vector representing a position in world space
14939	 * @param {number} [y] - The y coordinate in world space.
14940	 * @param {number} [z] - The z coordinate in world space.
14941	 */
14942	lookAt( x, y, z ) {
14943
14944		// This method does not support objects having non-uniformly-scaled parent(s)
14945
14946		if ( x.isVector3 ) {
14947
14948			_target.copy( x );
14949
14950		} else {
14951
14952			_target.set( x, y, z );
14953
14954		}
14955
14956		const parent = this.parent;
14957
14958		this.updateWorldMatrix( true, false );
14959
14960		_position$3.setFromMatrixPosition( this.matrixWorld );
14961
14962		if ( this.isCamera || this.isLight ) {
14963
14964			_m1$1.lookAt( _position$3, _target, this.up );
14965
14966		} else {
14967
14968			_m1$1.lookAt( _target, _position$3, this.up );
14969
14970		}
14971
14972		this.quaternion.setFromRotationMatrix( _m1$1 );
14973
14974		if ( parent ) {
14975
14976			_m1$1.extractRotation( parent.matrixWorld );
14977			_q1.setFromRotationMatrix( _m1$1 );
14978			this.quaternion.premultiply( _q1.invert() );
14979
14980		}
14981
14982	}
14983
14984	/**
14985	 * Adds the given 3D object as a child to this 3D object. An arbitrary number of
14986	 * objects may be added. Any current parent on an object passed in here will be
14987	 * removed, since an object can have at most one parent.
14988	 *
14989	 * @fires Object3D#added
14990	 * @fires Object3D#childadded
14991	 * @param {Object3D} object - The 3D object to add.
14992	 * @return {Object3D} A reference to this instance.
14993	 */
14994	add( object ) {
14995
14996		if ( arguments.length > 1 ) {
14997
14998			for ( let i = 0; i < arguments.length; i ++ ) {
14999
15000				this.add( arguments[ i ] );
15001
15002			}
15003
15004			return this;
15005
15006		}
15007
15008		if ( object === this ) {
15009
15010			console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
15011			return this;
15012
15013		}
15014
15015		if ( object && object.isObject3D ) {
15016
15017			object.removeFromParent();
15018			object.parent = this;
15019			this.children.push( object );
15020
15021			object.dispatchEvent( _addedEvent );
15022
15023			_childaddedEvent.child = object;
15024			this.dispatchEvent( _childaddedEvent );
15025			_childaddedEvent.child = null;
15026
15027		} else {
15028
15029			console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
15030
15031		}
15032
15033		return this;
15034
15035	}
15036
15037	/**
15038	 * Removes the given 3D object as child from this 3D object.
15039	 * An arbitrary number of objects may be removed.
15040	 *
15041	 * @fires Object3D#removed
15042	 * @fires Object3D#childremoved
15043	 * @param {Object3D} object - The 3D object to remove.
15044	 * @return {Object3D} A reference to this instance.
15045	 */
15046	remove( object ) {
15047
15048		if ( arguments.length > 1 ) {
15049
15050			for ( let i = 0; i < arguments.length; i ++ ) {
15051
15052				this.remove( arguments[ i ] );
15053
15054			}
15055
15056			return this;
15057
15058		}
15059
15060		const index = this.children.indexOf( object );
15061
15062		if ( index !== -1 ) {
15063
15064			object.parent = null;
15065			this.children.splice( index, 1 );
15066
15067			object.dispatchEvent( _removedEvent );
15068
15069			_childremovedEvent.child = object;
15070			this.dispatchEvent( _childremovedEvent );
15071			_childremovedEvent.child = null;
15072
15073		}
15074
15075		return this;
15076
15077	}
15078
vendor: 8,613 bytes, lines 15079-15420
15079	/**
15080	 * Removes this 3D object from its current parent.
15081	 *
15082	 * @fires Object3D#removed
15083	 * @fires Object3D#childremoved
15084	 * @return {Object3D} A reference to this instance.
15085	 */
15086	removeFromParent() {
15087
15088		const parent = this.parent;
15089
15090		if ( parent !== null ) {
15091
15092			parent.remove( this );
15093
15094		}
15095
15096		return this;
15097
15098	}
15099
15100	/**
15101	 * Removes all child objects.
15102	 *
15103	 * @fires Object3D#removed
15104	 * @fires Object3D#childremoved
15105	 * @return {Object3D} A reference to this instance.
15106	 */
15107	clear() {
15108
15109		return this.remove( ... this.children );
15110
15111	}
15112
15113	/**
15114	 * Adds the given 3D object as a child of this 3D object, while maintaining the object's world
15115	 * transform. This method does not support scene graphs having non-uniformly-scaled nodes(s).
15116	 *
15117	 * @fires Object3D#added
15118	 * @fires Object3D#childadded
15119	 * @param {Object3D} object - The 3D object to attach.
15120	 * @return {Object3D} A reference to this instance.
15121	 */
15122	attach( object ) {
15123
15124		// adds object as a child of this, while maintaining the object's world transform
15125
15126		// Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)
15127
15128		this.updateWorldMatrix( true, false );
15129
15130		_m1$1.copy( this.matrixWorld ).invert();
15131
15132		if ( object.parent !== null ) {
15133
15134			object.parent.updateWorldMatrix( true, false );
15135
15136			_m1$1.multiply( object.parent.matrixWorld );
15137
15138		}
15139
15140		object.applyMatrix4( _m1$1 );
15141
15142		object.removeFromParent();
15143		object.parent = this;
15144		this.children.push( object );
15145
15146		object.updateWorldMatrix( false, true );
15147
15148		object.dispatchEvent( _addedEvent );
15149
15150		_childaddedEvent.child = object;
15151		this.dispatchEvent( _childaddedEvent );
15152		_childaddedEvent.child = null;
15153
15154		return this;
15155
15156	}
15157
15158	/**
15159	 * Searches through the 3D object and its children, starting with the 3D object
15160	 * itself, and returns the first with a matching ID.
15161	 *
15162	 * @param {number} id - The id.
15163	 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found.
15164	 */
15165	getObjectById( id ) {
15166
15167		return this.getObjectByProperty( 'id', id );
15168
15169	}
15170
15171	/**
15172	 * Searches through the 3D object and its children, starting with the 3D object
15173	 * itself, and returns the first with a matching name.
15174	 *
15175	 * @param {string} name - The name.
15176	 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found.
15177	 */
15178	getObjectByName( name ) {
15179
15180		return this.getObjectByProperty( 'name', name );
15181
15182	}
15183
15184	/**
15185	 * Searches through the 3D object and its children, starting with the 3D object
15186	 * itself, and returns the first with a matching property value.
15187	 *
15188	 * @param {string} name - The name of the property.
15189	 * @param {any} value - The value.
15190	 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found.
15191	 */
15192	getObjectByProperty( name, value ) {
15193
15194		if ( this[ name ] === value ) return this;
15195
15196		for ( let i = 0, l = this.children.length; i < l; i ++ ) {
15197
15198			const child = this.children[ i ];
15199			const object = child.getObjectByProperty( name, value );
15200
15201			if ( object !== undefined ) {
15202
15203				return object;
15204
15205			}
15206
15207		}
15208
15209		return undefined;
15210
15211	}
15212
15213	/**
15214	 * Searches through the 3D object and its children, starting with the 3D object
15215	 * itself, and returns all 3D objects with a matching property value.
15216	 *
15217	 * @param {string} name - The name of the property.
15218	 * @param {any} value - The value.
15219	 * @param {Array<Object3D>} result - The method stores the result in this array.
15220	 * @return {Array<Object3D>} The found 3D objects.
15221	 */
15222	getObjectsByProperty( name, value, result = [] ) {
15223
15224		if ( this[ name ] === value ) result.push( this );
15225
15226		const children = this.children;
15227
15228		for ( let i = 0, l = children.length; i < l; i ++ ) {
15229
15230			children[ i ].getObjectsByProperty( name, value, result );
15231
15232		}
15233
15234		return result;
15235
15236	}
15237
15238	/**
15239	 * Returns a vector representing the position of the 3D object in world space.
15240	 *
15241	 * @param {Vector3} target - The target vector the result is stored to.
15242	 * @return {Vector3} The 3D object's position in world space.
15243	 */
15244	getWorldPosition( target ) {
15245
15246		this.updateWorldMatrix( true, false );
15247
15248		return target.setFromMatrixPosition( this.matrixWorld );
15249
15250	}
15251
15252	/**
15253	 * Returns a Quaternion representing the position of the 3D object in world space.
15254	 *
15255	 * @param {Quaternion} target - The target Quaternion the result is stored to.
15256	 * @return {Quaternion} The 3D object's rotation in world space.
15257	 */
15258	getWorldQuaternion( target ) {
15259
15260		this.updateWorldMatrix( true, false );
15261
15262		this.matrixWorld.decompose( _position$3, target, _scale$2 );
15263
15264		return target;
15265
15266	}
15267
15268	/**
15269	 * Returns a vector representing the scale of the 3D object in world space.
15270	 *
15271	 * @param {Vector3} target - The target vector the result is stored to.
15272	 * @return {Vector3} The 3D object's scale in world space.
15273	 */
15274	getWorldScale( target ) {
15275
15276		this.updateWorldMatrix( true, false );
15277
15278		this.matrixWorld.decompose( _position$3, _quaternion$2, target );
15279
15280		return target;
15281
15282	}
15283
15284	/**
15285	 * Returns a vector representing the ("look") direction of the 3D object in world space.
15286	 *
15287	 * @param {Vector3} target - The target vector the result is stored to.
15288	 * @return {Vector3} The 3D object's direction in world space.
15289	 */
15290	getWorldDirection( target ) {
15291
15292		this.updateWorldMatrix( true, false );
15293
15294		const e = this.matrixWorld.elements;
15295
15296		return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
15297
15298	}
15299
15300	/**
15301	 * Abstract method to get intersections between a casted ray and this
15302	 * 3D object. Renderable 3D objects such as {@link Mesh}, {@link Line} or {@link Points}
15303	 * implement this method in order to use raycasting.
15304	 *
15305	 * @abstract
15306	 * @param {Raycaster} raycaster - The raycaster.
15307	 * @param {Array<Object>} intersects - An array holding the result of the method.
15308	 */
15309	raycast( /* raycaster, intersects */ ) {}
15310
15311	/**
15312	 * Executes the callback on this 3D object and all descendants.
15313	 *
15314	 * Note: Modifying the scene graph inside the callback is discouraged.
15315	 *
15316	 * @param {Function} callback - A callback function that allows to process the current 3D object.
15317	 */
15318	traverse( callback ) {
15319
15320		callback( this );
15321
15322		const children = this.children;
15323
15324		for ( let i = 0, l = children.length; i < l; i ++ ) {
15325
15326			children[ i ].traverse( callback );
15327
15328		}
15329
15330	}
15331
15332	/**
15333	 * Like {@link Object3D#traverse}, but the callback will only be executed for visible 3D objects.
15334	 * Descendants of invisible 3D objects are not traversed.
15335	 *
15336	 * Note: Modifying the scene graph inside the callback is discouraged.
15337	 *
15338	 * @param {Function} callback - A callback function that allows to process the current 3D object.
15339	 */
15340	traverseVisible( callback ) {
15341
15342		if ( this.visible === false ) return;
15343
15344		callback( this );
15345
15346		const children = this.children;
15347
15348		for ( let i = 0, l = children.length; i < l; i ++ ) {
15349
15350			children[ i ].traverseVisible( callback );
15351
15352		}
15353
15354	}
15355
15356	/**
15357	 * Like {@link Object3D#traverse}, but the callback will only be executed for all ancestors.
15358	 *
15359	 * Note: Modifying the scene graph inside the callback is discouraged.
15360	 *
15361	 * @param {Function} callback - A callback function that allows to process the current 3D object.
15362	 */
15363	traverseAncestors( callback ) {
15364
15365		const parent = this.parent;
15366
15367		if ( parent !== null ) {
15368
15369			callback( parent );
15370
15371			parent.traverseAncestors( callback );
15372
15373		}
15374
15375	}
15376
15377	/**
15378	 * Updates the transformation matrix in local space by computing it from the current
15379	 * position, rotation and scale values.
15380	 */
15381	updateMatrix() {
15382
15383		this.matrix.compose( this.position, this.quaternion, this.scale );
15384
15385		this.matrixWorldNeedsUpdate = true;
15386
15387	}
15388
15389	/**
15390	 * Updates the transformation matrix in world space of this 3D objects and its descendants.
15391	 *
15392	 * To ensure correct results, this method also recomputes the 3D object's transformation matrix in
15393	 * local space. The computation of the local and world matrix can be controlled with the
15394	 * {@link Object3D#matrixAutoUpdate} and {@link Object3D#matrixWorldAutoUpdate} flags which are both
15395	 * `true` by default.  Set these flags to `false` if you need more control over the update matrix process.
15396	 *
15397	 * @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even
15398	 * when {@link Object3D#matrixWorldAutoUpdate} is set to `false`.
15399	 */
15400	updateMatrixWorld( force ) {
15401
15402		if ( this.matrixAutoUpdate ) this.updateMatrix();
15403
15404		if ( this.matrixWorldNeedsUpdate || force ) {
15405
15406			if ( this.matrixWorldAutoUpdate === true ) {
15407
15408				if ( this.parent === null ) {
15409
15410					this.matrixWorld.copy( this.matrix );
15411
15412				} else {
15413
15414					this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
15415
15416				}
15417
15418			}
15419
15420			this.matrixWorldNeedsUpdate = false;
vendor: 11,871 bytes, lines 15421-15943
15421
15422			force = true;
15423
15424		}
15425
15426		// make sure descendants are updated if required
15427
15428		const children = this.children;
15429
15430		for ( let i = 0, l = children.length; i < l; i ++ ) {
15431
15432			const child = children[ i ];
15433
15434			child.updateMatrixWorld( force );
15435
15436		}
15437
15438	}
15439
15440	/**
15441	 * An alternative version of {@link Object3D#updateMatrixWorld} with more control over the
15442	 * update of ancestor and descendant nodes.
15443	 *
15444	 * @param {boolean} [updateParents=false] Whether ancestor nodes should be updated or not.
15445	 * @param {boolean} [updateChildren=false] Whether descendant nodes should be updated or not.
15446	 */
15447	updateWorldMatrix( updateParents, updateChildren ) {
15448
15449		const parent = this.parent;
15450
15451		if ( updateParents === true && parent !== null ) {
15452
15453			parent.updateWorldMatrix( true, false );
15454
15455		}
15456
15457		if ( this.matrixAutoUpdate ) this.updateMatrix();
15458
15459		if ( this.matrixWorldAutoUpdate === true ) {
15460
15461			if ( this.parent === null ) {
15462
15463				this.matrixWorld.copy( this.matrix );
15464
15465			} else {
15466
15467				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
15468
15469			}
15470
15471		}
15472
15473		// make sure descendants are updated
15474
15475		if ( updateChildren === true ) {
15476
15477			const children = this.children;
15478
15479			for ( let i = 0, l = children.length; i < l; i ++ ) {
15480
15481				const child = children[ i ];
15482
15483				child.updateWorldMatrix( false, true );
15484
15485			}
15486
15487		}
15488
15489	}
15490
15491	/**
15492	 * Serializes the 3D object into JSON.
15493	 *
15494	 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
15495	 * @return {Object} A JSON object representing the serialized 3D object.
15496	 * @see {@link ObjectLoader#parse}
15497	 */
15498	toJSON( meta ) {
15499
15500		// meta is a string when called from JSON.stringify
15501		const isRootObject = ( meta === undefined || typeof meta === 'string' );
15502
15503		const output = {};
15504
15505		// meta is a hash used to collect geometries, materials.
15506		// not providing it implies that this is the root object
15507		// being serialized.
15508		if ( isRootObject ) {
15509
15510			// initialize meta obj
15511			meta = {
15512				geometries: {},
15513				materials: {},
15514				textures: {},
15515				images: {},
15516				shapes: {},
15517				skeletons: {},
15518				animations: {},
15519				nodes: {}
15520			};
15521
15522			output.metadata = {
15523				version: 4.6,
15524				type: 'Object',
15525				generator: 'Object3D.toJSON'
15526			};
15527
15528		}
15529
15530		// standard Object3D serialization
15531
15532		const object = {};
15533
15534		object.uuid = this.uuid;
15535		object.type = this.type;
15536
15537		if ( this.name !== '' ) object.name = this.name;
15538		if ( this.castShadow === true ) object.castShadow = true;
15539		if ( this.receiveShadow === true ) object.receiveShadow = true;
15540		if ( this.visible === false ) object.visible = false;
15541		if ( this.frustumCulled === false ) object.frustumCulled = false;
15542		if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
15543		if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;
15544
15545		object.layers = this.layers.mask;
15546		object.matrix = this.matrix.toArray();
15547		object.up = this.up.toArray();
15548
15549		if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
15550
15551		// object specific properties
15552
15553		if ( this.isInstancedMesh ) {
15554
15555			object.type = 'InstancedMesh';
15556			object.count = this.count;
15557			object.instanceMatrix = this.instanceMatrix.toJSON();
15558			if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
15559
15560		}
15561
15562		if ( this.isBatchedMesh ) {
15563
15564			object.type = 'BatchedMesh';
15565			object.perObjectFrustumCulled = this.perObjectFrustumCulled;
15566			object.sortObjects = this.sortObjects;
15567
15568			object.drawRanges = this._drawRanges;
15569			object.reservedRanges = this._reservedRanges;
15570
15571			object.visibility = this._visibility;
15572			object.active = this._active;
15573			object.bounds = this._bounds.map( bound => ( {
15574				boxInitialized: bound.boxInitialized,
15575				boxMin: bound.box.min.toArray(),
15576				boxMax: bound.box.max.toArray(),
15577
15578				sphereInitialized: bound.sphereInitialized,
15579				sphereRadius: bound.sphere.radius,
15580				sphereCenter: bound.sphere.center.toArray()
15581			} ) );
15582
15583			object.maxInstanceCount = this._maxInstanceCount;
15584			object.maxVertexCount = this._maxVertexCount;
15585			object.maxIndexCount = this._maxIndexCount;
15586
15587			object.geometryInitialized = this._geometryInitialized;
15588			object.geometryCount = this._geometryCount;
15589
15590			object.matricesTexture = this._matricesTexture.toJSON( meta );
15591
15592			if ( this._colorsTexture !== null ) object.colorsTexture = this._colorsTexture.toJSON( meta );
15593
15594			if ( this.boundingSphere !== null ) {
15595
15596				object.boundingSphere = {
15597					center: object.boundingSphere.center.toArray(),
15598					radius: object.boundingSphere.radius
15599				};
15600
15601			}
15602
15603			if ( this.boundingBox !== null ) {
15604
15605				object.boundingBox = {
15606					min: object.boundingBox.min.toArray(),
15607					max: object.boundingBox.max.toArray()
15608				};
15609
15610			}
15611
15612		}
15613
15614		//
15615
15616		function serialize( library, element ) {
15617
15618			if ( library[ element.uuid ] === undefined ) {
15619
15620				library[ element.uuid ] = element.toJSON( meta );
15621
15622			}
15623
15624			return element.uuid;
15625
15626		}
15627
15628		if ( this.isScene ) {
15629
15630			if ( this.background ) {
15631
15632				if ( this.background.isColor ) {
15633
15634					object.background = this.background.toJSON();
15635
15636				} else if ( this.background.isTexture ) {
15637
15638					object.background = this.background.toJSON( meta ).uuid;
15639
15640				}
15641
15642			}
15643
15644			if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {
15645
15646				object.environment = this.environment.toJSON( meta ).uuid;
15647
15648			}
15649
15650		} else if ( this.isMesh || this.isLine || this.isPoints ) {
15651
15652			object.geometry = serialize( meta.geometries, this.geometry );
15653
15654			const parameters = this.geometry.parameters;
15655
15656			if ( parameters !== undefined && parameters.shapes !== undefined ) {
15657
15658				const shapes = parameters.shapes;
15659
15660				if ( Array.isArray( shapes ) ) {
15661
15662					for ( let i = 0, l = shapes.length; i < l; i ++ ) {
15663
15664						const shape = shapes[ i ];
15665
15666						serialize( meta.shapes, shape );
15667
15668					}
15669
15670				} else {
15671
15672					serialize( meta.shapes, shapes );
15673
15674				}
15675
15676			}
15677
15678		}
15679
15680		if ( this.isSkinnedMesh ) {
15681
15682			object.bindMode = this.bindMode;
15683			object.bindMatrix = this.bindMatrix.toArray();
15684
15685			if ( this.skeleton !== undefined ) {
15686
15687				serialize( meta.skeletons, this.skeleton );
15688
15689				object.skeleton = this.skeleton.uuid;
15690
15691			}
15692
15693		}
15694
15695		if ( this.material !== undefined ) {
15696
15697			if ( Array.isArray( this.material ) ) {
15698
15699				const uuids = [];
15700
15701				for ( let i = 0, l = this.material.length; i < l; i ++ ) {
15702
15703					uuids.push( serialize( meta.materials, this.material[ i ] ) );
15704
15705				}
15706
15707				object.material = uuids;
15708
15709			} else {
15710
15711				object.material = serialize( meta.materials, this.material );
15712
15713			}
15714
15715		}
15716
15717		//
15718
15719		if ( this.children.length > 0 ) {
15720
15721			object.children = [];
15722
15723			for ( let i = 0; i < this.children.length; i ++ ) {
15724
15725				object.children.push( this.children[ i ].toJSON( meta ).object );
15726
15727			}
15728
15729		}
15730
15731		//
15732
15733		if ( this.animations.length > 0 ) {
15734
15735			object.animations = [];
15736
15737			for ( let i = 0; i < this.animations.length; i ++ ) {
15738
15739				const animation = this.animations[ i ];
15740
15741				object.animations.push( serialize( meta.animations, animation ) );
15742
15743			}
15744
15745		}
15746
15747		if ( isRootObject ) {
15748
15749			const geometries = extractFromCache( meta.geometries );
15750			const materials = extractFromCache( meta.materials );
15751			const textures = extractFromCache( meta.textures );
15752			const images = extractFromCache( meta.images );
15753			const shapes = extractFromCache( meta.shapes );
15754			const skeletons = extractFromCache( meta.skeletons );
15755			const animations = extractFromCache( meta.animations );
15756			const nodes = extractFromCache( meta.nodes );
15757
15758			if ( geometries.length > 0 ) output.geometries = geometries;
15759			if ( materials.length > 0 ) output.materials = materials;
15760			if ( textures.length > 0 ) output.textures = textures;
15761			if ( images.length > 0 ) output.images = images;
15762			if ( shapes.length > 0 ) output.shapes = shapes;
15763			if ( skeletons.length > 0 ) output.skeletons = skeletons;
15764			if ( animations.length > 0 ) output.animations = animations;
15765			if ( nodes.length > 0 ) output.nodes = nodes;
15766
15767		}
15768
15769		output.object = object;
15770
15771		return output;
15772
15773		// extract data from the cache hash
15774		// remove metadata on each item
15775		// and return as array
15776		function extractFromCache( cache ) {
15777
15778			const values = [];
15779			for ( const key in cache ) {
15780
15781				const data = cache[ key ];
15782				delete data.metadata;
15783				values.push( data );
15784
15785			}
15786
15787			return values;
15788
15789		}
15790
15791	}
15792
15793	/**
15794	 * Returns a new 3D object with copied values from this instance.
15795	 *
15796	 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are also cloned.
15797	 * @return {Object3D} A clone of this instance.
15798	 */
15799	clone( recursive ) {
15800
15801		return new this.constructor().copy( this, recursive );
15802
15803	}
15804
15805	/**
15806	 * Copies the values of the given 3D object to this instance.
15807	 *
15808	 * @param {Object3D} source - The 3D object to copy.
15809	 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are cloned.
15810	 * @return {Object3D} A reference to this instance.
15811	 */
15812	copy( source, recursive = true ) {
15813
15814		this.name = source.name;
15815
15816		this.up.copy( source.up );
15817
15818		this.position.copy( source.position );
15819		this.rotation.order = source.rotation.order;
15820		this.quaternion.copy( source.quaternion );
15821		this.scale.copy( source.scale );
15822
15823		this.matrix.copy( source.matrix );
15824		this.matrixWorld.copy( source.matrixWorld );
15825
15826		this.matrixAutoUpdate = source.matrixAutoUpdate;
15827
15828		this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
15829		this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
15830
15831		this.layers.mask = source.layers.mask;
15832		this.visible = source.visible;
15833
15834		this.castShadow = source.castShadow;
15835		this.receiveShadow = source.receiveShadow;
15836
15837		this.frustumCulled = source.frustumCulled;
15838		this.renderOrder = source.renderOrder;
15839
15840		this.animations = source.animations.slice();
15841
15842		this.userData = JSON.parse( JSON.stringify( source.userData ) );
15843
15844		if ( recursive === true ) {
15845
15846			for ( let i = 0; i < source.children.length; i ++ ) {
15847
15848				const child = source.children[ i ];
15849				this.add( child.clone() );
15850
15851			}
15852
15853		}
15854
15855		return this;
15856
15857	}
15858
15859}
15860
15861/**
15862 * The default up direction for objects, also used as the default
15863 * position for {@link DirectionalLight} and {@link HemisphereLight}.
15864 *
15865 * @static
15866 * @type {Vector3}
15867 * @default (0,1,0)
15868 */
15869Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );
15870
15871/**
15872 * The default setting for {@link Object3D#matrixAutoUpdate} for
15873 * newly created 3D objects.
15874 *
15875 * @static
15876 * @type {boolean}
15877 * @default true
15878 */
15879Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true;
15880
15881/**
15882 * The default setting for {@link Object3D#matrixWorldAutoUpdate} for
15883 * newly created 3D objects.
15884 *
15885 * @static
15886 * @type {boolean}
15887 * @default true
15888 */
15889Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;
15890
15891const _v0$1 = /*@__PURE__*/ new Vector3();
15892const _v1$3 = /*@__PURE__*/ new Vector3();
15893const _v2$2 = /*@__PURE__*/ new Vector3();
15894const _v3$2 = /*@__PURE__*/ new Vector3();
15895
15896const _vab = /*@__PURE__*/ new Vector3();
15897const _vac = /*@__PURE__*/ new Vector3();
15898const _vbc = /*@__PURE__*/ new Vector3();
15899const _vap = /*@__PURE__*/ new Vector3();
15900const _vbp = /*@__PURE__*/ new Vector3();
15901const _vcp = /*@__PURE__*/ new Vector3();
15902
15903const _v40 = /*@__PURE__*/ new Vector4();
15904const _v41 = /*@__PURE__*/ new Vector4();
15905const _v42 = /*@__PURE__*/ new Vector4();
15906
15907/**
15908 * A geometric triangle as defined by three vectors representing its three corners.
15909 */
15910class Triangle {
15911
15912	/**
15913	 * Constructs a new triangle.
15914	 *
15915	 * @param {Vector3} [a=(0,0,0)] - The first corner of the triangle.
15916	 * @param {Vector3} [b=(0,0,0)] - The second corner of the triangle.
15917	 * @param {Vector3} [c=(0,0,0)] - The third corner of the triangle.
15918	 */
15919	constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
15920
15921		/**
15922		 * The first corner of the triangle.
15923		 *
15924		 * @type {Vector3}
15925		 */
15926		this.a = a;
15927
15928		/**
15929		 * The second corner of the triangle.
15930		 *
15931		 * @type {Vector3}
15932		 */
15933		this.b = b;
15934
15935		/**
15936		 * The third corner of the triangle.
15937		 *
15938		 * @type {Vector3}
15939		 */
15940		this.c = c;
15941
15942	}
15943
vendor: 4,935 bytes, lines 15944-16102
15944	/**
15945	 * Computes the normal vector of a triangle.
15946	 *
15947	 * @param {Vector3} a - The first corner of the triangle.
15948	 * @param {Vector3} b - The second corner of the triangle.
15949	 * @param {Vector3} c - The third corner of the triangle.
15950	 * @param {Vector3} target - The target vector that is used to store the method's result.
15951	 * @return {Vector3} The triangle's normal.
15952	 */
15953	static getNormal( a, b, c, target ) {
15954
15955		target.subVectors( c, b );
15956		_v0$1.subVectors( a, b );
15957		target.cross( _v0$1 );
15958
15959		const targetLengthSq = target.lengthSq();
15960		if ( targetLengthSq > 0 ) {
15961
15962			return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
15963
15964		}
15965
15966		return target.set( 0, 0, 0 );
15967
15968	}
15969
15970	/**
15971	 * Computes a barycentric coordinates from the given vector.
15972	 * Returns `null` if the triangle is degenerate.
15973	 *
15974	 * @param {Vector3} point - A point in 3D space.
15975	 * @param {Vector3} a - The first corner of the triangle.
15976	 * @param {Vector3} b - The second corner of the triangle.
15977	 * @param {Vector3} c - The third corner of the triangle.
15978	 * @param {Vector3} target - The target vector that is used to store the method's result.
15979	 * @return {?Vector3} The barycentric coordinates for the given point
15980	 */
15981	static getBarycoord( point, a, b, c, target ) {
15982
15983		// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
15984
15985		_v0$1.subVectors( c, a );
15986		_v1$3.subVectors( b, a );
15987		_v2$2.subVectors( point, a );
15988
15989		const dot00 = _v0$1.dot( _v0$1 );
15990		const dot01 = _v0$1.dot( _v1$3 );
15991		const dot02 = _v0$1.dot( _v2$2 );
15992		const dot11 = _v1$3.dot( _v1$3 );
15993		const dot12 = _v1$3.dot( _v2$2 );
15994
15995		const denom = ( dot00 * dot11 - dot01 * dot01 );
15996
15997		// collinear or singular triangle
15998		if ( denom === 0 ) {
15999
16000			target.set( 0, 0, 0 );
16001			return null;
16002
16003		}
16004
16005		const invDenom = 1 / denom;
16006		const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
16007		const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
16008
16009		// barycentric coordinates must always sum to 1
16010		return target.set( 1 - u - v, v, u );
16011
16012	}
16013
16014	/**
16015	 * Returns `true` if the given point, when projected onto the plane of the
16016	 * triangle, lies within the triangle.
16017	 *
16018	 * @param {Vector3} point - The point in 3D space to test.
16019	 * @param {Vector3} a - The first corner of the triangle.
16020	 * @param {Vector3} b - The second corner of the triangle.
16021	 * @param {Vector3} c - The third corner of the triangle.
16022	 * @return {boolean} Whether the given point, when projected onto the plane of the
16023	 * triangle, lies within the triangle or not.
16024	 */
16025	static containsPoint( point, a, b, c ) {
16026
16027		// if the triangle is degenerate then we can't contain a point
16028		if ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) {
16029
16030			return false;
16031
16032		}
16033
16034		return ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 );
16035
16036	}
16037
16038	/**
16039	 * Computes the value barycentrically interpolated for the given point on the
16040	 * triangle. Returns `null` if the triangle is degenerate.
16041	 *
16042	 * @param {Vector3} point - Position of interpolated point.
16043	 * @param {Vector3} p1 - The first corner of the triangle.
16044	 * @param {Vector3} p2 - The second corner of the triangle.
16045	 * @param {Vector3} p3 - The third corner of the triangle.
16046	 * @param {Vector3} v1 - Value to interpolate of first vertex.
16047	 * @param {Vector3} v2 - Value to interpolate of second vertex.
16048	 * @param {Vector3} v3 - Value to interpolate of third vertex.
16049	 * @param {Vector3} target - The target vector that is used to store the method's result.
16050	 * @return {?Vector3} The interpolated value.
16051	 */
16052	static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {
16053
16054		if ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) {
16055
16056			target.x = 0;
16057			target.y = 0;
16058			if ( 'z' in target ) target.z = 0;
16059			if ( 'w' in target ) target.w = 0;
16060			return null;
16061
16062		}
16063
16064		target.setScalar( 0 );
16065		target.addScaledVector( v1, _v3$2.x );
16066		target.addScaledVector( v2, _v3$2.y );
16067		target.addScaledVector( v3, _v3$2.z );
16068
16069		return target;
16070
16071	}
16072
16073	/**
16074	 * Computes the value barycentrically interpolated for the given attribute and indices.
16075	 *
16076	 * @param {BufferAttribute} attr - The attribute to interpolate.
16077	 * @param {number} i1 - Index of first vertex.
16078	 * @param {number} i2 - Index of second vertex.
16079	 * @param {number} i3 - Index of third vertex.
16080	 * @param {Vector3} barycoord - The barycoordinate value to use to interpolate.
16081	 * @param {Vector3} target - The target vector that is used to store the method's result.
16082	 * @return {Vector3} The interpolated attribute value.
16083	 */
16084	static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) {
16085
16086		_v40.setScalar( 0 );
16087		_v41.setScalar( 0 );
16088		_v42.setScalar( 0 );
16089
16090		_v40.fromBufferAttribute( attr, i1 );
16091		_v41.fromBufferAttribute( attr, i2 );
16092		_v42.fromBufferAttribute( attr, i3 );
16093
16094		target.setScalar( 0 );
16095		target.addScaledVector( _v40, barycoord.x );
16096		target.addScaledVector( _v41, barycoord.y );
16097		target.addScaledVector( _v42, barycoord.z );
16098
16099		return target;
16100
16101	}
16102
vendor: 3,100 bytes, lines 16103-16215
16103	/**
16104	 * Returns `true` if the triangle is oriented towards the given direction.
16105	 *
16106	 * @param {Vector3} a - The first corner of the triangle.
16107	 * @param {Vector3} b - The second corner of the triangle.
16108	 * @param {Vector3} c - The third corner of the triangle.
16109	 * @param {Vector3} direction - The (normalized) direction vector.
16110	 * @return {boolean} Whether the triangle is oriented towards the given direction or not.
16111	 */
16112	static isFrontFacing( a, b, c, direction ) {
16113
16114		_v0$1.subVectors( c, b );
16115		_v1$3.subVectors( a, b );
16116
16117		// strictly front facing
16118		return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
16119
16120	}
16121
16122	/**
16123	 * Sets the triangle's vertices by copying the given values.
16124	 *
16125	 * @param {Vector3} a - The first corner of the triangle.
16126	 * @param {Vector3} b - The second corner of the triangle.
16127	 * @param {Vector3} c - The third corner of the triangle.
16128	 * @return {Triangle} A reference to this triangle.
16129	 */
16130	set( a, b, c ) {
16131
16132		this.a.copy( a );
16133		this.b.copy( b );
16134		this.c.copy( c );
16135
16136		return this;
16137
16138	}
16139
16140	/**
16141	 * Sets the triangle's vertices by copying the given array values.
16142	 *
16143	 * @param {Array<Vector3>} points - An array with 3D points.
16144	 * @param {number} i0 - The array index representing the first corner of the triangle.
16145	 * @param {number} i1 - The array index representing the second corner of the triangle.
16146	 * @param {number} i2 - The array index representing the third corner of the triangle.
16147	 * @return {Triangle} A reference to this triangle.
16148	 */
16149	setFromPointsAndIndices( points, i0, i1, i2 ) {
16150
16151		this.a.copy( points[ i0 ] );
16152		this.b.copy( points[ i1 ] );
16153		this.c.copy( points[ i2 ] );
16154
16155		return this;
16156
16157	}
16158
16159	/**
16160	 * Sets the triangle's vertices by copying the given attribute values.
16161	 *
16162	 * @param {BufferAttribute} attribute - A buffer attribute with 3D points data.
16163	 * @param {number} i0 - The attribute index representing the first corner of the triangle.
16164	 * @param {number} i1 - The attribute index representing the second corner of the triangle.
16165	 * @param {number} i2 - The attribute index representing the third corner of the triangle.
16166	 * @return {Triangle} A reference to this triangle.
16167	 */
16168	setFromAttributeAndIndices( attribute, i0, i1, i2 ) {
16169
16170		this.a.fromBufferAttribute( attribute, i0 );
16171		this.b.fromBufferAttribute( attribute, i1 );
16172		this.c.fromBufferAttribute( attribute, i2 );
16173
16174		return this;
16175
16176	}
16177
16178	/**
16179	 * Returns a new triangle with copied values from this instance.
16180	 *
16181	 * @return {Triangle} A clone of this instance.
16182	 */
16183	clone() {
16184
16185		return new this.constructor().copy( this );
16186
16187	}
16188
16189	/**
16190	 * Copies the values of the given triangle to this instance.
16191	 *
16192	 * @param {Triangle} triangle - The triangle to copy.
16193	 * @return {Triangle} A reference to this triangle.
16194	 */
16195	copy( triangle ) {
16196
16197		this.a.copy( triangle.a );
16198		this.b.copy( triangle.b );
16199		this.c.copy( triangle.c );
16200
16201		return this;
16202
16203	}
16204
16205	/**
16206	 * Computes the area of the triangle.
16207	 *
16208	 * @return {number} The triangle's area.
16209	 */
16210	getArea() {
16211
16212		_v0$1.subVectors( this.c, this.b );
16213		_v1$3.subVectors( this.a, this.b );
16214
16215		return _v0$1.cross( _v1$3
vendor: 5,857 bytes, lines 16215-16425
16215 ).length() * 0.5;
16216
16217	}
16218
16219	/**
16220	 * Computes the midpoint of the triangle.
16221	 *
16222	 * @param {Vector3} target - The target vector that is used to store the method's result.
16223	 * @return {Vector3} The triangle's midpoint.
16224	 */
16225	getMidpoint( target ) {
16226
16227		return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
16228
16229	}
16230
16231	/**
16232	 * Computes the normal of the triangle.
16233	 *
16234	 * @param {Vector3} target - The target vector that is used to store the method's result.
16235	 * @return {Vector3} The triangle's normal.
16236	 */
16237	getNormal( target ) {
16238
16239		return Triangle.getNormal( this.a, this.b, this.c, target );
16240
16241	}
16242
16243	/**
16244	 * Computes a plane the triangle lies within.
16245	 *
16246	 * @param {Plane} target - The target vector that is used to store the method's result.
16247	 * @return {Plane} The plane the triangle lies within.
16248	 */
16249	getPlane( target ) {
16250
16251		return target.setFromCoplanarPoints( this.a, this.b, this.c );
16252
16253	}
16254
16255	/**
16256	 * Computes a barycentric coordinates from the given vector.
16257	 * Returns `null` if the triangle is degenerate.
16258	 *
16259	 * @param {Vector3} point - A point in 3D space.
16260	 * @param {Vector3} target - The target vector that is used to store the method's result.
16261	 * @return {?Vector3} The barycentric coordinates for the given point
16262	 */
16263	getBarycoord( point, target ) {
16264
16265		return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
16266
16267	}
16268
16269	/**
16270	 * Computes the value barycentrically interpolated for the given point on the
16271	 * triangle. Returns `null` if the triangle is degenerate.
16272	 *
16273	 * @param {Vector3} point - Position of interpolated point.
16274	 * @param {Vector3} v1 - Value to interpolate of first vertex.
16275	 * @param {Vector3} v2 - Value to interpolate of second vertex.
16276	 * @param {Vector3} v3 - Value to interpolate of third vertex.
16277	 * @param {Vector3} target - The target vector that is used to store the method's result.
16278	 * @return {?Vector3} The interpolated value.
16279	 */
16280	getInterpolation( point, v1, v2, v3, target ) {
16281
16282		return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );
16283
16284	}
16285
16286	/**
16287	 * Returns `true` if the given point, when projected onto the plane of the
16288	 * triangle, lies within the triangle.
16289	 *
16290	 * @param {Vector3} point - The point in 3D space to test.
16291	 * @return {boolean} Whether the given point, when projected onto the plane of the
16292	 * triangle, lies within the triangle or not.
16293	 */
16294	containsPoint( point ) {
16295
16296		return Triangle.containsPoint( point, this.a, this.b, this.c );
16297
16298	}
16299
16300	/**
16301	 * Returns `true` if the triangle is oriented towards the given direction.
16302	 *
16303	 * @param {Vector3} direction - The (normalized) direction vector.
16304	 * @return {boolean} Whether the triangle is oriented towards the given direction or not.
16305	 */
16306	isFrontFacing( direction ) {
16307
16308		return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
16309
16310	}
16311
16312	/**
16313	 * Returns `true` if this triangle intersects with the given box.
16314	 *
16315	 * @param {Box3} box - The box to intersect.
16316	 * @return {boolean} Whether this triangle intersects with the given box or not.
16317	 */
16318	intersectsBox( box ) {
16319
16320		return box.intersectsTriangle( this );
16321
16322	}
16323
16324	/**
16325	 * Returns the closest point on the triangle to the given point.
16326	 *
16327	 * @param {Vector3} p - The point to compute the closest point for.
16328	 * @param {Vector3} target - The target vector that is used to store the method's result.
16329	 * @return {Vector3} The closest point on the triangle.
16330	 */
16331	closestPointToPoint( p, target ) {
16332
16333		const a = this.a, b = this.b, c = this.c;
16334		let v, w;
16335
16336		// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
16337		// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
16338		// under the accompanying license; see chapter 5.1.5 for detailed explanation.
16339		// basically, we're distinguishing which of the voronoi regions of the triangle
16340		// the point lies in with the minimum amount of redundant computation.
16341
16342		_vab.subVectors( b, a );
16343		_vac.subVectors( c, a );
16344		_vap.subVectors( p, a );
16345		const d1 = _vab.dot( _vap );
16346		const d2 = _vac.dot( _vap );
16347		if ( d1 <= 0 && d2 <= 0 ) {
16348
16349			// vertex region of A; barycentric coords (1, 0, 0)
16350			return target.copy( a );
16351
16352		}
16353
16354		_vbp.subVectors( p, b );
16355		const d3 = _vab.dot( _vbp );
16356		const d4 = _vac.dot( _vbp );
16357		if ( d3 >= 0 && d4 <= d3 ) {
16358
16359			// vertex region of B; barycentric coords (0, 1, 0)
16360			return target.copy( b );
16361
16362		}
16363
16364		const vc = d1 * d4 - d3 * d2;
16365		if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
16366
16367			v = d1 / ( d1 - d3 );
16368			// edge region of AB; barycentric coords (1-v, v, 0)
16369			return target.copy( a ).addScaledVector( _vab, v );
16370
16371		}
16372
16373		_vcp.subVectors( p, c );
16374		const d5 = _vab.dot( _vcp );
16375		const d6 = _vac.dot( _vcp );
16376		if ( d6 >= 0 && d5 <= d6 ) {
16377
16378			// vertex region of C; barycentric coords (0, 0, 1)
16379			return target.copy( c );
16380
16381		}
16382
16383		const vb = d5 * d2 - d1 * d6;
16384		if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
16385
16386			w = d2 / ( d2 - d6 );
16387			// edge region of AC; barycentric coords (1-w, 0, w)
16388			return target.copy( a ).addScaledVector( _vac, w );
16389
16390		}
16391
16392		const va = d3 * d6 - d5 * d4;
16393		if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
16394
16395			_vbc.subVectors( c, b );
16396			w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
16397			// edge region of BC; barycentric coords (0, 1-w, w)
16398			return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
16399
16400		}
16401
16402		// face region
16403		const denom = 1 / ( va + vb + vc );
16404		// u = va * denom
16405		v = vb * denom;
16406		w = vc * denom;
16407
16408		return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
16409
16410	}
16411
16412	/**
16413	 * Returns `true` if this triangle is equal with the given one.
16414	 *
16415	 * @param {Triangle} triangle - The triangle to test for equality.
16416	 * @return {boolean} Whether this triangle is equal with the given one.
16417	 */
16418	equals( triangle ) {
16419
16420		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
16421
16422	}
16423
16424}
16425
vendor: 9,866 bytes, lines 16426-16703
16426const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
16427	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
16428	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
16429	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
16430	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
16431	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
16432	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
16433	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
16434	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
16435	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
16436	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
16437	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
16438	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
16439	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
16440	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
16441	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
16442	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
16443	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
16444	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
16445	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
16446	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
16447	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
16448	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
16449	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
16450
16451const _hslA = { h: 0, s: 0, l: 0 };
16452const _hslB = { h: 0, s: 0, l: 0 };
16453
16454function hue2rgb( p, q, t ) {
16455
16456	if ( t < 0 ) t += 1;
16457	if ( t > 1 ) t -= 1;
16458	if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
16459	if ( t < 1 / 2 ) return q;
16460	if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
16461	return p;
16462
16463}
16464
16465/**
16466 * A Color instance is represented by RGB components in the linear <i>working
16467 * color space</i>, which defaults to `LinearSRGBColorSpace`. Inputs
16468 * conventionally using `SRGBColorSpace` (such as hexadecimals and CSS
16469 * strings) are converted to the working color space automatically.
16470 *
16471 * ```js
16472 * // converted automatically from SRGBColorSpace to LinearSRGBColorSpace
16473 * const color = new THREE.Color().setHex( 0x112233 );
16474 * ```
16475 * Source color spaces may be specified explicitly, to ensure correct conversions.
16476 * ```js
16477 * // assumed already LinearSRGBColorSpace; no conversion
16478 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5 );
16479 *
16480 * // converted explicitly from SRGBColorSpace to LinearSRGBColorSpace
16481 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5, SRGBColorSpace );
16482 * ```
16483 * If THREE.ColorManagement is disabled, no conversions occur. For details,
16484 * see <i>Color management</i>. Iterating through a Color instance will yield
16485 * its components (r, g, b) in the corresponding order. A Color can be initialised
16486 * in any of the following ways:
16487 * ```js
16488 * //empty constructor - will default white
16489 * const color1 = new THREE.Color();
16490 *
16491 * //Hexadecimal color (recommended)
16492 * const color2 = new THREE.Color( 0xff0000 );
16493 *
16494 * //RGB string
16495 * const color3 = new THREE.Color("rgb(255, 0, 0)");
16496 * const color4 = new THREE.Color("rgb(100%, 0%, 0%)");
16497 *
16498 * //X11 color name - all 140 color names are supported.
16499 * //Note the lack of CamelCase in the name
16500 * const color5 = new THREE.Color( 'skyblue' );
16501 * //HSL string
16502 * const color6 = new THREE.Color("hsl(0, 100%, 50%)");
16503 *
16504 * //Separate RGB values between 0 and 1
16505 * const color7 = new THREE.Color( 1, 0, 0 );
16506 * ```
16507 */
16508class Color {
16509
16510	/**
16511	 * Constructs a new color.
16512	 *
16513	 * Note that standard method of specifying color in three.js is with a hexadecimal triplet,
16514	 * and that method is used throughout the rest of the documentation.
16515	 *
16516	 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are
16517	 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance.
16518	 * @param {number} [g] - The green component.
16519	 * @param {number} [b] - The blue component.
16520	 */
16521	constructor( r, g, b ) {
16522
16523		/**
16524		 * This flag can be used for type testing.
16525		 *
16526		 * @type {boolean}
16527		 * @readonly
16528		 * @default true
16529		 */
16530		this.isColor = true;
16531
16532		/**
16533		 * The red component.
16534		 *
16535		 * @type {number}
16536		 * @default 1
16537		 */
16538		this.r = 1;
16539
16540		/**
16541		 * The green component.
16542		 *
16543		 * @type {number}
16544		 * @default 1
16545		 */
16546		this.g = 1;
16547
16548		/**
16549		 * The blue component.
16550		 *
16551		 * @type {number}
16552		 * @default 1
16553		 */
16554		this.b = 1;
16555
16556		return this.set( r, g, b );
16557
16558	}
16559
16560	/**
16561	 * Sets the colors's components from the given values.
16562	 *
16563	 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are
16564	 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance.
16565	 * @param {number} [g] - The green component.
16566	 * @param {number} [b] - The blue component.
16567	 * @return {Color} A reference to this color.
16568	 */
16569	set( r, g, b ) {
16570
16571		if ( g === undefined && b === undefined ) {
16572
16573			// r is THREE.Color, hex or string
16574
16575			const value = r;
16576
16577			if ( value && value.isColor ) {
16578
16579				this.copy( value );
16580
16581			} else if ( typeof value === 'number' ) {
16582
16583				this.setHex( value );
16584
16585			} else if ( typeof value === 'string' ) {
16586
16587				this.setStyle( value );
16588
16589			}
16590
16591		} else {
16592
16593			this.setRGB( r, g, b );
16594
16595		}
16596
16597		return this;
16598
16599	}
16600
16601	/**
16602	 * Sets the colors's components to the given scalar value.
16603	 *
16604	 * @param {number} scalar - The scalar value.
16605	 * @return {Color} A reference to this color.
16606	 */
16607	setScalar( scalar ) {
16608
16609		this.r = scalar;
16610		this.g = scalar;
16611		this.b = scalar;
16612
16613		return this;
16614
16615	}
16616
16617	/**
16618	 * Sets this color from a hexadecimal value.
16619	 *
16620	 * @param {number} hex - The hexadecimal value.
16621	 * @param {string} [colorSpace=SRGBColorSpace] - The color space.
16622	 * @return {Color} A reference to this color.
16623	 */
16624	setHex( hex, colorSpace = SRGBColorSpace ) {
16625
16626		hex = Math.floor( hex );
16627
16628		this.r = ( hex >> 16 & 255 ) / 255;
16629		this.g = ( hex >> 8 & 255 ) / 255;
16630		this.b = ( hex & 255 ) / 255;
16631
16632		ColorManagement.toWorkingColorSpace( this, colorSpace );
16633
16634		return this;
16635
16636	}
16637
16638	/**
16639	 * Sets this color from RGB values.
16640	 *
16641	 * @param {number} r - Red channel value between `0.0` and `1.0`.
16642	 * @param {number} g - Green channel value between `0.0` and `1.0`.
16643	 * @param {number} b - Blue channel value between `0.0` and `1.0`.
16644	 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space.
16645	 * @return {Color} A reference to this color.
16646	 */
16647	setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) {
16648
16649		this.r = r;
16650		this.g = g;
16651		this.b = b;
16652
16653		ColorManagement.toWorkingColorSpace( this, colorSpace );
16654
16655		return this;
16656
16657	}
16658
16659	/**
16660	 * Sets this color from RGB values.
16661	 *
16662	 * @param {number} h - Hue value between `0.0` and `1.0`.
16663	 * @param {number} s - Saturation value between `0.0` and `1.0`.
16664	 * @param {number} l - Lightness value between `0.0` and `1.0`.
16665	 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space.
16666	 * @return {Color} A reference to this color.
16667	 */
16668	setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {
16669
16670		// h,s,l ranges are in 0.0 - 1.0
16671		h = euclideanModulo( h, 1 );
16672		s = clamp( s, 0, 1 );
16673		l = clamp( l, 0, 1 );
16674
16675		if ( s === 0 ) {
16676
16677			this.r = this.g = this.b = l;
16678
16679		} else {
16680
16681			const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
16682			const q = ( 2 * l ) - p;
16683
16684			this.r = hue2rgb( q, p, h + 1 / 3 );
16685			this.g = hue2rgb( q, p, h );
16686			this.b = hue2rgb( q, p, h - 1 / 3 );
16687
16688		}
16689
16690		ColorManagement.toWorkingColorSpace( this, colorSpace );
16691
16692		return this;
16693
16694	}
16695
16696	/**
16697	 * Sets this color from a CSS-style string. For example, `rgb(250, 0,0)`,
16698	 * `rgb(100%, 0%, 0%)`, `hsl(0, 100%, 50%)`, `#ff0000`, `#f00`, or `red` ( or
16699	 * any [X11 color name]{@link https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart} -
16700	 * all 140 color names are supported).
16701	 *
16702	 * @param {string} style - Color as a CSS-style string.
16703	 * @param {string}
vendor: 4,222 bytes, lines 16703-16909
16703 [colorSpace=SRGBColorSpace] - The color space.
16704	 * @return {Color} A reference to this color.
16705	 */
16706	setStyle( style, colorSpace = SRGBColorSpace ) {
16707
16708		function handleAlpha( string ) {
16709
16710			if ( string === undefined ) return;
16711
16712			if ( parseFloat( string ) < 1 ) {
16713
16714				console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
16715
16716			}
16717
16718		}
16719
16720
16721		let m;
16722
16723		if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) {
16724
16725			// rgb / hsl
16726
16727			let color;
16728			const name = m[ 1 ];
16729			const components = m[ 2 ];
16730
16731			switch ( name ) {
16732
16733				case 'rgb':
16734				case 'rgba':
16735
16736					if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
16737
16738						// rgb(255,0,0) rgba(255,0,0,0.5)
16739
16740						handleAlpha( color[ 4 ] );
16741
16742						return this.setRGB(
16743							Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255,
16744							Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255,
16745							Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255,
16746							colorSpace
16747						);
16748
16749					}
16750
16751					if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
16752
16753						// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
16754
16755						handleAlpha( color[ 4 ] );
16756
16757						return this.setRGB(
16758							Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100,
16759							Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100,
16760							Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100,
16761							colorSpace
16762						);
16763
16764					}
16765
16766					break;
16767
16768				case 'hsl':
16769				case 'hsla':
16770
16771					if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
16772
16773						// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
16774
16775						handleAlpha( color[ 4 ] );
16776
16777						return this.setHSL(
16778							parseFloat( color[ 1 ] ) / 360,
16779							parseFloat( color[ 2 ] ) / 100,
16780							parseFloat( color[ 3 ] ) / 100,
16781							colorSpace
16782						);
16783
16784					}
16785
16786					break;
16787
16788				default:
16789
16790					console.warn( 'THREE.Color: Unknown color model ' + style );
16791
16792			}
16793
16794		} else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
16795
16796			// hex color
16797
16798			const hex = m[ 1 ];
16799			const size = hex.length;
16800
16801			if ( size === 3 ) {
16802
16803				// #ff0
16804				return this.setRGB(
16805					parseInt( hex.charAt( 0 ), 16 ) / 15,
16806					parseInt( hex.charAt( 1 ), 16 ) / 15,
16807					parseInt( hex.charAt( 2 ), 16 ) / 15,
16808					colorSpace
16809				);
16810
16811			} else if ( size === 6 ) {
16812
16813				// #ff0000
16814				return this.setHex( parseInt( hex, 16 ), colorSpace );
16815
16816			} else {
16817
16818				console.warn( 'THREE.Color: Invalid hex color ' + style );
16819
16820			}
16821
16822		} else if ( style && style.length > 0 ) {
16823
16824			return this.setColorName( style, colorSpace );
16825
16826		}
16827
16828		return this;
16829
16830	}
16831
16832	/**
16833	 * Sets this color from a color name. Faster than {@link Color#setStyle} if
16834	 * you don't need the other CSS-style formats.
16835	 *
16836	 * For convenience, the list of names is exposed in `Color.NAMES` as a hash.
16837	 * ```js
16838	 * Color.NAMES.aliceblue // returns 0xF0F8FF
16839	 * ```
16840	 *
16841	 * @param {string} style - The color name.
16842	 * @param {string} [colorSpace=SRGBColorSpace] - The color space.
16843	 * @return {Color} A reference to this color.
16844	 */
16845	setColorName( style, colorSpace = SRGBColorSpace ) {
16846
16847		// color keywords
16848		const hex = _colorKeywords[ style.toLowerCase() ];
16849
16850		if ( hex !== undefined ) {
16851
16852			// red
16853			this.setHex( hex, colorSpace );
16854
16855		} else {
16856
16857			// unknown color
16858			console.warn( 'THREE.Color: Unknown color ' + style );
16859
16860		}
16861
16862		return this;
16863
16864	}
16865
16866	/**
16867	 * Returns a new color with copied values from this instance.
16868	 *
16869	 * @return {Color} A clone of this instance.
16870	 */
16871	clone() {
16872
16873		return new this.constructor( this.r, this.g, this.b );
16874
16875	}
16876
16877	/**
16878	 * Copies the values of the given color to this instance.
16879	 *
16880	 * @param {Color} color - The color to copy.
16881	 * @return {Color} A reference to this color.
16882	 */
16883	copy( color ) {
16884
16885		this.r = color.r;
16886		this.g = color.g;
16887		this.b = color.b;
16888
16889		return this;
16890
16891	}
16892
16893	/**
16894	 * Copies the given color into this color, and then converts this color from
16895	 * `SRGBColorSpace` to `LinearSRGBColorSpace`.
16896	 *
16897	 * @param {Color} color - The color to copy/convert.
16898	 * @return {Color} A reference to this color.
16899	 */
16900	copySRGBToLinear( color ) {
16901
16902		this.r = SRGBToLinear( color.r );
16903		this.g = SRGBToLinear( color.g );
16904		this.b = SRGBToLinear( color.b );
16905
16906		return this;
16907
16908	}
16909
vendor: 11,584 bytes, lines 16910-17385
16910	/**
16911	 * Copies the given color into this color, and then converts this color from
16912	 * `LinearSRGBColorSpace` to `SRGBColorSpace`.
16913	 *
16914	 * @param {Color} color - The color to copy/convert.
16915	 * @return {Color} A reference to this color.
16916	 */
16917	copyLinearToSRGB( color ) {
16918
16919		this.r = LinearToSRGB( color.r );
16920		this.g = LinearToSRGB( color.g );
16921		this.b = LinearToSRGB( color.b );
16922
16923		return this;
16924
16925	}
16926
16927	/**
16928	 * Converts this color from `SRGBColorSpace` to `LinearSRGBColorSpace`.
16929	 *
16930	 * @return {Color} A reference to this color.
16931	 */
16932	convertSRGBToLinear() {
16933
16934		this.copySRGBToLinear( this );
16935
16936		return this;
16937
16938	}
16939
16940	/**
16941	 * Converts this color from `LinearSRGBColorSpace` to `SRGBColorSpace`.
16942	 *
16943	 * @return {Color} A reference to this color.
16944	 */
16945	convertLinearToSRGB() {
16946
16947		this.copyLinearToSRGB( this );
16948
16949		return this;
16950
16951	}
16952
16953	/**
16954	 * Returns the hexadecimal value of this color.
16955	 *
16956	 * @param {string} [colorSpace=SRGBColorSpace] - The color space.
16957	 * @return {number} The hexadecimal value.
16958	 */
16959	getHex( colorSpace = SRGBColorSpace ) {
16960
16961		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
16962
16963		return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) );
16964
16965	}
16966
16967	/**
16968	 * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').
16969	 *
16970	 * @param {string} [colorSpace=SRGBColorSpace] - The color space.
16971	 * @return {string} The hexadecimal value as a string.
16972	 */
16973	getHexString( colorSpace = SRGBColorSpace ) {
16974
16975		return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( -6 );
16976
16977	}
16978
16979	/**
16980	 * Converts the colors RGB values into the HSL format and stores them into the
16981	 * given target object.
16982	 *
16983	 * @param {{h:number,s:number,l:number}} target - The target object that is used to store the method's result.
16984	 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space.
16985	 * @return {{h:number,s:number,l:number}} The HSL representation of this color.
16986	 */
16987	getHSL( target, colorSpace = ColorManagement.workingColorSpace ) {
16988
16989		// h,s,l ranges are in 0.0 - 1.0
16990
16991		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
16992
16993		const r = _color.r, g = _color.g, b = _color.b;
16994
16995		const max = Math.max( r, g, b );
16996		const min = Math.min( r, g, b );
16997
16998		let hue, saturation;
16999		const lightness = ( min + max ) / 2.0;
17000
17001		if ( min === max ) {
17002
17003			hue = 0;
17004			saturation = 0;
17005
17006		} else {
17007
17008			const delta = max - min;
17009
17010			saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
17011
17012			switch ( max ) {
17013
17014				case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
17015				case g: hue = ( b - r ) / delta + 2; break;
17016				case b: hue = ( r - g ) / delta + 4; break;
17017
17018			}
17019
17020			hue /= 6;
17021
17022		}
17023
17024		target.h = hue;
17025		target.s = saturation;
17026		target.l = lightness;
17027
17028		return target;
17029
17030	}
17031
17032	/**
17033	 * Returns the RGB values of this color and stores them into the given target object.
17034	 *
17035	 * @param {Color} target - The target color that is used to store the method's result.
17036	 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space.
17037	 * @return {Color} The RGB representation of this color.
17038	 */
17039	getRGB( target, colorSpace = ColorManagement.workingColorSpace ) {
17040
17041		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
17042
17043		target.r = _color.r;
17044		target.g = _color.g;
17045		target.b = _color.b;
17046
17047		return target;
17048
17049	}
17050
17051	/**
17052	 * Returns the value of this color as a CSS style string. Example: `rgb(255,0,0)`.
17053	 *
17054	 * @param {string} [colorSpace=SRGBColorSpace] - The color space.
17055	 * @return {string} The CSS representation of this color.
17056	 */
17057	getStyle( colorSpace = SRGBColorSpace ) {
17058
17059		ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
17060
17061		const r = _color.r, g = _color.g, b = _color.b;
17062
17063		if ( colorSpace !== SRGBColorSpace ) {
17064
17065			// Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).
17066			return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`;
17067
17068		}
17069
17070		return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`;
17071
17072	}
17073
17074	/**
17075	 * Adds the given HSL values to this color's values.
17076	 * Internally, this converts the color's RGB values to HSL, adds HSL
17077	 * and then converts the color back to RGB.
17078	 *
17079	 * @param {number} h - Hue value between `0.0` and `1.0`.
17080	 * @param {number} s - Saturation value between `0.0` and `1.0`.
17081	 * @param {number} l - Lightness value between `0.0` and `1.0`.
17082	 * @return {Color} A reference to this color.
17083	 */
17084	offsetHSL( h, s, l ) {
17085
17086		this.getHSL( _hslA );
17087
17088		return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l );
17089
17090	}
17091
17092	/**
17093	 * Adds the RGB values of the given color to the RGB values of this color.
17094	 *
17095	 * @param {Color} color - The color to add.
17096	 * @return {Color} A reference to this color.
17097	 */
17098	add( color ) {
17099
17100		this.r += color.r;
17101		this.g += color.g;
17102		this.b += color.b;
17103
17104		return this;
17105
17106	}
17107
17108	/**
17109	 * Adds the RGB values of the given colors and stores the result in this instance.
17110	 *
17111	 * @param {Color} color1 - The first color.
17112	 * @param {Color} color2 - The second color.
17113	 * @return {Color} A reference to this color.
17114	 */
17115	addColors( color1, color2 ) {
17116
17117		this.r = color1.r + color2.r;
17118		this.g = color1.g + color2.g;
17119		this.b = color1.b + color2.b;
17120
17121		return this;
17122
17123	}
17124
17125	/**
17126	 * Adds the given scalar value to the RGB values of this color.
17127	 *
17128	 * @param {number} s - The scalar to add.
17129	 * @return {Color} A reference to this color.
17130	 */
17131	addScalar( s ) {
17132
17133		this.r += s;
17134		this.g += s;
17135		this.b += s;
17136
17137		return this;
17138
17139	}
17140
17141	/**
17142	 * Subtracts the RGB values of the given color from the RGB values of this color.
17143	 *
17144	 * @param {Color} color - The color to subtract.
17145	 * @return {Color} A reference to this color.
17146	 */
17147	sub( color ) {
17148
17149		this.r = Math.max( 0, this.r - color.r );
17150		this.g = Math.max( 0, this.g - color.g );
17151		this.b = Math.max( 0, this.b - color.b );
17152
17153		return this;
17154
17155	}
17156
17157	/**
17158	 * Multiplies the RGB values of the given color with the RGB values of this color.
17159	 *
17160	 * @param {Color} color - The color to multiply.
17161	 * @return {Color} A reference to this color.
17162	 */
17163	multiply( color ) {
17164
17165		this.r *= color.r;
17166		this.g *= color.g;
17167		this.b *= color.b;
17168
17169		return this;
17170
17171	}
17172
17173	/**
17174	 * Multiplies the given scalar value with the RGB values of this color.
17175	 *
17176	 * @param {number} s - The scalar to multiply.
17177	 * @return {Color} A reference to this color.
17178	 */
17179	multiplyScalar( s ) {
17180
17181		this.r *= s;
17182		this.g *= s;
17183		this.b *= s;
17184
17185		return this;
17186
17187	}
17188
17189	/**
17190	 * Linearly interpolates this color's RGB values toward the RGB values of the
17191	 * given color. The alpha argument can be thought of as the ratio between
17192	 * the two colors, where `0.0` is this color and `1.0` is the first argument.
17193	 *
17194	 * @param {Color} color - The color to converge on.
17195	 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`.
17196	 * @return {Color} A reference to this color.
17197	 */
17198	lerp( color, alpha ) {
17199
17200		this.r += ( color.r - this.r ) * alpha;
17201		this.g += ( color.g - this.g ) * alpha;
17202		this.b += ( color.b - this.b ) * alpha;
17203
17204		return this;
17205
17206	}
17207
17208	/**
17209	 * Linearly interpolates between the given colors and stores the result in this instance.
17210	 * The alpha argument can be thought of as the ratio between the two colors, where `0.0`
17211	 * is the first and `1.0` is the second color.
17212	 *
17213	 * @param {Color} color1 - The first color.
17214	 * @param {Color} color2 - The second color.
17215	 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`.
17216	 * @return {Color} A reference to this color.
17217	 */
17218	lerpColors( color1, color2, alpha ) {
17219
17220		this.r = color1.r + ( color2.r - color1.r ) * alpha;
17221		this.g = color1.g + ( color2.g - color1.g ) * alpha;
17222		this.b = color1.b + ( color2.b - color1.b ) * alpha;
17223
17224		return this;
17225
17226	}
17227
17228	/**
17229	 * Linearly interpolates this color's HSL values toward the HSL values of the
17230	 * given color. It differs from {@link Color#lerp} by not interpolating straight
17231	 * from one color to the other, but instead going through all the hues in between
17232	 * those two colors. The alpha argument can be thought of as the ratio between
17233	 * the two colors, where 0.0 is this color and 1.0 is the first argument.
17234	 *
17235	 * @param {Color} color - The color to converge on.
17236	 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`.
17237	 * @return {Color} A reference to this color.
17238	 */
17239	lerpHSL( color, alpha ) {
17240
17241		this.getHSL( _hslA );
17242		color.getHSL( _hslB );
17243
17244		const h = lerp( _hslA.h, _hslB.h, alpha );
17245		const s = lerp( _hslA.s, _hslB.s, alpha );
17246		const l = lerp( _hslA.l, _hslB.l, alpha );
17247
17248		this.setHSL( h, s, l );
17249
17250		return this;
17251
17252	}
17253
17254	/**
17255	 * Sets the color's RGB components from the given 3D vector.
17256	 *
17257	 * @param {Vector3} v - The vector to set.
17258	 * @return {Color} A reference to this color.
17259	 */
17260	setFromVector3( v ) {
17261
17262		this.r = v.x;
17263		this.g = v.y;
17264		this.b = v.z;
17265
17266		return this;
17267
17268	}
17269
17270	/**
17271	 * Transforms this color with the given 3x3 matrix.
17272	 *
17273	 * @param {Matrix3} m - The matrix.
17274	 * @return {Color} A reference to this color.
17275	 */
17276	applyMatrix3( m ) {
17277
17278		const r = this.r, g = this.g, b = this.b;
17279		const e = m.elements;
17280
17281		this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;
17282		this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;
17283		this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;
17284
17285		return this;
17286
17287	}
17288
17289	/**
17290	 * Returns `true` if this color is equal with the given one.
17291	 *
17292	 * @param {Color} c - The color to test for equality.
17293	 * @return {boolean} Whether this bounding color is equal with the given one.
17294	 */
17295	equals( c ) {
17296
17297		return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
17298
17299	}
17300
17301	/**
17302	 * Sets this color's RGB components from the given array.
17303	 *
17304	 * @param {Array<number>} array - An array holding the RGB values.
17305	 * @param {number} [offset=0] - The offset into the array.
17306	 * @return {Color} A reference to this color.
17307	 */
17308	fromArray( array, offset = 0 ) {
17309
17310		this.r = array[ offset ];
17311		this.g = array[ offset + 1 ];
17312		this.b = array[ offset + 2 ];
17313
17314		return this;
17315
17316	}
17317
17318	/**
17319	 * Writes the RGB components of this color to the given array. If no array is provided,
17320	 * the method returns a new instance.
17321	 *
17322	 * @param {Array<number>} [array=[]] - The target array holding the color components.
17323	 * @param {number} [offset=0] - Index of the first element in the array.
17324	 * @return {Array<number>} The color components.
17325	 */
17326	toArray( array = [], offset = 0 ) {
17327
17328		array[ offset ] = this.r;
17329		array[ offset + 1 ] = this.g;
17330		array[ offset + 2 ] = this.b;
17331
17332		return array;
17333
17334	}
17335
17336	/**
17337	 * Sets the components of this color from the given buffer attribute.
17338	 *
17339	 * @param {BufferAttribute} attribute - The buffer attribute holding color data.
17340	 * @param {number} index - The index into the attribute.
17341	 * @return {Color} A reference to this color.
17342	 */
17343	fromBufferAttribute( attribute, index ) {
17344
17345		this.r = attribute.getX( index );
17346		this.g = attribute.getY( index );
17347		this.b = attribute.getZ( index );
17348
17349		return this;
17350
17351	}
17352
17353	/**
17354	 * This methods defines the serialization result of this class. Returns the color
17355	 * as a hexadecimal value.
17356	 *
17357	 * @return {number} The hexadecimal value.
17358	 */
17359	toJSON() {
17360
17361		return this.getHex();
17362
17363	}
17364
17365	*[ Symbol.iterator ]() {
17366
17367		yield this.r;
17368		yield this.g;
17369		yield this.b;
17370
17371	}
17372
17373}
17374
17375const _color = /*@__PURE__*/ new Color();
17376
17377/**
17378 * A dictionary with X11 color names.
17379 *
17380 * Note that multiple words such as Dark Orange become the string 'darkorange'.
17381 *
17382 * @static
17383 * @type {Object}
17384 */
17385Color.NAMES = _colorKeywords;
vendor: 15,189 bytes, lines 17385-17906
17385
17386
17387let _materialId = 0;
17388
17389/**
17390 * Abstract base class for materials.
17391 *
17392 * Materials define the appearance of renderable 3D objects.
17393 *
17394 * @abstract
17395 * @augments EventDispatcher
17396 */
17397class Material extends EventDispatcher {
17398
17399	/**
17400	 * Constructs a new material.
17401	 */
17402	constructor() {
17403
17404		super();
17405
17406		/**
17407		 * This flag can be used for type testing.
17408		 *
17409		 * @type {boolean}
17410		 * @readonly
17411		 * @default true
17412		 */
17413		this.isMaterial = true;
17414
17415		/**
17416		 * The ID of the material.
17417		 *
17418		 * @name Material#id
17419		 * @type {number}
17420		 * @readonly
17421		 */
17422		Object.defineProperty( this, 'id', { value: _materialId ++ } );
17423
17424		/**
17425		 * The UUID of the material.
17426		 *
17427		 * @type {string}
17428		 * @readonly
17429		 */
17430		this.uuid = generateUUID();
17431
17432		/**
17433		 * The name of the material.
17434		 *
17435		 * @type {string}
17436		 */
17437		this.name = '';
17438
17439		/**
17440		 * The type property is used for detecting the object type
17441		 * in context of serialization/deserialization.
17442		 *
17443		 * @type {string}
17444		 * @readonly
17445		 */
17446		this.type = 'Material';
17447
17448		/**
17449		 * Defines the blending type of the material.
17450		 *
17451		 * It must be set to `CustomBlending` if custom blending properties like
17452		 * {@link Material#blendSrc}, {@link Material#blendDst} or {@link Material#blendEquation}
17453		 * should have any effect.
17454		 *
17455		 * @type {(NoBlending|NormalBlending|AdditiveBlending|SubtractiveBlending|MultiplyBlending|CustomBlending)}
17456		 * @default NormalBlending
17457		 */
17458		this.blending = NormalBlending;
17459
17460		/**
17461		 * Defines which side of faces will be rendered - front, back or both.
17462		 *
17463		 * @type {(FrontSide|BackSide|DoubleSide)}
17464		 * @default FrontSide
17465		 */
17466		this.side = FrontSide;
17467
17468		/**
17469		 * If set to `true`, vertex colors should be used.
17470		 *
17471		 * The engine supports RGB and RGBA vertex colors depending on whether a three (RGB) or
17472		 * four (RGBA) component color buffer attribute is used.
17473		 *
17474		 * @type {boolean}
17475		 * @default false
17476		 */
17477		this.vertexColors = false;
17478
17479		/**
17480		 * Defines how transparent the material is.
17481		 * A value of `0.0` indicates fully transparent, `1.0` is fully opaque.
17482		 *
17483		 * If the {@link Material#transparent} is not set to `true`,
17484		 * the material will remain fully opaque and this value will only affect its color.
17485		 *
17486		 * @type {number}
17487		 * @default 1
17488		 */
17489		this.opacity = 1;
17490
17491		/**
17492		 * Defines whether this material is transparent. This has an effect on
17493		 * rendering as transparent objects need special treatment and are rendered
17494		 * after non-transparent objects.
17495		 *
17496		 * When set to true, the extent to which the material is transparent is
17497		 * controlled by {@link Material#opacity}.
17498		 *
17499		 * @type {boolean}
17500		 * @default false
17501		 */
17502		this.transparent = false;
17503
17504		/**
17505		 * Enables alpha hashed transparency, an alternative to {@link Material#transparent} or
17506		 * {@link Material#alphaTest}. The material will not be rendered if opacity is lower than
17507		 * a random threshold. Randomization introduces some grain or noise, but approximates alpha
17508		 * blending without the associated problems of sorting. Using TAA can reduce the resulting noise.
17509		 *
17510		 * @type {boolean}
17511		 * @default false
17512		 */
17513		this.alphaHash = false;
17514
17515		/**
17516		 * Defines the blending source factor.
17517		 *
17518		 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
17519		 * @default SrcAlphaFactor
17520		 */
17521		this.blendSrc = SrcAlphaFactor;
17522
17523		/**
17524		 * Defines the blending destination factor.
17525		 *
17526		 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
17527		 * @default OneMinusSrcAlphaFactor
17528		 */
17529		this.blendDst = OneMinusSrcAlphaFactor;
17530
17531		/**
17532		 * Defines the blending equation.
17533		 *
17534		 * @type {(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)}
17535		 * @default AddEquation
17536		 */
17537		this.blendEquation = AddEquation;
17538
17539		/**
17540		 * Defines the blending source alpha factor.
17541		 *
17542		 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
17543		 * @default null
17544		 */
17545		this.blendSrcAlpha = null;
17546
17547		/**
17548		 * Defines the blending destination alpha factor.
17549		 *
17550		 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
17551		 * @default null
17552		 */
17553		this.blendDstAlpha = null;
17554
17555		/**
17556		 * Defines the blending equation of the alpha channel.
17557		 *
17558		 * @type {?(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)}
17559		 * @default null
17560		 */
17561		this.blendEquationAlpha = null;
17562
17563		/**
17564		 * Represents the RGB values of the constant blend color.
17565		 *
17566		 * This property has only an effect when using custom blending with `ConstantColor` or `OneMinusConstantColor`.
17567		 *
17568		 * @type {Color}
17569		 * @default (0,0,0)
17570		 */
17571		this.blendColor = new Color( 0, 0, 0 );
17572
17573		/**
17574		 * Represents the alpha value of the constant blend color.
17575		 *
17576		 * This property has only an effect when using custom blending with `ConstantAlpha` or `OneMinusConstantAlpha`.
17577		 *
17578		 * @type {number}
17579		 * @default 0
17580		 */
17581		this.blendAlpha = 0;
17582
17583		/**
17584		 * Defines the depth function.
17585		 *
17586		 * @type {(NeverDepth|AlwaysDepth|LessDepth|LessEqualDepth|EqualDepth|GreaterEqualDepth|GreaterDepth|NotEqualDepth)}
17587		 * @default LessEqualDepth
17588		 */
17589		this.depthFunc = LessEqualDepth;
17590
17591		/**
17592		 * Whether to have depth test enabled when rendering this material.
17593		 * When the depth test is disabled, the depth write will also be implicitly disabled.
17594		 *
17595		 * @type {boolean}
17596		 * @default true
17597		 */
17598		this.depthTest = true;
17599
17600		/**
17601		 * Whether rendering this material has any effect on the depth buffer.
17602		 *
17603		 * When drawing 2D overlays it can be useful to disable the depth writing in
17604		 * order to layer several things together without creating z-index artifacts.
17605		 *
17606		 * @type {boolean}
17607		 * @default true
17608		 */
17609		this.depthWrite = true;
17610
17611		/**
17612		 * The bit mask to use when writing to the stencil buffer.
17613		 *
17614		 * @type {number}
17615		 * @default 0xff
17616		 */
17617		this.stencilWriteMask = 0xff;
17618
17619		/**
17620		 * The stencil comparison function to use.
17621		 *
17622		 * @type {NeverStencilFunc|LessStencilFunc|EqualStencilFunc|LessEqualStencilFunc|GreaterStencilFunc|NotEqualStencilFunc|GreaterEqualStencilFunc|AlwaysStencilFunc}
17623		 * @default AlwaysStencilFunc
17624		 */
17625		this.stencilFunc = AlwaysStencilFunc;
17626
17627		/**
17628		 * The value to use when performing stencil comparisons or stencil operations.
17629		 *
17630		 * @type {number}
17631		 * @default 0
17632		 */
17633		this.stencilRef = 0;
17634
17635		/**
17636		 * The bit mask to use when comparing against the stencil buffer.
17637		 *
17638		 * @type {number}
17639		 * @default 0xff
17640		 */
17641		this.stencilFuncMask = 0xff;
17642
17643		/**
17644		 * Which stencil operation to perform when the comparison function returns `false`.
17645		 *
17646		 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp}
17647		 * @default KeepStencilOp
17648		 */
17649		this.stencilFail = KeepStencilOp;
17650
17651		/**
17652		 * Which stencil operation to perform when the comparison function returns
17653		 * `true` but the depth test fails.
17654		 *
17655		 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp}
17656		 * @default KeepStencilOp
17657		 */
17658		this.stencilZFail = KeepStencilOp;
17659
17660		/**
17661		 * Which stencil operation to perform when the comparison function returns
17662		 * `true` and the depth test passes.
17663		 *
17664		 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp}
17665		 * @default KeepStencilOp
17666		 */
17667		this.stencilZPass = KeepStencilOp;
17668
17669		/**
17670		 * Whether stencil operations are performed against the stencil buffer. In
17671		 * order to perform writes or comparisons against the stencil buffer this
17672		 * value must be `true`.
17673		 *
17674		 * @type {boolean}
17675		 * @default false
17676		 */
17677		this.stencilWrite = false;
17678
17679		/**
17680		 * User-defined clipping planes specified as THREE.Plane objects in world
17681		 * space. These planes apply to the objects this material is attached to.
17682		 * Points in space whose signed distance to the plane is negative are clipped
17683		 * (not rendered). This requires {@link WebGLRenderer#localClippingEnabled} to
17684		 * be `true`.
17685		 *
17686		 * @type {?Array<Plane>}
17687		 * @default null
17688		 */
17689		this.clippingPlanes = null;
17690
17691		/**
17692		 * Changes the behavior of clipping planes so that only their intersection is
17693		 * clipped, rather than their union.
17694		 *
17695		 * @type {boolean}
17696		 * @default false
17697		 */
17698		this.clipIntersection = false;
17699
17700		/**
17701		 * Defines whether to clip shadows according to the clipping planes specified
17702		 * on this material.
17703		 *
17704		 * @type {boolean}
17705		 * @default false
17706		 */
17707		this.clipShadows = false;
17708
17709		/**
17710		 * Defines which side of faces cast shadows. If `null`, the side casting shadows
17711		 * is determined as follows:
17712		 *
17713		 * - When {@link Material#side} is set to `FrontSide`, the back side cast shadows.
17714		 * - When {@link Material#side} is set to `BackSide`, the front side cast shadows.
17715		 * - When {@link Material#side} is set to `DoubleSide`, both sides cast shadows.
17716		 *
17717		 * @type {?(FrontSide|BackSide|DoubleSide)}
17718		 * @default null
17719		 */
17720		this.shadowSide = null;
17721
17722		/**
17723		 * Whether to render the material's color.
17724		 *
17725		 * This can be used in conjunction with {@link Object3D#renderOder} to create invisible
17726		 * objects that occlude other objects.
17727		 *
17728		 * @type {boolean}
17729		 * @default true
17730		 */
17731		this.colorWrite = true;
17732
17733		/**
17734		 * Override the renderer's default precision for this material.
17735		 *
17736		 * @type {?('highp'|'mediump'|'lowp')}
17737		 * @default null
17738		 */
17739		this.precision = null;
17740
17741		/**
17742		 * Whether to use polygon offset or not. When enabled, each fragment's depth value will
17743		 * be offset after it is interpolated from the depth values of the appropriate vertices.
17744		 * The offset is added before the depth test is performed and before the value is written
17745		 * into the depth buffer.
17746		 *
17747		 * Can be useful for rendering hidden-line images, for applying decals to surfaces, and for
17748		 * rendering solids with highlighted edges.
17749		 *
17750		 * @type {boolean}
17751		 * @default false
17752		 */
17753		this.polygonOffset = false;
17754
17755		/**
17756		 * Specifies a scale factor that is used to create a variable depth offset for each polygon.
17757		 *
17758		 * @type {number}
17759		 * @default 0
17760		 */
17761		this.polygonOffsetFactor = 0;
17762
17763		/**
17764		 * Is multiplied by an implementation-specific value to create a constant depth offset.
17765		 *
17766		 * @type {number}
17767		 * @default 0
17768		 */
17769		this.polygonOffsetUnits = 0;
17770
17771		/**
17772		 * Whether to apply dithering to the color to remove the appearance of banding.
17773		 *
17774		 * @type {boolean}
17775		 * @default false
17776		 */
17777		this.dithering = false;
17778
17779		/**
17780		 * Whether alpha to coverage should be enabled or not. Can only be used with MSAA-enabled contexts
17781		 * (meaning when the renderer was created with *antialias* parameter set to `true`). Enabling this
17782		 * will smooth aliasing on clip plane edges and alphaTest-clipped edges.
17783		 *
17784		 * @type {boolean}
17785		 * @default false
17786		 */
17787		this.alphaToCoverage = false;
17788
17789		/**
17790		 * Whether to premultiply the alpha (transparency) value.
17791		 *
17792		 * @type {boolean}
17793		 * @default false
17794		 */
17795		this.premultipliedAlpha = false;
17796
17797		/**
17798		 * Whether double-sided, transparent objects should be rendered with a single pass or not.
17799		 *
17800		 * The engine renders double-sided, transparent objects with two draw calls (back faces first,
17801		 * then front faces) to mitigate transparency artifacts. There are scenarios however where this
17802		 * approach produces no quality gains but still doubles draw calls e.g. when rendering flat
17803		 * vegetation like grass sprites. In these cases, set the `forceSinglePass` flag to `true` to
17804		 * disable the two pass rendering to avoid performance issues.
17805		 *
17806		 * @type {boolean}
17807		 * @default false
17808		 */
17809		this.forceSinglePass = false;
17810
17811		/**
17812		 * Whether it's possible to override the material with {@link Scene#overrideMaterial} or not.
17813		 *
17814		 * @type {boolean}
17815		 * @default true
17816		 */
17817		this.allowOverride = true;
17818
17819		/**
17820		 * Defines whether 3D objects using this material are visible.
17821		 *
17822		 * @type {boolean}
17823		 * @default true
17824		 */
17825		this.visible = true;
17826
17827		/**
17828		 * Defines whether this material is tone mapped according to the renderer's tone mapping setting.
17829		 *
17830		 * It is ignored when rendering to a render target or using post processing or when using
17831		 * `WebGPURenderer`. In all these cases, all materials are honored by tone mapping.
17832		 *
17833		 * @type {boolean}
17834		 * @default true
17835		 */
17836		this.toneMapped = true;
17837
17838		/**
17839		 * An object that can be used to store custom data about the Material. It
17840		 * should not hold references to functions as these will not be cloned.
17841		 *
17842		 * @type {Object}
17843		 */
17844		this.userData = {};
17845
17846		/**
17847		 * This starts at `0` and counts how many times {@link Material#needsUpdate} is set to `true`.
17848		 *
17849		 * @type {number}
17850		 * @readonly
17851		 * @default 0
17852		 */
17853		this.version = 0;
17854
17855		this._alphaTest = 0;
17856
17857	}
17858
17859	/**
17860	 * Sets the alpha value to be used when running an alpha test. The material
17861	 * will not be rendered if the opacity is lower than this value.
17862	 *
17863	 * @type {number}
17864	 * @readonly
17865	 * @default 0
17866	 */
17867	get alphaTest() {
17868
17869		return this._alphaTest;
17870
17871	}
17872
17873	set alphaTest( value ) {
17874
17875		if ( this._alphaTest > 0 !== value > 0 ) {
17876
17877			this.version ++;
17878
17879		}
17880
17881		this._alphaTest = value;
17882
17883	}
17884
17885	/**
17886	 * An optional callback that is executed immediately before the material is used to render a 3D object.
17887	 *
17888	 * This method can only be used when rendering with {@link WebGLRenderer}.
17889	 *
17890	 * @param {WebGLRenderer} renderer - The renderer.
17891	 * @param {Scene} scene - The scene.
17892	 * @param {Camera} camera - The camera that is used to render the scene.
17893	 * @param {BufferGeometry} geometry - The 3D object's geometry.
17894	 * @param {Object3D} object - The 3D object.
17895	 * @param {Object} group - The geometry group data.
17896	 */
17897	onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
17898
17899	/**
17900	 * An optional callback that is executed immediately before the shader
17901	 * program is compiled. This function is called with the shader source code
17902	 * as a parameter. Useful for the modification of built-in materials.
17903	 *
17904	 * This method can only be used when rendering with {@link WebGLRenderer}. The
17905	 * recommended approach when customizing materials is to use `WebGPURenderer` with the new
17906	 * Node Material system and [TSL]
vendor: 10,207 bytes, lines 17906-18178
17906{@link https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language}.
17907	 *
17908	 * @param {{vertexShader:string,fragmentShader:string,uniforms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source.
17909	 * @param {WebGLRenderer} renderer - A reference to the renderer.
17910	 */
17911	onBeforeCompile( /* shaderobject, renderer */ ) {}
17912
17913	/**
17914	 * In case {@link Material#onBeforeCompile} is used, this callback can be used to identify
17915	 * values of settings used in `onBeforeCompile()`, so three.js can reuse a cached
17916	 * shader or recompile the shader for this material as needed.
17917	 *
17918	 * This method can only be used when rendering with {@link WebGLRenderer}.
17919	 *
17920	 * @return {string} The custom program cache key.
17921	 */
17922	customProgramCacheKey() {
17923
17924		return this.onBeforeCompile.toString();
17925
17926	}
17927
17928	/**
17929	 * This method can be used to set default values from parameter objects.
17930	 * It is a generic implementation so it can be used with different types
17931	 * of materials.
17932	 *
17933	 * @param {Object} [values] - The material values to set.
17934	 */
17935	setValues( values ) {
17936
17937		if ( values === undefined ) return;
17938
17939		for ( const key in values ) {
17940
17941			const newValue = values[ key ];
17942
17943			if ( newValue === undefined ) {
17944
17945				console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );
17946				continue;
17947
17948			}
17949
17950			const currentValue = this[ key ];
17951
17952			if ( currentValue === undefined ) {
17953
17954				console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );
17955				continue;
17956
17957			}
17958
17959			if ( currentValue && currentValue.isColor ) {
17960
17961				currentValue.set( newValue );
17962
17963			} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
17964
17965				currentValue.copy( newValue );
17966
17967			} else {
17968
17969				this[ key ] = newValue;
17970
17971			}
17972
17973		}
17974
17975	}
17976
17977	/**
17978	 * Serializes the material into JSON.
17979	 *
17980	 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
17981	 * @return {Object} A JSON object representing the serialized material.
17982	 * @see {@link ObjectLoader#parse}
17983	 */
17984	toJSON( meta ) {
17985
17986		const isRootObject = ( meta === undefined || typeof meta === 'string' );
17987
17988		if ( isRootObject ) {
17989
17990			meta = {
17991				textures: {},
17992				images: {}
17993			};
17994
17995		}
17996
17997		const data = {
17998			metadata: {
17999				version: 4.6,
18000				type: 'Material',
18001				generator: 'Material.toJSON'
18002			}
18003		};
18004
18005		// standard Material serialization
18006		data.uuid = this.uuid;
18007		data.type = this.type;
18008
18009		if ( this.name !== '' ) data.name = this.name;
18010
18011		if ( this.color && this.color.isColor ) data.color = this.color.getHex();
18012
18013		if ( this.roughness !== undefined ) data.roughness = this.roughness;
18014		if ( this.metalness !== undefined ) data.metalness = this.metalness;
18015
18016		if ( this.sheen !== undefined ) data.sheen = this.sheen;
18017		if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
18018		if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
18019		if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
18020		if ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
18021
18022		if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
18023		if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
18024		if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
18025		if ( this.shininess !== undefined ) data.shininess = this.shininess;
18026		if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
18027		if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
18028
18029		if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
18030
18031			data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
18032
18033		}
18034
18035		if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
18036
18037			data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
18038
18039		}
18040
18041		if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
18042
18043			data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
18044			data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
18045
18046		}
18047
18048		if ( this.dispersion !== undefined ) data.dispersion = this.dispersion;
18049
18050		if ( this.iridescence !== undefined ) data.iridescence = this.iridescence;
18051		if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;
18052		if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;
18053
18054		if ( this.iridescenceMap && this.iridescenceMap.isTexture ) {
18055
18056			data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;
18057
18058		}
18059
18060		if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {
18061
18062			data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;
18063
18064		}
18065
18066		if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
18067		if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;
18068
18069		if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {
18070
18071			data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;
18072
18073		}
18074
18075		if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
18076		if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
18077		if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
18078
18079		if ( this.lightMap && this.lightMap.isTexture ) {
18080
18081			data.lightMap = this.lightMap.toJSON( meta ).uuid;
18082			data.lightMapIntensity = this.lightMapIntensity;
18083
18084		}
18085
18086		if ( this.aoMap && this.aoMap.isTexture ) {
18087
18088			data.aoMap = this.aoMap.toJSON( meta ).uuid;
18089			data.aoMapIntensity = this.aoMapIntensity;
18090
18091		}
18092
18093		if ( this.bumpMap && this.bumpMap.isTexture ) {
18094
18095			data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
18096			data.bumpScale = this.bumpScale;
18097
18098		}
18099
18100		if ( this.normalMap && this.normalMap.isTexture ) {
18101
18102			data.normalMap = this.normalMap.toJSON( meta ).uuid;
18103			data.normalMapType = this.normalMapType;
18104			data.normalScale = this.normalScale.toArray();
18105
18106		}
18107
18108		if ( this.displacementMap && this.displacementMap.isTexture ) {
18109
18110			data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
18111			data.displacementScale = this.displacementScale;
18112			data.displacementBias = this.displacementBias;
18113
18114		}
18115
18116		if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
18117		if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
18118
18119		if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
18120		if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
18121		if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
18122		if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
18123
18124		if ( this.envMap && this.envMap.isTexture ) {
18125
18126			data.envMap = this.envMap.toJSON( meta ).uuid;
18127
18128			if ( this.combine !== undefined ) data.combine = this.combine;
18129
18130		}
18131
18132		if ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray();
18133		if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
18134		if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
18135		if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
18136
18137		if ( this.gradientMap && this.gradientMap.isTexture ) {
18138
18139			data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
18140
18141		}
18142
18143		if ( this.transmission !== undefined ) data.transmission = this.transmission;
18144		if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
18145		if ( this.thickness !== undefined ) data.thickness = this.thickness;
18146		if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
18147		if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;
18148		if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
18149
18150		if ( this.size !== undefined ) data.size = this.size;
18151		if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
18152		if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
18153
18154		if ( this.blending !== NormalBlending ) data.blending = this.blending;
18155		if ( this.side !== FrontSide ) data.side = this.side;
18156		if ( this.vertexColors === true ) data.vertexColors = true;
18157
18158		if ( this.opacity < 1 ) data.opacity = this.opacity;
18159		if ( this.transparent === true ) data.transparent = true;
18160
18161		if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;
18162		if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;
18163		if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;
18164		if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;
18165		if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;
18166		if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;
18167		if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();
18168		if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;
18169
18170		if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;
18171		if ( this.depthTest === false ) data.depthTest = this.depthTest;
18172		if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
18173		if ( this.colorWrite === false ) data.colorWrite = this.colorWrite;
18174
18175		if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;
18176		if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;
18177		if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;
18178		if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
vendor: 4,271 bytes, lines 18179-18318
18179		if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;
18180		if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;
18181		if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;
18182		if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;
18183
18184		// rotation (SpriteMaterial)
18185		if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;
18186
18187		if ( this.polygonOffset === true ) data.polygonOffset = true;
18188		if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
18189		if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
18190
18191		if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;
18192		if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
18193		if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
18194		if ( this.scale !== undefined ) data.scale = this.scale;
18195
18196		if ( this.dithering === true ) data.dithering = true;
18197
18198		if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
18199		if ( this.alphaHash === true ) data.alphaHash = true;
18200		if ( this.alphaToCoverage === true ) data.alphaToCoverage = true;
18201		if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;
18202		if ( this.forceSinglePass === true ) data.forceSinglePass = true;
18203
18204		if ( this.wireframe === true ) data.wireframe = true;
18205		if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
18206		if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
18207		if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
18208
18209		if ( this.flatShading === true ) data.flatShading = true;
18210
18211		if ( this.visible === false ) data.visible = false;
18212
18213		if ( this.toneMapped === false ) data.toneMapped = false;
18214
18215		if ( this.fog === false ) data.fog = false;
18216
18217		if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
18218
18219		// TODO: Copied from Object3D.toJSON
18220
18221		function extractFromCache( cache ) {
18222
18223			const values = [];
18224
18225			for ( const key in cache ) {
18226
18227				const data = cache[ key ];
18228				delete data.metadata;
18229				values.push( data );
18230
18231			}
18232
18233			return values;
18234
18235		}
18236
18237		if ( isRootObject ) {
18238
18239			const textures = extractFromCache( meta.textures );
18240			const images = extractFromCache( meta.images );
18241
18242			if ( textures.length > 0 ) data.textures = textures;
18243			if ( images.length > 0 ) data.images = images;
18244
18245		}
18246
18247		return data;
18248
18249	}
18250
18251	/**
18252	 * Returns a new material with copied values from this instance.
18253	 *
18254	 * @return {Material} A clone of this instance.
18255	 */
18256	clone() {
18257
18258		return new this.constructor().copy( this );
18259
18260	}
18261
18262	/**
18263	 * Copies the values of the given material to this instance.
18264	 *
18265	 * @param {Material} source - The material to copy.
18266	 * @return {Material} A reference to this instance.
18267	 */
18268	copy( source ) {
18269
18270		this.name = source.name;
18271
18272		this.blending = source.blending;
18273		this.side = source.side;
18274		this.vertexColors = source.vertexColors;
18275
18276		this.opacity = source.opacity;
18277		this.transparent = source.transparent;
18278
18279		this.blendSrc = source.blendSrc;
18280		this.blendDst = source.blendDst;
18281		this.blendEquation = source.blendEquation;
18282		this.blendSrcAlpha = source.blendSrcAlpha;
18283		this.blendDstAlpha = source.blendDstAlpha;
18284		this.blendEquationAlpha = source.blendEquationAlpha;
18285		this.blendColor.copy( source.blendColor );
18286		this.blendAlpha = source.blendAlpha;
18287
18288		this.depthFunc = source.depthFunc;
18289		this.depthTest = source.depthTest;
18290		this.depthWrite = source.depthWrite;
18291
18292		this.stencilWriteMask = source.stencilWriteMask;
18293		this.stencilFunc = source.stencilFunc;
18294		this.stencilRef = source.stencilRef;
18295		this.stencilFuncMask = source.stencilFuncMask;
18296		this.stencilFail = source.stencilFail;
18297		this.stencilZFail = source.stencilZFail;
18298		this.stencilZPass = source.stencilZPass;
18299		this.stencilWrite = source.stencilWrite;
18300
18301		const srcPlanes = source.clippingPlanes;
18302		let dstPlanes = null;
18303
18304		if ( srcPlanes !== null ) {
18305
18306			const n = srcPlanes.length;
18307			dstPlanes = new Array( n );
18308
18309			for ( let i = 0; i !== n; ++ i ) {
18310
18311				dstPlanes[ i ] = srcPlanes[ i ].clone();
18312
18313			}
18314
18315		}
18316
18317		this.clippingPlanes = dstPlanes;
18318		this.clipIntersection = source.clipIntersection;
18319		this.clipShadows = source.clipShadows;
18320
18321		this.shadowSide = source.shadowSide;
18322
18323		this.colorWrite = source.colorWrite;
18324
18325		this.precision = source.precision;
18326
18327		this.polygonOffset = source.polygonOffset;
18328		this.polygonOffsetFactor = source.polygonOffsetFactor;
18329		this.polygonOffsetUnits = source.polygonOffsetUnits;
18330
18331		this.dithering = source.dithering;
18332
18333		this.alphaTest = source.alphaTest;
18334		this.alphaHash = source.alphaHash;
18335		this.alphaToCoverage = source.alphaToCoverage;
18336		this.premultipliedAlpha = source.premultipliedAlpha;
18337		this.forceSinglePass = source.forceSinglePass;
18338
18339		this.visible = source.visible;
18340
18341		this.toneMapped = source.toneMapped;
18342
18343		this.userData = JSON.parse( JSON.stringify( source.userData ) );
18344
18345		return this;
18346
18347	}
18348
18349	/**
18350	 * Frees the GPU-related resources allocated by this instance. Call this
18351	 * method whenever this instance is no longer used in your app.
18352	 *
18353	 * @fires Material#dispose
18354	 */
18355	dispose() {
18356
18357		/**
18358		 * Fires when the material has been disposed of.
18359		 *
18360		 * @event Material#dispose
18361		 * @type {Object}
18362		 */
18363		this.dispatchEvent( { type: 'dispose' } );
18364
18365	}
18366
18367	/**
18368	 * Setting this property to `true` indicates the engine the material
18369	 * needs to be recompiled.
18370	 *
18371	 * @type {boolean}
18372	 * @default false
18373	 * @param {boolean} value
18374	 */
18375	set needsUpdate( value ) {
18376
18377		if ( value === true ) this.version ++;
18378
18379	}
18380
18381	onBuild( /* shaderobject, renderer */ ) {
18382
18383		console.warn( 'Material: onBuild() has been removed.' ); // @deprecated, r166
18384
18385	}
18386
18387}
18388
18389/**
18390 * A material for drawing geometries in a simple shaded (flat or wireframe) way.
18391 *
18392 * This material is not affected by lights.
18393 *
18394 * @augments Material
18395 */
18396class MeshBasicMaterial extends Material {
18397
18398	/**
18399	 * Constructs a new mesh basic material.
18400	 *
18401	 * @param {Object} [parameters] - An object with one or more properties
18402	 * defining the material's appearance. Any property of the material
18403	 * (including any property from inherited materials) can be passed
18404	 * in here. Color values can be passed any type of value accepted
18405	 * by {@link Color#set}.
18406	 */
18407	constructor( parameters ) {
18408
18409		super();
18410
18411		/**
18412		 * This flag can be used for type testing.
18413		 *
18414		 * @type {boolean}
18415		 * @readonly
18416		 * @default true
18417		 */
18418		this.isMeshBasicMaterial = true;
18419
18420		this.type = 'MeshBasicMaterial';
18421
18422		/**
18423		 * Color of the material.
18424		 *
18425		 * @type {Color}
18426		 * @default (1,1,1)
18427		 */
18428		this.color = new Color( 0xffffff ); // emissive
18429
18430		/**
18431		 * The color map. May optionally include an alpha channel, typically combined
18432		 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map
18433		 * color is modulated by the diffuse `color`.
18434		 *
18435		 * @type {?Texture}
18436		 * @default null
18437		 */
18438		this.map = null;
18439
18440		/**
18441		 * The light map. Requires a second set of UVs.
18442		 *
18443		 * @type {?Texture}
18444		 * @default null
18445		 */
18446		this.lightMap = null;
18447
18448		/**
18449		 * Intensity of the baked light.
18450		 *
18451		 * @type {number}
18452		 * @default 1
18453		 */
18454		this.lightMapIntensity = 1.0;
18455
18456		/**
18457		 * The red channel of this texture is used as the ambient occlusion map.
18458		 * Requires a second set of UVs.
18459		 *
18460		 * @type {?Texture}
18461		 * @default null
18462		 */
18463		this.aoMap = null;
18464
18465		/**
18466		 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0`
18467		 * disables ambient occlusion. Where intensity is `1` and the AO map's
18468		 * red channel is also `1`, ambient light is fully occluded on a surface.
18469		 *
18470		 * @type {number}
18471		 * @default 1
18472		 */
18473		this.aoMapIntensity = 1.0;
18474
18475		/**
18476		 * Specular map used by the material.
18477		 *
18478		 * @type {?Texture}
18479		 * @default null
18480		 */
18481		this.specularMap = null;
18482
18483		/**
18484		 * The alpha map is a grayscale texture that controls the opacity across the
18485		 * surface (black: fully transparent; white: fully opaque).
18486		 *
18487		 * Only the color of the texture is used, ignoring the alpha channel if one
18488		 * exists. For RGB and RGBA textures, the renderer will use the green channel
18489		 * when sampling this texture due to the extra bit of precision provided for
18490		 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and
18491		 * luminance/alpha textures will also still work as expected.
18492		 *
18493		 * @type {?Texture}
18494		 * @default null
18495		 */
18496		this.alphaMap = null;
18497
18498		/**
18499		 * The environment map.
18500		 *
18501		 * @type {?Texture}
18502		 * @default null
18503		 */
18504		this.envMap = null;
18505
18506		/**
18507		 * The rotation of the environment map in radians.
18508		 *
18509		 * @type {Euler}
18510		 * @default (0,0,0)
18511		 */
18512		this.envMapRotation = new Euler();
18513
18514		/**
18515		 * How to combine the result of the surface's color with the environment map, if any.
18516		 *
18517		 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to
18518		 * blend between the two colors.
18519		 *
18520		 * @type {(MultiplyOperation|MixOperation|AddOperation)}
18521		 * @default MultiplyOperation
18522		 */
18523		this.combine = MultiplyOperation;
18524
18525		/**
18526		 * How much the environment map affects the surface.
18527		 * The valid range is between `0` (no reflections) and `1` (full reflections).
18528		 *
18529		 * @type {number}
18530		 * @default 1
18531		 */
18532		this.reflectivity = 1;
18533
18534		/**
18535		 * The index of refraction (IOR) of air (approximately 1) divided by the
18536		 * index of refraction of the material. It is used with environment mapping
18537		 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}.
18538		 * The refraction ratio should not exceed `1`.
18539		 *
18540		 * @type {number}
18541		 * @default 0.98
18542		 */
18543		this.refractionRatio = 0.98;
18544
18545		/**
18546		 * Renders the geometry as a wireframe.
18547		 *
18548		 * @type {boolean}
18549		 * @default false
18550		 */
18551		this.wireframe = false;
vendor: 5,003 bytes, lines 18552-18737
18552
18553		/**
18554		 * Controls the thickness of the wireframe.
18555		 *
18556		 * Can only be used with {@link SVGRenderer}.
18557		 *
18558		 * @type {number}
18559		 * @default 1
18560		 */
18561		this.wireframeLinewidth = 1;
18562
18563		/**
18564		 * Defines appearance of wireframe ends.
18565		 *
18566		 * Can only be used with {@link SVGRenderer}.
18567		 *
18568		 * @type {('round'|'bevel'|'miter')}
18569		 * @default 'round'
18570		 */
18571		this.wireframeLinecap = 'round';
18572
18573		/**
18574		 * Defines appearance of wireframe joints.
18575		 *
18576		 * Can only be used with {@link SVGRenderer}.
18577		 *
18578		 * @type {('round'|'bevel'|'miter')}
18579		 * @default 'round'
18580		 */
18581		this.wireframeLinejoin = 'round';
18582
18583		/**
18584		 * Whether the material is affected by fog or not.
18585		 *
18586		 * @type {boolean}
18587		 * @default true
18588		 */
18589		this.fog = true;
18590
18591		this.setValues( parameters );
18592
18593	}
18594
18595	copy( source ) {
18596
18597		super.copy( source );
18598
18599		this.color.copy( source.color );
18600
18601		this.map = source.map;
18602
18603		this.lightMap = source.lightMap;
18604		this.lightMapIntensity = source.lightMapIntensity;
18605
18606		this.aoMap = source.aoMap;
18607		this.aoMapIntensity = source.aoMapIntensity;
18608
18609		this.specularMap = source.specularMap;
18610
18611		this.alphaMap = source.alphaMap;
18612
18613		this.envMap = source.envMap;
18614		this.envMapRotation.copy( source.envMapRotation );
18615		this.combine = source.combine;
18616		this.reflectivity = source.reflectivity;
18617		this.refractionRatio = source.refractionRatio;
18618
18619		this.wireframe = source.wireframe;
18620		this.wireframeLinewidth = source.wireframeLinewidth;
18621		this.wireframeLinecap = source.wireframeLinecap;
18622		this.wireframeLinejoin = source.wireframeLinejoin;
18623
18624		this.fog = source.fog;
18625
18626		return this;
18627
18628	}
18629
18630}
18631
18632const _vector$9 = /*@__PURE__*/ new Vector3();
18633const _vector2$1 = /*@__PURE__*/ new Vector2();
18634
18635let _id$2 = 0;
18636
18637/**
18638 * This class stores data for an attribute (such as vertex positions, face
18639 * indices, normals, colors, UVs, and any custom attributes ) associated with
18640 * a geometry, which allows for more efficient passing of data to the GPU.
18641 *
18642 * When working with vector-like data, the `fromBufferAttribute( attribute, index )`
18643 * helper methods on vector and color class might be helpful. E.g. {@link Vector3#fromBufferAttribute}.
18644 */
18645class BufferAttribute {
18646
18647	/**
18648	 * Constructs a new buffer attribute.
18649	 *
18650	 * @param {TypedArray} array - The array holding the attribute data.
18651	 * @param {number} itemSize - The item size.
18652	 * @param {boolean} [normalized=false] - Whether the data are normalized or not.
18653	 */
18654	constructor( array, itemSize, normalized = false ) {
18655
18656		if ( Array.isArray( array ) ) {
18657
18658			throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
18659
18660		}
18661
18662		/**
18663		 * This flag can be used for type testing.
18664		 *
18665		 * @type {boolean}
18666		 * @readonly
18667		 * @default true
18668		 */
18669		this.isBufferAttribute = true;
18670
18671		/**
18672		 * The ID of the buffer attribute.
18673		 *
18674		 * @name BufferAttribute#id
18675		 * @type {number}
18676		 * @readonly
18677		 */
18678		Object.defineProperty( this, 'id', { value: _id$2 ++ } );
18679
18680		/**
18681		 * The name of the buffer attribute.
18682		 *
18683		 * @type {string}
18684		 */
18685		this.name = '';
18686
18687		/**
18688		 * The array holding the attribute data. It should have `itemSize * numVertices`
18689		 * elements, where `numVertices` is the number of vertices in the associated geometry.
18690		 *
18691		 * @type {TypedArray}
18692		 */
18693		this.array = array;
18694
18695		/**
18696		 * The number of values of the array that should be associated with a particular vertex.
18697		 * For instance, if this attribute is storing a 3-component vector (such as a position,
18698		 * normal, or color), then the value should be `3`.
18699		 *
18700		 * @type {number}
18701		 */
18702		this.itemSize = itemSize;
18703
18704		/**
18705		 * Represents the number of items this buffer attribute stores. It is internally computed
18706		 * by dividing the `array` length by the `itemSize`.
18707		 *
18708		 * @type {number}
18709		 * @readonly
18710		 */
18711		this.count = array !== undefined ? array.length / itemSize : 0;
18712
18713		/**
18714		 * Applies to integer data only. Indicates how the underlying data in the buffer maps to
18715		 * the values in the GLSL code. For instance, if `array` is an instance of `UInt16Array`,
18716		 * and `normalized` is `true`, the values `0 -+65535` in the array data will be mapped to
18717		 * `0.0f - +1.0f` in the GLSL attribute. If `normalized` is `false`, the values will be converted
18718		 * to floats unmodified, i.e. `65535` becomes `65535.0f`.
18719		 *
18720		 * @type {boolean}
18721		 */
18722		this.normalized = normalized;
18723
18724		/**
18725		 * Defines the intended usage pattern of the data store for optimization purposes.
18726		 *
18727		 * Note: After the initial use of a buffer, its usage cannot be changed. Instead,
18728		 * instantiate a new one and set the desired usage before the next render.
18729		 *
18730		 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)}
18731		 * @default StaticDrawUsage
18732		 */
18733		this.usage = StaticDrawUsage;
18734
18735		/**
18736		 * This can be used to only update some components of stored vectors (for example, just the
18737		 * component related to color). Use the `addUpdateRange()` function to add ranges to this array.
vendor: 8,896 bytes, lines 18738-19133
18738		 *
18739		 * @type {Array<Object>}
18740		 */
18741		this.updateRanges = [];
18742
18743		/**
18744		 * Configures the bound GPU type for use in shaders.
18745		 *
18746		 * Note: this only has an effect for integer arrays and is not configurable for float arrays.
18747		 * For lower precision float types, use `Float16BufferAttribute`.
18748		 *
18749		 * @type {(FloatType|IntType)}
18750		 * @default FloatType
18751		 */
18752		this.gpuType = FloatType;
18753
18754		/**
18755		 * A version number, incremented every time the `needsUpdate` is set to `true`.
18756		 *
18757		 * @type {number}
18758		 */
18759		this.version = 0;
18760
18761	}
18762
18763	/**
18764	 * A callback function that is executed after the renderer has transferred the attribute
18765	 * array data to the GPU.
18766	 */
18767	onUploadCallback() {}
18768
18769	/**
18770	 * Flag to indicate that this attribute has changed and should be re-sent to
18771	 * the GPU. Set this to `true` when you modify the value of the array.
18772	 *
18773	 * @type {number}
18774	 * @default false
18775	 * @param {boolean} value
18776	 */
18777	set needsUpdate( value ) {
18778
18779		if ( value === true ) this.version ++;
18780
18781	}
18782
18783	/**
18784	 * Sets the usage of this buffer attribute.
18785	 *
18786	 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set.
18787	 * @return {BufferAttribute} A reference to this buffer attribute.
18788	 */
18789	setUsage( value ) {
18790
18791		this.usage = value;
18792
18793		return this;
18794
18795	}
18796
18797	/**
18798	 * Adds a range of data in the data array to be updated on the GPU.
18799	 *
18800	 * @param {number} start - Position at which to start update.
18801	 * @param {number} count - The number of components to update.
18802	 */
18803	addUpdateRange( start, count ) {
18804
18805		this.updateRanges.push( { start, count } );
18806
18807	}
18808
18809	/**
18810	 * Clears the update ranges.
18811	 */
18812	clearUpdateRanges() {
18813
18814		this.updateRanges.length = 0;
18815
18816	}
18817
18818	/**
18819	 * Copies the values of the given buffer attribute to this instance.
18820	 *
18821	 * @param {BufferAttribute} source - The buffer attribute to copy.
18822	 * @return {BufferAttribute} A reference to this instance.
18823	 */
18824	copy( source ) {
18825
18826		this.name = source.name;
18827		this.array = new source.array.constructor( source.array );
18828		this.itemSize = source.itemSize;
18829		this.count = source.count;
18830		this.normalized = source.normalized;
18831
18832		this.usage = source.usage;
18833		this.gpuType = source.gpuType;
18834
18835		return this;
18836
18837	}
18838
18839	/**
18840	 * Copies a vector from the given buffer attribute to this one. The start
18841	 * and destination position in the attribute buffers are represented by the
18842	 * given indices.
18843	 *
18844	 * @param {number} index1 - The destination index into this buffer attribute.
18845	 * @param {BufferAttribute} attribute - The buffer attribute to copy from.
18846	 * @param {number} index2 - The source index into the given buffer attribute.
18847	 * @return {BufferAttribute} A reference to this instance.
18848	 */
18849	copyAt( index1, attribute, index2 ) {
18850
18851		index1 *= this.itemSize;
18852		index2 *= attribute.itemSize;
18853
18854		for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
18855
18856			this.array[ index1 + i ] = attribute.array[ index2 + i ];
18857
18858		}
18859
18860		return this;
18861
18862	}
18863
18864	/**
18865	 * Copies the given array data into this buffer attribute.
18866	 *
18867	 * @param {(TypedArray|Array)} array - The array to copy.
18868	 * @return {BufferAttribute} A reference to this instance.
18869	 */
18870	copyArray( array ) {
18871
18872		this.array.set( array );
18873
18874		return this;
18875
18876	}
18877
18878	/**
18879	 * Applies the given 3x3 matrix to the given attribute. Works with
18880	 * item size `2` and `3`.
18881	 *
18882	 * @param {Matrix3} m - The matrix to apply.
18883	 * @return {BufferAttribute} A reference to this instance.
18884	 */
18885	applyMatrix3( m ) {
18886
18887		if ( this.itemSize === 2 ) {
18888
18889			for ( let i = 0, l = this.count; i < l; i ++ ) {
18890
18891				_vector2$1.fromBufferAttribute( this, i );
18892				_vector2$1.applyMatrix3( m );
18893
18894				this.setXY( i, _vector2$1.x, _vector2$1.y );
18895
18896			}
18897
18898		} else if ( this.itemSize === 3 ) {
18899
18900			for ( let i = 0, l = this.count; i < l; i ++ ) {
18901
18902				_vector$9.fromBufferAttribute( this, i );
18903				_vector$9.applyMatrix3( m );
18904
18905				this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
18906
18907			}
18908
18909		}
18910
18911		return this;
18912
18913	}
18914
18915	/**
18916	 * Applies the given 4x4 matrix to the given attribute. Only works with
18917	 * item size `3`.
18918	 *
18919	 * @param {Matrix4} m - The matrix to apply.
18920	 * @return {BufferAttribute} A reference to this instance.
18921	 */
18922	applyMatrix4( m ) {
18923
18924		for ( let i = 0, l = this.count; i < l; i ++ ) {
18925
18926			_vector$9.fromBufferAttribute( this, i );
18927
18928			_vector$9.applyMatrix4( m );
18929
18930			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
18931
18932		}
18933
18934		return this;
18935
18936	}
18937
18938	/**
18939	 * Applies the given 3x3 normal matrix to the given attribute. Only works with
18940	 * item size `3`.
18941	 *
18942	 * @param {Matrix3} m - The normal matrix to apply.
18943	 * @return {BufferAttribute} A reference to this instance.
18944	 */
18945	applyNormalMatrix( m ) {
18946
18947		for ( let i = 0, l = this.count; i < l; i ++ ) {
18948
18949			_vector$9.fromBufferAttribute( this, i );
18950
18951			_vector$9.applyNormalMatrix( m );
18952
18953			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
18954
18955		}
18956
18957		return this;
18958
18959	}
18960
18961	/**
18962	 * Applies the given 4x4 matrix to the given attribute. Only works with
18963	 * item size `3` and with direction vectors.
18964	 *
18965	 * @param {Matrix4} m - The matrix to apply.
18966	 * @return {BufferAttribute} A reference to this instance.
18967	 */
18968	transformDirection( m ) {
18969
18970		for ( let i = 0, l = this.count; i < l; i ++ ) {
18971
18972			_vector$9.fromBufferAttribute( this, i );
18973
18974			_vector$9.transformDirection( m );
18975
18976			this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
18977
18978		}
18979
18980		return this;
18981
18982	}
18983
18984	/**
18985	 * Sets the given array data in the buffer attribute.
18986	 *
18987	 * @param {(TypedArray|Array)} value - The array data to set.
18988	 * @param {number} [offset=0] - The offset in this buffer attribute's array.
18989	 * @return {BufferAttribute} A reference to this instance.
18990	 */
18991	set( value, offset = 0 ) {
18992
18993		// Matching BufferAttribute constructor, do not normalize the array.
18994		this.array.set( value, offset );
18995
18996		return this;
18997
18998	}
18999
19000	/**
19001	 * Returns the given component of the vector at the given index.
19002	 *
19003	 * @param {number} index - The index into the buffer attribute.
19004	 * @param {number} component - The component index.
19005	 * @return {number} The returned value.
19006	 */
19007	getComponent( index, component ) {
19008
19009		let value = this.array[ index * this.itemSize + component ];
19010
19011		if ( this.normalized ) value = denormalize( value, this.array );
19012
19013		return value;
19014
19015	}
19016
19017	/**
19018	 * Sets the given value to the given component of the vector at the given index.
19019	 *
19020	 * @param {number} index - The index into the buffer attribute.
19021	 * @param {number} component - The component index.
19022	 * @param {number} value - The value to set.
19023	 * @return {BufferAttribute} A reference to this instance.
19024	 */
19025	setComponent( index, component, value ) {
19026
19027		if ( this.normalized ) value = normalize( value, this.array );
19028
19029		this.array[ index * this.itemSize + component ] = value;
19030
19031		return this;
19032
19033	}
19034
19035	/**
19036	 * Returns the x component of the vector at the given index.
19037	 *
19038	 * @param {number} index - The index into the buffer attribute.
19039	 * @return {number} The x component.
19040	 */
19041	getX( index ) {
19042
19043		let x = this.array[ index * this.itemSize ];
19044
19045		if ( this.normalized ) x = denormalize( x, this.array );
19046
19047		return x;
19048
19049	}
19050
19051	/**
19052	 * Sets the x component of the vector at the given index.
19053	 *
19054	 * @param {number} index - The index into the buffer attribute.
19055	 * @param {number} x - The value to set.
19056	 * @return {BufferAttribute} A reference to this instance.
19057	 */
19058	setX( index, x ) {
19059
19060		if ( this.normalized ) x = normalize( x, this.array );
19061
19062		this.array[ index * this.itemSize ] = x;
19063
19064		return this;
19065
19066	}
19067
19068	/**
19069	 * Returns the y component of the vector at the given index.
19070	 *
19071	 * @param {number} index - The index into the buffer attribute.
19072	 * @return {number} The y component.
19073	 */
19074	getY( index ) {
19075
19076		let y = this.array[ index * this.itemSize + 1 ];
19077
19078		if ( this.normalized ) y = denormalize( y, this.array );
19079
19080		return y;
19081
19082	}
19083
19084	/**
19085	 * Sets the y component of the vector at the given index.
19086	 *
19087	 * @param {number} index - The index into the buffer attribute.
19088	 * @param {number} y - The value to set.
19089	 * @return {BufferAttribute} A reference to this instance.
19090	 */
19091	setY( index, y ) {
19092
19093		if ( this.normalized ) y = normalize( y, this.array );
19094
19095		this.array[ index * this.itemSize + 1 ] = y;
19096
19097		return this;
19098
19099	}
19100
19101	/**
19102	 * Returns the z component of the vector at the given index.
19103	 *
19104	 * @param {number} index - The index into the buffer attribute.
19105	 * @return {number} The z component.
19106	 */
19107	getZ( index ) {
19108
19109		let z = this.array[ index * this.itemSize + 2 ];
19110
19111		if ( this.normalized ) z = denormalize( z, this.array );
19112
19113		return z;
19114
19115	}
19116
19117	/**
19118	 * Sets the z component of the vector at the given index.
19119	 *
19120	 * @param {number} index - The index into the buffer attribute.
19121	 * @param {number} z - The value to set.
19122	 * @return {BufferAttribute} A reference to this instance.
19123	 */
19124	setZ( index, z ) {
19125
19126		if ( this.normalized ) z = normalize( z, this.array );
19127
19128		this.array[ index * this.itemSize + 2 ] = z;
19129
19130		return this;
19131
19132	}
19133
vendor: 5,998 bytes, lines 19134-19380
19134	/**
19135	 * Returns the w component of the vector at the given index.
19136	 *
19137	 * @param {number} index - The index into the buffer attribute.
19138	 * @return {number} The w component.
19139	 */
19140	getW( index ) {
19141
19142		let w = this.array[ index * this.itemSize + 3 ];
19143
19144		if ( this.normalized ) w = denormalize( w, this.array );
19145
19146		return w;
19147
19148	}
19149
19150	/**
19151	 * Sets the w component of the vector at the given index.
19152	 *
19153	 * @param {number} index - The index into the buffer attribute.
19154	 * @param {number} w - The value to set.
19155	 * @return {BufferAttribute} A reference to this instance.
19156	 */
19157	setW( index, w ) {
19158
19159		if ( this.normalized ) w = normalize( w, this.array );
19160
19161		this.array[ index * this.itemSize + 3 ] = w;
19162
19163		return this;
19164
19165	}
19166
19167	/**
19168	 * Sets the x and y component of the vector at the given index.
19169	 *
19170	 * @param {number} index - The index into the buffer attribute.
19171	 * @param {number} x - The value for the x component to set.
19172	 * @param {number} y - The value for the y component to set.
19173	 * @return {BufferAttribute} A reference to this instance.
19174	 */
19175	setXY( index, x, y ) {
19176
19177		index *= this.itemSize;
19178
19179		if ( this.normalized ) {
19180
19181			x = normalize( x, this.array );
19182			y = normalize( y, this.array );
19183
19184		}
19185
19186		this.array[ index + 0 ] = x;
19187		this.array[ index + 1 ] = y;
19188
19189		return this;
19190
19191	}
19192
19193	/**
19194	 * Sets the x, y and z component of the vector at the given index.
19195	 *
19196	 * @param {number} index - The index into the buffer attribute.
19197	 * @param {number} x - The value for the x component to set.
19198	 * @param {number} y - The value for the y component to set.
19199	 * @param {number} z - The value for the z component to set.
19200	 * @return {BufferAttribute} A reference to this instance.
19201	 */
19202	setXYZ( index, x, y, z ) {
19203
19204		index *= this.itemSize;
19205
19206		if ( this.normalized ) {
19207
19208			x = normalize( x, this.array );
19209			y = normalize( y, this.array );
19210			z = normalize( z, this.array );
19211
19212		}
19213
19214		this.array[ index + 0 ] = x;
19215		this.array[ index + 1 ] = y;
19216		this.array[ index + 2 ] = z;
19217
19218		return this;
19219
19220	}
19221
19222	/**
19223	 * Sets the x, y, z and w component of the vector at the given index.
19224	 *
19225	 * @param {number} index - The index into the buffer attribute.
19226	 * @param {number} x - The value for the x component to set.
19227	 * @param {number} y - The value for the y component to set.
19228	 * @param {number} z - The value for the z component to set.
19229	 * @param {number} w - The value for the w component to set.
19230	 * @return {BufferAttribute} A reference to this instance.
19231	 */
19232	setXYZW( index, x, y, z, w ) {
19233
19234		index *= this.itemSize;
19235
19236		if ( this.normalized ) {
19237
19238			x = normalize( x, this.array );
19239			y = normalize( y, this.array );
19240			z = normalize( z, this.array );
19241			w = normalize( w, this.array );
19242
19243		}
19244
19245		this.array[ index + 0 ] = x;
19246		this.array[ index + 1 ] = y;
19247		this.array[ index + 2 ] = z;
19248		this.array[ index + 3 ] = w;
19249
19250		return this;
19251
19252	}
19253
19254	/**
19255	 * Sets the given callback function that is executed after the Renderer has transferred
19256	 * the attribute array data to the GPU. Can be used to perform clean-up operations after
19257	 * the upload when attribute data are not needed anymore on the CPU side.
19258	 *
19259	 * @param {Function} callback - The `onUpload()` callback.
19260	 * @return {BufferAttribute} A reference to this instance.
19261	 */
19262	onUpload( callback ) {
19263
19264		this.onUploadCallback = callback;
19265
19266		return this;
19267
19268	}
19269
19270	/**
19271	 * Returns a new buffer attribute with copied values from this instance.
19272	 *
19273	 * @return {BufferAttribute} A clone of this instance.
19274	 */
19275	clone() {
19276
19277		return new this.constructor( this.array, this.itemSize ).copy( this );
19278
19279	}
19280
19281	/**
19282	 * Serializes the buffer attribute into JSON.
19283	 *
19284	 * @return {Object} A JSON object representing the serialized buffer attribute.
19285	 */
19286	toJSON() {
19287
19288		const data = {
19289			itemSize: this.itemSize,
19290			type: this.array.constructor.name,
19291			array: Array.from( this.array ),
19292			normalized: this.normalized
19293		};
19294
19295		if ( this.name !== '' ) data.name = this.name;
19296		if ( this.usage !== StaticDrawUsage ) data.usage = this.usage;
19297
19298		return data;
19299
19300	}
19301
19302}
19303
19304/**
19305 * Convenient class that can be used when creating a `UInt16` buffer attribute with
19306 * a plain `Array` instance.
19307 *
19308 * @augments BufferAttribute
19309 */
19310class Uint16BufferAttribute extends BufferAttribute {
19311
19312	/**
19313	 * Constructs a new buffer attribute.
19314	 *
19315	 * @param {(Array<number>|Uint16Array)} array - The array holding the attribute data.
19316	 * @param {number} itemSize - The item size.
19317	 * @param {boolean} [normalized=false] - Whether the data are normalized or not.
19318	 */
19319	constructor( array, itemSize, normalized ) {
19320
19321		super( new Uint16Array( array ), itemSize, normalized );
19322
19323	}
19324
19325}
19326
19327/**
19328 * Convenient class that can be used when creating a `UInt32` buffer attribute with
19329 * a plain `Array` instance.
19330 *
19331 * @augments BufferAttribute
19332 */
19333class Uint32BufferAttribute extends BufferAttribute {
19334
19335	/**
19336	 * Constructs a new buffer attribute.
19337	 *
19338	 * @param {(Array<number>|Uint32Array)} array - The array holding the attribute data.
19339	 * @param {number} itemSize - The item size.
19340	 * @param {boolean} [normalized=false] - Whether the data are normalized or not.
19341	 */
19342	constructor( array, itemSize, normalized ) {
19343
19344		super( new Uint32Array( array ), itemSize, normalized );
19345
19346	}
19347
19348}
19349
19350/**
19351 * Convenient class that can be used when creating a `Float32` buffer attribute with
19352 * a plain `Array` instance.
19353 *
19354 * @augments BufferAttribute
19355 */
19356class Float32BufferAttribute extends BufferAttribute {
19357
19358	/**
19359	 * Constructs a new buffer attribute.
19360	 *
19361	 * @param {(Array<number>|Float32Array)} array - The array holding the attribute data.
19362	 * @param {number} itemSize - The item size.
19363	 * @param {boolean} [normalized=false] - Whether the data are normalized or not.
19364	 */
19365	constructor( array, itemSize, normalized ) {
19366
19367		super( new Float32Array( array ), itemSize, normalized );
19368
19369	}
19370
19371}
19372
19373let _id$1 = 0;
19374
19375const _m1 = /*@__PURE__*/ new Matrix4();
19376const _obj = /*@__PURE__*/ new Object3D();
19377const _offset = /*@__PURE__*/ new Vector3();
19378const _box$2 = /*@__PURE__*/ new Box3();
19379const _boxMorphTargets = /*@__PURE__*/ new Box3();
19380const _vector$8
vendor: 2,454 bytes, lines 19380-19475
19380 = /*@__PURE__*/ new Vector3();
19381
19382/**
19383 * A representation of mesh, line, or point geometry. Includes vertex
19384 * positions, face indices, normals, colors, UVs, and custom attributes
19385 * within buffers, reducing the cost of passing all this data to the GPU.
19386 *
19387 * ```js
19388 * const geometry = new THREE.BufferGeometry();
19389 * // create a simple square shape. We duplicate the top left and bottom right
19390 * // vertices because each vertex needs to appear once per triangle.
19391 * const vertices = new Float32Array( [
19392 * 	-1.0, -1.0,  1.0, // v0
19393 * 	 1.0, -1.0,  1.0, // v1
19394 * 	 1.0,  1.0,  1.0, // v2
19395 *
19396 * 	 1.0,  1.0,  1.0, // v3
19397 * 	-1.0,  1.0,  1.0, // v4
19398 * 	-1.0, -1.0,  1.0  // v5
19399 * ] );
19400 * // itemSize = 3 because there are 3 values (components) per vertex
19401 * geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
19402 * const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
19403 * const mesh = new THREE.Mesh( geometry, material );
19404 * ```
19405 *
19406 * @augments EventDispatcher
19407 */
19408class BufferGeometry extends EventDispatcher {
19409
19410	/**
19411	 * Constructs a new geometry.
19412	 */
19413	constructor() {
19414
19415		super();
19416
19417		/**
19418		 * This flag can be used for type testing.
19419		 *
19420		 * @type {boolean}
19421		 * @readonly
19422		 * @default true
19423		 */
19424		this.isBufferGeometry = true;
19425
19426		/**
19427		 * The ID of the geometry.
19428		 *
19429		 * @name BufferGeometry#id
19430		 * @type {number}
19431		 * @readonly
19432		 */
19433		Object.defineProperty( this, 'id', { value: _id$1 ++ } );
19434
19435		/**
19436		 * The UUID of the geometry.
19437		 *
19438		 * @type {string}
19439		 * @readonly
19440		 */
19441		this.uuid = generateUUID();
19442
19443		/**
19444		 * The name of the geometry.
19445		 *
19446		 * @type {string}
19447		 */
19448		this.name = '';
19449		this.type = 'BufferGeometry';
19450
19451		/**
19452		 * Allows for vertices to be re-used across multiple triangles; this is
19453		 * called using "indexed triangles". Each triangle is associated with the
19454		 * indices of three vertices. This attribute therefore stores the index of
19455		 * each vertex for each triangular face. If this attribute is not set, the
19456		 * renderer assumes that each three contiguous positions represent a single triangle.
19457		 *
19458		 * @type {?BufferAttribute}
19459		 * @default null
19460		 */
19461		this.index = null;
19462
19463		/**
19464		 * A (storage) buffer attribute which was generated with a compute shader and
19465		 * now defines indirect draw calls.
19466		 *
19467		 * Can only be used with {@link WebGPURenderer} and a WebGPU backend.
19468		 *
19469		 * @type {?BufferAttribute}
19470		 * @default null
19471		 */
19472		this.indirect = null;
19473
19474		/**
19475		 * Th
19475is dictionary has as id the name of the attribute to be set and as value
19476		 * the buffer attribute to set it to. Rather than accessing this property directly,
19477		 * use `setAttribute()` and `getAttribute()` to access attributes of this geometry.
19478		 *
19479		 * @type {Object<string,(BufferAttribute|InterleavedBufferAttribute)>}
19480		 */
19481		this.attributes = {};
19482
19483		/**
19484		 * This dictionary holds the morph targets of the geometry.
19485		 *
19486		 * Note: Once the geometry has been rendered, the morph attribute data cannot
19487		 * be changed. You will have to call `dispose()?, and create a new geometry instance.
19488		 *
19489		 * @type {Object}
19490		 */
19491		this.morphAttributes = {};
19492
19493		/**
19494		 * Used to control the morph target behavior; when set to `true`, the morph
19495		 * target data is treated as relative offsets, rather than as absolute
19496		 * positions/normals.
19497		 *
19498		 * @type {boolean}
19499		 * @default false
19500		 */
19501		this.morphTargetsRelative = false;
19502
19503		/**
19504		 * Split the geometry into groups, each of which will be rendered in a
19505		 * separate draw call. This allows an array of materials to be used with the geometry.
19506		 *
19507		 * Use `addGroup()` and `clearGroups()` to edit groups, rather than modifying this array directly.
19508		 *
19509		 * Every vertex and index must belong to exactly one group — groups must not share vertices or
19510		 * indices, and must not leave vertices or indices unused.
19511		 *
19512		 * @type {Array<Object>}
19513		 */
19514		this.groups = [];
19515
19516		/**
19517		 * Bounding box for the geometry which can be calculated with `computeBoundingBox()`.
19518		 *
19519		 * @type {Box3}
19520		 * @default null
19521		 */
19522		this.boundingBox = null;
19523
19524		/**
19525		 * Bounding sphere for the geometry which can be calculated with `computeBoundingSphere()`.
19526		 *
19527		 * @type {Sphere}
19528		 * @default null
19529		 */
19530		this.boundingSphere = null;
19531
19532		/**
19533		 * Determines the part of the geometry to render. This should not be set directly,
19534		 * instead use `setDrawRange()`.
19535		 *
19536		 * @type {{start:number,count:number}}
19537		 */
19538		this.drawRange = { start: 0, count: Infinity };
19539
19540		/**
19541		 * An object that can be used to store custom data about the geometry.
19542		 * It should not hold references to functions as these will not be cloned.
19543		 *
19544		 * @type {Object}
19545		 */
19546		this.userData = {};
19547
19548	}
19549
19550	/**
19551	 * Returns the index of this geometry.
19552	 *
19553	 * @return {?BufferAttribute} The index. Returns `null` if no index is defined.
19554	 */
19555	getIndex() {
19556
19557		return this.index;
19558
19559	}
19560
19561	/**
19562	 * Sets the given index to this geometry.
19563	 *
19564	 * @param {Array<number>|BufferAttribute} index - The index to set.
19565	 * @return {BufferGeometry} A reference to this instance.
19566	 */
19567	setIndex( index ) {
19568
19569		if ( Array.isArray( index ) ) {
19570
19571			this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
19572
19573		} else {
19574
19575			this.index = index;
19576
19577		}
19578
19579		return this;
19580
19581	}
19582
19583	/**
19584	 * Sets the given indirect attribute to this geometry.
19585	 *
19586	 * @param {BufferAttribute} indirect - The attribute holding indirect draw calls.
19587	 * @return {BufferGeometry} A reference to this instance.
19588	 */
19589	setIndirect( indirect ) {
19590
19591		this.indirect = indirec
vendor: 3,681 bytes, lines 19591-19769
19591t;
19592
19593		return this;
19594
19595	}
19596
19597	/**
19598	 * Returns the indirect attribute of this geometry.
19599	 *
19600	 * @return {?BufferAttribute} The indirect attribute. Returns `null` if no indirect attribute is defined.
19601	 */
19602	getIndirect() {
19603
19604		return this.indirect;
19605
19606	}
19607
19608	/**
19609	 * Returns the buffer attribute for the given name.
19610	 *
19611	 * @param {string} name - The attribute name.
19612	 * @return {BufferAttribute|InterleavedBufferAttribute|undefined} The buffer attribute.
19613	 * Returns `undefined` if not attribute has been found.
19614	 */
19615	getAttribute( name ) {
19616
19617		return this.attributes[ name ];
19618
19619	}
19620
19621	/**
19622	 * Sets the given attribute for the given name.
19623	 *
19624	 * @param {string} name - The attribute name.
19625	 * @param {BufferAttribute|InterleavedBufferAttribute} attribute - The attribute to set.
19626	 * @return {BufferGeometry} A reference to this instance.
19627	 */
19628	setAttribute( name, attribute ) {
19629
19630		this.attributes[ name ] = attribute;
19631
19632		return this;
19633
19634	}
19635
19636	/**
19637	 * Deletes the attribute for the given name.
19638	 *
19639	 * @param {string} name - The attribute name to delete.
19640	 * @return {BufferGeometry} A reference to this instance.
19641	 */
19642	deleteAttribute( name ) {
19643
19644		delete this.attributes[ name ];
19645
19646		return this;
19647
19648	}
19649
19650	/**
19651	 * Returns `true` if this geometry has an attribute for the given name.
19652	 *
19653	 * @param {string} name - The attribute name.
19654	 * @return {boolean} Whether this geometry has an attribute for the given name or not.
19655	 */
19656	hasAttribute( name ) {
19657
19658		return this.attributes[ name ] !== undefined;
19659
19660	}
19661
19662	/**
19663	 * Adds a group to this geometry.
19664	 *
19665	 * @param {number} start - The first element in this draw call. That is the first
19666	 * vertex for non-indexed geometry, otherwise the first triangle index.
19667	 * @param {number} count - Specifies how many vertices (or indices) are part of this group.
19668	 * @param {number} [materialIndex=0] - The material array index to use.
19669	 */
19670	addGroup( start, count, materialIndex = 0 ) {
19671
19672		this.groups.push( {
19673
19674			start: start,
19675			count: count,
19676			materialIndex: materialIndex
19677
19678		} );
19679
19680	}
19681
19682	/**
19683	 * Clears all groups.
19684	 */
19685	clearGroups() {
19686
19687		this.groups = [];
19688
19689	}
19690
19691	/**
19692	 * Sets the draw range for this geometry.
19693	 *
19694	 * @param {number} start - The first vertex for non-indexed geometry, otherwise the first triangle index.
19695	 * @param {number} count - For non-indexed BufferGeometry, `count` is the number of vertices to render.
19696	 * For indexed BufferGeometry, `count` is the number of indices to render.
19697	 */
19698	setDrawRange( start, count ) {
19699
19700		this.drawRange.start = start;
19701		this.drawRange.count = count;
19702
19703	}
19704
19705	/**
19706	 * Applies the given 4x4 transformation matrix to the geometry.
19707	 *
19708	 * @param {Matrix4} matrix - The matrix to apply.
19709	 * @return {BufferGeometry} A reference to this instance.
19710	 */
19711	applyMatrix4( matrix ) {
19712
19713		const position = this.attributes.position;
19714
19715		if ( position !== undefined ) {
19716
19717			position.applyMatrix4( matrix );
19718
19719			position.needsUpdate = true;
19720
19721		}
19722
19723		const normal = this.attributes.normal;
19724
19725		if ( normal !== undefined ) {
19726
19727			const normalMatrix = new Matrix3().getNormalMatrix( matrix );
19728
19729			normal.applyNormalMatrix( normalMatrix );
19730
19731			normal.needsUpdate = true;
19732
19733		}
19734
19735		const tangent = this.attributes.tangent;
19736
19737		if ( tangent !== undefined ) {
19738
19739			tangent.transformDirection( matrix );
19740
19741			tangent.needsUpdate = true;
19742
19743		}
19744
19745		if ( this.boundingBox !== null ) {
19746
19747			this.computeBoundingBox();
19748
19749		}
19750
19751		if ( this.boundingSphere !== null ) {
19752
19753			this.computeBoundingSphere();
19754
19755		}
19756
19757		return this;
19758
19759	}
19760
19761	/**
19762	 * Applies the rotation represented by the Quaternion to the geometry.
19763	 *
19764	 * @param {Quaternion} q - The Quaternion to apply.
19765	 * @return {BufferGeometry} A reference to this instance.
19766	 */
19767	applyQuaternion( q ) {
19768
19769		_m1
19769.makeRotationFromQuaternion( q );
19770
19771		this.applyMatrix4( _m1 );
19772
19773		return this;
19774
19775	}
19776
19777	/**
19778	 * Rotates the geometry about the X axis. This is typically done as a one time
19779	 * operation, and not during a loop. Use {@link Object3D#rotation} for typical
19780	 * real-time mesh rotation.
19781	 *
19782	 * @param {number} angle - The angle in radians.
19783	 * @return {BufferGeometry} A reference to this instance.
19784	 */
19785	rotateX( angle ) {
19786
19787		// rotate geometry around world x-axis
19788
19789		_m1.makeRotationX( angle );
19790
19791		this.applyMatrix4( _m1 );
19792
19793		return this;
19794
19795	}
19796
19797	/**
19798	 * Rotates the geometry about the Y axis. This is typically done as a one time
19799	 * operation, and not during a loop. Use {@link Object3D#rotation} for typical
19800	 * real-time mesh rotation.
19801	 *
19802	 * @param {number} angle - The angle in radians.
19803	 * @return {BufferGeometry} A reference to this instance.
19804	 */
19805	rotateY( angle ) {
19806
19807		// rotate geometry around world y-axis
19808
19809		_m1.makeRotationY( angle );
19810
19811		this.applyMatrix4( _m1 );
19812
19813		return this;
19814
19815	}
19816
19817	/**
19818	 * Rotates the geometry about the Z axis. This is typically done as a one time
19819	 * operation, and not during a loop. Use {@link Object3D#rotation} for typical
19820	 * real-time mesh rotation.
19821	 *
19822	 * @param {number} angle - The angle in radians.
19823	 * @return {BufferGeometry} A reference to this instance.
19824	 */
19825	rotateZ( angle ) {
19826
19827		// rotate geometry around world z-axis
19828
19829		_m1.makeRotationZ( angle );
19830
19831		this.applyMatrix4( _m1 );
19832
19833		return this;
19834
19835	}
19836
19837	/**
19838	 * Translates the geometry. This is typically done as a one time
19839	 * operation, and not during a loop. Use {@link Object3D#position} for typical
19840	 * real-time mesh rotation.
19841	 *
19842	 * @param {number} x - The x offset.
19843	 * @param {number} y - The y offset.
19844	 * @param {number} z - The z offset.
19845	 * @return {BufferGeometry} A reference to this instance.
19846	 */
19847	translate( x, y, z ) {
19848
19849		// translate geometry
19850
19851		_m1.makeTranslation( x, y, z );
19852
19853		this.applyMatrix4( _m1 );
19854
19855		return this;
19856
19857	}
19858
19859	/**
19860	 * Scales the geometry. This is typically done as a one time
19861	 * operation, and not during a loop. Use {@link Object3D#scale} for typical
19862	 * real-time mesh rotation.
19863	 *
19864	 * @param {number} x - The x scale.
19865	 * @param {number} y - The y scale.
19866	 * @param {number} z - The z scale.
19867	 * @return {BufferGeometry} A reference to this instance.
19868	 */
19869	scale( x, y, z ) {
19870
19871		// scale geometry
19872
19873		_m1.makeScale( x, y, z );
19874
19875		this.applyMatrix4( _m1 );
19876
19877		return this;
19878
19879	}
19880
19881	/**
19882	 * Rotates the geometry to face a point in 3D space. This is typically done as a one time
19883	 * operation, and not during a loop. Use {@link Object3D#lookAt} for typical
19884	 * real-time mesh rotation.
19885	 *
19886	 * @param {Vector3} vector - The target point.
19887	 * @return {BufferGeometry} A reference to this instance.
19888	 */
19889	lookAt( vector ) {
19890
19891		_obj.lookAt( vector );
19892
19893		_obj.updateMatrix();
19894
19895		this.applyMatrix4( _obj.matrix );
19896
19897		return this;
19898
19899	}
19900
19901	/**
19902	 * Center the geometry based on its bounding box.
19903	 *
19904	 * @return {BufferGeometry} A reference to this instance.
19905	 */
19906	center() {
19907
19908		this.computeBoundingBox();
19909
19910		this.boundingBox.getCenter( _offset ).negate();
19911
19912		this.translate( _offset.x, _offset.y, _offset.z );
19913
19914		return this;
19915
19916	}
19917
vendor: 5,043 bytes, lines 19918-20109
19918	/**
19919	 * Defines a geometry by creating a `position` attribute based on the given array of points. The array
19920	 * can hold 2D or 3D vectors. When using two-dimensional data, the `z` coordinate for all vertices is
19921	 * set to `0`.
19922	 *
19923	 * If the method is used with an existing `position` attribute, the vertex data are overwritten with the
19924	 * data from the array. The length of the array must match the vertex count.
19925	 *
19926	 * @param {Array<Vector2>|Array<Vector3>} points - The points.
19927	 * @return {BufferGeometry} A reference to this instance.
19928	 */
19929	setFromPoints( points ) {
19930
19931		const positionAttribute = this.getAttribute( 'position' );
19932
19933		if ( positionAttribute === undefined ) {
19934
19935			const position = [];
19936
19937			for ( let i = 0, l = points.length; i < l; i ++ ) {
19938
19939				const point = points[ i ];
19940				position.push( point.x, point.y, point.z || 0 );
19941
19942			}
19943
19944			this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
19945
19946		} else {
19947
19948			const l = Math.min( points.length, positionAttribute.count ); // make sure data do not exceed buffer size
19949
19950			for ( let i = 0; i < l; i ++ ) {
19951
19952				const point = points[ i ];
19953				positionAttribute.setXYZ( i, point.x, point.y, point.z || 0 );
19954
19955			}
19956
19957			if ( points.length > positionAttribute.count ) {
19958
19959				console.warn( 'THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry.' );
19960
19961			}
19962
19963			positionAttribute.needsUpdate = true;
19964
19965		}
19966
19967		return this;
19968
19969	}
19970
19971	/**
19972	 * Computes the bounding box of the geometry, and updates the `boundingBox` member.
19973	 * The bounding box is not computed by the engine; it must be computed by your app.
19974	 * You may need to recompute the bounding box if the geometry vertices are modified.
19975	 */
19976	computeBoundingBox() {
19977
19978		if ( this.boundingBox === null ) {
19979
19980			this.boundingBox = new Box3();
19981
19982		}
19983
19984		const position = this.attributes.position;
19985		const morphAttributesPosition = this.morphAttributes.position;
19986
19987		if ( position && position.isGLBufferAttribute ) {
19988
19989			console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this );
19990
19991			this.boundingBox.set(
19992				new Vector3( - Infinity, - Infinity, - Infinity ),
19993				new Vector3( + Infinity, + Infinity, + Infinity )
19994			);
19995
19996			return;
19997
19998		}
19999
20000		if ( position !== undefined ) {
20001
20002			this.boundingBox.setFromBufferAttribute( position );
20003
20004			// process morph attributes if present
20005
20006			if ( morphAttributesPosition ) {
20007
20008				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
20009
20010					const morphAttribute = morphAttributesPosition[ i ];
20011					_box$2.setFromBufferAttribute( morphAttribute );
20012
20013					if ( this.morphTargetsRelative ) {
20014
20015						_vector$8.addVectors( this.boundingBox.min, _box$2.min );
20016						this.boundingBox.expandByPoint( _vector$8 );
20017
20018						_vector$8.addVectors( this.boundingBox.max, _box$2.max );
20019						this.boundingBox.expandByPoint( _vector$8 );
20020
20021					} else {
20022
20023						this.boundingBox.expandByPoint( _box$2.min );
20024						this.boundingBox.expandByPoint( _box$2.max );
20025
20026					}
20027
20028				}
20029
20030			}
20031
20032		} else {
20033
20034			this.boundingBox.makeEmpty();
20035
20036		}
20037
20038		if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
20039
20040			console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
20041
20042		}
20043
20044	}
20045
20046	/**
20047	 * Computes the bounding sphere of the geometry, and updates the `boundingSphere` member.
20048	 * The engine automatically computes the bounding sphere when it is needed, e.g., for ray casting or view frustum culling.
20049	 * You may need to recompute the bounding sphere if the geometry vertices are modified.
20050	 */
20051	computeBoundingSphere() {
20052
20053		if ( this.boundingSphere === null ) {
20054
20055			this.boundingSphere = new Sphere();
20056
20057		}
20058
20059		const position = this.attributes.position;
20060		const morphAttributesPosition = this.morphAttributes.position;
20061
20062		if ( position && position.isGLBufferAttribute ) {
20063
20064			console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this );
20065
20066			this.boundingSphere.set( new Vector3(), Infinity );
20067
20068			return;
20069
20070		}
20071
20072		if ( position ) {
20073
20074			// first, find the center of the bounding sphere
20075
20076			const center = this.boundingSphere.center;
20077
20078			_box$2.setFromBufferAttribute( position );
20079
20080			// process morph attributes if present
20081
20082			if ( morphAttributesPosition ) {
20083
20084				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
20085
20086					const morphAttribute = morphAttributesPosition[ i ];
20087					_boxMorphTargets.setFromBufferAttribute( morphAttribute );
20088
20089					if ( this.morphTargetsRelative ) {
20090
20091						_vector$8.addVectors( _box$2.min, _boxMorphTargets.min );
20092						_box$2.expandByPoint( _vector$8 );
20093
20094						_vector$8.addVectors( _box$2.max, _boxMorphTargets.max );
20095						_box$2.expandByPoint( _vector$8 );
20096
20097					} else {
20098
20099						_box$2.expandByPoint( _boxMorphTargets.min );
20100						_box$2.expandByPoint( _boxMorphTargets.max );
20101
20102					}
20103
20104				}
20105
20106			}
20107
20108			_box$2.getCenter( center );
20109
vendor: 5,099 bytes, lines 20110-20328
20110			// second, try to find a boundingSphere with a radius smaller than the
20111			// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
20112
20113			let maxRadiusSq = 0;
20114
20115			for ( let i = 0, il = position.count; i < il; i ++ ) {
20116
20117				_vector$8.fromBufferAttribute( position, i );
20118
20119				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
20120
20121			}
20122
20123			// process morph attributes if present
20124
20125			if ( morphAttributesPosition ) {
20126
20127				for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
20128
20129					const morphAttribute = morphAttributesPosition[ i ];
20130					const morphTargetsRelative = this.morphTargetsRelative;
20131
20132					for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
20133
20134						_vector$8.fromBufferAttribute( morphAttribute, j );
20135
20136						if ( morphTargetsRelative ) {
20137
20138							_offset.fromBufferAttribute( position, j );
20139							_vector$8.add( _offset );
20140
20141						}
20142
20143						maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
20144
20145					}
20146
20147				}
20148
20149			}
20150
20151			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
20152
20153			if ( isNaN( this.boundingSphere.radius ) ) {
20154
20155				console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
20156
20157			}
20158
20159		}
20160
20161	}
20162
20163	/**
20164	 * Calculates and adds a tangent attribute to this geometry.
20165	 *
20166	 * The computation is only supported for indexed geometries and if position, normal, and uv attributes
20167	 * are defined. When using a tangent space normal map, prefer the MikkTSpace algorithm provided by
20168	 * {@link BufferGeometryUtils#computeMikkTSpaceTangents} instead.
20169	 */
20170	computeTangents() {
20171
20172		const index = this.index;
20173		const attributes = this.attributes;
20174
20175		// based on http://www.terathon.com/code/tangent.html
20176		// (per vertex tangents)
20177
20178		if ( index === null ||
20179			 attributes.position === undefined ||
20180			 attributes.normal === undefined ||
20181			 attributes.uv === undefined ) {
20182
20183			console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
20184			return;
20185
20186		}
20187
20188		const positionAttribute = attributes.position;
20189		const normalAttribute = attributes.normal;
20190		const uvAttribute = attributes.uv;
20191
20192		if ( this.hasAttribute( 'tangent' ) === false ) {
20193
20194			this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * positionAttribute.count ), 4 ) );
20195
20196		}
20197
20198		const tangentAttribute = this.getAttribute( 'tangent' );
20199
20200		const tan1 = [], tan2 = [];
20201
20202		for ( let i = 0; i < positionAttribute.count; i ++ ) {
20203
20204			tan1[ i ] = new Vector3();
20205			tan2[ i ] = new Vector3();
20206
20207		}
20208
20209		const vA = new Vector3(),
20210			vB = new Vector3(),
20211			vC = new Vector3(),
20212
20213			uvA = new Vector2(),
20214			uvB = new Vector2(),
20215			uvC = new Vector2(),
20216
20217			sdir = new Vector3(),
20218			tdir = new Vector3();
20219
20220		function handleTriangle( a, b, c ) {
20221
20222			vA.fromBufferAttribute( positionAttribute, a );
20223			vB.fromBufferAttribute( positionAttribute, b );
20224			vC.fromBufferAttribute( positionAttribute, c );
20225
20226			uvA.fromBufferAttribute( uvAttribute, a );
20227			uvB.fromBufferAttribute( uvAttribute, b );
20228			uvC.fromBufferAttribute( uvAttribute, c );
20229
20230			vB.sub( vA );
20231			vC.sub( vA );
20232
20233			uvB.sub( uvA );
20234			uvC.sub( uvA );
20235
20236			const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
20237
20238			// silently ignore degenerate uv triangles having coincident or colinear vertices
20239
20240			if ( ! isFinite( r ) ) return;
20241
20242			sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
20243			tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
20244
20245			tan1[ a ].add( sdir );
20246			tan1[ b ].add( sdir );
20247			tan1[ c ].add( sdir );
20248
20249			tan2[ a ].add( tdir );
20250			tan2[ b ].add( tdir );
20251			tan2[ c ].add( tdir );
20252
20253		}
20254
20255		let groups = this.groups;
20256
20257		if ( groups.length === 0 ) {
20258
20259			groups = [ {
20260				start: 0,
20261				count: index.count
20262			} ];
20263
20264		}
20265
20266		for ( let i = 0, il = groups.length; i < il; ++ i ) {
20267
20268			const group = groups[ i ];
20269
20270			const start = group.start;
20271			const count = group.count;
20272
20273			for ( let j = start, jl = start + count; j < jl; j += 3 ) {
20274
20275				handleTriangle(
20276					index.getX( j + 0 ),
20277					index.getX( j + 1 ),
20278					index.getX( j + 2 )
20279				);
20280
20281			}
20282
20283		}
20284
20285		const tmp = new Vector3(), tmp2 = new Vector3();
20286		const n = new Vector3(), n2 = new Vector3();
20287
20288		function handleVertex( v ) {
20289
20290			n.fromBufferAttribute( normalAttribute, v );
20291			n2.copy( n );
20292
20293			const t = tan1[ v ];
20294
20295			// Gram-Schmidt orthogonalize
20296
20297			tmp.copy( t );
20298			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
20299
20300			// Calculate handedness
20301
20302			tmp2.crossVectors( n2, t );
20303			const test = tmp2.dot( tan2[ v ] );
20304			const w = ( test < 0.0 ) ? -1 : 1.0;
20305
20306			tangentAttribute.setXYZW( v, tmp.x, tmp.y, tmp.z, w );
20307
20308		}
20309
20310		for ( let i = 0, il = groups.length; i < il; ++ i ) {
20311
20312			const group = groups[ i ];
20313
20314			const start = group.start;
20315			const count = group.count;
20316
20317			for ( let j = start, jl = start + count; j < jl; j += 3 ) {
20318
20319				handleVertex( index.getX( j + 0 ) );
20320				handleVertex( index.getX( j + 1 ) );
20321				handleVertex( index.getX( j + 2 ) );
20322
20323			}
20324
20325		}
20326
20327	}
20328
vendor: 4,020 bytes, lines 20329-20493
20329	/**
20330	 * Computes vertex normals for the given vertex data. For indexed geometries, the method sets
20331	 * each vertex normal to be the average of the face normals of the faces that share that vertex.
20332	 * For non-indexed geometries, vertices are not shared, and the method sets each vertex normal
20333	 * to be the same as the face normal.
20334	 */
20335	computeVertexNormals() {
20336
20337		const index = this.index;
20338		const positionAttribute = this.getAttribute( 'position' );
20339
20340		if ( positionAttribute !== undefined ) {
20341
20342			let normalAttribute = this.getAttribute( 'normal' );
20343
20344			if ( normalAttribute === undefined ) {
20345
20346				normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
20347				this.setAttribute( 'normal', normalAttribute );
20348
20349			} else {
20350
20351				// reset existing normals to zero
20352
20353				for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
20354
20355					normalAttribute.setXYZ( i, 0, 0, 0 );
20356
20357				}
20358
20359			}
20360
20361			const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
20362			const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
20363			const cb = new Vector3(), ab = new Vector3();
20364
20365			// indexed elements
20366
20367			if ( index ) {
20368
20369				for ( let i = 0, il = index.count; i < il; i += 3 ) {
20370
20371					const vA = index.getX( i + 0 );
20372					const vB = index.getX( i + 1 );
20373					const vC = index.getX( i + 2 );
20374
20375					pA.fromBufferAttribute( positionAttribute, vA );
20376					pB.fromBufferAttribute( positionAttribute, vB );
20377					pC.fromBufferAttribute( positionAttribute, vC );
20378
20379					cb.subVectors( pC, pB );
20380					ab.subVectors( pA, pB );
20381					cb.cross( ab );
20382
20383					nA.fromBufferAttribute( normalAttribute, vA );
20384					nB.fromBufferAttribute( normalAttribute, vB );
20385					nC.fromBufferAttribute( normalAttribute, vC );
20386
20387					nA.add( cb );
20388					nB.add( cb );
20389					nC.add( cb );
20390
20391					normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
20392					normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
20393					normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
20394
20395				}
20396
20397			} else {
20398
20399				// non-indexed elements (unconnected triangle soup)
20400
20401				for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
20402
20403					pA.fromBufferAttribute( positionAttribute, i + 0 );
20404					pB.fromBufferAttribute( positionAttribute, i + 1 );
20405					pC.fromBufferAttribute( positionAttribute, i + 2 );
20406
20407					cb.subVectors( pC, pB );
20408					ab.subVectors( pA, pB );
20409					cb.cross( ab );
20410
20411					normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
20412					normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
20413					normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
20414
20415				}
20416
20417			}
20418
20419			this.normalizeNormals();
20420
20421			normalAttribute.needsUpdate = true;
20422
20423		}
20424
20425	}
20426
20427	/**
20428	 * Ensures every normal vector in a geometry will have a magnitude of `1`. This will
20429	 * correct lighting on the geometry surfaces.
20430	 */
20431	normalizeNormals() {
20432
20433		const normals = this.attributes.normal;
20434
20435		for ( let i = 0, il = normals.count; i < il; i ++ ) {
20436
20437			_vector$8.fromBufferAttribute( normals, i );
20438
20439			_vector$8.normalize();
20440
20441			normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );
20442
20443		}
20444
20445	}
20446
20447	/**
20448	 * Return a new non-index version of this indexed geometry. If the geometry
20449	 * is already non-indexed, the method is a NOOP.
20450	 *
20451	 * @return {BufferGeometry} The non-indexed version of this indexed geometry.
20452	 */
20453	toNonIndexed() {
20454
20455		function convertBufferAttribute( attribute, indices ) {
20456
20457			const array = attribute.array;
20458			const itemSize = attribute.itemSize;
20459			const normalized = attribute.normalized;
20460
20461			const array2 = new array.constructor( indices.length * itemSize );
20462
20463			let index = 0, index2 = 0;
20464
20465			for ( let i = 0, l = indices.length; i < l; i ++ ) {
20466
20467				if ( attribute.isInterleavedBufferAttribute ) {
20468
20469					index = indices[ i ] * attribute.data.stride + attribute.offset;
20470
20471				} else {
20472
20473					index = indices[ i ] * itemSize;
20474
20475				}
20476
20477				for ( let j = 0; j < itemSize; j ++ ) {
20478
20479					array2[ index2 ++ ] = array[ index ++ ];
20480
20481				}
20482
20483			}
20484
20485			return new BufferAttribute( array2, itemSize, normalized );
20486
20487		}
20488
20489		//
20490
20491		if ( this.index === null ) {
20492
20493			console.warn( 'THREE.
vendor: 1,446 bytes, lines 20493-20564
20493BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
20494			return this;
20495
20496		}
20497
20498		const geometry2 = new BufferGeometry();
20499
20500		const indices = this.index.array;
20501		const attributes = this.attributes;
20502
20503		// attributes
20504
20505		for ( const name in attributes ) {
20506
20507			const attribute = attributes[ name ];
20508
20509			const newAttribute = convertBufferAttribute( attribute, indices );
20510
20511			geometry2.setAttribute( name, newAttribute );
20512
20513		}
20514
20515		// morph attributes
20516
20517		const morphAttributes = this.morphAttributes;
20518
20519		for ( const name in morphAttributes ) {
20520
20521			const morphArray = [];
20522			const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
20523
20524			for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
20525
20526				const attribute = morphAttribute[ i ];
20527
20528				const newAttribute = convertBufferAttribute( attribute, indices );
20529
20530				morphArray.push( newAttribute );
20531
20532			}
20533
20534			geometry2.morphAttributes[ name ] = morphArray;
20535
20536		}
20537
20538		geometry2.morphTargetsRelative = this.morphTargetsRelative;
20539
20540		// groups
20541
20542		const groups = this.groups;
20543
20544		for ( let i = 0, l = groups.length; i < l; i ++ ) {
20545
20546			const group = groups[ i ];
20547			geometry2.addGroup( group.start, group.count, group.materialIndex );
20548
20549		}
20550
20551		return geometry2;
20552
20553	}
20554
20555	/**
20556	 * Serializes the geometry into JSON.
20557	 *
20558	 * @return {Object} A JSON object representing the serialized geometry.
20559	 */
20560	toJSON() {
20561
20562		const data = {
20563			metadata: {
20564				version: 4.
vendor: 2,295 bytes, lines 20564-20687
205646,
20565				type: 'BufferGeometry',
20566				generator: 'BufferGeometry.toJSON'
20567			}
20568		};
20569
20570		// standard BufferGeometry serialization
20571
20572		data.uuid = this.uuid;
20573		data.type = this.type;
20574		if ( this.name !== '' ) data.name = this.name;
20575		if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
20576
20577		if ( this.parameters !== undefined ) {
20578
20579			const parameters = this.parameters;
20580
20581			for ( const key in parameters ) {
20582
20583				if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
20584
20585			}
20586
20587			return data;
20588
20589		}
20590
20591		// for simplicity the code assumes attributes are not shared across geometries, see #15811
20592
20593		data.data = { attributes: {} };
20594
20595		const index = this.index;
20596
20597		if ( index !== null ) {
20598
20599			data.data.index = {
20600				type: index.array.constructor.name,
20601				array: Array.prototype.slice.call( index.array )
20602			};
20603
20604		}
20605
20606		const attributes = this.attributes;
20607
20608		for ( const key in attributes ) {
20609
20610			const attribute = attributes[ key ];
20611
20612			data.data.attributes[ key ] = attribute.toJSON( data.data );
20613
20614		}
20615
20616		const morphAttributes = {};
20617		let hasMorphAttributes = false;
20618
20619		for ( const key in this.morphAttributes ) {
20620
20621			const attributeArray = this.morphAttributes[ key ];
20622
20623			const array = [];
20624
20625			for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
20626
20627				const attribute = attributeArray[ i ];
20628
20629				array.push( attribute.toJSON( data.data ) );
20630
20631			}
20632
20633			if ( array.length > 0 ) {
20634
20635				morphAttributes[ key ] = array;
20636
20637				hasMorphAttributes = true;
20638
20639			}
20640
20641		}
20642
20643		if ( hasMorphAttributes ) {
20644
20645			data.data.morphAttributes = morphAttributes;
20646			data.data.morphTargetsRelative = this.morphTargetsRelative;
20647
20648		}
20649
20650		const groups = this.groups;
20651
20652		if ( groups.length > 0 ) {
20653
20654			data.data.groups = JSON.parse( JSON.stringify( groups ) );
20655
20656		}
20657
20658		const boundingSphere = this.boundingSphere;
20659
20660		if ( boundingSphere !== null ) {
20661
20662			data.data.boundingSphere = {
20663				center: boundingSphere.center.toArray(),
20664				radius: boundingSphere.radius
20665			};
20666
20667		}
20668
20669		return data;
20670
20671	}
20672
20673	/**
20674	 * Returns a new geometry with copied values from this instance.
20675	 *
20676	 * @return {BufferGeometry} A clone of this instance.
20677	 */
20678	clone() {
20679
20680		return new this.constructor().copy( this );
20681
20682	}
20683
20684	/**
20685	 * Copies the values of the given geometry to this instance.
20686	 *
20687	 * @param {BufferGeometry}
vendor: 4,893 bytes, lines 20687-20920
20687 source - The geometry to copy.
20688	 * @return {BufferGeometry} A reference to this instance.
20689	 */
20690	copy( source ) {
20691
20692		// reset
20693
20694		this.index = null;
20695		this.attributes = {};
20696		this.morphAttributes = {};
20697		this.groups = [];
20698		this.boundingBox = null;
20699		this.boundingSphere = null;
20700
20701		// used for storing cloned, shared data
20702
20703		const data = {};
20704
20705		// name
20706
20707		this.name = source.name;
20708
20709		// index
20710
20711		const index = source.index;
20712
20713		if ( index !== null ) {
20714
20715			this.setIndex( index.clone() );
20716
20717		}
20718
20719		// attributes
20720
20721		const attributes = source.attributes;
20722
20723		for ( const name in attributes ) {
20724
20725			const attribute = attributes[ name ];
20726			this.setAttribute( name, attribute.clone( data ) );
20727
20728		}
20729
20730		// morph attributes
20731
20732		const morphAttributes = source.morphAttributes;
20733
20734		for ( const name in morphAttributes ) {
20735
20736			const array = [];
20737			const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
20738
20739			for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
20740
20741				array.push( morphAttribute[ i ].clone( data ) );
20742
20743			}
20744
20745			this.morphAttributes[ name ] = array;
20746
20747		}
20748
20749		this.morphTargetsRelative = source.morphTargetsRelative;
20750
20751		// groups
20752
20753		const groups = source.groups;
20754
20755		for ( let i = 0, l = groups.length; i < l; i ++ ) {
20756
20757			const group = groups[ i ];
20758			this.addGroup( group.start, group.count, group.materialIndex );
20759
20760		}
20761
20762		// bounding box
20763
20764		const boundingBox = source.boundingBox;
20765
20766		if ( boundingBox !== null ) {
20767
20768			this.boundingBox = boundingBox.clone();
20769
20770		}
20771
20772		// bounding sphere
20773
20774		const boundingSphere = source.boundingSphere;
20775
20776		if ( boundingSphere !== null ) {
20777
20778			this.boundingSphere = boundingSphere.clone();
20779
20780		}
20781
20782		// draw range
20783
20784		this.drawRange.start = source.drawRange.start;
20785		this.drawRange.count = source.drawRange.count;
20786
20787		// user data
20788
20789		this.userData = source.userData;
20790
20791		return this;
20792
20793	}
20794
20795	/**
20796	 * Frees the GPU-related resources allocated by this instance. Call this
20797	 * method whenever this instance is no longer used in your app.
20798	 *
20799	 * @fires BufferGeometry#dispose
20800	 */
20801	dispose() {
20802
20803		this.dispatchEvent( { type: 'dispose' } );
20804
20805	}
20806
20807}
20808
20809const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4();
20810const _ray$3 = /*@__PURE__*/ new Ray();
20811const _sphere$6 = /*@__PURE__*/ new Sphere();
20812const _sphereHitAt = /*@__PURE__*/ new Vector3();
20813
20814const _vA$1 = /*@__PURE__*/ new Vector3();
20815const _vB$1 = /*@__PURE__*/ new Vector3();
20816const _vC$1 = /*@__PURE__*/ new Vector3();
20817
20818const _tempA = /*@__PURE__*/ new Vector3();
20819const _morphA = /*@__PURE__*/ new Vector3();
20820
20821const _intersectionPoint = /*@__PURE__*/ new Vector3();
20822const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
20823
20824/**
20825 * Class representing triangular polygon mesh based objects.
20826 *
20827 * ```js
20828 * const geometry = new THREE.BoxGeometry( 1, 1, 1 );
20829 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
20830 * const mesh = new THREE.Mesh( geometry, material );
20831 * scene.add( mesh );
20832 * ```
20833 *
20834 * @augments Object3D
20835 */
20836class Mesh extends Object3D {
20837
20838	/**
20839	 * Constructs a new mesh.
20840	 *
20841	 * @param {BufferGeometry} [geometry] - The mesh geometry.
20842	 * @param {Material|Array<Material>} [material] - The mesh material.
20843	 */
20844	constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
20845
20846		super();
20847
20848		/**
20849		 * This flag can be used for type testing.
20850		 *
20851		 * @type {boolean}
20852		 * @readonly
20853		 * @default true
20854		 */
20855		this.isMesh = true;
20856
20857		this.type = 'Mesh';
20858
20859		/**
20860		 * The mesh geometry.
20861		 *
20862		 * @type {BufferGeometry}
20863		 */
20864		this.geometry = geometry;
20865
20866		/**
20867		 * The mesh material.
20868		 *
20869		 * @type {Material|Array<Material>}
20870		 * @default MeshBasicMaterial
20871		 */
20872		this.material = material;
20873
20874		/**
20875		 * A dictionary representing the morph targets in the geometry. The key is the
20876		 * morph targets name, the value its attribute index. This member is `undefined`
20877		 * by default and only set when morph targets are detected in the geometry.
20878		 *
20879		 * @type {Object<String,number>|undefined}
20880		 * @default undefined
20881		 */
20882		this.morphTargetDictionary = undefined;
20883
20884		/**
20885		 * An array of weights typically in the range `[0,1]` that specify how much of the morph
20886		 * is applied. This member is `undefined` by default and only set when morph targets are
20887		 * detected in the geometry.
20888		 *
20889		 * @type {Array<number>|undefined}
20890		 * @default undefined
20891		 */
20892		this.morphTargetInfluences = undefined;
20893
20894		this.updateMorphTargets();
20895
20896	}
20897
20898	copy( source, recursive ) {
20899
20900		super.copy( source, recursive );
20901
20902		if ( source.morphTargetInfluences !== undefined ) {
20903
20904			this.morphTargetInfluences = source.morphTargetInfluences.slice();
20905
20906		}
20907
20908		if ( source.morphTargetDictionary !== undefined ) {
20909
20910			this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
20911
20912		}
20913
20914		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
20915		this.geometry = source.geometry;
20916
20917		return this;
20918
20919	}
20920
vendor: 8,498 bytes, lines 20921-21254
20921	/**
20922	 * Sets the values of {@link Mesh#morphTargetDictionary} and {@link Mesh#morphTargetInfluences}
20923	 * to make sure existing morph targets can influence this 3D object.
20924	 */
20925	updateMorphTargets() {
20926
20927		const geometry = this.geometry;
20928
20929		const morphAttributes = geometry.morphAttributes;
20930		const keys = Object.keys( morphAttributes );
20931
20932		if ( keys.length > 0 ) {
20933
20934			const morphAttribute = morphAttributes[ keys[ 0 ] ];
20935
20936			if ( morphAttribute !== undefined ) {
20937
20938				this.morphTargetInfluences = [];
20939				this.morphTargetDictionary = {};
20940
20941				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
20942
20943					const name = morphAttribute[ m ].name || String( m );
20944
20945					this.morphTargetInfluences.push( 0 );
20946					this.morphTargetDictionary[ name ] = m;
20947
20948				}
20949
20950			}
20951
20952		}
20953
20954	}
20955
20956	/**
20957	 * Returns the local-space position of the vertex at the given index, taking into
20958	 * account the current animation state of both morph targets and skinning.
20959	 *
20960	 * @param {number} index - The vertex index.
20961	 * @param {Vector3} target - The target object that is used to store the method's result.
20962	 * @return {Vector3} The vertex position in local space.
20963	 */
20964	getVertexPosition( index, target ) {
20965
20966		const geometry = this.geometry;
20967		const position = geometry.attributes.position;
20968		const morphPosition = geometry.morphAttributes.position;
20969		const morphTargetsRelative = geometry.morphTargetsRelative;
20970
20971		target.fromBufferAttribute( position, index );
20972
20973		const morphInfluences = this.morphTargetInfluences;
20974
20975		if ( morphPosition && morphInfluences ) {
20976
20977			_morphA.set( 0, 0, 0 );
20978
20979			for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
20980
20981				const influence = morphInfluences[ i ];
20982				const morphAttribute = morphPosition[ i ];
20983
20984				if ( influence === 0 ) continue;
20985
20986				_tempA.fromBufferAttribute( morphAttribute, index );
20987
20988				if ( morphTargetsRelative ) {
20989
20990					_morphA.addScaledVector( _tempA, influence );
20991
20992				} else {
20993
20994					_morphA.addScaledVector( _tempA.sub( target ), influence );
20995
20996				}
20997
20998			}
20999
21000			target.add( _morphA );
21001
21002		}
21003
21004		return target;
21005
21006	}
21007
21008	/**
21009	 * Computes intersection points between a casted ray and this line.
21010	 *
21011	 * @param {Raycaster} raycaster - The raycaster.
21012	 * @param {Array<Object>} intersects - The target array that holds the intersection points.
21013	 */
21014	raycast( raycaster, intersects ) {
21015
21016		const geometry = this.geometry;
21017		const material = this.material;
21018		const matrixWorld = this.matrixWorld;
21019
21020		if ( material === undefined ) return;
21021
21022		// test with bounding sphere in world space
21023
21024		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
21025
21026		_sphere$6.copy( geometry.boundingSphere );
21027		_sphere$6.applyMatrix4( matrixWorld );
21028
21029		// check distance from ray origin to bounding sphere
21030
21031		_ray$3.copy( raycaster.ray ).recast( raycaster.near );
21032
21033		if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) {
21034
21035			if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return;
21036
21037			if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return;
21038
21039		}
21040
21041		// convert ray to local space of mesh
21042
21043		_inverseMatrix$3.copy( matrixWorld ).invert();
21044		_ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 );
21045
21046		// test with bounding box in local space
21047
21048		if ( geometry.boundingBox !== null ) {
21049
21050			if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return;
21051
21052		}
21053
21054		// test for intersections with geometry
21055
21056		this._computeIntersections( raycaster, intersects, _ray$3 );
21057
21058	}
21059
21060	_computeIntersections( raycaster, intersects, rayLocalSpace ) {
21061
21062		let intersection;
21063
21064		const geometry = this.geometry;
21065		const material = this.material;
21066
21067		const index = geometry.index;
21068		const position = geometry.attributes.position;
21069		const uv = geometry.attributes.uv;
21070		const uv1 = geometry.attributes.uv1;
21071		const normal = geometry.attributes.normal;
21072		const groups = geometry.groups;
21073		const drawRange = geometry.drawRange;
21074
21075		if ( index !== null ) {
21076
21077			// indexed buffer geometry
21078
21079			if ( Array.isArray( material ) ) {
21080
21081				for ( let i = 0, il = groups.length; i < il; i ++ ) {
21082
21083					const group = groups[ i ];
21084					const groupMaterial = material[ group.materialIndex ];
21085
21086					const start = Math.max( group.start, drawRange.start );
21087					const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
21088
21089					for ( let j = start, jl = end; j < jl; j += 3 ) {
21090
21091						const a = index.getX( j );
21092						const b = index.getX( j + 1 );
21093						const c = index.getX( j + 2 );
21094
21095						intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
21096
21097						if ( intersection ) {
21098
21099							intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
21100							intersection.face.materialIndex = group.materialIndex;
21101							intersects.push( intersection );
21102
21103						}
21104
21105					}
21106
21107				}
21108
21109			} else {
21110
21111				const start = Math.max( 0, drawRange.start );
21112				const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
21113
21114				for ( let i = start, il = end; i < il; i += 3 ) {
21115
21116					const a = index.getX( i );
21117					const b = index.getX( i + 1 );
21118					const c = index.getX( i + 2 );
21119
21120					intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
21121
21122					if ( intersection ) {
21123
21124						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
21125						intersects.push( intersection );
21126
21127					}
21128
21129				}
21130
21131			}
21132
21133		} else if ( position !== undefined ) {
21134
21135			// non-indexed buffer geometry
21136
21137			if ( Array.isArray( material ) ) {
21138
21139				for ( let i = 0, il = groups.length; i < il; i ++ ) {
21140
21141					const group = groups[ i ];
21142					const groupMaterial = material[ group.materialIndex ];
21143
21144					const start = Math.max( group.start, drawRange.start );
21145					const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
21146
21147					for ( let j = start, jl = end; j < jl; j += 3 ) {
21148
21149						const a = j;
21150						const b = j + 1;
21151						const c = j + 2;
21152
21153						intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
21154
21155						if ( intersection ) {
21156
21157							intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
21158							intersection.face.materialIndex = group.materialIndex;
21159							intersects.push( intersection );
21160
21161						}
21162
21163					}
21164
21165				}
21166
21167			} else {
21168
21169				const start = Math.max( 0, drawRange.start );
21170				const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
21171
21172				for ( let i = start, il = end; i < il; i += 3 ) {
21173
21174					const a = i;
21175					const b = i + 1;
21176					const c = i + 2;
21177
21178					intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );
21179
21180					if ( intersection ) {
21181
21182						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
21183						intersects.push( intersection );
21184
21185					}
21186
21187				}
21188
21189			}
21190
21191		}
21192
21193	}
21194
21195}
21196
21197function checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point ) {
21198
21199	let intersect;
21200
21201	if ( material.side === BackSide ) {
21202
21203		intersect = ray.intersectTriangle( pC, pB, pA, true, point );
21204
21205	} else {
21206
21207		intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point );
21208
21209	}
21210
21211	if ( intersect === null ) return null;
21212
21213	_intersectionPointWorld.copy( point );
21214	_intersectionPointWorld.applyMatrix4( object.matrixWorld );
21215
21216	const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
21217
21218	if ( distance < raycaster.near || distance > raycaster.far ) return null;
21219
21220	return {
21221		distance: distance,
21222		point: _intersectionPointWorld.clone(),
21223		object: object
21224	};
21225
21226}
21227
21228function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) {
21229
21230	object.getVertexPosition( a, _vA$1 );
21231	object.getVertexPosition( b, _vB$1 );
21232	object.getVertexPosition( c, _vC$1 );
21233
21234	const intersection = checkIntersection$1( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint );
21235
21236	if ( intersection ) {
21237
21238		const barycoord = new Vector3();
21239		Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord );
21240
21241		if ( uv ) {
21242
21243			intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() );
21244
21245		}
21246
21247		if ( uv1 ) {
21248
21249			intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() );
21250
21251		}
21252
21253		if ( normal ) {
21254
vendor: 4,211 bytes, lines 21255-21434
21255			intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() );
21256
21257			if ( intersection.normal.dot( ray.direction ) > 0 ) {
21258
21259				intersection.normal.multiplyScalar( -1 );
21260
21261			}
21262
21263		}
21264
21265		const face = {
21266			a: a,
21267			b: b,
21268			c: c,
21269			normal: new Vector3(),
21270			materialIndex: 0
21271		};
21272
21273		Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
21274
21275		intersection.face = face;
21276		intersection.barycoord = barycoord;
21277
21278	}
21279
21280	return intersection;
21281
21282}
21283
21284// Uniform Utilities
21285
21286function cloneUniforms( src ) {
21287
21288	const dst = {};
21289
21290	for ( const u in src ) {
21291
21292		dst[ u ] = {};
21293
21294		for ( const p in src[ u ] ) {
21295
21296			const property = src[ u ][ p ];
21297
21298			if ( property && ( property.isColor ||
21299				property.isMatrix3 || property.isMatrix4 ||
21300				property.isVector2 || property.isVector3 || property.isVector4 ||
21301				property.isTexture || property.isQuaternion ) ) {
21302
21303				if ( property.isRenderTargetTexture ) {
21304
21305					console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );
21306					dst[ u ][ p ] = null;
21307
21308				} else {
21309
21310					dst[ u ][ p ] = property.clone();
21311
21312				}
21313
21314			} else if ( Array.isArray( property ) ) {
21315
21316				dst[ u ][ p ] = property.slice();
21317
21318			} else {
21319
21320				dst[ u ][ p ] = property;
21321
21322			}
21323
21324		}
21325
21326	}
21327
21328	return dst;
21329
21330}
21331
21332function mergeUniforms( uniforms ) {
21333
21334	const merged = {};
21335
21336	for ( let u = 0; u < uniforms.length; u ++ ) {
21337
21338		const tmp = cloneUniforms( uniforms[ u ] );
21339
21340		for ( const p in tmp ) {
21341
21342			merged[ p ] = tmp[ p ];
21343
21344		}
21345
21346	}
21347
21348	return merged;
21349
21350}
21351
21352function cloneUniformsGroups( src ) {
21353
21354	const dst = [];
21355
21356	for ( let u = 0; u < src.length; u ++ ) {
21357
21358		dst.push( src[ u ].clone() );
21359
21360	}
21361
21362	return dst;
21363
21364}
21365
21366// Legacy
21367
21368const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
21369
21370var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
21371
21372var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
21373
21374/**
21375 * A material rendered with custom shaders. A shader is a small program written in GLSL.
21376 * that runs on the GPU. You may want to use a custom shader if you need to implement an
21377 * effect not included with any of the built-in materials.
21378 *
21379 * There are the following notes to bear in mind when using a `ShaderMaterial`:
21380 *
21381 * - `ShaderMaterial` can only be used with {@link WebGLRenderer}.
21382 * - Built in attributes and uniforms are passed to the shaders along with your code. If
21383 * you don't want that, use {@link RawShaderMaterial} instead.
21384 * - You can use the directive `#pragma unroll_loop_start` and `#pragma unroll_loop_end`
21385 * in order to unroll a `for` loop in GLSL by the shader preprocessor. The directive has
21386 * to be placed right above the loop. The loop formatting has to correspond to a defined standard.
21387 *   - The loop has to be [normalized]{@link https://en.wikipedia.org/wiki/Normalized_loop}.
21388 *   - The loop variable has to be *i*.
21389 *   - The value `UNROLLED_LOOP_INDEX` will be replaced with the explicitly
21390 * value of *i* for the given iteration and can be used in preprocessor
21391 * statements.
21392 *
21393 * ```js
21394 * const material = new THREE.ShaderMaterial( {
21395 * 	uniforms: {
21396 * 		time: { value: 1.0 },
21397 * 		resolution: { value: new THREE.Vector2() }
21398 * 	},
21399 * 	vertexShader: document.getElementById( 'vertexShader' ).textContent,
21400 * 	fragmentShader: document.getElementById( 'fragmentShader' ).textContent
21401 * } );
21402 * ```
21403 *
21404 * @augments Material
21405 */
21406class ShaderMaterial extends Material {
21407
21408	/**
21409	 * Constructs a new shader material.
21410	 *
21411	 * @param {Object} [parameters] - An object with one or more properties
21412	 * defining the material's appearance. Any property of the material
21413	 * (including any property from inherited materials) can be passed
21414	 * in here. Color values can be passed any type of value accepted
21415	 * by {@link Color#set}.
21416	 */
21417	constructor( parameters ) {
21418
21419		super();
21420
21421		/**
21422		 * This flag can be used for type testing.
21423		 *
21424		 * @type {boolean}
21425		 * @readonly
21426		 * @default true
21427		 */
21428		this.isShaderMaterial = true;
21429
21430		this.type = 'ShaderMaterial';
21431
21432		/**
21433		 * Defines custom constants using `#define` directives within the GLSL code
21434		 * for both the vertex shader and the fragment shader;
21434 each key/value pair
21435		 * yields another directive.
21436		 * ```js
21437		 * defines: {
21438		 * 	FOO: 15,
21439		 * 	BAR: true
21440		 * }
21441		 * ```
21442		 * Yields the lines:
21443		 * ```
21444		 * #define FOO 15
21445		 * #define BAR true
21446		 * ```
21447		 *
21448		 * @type {Object}
21449		 */
21450		this.defines = {};
21451
21452		/**
21453		 * An object of the form:
21454		 * ```js
21455		 * {
21456		 * 	"uniform1": { value: 1.0 },
21457		 * 	"uniform2": { value: 2 }
21458		 * }
21459		 * ```
21460		 * specifying the uniforms to be passed to the shader code; keys are uniform
21461		 * names, values are definitions of the form
21462		 * ```
21463		 * {
21464		 * 	value: 1.0
21465		 * }
21466		 * ```
21467		 * where `value` is the value of the uniform. Names must match the name of
21468		 * the uniform, as defined in the GLSL code. Note that uniforms are refreshed
21469		 * on every frame, so updating the value of the uniform will immediately
21470		 * update the value available to the GLSL code.
21471		 *
21472		 * @type {Object}
21473		 */
21474		this.uniforms = {};
21475
21476		/**
21477		 * An array holding uniforms groups for configuring UBOs.
21478		 *
21479		 * @type {Array<UniformsGroup>}
21480		 */
21481		this.uniformsGroups = [];
21482
21483		/**
21484		 * Vertex shader GLSL code. This is the actual code for the shader.
21485		 *
21486		 * @type {string}
21487		 */
21488		this.vertexShader = default_vertex;
21489
21490		/**
21491		 * Fragment shader GLSL code. This is the actual code for the shader.
21492		 *
21493		 * @type {string}
21494		 */
21495		this.fragmentShader = default_fragment;
21496
21497		/**
21498		 * Controls line thickness or lines.
21499		 *
21500		 * WebGL and WebGPU ignore this setting and always render line primitives with a
21501		 * width of one pixel.
21502		 *
21503		 * @type {number}
21504		 * @default 1
21505		 */
21506		this.linewidth = 1;
21507
21508		/**
21509		 * Renders the geometry as a wireframe.
21510		 *
21511		 * @type {boolean}
21512		 * @default false
21513		 */
21514		this.wireframe = false;
21515
21516		/**
21517		 * Controls the thickness of the wireframe.
21518		 *
21519		 * WebGL and WebGPU ignore this property and always render
21520		 * 1 pixel wide lines.
21521		 *
21522		 * @type {number}
21523		 * @default 1
21524		 */
21525		this.wireframeLinewidth = 1;
21526
21527		/**
21528		 * Define whether the material color is affected by global fog settings; `true`
21529		 * to pass fog uniforms to the shader.
21530		 *
21531		 * @type {boolean}
21532		 * @default false
21533		 */
21534		this.fog = false;
21535
21536		/**
21537		 * Defines whether this material uses lighting; `true` to pass uniform data
21538		 * related to lighting to this shader.
21539		 *
21540		 * @type {boolean}
21541		 * @default false
21542		 */
21543		this.lights = false;
21544
21545		/**
21546		 * Defines whether this material supports clipping; `true` to let the renderer
21547		 * pass the clippingPlanes uniform.
21548		 *
21549		 * @type {boolean}
21550		 * @default false
21551		 */
21552		this.clipping = false;
21553
21554		/**
21555		 * Overwritten and set to `true` by default.
21556		 *
21557		 * @type {boolean}
21558		 * @default true
21559		 */
21560		this.forceSinglePass = true;
21561
21562		/**
21563		 * This object allows to enable certain WebGL 2 extensions.
21564		 *
21565		 * - clipCullDistance: set to `true` to use vertex shader clipping
21566		 * - multiDraw: set to `true` to use vertex shader multi_draw / enable gl_DrawID
21567		 *
21568		 * @type {{clipCullDistance:false,multiDraw:false}}
21569		 */
21570		this.extensions = {
21571			clipCullDistance: false, // set to use vertex shader clipping
21572			multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID
21573		};
21574
21575		/**
21576		 * When the rendered geometry doesn't include these attributes but the
21577		 * material does, these default values will be passed to the shaders. This
21578		 * avoids errors when buffer data is missing.
21579		 *
21580		 * - color: [ 1, 1, 1 ]
21581		 * - uv: [ 0, 0 ]
21582		 * - uv1: [ 0, 0 ]
21583		 *
21584		 * @type {Object}
21585		 */
21586		this.defaultAttributeValues = {
21587			'color': [ 1, 1, 1 ],
21588			'uv': [ 0, 0 ],
21589			'uv1': [ 0, 0 ]
21590		};
21591
21592		/**
21593		 * If set, this calls [gl.bindAttribLocation]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bindAttribLocation}
21594		 * to bind a generic vertex index to an attribute variable.
21595		 *
21596		 * @type {string|undefined}
21597		 * @default undefined
21598		 */
21599		this.index0AttributeName = undefined;
21600
21601		/**
21602		 * Can be used to force a uniform update while changing uniforms in
21603		 * {@link Object3D#onBeforeRender}.
21604		 *
21605		 * @type {boolean}
21606		 * @default false
21607		 */
21608		this.uniformsNeedUpdate = false;
21609
21610		/**
21611		 * Defines the GLSL version of custom shader code.
21612		 *
21613		 * @type {?(GLSL1|GLSL3)}
21614		 * @default null
21615		 */
21616		this.glslVersion = null;
21617
21618		if ( parameters !== undefined ) {
21619
21620			this.setValues( parameters );
21621
21622		}
21623
21624	}
21625
21626	copy( source ) {
21627
21628		super.copy( source );
21629
21630		this.fragmentShader = source.fragmentShader;
21631		this.vertexShader = source.vertexShader;
21632
21633		this.uniforms = cloneUniforms( source.uniforms );
21634		this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );
21635
21636		this.defines = Object.assign( {}, source.defines );
21637
21638		this.wireframe = source.wireframe;
21639		this.wireframeLinewidth = source.wireframeLinewidth;
21640
vendor: 8,379 bytes, lines 21641-22017
21641		this.fog = source.fog;
21642		this.lights = source.lights;
21643		this.clipping = source.clipping;
21644
21645		this.extensions = Object.assign( {}, source.extensions );
21646
21647		this.glslVersion = source.glslVersion;
21648
21649		return this;
21650
21651	}
21652
21653	toJSON( meta ) {
21654
21655		const data = super.toJSON( meta );
21656
21657		data.glslVersion = this.glslVersion;
21658		data.uniforms = {};
21659
21660		for ( const name in this.uniforms ) {
21661
21662			const uniform = this.uniforms[ name ];
21663			const value = uniform.value;
21664
21665			if ( value && value.isTexture ) {
21666
21667				data.uniforms[ name ] = {
21668					type: 't',
21669					value: value.toJSON( meta ).uuid
21670				};
21671
21672			} else if ( value && value.isColor ) {
21673
21674				data.uniforms[ name ] = {
21675					type: 'c',
21676					value: value.getHex()
21677				};
21678
21679			} else if ( value && value.isVector2 ) {
21680
21681				data.uniforms[ name ] = {
21682					type: 'v2',
21683					value: value.toArray()
21684				};
21685
21686			} else if ( value && value.isVector3 ) {
21687
21688				data.uniforms[ name ] = {
21689					type: 'v3',
21690					value: value.toArray()
21691				};
21692
21693			} else if ( value && value.isVector4 ) {
21694
21695				data.uniforms[ name ] = {
21696					type: 'v4',
21697					value: value.toArray()
21698				};
21699
21700			} else if ( value && value.isMatrix3 ) {
21701
21702				data.uniforms[ name ] = {
21703					type: 'm3',
21704					value: value.toArray()
21705				};
21706
21707			} else if ( value && value.isMatrix4 ) {
21708
21709				data.uniforms[ name ] = {
21710					type: 'm4',
21711					value: value.toArray()
21712				};
21713
21714			} else {
21715
21716				data.uniforms[ name ] = {
21717					value: value
21718				};
21719
21720				// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
21721
21722			}
21723
21724		}
21725
21726		if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
21727
21728		data.vertexShader = this.vertexShader;
21729		data.fragmentShader = this.fragmentShader;
21730
21731		data.lights = this.lights;
21732		data.clipping = this.clipping;
21733
21734		const extensions = {};
21735
21736		for ( const key in this.extensions ) {
21737
21738			if ( this.extensions[ key ] === true ) extensions[ key ] = true;
21739
21740		}
21741
21742		if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
21743
21744		return data;
21745
21746	}
21747
21748}
21749
21750/**
21751 * This is almost identical to an {@link Object3D}. Its purpose is to
21752 * make working with groups of objects syntactically clearer.
21753 *
21754 * ```js
21755 * // Create a group and add the two cubes.
21756 * // These cubes can now be rotated / scaled etc as a group.
21757 * const group = new THREE.Group();
21758 *
21759 * group.add( meshA );
21760 * group.add( meshB );
21761 *
21762 * scene.add( group );
21763 * ```
21764 *
21765 * @augments Object3D
21766 */
21767class Group extends Object3D {
21768
21769	constructor() {
21770
21771		super();
21772
21773		/**
21774		 * This flag can be used for type testing.
21775		 *
21776		 * @type {boolean}
21777		 * @readonly
21778		 * @default true
21779		 */
21780		this.isGroup = true;
21781
21782		this.type = 'Group';
21783
21784	}
21785
21786}
21787
21788/**
21789 * "Interleaved" means that multiple attributes, possibly of different types,
21790 * (e.g., position, normal, uv, color) are packed into a single array buffer.
21791 *
21792 * An introduction into interleaved arrays can be found here: [Interleaved array basics]{@link https://blog.tojicode.com/2011/05/interleaved-array-basics.html}
21793 */
21794class InterleavedBuffer {
21795
21796	/**
21797	 * Constructs a new interleaved buffer.
21798	 *
21799	 * @param {TypedArray} array - A typed array with a shared buffer storing attribute data.
21800	 * @param {number} stride - The number of typed-array elements per vertex.
21801	 */
21802	constructor( array, stride ) {
21803
21804		/**
21805		 * This flag can be used for type testing.
21806		 *
21807		 * @type {boolean}
21808		 * @readonly
21809		 * @default true
21810		 */
21811		this.isInterleavedBuffer = true;
21812
21813		/**
21814		 * A typed array with a shared buffer storing attribute data.
21815		 *
21816		 * @type {TypedArray}
21817		 */
21818		this.array = array;
21819
21820		/**
21821		 * The number of typed-array elements per vertex.
21822		 *
21823		 * @type {number}
21824		 */
21825		this.stride = stride;
21826
21827		/**
21828		 * The total number of elements in the array
21829		 *
21830		 * @type {number}
21831		 * @readonly
21832		 */
21833		this.count = array !== undefined ? array.length / stride : 0;
21834
21835		/**
21836		 * Defines the intended usage pattern of the data store for optimization purposes.
21837		 *
21838		 * Note: After the initial use of a buffer, its usage cannot be changed. Instead,
21839		 * instantiate a new one and set the desired usage before the next render.
21840		 *
21841		 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)}
21842		 * @default StaticDrawUsage
21843		 */
21844		this.usage = StaticDrawUsage;
21845
21846		/**
21847		 * This can be used to only update some components of stored vectors (for example, just the
21848		 * component related to color). Use the `addUpdateRange()` function to add ranges to this array.
21849		 *
21850		 * @type {Array<Object>}
21851		 */
21852		this.updateRanges = [];
21853
21854		/**
21855		 * A version number, incremented every time the `needsUpdate` is set to `true`.
21856		 *
21857		 * @type {number}
21858		 */
21859		this.version = 0;
21860
21861		/**
21862		 * The UUID of the interleaved buffer.
21863		 *
21864		 * @type {string}
21865		 * @readonly
21866		 */
21867		this.uuid = generateUUID();
21868
21869	}
21870
21871	/**
21872	 * A callback function that is executed after the renderer has transferred the attribute array
21873	 * data to the GPU.
21874	 */
21875	onUploadCallback() {}
21876
21877	/**
21878	 * Flag to indicate that this attribute has changed and should be re-sent to
21879	 * the GPU. Set this to `true` when you modify the value of the array.
21880	 *
21881	 * @type {number}
21882	 * @default false
21883	 * @param {boolean} value
21884	 */
21885	set needsUpdate( value ) {
21886
21887		if ( value === true ) this.version ++;
21888
21889	}
21890
21891	/**
21892	 * Sets the usage of this interleaved buffer.
21893	 *
21894	 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set.
21895	 * @return {InterleavedBuffer} A reference to this interleaved buffer.
21896	 */
21897	setUsage( value ) {
21898
21899		this.usage = value;
21900
21901		return this;
21902
21903	}
21904
21905	/**
21906	 * Adds a range of data in the data array to be updated on the GPU.
21907	 *
21908	 * @param {number} start - Position at which to start update.
21909	 * @param {number} count - The number of components to update.
21910	 */
21911	addUpdateRange( start, count ) {
21912
21913		this.updateRanges.push( { start, count } );
21914
21915	}
21916
21917	/**
21918	 * Clears the update ranges.
21919	 */
21920	clearUpdateRanges() {
21921
21922		this.updateRanges.length = 0;
21923
21924	}
21925
21926	/**
21927	 * Copies the values of the given interleaved buffer to this instance.
21928	 *
21929	 * @param {InterleavedBuffer} source - The interleaved buffer to copy.
21930	 * @return {InterleavedBuffer} A reference to this instance.
21931	 */
21932	copy( source ) {
21933
21934		this.array = new source.array.constructor( source.array );
21935		this.count = source.count;
21936		this.stride = source.stride;
21937		this.usage = source.usage;
21938
21939		return this;
21940
21941	}
21942
21943	/**
21944	 * Copies a vector from the given interleaved buffer to this one. The start
21945	 * and destination position in the attribute buffers are represented by the
21946	 * given indices.
21947	 *
21948	 * @param {number} index1 - The destination index into this interleaved buffer.
21949	 * @param {InterleavedBuffer} interleavedBuffer - The interleaved buffer to copy from.
21950	 * @param {number} index2 - The source index into the given interleaved buffer.
21951	 * @return {InterleavedBuffer} A reference to this instance.
21952	 */
21953	copyAt( index1, interleavedBuffer, index2 ) {
21954
21955		index1 *= this.stride;
21956		index2 *= interleavedBuffer.stride;
21957
21958		for ( let i = 0, l = this.stride; i < l; i ++ ) {
21959
21960			this.array[ index1 + i ] = interleavedBuffer.array[ index2 + i ];
21961
21962		}
21963
21964		return this;
21965
21966	}
21967
21968	/**
21969	 * Sets the given array data in the interleaved buffer.
21970	 *
21971	 * @param {(TypedArray|Array)} value - The array data to set.
21972	 * @param {number} [offset=0] - The offset in this interleaved buffer's array.
21973	 * @return {InterleavedBuffer} A reference to this instance.
21974	 */
21975	set( value, offset = 0 ) {
21976
21977		this.array.set( value, offset );
21978
21979		return this;
21980
21981	}
21982
21983	/**
21984	 * Returns a new interleaved buffer with copied values from this instance.
21985	 *
21986	 * @param {Object} [data] - An object with shared array buffers that allows to retain shared structures.
21987	 * @return {InterleavedBuffer} A clone of this instance.
21988	 */
21989	clone( data ) {
21990
21991		if ( data.arrayBuffers === undefined ) {
21992
21993			data.arrayBuffers = {};
21994
21995		}
21996
21997		if ( this.array.buffer._uuid === undefined ) {
21998
21999			this.array.buffer._uuid = generateUUID();
22000
22001		}
22002
22003		if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
22004
22005			data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
22006
22007		}
22008
22009		const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
22010
22011		const ib = new this.constructor( array, this.stride );
22012		ib.setUsage( this.usage );
22013
22014		return ib;
22015
22016	}
22017
vendor: 2,927 bytes, lines 22018-22151
22018	/**
22019	 * Sets the given callback function that is executed after the Renderer has transferred
22020	 * the array data to the GPU. Can be used to perform clean-up operations after
22021	 * the upload when data are not needed anymore on the CPU side.
22022	 *
22023	 * @param {Function} callback - The `onUpload()` callback.
22024	 * @return {InterleavedBuffer} A reference to this instance.
22025	 */
22026	onUpload( callback ) {
22027
22028		this.onUploadCallback = callback;
22029
22030		return this;
22031
22032	}
22033
22034	/**
22035	 * Serializes the interleaved buffer into JSON.
22036	 *
22037	 * @param {Object} [data] - An optional value holding meta information about the serialization.
22038	 * @return {Object} A JSON object representing the serialized interleaved buffer.
22039	 */
22040	toJSON( data ) {
22041
22042		if ( data.arrayBuffers === undefined ) {
22043
22044			data.arrayBuffers = {};
22045
22046		}
22047
22048		// generate UUID for array buffer if necessary
22049
22050		if ( this.array.buffer._uuid === undefined ) {
22051
22052			this.array.buffer._uuid = generateUUID();
22053
22054		}
22055
22056		if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
22057
22058			data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) );
22059
22060		}
22061
22062		//
22063
22064		return {
22065			uuid: this.uuid,
22066			buffer: this.array.buffer._uuid,
22067			type: this.array.constructor.name,
22068			stride: this.stride
22069		};
22070
22071	}
22072
22073}
22074
22075const _vector$7 = /*@__PURE__*/ new Vector3();
22076
22077/**
22078 * An alternative version of a buffer attribute with interleaved data. Interleaved
22079 * attributes share a common interleaved data storage ({@link InterleavedBuffer}) and refer with
22080 * different offsets into the buffer.
22081 */
22082class InterleavedBufferAttribute {
22083
22084	/**
22085	 * Constructs a new interleaved buffer attribute.
22086	 *
22087	 * @param {InterleavedBuffer} interleavedBuffer - The buffer holding the interleaved data.
22088	 * @param {number} itemSize - The item size.
22089	 * @param {number} offset - The attribute offset into the buffer.
22090	 * @param {boolean} [normalized=false] - Whether the data are normalized or not.
22091	 */
22092	constructor( interleavedBuffer, itemSize, offset, normalized = false ) {
22093
22094		/**
22095		 * This flag can be used for type testing.
22096		 *
22097		 * @type {boolean}
22098		 * @readonly
22099		 * @default true
22100		 */
22101		this.isInterleavedBufferAttribute = true;
22102
22103		/**
22104		 * The name of the buffer attribute.
22105		 *
22106		 * @type {string}
22107		 */
22108		this.name = '';
22109
22110		/**
22111		 * The buffer holding the interleaved data.
22112		 *
22113		 * @type {InterleavedBuffer}
22114		 */
22115		this.data = interleavedBuffer;
22116
22117		/**
22118		 * The item size, see {@link BufferAttribute#itemSize}.
22119		 *
22120		 * @type {number}
22121		 */
22122		this.itemSize = itemSize;
22123
22124		/**
22125		 * The attribute offset into the buffer.
22126		 *
22127		 * @type {number}
22128		 */
22129		this.offset = offset;
22130
22131		/**
22132		 * Whether the data are normalized or not, see {@link BufferAttribute#normalized}
22133		 *
22134		 * @type {InterleavedBuffer}
22135		 */
22136		this.normalized = normalized;
22137
22138	}
22139
22140	/**
22141	 * The item count of this buffer attribute.
22142	 *
22143	 * @type {number}
22144	 * @readonly
22145	 */
22146	get count() {
22147
22148		return this.data.count;
22149
22150	}
22151
vendor: 4,140 bytes, lines 22152-22331
22152	/**
22153	 * The array holding the interleaved buffer attribute data.
22154	 *
22155	 * @type {TypedArray}
22156	 */
22157	get array() {
22158
22159		return this.data.array;
22160
22161	}
22162
22163	/**
22164	 * Flag to indicate that this attribute has changed and should be re-sent to
22165	 * the GPU. Set this to `true` when you modify the value of the array.
22166	 *
22167	 * @type {number}
22168	 * @default false
22169	 * @param {boolean} value
22170	 */
22171	set needsUpdate( value ) {
22172
22173		this.data.needsUpdate = value;
22174
22175	}
22176
22177	/**
22178	 * Applies the given 4x4 matrix to the given attribute. Only works with
22179	 * item size `3`.
22180	 *
22181	 * @param {Matrix4} m - The matrix to apply.
22182	 * @return {InterleavedBufferAttribute} A reference to this instance.
22183	 */
22184	applyMatrix4( m ) {
22185
22186		for ( let i = 0, l = this.data.count; i < l; i ++ ) {
22187
22188			_vector$7.fromBufferAttribute( this, i );
22189
22190			_vector$7.applyMatrix4( m );
22191
22192			this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z );
22193
22194		}
22195
22196		return this;
22197
22198	}
22199
22200	/**
22201	 * Applies the given 3x3 normal matrix to the given attribute. Only works with
22202	 * item size `3`.
22203	 *
22204	 * @param {Matrix3} m - The normal matrix to apply.
22205	 * @return {InterleavedBufferAttribute} A reference to this instance.
22206	 */
22207	applyNormalMatrix( m ) {
22208
22209		for ( let i = 0, l = this.count; i < l; i ++ ) {
22210
22211			_vector$7.fromBufferAttribute( this, i );
22212
22213			_vector$7.applyNormalMatrix( m );
22214
22215			this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z );
22216
22217		}
22218
22219		return this;
22220
22221	}
22222
22223	/**
22224	 * Applies the given 4x4 matrix to the given attribute. Only works with
22225	 * item size `3` and with direction vectors.
22226	 *
22227	 * @param {Matrix4} m - The matrix to apply.
22228	 * @return {InterleavedBufferAttribute} A reference to this instance.
22229	 */
22230	transformDirection( m ) {
22231
22232		for ( let i = 0, l = this.count; i < l; i ++ ) {
22233
22234			_vector$7.fromBufferAttribute( this, i );
22235
22236			_vector$7.transformDirection( m );
22237
22238			this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z );
22239
22240		}
22241
22242		return this;
22243
22244	}
22245
22246	/**
22247	 * Returns the given component of the vector at the given index.
22248	 *
22249	 * @param {number} index - The index into the buffer attribute.
22250	 * @param {number} component - The component index.
22251	 * @return {number} The returned value.
22252	 */
22253	getComponent( index, component ) {
22254
22255		let value = this.array[ index * this.data.stride + this.offset + component ];
22256
22257		if ( this.normalized ) value = denormalize( value, this.array );
22258
22259		return value;
22260
22261	}
22262
22263	/**
22264	 * Sets the given value to the given component of the vector at the given index.
22265	 *
22266	 * @param {number} index - The index into the buffer attribute.
22267	 * @param {number} component - The component index.
22268	 * @param {number} value - The value to set.
22269	 * @return {InterleavedBufferAttribute} A reference to this instance.
22270	 */
22271	setComponent( index, component, value ) {
22272
22273		if ( this.normalized ) value = normalize( value, this.array );
22274
22275		this.data.array[ index * this.data.stride + this.offset + component ] = value;
22276
22277		return this;
22278
22279	}
22280
22281	/**
22282	 * Sets the x component of the vector at the given index.
22283	 *
22284	 * @param {number} index - The index into the buffer attribute.
22285	 * @param {number} x - The value to set.
22286	 * @return {InterleavedBufferAttribute} A reference to this instance.
22287	 */
22288	setX( index, x ) {
22289
22290		if ( this.normalized ) x = normalize( x, this.array );
22291
22292		this.data.array[ index * this.data.stride + this.offset ] = x;
22293
22294		return this;
22295
22296	}
22297
22298	/**
22299	 * Sets the y component of the vector at the given index.
22300	 *
22301	 * @param {number} index - The index into the buffer attribute.
22302	 * @param {number} y - The value to set.
22303	 * @return {InterleavedBufferAttribute} A reference to this instance.
22304	 */
22305	setY( index, y ) {
22306
22307		if ( this.normalized ) y = normalize( y, this.array );
22308
22309		this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
22310
22311		return this;
22312
22313	}
22314
22315	/**
22316	 * Sets the z component of the vector at the given index.
22317	 *
22318	 * @param {number} index - The index into the buffer attribute.
22319	 * @param {number} z - The value to set.
22320	 * @return {InterleavedBufferAttribute} A reference to this instance.
22321	 */
22322	setZ( index, z ) {
22323
22324		if ( this.normalized ) z = normalize( z, this.array );
22325
22326		this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
22327
22328		return this;
22329
22330	}
22331
vendor: 5,375 bytes, lines 22332-22549
22332	/**
22333	 * Sets the w component of the vector at the given index.
22334	 *
22335	 * @param {number} index - The index into the buffer attribute.
22336	 * @param {number} w - The value to set.
22337	 * @return {InterleavedBufferAttribute} A reference to this instance.
22338	 */
22339	setW( index, w ) {
22340
22341		if ( this.normalized ) w = normalize( w, this.array );
22342
22343		this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
22344
22345		return this;
22346
22347	}
22348
22349	/**
22350	 * Returns the x component of the vector at the given index.
22351	 *
22352	 * @param {number} index - The index into the buffer attribute.
22353	 * @return {number} The x component.
22354	 */
22355	getX( index ) {
22356
22357		let x = this.data.array[ index * this.data.stride + this.offset ];
22358
22359		if ( this.normalized ) x = denormalize( x, this.array );
22360
22361		return x;
22362
22363	}
22364
22365	/**
22366	 * Returns the y component of the vector at the given index.
22367	 *
22368	 * @param {number} index - The index into the buffer attribute.
22369	 * @return {number} The y component.
22370	 */
22371	getY( index ) {
22372
22373		let y = this.data.array[ index * this.data.stride + this.offset + 1 ];
22374
22375		if ( this.normalized ) y = denormalize( y, this.array );
22376
22377		return y;
22378
22379	}
22380
22381	/**
22382	 * Returns the z component of the vector at the given index.
22383	 *
22384	 * @param {number} index - The index into the buffer attribute.
22385	 * @return {number} The z component.
22386	 */
22387	getZ( index ) {
22388
22389		let z = this.data.array[ index * this.data.stride + this.offset + 2 ];
22390
22391		if ( this.normalized ) z = denormalize( z, this.array );
22392
22393		return z;
22394
22395	}
22396
22397	/**
22398	 * Returns the w component of the vector at the given index.
22399	 *
22400	 * @param {number} index - The index into the buffer attribute.
22401	 * @return {number} The w component.
22402	 */
22403	getW( index ) {
22404
22405		let w = this.data.array[ index * this.data.stride + this.offset + 3 ];
22406
22407		if ( this.normalized ) w = denormalize( w, this.array );
22408
22409		return w;
22410
22411	}
22412
22413	/**
22414	 * Sets the x and y component of the vector at the given index.
22415	 *
22416	 * @param {number} index - The index into the buffer attribute.
22417	 * @param {number} x - The value for the x component to set.
22418	 * @param {number} y - The value for the y component to set.
22419	 * @return {InterleavedBufferAttribute} A reference to this instance.
22420	 */
22421	setXY( index, x, y ) {
22422
22423		index = index * this.data.stride + this.offset;
22424
22425		if ( this.normalized ) {
22426
22427			x = normalize( x, this.array );
22428			y = normalize( y, this.array );
22429
22430		}
22431
22432		this.data.array[ index + 0 ] = x;
22433		this.data.array[ index + 1 ] = y;
22434
22435		return this;
22436
22437	}
22438
22439	/**
22440	 * Sets the x, y and z component of the vector at the given index.
22441	 *
22442	 * @param {number} index - The index into the buffer attribute.
22443	 * @param {number} x - The value for the x component to set.
22444	 * @param {number} y - The value for the y component to set.
22445	 * @param {number} z - The value for the z component to set.
22446	 * @return {InterleavedBufferAttribute} A reference to this instance.
22447	 */
22448	setXYZ( index, x, y, z ) {
22449
22450		index = index * this.data.stride + this.offset;
22451
22452		if ( this.normalized ) {
22453
22454			x = normalize( x, this.array );
22455			y = normalize( y, this.array );
22456			z = normalize( z, this.array );
22457
22458		}
22459
22460		this.data.array[ index + 0 ] = x;
22461		this.data.array[ index + 1 ] = y;
22462		this.data.array[ index + 2 ] = z;
22463
22464		return this;
22465
22466	}
22467
22468	/**
22469	 * Sets the x, y, z and w component of the vector at the given index.
22470	 *
22471	 * @param {number} index - The index into the buffer attribute.
22472	 * @param {number} x - The value for the x component to set.
22473	 * @param {number} y - The value for the y component to set.
22474	 * @param {number} z - The value for the z component to set.
22475	 * @param {number} w - The value for the w component to set.
22476	 * @return {InterleavedBufferAttribute} A reference to this instance.
22477	 */
22478	setXYZW( index, x, y, z, w ) {
22479
22480		index = index * this.data.stride + this.offset;
22481
22482		if ( this.normalized ) {
22483
22484			x = normalize( x, this.array );
22485			y = normalize( y, this.array );
22486			z = normalize( z, this.array );
22487			w = normalize( w, this.array );
22488
22489		}
22490
22491		this.data.array[ index + 0 ] = x;
22492		this.data.array[ index + 1 ] = y;
22493		this.data.array[ index + 2 ] = z;
22494		this.data.array[ index + 3 ] = w;
22495
22496		return this;
22497
22498	}
22499
22500	/**
22501	 * Returns a new buffer attribute with copied values from this instance.
22502	 *
22503	 * If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data.
22504	 *
22505	 * @param {Object} [data] - An object with interleaved buffers that allows to retain the interleaved property.
22506	 * @return {BufferAttribute|InterleavedBufferAttribute} A clone of this instance.
22507	 */
22508	clone( data ) {
22509
22510		if ( data === undefined ) {
22511
22512			console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );
22513
22514			const array = [];
22515
22516			for ( let i = 0; i < this.count; i ++ ) {
22517
22518				const index = i * this.data.stride + this.offset;
22519
22520				for ( let j = 0; j < this.itemSize; j ++ ) {
22521
22522					array.push( this.data.array[ index + j ] );
22523
22524				}
22525
22526			}
22527
22528			return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
22529
22530		} else {
22531
22532			if ( data.interleavedBuffers === undefined ) {
22533
22534				data.interleavedBuffers = {};
22535
22536			}
22537
22538			if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
22539
22540				data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
22541
22542			}
22543
22544			return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
22545
22546		}
22547
22548	}
22549
vendor: 6,327 bytes, lines 22550-22837
22550	/**
22551	 * Serializes the buffer attribute into JSON.
22552	 *
22553	 * If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data.
22554	 *
22555	 * @param {Object} [data] - An optional value holding meta information about the serialization.
22556	 * @return {Object} A JSON object representing the serialized buffer attribute.
22557	 */
22558	toJSON( data ) {
22559
22560		if ( data === undefined ) {
22561
22562			console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );
22563
22564			const array = [];
22565
22566			for ( let i = 0; i < this.count; i ++ ) {
22567
22568				const index = i * this.data.stride + this.offset;
22569
22570				for ( let j = 0; j < this.itemSize; j ++ ) {
22571
22572					array.push( this.data.array[ index + j ] );
22573
22574				}
22575
22576			}
22577
22578			// de-interleave data and save it as an ordinary buffer attribute for now
22579
22580			return {
22581				itemSize: this.itemSize,
22582				type: this.array.constructor.name,
22583				array: array,
22584				normalized: this.normalized
22585			};
22586
22587		} else {
22588
22589			// save as true interleaved attribute
22590
22591			if ( data.interleavedBuffers === undefined ) {
22592
22593				data.interleavedBuffers = {};
22594
22595			}
22596
22597			if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
22598
22599				data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
22600
22601			}
22602
22603			return {
22604				isInterleavedBufferAttribute: true,
22605				itemSize: this.itemSize,
22606				data: this.data.uuid,
22607				offset: this.offset,
22608				normalized: this.normalized
22609			};
22610
22611		}
22612
22613	}
22614
22615}
22616
22617/**
22618 * A material for rendering line primitives.
22619 *
22620 * Materials define the appearance of renderable 3D objects.
22621 *
22622 * ```js
22623 * const material = new THREE.LineBasicMaterial( { color: 0xffffff } );
22624 * ```
22625 *
22626 * @augments Material
22627 */
22628class LineBasicMaterial extends Material {
22629
22630	/**
22631	 * Constructs a new line basic material.
22632	 *
22633	 * @param {Object} [parameters] - An object with one or more properties
22634	 * defining the material's appearance. Any property of the material
22635	 * (including any property from inherited materials) can be passed
22636	 * in here. Color values can be passed any type of value accepted
22637	 * by {@link Color#set}.
22638	 */
22639	constructor( parameters ) {
22640
22641		super();
22642
22643		/**
22644		 * This flag can be used for type testing.
22645		 *
22646		 * @type {boolean}
22647		 * @readonly
22648		 * @default true
22649		 */
22650		this.isLineBasicMaterial = true;
22651
22652		this.type = 'LineBasicMaterial';
22653
22654		/**
22655		 * Color of the material.
22656		 *
22657		 * @type {Color}
22658		 * @default (1,1,1)
22659		 */
22660		this.color = new Color( 0xffffff );
22661
22662		/**
22663		 * Sets the color of the lines using data from a texture. The texture map
22664		 * color is modulated by the diffuse `color`.
22665		 *
22666		 * @type {?Texture}
22667		 * @default null
22668		 */
22669		this.map = null;
22670
22671		/**
22672		 * Controls line thickness or lines.
22673		 *
22674		 * Can only be used with {@link SVGRenderer}. WebGL and WebGPU
22675		 * ignore this setting and always render line primitives with a
22676		 * width of one pixel.
22677		 *
22678		 * @type {number}
22679		 * @default 1
22680		 */
22681		this.linewidth = 1;
22682
22683		/**
22684		 * Defines appearance of line ends.
22685		 *
22686		 * Can only be used with {@link SVGRenderer}.
22687		 *
22688		 * @type {('butt'|'round'|'square')}
22689		 * @default 'round'
22690		 */
22691		this.linecap = 'round';
22692
22693		/**
22694		 * Defines appearance of line joints.
22695		 *
22696		 * Can only be used with {@link SVGRenderer}.
22697		 *
22698		 * @type {('round'|'bevel'|'miter')}
22699		 * @default 'round'
22700		 */
22701		this.linejoin = 'round';
22702
22703		/**
22704		 * Whether the material is affected by fog or not.
22705		 *
22706		 * @type {boolean}
22707		 * @default true
22708		 */
22709		this.fog = true;
22710
22711		this.setValues( parameters );
22712
22713	}
22714
22715	copy( source ) {
22716
22717		super.copy( source );
22718
22719		this.color.copy( source.color );
22720
22721		this.map = source.map;
22722
22723		this.linewidth = source.linewidth;
22724		this.linecap = source.linecap;
22725		this.linejoin = source.linejoin;
22726
22727		this.fog = source.fog;
22728
22729		return this;
22730
22731	}
22732
22733}
22734
22735const _vStart = /*@__PURE__*/ new Vector3();
22736const _vEnd = /*@__PURE__*/ new Vector3();
22737
22738const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();
22739const _ray$1 = /*@__PURE__*/ new Ray();
22740const _sphere$1 = /*@__PURE__*/ new Sphere();
22741
22742const _intersectPointOnRay = /*@__PURE__*/ new Vector3();
22743const _intersectPointOnSegment = /*@__PURE__*/ new Vector3();
22744
22745/**
22746 * A continuous line. The line are rendered by connecting consecutive
22747 * vertices with straight lines.
22748 *
22749 * ```js
22750 * const material = new THREE.LineBasicMaterial( { color: 0x0000ff } );
22751 *
22752 * const points = [];
22753 * points.push( new THREE.Vector3( - 10, 0, 0 ) );
22754 * points.push( new THREE.Vector3( 0, 10, 0 ) );
22755 * points.push( new THREE.Vector3( 10, 0, 0 ) );
22756 *
22757 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
22758 *
22759 * const line = new THREE.Line( geometry, material );
22760 * scene.add( line );
22761 * ```
22762 *
22763 * @augments Object3D
22764 */
22765class Line extends Object3D {
22766
22767	/**
22768	 * Constructs a new line.
22769	 *
22770	 * @param {BufferGeometry} [geometry] - The line geometry.
22771	 * @param {Material|Array<Material>} [material] - The line material.
22772	 */
22773	constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
22774
22775		super();
22776
22777		/**
22778		 * This flag can be used for type testing.
22779		 *
22780		 * @type {boolean}
22781		 * @readonly
22782		 * @default true
22783		 */
22784		this.isLine = true;
22785
22786		this.type = 'Line';
22787
22788		/**
22789		 * The line geometry.
22790		 *
22791		 * @type {BufferGeometry}
22792		 */
22793		this.geometry = geometry;
22794
22795		/**
22796		 * The line material.
22797		 *
22798		 * @type {Material|Array<Material>}
22799		 * @default LineBasicMaterial
22800		 */
22801		this.material = material;
22802
22803		/**
22804		 * A dictionary representing the morph targets in the geometry. The key is the
22805		 * morph targets name, the value its attribute index. This member is `undefined`
22806		 * by default and only set when morph targets are detected in the geometry.
22807		 *
22808		 * @type {Object<String,number>|undefined}
22809		 * @default undefined
22810		 */
22811		this.morphTargetDictionary = undefined;
22812
22813		/**
22814		 * An array of weights typically in the range `[0,1]` that specify how much of the morph
22815		 * is applied. This member is `undefined` by default and only set when morph targets are
22816		 * detected in the geometry.
22817		 *
22818		 * @type {Array<number>|undefined}
22819		 * @default undefined
22820		 */
22821		this.morphTargetInfluences = undefined;
22822
22823		this.updateMorphTargets();
22824
22825	}
22826
22827	copy( source, recursive ) {
22828
22829		super.copy( source, recursive );
22830
22831		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
22832		this.geometry = source.geometry;
22833
22834		return this;
22835
22836	}
22837
vendor: 6,280 bytes, lines 22838-23092
22838	/**
22839	 * Computes an array of distance values which are necessary for rendering dashed lines.
22840	 * For each vertex in the geometry, the method calculates the cumulative length from the
22841	 * current point to the very beginning of the line.
22842	 *
22843	 * @return {Line} A reference to this line.
22844	 */
22845	computeLineDistances() {
22846
22847		const geometry = this.geometry;
22848
22849		// we assume non-indexed geometry
22850
22851		if ( geometry.index === null ) {
22852
22853			const positionAttribute = geometry.attributes.position;
22854			const lineDistances = [ 0 ];
22855
22856			for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
22857
22858				_vStart.fromBufferAttribute( positionAttribute, i - 1 );
22859				_vEnd.fromBufferAttribute( positionAttribute, i );
22860
22861				lineDistances[ i ] = lineDistances[ i - 1 ];
22862				lineDistances[ i ] += _vStart.distanceTo( _vEnd );
22863
22864			}
22865
22866			geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
22867
22868		} else {
22869
22870			console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
22871
22872		}
22873
22874		return this;
22875
22876	}
22877
22878	/**
22879	 * Computes intersection points between a casted ray and this line.
22880	 *
22881	 * @param {Raycaster} raycaster - The raycaster.
22882	 * @param {Array<Object>} intersects - The target array that holds the intersection points.
22883	 */
22884	raycast( raycaster, intersects ) {
22885
22886		const geometry = this.geometry;
22887		const matrixWorld = this.matrixWorld;
22888		const threshold = raycaster.params.Line.threshold;
22889		const drawRange = geometry.drawRange;
22890
22891		// Checking boundingSphere distance to ray
22892
22893		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
22894
22895		_sphere$1.copy( geometry.boundingSphere );
22896		_sphere$1.applyMatrix4( matrixWorld );
22897		_sphere$1.radius += threshold;
22898
22899		if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;
22900
22901		//
22902
22903		_inverseMatrix$1.copy( matrixWorld ).invert();
22904		_ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
22905
22906		const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
22907		const localThresholdSq = localThreshold * localThreshold;
22908
22909		const step = this.isLineSegments ? 2 : 1;
22910
22911		const index = geometry.index;
22912		const attributes = geometry.attributes;
22913		const positionAttribute = attributes.position;
22914
22915		if ( index !== null ) {
22916
22917			const start = Math.max( 0, drawRange.start );
22918			const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
22919
22920			for ( let i = start, l = end - 1; i < l; i += step ) {
22921
22922				const a = index.getX( i );
22923				const b = index.getX( i + 1 );
22924
22925				const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b, i );
22926
22927				if ( intersect ) {
22928
22929					intersects.push( intersect );
22930
22931				}
22932
22933			}
22934
22935			if ( this.isLineLoop ) {
22936
22937				const a = index.getX( end - 1 );
22938				const b = index.getX( start );
22939
22940				const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b, end - 1 );
22941
22942				if ( intersect ) {
22943
22944					intersects.push( intersect );
22945
22946				}
22947
22948			}
22949
22950		} else {
22951
22952			const start = Math.max( 0, drawRange.start );
22953			const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
22954
22955			for ( let i = start, l = end - 1; i < l; i += step ) {
22956
22957				const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, i, i + 1, i );
22958
22959				if ( intersect ) {
22960
22961					intersects.push( intersect );
22962
22963				}
22964
22965			}
22966
22967			if ( this.isLineLoop ) {
22968
22969				const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, end - 1, start, end - 1 );
22970
22971				if ( intersect ) {
22972
22973					intersects.push( intersect );
22974
22975				}
22976
22977			}
22978
22979		}
22980
22981	}
22982
22983	/**
22984	 * Sets the values of {@link Line#morphTargetDictionary} and {@link Line#morphTargetInfluences}
22985	 * to make sure existing morph targets can influence this 3D object.
22986	 */
22987	updateMorphTargets() {
22988
22989		const geometry = this.geometry;
22990
22991		const morphAttributes = geometry.morphAttributes;
22992		const keys = Object.keys( morphAttributes );
22993
22994		if ( keys.length > 0 ) {
22995
22996			const morphAttribute = morphAttributes[ keys[ 0 ] ];
22997
22998			if ( morphAttribute !== undefined ) {
22999
23000				this.morphTargetInfluences = [];
23001				this.morphTargetDictionary = {};
23002
23003				for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
23004
23005					const name = morphAttribute[ m ].name || String( m );
23006
23007					this.morphTargetInfluences.push( 0 );
23008					this.morphTargetDictionary[ name ] = m;
23009
23010				}
23011
23012			}
23013
23014		}
23015
23016	}
23017
23018}
23019
23020function checkIntersection( object, raycaster, ray, thresholdSq, a, b, i ) {
23021
23022	const positionAttribute = object.geometry.attributes.position;
23023
23024	_vStart.fromBufferAttribute( positionAttribute, a );
23025	_vEnd.fromBufferAttribute( positionAttribute, b );
23026
23027	const distSq = ray.distanceSqToSegment( _vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment );
23028
23029	if ( distSq > thresholdSq ) return;
23030
23031	_intersectPointOnRay.applyMatrix4( object.matrixWorld ); // Move back to world space for distance calculation
23032
23033	const distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay );
23034
23035	if ( distance < raycaster.near || distance > raycaster.far ) return;
23036
23037	return {
23038
23039		distance: distance,
23040		// What do we want? intersection point on the ray or on the segment??
23041		// point: raycaster.ray.at( distance ),
23042		point: _intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ),
23043		index: i,
23044		face: null,
23045		faceIndex: null,
23046		barycoord: null,
23047		object: object
23048
23049	};
23050
23051}
23052
23053/**
23054 * An abstract base class for creating an analytic curve object that contains methods
23055 * for interpolation.
23056 *
23057 * @abstract
23058 */
23059class Curve {
23060
23061	/**
23062	 * Constructs a new curve.
23063	 */
23064	constructor() {
23065
23066		/**
23067		 * The type property is used for detecting the object type
23068		 * in context of serialization/deserialization.
23069		 *
23070		 * @type {string}
23071		 * @readonly
23072		 */
23073		this.type = 'Curve';
23074
23075		/**
23076		 * This value determines the amount of divisions when calculating the
23077		 * cumulative segment lengths of a curve via {@link Curve#getLengths}. To ensure
23078		 * precision when using methods like {@link Curve#getSpacedPoints}, it is
23079		 * recommended to increase the value of this property if the curve is very large.
23080		 *
23081		 * @type {number}
23082		 * @default 200
23083		 */
23084		this.arcLengthDivisions = 200;
23085
23086		/**
23087		 * Must be set to `true` if the curve parameters have changed.
23088		 *
23089		 * @type {boolean}
23090		 * @default false
23091		 */
23092		this.needsUpdate = false;
23093
23094		/**
23095		 * An internal cache that holds precomputed curve length values.
23096		 *
23097		 * @private
23098		 * @type {?Array<number>}
23099		 * @default null
23100		 */
23101		this.cacheArcLengths = null;
23102
23103	}
23104
23105	/**
23106	 * This method returns a vector in 2D or 3D space (depending on the curve definition)
23107	 * for the given interpolation factor.
23108	 *
23109	 * @abstract
23110	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
23111	 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to.
23112	 * @return {(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition.
23113	 */
23114	getPoint( /* t, optionalTarget */ ) {
23115
23116		console.warn( 'THREE.
vendor: 10,031 bytes, lines 23116-23533
23116Curve: .getPoint() not implemented.' );
23117
23118	}
23119
23120	/**
23121	 * This method returns a vector in 2D or 3D space (depending on the curve definition)
23122	 * for the given interpolation factor. Unlike {@link Curve#getPoint}, this method honors the length
23123	 * of the curve which equidistant samples.
23124	 *
23125	 * @param {number} u - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
23126	 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to.
23127	 * @return {(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition.
23128	 */
23129	getPointAt( u, optionalTarget ) {
23130
23131		const t = this.getUtoTmapping( u );
23132		return this.getPoint( t, optionalTarget );
23133
23134	}
23135
23136	/**
23137	 * This method samples the curve via {@link Curve#getPoint} and returns an array of points representing
23138	 * the curve shape.
23139	 *
23140	 * @param {number} [divisions=5] - The number of divisions.
23141	 * @return {Array<(Vector2|Vector3)>} An array holding the sampled curve values. The number of points is `divisions + 1`.
23142	 */
23143	getPoints( divisions = 5 ) {
23144
23145		const points = [];
23146
23147		for ( let d = 0; d <= divisions; d ++ ) {
23148
23149			points.push( this.getPoint( d / divisions ) );
23150
23151		}
23152
23153		return points;
23154
23155	}
23156
23157	// Get sequence of points using getPointAt( u )
23158
23159	/**
23160	 * This method samples the curve via {@link Curve#getPointAt} and returns an array of points representing
23161	 * the curve shape. Unlike {@link Curve#getPoints}, this method returns equi-spaced points across the entire
23162	 * curve.
23163	 *
23164	 * @param {number} [divisions=5] - The number of divisions.
23165	 * @return {Array<(Vector2|Vector3)>} An array holding the sampled curve values. The number of points is `divisions + 1`.
23166	 */
23167	getSpacedPoints( divisions = 5 ) {
23168
23169		const points = [];
23170
23171		for ( let d = 0; d <= divisions; d ++ ) {
23172
23173			points.push( this.getPointAt( d / divisions ) );
23174
23175		}
23176
23177		return points;
23178
23179	}
23180
23181	/**
23182	 * Returns the total arc length of the curve.
23183	 *
23184	 * @return {number} The length of the curve.
23185	 */
23186	getLength() {
23187
23188		const lengths = this.getLengths();
23189		return lengths[ lengths.length - 1 ];
23190
23191	}
23192
23193	/**
23194	 * Returns an array of cumulative segment lengths of the curve.
23195	 *
23196	 * @param {number} [divisions=this.arcLengthDivisions] - The number of divisions.
23197	 * @return {Array<number>} An array holding the cumulative segment lengths.
23198	 */
23199	getLengths( divisions = this.arcLengthDivisions ) {
23200
23201		if ( this.cacheArcLengths &&
23202			( this.cacheArcLengths.length === divisions + 1 ) &&
23203			! this.needsUpdate ) {
23204
23205			return this.cacheArcLengths;
23206
23207		}
23208
23209		this.needsUpdate = false;
23210
23211		const cache = [];
23212		let current, last = this.getPoint( 0 );
23213		let sum = 0;
23214
23215		cache.push( 0 );
23216
23217		for ( let p = 1; p <= divisions; p ++ ) {
23218
23219			current = this.getPoint( p / divisions );
23220			sum += current.distanceTo( last );
23221			cache.push( sum );
23222			last = current;
23223
23224		}
23225
23226		this.cacheArcLengths = cache;
23227
23228		return cache; // { sums: cache, sum: sum }; Sum is in the last element.
23229
23230	}
23231
23232	/**
23233	 * Update the cumulative segment distance cache. The method must be called
23234	 * every time curve parameters are changed. If an updated curve is part of a
23235	 * composed curve like {@link CurvePath}, this method must be called on the
23236	 * composed curve, too.
23237	 */
23238	updateArcLengths() {
23239
23240		this.needsUpdate = true;
23241		this.getLengths();
23242
23243	}
23244
23245	/**
23246	 * Given an interpolation factor in the range `[0,1]`, this method returns an updated
23247	 * interpolation factor in the same range that can be ued to sample equidistant points
23248	 * from a curve.
23249	 *
23250	 * @param {number} u - The interpolation factor.
23251	 * @param {?number} distance - An optional distance on the curve.
23252	 * @return {number} The updated interpolation factor.
23253	 */
23254	getUtoTmapping( u, distance = null ) {
23255
23256		const arcLengths = this.getLengths();
23257
23258		let i = 0;
23259		const il = arcLengths.length;
23260
23261		let targetArcLength; // The targeted u distance value to get
23262
23263		if ( distance ) {
23264
23265			targetArcLength = distance;
23266
23267		} else {
23268
23269			targetArcLength = u * arcLengths[ il - 1 ];
23270
23271		}
23272
23273		// binary search for the index with largest value smaller than target u distance
23274
23275		let low = 0, high = il - 1, comparison;
23276
23277		while ( low <= high ) {
23278
23279			i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
23280
23281			comparison = arcLengths[ i ] - targetArcLength;
23282
23283			if ( comparison < 0 ) {
23284
23285				low = i + 1;
23286
23287			} else if ( comparison > 0 ) {
23288
23289				high = i - 1;
23290
23291			} else {
23292
23293				high = i;
23294				break;
23295
23296				// DONE
23297
23298			}
23299
23300		}
23301
23302		i = high;
23303
23304		if ( arcLengths[ i ] === targetArcLength ) {
23305
23306			return i / ( il - 1 );
23307
23308		}
23309
23310		// we could get finer grain at lengths, or use simple interpolation between two points
23311
23312		const lengthBefore = arcLengths[ i ];
23313		const lengthAfter = arcLengths[ i + 1 ];
23314
23315		const segmentLength = lengthAfter - lengthBefore;
23316
23317		// determine where we are between the 'before' and 'after' points
23318
23319		const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
23320
23321		// add that fractional amount to t
23322
23323		const t = ( i + segmentFraction ) / ( il - 1 );
23324
23325		return t;
23326
23327	}
23328
23329	/**
23330	 * Returns a unit vector tangent for the given interpolation factor.
23331	 * If the derived curve does not implement its tangent derivation,
23332	 * two points a small delta apart will be used to find its gradient
23333	 * which seems to give a reasonable approximation.
23334	 *
23335	 * @param {number} t - The interpolation factor.
23336	 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to.
23337	 * @return {(Vector2|Vector3)} The tangent vector.
23338	 */
23339	getTangent( t, optionalTarget ) {
23340
23341		const delta = 0.0001;
23342		let t1 = t - delta;
23343		let t2 = t + delta;
23344
23345		// Capping in case of danger
23346
23347		if ( t1 < 0 ) t1 = 0;
23348		if ( t2 > 1 ) t2 = 1;
23349
23350		const pt1 = this.getPoint( t1 );
23351		const pt2 = this.getPoint( t2 );
23352
23353		const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
23354
23355		tangent.copy( pt2 ).sub( pt1 ).normalize();
23356
23357		return tangent;
23358
23359	}
23360
23361	/**
23362	 * Same as {@link Curve#getTangent} but with equidistant samples.
23363	 *
23364	 * @param {number} u - The interpolation factor.
23365	 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to.
23366	 * @return {(Vector2|Vector3)} The tangent vector.
23367	 * @see {@link Curve#getPointAt}
23368	 */
23369	getTangentAt( u, optionalTarget ) {
23370
23371		const t = this.getUtoTmapping( u );
23372		return this.getTangent( t, optionalTarget );
23373
23374	}
23375
23376	/**
23377	 * Generates the Frenet Frames. Requires a curve definition in 3D space. Used
23378	 * in geometries like {@link TubeGeometry} or {@link ExtrudeGeometry}.
23379	 *
23380	 * @param {number} segments - The number of segments.
23381	 * @param {boolean} [closed=false] - Whether the curve is closed or not.
23382	 * @return {{tangents: Array<Vector3>, normals: Array<Vector3>, binormals: Array<Vector3>}} The Frenet Frames.
23383	 */
23384	computeFrenetFrames( segments, closed = false ) {
23385
23386		// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
23387
23388		const normal = new Vector3();
23389
23390		const tangents = [];
23391		const normals = [];
23392		const binormals = [];
23393
23394		const vec = new Vector3();
23395		const mat = new Matrix4();
23396
23397		// compute the tangent vectors for each segment on the curve
23398
23399		for ( let i = 0; i <= segments; i ++ ) {
23400
23401			const u = i / segments;
23402
23403			tangents[ i ] = this.getTangentAt( u, new Vector3() );
23404
23405		}
23406
23407		// select an initial normal vector perpendicular to the first tangent vector,
23408		// and in the direction of the minimum tangent xyz component
23409
23410		normals[ 0 ] = new Vector3();
23411		binormals[ 0 ] = new Vector3();
23412		let min = Number.MAX_VALUE;
23413		const tx = Math.abs( tangents[ 0 ].x );
23414		const ty = Math.abs( tangents[ 0 ].y );
23415		const tz = Math.abs( tangents[ 0 ].z );
23416
23417		if ( tx <= min ) {
23418
23419			min = tx;
23420			normal.set( 1, 0, 0 );
23421
23422		}
23423
23424		if ( ty <= min ) {
23425
23426			min = ty;
23427			normal.set( 0, 1, 0 );
23428
23429		}
23430
23431		if ( tz <= min ) {
23432
23433			normal.set( 0, 0, 1 );
23434
23435		}
23436
23437		vec.crossVectors( tangents[ 0 ], normal ).normalize();
23438
23439		normals[ 0 ].crossVectors( tangents[ 0 ], vec );
23440		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
23441
23442
23443		// compute the slowly-varying normal and binormal vectors for each segment on the curve
23444
23445		for ( let i = 1; i <= segments; i ++ ) {
23446
23447			normals[ i ] = normals[ i - 1 ].clone();
23448
23449			binormals[ i ] = binormals[ i - 1 ].clone();
23450
23451			vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
23452
23453			if ( vec.length() > Number.EPSILON ) {
23454
23455				vec.normalize();
23456
23457				const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors
23458
23459				normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
23460
23461			}
23462
23463			binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
23464
23465		}
23466
23467		// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
23468
23469		if ( closed === true ) {
23470
23471			let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), -1, 1 ) );
23472			theta /= segments;
23473
23474			if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
23475
23476				theta = - theta;
23477
23478			}
23479
23480			for ( let i = 1; i <= segments; i ++ ) {
23481
23482				// twist a little...
23483				normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
23484				binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
23485
23486			}
23487
23488		}
23489
23490		return {
23491			tangents: tangents,
23492			normals: normals,
23493			binormals: binormals
23494		};
23495
23496	}
23497
23498	/**
23499	 * Returns a new curve with copied values from this instance.
23500	 *
23501	 * @return {Curve} A clone of this instance.
23502	 */
23503	clone() {
23504
23505		return new this.constructor().copy( this );
23506
23507	}
23508
23509	/**
23510	 * Copies the values of the given curve to this instance.
23511	 *
23512	 * @param {Curve} source - The curve to copy.
23513	 * @return {Curve} A reference to this curve.
23514	 */
23515	copy( source ) {
23516
23517		this.arcLengthDivisions = source.arcLengthDivisions;
23518
23519		return this;
23520
23521	}
23522
23523	/**
23524	 * Serializes the curve into JSON.
23525	 *
23526	 * @return {Object} A JSON object representing the serialized curve.
23527	 * @see {@link ObjectLoader#parse}
23528	 */
23529	toJSON() {
23530
23531		const data = {
23532			metadata: {
23533				version: 4.
235336
vendor: 14,056 bytes, lines 23533-24174
23533,
23534				type: 'Curve',
23535				generator: 'Curve.toJSON'
23536			}
23537		};
23538
23539		data.arcLengthDivisions = this.arcLengthDivisions;
23540		data.type = this.type;
23541
23542		return data;
23543
23544	}
23545
23546	/**
23547	 * Deserializes the curve from the given JSON.
23548	 *
23549	 * @param {Object} json - The JSON holding the serialized curve.
23550	 * @return {Curve} A reference to this curve.
23551	 */
23552	fromJSON( json ) {
23553
23554		this.arcLengthDivisions = json.arcLengthDivisions;
23555
23556		return this;
23557
23558	}
23559
23560}
23561
23562/**
23563 * A curve representing an ellipse.
23564 *
23565 * ```js
23566 * const curve = new THREE.EllipseCurve(
23567 * 	0, 0,
23568 * 	10, 10,
23569 * 	0, 2 * Math.PI,
23570 * 	false,
23571 * 	0
23572 * );
23573 *
23574 * const points = curve.getPoints( 50 );
23575 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
23576 *
23577 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
23578 *
23579 * // Create the final object to add to the scene
23580 * const ellipse = new THREE.Line( geometry, material );
23581 * ```
23582 *
23583 * @augments Curve
23584 */
23585class EllipseCurve extends Curve {
23586
23587	/**
23588	 * Constructs a new ellipse curve.
23589	 *
23590	 * @param {number} [aX=0] - The X center of the ellipse.
23591	 * @param {number} [aY=0] - The Y center of the ellipse.
23592	 * @param {number} [xRadius=1] - The radius of the ellipse in the x direction.
23593	 * @param {number} [yRadius=1] - The radius of the ellipse in the y direction.
23594	 * @param {number} [aStartAngle=0] - The start angle of the curve in radians starting from the positive X axis.
23595	 * @param {number} [aEndAngle=Math.PI*2] - The end angle of the curve in radians starting from the positive X axis.
23596	 * @param {boolean} [aClockwise=false] - Whether the ellipse is drawn clockwise or not.
23597	 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis.
23598	 */
23599	constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {
23600
23601		super();
23602
23603		/**
23604		 * This flag can be used for type testing.
23605		 *
23606		 * @type {boolean}
23607		 * @readonly
23608		 * @default true
23609		 */
23610		this.isEllipseCurve = true;
23611
23612		this.type = 'EllipseCurve';
23613
23614		/**
23615		 * The X center of the ellipse.
23616		 *
23617		 * @type {number}
23618		 * @default 0
23619		 */
23620		this.aX = aX;
23621
23622		/**
23623		 * The Y center of the ellipse.
23624		 *
23625		 * @type {number}
23626		 * @default 0
23627		 */
23628		this.aY = aY;
23629
23630		/**
23631		 * The radius of the ellipse in the x direction.
23632		 * Setting the this value equal to the {@link EllipseCurve#yRadius} will result in a circle.
23633		 *
23634		 * @type {number}
23635		 * @default 1
23636		 */
23637		this.xRadius = xRadius;
23638
23639		/**
23640		 * The radius of the ellipse in the y direction.
23641		 * Setting the this value equal to the {@link EllipseCurve#xRadius} will result in a circle.
23642		 *
23643		 * @type {number}
23644		 * @default 1
23645		 */
23646		this.yRadius = yRadius;
23647
23648		/**
23649		 * The start angle of the curve in radians starting from the positive X axis.
23650		 *
23651		 * @type {number}
23652		 * @default 0
23653		 */
23654		this.aStartAngle = aStartAngle;
23655
23656		/**
23657		 * The end angle of the curve in radians starting from the positive X axis.
23658		 *
23659		 * @type {number}
23660		 * @default Math.PI*2
23661		 */
23662		this.aEndAngle = aEndAngle;
23663
23664		/**
23665		 * Whether the ellipse is drawn clockwise or not.
23666		 *
23667		 * @type {boolean}
23668		 * @default false
23669		 */
23670		this.aClockwise = aClockwise;
23671
23672		/**
23673		 * The rotation angle of the ellipse in radians, counterclockwise from the positive X axis.
23674		 *
23675		 * @type {number}
23676		 * @default 0
23677		 */
23678		this.aRotation = aRotation;
23679
23680	}
23681
23682	/**
23683	 * Returns a point on the curve.
23684	 *
23685	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
23686	 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to.
23687	 * @return {Vector2} The position on the curve.
23688	 */
23689	getPoint( t, optionalTarget = new Vector2() ) {
23690
23691		const point = optionalTarget;
23692
23693		const twoPi = Math.PI * 2;
23694		let deltaAngle = this.aEndAngle - this.aStartAngle;
23695		const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
23696
23697		// ensures that deltaAngle is 0 .. 2 PI
23698		while ( deltaAngle < 0 ) deltaAngle += twoPi;
23699		while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
23700
23701		if ( deltaAngle < Number.EPSILON ) {
23702
23703			if ( samePoints ) {
23704
23705				deltaAngle = 0;
23706
23707			} else {
23708
23709				deltaAngle = twoPi;
23710
23711			}
23712
23713		}
23714
23715		if ( this.aClockwise === true && ! samePoints ) {
23716
23717			if ( deltaAngle === twoPi ) {
23718
23719				deltaAngle = - twoPi;
23720
23721			} else {
23722
23723				deltaAngle = deltaAngle - twoPi;
23724
23725			}
23726
23727		}
23728
23729		const angle = this.aStartAngle + t * deltaAngle;
23730		let x = this.aX + this.xRadius * Math.cos( angle );
23731		let y = this.aY + this.yRadius * Math.sin( angle );
23732
23733		if ( this.aRotation !== 0 ) {
23734
23735			const cos = Math.cos( this.aRotation );
23736			const sin = Math.sin( this.aRotation );
23737
23738			const tx = x - this.aX;
23739			const ty = y - this.aY;
23740
23741			// Rotate the point about the center of the ellipse.
23742			x = tx * cos - ty * sin + this.aX;
23743			y = tx * sin + ty * cos + this.aY;
23744
23745		}
23746
23747		return point.set( x, y );
23748
23749	}
23750
23751	copy( source ) {
23752
23753		super.copy( source );
23754
23755		this.aX = source.aX;
23756		this.aY = source.aY;
23757
23758		this.xRadius = source.xRadius;
23759		this.yRadius = source.yRadius;
23760
23761		this.aStartAngle = source.aStartAngle;
23762		this.aEndAngle = source.aEndAngle;
23763
23764		this.aClockwise = source.aClockwise;
23765
23766		this.aRotation = source.aRotation;
23767
23768		return this;
23769
23770	}
23771
23772	toJSON() {
23773
23774		const data = super.toJSON();
23775
23776		data.aX = this.aX;
23777		data.aY = this.aY;
23778
23779		data.xRadius = this.xRadius;
23780		data.yRadius = this.yRadius;
23781
23782		data.aStartAngle = this.aStartAngle;
23783		data.aEndAngle = this.aEndAngle;
23784
23785		data.aClockwise = this.aClockwise;
23786
23787		data.aRotation = this.aRotation;
23788
23789		return data;
23790
23791	}
23792
23793	fromJSON( json ) {
23794
23795		super.fromJSON( json );
23796
23797		this.aX = json.aX;
23798		this.aY = json.aY;
23799
23800		this.xRadius = json.xRadius;
23801		this.yRadius = json.yRadius;
23802
23803		this.aStartAngle = json.aStartAngle;
23804		this.aEndAngle = json.aEndAngle;
23805
23806		this.aClockwise = json.aClockwise;
23807
23808		this.aRotation = json.aRotation;
23809
23810		return this;
23811
23812	}
23813
23814}
23815
23816/**
23817 * A curve representing an arc.
23818 *
23819 * @augments EllipseCurve
23820 */
23821class ArcCurve extends EllipseCurve {
23822
23823	/**
23824	 * Constructs a new arc curve.
23825	 *
23826	 * @param {number} [aX=0] - The X center of the ellipse.
23827	 * @param {number} [aY=0] - The Y center of the ellipse.
23828	 * @param {number} [aRadius=1] - The radius of the ellipse in the x direction.
23829	 * @param {number} [aStartAngle=0] - The start angle of the curve in radians starting from the positive X axis.
23830	 * @param {number} [aEndAngle=Math.PI*2] - The end angle of the curve in radians starting from the positive X axis.
23831	 * @param {boolean} [aClockwise=false] - Whether the ellipse is drawn clockwise or not.
23832	 */
23833	constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
23834
23835		super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
23836
23837		/**
23838		 * This flag can be used for type testing.
23839		 *
23840		 * @type {boolean}
23841		 * @readonly
23842		 * @default true
23843		 */
23844		this.isArcCurve = true;
23845
23846		this.type = 'ArcCurve';
23847
23848	}
23849
23850}
23851
23852function CubicPoly() {
23853
23854	/**
23855	 * Centripetal CatmullRom Curve - which is useful for avoiding
23856	* cusps and self-intersections in non-uniform catmull rom curves.
23857	* http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
23858	*
23859	* curve.type accepts centripetal(default), chordal and catmullrom
23860	* curve.tension is used for catmullrom which defaults to 0.5
23861	*/
23862
23863	/*
23864	Based on an optimized c++ solution in
23865	- http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
23866	- http://ideone.com/NoEbVM
23867
23868	This CubicPoly class could be used for reusing some variables and calculations,
23869	but for three.js curve use, it could be possible inlined and flatten into a single function call
23870	which can be placed in CurveUtils.
23871	*/
23872
23873	let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
23874
23875	/*
23876	 * Compute coefficients for a cubic polynomial
23877	 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
23878	 * such that
23879	 *   p(0) = x0, p(1) = x1
23880	 *  and
23881	 *   p'(0) = t0, p'(1) = t1.
23882	 */
23883	function init( x0, x1, t0, t1 ) {
23884
23885		c0 = x0;
23886		c1 = t0;
23887		c2 = -3 * x0 + 3 * x1 - 2 * t0 - t1;
23888		c3 = 2 * x0 - 2 * x1 + t0 + t1;
23889
23890	}
23891
23892	return {
23893
23894		initCatmullRom: function ( x0, x1, x2, x3, tension ) {
23895
23896			init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
23897
23898		},
23899
23900		initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
23901
23902			// compute tangents when parameterized in [t1,t2]
23903			let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
23904			let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
23905
23906			// rescale tangents for parametrization in [0,1]
23907			t1 *= dt1;
23908			t2 *= dt1;
23909
23910			init( x1, x2, t1, t2 );
23911
23912		},
23913
23914		calc: function ( t ) {
23915
23916			const t2 = t * t;
23917			const t3 = t2 * t;
23918			return c0 + c1 * t + c2 * t2 + c3 * t3;
23919
23920		}
23921
23922	};
23923
23924}
23925
23926//
23927
23928const tmp = /*@__PURE__*/ new Vector3();
23929const px = /*@__PURE__*/ new CubicPoly();
23930const py = /*@__PURE__*/ new CubicPoly();
23931const pz = /*@__PURE__*/ new CubicPoly();
23932
23933/**
23934 * A curve representing a Catmull-Rom spline.
23935 *
23936 * ```js
23937 * //Create a closed wavey loop
23938 * const curve = new THREE.CatmullRomCurve3( [
23939 * 	new THREE.Vector3( -10, 0, 10 ),
23940 * 	new THREE.Vector3( -5, 5, 5 ),
23941 * 	new THREE.Vector3( 0, 0, 0 ),
23942 * 	new THREE.Vector3( 5, -5, 5 ),
23943 * 	new THREE.Vector3( 10, 0, 10 )
23944 * ] );
23945 *
23946 * const points = curve.getPoints( 50 );
23947 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
23948 *
23949 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
23950 *
23951 * // Create the final object to add to the scene
23952 * const curveObject = new THREE.Line( geometry, material );
23953 * ```
23954 *
23955 * @augments Curve
23956 */
23957class CatmullRomCurve3 extends Curve {
23958
23959	/**
23960	 * Constructs a new Catmull-Rom curve.
23961	 *
23962	 * @param {Array<Vector3>} [points] - An array of 3D points defining the curve.
23963	 * @param {boolean} [closed=false] - Whether the curve is closed or not.
23964	 * @param {('centripetal'|'chordal'|'catmullrom')} [curveType='centripetal'] - The curve type.
23965	 * @param {number} [tension=0.5] - Tension of the curve.
23966	 */
23967	constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
23968
23969		super();
23970
23971		/**
23972		 * This flag can be used for type testing.
23973		 *
23974		 * @type {boolean}
23975		 * @readonly
23976		 * @default true
23977		 */
23978		this.isCatmullRomCurve3 = true;
23979
23980		this.type = 'CatmullRomCurve3';
23981
23982		/**
23983		 * An array of 3D points defining the curve.
23984		 *
23985		 * @type {Array<Vector3>}
23986		 */
23987		this.points = points;
23988
23989		/**
23990		 * Whether the curve is closed or not.
23991		 *
23992		 * @type {boolean}
23993		 * @default false
23994		 */
23995		this.closed = closed;
23996
23997		/**
23998		 * The curve type.
23999		 *
24000		 * @type {('centripetal'|'chordal'|'catmullrom')}
24001		 * @default 'centripetal'
24002		 */
24003		this.curveType = curveType;
24004
24005		/**
24006		 * Tension of the curve.
24007		 *
24008		 * @type {number}
24009		 * @default 0.5
24010		 */
24011		this.tension = tension;
24012
24013	}
24014
24015	/**
24016	 * Returns a point on the curve.
24017	 *
24018	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
24019	 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
24020	 * @return {Vector3} The position on the curve.
24021	 */
24022	getPoint( t, optionalTarget = new Vector3() ) {
24023
24024		const point = optionalTarget;
24025
24026		const points = this.points;
24027		const l = points.length;
24028
24029		const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
24030		let intPoint = Math.floor( p );
24031		let weight = p - intPoint;
24032
24033		if ( this.closed ) {
24034
24035			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
24036
24037		} else if ( weight === 0 && intPoint === l - 1 ) {
24038
24039			intPoint = l - 2;
24040			weight = 1;
24041
24042		}
24043
24044		let p0, p3; // 4 points (p1 & p2 defined below)
24045
24046		if ( this.closed || intPoint > 0 ) {
24047
24048			p0 = points[ ( intPoint - 1 ) % l ];
24049
24050		} else {
24051
24052			// extrapolate first point
24053			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
24054			p0 = tmp;
24055
24056		}
24057
24058		const p1 = points[ intPoint % l ];
24059		const p2 = points[ ( intPoint + 1 ) % l ];
24060
24061		if ( this.closed || intPoint + 2 < l ) {
24062
24063			p3 = points[ ( intPoint + 2 ) % l ];
24064
24065		} else {
24066
24067			// extrapolate last point
24068			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
24069			p3 = tmp;
24070
24071		}
24072
24073		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
24074
24075			// init Centripetal / Chordal Catmull-Rom
24076			const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
24077			let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
24078			let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
24079			let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
24080
24081			// safety check for repeated points
24082			if ( dt1 < 1e-4 ) dt1 = 1.0;
24083			if ( dt0 < 1e-4 ) dt0 = dt1;
24084			if ( dt2 < 1e-4 ) dt2 = dt1;
24085
24086			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
24087			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
24088			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
24089
24090		} else if ( this.curveType === 'catmullrom' ) {
24091
24092			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
24093			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
24094			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
24095
24096		}
24097
24098		point.set(
24099			px.calc( weight ),
24100			py.calc( weight ),
24101			pz.calc( weight )
24102		);
24103
24104		return point;
24105
24106	}
24107
24108	copy( source ) {
24109
24110		super.copy( source );
24111
24112		this.points = [];
24113
24114		for ( let i = 0, l = source.points.length; i < l; i ++ ) {
24115
24116			const point = source.points[ i ];
24117
24118			this.points.push( point.clone() );
24119
24120		}
24121
24122		this.closed = source.closed;
24123		this.curveType = source.curveType;
24124		this.tension = source.tension;
24125
24126		return this;
24127
24128	}
24129
24130	toJSON() {
24131
24132		const data = super.toJSON();
24133
24134		data.points = [];
24135
24136		for ( let i = 0, l = this.points.length; i < l; i ++ ) {
24137
24138			const point = this.points[ i ];
24139			data.points.push( point.toArray() );
24140
24141		}
24142
24143		data.closed = this.closed;
24144		data.curveType = this.curveType;
24145		data.tension = this.tension;
24146
24147		return data;
24148
24149	}
24150
24151	fromJSON( json ) {
24152
24153		super.fromJSON( json );
24154
24155		this.points = [];
24156
24157		for ( let i = 0, l = json.points.length; i < l; i ++ ) {
24158
24159			const point = json.points[ i ];
24160			this.points.push( new Vector3().fromArray( point ) );
24161
24162		}
24163
24164		this.closed = json.closed;
24165		this.curveType = json.curveType;
24166		this.tension = json.tension;
24167
24168		return this;
24169
24170	}
24171
24172}
24173
24174/
24174/ Bezier Curves formulas obtained from: https://en.wikipedia.org/wiki/B%C3%A9zier_curve
vendor: 28,440 bytes, lines 24174-25660
24174
24175
24176/**
24177 * Computes a point on a Catmull-Rom spline.
24178 *
24179 * @param {number} t - The interpolation factor.
24180 * @param {number} p0 - The first control point.
24181 * @param {number} p1 - The second control point.
24182 * @param {number} p2 - The third control point.
24183 * @param {number} p3 - The fourth control point.
24184 * @return {number} The calculated point on a Catmull-Rom spline.
24185 */
24186function CatmullRom( t, p0, p1, p2, p3 ) {
24187
24188	const v0 = ( p2 - p0 ) * 0.5;
24189	const v1 = ( p3 - p1 ) * 0.5;
24190	const t2 = t * t;
24191	const t3 = t * t2;
24192	return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( -3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
24193
24194}
24195
24196//
24197
24198function QuadraticBezierP0( t, p ) {
24199
24200	const k = 1 - t;
24201	return k * k * p;
24202
24203}
24204
24205function QuadraticBezierP1( t, p ) {
24206
24207	return 2 * ( 1 - t ) * t * p;
24208
24209}
24210
24211function QuadraticBezierP2( t, p ) {
24212
24213	return t * t * p;
24214
24215}
24216
24217/**
24218 * Computes a point on a Quadratic Bezier curve.
24219 *
24220 * @param {number} t - The interpolation factor.
24221 * @param {number} p0 - The first control point.
24222 * @param {number} p1 - The second control point.
24223 * @param {number} p2 - The third control point.
24224 * @return {number} The calculated point on a Quadratic Bezier curve.
24225 */
24226function QuadraticBezier( t, p0, p1, p2 ) {
24227
24228	return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
24229		QuadraticBezierP2( t, p2 );
24230
24231}
24232
24233//
24234
24235function CubicBezierP0( t, p ) {
24236
24237	const k = 1 - t;
24238	return k * k * k * p;
24239
24240}
24241
24242function CubicBezierP1( t, p ) {
24243
24244	const k = 1 - t;
24245	return 3 * k * k * t * p;
24246
24247}
24248
24249function CubicBezierP2( t, p ) {
24250
24251	return 3 * ( 1 - t ) * t * t * p;
24252
24253}
24254
24255function CubicBezierP3( t, p ) {
24256
24257	return t * t * t * p;
24258
24259}
24260
24261/**
24262 * Computes a point on a Cubic Bezier curve.
24263 *
24264 * @param {number} t - The interpolation factor.
24265 * @param {number} p0 - The first control point.
24266 * @param {number} p1 - The second control point.
24267 * @param {number} p2 - The third control point.
24268 * @param {number} p3 - The fourth control point.
24269 * @return {number} The calculated point on a Cubic Bezier curve.
24270 */
24271function CubicBezier( t, p0, p1, p2, p3 ) {
24272
24273	return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
24274		CubicBezierP3( t, p3 );
24275
24276}
24277
24278/**
24279 * A curve representing a 2D Cubic Bezier curve.
24280 *
24281 * ```js
24282 * const curve = new THREE.CubicBezierCurve(
24283 * 	new THREE.Vector2( - 0, 0 ),
24284 * 	new THREE.Vector2( - 5, 15 ),
24285 * 	new THREE.Vector2( 20, 15 ),
24286 * 	new THREE.Vector2( 10, 0 )
24287 * );
24288 *
24289 * const points = curve.getPoints( 50 );
24290 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
24291 *
24292 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
24293 *
24294 * // Create the final object to add to the scene
24295 * const curveObject = new THREE.Line( geometry, material );
24296 * ```
24297 *
24298 * @augments Curve
24299 */
24300class CubicBezierCurve extends Curve {
24301
24302	/**
24303	 * Constructs a new Cubic Bezier curve.
24304	 *
24305	 * @param {Vector2} [v0] - The start point.
24306	 * @param {Vector2} [v1] - The first control point.
24307	 * @param {Vector2} [v2] - The second control point.
24308	 * @param {Vector2} [v3] - The end point.
24309	 */
24310	constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
24311
24312		super();
24313
24314		/**
24315		 * This flag can be used for type testing.
24316		 *
24317		 * @type {boolean}
24318		 * @readonly
24319		 * @default true
24320		 */
24321		this.isCubicBezierCurve = true;
24322
24323		this.type = 'CubicBezierCurve';
24324
24325		/**
24326		 * The start point.
24327		 *
24328		 * @type {Vector2}
24329		 */
24330		this.v0 = v0;
24331
24332		/**
24333		 * The first control point.
24334		 *
24335		 * @type {Vector2}
24336		 */
24337		this.v1 = v1;
24338
24339		/**
24340		 * The second control point.
24341		 *
24342		 * @type {Vector2}
24343		 */
24344		this.v2 = v2;
24345
24346		/**
24347		 * The end point.
24348		 *
24349		 * @type {Vector2}
24350		 */
24351		this.v3 = v3;
24352
24353	}
24354
24355	/**
24356	 * Returns a point on the curve.
24357	 *
24358	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
24359	 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to.
24360	 * @return {Vector2} The position on the curve.
24361	 */
24362	getPoint( t, optionalTarget = new Vector2() ) {
24363
24364		const point = optionalTarget;
24365
24366		const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
24367
24368		point.set(
24369			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
24370			CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
24371		);
24372
24373		return point;
24374
24375	}
24376
24377	copy( source ) {
24378
24379		super.copy( source );
24380
24381		this.v0.copy( source.v0 );
24382		this.v1.copy( source.v1 );
24383		this.v2.copy( source.v2 );
24384		this.v3.copy( source.v3 );
24385
24386		return this;
24387
24388	}
24389
24390	toJSON() {
24391
24392		const data = super.toJSON();
24393
24394		data.v0 = this.v0.toArray();
24395		data.v1 = this.v1.toArray();
24396		data.v2 = this.v2.toArray();
24397		data.v3 = this.v3.toArray();
24398
24399		return data;
24400
24401	}
24402
24403	fromJSON( json ) {
24404
24405		super.fromJSON( json );
24406
24407		this.v0.fromArray( json.v0 );
24408		this.v1.fromArray( json.v1 );
24409		this.v2.fromArray( json.v2 );
24410		this.v3.fromArray( json.v3 );
24411
24412		return this;
24413
24414	}
24415
24416}
24417
24418/**
24419 * A curve representing a 3D Cubic Bezier curve.
24420 *
24421 * @augments Curve
24422 */
24423class CubicBezierCurve3 extends Curve {
24424
24425	/**
24426	 * Constructs a new Cubic Bezier curve.
24427	 *
24428	 * @param {Vector3} [v0] - The start point.
24429	 * @param {Vector3} [v1] - The first control point.
24430	 * @param {Vector3} [v2] - The second control point.
24431	 * @param {Vector3} [v3] - The end point.
24432	 */
24433	constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
24434
24435		super();
24436
24437		/**
24438		 * This flag can be used for type testing.
24439		 *
24440		 * @type {boolean}
24441		 * @readonly
24442		 * @default true
24443		 */
24444		this.isCubicBezierCurve3 = true;
24445
24446		this.type = 'CubicBezierCurve3';
24447
24448		/**
24449		 * The start point.
24450		 *
24451		 * @type {Vector3}
24452		 */
24453		this.v0 = v0;
24454
24455		/**
24456		 * The first control point.
24457		 *
24458		 * @type {Vector3}
24459		 */
24460		this.v1 = v1;
24461
24462		/**
24463		 * The second control point.
24464		 *
24465		 * @type {Vector3}
24466		 */
24467		this.v2 = v2;
24468
24469		/**
24470		 * The end point.
24471		 *
24472		 * @type {Vector3}
24473		 */
24474		this.v3 = v3;
24475
24476	}
24477
24478	/**
24479	 * Returns a point on the curve.
24480	 *
24481	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
24482	 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
24483	 * @return {Vector3} The position on the curve.
24484	 */
24485	getPoint( t, optionalTarget = new Vector3() ) {
24486
24487		const point = optionalTarget;
24488
24489		const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
24490
24491		point.set(
24492			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
24493			CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
24494			CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
24495		);
24496
24497		return point;
24498
24499	}
24500
24501	copy( source ) {
24502
24503		super.copy( source );
24504
24505		this.v0.copy( source.v0 );
24506		this.v1.copy( source.v1 );
24507		this.v2.copy( source.v2 );
24508		this.v3.copy( source.v3 );
24509
24510		return this;
24511
24512	}
24513
24514	toJSON() {
24515
24516		const data = super.toJSON();
24517
24518		data.v0 = this.v0.toArray();
24519		data.v1 = this.v1.toArray();
24520		data.v2 = this.v2.toArray();
24521		data.v3 = this.v3.toArray();
24522
24523		return data;
24524
24525	}
24526
24527	fromJSON( json ) {
24528
24529		super.fromJSON( json );
24530
24531		this.v0.fromArray( json.v0 );
24532		this.v1.fromArray( json.v1 );
24533		this.v2.fromArray( json.v2 );
24534		this.v3.fromArray( json.v3 );
24535
24536		return this;
24537
24538	}
24539
24540}
24541
24542/**
24543 * A curve representing a 2D line segment.
24544 *
24545 * @augments Curve
24546 */
24547class LineCurve extends Curve {
24548
24549	/**
24550	 * Constructs a new line curve.
24551	 *
24552	 * @param {Vector2} [v1] - The start point.
24553	 * @param {Vector2} [v2] - The end point.
24554	 */
24555	constructor( v1 = new Vector2(), v2 = new Vector2() ) {
24556
24557		super();
24558
24559		/**
24560		 * This flag can be used for type testing.
24561		 *
24562		 * @type {boolean}
24563		 * @readonly
24564		 * @default true
24565		 */
24566		this.isLineCurve = true;
24567
24568		this.type = 'LineCurve';
24569
24570		/**
24571		 * The start point.
24572		 *
24573		 * @type {Vector2}
24574		 */
24575		this.v1 = v1;
24576
24577		/**
24578		 * The end point.
24579		 *
24580		 * @type {Vector2}
24581		 */
24582		this.v2 = v2;
24583
24584	}
24585
24586	/**
24587	 * Returns a point on the line.
24588	 *
24589	 * @param {number} t - A interpolation factor representing a position on the line. Must be in the range `[0,1]`.
24590	 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to.
24591	 * @return {Vector2} The position on the line.
24592	 */
24593	getPoint( t, optionalTarget = new Vector2() ) {
24594
24595		const point = optionalTarget;
24596
24597		if ( t === 1 ) {
24598
24599			point.copy( this.v2 );
24600
24601		} else {
24602
24603			point.copy( this.v2 ).sub( this.v1 );
24604			point.multiplyScalar( t ).add( this.v1 );
24605
24606		}
24607
24608		return point;
24609
24610	}
24611
24612	// Line curve is linear, so we can overwrite default getPointAt
24613	getPointAt( u, optionalTarget ) {
24614
24615		return this.getPoint( u, optionalTarget );
24616
24617	}
24618
24619	getTangent( t, optionalTarget = new Vector2() ) {
24620
24621		return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
24622
24623	}
24624
24625	getTangentAt( u, optionalTarget ) {
24626
24627		return this.getTangent( u, optionalTarget );
24628
24629	}
24630
24631	copy( source ) {
24632
24633		super.copy( source );
24634
24635		this.v1.copy( source.v1 );
24636		this.v2.copy( source.v2 );
24637
24638		return this;
24639
24640	}
24641
24642	toJSON() {
24643
24644		const data = super.toJSON();
24645
24646		data.v1 = this.v1.toArray();
24647		data.v2 = this.v2.toArray();
24648
24649		return data;
24650
24651	}
24652
24653	fromJSON( json ) {
24654
24655		super.fromJSON( json );
24656
24657		this.v1.fromArray( json.v1 );
24658		this.v2.fromArray( json.v2 );
24659
24660		return this;
24661
24662	}
24663
24664}
24665
24666/**
24667 * A curve representing a 3D line segment.
24668 *
24669 * @augments Curve
24670 */
24671class LineCurve3 extends Curve {
24672
24673	/**
24674	 * Constructs a new line curve.
24675	 *
24676	 * @param {Vector3} [v1] - The start point.
24677	 * @param {Vector3} [v2] - The end point.
24678	 */
24679	constructor( v1 = new Vector3(), v2 = new Vector3() ) {
24680
24681		super();
24682
24683		/**
24684		 * This flag can be used for type testing.
24685		 *
24686		 * @type {boolean}
24687		 * @readonly
24688		 * @default true
24689		 */
24690		this.isLineCurve3 = true;
24691
24692		this.type = 'LineCurve3';
24693
24694		/**
24695		 * The start point.
24696		 *
24697		 * @type {Vector3}
24698		 */
24699		this.v1 = v1;
24700
24701		/**
24702		 * The end point.
24703		 *
24704		 * @type {Vector2}
24705		 */
24706		this.v2 = v2;
24707
24708	}
24709
24710	/**
24711	 * Returns a point on the line.
24712	 *
24713	 * @param {number} t - A interpolation factor representing a position on the line. Must be in the range `[0,1]`.
24714	 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
24715	 * @return {Vector3} The position on the line.
24716	 */
24717	getPoint( t, optionalTarget = new Vector3() ) {
24718
24719		const point = optionalTarget;
24720
24721		if ( t === 1 ) {
24722
24723			point.copy( this.v2 );
24724
24725		} else {
24726
24727			point.copy( this.v2 ).sub( this.v1 );
24728			point.multiplyScalar( t ).add( this.v1 );
24729
24730		}
24731
24732		return point;
24733
24734	}
24735
24736	// Line curve is linear, so we can overwrite default getPointAt
24737	getPointAt( u, optionalTarget ) {
24738
24739		return this.getPoint( u, optionalTarget );
24740
24741	}
24742
24743	getTangent( t, optionalTarget = new Vector3() ) {
24744
24745		return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
24746
24747	}
24748
24749	getTangentAt( u, optionalTarget ) {
24750
24751		return this.getTangent( u, optionalTarget );
24752
24753	}
24754
24755	copy( source ) {
24756
24757		super.copy( source );
24758
24759		this.v1.copy( source.v1 );
24760		this.v2.copy( source.v2 );
24761
24762		return this;
24763
24764	}
24765
24766	toJSON() {
24767
24768		const data = super.toJSON();
24769
24770		data.v1 = this.v1.toArray();
24771		data.v2 = this.v2.toArray();
24772
24773		return data;
24774
24775	}
24776
24777	fromJSON( json ) {
24778
24779		super.fromJSON( json );
24780
24781		this.v1.fromArray( json.v1 );
24782		this.v2.fromArray( json.v2 );
24783
24784		return this;
24785
24786	}
24787
24788}
24789
24790/**
24791 * A curve representing a 2D Quadratic Bezier curve.
24792 *
24793 * ```js
24794 * const curve = new THREE.QuadraticBezierCurve(
24795 * 	new THREE.Vector2( - 10, 0 ),
24796 * 	new THREE.Vector2( 20, 15 ),
24797 * 	new THREE.Vector2( 10, 0 )
24798 * )
24799 *
24800 * const points = curve.getPoints( 50 );
24801 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
24802 *
24803 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
24804 *
24805 * // Create the final object to add to the scene
24806 * const curveObject = new THREE.Line( geometry, material );
24807 * ```
24808 *
24809 * @augments Curve
24810 */
24811class QuadraticBezierCurve extends Curve {
24812
24813	/**
24814	 * Constructs a new Quadratic Bezier curve.
24815	 *
24816	 * @param {Vector2} [v0] - The start point.
24817	 * @param {Vector2} [v1] - The control point.
24818	 * @param {Vector2} [v2] - The end point.
24819	 */
24820	constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
24821
24822		super();
24823
24824		/**
24825		 * This flag can be used for type testing.
24826		 *
24827		 * @type {boolean}
24828		 * @readonly
24829		 * @default true
24830		 */
24831		this.isQuadraticBezierCurve = true;
24832
24833		this.type = 'QuadraticBezierCurve';
24834
24835		/**
24836		 * The start point.
24837		 *
24838		 * @type {Vector2}
24839		 */
24840		this.v0 = v0;
24841
24842		/**
24843		 * The control point.
24844		 *
24845		 * @type {Vector2}
24846		 */
24847		this.v1 = v1;
24848
24849		/**
24850		 * The end point.
24851		 *
24852		 * @type {Vector2}
24853		 */
24854		this.v2 = v2;
24855
24856	}
24857
24858	/**
24859	 * Returns a point on the curve.
24860	 *
24861	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
24862	 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to.
24863	 * @return {Vector2} The position on the curve.
24864	 */
24865	getPoint( t, optionalTarget = new Vector2() ) {
24866
24867		const point = optionalTarget;
24868
24869		const v0 = this.v0, v1 = this.v1, v2 = this.v2;
24870
24871		point.set(
24872			QuadraticBezier( t, v0.x, v1.x, v2.x ),
24873			QuadraticBezier( t, v0.y, v1.y, v2.y )
24874		);
24875
24876		return point;
24877
24878	}
24879
24880	copy( source ) {
24881
24882		super.copy( source );
24883
24884		this.v0.copy( source.v0 );
24885		this.v1.copy( source.v1 );
24886		this.v2.copy( source.v2 );
24887
24888		return this;
24889
24890	}
24891
24892	toJSON() {
24893
24894		const data = super.toJSON();
24895
24896		data.v0 = this.v0.toArray();
24897		data.v1 = this.v1.toArray();
24898		data.v2 = this.v2.toArray();
24899
24900		return data;
24901
24902	}
24903
24904	fromJSON( json ) {
24905
24906		super.fromJSON( json );
24907
24908		this.v0.fromArray( json.v0 );
24909		this.v1.fromArray( json.v1 );
24910		this.v2.fromArray( json.v2 );
24911
24912		return this;
24913
24914	}
24915
24916}
24917
24918/**
24919 * A curve representing a 3D Quadratic Bezier curve.
24920 *
24921 * @augments Curve
24922 */
24923class QuadraticBezierCurve3 extends Curve {
24924
24925	/**
24926	 * Constructs a new Quadratic Bezier curve.
24927	 *
24928	 * @param {Vector3} [v0] - The start point.
24929	 * @param {Vector3} [v1] - The control point.
24930	 * @param {Vector3} [v2] - The end point.
24931	 */
24932	constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
24933
24934		super();
24935
24936		/**
24937		 * This flag can be used for type testing.
24938		 *
24939		 * @type {boolean}
24940		 * @readonly
24941		 * @default true
24942		 */
24943		this.isQuadraticBezierCurve3 = true;
24944
24945		this.type = 'QuadraticBezierCurve3';
24946
24947		/**
24948		 * The start point.
24949		 *
24950		 * @type {Vector3}
24951		 */
24952		this.v0 = v0;
24953
24954		/**
24955		 * The control point.
24956		 *
24957		 * @type {Vector3}
24958		 */
24959		this.v1 = v1;
24960
24961		/**
24962		 * The end point.
24963		 *
24964		 * @type {Vector3}
24965		 */
24966		this.v2 = v2;
24967
24968	}
24969
24970	/**
24971	 * Returns a point on the curve.
24972	 *
24973	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
24974	 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
24975	 * @return {Vector3} The position on the curve.
24976	 */
24977	getPoint( t, optionalTarget = new Vector3() ) {
24978
24979		const point = optionalTarget;
24980
24981		const v0 = this.v0, v1 = this.v1, v2 = this.v2;
24982
24983		point.set(
24984			QuadraticBezier( t, v0.x, v1.x, v2.x ),
24985			QuadraticBezier( t, v0.y, v1.y, v2.y ),
24986			QuadraticBezier( t, v0.z, v1.z, v2.z )
24987		);
24988
24989		return point;
24990
24991	}
24992
24993	copy( source ) {
24994
24995		super.copy( source );
24996
24997		this.v0.copy( source.v0 );
24998		this.v1.copy( source.v1 );
24999		this.v2.copy( source.v2 );
25000
25001		return this;
25002
25003	}
25004
25005	toJSON() {
25006
25007		const data = super.toJSON();
25008
25009		data.v0 = this.v0.toArray();
25010		data.v1 = this.v1.toArray();
25011		data.v2 = this.v2.toArray();
25012
25013		return data;
25014
25015	}
25016
25017	fromJSON( json ) {
25018
25019		super.fromJSON( json );
25020
25021		this.v0.fromArray( json.v0 );
25022		this.v1.fromArray( json.v1 );
25023		this.v2.fromArray( json.v2 );
25024
25025		return this;
25026
25027	}
25028
25029}
25030
25031/**
25032 * A curve representing a 2D spline curve.
25033 *
25034 * ```js
25035 * // Create a sine-like wave
25036 * const curve = new THREE.SplineCurve( [
25037 * 	new THREE.Vector2( -10, 0 ),
25038 * 	new THREE.Vector2( -5, 5 ),
25039 * 	new THREE.Vector2( 0, 0 ),
25040 * 	new THREE.Vector2( 5, -5 ),
25041 * 	new THREE.Vector2( 10, 0 )
25042 * ] );
25043 *
25044 * const points = curve.getPoints( 50 );
25045 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
25046 *
25047 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
25048 *
25049 * // Create the final object to add to the scene
25050 * const splineObject = new THREE.Line( geometry, material );
25051 * ```
25052 *
25053 * @augments Curve
25054 */
25055class SplineCurve extends Curve {
25056
25057	/**
25058	 * Constructs a new 2D spline curve.
25059	 *
25060	 * @param {Array<Vector2>} [points] -  An array of 2D points defining the curve.
25061	 */
25062	constructor( points = [] ) {
25063
25064		super();
25065
25066		/**
25067		 * This flag can be used for type testing.
25068		 *
25069		 * @type {boolean}
25070		 * @readonly
25071		 * @default true
25072		 */
25073		this.isSplineCurve = true;
25074
25075		this.type = 'SplineCurve';
25076
25077		/**
25078		 * An array of 2D points defining the curve.
25079		 *
25080		 * @type {Array<Vector2>}
25081		 */
25082		this.points = points;
25083
25084	}
25085
25086	/**
25087	 * Returns a point on the curve.
25088	 *
25089	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
25090	 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to.
25091	 * @return {Vector2} The position on the curve.
25092	 */
25093	getPoint( t, optionalTarget = new Vector2() ) {
25094
25095		const point = optionalTarget;
25096
25097		const points = this.points;
25098		const p = ( points.length - 1 ) * t;
25099
25100		const intPoint = Math.floor( p );
25101		const weight = p - intPoint;
25102
25103		const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
25104		const p1 = points[ intPoint ];
25105		const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
25106		const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
25107
25108		point.set(
25109			CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
25110			CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
25111		);
25112
25113		return point;
25114
25115	}
25116
25117	copy( source ) {
25118
25119		super.copy( source );
25120
25121		this.points = [];
25122
25123		for ( let i = 0, l = source.points.length; i < l; i ++ ) {
25124
25125			const point = source.points[ i ];
25126
25127			this.points.push( point.clone() );
25128
25129		}
25130
25131		return this;
25132
25133	}
25134
25135	toJSON() {
25136
25137		const data = super.toJSON();
25138
25139		data.points = [];
25140
25141		for ( let i = 0, l = this.points.length; i < l; i ++ ) {
25142
25143			const point = this.points[ i ];
25144			data.points.push( point.toArray() );
25145
25146		}
25147
25148		return data;
25149
25150	}
25151
25152	fromJSON( json ) {
25153
25154		super.fromJSON( json );
25155
25156		this.points = [];
25157
25158		for ( let i = 0, l = json.points.length; i < l; i ++ ) {
25159
25160			const point = json.points[ i ];
25161			this.points.push( new Vector2().fromArray( point ) );
25162
25163		}
25164
25165		return this;
25166
25167	}
25168
25169}
25170
25171var Curves = /*#__PURE__*/Object.freeze({
25172	__proto__: null,
25173	ArcCurve: ArcCurve,
25174	CatmullRomCurve3: CatmullRomCurve3,
25175	CubicBezierCurve: CubicBezierCurve,
25176	CubicBezierCurve3: CubicBezierCurve3,
25177	EllipseCurve: EllipseCurve,
25178	LineCurve: LineCurve,
25179	LineCurve3: LineCurve3,
25180	QuadraticBezierCurve: QuadraticBezierCurve,
25181	QuadraticBezierCurve3: QuadraticBezierCurve3,
25182	SplineCurve: SplineCurve
25183});
25184
25185/**
25186 * A base class extending {@link Curve}. `CurvePath` is simply an
25187 * array of connected curves, but retains the API of a curve.
25188 *
25189 * @augments Curve
25190 */
25191class CurvePath extends Curve {
25192
25193	/**
25194	 * Constructs a new curve path.
25195	 */
25196	constructor() {
25197
25198		super();
25199
25200		this.type = 'CurvePath';
25201
25202		/**
25203		 * An array of curves defining the
25204		 * path.
25205		 *
25206		 * @type {Array<Curve>}
25207		 */
25208		this.curves = [];
25209
25210		/**
25211		 * Whether the path should automatically be closed
25212		 * by a line curve.
25213		 *
25214		 * @type {boolean}
25215		 * @default false
25216		 */
25217		this.autoClose = false;
25218
25219	}
25220
25221	/**
25222	 * Adds a curve to this curve path.
25223	 *
25224	 * @param {Curve} curve - The curve to add.
25225	 */
25226	add( curve ) {
25227
25228		this.curves.push( curve );
25229
25230	}
25231
25232	/**
25233	 * Adds a line curve to close the path.
25234	 *
25235	 * @return {CurvePath} A reference to this curve path.
25236	 */
25237	closePath() {
25238
25239		// Add a line curve if start and end of lines are not connected
25240		const startPoint = this.curves[ 0 ].getPoint( 0 );
25241		const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
25242
25243		if ( ! startPoint.equals( endPoint ) ) {
25244
25245			const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';
25246			this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );
25247
25248		}
25249
25250		return this;
25251
25252	}
25253
25254	/**
25255	 * This method returns a vector in 2D or 3D space (depending on the curve definitions)
25256	 * for the given interpolation factor.
25257	 *
25258	 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
25259	 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to.
25260	 * @return {?(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition.
25261	 */
25262	getPoint( t, optionalTarget ) {
25263
25264		// To get accurate point with reference to
25265		// entire path distance at time t,
25266		// following has to be done:
25267
25268		// 1. Length of each sub path have to be known
25269		// 2. Locate and identify type of curve
25270		// 3. Get t for the curve
25271		// 4. Return curve.getPointAt(t')
25272
25273		const d = t * this.getLength();
25274		const curveLengths = this.getCurveLengths();
25275		let i = 0;
25276
25277		// To think about boundaries points.
25278
25279		while ( i < curveLengths.length ) {
25280
25281			if ( curveLengths[ i ] >= d ) {
25282
25283				const diff = curveLengths[ i ] - d;
25284				const curve = this.curves[ i ];
25285
25286				const segmentLength = curve.getLength();
25287				const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
25288
25289				return curve.getPointAt( u, optionalTarget );
25290
25291			}
25292
25293			i ++;
25294
25295		}
25296
25297		return null;
25298
25299		// loop where sum != 0, sum > d , sum+1 <d
25300
25301	}
25302
25303	getLength() {
25304
25305		// We cannot use the default THREE.Curve getPoint() with getLength() because in
25306		// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
25307		// getPoint() depends on getLength
25308
25309		const lens = this.getCurveLengths();
25310		return lens[ lens.length - 1 ];
25311
25312	}
25313
25314	updateArcLengths() {
25315
25316		// cacheLengths must be recalculated.
25317
25318		this.needsUpdate = true;
25319		this.cacheLengths = null;
25320		this.getCurveLengths();
25321
25322	}
25323
25324	/**
25325	 * Returns list of cumulative curve lengths of the defined curves.
25326	 *
25327	 * @return {Array<number>} The curve lengths.
25328	 */
25329	getCurveLengths() {
25330
25331		// Compute lengths and cache them
25332		// We cannot overwrite getLengths() because UtoT mapping uses it.
25333		// We use cache values if curves and cache array are same length
25334
25335		if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
25336
25337			return this.cacheLengths;
25338
25339		}
25340
25341		// Get length of sub-curve
25342		// Push sums into cached array
25343
25344		const lengths = [];
25345		let sums = 0;
25346
25347		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
25348
25349			sums += this.curves[ i ].getLength();
25350			lengths.push( sums );
25351
25352		}
25353
25354		this.cacheLengths = lengths;
25355
25356		return lengths;
25357
25358	}
25359
25360	getSpacedPoints( divisions = 40 ) {
25361
25362		const points = [];
25363
25364		for ( let i = 0; i <= divisions; i ++ ) {
25365
25366			points.push( this.getPoint( i / divisions ) );
25367
25368		}
25369
25370		if ( this.autoClose ) {
25371
25372			points.push( points[ 0 ] );
25373
25374		}
25375
25376		return points;
25377
25378	}
25379
25380	getPoints( divisions = 12 ) {
25381
25382		const points = [];
25383		let last;
25384
25385		for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
25386
25387			const curve = curves[ i ];
25388			const resolution = curve.isEllipseCurve ? divisions * 2
25389				: ( curve.isLineCurve || curve.isLineCurve3 ) ? 1
25390					: curve.isSplineCurve ? divisions * curve.points.length
25391						: divisions;
25392
25393			const pts = curve.getPoints( resolution );
25394
25395			for ( let j = 0; j < pts.length; j ++ ) {
25396
25397				const point = pts[ j ];
25398
25399				if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
25400
25401				points.push( point );
25402				last = point;
25403
25404			}
25405
25406		}
25407
25408		if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
25409
25410			points.push( points[ 0 ] );
25411
25412		}
25413
25414		return points;
25415
25416	}
25417
25418	copy( source ) {
25419
25420		super.copy( source );
25421
25422		this.curves = [];
25423
25424		for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
25425
25426			const curve = source.curves[ i ];
25427
25428			this.curves.push( curve.clone() );
25429
25430		}
25431
25432		this.autoClose = source.autoClose;
25433
25434		return this;
25435
25436	}
25437
25438	toJSON() {
25439
25440		const data = super.toJSON();
25441
25442		data.autoClose = this.autoClose;
25443		data.curves = [];
25444
25445		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
25446
25447			const curve = this.curves[ i ];
25448			data.curves.push( curve.toJSON() );
25449
25450		}
25451
25452		return data;
25453
25454	}
25455
25456	fromJSON( json ) {
25457
25458		super.fromJSON( json );
25459
25460		this.autoClose = json.autoClose;
25461		this.curves = [];
25462
25463		for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
25464
25465			const curve = json.curves[ i ];
25466			this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
25467
25468		}
25469
25470		return this;
25471
25472	}
25473
25474}
25475
25476/**
25477 * A 2D path representation. The class provides methods for creating paths
25478 * and contours of 2D shapes similar to the 2D Canvas API.
25479 *
25480 * ```js
25481 * const path = new THREE.Path();
25482 *
25483 * path.lineTo( 0, 0.8 );
25484 * path.quadraticCurveTo( 0, 1, 0.2, 1 );
25485 * path.lineTo( 1, 1 );
25486 *
25487 * const points = path.getPoints();
25488 *
25489 * const geometry = new THREE.BufferGeometry().setFromPoints( points );
25490 * const material = new THREE.LineBasicMaterial( { color: 0xffffff } );
25491 *
25492 * const line = new THREE.Line( geometry, material );
25493 * scene.add( line );
25494 * ```
25495 *
25496 * @augments CurvePath
25497 */
25498class Path extends CurvePath {
25499
25500	/**
25501	 * Constructs a new path.
25502	 *
25503	 * @param {Array<Vector2>} [points] - An array of 2D points defining the path.
25504	 */
25505	constructor( points ) {
25506
25507		super();
25508
25509		this.type = 'Path';
25510
25511		/**
25512		 * The current offset of the path. Any new curve added will start here.
25513		 *
25514		 * @type {Vector2}
25515		 */
25516		this.currentPoint = new Vector2();
25517
25518		if ( points ) {
25519
25520			this.setFromPoints( points );
25521
25522		}
25523
25524	}
25525
25526	/**
25527	 * Creates a path from the given list of points. The points are added
25528	 * to the path as instances of {@link LineCurve}.
25529	 *
25530	 * @param {Array<Vector2>} points - An array of 2D points.
25531	 * @return {Path} A reference to this path.
25532	 */
25533	setFromPoints( points ) {
25534
25535		this.moveTo( points[ 0 ].x, points[ 0 ].y );
25536
25537		for ( let i = 1, l = points.length; i < l; i ++ ) {
25538
25539			this.lineTo( points[ i ].x, points[ i ].y );
25540
25541		}
25542
25543		return this;
25544
25545	}
25546
25547	/**
25548	 * Moves {@link Path#currentPoint} to the given point.
25549	 *
25550	 * @param {number} x - The x coordinate.
25551	 * @param {number} y - The y coordinate.
25552	 * @return {Path} A reference to this path.
25553	 */
25554	moveTo( x, y ) {
25555
25556		this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
25557
25558		return this;
25559
25560	}
25561
25562	/**
25563	 * Adds an instance of {@link LineCurve} to the path by connecting
25564	 * the current point with the given one.
25565	 *
25566	 * @param {number} x - The x coordinate of the end point.
25567	 * @param {number} y - The y coordinate of the end point.
25568	 * @return {Path} A reference to this path.
25569	 */
25570	lineTo( x, y ) {
25571
25572		const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
25573		this.curves.push( curve );
25574
25575		this.currentPoint.set( x, y );
25576
25577		return this;
25578
25579	}
25580
25581	/**
25582	 * Adds an instance of {@link QuadraticBezierCurve} to the path by connecting
25583	 * the current point with the given one.
25584	 *
25585	 * @param {number} aCPx - The x coordinate of the control point.
25586	 * @param {number} aCPy - The y coordinate of the control point.
25587	 * @param {number} aX - The x coordinate of the end point.
25588	 * @param {number} aY - The y coordinate of the end point.
25589	 * @return {Path} A reference to this path.
25590	 */
25591	quadraticCurveTo( aCPx, aCPy, aX, aY ) {
25592
25593		const curve = new QuadraticBezierCurve(
25594			this.currentPoint.clone(),
25595			new Vector2( aCPx, aCPy ),
25596			new Vector2( aX, aY )
25597		);
25598
25599		this.curves.push( curve );
25600
25601		this.currentPoint.set( aX, aY );
25602
25603		return this;
25604
25605	}
25606
25607	/**
25608	 * Adds an instance of {@link CubicBezierCurve} to the path by connecting
25609	 * the current point with the given one.
25610	 *
25611	 * @param {number} aCP1x - The x coordinate of the first control point.
25612	 * @param {number} aCP1y - The y coordinate of the first control point.
25613	 * @param {number} aCP2x - The x coordinate of the second control point.
25614	 * @param {number} aCP2y - The y coordinate of the second control point.
25615	 * @param {number} aX - The x coordinate of the end point.
25616	 * @param {number} aY - The y coordinate of the end point.
25617	 * @return {Path} A reference to this path.
25618	 */
25619	bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
25620
25621		const curve = new CubicBezierCurve(
25622			this.currentPoint.clone(),
25623			new Vector2( aCP1x, aCP1y ),
25624			new Vector2( aCP2x, aCP2y ),
25625			new Vector2( aX, aY )
25626		);
25627
25628		this.curves.push( curve );
25629
25630		this.currentPoint.set( aX, aY );
25631
25632		return this;
25633
25634	}
25635
25636	/**
25637	 * Adds an instance of {@link SplineCurve} to the path by connecting
25638	 * the current point with the given list of points.
25639	 *
25640	 * @param {Array<Vector2>} pts - An array of points in 2D space.
25641	 * @return {Path} A reference to this path.
25642	 */
25643	splineThru( pts ) {
25644
25645		const npts = [ this.currentPoint.clone() ].concat( pts );
25646
25647		const curve = new SplineCurve( npts );
25648		this.curves.push( curve );
25649
25650		this.currentPoint.copy( pts[ pts.length - 1 ] );
25651
25652		return this;
25653
25654	}
25655
25656	/**
25657	 * Adds an arc as an instance of {@link EllipseCurve} to the path, positioned relative
25658	 * to the current point.
25659	 *
25660	 * @param {number} 
25660aX - The x coordinate of the center of the arc offsetted from the previous curve.
25661	 * @param {number} aY - The y coordinate of the center of the arc offsetted from the previous curve.
25662	 * @param {number} aRadius - The radius of the arc.
25663	 * @param {number} aStartAngle - The start angle in radians.
25664	 * @param {number} aEndAngle - The end angle in radians.
25665	 * @param {boolean} [aClockwise=false] - Whether to sweep the arc clockwise or not.
25666	 * @return {Path} A reference to this path.
25667	 */
25668	arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
25669
25670		const x0 = this.currentPoint.x;
25671		const y0 = this.currentPoint.y;
25672
25673		this.absarc( aX + x0, aY + y0, aRadius,
25674			aStartAngle, aEndAngle, aClockwise );
25675
25676		return this;
25677
25678	}
25679
vendor: 31,426 bytes, lines 25680-26835
25680	/**
25681	 * Adds an absolutely positioned arc as an instance of {@link EllipseCurve} to the path.
25682	 *
25683	 * @param {number} aX - The x coordinate of the center of the arc.
25684	 * @param {number} aY - The y coordinate of the center of the arc.
25685	 * @param {number} aRadius - The radius of the arc.
25686	 * @param {number} aStartAngle - The start angle in radians.
25687	 * @param {number} aEndAngle - The end angle in radians.
25688	 * @param {boolean} [aClockwise=false] - Whether to sweep the arc clockwise or not.
25689	 * @return {Path} A reference to this path.
25690	 */
25691	absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
25692
25693		this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
25694
25695		return this;
25696
25697	}
25698
25699	/**
25700	 * Adds an ellipse as an instance of {@link EllipseCurve} to the path, positioned relative
25701	 * to the current point
25702	 *
25703	 * @param {number} aX - The x coordinate of the center of the ellipse offsetted from the previous curve.
25704	 * @param {number} aY - The y coordinate of the center of the ellipse offsetted from the previous curve.
25705	 * @param {number} xRadius - The radius of the ellipse in the x axis.
25706	 * @param {number} yRadius - The radius of the ellipse in the y axis.
25707	 * @param {number} aStartAngle - The start angle in radians.
25708	 * @param {number} aEndAngle - The end angle in radians.
25709	 * @param {boolean} [aClockwise=false] - Whether to sweep the ellipse clockwise or not.
25710	 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis.
25711	 * @return {Path} A reference to this path.
25712	 */
25713	ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
25714
25715		const x0 = this.currentPoint.x;
25716		const y0 = this.currentPoint.y;
25717
25718		this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
25719
25720		return this;
25721
25722	}
25723
25724	/**
25725	 * Adds an absolutely positioned ellipse as an instance of {@link EllipseCurve} to the path.
25726	 *
25727	 * @param {number} aX - The x coordinate of the absolute center of the ellipse.
25728	 * @param {number} aY - The y coordinate of the absolute center of the ellipse.
25729	 * @param {number} xRadius - The radius of the ellipse in the x axis.
25730	 * @param {number} yRadius - The radius of the ellipse in the y axis.
25731	 * @param {number} aStartAngle - The start angle in radians.
25732	 * @param {number} aEndAngle - The end angle in radians.
25733	 * @param {boolean} [aClockwise=false] - Whether to sweep the ellipse clockwise or not.
25734	 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis.
25735	 * @return {Path} A reference to this path.
25736	 */
25737	absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
25738
25739		const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
25740
25741		if ( this.curves.length > 0 ) {
25742
25743			// if a previous curve is present, attempt to join
25744			const firstPoint = curve.getPoint( 0 );
25745
25746			if ( ! firstPoint.equals( this.currentPoint ) ) {
25747
25748				this.lineTo( firstPoint.x, firstPoint.y );
25749
25750			}
25751
25752		}
25753
25754		this.curves.push( curve );
25755
25756		const lastPoint = curve.getPoint( 1 );
25757		this.currentPoint.copy( lastPoint );
25758
25759		return this;
25760
25761	}
25762
25763	copy( source ) {
25764
25765		super.copy( source );
25766
25767		this.currentPoint.copy( source.currentPoint );
25768
25769		return this;
25770
25771	}
25772
25773	toJSON() {
25774
25775		const data = super.toJSON();
25776
25777		data.currentPoint = this.currentPoint.toArray();
25778
25779		return data;
25780
25781	}
25782
25783	fromJSON( json ) {
25784
25785		super.fromJSON( json );
25786
25787		this.currentPoint.fromArray( json.currentPoint );
25788
25789		return this;
25790
25791	}
25792
25793}
25794
25795/**
25796 * A geometry class for representing a cylinder.
25797 *
25798 * ```js
25799 * const geometry = new THREE.CylinderGeometry( 5, 5, 20, 32 );
25800 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
25801 * const cylinder = new THREE.Mesh( geometry, material );
25802 * scene.add( cylinder );
25803 * ```
25804 *
25805 * @augments BufferGeometry
25806 */
25807class CylinderGeometry extends BufferGeometry {
25808
25809	/**
25810	 * Constructs a new cylinder geometry.
25811	 *
25812	 * @param {number} [radiusTop=1] - Radius of the cylinder at the top.
25813	 * @param {number} [radiusBottom=1] - Radius of the cylinder at the bottom.
25814	 * @param {number} [height=1] - Height of the cylinder.
25815	 * @param {number} [radialSegments=32] - Number of segmented faces around the circumference of the cylinder.
25816	 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the cylinder.
25817	 * @param {boolean} [openEnded=false] - Whether the base of the cylinder is open or capped.
25818	 * @param {number} [thetaStart=0] - Start angle for first segment, in radians.
25819	 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, of the circular sector, in radians.
25820	 * The default value results in a complete cylinder.
25821	 */
25822	constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
25823
25824		super();
25825
25826		this.type = 'CylinderGeometry';
25827
25828		/**
25829		 * Holds the constructor parameters that have been
25830		 * used to generate the geometry. Any modification
25831		 * after instantiation does not change the geometry.
25832		 *
25833		 * @type {Object}
25834		 */
25835		this.parameters = {
25836			radiusTop: radiusTop,
25837			radiusBottom: radiusBottom,
25838			height: height,
25839			radialSegments: radialSegments,
25840			heightSegments: heightSegments,
25841			openEnded: openEnded,
25842			thetaStart: thetaStart,
25843			thetaLength: thetaLength
25844		};
25845
25846		const scope = this;
25847
25848		radialSegments = Math.floor( radialSegments );
25849		heightSegments = Math.floor( heightSegments );
25850
25851		// buffers
25852
25853		const indices = [];
25854		const vertices = [];
25855		const normals = [];
25856		const uvs = [];
25857
25858		// helper variables
25859
25860		let index = 0;
25861		const indexArray = [];
25862		const halfHeight = height / 2;
25863		let groupStart = 0;
25864
25865		// generate geometry
25866
25867		generateTorso();
25868
25869		if ( openEnded === false ) {
25870
25871			if ( radiusTop > 0 ) generateCap( true );
25872			if ( radiusBottom > 0 ) generateCap( false );
25873
25874		}
25875
25876		// build geometry
25877
25878		this.setIndex( indices );
25879		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
25880		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
25881		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
25882
25883		function generateTorso() {
25884
25885			const normal = new Vector3();
25886			const vertex = new Vector3();
25887
25888			let groupCount = 0;
25889
25890			// this will be used to calculate the normal
25891			const slope = ( radiusBottom - radiusTop ) / height;
25892
25893			// generate vertices, normals and uvs
25894
25895			for ( let y = 0; y <= heightSegments; y ++ ) {
25896
25897				const indexRow = [];
25898
25899				const v = y / heightSegments;
25900
25901				// calculate the radius of the current row
25902
25903				const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
25904
25905				for ( let x = 0; x <= radialSegments; x ++ ) {
25906
25907					const u = x / radialSegments;
25908
25909					const theta = u * thetaLength + thetaStart;
25910
25911					const sinTheta = Math.sin( theta );
25912					const cosTheta = Math.cos( theta );
25913
25914					// vertex
25915
25916					vertex.x = radius * sinTheta;
25917					vertex.y = - v * height + halfHeight;
25918					vertex.z = radius * cosTheta;
25919					vertices.push( vertex.x, vertex.y, vertex.z );
25920
25921					// normal
25922
25923					normal.set( sinTheta, slope, cosTheta ).normalize();
25924					normals.push( normal.x, normal.y, normal.z );
25925
25926					// uv
25927
25928					uvs.push( u, 1 - v );
25929
25930					// save index of vertex in respective row
25931
25932					indexRow.push( index ++ );
25933
25934				}
25935
25936				// now save vertices of the row in our index array
25937
25938				indexArray.push( indexRow );
25939
25940			}
25941
25942			// generate indices
25943
25944			for ( let x = 0; x < radialSegments; x ++ ) {
25945
25946				for ( let y = 0; y < heightSegments; y ++ ) {
25947
25948					// we use the index array to access the correct indices
25949
25950					const a = indexArray[ y ][ x ];
25951					const b = indexArray[ y + 1 ][ x ];
25952					const c = indexArray[ y + 1 ][ x + 1 ];
25953					const d = indexArray[ y ][ x + 1 ];
25954
25955					// faces
25956
25957					if ( radiusTop > 0 || y !== 0 ) {
25958
25959						indices.push( a, b, d );
25960						groupCount += 3;
25961
25962					}
25963
25964					if ( radiusBottom > 0 || y !== heightSegments - 1 ) {
25965
25966						indices.push( b, c, d );
25967						groupCount += 3;
25968
25969					}
25970
25971				}
25972
25973			}
25974
25975			// add a group to the geometry. this will ensure multi material support
25976
25977			scope.addGroup( groupStart, groupCount, 0 );
25978
25979			// calculate new start value for groups
25980
25981			groupStart += groupCount;
25982
25983		}
25984
25985		function generateCap( top ) {
25986
25987			// save the index of the first center vertex
25988			const centerIndexStart = index;
25989
25990			const uv = new Vector2();
25991			const vertex = new Vector3();
25992
25993			let groupCount = 0;
25994
25995			const radius = ( top === true ) ? radiusTop : radiusBottom;
25996			const sign = ( top === true ) ? 1 : -1;
25997
25998			// first we generate the center vertex data of the cap.
25999			// because the geometry needs one set of uvs per face,
26000			// we must generate a center vertex per face/segment
26001
26002			for ( let x = 1; x <= radialSegments; x ++ ) {
26003
26004				// vertex
26005
26006				vertices.push( 0, halfHeight * sign, 0 );
26007
26008				// normal
26009
26010				normals.push( 0, sign, 0 );
26011
26012				// uv
26013
26014				uvs.push( 0.5, 0.5 );
26015
26016				// increase index
26017
26018				index ++;
26019
26020			}
26021
26022			// save the index of the last center vertex
26023			const centerIndexEnd = index;
26024
26025			// now we generate the surrounding vertices, normals and uvs
26026
26027			for ( let x = 0; x <= radialSegments; x ++ ) {
26028
26029				const u = x / radialSegments;
26030				const theta = u * thetaLength + thetaStart;
26031
26032				const cosTheta = Math.cos( theta );
26033				const sinTheta = Math.sin( theta );
26034
26035				// vertex
26036
26037				vertex.x = radius * sinTheta;
26038				vertex.y = halfHeight * sign;
26039				vertex.z = radius * cosTheta;
26040				vertices.push( vertex.x, vertex.y, vertex.z );
26041
26042				// normal
26043
26044				normals.push( 0, sign, 0 );
26045
26046				// uv
26047
26048				uv.x = ( cosTheta * 0.5 ) + 0.5;
26049				uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
26050				uvs.push( uv.x, uv.y );
26051
26052				// increase index
26053
26054				index ++;
26055
26056			}
26057
26058			// generate indices
26059
26060			for ( let x = 0; x < radialSegments; x ++ ) {
26061
26062				const c = centerIndexStart + x;
26063				const i = centerIndexEnd + x;
26064
26065				if ( top === true ) {
26066
26067					// face top
26068
26069					indices.push( i, i + 1, c );
26070
26071				} else {
26072
26073					// face bottom
26074
26075					indices.push( i + 1, i, c );
26076
26077				}
26078
26079				groupCount += 3;
26080
26081			}
26082
26083			// add a group to the geometry. this will ensure multi material support
26084
26085			scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
26086
26087			// calculate new start value for groups
26088
26089			groupStart += groupCount;
26090
26091		}
26092
26093	}
26094
26095	copy( source ) {
26096
26097		super.copy( source );
26098
26099		this.parameters = Object.assign( {}, source.parameters );
26100
26101		return this;
26102
26103	}
26104
26105	/**
26106	 * Factory method for creating an instance of this class from the given
26107	 * JSON object.
26108	 *
26109	 * @param {Object} data - A JSON object representing the serialized geometry.
26110	 * @return {CylinderGeometry} A new instance.
26111	 */
26112	static fromJSON( data ) {
26113
26114		return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
26115
26116	}
26117
26118}
26119
26120/**
26121 * A geometry class for representing a cone.
26122 *
26123 * ```js
26124 * const geometry = new THREE.ConeGeometry( 5, 20, 32 );
26125 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
26126 * const cone = new THREE.Mesh(geometry, material );
26127 * scene.add( cone );
26128 * ```
26129 *
26130 * @augments CylinderGeometry
26131 */
26132class ConeGeometry extends CylinderGeometry {
26133
26134	/**
26135	 * Constructs a new cone geometry.
26136	 *
26137	 * @param {number} [radius=1] - Radius of the cone base.
26138	 * @param {number} [height=1] - Height of the cone.
26139	 * @param {number} [radialSegments=32] - Number of segmented faces around the circumference of the cone.
26140	 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the cone.
26141	 * @param {boolean} [openEnded=false] - Whether the base of the cone is open or capped.
26142	 * @param {number} [thetaStart=0] - Start angle for first segment, in radians.
26143	 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, of the circular sector, in radians.
26144	 * The default value results in a complete cone.
26145	 */
26146	constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
26147
26148		super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
26149
26150		this.type = 'ConeGeometry';
26151
26152		/**
26153		 * Holds the constructor parameters that have been
26154		 * used to generate the geometry. Any modification
26155		 * after instantiation does not change the geometry.
26156		 *
26157		 * @type {Object}
26158		 */
26159		this.parameters = {
26160			radius: radius,
26161			height: height,
26162			radialSegments: radialSegments,
26163			heightSegments: heightSegments,
26164			openEnded: openEnded,
26165			thetaStart: thetaStart,
26166			thetaLength: thetaLength
26167		};
26168
26169	}
26170
26171	/**
26172	 * Factory method for creating an instance of this class from the given
26173	 * JSON object.
26174	 *
26175	 * @param {Object} data - A JSON object representing the serialized geometry.
26176	 * @return {ConeGeometry} A new instance.
26177	 */
26178	static fromJSON( data ) {
26179
26180		return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
26181
26182	}
26183
26184}
26185
26186/**
26187 * Defines an arbitrary 2d shape plane using paths with optional holes. It
26188 * can be used with {@link ExtrudeGeometry}, {@link ShapeGeometry}, to get
26189 * points, or to get triangulated faces.
26190 *
26191 * ```js
26192 * const heartShape = new THREE.Shape();
26193 *
26194 * heartShape.moveTo( 25, 25 );
26195 * heartShape.bezierCurveTo( 25, 25, 20, 0, 0, 0 );
26196 * heartShape.bezierCurveTo( - 30, 0, - 30, 35, - 30, 35 );
26197 * heartShape.bezierCurveTo( - 30, 55, - 10, 77, 25, 95 );
26198 * heartShape.bezierCurveTo( 60, 77, 80, 55, 80, 35 );
26199 * heartShape.bezierCurveTo( 80, 35, 80, 0, 50, 0 );
26200 * heartShape.bezierCurveTo( 35, 0, 25, 25, 25, 25 );
26201 *
26202 * const extrudeSettings = {
26203 * 	depth: 8,
26204 * 	bevelEnabled: true,
26205 * 	bevelSegments: 2,
26206 * 	steps: 2,
26207 * 	bevelSize: 1,
26208 * 	bevelThickness: 1
26209 * };
26210 *
26211 * const geometry = new THREE.ExtrudeGeometry( heartShape, extrudeSettings );
26212 * const mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial() );
26213 * ```
26214 *
26215 * @augments Path
26216 */
26217class Shape extends Path {
26218
26219	/**
26220	 * Constructs a new shape.
26221	 *
26222	 * @param {Array<Vector2>} [points] - An array of 2D points defining the shape.
26223	 */
26224	constructor( points ) {
26225
26226		super( points );
26227
26228		/**
26229		 * The UUID of the shape.
26230		 *
26231		 * @type {string}
26232		 * @readonly
26233		 */
26234		this.uuid = generateUUID();
26235
26236		this.type = 'Shape';
26237
26238		/**
26239		 * Defines the holes in the shape. Hole definitions must use the
26240		 * opposite winding order (CW/CCW) than the outer shape.
26241		 *
26242		 * @type {Array<Path>}
26243		 * @readonly
26244		 */
26245		this.holes = [];
26246
26247	}
26248
26249	/**
26250	 * Returns an array representing each contour of the holes
26251	 * as a list of 2D points.
26252	 *
26253	 * @param {number} divisions - The fineness of the result.
26254	 * @return {Array<Array<Vector2>>} The holes as a series of 2D points.
26255	 */
26256	getPointsHoles( divisions ) {
26257
26258		const holesPts = [];
26259
26260		for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
26261
26262			holesPts[ i ] = this.holes[ i ].getPoints( divisions );
26263
26264		}
26265
26266		return holesPts;
26267
26268	}
26269
26270	// get points of shape and holes (keypoints based on segments parameter)
26271
26272	/**
26273	 * Returns an object that holds contour data for the shape and its holes as
26274	 * arrays of 2D points.
26275	 *
26276	 * @param {number} divisions - The fineness of the result.
26277	 * @return {{shape:Array<Vector2>,holes:Array<Array<Vector2>>}} An object with contour data.
26278	 */
26279	extractPoints( divisions ) {
26280
26281		return {
26282
26283			shape: this.getPoints( divisions ),
26284			holes: this.getPointsHoles( divisions )
26285
26286		};
26287
26288	}
26289
26290	copy( source ) {
26291
26292		super.copy( source );
26293
26294		this.holes = [];
26295
26296		for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
26297
26298			const hole = source.holes[ i ];
26299
26300			this.holes.push( hole.clone() );
26301
26302		}
26303
26304		return this;
26305
26306	}
26307
26308	toJSON() {
26309
26310		const data = super.toJSON();
26311
26312		data.uuid = this.uuid;
26313		data.holes = [];
26314
26315		for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
26316
26317			const hole = this.holes[ i ];
26318			data.holes.push( hole.toJSON() );
26319
26320		}
26321
26322		return data;
26323
26324	}
26325
26326	fromJSON( json ) {
26327
26328		super.fromJSON( json );
26329
26330		this.uuid = json.uuid;
26331		this.holes = [];
26332
26333		for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
26334
26335			const hole = json.holes[ i ];
26336			this.holes.push( new Path().fromJSON( hole ) );
26337
26338		}
26339
26340		return this;
26341
26342	}
26343
26344}
26345
26346/* eslint-disable */
26347// copy of mapbox/earcut version 3.0.1
26348// https://github.com/mapbox/earcut/tree/v3.0.1
26349
26350function earcut(data, holeIndices, dim = 2) {
26351
26352    const hasHoles = holeIndices && holeIndices.length;
26353    const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
26354    let outerNode = linkedList(data, 0, outerLen, dim, true);
26355    const triangles = [];
26356
26357    if (!outerNode || outerNode.next === outerNode.prev) return triangles;
26358
26359    let minX, minY, invSize;
26360
26361    if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
26362
26363    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
26364    if (data.length > 80 * dim) {
26365        minX = Infinity;
26366        minY = Infinity;
26367        let maxX = -Infinity;
26368        let maxY = -Infinity;
26369
26370        for (let i = dim; i < outerLen; i += dim) {
26371            const x = data[i];
26372            const y = data[i + 1];
26373            if (x < minX) minX = x;
26374            if (y < minY) minY = y;
26375            if (x > maxX) maxX = x;
26376            if (y > maxY) maxY = y;
26377        }
26378
26379        // minX, minY and invSize are later used to transform coords into integers for z-order calculation
26380        invSize = Math.max(maxX - minX, maxY - minY);
26381        invSize = invSize !== 0 ? 32767 / invSize : 0;
26382    }
26383
26384    earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
26385
26386    return triangles;
26387}
26388
26389// create a circular doubly linked list from polygon points in the specified winding order
26390function linkedList(data, start, end, dim, clockwise) {
26391    let last;
26392
26393    if (clockwise === (signedArea(data, start, end, dim) > 0)) {
26394        for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
26395    } else {
26396        for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
26397    }
26398
26399    if (last && equals(last, last.next)) {
26400        removeNode(last);
26401        last = last.next;
26402    }
26403
26404    return last;
26405}
26406
26407// eliminate colinear or duplicate points
26408function filterPoints(start, end) {
26409    if (!start) return start;
26410    if (!end) end = start;
26411
26412    let p = start,
26413        again;
26414    do {
26415        again = false;
26416
26417        if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
26418            removeNode(p);
26419            p = end = p.prev;
26420            if (p === p.next) break;
26421            again = true;
26422
26423        } else {
26424            p = p.next;
26425        }
26426    } while (again || p !== end);
26427
26428    return end;
26429}
26430
26431// main ear slicing loop which triangulates a polygon (given as a linked list)
26432function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
26433    if (!ear) return;
26434
26435    // interlink polygon nodes in z-order
26436    if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
26437
26438    let stop = ear;
26439
26440    // iterate through ears, slicing them one by one
26441    while (ear.prev !== ear.next) {
26442        const prev = ear.prev;
26443        const next = ear.next;
26444
26445        if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
26446            triangles.push(prev.i, ear.i, next.i); // cut off the triangle
26447
26448            removeNode(ear);
26449
26450            // skipping the next vertex leads to less sliver triangles
26451            ear = next.next;
26452            stop = next.next;
26453
26454            continue;
26455        }
26456
26457        ear = next;
26458
26459        // if we looped through the whole remaining polygon and can't find any more ears
26460        if (ear === stop) {
26461            // try filtering points and slicing again
26462            if (!pass) {
26463                earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
26464
26465            // if this didn't work, try curing all small self-intersections locally
26466            } else if (pass === 1) {
26467                ear = cureLocalIntersections(filterPoints(ear), triangles);
26468                earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
26469
26470            // as a last resort, try splitting the remaining polygon into two
26471            } else if (pass === 2) {
26472                splitEarcut(ear, triangles, dim, minX, minY, invSize);
26473            }
26474
26475            break;
26476        }
26477    }
26478}
26479
26480// check whether a polygon node forms a valid ear with adjacent nodes
26481function isEar(ear) {
26482    const a = ear.prev,
26483        b = ear,
26484        c = ear.next;
26485
26486    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
26487
26488    // now make sure we don't have other points inside the potential ear
26489    const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
26490
26491    // triangle bbox
26492    const x0 = Math.min(ax, bx, cx),
26493        y0 = Math.min(ay, by, cy),
26494        x1 = Math.max(ax, bx, cx),
26495        y1 = Math.max(ay, by, cy);
26496
26497    let p = c.next;
26498    while (p !== a) {
26499        if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
26500            pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) &&
26501            area(p.prev, p, p.next) >= 0) return false;
26502        p = p.next;
26503    }
26504
26505    return true;
26506}
26507
26508function isEarHashed(ear, minX, minY, invSize) {
26509    const a = ear.prev,
26510        b = ear,
26511        c = ear.next;
26512
26513    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
26514
26515    const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
26516
26517    // triangle bbox
26518    const x0 = Math.min(ax, bx, cx),
26519        y0 = Math.min(ay, by, cy),
26520        x1 = Math.max(ax, bx, cx),
26521        y1 = Math.max(ay, by, cy);
26522
26523    // z-order range for the current triangle bbox;
26524    const minZ = zOrder(x0, y0, minX, minY, invSize),
26525        maxZ = zOrder(x1, y1, minX, minY, invSize);
26526
26527    let p = ear.prevZ,
26528        n = ear.nextZ;
26529
26530    // look for points inside the triangle in both directions
26531    while (p && p.z >= minZ && n && n.z <= maxZ) {
26532        if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
26533            pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
26534        p = p.prevZ;
26535
26536        if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
26537            pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
26538        n = n.nextZ;
26539    }
26540
26541    // look for remaining points in decreasing z-order
26542    while (p && p.z >= minZ) {
26543        if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
26544            pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
26545        p = p.prevZ;
26546    }
26547
26548    // look for remaining points in increasing z-order
26549    while (n && n.z <= maxZ) {
26550        if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
26551            pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
26552        n = n.nextZ;
26553    }
26554
26555    return true;
26556}
26557
26558// go through all polygon nodes and cure small local self-intersections
26559function cureLocalIntersections(start, triangles) {
26560    let p = start;
26561    do {
26562        const a = p.prev,
26563            b = p.next.next;
26564
26565        if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
26566
26567            triangles.push(a.i, p.i, b.i);
26568
26569            // remove two nodes involved
26570            removeNode(p);
26571            removeNode(p.next);
26572
26573            p = start = b;
26574        }
26575        p = p.next;
26576    } while (p !== start);
26577
26578    return filterPoints(p);
26579}
26580
26581// try splitting polygon into two and triangulate them independently
26582function splitEarcut(start, triangles, dim, minX, minY, invSize) {
26583    // look for a valid diagonal that divides the polygon into two
26584    let a = start;
26585    do {
26586        let b = a.next.next;
26587        while (b !== a.prev) {
26588            if (a.i !== b.i && isValidDiagonal(a, b)) {
26589                // split the polygon in two by the diagonal
26590                let c = splitPolygon(a, b);
26591
26592                // filter colinear points around the cuts
26593                a = filterPoints(a, a.next);
26594                c = filterPoints(c, c.next);
26595
26596                // run earcut on each half
26597                earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
26598                earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
26599                return;
26600            }
26601            b = b.next;
26602        }
26603        a = a.next;
26604    } while (a !== start);
26605}
26606
26607// link every hole into the outer loop, producing a single-ring polygon without holes
26608function eliminateHoles(data, holeIndices, outerNode, dim) {
26609    const queue = [];
26610
26611    for (let i = 0, len = holeIndices.length; i < len; i++) {
26612        const start = holeIndices[i] * dim;
26613        const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
26614        const list = linkedList(data, start, end, dim, false);
26615        if (list === list.next) list.steiner = true;
26616        queue.push(getLeftmost(list));
26617    }
26618
26619    queue.sort(compareXYSlope);
26620
26621    // process holes from left to right
26622    for (let i = 0; i < queue.length; i++) {
26623        outerNode = eliminateHole(queue[i], outerNode);
26624    }
26625
26626    return outerNode;
26627}
26628
26629function compareXYSlope(a, b) {
26630    let result = a.x - b.x;
26631    // when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find
26632    // the bridge to the outer shell is always the point that they meet at.
26633    if (result === 0) {
26634        result = a.y - b.y;
26635        if (result === 0) {
26636            const aSlope = (a.next.y - a.y) / (a.next.x - a.x);
26637            const bSlope = (b.next.y - b.y) / (b.next.x - b.x);
26638            result = aSlope - bSlope;
26639        }
26640    }
26641    return result;
26642}
26643
26644// find a bridge between vertices that connects hole with an outer ring and and link it
26645function eliminateHole(hole, outerNode) {
26646    const bridge = findHoleBridge(hole, outerNode);
26647    if (!bridge) {
26648        return outerNode;
26649    }
26650
26651    const bridgeReverse = splitPolygon(bridge, hole);
26652
26653    // filter collinear points around the cuts
26654    filterPoints(bridgeReverse, bridgeReverse.next);
26655    return filterPoints(bridge, bridge.next);
26656}
26657
26658// David Eberly's algorithm for finding a bridge between hole and outer polygon
26659function findHoleBridge(hole, outerNode) {
26660    let p = outerNode;
26661    const hx = hole.x;
26662    const hy = hole.y;
26663    let qx = -Infinity;
26664    let m;
26665
26666    // find a segment intersected by a ray from the hole's leftmost point to the left;
26667    // segment's endpoint with lesser x will be potential connection point
26668    // unless they intersect at a vertex, then choose the vertex
26669    if (equals(hole, p)) return p;
26670    do {
26671        if (equals(hole, p.next)) return p.next;
26672        else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
26673            const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
26674            if (x <= hx && x > qx) {
26675                qx = x;
26676                m = p.x < p.next.x ? p : p.next;
26677                if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
26678            }
26679        }
26680        p = p.next;
26681    } while (p !== outerNode);
26682
26683    if (!m) return null;
26684
26685    // look for points inside the triangle of hole point, segment intersection and endpoint;
26686    // if there are no points found, we have a valid connection;
26687    // otherwise choose the point of the minimum angle with the ray as connection point
26688
26689    const stop = m;
26690    const mx = m.x;
26691    const my = m.y;
26692    let tanMin = Infinity;
26693
26694    p = m;
26695
26696    do {
26697        if (hx >= p.x && p.x >= mx && hx !== p.x &&
26698                pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
26699
26700            const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
26701
26702            if (locallyInside(p, hole) &&
26703                (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
26704                m = p;
26705                tanMin = tan;
26706            }
26707        }
26708
26709        p = p.next;
26710    } while (p !== stop);
26711
26712    return m;
26713}
26714
26715// whether sector in vertex m contains sector in vertex p in the same coordinates
26716function sectorContainsSector(m, p) {
26717    return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
26718}
26719
26720// interlink polygon nodes in z-order
26721function indexCurve(start, minX, minY, invSize) {
26722    let p = start;
26723    do {
26724        if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
26725        p.prevZ = p.prev;
26726        p.nextZ = p.next;
26727        p = p.next;
26728    } while (p !== start);
26729
26730    p.prevZ.nextZ = null;
26731    p.prevZ = null;
26732
26733    sortLinked(p);
26734}
26735
26736// Simon Tatham's linked list merge sort algorithm
26737// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
26738function sortLinked(list) {
26739    let numMerges;
26740    let inSize = 1;
26741
26742    do {
26743        let p = list;
26744        let e;
26745        list = null;
26746        let tail = null;
26747        numMerges = 0;
26748
26749        while (p) {
26750            numMerges++;
26751            let q = p;
26752            let pSize = 0;
26753            for (let i = 0; i < inSize; i++) {
26754                pSize++;
26755                q = q.nextZ;
26756                if (!q) break;
26757            }
26758            let qSize = inSize;
26759
26760            while (pSize > 0 || (qSize > 0 && q)) {
26761
26762                if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
26763                    e = p;
26764                    p = p.nextZ;
26765                    pSize--;
26766                } else {
26767                    e = q;
26768                    q = q.nextZ;
26769                    qSize--;
26770                }
26771
26772                if (tail) tail.nextZ = e;
26773                else list = e;
26774
26775                e.prevZ = tail;
26776                tail = e;
26777            }
26778
26779            p = q;
26780        }
26781
26782        tail.nextZ = null;
26783        inSize *= 2;
26784
26785    } while (numMerges > 1);
26786
26787    return list;
26788}
26789
26790// z-order of a point given coords and inverse of the longer side of data bbox
26791function zOrder(x, y, minX, minY, invSize) {
26792    // coords are transformed into non-negative 15-bit integer range
26793    x = (x - minX) * invSize | 0;
26794    y = (y - minY) * invSize | 0;
26795
26796    x = (x | (x << 8)) & 0x00FF00FF;
26797    x = (x | (x << 4)) & 0x0F0F0F0F;
26798    x = (x | (x << 2)) & 0x33333333;
26799    x = (x | (x << 1)) & 0x55555555;
26800
26801    y = (y | (y << 8)) & 0x00FF00FF;
26802    y = (y | (y << 4)) & 0x0F0F0F0F;
26803    y = (y | (y << 2)) & 0x33333333;
26804    y = (y | (y << 1)) & 0x55555555;
26805
26806    return x | (y << 1);
26807}
26808
26809// find the leftmost node of a polygon ring
26810function getLeftmost(start) {
26811    let p = start,
26812        leftmost = start;
26813    do {
26814        if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
26815        p = p.next;
26816    } while (p !== start);
26817
26818    return leftmost;
26819}
26820
26821// check if a point lies within a convex triangle
26822function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
26823    return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
26824           (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
26825           (bx - px) * (cy - py) >= (cx - px) * (by - py);
26826}
26827
26828// check if a point lies within a convex triangle but false if its equal to the first point of the triangle
26829function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) {
26830    return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py);
26831}
26832
26833// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
26834function isValidDiagonal(a, b) {
26835    return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones
vendor: 4,345 bytes, lines 26835-26981
26835't intersect other edges
26836           (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
26837            (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
26838            equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case
26839}
26840
26841// signed area of a triangle
26842function area(p, q, r) {
26843    return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
26844}
26845
26846// check if two points are equal
26847function equals(p1, p2) {
26848    return p1.x === p2.x && p1.y === p2.y;
26849}
26850
26851// check if two segments intersect
26852function intersects(p1, q1, p2, q2) {
26853    const o1 = sign(area(p1, q1, p2));
26854    const o2 = sign(area(p1, q1, q2));
26855    const o3 = sign(area(p2, q2, p1));
26856    const o4 = sign(area(p2, q2, q1));
26857
26858    if (o1 !== o2 && o3 !== o4) return true; // general case
26859
26860    if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
26861    if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
26862    if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
26863    if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
26864
26865    return false;
26866}
26867
26868// for collinear points p, q, r, check if point q lies on segment pr
26869function onSegment(p, q, r) {
26870    return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
26871}
26872
26873function sign(num) {
26874    return num > 0 ? 1 : num < 0 ? -1 : 0;
26875}
26876
26877// check if a polygon diagonal intersects any polygon segments
26878function intersectsPolygon(a, b) {
26879    let p = a;
26880    do {
26881        if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
26882                intersects(p, p.next, a, b)) return true;
26883        p = p.next;
26884    } while (p !== a);
26885
26886    return false;
26887}
26888
26889// check if a polygon diagonal is locally inside the polygon
26890function locallyInside(a, b) {
26891    return area(a.prev, a, a.next) < 0 ?
26892        area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
26893        area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
26894}
26895
26896// check if the middle point of a polygon diagonal is inside the polygon
26897function middleInside(a, b) {
26898    let p = a;
26899    let inside = false;
26900    const px = (a.x + b.x) / 2;
26901    const py = (a.y + b.y) / 2;
26902    do {
26903        if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
26904                (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
26905            inside = !inside;
26906        p = p.next;
26907    } while (p !== a);
26908
26909    return inside;
26910}
26911
26912// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
26913// if one belongs to the outer ring and another to a hole, it merges it into a single ring
26914function splitPolygon(a, b) {
26915    const a2 = createNode(a.i, a.x, a.y),
26916        b2 = createNode(b.i, b.x, b.y),
26917        an = a.next,
26918        bp = b.prev;
26919
26920    a.next = b;
26921    b.prev = a;
26922
26923    a2.next = an;
26924    an.prev = a2;
26925
26926    b2.next = a2;
26927    a2.prev = b2;
26928
26929    bp.next = b2;
26930    b2.prev = bp;
26931
26932    return b2;
26933}
26934
26935// create a node and optionally link it with previous one (in a circular doubly linked list)
26936function insertNode(i, x, y, last) {
26937    const p = createNode(i, x, y);
26938
26939    if (!last) {
26940        p.prev = p;
26941        p.next = p;
26942
26943    } else {
26944        p.next = last.next;
26945        p.prev = last;
26946        last.next.prev = p;
26947        last.next = p;
26948    }
26949    return p;
26950}
26951
26952function removeNode(p) {
26953    p.next.prev = p.prev;
26954    p.prev.next = p.next;
26955
26956    if (p.prevZ) p.prevZ.nextZ = p.nextZ;
26957    if (p.nextZ) p.nextZ.prevZ = p.prevZ;
26958}
26959
26960function createNode(i, x, y) {
26961    return {
26962        i, // vertex index in coordinates array
26963        x, y, // vertex coordinates
26964        prev: null, // previous and next vertex nodes in a polygon ring
26965        next: null,
26966        z: 0, // z-order curve value
26967        prevZ: null, // previous and next nodes in z-order
26968        nextZ: null,
26969        steiner: false // indicates whether this is a steiner point
26970    };
26971}
26972
26973function signedArea(data, start, end, dim) {
26974    let sum = 0;
26975    for (let i = start, j = end - dim; i < end; i += dim) {
26976        sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
26977        j = i;
26978    }
26979    return sum;
26980}
26981
vendor: 25,005 bytes, lines 26982-28082
26982class Earcut {
26983
26984	/**
26985	 * Triangulates the given shape definition by returning an array of triangles.
26986	 *
26987	 * @param {Array<number>} data - An array with 2D points.
26988	 * @param {Array<number>} holeIndices - An array with indices defining holes.
26989	 * @param {number} [dim=2] - The number of coordinates per vertex in the input array.
26990	 * @return {Array<number>} An array representing the triangulated faces. Each face is defined by three consecutive numbers
26991	 * representing vertex indices.
26992	 */
26993	static triangulate( data, holeIndices, dim = 2 ) {
26994
26995		return earcut( data, holeIndices, dim );
26996
26997	}
26998
26999}
27000
27001/**
27002 * A class containing utility functions for shapes.
27003 *
27004 * @hideconstructor
27005 */
27006class ShapeUtils {
27007
27008	/**
27009	 * Calculate area of a ( 2D ) contour polygon.
27010	 *
27011	 * @param {Array<Vector2>} contour - An array of 2D points.
27012	 * @return {number} The area.
27013	 */
27014	static area( contour ) {
27015
27016		const n = contour.length;
27017		let a = 0.0;
27018
27019		for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
27020
27021			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
27022
27023		}
27024
27025		return a * 0.5;
27026
27027	}
27028
27029	/**
27030	 * Returns `true` if the given contour uses a clockwise winding order.
27031	 *
27032	 * @param {Array<Vector2>} pts - An array of 2D points defining a polygon.
27033	 * @return {boolean} Whether the given contour uses a clockwise winding order or not.
27034	 */
27035	static isClockWise( pts ) {
27036
27037		return ShapeUtils.area( pts ) < 0;
27038
27039	}
27040
27041	/**
27042	 * Triangulates the given shape definition.
27043	 *
27044	 * @param {Array<Vector2>} contour - An array of 2D points defining the contour.
27045	 * @param {Array<Array<Vector2>>} holes - An array that holds arrays of 2D points defining the holes.
27046	 * @return {Array<Array<number>>} An array that holds for each face definition an array with three indices.
27047	 */
27048	static triangulateShape( contour, holes ) {
27049
27050		const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
27051		const holeIndices = []; // array of hole indices
27052		const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
27053
27054		removeDupEndPts( contour );
27055		addContour( vertices, contour );
27056
27057		//
27058
27059		let holeIndex = contour.length;
27060
27061		holes.forEach( removeDupEndPts );
27062
27063		for ( let i = 0; i < holes.length; i ++ ) {
27064
27065			holeIndices.push( holeIndex );
27066			holeIndex += holes[ i ].length;
27067			addContour( vertices, holes[ i ] );
27068
27069		}
27070
27071		//
27072
27073		const triangles = Earcut.triangulate( vertices, holeIndices );
27074
27075		//
27076
27077		for ( let i = 0; i < triangles.length; i += 3 ) {
27078
27079			faces.push( triangles.slice( i, i + 3 ) );
27080
27081		}
27082
27083		return faces;
27084
27085	}
27086
27087}
27088
27089function removeDupEndPts( points ) {
27090
27091	const l = points.length;
27092
27093	if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
27094
27095		points.pop();
27096
27097	}
27098
27099}
27100
27101function addContour( vertices, contour ) {
27102
27103	for ( let i = 0; i < contour.length; i ++ ) {
27104
27105		vertices.push( contour[ i ].x );
27106		vertices.push( contour[ i ].y );
27107
27108	}
27109
27110}
27111
27112/**
27113 * Creates extruded geometry from a path shape.
27114 *
27115 * ```js
27116 * const length = 12, width = 8;
27117 *
27118 * const shape = new THREE.Shape();
27119 * shape.moveTo( 0,0 );
27120 * shape.lineTo( 0, width );
27121 * shape.lineTo( length, width );
27122 * shape.lineTo( length, 0 );
27123 * shape.lineTo( 0, 0 );
27124 *
27125 * const geometry = new THREE.ExtrudeGeometry( shape );
27126 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
27127 * const mesh = new THREE.Mesh( geometry, material ) ;
27128 * scene.add( mesh );
27129 * ```
27130 *
27131 * @augments BufferGeometry
27132 */
27133class ExtrudeGeometry extends BufferGeometry {
27134
27135	/**
27136	 * Constructs a new extrude geometry.
27137	 *
27138	 * @param {Shape|Array<Shape>} [shapes] - A shape or an array of shapes.
27139	 * @param {ExtrudeGeometry~Options} [options] - The extrude settings.
27140	 */
27141	constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( -0.5, 0.5 ), new Vector2( -0.5, -0.5 ), new Vector2( 0.5, -0.5 ) ] ), options = {} ) {
27142
27143		super();
27144
27145		this.type = 'ExtrudeGeometry';
27146
27147		/**
27148		 * Holds the constructor parameters that have been
27149		 * used to generate the geometry. Any modification
27150		 * after instantiation does not change the geometry.
27151		 *
27152		 * @type {Object}
27153		 */
27154		this.parameters = {
27155			shapes: shapes,
27156			options: options
27157		};
27158
27159		shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
27160
27161		const scope = this;
27162
27163		const verticesArray = [];
27164		const uvArray = [];
27165
27166		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
27167
27168			const shape = shapes[ i ];
27169			addShape( shape );
27170
27171		}
27172
27173		// build geometry
27174
27175		this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
27176		this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
27177
27178		this.computeVertexNormals();
27179
27180		// functions
27181
27182		function addShape( shape ) {
27183
27184			const placeholder = [];
27185
27186			// options
27187
27188			const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
27189			const steps = options.steps !== undefined ? options.steps : 1;
27190			const depth = options.depth !== undefined ? options.depth : 1;
27191
27192			let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
27193			let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;
27194			let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;
27195			let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
27196			let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
27197
27198			const extrudePath = options.extrudePath;
27199
27200			const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
27201
27202			//
27203
27204			let extrudePts, extrudeByPath = false;
27205			let splineTube, binormal, normal, position2;
27206
27207			if ( extrudePath ) {
27208
27209				extrudePts = extrudePath.getSpacedPoints( steps );
27210
27211				extrudeByPath = true;
27212				bevelEnabled = false; // bevels not supported for path extrusion
27213
27214				// SETUP TNB variables
27215
27216				// TODO1 - have a .isClosed in spline?
27217
27218				splineTube = extrudePath.computeFrenetFrames( steps, false );
27219
27220				// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
27221
27222				binormal = new Vector3();
27223				normal = new Vector3();
27224				position2 = new Vector3();
27225
27226			}
27227
27228			// Safeguards if bevels are not enabled
27229
27230			if ( ! bevelEnabled ) {
27231
27232				bevelSegments = 0;
27233				bevelThickness = 0;
27234				bevelSize = 0;
27235				bevelOffset = 0;
27236
27237			}
27238
27239			// Variables initialization
27240
27241			const shapePoints = shape.extractPoints( curveSegments );
27242
27243			let vertices = shapePoints.shape;
27244			const holes = shapePoints.holes;
27245
27246			const reverse = ! ShapeUtils.isClockWise( vertices );
27247
27248			if ( reverse ) {
27249
27250				vertices = vertices.reverse();
27251
27252				// Maybe we should also check if holes are in the opposite direction, just to be safe ...
27253
27254				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
27255
27256					const ahole = holes[ h ];
27257
27258					if ( ShapeUtils.isClockWise( ahole ) ) {
27259
27260						holes[ h ] = ahole.reverse();
27261
27262					}
27263
27264				}
27265
27266			}
27267
27268			/**Merges index-adjacent points that are within a threshold distance of each other. Array is modified in-place. Threshold distance is empirical, and scaled based on the magnitude of point coordinates.
27269			 * @param {Array<Vector2>} points
27270			*/
27271			function mergeOverlappingPoints( points ) {
27272
27273				const THRESHOLD = 1e-10;
27274				const THRESHOLD_SQ = THRESHOLD * THRESHOLD;
27275				let prevPos = points[ 0 ];
27276				for ( let i = 1; i <= points.length; i ++ ) {
27277
27278					const currentIndex = i % points.length;
27279					const currentPos = points[ currentIndex ];
27280					const dx = currentPos.x - prevPos.x;
27281					const dy = currentPos.y - prevPos.y;
27282					const distSq = dx * dx + dy * dy;
27283
27284					const scalingFactorSqrt = Math.max(
27285						Math.abs( currentPos.x ),
27286						Math.abs( currentPos.y ),
27287						Math.abs( prevPos.x ),
27288						Math.abs( prevPos.y )
27289					);
27290					const thesholdSqScaled = THRESHOLD_SQ * scalingFactorSqrt * scalingFactorSqrt;
27291					if ( distSq <= thesholdSqScaled ) {
27292
27293						points.splice( currentIndex, 1 );
27294						i --;
27295						continue;
27296
27297					}
27298
27299					prevPos = currentPos;
27300
27301				}
27302
27303			}
27304
27305			mergeOverlappingPoints( vertices );
27306			holes.forEach( mergeOverlappingPoints );
27307
27308			const numHoles = holes.length;
27309
27310			/* Vertices */
27311
27312			const contour = vertices; // vertices has all points but contour has only points of circumference
27313
27314			for ( let h = 0; h < numHoles; h ++ ) {
27315
27316				const ahole = holes[ h ];
27317
27318				vertices = vertices.concat( ahole );
27319
27320			}
27321
27322
27323			function scalePt2( pt, vec, size ) {
27324
27325				if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
27326
27327				return pt.clone().addScaledVector( vec, size );
27328
27329			}
27330
27331			const vlen = vertices.length;
27332
27333
27334			// Find directions for point movement
27335
27336
27337			function getBevelVec( inPt, inPrev, inNext ) {
27338
27339				// computes for inPt the corresponding point inPt' on a new contour
27340				//   shifted by 1 unit (length of normalized vector) to the left
27341				// if we walk along contour clockwise, this new contour is outside the old one
27342				//
27343				// inPt' is the intersection of the two lines parallel to the two
27344				//  adjacent edges of inPt at a distance of 1 unit on the left side.
27345
27346				let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
27347
27348				// good reading for geometry algorithms (here: line-line intersection)
27349				// http://geomalgorithms.com/a05-_intersect-1.html
27350
27351				const v_prev_x = inPt.x - inPrev.x,
27352					v_prev_y = inPt.y - inPrev.y;
27353				const v_next_x = inNext.x - inPt.x,
27354					v_next_y = inNext.y - inPt.y;
27355
27356				const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
27357
27358				// check for collinear edges
27359				const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
27360
27361				if ( Math.abs( collinear0 ) > Number.EPSILON ) {
27362
27363					// not collinear
27364
27365					// length of vectors for normalizing
27366
27367					const v_prev_len = Math.sqrt( v_prev_lensq );
27368					const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
27369
27370					// shift adjacent points by unit vectors to the left
27371
27372					const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
27373					const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
27374
27375					const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
27376					const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
27377
27378					// scaling factor for v_prev to intersection point
27379
27380					const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
27381							( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
27382						( v_prev_x * v_next_y - v_prev_y * v_next_x );
27383
27384					// vector from inPt to intersection point
27385
27386					v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
27387					v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
27388
27389					// Don't normalize!, otherwise sharp corners become ugly
27390					//  but prevent crazy spikes
27391					const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
27392					if ( v_trans_lensq <= 2 ) {
27393
27394						return new Vector2( v_trans_x, v_trans_y );
27395
27396					} else {
27397
27398						shrink_by = Math.sqrt( v_trans_lensq / 2 );
27399
27400					}
27401
27402				} else {
27403
27404					// handle special case of collinear edges
27405
27406					let direction_eq = false; // assumes: opposite
27407
27408					if ( v_prev_x > Number.EPSILON ) {
27409
27410						if ( v_next_x > Number.EPSILON ) {
27411
27412							direction_eq = true;
27413
27414						}
27415
27416					} else {
27417
27418						if ( v_prev_x < - Number.EPSILON ) {
27419
27420							if ( v_next_x < - Number.EPSILON ) {
27421
27422								direction_eq = true;
27423
27424							}
27425
27426						} else {
27427
27428							if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
27429
27430								direction_eq = true;
27431
27432							}
27433
27434						}
27435
27436					}
27437
27438					if ( direction_eq ) {
27439
27440						// console.log("Warning: lines are a straight sequence");
27441						v_trans_x = - v_prev_y;
27442						v_trans_y = v_prev_x;
27443						shrink_by = Math.sqrt( v_prev_lensq );
27444
27445					} else {
27446
27447						// console.log("Warning: lines are a straight spike");
27448						v_trans_x = v_prev_x;
27449						v_trans_y = v_prev_y;
27450						shrink_by = Math.sqrt( v_prev_lensq / 2 );
27451
27452					}
27453
27454				}
27455
27456				return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
27457
27458			}
27459
27460
27461			const contourMovements = [];
27462
27463			for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
27464
27465				if ( j === il ) j = 0;
27466				if ( k === il ) k = 0;
27467
27468				//  (j)---(i)---(k)
27469				// console.log('i,j,k', i, j , k)
27470
27471				contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
27472
27473			}
27474
27475			const holesMovements = [];
27476			let oneHoleMovements, verticesMovements = contourMovements.concat();
27477
27478			for ( let h = 0, hl = numHoles; h < hl; h ++ ) {
27479
27480				const ahole = holes[ h ];
27481
27482				oneHoleMovements = [];
27483
27484				for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
27485
27486					if ( j === il ) j = 0;
27487					if ( k === il ) k = 0;
27488
27489					//  (j)---(i)---(k)
27490					oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
27491
27492				}
27493
27494				holesMovements.push( oneHoleMovements );
27495				verticesMovements = verticesMovements.concat( oneHoleMovements );
27496
27497			}
27498
27499			const contractedContourVertices = [];
27500			const expandedHoleVertices = [];
27501
27502			// Loop bevelSegments, 1 for the front, 1 for the back
27503
27504			for ( let b = 0; b < bevelSegments; b ++ ) {
27505
27506				//for ( b = bevelSegments; b > 0; b -- ) {
27507
27508				const t = b / bevelSegments;
27509				const z = bevelThickness * Math.cos( t * Math.PI / 2 );
27510				const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
27511
27512				// contract shape
27513
27514				for ( let i = 0, il = contour.length; i < il; i ++ ) {
27515
27516					const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
27517
27518					v( vert.x, vert.y, - z );
27519					if ( t == 0 ) contractedContourVertices.push( vert );
27520
27521				}
27522
27523				// expand holes
27524
27525				for ( let h = 0, hl = numHoles; h < hl; h ++ ) {
27526
27527					const ahole = holes[ h ];
27528					oneHoleMovements = holesMovements[ h ];
27529					const oneHoleVertices = [];
27530					for ( let i = 0, il = ahole.length; i < il; i ++ ) {
27531
27532						const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
27533
27534						v( vert.x, vert.y, - z );
27535						if ( t == 0 ) oneHoleVertices.push( vert );
27536
27537					}
27538
27539					if ( t == 0 ) expandedHoleVertices.push( oneHoleVertices );
27540
27541				}
27542
27543			}
27544
27545			const faces = ShapeUtils.triangulateShape( contractedContourVertices, expandedHoleVertices );
27546
27547			const flen = faces.length;
27548
27549			const bs = bevelSize + bevelOffset;
27550
27551			// Back facing vertices
27552
27553			for ( let i = 0; i < vlen; i ++ ) {
27554
27555				const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
27556
27557				if ( ! extrudeByPath ) {
27558
27559					v( vert.x, vert.y, 0 );
27560
27561				} else {
27562
27563					// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
27564
27565					normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
27566					binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
27567
27568					position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
27569
27570					v( position2.x, position2.y, position2.z );
27571
27572				}
27573
27574			}
27575
27576			// Add stepped vertices...
27577			// Including front facing vertices
27578
27579			for ( let s = 1; s <= steps; s ++ ) {
27580
27581				for ( let i = 0; i < vlen; i ++ ) {
27582
27583					const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
27584
27585					if ( ! extrudeByPath ) {
27586
27587						v( vert.x, vert.y, depth / steps * s );
27588
27589					} else {
27590
27591						// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
27592
27593						normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
27594						binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
27595
27596						position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
27597
27598						v( position2.x, position2.y, position2.z );
27599
27600					}
27601
27602				}
27603
27604			}
27605
27606
27607			// Add bevel segments planes
27608
27609			//for ( b = 1; b <= bevelSegments; b ++ ) {
27610			for ( let b = bevelSegments - 1; b >= 0; b -- ) {
27611
27612				const t = b / bevelSegments;
27613				const z = bevelThickness * Math.cos( t * Math.PI / 2 );
27614				const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
27615
27616				// contract shape
27617
27618				for ( let i = 0, il = contour.length; i < il; i ++ ) {
27619
27620					const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
27621					v( vert.x, vert.y, depth + z );
27622
27623				}
27624
27625				// expand holes
27626
27627				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
27628
27629					const ahole = holes[ h ];
27630					oneHoleMovements = holesMovements[ h ];
27631
27632					for ( let i = 0, il = ahole.length; i < il; i ++ ) {
27633
27634						const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
27635
27636						if ( ! extrudeByPath ) {
27637
27638							v( vert.x, vert.y, depth + z );
27639
27640						} else {
27641
27642							v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
27643
27644						}
27645
27646					}
27647
27648				}
27649
27650			}
27651
27652			/* Faces */
27653
27654			// Top and bottom faces
27655
27656			buildLidFaces();
27657
27658			// Sides faces
27659
27660			buildSideFaces();
27661
27662
27663			/////  Internal functions
27664
27665			function buildLidFaces() {
27666
27667				const start = verticesArray.length / 3;
27668
27669				if ( bevelEnabled ) {
27670
27671					let layer = 0; // steps + 1
27672					let offset = vlen * layer;
27673
27674					// Bottom faces
27675
27676					for ( let i = 0; i < flen; i ++ ) {
27677
27678						const face = faces[ i ];
27679						f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
27680
27681					}
27682
27683					layer = steps + bevelSegments * 2;
27684					offset = vlen * layer;
27685
27686					// Top faces
27687
27688					for ( let i = 0; i < flen; i ++ ) {
27689
27690						const face = faces[ i ];
27691						f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
27692
27693					}
27694
27695				} else {
27696
27697					// Bottom faces
27698
27699					for ( let i = 0; i < flen; i ++ ) {
27700
27701						const face = faces[ i ];
27702						f3( face[ 2 ], face[ 1 ], face[ 0 ] );
27703
27704					}
27705
27706					// Top faces
27707
27708					for ( let i = 0; i < flen; i ++ ) {
27709
27710						const face = faces[ i ];
27711						f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
27712
27713					}
27714
27715				}
27716
27717				scope.addGroup( start, verticesArray.length / 3 - start, 0 );
27718
27719			}
27720
27721			// Create faces for the z-sides of the shape
27722
27723			function buildSideFaces() {
27724
27725				const start = verticesArray.length / 3;
27726				let layeroffset = 0;
27727				sidewalls( contour, layeroffset );
27728				layeroffset += contour.length;
27729
27730				for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
27731
27732					const ahole = holes[ h ];
27733					sidewalls( ahole, layeroffset );
27734
27735					//, true
27736					layeroffset += ahole.length;
27737
27738				}
27739
27740
27741				scope.addGroup( start, verticesArray.length / 3 - start, 1 );
27742
27743
27744			}
27745
27746			function sidewalls( contour, layeroffset ) {
27747
27748				let i = contour.length;
27749
27750				while ( -- i >= 0 ) {
27751
27752					const j = i;
27753					let k = i - 1;
27754					if ( k < 0 ) k = contour.length - 1;
27755
27756					//console.log('b', i,j, i-1, k,vertices.length);
27757
27758					for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
27759
27760						const slen1 = vlen * s;
27761						const slen2 = vlen * ( s + 1 );
27762
27763						const a = layeroffset + j + slen1,
27764							b = layeroffset + k + slen1,
27765							c = layeroffset + k + slen2,
27766							d = layeroffset + j + slen2;
27767
27768						f4( a, b, c, d );
27769
27770					}
27771
27772				}
27773
27774			}
27775
27776			function v( x, y, z ) {
27777
27778				placeholder.push( x );
27779				placeholder.push( y );
27780				placeholder.push( z );
27781
27782			}
27783
27784
27785			function f3( a, b, c ) {
27786
27787				addVertex( a );
27788				addVertex( b );
27789				addVertex( c );
27790
27791				const nextIndex = verticesArray.length / 3;
27792				const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
27793
27794				addUV( uvs[ 0 ] );
27795				addUV( uvs[ 1 ] );
27796				addUV( uvs[ 2 ] );
27797
27798			}
27799
27800			function f4( a, b, c, d ) {
27801
27802				addVertex( a );
27803				addVertex( b );
27804				addVertex( d );
27805
27806				addVertex( b );
27807				addVertex( c );
27808				addVertex( d );
27809
27810
27811				const nextIndex = verticesArray.length / 3;
27812				const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
27813
27814				addUV( uvs[ 0 ] );
27815				addUV( uvs[ 1 ] );
27816				addUV( uvs[ 3 ] );
27817
27818				addUV( uvs[ 1 ] );
27819				addUV( uvs[ 2 ] );
27820				addUV( uvs[ 3 ] );
27821
27822			}
27823
27824			function addVertex( index ) {
27825
27826				verticesArray.push( placeholder[ index * 3 + 0 ] );
27827				verticesArray.push( placeholder[ index * 3 + 1 ] );
27828				verticesArray.push( placeholder[ index * 3 + 2 ] );
27829
27830			}
27831
27832
27833			function addUV( vector2 ) {
27834
27835				uvArray.push( vector2.x );
27836				uvArray.push( vector2.y );
27837
27838			}
27839
27840		}
27841
27842	}
27843
27844	copy( source ) {
27845
27846		super.copy( source );
27847
27848		this.parameters = Object.assign( {}, source.parameters );
27849
27850		return this;
27851
27852	}
27853
27854	toJSON() {
27855
27856		const data = super.toJSON();
27857
27858		const shapes = this.parameters.shapes;
27859		const options = this.parameters.options;
27860
27861		return toJSON$1( shapes, options, data );
27862
27863	}
27864
27865	/**
27866	 * Factory method for creating an instance of this class from the given
27867	 * JSON object.
27868	 *
27869	 * @param {Object} data - A JSON object representing the serialized geometry.
27870	 * @param {Array<Shape>} shapes - An array of shapes.
27871	 * @return {ExtrudeGeometry} A new instance.
27872	 */
27873	static fromJSON( data, shapes ) {
27874
27875		const geometryShapes = [];
27876
27877		for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
27878
27879			const shape = shapes[ data.shapes[ j ] ];
27880
27881			geometryShapes.push( shape );
27882
27883		}
27884
27885		const extrudePath = data.options.extrudePath;
27886
27887		if ( extrudePath !== undefined ) {
27888
27889			data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
27890
27891		}
27892
27893		return new ExtrudeGeometry( geometryShapes, data.options );
27894
27895	}
27896
27897}
27898
27899const WorldUVGenerator = {
27900
27901	generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
27902
27903		const a_x = vertices[ indexA * 3 ];
27904		const a_y = vertices[ indexA * 3 + 1 ];
27905		const b_x = vertices[ indexB * 3 ];
27906		const b_y = vertices[ indexB * 3 + 1 ];
27907		const c_x = vertices[ indexC * 3 ];
27908		const c_y = vertices[ indexC * 3 + 1 ];
27909
27910		return [
27911			new Vector2( a_x, a_y ),
27912			new Vector2( b_x, b_y ),
27913			new Vector2( c_x, c_y )
27914		];
27915
27916	},
27917
27918	generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
27919
27920		const a_x = vertices[ indexA * 3 ];
27921		const a_y = vertices[ indexA * 3 + 1 ];
27922		const a_z = vertices[ indexA * 3 + 2 ];
27923		const b_x = vertices[ indexB * 3 ];
27924		const b_y = vertices[ indexB * 3 + 1 ];
27925		const b_z = vertices[ indexB * 3 + 2 ];
27926		const c_x = vertices[ indexC * 3 ];
27927		const c_y = vertices[ indexC * 3 + 1 ];
27928		const c_z = vertices[ indexC * 3 + 2 ];
27929		const d_x = vertices[ indexD * 3 ];
27930		const d_y = vertices[ indexD * 3 + 1 ];
27931		const d_z = vertices[ indexD * 3 + 2 ];
27932
27933		if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {
27934
27935			return [
27936				new Vector2( a_x, 1 - a_z ),
27937				new Vector2( b_x, 1 - b_z ),
27938				new Vector2( c_x, 1 - c_z ),
27939				new Vector2( d_x, 1 - d_z )
27940			];
27941
27942		} else {
27943
27944			return [
27945				new Vector2( a_y, 1 - a_z ),
27946				new Vector2( b_y, 1 - b_z ),
27947				new Vector2( c_y, 1 - c_z ),
27948				new Vector2( d_y, 1 - d_z )
27949			];
27950
27951		}
27952
27953	}
27954
27955};
27956
27957function toJSON$1( shapes, options, data ) {
27958
27959	data.shapes = [];
27960
27961	if ( Array.isArray( shapes ) ) {
27962
27963		for ( let i = 0, l = shapes.length; i < l; i ++ ) {
27964
27965			const shape = shapes[ i ];
27966
27967			data.shapes.push( shape.uuid );
27968
27969		}
27970
27971	} else {
27972
27973		data.shapes.push( shapes.uuid );
27974
27975	}
27976
27977	data.options = Object.assign( {}, options );
27978
27979	if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
27980
27981	return data;
27982
27983}
27984
27985/**
27986 * A geometry class for representing a plane.
27987 *
27988 * ```js
27989 * const geometry = new THREE.PlaneGeometry( 1, 1 );
27990 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } );
27991 * const plane = new THREE.Mesh( geometry, material );
27992 * scene.add( plane );
27993 * ```
27994 *
27995 * @augments BufferGeometry
27996 */
27997class PlaneGeometry extends BufferGeometry {
27998
27999	/**
28000	 * Constructs a new plane geometry.
28001	 *
28002	 * @param {number} [width=1] - The width along the X axis.
28003	 * @param {number} [height=1] - The height along the Y axis
28004	 * @param {number} [widthSegments=1] - The number of segments along the X axis.
28005	 * @param {number} [heightSegments=1] - The number of segments along the Y axis.
28006	 */
28007	constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
28008
28009		super();
28010
28011		this.type = 'PlaneGeometry';
28012
28013		/**
28014		 * Holds the constructor parameters that have been
28015		 * used to generate the geometry. Any modification
28016		 * after instantiation does not change the geometry.
28017		 *
28018		 * @type {Object}
28019		 */
28020		this.parameters = {
28021			width: width,
28022			height: height,
28023			widthSegments: widthSegments,
28024			heightSegments: heightSegments
28025		};
28026
28027		const width_half = width / 2;
28028		const height_half = height / 2;
28029
28030		const gridX = Math.floor( widthSegments );
28031		const gridY = Math.floor( heightSegments );
28032
28033		const gridX1 = gridX + 1;
28034		const gridY1 = gridY + 1;
28035
28036		const segment_width = width / gridX;
28037		const segment_height = height / gridY;
28038
28039		//
28040
28041		const indices = [];
28042		const vertices = [];
28043		const normals = [];
28044		const uvs = [];
28045
28046		for ( let iy = 0; iy < gridY1; iy ++ ) {
28047
28048			const y = iy * segment_height - height_half;
28049
28050			for ( let ix = 0; ix < gridX1; ix ++ ) {
28051
28052				const x = ix * segment_width - width_half;
28053
28054				vertices.push( x, - y, 0 );
28055
28056				normals.push( 0, 0, 1 );
28057
28058				uvs.push( ix / gridX );
28059				uvs.push( 1 - ( iy / gridY ) );
28060
28061			}
28062
28063		}
28064
28065		for ( let iy = 0; iy < gridY; iy ++ ) {
28066
28067			for ( let ix = 0; ix < gridX; ix ++ ) {
28068
28069				const a = ix + gridX1 * iy;
28070				const b = ix + gridX1 * ( iy + 1 );
28071				const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
28072				const d = ( ix + 1 ) + gridX1 * iy;
28073
28074				indices.push( a, b, d );
28075				indices.push( b, c, d );
28076
28077			}
28078
28079		}
28080
28081		this.setIndex( indices );
28082		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,215 bytes, lines 28083-28251
28083		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
28084		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28085
28086	}
28087
28088	copy( source ) {
28089
28090		super.copy( source );
28091
28092		this.parameters = Object.assign( {}, source.parameters );
28093
28094		return this;
28095
28096	}
28097
28098	/**
28099	 * Factory method for creating an instance of this class from the given
28100	 * JSON object.
28101	 *
28102	 * @param {Object} data - A JSON object representing the serialized geometry.
28103	 * @return {PlaneGeometry} A new instance.
28104	 */
28105	static fromJSON( data ) {
28106
28107		return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );
28108
28109	}
28110
28111}
28112
28113/**
28114 * A class for generating a sphere geometry.
28115 *
28116 * ```js
28117 * const geometry = new THREE.SphereGeometry( 15, 32, 16 );
28118 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
28119 * const sphere = new THREE.Mesh( geometry, material );
28120 * scene.add( sphere );
28121 * ```
28122 *
28123 * @augments BufferGeometry
28124 */
28125class SphereGeometry extends BufferGeometry {
28126
28127	/**
28128	 * Constructs a new sphere geometry.
28129	 *
28130	 * @param {number} [radius=1] - The sphere radius.
28131	 * @param {number} [widthSegments=32] - The number of horizontal segments. Minimum value is `3`.
28132	 * @param {number} [heightSegments=16] - The number of vertical segments. Minimum value is `2`.
28133	 * @param {number} [phiStart=0] - The horizontal starting angle in radians.
28134	 * @param {number} [phiLength=Math.PI*2] - The horizontal sweep angle size.
28135	 * @param {number} [thetaStart=0] - The vertical starting angle in radians.
28136	 * @param {number} [thetaLength=Math.PI] - The vertical sweep angle size.
28137	 */
28138	constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
28139
28140		super();
28141
28142		this.type = 'SphereGeometry';
28143
28144		/**
28145		 * Holds the constructor parameters that have been
28146		 * used to generate the geometry. Any modification
28147		 * after instantiation does not change the geometry.
28148		 *
28149		 * @type {Object}
28150		 */
28151		this.parameters = {
28152			radius: radius,
28153			widthSegments: widthSegments,
28154			heightSegments: heightSegments,
28155			phiStart: phiStart,
28156			phiLength: phiLength,
28157			thetaStart: thetaStart,
28158			thetaLength: thetaLength
28159		};
28160
28161		widthSegments = Math.max( 3, Math.floor( widthSegments ) );
28162		heightSegments = Math.max( 2, Math.floor( heightSegments ) );
28163
28164		const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
28165
28166		let index = 0;
28167		const grid = [];
28168
28169		const vertex = new Vector3();
28170		const normal = new Vector3();
28171
28172		// buffers
28173
28174		const indices = [];
28175		const vertices = [];
28176		const normals = [];
28177		const uvs = [];
28178
28179		// generate vertices, normals and uvs
28180
28181		for ( let iy = 0; iy <= heightSegments; iy ++ ) {
28182
28183			const verticesRow = [];
28184
28185			const v = iy / heightSegments;
28186
28187			// special case for the poles
28188
28189			let uOffset = 0;
28190
28191			if ( iy === 0 && thetaStart === 0 ) {
28192
28193				uOffset = 0.5 / widthSegments;
28194
28195			} else if ( iy === heightSegments && thetaEnd === Math.PI ) {
28196
28197				uOffset = -0.5 / widthSegments;
28198
28199			}
28200
28201			for ( let ix = 0; ix <= widthSegments; ix ++ ) {
28202
28203				const u = ix / widthSegments;
28204
28205				// vertex
28206
28207				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
28208				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
28209				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
28210
28211				vertices.push( vertex.x, vertex.y, vertex.z );
28212
28213				// normal
28214
28215				normal.copy( vertex ).normalize();
28216				normals.push( normal.x, normal.y, normal.z );
28217
28218				// uv
28219
28220				uvs.push( u + uOffset, 1 - v );
28221
28222				verticesRow.push( index ++ );
28223
28224			}
28225
28226			grid.push( verticesRow );
28227
28228		}
28229
28230		// indices
28231
28232		for ( let iy = 0; iy < heightSegments; iy ++ ) {
28233
28234			for ( let ix = 0; ix < widthSegments; ix ++ ) {
28235
28236				const a = grid[ iy ][ ix + 1 ];
28237				const b = grid[ iy ][ ix ];
28238				const c = grid[ iy + 1 ][ ix ];
28239				const d = grid[ iy + 1 ][ ix + 1 ];
28240
28241				if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
28242				if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
28243
28244			}
28245
28246		}
28247
28248		// build geometry
28249
28250		this.setIndex( indices );
28251		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,237 bytes, lines 28252-28443
28252		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
28253		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
28254
28255	}
28256
28257	copy( source ) {
28258
28259		super.copy( source );
28260
28261		this.parameters = Object.assign( {}, source.parameters );
28262
28263		return this;
28264
28265	}
28266
28267	/**
28268	 * Factory method for creating an instance of this class from the given
28269	 * JSON object.
28270	 *
28271	 * @param {Object} data - A JSON object representing the serialized geometry.
28272	 * @return {SphereGeometry} A new instance.
28273	 */
28274	static fromJSON( data ) {
28275
28276		return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );
28277
28278	}
28279
28280}
28281
28282/**
28283 * Can be used as a helper object to visualize a geometry as a wireframe.
28284 *
28285 * ```js
28286 * const geometry = new THREE.SphereGeometry();
28287 *
28288 * const wireframe = new THREE.WireframeGeometry( geometry );
28289 *
28290 * const line = new THREE.LineSegments( wireframe );
28291 * line.material.depthWrite = false;
28292 * line.material.opacity = 0.25;
28293 * line.material.transparent = true;
28294 *
28295 * scene.add( line );
28296 * ```
28297 *
28298 * Note: It is not yet possible to serialize/deserialize instances of this class.
28299 *
28300 * @augments BufferGeometry
28301 */
28302class WireframeGeometry extends BufferGeometry {
28303
28304	/**
28305	 * Constructs a new wireframe geometry.
28306	 *
28307	 * @param {?BufferGeometry} [geometry=null] - The geometry.
28308	 */
28309	constructor( geometry = null ) {
28310
28311		super();
28312
28313		this.type = 'WireframeGeometry';
28314
28315		/**
28316		 * Holds the constructor parameters that have been
28317		 * used to generate the geometry. Any modification
28318		 * after instantiation does not change the geometry.
28319		 *
28320		 * @type {Object}
28321		 */
28322		this.parameters = {
28323			geometry: geometry
28324		};
28325
28326		if ( geometry !== null ) {
28327
28328			// buffer
28329
28330			const vertices = [];
28331			const edges = new Set();
28332
28333			// helper variables
28334
28335			const start = new Vector3();
28336			const end = new Vector3();
28337
28338			if ( geometry.index !== null ) {
28339
28340				// indexed BufferGeometry
28341
28342				const position = geometry.attributes.position;
28343				const indices = geometry.index;
28344				let groups = geometry.groups;
28345
28346				if ( groups.length === 0 ) {
28347
28348					groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
28349
28350				}
28351
28352				// create a data structure that contains all edges without duplicates
28353
28354				for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
28355
28356					const group = groups[ o ];
28357
28358					const groupStart = group.start;
28359					const groupCount = group.count;
28360
28361					for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) {
28362
28363						for ( let j = 0; j < 3; j ++ ) {
28364
28365							const index1 = indices.getX( i + j );
28366							const index2 = indices.getX( i + ( j + 1 ) % 3 );
28367
28368							start.fromBufferAttribute( position, index1 );
28369							end.fromBufferAttribute( position, index2 );
28370
28371							if ( isUniqueEdge( start, end, edges ) === true ) {
28372
28373								vertices.push( start.x, start.y, start.z );
28374								vertices.push( end.x, end.y, end.z );
28375
28376							}
28377
28378						}
28379
28380					}
28381
28382				}
28383
28384			} else {
28385
28386				// non-indexed BufferGeometry
28387
28388				const position = geometry.attributes.position;
28389
28390				for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
28391
28392					for ( let j = 0; j < 3; j ++ ) {
28393
28394						// three edges per triangle, an edge is represented as (index1, index2)
28395						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
28396
28397						const index1 = 3 * i + j;
28398						const index2 = 3 * i + ( ( j + 1 ) % 3 );
28399
28400						start.fromBufferAttribute( position, index1 );
28401						end.fromBufferAttribute( position, index2 );
28402
28403						if ( isUniqueEdge( start, end, edges ) === true ) {
28404
28405							vertices.push( start.x, start.y, start.z );
28406							vertices.push( end.x, end.y, end.z );
28407
28408						}
28409
28410					}
28411
28412				}
28413
28414			}
28415
28416			// build geometry
28417
28418			this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
28419
28420		}
28421
28422	}
28423
28424	copy( source ) {
28425
28426		super.copy( source );
28427
28428		this.parameters = Object.assign( {}, source.parameters );
28429
28430		return this;
28431
28432	}
28433
28434}
28435
28436function isUniqueEdge( start, end, edges ) {
28437
28438	const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;
28439	const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge
28440
28441	if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) {
28442
28443		return false;
28444
28445	} else {
28446
28447		edges.add( hash1 );
28448		edges.add( hash2 );
28449		return true;
28450
28451	}
28452
28453}
28454
28455/**
28456 * A material for shiny surfaces with specular highlights.
28457 *
28458 * The material uses a non-physically based [Blinn-Phong]{@link https://en.wikipedia.org/wiki/Blinn-Phong_shading_model}
28459 * model for calculating reflectance. Unlike the Lambertian model used in the
28460 * {@link MeshLambertMaterial} this can simulate shiny surfaces with specular
28461 * highlights (such as varnished wood). `MeshPhongMaterial` uses per-fragment shading.
28462 *
28463 * Performance will generally be greater when using this material over the
28464 * {@link MeshStandardMaterial} or {@link MeshPhysicalMaterial}, at the cost of
28465 * some graphical accuracy.
28466 *
28467 * @augments Material
28468 */
28469class MeshPhongMaterial extends Material {
28470
28471	/**
28472	 * Constructs a new mesh phong material.
28473	 *
28474	 * @param {Object} [parameters] - An object with one or more properties
28475	 * defining the material's appearance. Any property of the material
28476	 * (including any property from inherited materials) can be passed
28477	 * in here. Color values can be passed any type of value accepted
28478	 * by {@link Color#set}.
28479	 */
28480	constructor( parameters ) {
28481
28482		super();
28483
28484		/**
28485		 * This flag can be used for type testing.
28486		 *
28487		 * @type {boolean}
28488		 * @readonly
28489		 * @default true
28490		 */
28491		this.isMeshPhongMaterial = true;
28492
28493		this.type = 'MeshPhongMaterial';
28494
28495		/**
28496		 * Color of the material.
28497		 *
28498		 * @type {Color}
28499		 * @default (1,1,1)
28500		 */
28501		this.color = new Color( 0xffffff ); // diffuse
28502
28503		/**
28504		 * Specular color of the material. The default color is set to `0x111111` (very dark grey)
28505		 *
28506		 * This defines how shiny the material is and the color of its shine.
28507		 *
28508		 * @type {Color}
28509		 */
28510		this.specular = new Color( 0x111111 );
28511
28512		/**
28513		 * How shiny the specular highlight is; a higher value gives a sharper highlight.
28514		 *
28515		 * @type {number}
28516		 * @default 30
28517		 */
28518		this.shininess = 30;
28519
28520		/**
28521		 * The color map. May optionally include an alpha channel, typically combined
28522		 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map
28523		 * color is modulated by the diffuse `color`.
28524		 *
28525		 * @type {?Texture}
28526		 * @default null
28527		 */
28528		this.map = null;
28529
28530		/**
28531		 * The light map. Requires a second set of UVs.
28532		 *
28533		 * @type {?Texture}
28534		 * @default null
28535		 */
28536		this.lightMap = null;
28537
28538		/**
28539		 * Intensity of the baked light.
28540		 *
28541		 * @type {number}
28542		 * @default 1
28543		 */
28544		this.lightMapIntensity = 1.0;
28545
28546		/**
28547		 * The red channel of this texture is used as the ambient occlusion map.
28548		 * Requires a second set of UVs.
28549		 *
28550		 * @type {?Texture}
28551		 * @default null
28552		 */
28553		this.aoMap = null;
28554
28555		/**
28556		 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0`
28557		 * disables ambient occlusion. Where intensity is `1` and the AO map's
28558		 * red channel is also `1`, ambient light is fully occluded on a surface.
28559		 *
28560		 * @type {number}
28561		 * @default 1
28562		 */
28563		this.aoMapIntensity = 1.0;
28564
28565		/**
28566		 * Emissive (light) color of the material, essentially a solid color
28567		 * unaffected by other lighting.
28568		 *
28569		 * @type {Color}
28570		 * @default (0,0,0)
28571		 */
28572		this.emissive = new Color( 0x000000 );
28573
28574		/**
28575		 * Intensity of the emissive light. Modulates the emissive color.
28576		 *
28577		 * @type {number}
28578		 * @default 1
28579		 */
28580		this.emissiveIntensity = 1.0;
28581
28582		/**
28583		 * Set emissive (glow) map. The emissive map color is modulated by the
28584		 * emissive color and the emissive intensity. If you have an emissive map,
28585		 * be sure to set the emissive color to something other than black.
28586		 *
28587		 * @type {?Texture}
28588		 * @default null
28589		 */
28590		this.emissiveMap = null;
28591
28592		/**
28593		 * The texture to create a bump map. The black and white values map to the
28594		 * perceived depth in relation to the lights. Bump doesn't actually affect
28595		 * the geometry of the object, only the lighting. If a normal map is defined
28596		 * this will be ignored.
28597		 *
28598		 * @type {?Texture}
28599		 * @default null
28600		 */
28601		this.bumpMap = null;
28602
28603		/**
28604		 * How much the bump map affects the material. Typical range is `[0,1]`.
28605		 *
28606		 * @type {number}
28607		 * @default 1
28608		 */
28609		this.bumpScale = 1;
28610
28611		/**
28612		 * The texture to create a normal map. The RGB values affect the surface
28613		 * normal for each pixel fragment and change the way the color is lit. Normal
28614		 * maps do not change the actual shape of the surface, only the lighting. In
28615		 * case the material has a normal map authored using the left handed
28616		 * convention, the `y` component of `normalScale` should be negated to compensate
28617		 * for the different handedness.
28618		 *
28619		 * @type {?Texture}
28620		 * @default null
28621		 */
28622		this.normalMap = null;
28623
28624		/**
28625		 * The type of normal map.
28626		 *
28627		 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)}
28628		 * @default TangentSpaceNormalMap
28629		 */
28630		this.normalMapType = TangentSpaceNormalMap;
28631
28632		/**
28633		 * How much the normal map affects the material. Typical value range is `[0,1]`.
28634		 *
28635		 * @type {Vector2}
28636		 * @default (1,1)
28637		 */
28638		this.normalScale = new Vector2( 1, 1 );
28639
28640		/**
28641		 * The displacement map affects the position of the mesh's vertices. Unlike
28642		 * other maps which only affect the light and shade of the material the
28643		 * displaced vertices can cast shadows, block other objects, and otherwise
28644		 * act as real geometry. The displacement texture is an image where the value
28645		 * of each pixel (white being the highest) is mapped against, and
28646		 * repositions, the vertices of the mesh.
28647		 *
28648		 * @type {?Texture}
28649		 * @default null
28650		 */
28651		this.displacementMap = null;
28652
28653		/**
28654		 * How much the displacement map affects the mesh (where black is no
28655		 * displacement, and white is maximum displacement). Without a displacement
28656		 * map set, this value is not applied.
28657		 *
28658		 * @type {number}
28659		 * @default 0
28660		 */
28661		this.displacementScale = 1;
28662
28663		/**
28664		 * The offset of the displacement map's values on the mesh's vertices.
28665		 * The bias is added to the scaled sample of the displacement map.
28666		 * Without a displacement map set, this value is not applied.
28667		 *
28668		 * @type {number}
28669		 * @default 0
28670		 */
28671		this.displacementBias = 0;
28672
28673		/**
28674		 * The specular map value affects both how much the specular surface
28675		 * highlight contributes and how much of the environment map affects the
28676		 * surface.
28677		 *
28678		 * @type {?Texture}
28679		 * @default null
28680		 */
28681		this.specularMap = null;
28682
28683		/**
28684		 * The alpha map is a grayscale texture that controls the opacity across the
28685		 * surface (black: fully transparent; white: fully opaque).
28686		 *
28687		 * Only the color of the texture is used, ignoring the alpha channel if one
28688		 * exists. For RGB and RGBA textures, the renderer will use the green channel
28689		 * when sampling this texture due to the extra bit of precision provided for
28690		 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and
28691		 * luminance/alpha textures will also still work as expected.
28692		 *
28693		 * @type {?Texture}
28694		 * @default null
28695		 */
28696		this.alphaMap = null;
28697
28698		/**
28699		 * The environment map.
28700		 *
28701		 * @type {?Texture}
28702		 * @default null
28703		 */
28704		this.envMap = null;
28705
28706		/**
28707		 * The rotation of the environment map in radians.
28708		 *
28709		 * @type {Euler}
28710		 * @default (0,0,0)
28711		 */
28712		this.envMapRotation = new Euler();
28713
28714		/**
28715		 * How to combine the result of the surface's color with the environment map, if any.
28716		 *
28717		 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to
28718		 * blend between the two colors.
28719		 *
28720		 * @type {(MultiplyOperation|MixOperation|AddOperation)}
28721		 * @default MultiplyOperation
28722		 */
28723		this.combine = MultiplyOperation;
28724
28725		/**
28726		 * How much the environment map affects the surface.
28727		 * The valid range is between `0` (no reflections) and `1` (full reflections).
28728		 *
28729		 * @type {number}
28730		 * @default 1
28731		 */
28732		this.reflectivity = 1;
28733
28734		/**
28735		 * The index of refraction (IOR) of air (approximately 1) divided by the
28736		 * index of refraction of the material. It is used with environment mapping
28737		 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}.
28738		 * The refraction ratio should not exceed `1`.
28739		 *
28740		 * @type {number}
28741		 * @default 0.98
28742		 */
28743		this.refractionRatio = 0.98;
28744
28745		/**
28746		 * Renders the geometry as a wireframe.
28747		 *
28748		 * @type {boolean}
28749		 * @default false
28750		 */
28751		this.wireframe = false;
28752
28753		/**
28754		 * Controls the thickness of the wireframe.
28755		 *
28756		 * Can only be used with {@link SVGRenderer}.
28757		 *
28758		 * @type {number}
28759		 * @default 1
28760		 */
28761		this.wireframeLinewidth = 1;
28762
28763		/**
28764		 * Defines appearance of wireframe ends.
28765		 *
28766		 * Can only be used with {@link SVGRenderer}.
28767		 *
28768		 * @type {('round'|'bevel'|'miter')}
28769		 * @default 'round'
28770		 */
28771		this.wireframeLinecap = 'round';
28772
28773		/**
28774		 * Defines appearance of wireframe joints.
28775		 *
28776		 * Can only be used with {@link SVGRenderer}.
28777		 *
28778		 * @type {('round'|'bevel'|'miter')}
28779		 * @default 'round'
28780		 */
28781		this.wireframeLinejoin = 'round';
28782
28783		/**
28784		 * Whether the material is rendered with flat shading or not.
28785		 *
28786		 * @type {boolean}
28787		 * @default false
28788		 */
28789		this.flatShading = false;
28790
28791		/**
28792		 * Whether the material is affected by fog or not.
28793		 *
28794		 * @type {boolean}
28795		 * @default true
28796		 */
28797		this.fog = true;
28798
28799		this.setValues( parameters );
28800
28801	}
28802
28803	copy( source ) {
28804
28805		super.copy( source );
28806
28807		this.color.copy( source.color );
28808		this.specular.copy( source.specular );
28809		this.shininess = source.shininess;
28810
28811		this.map = source.map;
28812
28813		this.lightMap = source.lightMap;
28814		this.lightMapIntensity = source.lightMapIntensity;
28815
28816		this.aoMap = source.aoMap;
28817		this.aoMapIntensity = source.aoMapIntensity;
28818
28819		this.emissive.copy( source.emissive );
28820		this.emissiveMap = source.emissiveMap;
28821		this.emissiveIntensity = source.emissiveIntensity;
28822
28823		this.bumpMap = source.bumpMap;
28824		this.bumpScale = source.bumpScale;
28825
28826		this.normalMap = source.normalMap;
28827		this.normalMapType = source.normalMapType;
28828		this.normalScale.copy( source.normalScale );
28829
28830		this.displacementMap = source.displacementMap;
28831		this.displacementScale = source.displacementScale;
28832		this.displacementBias = source.displacementBias;
28833
28834		this.specularMap = source.specularMap;
28835
28836		this.alphaMap = source.alphaMap;
28837
28838		this.envMap = source.envMap;
28839		this.envMapRotation.copy( source.envMapRotation );
28840		this.combine = source.combine;
28841		this.reflectivity = source.reflectivity;
28842		this.refractionRatio = source.refractionRatio;
28843
28844		this.wireframe = source.wireframe;
28845		this.wireframeLinewidth = source.wireframeLinewidth;
28846		this.wireframeLinecap = source.wireframeLinecap;
28847		this.wireframeLinejoin = source.wireframeLinejoin;
28848
28849		this.flatShading = source.flatShading;
28850
28851		this.fog = source.fog;
28852
28853		return this;
28854
28855	}
28856
28857}
28858
28859/**
28860 * A material for non-shiny surfaces, without specular highlights.
28861 *
28862 * The material uses a non-physically based [Lambertian]{@link https://en.wikipedia.org/wiki/Lambertian_reflectance}
28863 * model for calculating reflectance. This can simulate some surfaces (such
28864 * as untreated wood or stone) well, but cannot simulate shiny surfaces with
28865 * specular highlights (such as varnished wood). `MeshLambertMaterial` uses per-fragment
28866 * shading.
28867 *
28868 * Due to the simplicity of the reflectance and illumination models,
28869 * performance will be greater when using this material over the
28870 * {@link MeshPhongMaterial}, {@link MeshStandardMaterial} or
28871 * {@link MeshPhysicalMaterial}, at the cost of some graphical accuracy.
28872 *
28873 * @augments Material
28874 */
28875class MeshLambertMaterial extends Material {
28876
28877	/**
28878	 * Constructs a new mesh lambert material.
28879	 *
28880	 * @param {Object} [parameters] - An object with one or more properties
28881	 * defining the material's appearance. Any property of the material
28882	 * (including any property from inherited materials) can be passed
28883	 * in here. Color values can be passed any type of value accepted
28884	 * by {@link Color#set}.
28885	 */
28886	constructor( parameters ) {
28887
28888		super();
28889
28890		/**
28891		 * This flag can be used for type testing.
28892		 *
28893		 * @type {boolean}
28894		 * @readonly
28895		 * @default true
28896		 */
28897		this.isMeshLambertMaterial = true;
28898
28899		this.type = 'MeshLambertMaterial';
28900
28901		/**
28902		 * Color of the material.
28903		 *
28904		 * @type {Color}
28905		 * @default (1,1,1)
28906		 */
28907		this.color = new Color( 0xffffff ); // diffuse
28908
28909		/**
28910		 * The color map. May optionally include an alpha channel, typically combined
28911		 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map
28912		 * color is modulated by the diffuse `color`.
28913		 *
28914		 * @type {?Texture}
28915		 * @default null
28916		 */
28917		this.map = null;
28918
28919		/**
28920		 * The light map. Requires a second set of UVs.
28921		 *
28922		 * @type {?Texture}
28923		 * @default null
28924		 */
28925		this.lightMap = null;
28926
28927		/**
28928		 * Intensity of the baked light.
28929		 *
28930		 * @type {number}
28931		 * @default 1
28932		 */
28933		this.lightMapIntensity = 1.0;
28934
28935		/**
28936		 * The red channel of this texture is used as the ambient occlusion map.
28937		 * Requires a second set of UVs.
28938		 *
28939		 * @type {?Texture}
28940		 * @default null
28941		 */
28942		this.aoMap = null;
28943
28944		/**
28945		 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0`
28946		 * disables ambient occlusion. Where intensity is `1` and the AO map's
28947		 * red channel is also `1`, ambient light is fully occluded on a surface.
28948		 *
28949		 * @type {number}
28950		 * @default 1
28951		 */
28952		this.aoMapIntensity = 1.0;
28953
28954		/**
28955		 * Emissive (light) color of the material, essentially a solid color
28956		 * unaffected by other lighting.
28957		 *
28958		 * @type {Color}
28959		 * @default (0,0,0)
28960		 */
28961		this.emissive = new Color( 0x000000 );
28962
28963		/**
28964		 * Intensity of the emissive light. Modulates the emissive color.
28965		 *
28966		 * @type {number}
28967		 * @default 1
28968		 */
28969		this.emissiveIntensity = 1.0;
28970
28971		/**
28972		 * Set emissive (glow) map. The emissive map color is modulated by the
28973		 * emissive color and the emissive intensity. If you have an emissive map,
28974		 * be sure to set the emissive color to something other than black.
28975		 *
28976		 * @type {?Texture}
28977		 * @default null
28978		 */
28979		this.emissiveMap = null;
28980
28981		/**
28982		 * The texture to create a bump map. The black and white values map to the
28983		 * perceived depth in relation to the lights. Bump doesn't actually affect
28984		 * the geometry of the object, only the lighting. If a normal map is defined
28985		 * this will be ignored.
28986		 *
28987		 * @type {?Texture}
28988		 * @default null
28989		 */
28990		this.bumpMap = null;
28991
28992		/**
28993		 * How much the bump map affects the material. Typical range is `[0,1]`.
28994		 *
28995		 * @type {number}
28996		 * @default 1
28997		 */
28998		this.bumpScale = 1;
28999
29000		/**
29001		 * The texture to create a normal map. The RGB values affect the surface
29002		 * normal for each pixel fragment and change the way the color is lit. Normal
29003		 * maps do not change the actual shape of the surface, only the lighting. In
29004		 * case the material has a normal map authored using the left handed
29005		 * convention, the `y` component of `normalScale` should be negated to compensate
29006		 * for the different handedness.
29007		 *
29008		 * @type {?Texture}
29009		 * @default null
29010		 */
29011		this.normalMap = null;
29012
29013		/**
29014		 * The type of normal map.
29015		 *
29016		 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)}
29017		 * @default TangentSpaceNormalMap
29018		 */
29019		this.normalMapType = TangentSpaceNormalMap;
29020
29021		/**
29022		 * How much the normal map affects the material. Typical value range is `[0,1]`.
29023		 *
29024		 * @type {Vector2}
29025		 * @default (1,1)
29026		 */
29027		this.normalScale = new Vector2( 1, 1 );
29028
29029		/**
29030		 * The displacement map affects the position of the mesh's vertices. Unlike
29031		 * other maps which only affect the light and shade of the material the
29032		 * displaced vertices can cast shadows, block other objects, and otherwise
29033		 * act as real geometry. The displacement texture is an image where the value
29034		 * of each pixel (white being the highest) is mapped against, and
29035		 * repositions, the vertices of the mesh.
29036		 *
29037		 * @type {?Texture}
29038		 * @default null
29039		 */
29040		this.displacementMap = null;
29041
29042		/**
29043		 * How much the displacement map affects the mesh (where black is no
29044		 * displacement, and white is maximum displacement). Without a displacement
29045		 * map set, this value is not applied.
29046		 *
29047		 * @type {number}
29048		 * @default 0
29049		 */
29050		this.displacementScale = 1;
29051
29052		/**
29053		 * The offset of the displacement map's values on the mesh's vertices.
29054		 * The bias is added to the scaled sample of the displacement map.
29055		 * Without a displacement map set, this value is not applied.
29056		 *
29057		 * @type {number}
29058		 * @default 0
29059		 */
29060		this.displacementBias = 0;
29061
29062		/**
29063		 * Specular map used by the material.
29064		 *
29065		 * @type {?Texture}
29066		 * @default null
29067		 */
29068		this.specularMap = null;
29069
29070		/**
29071		 * The alpha map is a grayscale texture that controls the opacity across the
29072		 * surface (black: fully transparent; white: fully opaque).
29073		 *
29074		 * Only the color of the texture is used, ignoring the alpha channel if one
29075		 * exists. For RGB and RGBA textures, the renderer will use the green channel
29076		 * when sampling this texture due to the extra bit of precision provided for
29077		 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and
29078		 * luminance/alpha textures will also still work as expected.
29079		 *
29080		 * @type {?Texture}
29081		 * @default null
29082		 */
29083		this.alphaMap = null;
29084
29085		/**
29086		 * The environment map.
29087		 *
29088		 * @type {?Texture}
29089		 * @default null
29090		 */
29091		this.envMap = null;
29092
29093		/**
29094		 * The rotation of the environment map in radians.
29095		 *
29096		 * @type {Euler}
29097		 * @default (0,0,0)
29098		 */
29099		this.envMapRotation = new Euler();
29100
29101		/**
29102		 * How to combine the result of the surface's color with the environment map, if any.
29103		 *
29104		 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to
29105		 * blend between the two colors.
29106		 *
29107		 * @type {(MultiplyOperation|MixOperation|AddOperation)}
29108		 * @default MultiplyOperation
29109		 */
29110		this.combine = MultiplyOperation;
29111
29112		/**
29113		 * How much the environment map affects the surface.
29114		 * The valid range is between `0` (no reflections) and `1` (full reflections).
29115		 *
29116		 * @type {number}
29117		 * @default 1
29118		 */
29119		this.reflectivity = 1;
29120
29121		/**
29122		 * The index of refraction (IOR) of air (approximately 1) divided by the
29123		 * index of refraction of the material. It is used with environment mapping
29124		 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}.
29125		 * The refraction ratio should not exceed `1`.
29126		 *
29127		 * @type {number}
29128		 * @default 0.98
29129		 */
29130		this.refractionRatio = 0.98;
29131
29132		/**
29133		 * Renders the geometry as a wireframe.
29134		 *
29135		 * @type {boolean}
29136		 * @default false
29137		 */
29138		this.wireframe = false;
29139
29140		/**
29141		 * Controls the thickness of the wireframe.
29142		 *
29143		 * Can only be used with {@link SVGRenderer}.
29144		 *
29145		 * @type {number}
29146		 * @default 1
29147		 */
29148		this.wireframeLinewidth = 1;
29149
29150		/**
29151		 * Defines appearance of wireframe ends.
29152		 *
29153		 * Can only be used with {@link SVGRenderer}.
29154		 *
29155		 * @type {('round'|'bevel'|'miter')}
29156		 * @default 'round'
29157		 */
29158		this.wireframeLinecap = 'round';
29159
29160		/**
29161		 * Defines appearance of wireframe joints.
29162		 *
29163		 * Can only be used with {@link SVGRenderer}.
29164		 *
29165		 * @type {('round'|'bevel'|'miter')}
29166		 * @default 'round'
29167		 */
29168		this.wireframeLinejoin = 'round';
29169
29170		/**
29171		 * Whether the material is rendered with flat shading or not.
29172		 *
29173		 * @type {boolean}
29174		 * @default false
29175		 */
29176		this.flatShading = false;
vendor: 4,123 bytes, lines 29177-29359
29177
29178		/**
29179		 * Whether the material is affected by fog or not.
29180		 *
29181		 * @type {boolean}
29182		 * @default true
29183		 */
29184		this.fog = true;
29185
29186		this.setValues( parameters );
29187
29188	}
29189
29190	copy( source ) {
29191
29192		super.copy( source );
29193
29194		this.color.copy( source.color );
29195
29196		this.map = source.map;
29197
29198		this.lightMap = source.lightMap;
29199		this.lightMapIntensity = source.lightMapIntensity;
29200
29201		this.aoMap = source.aoMap;
29202		this.aoMapIntensity = source.aoMapIntensity;
29203
29204		this.emissive.copy( source.emissive );
29205		this.emissiveMap = source.emissiveMap;
29206		this.emissiveIntensity = source.emissiveIntensity;
29207
29208		this.bumpMap = source.bumpMap;
29209		this.bumpScale = source.bumpScale;
29210
29211		this.normalMap = source.normalMap;
29212		this.normalMapType = source.normalMapType;
29213		this.normalScale.copy( source.normalScale );
29214
29215		this.displacementMap = source.displacementMap;
29216		this.displacementScale = source.displacementScale;
29217		this.displacementBias = source.displacementBias;
29218
29219		this.specularMap = source.specularMap;
29220
29221		this.alphaMap = source.alphaMap;
29222
29223		this.envMap = source.envMap;
29224		this.envMapRotation.copy( source.envMapRotation );
29225		this.combine = source.combine;
29226		this.reflectivity = source.reflectivity;
29227		this.refractionRatio = source.refractionRatio;
29228
29229		this.wireframe = source.wireframe;
29230		this.wireframeLinewidth = source.wireframeLinewidth;
29231		this.wireframeLinecap = source.wireframeLinecap;
29232		this.wireframeLinejoin = source.wireframeLinejoin;
29233
29234		this.flatShading = source.flatShading;
29235
29236		this.fog = source.fog;
29237
29238		return this;
29239
29240	}
29241
29242}
29243
29244/**
29245 * @class
29246 * @classdesc A simple caching system, used internally by {@link FileLoader}.
29247 * To enable caching across all loaders that use {@link FileLoader}, add `THREE.Cache.enabled = true.` once in your app.
29248 * @hideconstructor
29249 */
29250const Cache = {
29251
29252	/**
29253	 * Whether caching is enabled or not.
29254	 *
29255	 * @static
29256	 * @type {boolean}
29257	 * @default false
29258	 */
29259	enabled: false,
29260
29261	/**
29262	 * A dictionary that holds cached files.
29263	 *
29264	 * @static
29265	 * @type {Object<string,Object>}
29266	 */
29267	files: {},
29268
29269	/**
29270	 * Adds a cache entry with a key to reference the file. If this key already
29271	 * holds a file, it is overwritten.
29272	 *
29273	 * @static
29274	 * @param {string} key - The key to reference the cached file.
29275	 * @param {Object} file -  The file to be cached.
29276	 */
29277	add: function ( key, file ) {
29278
29279		if ( this.enabled === false ) return;
29280
29281		// console.log( 'THREE.Cache', 'Adding key:', key );
29282
29283		this.files[ key ] = file;
29284
29285	},
29286
29287	/**
29288	 * Gets the cached value for the given key.
29289	 *
29290	 * @static
29291	 * @param {string} key - The key to reference the cached file.
29292	 * @return {Object|undefined} The cached file. If the key does not exist `undefined` is returned.
29293	 */
29294	get: function ( key ) {
29295
29296		if ( this.enabled === false ) return;
29297
29298		// console.log( 'THREE.Cache', 'Checking key:', key );
29299
29300		return this.files[ key ];
29301
29302	},
29303
29304	/**
29305	 * Removes the cached file associated with the given key.
29306	 *
29307	 * @static
29308	 * @param {string} key - The key to reference the cached file.
29309	 */
29310	remove: function ( key ) {
29311
29312		delete this.files[ key ];
29313
29314	},
29315
29316	/**
29317	 * Remove all values from the cache.
29318	 *
29319	 * @static
29320	 */
29321	clear: function () {
29322
29323		this.files = {};
29324
29325	}
29326
29327};
29328
29329/**
29330 * Handles and keeps track of loaded and pending data. A default global
29331 * instance of this class is created and used by loaders if not supplied
29332 * manually.
29333 *
29334 * In general that should be sufficient, however there are times when it can
29335 * be useful to have separate loaders - for example if you want to show
29336 * separate loading bars for objects and textures.
29337 *
29338 * ```js
29339 * const manager = new THREE.LoadingManager();
29340 * manager.onLoad = () => console.log( 'Loading complete!' );
29341 *
29342 * const loader1 = new OBJLoader( manager );
29343 * const loader2 = new ColladaLoader( manager );
29344 * ```
29345 */
29346class LoadingManager {
29347
29348	/**
29349	 * Constructs a new loading manager.
29350	 *
29351	 * @param {Function} [onLoad] - Executes when all items have been loaded.
29352	 * @param {Function} [onProgress] - Executes when single items have been loaded.
29353	 * @param {Function} [onError] - Executes when an error occurs.
29354	 */
29355	constructor( onLoad, onProgress, onError ) {
29356
29357		const scope = this;
29358
29359		let isLoading = false;
vendor: 6,083 bytes, lines 29360-29649
29360		let itemsLoaded = 0;
29361		let itemsTotal = 0;
29362		let urlModifier = undefined;
29363		const handlers = [];
29364
29365		// Refer to #5689 for the reason why we don't set .onStart
29366		// in the constructor
29367
29368		/**
29369		 * Executes when an item starts loading.
29370		 *
29371		 * @type {Function|undefined}
29372		 * @default undefined
29373		 */
29374		this.onStart = undefined;
29375
29376		/**
29377		 * Executes when all items have been loaded.
29378		 *
29379		 * @type {Function|undefined}
29380		 * @default undefined
29381		 */
29382		this.onLoad = onLoad;
29383
29384		/**
29385		 * Executes when single items have been loaded.
29386		 *
29387		 * @type {Function|undefined}
29388		 * @default undefined
29389		 */
29390		this.onProgress = onProgress;
29391
29392		/**
29393		 * Executes when an error occurs.
29394		 *
29395		 * @type {Function|undefined}
29396		 * @default undefined
29397		 */
29398		this.onError = onError;
29399
29400		/**
29401		 * This should be called by any loader using the manager when the loader
29402		 * starts loading an item.
29403		 *
29404		 * @param {string} url - The URL to load.
29405		 */
29406		this.itemStart = function ( url ) {
29407
29408			itemsTotal ++;
29409
29410			if ( isLoading === false ) {
29411
29412				if ( scope.onStart !== undefined ) {
29413
29414					scope.onStart( url, itemsLoaded, itemsTotal );
29415
29416				}
29417
29418			}
29419
29420			isLoading = true;
29421
29422		};
29423
29424		/**
29425		 * This should be called by any loader using the manager when the loader
29426		 * ended loading an item.
29427		 *
29428		 * @param {string} url - The URL of the loaded item.
29429		 */
29430		this.itemEnd = function ( url ) {
29431
29432			itemsLoaded ++;
29433
29434			if ( scope.onProgress !== undefined ) {
29435
29436				scope.onProgress( url, itemsLoaded, itemsTotal );
29437
29438			}
29439
29440			if ( itemsLoaded === itemsTotal ) {
29441
29442				isLoading = false;
29443
29444				if ( scope.onLoad !== undefined ) {
29445
29446					scope.onLoad();
29447
29448				}
29449
29450			}
29451
29452		};
29453
29454		/**
29455		 * This should be called by any loader using the manager when the loader
29456		 * encounters an error when loading an item.
29457		 *
29458		 * @param {string} url - The URL of the item that produces an error.
29459		 */
29460		this.itemError = function ( url ) {
29461
29462			if ( scope.onError !== undefined ) {
29463
29464				scope.onError( url );
29465
29466			}
29467
29468		};
29469
29470		/**
29471		 * Given a URL, uses the URL modifier callback (if any) and returns a
29472		 * resolved URL. If no URL modifier is set, returns the original URL.
29473		 *
29474		 * @param {string} url - The URL to load.
29475		 * @return {string} The resolved URL.
29476		 */
29477		this.resolveURL = function ( url ) {
29478
29479			if ( urlModifier ) {
29480
29481				return urlModifier( url );
29482
29483			}
29484
29485			return url;
29486
29487		};
29488
29489		/**
29490		 * If provided, the callback will be passed each resource URL before a
29491		 * request is sent. The callback may return the original URL, or a new URL to
29492		 * override loading behavior. This behavior can be used to load assets from
29493		 * .ZIP files, drag-and-drop APIs, and Data URIs.
29494		 *
29495		 * ```js
29496		 * const blobs = {'fish.gltf': blob1, 'diffuse.png': blob2, 'normal.png': blob3};
29497		 *
29498		 * const manager = new THREE.LoadingManager();
29499		 *
29500		 * // Initialize loading manager with URL callback.
29501		 * const objectURLs = [];
29502		 * manager.setURLModifier( ( url ) => {
29503		 *
29504		 * 	url = URL.createObjectURL( blobs[ url ] );
29505		 * 	objectURLs.push( url );
29506		 * 	return url;
29507		 *
29508		 * } );
29509		 *
29510		 * // Load as usual, then revoke the blob URLs.
29511		 * const loader = new GLTFLoader( manager );
29512		 * loader.load( 'fish.gltf', (gltf) => {
29513		 *
29514		 * 	scene.add( gltf.scene );
29515		 * 	objectURLs.forEach( ( url ) => URL.revokeObjectURL( url ) );
29516		 *
29517		 * } );
29518		 * ```
29519		 *
29520		 * @param {function(string):string} transform - URL modifier callback. Called with an URL and must return a resolved URL.
29521		 * @return {LoadingManager} A reference to this loading manager.
29522		 */
29523		this.setURLModifier = function ( transform ) {
29524
29525			urlModifier = transform;
29526
29527			return this;
29528
29529		};
29530
29531		/**
29532		 * Registers a loader with the given regular expression. Can be used to
29533		 * define what loader should be used in order to load specific files. A
29534		 * typical use case is to overwrite the default loader for textures.
29535		 *
29536		 * ```js
29537		 * // add handler for TGA textures
29538		 * manager.addHandler( /\.tga$/i, new TGALoader() );
29539		 * ```
29540		 *
29541		 * @param {string} regex - A regular expression.
29542		 * @param {Loader} loader - A loader that should handle matched cases.
29543		 * @return {LoadingManager} A reference to this loading manager.
29544		 */
29545		this.addHandler = function ( regex, loader ) {
29546
29547			handlers.push( regex, loader );
29548
29549			return this;
29550
29551		};
29552
29553		/**
29554		 * Removes the loader for the given regular expression.
29555		 *
29556		 * @param {string} regex - A regular expression.
29557		 * @return {LoadingManager} A reference to this loading manager.
29558		 */
29559		this.removeHandler = function ( regex ) {
29560
29561			const index = handlers.indexOf( regex );
29562
29563			if ( index !== -1 ) {
29564
29565				handlers.splice( index, 2 );
29566
29567			}
29568
29569			return this;
29570
29571		};
29572
29573		/**
29574		 * Can be used to retrieve the registered loader for the given file path.
29575		 *
29576		 * @param {string} file - The file path.
29577		 * @return {?Loader} The registered loader. Returns `null` if no loader was found.
29578		 */
29579		this.getHandler = function ( file ) {
29580
29581			for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
29582
29583				const regex = handlers[ i ];
29584				const loader = handlers[ i + 1 ];
29585
29586				if ( regex.global ) regex.lastIndex = 0; // see #17920
29587
29588				if ( regex.test( file ) ) {
29589
29590					return loader;
29591
29592				}
29593
29594			}
29595
29596			return null;
29597
29598		};
29599
29600	}
29601
29602}
29603
29604/**
29605 * The global default loading manager.
29606 *
29607 * @constant
29608 * @type {LoadingManager}
29609 */
29610const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager();
29611
29612/**
29613 * Abstract base class for loaders.
29614 *
29615 * @abstract
29616 */
29617class Loader {
29618
29619	/**
29620	 * Constructs a new loader.
29621	 *
29622	 * @param {LoadingManager} [manager] - The loading manager.
29623	 */
29624	constructor( manager ) {
29625
29626		/**
29627		 * The loading manager.
29628		 *
29629		 * @type {LoadingManager}
29630		 * @default DefaultLoadingManager
29631		 */
29632		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
29633
29634		/**
29635		 * The crossOrigin string to implement CORS for loading the url from a
29636		 * different domain that allows CORS.
29637		 *
29638		 * @type {string}
29639		 * @default 'anonymous'
29640		 */
29641		this.crossOrigin = 'anonymous';
29642
29643		/**
29644		 * Whether the XMLHttpRequest uses credentials.
29645		 *
29646		 * @type {boolean}
29647		 * @default false
29648		 */
29649		this.withCredentials = false;
29650
29651		/**
29652		 * The base path from which the asset will be loaded.
29653		 *
29654		 * @type {string}
29655		 */
29656		this.path = '';
29657
29658		/**
29659		 * The base path from which additional resources like textures will be loaded.
29660		 *
29661		 * @type {string}
29662		 */
29663		this.resourcePath = '';
29664
29665		/**
29666		 * The [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header}
29667		 * used in HTTP request.
29668		 *
29669		 * @type {Object<string, any>}
29670		 */
29671		this.requestHeader = {};
29672
29673	}
29674
29675	/**
29676	 * This method needs to be implemented by all concrete loaders. It holds the
29677	 * logic for loading assets from the backend.
29678	 *
29679	 * @param {string} url - The path/URL of the file to be loaded.
29680	 * @param {Function} onLoad - Executed when the loading process has been finished.
29681	 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress.
29682	 * @param {onErrorCallback} [onError] - Executed when errors occur.
29683	 */
29684	load( /* url, onLoad, onProgress, onError */ ) {}
29685
29686	/**
29687	 * A async version of {@link Loader#load}.
29688	 *
29689	 * @param {string} url - The path/URL of the file to be loaded.
29690	 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress.
29691	 * @return {Promise} A Promise that resolves when the asset has been loaded.
29692	 */
29693	loadAsync( url, onProgress ) {
29694
29695		const scope = this;
29696
29697		return new Promise( function ( resolve, reject ) {
29698
29699			scope.load( url, resolve, onProgress, reject );
29700
29701		} );
29702
29703	}
29704
29705	/**
29706	 * This method needs to be implemented by all concrete loaders. It holds the
29707	 * logic for parsing the asset into three.js entities.
29708	 *
29709	 * @param {any} data - The data to parse.
29710	 */
29711	parse( /* data */ ) {}
29712
29713	/**
29714	 * Sets the `crossOrigin` String to implement CORS for loading the URL
29715	 * from a different domain that allows CORS.
29716	 *
29717	 * @param {string} crossOrigin - The `crossOrigin` value.
29718	 * @return {Loader} A reference to this instance.
29719	 */
29720	setCrossOrigin( crossOrigin ) {
29721
29722		this.crossOrigin = crossOrigin;
29723		return this;
29724
29725	}
29726
29727	/**
29728	 * Whether the XMLHttpRequest uses credentials such as cookies, authorization
29729	 * headers or TLS client certificates, see [XMLHttpRequest.withCredentials]{@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials}.
29730	 *
29731	 * Note: This setting has no effect if you are loading files locally or from the same domain.
29732	 *
29733	 * @param {boolean} value - The `withCredentials` value.
29734	 * @return {Loader} A reference to this instance.
29735	 */
29736	setWithCredentials( value ) {
29737
29738		this.withCredentials = value;
29739		return this;
29740
29741	}
29742
29743	/**
29744	 * Sets the base path for the asset.
29745	 *
29746	 * @param {string} path - The base path.
29747	 * @return {Loader} A reference to this instance.
29748	 */
29749	setPath( path ) {
29750
29751		this.path = path;
29752		return this;
29753
29754	}
29755
29756	/**
29757	 * Sets the base path for dependent resources like textures.
29758	 *
29759	 * @param {string} resourcePath - The resource path.
29760	 * @return {Loader} A reference to this instance.
29761	 */
29762	setResourcePath( resourcePath ) {
29763
29764		this.resourcePath = resourcePath;
29765		return this;
29766
29767	}
29768
29769	/**
29770	 * Sets the given request header.
29771	 *
29772	 * @param {Object} requestHeader - A [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header}
29773	 * for configuring the HTTP request.
29774	 * @return {Loader} A reference to this instance.
29775	 */
29776	setRequestHeader( requestHeader ) {
29777
29778		this.requestHeader = requestHeader;
29779		return this;
29780
29781	}
29782
29783}
29784
29785/**
29786 * Callback for onProgress in loaders.
29787 *
29788 * @callback onProgressCallback
29789 * @param {ProgressEvent} event - An instance of `ProgressEvent` that represents the current loading status.
29790 */
29791
29792/**
29793 * Callback for onError in loaders.
29794 *
29795 * @callback onErrorCallback
29796 * @param {Error} error - The error which occurred during the loading process.
29797 */
29798
29799/**
29800 * The default material name that is used by loaders
29801 * when creating materials for loaded 3D objects.
29802 *
29803 * Note: Not all loaders might honor this setting.
29804 *
29805 * @static
29806 * @type {string}
29807 * @default '__DEFAULT'
29808 */
29809Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT';
29810
29811/**
29812 * A loader for loading images. The class loads images with the HTML `Image` API.
29813 *
29814 * ```js
29815 * const loader = new THREE.ImageLoader();
29816 * const image = await loader.loadAsync( 'image.png' );
29817 * ```
29818 * Please note that `ImageLoader` has dropped support for progress
29819 * events in `r84`. For an `ImageLoader` that supports progress events, see
29820 * [this thread]{@link https://github.com/mrdoob/three.js/issues/10439#issuecomment-275785639}.
29821 *
29822 * @augments Loader
29823 */
29824class ImageLoader extends Loader {
29825
29826	/**
29827	 * Constructs a new image loader.
29828	 *
29829	 * @param {LoadingManager} [manager] - The loading manager.
29830	 */
29831	constructor( manager ) {
29832
29833		super( manager );
29834
29835	}
29836
29837	/**
29838	 * Starts loading from the given URL and passes the loaded image
29839	 * to the `onLoad()` callback. The method also returns a new `Image` object which can
29840	 * directly be used for texture creation. If you do it this way, the texture
29841	 * may pop up in your scene once the respective loading process is finished.
29842	 *
29843	 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
29844	 * @param {function(Image)} onLoad - Executed when the loading process has been finished.
29845	 * @param {onProgressCallback} onProgress - Unsupported in this loader.
29846	 * @param {onErrorCallback} onError - Executed when errors occur.
29847	 * @return {Image} The image.
29848	 */
29849	load( url, onLoad, onProgress, onError ) {
29850
29851		if ( this.path !== undefined ) url = this.path + url;
29852
29853		url = this.manager.resolveURL( url );
29854
29855		const scope = this;
29856
29857		const cached = Cache.get( url );
29858
29859		if ( cached !== undefined ) {
29860
29861			scope.manager.itemStart( url );
29862
29863			setTimeout( function () {
29864
29865				if ( onLoad ) onLoad( cached );
29866
29867				scope.manager.itemEnd( url );
29868
29869			}, 0 );
29870
29871			return cached;
29872
29873		}
29874
29875		const image = createElementNS( 'img' );
29876
29877		function onImageLoad() {
29878
29879			removeEventListeners();
29880
29881			Cache.add( url, this );
29882
29883			if ( onLoad ) onLoad( this );
29884
29885			scope.manager.itemEnd( url );
29886
29887		}
29888
29889		function onImageError( event ) {
29890
29891			removeEventListeners();
29892
29893			if ( onError ) onError( event );
29894
29895			scope.manager.itemError( url );
29896			scope.manager.itemEnd( url );
29897
29898		}
29899
29900		function removeEventListeners() {
29901
29902			image.removeEventListener( 'load', onImageLoad, false );
29903			image.removeEventListener( 'error', onImageError, false );
29904
29905		}
29906
29907		image.addEventListener( 'load', onImageLoad, false );
29908		image.addEventListener( 'error', onImageError, false );
29909
29910		if ( url.slice( 0, 5 ) !== 'data:' ) {
29911
29912			if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
29913
29914		}
29915
29916		scope.manager.itemStart( url );
29917
29918		image.src = url;
29919
29920		return image;
29921
29922	}
29923
29924}
29925
29926/**
29927 * Class for loading textures. Images are internally
29928 * loaded via {@link ImageLoader}.
29929 *
29930 * ```js
29931 * const loader = new THREE.TextureLoader();
29932 * const texture = await loader.loadAsync( 'textures/land_ocean_ice_cloud_2048.jpg' );
29933 *
29934 * const material = new THREE.MeshBasicMaterial( { map:texture } );
29935 * ```
29936 * Please note that `TextureLoader` has dropped support for progress
29937 * events in `r84`. For a `TextureLoader` that supports progress events, see
29938 * [this thread]{@link https://github.com/mrdoob/three.js/issues/10439#
vendor: 9,961 bytes, lines 29938-30357
29938issuecomment-293260145}.
29939 *
29940 * @augments Loader
29941 */
29942class TextureLoader extends Loader {
29943
29944	/**
29945	 * Constructs a new texture loader.
29946	 *
29947	 * @param {LoadingManager} [manager] - The loading manager.
29948	 */
29949	constructor( manager ) {
29950
29951		super( manager );
29952
29953	}
29954
29955	/**
29956	 * Starts loading from the given URL and pass the fully loaded texture
29957	 * to the `onLoad()` callback. The method also returns a new texture object which can
29958	 * directly be used for material creation. If you do it this way, the texture
29959	 * may pop up in your scene once the respective loading process is finished.
29960	 *
29961	 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
29962	 * @param {function(Texture)} onLoad - Executed when the loading process has been finished.
29963	 * @param {onProgressCallback} onProgress - Unsupported in this loader.
29964	 * @param {onErrorCallback} onError - Executed when errors occur.
29965	 * @return {Texture} The texture.
29966	 */
29967	load( url, onLoad, onProgress, onError ) {
29968
29969		const texture = new Texture();
29970
29971		const loader = new ImageLoader( this.manager );
29972		loader.setCrossOrigin( this.crossOrigin );
29973		loader.setPath( this.path );
29974
29975		loader.load( url, function ( image ) {
29976
29977			texture.image = image;
29978			texture.needsUpdate = true;
29979
29980			if ( onLoad !== undefined ) {
29981
29982				onLoad( texture );
29983
29984			}
29985
29986		}, onProgress, onError );
29987
29988		return texture;
29989
29990	}
29991
29992}
29993
29994/**
29995 * An instanced version of a geometry.
29996 */
29997class InstancedBufferGeometry extends BufferGeometry {
29998
29999	/**
30000	 * Constructs a new instanced buffer geometry.
30001	 */
30002	constructor() {
30003
30004		super();
30005
30006		/**
30007		 * This flag can be used for type testing.
30008		 *
30009		 * @type {boolean}
30010		 * @readonly
30011		 * @default true
30012		 */
30013		this.isInstancedBufferGeometry = true;
30014
30015		this.type = 'InstancedBufferGeometry';
30016
30017		/**
30018		 * The instance count.
30019		 *
30020		 * @type {number}
30021		 * @default Infinity
30022		 */
30023		this.instanceCount = Infinity;
30024
30025	}
30026
30027	copy( source ) {
30028
30029		super.copy( source );
30030
30031		this.instanceCount = source.instanceCount;
30032
30033		return this;
30034
30035	}
30036
30037	toJSON() {
30038
30039		const data = super.toJSON();
30040
30041		data.instanceCount = this.instanceCount;
30042
30043		data.isInstancedBufferGeometry = true;
30044
30045		return data;
30046
30047	}
30048
30049}
30050
30051/**
30052 * An instanced version of an interleaved buffer.
30053 *
30054 * @augments InterleavedBuffer
30055 */
30056class InstancedInterleavedBuffer extends InterleavedBuffer {
30057
30058	/**
30059	 * Constructs a new instanced interleaved buffer.
30060	 *
30061	 * @param {TypedArray} array - A typed array with a shared buffer storing attribute data.
30062	 * @param {number} stride - The number of typed-array elements per vertex.
30063	 * @param {number} [meshPerAttribute=1] - Defines how often a value of this interleaved buffer should be repeated.
30064	 */
30065	constructor( array, stride, meshPerAttribute = 1 ) {
30066
30067		super( array, stride );
30068
30069		/**
30070		 * This flag can be used for type testing.
30071		 *
30072		 * @type {boolean}
30073		 * @readonly
30074		 * @default true
30075		 */
30076		this.isInstancedInterleavedBuffer = true;
30077
30078		/**
30079		 * Defines how often a value of this buffer attribute should be repeated,
30080		 * see {@link InstancedBufferAttribute#meshPerAttribute}.
30081		 *
30082		 * @type {number}
30083		 * @default 1
30084		 */
30085		this.meshPerAttribute = meshPerAttribute;
30086
30087	}
30088
30089	copy( source ) {
30090
30091		super.copy( source );
30092
30093		this.meshPerAttribute = source.meshPerAttribute;
30094
30095		return this;
30096
30097	}
30098
30099	clone( data ) {
30100
30101		const ib = super.clone( data );
30102
30103		ib.meshPerAttribute = this.meshPerAttribute;
30104
30105		return ib;
30106
30107	}
30108
30109	toJSON( data ) {
30110
30111		const json = super.toJSON( data );
30112
30113		json.isInstancedInterleavedBuffer = true;
30114		json.meshPerAttribute = this.meshPerAttribute;
30115
30116		return json;
30117
30118	}
30119
30120}
30121
30122const _startP = /*@__PURE__*/ new Vector3();
30123const _startEnd = /*@__PURE__*/ new Vector3();
30124
30125/**
30126 * An analytical line segment in 3D space represented by a start and end point.
30127 */
30128class Line3 {
30129
30130	/**
30131	 * Constructs a new line segment.
30132	 *
30133	 * @param {Vector3} [start=(0,0,0)] - Start of the line segment.
30134	 * @param {Vector3} [end=(0,0,0)] - End of the line segment.
30135	 */
30136	constructor( start = new Vector3(), end = new Vector3() ) {
30137
30138		/**
30139		 * Start of the line segment.
30140		 *
30141		 * @type {Vector3}
30142		 */
30143		this.start = start;
30144
30145		/**
30146		 * End of the line segment.
30147		 *
30148		 * @type {Vector3}
30149		 */
30150		this.end = end;
30151
30152	}
30153
30154	/**
30155	 * Sets the start and end values by copying the given vectors.
30156	 *
30157	 * @param {Vector3} start - The start point.
30158	 * @param {Vector3} end - The end point.
30159	 * @return {Line3} A reference to this line segment.
30160	 */
30161	set( start, end ) {
30162
30163		this.start.copy( start );
30164		this.end.copy( end );
30165
30166		return this;
30167
30168	}
30169
30170	/**
30171	 * Copies the values of the given line segment to this instance.
30172	 *
30173	 * @param {Line3} line - The line segment to copy.
30174	 * @return {Line3} A reference to this line segment.
30175	 */
30176	copy( line ) {
30177
30178		this.start.copy( line.start );
30179		this.end.copy( line.end );
30180
30181		return this;
30182
30183	}
30184
30185	/**
30186	 * Returns the center of the line segment.
30187	 *
30188	 * @param {Vector3} target - The target vector that is used to store the method's result.
30189	 * @return {Vector3} The center point.
30190	 */
30191	getCenter( target ) {
30192
30193		return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
30194
30195	}
30196
30197	/**
30198	 * Returns the delta vector of the line segment's start and end point.
30199	 *
30200	 * @param {Vector3} target - The target vector that is used to store the method's result.
30201	 * @return {Vector3} The delta vector.
30202	 */
30203	delta( target ) {
30204
30205		return target.subVectors( this.end, this.start );
30206
30207	}
30208
30209	/**
30210	 * Returns the squared Euclidean distance between the line' start and end point.
30211	 *
30212	 * @return {number} The squared Euclidean distance.
30213	 */
30214	distanceSq() {
30215
30216		return this.start.distanceToSquared( this.end );
30217
30218	}
30219
30220	/**
30221	 * Returns the Euclidean distance between the line' start and end point.
30222	 *
30223	 * @return {number} The Euclidean distance.
30224	 */
30225	distance() {
30226
30227		return this.start.distanceTo( this.end );
30228
30229	}
30230
30231	/**
30232	 * Returns a vector at a certain position along the line segment.
30233	 *
30234	 * @param {number} t - A value between `[0,1]` to represent a position along the line segment.
30235	 * @param {Vector3} target - The target vector that is used to store the method's result.
30236	 * @return {Vector3} The delta vector.
30237	 */
30238	at( t, target ) {
30239
30240		return this.delta( target ).multiplyScalar( t ).add( this.start );
30241
30242	}
30243
30244	/**
30245	 * Returns a point parameter based on the closest point as projected on the line segment.
30246	 *
30247	 * @param {Vector3} point - The point for which to return a point parameter.
30248	 * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not.
30249	 * @return {number} The point parameter.
30250	 */
30251	closestPointToPointParameter( point, clampToLine ) {
30252
30253		_startP.subVectors( point, this.start );
30254		_startEnd.subVectors( this.end, this.start );
30255
30256		const startEnd2 = _startEnd.dot( _startEnd );
30257		const startEnd_startP = _startEnd.dot( _startP );
30258
30259		let t = startEnd_startP / startEnd2;
30260
30261		if ( clampToLine ) {
30262
30263			t = clamp( t, 0, 1 );
30264
30265		}
30266
30267		return t;
30268
30269	}
30270
30271	/**
30272	 * Returns the closets point on the line for a given point.
30273	 *
30274	 * @param {Vector3} point - The point to compute the closest point on the line for.
30275	 * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not.
30276	 * @param {Vector3} target -  The target vector that is used to store the method's result.
30277	 * @return {Vector3} The closest point on the line.
30278	 */
30279	closestPointToPoint( point, clampToLine, target ) {
30280
30281		const t = this.closestPointToPointParameter( point, clampToLine );
30282
30283		return this.delta( target ).multiplyScalar( t ).add( this.start );
30284
30285	}
30286
30287	/**
30288	 * Applies a 4x4 transformation matrix to this line segment.
30289	 *
30290	 * @param {Matrix4} matrix - The transformation matrix.
30291	 * @return {Line3} A reference to this line segment.
30292	 */
30293	applyMatrix4( matrix ) {
30294
30295		this.start.applyMatrix4( matrix );
30296		this.end.applyMatrix4( matrix );
30297
30298		return this;
30299
30300	}
30301
30302	/**
30303	 * Returns `true` if this line segment is equal with the given one.
30304	 *
30305	 * @param {Line3} line - The line segment to test for equality.
30306	 * @return {boolean} Whether this line segment is equal with the given one.
30307	 */
30308	equals( line ) {
30309
30310		return line.start.equals( this.start ) && line.end.equals( this.end );
30311
30312	}
30313
30314	/**
30315	 * Returns a new line segment with copied values from this instance.
30316	 *
30317	 * @return {Line3} A clone of this instance.
30318	 */
30319	clone() {
30320
30321		return new this.constructor().copy( this );
30322
30323	}
30324
30325}
30326
30327if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
30328
30329	__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
30330		revision: REVISION,
30331	} } ) );
30332
30333}
30334
30335if ( typeof window !== 'undefined' ) {
30336
30337	if ( window.__THREE__ ) {
30338
30339		console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
30340
30341	} else {
30342
30343		window.__THREE__ = REVISION;
30344
30345	}
30346
30347}
30348
30349/**
30350 * @license
30351 * Copyright 2010-2025 Three.js Authors
30352 * SPDX-License-Identifier: MIT
30353 */
30354
30355var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif";
30356
30357var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 
30357- ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif";
30358
30359var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif";
30360
30361var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
30362
30363var alphatest_fragment = "#ifdef USE_ALPHATEST\n\t#ifdef ALPHA_TO_COVERAGE\n\tdiffuseColor.a = smoothstep( alphaTest, alphaTest + fwidth( diffuseColor.a ), diffuseColor.a );\n\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\tif ( diffuseColor.a < alphaTest ) discard;\n\t#endif\n#endif";
30364
30365var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif";
30366
30367var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif";
30368
30369var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
30370
30371var batching_pars_vertex = "#ifdef USE_BATCHING\n\t#if ! defined( GL_ANGLE_multi_draw )\n\t#define gl_DrawID _gl_DrawID\n\tuniform int _gl_DrawID;\n\t#endif\n\tuniform highp sampler2D batchingTexture;\n\tuniform highp usampler2D batchingIdTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n\tfloat getIndirectIndex( const in int i ) {\n\t\tint size = textureSize( batchingIdTexture, 0 ).x;\n\t\tint x = i % size;\n\t\tint y = i / size;\n\t\treturn float( texelFetch( batchingIdTexture, ivec2( x, y ), 0 ).r );\n\t}\n#endif\n#ifdef USE_BATCHING_COLOR\n\tuniform sampler2D batchingColorTexture;\n\tvec3 getBatchingColor( const in float i ) {\n\t\tint size = textureSize( batchingColorTexture, 0 ).x;\n\t\tint j = int( i );\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\treturn texelFetch( batchingColorTexture, ivec2( x, y ), 0 ).rgb;\n\t}\n#endif";
30372
30373var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );\n#endif";
30374
30375var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif";
30376
30377var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
30378
30379var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated";
30380
30381var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660,  0.0556434,\n\t\t-1.5371385,  1.8760108, -0.2040259,\n\t\t-0.4985314,  0.0415560,  1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );
30381\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif";
30382
30383var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif";
30384
30385var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif";
30386
30387var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
30388
30389var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
30390
30391var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
30392
30393var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif";
30394
30395var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif";
30396
30397var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvarying vec3 vColor;\n#endif";
30398
30399var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif\n#ifdef USE_BATCHING_COLOR\n\tvec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );\n\tvColor.xyz *= batchingColor.xyz;\n#endif";
30400
30401var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated";
30402
30403var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif";
30404
30405var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
30405\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
30406
30407var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
30408
30409var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif";
30410
30411var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE_EMISSIVE\n\t\temissiveColor = sRGBTransferEOTF( emissiveColor );\n\t#endif\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
30412
30413var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
30414
30415var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
30416
30417var colorspace_pars_fragment = "vec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferEOTF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}";
30418
30419var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif";
30420
30421var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform mat3 envMapRotation;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t
vendor: 6,748 bytes, lines 30421-30445
30421\n#endif";
30422
30423var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif";
30424
30425var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif";
30426
30427var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif";
30428
30429var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif";
30430
30431var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif";
30432
30433var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif";
30434
30435var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif";
30436
30437var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}";
30438
30439var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
30440
30441var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;";
30442
30443var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert";
30444
30445var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif ( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}
vendor: 8,222 bytes, lines 30445-30457
30445\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif";
30446
30447var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif";
30448
30449var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
30450
30451var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon";
30452
30453var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
30454
30455var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong";
30456
30457var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_
30457DISPERSION\n\tmaterial.dispersion = dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif";
30458
30459var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\tfloat dispersion
vendor: 16,747 bytes, lines 30459-30461
30459;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n    float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n    float x2 = x * x;\n    float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n    return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3(    0, 1,    0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
30460
30461var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadow
30461Intensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
30462
30463var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif";
30464
30465var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif";
30466
30467var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
30468
30469var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
30470
30471var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
30472
30473var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF
vendor: 10,573 bytes, lines 30473-30519
30473\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n#endif";
30474
30475var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = sRGBTransferEOTF( sampledDiffuseColor );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif";
30476
30477var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
30478
30479var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif";
30480
30481var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
30482
30483var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
30484
30485var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
30486
30487var morphinstance_vertex = "#ifdef USE_INSTANCING_MORPH\n\tfloat morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\tfloat morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tmorphTargetInfluences[i] =  texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r;\n\t}\n#endif";
30488
30489var morphcolor_vertex = "#if defined( USE_MORPHCOLORS )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif";
30490
30491var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif";
30492
30493var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_INSTANCING_MORPH\n\t\tuniform float morphTargetBaseInfluence;\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t#endif\n\tuniform sampler2DArray morphTargetsTexture;\n\tuniform ivec2 morphTargetsTextureSize;\n\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t}\n#endif";
30494
30495var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif";
30496
30497var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;";
30498
30499var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
30500
30501var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
30502
30503var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
30504
30505var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif";
30506
30507var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif";
30508
30509var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif";
30510
30511var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif";
30512
30513var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif";
30514
30515var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif";
30516
30517var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );";
30518
30519var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;const float ShiftRight8 = 1. / 256.;\nconst float Inv255 = 1. / 255.;\nconst vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 );\nconst vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g );\nconst vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b );\nconst vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a );\nvec4 packDepthToRGBA( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec4( 0., 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec4( 1., 1., 1., 1. );\n\tfloat vuf;\n\tfloat af = modf( v * PackFactors.a, vuf );\n\tfloat bf = modf( vuf * ShiftRight8, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af );\n}\nvec3 packDepthToRGB( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec3( 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec3( 1., 1., 1. );\n\tfloat vuf;\n\tfloat bf = modf( v * PackFactors.b, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec3( vuf * Inv255, gf * PackUpscale, bf );\n}\nvec2 packDepthToRG( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec2( 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec2( 1., 1. );\n\tfloat vuf;\n\tfloat gf = modf( v * 256., vuf );\n\treturn vec2( vuf * Inv255, gf );\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors4 );\n}\nfloat unpackRGBToDepth( const in vec3 v ) {\n\treturn dot( v, UnpackFactors3 );\n}\nfloat unpackRGToDepth( const in vec2 v ) {\n\treturn v.r * UnpackFactors2.r + v.g * UnpackFactors2.g;\n}\nvec4 pack2HalfToRGBA( const in vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( const in vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\t
30519return depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}";
30520
30521var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
30522
30523var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;";
30524
30525var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
30526
30527var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif";
30528
30529var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
30530
30531var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
30532
30533var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;
30533\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t  texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t  f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t  texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t  f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tfloat shadow = 1.0;\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\t\n\t\tfloat lightToPositionLength = length( lightToPosition );\n\t\tif ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {\n\t\t\tfloat dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\t\tdp += shadowBias;\n\t\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\t\tshadow = (\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t\t) * ( 1.0 / 9.0 );\n\t\t\t#else\n\t\t\t\tshadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n#endif";
30534
30535var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif";
30536
30537var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif";
30538
30539var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowIntensity, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowIntensity, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}";
30540
30541var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
30542
30543var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif";
30544
30545var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif";
30546
30547var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif";
30548
30549var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
30550
30551var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
30552
30553var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
30554
30555var tonemapping_pars_fragment = 
vendor: 3,668 bytes, line 30555
30555"#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 CineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3(  1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108,  1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605,  1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 NeutralToneMapping( vec3 color ) {\n\tconst float StartCompression = 0.8 - 0.04;\n\tconst float Desaturation = 0.15;\n\tcolor *= toneMappingExposure;\n\tfloat x = min( color.r, min( color.g, color.b ) );\n\tfloat offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n\tcolor -= offset;\n\tfloat peak = max( color.r, max( color.g, color.b ) );\n\tif ( peak < StartCompression ) return color;\n\tfloat d = 1. - StartCompression;\n\tfloat newPeak = 1. - d * d / ( peak + d - StartCompression );\n\tcolor *= newPeak / peak;\n\tfloat g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\n\treturn mix( color, vec3( newPeak ), g );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"
30555;
30556
30557var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor
vendor: 15,291 bytes, lines 30557-30575
30557, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif";
30558
30559var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a *  a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec4 transmittedLight;\n\t\tvec3 transmittance;\n\t\t#ifdef USE_DISPERSION\n\t\t\tfloat halfSpread = ( ior - 1.0 ) * 0.025 * dispersion;\n\t\t\tvec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread );\n\t\t\tfor ( int i = 0; i < 3; i ++ ) {\n\t\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix );\n\t\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\t\trefractionCoords += 1.0;\n\t\t\t\trefractionCoords /= 2.0;\n\t\t\t\tvec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] );\n\t\t\t\ttransmittedLight[ i ] = transmissionSample[ i ];\n\t\t\t\ttransmittedLight.a += transmissionSample.a;\n\t\t\t\ttransmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ];\n\t\t\t}\n\t\t\ttransmittedLight.a /= 3.0;\n\t\t#else\n\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\trefractionCoords += 1.0;\n\t\t\trefractionCoords /= 2.0;\n\t\t\ttransmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\t\ttransmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\t#endif\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif";
30560
30561var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif";
30562
30563var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif";
30564
30565var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif";
30566
30567var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif";
30568
30569const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
30570
30571const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
30572
30573const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
30574
30575const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float 
30575flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
30576
30577const vertex$f = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
30578
30579const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
30580
30581const vertex$e = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#include <morphinstance_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvHighPrecisionZW = gl_Position.zw;\n}";
30582
30583const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <clipping_planes_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <logdepthbuf_fragment>\n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#elif DEPTH_PACKING == 3202\n\t\tgl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 );\n\t#elif DEPTH_PACKING == 3203\n\t\tgl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 );\n\t#endif\n}";
30584
30585const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#include <morphinstance_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}";
30586
30587const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <clipping_planes_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}";
30588
30589const vertex$c = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}";
30590
30591const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
30592
30593const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
30594
30595const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
30596
30597const vertex$a = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinbase_vertex>\n\t\t#include <skinnormal_vertex>\n\t\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}";
30598
30599const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
30600
30601const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
30602
30603const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_lambert_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_lambert_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
30604
30605const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
30606
30607const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;
30607\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
30608
30609const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}";
30610
30611const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}";
30612
30613const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
30614
30615const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
30616
30617const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}";
30618
30619const fragment$5 = 
vendor: 4,251 bytes, line 30619
30619"#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_DISPERSION\n\tuniform float dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <iridescence_fragment>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_physical_pars_fragment>\n#include <transmission_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_pars_fragment>\n#include <iridescence_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <clearcoat_normal_fragment_begin>\n\t#include <clearcoat_normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include <transmission_fragment>\n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"
vendor: 20,917 bytes, lines 30619-31135
30619;
30620
30621const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
30622
30623const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_toon_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_toon_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
30624
30625const vertex$3 = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}";
30626
30627const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
30628
30629const vertex$2 = "#include <common>\n#include <batching_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
30630
30631const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <logdepthbuf_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
30632
30633const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
30634
30635const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
30636
30637const ShaderChunk = {
30638	alphahash_fragment: alphahash_fragment,
30639	alphahash_pars_fragment: alphahash_pars_fragment,
30640	alphamap_fragment: alphamap_fragment,
30641	alphamap_pars_fragment: alphamap_pars_fragment,
30642	alphatest_fragment: alphatest_fragment,
30643	alphatest_pars_fragment: alphatest_pars_fragment,
30644	aomap_fragment: aomap_fragment,
30645	aomap_pars_fragment: aomap_pars_fragment,
30646	batching_pars_vertex: batching_pars_vertex,
30647	batching_vertex: batching_vertex,
30648	begin_vertex: begin_vertex,
30649	beginnormal_vertex: beginnormal_vertex,
30650	bsdfs: bsdfs,
30651	iridescence_fragment: iridescence_fragment,
30652	bumpmap_pars_fragment: bumpmap_pars_fragment,
30653	clipping_planes_fragment: clipping_planes_fragment,
30654	clipping_planes_pars_fragment: clipping_planes_pars_fragment,
30655	clipping_planes_pars_vertex: clipping_planes_pars_vertex,
30656	clipping_planes_vertex: clipping_planes_vertex,
30657	color_fragment: color_fragment,
30658	color_pars_fragment: color_pars_fragment,
30659	color_pars_vertex: color_pars_vertex,
30660	color_vertex: color_vertex,
30661	common: common,
30662	cube_uv_reflection_fragment: cube_uv_reflection_fragment,
30663	defaultnormal_vertex: defaultnormal_vertex,
30664	displacementmap_pars_vertex: displacementmap_pars_vertex,
30665	displacementmap_vertex: displacementmap_vertex,
30666	emissivemap_fragment: emissivemap_fragment,
30667	emissivemap_pars_fragment: emissivemap_pars_fragment,
30668	colorspace_fragment: colorspace_fragment,
30669	colorspace_pars_fragment: colorspace_pars_fragment,
30670	envmap_fragment: envmap_fragment,
30671	envmap_common_pars_fragment: envmap_common_pars_fragment,
30672	envmap_pars_fragment: envmap_pars_fragment,
30673	envmap_pars_vertex: envmap_pars_vertex,
30674	envmap_physical_pars_fragment: envmap_physical_pars_fragment,
30675	envmap_vertex: envmap_vertex,
30676	fog_vertex: fog_vertex,
30677	fog_pars_vertex: fog_pars_vertex,
30678	fog_fragment: fog_fragment,
30679	fog_pars_fragment: fog_pars_fragment,
30680	gradientmap_pars_fragment: gradientmap_pars_fragment,
30681	lightmap_pars_fragment: lightmap_pars_fragment,
30682	lights_lambert_fragment: lights_lambert_fragment,
30683	lights_lambert_pars_fragment: lights_lambert_pars_fragment,
30684	lights_pars_begin: lights_pars_begin,
30685	lights_toon_fragment: lights_toon_fragment,
30686	lights_toon_pars_fragment: lights_toon_pars_fragment,
30687	lights_phong_fragment: lights_phong_fragment,
30688	lights_phong_pars_fragment: lights_phong_pars_fragment,
30689	lights_physical_fragment: lights_physical_fragment,
30690	lights_physical_pars_fragment: lights_physical_pars_fragment,
30691	lights_fragment_begin: lights_fragment_begin,
30692	lights_fragment_maps: lights_fragment_maps,
30693	lights_fragment_end: lights_fragment_end,
30694	logdepthbuf_fragment: logdepthbuf_fragment,
30695	logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
30696	logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
30697	logdepthbuf_vertex: logdepthbuf_vertex,
30698	map_fragment: map_fragment,
30699	map_pars_fragment: map_pars_fragment,
30700	map_particle_fragment: map_particle_fragment,
30701	map_particle_pars_fragment: map_particle_pars_fragment,
30702	metalnessmap_fragment: metalnessmap_fragment,
30703	metalnessmap_pars_fragment: metalnessmap_pars_fragment,
30704	morphinstance_vertex: morphinstance_vertex,
30705	morphcolor_vertex: morphcolor_vertex,
30706	morphnormal_vertex: morphnormal_vertex,
30707	morphtarget_pars_vertex: morphtarget_pars_vertex,
30708	morphtarget_vertex: morphtarget_vertex,
30709	normal_fragment_begin: normal_fragment_begin,
30710	normal_fragment_maps: normal_fragment_maps,
30711	normal_pars_fragment: normal_pars_fragment,
30712	normal_pars_vertex: normal_pars_vertex,
30713	normal_vertex: normal_vertex,
30714	normalmap_pars_fragment: normalmap_pars_fragment,
30715	clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
30716	clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
30717	clearcoat_pars_fragment: clearcoat_pars_fragment,
30718	iridescence_pars_fragment: iridescence_pars_fragment,
30719	opaque_fragment: opaque_fragment,
30720	packing: packing,
30721	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
30722	project_vertex: project_vertex,
30723	dithering_fragment: dithering_fragment,
30724	dithering_pars_fragment: dithering_pars_fragment,
30725	roughnessmap_fragment: roughnessmap_fragment,
30726	roughnessmap_pars_fragment: roughnessmap_pars_fragment,
30727	shadowmap_pars_fragment: shadowmap_pars_fragment,
30728	shadowmap_pars_vertex: shadowmap_pars_vertex,
30729	shadowmap_vertex: shadowmap_vertex,
30730	shadowmask_pars_fragment: shadowmask_pars_fragment,
30731	skinbase_vertex: skinbase_vertex,
30732	skinning_pars_vertex: skinning_pars_vertex,
30733	skinning_vertex: skinning_vertex,
30734	skinnormal_vertex: skinnormal_vertex,
30735	specularmap_fragment: specularmap_fragment,
30736	specularmap_pars_fragment: specularmap_pars_fragment,
30737	tonemapping_fragment: tonemapping_fragment,
30738	tonemapping_pars_fragment: tonemapping_pars_fragment,
30739	transmission_fragment: transmission_fragment,
30740	transmission_pars_fragment: transmission_pars_fragment,
30741	uv_pars_fragment: uv_pars_fragment,
30742	uv_pars_vertex: uv_pars_vertex,
30743	uv_vertex: uv_vertex,
30744	worldpos_vertex: worldpos_vertex,
30745
30746	background_vert: vertex$h,
30747	background_frag: fragment$h,
30748	backgroundCube_vert: vertex$g,
30749	backgroundCube_frag: fragment$g,
30750	cube_vert: vertex$f,
30751	cube_frag: fragment$f,
30752	depth_vert: vertex$e,
30753	depth_frag: fragment$e,
30754	distanceRGBA_vert: vertex$d,
30755	distanceRGBA_frag: fragment$d,
30756	equirect_vert: vertex$c,
30757	equirect_frag: fragment$c,
30758	linedashed_vert: vertex$b,
30759	linedashed_frag: fragment$b,
30760	meshbasic_vert: vertex$a,
30761	meshbasic_frag: fragment$a,
30762	meshlambert_vert: vertex$9,
30763	meshlambert_frag: fragment$9,
30764	meshmatcap_vert: vertex$8,
30765	meshmatcap_frag: fragment$8,
30766	meshnormal_vert: vertex$7,
30767	meshnormal_frag: fragment$7,
30768	meshphong_vert: vertex$6,
30769	meshphong_frag: fragment$6,
30770	meshphysical_vert: vertex$5,
30771	meshphysical_frag: fragment$5,
30772	meshtoon_vert: vertex$4,
30773	meshtoon_frag: fragment$4,
30774	points_vert: vertex$3,
30775	points_frag: fragment$3,
30776	shadow_vert: vertex$2,
30777	shadow_frag: fragment$2,
30778	sprite_vert: vertex$1,
30779	sprite_frag: fragment$1
30780};
30781
30782// Uniforms library for shared webgl shaders
30783const UniformsLib = {
30784
30785	common: {
30786
30787		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
30788		opacity: { value: 1.0 },
30789
30790		map: { value: null },
30791		mapTransform: { value: /*@__PURE__*/ new Matrix3() },
30792
30793		alphaMap: { value: null },
30794		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
30795
30796		alphaTest: { value: 0 }
30797
30798	},
30799
30800	specularmap: {
30801
30802		specularMap: { value: null },
30803		specularMapTransform: { value: /*@__PURE__*/ new Matrix3() }
30804
30805	},
30806
30807	envmap: {
30808
30809		envMap: { value: null },
30810		envMapRotation: { value: /*@__PURE__*/ new Matrix3() },
30811		flipEnvMap: { value: -1 },
30812		reflectivity: { value: 1.0 }, // basic, lambert, phong
30813		ior: { value: 1.5 }, // physical
30814		refractionRatio: { value: 0.98 }, // basic, lambert, phong
30815
30816	},
30817
30818	aomap: {
30819
30820		aoMap: { value: null },
30821		aoMapIntensity: { value: 1 },
30822		aoMapTransform: { value: /*@__PURE__*/ new Matrix3() }
30823
30824	},
30825
30826	lightmap: {
30827
30828		lightMap: { value: null },
30829		lightMapIntensity: { value: 1 },
30830		lightMapTransform: { value: /*@__PURE__*/ new Matrix3() }
30831
30832	},
30833
30834	bumpmap: {
30835
30836		bumpMap: { value: null },
30837		bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() },
30838		bumpScale: { value: 1 }
30839
30840	},
30841
30842	normalmap: {
30843
30844		normalMap: { value: null },
30845		normalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
30846		normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }
30847
30848	},
30849
30850	displacementmap: {
30851
30852		displacementMap: { value: null },
30853		displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() },
30854		displacementScale: { value: 1 },
30855		displacementBias: { value: 0 }
30856
30857	},
30858
30859	emissivemap: {
30860
30861		emissiveMap: { value: null },
30862		emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() }
30863
30864	},
30865
30866	metalnessmap: {
30867
30868		metalnessMap: { value: null },
30869		metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
30870
30871	},
30872
30873	roughnessmap: {
30874
30875		roughnessMap: { value: null },
30876		roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
30877
30878	},
30879
30880	gradientmap: {
30881
30882		gradientMap: { value: null }
30883
30884	},
30885
30886	fog: {
30887
30888		fogDensity: { value: 0.00025 },
30889		fogNear: { value: 1 },
30890		fogFar: { value: 2000 },
30891		fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }
30892
30893	},
30894
30895	lights: {
30896
30897		ambientLightColor: { value: [] },
30898
30899		lightProbe: { value: [] },
30900
30901		directionalLights: { value: [], properties: {
30902			direction: {},
30903			color: {}
30904		} },
30905
30906		directionalLightShadows: { value: [], properties: {
30907			shadowIntensity: 1,
30908			shadowBias: {},
30909			shadowNormalBias: {},
30910			shadowRadius: {},
30911			shadowMapSize: {}
30912		} },
30913
30914		directionalShadowMap: { value: [] },
30915		directionalShadowMatrix: { value: [] },
30916
30917		spotLights: { value: [], properties: {
30918			color: {},
30919			position: {},
30920			direction: {},
30921			distance: {},
30922			coneCos: {},
30923			penumbraCos: {},
30924			decay: {}
30925		} },
30926
30927		spotLightShadows: { value: [], properties: {
30928			shadowIntensity: 1,
30929			shadowBias: {},
30930			shadowNormalBias: {},
30931			shadowRadius: {},
30932			shadowMapSize: {}
30933		} },
30934
30935		spotLightMap: { value: [] },
30936		spotShadowMap: { value: [] },
30937		spotLightMatrix: { value: [] },
30938
30939		pointLights: { value: [], properties: {
30940			color: {},
30941			position: {},
30942			decay: {},
30943			distance: {}
30944		} },
30945
30946		pointLightShadows: { value: [], properties: {
30947			shadowIntensity: 1,
30948			shadowBias: {},
30949			shadowNormalBias: {},
30950			shadowRadius: {},
30951			shadowMapSize: {},
30952			shadowCameraNear: {},
30953			shadowCameraFar: {}
30954		} },
30955
30956		pointShadowMap: { value: [] },
30957		pointShadowMatrix: { value: [] },
30958
30959		hemisphereLights: { value: [], properties: {
30960			direction: {},
30961			skyColor: {},
30962			groundColor: {}
30963		} },
30964
30965		// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
30966		rectAreaLights: { value: [], properties: {
30967			color: {},
30968			position: {},
30969			width: {},
30970			height: {}
30971		} },
30972
30973		ltc_1: { value: null },
30974		ltc_2: { value: null }
30975
30976	},
30977
30978	points: {
30979
30980		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
30981		opacity: { value: 1.0 },
30982		size: { value: 1.0 },
30983		scale: { value: 1.0 },
30984		map: { value: null },
30985		alphaMap: { value: null },
30986		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
30987		alphaTest: { value: 0 },
30988		uvTransform: { value: /*@__PURE__*/ new Matrix3() }
30989
30990	},
30991
30992	sprite: {
30993
30994		diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
30995		opacity: { value: 1.0 },
30996		center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) },
30997		rotation: { value: 0.0 },
30998		map: { value: null },
30999		mapTransform: { value: /*@__PURE__*/ new Matrix3() },
31000		alphaMap: { value: null },
31001		alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31002		alphaTest: { value: 0 }
31003
31004	}
31005
31006};
31007
31008const ShaderLib = {
31009
31010	basic: {
31011
31012		uniforms: /*@__PURE__*/ mergeUniforms( [
31013			UniformsLib.common,
31014			UniformsLib.specularmap,
31015			UniformsLib.envmap,
31016			UniformsLib.aomap,
31017			UniformsLib.lightmap,
31018			UniformsLib.fog
31019		] ),
31020
31021		vertexShader: ShaderChunk.meshbasic_vert,
31022		fragmentShader: ShaderChunk.meshbasic_frag
31023
31024	},
31025
31026	lambert: {
31027
31028		uniforms: /*@__PURE__*/ mergeUniforms( [
31029			UniformsLib.common,
31030			UniformsLib.specularmap,
31031			UniformsLib.envmap,
31032			UniformsLib.aomap,
31033			UniformsLib.lightmap,
31034			UniformsLib.emissivemap,
31035			UniformsLib.bumpmap,
31036			UniformsLib.normalmap,
31037			UniformsLib.displacementmap,
31038			UniformsLib.fog,
31039			UniformsLib.lights,
31040			{
31041				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
31042			}
31043		] ),
31044
31045		vertexShader: ShaderChunk.meshlambert_vert,
31046		fragmentShader: ShaderChunk.meshlambert_frag
31047
31048	},
31049
31050	phong: {
31051
31052		uniforms: /*@__PURE__*/ mergeUniforms( [
31053			UniformsLib.common,
31054			UniformsLib.specularmap,
31055			UniformsLib.envmap,
31056			UniformsLib.aomap,
31057			UniformsLib.lightmap,
31058			UniformsLib.emissivemap,
31059			UniformsLib.bumpmap,
31060			UniformsLib.normalmap,
31061			UniformsLib.displacementmap,
31062			UniformsLib.fog,
31063			UniformsLib.lights,
31064			{
31065				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
31066				specular: { value: /*@__PURE__*/ new Color( 0x111111 ) },
31067				shininess: { value: 30 }
31068			}
31069		] ),
31070
31071		vertexShader: ShaderChunk.meshphong_vert,
31072		fragmentShader: ShaderChunk.meshphong_frag
31073
31074	},
31075
31076	standard: {
31077
31078		uniforms: /*@__PURE__*/ mergeUniforms( [
31079			UniformsLib.common,
31080			UniformsLib.envmap,
31081			UniformsLib.aomap,
31082			UniformsLib.lightmap,
31083			UniformsLib.emissivemap,
31084			UniformsLib.bumpmap,
31085			UniformsLib.normalmap,
31086			UniformsLib.displacementmap,
31087			UniformsLib.roughnessmap,
31088			UniformsLib.metalnessmap,
31089			UniformsLib.fog,
31090			UniformsLib.lights,
31091			{
31092				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
31093				roughness: { value: 1.0 },
31094				metalness: { value: 0.0 },
31095				envMapIntensity: { value: 1 }
31096			}
31097		] ),
31098
31099		vertexShader: ShaderChunk.meshphysical_vert,
31100		fragmentShader: ShaderChunk.meshphysical_frag
31101
31102	},
31103
31104	toon: {
31105
31106		uniforms: /*@__PURE__*/ mergeUniforms( [
31107			UniformsLib.common,
31108			UniformsLib.aomap,
31109			UniformsLib.lightmap,
31110			UniformsLib.emissivemap,
31111			UniformsLib.bumpmap,
31112			UniformsLib.normalmap,
31113			UniformsLib.displacementmap,
31114			UniformsLib.gradientmap,
31115			UniformsLib.fog,
31116			UniformsLib.lights,
31117			{
31118				emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
31119			}
31120		] ),
31121
31122		vertexShader: ShaderChunk.meshtoon_vert,
31123		fragmentShader: ShaderChunk.meshtoon_frag
31124
31125	},
31126
31127	matcap: {
31128
31129		uniforms: /*@__PURE__*/ mergeUniforms( [
31130			UniformsLib.common,
31131			UniformsLib.bumpmap,
31132			UniformsLib.normalmap,
31133			UniformsLib.displacementmap,
31134			UniformsLib.fog,
31135			{
vendor: 6,435 bytes, lines 31136-31399
31136				matcap: { value: null }
31137			}
31138		] ),
31139
31140		vertexShader: ShaderChunk.meshmatcap_vert,
31141		fragmentShader: ShaderChunk.meshmatcap_frag
31142
31143	},
31144
31145	points: {
31146
31147		uniforms: /*@__PURE__*/ mergeUniforms( [
31148			UniformsLib.points,
31149			UniformsLib.fog
31150		] ),
31151
31152		vertexShader: ShaderChunk.points_vert,
31153		fragmentShader: ShaderChunk.points_frag
31154
31155	},
31156
31157	dashed: {
31158
31159		uniforms: /*@__PURE__*/ mergeUniforms( [
31160			UniformsLib.common,
31161			UniformsLib.fog,
31162			{
31163				scale: { value: 1 },
31164				dashSize: { value: 1 },
31165				totalSize: { value: 2 }
31166			}
31167		] ),
31168
31169		vertexShader: ShaderChunk.linedashed_vert,
31170		fragmentShader: ShaderChunk.linedashed_frag
31171
31172	},
31173
31174	depth: {
31175
31176		uniforms: /*@__PURE__*/ mergeUniforms( [
31177			UniformsLib.common,
31178			UniformsLib.displacementmap
31179		] ),
31180
31181		vertexShader: ShaderChunk.depth_vert,
31182		fragmentShader: ShaderChunk.depth_frag
31183
31184	},
31185
31186	normal: {
31187
31188		uniforms: /*@__PURE__*/ mergeUniforms( [
31189			UniformsLib.common,
31190			UniformsLib.bumpmap,
31191			UniformsLib.normalmap,
31192			UniformsLib.displacementmap,
31193			{
31194				opacity: { value: 1.0 }
31195			}
31196		] ),
31197
31198		vertexShader: ShaderChunk.meshnormal_vert,
31199		fragmentShader: ShaderChunk.meshnormal_frag
31200
31201	},
31202
31203	sprite: {
31204
31205		uniforms: /*@__PURE__*/ mergeUniforms( [
31206			UniformsLib.sprite,
31207			UniformsLib.fog
31208		] ),
31209
31210		vertexShader: ShaderChunk.sprite_vert,
31211		fragmentShader: ShaderChunk.sprite_frag
31212
31213	},
31214
31215	background: {
31216
31217		uniforms: {
31218			uvTransform: { value: /*@__PURE__*/ new Matrix3() },
31219			t2D: { value: null },
31220			backgroundIntensity: { value: 1 }
31221		},
31222
31223		vertexShader: ShaderChunk.background_vert,
31224		fragmentShader: ShaderChunk.background_frag
31225
31226	},
31227
31228	backgroundCube: {
31229
31230		uniforms: {
31231			envMap: { value: null },
31232			flipEnvMap: { value: -1 },
31233			backgroundBlurriness: { value: 0 },
31234			backgroundIntensity: { value: 1 },
31235			backgroundRotation: { value: /*@__PURE__*/ new Matrix3() }
31236		},
31237
31238		vertexShader: ShaderChunk.backgroundCube_vert,
31239		fragmentShader: ShaderChunk.backgroundCube_frag
31240
31241	},
31242
31243	cube: {
31244
31245		uniforms: {
31246			tCube: { value: null },
31247			tFlip: { value: -1 },
31248			opacity: { value: 1.0 }
31249		},
31250
31251		vertexShader: ShaderChunk.cube_vert,
31252		fragmentShader: ShaderChunk.cube_frag
31253
31254	},
31255
31256	equirect: {
31257
31258		uniforms: {
31259			tEquirect: { value: null },
31260		},
31261
31262		vertexShader: ShaderChunk.equirect_vert,
31263		fragmentShader: ShaderChunk.equirect_frag
31264
31265	},
31266
31267	distanceRGBA: {
31268
31269		uniforms: /*@__PURE__*/ mergeUniforms( [
31270			UniformsLib.common,
31271			UniformsLib.displacementmap,
31272			{
31273				referencePosition: { value: /*@__PURE__*/ new Vector3() },
31274				nearDistance: { value: 1 },
31275				farDistance: { value: 1000 }
31276			}
31277		] ),
31278
31279		vertexShader: ShaderChunk.distanceRGBA_vert,
31280		fragmentShader: ShaderChunk.distanceRGBA_frag
31281
31282	},
31283
31284	shadow: {
31285
31286		uniforms: /*@__PURE__*/ mergeUniforms( [
31287			UniformsLib.lights,
31288			UniformsLib.fog,
31289			{
31290				color: { value: /*@__PURE__*/ new Color( 0x00000 ) },
31291				opacity: { value: 1.0 }
31292			},
31293		] ),
31294
31295		vertexShader: ShaderChunk.shadow_vert,
31296		fragmentShader: ShaderChunk.shadow_frag
31297
31298	}
31299
31300};
31301
31302ShaderLib.physical = {
31303
31304	uniforms: /*@__PURE__*/ mergeUniforms( [
31305		ShaderLib.standard.uniforms,
31306		{
31307			clearcoat: { value: 0 },
31308			clearcoatMap: { value: null },
31309			clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31310			clearcoatNormalMap: { value: null },
31311			clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31312			clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) },
31313			clearcoatRoughness: { value: 0 },
31314			clearcoatRoughnessMap: { value: null },
31315			clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31316			dispersion: { value: 0 },
31317			iridescence: { value: 0 },
31318			iridescenceMap: { value: null },
31319			iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31320			iridescenceIOR: { value: 1.3 },
31321			iridescenceThicknessMinimum: { value: 100 },
31322			iridescenceThicknessMaximum: { value: 400 },
31323			iridescenceThicknessMap: { value: null },
31324			iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31325			sheen: { value: 0 },
31326			sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
31327			sheenColorMap: { value: null },
31328			sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31329			sheenRoughness: { value: 1 },
31330			sheenRoughnessMap: { value: null },
31331			sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31332			transmission: { value: 0 },
31333			transmissionMap: { value: null },
31334			transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31335			transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() },
31336			transmissionSamplerMap: { value: null },
31337			thickness: { value: 0 },
31338			thicknessMap: { value: null },
31339			thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31340			attenuationDistance: { value: 0 },
31341			attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
31342			specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) },
31343			specularColorMap: { value: null },
31344			specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31345			specularIntensity: { value: 1 },
31346			specularIntensityMap: { value: null },
31347			specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31348			anisotropyVector: { value: /*@__PURE__*/ new Vector2() },
31349			anisotropyMap: { value: null },
31350			anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() },
31351		}
31352	] ),
31353
31354	vertexShader: ShaderChunk.meshphysical_vert,
31355	fragmentShader: ShaderChunk.meshphysical_frag
31356
31357};
31358
31359const _box$1 = new Box3();
31360const _vector = new Vector3();
31361
31362/**
31363 * A series of vertex pairs, forming line segments.
31364 *
31365 * This is used in {@link LineSegments2} to describe the shape.
31366 *
31367 * @augments InstancedBufferGeometry
31368 * @three_import import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js';
31369 */
31370class LineSegmentsGeometry extends InstancedBufferGeometry {
31371
31372	/**
31373	 * Constructs a new line segments geometry.
31374	 */
31375	constructor() {
31376
31377		super();
31378
31379		/**
31380		 * This flag can be used for type testing.
31381		 *
31382		 * @type {boolean}
31383		 * @readonly
31384		 * @default true
31385		 */
31386		this.isLineSegmentsGeometry = true;
31387
31388		this.type = 'LineSegmentsGeometry';
31389
31390		const positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
31391		const uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ];
31392		const index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
31393
31394		this.setIndex( index );
31395		this.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
31396		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
31397
31398	}
31399
vendor: 6,346 bytes, lines 31400-31681
31400	/**
31401	 * Applies the given 4x4 transformation matrix to the geometry.
31402	 *
31403	 * @param {Matrix4} matrix - The matrix to apply.
31404	 * @return {LineSegmentsGeometry} A reference to this instance.
31405	 */
31406	applyMatrix4( matrix ) {
31407
31408		const start = this.attributes.instanceStart;
31409		const end = this.attributes.instanceEnd;
31410
31411		if ( start !== undefined ) {
31412
31413			start.applyMatrix4( matrix );
31414
31415			end.applyMatrix4( matrix );
31416
31417			start.needsUpdate = true;
31418
31419		}
31420
31421		if ( this.boundingBox !== null ) {
31422
31423			this.computeBoundingBox();
31424
31425		}
31426
31427		if ( this.boundingSphere !== null ) {
31428
31429			this.computeBoundingSphere();
31430
31431		}
31432
31433		return this;
31434
31435	}
31436
31437	/**
31438	 * Sets the given line positions for this geometry. The length must be a multiple of six since
31439	 * each line segment is defined by a start end vertex in the pattern `(xyz xyz)`.
31440	 *
31441	 * @param {Float32Array|Array<number>} array - The position data to set.
31442	 * @return {LineSegmentsGeometry} A reference to this geometry.
31443	 */
31444	setPositions( array ) {
31445
31446		let lineSegments;
31447
31448		if ( array instanceof Float32Array ) {
31449
31450			lineSegments = array;
31451
31452		} else if ( Array.isArray( array ) ) {
31453
31454			lineSegments = new Float32Array( array );
31455
31456		}
31457
31458		const instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz
31459
31460		this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
31461		this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
31462
31463		this.instanceCount = this.attributes.instanceStart.count;
31464
31465		//
31466
31467		this.computeBoundingBox();
31468		this.computeBoundingSphere();
31469
31470		return this;
31471
31472	}
31473
31474	/**
31475	 * Sets the given line colors for this geometry. The length must be a multiple of six since
31476	 * each line segment is defined by a start end color in the pattern `(rgb rgb)`.
31477	 *
31478	 * @param {Float32Array|Array<number>} array - The position data to set.
31479	 * @return {LineSegmentsGeometry} A reference to this geometry.
31480	 */
31481	setColors( array ) {
31482
31483		let colors;
31484
31485		if ( array instanceof Float32Array ) {
31486
31487			colors = array;
31488
31489		} else if ( Array.isArray( array ) ) {
31490
31491			colors = new Float32Array( array );
31492
31493		}
31494
31495		const instanceColorBuffer = new InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb
31496
31497		this.setAttribute( 'instanceColorStart', new InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb
31498		this.setAttribute( 'instanceColorEnd', new InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb
31499
31500		return this;
31501
31502	}
31503
31504	/**
31505	 * Setups this line segments geometry from the given wireframe geometry.
31506	 *
31507	 * @param {WireframeGeometry} geometry - The geometry that should be used as a data source for this geometry.
31508	 * @return {LineSegmentsGeometry} A reference to this geometry.
31509	 */
31510	fromWireframeGeometry( geometry ) {
31511
31512		this.setPositions( geometry.attributes.position.array );
31513
31514		return this;
31515
31516	}
31517
31518	/**
31519	 * Setups this line segments geometry from the given edges geometry.
31520	 *
31521	 * @param {EdgesGeometry} geometry - The geometry that should be used as a data source for this geometry.
31522	 * @return {LineSegmentsGeometry} A reference to this geometry.
31523	 */
31524	fromEdgesGeometry( geometry ) {
31525
31526		this.setPositions( geometry.attributes.position.array );
31527
31528		return this;
31529
31530	}
31531
31532	/**
31533	 * Setups this line segments geometry from the given mesh.
31534	 *
31535	 * @param {Mesh} mesh - The mesh geometry that should be used as a data source for this geometry.
31536	 * @return {LineSegmentsGeometry} A reference to this geometry.
31537	 */
31538	fromMesh( mesh ) {
31539
31540		this.fromWireframeGeometry( new WireframeGeometry( mesh.geometry ) );
31541
31542		// set colors, maybe
31543
31544		return this;
31545
31546	}
31547
31548	/**
31549	 * Setups this line segments geometry from the given line segments.
31550	 *
31551	 * @param {LineSegments} lineSegments - The line segments that should be used as a data source for this geometry.
31552	 * Assumes the source geometry is not using indices.
31553	 * @return {LineSegmentsGeometry} A reference to this geometry.
31554	 */
31555	fromLineSegments( lineSegments ) {
31556
31557		const geometry = lineSegments.geometry;
31558
31559		this.setPositions( geometry.attributes.position.array ); // assumes non-indexed
31560
31561		// set colors, maybe
31562
31563		return this;
31564
31565	}
31566
31567	computeBoundingBox() {
31568
31569		if ( this.boundingBox === null ) {
31570
31571			this.boundingBox = new Box3();
31572
31573		}
31574
31575		const start = this.attributes.instanceStart;
31576		const end = this.attributes.instanceEnd;
31577
31578		if ( start !== undefined && end !== undefined ) {
31579
31580			this.boundingBox.setFromBufferAttribute( start );
31581
31582			_box$1.setFromBufferAttribute( end );
31583
31584			this.boundingBox.union( _box$1 );
31585
31586		}
31587
31588	}
31589
31590	computeBoundingSphere() {
31591
31592		if ( this.boundingSphere === null ) {
31593
31594			this.boundingSphere = new Sphere();
31595
31596		}
31597
31598		if ( this.boundingBox === null ) {
31599
31600			this.computeBoundingBox();
31601
31602		}
31603
31604		const start = this.attributes.instanceStart;
31605		const end = this.attributes.instanceEnd;
31606
31607		if ( start !== undefined && end !== undefined ) {
31608
31609			const center = this.boundingSphere.center;
31610
31611			this.boundingBox.getCenter( center );
31612
31613			let maxRadiusSq = 0;
31614
31615			for ( let i = 0, il = start.count; i < il; i ++ ) {
31616
31617				_vector.fromBufferAttribute( start, i );
31618				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
31619
31620				_vector.fromBufferAttribute( end, i );
31621				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
31622
31623			}
31624
31625			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
31626
31627			if ( isNaN( this.boundingSphere.radius ) ) {
31628
31629				console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this );
31630
31631			}
31632
31633		}
31634
31635	}
31636
31637	toJSON() {
31638
31639		// todo
31640
31641	}
31642
31643}
31644
31645UniformsLib.line = {
31646
31647	worldUnits: { value: 1 },
31648	linewidth: { value: 1 },
31649	resolution: { value: new Vector2( 1, 1 ) },
31650	dashOffset: { value: 0 },
31651	dashScale: { value: 1 },
31652	dashSize: { value: 1 },
31653	gapSize: { value: 1 } // todo FIX - maybe change to totalSize
31654
31655};
31656
31657ShaderLib[ 'line' ] = {
31658
31659	uniforms: UniformsUtils.merge( [
31660		UniformsLib.common,
31661		UniformsLib.fog,
31662		UniformsLib.line
31663	] ),
31664
31665	vertexShader:
31666	/* glsl */`
31667		#include <common>
31668		#include <color_pars_vertex>
31669		#include <fog_pars_vertex>
31670		#include <logdepthbuf_pars_vertex>
31671		#include <clipping_planes_pars_vertex>
31672
31673		uniform float linewidth;
31674		uniform vec2 resolution;
31675
31676		attribute vec3 instanceStart;
31677		attribute vec3 instanceEnd;
31678
31679		attribute vec3 instanceColorStart;
31680		attribute vec3 instanceColorEnd;
31681
31682		#ifdef WORLD_UNITS
31683
31684			varying vec4 worldPos;
31685			varying vec3 worldStart;
31686			varying vec3 worldEnd;
31687
31688			#ifdef USE_DASH
31689
31690				varying vec2 vUv;
31691
31692			#endif
31693
31694		#else
31695
31696			varying vec2 vUv;
31697
31698		#endif
31699
31700		#ifdef USE_DASH
31701
31702			uniform float dashScale;
31703			attribute float instanceDistanceStart;
31704			attribute float instanceDistanceEnd;
31705			varying float vLineDistance;
31706
31707		#endif
31708
31709		void trimSegment( const in vec4 start, inout vec4 end ) {
31710
31711			// trim end segment so it terminates between the camera plane and the near plane
31712
31713			// conservative estimate of the near plane
31714			float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
31715			float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
31716			float nearEstimate = - 0.5 * b / a;
31717
31718			float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
31719
31720			end.xyz = mix( start.xyz, end.xyz, alpha );
31721
31722		}
31723
31724		void main() {
31725
31726			#ifdef USE_COLOR
31727
31728				vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
31729
31730			#endif
31731
31732			#ifdef USE_DASH
31733
31734				vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
31735				vUv = uv;
31736
31737			#endif
31738
31739			float aspect = resolution.x / resolution.y;
31740
31741			// camera space
31742			vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
31743			vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
31744
31745			#ifdef WORLD_UNITS
31746
31747				worldStart = start.xyz;
31748				worldEnd = end.xyz;
31749
31750			#else
31751
31752				vUv = uv;
31753
31754			#endif
31755
31756			// special case for perspective projection, and segments that terminate either in, or behind, the camera plane
31757			// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
31758			// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
31759			// perhaps there is a more elegant solution -- WestLangley
31760
31761			bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
31762
31763			if ( perspective ) {
31764
31765				if ( start.z < 0.0 && end.z >= 0.0 ) {
31766
31767					trimSegment( start, end );
31768
31769				} else if ( end.z < 0.0 && start.z >= 0.0 ) {
31770
31771					trimSegment( end, start );
31772
31773				}
31774
31775			}
31776
31777			// clip space
31778			vec4 clipStart = projectionMatrix * start;
31779			vec4 clipEnd = projectionMatrix * end;
31780
31781			// ndc space
31782			vec3 ndcStart = clipStart.xyz / clipStart.w;
31783			vec3 ndcEnd = clipEnd.xyz / clipEnd.w;
31784
31785			// direction
31786			vec2 dir = ndcEnd.xy - ndcStart.xy;
31787
31788			// account for clip-space aspect ratio
31789			dir.x *= aspect;
31790			dir = normalize( dir );
31791
31792			#ifdef WORLD_UNITS
31793
31794				vec3 worldDir = normalize( end.xyz - start.xyz );
31795				vec3 tmpFwd = normalize( mix( start.xyz, end.xyz, 0.5 ) );
31796				vec3 worldUp = normalize( cross( worldDir, tmpFwd ) );
31797				vec3 worldFwd = cross( worldDir, worldUp );
31798				worldPos = position.y < 0.5 ? start: end;
31799
31800				// height offset
31801				float hw = linewidth * 0.5;
31802				worldPos.xyz += position.x < 0.0 ? hw * worldUp : - hw * worldUp;
31803
31804				// don't extend the line if we're rendering dashes because we
31805				// won't be rendering the endcaps
31806				#ifndef USE_DASH
31807
31808					// cap extension
31809					worldPos.xyz += position.y < 0.5 ? - hw * worldDir : hw * worldDir;
31810
31811					// add width to the box
31812					worldPos.xyz += worldFwd * hw;
31813
31814					// endcaps
31815					if ( position.y > 1.0 || position.y < 0.0 ) {
31816
31817						worldPos.xyz -= worldFwd * 2.0 * hw;
31818
31819					}
31820
31821				#endif
31822
31823				// project the worldpos
31824				vec4 clip = projectionMatrix * worldPos;
31825
31826				// shift the depth of the projected points so the line
31827				// segments overlap neatly
31828				vec3 clipPose = ( position.y < 0.5 ) ? ndcStart : ndcEnd;
31829				clip.z = clipPose.z * clip.w;
31830
31831			#else
31832
31833				vec2 offset = vec2( dir.y, - dir.x );
31834				// undo aspect ratio adjustment
31835				dir.x /= aspect;
31836				offset.x /= aspect;
31837
31838				// sign flip
31839				if ( position.x < 0.0 ) offset *= - 1.0;
31840
31841				// endcaps
31842				if ( position.y < 0.0 ) {
31843
31844					offset += - dir;
31845
31846				} else if ( position.y > 1.0 ) {
31847
31848					offset += dir;
31849
31850				}
31851
31852				// adjust for linewidth
31853				offset *= linewidth;
31854
31855				// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
31856				offset /= resolution.y;
31857
31858				// select end
31859				vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
31860
31861				// back to clip space
31862				offset *= clip.w;
31863
31864				clip.xy += offset;
31865
31866			#endif
31867
31868			gl_Position = clip;
31869
31870			vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation
31871
31872			#include <logdepthbuf_vertex>
31873			#include <clipping_planes_vertex>
31874			#include <fog_vertex>
31875
31876		}
31877		`,
31878
31879	fragmentShader:
31880	/* glsl */`
31881		uniform vec3 diffuse;
31882		uniform float opacity;
31883		uniform float linewidth;
31884
31885		#ifdef USE_DASH
31886
31887			uniform float dashOffset;
31888			uniform float dashSize;
31889			uniform float gapSize;
31890
31891		#endif
31892
31893		varying float vLineDistance;
31894
31895		#ifdef WORLD_UNITS
31896
31897			varying vec4 worldPos;
31898			varying vec3 worldStart;
31899			varying vec3 worldEnd;
31900
31901			#ifdef USE_DASH
31902
31903				varying vec2 vUv;
31904
31905			#endif
31906
31907		#else
31908
31909			varying vec2 vUv;
31910
31911		#endif
31912
31913		#include <common>
31914		#include <color_pars_fragment>
31915		#include <fog_pars_fragment>
31916		#include <logdepthbuf_pars_fragment>
31917		#include <clipping_planes_pars_fragment>
31918
31919		vec2 closestLineToLine(vec3 p1, vec3 p2, vec3 p3, vec3 p4) {
31920
31921			float mua;
31922			float mub;
31923
31924			vec3 p13 = p1 - p3;
31925			vec3 p43 = p4 - p3;
31926
31927			vec3 p21 = p2 - p1;
31928
31929			float d1343 = dot( p13, p43 );
31930			float d4321 = dot( p43, p21 );
31931			float d1321 = dot( p13, p21 );
31932			float d4343 = dot( p43, p43 );
31933			float d2121 = dot( p21, p21 );
31934
31935			float denom = d2121 * d4343 - d4321 * d4321;
31936
31937			float numer = d1343 * d4321 - d1321 * d4343;
31938
31939			mua = numer / denom;
31940			mua = clamp( mua, 0.0, 1.0 );
31941			mub = ( d1343 + d4321 * ( mua ) ) / d4343;
31942			mub = clamp( mub, 0.0, 1.0 );
31943
31944			return vec2( mua, mub );
31945
31946		}
31947
31948		void main() {
31949
31950			float alpha = opacity;
31951			vec4 diffuseColor = vec4( diffuse, alpha );
31952
31953			#include <clipping_planes_fragment>
31954
31955			#ifdef USE_DASH
31956
31957				if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
31958
31959				if ( mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize ) discard; // todo - FIX
31960
31961			#endif
31962
31963			#ifdef WORLD_UNITS
31964
31965				// Find the closest points on the view ray and the line segment
31966				vec3 rayEnd = normalize( worldPos.xyz ) * 1e5;
31967				vec3 lineDir = worldEnd - worldStart;
31968				vec2 params = closestLineToLine( worldStart, worldEnd, vec3( 0.0, 0.0, 0.0 ), rayEnd );
31969
31970				vec3 p1 = worldStart + lineDir * params.x;
31971				vec3 p2 = rayEnd * params.y;
31972				vec3 delta = p1 - p2;
31973				float len = length( delta );
31974				float norm = len / linewidth;
31975
31976				#ifndef USE_DASH
31977
31978					#ifdef USE_ALPHA_TO_COVERAGE
31979
31980						float dnorm = fwidth( norm );
31981						alpha = 1.0 - smoothstep( 0.5 - dnorm, 0.5 + dnorm, norm );
31982
31983					#else
31984
31985						if ( norm > 0.5 ) {
31986
31987							discard;
31988
31989						}
31990
31991					#endif
31992
31993				#endif
31994
31995			#else
31996
31997				#ifdef USE_ALPHA_TO_COVERAGE
31998
31999					// artifacts appear on some hardware if a derivative is taken within a conditional
32000					float a = vUv.x;
32001					float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
32002					float len2 = a * a + b * b;
32003					float dlen = fwidth( len2 );
32004
32005					if ( abs( vUv.y ) > 1.0 ) {
32006
32007						alpha = 1.0 - smoothstep( 1.0 - dlen, 1.0 + dlen, len2 );
32008
32009					}
32010
32011				#else
32012
32013					if ( abs( vUv.y ) > 1.0 ) {
32014
32015						float a = vUv.x;
32016						float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
32017						float len2 = a * a + b * b;
32018
32019						if ( len2 > 1.0 ) discard;
32020
32021					}
32022
32023				#endif
32024
32025			#endif
32026
32027			#include <logdepthbuf_fragment>
32028			#include <color_fragment>
32029
32030			gl_FragColor = vec4( diffuseColor.rgb, alpha );
32031
32032			#include <tonemapping_fragment>
32033			#include <colorspace_fragment>
32034			#include <fog_fragment>
32035			#include <premultiplied_alpha_fragment>
32036
32037		}
32038		`
32039};
32040
32041/**
32042 * A material for drawing wireframe-style geometries.
32043 *
32044 * Unlike {@link LineBasicMaterial}, it supports arbitrary line widths and allows using world units
32045 * instead of screen space units. This material is used with {@link LineSegments2} and {@link Line2}.
32046 *
32047 * This module can only be used with {@link WebGLRenderer}. When using {@link WebGPURenderer},
32048 * use {@link Line2NodeMaterial}.
32049 *
32050 * @augments ShaderMaterial
32051 * @three_import import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
32052 */
32053class LineMaterial extends ShaderMaterial {
32054
32055	/**
32056	 * Constructs a new line segments geometry.
32057	 *
32058	 * @param {Object} [parameters] - An object with one or more properties
32059	 * defining the material's appearance. Any property of the material
32060	 * (including any property from inherited materials) can be passed
32061	 * in here. Color values can be passed any type of value accepted
32062	 * by {@link Color#set}.
32063	 */
32064	constructor( parameters ) {
32065
32066		super( {
32067
32068			type: 'LineMaterial',
32069			uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
32070
32071			vertexShader: ShaderLib[ 'line' ].vertexShader,
32072			fragmentShader: ShaderLib[ 'line' ].fragmentShader,
32073
32074			clipping: true // required for clipping support
32075
32076		} );
32077
32078		/**
32079		 * This flag can be used for type testing.
32080		 *
32081		 * @type {boolean}
32082		 * @readonly
32083		 * @default true
32084		 */
32085		this.isLineMaterial = true;
32086
32087		this.setValues( parameters );
32088
32089	}
32090
32091	/**
32092	 * The material's color.
32093	 *
32094	 * @type {Color}
32095	 * @default (1,1,1)
32096	 */
32097	get color() {
32098
32099		return this.uniforms.diffuse.value;
32100
32101	}
32102
32103	set color( value ) {
32104
32105		this.uniforms.diffuse.value = value;
32106
32107	}
32108
32109	/**
32110	 * Whether the material's sizes (width, dash gaps) are in world units.
32111	 *
32112	 * @type {boolean}
32113	 * @default false
32114	 */
32115	get worldUnits() {
32116
32117		return 'WORLD_UNITS' in this.defines;
32118
32119	}
32120
32121	set worldUnits( value ) {
32122
32123		if ( value === true ) {
32124
32125			this.defines.WORLD_UNITS = '';
32126
32127		} else {
32128
32129			delete this.defines.WORLD_UNITS;
32130
32131		}
32132
32133	}
32134
vendor: 11,241 bytes, lines 32135-32628
32135	/**
32136	 * Controls line thickness in CSS pixel units when `worldUnits` is `false` (default),
32137	 * or in world units when `worldUnits` is `true`.
32138	 *
32139	 * @type {number}
32140	 * @default 1
32141	 */
32142	get linewidth() {
32143
32144		return this.uniforms.linewidth.value;
32145
32146	}
32147
32148	set linewidth( value ) {
32149
32150		if ( ! this.uniforms.linewidth ) return;
32151		this.uniforms.linewidth.value = value;
32152
32153	}
32154
32155	/**
32156	 * Whether the line is dashed, or solid.
32157	 *
32158	 * @type {boolean}
32159	 * @default false
32160	 */
32161	get dashed() {
32162
32163		return 'USE_DASH' in this.defines;
32164
32165	}
32166
32167	set dashed( value ) {
32168
32169		if ( ( value === true ) !== this.dashed ) {
32170
32171			this.needsUpdate = true;
32172
32173		}
32174
32175		if ( value === true ) {
32176
32177			this.defines.USE_DASH = '';
32178
32179		} else {
32180
32181			delete this.defines.USE_DASH;
32182
32183		}
32184
32185	}
32186
32187	/**
32188	 * The scale of the dashes and gaps.
32189	 *
32190	 * @type {number}
32191	 * @default 1
32192	 */
32193	get dashScale() {
32194
32195		return this.uniforms.dashScale.value;
32196
32197	}
32198
32199	set dashScale( value ) {
32200
32201		this.uniforms.dashScale.value = value;
32202
32203	}
32204
32205	/**
32206	 * The size of the dash.
32207	 *
32208	 * @type {number}
32209	 * @default 1
32210	 */
32211	get dashSize() {
32212
32213		return this.uniforms.dashSize.value;
32214
32215	}
32216
32217	set dashSize( value ) {
32218
32219		this.uniforms.dashSize.value = value;
32220
32221	}
32222
32223	/**
32224	 * Where in the dash cycle the dash starts.
32225	 *
32226	 * @type {number}
32227	 * @default 0
32228	 */
32229	get dashOffset() {
32230
32231		return this.uniforms.dashOffset.value;
32232
32233	}
32234
32235	set dashOffset( value ) {
32236
32237		this.uniforms.dashOffset.value = value;
32238
32239	}
32240
32241	/**
32242	 * The size of the gap.
32243	 *
32244	 * @type {number}
32245	 * @default 0
32246	 */
32247	get gapSize() {
32248
32249		return this.uniforms.gapSize.value;
32250
32251	}
32252
32253	set gapSize( value ) {
32254
32255		this.uniforms.gapSize.value = value;
32256
32257	}
32258
32259	/**
32260	 * The opacity.
32261	 *
32262	 * @type {number}
32263	 * @default 1
32264	 */
32265	get opacity() {
32266
32267		return this.uniforms.opacity.value;
32268
32269	}
32270
32271	set opacity( value ) {
32272
32273		if ( ! this.uniforms ) return;
32274		this.uniforms.opacity.value = value;
32275
32276	}
32277
32278	/**
32279	 * The size of the viewport, in screen pixels. This must be kept updated to make
32280	 * screen-space rendering accurate.The `LineSegments2.onBeforeRender` callback
32281	 * performs the update for visible objects.
32282	 *
32283	 * @type {Vector2}
32284	 */
32285	get resolution() {
32286
32287		return this.uniforms.resolution.value;
32288
32289	}
32290
32291	set resolution( value ) {
32292
32293		this.uniforms.resolution.value.copy( value );
32294
32295	}
32296
32297	/**
32298	 * Whether to use alphaToCoverage or not. When enabled, this can improve the
32299	 * anti-aliasing of line edges when using MSAA.
32300	 *
32301	 * @type {boolean}
32302	 */
32303	get alphaToCoverage() {
32304
32305		return 'USE_ALPHA_TO_COVERAGE' in this.defines;
32306
32307	}
32308
32309	set alphaToCoverage( value ) {
32310
32311		if ( ! this.defines ) return;
32312
32313		if ( ( value === true ) !== this.alphaToCoverage ) {
32314
32315			this.needsUpdate = true;
32316
32317		}
32318
32319		if ( value === true ) {
32320
32321			this.defines.USE_ALPHA_TO_COVERAGE = '';
32322
32323		} else {
32324
32325			delete this.defines.USE_ALPHA_TO_COVERAGE;
32326
32327		}
32328
32329	}
32330
32331}
32332
32333const _viewport = new Vector4();
32334
32335const _start = new Vector3();
32336const _end = new Vector3();
32337
32338const _start4 = new Vector4();
32339const _end4 = new Vector4();
32340
32341const _ssOrigin = new Vector4();
32342const _ssOrigin3 = new Vector3();
32343const _mvMatrix = new Matrix4();
32344const _line = new Line3();
32345const _closestPoint = new Vector3();
32346
32347const _box = new Box3();
32348const _sphere = new Sphere();
32349const _clipToWorldVector = new Vector4();
32350
32351let _ray, _lineWidth;
32352
32353// Returns the margin required to expand by in world space given the distance from the camera,
32354// line width, resolution, and camera projection
32355function getWorldSpaceHalfWidth( camera, distance, resolution ) {
32356
32357	// transform into clip space, adjust the x and y values by the pixel width offset, then
32358	// transform back into world space to get world offset. Note clip space is [-1, 1] so full
32359	// width does not need to be halved.
32360	_clipToWorldVector.set( 0, 0, - distance, 1.0 ).applyMatrix4( camera.projectionMatrix );
32361	_clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
32362	_clipToWorldVector.x = _lineWidth / resolution.width;
32363	_clipToWorldVector.y = _lineWidth / resolution.height;
32364	_clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
32365	_clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w );
32366
32367	return Math.abs( Math.max( _clipToWorldVector.x, _clipToWorldVector.y ) );
32368
32369}
32370
32371function raycastWorldUnits( lineSegments, intersects ) {
32372
32373	const matrixWorld = lineSegments.matrixWorld;
32374	const geometry = lineSegments.geometry;
32375	const instanceStart = geometry.attributes.instanceStart;
32376	const instanceEnd = geometry.attributes.instanceEnd;
32377	const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
32378
32379	for ( let i = 0, l = segmentCount; i < l; i ++ ) {
32380
32381		_line.start.fromBufferAttribute( instanceStart, i );
32382		_line.end.fromBufferAttribute( instanceEnd, i );
32383
32384		_line.applyMatrix4( matrixWorld );
32385
32386		const pointOnLine = new Vector3();
32387		const point = new Vector3();
32388
32389		_ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
32390		const isInside = point.distanceTo( pointOnLine ) < _lineWidth * 0.5;
32391
32392		if ( isInside ) {
32393
32394			intersects.push( {
32395				point,
32396				pointOnLine,
32397				distance: _ray.origin.distanceTo( point ),
32398				object: lineSegments,
32399				face: null,
32400				faceIndex: i,
32401				uv: null,
32402				uv1: null,
32403			} );
32404
32405		}
32406
32407	}
32408
32409}
32410
32411function raycastScreenSpace( lineSegments, camera, intersects ) {
32412
32413	const projectionMatrix = camera.projectionMatrix;
32414	const material = lineSegments.material;
32415	const resolution = material.resolution;
32416	const matrixWorld = lineSegments.matrixWorld;
32417
32418	const geometry = lineSegments.geometry;
32419	const instanceStart = geometry.attributes.instanceStart;
32420	const instanceEnd = geometry.attributes.instanceEnd;
32421	const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
32422
32423	const near = - camera.near;
32424
32425	//
32426
32427	// pick a point 1 unit out along the ray to avoid the ray origin
32428	// sitting at the camera origin which will cause "w" to be 0 when
32429	// applying the projection matrix.
32430	_ray.at( 1, _ssOrigin );
32431
32432	// ndc space [ - 1.0, 1.0 ]
32433	_ssOrigin.w = 1;
32434	_ssOrigin.applyMatrix4( camera.matrixWorldInverse );
32435	_ssOrigin.applyMatrix4( projectionMatrix );
32436	_ssOrigin.multiplyScalar( 1 / _ssOrigin.w );
32437
32438	// screen space
32439	_ssOrigin.x *= resolution.x / 2;
32440	_ssOrigin.y *= resolution.y / 2;
32441	_ssOrigin.z = 0;
32442
32443	_ssOrigin3.copy( _ssOrigin );
32444
32445	_mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
32446
32447	for ( let i = 0, l = segmentCount; i < l; i ++ ) {
32448
32449		_start4.fromBufferAttribute( instanceStart, i );
32450		_end4.fromBufferAttribute( instanceEnd, i );
32451
32452		_start4.w = 1;
32453		_end4.w = 1;
32454
32455		// camera space
32456		_start4.applyMatrix4( _mvMatrix );
32457		_end4.applyMatrix4( _mvMatrix );
32458
32459		// skip the segment if it's entirely behind the camera
32460		const isBehindCameraNear = _start4.z > near && _end4.z > near;
32461		if ( isBehindCameraNear ) {
32462
32463			continue;
32464
32465		}
32466
32467		// trim the segment if it extends behind camera near
32468		if ( _start4.z > near ) {
32469
32470			const deltaDist = _start4.z - _end4.z;
32471			const t = ( _start4.z - near ) / deltaDist;
32472			_start4.lerp( _end4, t );
32473
32474		} else if ( _end4.z > near ) {
32475
32476			const deltaDist = _end4.z - _start4.z;
32477			const t = ( _end4.z - near ) / deltaDist;
32478			_end4.lerp( _start4, t );
32479
32480		}
32481
32482		// clip space
32483		_start4.applyMatrix4( projectionMatrix );
32484		_end4.applyMatrix4( projectionMatrix );
32485
32486		// ndc space [ - 1.0, 1.0 ]
32487		_start4.multiplyScalar( 1 / _start4.w );
32488		_end4.multiplyScalar( 1 / _end4.w );
32489
32490		// screen space
32491		_start4.x *= resolution.x / 2;
32492		_start4.y *= resolution.y / 2;
32493
32494		_end4.x *= resolution.x / 2;
32495		_end4.y *= resolution.y / 2;
32496
32497		// create 2d segment
32498		_line.start.copy( _start4 );
32499		_line.start.z = 0;
32500
32501		_line.end.copy( _end4 );
32502		_line.end.z = 0;
32503
32504		// get closest point on ray to segment
32505		const param = _line.closestPointToPointParameter( _ssOrigin3, true );
32506		_line.at( param, _closestPoint );
32507
32508		// check if the intersection point is within clip space
32509		const zPos = MathUtils.lerp( _start4.z, _end4.z, param );
32510		const isInClipSpace = zPos >= - 1 && zPos <= 1;
32511
32512		const isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5;
32513
32514		if ( isInClipSpace && isInside ) {
32515
32516			_line.start.fromBufferAttribute( instanceStart, i );
32517			_line.end.fromBufferAttribute( instanceEnd, i );
32518
32519			_line.start.applyMatrix4( matrixWorld );
32520			_line.end.applyMatrix4( matrixWorld );
32521
32522			const pointOnLine = new Vector3();
32523			const point = new Vector3();
32524
32525			_ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
32526
32527			intersects.push( {
32528				point: point,
32529				pointOnLine: pointOnLine,
32530				distance: _ray.origin.distanceTo( point ),
32531				object: lineSegments,
32532				face: null,
32533				faceIndex: i,
32534				uv: null,
32535				uv1: null,
32536			} );
32537
32538		}
32539
32540	}
32541
32542}
32543
32544/**
32545 * A series of lines drawn between pairs of vertices.
32546 *
32547 * This adds functionality beyond {@link LineSegments}, like arbitrary line width and changing width
32548 * to be in world units. {@link Line2} extends this object, forming a polyline instead of individual
32549 * segments.
32550 *
32551 * This module can only be used with {@link WebGLRenderer}. When using {@link WebGPURenderer},
32552 * import the class from `lines/webgpu/LineSegments2.js`.
32553 *
32554 *  ```js
32555 * const geometry = new LineSegmentsGeometry();
32556 * geometry.setPositions( positions );
32557 * geometry.setColors( colors );
32558 *
32559 * const material = new LineMaterial( { linewidth: 5, vertexColors: true } };
32560 *
32561 * const lineSegments = new LineSegments2( geometry, material );
32562 * scene.add( lineSegments );
32563 * ```
32564 *
32565 * @augments Mesh
32566 * @three_import import { LineSegments2 } from 'three/addons/lines/LineSegments2.js';
32567 */
32568class LineSegments2 extends Mesh {
32569
32570	/**
32571	 * Constructs a new wide line.
32572	 *
32573	 * @param {LineSegmentsGeometry} [geometry] - The line geometry.
32574	 * @param {LineMaterial} [material] - The line material.
32575	 */
32576	constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) {
32577
32578		super( geometry, material );
32579
32580		/**
32581		 * This flag can be used for type testing.
32582		 *
32583		 * @type {boolean}
32584		 * @readonly
32585		 * @default true
32586		 */
32587		this.isLineSegments2 = true;
32588
32589		this.type = 'LineSegments2';
32590
32591	}
32592
32593	/**
32594	 * Computes an array of distance values which are necessary for rendering dashed lines.
32595	 * For each vertex in the geometry, the method calculates the cumulative length from the
32596	 * current point to the very beginning of the line.
32597	 *
32598	 * @return {LineSegments2} A reference to this instance.
32599	 */
32600	computeLineDistances() {
32601
32602		// for backwards-compatibility, but could be a method of LineSegmentsGeometry...
32603
32604		const geometry = this.geometry;
32605
32606		const instanceStart = geometry.attributes.instanceStart;
32607		const instanceEnd = geometry.attributes.instanceEnd;
32608		const lineDistances = new Float32Array( 2 * instanceStart.count );
32609
32610		for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
32611
32612			_start.fromBufferAttribute( instanceStart, i );
32613			_end.fromBufferAttribute( instanceEnd, i );
32614
32615			lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
32616			lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end );
32617
32618		}
32619
32620		const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1
32621
32622		geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
32623		geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1
32624
32625		return this;
32626
32627	}
32628
32629	/**
32630	 * Computes intersection points between a casted ray and this instance.
32631	 *
32632	 * @param {Raycaster} raycaster - The raycaster.
32633	 * @param {Array<Object>} intersects - The target array that holds the intersection points.
32634	 */
32635	raycast( raycaster, intersects ) {
32636
32637		const worldUnits = this.material.worldUnits;
32638		const camera = raycaster.camera;
32639
32640		if ( camera === null && ! worldUnits ) {
32641
32642			console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false.' );
32643
32644		}
32645
32646		const threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0;
32647
32648		_ray = raycaster.ray;
32649
32650		const matrixWorld = this.matrixWorld;
32651		const geometry = this.geometry;
32652		const material = this.material;
32653
32654		_lineWidth = material.linewidth + threshold;
32655
32656		// check if we intersect the sphere bounds
32657		if ( geometry.boundingSphere === null ) {
32658
32659			geometry.computeBoundingSphere();
32660
32661		}
32662
32663		_sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
32664
32665		// increase the sphere bounds by the worst case line screen space width
32666		let sphereMargin;
32667		if ( worldUnits ) {
32668
32669			sphereMargin = _lineWidth * 0.5;
32670
32671		} else {
32672
32673			const distanceToSphere = Math.max( camera.near, _sphere.distanceToPoint( _ray.origin ) );
32674			sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere, material.resolution );
32675
32676		}
32677
32678		_sphere.radius += sphereMargin;
32679
32680		if ( _ray.intersectsSphere( _sphere ) === false ) {
32681
32682			return;
32683
32684		}
32685
32686		// check if we intersect the box bounds
32687		if ( geometry.boundingBox === null ) {
32688
32689			geometry.computeBoundingBox();
32690
32691		}
32692
32693		_box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
32694
32695		// increase the box bounds by the worst case line width
32696		let boxMargin;
32697		if ( worldUnits ) {
32698
32699			boxMargin = _lineWidth * 0.5;
32700
32701		} else {
32702
32703			const distanceToBox = Math.max( camera.near, _box.distanceToPoint( _ray.origin ) );
32704			boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, material.resolution );
32705
32706		}
32707
32708		_box.expandByScalar( boxMargin );
32709
32710		if ( _ray.intersectsBox( _box ) === false ) {
32711
32712			return;
32713
32714		}
32715
32716		if ( worldUnits ) {
32717
32718			raycastWorldUnits( this, intersects );
32719
32720		} else {
32721
32722			raycastScreenSpace( this, camera, intersects );
32723
32724		}
32725
32726	}
32727
32728	onBeforeRender( renderer ) {
32729
32730		const uniforms = this.material.uniforms;
32731
32732		if ( uniforms && uniforms.resolution ) {
32733
32734			renderer.getViewport( _viewport );
32735			this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
32736
32737		}
32738
32739	}
32740
32741}
32742
32743function lonLatToVector3(lon, lat, radius, altitude ) {
32744	let new_radius = radius + altitude;
32745	const phi = (90 - lat) * (Math.PI / 180);
32746	const theta = (lon + 180) * (Math.PI / 180);
32747	return new Vector3(
32748		-new_radius * Math.sin(phi) * Math.cos(theta),
32749		new_radius * Math.cos(phi),
32750		new_radius * Math.sin(phi) * Math.sin(theta)
32751	);
32752}
32753
32754/**
32755 * Creates positions for graticule lines
32756 *
32757 * @param {*} radius
32758 * @param {*} lonStep
32759 * @param {*} latStep
32760 * @returns
32761 */
32762
32763function createGraticulePositions( radius, lonStep = 10, latStep = 10, altitude = 0.0 ) {
32764	const positions = [];
32765
32766	// Longitude lines
32767	for (let lon = -180; lon <= 180; lon += lonStep) {
32768		for (let lat = -90; lat < 90; lat += 1) {
32769			const v1 = lonLatToVector3(lon, lat, radius, altitude );
32770			const v2 = lonLatToVector3(lon, lat + 1, radius, altitude );
32771			positions.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
32772		}
32773	}
32774
32775	// Latitude lines
32776	for (let lat = -90; lat <= 90; lat += latStep) {
32777		for (let lon = -180; lon < 180; lon += 1) {
32778			const v1 = lonLatToVector3(lon, lat, radius, altitude );
32779			const v2 = lonLatToVector3(lon + 1, lat, radius, altitude );
32780			positions.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
32781		}
32782	}
32783	return positions;
32784}
32785
32786/**
32787 * Creates a graticule geometry using LineSegmentsGeometry
32788 * @param {*} radius - Radius of the globe
32789 * @param {*} lonStep - Longitude step in degrees
32790 * @param {*} latStep - Latitude step in degrees
32791 * @param {*} altitude - Altitude above the globe surface
32792 * @returns {LineSegmentsGeometry} - Geometry for graticule lines
32793 */
32794
32795function createGraticuleGeometry( radius, lonStep = 10, latStep = 10, altitude = 0.0 ) {
32796	const positions = createGraticulePositions( radius, lonStep, latStep, altitude ); // Earth radius in km, adjust as needed
32797
32798	const lineGeometry = new LineSegmentsGeometry();
32799	lineGeometry.setPositions(positions);
32800
32801	return lineGeometry;
32802}
32803
32804/**
32805 * Creates a graticule object with LineSegments2 and LineMaterial
32806 * @param {*} lineGeometry - Geometry for the graticule lines
32807 * @param {*}
32807 linewidth - Width of the lines
32808 * @param {*} opacity - Opacity of the lines
32809 * @param {*} color - Color of the lines
32810 * @returns {LineSegments2} - Graticule object
32811 */
32812function createGraticuleObject( lineGeometry, linewidth, opacity, color ) {
32813	// Use THREE.js to create your graticule lines
32814
32815	// Create a LineMaterial for the graticule lines
32816	// it allows line width to be set, as opposed to LineBasicMaterial with width of 1
32817	const lineMaterial = new LineMaterial({
32818		color: color,
32819		linewidth: linewidth, // In world units, not pixels!
32820		transparent: true,
32821		opacity: opacity,
32822	});
32823	// linesegments2 is a 3D object that can handle more details
32824	const lineGraticule = new LineSegments2( lineGeometry, lineMaterial );
32825	lineGraticule.computeLineDistances();
32826
32827	// Optionally tag it for future reference
32828	lineGraticule.userData.isGraticule = true;
32829
32830	// disable raycasting so it doesn't trigger library click events (prevents crash)
32831	lineGraticule.raycast = () => {};
32832
32833	return lineGraticule;
32834}
32835
32836/**
32837 * Sets custom graticule lines on the globe
32838 * This function checks if the graticule lines are enabled and creates them if they are not
32839 * @param {Object} thisGlobe - The globe instance where the graticule will be set
32840 * @param {Object} data - The data object containing graticule settings
32841 * @returns {void}
32842 */
32843
32844function setCustomGraticule( thisGlobe, data ) {
32845
32846	// runs on globe ready
32847	if ( !thisGlobe || !thisGlobe.scene ) {
32848		console.warn( 'Globe or scene not available' );
32849		return;
32850	}
32851
32852	// if no data or graticules are not enabled, return
32853	if ( ! data || !globe_ut_bool( data.showGraticules ) || !globe_ut_bool( data.graticules ) ) {
32854		return;
32855	}
32856	const scene = thisGlobe.scene();
32857	if ( ! Array.isArray( scene?.children ) || scene.children.length === 0 ) {
32858		console.warn('Scene or scene.children not available');
32859		return;
32860	}
32861
32862	let top_group = scene.children.find( obj => obj?.type === 'Group' );
32863	if ( ! Array.isArray( top_group?.children ) ) {
32864		top_group = new Group();
32865		top_group.name = 'topGroup';
32866		scene.add( top_group );
32867	}
32868
32869	let middle_group = top_group.children.find( obj => obj && obj.type === 'Group' );
32870	if ( ! Array.isArray( middle_group?.children ) ) {
32871		middle_group = new Group();
32872		middle_group.name = 'middle_group';
32873		top_group.add( middle_group );
32874	}
32875
32876	let graticule;
32877
32878	// if graticule already exists, and is render is set to simple
32879	if ( ! globe_ut_bool( data.graticules.useLargeLinesGraticules ) ) {
32880		graticule = middle_group.children.find(obj => obj && obj.type === 'LineSegments' && obj.material?.transparent);
32881
32882		if ( graticule && globe_ut_bool( data.graticules ) ) {
32883			// color
32884			if ( typeof data.graticules.color !== 'undefined') {
32885				graticule.material.color.set(data.graticules.color);
32886			}
32887
32888			// opacity
32889			if ( typeof data.graticules.opacity !== 'undefined') {
32890				graticule.material.opacity = parseFloat(data.graticules.opacity);
32891			}
32892			graticule.userData.isGraticule = true; // Tag for future access
32893		}
32894	}
32895
32896	// if render is set to 3D, create new graticule with LineSegmentsGeometry
32897	if ( ! graticule && globe_ut_bool( data.graticules.useLargeLinesGraticules ) ) {
32898		let graticule3D = middle_group.children.find(
32899			obj => obj?.userData?.is3DGraticule
32900		);
32901
32902		const globe_radius = thisGlobe.getGlobeRadius();
32903
32904		const graticuleSettings = data.graticules || {};
32905		const altitude  = parseFloat(graticuleSettings.altitude ?? 0);
32906		const color     = graticuleSettings.color ?? 'lightgrey';
32907		const thickness = parseFloat(graticuleSettings.thickness ?? 1);
32908		const opacity   = parseFloat(graticuleSettings.opacity ?? 0.5);
32909
32910		const graticule_geometry = createGraticuleGeometry( globe_radius, 10, 10, altitude );
32911
32912		// if graticule3D already exists, update it
32913		if ( graticule3D ) {
32914			// Update geometry
32915			graticule3D.geometry.dispose();
32916			graticule3D.geometry = graticule_geometry;
32917			// Update material
32918			graticule3D.material.color.set(color);
32919			graticule3D.material.linewidth = thickness;
32920			graticule3D.material.opacity = opacity;
32921			graticule3D.material.needsUpdate = true;
32922			return;
32923		}
32924
32925		// create new graticule if it does not exist
32926		graticule = createGraticuleObject( graticule_geometry, thickness, opacity, color );
32927		graticule.userData.isGraticule = true; // Tag for future access
32928		graticule.userData.is3DGraticule = true; // Tag for future access
32929		// Add to the group
32930		middle_group.add(graticule);
32931
32932	}
32933
32934}
32935
32936/** Add Points Layer to Globe */
32937function addHTMLElementsLayer ( thisGlobe, GlobeData ) {
32938
32939	thisGlobe.htmlElementsData( GlobeData.html )
32940		.htmlLat(p => globe_ut_prepare_coordinates('latitude', p) )
32941		.htmlLng(p => globe_ut_prepare_coordinates('longitude', p) )
32942		.htmlAltitude(0.01) // there was no benefit in using the altitude from the backend
32943		.htmlElement(p => {
32944
32945			let html = p.html ? p.html : buildHtml(p, GlobeData);
32946
32947			const el = document.createElement('div');
32948			el.innerHTML = html;
32949			el.classList.add('itt_globe_html_element');
32950			el.style['pointer-events'] = 'auto';
32951			el.onclick = function() {
32952				setupClickEvent$1(thisGlobe, GlobeData, p);
32953			};
32954			return el;
32955		});
32956}
32957
32958function buildHtml(p, GlobeData) {
32959	let template = GlobeData.htmlDefaults?.htmlTemplate || '';
32960
32961	if (!template || typeof template !== 'string' ) {
32962		// Provide a fallback or handle the missing template
32963		template = ''; // example fallback
32964	}
32965	// replace placeholders with values from p
32966	template = template.replace(/\{([^}]+)\}/g, (match, key) => {
32967		// Handle dot notation by splitting on dots
32968		const keys = key.split('.');
32969		let value = p;
32970
32971		// Traverse the object/array following the dot notation
32972		for (const k of keys) {
32973			if (value === undefined || value === null) return match;
32974			value = value[k];
32975		}
32976
32977		return value !== undefined ? value : match;
32978	});
32979
32980	return template;
32981}
32982
32983/**
32984 * Adds geojson regions layer
32985 * @param {*} thisGlobe
32986 * @param {*} GlobeData
32987 */
32988const addRegionLayer = function( thisGlobe, GlobeData ) {
32989
32990	// in case it's a hollow globe, we don't want to see the side color
32991	let sideColor = 'rgba(100, 100, 100, 0.05)';
32992	if( GlobeData.globeImage === 'earth-hollow'){
32993		sideColor = 'rgba(100, 100, 100, 0)';
32994	}
32995
32996	if ( GlobeData.regionDefaults === undefined ) {
32997		GlobeData.regionDefaults = {};
32998	}
32999
33000	let defaultStrokeColor = GlobeData.regionDefaults.strokeColor ?? '#f0f0f0';
33001
33002	return new Promise((resolve) => {
33003		thisGlobe.polygonAltitude( r => r.properties.altitude ?? 0.005 )
33004			.lineHoverPrecision(0)
33005			.polygonCapColor(r => r.properties.color ? r.properties.color : GlobeData.regionDefaults.inactive)
33006			.polygonSideColor(() => sideColor)
33007			.polygonStrokeColor(r => r.properties.strokeColor || defaultStrokeColor)
33008			.polygonCapCurvatureResolution(5)
33009			.polygonsTransitionDuration(300);
33010
33011		thisGlobe.regionLayers = {};
33012		thisGlobe.originalPolygonsData = [];
33013
33014		// tooltip
33015		thisGlobe.polygonLabel(function (region) {
33016
33017			// if region was not added manually and option to only display on active region is enabled, skip
33018			let onlyActive = globe_ut_bool(GlobeData.tooltipOnlyActive);
33019			if( onlyActive && typeof region.properties.originalId === 'undefined' ){
33020				return;
33021			}
33022			// set tooltip template
33023			let regionsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}';
33024			if( GlobeData.regionsTooltipTemplate ){
33025				regionsTooltipTemplate = GlobeData.regionsTooltipTemplate;
33026			}
33027
33028			return setupTooltip(region.properties, regionsTooltipTemplate);
33029		});
33030
33031		// click events
33032		thisGlobe.onPolygonClick(function (region) {
33033			setupClickEvent$1(thisGlobe, GlobeData, region.properties);
33034		});
33035
33036		// hover events
33037		thisGlobe.onPolygonHover(function (current, previous) {
33038			setupHoverEvent$1( thisGlobe, current, previous, 'regions' );
33039		});
33040
33041
33042		if ( (!GlobeData.regions || GlobeData.regions.length === 0) && globe_ut_bool(GlobeData.onlyActiveRegions) ) {
33043			resolve();
33044			return;
33045		}
33046
33047		// fetch regions
33048		(async () => {
33049			const regions = await prepareRegions(thisGlobe, GlobeData);
33050			thisGlobe.polygonsData(regions);
33051			thisGlobe.originalPolygonsData = regions;
33052
33053			resolve();
33054		})();
33055	});
33056};
33057
33058const prepareRegions = async function( thisGlobe, GlobeData, alt
33058itudeMultiplier ){
33059
33060	// if it already exists, return it, otherwise fetch it
33061	if (thisGlobe.regionLayers && thisGlobe.regionLayers[GlobeData.id]) {
33062		return thisGlobe.regionLayers[GlobeData.id];
33063	}
33064
33065	altitudeMultiplier = altitudeMultiplier ?? 0;
33066
33067	let geojson_source = GlobeData.regionSource;
33068	if ( geojson_source === 'disabled' || geojson_source === undefined ){
33069		return;
33070	}
33071	if ( GlobeData.regions === undefined ){
33072		return;
33073	}
33074
33075	let fullpath;
33076	if( geojson_source !== 'custom' ){
33077		if ( ! geojson_source.includes('.geojson') && ! geojson_source.includes('.json') ) {
33078			geojson_source += '.json';
33079		}
33080		fullpath = ittGlobeData.assetsUrl + 'geojson/' + geojson_source;
33081	} else {
33082		fullpath = GlobeData.regionCustomSourceURL;
33083	}
33084
33085	const selectedRegionsIndividually = GlobeData.regions.reduce((acc, region) => {
33086
33087		// save original id, to use for grouped hover
33088		region.originalId = region.id;
33089
33090		// Destructure the region to get all properties except ids
33091		const { id, ...regionProps } = region;
33092		if ( ! id ) {
33093			return acc;
33094		}
33095
33096		// Convert string id to array if needed
33097		if (typeof id === 'string') {
33098			id = id.includes(',') ? id.split(',').map(i => i.trim()) : [id];
33099		}
33100
33101		// Create new objects with all region properties and the individual id
33102		const idsWithProps = id.map(id => ({ ...regionProps, id }));
33103		return acc.concat(idsWithProps);
33104	}, []);
33105
33106	// Convert the selection of regions array to a dictionary for quick lookup
33107	const regionsDict = selectedRegionsIndividually.reduce((acc, item) => {
33108		// Add both id and name as keys if available
33109		acc[item.id] = item; // id from the regions object
33110		if (item.title) {     // title or name for country
33111			acc[item.title] = item;  // Store the title (e.g., "Algeria")
33112		}
33113		return acc;
33114	}, {});
33115
33116	return fetch(fullpath)
33117		.then(res => res.json())
33118		.then(regionsAvailable => {
33119			// Enrich the GeoJSON data with each regions data
33120			regionsAvailable.features.forEach(feature => {
33121
33122				// Sanitize all string properties found in the geojson to prevent XSS
33123				Object.keys(feature.properties).forEach(key => {
33124					if (typeof feature.properties[key] === 'string') {
33125						feature.properties[key] = globe_ut_sanitize(feature.properties[key]);
33126					}
33127				});
33128
33129				const regionId = feature.id;
33130				const regionName = feature.properties.name;
33131
33132				// Try to find the matching region data by id or name
33133				const regionData = regionsDict[regionId] || regionsDict[regionName];
33134
33135				if (regionData) {
33136					feature.properties = {
33137						...feature.properties,
33138						...regionData
33139					};
33140				}
33141				// Add globe_id to feature properties
33142				feature.properties.globe_id = GlobeData.id;
33143
33144				if (thisGlobe.liveFilter && thisGlobe.liveFilter.allLabel && thisGlobe.liveFilter.allLabel.trim() !== '') {
33145					feature.properties.altitude = 0.005 + ( 0.0025 * altitudeMultiplier );
33146				}
33147
33148			});
33149
33150			let features = regionsAvailable.features;
33151
33152			// save total of available features
33153			thisGlobe.totalAvailableRegions = features.length;
33154			// get total of active regions
33155			thisGlobe.totalActiveRegions = features.filter(feature => feature.properties.originalId).length;
33156
33157			// Filter to only active regions if setting enabled
33158			if (globe_ut_bool(GlobeData.onlyActiveRegions)) {
33159				features = features.filter(feature => feature.properties.originalId);
33160			}
33161
33162			thisGlobe.regionLayers[GlobeData.id] = features;
33163			return features;
33164		});
33165};
33166
33167/** Add Marker Objects Layer to Globe
33168 * It will inherit the same properties as the points layer
33169*/
33170function addObjectsLayer ( thisGlobe, GlobeData ) {
33171
33172	// use in images if needed
33173	thisGlobe.textureLoader = new TextureLoader();
33174
33175	thisGlobe.objectsData( GlobeData.objects )
33176		.objectLat(p => globe_ut_prepare_coordinates('latitude', p) )
33177		.objectLng(p => globe_ut_prepare_coordinates('longitude', p) )
33178		.objectAltitude(p => 0);
33179	// object shape
33180	thisGlobe.objectThreeObject(function(d) {
33181		if (d.type === 'pin') {
33182			return createPin(d, thisGlobe);
33183		}
33184		if (d.type === 'marker') {
33185			return createMarker(d);
33186		}
33187		if (d.type === 'image') {
33188			return createImage(d, thisGlobe);
33189		}
33190		if (d.type === 'flag') {
33191			if(d.image?.url){
33192				return createFlagImage(d, thisGlobe);
33193			}
33194			else {
33195				return createFlag(d, thisGlobe);
33196			}
33197		}
33198		return null;
33199	});
33200
33201	// tooltip
33202	thisGlobe.objectLabel(function (label) {
33203
33204		let pointsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}';
33205		if( GlobeData.pointsTooltipTemplate ){
33206			pointsTooltipTemplate = GlobeData.pointsTooltipTemplate;
33207		}
33208		return setupTooltip(label, pointsTooltipTemplate );
33209
33210	});
33211
33212	// click events
33213	thisGlobe.onObjectClick(function ( element ) {
33214		setupClickEvent$1( thisGlobe, GlobeData, element );
33215	});
33216
33217	// hover events
33218	thisGlobe.onObjectHover(function (object, prevObject) {
33219		let type = object && object.type ? object.type : prevObject.type;
33220		setupHoverEvent$1(thisGlobe, object, prevObject, type );
33221	});
33222}
33223
33224function createFlag(d, thisGlobe) {
33225	const flagGroup = new Group();
33226	let globeRadius = thisGlobe.getGlobeRadius();
33227	let size = d.radius * 0.5;
33228	let height = size * (3/5);
33229	// Set minimum altitude without dividing by globe radius
33230	let minAltitude = height + 1;
33231	let altitude = Math.max(d.altitude, minAltitude);
33232	let altitudeInUnits = parseFloat((altitude * globeRadius).toFixed(2)) * 0.01;
33233	let poleRadius = size * 0.025;
33234	let animate = d.animate ? globe_ut_bool(d.animate) : true;
33235	let width = size;
33236	let flagMaterial;
33237	let flagPole = createFlagPole(d, thisGlobe);
33238
33239	flagGroup.add(flagPole);
33240
33241	flagMaterial = new MeshLambertMaterial({
33242		color: d.color,
33243		side: DoubleSide
33244	});
33245
33246	const geometry = new PlaneGeometry(width, height, width, height);
33247	const flagMesh = new Mesh(geometry, flagMaterial);
33248
33249	// Position flag mesh with bottom edge at the top of the pole
33250	flagMesh.position.set(width/2 + poleRadius, altitudeInUnits - height/2, 0);
33251
33252	const animateFunction = () => {
33253		// Get the position attribute
33254		const positions = flagMesh.geometry.getAttribute('position');
33255
33256		for (let y = 0; y <= height; y++) {
33257			for (let x = 0; x <= width; x++) {
33258				const index = x + y * (width + 1);
33259				// Create wave effect by combining sine waves
33260				const waveX = Math.sin(x * 0.5 - Date.now() * 0.003) * 0.5;
33261				const waveY = Math.sin(y * 0.3 - Date.now() * 0.004) * 0.3;
33262				const wave = waveX + waveY;
33263				// Increase amplitude towards flag edge
33264				const amplitude = (x / width) * 2;
33265				positions.array[index * 3 + 2] = wave * amplitude;
33266			}
33267		}
33268
33269		// Mark the positions as needing an update
33270		positions.needsUpdate = true;
33271		requestAnimationFrame(animateFunction);
33272	};
33273
33274	if(animate){
33275		animateFunction();
33276	}
33277
33278	flagGroup.add(flagMesh);
33279
33280	// Rotate entire flag group to be perpendicular to globe surface
33281	flagGroup.rotation.x = Math.PI / 2;
33282	return flagGroup;
33283}
33284
33285function createFlagImage(d, thisGlobe) {
33286	const flagGroup = new Group();
33287	let globeRadius = thisGlobe.getGlobeRadius();
33288	let size = d.radius * 0.5;
33289	let height = size * (3/5);
33290	// Set minimum altitude without dividing by globe radius
33291	let minAltitude = height + 1;
33292	let altitude = Math.max(d.altitude, minAltitude);
33293	let altitudeInUnits = parseFloat((altitude * globeRadius).toFixed(2)) * 0.01;
33294	let poleRadius = size * 0.025;
33295	let animate = d.animate ? globe_ut_bool(d.animate) : true;
33296	let width = size;
33297	let flagMaterial;
33298	let flagPole = createFlagPole(d, thisGlobe);
33299
33300	flagGroup.add(flagPole);
33301
33302	flagMaterial = new MeshBasicMaterial({
33303		map: thisGlobe.textureLoader.load(d.image.url),
33304		side: DoubleSide,
33305		transparent: true
33306	});
33307
33308	const geometry = new PlaneGeometry(width, height, width, height);
33309	const flagMesh = new Mesh(geometry, flagMaterial);
33310
33311	// Position flag mesh with bottom edge at the top of the pole
33312	flagMesh.position.set(width/2 + poleRadius, altitudeInUnits - height/2, 0);
33313
33314	// Update geometry and position once image loads
33315	const img = new Image();
33316	img.onload = function() {
33317		const aspectRatio = img.height / img.width;
33318		const adjustedHeight = width * aspectRatio;
33319
33320		// Update geometry with correct dimensions
33321		flagMesh.geometry = new PlaneGeometry(width, adjustedHeight, width, adjustedHeight);
33322
33323		// Update position to account for new height, keeping bottom edge at top of pole
33324		flagMesh.position.set(width/2 + poleRadius, altitudeInUnits - adjustedHeight/2, 0);
33325	};
33326	img.src = d.image.url;
33327
33328	const animateFunction = () => {
33329		// Get the position attribute
33330		const positions = flagMesh.geometry.getAttribute('position');
33331
33332		for (let y = 0; y <= height; y++) {
33333			for (let x = 0; x <= width; x++) {
33334				const index = x + y * (width + 1);
33335				// Create wave effect by combining sine waves
33336				const waveX = Math.sin(x * 0.5 - Date.now() * 0.003) * 0.5;
33337				const waveY = Math.sin(y * 0.3 - Date.now() * 0.004) * 0.3;
33338				const wave = waveX + waveY;
33339				// Increase amplitude towards flag edge
33340				const amplitude = (x / width) * 2;
33341				positions.array[index * 3 + 2] = wave * amplitude;
33342			}
33343		}
33344
33345		// Mark the positions as needing an update
33346		positions.needsUpdate = true;
33347		requestAnimationFrame(animateFunction);
33348	};
33349
33350	if(animate){
33351		animateFunction();
33352	}
33353
33354	flagGroup.add(flagMesh);
33355
33356	// Rotate entire flag group to be perpendicular to globe surface
33357	flagGroup.rotation.x = Math.PI / 2;
33358	return flagGroup;
33359}
33360
33361function createFlagPole(d, thisGlobe) {
33362	let globeRadius = thisGlobe.getGlobeRadius();
33363	let size = d.radius * 0.5;
33364	let height = size * (3/5);
33365	// Use the same minimum altitude calculation as the flag
33366	let minAltitude = height + 1;
33367	let altitude = Math.max(d.altitude, minAltitude);
33368	let altitudeInUnits = parseFloat((altitude * globeRadius).toFixed(2)) * 0.01;
33369	let poleRadius = size * 0.025;
33370
33371	let geometry = new CylinderGeometry(poleRadius, poleRadius, altitudeInUnits, 16, 1);
33372	let material = new MeshPhongMaterial({
33373		color: d.color,
33374		specular: "#999999",
33375		shininess: 30
33376	});
33377	const pole = new Mesh(geometry, material);
33378
33379	// Position the pole so its base is at the surface and it extends upward
33380	pole.position.set(0, altitudeInUnits/2, 0);
33381
33382	return pole;
33383}
33384
33385/** Create a 3d image object */
33386function createImage(d, thisGlobe) {
33387
33388	const textureLoader = thisGlobe.textureLoader;
33389	const group = new Group();
33390	let size = d.radius;
33391
33392	// currently not being used, could be a future feature
33393	let includeLine = d.includeLine ? globe_ut_bool(d.includeLine) : false;
33394	let animate = d.animate ? globe_ut_bool(d.animate) : false;
33395
33396	// Get globe width and altitude in units
33397	const globeRadius = thisGlobe.getGlobeRadius();
33398	const altitudeInUnits = parseFloat((d.altitude * globeRadius).toFixed(2)) * 0.01;
33399
33400	// Create a plane geometry for the image
33401	// Load the image and calculate its aspect ratio
33402	const img = new Image();
33403	img.onload = function() {
33404		const aspectRatio = img.height / img.width;
33405		const width = size;
33406		const height = width * aspectRatio;
33407
33408		// Update plane geometry with calculated dimensions
33409		const planeGeometry = new PlaneGeometry(width, height);
33410		imagePlane.geometry = planeGeometry;
33411
33412		// Ensure the plane is centered
33413		if(d.imageOrientation === 'horizontal'){
33414			imagePlane.position.set(0, 0, altitudeInUnits);
33415		} else {
33416			imagePlane.position.set(0, 0, altitudeInUnits + height / 2);
33417		}
33418
33419	};
33420
33421	img.src = d.image.url;
33422
33423	const planeGeometry = new PlaneGeometry(size, size);
33424
33425	// Load the texture from the image URL
33426	const texture = textureLoader.load(d.image.url);
33427	const planeMaterial = new MeshBasicMaterial({
33428		map: texture,
33429		transparent: true,
33430		side: DoubleSide
33431	});
33432
33433	const imagePlane = new Mesh(planeGeometry, planeMaterial);
33434
33435	// Position the image plane
33436	imagePlane.position.set(0, 0, altitudeInUnits);
33437
33438	let orientation = new Vector3(0, -1, altitudeInUnits);
33439	if(d.imageOrientation === 'horizontal'){
33440		orientation = new Vector3(0, 0, 0);
33441	}
33442
33443	// Rotate the image plane to face outward or vertical from the globe
33444	imagePlane.lookAt(orientation);
33445
33446	group.add(imagePlane);
33447
33448	// Create a line from the surface to the image
33449	// currently not being used, could be a future feature
33450	if (altitudeInUnits > 1 && includeLine) {
33451	const lineGeometry = new BufferGeometry().setFromPoints([
33452				new Vector3(0, 0, 0),  // Start from the globe surface
33453				new Vector3(0, 0, altitudeInUnits)  // End at the image
33454			]);
33455
33456		const lineMaterial = new LineBasicMaterial({ color: d.color });
33457		const line = new Line(lineGeometry, lineMaterial);
33458		group.add(line);
33459	}
33460
33461	// Add animation for vertical orientation
33462	// currently not being used, could be a future feature
33463	if (animate) {
33464		const animate = () => {
33465		imagePlane.rotation.y += 0.05; // Adjust rotation speed as needed
33466		requestAnimationFrame(animate);
33467		};
33468		animate();
33469	}
33470
33471	return group;
33472
33473}
33474
33475/** Create a 3d marker object */
33476function createMarker(d, thisGlobe) {
33477	// Create the outer shape of the pin
33478	const outerShape = new Shape();
33479	outerShape.moveTo(0, 0);
33480	outerShape.bezierCurveTo(0, 0.8, 0.8, 1.6, 1.6, 1.6);
33481	outerShape.bezierCurveTo(2.4, 1.6, 3.2, 0.8, 3.2, 0);
33482	outerShape.bezierCurveTo(3.2, -0.8, 2.4, -2.4, 1.6, -4);
33483	outerShape.bezierCurveTo(0.8, -2.4, 0, -0.8, 0, 0);
33484
33485	// Create the inner shape for the hole with a bigger radius and moved down
33486	const innerShape = new Path();
33487	innerShape.moveTo(1.6, 0.6);
33488	innerShape.absarc(1.6, 0.6, 0.9, 0, Math.PI * 2, false);
33489
33490	outerShape.holes.push(innerShape);
33491
33492	// Create extrusion settings
33493	const extrudeSettings = {
33494		steps: 2,
33495		depth: 0.4,
33496		bevelEnabled: true,
33497		bevelThickness: 0.2,
33498		bevelSize: 0.1,
33499		bevelSegments: 1
33500	};
33501
33502	// Create geometry
33503	const geometry = new ExtrudeGeometry(outerShape, extrudeSettings);
33504
33505	// Center the geometry so that its local origin (0, 0, 0) is in the middle
33506	geometry.center();
33507
33508	// Create material
33509	const material = new MeshPhongMaterial({
33510		color: d.color,
33511		shininess: 100
33512	});
33513
33514	// Create mesh
33515	const pinMesh = new Mesh(geometry, material);
33516
33517	// Rotate the pin to face the globe
33518	pinMesh.lookAt(new Vector3(0, 0, 0));
33519	pinMesh.rotateX(Math.PI / 2);
33520
33521	// Scale the pin
33522	const scale = d.radius * 0.1; // Reduced scale to make pins smaller
33523	pinMesh.scale.set(scale, scale, scale);
33524
33525	// Move the pin up/away from the globe
33526	const offset = scale * 3 + d.altitude * 0.1; // Adjust this value to fine-tune the offset
33527	pinMesh.position.set(0, 0, offset);
33528
33529	// Add animation for vertical orientation
33530	if (d.animate) {
33531		const animate = () => {
33532			pinMesh.rotation.y += 0.05; // Adjust rotation speed as needed
33533			requestAnimationFrame(animate);
33534		};
33535		animate();
33536	}
33537
33538	return pinMesh;
33539}
33540
33541
33542/** Create a pin object */
33543function createPin(d, thisGlobe) {
33544
33545	const group = new Group();
33546
33547	// radius will originally be 20 for example.
33548	// altitude will originally be 10 for example.
33549	let AdjustedRadius = parseFloat((d.radius * 0.2).toFixed(2));
33550	let AdjustedAltitude = parseFloat((d.altitude / 100 ).toFixed(2));
33551	// Get globe radius and altitude in units
33552	const globeRadius = thisGlobe.getGlobeRadius();
33553	const altitudeInUnits = parseFloat((AdjustedAltitude * globeRadius).toFixed(2));
33554	// Sphere for the round part
33555	const sphereGeometry = new SphereGeometry(AdjustedRadius, 32, 32);
33556	const sphereMaterial = new MeshLambertMaterial({ color: d.color });
33557	const sphere = new Mesh(sphereGeometry, sphereMaterial);
33558
33559	// Position the sphere so that it sits above the cone
33560	sphere.position.set(0, 0, altitudeInUnits);  // Adjusted position based on cone's rotation
33561
33562	group.add(sphere);
33563
33564	// Cone for the pointer
33565	const coneHeight = Math.max(0, parseInt(altitudeInUnits));
33566	if(coneHeight > 0){
33567	  const coneGeometry = new ConeGeometry(AdjustedRadius/4, coneHeight, 32);
33568	  const coneMaterial = new MeshLambertMaterial({ color: d.color });
33569	  const cone = new Mesh(coneGeometry, coneMaterial);
33570
33571	  cone.position.set(0, 0, coneHeight/2);
33572	  cone.rotation.y = -Math.PI / 2;  // Keep the rotation around Y
33573	  cone.rotation.x = -Math.PI / 2;  // Keep the rotation around X
33574
33575	  group.add(cone);
33576	}
33577	return group;
33578}
33579
33580/**
33581 * Adds Auto Rotate and its speed controls
33582 * @param {*} thisGlobe
33583 * @param {*} data
33584 */
33585function addAutoRotate( thisGlobe, data ) {
33586	if (typeof data.rotate !== 'undefined' && globe_ut_bool(data.rotate.enabled)) {
33587		thisGlobe.controls().autoRotate = true;
33588		thisGlobe.controls().autoRotateSpeed = data.rotate.speed;
33589	}
33590}
33591
33592/**
33593 * Handles click actions to display content
33594 */
33595function displayContent( thisGlobe, GlobeData, data, position, scroll ) {
33596
33597	// we could try to use thisGlobe to rotate the globe to the clicked coordinates
33598	// and we could use position to target specific container, if multiple displayContent were selected
33599
33600	var contentContainer = document.getElementById('itt_globe_content_' + position + '_' + GlobeData.id );
33601
33602	if ( contentContainer === undefined || contentContainer === null ) {
33603		return;
33604	}
33605	var thisContent = data.content ? data.content : '';
33606
33607	contentContainer.innerHTML = thisContent;
33608
33609	if (scroll) {
33610		var originalTop = Math.floor(contentContainer.getBoundingClientRect().top - 100);
33611		window.scrollBy({
33612			top: originalTop,
33613			left: 0,
33614			behavior: 'smooth',
33615		});
33616	}
33617
33618}
33619
33620function contentBelowScroll( thisGlobe, GlobeData, data ) {
33621	displayContent( thisGlobe, GlobeData, data, 'below', true );
33622}
33623
33624function contentBelow( thisGlobe, GlobeData, data ) {
33625	displayContent( thisGlobe, GlobeData, data, 'below', false );
33626}
33627
33628function contentAbove( thisGlobe, GlobeData, data ) {
33629	displayContent( thisGlobe, GlobeData, data, 'above', false );
33630}
33631
33632function contentRight( thisGlobe, GlobeData, data ) {
33633	displayContent( thisGlobe, GlobeData, data, 'right', false );
33634}
33635
33636function contentLeft( thisGlobe, GlobeData, data ) {
33637	displayContent( thisGlobe, GlobeData, data, 'left', false );
33638}
33639
33640function contentLighbox( thisGlobe, GlobeData, data ) {
33641	openLightbox( thisGlobe, GlobeData, data, 'inline' );
33642}
33643
33644function iframeLightbox( thisGlobe, GlobeData, data ) {
33645	openLightbox( thisGlobe, GlobeData, data, 'iframe' );
33646}
33647
33648function openLightbox( thisGlobe, GlobeData, data, type ) {
33649	//function (id, data, type) {
33650	var elements = [],
33651		width = window.innerWidth < 900 ? '90%' : '60%',
33652		opts = {};
33653
33654	if (type === 'inline') {
33655		elements.push({
33656			content: data.content,
33657			type: type,
33658			width: width,
33659			height: 'auto',
33660		});
33661	} else if (type === 'iframe') {
33662		elements.push({
33663			href: data.content,
33664			type: 'external',
33665			width: width,
33666			height: parseInt(window.innerHeight * 0.8),
33667		});
33668	}
33669
33670	opts = {
33671		touchNavigation: false,
33672		draggable: false,
33673		keyboardNavigation: false,
33674		loopAtEnd: false,
33675		loop: false,
33676		zoomable: false,
33677		elements: elements,
33678		closeButton: true,
33679		closeOnOutsideClick: true,
33680	};
33681
33682	// fix for lightbox closing on bigger touch devices
33683	/*
33684	if (window.innerWidth > 768 && functionToCheckifTouchScreenDevice()) {
33685		opts.closeOnOutsideClick = false;
33686	}
33687	*/
33688
33689	// let's make it global for better debugging, just in case
33690	ittGlobes.lightbox = GLightbox(opts);
33691
33692	if (data.content !== '' && ittGlobes.lightbox) {
33693		ittGlobes.lightbox.open();
33694		ittGlobes.lightboxIsRunning = true;
33695	} else {
33696		console.debug('Empty Action Content or Incorrect Request - Lightbox not triggered');
33697	}
33698
33699	ittGlobes.lightbox.on('close', function () {
33700		console.debug('lightbox closed, we might need to reset stuff');
33701		ittGlobes.lightboxIsRunning = false;
33702	});
33703
33704	// add custom close button to solve issues on touch devices
33705	ittGlobes.lightbox.on('open', function () {
33706		console.debug('Open event not working?');
33707		/*
33708		let close = document.querySelector('.ginner-container .gslide-media .ittglobe_close');
33709		if (!close) {
33710		close = document.createElement('span');
33711		close.classList.add('ittglobe_close');
33712		close.innerHTML = 'XXX╳';
33713		let containers = document.querySelectorAll('.ginner-container .gslide-media');
33714		containers.forEach(function (el) {
33715			let clone = close.cloneNode(true);
33716			clone.addEventListener('click', function () {
33717			lightbox.close();
33718			});
33719
33720			el.prepend(clone);
33721		});
33722		}
33723		*/
33724	});
33725}
33726
33727ittGlobes$1.clickActions.DisplayContentBelow = contentBelow;
33728ittGlobes$1.clickActions.DisplayContentBelowScroll = contentBelowScroll;
33729ittGlobes$1.clickActions.DisplayContentAbove = contentAbove;
33730ittGlobes$1.clickActions.DisplayContentRight = contentRight;
33731ittGlobes$1.clickActions.DisplayContentLeft = contentLeft;
33732ittGlobes$1.clickActions.DisplayContentLightbox = contentLighbox;
33733ittGlobes$1.clickActions.DisplayIframeLightbox = iframeLightbox;
33734
33735/** initialize globe */
33736ittGlobes$1.pro = function () {
33737
33738	// check for globe container created by the shortcode
33739	let globe_render_container = document.getElementsByClassName( 'js-itt-globe-render' );
33740	for (const globe_container of globe_render_container) {
33741		if ( ! globe_container.dataset.hasOwnProperty('globe_id') ) {
33742			continue;
33743		}
33744		let globe_id = 0;
33745		try {
33746			globe_id = parseInt( JSON.parse(globe_container.dataset.globe_id ) );
33747		} catch (e) {
33748			continue;
33749		}
33750
33751		if ( ! globe_container.dataset.hasOwnProperty( 'globe_meta' ) ) {
33752			continue;
33753		}
33754
33755		let globe_meta = {};
33756		try {
33757			globe_meta = JSON.parse( globe_container.dataset.globe_meta );
33758		} catch (e) {
33759			globe_meta = {};
33760		}
33761
33762		if ( globe_meta.library === 'maplibre' ) {
33763			return;
33764		}
33765
33766		extend_globe( globe_id, globe_meta );
33767	}
33768};
33769
33770var extend_globe = function ( id, data ) {
33771	//data types - normal
33772	let dataTypes = {
33773		'arcLines': 'arcLineDefaults',
33774		'regions': 'regionDefaults',
33775		'html': 'htmlDefaults',
33776		'objects': 'pointDefaults',
33777	};
33778
33779	globe_ut_prepareData( data );
33780	globe_ut_prepareProData( data );
33781	globe_ut_setupData( data, dataTypes );
33782
33783	let thisGlobe = ittGlobes$1.globesIndex[ id ];
33784
33785	if ( data.globeImage === 'earth-hollow' ) {
33786		thisGlobe.showGlobe(false).showAtmosphere(false);
33787	}
33788
33789	if( data.globeImage === 'noImage' ){
33790		// return compatible color object
33791		let globeColor = typeof data.globeColor !== 'undefined' ? data.globeColor : '#064273';
33792		thisGlobe.globeMaterial().color.set( globeColor );
33793	}
33794
33795	if ( data.globeImage === 'customImage' ) {
33796		let globeCustomImage = typeof data.customImage !== 'undefined' ?  data.customImage.url : false;
33797		thisGlobe.globeImageUrl( globeCustomImage );
33798	}
33799
33800	addAutoRotate( thisGlobe, data );
33801	addArcsLayer( thisGlobe, data );
33802	addHTMLElementsLayer( thisGlobe, data );
33803
33804	// if there's a live filter, add that info to the main globe
33805	if( data.layers && Array.isArray(data.layers) && data.liveFilter && data.liveFilter.enabled === "1" ){
33806		thisGlobe.liveFilter = data.liveFilter;
33807	}
33808
33809	// setup marker objects
33810	if ( data.objects ) {
33811		addObjectsLayer( thisGlobe, data );
33812	}
33813
33814	// overlay layers for Regions, async
33815	// Wait for the addRegionLayer async operation to complete
33816	(async () => {
33817		await Promise.resolve(addRegionLayer(thisGlobe, data));
33818
33819		// Now that addRegionLayer is complete, we can proceed with the overlay layers
33820		if (data.layers && Array.isArray(data.layers)) {
33821			let altitudeMultiplier = 1;
33822			for (let layer of data.layers) {
33823				if (layer.regions && Array.isArray(layer.regions)) {
33824
33825					globe_ut_setupData( layer, {'regions': 'regionDefaults'} );
33826
33827					// fetch regions
33828					const existingRegions = thisGlobe.originalPolygonsData || [];
33829					const layerData = { ...layer, onlyActiveRegions: true };
33830					const preparedLayerRegions = await prepareRegions(thisGlobe, layerData, alt
33830itudeMultiplier) || [];
33831					const mergedRegions = [...existingRegions, ...preparedLayerRegions];
33832
33833					altitudeMultiplier++;
33834
33835					thisGlobe.originalPolygonsData = mergedRegions;
33836
33837					if (data.liveFilter && data.liveFilter.enabled === "1" && parseInt(data.liveFilter.default) !== parseInt(id)) {
33838						if (parseInt(data.liveFilter.default) === parseInt(layer.id)) {
33839							// we need to keep base, so merge base also
33840							if (data.liveFilter.keepBase === "1") {
33841								let baseAndLayerRegions = [...thisGlobe.basePolygonsData, ...preparedLayerRegions];
33842								thisGlobe.polygonsData(baseAndLayerRegions);
33843							} else {
33844								thisGlobe.polygonsData(layer.regions);
33845							}
33846						}
33847					} else {
33848						thisGlobe.polygonsData(mergedRegions);
33849					}
33850				}
33851			}
33852		}
33853	})();
33854
33855	// overlay layers for dotLabels, points, object markers and arcs
33856	if( data.layers && Array.isArray( data.layers ) ){
33857		// Initialize arrays for data collection
33858		thisGlobe.originalPointsData = thisGlobe.pointsData();
33859		thisGlobe.originalLabelsData = thisGlobe.labelsData();
33860		thisGlobe.originalArcsData = thisGlobe.arcsData();
33861		thisGlobe.originalHtmlData = thisGlobe.htmlElementsData();
33862		thisGlobe.originalObjectsData = thisGlobe.objectsData();
33863
33864		// store original base map data, if needed
33865		thisGlobe.basePointsData = thisGlobe.pointsData();
33866		thisGlobe.baseLabelsData = thisGlobe.labelsData();
33867		thisGlobe.baseArcsData = thisGlobe.arcsData();
33868		thisGlobe.baseHtmlData = thisGlobe.htmlElementsData();
33869		thisGlobe.baseObjectsData = thisGlobe.objectsData();
33870
33871		for( let layer of data.layers ){
33872
33873			let layerDataTypes = {
33874				'arcLines': 'arcLineDefaults',
33875				'points': 'pointDefaults',
33876				'objects': 'pointDefaults',
33877				'dotLabels': 'labelDefaults',
33878				'html': 'htmlDefaults',
33879				'pins': 'pointDefaults'
33880			};
33881
33882			globe_ut_setupData( layer, layerDataTypes );
33883			// points
33884			if (layer.points && Array.isArray(layer.points)) {
33885
33886				const existingPoints = thisGlobe.originalPointsData;
33887				const mergedPoints = [...existingPoints, ...layer.points];
33888
33889				thisGlobe.originalPointsData = mergedPoints;
33890
33891				if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){
33892					if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){
33893						thisGlobe.pointsData(layer.points);
33894						// we need to keep base, so merge base also
33895						if( data.liveFilter.keepBase === "1" ){
33896							let baseAndLayerPoints = [...thisGlobe.basePointsData, ...layer.points];
33897							thisGlobe.pointsData( baseAndLayerPoints );
33898						}
33899					}
33900				} else {
33901					thisGlobe.pointsData(mergedPoints);
33902				}
33903			}
33904
33905			// html
33906			if (layer.html && Array.isArray(layer.html)) {
33907				const existingHtml = thisGlobe.originalHtmlData;
33908				const mergedHtml = [...existingHtml, ...layer.html];
33909
33910				thisGlobe.originalHtmlData = mergedHtml;
33911
33912				if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){
33913					if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){
33914						thisGlobe.htmlElementsData(layer.html);
33915					}
33916				} else {
33917					thisGlobe.htmlElementsData(mergedHtml);
33918				}
33919			}
33920			// objects
33921			if (layer.objects && Array.isArray(layer.objects)) {
33922
33923				const existingObjects = thisGlobe.originalObjectsData;
33924				const mergedObjects = [...existingObjects, ...layer.objects];
33925
33926				thisGlobe.originalObjectsData = mergedObjects;
33927
33928				if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){
33929					if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){
33930						thisGlobe.objectsData(layer.objects);
33931						// we need to keep base, so merge base also
33932						if( data.liveFilter.keepBase === "1" ){
33933							let baseAndLayerObjects = [...thisGlobe.baseObjectsData, ...layer.objects];
33934							thisGlobe.objectsData( baseAndLayerObjects );
33935						}
33936					}
33937				} else {
33938					thisGlobe.objectsData(mergedObjects);
33939				}
33940			}
33941
33942			// dot labels
33943			if (layer.dotLabels && Array.isArray(layer.dotLabels)) {
33944				const existingLabels = thisGlobe.originalLabelsData;
33945				const mergedLabels = [...existingLabels, ...layer.dotLabels];
33946
33947				thisGlobe.originalLabelsData = mergedLabels;
33948
33949				if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){
33950					if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){
33951						thisGlobe.labelsData(layer.dotLabels);
33952						// we need to keep base, so merge base also
33953						if( data.liveFilter.keepBase === "1" ){
33954							let baseAndLayerDotLabels = [...thisGlobe.baseLabelsData, ...layer.dotLabels];
33955							thisGlobe.labelsData( baseAndLayerDotLabels );
33956						}
33957					}
33958				} else {
33959					thisGlobe.labelsData(mergedLabels);
33960				}
33961			}
33962
33963			// arcs
33964			if (layer.arcLines && Array.isArray(layer.arcLines)) {
33965				const existingArcs = thisGlobe.originalArcsData;
33966				const mergedArcs = [...existingArcs, ...layer.arcLines];
33967
33968				thisGlobe.originalArcsData = mergedArcs;
33969
33970				if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){
33971					if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){
33972						thisGlobe.arcsData(layer.arcLines);
33973						// we need to keep base, so merge base also
33974						if( data.liveFilter.keepBase === "1" ){
33975							let baseAndLayerArcs = [...thisGlobe.baseArcsData, ...layer.arcLines];
33976							thisGlobe.arcsData( baseAndLayerArcs );
33977						}
33978					}
33979				} else {
33980					thisGlobe.arcsData(mergedArcs);
33981				}
33982			}
33983
33984			// regions are done async
33985		}
33986	}
33987
33988	const existingOnGlobeReady = thisGlobe.onGlobeReady();
33989	thisGlobe.onGlobeReady(function () {
33990		if ( existingOnGlobeReady ) {
33991			existingOnGlobeReady();
33992		}
33993		setCustomGraticule( thisGlobe, data );
33994
33995		// only admin hook
33996		if ( ittGlobeData.isAdmin ) {
33997			document.dispatchEvent(new Event("adminProGlobeReady"));
33998		}
33999	});
34000
34001
34002	// to make it publically accessible
34003	thisGlobe.meta = data;
34004};
34005
34006ittGlobes$1.pro();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.