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 "core/pipeline/pipeline_base.h"
19
20 namespace OHOS::Ace {
21 namespace {
22 constexpr int64_t NANOS_TO_MILLS = 1000000;
23 constexpr int32_t CHAIN_NODE_NUMBER = 15;
24 constexpr double DEFAULT_CHAIN_VALUE_ACCURACY = 0.5;
25 constexpr double DEFAULT_CHAIN_VALUE_VELOCITY_ACCURACY = 1000.0;
26 } // namespace
27
ChainAnimationNode(int32_t index,float space,float maxSpace,float minSpace,RefPtr<SpringProperty> springProperty)28 ChainAnimationNode::ChainAnimationNode(
29 int32_t index, float space, float maxSpace, float minSpace, RefPtr<SpringProperty> springProperty)
30 : springProperty_(std::move(springProperty)), index_(index), space_(space), maxSpace_(maxSpace),
31 minSpace_(minSpace), curPosition_(space)
32 {
33 spring_ = AceType::MakeRefPtr<SpringMotion>(space, space, 0.0, springProperty_);
34 spring_->SetAccuracy(DEFAULT_CHAIN_VALUE_ACCURACY);
35 spring_->SetVelocityAccuracy(DEFAULT_CHAIN_VALUE_VELOCITY_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 spaceDelta,float duration)46 void ChainAnimationNode::SetDelta(float delta, float spaceDelta, float duration)
47 {
48 spaceDelta = std::clamp(spaceDelta, minSpace_ - space_, maxSpace_ - space_);
49 spring_->OnTimestampChanged(duration, 0.0f, false);
50 curPosition_ = spring_->GetCurrentPosition();
51 curPosition_ = std::clamp(curPosition_ + delta, minSpace_ - spaceDelta, maxSpace_ - spaceDelta);
52 spring_->Reset(curPosition_, space_, curVelocity_, springProperty_);
53 spaceDelta_ = spaceDelta;
54 }
55
GetDeltaPredict(float delta,float duration)56 float ChainAnimationNode::GetDeltaPredict(float delta, float duration)
57 {
58 spring_->OnTimestampChanged(duration, 0.0f, false);
59 float curPosition = spring_->GetCurrentPosition();
60 curPosition = std::clamp(curPosition + delta, minSpace_, maxSpace_);
61 return curPosition - space_;
62 }
63
GetDelta() const64 float ChainAnimationNode::GetDelta() const
65 {
66 return curPosition_ - space_ + spaceDelta_;
67 }
68
ChainAnimation(float space,float maxSpace,float minSpace,RefPtr<SpringProperty> springProperty)69 ChainAnimation::ChainAnimation(float space, float maxSpace, float minSpace, RefPtr<SpringProperty> springProperty)
70 : springProperty_(springProperty), space_(space), maxSpace_(maxSpace), minSpace_(minSpace)
71 {
72 for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
73 nodes_.emplace(i, AceType::MakeRefPtr<ChainAnimationNode>(i, space, maxSpace, minSpace, springProperty));
74 nodes_.emplace(-i, AceType::MakeRefPtr<ChainAnimationNode>(-i, space, maxSpace, minSpace, springProperty));
75 }
76 auto&& callback = [weak = AceType::WeakClaim(this)](uint64_t duration) {
77 ACE_SCOPED_TRACE("ChainAnimation");
78 auto chain = weak.Upgrade();
79 CHECK_NULL_VOID(chain);
80 chain->TickAnimation();
81 };
82 scheduler_ = AceType::MakeRefPtr<Scheduler>(callback, PipelineBase::GetCurrentContext());
83 }
84
SetDelta(float delta,float overOffset)85 void ChainAnimation::SetDelta(float delta, float overOffset)
86 {
87 auto context = PipelineBase::GetCurrentContext();
88 CHECK_NULL_VOID(context);
89 auto timestamp = context->GetVsyncTime();
90 double duration = 0.0;
91 if (timestamp > timestamp_) {
92 duration = static_cast<double>(timestamp - timestamp_) / static_cast<double>(NANOS_TO_MILLS);
93 }
94 float factor = (1 - conductivity_) * intensity_;
95 if (edgeEffect_ == ChainEdgeEffect::STRETCH) {
96 float spaceDelta = std::abs(overOffset) * edgeEffectIntensity_;
97 for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
98 nodes_[i]->SetDelta(delta * factor, spaceDelta, static_cast<float>(duration));
99 nodes_[-i]->SetDelta(-delta * factor, spaceDelta, static_cast<float>(duration));
100 factor *= conductivity_;
101 }
102 } else {
103 float spaceDelta = overOffset * edgeEffectIntensity_;
104 for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
105 nodes_[i]->SetDelta(delta * factor, -spaceDelta, static_cast<float>(duration));
106 nodes_[-i]->SetDelta(-delta * factor, spaceDelta, static_cast<float>(duration));
107 factor *= conductivity_;
108 spaceDelta *= conductivity_;
109 }
110 }
111 if (!scheduler_->IsActive() && !NearZero(delta)) {
112 scheduler_->Start();
113 }
114 timestamp_ = timestamp;
115 }
116
TickAnimation()117 void ChainAnimation::TickAnimation()
118 {
119 auto context = PipelineBase::GetCurrentContext();
120 CHECK_NULL_VOID(context);
121 auto timestamp = context->GetVsyncTime();
122 double duration = 0.0;
123 if (timestamp > timestamp_) {
124 duration = static_cast<double>(timestamp - timestamp_) / static_cast<double>(NANOS_TO_MILLS);
125 }
126 auto finish = true;
127 for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
128 finish = nodes_[i]->TickAnimation(duration) && finish;
129 finish = nodes_[-i]->TickAnimation(duration) && finish;
130 }
131 if (finish) {
132 scheduler_->Stop();
133 }
134 if (animationCallback_) {
135 animationCallback_();
136 }
137 }
138
GetValue(int32_t index)139 float ChainAnimation::GetValue(int32_t index)
140 {
141 float value = 0.0f;
142 if (index > controlIndex_) {
143 for (int32_t i = 1; i <= index - controlIndex_ && i < CHAIN_NODE_NUMBER; i++) {
144 value += nodes_[i]->GetDelta();
145 }
146 } else if (index < controlIndex_) {
147 for (int32_t i = 1; i <= controlIndex_ - index && i < CHAIN_NODE_NUMBER; i++) {
148 value -= nodes_[-i]->GetDelta();
149 }
150 }
151 return value;
152 }
153
GetValuePredict(int32_t index,float delta)154 float ChainAnimation::GetValuePredict(int32_t index, float delta)
155 {
156 auto context = PipelineBase::GetCurrentContext();
157 CHECK_NULL_RETURN(context, 0);
158 auto timestamp = context->GetVsyncTime();
159 double duration = 0.0;
160 if (timestamp > timestamp_) {
161 duration = static_cast<double>(timestamp - timestamp_) / static_cast<double>(NANOS_TO_MILLS);
162 }
163 float value = 0.0f;
164 float factor = (1 - conductivity_) * intensity_;
165 if (index > controlIndex_) {
166 for (int32_t i = 1; i <= index - controlIndex_ && i < CHAIN_NODE_NUMBER; i++) {
167 value += nodes_[i]->GetDeltaPredict(delta * factor, duration);
168 factor *= conductivity_;
169 }
170 } else if (index < controlIndex_) {
171 for (int32_t i = 1; i <= controlIndex_ - index && i < CHAIN_NODE_NUMBER; i++) {
172 value -= nodes_[-i]->GetDeltaPredict(-delta * factor, duration);
173 factor *= conductivity_;
174 }
175 }
176 return value;
177 }
178
SetControlIndex(int32_t index)179 float ChainAnimation::SetControlIndex(int32_t index)
180 {
181 if (index == controlIndex_) {
182 return 0.0f;
183 }
184 float delta = GetValue(index);
185 if (scheduler_->IsActive()) {
186 std::map<int32_t, RefPtr<ChainAnimationNode>> tmpNodes;
187 int32_t dt = index - controlIndex_;
188 for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
189 auto next = i + dt <= 0 ? i + dt - 1 : i + dt;
190 if (next > -CHAIN_NODE_NUMBER && next < CHAIN_NODE_NUMBER) {
191 tmpNodes[i] = nodes_[next];
192 tmpNodes[i]->SetIndex(i);
193 } else {
194 tmpNodes.emplace(
195 i, AceType::MakeRefPtr<ChainAnimationNode>(i, space_, maxSpace_, minSpace_, springProperty_));
196 }
197 auto prev = dt - i >= 0 ? dt - i + 1 : dt - i;
198 if (prev > -CHAIN_NODE_NUMBER && prev < CHAIN_NODE_NUMBER) {
199 tmpNodes[-i] = nodes_[prev];
200 tmpNodes[-i]->SetIndex(-i);
201 } else {
202 tmpNodes.emplace(
203 -i, AceType::MakeRefPtr<ChainAnimationNode>(-i, space_, maxSpace_, minSpace_, springProperty_));
204 }
205 }
206 nodes_.swap(tmpNodes);
207 }
208 controlIndex_ = index;
209 return delta;
210 }
211
SetSpace(float space,float maxSpace,float minSpace)212 void ChainAnimation::SetSpace(float space, float maxSpace, float minSpace)
213 {
214 space_ = space;
215 maxSpace_ = maxSpace;
216 minSpace_ = minSpace;
217 for (int32_t i = 1; i < CHAIN_NODE_NUMBER; i++) {
218 nodes_[i]->SetSpace(space, maxSpace, minSpace);
219 nodes_[-i]->SetSpace(space, maxSpace, minSpace);
220 }
221 }
222 } // namespace OHOS::Ace
223