• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "chain_animation.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "core/pipeline/pipeline_base.h"
21 
22 namespace OHOS::Ace {
23 namespace {
24 constexpr int64_t NANOS_TO_MILLS = 1000000;
25 constexpr int32_t CHAIN_NODE_NUMBER = 15;
26 constexpr double DEFAULT_CHAIN_VALUE_ACCURACY = 0.1;
27 } // namespace
28 
ChainAnimationNode(int32_t index,float space,float maxSpace,float minSpace,RefPtr<SpringProperty> springProperty)29 ChainAnimationNode::ChainAnimationNode(
30     int32_t index, float space, float maxSpace, float minSpace, RefPtr<SpringProperty> springProperty)
31     : springProperty_(std::move(springProperty)), index_(index), space_(space), maxSpace_(maxSpace),
32       minSpace_(minSpace), curPosition_(space)
33 {
34     spring_ = AceType::MakeRefPtr<SpringMotion>(space, space, 0.0, springProperty_);
35     spring_->SetAccuracy(DEFAULT_CHAIN_VALUE_ACCURACY);
36 }
37 
TickAnimation(float duration)38 bool ChainAnimationNode::TickAnimation(float duration)
39 {
40     spring_->OnTimestampChanged(duration, 0.0f, false);
41     curPosition_ = spring_->GetCurrentPosition();
42     curVelocity_ = spring_->GetCurrentVelocity();
43     return spring_->IsCompleted();
44 }
45 
SetDelta(float delta,float duration)46 void ChainAnimationNode::SetDelta(float delta, float duration)
47 {
48     spring_->OnTimestampChanged(duration, 0.0f, false);
49     curPosition_ = spring_->GetCurrentPosition();
50     curPosition_ = std::clamp(curPosition_ + delta, minSpace_, maxSpace_);
51     spring_->Reset(curPosition_, space_, curVelocity_, springProperty_);
52 }
53 
GetDelta() const54 float ChainAnimationNode::GetDelta() const
55 {
56     return curPosition_ - space_;
57 }
58 
ChainAnimation(float space,float maxSpace,float minSpace,RefPtr<SpringProperty> springProperty)59 ChainAnimation::ChainAnimation(float space, float maxSpace, float minSpace, RefPtr<SpringProperty> springProperty)
60     : springProperty_(springProperty), space_(space), maxSpace_(maxSpace), minSpace_(minSpace)
61 {
62     for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
63         nodes_.emplace(i, AceType::MakeRefPtr<ChainAnimationNode>(i, space, maxSpace, minSpace, springProperty));
64         nodes_.emplace(-i, AceType::MakeRefPtr<ChainAnimationNode>(-i, space, maxSpace, minSpace, springProperty));
65     }
66     auto&& callback = [weak = AceType::WeakClaim(this)](uint64_t duration) {
67         auto chain = weak.Upgrade();
68         CHECK_NULL_VOID_NOLOG(chain);
69         if (!chain->isOverDrag_) {
70             chain->TickAnimation();
71         }
72     };
73     scheduler_ = AceType::MakeRefPtr<Scheduler>(callback, PipelineBase::GetCurrentContext());
74 }
75 
SetDelta(float delta,bool isOverDrag)76 void ChainAnimation::SetDelta(float delta, bool isOverDrag)
77 {
78     auto context = PipelineBase::GetCurrentContext();
79     CHECK_NULL_VOID(context);
80     auto timestamp = context->GetTimeFromExternalTimer();
81     double duration = 0.0;
82     if (!isOverDrag) {
83         duration = static_cast<double>(timestamp - timestamp_) / static_cast<double>(NANOS_TO_MILLS);
84     }
85     float factor = (1 - conductivity_) * intensity_;
86     if (isOverDrag) {
87         factor *= edgeEffectIntensity_;
88     }
89     if (edgeEffect_ == ChainEdgeEffect::STRETCH && isOverDrag) {
90         for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
91             auto value = delta > 0 ? delta * factor : -delta * factor;
92             nodes_[i]->SetDelta(value, static_cast<float>(duration));
93             nodes_[-i]->SetDelta(value, static_cast<float>(duration));
94             factor *= conductivity_;
95         }
96     } else {
97         for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
98             nodes_[i]->SetDelta(delta * factor, static_cast<float>(duration));
99             nodes_[-i]->SetDelta(-delta * factor, static_cast<float>(duration));
100             factor *= conductivity_;
101         }
102     }
103     if (!scheduler_->IsActive()) {
104         scheduler_->Start();
105     }
106     timestamp_ = timestamp;
107     isOverDrag_ = isOverDrag;
108 }
109 
TickAnimation()110 void ChainAnimation::TickAnimation()
111 {
112     auto context = PipelineBase::GetCurrentContext();
113     CHECK_NULL_VOID(context);
114     auto timestamp = context->GetTimeFromExternalTimer();
115     auto duration = static_cast<double>(timestamp - timestamp_) / static_cast<double>(NANOS_TO_MILLS);
116     auto finish = true;
117     for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
118         finish = nodes_[i]->TickAnimation(duration) && finish;
119         finish = nodes_[-i]->TickAnimation(duration) && finish;
120     }
121     if (finish) {
122         scheduler_->Stop();
123     }
124     if (animationCallback_) {
125         animationCallback_();
126     }
127 }
128 
GetValue(int32_t index)129 float ChainAnimation::GetValue(int32_t index)
130 {
131     float value = 0.0f;
132     if (index > controlIndex_) {
133         for (int32_t i = 1; i <= index - controlIndex_ && i < CHAIN_NODE_NUMBER; i++) {
134             value += nodes_[i]->GetDelta();
135         }
136     } else if (index < controlIndex_) {
137         for (int32_t i = 1; i <= controlIndex_ - index && i < CHAIN_NODE_NUMBER; i++) {
138             value -= nodes_[-i]->GetDelta();
139         }
140     }
141     return value;
142 }
143 
SetControlIndex(int32_t index)144 float ChainAnimation::SetControlIndex(int32_t index)
145 {
146     if (index == controlIndex_) {
147         return 0.0f;
148     }
149     float delta = GetValue(index);
150     if (scheduler_->IsActive()) {
151         std::map<int32_t, RefPtr<ChainAnimationNode>> tmpNodes;
152         int32_t dt = index - controlIndex_;
153         for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
154             auto next = i + dt <= 0 ? i + dt - 1 : i + dt;
155             if (next > -CHAIN_NODE_NUMBER && next < CHAIN_NODE_NUMBER) {
156                 tmpNodes[i] = nodes_[next];
157                 tmpNodes[i]->SetIndex(i);
158             } else {
159                 tmpNodes.emplace(
160                     i, AceType::MakeRefPtr<ChainAnimationNode>(i, space_, maxSpace_, minSpace_, springProperty_));
161             }
162             auto prev = dt - i >= 0 ? dt - i + 1 : dt - i;
163             if (prev > -CHAIN_NODE_NUMBER && prev < CHAIN_NODE_NUMBER) {
164                 tmpNodes[-i] = nodes_[prev];
165                 tmpNodes[-i]->SetIndex(-i);
166             } else {
167                 tmpNodes.emplace(
168                     -i, AceType::MakeRefPtr<ChainAnimationNode>(-i, space_, maxSpace_, minSpace_, springProperty_));
169             }
170         }
171         nodes_.swap(tmpNodes);
172     }
173     controlIndex_ = index;
174     return delta;
175 }
176 
SetSpace(float space,float maxSpace,float minSpace)177 void ChainAnimation::SetSpace(float space, float maxSpace, float minSpace)
178 {
179     space_ = space;
180     maxSpace_ = maxSpace;
181     minSpace_ = minSpace;
182     for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
183         nodes_[i]->SetSpace(space, maxSpace, minSpace);
184         nodes_[-i]->SetSpace(space, maxSpace, minSpace);
185     }
186 }
187 
SetOverDrag(bool isOverDrag)188 void ChainAnimation::SetOverDrag(bool isOverDrag)
189 {
190     if (isOverDrag_ == isOverDrag) {
191         return;
192     }
193     isOverDrag_ = isOverDrag;
194     if (!isOverDrag) {
195         auto context = PipelineBase::GetCurrentContext();
196         CHECK_NULL_VOID(context);
197         timestamp_ = context->GetTimeFromExternalTimer();
198     }
199 }
200 } // namespace OHOS::Ace