blob: 5e9672f1f36fc9b4a81d5681e8846d2e3f05513c [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_VR_ANDROID_ARCORE_ARCORE_PLANE_MANAGER_H_
#define DEVICE_VR_ANDROID_ARCORE_ARCORE_PLANE_MANAGER_H_
#include <map>
#include "base/types/id_type.h"
#include "base/types/pass_key.h"
#include "device/vr/android/arcore/address_to_id_map.h"
#include "device/vr/android/arcore/arcore_sdk.h"
#include "device/vr/android/arcore/scoped_arcore_objects.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace device {
class ArCoreImpl;
class ArCoreAnchorManager;
using PlaneId = base::IdTypeU64<class PlaneTag>;
std::pair<gfx::Quaternion, gfx::Point3F> GetPositionAndOrientationFromArPose(
const ArSession* session,
const ArPose* pose);
device::Pose GetPoseFromArPose(const ArSession* session, const ArPose* pose);
device::internal::ScopedArCoreObject<ArPose*> GetArPoseFromMojomPose(
const ArSession* session,
const device::mojom::Pose& pose);
class ArCorePlaneManager {
public:
ArCorePlaneManager(base::PassKey<ArCoreImpl> pass_key,
ArSession* arcore_session);
~ArCorePlaneManager();
// Updates plane manager state - it should be called in every frame if the
// ARCore session supports plane detection. Currently, if the WebXR session
// supports hit test feature or plane detection feature, the ARCore session
// needs to be configured with planes enabled and this method needs to be
// called.
void Update(ArFrame* ar_frame);
mojom::XRPlaneDetectionDataPtr GetDetectedPlanesData() const;
bool PlaneExists(PlaneId id) const;
// Returns absl::nullopt if plane with the given address does not exist.
absl::optional<PlaneId> GetPlaneId(void* plane_address) const;
// Returns absl::nullopt if plane with the given id does not exist.
absl::optional<gfx::Transform> GetMojoFromPlane(PlaneId id) const;
// Creates Anchor object given a plane ID. This is needed since Plane objects
// are managed by this class in its entirety and are not accessible outside
// it. Callable only from ArCoreAnchorManager.
device::internal::ScopedArCoreObject<ArAnchor*> CreateAnchor(
base::PassKey<ArCoreAnchorManager> pass_key,
PlaneId id,
const device::mojom::Pose& pose) const;
private:
struct PlaneInfo {
device::internal::ScopedArCoreObject<ArTrackable*> plane;
ArTrackingState tracking_state;
PlaneInfo(device::internal::ScopedArCoreObject<ArTrackable*> plane,
ArTrackingState tracking_state);
PlaneInfo(PlaneInfo&& other);
~PlaneInfo();
};
// Executes |fn| for each still tracked, non-subsumed plane present in
// |arcore_planes|. |fn| will receive 3 parameters - a
// `ScopedArCoreObject<ArAnchor*>` that can be stored, the non-owning ArPlane*
// typecast from the first parameter, and ArTrackingState. A plane is tracked
// if its state is not AR_TRACKING_STATE_STOPPED.
template <typename FunctionType>
void ForEachArCorePlane(ArTrackableList* arcore_planes, FunctionType fn);
// Owned by ArCoreImpl - non-owning pointer is fine since ArCorePlaneManager
// is also owned by ArCoreImpl.
ArSession* arcore_session_;
// List of trackables - used for retrieving planes detected by ARCore.
// Allows reuse of the list across updates; ARCore clears the list on each
// call to the ARCore SDK.
internal::ScopedArCoreObject<ArTrackableList*> arcore_planes_;
// Allows reuse of the pose object; ARCore will populate it with new data on
// each call to the ARCore SDK.
internal::ScopedArCoreObject<ArPose*> ar_pose_;
// Mapping from plane address to plane ID. It should be modified only during
// calls to |Update()|.
AddressToIdMap<PlaneId> plane_address_to_id_;
// Mapping from plane ID to ARCore plane information. It should be modified
// only during calls to |Update()|.
std::map<PlaneId, PlaneInfo> plane_id_to_plane_info_;
// Set containing IDs of planes updated in the last frame. It should be
// modified only during calls to |Update()|.
std::set<PlaneId> updated_plane_ids_;
#if DCHECK_IS_ON()
// True if |GetDetectedPlanesData()| was called after |Update()|. It is used
// to track if |Update()| was called twice in a row w/o a call to
// |GetDetectedPlanesData()| in between. Initially true since we expect the
// call to |Update()| to happen next.
// TODO(https://crbug.com/1192844): remove the assumption that the calls to
// |Update()| will always be followed by at least one call to
// |GetDetectedPlanesData()| before the next call to |Update()| happens.
mutable bool was_plane_data_retrieved_in_current_frame_ = true;
#endif
};
} // namespace device
#endif // DEVICE_VR_ANDROID_ARCORE_ARCORE_PLANE_MANAGER_H_