three#Plane JavaScript Examples
The following examples show how to use
three#Plane.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: roof_item.js From architect3d with MIT License | 6 votes |
roofContainsPoint(roof, forpoint)
{
var g = roof.geometry;
var result = {distance: Number.MAX_VALUE, contains: false, point: null, closestPoint: null};
var closestPoint = null;
for (var i=0;i< g.faces.length;i++)
{
var f = g.faces[i];
var plane = new Plane();
var triangle = new Triangle(g.vertices[f.a], g.vertices[f.b], g.vertices[f.c]);
var ipoint = new Vector3();
var cpoint = new Vector3();
var contains = false;
var distance = 0.0;
closestPoint = triangle.closestPointToPoint(forpoint, cpoint);
triangle.getPlane(plane);
plane.projectPoint(forpoint, ipoint);
contains = triangle.containsPoint(ipoint);
distance = plane.distanceToPoint(forpoint);
if(distance < result.distance && contains)
{
result.distance = distance;
result.contains = contains;
result.point = ipoint;
result.closestPoint = closestPoint.clone();
}
}
//No good result so return the closest point of the last triangle in this roof mesh
if(result.point == null)
{
result.closestPoint = closestPoint.clone();
}
return result;
}
Example #2
Source File: DragControls.js From geometry_3d with MIT License | 6 votes |
constructor(_objects, _camera) {
this._objects = _objects;
this._camera = _camera;
this._plane = new Plane();
this._raycaster = new Raycaster();
_mouse = new Vector2();
this._offset = new Vector3();
this._intersection = new Vector3();
this._worldPosition = new Vector3();
this._inverseMatrix = new Matrix4();
this._intersections = [];
this._selected = null;
}
Example #3
Source File: main.js From architect3d with MIT License | 5 votes |
constructor(model, element, canvasElement, opts)
{
super();
var options = {resize: true,pushHref: false,spin: true,spinSpeed: .00002,clickPan: true,canMoveFixedItems: false};
for (var opt in options)
{
if (options.hasOwnProperty(opt) && opts.hasOwnProperty(opt))
{
options[opt] = opts[opt];
}
}
this.pauseRender = true;
this.model = model;
this.scene = model.scene;
this.element = $(element);
this.canvasElement = canvasElement;
this.options = options;
this.domElement = null;
this.orthocamera = null;
this.perspectivecamera = null;
this.camera = null;
this.savedcameraposition = null;
this.fpscamera = null;
this.cameraNear = 10;
this.cameraFar = 10000;
this.controls = null;
this.fpscontrols = null;
this.fpsclock = new Clock(true);
this.firstpersonmode = false;
this.renderer = null;
this.controller = null;
this.needsUpdate = false;
this.lastRender = Date.now();
this.mouseOver = false;
this.hasClicked = false;
this.hud = null;
this.heightMargin = null;
this.widthMargin = null;
this.elementHeight = null;
this.elementWidth = null;
this.itemSelectedCallbacks = $.Callbacks(); // item
this.itemUnselectedCallbacks = $.Callbacks();
this.wallClicked = $.Callbacks(); // wall
this.floorClicked = $.Callbacks(); // floor
this.nothingClicked = $.Callbacks();
this.floorplan = null;
var scope = this;
this.updatedevent = ()=>{scope.centerCamera();};
this.gltfreadyevent = (o)=>{scope.gltfReady(o);};
this.clippingPlaneActive = new Plane(new Vector3(0, 0, 1), 0.0);
this.clippingPlaneActive2 = new Plane(new Vector3(0, 0, -1), 0.0);
this.globalClippingPlane = [this.clippingPlaneActive, this.clippingPlaneActive2];
this.clippingEmpty = Object.freeze([]);
this.clippingEnabled = false;
// console.log('THIS ON MOBILE DEVICE ::: ', isMobile, isTablet);
this.init();
}
Example #4
Source File: DragControls.js From Computer-Graphics with MIT License | 5 votes |
_plane = new Plane()
Example #5
Source File: Water.js From canvas with Apache License 2.0 | 4 votes |
Water = function ( geometry, options ) {
Mesh.call( this, geometry );
var scope = this;
options = options || {};
var textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
var textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
var clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
var alpha = options.alpha !== undefined ? options.alpha : 1.0;
var time = options.time !== undefined ? options.time : 0.0;
var normalSampler = options.waterNormals !== undefined ? options.waterNormals : null;
var sunDirection = options.sunDirection !== undefined ? options.sunDirection : new Vector3( 0.70707, 0.70707, 0.0 );
var sunColor = new Color( options.sunColor !== undefined ? options.sunColor : 0xffffff );
var waterColor = new Color( options.waterColor !== undefined ? options.waterColor : 0x7F7F7F );
var eye = options.eye !== undefined ? options.eye : new Vector3( 0, 0, 0 );
var distortionScale = options.distortionScale !== undefined ? options.distortionScale : 20.0;
var side = options.side !== undefined ? options.side : FrontSide;
var fog = options.fog !== undefined ? options.fog : false;
//
var mirrorPlane = new Plane();
var normal = new Vector3();
var mirrorWorldPosition = new Vector3();
var cameraWorldPosition = new Vector3();
var rotationMatrix = new Matrix4();
var lookAtPosition = new Vector3( 0, 0, - 1 );
var clipPlane = new Vector4();
var view = new Vector3();
var target = new Vector3();
var q = new Vector4();
var textureMatrix = new Matrix4();
var mirrorCamera = new PerspectiveCamera();
var parameters = {
minFilter: LinearFilter,
magFilter: LinearFilter,
format: RGBFormat,
stencilBuffer: false
};
var renderTarget = new WebGLRenderTarget( textureWidth, textureHeight, parameters );
if ( ! MathUtils.isPowerOfTwo( textureWidth ) || ! MathUtils.isPowerOfTwo( textureHeight ) ) {
renderTarget.texture.generateMipmaps = false;
}
var mirrorShader = {
uniforms: UniformsUtils.merge( [
UniformsLib[ 'fog' ],
UniformsLib[ 'lights' ],
{
"normalSampler": { value: null },
"mirrorSampler": { value: null },
"alpha": { value: 1.0 },
"time": { value: 0.0 },
"size": { value: 1.0 },
"distortionScale": { value: 20.0 },
"textureMatrix": { value: new Matrix4() },
"sunColor": { value: new Color( 0x7F7F7F ) },
"sunDirection": { value: new Vector3( 0.70707, 0.70707, 0 ) },
"eye": { value: new Vector3() },
"waterColor": { value: new Color( 0x555555 ) }
}
] ),
vertexShader: [
'uniform mat4 textureMatrix;',
'uniform float time;',
'varying vec4 mirrorCoord;',
'varying vec4 worldPosition;',
'#include <common>',
'#include <fog_pars_vertex>',
'#include <shadowmap_pars_vertex>',
'#include <logdepthbuf_pars_vertex>',
'void main() {',
' mirrorCoord = modelMatrix * vec4( position, 1.0 );',
' worldPosition = mirrorCoord.xyzw;',
' mirrorCoord = textureMatrix * mirrorCoord;',
' vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
' gl_Position = projectionMatrix * mvPosition;',
'#include <logdepthbuf_vertex>',
'#include <fog_vertex>',
'#include <shadowmap_vertex>',
'}'
].join( '\n' ),
fragmentShader: [
'uniform sampler2D mirrorSampler;',
'uniform float alpha;',
'uniform float time;',
'uniform float size;',
'uniform float distortionScale;',
'uniform sampler2D normalSampler;',
'uniform vec3 sunColor;',
'uniform vec3 sunDirection;',
'uniform vec3 eye;',
'uniform vec3 waterColor;',
'varying vec4 mirrorCoord;',
'varying vec4 worldPosition;',
'vec4 getNoise( vec2 uv ) {',
' vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0);',
' vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 );',
' vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 );',
' vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 );',
' vec4 noise = texture2D( normalSampler, uv0 ) +',
' texture2D( normalSampler, uv1 ) +',
' texture2D( normalSampler, uv2 ) +',
' texture2D( normalSampler, uv3 );',
' return noise * 0.5 - 1.0;',
'}',
'void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) {',
' vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) );',
' float direction = max( 0.0, dot( eyeDirection, reflection ) );',
' specularColor += pow( direction, shiny ) * sunColor * spec;',
' diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse;',
'}',
'#include <common>',
'#include <packing>',
'#include <bsdfs>',
'#include <fog_pars_fragment>',
'#include <logdepthbuf_pars_fragment>',
'#include <lights_pars_begin>',
'#include <shadowmap_pars_fragment>',
'#include <shadowmask_pars_fragment>',
'void main() {',
'#include <logdepthbuf_fragment>',
' vec4 noise = getNoise( worldPosition.xz * size );',
' vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) );',
' vec3 diffuseLight = vec3(0.0);',
' vec3 specularLight = vec3(0.0);',
' vec3 worldToEye = eye-worldPosition.xyz;',
' vec3 eyeDirection = normalize( worldToEye );',
' sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight );',
' float distance = length(worldToEye);',
' vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale;',
' vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.w + distortion ) );',
' float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );',
' float rf0 = 0.3;',
' float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );',
' vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;',
' vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);',
' vec3 outgoingLight = albedo;',
' gl_FragColor = vec4( outgoingLight, alpha );',
'#include <tonemapping_fragment>',
'#include <fog_fragment>',
'}'
].join( '\n' )
};
var material = new ShaderMaterial( {
fragmentShader: mirrorShader.fragmentShader,
vertexShader: mirrorShader.vertexShader,
uniforms: UniformsUtils.clone( mirrorShader.uniforms ),
lights: true,
side: side,
fog: fog
} );
material.uniforms[ "mirrorSampler" ].value = renderTarget.texture;
material.uniforms[ "textureMatrix" ].value = textureMatrix;
material.uniforms[ "alpha" ].value = alpha;
material.uniforms[ "time" ].value = time;
material.uniforms[ "normalSampler" ].value = normalSampler;
material.uniforms[ "sunColor" ].value = sunColor;
material.uniforms[ "waterColor" ].value = waterColor;
material.uniforms[ "sunDirection" ].value = sunDirection;
material.uniforms[ "distortionScale" ].value = distortionScale;
material.uniforms[ "eye" ].value = eye;
scope.material = material;
scope.onBeforeRender = function ( renderer, scene, camera ) {
mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
rotationMatrix.extractRotation( scope.matrixWorld );
normal.set( 0, 0, 1 );
normal.applyMatrix4( rotationMatrix );
view.subVectors( mirrorWorldPosition, cameraWorldPosition );
// Avoid rendering when mirror is facing away
if ( view.dot( normal ) > 0 ) return;
view.reflect( normal ).negate();
view.add( mirrorWorldPosition );
rotationMatrix.extractRotation( camera.matrixWorld );
lookAtPosition.set( 0, 0, - 1 );
lookAtPosition.applyMatrix4( rotationMatrix );
lookAtPosition.add( cameraWorldPosition );
target.subVectors( mirrorWorldPosition, lookAtPosition );
target.reflect( normal ).negate();
target.add( mirrorWorldPosition );
mirrorCamera.position.copy( view );
mirrorCamera.up.set( 0, 1, 0 );
mirrorCamera.up.applyMatrix4( rotationMatrix );
mirrorCamera.up.reflect( normal );
mirrorCamera.lookAt( target );
mirrorCamera.far = camera.far; // Used in WebGLBackground
mirrorCamera.updateMatrixWorld();
mirrorCamera.projectionMatrix.copy( camera.projectionMatrix );
// Update the texture matrix
textureMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
textureMatrix.multiply( mirrorCamera.projectionMatrix );
textureMatrix.multiply( mirrorCamera.matrixWorldInverse );
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
mirrorPlane.setFromNormalAndCoplanarPoint( normal, mirrorWorldPosition );
mirrorPlane.applyMatrix4( mirrorCamera.matrixWorldInverse );
clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant );
var projectionMatrix = mirrorCamera.projectionMatrix;
q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
q.z = - 1.0;
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
// Calculate the scaled plane vector
clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
// Replacing the third row of the projection matrix
projectionMatrix.elements[ 2 ] = clipPlane.x;
projectionMatrix.elements[ 6 ] = clipPlane.y;
projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
projectionMatrix.elements[ 14 ] = clipPlane.w;
eye.setFromMatrixPosition( camera.matrixWorld );
//
var currentRenderTarget = renderer.getRenderTarget();
var currentXrEnabled = renderer.xr.enabled;
var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
scope.visible = false;
renderer.xr.enabled = false; // Avoid camera modification and recursion
renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
renderer.setRenderTarget( renderTarget );
renderer.state.buffers.depth.setMask( true ); // make sure the depth buffer is writable so it can be properly cleared, see #18897
if ( renderer.autoClear === false ) renderer.clear();
renderer.render( scene, mirrorCamera );
scope.visible = true;
renderer.xr.enabled = currentXrEnabled;
renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
renderer.setRenderTarget( currentRenderTarget );
// Restore viewport
var viewport = camera.viewport;
if ( viewport !== undefined ) {
renderer.state.viewport( viewport );
}
};
}
Example #6
Source File: MeshUIComponent.js From three-mesh-ui with MIT License | 4 votes |
/**
Job:
- Set this component attributes and call updates accordingly
- Getting this component attribute, from itself or from its parents
- Managing this component's states
This is the core module of three-mesh-ui. Every component is composed with it.
It owns the principal public methods of a component : set, setupState and setState.
*/
export default function MeshUIComponent( Base ) {
return class MeshUIComponent extends Base {
constructor( options ) {
super( options );
this.states = {};
this.currentState = undefined;
this.isUI = true;
this.autoLayout = true;
// children
this.childrenUIs = [];
this.childrenBoxes = [];
this.childrenTexts = [];
this.childrenInlines = [];
// parents
this.parentUI = null;
// update parentUI when this component will be added or removed
this.addEventListener( 'added', this._rebuildParentUI );
this.addEventListener( 'removed', this._rebuildParentUI );
}
/////////////
/// GETTERS
/////////////
getClippingPlanes() {
const planes = [];
if ( this.parentUI ) {
if ( this.isBlock && this.parentUI.getHiddenOverflow() ) {
const yLimit = ( this.parentUI.getHeight() / 2 ) - ( this.parentUI.padding || 0 );
const xLimit = ( this.parentUI.getWidth() / 2 ) - ( this.parentUI.padding || 0 );
const newPlanes = [
new Plane( new Vector3( 0, 1, 0 ), yLimit ),
new Plane( new Vector3( 0, -1, 0 ), yLimit ),
new Plane( new Vector3( 1, 0, 0 ), xLimit ),
new Plane( new Vector3( -1, 0, 0 ), xLimit )
];
newPlanes.forEach( plane => {
plane.applyMatrix4( this.parent.matrixWorld );
} );
planes.push( ...newPlanes );
}
if ( this.parentUI.parentUI ) {
planes.push( ...this.parentUI.getClippingPlanes() );
}
}
return planes;
}
/** Get the highest parent of this component (the parent that has no parent on top of it) */
getHighestParent() {
if ( !this.parentUI ) {
return this;
}
return this.parent.getHighestParent();
}
/**
* look for a property in this object, and if does not find it, find in parents or return default value
* @private
*/
_getProperty( propName ) {
if ( this[ propName ] === undefined && this.parentUI ) {
return this.parent._getProperty( propName );
} else if ( this[ propName ] !== undefined ) {
return this[ propName ];
}
return DEFAULTS[ propName ];
}
//
getFontSize() {
return this._getProperty( 'fontSize' );
}
getFontKerning() {
return this._getProperty( 'fontKerning' );
}
getLetterSpacing() {
return this._getProperty( 'letterSpacing' );
}
getFontTexture() {
return this._getProperty( 'fontTexture' );
}
getFontFamily() {
return this._getProperty( 'fontFamily' );
}
getBreakOn() {
return this._getProperty( 'breakOn' );
}
getWhiteSpace() {
return this._getProperty( 'whiteSpace' );
}
getTextAlign() {
return this._getProperty( 'textAlign' );
}
getTextType() {
return this._getProperty( 'textType' );
}
getFontColor() {
return this._getProperty( 'fontColor' );
}
getFontSupersampling() {
return this._getProperty( 'fontSupersampling' );
}
getFontOpacity() {
return this._getProperty( 'fontOpacity' );
}
getFontPXRange() {
return this._getProperty( 'fontPXRange' );
}
getBorderRadius() {
return this._getProperty( 'borderRadius' );
}
getBorderWidth() {
return this._getProperty( 'borderWidth' );
}
getBorderColor() {
return this._getProperty( 'borderColor' );
}
getBorderOpacity() {
return this._getProperty( 'borderOpacity' );
}
/// SPECIALS
/** return the first parent with a 'threeOBJ' property */
getContainer() {
if ( !this.threeOBJ && this.parent ) {
return this.parent.getContainer();
} else if ( this.threeOBJ ) {
return this;
}
return DEFAULTS.container;
}
/** Get the number of UI parents above this elements (0 if no parent) */
getParentsNumber( i ) {
i = i || 0;
if ( this.parentUI ) {
return this.parentUI.getParentsNumber( i + 1 );
}
return i;
}
////////////////////////////////////
/// GETTERS WITH NO PARENTS LOOKUP
////////////////////////////////////
getBackgroundOpacity() {
return ( !this.backgroundOpacity && this.backgroundOpacity !== 0 ) ?
DEFAULTS.backgroundOpacity : this.backgroundOpacity;
}
getBackgroundColor() {
return this.backgroundColor || DEFAULTS.backgroundColor;
}
getBackgroundTexture() {
return this.backgroundTexture || DEFAULTS.backgroundTexture();
}
/**
* @deprecated
* @returns {string}
*/
getAlignContent() {
return this.alignContent || DEFAULTS.alignContent;
}
getAlignItems() {
return this.alignItems || DEFAULTS.alignItems;
}
getContentDirection() {
return this.contentDirection || DEFAULTS.contentDirection;
}
getJustifyContent() {
return this.justifyContent || DEFAULTS.justifyContent;
}
getInterLine() {
return ( this.interLine === undefined ) ? DEFAULTS.interLine : this.interLine;
}
getOffset() {
return ( this.offset === undefined ) ? DEFAULTS.offset : this.offset;
}
getBackgroundSize() {
return ( this.backgroundSize === undefined ) ? DEFAULTS.backgroundSize : this.backgroundSize;
}
getHiddenOverflow() {
return ( this.hiddenOverflow === undefined ) ? DEFAULTS.hiddenOverflow : this.hiddenOverflow;
}
getBestFit() {
return ( this.bestFit === undefined ) ? DEFAULTS.bestFit : this.bestFit;
}
///////////////
/// UPDATE
///////////////
/**
* Filters children in order to compute only one times children lists
* @private
*/
_rebuildChildrenLists() {
// Stores all children that are ui
this.childrenUIs = this.children.filter( child => child.isUI );
// Stores all children that are box
this.childrenBoxes = this.children.filter( child => child.isBoxComponent );
// Stores all children that are inline
this.childrenInlines = this.children.filter( child => child.isInline );
// Stores all children that are text
this.childrenTexts = this.children.filter( child => child.isText );
}
/**
* Try to retrieve parentUI after each structural change
* @private
*/
_rebuildParentUI = ( ) => {
if ( this.parent && this.parent.isUI ) {
this.parentUI = this.parent;
} else {
this.parentUI = null;
}
};
/**
* When the user calls component.add, it registers for updates,
* then call THREE.Object3D.add.
*/
add() {
for ( const id of Object.keys( arguments ) ) {
// An inline component relies on its parent for positioning
if ( arguments[ id ].isInline ) this.update( null, true );
}
const result = super.add( ...arguments );
this._rebuildChildrenLists();
return result;
}
/**
* When the user calls component.remove, it registers for updates,
* then call THREE.Object3D.remove.
*/
remove() {
for ( const id of Object.keys( arguments ) ) {
// An inline component relies on its parent for positioning
if ( arguments[ id ].isInline ) this.update( null, true );
}
const result = super.remove( ...arguments );
this._rebuildChildrenLists();
return result;
}
//
update( updateParsing, updateLayout, updateInner ) {
UpdateManager.requestUpdate( this, updateParsing, updateLayout, updateInner );
}
onAfterUpdate() {
}
/**
* Called by FontLibrary when the font requested for the current component is ready.
* Trigger an update for the component whose font is now available.
* @private - "package protected"
*/
_updateFontFamily( font ) {
this.fontFamily = font;
this.traverse( ( child ) => {
if ( child.isUI ) child.update( true, true, false );
} );
this.getHighestParent().update( false, true, false );
}
/** @private - "package protected" */
_updateFontTexture( texture ) {
this.fontTexture = texture;
this.getHighestParent().update( false, true, false );
}
/**
* Set this component's passed parameters.
* If necessary, take special actions.
* Update this component unless otherwise specified.
*/
set( options ) {
let parsingNeedsUpdate, layoutNeedsUpdate, innerNeedsUpdate;
// Register to the update manager, so that it knows when to update
UpdateManager.register( this );
// Abort if no option passed
if ( !options || JSON.stringify( options ) === JSON.stringify( {} ) ) return;
// DEPRECATION Warnings until -------------------------------------- 7.x.x ---------------------------------------
// Align content has been removed
if( options["alignContent"] ){
options["alignItems"] = options["alignContent"];
if( !options["textAlign"] ){
options["textAlign"] = options["alignContent"];
}
console.warn("`alignContent` property has been deprecated, please rely on `alignItems` and `textAlign` instead.")
delete options["alignContent"];
}
// Align items left top bottom right will be removed
if( options['alignItems'] ){
warnAboutDeprecatedAlignItems( options['alignItems'] );
}
// Set this component parameters according to options, and trigger updates accordingly
// The benefit of having two types of updates, is to put everthing that takes time
// in one batch, and the rest in the other. This way, efficient animation is possible with
// attribute from the light batch.
for ( const prop of Object.keys( options ) ) {
if ( this[ prop ] != options[ prop ] ) {
switch ( prop ) {
case 'content' :
case 'fontSize' :
case 'fontKerning' :
case 'breakOn':
case 'whiteSpace':
if ( this.isText ) parsingNeedsUpdate = true;
layoutNeedsUpdate = true;
this[ prop ] = options[ prop ];
break;
case 'bestFit' :
if ( this.isBlock ) {
parsingNeedsUpdate = true;
layoutNeedsUpdate = true;
}
this[ prop ] = options[ prop ];
break;
case 'width' :
case 'height' :
case 'padding' :
if ( this.isInlineBlock || ( this.isBlock && this.getBestFit() != 'none' ) ) parsingNeedsUpdate = true;
layoutNeedsUpdate = true;
this[ prop ] = options[ prop ];
break;
case 'letterSpacing' :
case 'interLine' :
if ( this.isBlock && this.getBestFit() != 'none' ) parsingNeedsUpdate = true;
layoutNeedsUpdate = true;
this[ prop ] = options[ prop ];
break;
case 'margin' :
case 'contentDirection' :
case 'justifyContent' :
case 'alignContent' :
case 'alignItems' :
case 'textAlign' :
case 'textType' :
layoutNeedsUpdate = true;
this[ prop ] = options[ prop ];
break;
case 'fontColor' :
case 'fontOpacity' :
case 'fontSupersampling' :
case 'offset' :
case 'backgroundColor' :
case 'backgroundOpacity' :
case 'backgroundTexture' :
case 'backgroundSize' :
case 'borderRadius' :
case 'borderWidth' :
case 'borderColor' :
case 'borderOpacity' :
innerNeedsUpdate = true;
this[ prop ] = options[ prop ];
break;
case 'hiddenOverflow' :
this[ prop ] = options[ prop ];
break;
}
}
}
// special cases, this.update() must be called only when some files finished loading
if ( options.fontFamily ) {
FontLibrary.setFontFamily( this, options.fontFamily );
}
if ( options.fontTexture ) {
FontLibrary.setFontTexture( this, options.fontTexture );
}
// if font kerning changes for a child of a block with Best Fit enabled, we need to trigger parsing for the parent as well.
if ( this.parentUI && this.parentUI.getBestFit() != 'none' ) this.parentUI.update( true, true, false );
// Call component update
this.update( parsingNeedsUpdate, layoutNeedsUpdate, innerNeedsUpdate );
if ( layoutNeedsUpdate ) this.getHighestParent().update( false, true, false );
}
/////////////////////
// STATES MANAGEMENT
/////////////////////
/** Store a new state in this component, with linked attributes */
setupState( options ) {
this.states[ options.state ] = {
attributes: options.attributes,
onSet: options.onSet
};
}
/** Set the attributes of a stored state of this component */
setState( state ) {
const savedState = this.states[ state ];
if ( !savedState ) {
console.warn( `state "${state}" does not exist within this component:`, this.name );
return;
}
if ( state === this.currentState ) return;
this.currentState = state;
if ( savedState.onSet ) savedState.onSet();
if ( savedState.attributes ) this.set( savedState.attributes );
}
/** Get completely rid of this component and its children, also unregister it for updates */
clear() {
this.traverse( ( obj ) => {
UpdateManager.disposeOf( obj );
if ( obj.material ) obj.material.dispose();
if ( obj.geometry ) obj.geometry.dispose();
} );
}
};
}