diff --git a/TODO b/TODO index 6e72cfd5..07e87591 100644 --- a/TODO +++ b/TODO @@ -14,7 +14,7 @@ FEATURES TO ADD AND FIX AND STUFF [x]Text (and strings) [ ]Draft [ ]Minkowski Sum -[ ]Switch to three.js +[x]Switch to three.js [ ]Transparency (like openscad's #, or alpha channel in color) [ ]Internationalization support (bring back from blockly) [ ]Simplified mode (elementary-friendly, hiding distracting fancy stuff) diff --git a/blockscad/OrbitControls.js b/blockscad/OrbitControls.js new file mode 100644 index 00000000..d8396519 --- /dev/null +++ b/blockscad/OrbitControls.js @@ -0,0 +1,1116 @@ +/** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + */ +/*global THREE, console */ + +( function () { + + function OrbitConstraint ( object ) { + + this.object = object; + + // "target" sets the location of focus, where the object orbits around + // and where it pans with respect to. + this.target = new THREE.Vector3(); + + // Limits to how far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; + + // Limits to how far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.25; + + //////////// + // internals + + var scope = this; + + var EPS = 0.000001; + + // Current position in spherical coordinate system. + var theta; + var phi; + + // Pending changes + var phiDelta = 0; + var thetaDelta = 0; + var scale = 1; + var panOffset = new THREE.Vector3(); + var zoomChanged = false; + + // API + + this.getPolarAngle = function () { + + return phi; + + }; + + this.getAzimuthalAngle = function () { + + return theta; + + }; + + this.rotateLeft = function ( angle ) { + + thetaDelta -= angle; + + }; + + this.rotateUp = function ( angle ) { + + phiDelta -= angle; + + }; + + // pass in distance in world space to move left + this.panLeft = function() { + + var v = new THREE.Vector3(); + + return function panLeft ( distance ) { + + var te = this.object.matrix.elements; + + // get X column of matrix + v.set( te[ 0 ], te[ 1 ], te[ 2 ] ); + v.multiplyScalar( - distance ); + + panOffset.add( v ); + + }; + + }(); + + // pass in distance in world space to move up + this.panUp = function() { + + var v = new THREE.Vector3(); + + return function panUp ( distance ) { + + var te = this.object.matrix.elements; + + // get Y column of matrix + v.set( te[ 4 ], te[ 5 ], te[ 6 ] ); + v.multiplyScalar( distance ); + + panOffset.add( v ); + + }; + + }(); + + // pass in x,y of change desired in pixel space, + // right and down are positive + this.pan = function ( deltaX, deltaY, screenWidth, screenHeight ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + // perspective + var position = scope.object.position; + var offset = position.clone().sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); + + // we actually don't use screenWidth, since perspective camera is fixed to screen height + scope.panLeft( 2 * deltaX * targetDistance / screenHeight ); + scope.panUp( 2 * deltaY * targetDistance / screenHeight ); + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + // orthographic + scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth ); + scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight ); + + } else { + + // camera neither orthographic or perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + + } + + }; + + this.dollyIn = function ( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale /= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + + } + + }; + + this.dollyOut = function ( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale *= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + + } + + }; + + this.update = function() { + + var offset = new THREE.Vector3(); + + // so camera.up is the orbit axis + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().inverse(); + + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); + + return function () { + + var position = this.object.position; + + offset.copy( position ).sub( this.target ); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion( quat ); + + // angle from z-axis around y-axis + + theta = Math.atan2( offset.x, offset.z ); + + // angle from y-axis + + phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); + + theta += thetaDelta; + phi += phiDelta; + + // restrict theta to be between desired limits + theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) ); + + // restrict phi to be between desired limits + phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); + + // restrict phi to be betwee EPS and PI-EPS + phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); + + var radius = offset.length() * scale; + + // restrict radius to be between desired limits + radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); + + // move target to panned location + this.target.add( panOffset ); + + offset.x = radius * Math.sin( phi ) * Math.sin( theta ); + offset.y = radius * Math.cos( phi ); + offset.z = radius * Math.sin( phi ) * Math.cos( theta ); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion( quatInverse ); + + position.copy( this.target ).add( offset ); + + this.object.lookAt( this.target ); + + if ( this.enableDamping === true ) { + + thetaDelta *= ( 1 - this.dampingFactor ); + phiDelta *= ( 1 - this.dampingFactor ); + + } else { + + thetaDelta = 0; + phiDelta = 0; + + } + + scale = 1; + panOffset.set( 0, 0, 0 ); + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( zoomChanged || + lastPosition.distanceToSquared( this.object.position ) > EPS || + 8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) { + + lastPosition.copy( this.object.position ); + lastQuaternion.copy( this.object.quaternion ); + zoomChanged = false; + + return true; + + } + + return false; + + }; + + }(); + + }; + + + // This set of controls performs orbiting, dollying (zooming), and panning. It maintains + // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is + // supported. + // + // Orbit - left mouse / touch: one finger move + // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish + // Pan - right mouse, or arrow keys / touch: three finter swipe + + THREE.OrbitControls = function ( object, domElement ) { + + var constraint = new OrbitConstraint( object ); + + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // API + + Object.defineProperty( this, 'constraint', { + + get: function() { + + return constraint; + + } + + } ); + + this.getPolarAngle = function () { + + return constraint.getPolarAngle(); + + }; + + this.getAzimuthalAngle = function () { + + return constraint.getAzimuthalAngle(); + + }; + + // Set to false to disable this control + this.enabled = true; + + // center is old, deprecated; use "target" instead + this.center = this.target; + + // This option actually enables dollying in and out; left as "zoom" for + // backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; + + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; + + // Set to false to disable panning + this.enablePan = true; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // Set to false to disable use of the keys + this.enableKeys = true; + + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // Mouse buttons + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + + //////////// + // internals + + var scope = this; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + + var state = STATE.NONE; + + // for reset + + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // events + + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + // pass in x,y of change desired in pixel space, + // right and down are positive + function pan( deltaX, deltaY ) { + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight ); + + } + + this.update = function () { + + if ( this.autoRotate && state === STATE.NONE ) { + + constraint.rotateLeft( getAutoRotationAngle() ); + + } + + if ( constraint.update() === true ) { + + this.dispatchEvent( changeEvent ); + + } + + }; + + this.reset = function () { + + state = STATE.NONE; + + this.target.copy( this.target0 ); + this.object.position.copy( this.position0 ); + this.object.zoom = this.zoom0; + + this.object.updateProjectionMatrix(); + this.dispatchEvent( changeEvent ); + + this.update(); + + }; + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function onMouseDown( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + if ( event.button === scope.mouseButtons.ORBIT ) { + + if ( scope.enableRotate === false ) return; + + state = STATE.ROTATE; + + rotateStart.set( event.clientX, event.clientY ); + + } else if ( event.button === scope.mouseButtons.ZOOM ) { + + if ( scope.enableZoom === false ) return; + + state = STATE.DOLLY; + + dollyStart.set( event.clientX, event.clientY ); + + } else if ( event.button === scope.mouseButtons.PAN ) { + + if ( scope.enablePan === false ) return; + + state = STATE.PAN; + + panStart.set( event.clientX, event.clientY ); + + } + + if ( state !== STATE.NONE ) { + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( startEvent ); + + } + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if ( state === STATE.ROTATE ) { + + if ( scope.enableRotate === false ) return; + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + } else if ( state === STATE.DOLLY ) { + + if ( scope.enableZoom === false ) return; + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + constraint.dollyIn( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + constraint.dollyOut( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + } else if ( state === STATE.PAN ) { + + if ( scope.enablePan === false ) return; + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + } + + if ( state !== STATE.NONE ) scope.update(); + + } + + function onMouseUp( /* event */ ) { + + if ( scope.enabled === false ) return; + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( endEvent ); + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + + if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return; + + event.preventDefault(); + event.stopPropagation(); + + var delta = 0; + + if ( event.wheelDelta !== undefined ) { + + // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta; + + } else if ( event.detail !== undefined ) { + + // Firefox + + delta = - event.detail; + + } + + if ( delta > 0 ) { + + constraint.dollyOut( getZoomScale() ); + + } else if ( delta < 0 ) { + + constraint.dollyIn( getZoomScale() ); + + } + + scope.update(); + scope.dispatchEvent( startEvent ); + scope.dispatchEvent( endEvent ); + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; + + switch ( event.keyCode ) { + + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + scope.update(); + break; + + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + scope.update(); + break; + + } + + } + + function touchstart( event ) { + + if ( scope.enabled === false ) return; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.enableRotate === false ) return; + + state = STATE.TOUCH_ROTATE; + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: // two-fingered touch: dolly + + if ( scope.enableZoom === false ) return; + + state = STATE.TOUCH_DOLLY; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + break; + + case 3: // three-fingered touch: pan + + if ( scope.enablePan === false ) return; + + state = STATE.TOUCH_PAN; + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent ); + + } + + function touchmove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.enableRotate === false ) return; + if ( state !== STATE.TOUCH_ROTATE ) return; + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + break; + + case 2: // two-fingered touch: dolly + + if ( scope.enableZoom === false ) return; + if ( state !== STATE.TOUCH_DOLLY ) return; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + constraint.dollyOut( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + constraint.dollyIn( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + break; + + case 3: // three-fingered touch: pan + + if ( scope.enablePan === false ) return; + if ( state !== STATE.TOUCH_PAN ) return; + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + break; + + default: + + state = STATE.NONE; + + } + + } + + function touchend( /* event */ ) { + + if ( scope.enabled === false ) return; + + scope.dispatchEvent( endEvent ); + state = STATE.NONE; + + } + + function contextmenu( event ) { + + event.preventDefault(); + + } + + this.dispose = function() { + + this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); + this.domElement.removeEventListener( 'mousedown', onMouseDown, false ); + this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.removeEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.removeEventListener( 'touchstart', touchstart, false ); + this.domElement.removeEventListener( 'touchend', touchend, false ); + this.domElement.removeEventListener( 'touchmove', touchmove, false ); + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + window.removeEventListener( 'keydown', onKeyDown, false ); + + } + + this.domElement.addEventListener( 'contextmenu', contextmenu, false ); + + this.domElement.addEventListener( 'mousedown', onMouseDown, false ); + this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + + window.addEventListener( 'keydown', onKeyDown, false ); + + // force an update at start + this.update(); + + }; + + THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); + THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; + + Object.defineProperties( THREE.OrbitControls.prototype, { + + object: { + + get: function () { + + return this.constraint.object; + + } + + }, + + target: { + + get: function () { + + return this.constraint.target; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' ); + this.constraint.target.copy( value ); + + } + + }, + + minDistance : { + + get: function () { + + return this.constraint.minDistance; + + }, + + set: function ( value ) { + + this.constraint.minDistance = value; + + } + + }, + + maxDistance : { + + get: function () { + + return this.constraint.maxDistance; + + }, + + set: function ( value ) { + + this.constraint.maxDistance = value; + + } + + }, + + minZoom : { + + get: function () { + + return this.constraint.minZoom; + + }, + + set: function ( value ) { + + this.constraint.minZoom = value; + + } + + }, + + maxZoom : { + + get: function () { + + return this.constraint.maxZoom; + + }, + + set: function ( value ) { + + this.constraint.maxZoom = value; + + } + + }, + + minPolarAngle : { + + get: function () { + + return this.constraint.minPolarAngle; + + }, + + set: function ( value ) { + + this.constraint.minPolarAngle = value; + + } + + }, + + maxPolarAngle : { + + get: function () { + + return this.constraint.maxPolarAngle; + + }, + + set: function ( value ) { + + this.constraint.maxPolarAngle = value; + + } + + }, + + minAzimuthAngle : { + + get: function () { + + return this.constraint.minAzimuthAngle; + + }, + + set: function ( value ) { + + this.constraint.minAzimuthAngle = value; + + } + + }, + + maxAzimuthAngle : { + + get: function () { + + return this.constraint.maxAzimuthAngle; + + }, + + set: function ( value ) { + + this.constraint.maxAzimuthAngle = value; + + } + + }, + + enableDamping : { + + get: function () { + + return this.constraint.enableDamping; + + }, + + set: function ( value ) { + + this.constraint.enableDamping = value; + + } + + }, + + dampingFactor : { + + get: function () { + + return this.constraint.dampingFactor; + + }, + + set: function ( value ) { + + this.constraint.dampingFactor = value; + + } + + }, + + // backward compatibility + + noZoom: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + return ! this.enableZoom; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + this.enableZoom = ! value; + + } + + }, + + noRotate: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + return ! this.enableRotate; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + this.enableRotate = ! value; + + } + + }, + + noPan: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + return ! this.enablePan; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + this.enablePan = ! value; + + } + + }, + + noKeys: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + return ! this.enableKeys; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + this.enableKeys = ! value; + + } + + }, + + staticMoving : { + + get: function () { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + return ! this.constraint.enableDamping; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + this.constraint.enableDamping = ! value; + + } + + }, + + dynamicDampingFactor : { + + get: function () { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + return this.constraint.dampingFactor; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + this.constraint.dampingFactor = value; + + } + + } + + } ); + +}() ); + diff --git a/blockscad/blockscad.js b/blockscad/blockscad.js index 6fcf4b18..caa848b9 100644 --- a/blockscad/blockscad.js +++ b/blockscad/blockscad.js @@ -170,7 +170,7 @@ Blockscad.init = function() { // toggle whether or not we draw the axes, then redraw Blockscad.drawAxes = (Blockscad.drawAxes + 1) % 2; $( '#axesButton' ).toggleClass("btn-pushed"); - gProcessor.viewer.onDraw(); + gProcessor.viewer.toggleAxes(); }); // can I bind a click to a tab? diff --git a/blockscad/blockscad_build.py b/blockscad/blockscad_build.py index cdf12e4c..34d0d73b 100755 --- a/blockscad/blockscad_build.py +++ b/blockscad/blockscad_build.py @@ -56,7 +56,7 @@ def gen_blockscad(self): # Read in all the source files. filenames = ['storage.js','utils.js','blockscad.js', 'FileSaver.js', - 'text.js','lightgl.js','toolbox.js','deflate.js', 'stl.js'] + 'text.js','three.min.js','OrbitControls.js','toolbox.js','deflate.js', 'stl.js'] for filename in filenames: f = open(filename) print filename @@ -79,7 +79,7 @@ def gen_viewer(self): ] # Read in all the source files. - filenames = ['viewer.js', 'csg.js', 'formats.js'] + filenames = ['threeViewer.js', 'csg.js', 'formats.js'] for filename in filenames: f = open(filename) print filename @@ -165,4 +165,4 @@ def file_lookup(name): n = int(name[6:]) return filenames[n] if __name__ == '__main__': - Gen_compressed('').start() \ No newline at end of file + Gen_compressed('').start() diff --git a/blockscad/blockscad_compressed.js b/blockscad/blockscad_compressed.js index f6d24c95..9ec4fc70 100644 --- a/blockscad/blockscad_compressed.js +++ b/blockscad/blockscad_compressed.js @@ -1,143 +1,976 @@ // Do not edit this file; automatically generated by blockscad_build.py. "use strict"; var BlocklyStorage=BlocklyStorage||{},Blockscad=Blockscad||{};Blockscad.Auth=Blockscad.Auth||{};var Blockly=Blockly||{};Blockly.Xml=Blockly.Xml||{}; -BlocklyStorage.backupBlocks_=function(){console.log("in backupBlocks");if("localStorage"in window){localStorage.clear();for(var a=Blockly.Xml.workspaceToDom(Blockscad.workspace),d=window.location.href.split("#")[0],e=d+"proj_name",h=d+"current_project",m=Blockscad.workspace.getAllBlocks(),k=0;kBlockscad.csg_commands[l].length){var n=Base64.toBase64(RawDeflate.deflate(Base64.utob(Blockscad.csg_commands[l]))); -window.localStorage.setItem(r,n);window.localStorage.setItem(w,Blockscad.csg_center[l])}}}window.localStorage.setItem(d,Blockly.Xml.domToText(a));window.localStorage.setItem(e,$("#project-name").val());window.localStorage.setItem(h,Blockscad.Auth.current_project)}};BlocklyStorage.backupOnUnload=function(){window.addEventListener("unload",BlocklyStorage.backupBlocks_,!1)}; -BlocklyStorage.restoreBlocks=function(){var a=window.location.href.split("#")[0],d=a+"proj_name",e=a+"current_project";console.log(window.localStorage);if("localStorage"in window&&window.localStorage[a]){var h=Blockly.Xml.textToDom(window.localStorage[a]);Blockly.Xml.domToWorkspace(Blockscad.workspace,h);for(var h=Blockscad.workspace.getAllBlocks(),m=0;mBlockscad.csg_commands[f].length){var l=Base64.toBase64(RawDeflate.deflate(Base64.utob(Blockscad.csg_commands[f]))); +window.localStorage.setItem(h,l);window.localStorage.setItem(k,Blockscad.csg_center[f])}}}window.localStorage.setItem(b,Blockly.Xml.domToText(a));window.localStorage.setItem(c,$("#project-name").val());window.localStorage.setItem(d,Blockscad.Auth.current_project)}};BlocklyStorage.backupOnUnload=function(){window.addEventListener("unload",BlocklyStorage.backupBlocks_,!1)}; +BlocklyStorage.restoreBlocks=function(){var a=window.location.href.split("#")[0],b=a+"proj_name",c=a+"current_project";console.log(window.localStorage);if("localStorage"in window&&window.localStorage[a]){var d=Blockly.Xml.textToDom(window.localStorage[a]);Blockly.Xml.domToWorkspace(Blockscad.workspace,d);for(var d=Blockscad.workspace.getAllBlocks(),e=0;ee[0]?1:a[0]screen.availWidth&&a.setAttribute("content","width=725, initial-scale=.35, user-scalable=no")}; +BSUtils.init=function(){var a=BSUtils.isRtl();document.head.parentElement.setAttribute("dir",a?"rtl":"ltr");document.head.parentElement.setAttribute("lang",BSUtils.LANG);for(var a=[],b,c=0;cb[0]?1:a[0]screen.availWidth&&a.setAttribute("content","width=725, initial-scale=.35, user-scalable=no")}; BSUtils.initReadonly=function(){Blockly.inject(document.getElementById("blockly"),{path:"./",readOnly:!0,rtl:BSUtils.isRtl(),scrollbars:!1});var a=BSUtils.getStringParamFromUrl("xml",""),a=Blockly.Xml.textToDom(""+a+"");Blockly.Xml.domToWorkspace(Blockly.mainWorkspace,a)}; -BSUtils.loadBlocks=function(a){try{var d=window.sessionStorage.loadOnceBlocks}catch(e){d=null}"BlocklyStorage"in window&&1=d.length?"?lang="+a:d.match(/[?&]lang=[^&]*/)?d.replace(/([?&]lang=)[^&]*/,"$1"+a):d.replace(/\?/,"?lang="+a+"&");window.location=window.location.protocol+"//"+ -window.location.host+window.location.pathname+d};BSUtils.isDialogVisible_=!1;BSUtils.dialogOrigin_=null;BSUtils.dialogDispose_=null; -BSUtils.showDialog=function(a,d,e,h,m,k){function l(){BSUtils.isDialogVisible_&&(r.style.visibility="visible",r.style.zIndex=1,w.style.visibility="hidden")}BSUtils.isDialogVisible_&&BSUtils.hideDialog(!1);BSUtils.isDialogVisible_=!0;BSUtils.dialogOrigin_=d;BSUtils.dialogDispose_=k;var r=document.getElementById("dialog");k=document.getElementById("dialogShadow");var w=document.getElementById("dialogBorder"),n;for(n in m)r.style[n]=m[n];h&&(k.style.visibility="visible",k.style.opacity=.3,h=document.createElement("div"), -h.id="dialogHeader",r.appendChild(h),BSUtils.dialogMouseDownWrapper_=Blockly.bindEvent_(h,"mousedown",null,BSUtils.dialogMouseDown_));r.appendChild(a);a.className=a.className.replace("dialogHiddenContent","");e&&d?(BSUtils.matchBorder_(d,!1,.2),BSUtils.matchBorder_(r,!0,.8),window.setTimeout(l,175)):l()};BSUtils.dialogStartX_=0;BSUtils.dialogStartY_=0; -BSUtils.dialogMouseDown_=function(a){BSUtils.dialogUnbindDragEvents_();if(!Blockly.isRightButton(a)){var d=document.getElementById("dialog");BSUtils.dialogStartX_=d.offsetLeft-a.clientX;BSUtils.dialogStartY_=d.offsetTop-a.clientY;BSUtils.dialogMouseUpWrapper_=Blockly.bindEvent_(document,"mouseup",null,BSUtils.dialogUnbindDragEvents_);BSUtils.dialogMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",null,BSUtils.dialogMouseMove_);a.stopPropagation()}}; -BSUtils.dialogMouseMove_=function(a){var d=document.getElementById("dialog"),e=BSUtils.dialogStartX_+a.clientX;a=BSUtils.dialogStartY_+a.clientY;a=Math.max(a,0);a=Math.min(a,window.innerHeight-d.offsetHeight);e=Math.max(e,0);e=Math.min(e,window.innerWidth-d.offsetWidth);d.style.left=e+"px";d.style.top=a+"px"}; +BSUtils.loadBlocks=function(a){try{var b=window.sessionStorage.loadOnceBlocks}catch(c){b=null}"BlocklyStorage"in window&&1=b.length?"?lang="+a:b.match(/[?&]lang=[^&]*/)?b.replace(/([?&]lang=)[^&]*/,"$1"+a):b.replace(/\?/,"?lang="+a+"&");window.location=window.location.protocol+"//"+ +window.location.host+window.location.pathname+b};BSUtils.isDialogVisible_=!1;BSUtils.dialogOrigin_=null;BSUtils.dialogDispose_=null; +BSUtils.showDialog=function(a,b,c,d,e,g){function f(){BSUtils.isDialogVisible_&&(h.style.visibility="visible",h.style.zIndex=1,k.style.visibility="hidden")}BSUtils.isDialogVisible_&&BSUtils.hideDialog(!1);BSUtils.isDialogVisible_=!0;BSUtils.dialogOrigin_=b;BSUtils.dialogDispose_=g;var h=document.getElementById("dialog");g=document.getElementById("dialogShadow");var k=document.getElementById("dialogBorder"),l;for(l in e)h.style[l]=e[l];d&&(g.style.visibility="visible",g.style.opacity=.3,d=document.createElement("div"), +d.id="dialogHeader",h.appendChild(d),BSUtils.dialogMouseDownWrapper_=Blockly.bindEvent_(d,"mousedown",null,BSUtils.dialogMouseDown_));h.appendChild(a);a.className=a.className.replace("dialogHiddenContent","");c&&b?(BSUtils.matchBorder_(b,!1,.2),BSUtils.matchBorder_(h,!0,.8),window.setTimeout(f,175)):f()};BSUtils.dialogStartX_=0;BSUtils.dialogStartY_=0; +BSUtils.dialogMouseDown_=function(a){BSUtils.dialogUnbindDragEvents_();if(!Blockly.isRightButton(a)){var b=document.getElementById("dialog");BSUtils.dialogStartX_=b.offsetLeft-a.clientX;BSUtils.dialogStartY_=b.offsetTop-a.clientY;BSUtils.dialogMouseUpWrapper_=Blockly.bindEvent_(document,"mouseup",null,BSUtils.dialogUnbindDragEvents_);BSUtils.dialogMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",null,BSUtils.dialogMouseMove_);a.stopPropagation()}}; +BSUtils.dialogMouseMove_=function(a){var b=document.getElementById("dialog"),c=BSUtils.dialogStartX_+a.clientX;a=BSUtils.dialogStartY_+a.clientY;a=Math.max(a,0);a=Math.min(a,window.innerHeight-b.offsetHeight);c=Math.max(c,0);c=Math.min(c,window.innerWidth-b.offsetWidth);b.style.left=c+"px";b.style.top=a+"px"}; BSUtils.dialogUnbindDragEvents_=function(){BSUtils.dialogMouseUpWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseUpWrapper_),BSUtils.dialogMouseUpWrapper_=null);BSUtils.dialogMouseMoveWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseMoveWrapper_),BSUtils.dialogMouseMoveWrapper_=null)}; -BSUtils.hideDialog=function(a){function d(){h.style.visibility="hidden";m.style.visibility="hidden"}if(BSUtils.isDialogVisible_){BSUtils.dialogUnbindDragEvents_();BSUtils.dialogMouseDownWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseDownWrapper_),BSUtils.dialogMouseDownWrapper_=null);BSUtils.isDialogVisible_=!1;BSUtils.dialogDispose_&&BSUtils.dialogDispose_();BSUtils.dialogDispose_=null;var e=!1===a?null:BSUtils.dialogOrigin_;a=document.getElementById("dialog");var h=document.getElementById("dialogShadow"), -m=document.getElementById("dialogBorder");h.style.opacity=0;e?(BSUtils.matchBorder_(a,!1,.8),BSUtils.matchBorder_(e,!0,.2),window.setTimeout(d,175)):d();a.style.visibility="hidden";a.style.zIndex=-1;for((e=document.getElementById("dialogHeader"))&&e.parentNode.removeChild(e);a.firstChild;)e=a.firstChild,e.className+=" dialogHiddenContent",document.body.appendChild(e)}}; -BSUtils.matchBorder_=function(a,d,e){function h(){m.style.width=k.width+"px";m.style.height=k.height+"px";m.style.left=k.x+"px";m.style.top=k.y+"px";m.style.opacity=e}if(a){var m=document.getElementById("dialogBorder"),k=BSUtils.getBBox_(a);d?(m.className="dialogAnimate",window.setTimeout(h,1)):(m.className="",h());m.style.visibility="visible"}}; -BSUtils.getBBox_=function(a){var d=a.offsetHeight,e=a.offsetWidth,h=0,m=0;do h+=a.offsetLeft,m+=a.offsetTop,a=a.offsetParent;while(a);return{height:d,width:e,x:h,y:m}}; -BSUtils.storageAlert=function(a){var d=document.getElementById("containerStorage");d.textContent="";a=a.split("\n");for(var e=0;e$("#main").height()-$(".resizableDiv").height()&&$(".resizableDiv").height($("#main").height()-70);20>$("#main").width()-$(".resizableDiv").width()&&$(".resizableDiv").width($("#main").width()- +BSUtils.hideDialog=function(a){function b(){d.style.visibility="hidden";e.style.visibility="hidden"}if(BSUtils.isDialogVisible_){BSUtils.dialogUnbindDragEvents_();BSUtils.dialogMouseDownWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseDownWrapper_),BSUtils.dialogMouseDownWrapper_=null);BSUtils.isDialogVisible_=!1;BSUtils.dialogDispose_&&BSUtils.dialogDispose_();BSUtils.dialogDispose_=null;var c=!1===a?null:BSUtils.dialogOrigin_;a=document.getElementById("dialog");var d=document.getElementById("dialogShadow"), +e=document.getElementById("dialogBorder");d.style.opacity=0;c?(BSUtils.matchBorder_(a,!1,.8),BSUtils.matchBorder_(c,!0,.2),window.setTimeout(b,175)):b();a.style.visibility="hidden";a.style.zIndex=-1;for((c=document.getElementById("dialogHeader"))&&c.parentNode.removeChild(c);a.firstChild;)c=a.firstChild,c.className+=" dialogHiddenContent",document.body.appendChild(c)}}; +BSUtils.matchBorder_=function(a,b,c){function d(){e.style.width=g.width+"px";e.style.height=g.height+"px";e.style.left=g.x+"px";e.style.top=g.y+"px";e.style.opacity=c}if(a){var e=document.getElementById("dialogBorder"),g=BSUtils.getBBox_(a);b?(e.className="dialogAnimate",window.setTimeout(d,1)):(e.className="",d());e.style.visibility="visible"}}; +BSUtils.getBBox_=function(a){var b=a.offsetHeight,c=a.offsetWidth,d=0,e=0;do d+=a.offsetLeft,e+=a.offsetTop,a=a.offsetParent;while(a);return{height:b,width:c,x:d,y:e}}; +BSUtils.storageAlert=function(a){var b=document.getElementById("containerStorage");b.textContent="";a=a.split("\n");for(var c=0;c$("#main").height()-$(".resizableDiv").height()&&$(".resizableDiv").height($("#main").height()-70);20>$("#main").width()-$(".resizableDiv").width()&&$(".resizableDiv").width($("#main").width()- 20);$(".resizableDiv").position({of:$("#main"),my:"right top",at:"right top",offset:"-12 -55"})},!1);Blockscad.workspace=Blockly.inject(document.getElementById("blocklyDiv"),{media:"blockly/media/",zoom:{enabled:!0,scaleSpeed:1.1,controls:!0},trashcan:!1,toolbox:Blockscad.Toolbox.adv});Blockscad.Toolbox.setColorScheme(Blockscad.Toolbox.colorScheme.one);Blockscad.Toolbox.setCatColors();$("#advancedToolbox").hide();BSUtils.loadBlocks("");"BlocklyStorage"in window&&BlocklyStorage.backupOnUnload();$(".resizableDiv").resizable({handles:"s,w,sw", -resize:function(a,d){var m=$(window).height();gProcessor&&(m=gProcessor.viewerdiv.offsetHeight,gProcessor.viewer.rendered_resize(gProcessor.viewerdiv.offsetWidth,m));20>$("#main").width()-d.size.width&&(d.size.width=$("#main").width()-20);70>$("#main").height()-d.size.height&&(d.size.height=$("#main").height()-70);d.position.left=$(window).width()-(d.size.width+12);d.position.top=55}});Blockly.fireUiEvent(window,"resize");Blockscad.offline||Blockscad.Auth.init();BSUtils.bindClick("trashButton",function(){Blockscad.discard()}); -BSUtils.bindClick("renderButton",Blockscad.doRender);BSUtils.bindClick("undoButton",Blockscad.onUndo);BSUtils.bindClick("redoButton",Blockscad.onRedo);$("#axesButton").click(function(){Blockscad.drawAxes=(Blockscad.drawAxes+1)%2;$("#axesButton").toggleClass("btn-pushed");gProcessor.viewer.onDraw()});$("#displayCode").click(function(){var a=document.getElementById("openScadPre"),d=Blockly.OpenSCAD.workspaceToCode(Blockscad.workspace);a.textContent=d;"function"==typeof prettyPrintOne&&(d=a.innerHTML, -d=prettyPrintOne(d,"js"),a.innerHTML=d);Blockly.fireUiEvent(window,"resize")});$("#renderButton").prop("disabled",!0);$("#throw-it-away").click(Blockscad.clearProject);$("#main").on("click",".new-project",Blockscad.newProject);Blockscad.readStlFile=function(a){var d=a.target.files[0];d?(a=new FileReader,a.onload=function(a){a=importSTL(a.target.result);var e=a[0];(a=a[1])||(a="blah");for(var l=d.name.substr(0,d.name.lastIndexOf("("))||d.name,l=l.substr(0,d.name.lastIndexOf("."))||l,r=l=l.replace(/^\s+|\s+$/g, -""),w=1,n=0;Blockscad.csg_commands[r]&&!n;)e!=Blockscad.csg_commands[r]?(r=l+"_"+w,w++):n=1;Blockscad.csg_commands[r]=e;Blockscad.csg_filename[r]=n?Blockscad.csg_filename[r]+(d.name+":::"):d.name+":::";Blockscad.csg_center[r]=a;Blockscad.currentInterestingBlock?(l=Blockscad.currentInterestingBlock.getField("STL_FILENAME"),e=Blockscad.currentInterestingBlock.getField("STL_BUTTON"),w=Blockscad.currentInterestingBlock.getField("STL_CONTENTS"),l.setText(d.name),l.setVisible(!0),e.setVisible(!1),w.setText(r), -Blockscad.currentInterestingBlock.setCommentText(d.name+"\ncenter:("+a+")"),Blockscad.currentInterestingBlock=null):(r=Blockly.Xml.textToDom(''+d.name+'Browse'+r+""),r=Blockly.Xml.domToBlock(Blockscad.workspace,r.firstChild),e=r.getField("STL_BUTTON"),e.setVisible(!1),r.setCommentText(d.name+"\ncenter:("+ -a+")"),r.render())},a.readAsBinaryString(d),$("#importStl")[0].value="",$("#displayBlocks").click(),$("#renderButton").prop("disabled",!1)):alert("Failed to load file")};$("#file-menu").on("change","#loadLocal",function(d){a(d,!0)});$("#file-menu").on("change","#importLocal",function(d){a(d,!1)});$("#file-menu").on("change","#importStl",function(a){Blockscad.readStlFile(a)});gProcessor=new Blockscad.Processor(document.getElementById("renderDiv"));BSUtils.bindClick("viewReset",Blockscad.resetView); +resize:function(a,b){var e=$(window).height();gProcessor&&(e=gProcessor.viewerdiv.offsetHeight,gProcessor.viewer.rendered_resize(gProcessor.viewerdiv.offsetWidth,e));20>$("#main").width()-b.size.width&&(b.size.width=$("#main").width()-20);70>$("#main").height()-b.size.height&&(b.size.height=$("#main").height()-70);b.position.left=$(window).width()-(b.size.width+12);b.position.top=55}});Blockly.fireUiEvent(window,"resize");Blockscad.offline||Blockscad.Auth.init();BSUtils.bindClick("trashButton",function(){Blockscad.discard()}); +BSUtils.bindClick("renderButton",Blockscad.doRender);BSUtils.bindClick("undoButton",Blockscad.onUndo);BSUtils.bindClick("redoButton",Blockscad.onRedo);$("#axesButton").click(function(){Blockscad.drawAxes=(Blockscad.drawAxes+1)%2;$("#axesButton").toggleClass("btn-pushed");gProcessor.viewer.toggleAxes()});$("#displayCode").click(function(){var a=document.getElementById("openScadPre"),b=Blockly.OpenSCAD.workspaceToCode(Blockscad.workspace);a.textContent=b;"function"==typeof prettyPrintOne&&(b=a.innerHTML, +b=prettyPrintOne(b,"js"),a.innerHTML=b);Blockly.fireUiEvent(window,"resize")});$("#renderButton").prop("disabled",!0);$("#throw-it-away").click(Blockscad.clearProject);$("#main").on("click",".new-project",Blockscad.newProject);Blockscad.readStlFile=function(a){var b=a.target.files[0];b?(a=new FileReader,a.onload=function(a){a=importSTL(a.target.result);var c=a[0];(a=a[1])||(a="blah");for(var f=b.name.substr(0,b.name.lastIndexOf("("))||b.name,f=f.substr(0,b.name.lastIndexOf("."))||f,h=f=f.replace(/^\s+|\s+$/g, +""),k=1,l=0;Blockscad.csg_commands[h]&&!l;)c!=Blockscad.csg_commands[h]?(h=f+"_"+k,k++):l=1;Blockscad.csg_commands[h]=c;Blockscad.csg_filename[h]=l?Blockscad.csg_filename[h]+(b.name+":::"):b.name+":::";Blockscad.csg_center[h]=a;Blockscad.currentInterestingBlock?(f=Blockscad.currentInterestingBlock.getField("STL_FILENAME"),c=Blockscad.currentInterestingBlock.getField("STL_BUTTON"),k=Blockscad.currentInterestingBlock.getField("STL_CONTENTS"),f.setText(b.name),f.setVisible(!0),c.setVisible(!1),k.setText(h), +Blockscad.currentInterestingBlock.setCommentText(b.name+"\ncenter:("+a+")"),Blockscad.currentInterestingBlock=null):(h=Blockly.Xml.textToDom(''+b.name+'Browse'+h+""),h=Blockly.Xml.domToBlock(Blockscad.workspace,h.firstChild),c=h.getField("STL_BUTTON"),c.setVisible(!1),h.setCommentText(b.name+"\ncenter:("+ +a+")"),h.render())},a.readAsBinaryString(b),$("#importStl")[0].value="",$("#displayBlocks").click(),$("#renderButton").prop("disabled",!1)):alert("Failed to load file")};$("#file-menu").on("change","#loadLocal",function(b){a(b,!0)});$("#file-menu").on("change","#importLocal",function(b){a(b,!1)});$("#file-menu").on("change","#importStl",function(a){Blockscad.readStlFile(a)});gProcessor=new Blockscad.Processor(document.getElementById("renderDiv"));BSUtils.bindClick("viewReset",Blockscad.resetView); Blockscad.undo={blockList:[],oldBlockList:[],undoStack:[],redoStack:[],current_xml:null,blockCount:0,yesthis:0,fieldChanging:0,blockIds:[],fieldValues:[],parentIds:[],oldBlockIds:[],oldFieldValues:[],oldParentIds:[],just_did_undo:0};Blockscad.workspace.addUndoListener(Blockscad.workspaceChanged);Blockscad.offline||Blockscad.Auth.checkForUser();$("#help-menu").on("click","#about",function(){$("#about-modal").modal("show")});$("#file-menu").on("click","#saveLocal",Blockscad.saveBlocksLocal);$("#simpleToolbox").on("click", function(){console.log("switching to simple toolbox");$("#simpleToolbox").hide();$("#advancedToolbox").show();Blockscad.workspace&&(Blockscad.Toolbox.catIDs=[],Blockscad.workspace.updateToolbox(Blockscad.Toolbox.sim),Blockscad.Toolbox.setCatColors())});$("#advancedToolbox").on("click",function(){console.log("switching to advanced toolbox");$("#advancedToolbox").hide();$("#simpleToolbox").show();Blockscad.workspace&&(Blockscad.Toolbox.catIDs=[],Blockscad.workspace.updateToolbox(Blockscad.Toolbox.adv), Blockscad.Toolbox.setCatColors())});$("#colors_one").on("click",function(){console.log("switching block color scheme");Blockscad.workspace&&(Blockscad.Toolbox.setColorScheme(Blockscad.Toolbox.colorScheme.one),Blockscad.Toolbox.setCatColors(),Blockscad.workspace.clear(),Blockly.Xml.domToWorkspace(Blockscad.workspace,Blockscad.undo.current_xml))});$("#colors_two").on("click",function(){console.log("switching block color scheme");Blockscad.workspace&&(Blockscad.Toolbox.setColorScheme(Blockscad.Toolbox.colorScheme.two), -Blockscad.Toolbox.setCatColors(),Blockscad.workspace.clear(),Blockly.Xml.domToWorkspace(Blockscad.workspace,Blockscad.undo.current_xml))});$(function(){$(".dropdown-menu > li > a.trigger").on("click",function(a){var d=$(this).next(),m=$(this).parent().parent();($(this).hasClass("left-caret")||$(this).hasClass("right-caret"))&&$(this).toggleClass("right-caret left-caret");m.find(".left-caret").not(this).toggleClass("right-caret left-caret");m.find(".sub-menu:visible").not(d).hide();d.toggle();a.stopPropagation()}); +Blockscad.Toolbox.setCatColors(),Blockscad.workspace.clear(),Blockly.Xml.domToWorkspace(Blockscad.workspace,Blockscad.undo.current_xml))});$(function(){$(".dropdown-menu > li > a.trigger").on("click",function(a){var b=$(this).next(),e=$(this).parent().parent();($(this).hasClass("left-caret")||$(this).hasClass("right-caret"))&&$(this).toggleClass("right-caret left-caret");e.find(".left-caret").not(this).toggleClass("right-caret left-caret");e.find(".sub-menu:visible").not(b).hide();b.toggle();a.stopPropagation()}); $(".dropdown-menu > li > a:not(.trigger)").on("click",function(){var a=$(this).closest(".dropdown");a.find(".left-caret").toggleClass("right-caret left-caret");a.find(".sub-menu:visible").hide()})})};document.write('