diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-03 00:30:36 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-03 00:30:36 +0000 |
commit | 8dc465e39dd10bd23a4f24481d2bf146404596a7 (patch) | |
tree | e0da44eaee7bd4402a9844e1b68c50149cd290dd /o3d | |
parent | acaae862120b887d04432fd81e2c2c47cbd1256c (diff) | |
download | chromium_src-8dc465e39dd10bd23a4f24481d2bf146404596a7.zip chromium_src-8dc465e39dd10bd23a4f24481d2bf146404596a7.tar.gz chromium_src-8dc465e39dd10bd23a4f24481d2bf146404596a7.tar.bz2 |
Updates the picking library to have a PickManager and
support both not picking invisible objects and
the option to pick even if invisible.
The idea is you can do something like this
// Make a picking manager
var pm = o3djs.picking.createPickManager(rootTransform);
... // add a bunch of transforms.
// generate picking objects.
pm.update();
// Get the picking object that was created for some specific transform
var info = pm.getTransformInfo(someTransform);
// Set properties on that object related to picking
info.pickEvenIfInvisible = true;
I think this is just a first step. How an object should
be defined as pickable is up for debate. As it is,
you can basically override info.isPickable.
as in
info.isPickable = function() {
// do something custom.
}
You can also start adding things easier like
info.onPick = function() {
// do something.
}
and then write code like
info = pm.pick(worldRay);
if (info) {
info.onPick();
}
While you could have done that before there was no
easy way to find a the TransformInfo for a
specific Transform. Now you can use
PickManager.getTransformInfo
Review URL: http://codereview.chromium.org/452027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33632 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/samples/checkers.html | 16 | ||||
-rw-r--r-- | o3d/samples/home-configurators/deletetool.js | 6 | ||||
-rw-r--r-- | o3d/samples/home-configurators/movetool.js | 8 | ||||
-rw-r--r-- | o3d/samples/home-configurators/rotatetool.js | 6 | ||||
-rw-r--r-- | o3d/samples/home-configurators/viewer.js | 3 | ||||
-rw-r--r-- | o3d/samples/o3djs/manipulators.js | 25 | ||||
-rw-r--r-- | o3d/samples/o3djs/picking.js | 348 | ||||
-rw-r--r-- | o3d/samples/picking.html | 23 |
8 files changed, 307 insertions, 128 deletions
diff --git a/o3d/samples/checkers.html b/o3d/samples/checkers.html index 219bc6f..9275bfe 100644 --- a/o3d/samples/checkers.html +++ b/o3d/samples/checkers.html @@ -74,7 +74,7 @@ var g_thisRot; var g_lastRot; var g_zoomFactor; var g_dragging = false; -var g_treeInfo; // information about the transform graph. +var g_pickManager; // information about the transform graph. var g_statusInfoElem; // Animation globals. @@ -354,7 +354,7 @@ function createCheckersBoard() { } // Update our tree info. - updateTreeInfo(); + updateg_pickManager(); // update status. updateStatus('Game starting... RED moves first.', true); @@ -391,11 +391,11 @@ function checkAndUpdateKing(x, y) { /** * Updates the transform tree info. */ -function updateTreeInfo() { - if (!g_treeInfo) { - g_treeInfo = o3djs.picking.createTransformInfo(g_client.root, null); +function updateg_pickManager() { + if (!g_pickManager) { + g_pickManager = o3djs.picking.createPickManager(g_client.root); } - g_treeInfo.update(); + g_pickManager.update(); } /** @@ -577,7 +577,7 @@ function detectSelection(e) { g_client.height); // check if we picked any objects. - var pickInfo = g_treeInfo.pick(worldRay); + var pickInfo = g_pickManager.pick(worldRay); if (pickInfo) { // get the parent transform of this object. var pickTrans = pickInfo.shapeInfo.parent.transform; @@ -774,7 +774,7 @@ function moveSelectedPiece(elapsedTime) { g_moveTimer = 0; // update the tree info. - updateTreeInfo(); + updateg_pickManager(); // check if current player can jump again. if (wasJump && pieceCanJump(g_board[x1][y1])) { diff --git a/o3d/samples/home-configurators/deletetool.js b/o3d/samples/home-configurators/deletetool.js index 616303bb..022d65f 100644 --- a/o3d/samples/home-configurators/deletetool.js +++ b/o3d/samples/home-configurators/deletetool.js @@ -38,7 +38,7 @@ function DeleteTool(context, root) { this.context = context; this.root = root; - this.transformInfo = o3djs.picking.createTransformInfo(root, null); + this.pickManager = g_pickManager; this.selectedObject = null; } @@ -48,8 +48,8 @@ DeleteTool.prototype.getPickedObject = function(e) { this.context, g_client.width, g_client.height); - this.transformInfo.update(); - var pickInfo = this.transformInfo.pick(worldRay); + this.pickManager.update(); + var pickInfo = this.pickManager.pick(worldRay); var picked_object_root = null; if (pickInfo) { pickedObject = pickInfo.shapeInfo.parent; diff --git a/o3d/samples/home-configurators/movetool.js b/o3d/samples/home-configurators/movetool.js index d0db043..5d0e190 100644 --- a/o3d/samples/home-configurators/movetool.js +++ b/o3d/samples/home-configurators/movetool.js @@ -40,7 +40,7 @@ function MoveTool(context, root) { this.lastMove = null; this.context = context; this.root = root; - this.transformInfo = o3djs.picking.createTransformInfo(root, null); + this.pickManager = g_pickManager; this.movePlane = [0.0, 0.0, 1.0]; this.downPoint = null; this.selectedObject = null; @@ -51,7 +51,7 @@ function MoveTool(context, root) { * (the same node as would be found by our picking code) */ MoveTool.prototype.initializeWithShape = function(transform_node) { - this.transformInfo.update(); + this.pickManager.update(); translation = g_math.matrix4.getTranslation( transform_node.getUpdatedWorldMatrix()); this.downPoint = translation; @@ -65,9 +65,9 @@ MoveTool.prototype.handleMouseDown = function(e) { this.context, g_client.width, g_client.height); - this.transformInfo.update(); + this.pickManager.update(); this.selectedObject = null; - var pickInfo = this.transformInfo.pick(worldRay); + var pickInfo = this.pickManager.pick(worldRay); if (pickInfo) { pickedObject = pickInfo.shapeInfo.parent; while (pickedObject.parent != null && diff --git a/o3d/samples/home-configurators/rotatetool.js b/o3d/samples/home-configurators/rotatetool.js index 9bf852b..2a78a2a4 100644 --- a/o3d/samples/home-configurators/rotatetool.js +++ b/o3d/samples/home-configurators/rotatetool.js @@ -42,7 +42,7 @@ function RotateTool(context, root) { this.context = context; this.selectedObject = null; this.root = root; - this.transformInfo = o3djs.picking.createTransformInfo(root, null); + this.pickManager = g_pickManager; this.rotateAxis = [0.0, 0.0, 1.0]; this.rotateCenter = null; } @@ -56,8 +56,8 @@ RotateTool.prototype.handleMouseDown = function(e) { this.context, window_width, window_height); - this.transformInfo.update(); - var pickInfo = this.transformInfo.pick(worldRay); + this.pickManager.update(); + var pickInfo = this.pickManager.pick(worldRay); if (pickInfo) { pickedObject = pickInfo.shapeInfo.parent; while (pickedObject.parent != null && diff --git a/o3d/samples/home-configurators/viewer.js b/o3d/samples/home-configurators/viewer.js index 69c4fb7..2e334f4 100644 --- a/o3d/samples/home-configurators/viewer.js +++ b/o3d/samples/home-configurators/viewer.js @@ -54,6 +54,7 @@ var g_lastRot; var g_pack = null; var g_mainPack; var g_viewInfo; +var g_pickManager; var g_lightPosParam; var g_currentTool = null; var g_floorplanRoot = null; @@ -428,6 +429,8 @@ function loadFile(context, path) { // Put the object we're loading on the floorplan. new_object_root = g_floorplanRoot; + g_pickManager = o3djs.picking.createPickManager(g_placedModelsRoot); + // Create our set of tools that can be activated. // Note: Currently only the Delete, Move, Rotate, Orbit, Pan and Zoom // tools are implemented. The last four icons in the toolbar are unused. diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js index 7bea7a5..85fb611 100644 --- a/o3d/samples/o3djs/manipulators.js +++ b/o3d/samples/o3djs/manipulators.js @@ -511,11 +511,11 @@ o3djs.manipulators.Manager = function(pack, this.manipsByClientId = []; /** - * Presumably we need a TransformInfo for the parentTransform. + * A PickManager to manage picking for the manipulators. * @type {!o3djs.picking.TransformInfo} */ - this.transformInfo = - o3djs.picking.createTransformInfo(this.parentTransform, null); + this.pickManager = + o3djs.picking.createPickManager(this.parentTransform); /** * The currently-highlighted manipulator. @@ -614,7 +614,7 @@ o3djs.manipulators.Manager.prototype.handleMouse_ = function(x, width, height, func) { - this.transformInfo.update(); + this.pickManager.update(); // Create the world ray var worldRay = @@ -623,7 +623,7 @@ o3djs.manipulators.Manager.prototype.handleMouse_ = function(x, width, height); // Pick against all of the manipulators' geometry - var pickResult = this.transformInfo.pick(worldRay); + var pickResult = this.pickManager.pick(worldRay); if (pickResult != null) { // Find which manipulator we picked. // NOTE this assumes some things about the transform graph @@ -1159,8 +1159,9 @@ o3djs.manipulators.Translate1 = function(manager) { this.addShapes_([ shape ]); - this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(), - manager.transformInfo); + this.transformInfo = manager.pickManager.createTransformInfo( + this.getTransform(), + manager.transformInfo); /** * A parameter added to our transform to be able to change the @@ -1270,8 +1271,9 @@ o3djs.manipulators.Translate2 = function(manager) { this.addShapes_([ shape ]); - this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(), - manager.transformInfo); + this.transformInfo = manager.pickManager.createTransformInfo( + this.getTransform(), + manager.transformInfo); /** * A parameter added to our transform to be able to change the @@ -1383,8 +1385,9 @@ o3djs.manipulators.Rotate1 = function(manager) { this.addShapes_([ shape ]); - this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(), - manager.transformInfo); + this.transformInfo = manager.pickManager.createTransformInfo( + this.getTransform(), + manager.transformInfo); /** * A parameter added to our transform to be able to change the diff --git a/o3d/samples/o3djs/picking.js b/o3d/samples/o3djs/picking.js index 409104d..a67de17 100644 --- a/o3d/samples/o3djs/picking.js +++ b/o3d/samples/o3djs/picking.js @@ -89,27 +89,6 @@ o3djs.picking.createPickInfo = function(element, }; /** - * Creates a new ShapeInfo. - * @param {!o3d.Shape} shape Shape to keep info about. - * @param {!o3djs.picking.TransformInfo} parent Parent transform of the shape. - * @return {!o3djs.picking.ShapeInfo} The new ShapeInfo. - */ -o3djs.picking.createShapeInfo = function(shape, parent) { - return new o3djs.picking.ShapeInfo(shape, parent); -}; - -/** - * Creates a new TransformInfo. - * @param {!o3d.Transform} transform Transform to keep info about. - * @param {o3djs.picking.TransformInfo} parent Parent transform of the - * transform. Can be null. - * @return {!o3djs.picking.TransformInfo} The new TransformInfo. - */ -o3djs.picking.createTransformInfo = function(transform, parent) { - return new o3djs.picking.TransformInfo(transform, parent); -}; - -/** * Convert a pixel position relative to the top left corner of the client area * into the corresponding ray through the frustum in world space. * @param {number} clientXPosition x position relative to client area. @@ -205,9 +184,10 @@ o3djs.picking.dprintBoundingBox = function(label, */ o3djs.picking.dumpRayIntersectionInfo = function(label, rayIntersectionInfo) { - o3djs.picking.dprint(label + ' : valid = ' + - rayIntersectionInfo.valid + ' : intersected = ' + - rayIntersectionInfo.intersected); + o3djs.picking.dprint( + label + ' : valid = ' + + rayIntersectionInfo.valid + ' : intersected = ' + + rayIntersectionInfo.intersected); if (rayIntersectionInfo.intersected) { o3djs.picking.dprint( ' : pos: ' + @@ -258,12 +238,16 @@ o3djs.picking.PickInfo = function(element, }; /** - * Creates a new ShapeInfo. Used to store information about Shapes. + * Creates a new ShapeInfo. Used to store information about Shapes. Note, even + * though Shapes can be instanced, ShapeInfos can not so if a Shape is instanced + * there will be more than one ShapeInfo for it. * @constructor * @param {!o3d.Shape} shape Shape to keep info about. * @param {!o3djs.picking.TransformInfo} parent Parent transform of the shape. + * @param {!o3djs.picking.PickManager} pickManager The PickManager this + * ShapeInfo belongs to. */ -o3djs.picking.ShapeInfo = function(shape, parent) { +o3djs.picking.ShapeInfo = function(shape, parent, pickManager) { /** * The Shape for this ShapeInfo * @type {!o3d.Shape} @@ -282,10 +266,24 @@ o3djs.picking.ShapeInfo = function(shape, parent) { */ this.boundingBox = null; + /** + * The PickManager this ShapeInfo belongs to. + * @type {!o3djs.picking.PickManager} + */ + this.pickManager = pickManager; + this.update(); }; /** + * Returns whether or not this ShapeInfo is pickable. + * @return {boolean} Whether or not this ShapeInfo is pickable. + */ +o3djs.picking.ShapeInfo.prototype.isPickable = function() { + return true; +} + +/** * Gets the BoundingBox of the Shape in this ShapeInfo. * @return {o3d.BoundingBox} The Shape's BoundingBox. */ @@ -314,40 +312,42 @@ o3djs.picking.ShapeInfo.prototype.update = function() { * null if the ray did not intersect any triangles. */ o3djs.picking.ShapeInfo.prototype.pick = function(worldRay) { - var worldMatrix = this.parent.transform.getUpdatedWorldMatrix() - var inverseWorldMatrix = o3djs.math.inverse(worldMatrix); - var relativeNear = o3djs.math.matrix4.transformPoint( - inverseWorldMatrix, worldRay.near); - var relativeFar = o3djs.math.matrix4.transformPoint( - inverseWorldMatrix, worldRay.far); - var rayIntersectionInfo = - this.boundingBox.intersectRay(relativeNear, - relativeFar); - - o3djs.picking.dumpRayIntersectionInfo('SHAPE(box): ' + this.shape.name, - rayIntersectionInfo); + if (this.isPickable()) { + var worldMatrix = this.parent.transform.getUpdatedWorldMatrix() + var inverseWorldMatrix = o3djs.math.inverse(worldMatrix); + var relativeNear = o3djs.math.matrix4.transformPoint( + inverseWorldMatrix, worldRay.near); + var relativeFar = o3djs.math.matrix4.transformPoint( + inverseWorldMatrix, worldRay.far); + var rayIntersectionInfo = + this.boundingBox.intersectRay(relativeNear, + relativeFar); - if (rayIntersectionInfo.intersected) { - var elements = this.shape.elements; - for (var e = 0; e < elements.length; e++) { - var element = elements[e]; - rayIntersectionInfo = element.intersectRay( - 0, - o3djs.base.o3d.State.CULL_CCW, - relativeNear, - relativeFar); - o3djs.picking.dumpRayIntersectionInfo( - 'SHAPE(tris): ' + this.shape.name + ' : element ' + element.name, - rayIntersectionInfo); - - // TODO: get closest element not just first element. - if (rayIntersectionInfo.intersected) { - var worldIntersectionPosition = o3djs.math.matrix4.transformPoint( - worldMatrix, rayIntersectionInfo.position); - return o3djs.picking.createPickInfo(element, - this, - rayIntersectionInfo, - worldIntersectionPosition); + o3djs.picking.dumpRayIntersectionInfo('SHAPE(box): ' + this.shape.name, + rayIntersectionInfo); + + if (rayIntersectionInfo.intersected) { + var elements = this.shape.elements; + for (var e = 0; e < elements.length; e++) { + var element = elements[e]; + rayIntersectionInfo = element.intersectRay( + 0, + o3djs.base.o3d.State.CULL_CCW, + relativeNear, + relativeFar); + o3djs.picking.dumpRayIntersectionInfo( + 'SHAPE(tris): ' + this.shape.name + ' : element ' + element.name, + rayIntersectionInfo); + + // TODO: get closest element not just first element. + if (rayIntersectionInfo.intersected) { + var worldIntersectionPosition = o3djs.math.matrix4.transformPoint( + worldMatrix, rayIntersectionInfo.position); + return o3djs.picking.createPickInfo(element, + this, + rayIntersectionInfo, + worldIntersectionPosition); + } } } } @@ -356,9 +356,10 @@ o3djs.picking.ShapeInfo.prototype.pick = function(worldRay) { /** * Dumps info about a ShapeInfo - * @param {string} prefix optional prefix for indenting. + * @param {string} opt_prefix optional prefix for indenting. */ -o3djs.picking.ShapeInfo.prototype.dump = function(prefix) { +o3djs.picking.ShapeInfo.prototype.dump = function(opt_prefix) { + var prefix = opt_prefix || ''; o3djs.picking.dprint(prefix + 'SHAPE: ' + this.shape.name + '\n'); o3djs.picking.dprintPoint3('bb min', this.boundingBox.minExtent, @@ -374,21 +375,55 @@ o3djs.picking.ShapeInfo.prototype.dump = function(prefix) { * @param {!o3d.Transform} transform Transform to keep info about. * @param {o3djs.picking.TransformInfo} parent Parent transformInfo of the * transform. Can be null. + * @param {!o3djs.picking.PickManager} pickManager The PickManager this + * ShapeInfo belongs to. */ -o3djs.picking.TransformInfo = function(transform, parent) { - this.childTransformInfos = {}; // Object of TransformInfo by id - this.shapeInfos = {}; // Object of ShapeInfo by id +o3djs.picking.TransformInfo = function(transform, parent, pickManager) { + /** + * TransformInfos for children by client id. + * @type {!Object.<number, !o3djs.picking.TransformInfo>} + */ + this.childTransformInfos = {}; + + /** + * ShapeInfos for shape of this transform by client id. + * @type {!Object.<number, !o3djs.picking.ShapeInfo>} + */ + this.shapeInfos = {}; + /** * The transform of this transform info. * @type {!o3d.Transform} */ this.transform = transform; + /** * The parent of this transform info. * @type {o3djs.picking.TransformInfo} */ this.parent = parent; + + /** + * The bounding box of this transform info. + * @type {o3d.BoundingBox} + */ this.boundingBox = null; + + /** + * The PickManager this TransformInfo belongs to. + * @type {!o3djs.picking.PickManager} + */ + this.pickManager = pickManager; + + /** + * Whether or not this object is pickable when invisible. + * This is useful for collision geometry that is not visible. + * Of course it might argubly be better to store collision geometry + * in a separate graph from visible geometry but sometimes it's useful + * to have them in the same graph. + * @type {boolean} + */ + this.pickableEvenIfInvisible = false; }; /** @@ -400,18 +435,33 @@ o3djs.picking.TransformInfo.prototype.getBoundingBox = function() { }; /** + * Returns whether or not this TransformInfo is pickable. + * + * If this TransformInfo is not pickable then all child shapes and + * TransformInfos will be skipped during the picking process. + * + * @return {boolean} Whether or not this TransformInfo is pickable. + */ +o3djs.picking.TransformInfo.prototype.isPickable = function() { + return this.transform.visible || this.pickableEvenIfInvisible; +}; + +/** * Updates the shape and child lists for this TransformInfo and recomputes its * BoundingBox. */ o3djs.picking.TransformInfo.prototype.update = function() { var newChildTransformInfos = {}; var newShapeInfos = {}; + // We need to add new children and remove old ones so we walk the children + // and for each one we find, if it already has a TransformInfo or ShapeInfo we + // add it to our new lists, if not we create one and add it to our new lists. var children = this.transform.children; for (var c = 0; c < children.length; c++) { var child = children[c]; var transformInfo = this.childTransformInfos[child.clientId]; if (!transformInfo) { - transformInfo = o3djs.picking.createTransformInfo(child, this); + transformInfo = this.pickManager.createTransformInfo(child, this); } else { // clear the boundingBox so we'll regenerate it. transformInfo.boundingBox = null; @@ -424,11 +474,11 @@ o3djs.picking.TransformInfo.prototype.update = function() { var shape = shapes[s]; var shapeInfo = this.shapeInfos[shape.clientId]; if (!shapeInfo) { - shapeInfo = o3djs.picking.createShapeInfo(shape, this); + shapeInfo = this.pickManager.createShapeInfo(shape, this); } else { // unless the vertices or elements change there is no need to // recompute this. - // shape.update(); + // shapeInfo.update(); } newShapeInfos[shape.clientId] = shapeInfo; } @@ -438,30 +488,43 @@ o3djs.picking.TransformInfo.prototype.update = function() { // o3djs.picking.dprint( // 'num Shapes: ' + shapes.length + '\n'); + // Now our new lists have the correct children so replace the old lists. + // and remove any old children from the PickManager. + for (var skey in this.childTransformInfos) { + var key = /** @type {number} */ (skey); + if (!newChildTransformInfos[key]) { + this.pickManager.removeTransformInfo(this.childTransformInfos[key]); + } + } + this.childTransformInfos = newChildTransformInfos; this.shapeInfos = newShapeInfos; var boundingBox = null; for (var key in newShapeInfos) { var shapeInfo = newShapeInfos[key]; - var box = shapeInfo.getBoundingBox().mul(this.transform.localMatrix); - if (!boundingBox) { - boundingBox = box; - } else if (box) { - boundingBox = boundingBox.add(box); + if (shapeInfo.isPickable()) { + var box = shapeInfo.getBoundingBox().mul(this.transform.localMatrix); + if (!boundingBox) { + boundingBox = box; + } else if (box) { + boundingBox = boundingBox.add(box); + } } } for (var key in newChildTransformInfos) { var transformInfo = newChildTransformInfos[key]; - // Note: If there is no shape at the leaf on this branch - // there will be no bounding box. - var box = transformInfo.getBoundingBox(); - if (box) { - if (!boundingBox) { - boundingBox = box.mul(this.transform.localMatrix); - } else { - boundingBox = boundingBox.add(box.mul(this.transform.localMatrix)); + if (transformInfo.isPickable()) { + // Note: If there is no shape at the leaf on this branch + // there will be no bounding box. + var box = transformInfo.getBoundingBox(); + if (box) { + if (!boundingBox) { + boundingBox = box.mul(this.transform.localMatrix); + } else { + boundingBox = boundingBox.add(box.mul(this.transform.localMatrix)); + } } } } @@ -479,7 +542,7 @@ o3djs.picking.TransformInfo.prototype.update = function() { * null if the ray did not intersect any triangles. */ o3djs.picking.TransformInfo.prototype.pick = function(worldRay) { - if (this.boundingBox) { + if (this.isPickable() && this.boundingBox) { var inverseWorldMatrix = o3djs.math.matrix4.identity(); if (this.parent) { inverseWorldMatrix = o3djs.math.inverse( @@ -497,7 +560,8 @@ o3djs.picking.TransformInfo.prototype.pick = function(worldRay) { if (rayIntersectionInfo.intersected) { var closestPickInfo = null; var minDistance = -1; - for (var key in this.childTransformInfos) { + for (var skey in this.childTransformInfos) { + var key = /** @type {number} */ (skey); var transformInfo = this.childTransformInfos[key]; var pickInfo = transformInfo.pick(worldRay); if (pickInfo) { @@ -512,7 +576,8 @@ o3djs.picking.TransformInfo.prototype.pick = function(worldRay) { } } - for (var key in this.shapeInfos) { + for (var skey in this.shapeInfos) { + var key = /** @type {number} */ (skey); var shapeInfo = this.shapeInfos[key]; var pickInfo = shapeInfo.pick(worldRay); if (pickInfo) { @@ -534,10 +599,10 @@ o3djs.picking.TransformInfo.prototype.pick = function(worldRay) { /** * Dumps info about a TransformInfo - * @param {string} prefix optional prefix for indenting. + * @param {string} opt_prefix optional prefix for indenting. */ -o3djs.picking.TransformInfo.prototype.dump = function(prefix) { - prefix = prefix || ''; +o3djs.picking.TransformInfo.prototype.dump = function(opt_prefix) { + var prefix = opt_prefix || ''; o3djs.picking.dprint(prefix + 'TRANSFORM: ' + this.transform.name + '\n'); @@ -554,17 +619,124 @@ o3djs.picking.TransformInfo.prototype.dump = function(prefix) { } o3djs.picking.dprint(prefix + '--Shapes--\n'); - for (var key in this.shapeInfos) { + for (var skey in this.shapeInfos) { + var key = /** @type {number} */ (skey); var shapeInfo = this.shapeInfos[key]; shapeInfo.dump(prefix + ' '); } o3djs.picking.dprint(prefix + '--Children--\n'); - for (var key in this.childTransformInfos) { + for (var skey in this.childTransformInfos) { + var key = /** @type {number} */ (skey); var transformInfo = this.childTransformInfos[key]; transformInfo.dump(prefix + ' '); } }; +/** + * A PickManager manages picking of primitives from a transform graph. + * @constructor + * @param {!o3d.Transform} rootTransform The root of the transform graph this + * PickManager should manage. + */ +o3djs.picking.PickManager = function(rootTransform) { + /** + * TransformInfos for transforms of this PickManager by client id. + * @type {!Object.<number, !o3djs.picking.TransformInfo>} + */ + this.transformInfosByClientId = {}; + + /** + * The root transform for this PickManager. + * @type {!o3djs.picking.TransformInfo} + */ + this.rootTransformInfo = this.createTransformInfo(rootTransform, null); +}; + +/** + * Creates a new ShapeInfo. + * @param {!o3d.Shape} shape Shape to keep info about. + * @param {!o3djs.picking.TransformInfo} parent Parent transform of the shape. + * @return {!o3djs.picking.ShapeInfo} The new ShapeInfo. + */ +o3djs.picking.PickManager.prototype.createShapeInfo = function(shape, parent) { + return new o3djs.picking.ShapeInfo(shape, parent, this); +}; + +/** + * Creates a new TransformInfo. + * @param {!o3d.Transform} transform Transform to keep info about. + * @param {o3djs.picking.TransformInfo} parent Parent transform of the + * transform. Can be null. + * @return {!o3djs.picking.TransformInfo} The new TransformInfo. + */ +o3djs.picking.PickManager.prototype.createTransformInfo = + function(transform, parent) { + var info = new o3djs.picking.TransformInfo(transform, parent, this); + this.addTransformInfo(info); + return info; +}; + +/** + * Adds a transform info to this PickManager. + * @param {!o3djs.picking.TransformInfo} transformInfo The TransformInfo to add. + */ +o3djs.picking.PickManager.prototype.addTransformInfo = function(transformInfo) { + this.transformInfosByClientId[transformInfo.transform.clientId] = + transformInfo; +}; + +/** + * Removes a transform info from this PickManager. + * @param {!o3djs.picking.TransformInfo} transformInfo The TransformInfo to + * remove. + */ +o3djs.picking.PickManager.prototype.removeTransformInfo = + function(transformInfo) { + delete this.transformInfosByClientId[transformInfo.transform.clientId]; +}; + +/** + * Gets a transform info from this PickManager by transform. + * @param {!o3d.Transform} transform The Transform to get a TransformInfo for. + * @return {o3djs.picking.TransformInfo} The TransformInfo for the transform or + * null if there isn't one. + */ +o3djs.picking.PickManager.prototype.getTransformInfo = function(transform) { + return this.transformInfosByClientId[transform.clientId]; +}; + +/** + * Updates the picking info to match the transform graph in its current state. + */ +o3djs.picking.PickManager.prototype.update = function() { + this.rootTransformInfo.update(); +}; + +/** + * Dumps info about a PickManager + */ +o3djs.picking.PickManager.prototype.dump = function() { + this.rootTransformInfo.dump(); +}; +/** + * Attempts to "pick" objects managed by this PickManager. + * @param {!o3djs.picking.Ray} worldRay A ray in world space to pick against. + * @return {o3djs.picking.PickInfo} Information about the picking. + * null if the ray did not intersect any triangles. + */ +o3djs.picking.PickManager.prototype.pick = function(worldRay) { + return this.rootTransformInfo.pick(worldRay); +}; + +/** + * Creates a PickManager. + * @param {!o3d.Transform} rootTransform The root of the transform graph this + * PickManager should manage. + * @return {!o3djs.picking.PickManager} The created PickManager. + */ +o3djs.picking.createPickManager = function(rootTransform) { + return new o3djs.picking.PickManager(rootTransform); +}; diff --git a/o3d/samples/picking.html b/o3d/samples/picking.html index f4a73a0..3466ff5 100644 --- a/o3d/samples/picking.html +++ b/o3d/samples/picking.html @@ -81,7 +81,7 @@ var g_math; var g_client; var g_pack; var g_viewInfo; -var g_treeInfo; // information about the transform graph. +var g_pickManager; // information about the transform graph. var g_pickInfoElem; var g_debugHelper; var g_debugLineGroup; @@ -93,11 +93,10 @@ var g_highlightShape; var g_finished = false; // for selenium testing. function updateInfo() { - if (!g_treeInfo) { - g_treeInfo = o3djs.picking.createTransformInfo(g_client.root, - null); + if (!g_pickManager) { + g_pickManager = o3djs.picking.createPickManager(g_client.root); } - g_treeInfo.update(); + g_pickManager.update(); } function unSelectAll() { @@ -108,6 +107,8 @@ function unSelectAll() { o3djs.shape.deleteDuplicateShape(g_highlightShape, g_pack); g_highlightShape = null; g_selectedInfo = null; + // Turn off the debug line. + g_debugLine.setVisible(false); } } @@ -152,9 +153,9 @@ function pick(e) { // transform graph and only pick against that subgraph. // Even better, make a separate transform graph with only cubes on it to // represent the animals and use that instead of the actual animals. - g_treeInfo.update(); + g_pickManager.update(); - var pickInfo = g_treeInfo.pick(worldRay); + var pickInfo = g_pickManager.pick(worldRay); if (pickInfo) { select(pickInfo); g_pickInfoElem.innerHTML = pickInfo.shapeInfo.shape.name; @@ -188,7 +189,6 @@ function pick(e) { g_debugLine.setVisible(true); g_debugLine.setEndPoints(worldPosition, normalSpot); } else { - g_debugLine.setVisible(false); g_pickInfoElem.innerHTML = '--nothing--'; } } @@ -198,9 +198,9 @@ function onrender(renderEvent) { g_flashTimer = g_flashTimer % 0.5; if (g_selectedInfo) { if (g_flashTimer < 0.25) { - g_highlightMaterial.getParam('color').value = [1, 1, 1, 1]; + g_highlightMaterial.getParam('emissive').value = [1, 1, 1, 1]; } else { - g_highlightMaterial.getParam('color').value = [0, 0, 0, 1]; + g_highlightMaterial.getParam('emissive').value = [0, 0, 0, 1]; } } } @@ -249,7 +249,7 @@ function loadScene(pack, fileName, parent) { // Update our info updateInfo(); - g_treeInfo.dump(''); + g_pickManager.dump(''); g_finished = true; // for selenium testing. } @@ -292,6 +292,7 @@ function initStep2(clientElements) { g_debugLineGroup = g_debugHelper.createDebugLineGroup(g_client.root); g_debugLine = g_debugLineGroup.addLine(); g_debugLine.setColor([0,1,0,1]); + g_debugLine.setVisible(false); // Create a material for highlighting. g_highlightMaterial = o3djs.material.createConstantMaterial( |