From d80249cd1cb608029d48df72eab23efacb3ad1fb Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Fri, 28 May 2021 22:22:22 +0200 Subject: [PATCH] Start design of AR abstraction layer --- openVulkanoCpp/AR/ArConstans.hpp | 27 +++ openVulkanoCpp/AR/ArDepthFormat.hpp | 59 +++++ openVulkanoCpp/AR/ArFrame.h | 113 +++++++++ openVulkanoCpp/AR/ArRecorder.h | 90 ++++++++ openVulkanoCpp/AR/ArSession.cpp | 132 +++++++++++ openVulkanoCpp/AR/ArSession.h | 218 ++++++++++++++++++ openVulkanoCpp/AR/ArTrackingState.hpp | 99 ++++++++ openVulkanoCpp/AR/ArType.hpp | 55 +++++ .../AR/Provider/ArCore/ArSessionArCore.cpp | 26 +++ .../AR/Provider/ArCore/ArSessionArCore.h | 32 +++ openVulkanoCpp/AR/Provider/ArSessionNull.hpp | 35 +++ .../AR/Provider/Network/ArSessionStream.cpp | 40 ++++ .../AR/Provider/Network/ArSessionStream.h | 35 +++ .../AR/Provider/Playback/ArFramePlayback.hpp | 52 +++++ 14 files changed, 1013 insertions(+) create mode 100644 openVulkanoCpp/AR/ArConstans.hpp create mode 100644 openVulkanoCpp/AR/ArDepthFormat.hpp create mode 100644 openVulkanoCpp/AR/ArFrame.h create mode 100644 openVulkanoCpp/AR/ArRecorder.h create mode 100644 openVulkanoCpp/AR/ArSession.cpp create mode 100644 openVulkanoCpp/AR/ArSession.h create mode 100644 openVulkanoCpp/AR/ArTrackingState.hpp create mode 100644 openVulkanoCpp/AR/ArType.hpp create mode 100644 openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.cpp create mode 100644 openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.h create mode 100644 openVulkanoCpp/AR/Provider/ArSessionNull.hpp create mode 100644 openVulkanoCpp/AR/Provider/Network/ArSessionStream.cpp create mode 100644 openVulkanoCpp/AR/Provider/Network/ArSessionStream.h create mode 100644 openVulkanoCpp/AR/Provider/Playback/ArFramePlayback.hpp diff --git a/openVulkanoCpp/AR/ArConstans.hpp b/openVulkanoCpp/AR/ArConstans.hpp new file mode 100644 index 0000000..569d3a5 --- /dev/null +++ b/openVulkanoCpp/AR/ArConstans.hpp @@ -0,0 +1,27 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Math/Math.hpp" +#include "Math/Range.hpp" + +namespace openVulkanoCpp::AR +{ + class ArConstants final + { + public: + Math::Matrix4f yuvToRgbMatrix; + Math::Range confidenceValueRange; + + ArConstants() : yuvToRgbMatrix(0), confidenceValueRange(0, 255) + {} + + ArConstants(const Math::Matrix4f& yuvToRgb, const Math::Range confidenceRange) + : yuvToRgbMatrix(yuvToRgb), confidenceValueRange(confidenceRange) + {} + }; +} diff --git a/openVulkanoCpp/AR/ArDepthFormat.hpp b/openVulkanoCpp/AR/ArDepthFormat.hpp new file mode 100644 index 0000000..2dee19d --- /dev/null +++ b/openVulkanoCpp/AR/ArDepthFormat.hpp @@ -0,0 +1,59 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +namespace openVulkanoCpp::AR +{ + class ArDepthFormat final + { + static inline constexpr std::string_view ALT_NAMES[] = { + "Unavailable", "FP32_METER", "FP64_METER", "U16_MILLIMETER", "U32_MILLIMETER" + }; + + public: + enum Format : uint8_t { UNAVAILABLE = 0, METER_FP32, METER_FP64, MILLIMETER_U16, MILLIMETER_U32 }; + + ArDepthFormat() : ArDepthFormat(UNAVAILABLE) {} + + ArDepthFormat(Format format) : m_format(format) {} + + [[nodiscard]] std::string_view GetName() const + { + return magic_enum::enum_name(m_format); + } + + static std::optional GetFromName(std::string_view name) + { + auto result = magic_enum::enum_cast(name); + if (result.has_value()) return ArDepthFormat(result.value()); + return GetFromAltName(name); + } + + [[nodiscard]] const std::string_view& GetAltName() const + { + return ALT_NAMES[m_format]; + } + + static std::optional GetFromAltName(std::string_view name) + { + uint8_t i = 0; + for(const std::string_view& n : ALT_NAMES) + { + if (n == name) return { static_cast(i) }; + i++; + } + return std::nullopt; + } + + operator Format() const { return m_format; } + + private: + Format m_format; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/ArFrame.h b/openVulkanoCpp/AR/ArFrame.h new file mode 100644 index 0000000..2897a97 --- /dev/null +++ b/openVulkanoCpp/AR/ArFrame.h @@ -0,0 +1,113 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Math/Math.hpp" +#include "Math/Timestamp.hpp" +#include "Math/Pose.hpp" +#include "Math/CameraIntrinsic.hpp" +#include "ArDepthFormat.hpp" +#include "ArTrackingState.hpp" + +namespace openVulkanoCpp::AR +{ + class ArImage + { + public: + void* data; + Math::Vector2ui resolution; + }; + + class ArImagePlanar + { + public: + enum class Format { NV12, NV21, RGB, BGR }; + + ArImage luminescenceOrColor; + ArImage uv; + + Math::CameraIntrinsic intrinsic; + Format format = Format::NV12; + + [[nodiscard]] Math::Vector4uc Sample(uint32_t x, uint32_t y, bool asRgb = true) const + { + const uint8_t* lumColBuffer = static_cast(luminescenceOrColor.data); + if (format == Format::BGR) + { + size_t idx = (y * luminescenceOrColor.resolution.x + x) * 3; + return { lumColBuffer[idx + 2], lumColBuffer[idx + 1], lumColBuffer[idx], 255 }; + } + else if (format == Format::RGB) + { + size_t idx = (y * luminescenceOrColor.resolution.x + x) * 3; + return { lumColBuffer[idx], lumColBuffer[idx + 1], lumColBuffer[idx + 2], 255 }; + } + + int iUV = ((y / 2) * uv.resolution.x + x / 2) * 2; + + Math::Vector4uc sample( + lumColBuffer[y * luminescenceOrColor.resolution.x + x], + static_cast(uv.data)[iUV], + static_cast(uv.data)[iUV+1], + 255); + + if (asRgb) + { + Math::Vector4f c(sample); + Math::Matrix4f conversionMatrix( + Math::Vector4f(+1.0000f, +1.0000f, +1.0000f, +0.0000f), + Math::Vector4f(+0.0000f, -0.3441f, +1.7720f, +0.0000f), + Math::Vector4f(+1.4020f, -0.7141f, +0.0000f, +0.0000f), + Math::Vector4f(-0.7010f, +0.5291f, -0.8860f, +1.0000f) + ); + sample = Math::Utils::clamp(conversionMatrix * c, 0.0f, 255.0f); + } + + return sample; + } + }; + + class ArDepthImage + { + public: + ArImage depth; + ArImage confidence; + ArDepthFormat format; + Math::CameraIntrinsic intrinsic; + }; + + class ArFrame + { + protected: + ArFrame() = default; + + public: + virtual ~ArFrame() = default; + + [[nodiscard]] virtual ArTrackingState GetTrackingState() = 0; + + [[nodiscard]] virtual Math::PoseF GetPose() = 0; + + [[nodiscard]] virtual Math::Timestamp GetTimestamp() = 0; + + //[[nodiscard]] virtual Math::Timestamp GetTimestampDepth() = 0; + + [[nodiscard]] virtual ArImagePlanar GetCameraImage() = 0; + + [[nodiscard]] virtual ArDepthImage GetDepthImage() = 0; + + [[nodiscard]] virtual const Math::Matrix4f& GetCameraTransformation() = 0; + + [[nodiscard]] virtual Math::Matrix4f GetCameraViewForCurrentDeviceOrientation() = 0; + + [[nodiscard]] virtual Math::Matrix4f GetCameraProjection(Math::Vector2f viewportSize, float near = 0.25f, float far = 250.0f) = 0; + + [[nodiscard]] virtual float GetConfidenceNormalisationFactor() = 0; + + [[nodiscard]] virtual float GetColorTemperature() const = 0; + }; +} diff --git a/openVulkanoCpp/AR/ArRecorder.h b/openVulkanoCpp/AR/ArRecorder.h new file mode 100644 index 0000000..5b20b62 --- /dev/null +++ b/openVulkanoCpp/AR/ArRecorder.h @@ -0,0 +1,90 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +namespace openVulkanoCpp::AR +{ + enum class RecordingMode + { + /** + * Frames will only be saved when manually requested through ArFrame::Save() + */ + MANUAL, + /** + * Frames will only be saved when the frame is manually requested through ArSession::GetFrame() + */ + FRAME_REQUEST, + /** + * Every new frame will be stored automatically + */ + NEW_FRAME + }; + + class ArRecorder + { + protected: + ArRecorder() = default; + + public: + virtual ~ArRecorder() = default; + + /** + * Starts the recording of the owning AR session + */ + virtual void Start() = 0; + + /** + * Stops the recording of the owning AR session + */ + virtual void Stop() = 0; + + /** + * Sets the directory into which the AR recording should be stored. + * The path needs to be set to make the recording persistent. + * If path is changed after starting the recording, the already running recording will be moved to the new path. + * @param path The path to be used to store the recording + */ + virtual void SetRecordingPath(const std::string& path) = 0; + + /** + * Gets the current recording path + * @return Current recording dir + */ + [[nodiscard]] virtual const std::filesystem::path& GetRecordingPath() const = 0; + + /** + * Checks if a path to be used for the recording has been set. + * If no path has been set the recording will be stored in a temporary location and will be deleted once the recording is stopped. + * @return True if a path has been set and the recording will persist after stopping the recording. + */ + [[nodiscard]] virtual bool IsPersistent() const = 0; + + /** + * Checks if the recording of the AR session is running + * @return True if recording is started + */ + [[nodiscard]] virtual bool IsRecording() const = 0; + + /** + * Sets the used recording mode + * @param mode The mode that should be used to record the current session + */ + void SetRecordingMode(RecordingMode mode) { recordingMode = mode; } + + /** + * Chceks the currently used recording mode for the AR session + * @return The currently used recording mode + */ + [[nodiscard]] RecordingMode SetRecordingMode() { return recordingMode; } + + protected: + RecordingMode recordingMode = RecordingMode::FRAME_REQUEST; + }; +} diff --git a/openVulkanoCpp/AR/ArSession.cpp b/openVulkanoCpp/AR/ArSession.cpp new file mode 100644 index 0000000..89be2c1 --- /dev/null +++ b/openVulkanoCpp/AR/ArSession.cpp @@ -0,0 +1,132 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "ArSession.h" +#ifndef __APPLE__ +#include "Provider/Playback/ArSessionPlayback.h" +#endif +#include "Provider/Network/ArSessionStream.h" +#ifdef __APPLE__ +#include "Provider/ArKit/ArSessionArKit.h" +#else +#ifdef ANDROID +#include "Provider/ArCore/ArSessionArCore.h" +#else +#include "Provider/ArSessionNull.hpp" +#endif +#endif + +namespace openVulkanoCpp::AR +{ + std::vector> ArSession::sessions; + std::weak_ptr ArSession::nativeSession; + + ArCreateResult ArSession::Create(const ArSessionConfig& config) + { + if (!IsNativeArAvailable()) + { + return { nullptr, ArCreateResult::FAILED_NOT_SUPPORTED, "No native AR implementation available for current system." }; + } + if (auto session = nativeSession.lock()) + { + return { session, ArCreateResult::FAILED_ALREADY_CREATED, "Session has already been created. Return existing session." }; + } + if (!GetNativeCapabilities().IsDepthSupported() && config.enableDepth) + { + return { nullptr, ArCreateResult::FAILED_INCOMPATIBLE_CONFIG, "AR depth is not supported on the current system." }; + } + try + { + if (auto session = NATIVE_AR_SESSION_CLASS::Create(config)) + { + return {session, ArCreateResult::SUCCESS, ""}; + } + return { nullptr, ArCreateResult::FAILED_NOT_SUPPORTED, "No implementation for current system." }; + } + catch (const std::exception& e) + { + return { nullptr, ArCreateResult::FAILED_UNKNOWN, e.what() }; + } + catch (...) {} + return { nullptr, ArCreateResult::FAILED_UNKNOWN, "Unknown exception while initializing AR system." }; + } + + ArCreateResult ArSession::CreatePlayback(const std::string& recordingPath, bool autoAdvance) + { + return { nullptr, ArCreateResult::FAILED_NOT_SUPPORTED, "not yet implemented" }; + try + { + /*const auto session = std::make_shared(recordingPath, autoAdvance); + sessions.push_back(session); + return { session, ArCreateResult::SUCCESS, "" };*/ + } + catch (const std::exception& e) + { // TODO error handling + return { nullptr, ArCreateResult::FAILED_INVALID_PATH, e.what() }; + } + catch (...) + {} + return { nullptr, ArCreateResult::FAILED_UNKNOWN, "Unknown exception while initializing AR system." }; + } + + ArCreateResult ArSession::CreateNetwork(const std::string& serverAddress, std::optional requestConfig) + { + return { nullptr, ArCreateResult::FAILED_NOT_SUPPORTED, "not yet implemented" }; + try + { + const auto session = std::make_shared(serverAddress, requestConfig); + sessions.push_back(session); + return { session, ArCreateResult::SUCCESS, "" }; + } + catch (std::exception& e) + {} // TODO error handling + catch (...) + {} + return { nullptr, ArCreateResult::FAILED_UNKNOWN, "Unknown exception while initializing networked AR system." }; + } + + std::future ArSession::CreateNetworkAsync(const std::string& serverAddress, std::optional requestConfig) + { + return std::async(&CreateNetwork, serverAddress, requestConfig); + } + + std::shared_ptr ArSession::GetPrimarySession() + { + const auto activeSessions = GetActiveSessions(); + if (activeSessions.empty()) return nullptr; + return activeSessions[0]; + } + + std::vector> ArSession::GetActiveSessions() + { + std::vector> activeSessions; + + auto it = sessions.begin(); + while(it != sessions.end()) + { + if (auto activeSession = (*it).lock()) + { + activeSessions.push_back(std::move(activeSession)); + } + else + { + it = sessions.erase(it); + } + } + + return activeSessions; + } + + bool ArSession::IsNativeArAvailable() + { + return NATIVE_AR_SESSION_CLASS::IsAvailable(); + } + + const ArSessionCapabilities& ArSession::GetNativeCapabilities() + { + return NATIVE_AR_SESSION_CLASS::GetCapabilities(); + } +} diff --git a/openVulkanoCpp/AR/ArSession.h b/openVulkanoCpp/AR/ArSession.h new file mode 100644 index 0000000..08e805a --- /dev/null +++ b/openVulkanoCpp/AR/ArSession.h @@ -0,0 +1,218 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "ArType.hpp" +#include "ArConstans.hpp" +#include "ArTrackingState.hpp" +#include "Math/Range.hpp" +#include "Base/Event.hpp" +#include +#include +#include +#include +#include + +namespace openVulkanoCpp::AR +{ + class ArSession; + class ArFrame; + class ArRecorder; + + enum class ArSessionType + { + NATIVE, PLAYBACK, NETWORK_STREAM + }; + + class ArSessionCapabilities final + { + ArType type = ArType::UNKNOWN; + ArSessionType sessionType = ArSessionType::NATIVE; + bool uncompressed = true; + bool depthSupported = false; + bool recordingSupported = false; + + public: + ArSessionCapabilities() = default; + + ArSessionCapabilities(const ArType type, const ArSessionType sessionType, const bool uncompressed, const bool depthSupported, const bool recordingSupported) + : type(type), sessionType(sessionType), uncompressed(uncompressed), depthSupported(depthSupported), recordingSupported(recordingSupported) + {} + + [[nodiscard]] bool IsUncompressed() const { return uncompressed; } + [[nodiscard]] bool IsDepthSupported() const { return depthSupported; } + [[nodiscard]] bool IsRecordingSupported() const { return recordingSupported; } + [[nodiscard]] bool IsNative() const { return sessionType == ArSessionType::NATIVE; } + [[nodiscard]] bool IsPlayback() const { return sessionType == ArSessionType::PLAYBACK; } + [[nodiscard]] bool IsStream() const { return sessionType == ArSessionType::NETWORK_STREAM; } + [[nodiscard]] ArType GetArType() const { return type; } + [[nodiscard]] ArSessionType GetSessionType() const { return sessionType; } + }; + + struct ArSessionConfig + { + bool enableDepth = true; + }; + + struct ArCreateResult + { + enum Status { SUCCESS, FAILED_UNKNOWN, FAILED_INCOMPATIBLE_CONFIG, FAILED_ALREADY_CREATED, FAILED_NOT_SUPPORTED, FAILED_INVALID_PATH, FAILED_TIMEOUT, FAILED_INVALID_SERVER }; + + const std::shared_ptr session; + const Status status; + const std::string statusMessage; + + [[nodiscard]] bool IsSuccess() const { return status == SUCCESS; } + }; + + class ArSession + { + public: + /** + * Creates a platform native AR session. nullptr if failed to create session. + * @return ArCreateResult about the status of the AR session creation. The session pointer will always be nullptr unless the status is SUCCESS or FAILED_ALREADY_CREATED (in this case the session pointer will point to the previously created instance). + */ + [[nodiscard]] static ArCreateResult Create(const ArSessionConfig& config = {}); + + /** + * Creates a playback AR session. nullptr if failed to create session for given path. + * @param recordingPath Path to a previously recorded AR session. + * @param autoAdvance If set to true the playback will advance based on the stored timestamps. If set to false it will only advance if a new frame is requested. + * @return ArCreateResult about the status of the AR session creation. The session pointer will always be nullptr unless the status is SUCCESS. + */ + [[nodiscard]] static ArCreateResult CreatePlayback(const std::string& recordingPath, bool autoAdvance = true); + + /** + * Creates a network streamed AR session. nullptr if failed to create session for given address. This will block till the connection with the remote host has been established. + * @param serverAddress The address of the server that is hosting the AR session. + * @param requestConfig An optional config to be requested. It is not guaranteed that this will be honored (especially in multi guest sessions). + * @return ArCreateResult about the status of the AR session creation. The session pointer will always be nullptr unless the status is SUCCESS. + */ + [[nodiscard]] static ArCreateResult CreateNetwork(const std::string& serverAddress, std::optional requestConfig = std::nullopt); + + /** + * Creates a network streamed AR session. nullptr if failed to create session for given address. + * @param serverAddress The address of the server that is hosting the AR session. + * @param requestConfig An optional config to be requested. It is not guaranteed that this will be honored (especially in multi guest sessions). + * @return ArCreateResult about the status of the AR session creation. The session pointer will always be nullptr unless the status is SUCCESS. + */ + [[nodiscard]] static std::future CreateNetworkAsync(const std::string& serverAddress, std::optional requestConfig = std::nullopt); + + /** + * Gets the primary session. This is the longest running session. + * @return The primary ar session. nullptr if no active session. + */ + [[nodiscard]] static std::shared_ptr GetPrimarySession(); + + /** + * Gets all the active ar sessions. + * @return Vector of active ar sessions. + */ + [[nodiscard]] static std::vector> GetActiveSessions(); + + /** + * Gets the capabilities of the native AR system. + * @return ArSessionCapabilities for the current system. + */ + [[nodiscard]] static const ArSessionCapabilities& GetNativeCapabilities(); + + /** + * Checks if a native AR implementation is available for this system. If false the Create(...) call will fail and only CreatePlayback(...) and CreateNetwork(...) are available. + * @return true if there is a native AR system available. false if not. + */ + static bool IsNativeArAvailable(); + + virtual ~ArSession() = default; + + /** + * Starts the AR session. + */ + virtual void Start() = 0; + + /** + * Stops the AR session. + */ + virtual void Stop() = 0; + + /** + * Pauses the AR session. The behaviour of this will depend on the type of the AR session. + * The type can be checked with the GetSessionType() method. + * NATIVE: The session will continue to run, but GetFrame() will block until continued and events will not be triggered. + * PLAYBACK: There will be no new frames being read from the recording until continued. As a result GetFrame() will block until continued and no events will be triggered. + * NETWORK_STREAM: The session on the remote host will stay active. Data might still be sent to the client (in multi client mode). But no data will be forwarded to app and thus GetFrame() will block until continued and no events will be triggered. + */ + virtual void Pause() { paused = true; } + + /** + * Checks if the AR session is running. Will be true while paused! + * @return True if the AR session is running. False if not. + */ + [[nodiscard]] virtual bool IsRunning() const { return running; }; + + /** + * Checks if the AR session is paused. + * @return True if the AR session is paused. False if not. + */ + [[nodiscard]] virtual bool IsPaused() const { return paused; }; + + /** + * Gets the next ArFrame. Is guaranteed to be a new frame. Will block till new frame is available or an internal timeout is reached. + * @return Next ArFrame, or nullptr if no more frames are available or internal timeout was reached. + */ + [[nodiscard]] virtual std::shared_ptr GetFrame() = 0; + + /** + * The ArRecorder for this ArSession. + * @return ArRecorder instance or nullptr if the ArSession does not support recording. + */ + [[nodiscard]] virtual ArRecorder* GetRecorder() = 0; + + /** + * Gets the type of the AR session. + * @return Type of the AR session. + */ + [[nodiscard]] virtual ArSessionType GetSessionType() = 0; + + /** + * Gets the type of the AR system backed by this session. + * @return The type of the AR system used by this session. + */ + [[nodiscard]] virtual ArType GetArType() = 0; + + virtual void RequestHighResolutionFrame() {} + + /** + * Gets the capabilities for this ArSession. + * @return The capabilities for the current AR session. + */ + [[nodiscard]] const ArSessionCapabilities& GetCapabilities() const { return capabilities; }; + + [[nodiscard]] const ArConstants& GetConstants() const { return constants; } + + [[nodiscard]] bool GetShouldAttemptRelocalization() { return shouldAttemptRelocalization; } + + void SetShouldAttemptRelocalization(bool attemptReloc) { shouldAttemptRelocalization = attemptReloc; } + + Event<> OnNewFrameAvailable; + Event&> OnNewFrame; + Event OnSessionInterruptionChange; + Event OnTrackingStateChanged; + Event OnNewCameraTransformation; + Event OnNewCameraViewMatrix; + Event OnSessionFailed; + Event<> OnAnchorsUpdated; + + protected: + bool running = false, paused = false, shouldAttemptRelocalization = false; + ArSessionCapabilities capabilities; + ArConstants constants; + + private: + static std::vector> sessions; + static std::weak_ptr nativeSession; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/ArTrackingState.hpp b/openVulkanoCpp/AR/ArTrackingState.hpp new file mode 100644 index 0000000..fa38d10 --- /dev/null +++ b/openVulkanoCpp/AR/ArTrackingState.hpp @@ -0,0 +1,99 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +namespace openVulkanoCpp::AR +{ + class ArTrackingState final + { + static inline constexpr std::string_view ALT_NAMES[] = { + "unknown", "notAvailable", "limitedInitializing", + "limitedRelocalizing", "limitedExcessiveMotion", + "limitedInsufficientFeatures", "normal", "paused" + }; + + public: + enum State : uint8_t + { + UNKNOWN, + UNAVAILABLE, + INITIALIZING, + RELOCALIZING, + EXCESSIVE_MOTION, + INSUFFICIENT_FEATURES, + NORMAL, + PAUSED + }; + + ArTrackingState() : ArTrackingState(UNKNOWN) {} + + ArTrackingState(State state) : m_state(state) {} + + [[nodiscard]] constexpr bool IsLimited() const + { + return m_state > UNAVAILABLE && m_state < NORMAL; + } + + [[nodiscard]] constexpr bool IsUnavailable() const + { + return m_state == PAUSED || m_state == UNAVAILABLE; + } + + [[nodiscard]] constexpr bool IsGood() const + { + return m_state == NORMAL; + } + + [[nodiscard]] constexpr bool IsPaused() const + { + return m_state == PAUSED; + } + + [[nodiscard]] constexpr std::string_view GetName() const + { + return magic_enum::enum_name(m_state); + } + + [[nodiscard]] constexpr std::string_view GetAltName() const + { + return ALT_NAMES[m_state]; + } + + [[nodiscard]] constexpr bool operator ==(State rhs) + { + return m_state == rhs; + } + + [[nodiscard]] constexpr bool operator !=(State rhs) + { + return m_state != rhs; + } + + static ArTrackingState GetFromName(std::string_view name) + { + auto result = magic_enum::enum_cast(name); + if (result.has_value()) return ArTrackingState(result.value()); + return GetFromAltName(name); + } + + static ArTrackingState GetFromAltName(std::string_view name) + { + uint8_t i = 0; + for(const std::string_view& n : ALT_NAMES) + { + if (n == name) return static_cast(i); + i++; + } + return UNKNOWN; + } + + private: + State m_state; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/ArType.hpp b/openVulkanoCpp/AR/ArType.hpp new file mode 100644 index 0000000..c81650a --- /dev/null +++ b/openVulkanoCpp/AR/ArType.hpp @@ -0,0 +1,55 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +namespace openVulkanoCpp::AR +{ + class ArType final + { + static inline constexpr std::string_view HUMAN_READABLE_NAMES[] = { "Unknown", "ARKit", "ARCore" }; + + public: + enum Type : uint8_t { UNKNOWN = 0, AR_KIT, AR_CORE }; + + ArType() : ArType(UNKNOWN) {} + + ArType(Type type) : m_type(type) {} + + [[nodiscard]] std::string_view GetName() const + { + return magic_enum::enum_name(m_type); + } + + static ArType GetFromName(std::string_view name) + { + auto result = magic_enum::enum_cast(name); + if (result.has_value()) return { result.value() }; + return GetFromHumanReadableName(name); + } + + [[nodiscard]] const std::string_view& GetHumanReadableName() const + { + return HUMAN_READABLE_NAMES[m_type]; + } + + static ArType GetFromHumanReadableName(const std::string_view& name) + { + uint8_t i = 0; + for (const std::string_view& n : HUMAN_READABLE_NAMES) + { + if (n == name) return {static_cast(i)}; + i++; + } + return UNKNOWN; + } + + private: + Type m_type; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.cpp b/openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.cpp new file mode 100644 index 0000000..6c7928d --- /dev/null +++ b/openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.cpp @@ -0,0 +1,26 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "ArSessionArCore.h" + +namespace openVulkanoCpp::AR::ArCore +{ + std::shared_ptr ArSessionArCore::Create(const ArSessionConfig& config) + { + return nullptr; // TODO + } + + bool ArSessionArCore::IsAvailable() + { + return false; + } + + const ArSessionCapabilities& ArSessionArCore::GetCapabilities() + { + static ArSessionCapabilities capabilities; // TODO setup + return capabilities; + } +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.h b/openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.h new file mode 100644 index 0000000..955607e --- /dev/null +++ b/openVulkanoCpp/AR/Provider/ArCore/ArSessionArCore.h @@ -0,0 +1,32 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "AR/ArSession.h" + +// Define the class of the native AR session to be used +#define NATIVE_AR_SESSION_CLASS ArCore::ArSessionArCore + +namespace openVulkanoCpp::AR::ArCore +{ + class ArSessionArCore : public ArSession + { + public: + [[nodiscard]] static std::shared_ptr Create(const ArSessionConfig& config); + + [[nodiscard]] static bool IsAvailable(); + + [[nodiscard]] static const ArSessionCapabilities& GetCapabilities(); + + [[nodiscard]] ArSessionType GetSessionType() final { return ArSessionType::NATIVE; } + + [[nodiscard]] ArType GetArType() final { return ArType::AR_CORE; } + + protected: + ~ArSessionArCore() override = default; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/Provider/ArSessionNull.hpp b/openVulkanoCpp/AR/Provider/ArSessionNull.hpp new file mode 100644 index 0000000..8d788fa --- /dev/null +++ b/openVulkanoCpp/AR/Provider/ArSessionNull.hpp @@ -0,0 +1,35 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "AR/ArSession.h" + +// Define the class of the native AR session to be used +#define NATIVE_AR_SESSION_CLASS ArSessionNull + +namespace openVulkanoCpp::AR +{ + struct ArSessionNull final + { + inline static const ArSessionCapabilities AR_CAPS_UNAVAILABLE; + + static std::shared_ptr Create(const ArSessionConfig& config) + { + return nullptr; + } + + static bool IsAvailable() + { + return false; + } + + static const ArSessionCapabilities& GetCapabilities() + { + return AR_CAPS_UNAVAILABLE; + } + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/AR/Provider/Network/ArSessionStream.cpp b/openVulkanoCpp/AR/Provider/Network/ArSessionStream.cpp new file mode 100644 index 0000000..70b42e5 --- /dev/null +++ b/openVulkanoCpp/AR/Provider/Network/ArSessionStream.cpp @@ -0,0 +1,40 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "ArSessionStream.h" + +namespace openVulkanoCpp::AR::Network +{ + ArSessionStream::ArSessionStream(const std::string& serverAddress, std::optional requestConfig) + { + // TODO + } + + void ArSessionStream::Start() + { + + } + + void ArSessionStream::Stop() + { + + } + + void ArSessionStream::Pause() + { + ArSession::Pause(); + } + + std::shared_ptr ArSessionStream::GetFrame() + { + return nullptr; + } + + ArType ArSessionStream::GetArType() + { + return GetCapabilities().GetArType(); + } +} diff --git a/openVulkanoCpp/AR/Provider/Network/ArSessionStream.h b/openVulkanoCpp/AR/Provider/Network/ArSessionStream.h new file mode 100644 index 0000000..f960e8b --- /dev/null +++ b/openVulkanoCpp/AR/Provider/Network/ArSessionStream.h @@ -0,0 +1,35 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "AR/ArSession.h" + +namespace openVulkanoCpp::AR::Network +{ + class ArSessionStream final : public ArSession + { + public: + ArSessionStream(const std::string& serverAddress, std::optional requestConfig = std::nullopt); + + ~ArSessionStream() override = default; + + void Start() override; + + void Stop() override; + + void Pause() override; + + [[nodiscard]] std::shared_ptr GetFrame() override; + + [[nodiscard]] ArRecorder* GetRecorder() override { return nullptr; } + + [[nodiscard]] ArSessionType GetSessionType() override { return ArSessionType::NETWORK_STREAM; } + + [[nodiscard]] ArType GetArType() override; + }; +} + diff --git a/openVulkanoCpp/AR/Provider/Playback/ArFramePlayback.hpp b/openVulkanoCpp/AR/Provider/Playback/ArFramePlayback.hpp new file mode 100644 index 0000000..c3987e5 --- /dev/null +++ b/openVulkanoCpp/AR/Provider/Playback/ArFramePlayback.hpp @@ -0,0 +1,52 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "AR/ArFrame.h" +#include "ArPlaybackReader.hpp" +#include "ArPlaybackData.hpp" + +namespace openVulkanoCpp::AR::Playback +{ + class ArSessionPlayback; + + class ArFramePlayback final : public ArFrame + { + public: + ArFramePlayback(const std::shared_ptr& session, ArPlaybackReader& frameReader); + + ArTrackingState GetTrackingState() override; + + Math::PoseF GetPose() override; + + Math::Timestamp GetTimestamp() override; + + ArImagePlanar GetCameraImage() override; + + ArDepthImage GetDepthImage() override; + + const Math::Matrix4f& GetCameraTransformation() override; + + Math::Matrix4f GetCameraViewForCurrentDeviceOrientation() override; + + Math::Matrix4f GetCameraProjection(Math::Vector2f viewportSize, float near, float far) override; + + float GetConfidenceNormalisationFactor() override; + + [[nodiscard]] float GetColorTemperature() const override; + + private: + ArPlaybackFrameData frameData; + ArImagePlanar colorImage; + ArDepthImage depthImage; + + std::unique_ptr confImgData; + std::unique_ptr depthImgData; + ColorImg colorImgData; + //cv::Mat colorImgData; + }; +}