1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h"
#include <memory>
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/frozen_array.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space_event.h"
#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_utils.h"
#include "ui/gfx/geometry/point3_f.h"
namespace blink {
namespace {
// Bounds must be a valid polygon (at least 3 vertices).
constexpr wtf_size_t kMinimumNumberOfBoundVertices = 3;
float RoundCm(float val) {
// Float round will only round to the nearest whole number. In order to get
// two decimal points of precision, we need to move the decimal out then
// back.
return std::round(val * 100) / 100;
}
Member<DOMPointReadOnly> RoundedDOMPoint(const gfx::Point3F& val) {
return DOMPointReadOnly::Create(RoundCm(val.x()), RoundCm(val.y()),
RoundCm(val.z()), 1.0);
}
} // anonymous namespace
XRBoundedReferenceSpace::XRBoundedReferenceSpace(XRSession* session)
: XRReferenceSpace(
session,
device::mojom::blink::XRReferenceSpaceType::kBoundedFloor),
offset_bounds_geometry_(
MakeGarbageCollected<FrozenArray<DOMPointReadOnly>>()) {}
XRBoundedReferenceSpace::XRBoundedReferenceSpace(
XRSession* session,
XRRigidTransform* origin_offset)
: XRReferenceSpace(
session,
origin_offset,
device::mojom::blink::XRReferenceSpaceType::kBoundedFloor),
offset_bounds_geometry_(
MakeGarbageCollected<FrozenArray<DOMPointReadOnly>>()) {}
XRBoundedReferenceSpace::~XRBoundedReferenceSpace() = default;
void XRBoundedReferenceSpace::EnsureUpdated() const {
// Check first to see if the stage parameters have updated since the last
// call. We only need to update the transform and bounds if it has.
if (stage_parameters_id_ == session()->StageParametersId())
return;
stage_parameters_id_ = session()->StageParametersId();
const device::mojom::blink::VRStageParametersPtr& stage_parameters =
session()->GetStageParameters();
if (stage_parameters) {
// Use the transform given by stage_parameters if available.
mojo_from_bounded_native_ =
std::make_unique<gfx::Transform>(stage_parameters->mojo_from_stage);
// In order to ensure that the bounds continue to line up with the user's
// physical environment we need to transform them from native to offset.
// Bounds are provided in our native coordinate space.
// TODO(https://crbug.com/1008466): move originOffset to separate class? If
// yes, that class would need to apply a transform in the boundsGeometry
// accessor.
gfx::Transform offset_from_native = OffsetFromNativeMatrix();
// We may not have bounds if we've lost tracking after being created.
// Whether we have them or not, we need to clear the existing bounds.
FrozenArray<DOMPointReadOnly>::VectorType offset_bounds_geometry;
if (stage_parameters->bounds &&
stage_parameters->bounds->size() >= kMinimumNumberOfBoundVertices) {
for (const auto& bound : *(stage_parameters->bounds)) {
gfx::Point3F p = offset_from_native.MapPoint(
gfx::Point3F(bound.x(), 0.0, bound.z()));
offset_bounds_geometry.push_back(RoundedDOMPoint(p));
}
}
offset_bounds_geometry_ =
MakeGarbageCollected<FrozenArray<DOMPointReadOnly>>(
std::move(offset_bounds_geometry));
} else {
// If stage parameters aren't available set the transform to null, which
// will subsequently cause this reference space to return null poses.
mojo_from_bounded_native_.reset();
offset_bounds_geometry_ =
MakeGarbageCollected<FrozenArray<DOMPointReadOnly>>();
}
// DispatchEvent inherited from core/dom/events/event_target.h isn't const.
XRBoundedReferenceSpace* mutable_this =
const_cast<XRBoundedReferenceSpace*>(this);
mutable_this->DispatchEvent(
*XRReferenceSpaceEvent::Create(event_type_names::kReset, mutable_this));
}
std::optional<gfx::Transform> XRBoundedReferenceSpace::MojoFromNative() const {
EnsureUpdated();
if (!mojo_from_bounded_native_)
return std::nullopt;
return *mojo_from_bounded_native_;
}
const FrozenArray<DOMPointReadOnly>& XRBoundedReferenceSpace::boundsGeometry()
const {
EnsureUpdated();
return *offset_bounds_geometry_.Get();
}
void XRBoundedReferenceSpace::Trace(Visitor* visitor) const {
visitor->Trace(offset_bounds_geometry_);
XRReferenceSpace::Trace(visitor);
}
void XRBoundedReferenceSpace::OnReset() {
// Anything that would cause an external source to try to tell us that we've
// been reset should have also updated the stage_parameters, and thus caused
// us to reset via that mechanism instead.
}
XRBoundedReferenceSpace* XRBoundedReferenceSpace::cloneWithOriginOffset(
XRRigidTransform* origin_offset) const {
return MakeGarbageCollected<XRBoundedReferenceSpace>(this->session(),
origin_offset);
}
} // namespace blink
|