1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ModeSelector.h"
18 
19 namespace android {
20 namespace media {
21 
ModeSelector(const Options & options,HeadTrackingMode initialMode)22 ModeSelector::ModeSelector(const Options& options, HeadTrackingMode initialMode)
23     : mOptions(options), mDesiredMode(initialMode), mActualMode(initialMode) {}
24 
setDesiredMode(HeadTrackingMode mode)25 void ModeSelector::setDesiredMode(HeadTrackingMode mode) {
26     mDesiredMode = mode;
27 }
28 
setScreenToStagePose(const Pose3f & screenToStage)29 void ModeSelector::setScreenToStagePose(const Pose3f& screenToStage) {
30     mScreenToStage = screenToStage;
31 }
32 
setScreenToHeadPose(int64_t timestamp,const std::optional<Pose3f> & screenToHead)33 void ModeSelector::setScreenToHeadPose(int64_t timestamp,
34                                        const std::optional<Pose3f>& screenToHead) {
35     mScreenToHead = screenToHead;
36     mScreenToHeadTimestamp = timestamp;
37 }
38 
setWorldToHeadPose(int64_t timestamp,const Pose3f & worldToHead)39 void ModeSelector::setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead) {
40     mWorldToHead = worldToHead;
41     mWorldToHeadTimestamp = timestamp;
42 }
43 
calculateActualMode(int64_t timestamp)44 void ModeSelector::calculateActualMode(int64_t timestamp) {
45     bool isValidScreenToHead = mScreenToHead.has_value() &&
46                                timestamp - mScreenToHeadTimestamp < mOptions.freshnessTimeout;
47     bool isValidWorldToHead = mWorldToHead.has_value() &&
48                               timestamp - mWorldToHeadTimestamp < mOptions.freshnessTimeout;
49 
50     HeadTrackingMode mode = mDesiredMode;
51 
52     // Optional downgrade from screen-relative to world-relative.
53     if (mode == HeadTrackingMode::SCREEN_RELATIVE) {
54         if (!isValidScreenToHead) {
55             mode = HeadTrackingMode::WORLD_RELATIVE;
56         }
57     }
58 
59     // Optional downgrade from world-relative to static.
60     if (mode == HeadTrackingMode::WORLD_RELATIVE) {
61         if (!isValidWorldToHead) {
62             mode = HeadTrackingMode::STATIC;
63         }
64     }
65 
66     mActualMode = mode;
67 }
68 
calculate(int64_t timestamp)69 void ModeSelector::calculate(int64_t timestamp) {
70     calculateActualMode(timestamp);
71 
72     switch (mActualMode) {
73         case HeadTrackingMode::STATIC:
74             mHeadToStage = mScreenToStage;
75             break;
76 
77         case HeadTrackingMode::WORLD_RELATIVE:
78             mHeadToStage = mWorldToHead.value().inverse() * mScreenToStage;
79             break;
80 
81         case HeadTrackingMode::SCREEN_RELATIVE:
82             mHeadToStage = mScreenToHead.value().inverse() * mScreenToStage;
83             break;
84     }
85 }
86 
getHeadToStagePose() const87 Pose3f ModeSelector::getHeadToStagePose() const {
88     return mHeadToStage;
89 }
90 
getActualMode() const91 HeadTrackingMode ModeSelector::getActualMode() const {
92     return mActualMode;
93 }
94 
95 }  // namespace media
96 }  // namespace android
97