- /**
-
- Helper that visualizes the position and direction of a plane.
-
- @class ClipControl
- @constructor
- @param cfg {*} Configuration
- @param [cfg.pos=[0,0,0]] {Float32Array} World-space position.
- @param [cfg.dir=[0,0,1]] {Float32Array} World-space direction vector.
- @param [cfg.color=[0.4,0.4,0.4]] {Float32Array} Emmissive color
- @param [cfg.solid=true] {Boolean} Indicates whether or not this helper is filled with color or just wireframe.
- @param [cfg.visible=true] {Boolean} Indicates whether or not this helper is visible.
- @param [cfg.planeSize] {Float32Array} The width and height of the ClipControl plane indicator.
- @param [cfg.autoPlaneSize=false] {Boolean} Indicates whether or not this ClipControl's
- {{#crossLink "ClipControl/planeSize:property"}}{{/crossLink}} is automatically sized to fit within
- the {{#crossLink "Scene/aabb:property"}}Scene's boundary{{/crossLink}}.
- */
- (function () {
-
- "use strict";
-
- xeogl.ClipControl = xeogl.Component.extend({
-
- type: "xeogl.ClipControl",
-
- _init: function (cfg) {
-
- this._solid = false;
- this._visible = false;
- this._clipStartDir = xeogl.math.vec3();
- this._clipPos = xeogl.math.vec3();
-
- this._gumballGroup = null;
- this._planeScale = null;
-
- this._initEntities();
-
- this.planeSize = cfg.planeSize;
- this.autoPlaneSize = cfg.autoPlaneSize;
- this.color = cfg.color;
- this.solid = cfg.solid;
- this.clip = cfg.clip;
- this.visible = cfg.visible;
- this.active = true;
-
- this._initEvents();
- },
-
- _update: (function () {
- var arrowPositions = new Float32Array(6);
- return function () {
-
- var pos = this._pos;
- var dir = this._dir;
-
- // Rebuild arrow geometry
-
- arrowPositions[0] = pos[0];
- arrowPositions[1] = pos[1];
- arrowPositions[2] = pos[2];
- arrowPositions[3] = pos[0] + dir[0];
- arrowPositions[4] = pos[1] + dir[1];
- arrowPositions[5] = pos[2] + dir[2];
-
- //this._display.arrow.geometry.positions = arrowPositions;
- }
- })(),
-
- _props: {
-
- /**
- Indicates whether this ClipControl is active or not.
-
- @property active
- @default true
- @type Boolean
- */
- active: {
- set: function (value) {
- value = value !== false;
- if (value === this._active) {
- return;
- }
- this._active = value;
- },
- get: function () {
- return this._active;
- }
- },
-
- /**
- The {{#crossLink "Clip"}}{{/crossLink}} attached to this ClipControl.
-
- @property clip
- @type Clip
- */
- clip: {
- set: function (value) {
- var self = this;
- this._attach({name: "clip", type: "xeogl.Clip", component: value});
- var clip = this._attached.clip;
- if (clip) { // Reset rotation and translation basis
- this._setGumballDir(clip.dir);
- this._setGumballPos(clip.pos);
- }
- },
- get: function () {
- return this._attached.clip;
- }
- },
-
- /**
- * The width and height of the ClipControl plane indicator.
- *
- * Values assigned to this property will be overridden by an auto-computed value when
- * {{#crossLink "ClipControl/autoPlaneSize:property"}}{{/crossLink}} is true.
- *
- * @property planeSize
- * @default [1,1]
- * @type {Float32Array}
- */
- planeSize: {
- set: function (value) {
- (this._planeSize = this._planeSize || new xeogl.math.vec2()).set(value || [1, 1]);
- // this._planeScale.xyz = [this._planeSize[0], this._planeSize[1], 1.0];
- },
- get: function () {
- return this._planeSize;
- }
- },
-
- /**
- * Indicates whether this ClipControl's {{#crossLink "ClipControl/planeSize:property"}}{{/crossLink}} is automatically
- * generated or not.
- *
- * When auto-generated, {{#crossLink "ClipControl/planeSize:property"}}{{/crossLink}} will automatically size
- * to fit within the {{#crossLink "Scene/aabb:property"}}Scene's boundary{{/crossLink}}.
- *
- * @property autoPlaneSize
- * @default false
- * @type {Boolean}
- */
- autoPlaneSize: {
- set: function (value) {
- value = !!value;
- if (this._autoPlaneSize === value) {
- return;
- }
- this._autoPlaneSize = value;
- if (this._autoPlaneSize) {
- if (!this._onSceneAABB) {
- this._onSceneAABB = this.scene.on("boundary", function () {
- var aabbDiag = xeogl.math.getAABB3Diag(this.scene.aabb);
- var clipSize = (aabbDiag * 0.50);
- this.planeSize = [clipSize, clipSize];
- }, this);
- }
- } else {
- if (this._onSceneAABB) {
- this.scene.off(this._onSceneAABB);
- this._onSceneAABB = null;
- }
- }
- },
- get: function () {
- return this._autoPlaneSize;
- }
- },
-
- /**
- * Emissive color of this ClipControl.
- *
- * @property color
- * @default [0.4,0.4,0.4]
- * @type {Float32Array}
- */
- color: {
- set: function (value) {
- (this._color = this._color || new xeogl.math.vec3()).set(value || [0.4, 0.4, 0.4]);
- this._display.planeWire.material.emissive = this._color;
- },
- get: function () {
- return this._color;
- }
- },
-
- /**
- Indicates whether this ClipControl is filled with color or just wireframe.
-
- @property solid
- @default true
- @type Boolean
- */
- solid: {
- set: function (value) {
- this._solid = value !== false;
- this._display.planeSolid.visible = this._solid && this._visible;
- },
- get: function () {
- return this._solid;
- }
- },
-
- /**
- * Visibility of this ClipControl.
- *
- * @property visible
- * @type Boolean
- * @default true
- */
- visible: {
- set: function (value) {
- value = !!value;
- if (this._visible === value) {
- return;
- }
- this._visible = value;
- for (var id in this._display) {
- if (this._display.hasOwnProperty(id)) {
- this._display[id].visible = value;
- }
- }
- },
- get: function () {
- return this._visible;
- }
- }
- },
-
- _setGumballPos: function (xyz) {
- this._clipPos.set(xyz);
- this._gumballGroup.position = xyz;
- },
-
- _setGumballDir: (function () {
- var zeroVec = new Float32Array([0, 0, 1]);
- var quat = new Float32Array(4);
- return function (xyz) {
- this._clipStartDir.set(xyz);
- xeogl.math.vec3PairToQuaternion(zeroVec, xyz, quat);
- this._gumballGroup.quaternion = quat;
- };
- })(),
-
- _initEntities: function () {
-
- // Option for xeogl.Group.addChild(), to prevent child xeogl.Objects from inheriting
- // state from their parent xeogl.Group, such as 'pickable', 'visible', 'collidable' etc.
- // Although, the children's transforms are relative to the xeogl.Group.
- const DONT_INHERIT_GROUP_STATE = false;
-
- // Positions, rotates & scales all Meshes as a group;
- // Meshes still have their relative transforms.
- var gumballGroup = this._gumballGroup = new xeogl.Group(this, {
- //scale: [10, 10, 0],
- position: [0, 0, 0]
- });
-
- var radius = 1.2;
- var hoopRadius = radius - 0.2;
-
- var geometries = {
-
- arrowHead: new xeogl.CylinderGeometry(this, {
- radiusTop: 0.001,
- radiusBottom: 0.10,
- height: 0.2,
- radialSegments: 16,
- heightSegments: 1,
- openEnded: false
- }),
- curve: new xeogl.TorusGeometry(this, {
- radius: hoopRadius,
- tube: 0.0175,
- radialSegments: 64,
- tubeSegments: 14,
- arc: (Math.PI * 2.0) / 4.0
- }),
- hoop: new xeogl.TorusGeometry(this, {
- radius: hoopRadius,
- tube: 0.0175,
- radialSegments: 64,
- tubeSegments: 8,
- arc: (Math.PI * 2.0)
- }),
- curvePickable: new xeogl.TorusGeometry(this, {
- radius: hoopRadius,
- tube: 0.06,
- radialSegments: 64,
- tubeSegments: 14,
- arc: (Math.PI * 2.0) / 4.0
- }),
- axis: new xeogl.CylinderGeometry(scene, {
- radiusTop: 0.0175,
- radiusBottom: 0.0175,
- height: radius,
- radialSegments: 20,
- heightSegments: 1,
- openEnded: false
- })
- };
-
- var materials = {
- pickable: new xeogl.PhongMaterial(this, {
- diffuse: [1, 1, 0],
- alpha: 0, // Invisible
- alphaMode: "blend"
- }),
- red: new xeogl.PhongMaterial(scene, {
- diffuse: [1, 0.3, 0.3],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2
- }),
- transparentRed: new xeogl.PhongMaterial(scene, {
- diffuse: [1, 0.3, 0.3],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2,
- alpha: 0.6,
- alphaMode: "blend"
- }),
- highlightRed: new xeogl.GhostMaterial(scene, {
- edges: false,
- fill: true,
- fillColor: [1, 0, 0],
- fillAlpha: 0.5,
- vertices: false
- }),
- labelRed: new xeogl.PhongMaterial(scene, {
- emissive: [1, 0.3, 0.3],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 3
- }),
- green: new xeogl.PhongMaterial(scene, {
- diffuse: [0.3, 1, 0.3],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2
- }),
- highlightGreen: new xeogl.GhostMaterial(scene, {
- edges: false,
- fill: true,
- fillColor: [0, 1, 0],
- fillAlpha: 0.5,
- vertices: false
- }),
- transparentGreen: new xeogl.PhongMaterial(scene, {
- diffuse: [0.3, 1.0, 0.3],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2,
- alpha: 0.4,
- alphaMode: "blend"
- }),
- labelGreen: new xeogl.PhongMaterial(scene, { // Green by convention
- emissive: [0.3, 1, 0.3],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 3
- }),
- blue: new xeogl.PhongMaterial(scene, { // Blue by convention
- diffuse: [0.3, 0.3, 1],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2
- }),
- highlightBlue: new xeogl.GhostMaterial(scene, {
- edges: false,
- fill: true,
- fillColor: [0, 0, 1],
- fillAlpha: 0.5,
- vertices: false
- }),
- transparentBlue: new xeogl.PhongMaterial(scene, {
- diffuse: [0.3, 0.3, 1.0],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2,
- alpha: 0.4,
- alphaMode: "blend"
- }),
- labelBlue: new xeogl.PhongMaterial(scene, {
- emissive: [0.3, 0.3, 1],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 3
- }),
- ball: new xeogl.PhongMaterial(scene, {
- diffuse: [0.5, 0.5, 0.5],
- ambient: [0.0, 0.0, 0.0],
- specular: [.6, .6, .3],
- shininess: 80,
- lineWidth: 2
- }),
- highlightBall: new xeogl.GhostMaterial(scene, {
- edges: false,
- fill: true,
- fillColor: [0.5, 0.5, 0.5],
- fillAlpha: 0.5,
- vertices: false
- }),
- highlightPlane: new xeogl.GhostMaterial(scene, {
- edges: true,
- edgeWidth: 3,
- fill: false,
- fillColor: [0.5, 0.5, .5],
- fillAlpha: 0.5,
- vertices: false
- })
- };
-
- this._display = {
- planeWire: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: new xeogl.Geometry(this, {
- primitive: "lines",
- positions: [
- 1.1, 1.1, 0.0, 1.1, -1.1, 0.0, // 0
- -1.1, -1.1, 0.0, -1.1, 1.1, 0.0, // 1
- 1.1, 1.1, -0.0, 1.1, -1.1, -0.0, // 2
- -1.1, -1.1, -0.0, -1.1, 1.1, -0.0 // 3
- ],
- indices: [0, 1, 0, 3, 1, 2, 2, 3]
- }),
- highlight: true,
- highlightMaterial: materials.highlightPlane,
- material: new xeogl.PhongMaterial(this, {
- emissive: [1, 0, 0],
- diffuse: [0, 0, 0],
- lineWidth: 2
- }),
- pickable: false,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- planeSolid: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: new xeogl.Geometry(this, {
- primitive: "triangles",
- positions: [
- 1.1, 1.1, 0.0, 1.1, -1.1, 0.0, // 0
- -1.1, -1.1, 0.0, -1.1, 1.1, 0.0, // 1
- 1.1, 1.1, -0.0, 1.1, -1.1, -0.0, // 2
- -1.1, -1.1, -0.0, -1.1, 1.1, -0.0 // 3
- ],
- indices: [0, 1, 2, 2, 3, 0]
- }),
- highlight: true,
- highlightMaterial: materials.highlightPlane,
- material: new xeogl.PhongMaterial(this, {
- emissive: [0, 0, 0],
- diffuse: [0, 0, 0],
- specular: [1, 1, 1],
- shininess: 120,
- alpha: 0.3,
- alphaMode: "blend",
- backfaces: true
- }),
- pickable: false,
- collidable: true,
- clippable: false,
- backfaces: true
- }), DONT_INHERIT_GROUP_STATE),
-
- xRedCurve: gumballGroup.addChild(new xeogl.Mesh(this, { // Red hoop about Y-axis
- geometry: geometries.curve,
- material: materials.red,
- highlight: true,
- highlightMaterial: materials.highlightRed,
- matrix: (function () {
- var rotate2 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [0, 1, 0], xeogl.math.identityMat4());
- var rotate1 = xeogl.math.rotationMat4v(270 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate1, rotate2, xeogl.math.identityMat4());
- })(),
- pickable: false,
- collidable: true,
- clippable: false,
- backfaces: true
- }), DONT_INHERIT_GROUP_STATE),
-
- xRedCurvePickable: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.curvePickable,
- material: materials.pickable,
- matrix: (function () {
- var rotate2 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [0, 1, 0], xeogl.math.identityMat4());
- var rotate1 = xeogl.math.rotationMat4v(270 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate1, rotate2, xeogl.math.identityMat4());
- })(),
- pickable: true,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
-
-
- yGreenCurve: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.curve,
- material: materials.green,
- highlight: true,
- highlightMaterial: materials.highlightGreen,
- rotation: [-90, 0, 0],
- pickable: false,
- collidable: true,
- clippable: false,
- backfaces: true
- }), DONT_INHERIT_GROUP_STATE),
-
- yGreenCurvePickable: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.curvePickable,
- material: materials.pickable,
- rotation: [-90, 0, 0],
- pickable: true,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- zBlueCurve: gumballGroup.addChild(new xeogl.Mesh(this, { // Blue hoop about Z-axis
- geometry: geometries.curve,
- material: materials.blue,
- highlight: true,
- highlightMaterial: materials.highlightBlue,
- matrix: (function () {
- var rotate2 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- var rotate1 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate2, rotate1, xeogl.math.identityMat4());
- })(),
- pickable: false,
- collidable: true,
- clippable: false,
- backfaces: true
- }), DONT_INHERIT_GROUP_STATE),
-
- zBlueCurvePickable: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.curvePickable,
- material: materials.pickable,
-
- matrix: (function () {
- var rotate2 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- var rotate1 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate2, rotate1, xeogl.math.identityMat4());
- })(),
- pickable: true,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- ball: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: new xeogl.SphereGeometry(this, {
- radius: 0.05
- }),
- highlight: true,
- highlightMaterial: materials.highlightBall,
- material: materials.ball,
- pickable: false,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- xRedArrow: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.arrowHead,
- material: materials.red,
- highlight: true,
- highlightMaterial: materials.highlightRed,
- matrix: (function () {
- var translate = xeogl.math.translateMat4c(0, radius + .1, 0, xeogl.math.identityMat4());
- var rotate = xeogl.math.rotationMat4v(-90 * xeogl.math.DEGTORAD, [0, 0, 1], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate, translate, xeogl.math.identityMat4());
- })(),
- pickable: true,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- xRedShaft: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.axis,
- material: materials.red,
- highlight: true,
- highlightMaterial: materials.highlightRed,
- matrix: (function () {
- var translate = xeogl.math.translateMat4c(0, radius / 2, 0, xeogl.math.identityMat4());
- var rotate = xeogl.math.rotationMat4v(-90 * xeogl.math.DEGTORAD, [0, 0, 1], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate, translate, xeogl.math.identityMat4());
- })(),
- pickable: false,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- yGreenArrow: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.arrowHead,
- material: materials.green,
- highlight: true,
- highlightMaterial: materials.highlightGreen,
- matrix: (function () {
- var translate = xeogl.math.translateMat4c(0, radius + .1, 0, xeogl.math.identityMat4());
- var rotate = xeogl.math.rotationMat4v(180 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate, translate, xeogl.math.identityMat4());
- })(),
- pickable: true,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- yGreenShaft: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.axis,
- material: materials.green,
- highlight: true,
- highlightMaterial: materials.highlightGreen,
- position: [0, -radius / 2, 0],
- pickable: false,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- zBlueArrow: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.arrowHead,
- material: materials.blue,
- highlight: true,
- highlightMaterial: materials.highlightBlue,
- matrix: (function () {
- var translate = xeogl.math.translateMat4c(0, radius + .1, 0, xeogl.math.identityMat4());
- var rotate = xeogl.math.rotationMat4v(-90 * xeogl.math.DEGTORAD, [0.8, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate, translate, xeogl.math.identityMat4());
- })(),
- pickable: true,
- collidable: true,
- clippable: false
- }), DONT_INHERIT_GROUP_STATE),
-
- zBlueShaft: gumballGroup.addChild(new xeogl.Mesh(this, {
- geometry: geometries.axis,
- material: materials.blue,
- highlight: true,
- highlightMaterial: materials.highlightBlue,
- matrix: (function () {
- var translate = xeogl.math.translateMat4c(0, radius / 2, 0, xeogl.math.identityMat4());
- var rotate = xeogl.math.rotationMat4v(-90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate, translate, xeogl.math.identityMat4());
- })(),
- clippable: false,
- pickable: false,
- collidable: true
- }), DONT_INHERIT_GROUP_STATE)
- };
-
- this._hoops = {
-
- xHoop: gumballGroup.addChild(new xeogl.Mesh(this, { // Red hoop about Y-axis
- geometry: geometries.hoop,
- material: materials.transparentRed,
- highlight: true,
- highlightMaterial: materials.highlightRed,
- matrix: (function () {
- var rotate2 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [0, 1, 0], xeogl.math.identityMat4());
- var rotate1 = xeogl.math.rotationMat4v(270 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate1, rotate2, xeogl.math.identityMat4());
- })(),
- pickable: false,
- collidable: true,
- clippable: false,
- visible: false
- }), DONT_INHERIT_GROUP_STATE),
-
- yHoop: gumballGroup.addChild(new xeogl.Mesh(this, { // Green hoop about Y-axis
- geometry: geometries.hoop,
- material: materials.transparentGreen,
- highlight: true,
- highlightMaterial: materials.highlightGreen,
- rotation: [-90, 0, 0],
- pickable: false,
- collidable: true,
- clippable: false,
- visible: false
- }), DONT_INHERIT_GROUP_STATE),
-
- zHoop: gumballGroup.addChild(new xeogl.Mesh(this, { // Blue hoop about Z-axis
- geometry: geometries.hoop,
- material: materials.transparentBlue,
- highlight: true,
- highlightMaterial: materials.highlightBlue,
- matrix: (function () {
- var rotate2 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- var rotate1 = xeogl.math.rotationMat4v(90 * xeogl.math.DEGTORAD, [1, 0, 0], xeogl.math.identityMat4());
- return xeogl.math.mulMat4(rotate2, rotate1, xeogl.math.identityMat4());
- })(),
- pickable: false,
- collidable: true,
- clippable: false,
- visible: false
- }), DONT_INHERIT_GROUP_STATE)
- };
- },
-
- _initEvents: function () {
-
- var self = this;
- var scene = this.scene;
- var math = xeogl.math;
- var canvas = this.scene.canvas.canvas;
- var over = false;
-
- const DRAG_ACTIONS = {
- none: -1,
- xPan: 0,
- yPan: 1,
- zPan: 2,
- xRotate: 3,
- yRotate: 4,
- zRotate: 5
- };
-
- var nextDragAction = null; // As we hover over an arrow or hoop, self is the action we would do if we then dragged it.
- var dragAction = null; // Action we're doing while we drag an arrow or hoop.
-
- var lastMouse = math.vec2();
-
- var xLocalAxis = math.vec3([1, 0, 0]);
- var yLocalAxis = math.vec3([0, 1, 0]);
- var zLocalAxis = math.vec3([0, 0, 1]);
-
- canvas.oncontextmenu = function (e) {
- e.preventDefault();
- };
-
- var getClickCoordsWithinElement = (function () {
- var coords = new Float32Array(2);
- return function (event) {
- if (!event) {
- event = window.event;
- coords[0] = event.x;
- coords[a] = event.y;
- } else {
- var element = event.target;
- var totalOffsetLeft = 0;
- var totalOffsetTop = 0;
-
- while (element.offsetParent) {
- totalOffsetLeft += element.offsetLeft;
- totalOffsetTop += element.offsetTop;
- element = element.offsetParent;
- }
- coords[0] = event.pageX - totalOffsetLeft;
- coords[1] = event.pageY - totalOffsetTop;
- }
- return coords;
- };
- })();
-
- var localToWorldVec = (function () {
- var math = xeogl.math;
- var mat = math.mat4();
- return function (localVec, worldVec) {
- math.quaternionToMat4(self._gumballGroup.quaternion, mat);
- math.transformVec3(mat, localVec, worldVec);
- math.normalizeVec3(worldVec);
- return worldVec;
- };
- })();
-
- var pan = (function() {
- var p1 = math.vec3();
- var p2 = math.vec3();
- var worldAxis = math.vec4();
-
- return function (localAxis, fromMouse, toMouse) {
- localToWorldVec(localAxis, worldAxis);
-
- var planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse);
-
- getMouseVectorOnPlane(fromMouse, planeNormal, p1);
- getMouseVectorOnPlane(toMouse, planeNormal, p2);
-
- math.subVec3(p2, p1);
-
- var dot = math.dotVec3(p2, worldAxis);
-
- self._clipPos[0] += worldAxis[0] * dot;
- self._clipPos[1] += worldAxis[1] * dot;
- self._clipPos[2] += worldAxis[2] * dot;
-
- self._gumballGroup.position = self._clipPos;
- if (self._attached.clip) {
- self._attached.clip.pos = self._clipPos;
- }
- }
- })();
-
- var getTranslationPlane = (function() {
- var planeNormal = math.vec3();
- return function(worldAxis) {
- // find a best fit to find intersections with
- var absX = Math.abs(worldAxis.x);
- if (absX > Math.abs(worldAxis.y) && absX > Math.abs(worldAxis.z))
- math.cross3Vec3(worldAxis, [0, 1, 0], planeNormal);
- else
- math.cross3Vec3(worldAxis, [1, 0, 0], planeNormal);
-
- math.cross3Vec3(planeNormal, worldAxis, planeNormal);
-
- math.normalizeVec3(planeNormal);
- return planeNormal;
- }
- })();
-
- var rotate = (function() {
- var p1 = math.vec4();
- var p2 = math.vec4();
- var c = math.vec4();
- var worldAxis = math.vec4();
-
- return function (localAxis, fromMouse, toMouse) {
- localToWorldVec(localAxis, worldAxis);
-
- var dot;
- var hasData = getMouseVectorOnPlane(fromMouse, worldAxis, p1);
- hasData = hasData && getMouseVectorOnPlane(toMouse, worldAxis, p2);
-
- if (!hasData) {
- // find intersections with view plane and project down to origin
- var planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse);
-
- // the "1" makes sure the plane moves closer to the camera a bit, so the angles become workable
- getMouseVectorOnPlane(fromMouse, planeNormal, p1, 1);
- getMouseVectorOnPlane(toMouse, planeNormal, p2, 1);
- dot = math.dotVec3(p1, worldAxis);
- p1[0] -= dot * worldAxis[0];
- p1[1] -= dot * worldAxis[1];
- p1[2] -= dot * worldAxis[2];
-
- dot = math.dotVec3(p2, worldAxis);
- p2[0] -= dot * worldAxis[0];
- p2[1] -= dot * worldAxis[1];
- p2[2] -= dot * worldAxis[2];
- }
-
- math.normalizeVec3(p1);
- math.normalizeVec3(p2);
-
- dot = math.dotVec3(p1, p2);
- // rounding errors can cause the dot to exceed its allowed range
- dot = math.clamp(dot, -1.0, 1.0);
- var incDegrees = Math.acos(dot) * math.RADTODEG;
-
- // console.log(incDegrees);
- math.cross3Vec3(p1, p2, c);
- // test orientation of cross with actual axis
- if (math.dotVec3(c, worldAxis) < 0.0)
- incDegrees = -incDegrees;
-
- self._gumballGroup.rotate(localAxis, incDegrees);
- rotateClip();
- }})();
-
- // this returns the vector that points from the gumball origin to where the mouse ray intersects the plane
- var getMouseVectorOnPlane = (function() {
- var dir = math.vec4([0, 0, 0, 1]);
- var matrix = math.mat4();
-
- return function(mouse, axis, dest, offset) {
- offset = offset || 0;
- dir[0] = mouse[0] / canvas.width * 2.0 - 1.0;
- dir[1] = -(mouse[1] / canvas.height * 2.0 - 1.0);
- dir[2] = 0.0;
- dir[3] = 1.0;
-
- // unproject ndc to view coords
- math.mulMat4(camera.projMatrix, camera.viewMatrix, matrix);
- math.inverseMat4(matrix);
- math.transformVec4(matrix, dir, dir);
-
- // this is now "a" point on the ray in world space
- math.mulVec4Scalar(dir, 1.0 / dir[3]);
-
- // the direction
- var rayO = camera.eye;
- math.subVec4(dir, rayO, dir);
-
- // the plane origin:
- var origin = clip.pos;
-
- var d = -math.dotVec3(origin, axis) - offset;
- var dot = math.dotVec3(axis, dir);
-
- console.log(Math.abs(dot));
- if (Math.abs(dot) > 0.005) {
- var t = -(math.dotVec3(axis, rayO) + d) / dot;
- math.mulVec3Scalar(dir, t, dest);
- math.addVec3(dest, rayO);
- math.subVec3(dest, origin, dest)
- return true;
- }
-
- return false;
- }
- })();
-
- var rotateClip = (function () {
- var math = xeogl.math;
- var dir = math.vec3();
- var mat = math.mat4();
-
- return function () {
- if (self._attached.clip) {
- math.quaternionToMat4(self._gumballGroup.quaternion, mat); // << ---
- math.transformVec3(mat, [0, 0, 1], dir);
- self._attached.clip.dir = dir;
- }
- };
- })();
-
- var pick = (function () {
-
- var lastHighlightedMesh;
- var lastShownMesh;
-
- return function pick(canvasPos) {
-
- var hit = scene.pick({
- canvasPos: canvasPos
- });
-
- if (lastHighlightedMesh) {
- lastHighlightedMesh.highlight = false;
- }
-
- if (lastShownMesh) {
- lastShownMesh.visible = false;
- }
-
- if (hit) {
-
- var id = hit.mesh.id;
-
- var highlightMesh;
- var shownMesh;
-
- switch (id) {
- case self._display.xRedArrow.id:
- highlightMesh = self._display.xRedArrow;
- nextDragAction = DRAG_ACTIONS.xPan;
- // localToWorldVec(xLocalAxis, panWorldVec);
- // worldToCanvasVec(panWorldVec, panCanvasVec);
- break;
-
- case self._display.yGreenArrow.id:
- highlightMesh = self._display.yGreenArrow;
- nextDragAction = DRAG_ACTIONS.yPan;
- // localToWorldVec(yLocalAxis, panWorldVec);
- // worldToCanvasVec(panWorldVec, panCanvasVec);
- break;
-
- case self._display.zBlueArrow.id:
- highlightMesh = self._display.zBlueArrow;
- nextDragAction = DRAG_ACTIONS.zPan;
- // localToWorldVec(zLocalAxis, panWorldVec);
- // worldToCanvasVec(panWorldVec, panCanvasVec);
- break;
-
- case self._display.xRedCurvePickable.id:
- highlightMesh = self._display.xRedCurve;
- shownMesh = self._hoops.xHoop;
- nextDragAction = DRAG_ACTIONS.xRotate;
- break;
-
- case self._display.yGreenCurvePickable.id:
- highlightMesh = self._display.yGreenCurve;
- shownMesh = self._hoops.yHoop;
- nextDragAction = DRAG_ACTIONS.yRotate;
- break;
-
- case self._display.zBlueCurvePickable.id:
- highlightMesh = self._display.zBlueCurve;
- shownMesh = self._hoops.zHoop;
- nextDragAction = DRAG_ACTIONS.zRotate;
- break;
-
- default:
- nextDragAction = DRAG_ACTIONS.none;
- return; // Not clicked an arrow or hoop
- }
-
- if (highlightMesh) {
- highlightMesh.highlight = true;
- }
-
- if (shownMesh) {
- shownMesh.visible = true;
- }
-
- lastHighlightedMesh = highlightMesh;
- lastShownMesh = shownMesh;
-
- } else {
-
- lastHighlightedMesh = null;
- lastShownMesh = null;
- nextDragAction = DRAG_ACTIONS.none;
- }
- };
- })();
-
- (function () {
-
- var down = false;
-
- var mouseDownLeft;
- var mouseDownMiddle;
- var mouseDownRight;
-
- canvas.addEventListener("mousemove", function (e) {
-
- if (!self._active) {
- return;
- }
-
- if (!over) {
- return;
- }
-
- var coords = getClickCoordsWithinElement(e);
-
- if (!down) {
- pick(coords);
- return;
- }
-
- var x = coords[0];
- var y = coords[1];
-
- updateControls(coords, lastMouse);
-
- lastMouse[0] = x;
- lastMouse[1] = y;
- });
-
- canvas.addEventListener("mousedown", function (e) {
- if (!self._active) {
- return;
- }
- if (!over) {
- return;
- }
- switch (e.which) {
-
- case 1: // Left button
-
- mouseDownLeft = true;
- down = true;
- var coords = getClickCoordsWithinElement(e);
-
- dragAction = nextDragAction;
-
- lastMouse[0] = coords[0];
- lastMouse[1] = coords[1];
-
- break;
-
- default:
- break;
- }
- });
-
- canvas.addEventListener("mouseup", function (e) {
- if (!self._active) {
- return;
- }
- switch (e.which) {
- case 1: // Left button
- mouseDownLeft = false;
- break;
- case 2: // Middle/both buttons
- mouseDownMiddle = false;
- break;
- case 3: // Right button
- mouseDownRight = false;
- break;
- default:
- break;
- }
- down = false;
- });
-
- canvas.addEventListener("mouseenter", function () {
- if (!self._active) {
- return;
- }
- over = true;
- });
-
- canvas.addEventListener("mouseleave", function () {
- if (!self._active) {
- return;
- }
- over = false;
- });
-
- canvas.addEventListener("wheel", function (e) {
- if (!self._active) {
- return;
- }
- var delta = Math.max(-1, Math.min(1, -e.deltaY * 40));
- if (delta === 0) {
- return;
- }
- e.preventDefault();
- });
-
- function updateControls(mouse, oldMouse) {
-
- if (dragAction === DRAG_ACTIONS.none) {
- return;
- }
-
- switch (dragAction) {
- case DRAG_ACTIONS.xPan:
- // defined by projections on axis
- pan(xLocalAxis, oldMouse, mouse);
- break;
- case DRAG_ACTIONS.yPan:
- pan(yLocalAxis, oldMouse, mouse);
- break;
- case DRAG_ACTIONS.zPan:
- pan(zLocalAxis, oldMouse, mouse);
- break;
- case DRAG_ACTIONS.xRotate:
- rotate(xLocalAxis, oldMouse, mouse);
- break;
- case DRAG_ACTIONS.yRotate:
- rotate(yLocalAxis, oldMouse, mouse);
- break;
- case DRAG_ACTIONS.zRotate:
- rotate(zLocalAxis, oldMouse, mouse);
- break;
- }
- }
-
- })();
- },
-
- _destroy: function () {
- if (this._onSceneAABB) {
- this.scene.off(this._onSceneAABB);
- }
- }
- });
- })();
-