summaryrefslogtreecommitdiffstats
path: root/o3d/samples
diff options
context:
space:
mode:
authorsimonrad@chromium.org <simonrad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-12 22:44:54 +0000
committersimonrad@chromium.org <simonrad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-12 22:44:54 +0000
commit3603b3f52fa150402b4d98d43c71aa5e48cecc36 (patch)
tree382307d0c54e55991974d3e45031737f2879da8f /o3d/samples
parent77599916d877c02275267ddccbb861f31612fa1d (diff)
downloadchromium_src-3603b3f52fa150402b4d98d43c71aa5e48cecc36.zip
chromium_src-3603b3f52fa150402b4d98d43c71aa5e48cecc36.tar.gz
chromium_src-3603b3f52fa150402b4d98d43c71aa5e48cecc36.tar.bz2
Created o3djs Plane and Translate2 classes.
BUG=none TEST=none Review URL: http://codereview.chromium.org/382001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31841 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/samples')
-rw-r--r--o3d/samples/manipulators/translate2.html273
-rw-r--r--o3d/samples/o3djs/manipulators.js549
2 files changed, 731 insertions, 91 deletions
diff --git a/o3d/samples/manipulators/translate2.html b/o3d/samples/manipulators/translate2.html
new file mode 100644
index 0000000..f9cbff7
--- /dev/null
+++ b/o3d/samples/manipulators/translate2.html
@@ -0,0 +1,273 @@
+<!--
+Copyright 2009, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<!--
+Translate2 manipulator
+
+This sample shows how to use the o3djs.manipulators.Translate2 class
+to interactively drag objects around the scene.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Translate2 Manipulator
+</title>
+<script type="text/javascript" src="../o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.quaternions');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.manipulators');
+o3djs.require('o3djs.effect');
+
+// global variables
+var g_o3dElement;
+var g_client;
+var g_o3d;
+var g_math;
+var g_pack;
+var g_viewInfo;
+
+var g_lightPosition = [5, 5, 7];
+var g_eyePosition = [1, 5, 23];
+
+var g_primitives = [];
+var g_manager;
+
+/**
+ * Creates the client area.
+ */
+function initClient() {
+ window.g_finished = false; // for selenium testing.
+
+ // Runs the sample in V8. Comment out this line to run it in the browser
+ // JavaScript engine, for example if you want to debug it.
+ // TODO(kbr): we need to investigate why turning this on is
+ // significantly slower than leaving it disabled.
+ // o3djs.util.setMainEngine(o3djs.util.Engine.V8);
+
+ o3djs.util.makeClients(main);
+}
+
+/**
+ * Initializes global variables, positions camera, draws shapes.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function main(clientElements) {
+ var o3dElement = clientElements[0];
+
+ // Init global variables.
+ initGlobals(clientElements);
+
+ // Set up the view and projection transformations.
+ initContext();
+
+ // Add the shapes to the transform heirarchy.
+ createShapes();
+
+ // Add the manipulators to the transform hierarchy.
+ createManipulators();
+
+ // Start picking; it won't do anything until the scene finishes loading.
+ o3djs.event.addEventListener(o3dElement, 'mousedown', onMouseDown);
+ o3djs.event.addEventListener(o3dElement, 'mousemove', onMouseMove);
+ o3djs.event.addEventListener(o3dElement, 'mouseup', onMouseUp);
+
+ window.g_finished = true; // for selenium testing.
+}
+
+function onMouseDown(e) {
+ g_manager.mousedown(e.x, e.y,
+ g_viewInfo.drawContext.view,
+ g_viewInfo.drawContext.projection,
+ g_client.width,
+ g_client.height);
+}
+
+function onMouseMove(e) {
+ g_manager.mousemove(e.x, e.y,
+ g_viewInfo.drawContext.view,
+ g_viewInfo.drawContext.projection,
+ g_client.width,
+ g_client.height);
+ g_manager.updateInactiveManipulators();
+}
+
+function onMouseUp(e) {
+ g_manager.mouseup();
+ g_manager.updateInactiveManipulators();
+}
+
+/**
+ * Initializes global variables and libraries.
+ */
+function initGlobals(clientElements) {
+ g_o3dElement = clientElements[0];
+ window.g_client = g_client = g_o3dElement.client;
+ g_o3d = g_o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ g_viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+}
+
+/**
+ * Sets up reasonable view and projection matrices.
+ */
+function initContext() {
+ // Set up a perspective transformation for the projection.
+ g_viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree frustum.
+ g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // primitives are located.
+ g_viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ g_eyePosition, // eye
+ [0, 2, 0], // target
+ [0, 1, 0]); // up
+}
+
+/**
+ * Creates shapes using the primitives utility library, and adds them to the
+ * transform graph at the root node.
+ */
+function createShapes() {
+ // Create a little tree-like hierarchy of cubes
+ createCubeTree(2, 1.5, [0, 0, 0], g_client.root);
+}
+
+/**
+ * Creates a small tree of cubes to demonstrate interaction with a
+ * hierarchy of shapes.
+ */
+function createCubeTree(depth, edgeLength, translation, parent) {
+ var cur = createCube(edgeLength, translation, parent);
+ if (depth > 0) {
+ createCubeTree(depth - 1,
+ edgeLength / 1.5,
+ o3djs.math.addVector(translation,
+ [-1.2 * edgeLength,
+ 1.0 * edgeLength,
+ 0]),
+ cur);
+ createCubeTree(depth - 1,
+ edgeLength / 1.5,
+ o3djs.math.addVector(translation,
+ [1.2 * edgeLength,
+ 1.0 * edgeLength,
+ 0]),
+ cur);
+ }
+ return cur;
+}
+
+/**
+ * Creates a cube shape using the primitives utility library, with an
+ * optional translation and parent. Returns the newly-created
+ * transform for the cube.
+ */
+function createCube(edgeLength, opt_translation, opt_parent) {
+ var cube = o3djs.primitives.createCube(
+ g_pack,
+ // A green phong-shaded material.
+ o3djs.material.createBasicMaterial(g_pack,
+ g_viewInfo,
+ [0, 1, 0, 1]),
+ edgeLength);
+ var transform = g_pack.createObject('Transform');
+ transform.addShape(cube);
+ if (opt_translation) {
+ transform.translate(opt_translation);
+ }
+ if (opt_parent) {
+ transform.parent = opt_parent;
+ } else {
+ transform.parent = g_client.root;
+ }
+ g_primitives.push(transform);
+ return transform;
+}
+
+/**
+ * Creates manipulators attached to the objects we've just created.
+ */
+function createManipulators() {
+ g_manager = o3djs.manipulators.createManager(g_pack,
+ g_viewInfo.performanceDrawList,
+ g_client.root,
+ null,
+ 0);
+ var jj = 2;
+ for (var ii = 0; ii < g_primitives.length; ii++) {
+ var manip = g_manager.createTranslate2();
+ manip.attachTo(g_primitives[ii]);
+ manip.setOffsetTranslation([0, -1.5, 0]);
+ // Demonstrate that we can drag along arbitrary directions.
+ if ((++jj % 4) == 0) {
+ manip.setOffsetRotation(o3djs.quaternions.rotationY(Math.PI / 4));
+ }
+ }
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function unload() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+</script>
+</head>
+<body onload="initClient()" onunload="unload()">
+<h1>Translate2 Manipulator Sample</h1>
+This example shows how to move objects around the scene using the
+Translate2 manipulator.
+<br/>
+<!-- Start of O3D plugin -->
+<div id="o3d" style="width: 600px; height: 600px;"></div>
+<!-- End of O3D plugin -->
+</body>
+</html>
diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js
index cade671..c38089c 100644
--- a/o3d/samples/o3djs/manipulators.js
+++ b/o3d/samples/o3djs/manipulators.js
@@ -96,28 +96,26 @@ o3djs.manipulators.createManager = function(pack,
* closest-point operations.
* @constructor
* @private
- * @param {o3djs.math.Vector3} opt_direction The direction of the
+ * @param {!o3djs.math.Vector3} opt_direction The direction of the
* line. Does not need to be normalized but must not be the zero
* vector. Defaults to [1, 0, 0] if not specified.
- * @param {o3djs.math.Vector3} opt_point A point through which the
+ * @param {!o3djs.math.Vector3} opt_point A point through which the
* line goes. Defaults to [0, 0, 0] if not specified.
*/
o3djs.manipulators.Line_ = function(opt_direction,
opt_point) {
- if (opt_direction) {
- this.direction_ = o3djs.math.copyVector(opt_direction);
- } else {
- this.direction_ = [1, 0, 0];
- }
-
- if (opt_point) {
- this.point_ = o3djs.math.copyVector(opt_point);
- } else {
- this.point_ = [0, 0, 0];
- }
-
- // Helper for computing projections along the line
- this.alongVec_ = [0, 0, 0];
+ /**
+ * The direction of the line.
+ * @private
+ * @type {!o3djs.math.Vector3}
+ */
+ this.direction_ = o3djs.math.copyVector(opt_direction || [1, 0, 0]);
+ /**
+ * A point through which the line goes.
+ * @private
+ * @type {!o3djs.math.Vector3}
+ */
+ this.point_ = o3djs.math.copyVector(opt_point || [0, 0, 0]);
this.recalc_();
}
@@ -177,9 +175,25 @@ o3djs.manipulators.Line_.prototype.projectPoint = function(point) {
this.direction_));
}
+/**
+ * A threshold / error tolerance for determining if a number should be
+ * considered zero.
+ * @type {!number}
+ */
o3djs.manipulators.EPSILON = 0.00001;
+
+/**
+ * A unit vector pointing along the positive X-axis.
+ * @type {!o3djs.math.Vector3}
+ */
o3djs.manipulators.X_AXIS = [1, 0, 0];
+/**
+ * A unit vector pointing along the positive Z-axis.
+ * @type {!o3djs.math.Vector3}
+ */
+o3djs.manipulators.Z_AXIS = [0, 0, 1];
+
/**
* Returns the closest point on this line to the given ray, which is
@@ -264,8 +278,14 @@ o3djs.manipulators.Line_.prototype.closestPointToRay = function(startPoint,
o3djs.manipulators.Line_.prototype.recalc_ = function() {
var denom = o3djs.math.lengthSquared(this.direction_);
if (denom == 0.0) {
- throw 'Line_.recalc: ERROR: direction was the zero vector (not allowed)';
+ throw 'Line_.recalc_: ERROR: direction was the zero vector (not allowed)';
}
+
+ /**
+ * Helper (internal cache) for computing projections along the line.
+ * @private
+ * @type {!o3djs.math.Vector3}
+ */
this.alongVec_ =
o3djs.math.subVector(this.point_,
o3djs.math.mulScalarVector(
@@ -274,9 +294,148 @@ o3djs.manipulators.Line_.prototype.recalc_ = function() {
this.direction_));
}
+/**
+ * A vector with 4 entries, the R,G,B, and A components of the default color
+ * for manipulators (used when not highlighted).
+ * @type {!o3djs.math.Vector4}
+ */
o3djs.manipulators.DEFAULT_COLOR = [0.8, 0.8, 0.8, 1.0];
+
+/**
+ * A vector with 4 entries, the R,G,B, and A components of the color used
+ * for manipulators when they are highlighted.
+ * @type {!o3djs.math.Vector4}
+ */
o3djs.manipulators.HIGHLIGHTED_COLOR = [0.9, 0.9, 0.0, 1.0];
+
+/**
+ * Creates a new Plane object.
+ * @constructor
+ * @private
+ * @param {!o3djs.math.Vector3} opt_normal The normal of the
+ * plane. Does not need to be unit length, but must not be the zero
+ * vector. Defaults to [0, 1, 0] if not specified.
+ * @param {!o3djs.math.Vector3} opt_point A point through which the
+ * plane passes. Defaults to [0, 0, 0] if not specified.
+ */
+o3djs.manipulators.Plane_ = function(opt_normal,
+ opt_point) {
+ /**
+ * A point through which the plane passes.
+ * @private
+ * @type {!o3djs.math.Vector3}
+ */
+ this.point_ = o3djs.math.copyVector(opt_point || [0, 0, 0]);
+ this.setNormal(opt_normal || [0, 1, 0]);
+}
+
+/**
+ * Sets the normal of this plane.
+ * @private
+ * @param {!o3djs.math.Vector3} normal The new normal of the
+ * plane. Does not need to be unit length, but must not be the zero
+ * vector.
+ */
+o3djs.manipulators.Plane_.prototype.setNormal = function(normal) {
+ // Make sure the normal isn't zero.
+ var denom = o3djs.math.lengthSquared(normal);
+ if (denom == 0.0) {
+ throw 'Plane_.setNormal: ERROR: normal was the zero vector (not allowed)';
+ }
+
+ /**
+ * The normal to the plane. Normalized, cannot be zero.
+ * @private
+ * @type {!o3djs.math.Vector3}
+ */
+ this.normal_ = o3djs.math.normalize(normal); // Makes copy.
+ this.recalc_();
+}
+
+/**
+ * Gets the normal of this plane, as a unit vector.
+ * @private
+ * @return {!o3djs.math.Vector3} The (normalized) normal of the plane.
+ */
+o3djs.manipulators.Plane_.prototype.getNormal = function() {
+ return this.normal_;
+}
+
+/**
+ * Sets one point through which this plane passes.
+ * @private
+ * @param {!o3djs.math.Vector3} point A point through which the plane passes.
+ */
+o3djs.manipulators.Plane_.prototype.setPoint = function(point) {
+ this.point_ = o3djs.math.copyVector(point);
+ this.recalc_();
+}
+
+/**
+ * Gets one point through which this plane passes.
+ * @private
+ * @return {!o3djs.math.Vector3} A point which through the plane passes.
+ */
+o3djs.manipulators.Plane_.prototype.getPoint = function() {
+ return this.point_;
+}
+
+/**
+ * Projects a point onto the plane.
+ * @private
+ * @param {!o3djs.math.Vector3} point Point to be projected.
+ * @return {!o3djs.math.Vector3} Point on the plane closest to the
+ * passed point.
+ */
+o3djs.manipulators.Plane_.prototype.projectPoint = function(point) {
+ var distFromPlane =
+ o3djs.math.dot(this.normal_, point) - this.normalDotPoint_;
+ return o3djs.math.subVector(point,
+ o3djs.math.mulScalarVector(distFromPlane,
+ this.normal_));
+}
+
+/**
+ * Intersects a ray with the plane. Returns the point of intersection.
+ * This is a two-sided ray cast. If the ray is parallel to the plane,
+ * returns null.
+ * @private
+ * @param {!o3djs.math.Vector3} rayStart Start point of ray.
+ * @param {!o3djs.math.Vector3} rayDirection Direction vector of ray.
+ * Does not need to be normalized, but must not be the zero vector.
+ * @return {o3djs.math.Vector3} The point of intersection of the ray
+ * with the plane, or null if the ray is parallel to the plane.
+ */
+o3djs.manipulators.Plane_.prototype.intersectRay = function(rayStart,
+ rayDirection) {
+ var distFromPlane =
+ this.normalDotPoint_ - o3djs.math.dot(this.normal_, rayStart);
+ var denom = o3djs.math.dot(this.normal_, rayDirection);
+ if (denom == 0) {
+ return null;
+ }
+ var t = distFromPlane / denom;
+ return o3djs.math.addVector(rayStart,
+ o3djs.math.mulScalarVector(t, rayDirection));
+}
+
+/**
+ * Performs internal recalculations when the parameters of the plane change.
+ * @private
+ */
+o3djs.manipulators.Plane_.prototype.recalc_ = function() {
+ /**
+ * Helper (internal cache) for computing projections into the plane.
+ * The dot product between normal_ and point_.
+ * @private
+ * @type {!number}
+ */
+ this.normalDotPoint_ = o3djs.math.dot(this.normal_, this.point_);
+}
+
+
+
/**
* Constructs a new manipulator manager. Do not call this directly;
* use o3djs.manipulators.createManager instead.
@@ -297,24 +456,64 @@ o3djs.manipulators.Manager = function(pack,
parentTransform,
parentRenderNode,
renderNodePriority) {
+ /**
+ * Pack in which manipulators' geometry and materials are created.
+ * @type {!o3d.Pack}
+ */
this.pack = pack;
+ /**
+ * The draw list against which internal materials are created.
+ * @type {!o3d.DrawList}
+ */
this.drawList = drawList;
+ /**
+ * The parent transform under which the manipulators' geometry
+ * shall be parented.
+ * @type {!o3d.Transform}
+ */
this.parentTransform = parentTransform;
+ /**
+ * The parent render node under which the manipulators' draw elements
+ * shall be placed.
+ * @type {!o3d.RenderNode}
+ */
this.parentRenderNode = parentRenderNode;
+ /**
+ * The priority that the manipulators' geometry should use for rendering.
+ * @type {number}
+ */
this.renderNodePriority = renderNodePriority;
+ /**
+ * The light position used by the manipulators' shader.
+ * @type {!o3djs.math.Vector3}
+ */
this.lightPosition = [10, 10, 10];
- // Create the default and highlighted materials.
+ /**
+ * The default material for manipulators (used when not highlighted).
+ * @type {!o3d.Material}
+ */
this.defaultMaterial =
this.createPhongMaterial_(o3djs.manipulators.DEFAULT_COLOR);
+ /**
+ * The material used for manipulators when they are highlighted.
+ * (TODO(simonrad): This is not currently used; only defaultMaterial is used. Remove this?)
+ * @type {!o3d.Material}
+ */
this.highlightedMaterial =
this.createPhongMaterial_(o3djs.manipulators.HIGHLIGHTED_COLOR);
- // This is a map from the manip's parent Transform clientId to the manip.
+ /**
+ * A map from the manip's parent Transform clientId to the manip.
+ * @type {!Array.<!o3djs.manipulators.Manip>}
+ */
this.manipsByClientId = [];
- // Presumably we need a TransformInfo for the parentTransform.
+ /**
+ * Presumably we need a TransformInfo for the parentTransform.
+ * @type {!o3djs.picking.TransformInfo}
+ */
this.transformInfo =
o3djs.picking.createTransformInfo(this.parentTransform, null);
@@ -372,6 +571,17 @@ o3djs.manipulators.Manager.prototype.createTranslate1 = function() {
}
/**
+ * Creates a new Translate2 manipulator. A Translate2 moves around the
+ * XY plane in its local coordinate system.
+ * @return {!o3djs.manipulators.Translate2} A new Translate2 manipulator.
+ */
+o3djs.manipulators.Manager.prototype.createTranslate2 = function() {
+ var manip = new o3djs.manipulators.Translate2(this);
+ this.add_(manip);
+ return manip;
+}
+
+/**
* Adds a manipulator to this manager's set.
* @private
* @param {!o3djs.manipulators.Manip} manip The manipulator to add.
@@ -556,41 +766,68 @@ o3djs.manipulators.Manager.prototype.updateInactiveManipulators = function() {
* manipulator.
*/
o3djs.manipulators.Manip = function(manager) {
+ /**
+ * The manager of this manipulator.
+ * @private
+ * @type {!o3djs.manipulators.Manager}
+ */
this.manager_ = manager;
var pack = manager.pack;
- // This transform holds the local transformation of the manipulator,
- // which is either applied to the transform to which it is attached,
- // or (see below) consumed by the user in the manipulator's
- // callbacks. After each interaction, if there is an attached
- // transform, this local transform is added in to it and reset to
- // the identity.
- // TODO(kbr): add support for user callbacks on manipulators.
+
+ /**
+ * This transform holds the local transformation of the manipulator,
+ * which is either applied to the transform to which it is attached,
+ * or (see below) consumed by the user in the manipulator's
+ * callbacks. After each interaction, if there is an attached
+ * transform, this local transform is added in to it and reset to
+ * the identity.
+ * TODO(kbr): add support for user callbacks on manipulators.
+ * @private
+ * @type {!o3d.Transform}
+ */
this.localTransform_ = pack.createObject('Transform');
- // This transform provides an offset, if desired, between the
- // manipulator's geometry and the transform (and, implicitly, the
- // shape) to which it is attached. This allows the manipulator to be
- // easily placed below an object, for example.
+ /**
+ * This transform provides an offset, if desired, between the
+ * manipulator's geometry and the transform (and, implicitly, the
+ * shape) to which it is attached. This allows the manipulator to be
+ * easily placed below an object, for example.
+ * @private
+ * @type {!o3d.Transform}
+ */
this.offsetTransform_ = pack.createObject('Transform');
- // This transform is the one which is actually parented to the
- // manager's parentTransform. It is used to place the manipulator in
- // world space, regardless of the world space location of the
- // parentTransform supplied to the manager. If this manipulator is
- // attached to a given transform, then upon completion of a
- // particular drag interaction, this transform is adjusted to take
- // into account the attached transform's new value.
+ /**
+ * This transform is the one which is actually parented to the
+ * manager's parentTransform. It is used to place the manipulator in
+ * world space, regardless of the world space location of the
+ * parentTransform supplied to the manager. If this manipulator is
+ * attached to a given transform, then upon completion of a
+ * particular drag interaction, this transform is adjusted to take
+ * into account the attached transform's new value.
+ * @private
+ * @type {!o3d.Transform}
+ */
this.baseTransform_ = pack.createObject('Transform');
// Hook up these transforms
this.localTransform_.parent = this.offsetTransform_;
this.offsetTransform_.parent = this.baseTransform_;
- // This is the transform in the scene graph to which this
- // manipulator is conceptually "attached", and whose local transform
- // we are modifying.
+ /**
+ * This is the transform in the scene graph to which this
+ * manipulator is conceptually "attached", and whose local transform
+ * we are modifying.
+ * @private
+ * @type {o3d.Transform}
+ */
this.attachedTransform_ = null;
+ /**
+ * Whether this manipulator is active (ie being dragged).
+ * @private
+ * @type {boolean}
+ */
this.active_ = false;
}
@@ -647,10 +884,9 @@ o3djs.manipulators.Manip.prototype.getTransform = function() {
*/
o3djs.manipulators.Manip.prototype.setOffsetTranslation =
function(translation) {
- this.getOffsetTransform().localMatrix =
+ this.getOffsetTransform().localMatrix =
o3djs.math.matrix4.setTranslation(this.getOffsetTransform().localMatrix,
translation);
-
}
/**
@@ -662,10 +898,9 @@ o3djs.manipulators.Manip.prototype.setOffsetTranslation =
*/
o3djs.manipulators.Manip.prototype.setOffsetRotation = function(quaternion) {
var rot = o3djs.quaternions.quaternionToRotation(quaternion);
- this.getOffsetTransform().localMatrix =
+ this.getOffsetTransform().localMatrix =
o3djs.math.matrix4.setUpper3x3(this.getOffsetTransform().localMatrix,
rot);
-
}
/**
@@ -676,10 +911,9 @@ o3djs.manipulators.Manip.prototype.setOffsetRotation = function(quaternion) {
* this manipulator.
*/
o3djs.manipulators.Manip.prototype.setTranslation = function(translation) {
- this.getTransform().localMatrix =
+ this.getTransform().localMatrix =
o3djs.math.matrix4.setTranslation(this.getTransform().localMatrix,
translation);
-
}
/**
@@ -690,10 +924,9 @@ o3djs.manipulators.Manip.prototype.setTranslation = function(translation) {
*/
o3djs.manipulators.Manip.prototype.setRotation = function(quaternion) {
var rot = o3djs.quaternions.quaternionToRotation(quaternion);
- this.getTransform().localMatrix =
+ this.getTransform().localMatrix =
o3djs.math.matrix4.setUpper3x3(this.getTransform().localMatrix,
rot);
-
}
/**
@@ -746,7 +979,7 @@ o3djs.manipulators.Manip.prototype.makeInactive = function() {
* Drags this manipulator according to the world-space ray specified
* by startPoint and endPoint. makeActive must already have been
* called with the initial pick result causing this manipulator to
- * become active. This method exists only to be overridden.
+ * become active.
* @param {!o3djs.math.Vector3} startPoint Start point of the
* world-space ray through the current mouse position.
* @param {!o3djs.math.Vector3} endPoint End point of the world-space
@@ -798,7 +1031,7 @@ o3djs.manipulators.Manip.prototype.updateAttachedTransformFromLocalTransform_ =
var base = this.baseTransform_.worldMatrix;
var local = this.localTransform_.localMatrix;
var xlate = o3djs.math.matrix4.getTranslation(local);
- var transformedXlate =
+ var transformedXlate =
o3djs.math.matrix4.transformDirection(
this.offsetTransform_.localMatrix,
o3djs.math.matrix4.getTranslation(local));
@@ -823,7 +1056,10 @@ o3djs.manipulators.Manip.prototype.updateAttachedTransformFromLocalTransform_ =
/**
* Sets the material of the given shape's draw elements.
+ * TODO(simonrad): This function is not used, remove it?
* @private
+ * @param {!o3d.Shape} shape Shape to modify the material of.
+ * @param {!o3d.Material} material Material to set.
*/
o3djs.manipulators.Manip.prototype.setMaterial_ = function(shape, material) {
var elements = shape.elements;
@@ -837,7 +1073,10 @@ o3djs.manipulators.Manip.prototype.setMaterial_ = function(shape, material) {
/**
* Sets the materials of the given shapes' draw elements.
+ * TODO(simonrad): This function is not used, remove it?
* @private
+ * @param {!Array.<!o3d.Shape>} shapes Array of shapes to modify the materials of.
+ * @param {!o3d.Material} material Material to set.
*/
o3djs.manipulators.Manip.prototype.setMaterials_ = function(shapes, material) {
for (var ii = 0; ii < shapes.length; ii++) {
@@ -845,6 +1084,45 @@ o3djs.manipulators.Manip.prototype.setMaterials_ = function(shapes, material) {
}
}
+
+/**
+ * Create the geometry for a double-ended arrow going from
+ * (0, -1, 0) to (0, 1, 0), transformed by the given matrix.
+ * @private
+ * @param {!o3djs.math.Matrix4} matrix A matrix by which to multiply
+ * all the vertices.
+ * @return {!o3djs.primitives.VertexInfo} The created vertices.
+ */
+o3djs.manipulators.createArrowVertices_ = function(matrix) {
+ var matrix4 = o3djs.math.matrix4;
+
+ var verts = o3djs.primitives.createTruncatedConeVertices(
+ 0.15, // Bottom radius.
+ 0.0, // Top radius.
+ 0.3, // Height.
+ 4, // Number of radial subdivisions.
+ 1, // Number of vertical subdivisions.
+ matrix4.mul(matrix4.translation([0, 0.85, 0]), matrix));
+
+ verts.append(o3djs.primitives.createCylinderVertices(
+ 0.06, // Radius.
+ 1.4, // Height.
+ 4, // Number of radial subdivisions.
+ 1, // Number of vertical subdivisions.
+ matrix));
+
+ verts.append(o3djs.primitives.createTruncatedConeVertices(
+ 0.0, // Bottom radius.
+ 0.15, // Top radius.
+ 0.3, // Height.
+ 4, // Number of radial subdivisions.
+ 1, // Number of vertical subdivisions.
+ matrix4.mul(matrix4.translation([0, -0.85, 0]), matrix)));
+
+ return verts;
+}
+
+
/**
* A manipulator allowing an object to be dragged along a line.
* @constructor
@@ -862,34 +1140,10 @@ o3djs.manipulators.Translate1 = function(manager) {
if (!shape) {
// Create the geometry for the manipulator, which looks like a
// two-way arrow going from (-1, 0, 0) to (1, 0, 0).
- var matrix4 = o3djs.math.matrix4;
- var zRot = matrix4.rotationZ(Math.PI / 2);
-
- var verts = o3djs.primitives.createTruncatedConeVertices(
- 0.15, // Bottom radius.
- 0.0, // Top radius.
- 0.3, // Height.
- 4, // Number of radial subdivisions.
- 1, // Number of vertical subdivisions.
- matrix4.mul(matrix4.translation([0, 0.85, 0]), zRot));
-
- verts.append(o3djs.primitives.createCylinderVertices(
- 0.06, // Radius.
- 1.4, // Height.
- 4, // Number of radial subdivisions.
- 1, // Number of vertical subdivisions.
- zRot));
-
- verts.append(o3djs.primitives.createTruncatedConeVertices(
- 0.0, // Bottom radius.
- 0.15, // Top radius.
- 0.3, // Height.
- 4, // Number of radial subdivisions.
- 1, // Number of vertical subdivisions.
- matrix4.mul(matrix4.translation([0, -0.85, 0]), zRot)));
-
+ var verts = o3djs.manipulators.createArrowVertices_(
+ o3djs.math.matrix4.rotationZ(Math.PI / 2));
shape = verts.createShape(pack, material);
- manager.translate1Shape_ = shape;
+ manager.translate1Shape_ = shape;
}
this.addShapes_([ shape ]);
@@ -897,13 +1151,21 @@ o3djs.manipulators.Translate1 = function(manager) {
this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(),
manager.transformInfo);
- // Add a parameter to our transform to be able to change the
- // material's color for highlighting.
- this.colorParam = this.getTransform().createParam('diffuse', 'ParamFloat4');
+ /**
+ * A parameter added to our transform to be able to change the
+ * material's color for highlighting.
+ * @private
+ * @type {!o3d.ParamFloat4}
+ */
+ this.colorParam_ = this.getTransform().createParam('diffuse', 'ParamFloat4');
this.clearHighlight();
- /** Dragging state */
- this.dragLine = new o3djs.manipulators.Line_();
+ /**
+ * Line along which we are dragging.
+ * @private
+ * @type {!o3djs.manipulators.Line_}
+ */
+ this.dragLine_ = new o3djs.manipulators.Line_();
}
o3djs.base.inherit(o3djs.manipulators.Translate1, o3djs.manipulators.Manip);
@@ -912,21 +1174,21 @@ o3djs.manipulators.Translate1.prototype.highlight = function(pickResult) {
// We can use instanced geometry for the entire Translate1 since its
// entire color changes during highlighting.
// TODO(kbr): support custom user geometry and associated callbacks.
- this.colorParam.value = o3djs.manipulators.HIGHLIGHTED_COLOR;
+ this.colorParam_.value = o3djs.manipulators.HIGHLIGHTED_COLOR;
}
o3djs.manipulators.Translate1.prototype.clearHighlight = function() {
- this.colorParam.value = o3djs.manipulators.DEFAULT_COLOR;
+ this.colorParam_.value = o3djs.manipulators.DEFAULT_COLOR;
}
o3djs.manipulators.Translate1.prototype.makeActive = function(pickResult) {
o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
this.highlight(pickResult);
var worldMatrix = this.getTransform().worldMatrix;
- this.dragLine.setDirection(
+ this.dragLine_.setDirection(
o3djs.math.matrix4.transformDirection(worldMatrix,
o3djs.manipulators.X_AXIS));
- this.dragLine.setPoint(pickResult.worldIntersectionPosition);
+ this.dragLine_.setPoint(pickResult.worldIntersectionPosition);
}
o3djs.manipulators.Translate1.prototype.makeInactive = function() {
@@ -938,11 +1200,11 @@ o3djs.manipulators.Translate1.prototype.makeInactive = function() {
o3djs.manipulators.Translate1.prototype.drag = function(startPoint,
endPoint) {
- // Algorithm: Find closest point of ray to dragLine. Subtract this
+ // Algorithm: Find closest point of ray to dragLine_. Subtract this
// point from the line's point to find difference vector; transform
// from world to local coordinates to find new local offset of
// manipulator.
- var closestPoint = this.dragLine.closestPointToRay(startPoint, endPoint);
+ var closestPoint = this.dragLine_.closestPointToRay(startPoint, endPoint);
if (closestPoint == null) {
// Drag axis is parallel to ray. Punt.
return;
@@ -950,12 +1212,117 @@ o3djs.manipulators.Translate1.prototype.drag = function(startPoint,
// Need to do a world-to-local transformation on the difference vector.
// Note that we also incorporate the translation portion of the matrix.
var diffVector =
- o3djs.math.subVector(closestPoint, this.dragLine.getPoint());
+ o3djs.math.subVector(closestPoint, this.dragLine_.getPoint());
+ var worldToLocal =
+ o3djs.math.matrix4.inverse(this.getTransform().worldMatrix);
+ this.getTransform().localMatrix =
+ o3djs.math.matrix4.setTranslation(
+ this.getTransform().localMatrix,
+ o3djs.math.matrix4.transformDirection(worldToLocal,
+ diffVector));
+ this.updateAttachedTransformFromLocalTransform_();
+}
+
+
+/**
+ * A manipulator allowing an object to be dragged around a plane.
+ * @constructor
+ * @extends {o3djs.manipulators.Manip}
+ * @param {!o3djs.manipulators.Manager} manager The manager for the
+ * new Translate2 manipulator.
+ */
+o3djs.manipulators.Translate2 = function(manager) {
+ o3djs.manipulators.Manip.call(this, manager);
+
+ var pack = manager.pack;
+ var material = manager.defaultMaterial;
+
+ var shape = manager.Translate2Shape_;
+ if (!shape) {
+ // Create the geometry for the manipulator, which looks like
+ // a two-way arrow going from (-1, 0, 0) to (1, 0, 0),
+ // and another one going from (0, -1, 0) to (0, 1, 0).
+ var verts = o3djs.manipulators.createArrowVertices_(
+ o3djs.math.matrix4.rotationZ(Math.PI / 2));
+ verts.append(o3djs.manipulators.createArrowVertices_(
+ o3djs.math.matrix4.rotationZ(0)));
+ shape = verts.createShape(pack, material);
+ manager.Translate2Shape_ = shape;
+ }
+
+ this.addShapes_([ shape ]);
+
+ this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(),
+ manager.transformInfo);
+
+ /**
+ * A parameter added to our transform to be able to change the
+ * material's color for highlighting.
+ * @private
+ * @type {!o3d.ParamFloat4}
+ */
+ this.colorParam_ = this.getTransform().createParam('diffuse', 'ParamFloat4');
+ this.clearHighlight();
+
+ /**
+ * Plane through which we are dragging.
+ * @private
+ * @type {!o3djs.manipulators.Plane_}
+ */
+ this.dragPlane_ = new o3djs.manipulators.Plane_();
+}
+
+o3djs.base.inherit(o3djs.manipulators.Translate2, o3djs.manipulators.Manip);
+
+o3djs.manipulators.Translate2.prototype.highlight = function(pickResult) {
+ // We can use instanced geometry for the entire Translate2 since its
+ // entire color changes during highlighting.
+ // TODO(kbr): support custom user geometry and associated callbacks.
+ this.colorParam_.value = o3djs.manipulators.HIGHLIGHTED_COLOR;
+}
+
+o3djs.manipulators.Translate2.prototype.clearHighlight = function() {
+ this.colorParam_.value = o3djs.manipulators.DEFAULT_COLOR;
+}
+
+o3djs.manipulators.Translate2.prototype.makeActive = function(pickResult) {
+ o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
+ this.highlight(pickResult);
+ var worldMatrix = this.getTransform().worldMatrix;
+ this.dragPlane_.setNormal(
+ o3djs.math.matrix4.transformDirection(worldMatrix,
+ o3djs.manipulators.Z_AXIS));
+ this.dragPlane_.setPoint(pickResult.worldIntersectionPosition);
+}
+
+o3djs.manipulators.Translate2.prototype.makeInactive = function() {
+ o3djs.manipulators.Manip.prototype.makeInactive.call(this);
+ this.clearHighlight();
+ this.updateAttachedTransformFromLocalTransform_();
+ this.updateBaseTransformFromAttachedTransform_();
+}
+
+o3djs.manipulators.Translate2.prototype.drag = function(startPoint,
+ endPoint) {
+ // Algorithm: Find intersection of ray with dragPlane_. Subtract this
+ // point from the plane's point to find difference vector; transform
+ // from world to local coordinates to find new local offset of
+ // manipulator.
+ var intersectPoint = this.dragPlane_.intersectRay(startPoint,
+ o3djs.math.subVector(endPoint, startPoint));
+ if (intersectPoint == null) {
+ // Drag plane is parallel to ray. Punt.
+ return;
+ }
+ // Need to do a world-to-local transformation on the difference vector.
+ // Note that we also incorporate the translation portion of the matrix.
+ var diffVector =
+ o3djs.math.subVector(intersectPoint, this.dragPlane_.getPoint());
var worldToLocal =
o3djs.math.matrix4.inverse(this.getTransform().worldMatrix);
this.getTransform().localMatrix =
o3djs.math.matrix4.setTranslation(
- this.getTransform().localMatrix,
+ this.getTransform().localMatrix,
o3djs.math.matrix4.transformDirection(worldToLocal,
diffVector));
this.updateAttachedTransformFromLocalTransform_();