1 /*
2 * Copyright (c) 2024 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 #include "render/rs_attraction_effect_filter.h"
16
17 #include "common/rs_common_def.h"
18 #include "utils/point.h"
19 #include "common/rs_optional_trace.h"
20 #include "platform/common/rs_log.h"
21 #ifdef USE_M133_SKIA
22 #include "src/core/SkChecksum.h"
23 #else
24 #include "src/core/SkOpts.h"
25 #endif
26
27 namespace OHOS {
28 namespace Rosen {
RSAttractionEffectFilter(float attractionFraction)29 RSAttractionEffectFilter::RSAttractionEffectFilter(float attractionFraction)
30 : RSDrawingFilterOriginal(nullptr), attractionFraction_(attractionFraction)
31 {
32 type_ = FilterType::ATTRACTION_EFFECT;
33
34 #ifdef USE_M133_SKIA
35 const auto hashFunc = SkChecksum::Hash32;
36 #else
37 const auto hashFunc = SkOpts::hash;
38 #endif
39 hash_ = hashFunc(&type_, sizeof(type_), 0);
40 hash_ = hashFunc(&attractionFraction_, sizeof(attractionFraction_), hash_);
41 }
42
43 RSAttractionEffectFilter::~RSAttractionEffectFilter() = default;
44
GetDescription()45 std::string RSAttractionEffectFilter::GetDescription()
46 {
47 return "RSAttractionEffectFilter " + std::to_string(attractionFraction_);
48 }
49
IsValid() const50 bool RSAttractionEffectFilter::IsValid() const
51 {
52 constexpr float epsilon = 0.001f;
53 return attractionFraction_ > epsilon;
54 }
55
GetAttractionFraction() const56 float RSAttractionEffectFilter::GetAttractionFraction() const
57 {
58 return attractionFraction_;
59 }
60
GetAttractionDirtyRegion() const61 RectI RSAttractionEffectFilter::GetAttractionDirtyRegion() const
62 {
63 return attractionDirtyRegion_;
64 }
65
IsWithinThreshold(const float left,const float right,const float threshold)66 bool RSAttractionEffectFilter::IsWithinThreshold(const float left, const float right, const float threshold)
67 {
68 return (std::abs(left - right) <= threshold);
69 }
70
LerpPoint(const Drawing::Point & firstPoint,const Drawing::Point & secondPoint,float firstFactor,float secondFactor)71 Drawing::Point RSAttractionEffectFilter::LerpPoint(const Drawing::Point &firstPoint, const Drawing::Point &secondPoint,
72 float firstFactor, float secondFactor)
73 {
74 Drawing::Point p = { 0.0f, 0.0f };
75 p = firstFactor * firstPoint + secondFactor * secondPoint;
76 return p;
77 }
78
CubicBezier(const Drawing::Point & p0,const Drawing::Point & p1,const Drawing::Point & p2,const Drawing::Point & p3,float t)79 Drawing::Point RSAttractionEffectFilter::CubicBezier(const Drawing::Point &p0, const Drawing::Point &p1,
80 const Drawing::Point &p2, const Drawing::Point &p3, float t)
81 {
82 // p(t) = (1 - t)^3 * p0 + 3 * t * (1 - t)^2 * p1 + 3 * t^2 * (1-t) * p2 + t^3 * p3
83 float tSquared = t * t;
84 float tCubed = t * t * t;
85 float u = 1 - t;
86 float uSquared = u * u;
87 float uCubed = u * u * u;
88
89 Drawing::Point p = { 0.0f, 0.0f };
90 float besselCoefficient = 3.0f;
91 p = p0 * uCubed + p1 * besselCoefficient * uSquared * t + p2 * besselCoefficient * u * tSquared + p3 * tCubed;
92 return p;
93 }
94
CalculateCubic(float p1,float p2,float t)95 float RSAttractionEffectFilter::CalculateCubic(float p1, float p2, float t)
96 {
97 // p(t) = 3 * t * (1 - t)^2 * p1 + 3 * t^2 * (1-t) * p2 + t^3
98 return 3.0f * p1 * (1.0f - t) * (1.0f - t) * t + 3.0f * p2 * (1.0f - t) * t * t + t * t * t;
99 }
100
BinarySearch(float targetX,const Drawing::Point & p1,const Drawing::Point & p2)101 float RSAttractionEffectFilter::BinarySearch(float targetX, const Drawing::Point &p1, const Drawing::Point &p2)
102 {
103 float start = 0.0f;
104 float end = 1.0f;
105 float midPoint = 0.0f;
106 int maxIterCount = 100;
107 int currentIter = 0;
108 while (currentIter < maxIterCount) {
109 midPoint = (start + end) / 2.0f;
110 float estimate = CalculateCubic(p1.GetX(), p2.GetX(), midPoint);
111 if (IsWithinThreshold(targetX, estimate, 0.001f)) {
112 return CalculateCubic(p1.GetY(), p2.GetY(), midPoint);
113 }
114 if (estimate < targetX) {
115 start = midPoint;
116 } else {
117 end = midPoint;
118 }
119 currentIter++;
120 }
121 return CalculateCubic(p1.GetY(), p2.GetY(), midPoint);
122 }
123
CalculateCubicsCtrlPointOffset(const std::vector<Drawing::Point> controlPointOfVertex)124 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateCubicsCtrlPointOffset(
125 const std::vector<Drawing::Point> controlPointOfVertex)
126 {
127 std::vector<Drawing::Point> pathList;
128 Drawing::Point topLeft = controlPointOfVertex[0];
129 Drawing::Point topRight = controlPointOfVertex[1];
130 Drawing::Point bottomLeft = controlPointOfVertex[2];
131 Drawing::Point bottomRight = controlPointOfVertex[3];
132
133 // The two numbers represent the weights of the two points
134 pathList.push_back(topLeft); // 0:top left
135 pathList.push_back(LerpPoint(topLeft, topRight, 0.67f, 0.33f)); // 1:top one third
136 pathList.push_back(LerpPoint(topLeft, topRight, 0.33f, 0.67f)); // 2:top two thirds
137 pathList.push_back(topRight); // 3:top right
138 pathList.push_back(LerpPoint(topRight, bottomRight, 0.67f, 0.33f)); // 4:right one third
139 pathList.push_back(LerpPoint(topRight, bottomRight, 0.33f, 0.67f)); // 5:right two thirds
140 pathList.push_back(bottomRight); // 6:bottom right
141 pathList.push_back(LerpPoint(bottomLeft, bottomRight, 0.33f, 0.67f)); // 7:bottom two thirds
142 pathList.push_back(LerpPoint(bottomLeft, bottomRight, 0.67f, 0.33f)); // 8:bottom one third
143 pathList.push_back(bottomLeft); // 9:bottom left
144 pathList.push_back(LerpPoint(topLeft, bottomLeft, 0.33f, 0.67f)); // 10:left two thirds
145 pathList.push_back(LerpPoint(topLeft, bottomLeft, 0.67f, 0.33f)); // 11:left one third
146 return pathList;
147 }
148
CreateIndexSequence(float location)149 std::vector<int> RSAttractionEffectFilter::CreateIndexSequence(float location)
150 {
151 float locationValue = 1.0f;
152 float tolerance = 0.001f;
153 // Select the parameter index of the window control point according to the window position.
154 // 0 to 11 indicate the index of the window control point, which is rotated clockwise.
155 if (!isBelowTarget_) {
156 return IsWithinThreshold(location, locationValue, tolerance) ?
157 std::vector<int>{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 } :
158 std::vector<int>{ 3, 2, 1, 0, 11, 10, 9, 8, 7, 6, 5, 4 };
159 } else {
160 return IsWithinThreshold(location, locationValue, tolerance) ?
161 std::vector<int>{ 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8 } :
162 std::vector<int>{ 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
163 }
164 }
165
CalculateCubicsCtrlPoint(std::vector<Drawing::Point> controlPointOfVertex,const Drawing::Point points[],float location,bool isFirstCtrl)166 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateCubicsCtrlPoint(
167 std::vector<Drawing::Point> controlPointOfVertex,
168 const Drawing::Point points[], // Array instead of vector
169 float location, // Determine whether the flag on the left or right is used.
170 bool isFirstCtrl)
171 {
172 int pointNum = 12;
173 std::vector<Drawing::Point> pathList = CalculateCubicsCtrlPointOffset(controlPointOfVertex);
174
175 std::vector<int> indice = CreateIndexSequence(location);
176 std::vector<Drawing::Point> pathCtrlPointList(pointNum, Drawing::Point(0.0f, 0.0f));
177
178 for (int i = 0; i < pointNum; i++) {
179 int index = indice[i];
180 if (!isBelowTarget_) {
181 pathCtrlPointList[i] = pathList[index] + (isFirstCtrl ? points[i] : points[0]);
182 } else {
183 float px = isFirstCtrl ? points[i].GetX() : points[0].GetX();
184 float py = isFirstCtrl ? points[i].GetY() : points[0].GetY();
185
186 if (location == 1.0f) {
187 px = -px;
188 pathCtrlPointList[i] = { -(pathList[index].GetY() + px), pathList[index].GetX() + py };
189 } else {
190 py = -py;
191 pathCtrlPointList[i] = { pathList[index].GetY() + px, -(pathList[index].GetX() + py) };
192 }
193 }
194 }
195 return pathCtrlPointList;
196 }
197
CalculateBezierVelList(const std::vector<Drawing::Point> & velocityList,std::vector<Drawing::Point> & velocityCtrl,float location)198 void RSAttractionEffectFilter::CalculateBezierVelList(const std::vector<Drawing::Point> &velocityList,
199 std::vector<Drawing::Point> &velocityCtrl, float location)
200 {
201 std::vector<Drawing::Point> curveVelList;
202 Drawing::Point topVelocity = velocityList[0];
203 Drawing::Point bottomVelocity = velocityList[1];
204 // The two numbers represent the weights of the two points
205 curveVelList.push_back(LerpPoint(topVelocity, bottomVelocity, 0.5f, 0.5f));
206 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.33f, 0.67f));
207 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.17f, 0.83f));
208 curveVelList.push_back(topVelocity);
209 if (isBelowTarget_) {
210 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.17f, 0.68f));
211 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.33f, 0.57f));
212 } else {
213 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.17f, 0.83f));
214 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.33f, 0.67f));
215 }
216 curveVelList.push_back(LerpPoint(topVelocity, bottomVelocity, 0.5f, 0.5f));
217 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.67f, 0.33f));
218 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.83f, 0.17f));
219 curveVelList.push_back(bottomVelocity);
220 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.83f, 0.17f));
221 curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, 0.67f, 0.33f));
222 std::vector<int> indice = CreateIndexSequence(location);
223 int pointNum = 12;
224 for (int i = 0; i < pointNum; i++) {
225 int index = indice[i];
226 velocityCtrl[i] = curveVelList[index];
227 }
228 }
229
GetWindowInitCtrlPoints(Drawing::Point windowCtrlPoints[],float canvasWidth,float canvasHeight,int size)230 void RSAttractionEffectFilter::GetWindowInitCtrlPoints(Drawing::Point windowCtrlPoints[], float canvasWidth,
231 float canvasHeight, int size)
232 {
233 // 0 to 11 indicate the index of the window control point, which is rotated clockwise.
234 const int TOP_LEFT = 0;
235 const int TOP_ONE_THIRD = 1;
236 const int TOP_TWO_THIRDS = 2;
237 const int TOP_RIGHT = 3;
238 const int RIGHT_ONE_THIRD = 4;
239 const int RIGHT_TWO_THIRDS = 5;
240 const int BOTTOM_RIGHT = 6;
241 const int BOTTOM_TWO_THIRDS = 7;
242 const int BOTTOM_ONE_THIRD = 8;
243 const int BOTTOM_LEFT = 9;
244 const int LEFT_TWO_THIRDS = 10;
245 const int LEFT_ONE_THIRD = 11;
246
247 // Find the third division point
248 float third = 1.0f / 3.0f;
249 float twoThirds = 2.0f / 3.0f;
250 float widthOneThird = canvasWidth * third;
251 float widthTwoThirds = canvasWidth * twoThirds;
252 float heightOneThird = canvasHeight * third;
253 float heightTwoThirds = canvasHeight * twoThirds;
254
255 int pointNum = 12;
256 if (size == pointNum) {
257 windowCtrlPoints[TOP_LEFT] = { 0.0f, 0.0f };
258 windowCtrlPoints[TOP_ONE_THIRD] = { widthOneThird, 0.0f };
259 windowCtrlPoints[TOP_TWO_THIRDS] = { widthTwoThirds, 0.0f };
260 windowCtrlPoints[TOP_RIGHT] = { canvasWidth, 0.0f };
261 windowCtrlPoints[RIGHT_ONE_THIRD] = { canvasWidth, heightOneThird };
262 windowCtrlPoints[RIGHT_TWO_THIRDS] = { canvasWidth, heightTwoThirds };
263 windowCtrlPoints[BOTTOM_RIGHT] = { canvasWidth, canvasHeight };
264 windowCtrlPoints[BOTTOM_TWO_THIRDS] = { widthTwoThirds, canvasHeight };
265 windowCtrlPoints[BOTTOM_ONE_THIRD] = { widthOneThird, canvasHeight };
266 windowCtrlPoints[BOTTOM_LEFT] = { 0.0f, canvasHeight };
267 windowCtrlPoints[LEFT_TWO_THIRDS] = { 0.0f, heightTwoThirds };
268 windowCtrlPoints[LEFT_ONE_THIRD] = { 0.0f, heightOneThird };
269 }
270 }
271
CalculateDeltaXAndDeltaY(const Drawing::Point windowCtrlPoints[],const Drawing::Point & pointDst,float & deltaX,float & deltaY,int location)272 void RSAttractionEffectFilter::CalculateDeltaXAndDeltaY(const Drawing::Point windowCtrlPoints[],
273 const Drawing::Point &pointDst, float &deltaX, float &deltaY, int location)
274 {
275 int topLeftIndex = 0;
276 int topRightIndex = 3;
277 int bottomRightIndex = 6;
278 int bottomLeftIndex = 9;
279 Drawing::Point windowCenter = { 0.5 * canvasWidth_, canvasHeight_ };
280 if (windowCenter.GetY() > pointDst.GetY()) {
281 float locationValue = 1.0f;
282 float tolerance = 0.001f;
283 if (IsWithinThreshold(location, locationValue, tolerance)) {
284 deltaX =
285 std::abs((windowCtrlPoints[topLeftIndex].GetY() + windowCtrlPoints[bottomLeftIndex].GetY()) / 2.0f -
286 pointDst.GetY());
287 deltaY = std::abs(windowCtrlPoints[topLeftIndex].GetX() - pointDst.GetX());
288 } else {
289 deltaX =
290 std::abs((windowCtrlPoints[topRightIndex].GetY() + windowCtrlPoints[bottomRightIndex].GetY()) / 2.0f -
291 pointDst.GetY());
292 deltaY = std::abs(windowCtrlPoints[topRightIndex].GetX() - pointDst.GetX());
293 }
294 } else {
295 deltaX = std::abs(windowCenter.GetX() - pointDst.GetX());
296 deltaY = std::abs(windowCenter.GetY() - pointDst.GetY());
297 }
298 }
299
CalculateUpperCtrlPointOfVertex(float deltaX,float deltaY,float width,float height,int location)300 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateUpperCtrlPointOfVertex(float deltaX, float deltaY,
301 float width, float height, int location)
302 {
303 // Different regression parameters are used for different scenarios
304 // Coordinates of the upper control point of the curve:(k1 * width + k2 * deltaX, k3 * height + k4 * deltaY)
305 Drawing::Point topLeft = isBelowTarget_ ?
306 Drawing::Point((0.016f * width - 0.08f * deltaX) * location, 0.464f * height + 0.40f * deltaY) :
307 Drawing::Point((-0.100f * width - 0.008f * deltaX) * location, 0.008f * height + 0.085f * deltaY);
308 Drawing::Point bottomLeft = isBelowTarget_ ?
309 Drawing::Point((-0.15f * width - 0.075f * deltaX) * location, 0.0f * height + 0.2f * deltaY) :
310 Drawing::Point((-0.008f * width - 0.008f * deltaX) * location, 0.0f * height - 0.008f * deltaY);
311 Drawing::Point topRight = { (-1.147f * width - 0.016f * deltaX) * location, -0.187f * height + 0.30f * deltaY };
312 Drawing::Point bottomRight = { (-0.848f * width - 0.2f * deltaX) * location, -0.859f * height - 0.2f * deltaY };
313 std::vector<Drawing::Point> upperControlPoint = { topLeft, topRight, bottomLeft, bottomRight };
314 return upperControlPoint;
315 }
316
CalculateLowerCtrlPointOfVertex(float deltaX,float deltaY,float width,float height,int location)317 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateLowerCtrlPointOfVertex(float deltaX, float deltaY,
318 float width, float height, int location)
319 {
320 float inverseWidth = (width >= 1.0f) ? (1.0f / width) : 1.0f;
321 // Different regression parameters are used for different scenarios
322 // Coordinates of the lower control point of the curve:(m1*(deltaX * height/width - width)), m2 * deltaY)
323 Drawing::Point topLeft = isBelowTarget_ ?
324 Drawing::Point((0.300f * (deltaX * height * inverseWidth - width)) * location, -0.20f * deltaY) :
325 Drawing::Point((0.131f * (deltaX * height * inverseWidth - width)) * location, -0.20f * deltaY);
326 Drawing::Point topRight = isBelowTarget_ ?
327 Drawing::Point((0.450f * (deltaX * height * inverseWidth - width)) * location, -0.30f * deltaY) :
328 Drawing::Point((0.147f * (deltaX * height * inverseWidth - width)) * location, -0.30f * deltaY);
329 Drawing::Point bottomLeft = isBelowTarget_ ?
330 Drawing::Point((0.150f * (deltaX * height * inverseWidth - width)) * location, -0.20f * deltaY) :
331 Drawing::Point((0.085f * (deltaX * height * inverseWidth - width)) * location, 0.008f * deltaY);
332 Drawing::Point bottomRight = isBelowTarget_ ?
333 Drawing::Point((0.300f * (deltaX * height * inverseWidth - width)) * location, -0.112f * deltaY) :
334 Drawing::Point((0.147f * (deltaX * height * inverseWidth - width)) * location, -0.069f * deltaY);
335 std::vector<Drawing::Point> lowerControlPoint = { topLeft, topRight, bottomLeft, bottomRight };
336 return lowerControlPoint;
337 }
338
CalculateVelocityCtrlPointUpper()339 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateVelocityCtrlPointUpper()
340 {
341 // Cubic Bezier curve with two control points
342 Drawing::Point topVelFirst = { 0.50f, 0.0f };
343 Drawing::Point bottomVelFirst = isBelowTarget_ ? Drawing::Point(0.2f, 0.0f) : Drawing::Point(0.0f, 0.0f);
344 std::vector<Drawing::Point> velocityCtrlPoint = {topVelFirst, bottomVelFirst};
345 return velocityCtrlPoint;
346 }
347
CalculateVelocityCtrlPointLower()348 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateVelocityCtrlPointLower()
349 {
350 // Cubic Bezier curve with two control points
351 Drawing::Point topVelSecond = { 0.50f, 1.0f };
352 Drawing::Point bottomVelSecond = isBelowTarget_ ? Drawing::Point(0.2f, 1.0f) : Drawing::Point(0.0f, 1.0f);
353 std::vector<Drawing::Point> velocityCtrlPoint = {topVelSecond, bottomVelSecond};
354 return velocityCtrlPoint;
355 }
356
UpdateDirtyRegion(float leftPoint,float topPonit)357 void RSAttractionEffectFilter::UpdateDirtyRegion(float leftPoint, float topPonit)
358 {
359 float dirtyRegionMinX_ = windowStatusPoints_[0].GetX();
360 float dirtyRegionMaxX_ = windowStatusPoints_[0].GetX();
361 float dirtyRegionMinY_ = windowStatusPoints_[0].GetY();
362 float dirtyRegionMaxY_ = windowStatusPoints_[0].GetY();
363
364 int pointNum = 12;
365 for (int i = 1; i < pointNum; ++i) {
366 float x = windowStatusPoints_[i].GetX();
367 float y = windowStatusPoints_[i].GetY();
368 dirtyRegionMinX_ = std::min(dirtyRegionMinX_, x);
369 dirtyRegionMaxX_ = std::min(dirtyRegionMaxX_, x);
370 dirtyRegionMinY_ = std::min(dirtyRegionMinY_, y);
371 dirtyRegionMaxY_ = std::min(dirtyRegionMaxY_, y);
372 }
373
374 int dirtyRegionLeftCurrent = static_cast<int>(dirtyRegionMinX_ + leftPoint);
375 int dirtyRegionTopCurrent = static_cast<int>(dirtyRegionMinY_ + topPonit);
376 int dirtyRegionRightCurrent = static_cast<int>(dirtyRegionMinX_ + leftPoint);
377 int dirtyRegionBottomCurrent = static_cast<int>(dirtyRegionMinY_ + topPonit);
378
379 attractionDirtyRegion_.left_ = dirtyRegionLeftCurrent;
380 attractionDirtyRegion_.top_ = dirtyRegionTopCurrent;
381 attractionDirtyRegion_.width_ = dirtyRegionRightCurrent - dirtyRegionLeftCurrent;
382 attractionDirtyRegion_.height_ = dirtyRegionBottomCurrent - dirtyRegionTopCurrent;
383 }
384
CalculateWindowStatus(float canvasWidth,float canvasHeight,Vector2f destinationPoint)385 void RSAttractionEffectFilter::CalculateWindowStatus(float canvasWidth, float canvasHeight, Vector2f destinationPoint)
386 {
387 canvasWidth_ = canvasWidth;
388 canvasHeight_ = canvasHeight;
389 const int pointNum = 12;
390
391 Drawing::Point windowCtrlPoints[pointNum];
392 GetWindowInitCtrlPoints(windowCtrlPoints, canvasWidth_, canvasHeight_, pointNum);
393
394 Drawing::Point pointDst[1] = { { destinationPoint.x_, destinationPoint.y_ } };
395
396 Drawing::Point windowBottomCenter = { 0.5 * canvasWidth_, 0.5 * canvasHeight_ };
397
398 // 1.0 indicates that the window is to the right of the target point,
399 // and - 1.0 indicates that the window is to the left.
400 float location = (windowBottomCenter.GetX() > pointDst[0].GetX()) ? 1.0f : -1.0f;
401 location_ = location;
402 isBelowTarget_ = (windowBottomCenter.GetY() > pointDst[0].GetY()) ? true : false;
403
404 float width = isBelowTarget_ ? canvasHeight_ : canvasWidth_;
405 float height = isBelowTarget_ ? canvasWidth_ : canvasHeight_;
406 float deltaX = 0.0f;
407 float deltaY = 0.0f;
408 CalculateDeltaXAndDeltaY(windowCtrlPoints, pointDst[0], deltaX, deltaY, location);
409
410 std::vector<Drawing::Point> upperControlPointOfVertex =
411 CalculateUpperCtrlPointOfVertex(deltaX, deltaY, width, height, location);
412 std::vector<Drawing::Point> lowerControlPointOfVertex =
413 CalculateLowerCtrlPointOfVertex(deltaX, deltaY, width, height, location);
414 std::vector<Drawing::Point> velocityCtrlPointUpper = CalculateVelocityCtrlPointUpper();
415 std::vector<Drawing::Point> velocityCtrlPointLower = CalculateVelocityCtrlPointLower();
416
417 std::vector<Drawing::Point> controlPointListFirst =
418 CalculateCubicsCtrlPoint(upperControlPointOfVertex, windowCtrlPoints, location, true);
419 std::vector<Drawing::Point> controlPointListSecond =
420 CalculateCubicsCtrlPoint(lowerControlPointOfVertex, pointDst, location, false);
421
422 std::vector<Drawing::Point> speedListsFirst(pointNum, Drawing::Point(0.0f, 0.0f));
423 std::vector<Drawing::Point> speedListsSecond(pointNum, Drawing::Point(0.0f, 0.0f));
424 CalculateBezierVelList(velocityCtrlPointUpper, speedListsFirst, location);
425 CalculateBezierVelList(velocityCtrlPointLower, speedListsSecond, location);
426
427 for (int i = 0; i < pointNum; ++i) {
428 float speed = BinarySearch(attractionFraction_, speedListsFirst[i], speedListsSecond[i]);
429 windowStatusPoints_[i] = CubicBezier(windowCtrlPoints[i], controlPointListFirst[i], controlPointListSecond[i],
430 pointDst[0], speed);
431 }
432 }
433
GetBrush(const std::shared_ptr<Drawing::Image> & image) const434 Drawing::Brush RSAttractionEffectFilter::GetBrush(const std::shared_ptr<Drawing::Image>& image) const
435 {
436 Drawing::Brush brush;
437 if (image == nullptr) {
438 ROSEN_LOGE("RSAttractionEffectFilter::GetBrush image = nullptr");
439 return brush;
440 }
441 brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
442 Drawing::Point startPt;
443 Drawing::Point endPt;
444
445 const float width = static_cast<float>(image->GetWidth());
446 const float height = static_cast<float>(image->GetHeight());
447
448 const Drawing::Point points[] = {
449 Drawing::Point(0.0f, 0.0f),
450 Drawing::Point(width, 0.0f),
451 Drawing::Point(0.0f, height),
452 Drawing::Point(width, height)
453
454 };
455 const int startIdx = (isBelowTarget_ ? (location_ == 1 ? 0 : 1) : (location_ == 1 ? 2 : 3));
456 const int endIdx = (isBelowTarget_ ? (location_ == 1 ? 3 : 2) : (location_ == 1 ? 0 : 1));
457
458 startPt = points[startIdx];
459 endPt = points[endIdx];
460
461 float startAlpha = 1.0f - std::min(1.0f, attractionFraction_ * 2.0f);
462 std::vector<Drawing::ColorQuad> colors;
463 uint8_t alphaVal = static_cast<uint8_t>(startAlpha * 255);
464 Drawing::ColorQuad fixedColor = Drawing::Color::ColorQuadSetARGB(255, 255, 255, 255);
465 Drawing::ColorQuad stateColor = Drawing::Color::ColorQuadSetARGB(alphaVal, 255, 255, 255);
466 colors.push_back(fixedColor);
467 colors.push_back(stateColor);
468
469 std::vector<Drawing::scalar> positions;
470 positions.push_back(0.0f);
471 positions.push_back(1.0f);
472
473 auto gradientShader = Drawing::ShaderEffect::CreateLinearGradient(
474 startPt, endPt, colors, positions, Drawing::TileMode::CLAMP, nullptr);
475
476 Drawing::SamplingOptions samplingOptions;
477 Drawing::Matrix scaleMat;
478 auto imageShader = Drawing::ShaderEffect::CreateImageShader(
479 *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat);
480 auto blendShader = Drawing::ShaderEffect::CreateBlendShader(
481 *imageShader, *gradientShader, Drawing::BlendMode::DST_IN);
482 brush.SetShaderEffect(blendShader);
483 return brush;
484 }
485
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const486 void RSAttractionEffectFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
487 const Drawing::Rect& src, const Drawing::Rect& dst) const
488 {
489 if (!attractionFraction_ || !image || image->GetWidth() == 0 || image->GetHeight() == 0) {
490 ROSEN_LOGE("RSAttractionEffectFilter::shader error");
491 return;
492 }
493 RS_OPTIONAL_TRACE_NAME_FMT("DrawAttraction:%f", attractionFraction_);
494 int width = image->GetWidth();
495 int height = image->GetHeight();
496
497 auto brush = GetBrush(image);
498 canvas.AttachBrush(brush);
499
500 // 4 coordinates of image texture
501 const Drawing::Point texCoords[4] = { { 0.0f, 0.0f }, { width, 0.0f }, { width, height }, { 0.0f, height } };
502
503 canvas.DrawPatch(windowStatusPoints_, nullptr, texCoords, Drawing::BlendMode::SRC_OVER);
504 canvas.DetachBrush();
505 }
506 } // namespace Rosen
507 } // namespace OHOS