diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4f5db991c8..cf20179250 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1769,7 +1769,6 @@ void EntityItem::updateDimensions(const glm::vec3& value) { setDimensions(value); markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); _queryAACubeSet = false; - dimensionsChanged(); } } diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 9a1a500a54..4115a606df 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -51,12 +51,12 @@ namespace entity { } } -// shapeCalculator is a hook for external code that knows how to configure a ShapeInfo +// hullShapeCalculator is a hook for external code that knows how to configure a ShapeInfo // for given entity::Shape and dimensions -ShapeEntityItem::ShapeInfoCalculator shapeCalculator = nullptr; +ShapeEntityItem::ShapeInfoCalculator hullShapeCalculator = nullptr; void ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator callback) { - shapeCalculator = callback; + hullShapeCalculator = callback; } ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -104,6 +104,14 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { case entity::Shape::Sphere: _type = EntityTypes::Sphere; break; + case entity::Shape::Circle: + // Circle is implicitly flat so we enforce flat dimensions + setDimensions(getDimensions()); + break; + case entity::Shape::Quad: + // Quad is implicitly flat so we enforce flat dimensions + setDimensions(getDimensions()); + break; default: _type = EntityTypes::Shape; break; @@ -196,6 +204,18 @@ void ShapeEntityItem::setColor(const QColor& value) { setAlpha(value.alpha()); } +void ShapeEntityItem::setDimensions(const glm::vec3& value) { + const float MAX_FLAT_DIMENSION = 0.0001f; + if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { + // enforce flatness in Y + glm::vec3 newDimensions = value; + newDimensions.y = MAX_FLAT_DIMENSION; + EntityItem::setDimensions(newDimensions); + } else { + EntityItem::setDimensions(value); + } +} + bool ShapeEntityItem::supportsDetailedRayIntersection() const { return _shape == entity::Sphere; } @@ -249,19 +269,13 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { const glm::vec3 entityDimensions = getDimensions(); switch (_shape){ - case entity::Shape::Quad: { - // Not in GeometryCache::buildShapes, unsupported. - _collisionShapeType = SHAPE_TYPE_ELLIPSOID; - //TODO WL21389: Add a SHAPE_TYPE_QUAD ShapeType and treat - // as a special box (later if desired support) - } - break; + case entity::Shape::Quad: + // Quads collide like flat Cubes case entity::Shape::Cube: { _collisionShapeType = SHAPE_TYPE_BOX; } break; case entity::Shape::Sphere: { - float diameter = entityDimensions.x; const float MIN_DIAMETER = 0.001f; const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; @@ -275,25 +289,28 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { } } break; - case entity::Shape::Circle: { - _collisionShapeType = SHAPE_TYPE_CIRCLE; - } - break; + case entity::Shape::Circle: + // Circles collide like flat Cylinders case entity::Shape::Cylinder: { - _collisionShapeType = SHAPE_TYPE_CYLINDER_Y; - // TODO WL21389: determine if rotation is axis-aligned - //const Transform::Quat & rot = _transform.getRotation(); - - // TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and - // hull ( or dimensions, need circular cross section) - // Should allow for minor variance along axes? - + float diameter = entityDimensions.x; + const float MIN_DIAMETER = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (diameter > MIN_DIAMETER + && fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) { + _collisionShapeType = SHAPE_TYPE_SPHERE; + } else if (hullShapeCalculator) { + hullShapeCalculator(this, info); + _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; + } else { + // woops, someone forgot to hook up the hullShapeCalculator()! + // final fallback is ellipsoid + _collisionShapeType = SHAPE_TYPE_ELLIPSOID; + } } break; case entity::Shape::Cone: { - if (shapeCalculator) { - shapeCalculator(this, info); - // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL) + if (hullShapeCalculator) { + hullShapeCalculator(this, info); _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; } else { _collisionShapeType = SHAPE_TYPE_ELLIPSOID; @@ -304,9 +321,8 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { case entity::Shape::Triangle: case entity::Shape::Hexagon: case entity::Shape::Octagon: { - if (shapeCalculator) { - shapeCalculator(this, info); - // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL) + if (hullShapeCalculator) { + hullShapeCalculator(this, info); _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; } else { _collisionShapeType = SHAPE_TYPE_ELLIPSOID; @@ -318,9 +334,8 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { case entity::Shape::Octahedron: case entity::Shape::Dodecahedron: case entity::Shape::Icosahedron: { - if ( shapeCalculator ) { - shapeCalculator(this, info); - // shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL) + if ( hullShapeCalculator ) { + hullShapeCalculator(this, info); _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; } else { _collisionShapeType = SHAPE_TYPE_ELLIPSOID; @@ -330,7 +345,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { case entity::Shape::Torus: { // Not in GeometryCache::buildShapes, unsupported. _collisionShapeType = SHAPE_TYPE_ELLIPSOID; - //TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support) + //TODO handle this shape more correctly } break; default: { diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index a88a2098e9..20e36c88e6 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -80,6 +80,8 @@ public: const rgbColor& getColor() const { return _color; } void setColor(const rgbColor& value); + void setDimensions(const glm::vec3& value) override; + xColor getXColor() const; void setColor(const xColor& value); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index f35fb9f830..fa00737e3c 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -482,8 +482,10 @@ void GeometryCache::buildShapes() { using namespace geometry; auto vertexBuffer = std::make_shared(); auto indexBuffer = std::make_shared(); - // Cube + // Cube setupFlatShape(_shapes[Cube], geometry::cube(), _shapeVertices, _shapeIndices); + //Quad renders as flat Cube + setupFlatShape(_shapes[Quad], geometry::cube(), _shapeVertices, _shapeIndices); // Tetrahedron setupFlatShape(_shapes[Tetrahedron], geometry::tetrahedron(), _shapeVertices, _shapeIndices); // Icosahedron @@ -524,12 +526,10 @@ void GeometryCache::buildShapes() { extrudePolygon<64>(_shapes[Cylinder], _shapeVertices, _shapeIndices); //Cone, extrudePolygon<64>(_shapes[Cone], _shapeVertices, _shapeIndices, true); - //Circle - drawCircle(_shapes[Circle], _shapeVertices, _shapeIndices); + // Circle renders as flat Cylinder + extrudePolygon<64>(_shapes[Circle], _shapeVertices, _shapeIndices); // Not implemented yet: - //Quad, - //Torus, - + //Torus, } const GeometryCache::ShapeData * GeometryCache::getShapeData(const Shape shape) const { diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 565a67e116..7843f3a18a 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -225,28 +225,41 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } function getAttachPointForHotspotFromSettings(hotspot, hand) { + var skeletonModelURL = MyAvatar.skeletonModelURL; var attachPointSettings = getAttachPointSettings(); - var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand"; - var joints = attachPointSettings[hotspot.key]; - if (joints) { - return joints[jointName]; - } else { - return undefined; + var avatarSettingsData = attachPointSettings[skeletonModelURL]; + if (avatarSettingsData) { + var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand"; + var joints = avatarSettingsData[hotspot.key]; + if (joints) { + return joints[jointName]; + } } + return undefined; } function storeAttachPointForHotspotInSettings(hotspot, hand, offsetPosition, offsetRotation) { var attachPointSettings = getAttachPointSettings(); + var skeletonModelURL = MyAvatar.skeletonModelURL; + var avatarSettingsData = attachPointSettings[skeletonModelURL]; + if (!avatarSettingsData) { + avatarSettingsData = {}; + attachPointSettings[skeletonModelURL] = avatarSettingsData; + } var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand"; - var joints = attachPointSettings[hotspot.key]; + var joints = avatarSettingsData[hotspot.key]; if (!joints) { joints = {}; - attachPointSettings[hotspot.key] = joints; + avatarSettingsData[hotspot.key] = joints; } joints[jointName] = [offsetPosition, offsetRotation]; setAttachPointSettings(attachPointSettings); } + function clearAttachPoints() { + setAttachPointSettings({}); + } + function EquipEntity(hand) { this.hand = hand; this.targetEntityID = null; @@ -538,6 +551,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa }; this.endEquipEntity = function () { + this.storeAttachPointInSettings(); Entities.editEntity(this.targetEntityID, { parentID: Uuid.NULL, parentJointIndex: -1 @@ -684,14 +698,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa if (dropDetected && !this.waitForTriggerRelease && this.triggerSmoothedGrab()) { this.waitForTriggerRelease = true; // store the offset attach points into preferences. - if (this.grabbedHotspot && this.targetEntityID) { - var prefprops = Entities.getEntityProperties(this.targetEntityID, ["localPosition", "localRotation"]); - if (prefprops && prefprops.localPosition && prefprops.localRotation) { - storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand, - prefprops.localPosition, prefprops.localRotation); - } - } - this.endEquipEntity(); return makeRunningValues(false, [], []); } @@ -707,6 +713,16 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa return makeRunningValues(true, [this.targetEntityID], []); }; + this.storeAttachPointInSettings = function() { + if (this.grabbedHotspot && this.targetEntityID) { + var prefProps = Entities.getEntityProperties(this.targetEntityID, ["localPosition", "localRotation"]); + if (prefProps && prefProps.localPosition && prefProps.localRotation) { + storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand, + prefProps.localPosition, prefProps.localRotation); + } + } + }; + this.cleanup = function () { if (this.targetEntityID) { this.endEquipEntity(); @@ -751,11 +767,12 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa enableDispatcherModule("LeftEquipEntity", leftEquipEntity); enableDispatcherModule("RightEquipEntity", rightEquipEntity); - this.cleanup = function () { + function cleanup() { leftEquipEntity.cleanup(); rightEquipEntity.cleanup(); disableDispatcherModule("LeftEquipEntity"); disableDispatcherModule("RightEquipEntity"); + clearAttachPoints(); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/tabletStylusInput.js b/scripts/system/controllers/controllerModules/tabletStylusInput.js index beb86d0ef4..46b630d023 100644 --- a/scripts/system/controllers/controllerModules/tabletStylusInput.js +++ b/scripts/system/controllers/controllerModules/tabletStylusInput.js @@ -154,6 +154,25 @@ Script.include("/~/system/libraries/controllers.js"); this.showStylus = function() { if (this.stylus) { + var X_ROT_NEG_90 = { x: -0.70710678, y: 0, z: 0, w: 0.70710678 }; + var modelOrientation = Quat.multiply(this.stylusTip.orientation, X_ROT_NEG_90); + var modelOrientationAngles = Quat.safeEulerAngles(modelOrientation); + + var rotation = Overlays.getProperty(this.stylus, "rotation"); + var rotationAngles = Quat.safeEulerAngles(rotation); + + if(!Vec3.withinEpsilon(modelOrientationAngles, rotationAngles, 1)) { + var modelPositionOffset = Vec3.multiplyQbyV(modelOrientation, { x: 0, y: 0, z: MyAvatar.sensorToWorldScale * -WEB_STYLUS_LENGTH / 2 }); + + var updatedStylusProperties = { + position: Vec3.sum(this.stylusTip.position, modelPositionOffset), + rotation: modelOrientation, + dimensions: Vec3.multiply(MyAvatar.sensorToWorldScale, { x: 0.01, y: 0.01, z: WEB_STYLUS_LENGTH }), + }; + + Overlays.editOverlay(this.stylus, updatedStylusProperties); + } + return; } diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 10ccfc52a7..e7d4aed3fb 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -59,6 +59,7 @@ +