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 
16 #include "drawable/rs_property_drawable_foreground.h"
17 
18 #include "common/rs_obj_abs_geometry.h"
19 #include "drawable/rs_property_drawable_utils.h"
20 #include "pipeline/rs_recording_canvas.h"
21 #include "pipeline/rs_render_node.h"
22 #include "platform/common/rs_log.h"
23 #include "property/rs_point_light_manager.h"
24 
25 namespace OHOS::Rosen {
26 namespace DrawableV2 {
27 namespace {
28 constexpr int PARAM_TWO = 2;
29 } // namespace
30 
31 const bool FOREGROUND_FILTER_ENABLED = RSSystemProperties::GetForegroundFilterEnabled();
32 
33 // ====================================
34 // Binarization
OnGenerate(const RSRenderNode & node)35 RSDrawable::Ptr RSBinarizationDrawable::OnGenerate(const RSRenderNode& node)
36 {
37     if (auto ret = std::make_shared<RSBinarizationDrawable>(); ret->OnUpdate(node)) {
38         return std::move(ret);
39     }
40     return nullptr;
41 }
42 
OnUpdate(const RSRenderNode & node)43 bool RSBinarizationDrawable::OnUpdate(const RSRenderNode& node)
44 {
45     auto& aiInvert = node.GetRenderProperties().GetAiInvert();
46     if (!aiInvert.has_value()) {
47         return false;
48     }
49     needSync_ = true;
50     stagingAiInvert_ = aiInvert;
51     return true;
52 }
53 
OnSync()54 void RSBinarizationDrawable::OnSync()
55 {
56     if (!needSync_) {
57         return;
58     }
59     aiInvert_ = std::move(stagingAiInvert_);
60     needSync_ = false;
61 }
62 
CreateDrawFunc() const63 Drawing::RecordingCanvas::DrawFunc RSBinarizationDrawable::CreateDrawFunc() const
64 {
65     auto ptr = std::static_pointer_cast<const RSBinarizationDrawable>(shared_from_this());
66     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
67         RSPropertyDrawableUtils::DrawBinarization(canvas, ptr->aiInvert_);
68     };
69 }
70 
OnGenerate(const RSRenderNode & node)71 RSDrawable::Ptr RSColorFilterDrawable::OnGenerate(const RSRenderNode& node)
72 {
73     if (auto ret = std::make_shared<RSColorFilterDrawable>(); ret->OnUpdate(node)) {
74         return std::move(ret);
75     }
76     return nullptr;
77 }
78 
OnUpdate(const RSRenderNode & node)79 bool RSColorFilterDrawable::OnUpdate(const RSRenderNode& node)
80 {
81     auto& colorFilter = node.GetRenderProperties().GetColorFilter();
82     if (colorFilter == nullptr) {
83         return false;
84     }
85     needSync_ = true;
86     stagingFilter_ = colorFilter;
87     return true;
88 }
89 
OnSync()90 void RSColorFilterDrawable::OnSync()
91 {
92     if (!needSync_) {
93         return;
94     }
95     filter_ = std::move(stagingFilter_);
96     needSync_ = false;
97 }
98 
CreateDrawFunc() const99 Drawing::RecordingCanvas::DrawFunc RSColorFilterDrawable::CreateDrawFunc() const
100 {
101     auto ptr = std::static_pointer_cast<const RSColorFilterDrawable>(shared_from_this());
102     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
103         RSPropertyDrawableUtils::DrawColorFilter(canvas, ptr->filter_);
104     };
105 }
OnGenerate(const RSRenderNode & node)106 RSDrawable::Ptr RSLightUpEffectDrawable::OnGenerate(const RSRenderNode& node)
107 {
108     if (auto ret = std::make_shared<RSLightUpEffectDrawable>(); ret->OnUpdate(node)) {
109         return std::move(ret);
110     }
111     return nullptr;
112 }
113 
OnUpdate(const RSRenderNode & node)114 bool RSLightUpEffectDrawable::OnUpdate(const RSRenderNode& node)
115 {
116     if (!node.GetRenderProperties().IsLightUpEffectValid()) {
117         return false;
118     }
119     needSync_ = true;
120     stagingLightUpEffectDegree_ = node.GetRenderProperties().GetLightUpEffect();
121     return true;
122 }
123 
OnSync()124 void RSLightUpEffectDrawable::OnSync()
125 {
126     if (!needSync_) {
127         return;
128     }
129     lightUpEffectDegree_ = stagingLightUpEffectDegree_;
130     stagingLightUpEffectDegree_ = 1.0f;
131     needSync_ = false;
132 }
133 
CreateDrawFunc() const134 Drawing::RecordingCanvas::DrawFunc RSLightUpEffectDrawable::CreateDrawFunc() const
135 {
136     auto ptr = std::static_pointer_cast<const RSLightUpEffectDrawable>(shared_from_this());
137     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
138         RSPropertyDrawableUtils::DrawLightUpEffect(canvas, ptr->lightUpEffectDegree_);
139     };
140 }
141 
OnGenerate(const RSRenderNode & node)142 RSDrawable::Ptr RSDynamicDimDrawable::OnGenerate(const RSRenderNode& node)
143 {
144     if (auto ret = std::make_shared<RSDynamicDimDrawable>(); ret->OnUpdate(node)) {
145         return std::move(ret);
146     }
147     return nullptr;
148 }
149 
OnUpdate(const RSRenderNode & node)150 bool RSDynamicDimDrawable::OnUpdate(const RSRenderNode& node)
151 {
152     if (!node.GetRenderProperties().IsDynamicDimValid()) {
153         return false;
154     }
155     needSync_ = true;
156     stagingDynamicDimDegree_ = node.GetRenderProperties().GetDynamicDimDegree().value();
157     return true;
158 }
159 
OnSync()160 void RSDynamicDimDrawable::OnSync()
161 {
162     if (!needSync_) {
163         return;
164     }
165     dynamicDimDegree_ = stagingDynamicDimDegree_;
166     needSync_ = false;
167 }
168 
CreateDrawFunc() const169 Drawing::RecordingCanvas::DrawFunc RSDynamicDimDrawable::CreateDrawFunc() const
170 {
171     auto ptr = std::static_pointer_cast<const RSDynamicDimDrawable>(shared_from_this());
172     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
173         RSPropertyDrawableUtils::DrawDynamicDim(canvas, ptr->dynamicDimDegree_);
174     };
175 }
176 
OnGenerate(const RSRenderNode & node)177 RSDrawable::Ptr RSForegroundColorDrawable::OnGenerate(const RSRenderNode& node)
178 {
179     if (auto ret = std::make_shared<RSForegroundColorDrawable>(); ret->OnUpdate(node)) {
180         return std::move(ret);
181     }
182     return nullptr;
183 };
184 
OnUpdate(const RSRenderNode & node)185 bool RSForegroundColorDrawable::OnUpdate(const RSRenderNode& node)
186 {
187     const RSProperties& properties = node.GetRenderProperties();
188     auto fgColor = properties.GetForegroundColor();
189     if (fgColor == RgbPalette::Transparent()) {
190         return false;
191     }
192 
193     RSPropertyDrawCmdListUpdater updater(0, 0, this);
194     Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
195     Drawing::Brush brush;
196     brush.SetColor(Drawing::Color(fgColor.AsArgbInt()));
197     brush.SetAntiAlias(true);
198     canvas.AttachBrush(brush);
199     canvas.DrawRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetRRect()));
200     canvas.DetachBrush();
201     return true;
202 }
203 
OnGenerate(const RSRenderNode & node)204 RSDrawable::Ptr RSCompositingFilterDrawable::OnGenerate(const RSRenderNode& node)
205 {
206     if (auto ret = std::make_shared<RSCompositingFilterDrawable>(); ret->OnUpdate(node)) {
207         return std::move(ret);
208     }
209     return nullptr;
210 }
211 
OnUpdate(const RSRenderNode & node)212 bool RSCompositingFilterDrawable::OnUpdate(const RSRenderNode& node)
213 {
214     stagingNodeId_ = node.GetId();
215     auto& rsFilter = node.GetRenderProperties().GetFilter();
216     if (rsFilter == nullptr) {
217         return false;
218     }
219     RecordFilterInfos(rsFilter);
220     needSync_ = true;
221     stagingFilter_ = rsFilter;
222     return true;
223 }
224 
225 // foregroundFilter
OnGenerate(const RSRenderNode & node)226 RSDrawable::Ptr RSForegroundFilterDrawable::OnGenerate(const RSRenderNode& node)
227 {
228     if (!FOREGROUND_FILTER_ENABLED) {
229         ROSEN_LOGD("RSForegroundFilterDrawable::OnGenerate close blur.");
230         return nullptr;
231     }
232     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
233     if (rsFilter == nullptr) {
234         return nullptr;
235     }
236 
237     if (auto ret = std::make_shared<RSForegroundFilterDrawable>(); ret->OnUpdate(node)) {
238         return std::move(ret);
239     }
240     return nullptr;
241 }
242 
OnUpdate(const RSRenderNode & node)243 bool RSForegroundFilterDrawable::OnUpdate(const RSRenderNode& node)
244 {
245     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
246     if (rsFilter == nullptr) {
247         return false;
248     }
249     needSync_ = true;
250     stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
251     return true;
252 }
253 
CreateDrawFunc() const254 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterDrawable::CreateDrawFunc() const
255 {
256     auto ptr = std::static_pointer_cast<const RSForegroundFilterDrawable>(shared_from_this());
257     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
258         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
259         RSPropertyDrawableUtils::BeginForegroundFilter(*paintFilterCanvas, ptr->boundsRect_);
260     };
261 }
262 
OnSync()263 void RSForegroundFilterDrawable::OnSync()
264 {
265     if (needSync_ == false) {
266         return;
267     }
268     boundsRect_ = stagingBoundsRect_;
269     needSync_ = false;
270 }
271 
272 // Restore RSForegroundFilter
OnGenerate(const RSRenderNode & node)273 RSDrawable::Ptr RSForegroundFilterRestoreDrawable::OnGenerate(const RSRenderNode& node)
274 {
275     if (!FOREGROUND_FILTER_ENABLED) {
276         ROSEN_LOGD("RSForegroundFilterRestoreDrawable::OnGenerate close blur.");
277         return nullptr;
278     }
279     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
280     if (rsFilter == nullptr) {
281         return nullptr;
282     }
283 
284     if (auto ret = std::make_shared<RSForegroundFilterRestoreDrawable>(); ret->OnUpdate(node)) {
285         return std::move(ret);
286     }
287     return nullptr;
288 }
289 
OnUpdate(const RSRenderNode & node)290 bool RSForegroundFilterRestoreDrawable::OnUpdate(const RSRenderNode& node)
291 {
292     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
293     if (rsFilter == nullptr) {
294         return false;
295     }
296     needSync_ = true;
297     stagingForegroundFilter_ = rsFilter;
298     return true;
299 }
300 
CreateDrawFunc() const301 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterRestoreDrawable::CreateDrawFunc() const
302 {
303     auto ptr = std::static_pointer_cast<const RSForegroundFilterRestoreDrawable>(shared_from_this());
304     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
305         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
306         RSPropertyDrawableUtils::DrawForegroundFilter(*paintFilterCanvas, ptr->foregroundFilter_);
307     };
308 }
309 
OnSync()310 void RSForegroundFilterRestoreDrawable::OnSync()
311 {
312     if (needSync_ == false) {
313         return;
314     }
315     foregroundFilter_ = std::move(stagingForegroundFilter_);
316     needSync_ = false;
317 }
318 
OnGenerate(const RSRenderNode & node)319 RSDrawable::Ptr RSPixelStretchDrawable::OnGenerate(const RSRenderNode& node)
320 {
321     if (auto ret = std::make_shared<RSPixelStretchDrawable>(); ret->OnUpdate(node)) {
322         return std::move(ret);
323     }
324     return nullptr;
325 }
326 
OnUpdate(const RSRenderNode & node)327 bool RSPixelStretchDrawable::OnUpdate(const RSRenderNode& node)
328 {
329     auto& pixelStretch = node.GetRenderProperties().GetPixelStretch();
330     if (!pixelStretch.has_value()) {
331         return false;
332     }
333     needSync_ = true;
334     stagingPixelStretch_ = pixelStretch;
335     stagePixelStretchTileMode_ = node.GetRenderProperties().GetPixelStretchTileMode();
336     const auto& boundsGeo = node.GetRenderProperties().GetBoundsGeometry();
337     stagingBoundsGeoValid_ = boundsGeo && !boundsGeo->IsEmpty();
338     stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
339     return true;
340 }
341 
SetPixelStretch(const std::optional<Vector4f> & pixelStretch)342 void RSPixelStretchDrawable::SetPixelStretch(const std::optional<Vector4f>& pixelStretch)
343 {
344     stagingPixelStretch_ = pixelStretch;
345 }
346 
OnSync()347 void RSPixelStretchDrawable::OnSync()
348 {
349     if (!needSync_) {
350         return;
351     }
352     pixelStretch_ = std::move(stagingPixelStretch_);
353     pixelStretchTileMode_ = stagePixelStretchTileMode_;
354     boundsGeoValid_ = stagingBoundsGeoValid_;
355     stagingBoundsGeoValid_ = false;
356     boundsRect_ = stagingBoundsRect_;
357     stagingBoundsRect_.Clear();
358     needSync_ = false;
359 }
360 
CreateDrawFunc() const361 Drawing::RecordingCanvas::DrawFunc RSPixelStretchDrawable::CreateDrawFunc() const
362 {
363     auto ptr = std::static_pointer_cast<const RSPixelStretchDrawable>(shared_from_this());
364     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
365         RSPropertyDrawableUtils::DrawPixelStretch(canvas, ptr->pixelStretch_, ptr->boundsRect_, ptr->boundsGeoValid_,
366             static_cast<Drawing::TileMode>(ptr->pixelStretchTileMode_));
367     };
368 }
369 
OnGenerate(const RSRenderNode & node)370 RSDrawable::Ptr RSBorderDrawable::OnGenerate(const RSRenderNode& node)
371 {
372     if (auto ret = std::make_shared<RSBorderDrawable>(); ret->OnUpdate(node)) {
373         return std::move(ret);
374     }
375     return nullptr;
376 };
377 
OnUpdate(const RSRenderNode & node)378 bool RSBorderDrawable::OnUpdate(const RSRenderNode& node)
379 {
380     const RSProperties& properties = node.GetRenderProperties();
381     auto& border = properties.GetBorder();
382     if (!border || !border->HasBorder()) {
383         return false;
384     }
385     // regenerate stagingDrawCmdList_
386     RSPropertyDrawCmdListUpdater updater(0, 0, this);
387     DrawBorder(properties, *updater.GetRecordingCanvas(), border, false);
388     return true;
389 }
390 
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool & isOutline)391 void RSBorderDrawable::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas,
392     const std::shared_ptr<RSBorder>& border, const bool& isOutline)
393 {
394     Drawing::Brush brush;
395     Drawing::Pen pen;
396     brush.SetAntiAlias(true);
397     pen.SetAntiAlias(true);
398     if (border->ApplyFillStyle(brush)) {
399         auto roundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
400             RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
401         auto innerRoundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
402             RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
403         canvas.AttachBrush(brush);
404         canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
405         canvas.DetachBrush();
406         return;
407     }
408     bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
409     if (isZero && border->ApplyFourLine(pen)) {
410         RectF rectf =
411             isOutline ? properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
412         border->PaintFourLine(canvas, pen, rectf);
413         return;
414     }
415     if (border->ApplyPathStyle(pen)) {
416         auto borderWidth = border->GetWidth();
417         RRect rrect = RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline);
418         rrect.rect_.width_ -= borderWidth;
419         rrect.rect_.height_ -= borderWidth;
420         rrect.rect_.Move(borderWidth / PARAM_TWO, borderWidth / PARAM_TWO);
421         Drawing::Path borderPath;
422         borderPath.AddRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(rrect));
423         canvas.AttachPen(pen);
424         canvas.DrawPath(borderPath);
425         canvas.DetachPen();
426         return;
427     }
428 
429     RSBorderGeo borderGeo;
430     borderGeo.rrect = RSPropertyDrawableUtils::RRect2DrawingRRect(
431         RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
432     borderGeo.innerRRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
433         RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
434     auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
435     auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
436     borderGeo.center = { centerX, centerY };
437     auto rect = borderGeo.rrect.GetRect();
438     Drawing::AutoCanvasRestore acr(canvas, false);
439     Drawing::SaveLayerOps slr(&rect, nullptr);
440     canvas.SaveLayer(slr);
441     border->DrawBorders(canvas, pen, borderGeo);
442 }
443 
OnGenerate(const RSRenderNode & node)444 RSDrawable::Ptr RSOutlineDrawable::OnGenerate(const RSRenderNode& node)
445 {
446     if (auto ret = std::make_shared<RSOutlineDrawable>(); ret->OnUpdate(node)) {
447         return std::move(ret);
448     }
449     return nullptr;
450 };
451 
OnUpdate(const RSRenderNode & node)452 bool RSOutlineDrawable::OnUpdate(const RSRenderNode& node)
453 {
454     const RSProperties& properties = node.GetRenderProperties();
455     auto& outline = properties.GetOutline();
456     if (!outline || !outline->HasBorder()) {
457         return false;
458     }
459     // regenerate stagingDrawCmdList_
460     RSPropertyDrawCmdListUpdater updater(0, 0, this);
461     RSBorderDrawable::DrawBorder(properties, *updater.GetRecordingCanvas(), outline, true);
462     return true;
463 }
464 
OnGenerate(const RSRenderNode & node)465 RSDrawable::Ptr RSPointLightDrawable::OnGenerate(const RSRenderNode& node)
466 {
467     if (auto ret = std::make_shared<RSPointLightDrawable>(node.GetRenderProperties()); ret->OnUpdate(node)) {
468         return std::move(ret);
469     }
470     return nullptr;
471 };
472 
CreateDrawFunc() const473 Drawing::RecordingCanvas::DrawFunc RSPointLightDrawable::CreateDrawFunc() const
474 {
475     auto ptr = std::static_pointer_cast<const RSPointLightDrawable>(shared_from_this());
476     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
477         ptr->DrawLight(canvas);
478     };
479 }
480 
OnUpdate(const RSRenderNode & node)481 bool RSPointLightDrawable::OnUpdate(const RSRenderNode& node)
482 {
483     const auto& illuminatedPtr = properties_.GetIlluminated();
484     if (!illuminatedPtr || !illuminatedPtr->IsIlluminatedValid()) {
485         return false;
486     }
487     return true;
488 }
489 
OnSync()490 void RSPointLightDrawable::OnSync()
491 {
492     lightSourcesAndPosVec_.clear();
493     const auto& lightSourcesAndPosMap  = properties_.GetIlluminated()->GetLightSourcesAndPosMap();
494     for (auto &pair : lightSourcesAndPosMap) {
495         lightSourcesAndPosVec_.push_back(pair);
496     }
497     properties_.GetIlluminated()->ClearLightSourcesAndPosMap();
498     if (lightSourcesAndPosVec_.empty()) {
499         return;
500     }
501     if (lightSourcesAndPosVec_.size() > MAX_LIGHT_SOURCES) {
502         std::sort(lightSourcesAndPosVec_.begin(), lightSourcesAndPosVec_.end(), [](const auto& x, const auto& y) {
503             return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
504                    y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
505         });
506     }
507     illuminatedType_ = properties_.GetIlluminated()->GetIlluminatedType();
508     borderWidth_ = std::ceil(properties_.GetIlluminatedBorderWidth());
509     auto& rrect = properties_.GetRRect();
510     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT || illuminatedType_ == IlluminatedType::BORDER) {
511         auto borderRect = rrect.rect_;
512         float borderRadius = rrect.radius_[0].x_;
513         // half width and half height requires divide by 2.0f
514         auto borderRRect = RRect(RectF(borderRect.left_ + borderWidth_ / 2.0f, borderRect.top_ + borderWidth_ / 2.0f,
515             borderRect.width_ - borderWidth_, borderRect.height_ - borderWidth_),
516             borderRadius - borderWidth_ / 2.0f, borderRadius - borderWidth_ / 2.0f);
517         borderRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(borderRRect);
518     }
519     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT || illuminatedType_ == IlluminatedType::CONTENT) {
520         contentRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(rrect);
521     }
522     if (properties_.GetBoundsGeometry()) {
523         rect_ = properties_.GetBoundsGeometry()->GetAbsRect();
524     }
525 }
526 
DrawLight(Drawing::Canvas * canvas) const527 void RSPointLightDrawable::DrawLight(Drawing::Canvas* canvas) const
528 {
529     if (lightSourcesAndPosVec_.empty()) {
530         return;
531     }
532     auto phongShaderBuilder = GetPhongShaderBuilder();
533     if (!phongShaderBuilder) {
534         return;
535     }
536     constexpr int vectorLen = 4;
537     float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
538     float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
539     float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
540     std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
541 
542     auto iter = lightSourcesAndPosVec_.begin();
543     auto cnt = 0;
544     while (iter != lightSourcesAndPosVec_.end() && cnt < MAX_LIGHT_SOURCES) {
545         auto lightPos = iter->second;
546         auto lightIntensity = iter->first->GetLightIntensity();
547         auto lightColor = iter->first->GetLightColor();
548         Vector4f lightColorVec =
549             Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
550         for (int i = 0; i < vectorLen; i++) {
551             lightPosArray[cnt * vectorLen + i] = lightPos[i];
552             viewPosArray[cnt * vectorLen + i] = lightPos[i];
553             lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
554         }
555         lightIntensityArray[cnt] = lightIntensity;
556         iter++;
557         cnt++;
558     }
559     phongShaderBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
560     phongShaderBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
561     phongShaderBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
562     Drawing::Pen pen;
563     Drawing::Brush brush;
564     pen.SetAntiAlias(true);
565     brush.SetAntiAlias(true);
566     ROSEN_LOGD("RSPointLightDrawable::DrawLight illuminatedType:%{public}d", illuminatedType_);
567     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT) {
568         DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
569         DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
570     } else if (illuminatedType_ == IlluminatedType::CONTENT) {
571         DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
572     } else if (illuminatedType_ == IlluminatedType::BORDER) {
573         DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
574     }
575 }
576 
GetPhongShaderBuilder()577 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPointLightDrawable::GetPhongShaderBuilder()
578 {
579     static std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder;
580     if (phongShaderBuilder) {
581         return phongShaderBuilder;
582     }
583     std::shared_ptr<Drawing::RuntimeEffect> lightEffect;
584     const static std::string lightString(R"(
585         uniform vec4 lightPos[12];
586         uniform vec4 viewPos[12];
587         uniform vec4 specularLightColor[12];
588         uniform float specularStrength[12];
589 
590         mediump vec4 main(vec2 drawing_coord) {
591             vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
592             float ambientStrength = 0.0;
593             vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
594             float diffuseStrength = 0.0;
595             float shininess = 8.0;
596             mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
597             vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
598             // ambient
599             vec4 ambient = lightColor * ambientStrength;
600             vec3 norm = normalize(NormalMap.rgb);
601 
602             for (int i = 0; i < 12; i++) {
603                 if (abs(specularStrength[i]) > 0.01) {
604                     vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
605                     float diff = max(dot(norm, lightDir), 0.0);
606                     vec4 diffuse = diff * lightColor;
607                     vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
608                     vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
609                     float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
610                     vec4 specular = lightColor * spec; // multiply color of incident light
611                     vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
612                     vec4 specularColor = specularLightColor[i];
613                     fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
614                 }
615             }
616             return fragColor;
617         }
618     )");
619     std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(lightString);
620     if (!effect) {
621         ROSEN_LOGE("light effect error");
622         return phongShaderBuilder;
623     }
624     lightEffect = std::move(effect);
625     phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect);
626     return phongShaderBuilder;
627 }
628 
DrawContentLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const629 void RSPointLightDrawable::DrawContentLight(Drawing::Canvas& canvas,
630     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
631     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
632 {
633     constexpr float contentIntensityCoefficient = 0.3f;
634     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
635     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
636         specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
637     }
638     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
639     std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
640     brush.SetShaderEffect(shader);
641     canvas.AttachBrush(brush);
642     canvas.DrawRoundRect(contentRRect_);
643     canvas.DetachBrush();
644 }
645 
DrawBorderLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const646 void RSPointLightDrawable::DrawBorderLight(Drawing::Canvas& canvas,
647     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
648     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
649 {
650     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
651     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
652         specularStrengthArr[i] = lightIntensityArray[i];
653     }
654     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
655     std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
656     pen.SetShaderEffect(shader);
657     float borderWidth = std::ceil(borderWidth_);
658     pen.SetWidth(borderWidth);
659     canvas.AttachPen(pen);
660     canvas.DrawRoundRect(borderRRect_);
661     canvas.DetachPen();
662 }
663 
OnGenerate(const RSRenderNode & node)664 RSDrawable::Ptr RSParticleDrawable::OnGenerate(const RSRenderNode& node)
665 {
666     if (auto ret = std::make_shared<RSParticleDrawable>(); ret->OnUpdate(node)) {
667         return std::move(ret);
668     }
669     return nullptr;
670 };
671 
OnUpdate(const RSRenderNode & node)672 bool RSParticleDrawable::OnUpdate(const RSRenderNode& node)
673 {
674     const RSProperties& properties = node.GetRenderProperties();
675     const auto& particleVector = properties.GetParticles();
676     if (particleVector.GetParticleSize() == 0) {
677         return false;
678     }
679 
680     RSPropertyDrawCmdListUpdater updater(0, 0, this);
681     Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
682     const auto& particles = particleVector.GetParticleVector();
683     auto bounds = properties.GetDrawRegion();
684     auto imageCount = particleVector.GetParticleImageCount();
685     auto imageVector = particleVector.GetParticleImageVector();
686     auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
687     if (particleDrawable != nullptr) {
688         particleDrawable->Draw(canvas, bounds);
689     }
690     return true;
691 }
692 } // namespace DrawableV2
693 } // namespace OHOS::Rosen
694