• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     stagingNodeName_ = node.GetNodeName();
216     auto& rsFilter = node.GetRenderProperties().GetFilter();
217     if (rsFilter == nullptr) {
218         return false;
219     }
220     RecordFilterInfos(rsFilter);
221     needSync_ = true;
222     stagingFilter_ = rsFilter;
223     return true;
224 }
225 
226 // foregroundFilter
OnGenerate(const RSRenderNode & node)227 RSDrawable::Ptr RSForegroundFilterDrawable::OnGenerate(const RSRenderNode& node)
228 {
229     if (!FOREGROUND_FILTER_ENABLED) {
230         ROSEN_LOGD("RSForegroundFilterDrawable::OnGenerate close blur.");
231         return nullptr;
232     }
233     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
234     if (rsFilter == nullptr) {
235         return nullptr;
236     }
237 
238     if (auto ret = std::make_shared<RSForegroundFilterDrawable>(); ret->OnUpdate(node)) {
239         return std::move(ret);
240     }
241     return nullptr;
242 }
243 
OnUpdate(const RSRenderNode & node)244 bool RSForegroundFilterDrawable::OnUpdate(const RSRenderNode& node)
245 {
246     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
247     if (rsFilter == nullptr) {
248         return false;
249     }
250     needSync_ = true;
251     stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
252     return true;
253 }
254 
CreateDrawFunc() const255 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterDrawable::CreateDrawFunc() const
256 {
257     auto ptr = std::static_pointer_cast<const RSForegroundFilterDrawable>(shared_from_this());
258     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
259         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
260         RSPropertyDrawableUtils::BeginForegroundFilter(*paintFilterCanvas, ptr->boundsRect_);
261     };
262 }
263 
OnSync()264 void RSForegroundFilterDrawable::OnSync()
265 {
266     if (needSync_ == false) {
267         return;
268     }
269     boundsRect_ = stagingBoundsRect_;
270     needSync_ = false;
271 }
272 
273 // Restore RSForegroundFilter
OnGenerate(const RSRenderNode & node)274 RSDrawable::Ptr RSForegroundFilterRestoreDrawable::OnGenerate(const RSRenderNode& node)
275 {
276     if (!FOREGROUND_FILTER_ENABLED) {
277         ROSEN_LOGD("RSForegroundFilterRestoreDrawable::OnGenerate close blur.");
278         return nullptr;
279     }
280     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
281     if (rsFilter == nullptr) {
282         return nullptr;
283     }
284 
285     if (auto ret = std::make_shared<RSForegroundFilterRestoreDrawable>(); ret->OnUpdate(node)) {
286         return std::move(ret);
287     }
288     return nullptr;
289 }
290 
OnUpdate(const RSRenderNode & node)291 bool RSForegroundFilterRestoreDrawable::OnUpdate(const RSRenderNode& node)
292 {
293     auto& rsFilter = node.GetRenderProperties().GetForegroundFilter();
294     if (rsFilter == nullptr) {
295         return false;
296     }
297     needSync_ = true;
298     stagingForegroundFilter_ = rsFilter;
299     return true;
300 }
301 
CreateDrawFunc() const302 Drawing::RecordingCanvas::DrawFunc RSForegroundFilterRestoreDrawable::CreateDrawFunc() const
303 {
304     auto ptr = std::static_pointer_cast<const RSForegroundFilterRestoreDrawable>(shared_from_this());
305     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
306         auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
307         RSPropertyDrawableUtils::DrawForegroundFilter(*paintFilterCanvas, ptr->foregroundFilter_);
308     };
309 }
310 
OnSync()311 void RSForegroundFilterRestoreDrawable::OnSync()
312 {
313     if (needSync_ == false) {
314         return;
315     }
316     foregroundFilter_ = std::move(stagingForegroundFilter_);
317     needSync_ = false;
318 }
319 
OnGenerate(const RSRenderNode & node)320 RSDrawable::Ptr RSPixelStretchDrawable::OnGenerate(const RSRenderNode& node)
321 {
322     if (auto ret = std::make_shared<RSPixelStretchDrawable>(); ret->OnUpdate(node)) {
323         return std::move(ret);
324     }
325     return nullptr;
326 }
327 
OnUpdate(const RSRenderNode & node)328 bool RSPixelStretchDrawable::OnUpdate(const RSRenderNode& node)
329 {
330     auto& pixelStretch = node.GetRenderProperties().GetPixelStretch();
331     if (!pixelStretch.has_value()) {
332         return false;
333     }
334     needSync_ = true;
335     stagingPixelStretch_ = pixelStretch;
336     stagePixelStretchTileMode_ = node.GetRenderProperties().GetPixelStretchTileMode();
337     const auto& boundsGeo = node.GetRenderProperties().GetBoundsGeometry();
338     stagingBoundsGeoValid_ = boundsGeo && !boundsGeo->IsEmpty();
339     stagingBoundsRect_ = node.GetRenderProperties().GetBoundsRect();
340     return true;
341 }
342 
SetPixelStretch(const std::optional<Vector4f> & pixelStretch)343 void RSPixelStretchDrawable::SetPixelStretch(const std::optional<Vector4f>& pixelStretch)
344 {
345     stagingPixelStretch_ = pixelStretch;
346 }
347 
OnSync()348 void RSPixelStretchDrawable::OnSync()
349 {
350     if (!needSync_) {
351         return;
352     }
353     pixelStretch_ = std::move(stagingPixelStretch_);
354     pixelStretchTileMode_ = stagePixelStretchTileMode_;
355     boundsGeoValid_ = stagingBoundsGeoValid_;
356     stagingBoundsGeoValid_ = false;
357     boundsRect_ = stagingBoundsRect_;
358     stagingBoundsRect_.Clear();
359     needSync_ = false;
360 }
361 
CreateDrawFunc() const362 Drawing::RecordingCanvas::DrawFunc RSPixelStretchDrawable::CreateDrawFunc() const
363 {
364     auto ptr = std::static_pointer_cast<const RSPixelStretchDrawable>(shared_from_this());
365     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
366         RSPropertyDrawableUtils::DrawPixelStretch(canvas, ptr->pixelStretch_, ptr->boundsRect_, ptr->boundsGeoValid_,
367             static_cast<Drawing::TileMode>(ptr->pixelStretchTileMode_));
368     };
369 }
370 
OnGenerate(const RSRenderNode & node)371 RSDrawable::Ptr RSBorderDrawable::OnGenerate(const RSRenderNode& node)
372 {
373     if (auto ret = std::make_shared<RSBorderDrawable>(); ret->OnUpdate(node)) {
374         return std::move(ret);
375     }
376     return nullptr;
377 };
378 
OnUpdate(const RSRenderNode & node)379 bool RSBorderDrawable::OnUpdate(const RSRenderNode& node)
380 {
381     const RSProperties& properties = node.GetRenderProperties();
382     auto& border = properties.GetBorder();
383     if (!border || !border->HasBorder()) {
384         return false;
385     }
386     // regenerate stagingDrawCmdList_
387     RSPropertyDrawCmdListUpdater updater(0, 0, this);
388     DrawBorder(properties, *updater.GetRecordingCanvas(), border, false);
389     return true;
390 }
391 
DrawBorder(const RSProperties & properties,Drawing::Canvas & canvas,const std::shared_ptr<RSBorder> & border,const bool & isOutline)392 void RSBorderDrawable::DrawBorder(const RSProperties& properties, Drawing::Canvas& canvas,
393     const std::shared_ptr<RSBorder>& border, const bool& isOutline)
394 {
395     Drawing::Brush brush;
396     Drawing::Pen pen;
397     brush.SetAntiAlias(true);
398     pen.SetAntiAlias(true);
399     if (border->ApplyFillStyle(brush)) {
400         auto roundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
401             RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
402         auto innerRoundRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
403             RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
404         canvas.AttachBrush(brush);
405         canvas.DrawNestedRoundRect(roundRect, innerRoundRect);
406         canvas.DetachBrush();
407         return;
408     }
409     bool isZero = isOutline ? border->GetRadiusFour().IsZero() : properties.GetCornerRadius().IsZero();
410     if (isZero && border->ApplyFourLine(pen)) {
411         RectF rectf =
412             isOutline ? properties.GetBoundsRect().MakeOutset(border->GetWidthFour()) : properties.GetBoundsRect();
413         border->PaintFourLine(canvas, pen, rectf);
414         return;
415     }
416     if (border->ApplyPathStyle(pen)) {
417         auto borderWidth = border->GetWidth();
418         RRect rrect = RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline);
419         rrect.rect_.width_ -= borderWidth;
420         rrect.rect_.height_ -= borderWidth;
421         rrect.rect_.Move(borderWidth / PARAM_TWO, borderWidth / PARAM_TWO);
422         Drawing::Path borderPath;
423         borderPath.AddRoundRect(RSPropertyDrawableUtils::RRect2DrawingRRect(rrect));
424         canvas.AttachPen(pen);
425         canvas.DrawPath(borderPath);
426         canvas.DetachPen();
427         return;
428     }
429 
430     RSBorderGeo borderGeo;
431     borderGeo.rrect = RSPropertyDrawableUtils::RRect2DrawingRRect(
432         RSPropertyDrawableUtils::GetRRectForDrawingBorder(properties, border, isOutline));
433     borderGeo.innerRRect = RSPropertyDrawableUtils::RRect2DrawingRRect(
434         RSPropertyDrawableUtils::GetInnerRRectForDrawingBorder(properties, border, isOutline));
435     auto centerX = borderGeo.innerRRect.GetRect().GetLeft() + borderGeo.innerRRect.GetRect().GetWidth() / 2;
436     auto centerY = borderGeo.innerRRect.GetRect().GetTop() + borderGeo.innerRRect.GetRect().GetHeight() / 2;
437     borderGeo.center = { centerX, centerY };
438     auto rect = borderGeo.rrect.GetRect();
439     Drawing::AutoCanvasRestore acr(canvas, false);
440     Drawing::SaveLayerOps slr(&rect, nullptr);
441     canvas.SaveLayer(slr);
442     border->DrawBorders(canvas, pen, borderGeo);
443 }
444 
OnGenerate(const RSRenderNode & node)445 RSDrawable::Ptr RSOutlineDrawable::OnGenerate(const RSRenderNode& node)
446 {
447     if (auto ret = std::make_shared<RSOutlineDrawable>(); ret->OnUpdate(node)) {
448         return std::move(ret);
449     }
450     return nullptr;
451 };
452 
OnUpdate(const RSRenderNode & node)453 bool RSOutlineDrawable::OnUpdate(const RSRenderNode& node)
454 {
455     const RSProperties& properties = node.GetRenderProperties();
456     auto& outline = properties.GetOutline();
457     if (!outline || !outline->HasBorder()) {
458         return false;
459     }
460     // regenerate stagingDrawCmdList_
461     RSPropertyDrawCmdListUpdater updater(0, 0, this);
462     RSBorderDrawable::DrawBorder(properties, *updater.GetRecordingCanvas(), outline, true);
463     return true;
464 }
465 
OnGenerate(const RSRenderNode & node)466 RSDrawable::Ptr RSPointLightDrawable::OnGenerate(const RSRenderNode& node)
467 {
468     if (auto ret = std::make_shared<RSPointLightDrawable>(node.GetRenderProperties()); ret->OnUpdate(node)) {
469         return std::move(ret);
470     }
471     return nullptr;
472 };
473 
CreateDrawFunc() const474 Drawing::RecordingCanvas::DrawFunc RSPointLightDrawable::CreateDrawFunc() const
475 {
476     auto ptr = std::static_pointer_cast<const RSPointLightDrawable>(shared_from_this());
477     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
478         ptr->DrawLight(canvas);
479     };
480 }
481 
OnUpdate(const RSRenderNode & node)482 bool RSPointLightDrawable::OnUpdate(const RSRenderNode& node)
483 {
484     const auto& illuminatedPtr = properties_.GetIlluminated();
485     if (!illuminatedPtr || !illuminatedPtr->IsIlluminatedValid()) {
486         return false;
487     }
488     return true;
489 }
490 
OnSync()491 void RSPointLightDrawable::OnSync()
492 {
493     lightSourcesAndPosVec_.clear();
494     const auto& lightSourcesAndPosMap  = properties_.GetIlluminated()->GetLightSourcesAndPosMap();
495     for (auto &pair : lightSourcesAndPosMap) {
496         lightSourcesAndPosVec_.push_back(pair);
497     }
498     properties_.GetIlluminated()->ClearLightSourcesAndPosMap();
499     if (lightSourcesAndPosVec_.empty()) {
500         return;
501     }
502     if (lightSourcesAndPosVec_.size() > MAX_LIGHT_SOURCES) {
503         std::sort(lightSourcesAndPosVec_.begin(), lightSourcesAndPosVec_.end(), [](const auto& x, const auto& y) {
504             return x.second.x_ * x.second.x_ + x.second.y_ * x.second.y_ <
505                    y.second.x_ * y.second.x_ + y.second.y_ * y.second.y_;
506         });
507     }
508     illuminatedType_ = properties_.GetIlluminated()->GetIlluminatedType();
509     borderWidth_ = std::ceil(properties_.GetIlluminatedBorderWidth());
510     auto& rrect = properties_.GetRRect();
511     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT ||
512         illuminatedType_ == IlluminatedType::BORDER ||
513         illuminatedType_ == IlluminatedType::BLEND_BORDER ||
514         illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT) {
515         // half width and half height requires divide by 2.0f
516         Vector4f width = { borderWidth_ / 2.0f };
517         auto borderRRect = rrect.Inset(width);
518         borderRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(borderRRect);
519     }
520     if (illuminatedType_ == IlluminatedType::BORDER_CONTENT ||
521         illuminatedType_ == IlluminatedType::CONTENT ||
522         illuminatedType_ == IlluminatedType::BLEND_CONTENT ||
523         illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT) {
524         contentRRect_ = RSPropertyDrawableUtils::RRect2DrawingRRect(rrect);
525     }
526     if (properties_.GetBoundsGeometry()) {
527         rect_ = properties_.GetBoundsGeometry()->GetAbsRect();
528     }
529 }
530 
DrawLight(Drawing::Canvas * canvas) const531 void RSPointLightDrawable::DrawLight(Drawing::Canvas* canvas) const
532 {
533     if (lightSourcesAndPosVec_.empty()) {
534         return;
535     }
536     auto phongShaderBuilder = GetPhongShaderBuilder();
537     if (!phongShaderBuilder) {
538         return;
539     }
540     constexpr int vectorLen = 4;
541     float lightPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
542     float viewPosArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
543     float lightColorArray[vectorLen * MAX_LIGHT_SOURCES] = { 0 };
544     std::array<float, MAX_LIGHT_SOURCES> lightIntensityArray = { 0 };
545 
546     auto iter = lightSourcesAndPosVec_.begin();
547     auto cnt = 0;
548     while (iter != lightSourcesAndPosVec_.end() && cnt < MAX_LIGHT_SOURCES) {
549         auto lightPos = iter->second;
550         auto lightIntensity = iter->first->GetLightIntensity();
551         auto lightColor = iter->first->GetLightColor();
552         Vector4f lightColorVec =
553             Vector4f(lightColor.GetRed(), lightColor.GetGreen(), lightColor.GetBlue(), lightColor.GetAlpha());
554         for (int i = 0; i < vectorLen; i++) {
555             lightPosArray[cnt * vectorLen + i] = lightPos[i];
556             viewPosArray[cnt * vectorLen + i] = lightPos[i];
557             lightColorArray[cnt * vectorLen + i] = lightColorVec[i] / UINT8_MAX;
558         }
559         lightIntensityArray[cnt] = lightIntensity;
560         iter++;
561         cnt++;
562     }
563     phongShaderBuilder->SetUniform("lightPos", lightPosArray, vectorLen * MAX_LIGHT_SOURCES);
564     phongShaderBuilder->SetUniform("viewPos", viewPosArray, vectorLen * MAX_LIGHT_SOURCES);
565     phongShaderBuilder->SetUniform("specularLightColor", lightColorArray, vectorLen * MAX_LIGHT_SOURCES);
566     Drawing::Pen pen;
567     Drawing::Brush brush;
568     pen.SetAntiAlias(true);
569     brush.SetAntiAlias(true);
570     ROSEN_LOGD("RSPointLightDrawable::DrawLight illuminatedType:%{public}d", illuminatedType_);
571     if ((illuminatedType_ == IlluminatedType::BORDER_CONTENT) ||
572         (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
573         DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
574         DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
575     } else if ((illuminatedType_ == IlluminatedType::CONTENT) ||
576         (illuminatedType_ == IlluminatedType::BLEND_CONTENT)) {
577         DrawContentLight(*canvas, phongShaderBuilder, brush, lightIntensityArray);
578     } else if ((illuminatedType_ == IlluminatedType::BORDER) ||
579         (illuminatedType_ == IlluminatedType::BLEND_BORDER)) {
580         DrawBorderLight(*canvas, phongShaderBuilder, pen, lightIntensityArray);
581     }
582 }
583 
GetPhongShaderBuilder()584 const std::shared_ptr<Drawing::RuntimeShaderBuilder>& RSPointLightDrawable::GetPhongShaderBuilder()
585 {
586     thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> phongShaderBuilder;
587     if (phongShaderBuilder) {
588         return phongShaderBuilder;
589     }
590     std::shared_ptr<Drawing::RuntimeEffect> lightEffect;
591     const static std::string lightString(R"(
592         uniform vec4 lightPos[12];
593         uniform vec4 viewPos[12];
594         uniform vec4 specularLightColor[12];
595         uniform float specularStrength[12];
596 
597         mediump vec4 main(vec2 drawing_coord) {
598             vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
599             float ambientStrength = 0.0;
600             vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0);
601             float diffuseStrength = 0.0;
602             float shininess = 8.0;
603             mediump vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0);
604             vec4 NormalMap = vec4(0.0, 0.0, 1.0, 0.0);
605             // ambient
606             vec4 ambient = lightColor * ambientStrength;
607             vec3 norm = normalize(NormalMap.rgb);
608 
609             for (int i = 0; i < 12; i++) {
610                 if (abs(specularStrength[i]) > 0.01) {
611                     vec3 lightDir = normalize(vec3(lightPos[i].xy - drawing_coord, lightPos[i].z));
612                     float diff = max(dot(norm, lightDir), 0.0);
613                     vec4 diffuse = diff * lightColor;
614                     vec3 viewDir = normalize(vec3(viewPos[i].xy - drawing_coord, viewPos[i].z)); // view vector
615                     vec3 halfwayDir = normalize(lightDir + viewDir); // half vector
616                     float spec = pow(max(dot(norm, halfwayDir), 0.0), shininess); // exponential relationship of angle
617                     vec4 specular = lightColor * spec; // multiply color of incident light
618                     vec4 o = ambient + diffuse * diffuseStrength * diffuseColor; // diffuse reflection
619                     vec4 specularColor = specularLightColor[i];
620                     fragColor = fragColor + o + specular * specularStrength[i] * specularColor;
621                 }
622             }
623             return fragColor;
624         }
625     )");
626     std::shared_ptr<Drawing::RuntimeEffect> effect = Drawing::RuntimeEffect::CreateForShader(lightString);
627     if (!effect) {
628         ROSEN_LOGE("light effect error");
629         return phongShaderBuilder;
630     }
631     lightEffect = std::move(effect);
632     phongShaderBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(lightEffect);
633     return phongShaderBuilder;
634 }
635 
DrawContentLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Brush & brush,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const636 void RSPointLightDrawable::DrawContentLight(Drawing::Canvas& canvas,
637     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Brush& brush,
638     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
639 {
640     constexpr float contentIntensityCoefficient = 0.3f;
641     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
642     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
643         specularStrengthArr[i] = lightIntensityArray[i] * contentIntensityCoefficient;
644     }
645     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
646     std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
647     brush.SetShaderEffect(shader);
648     if ((illuminatedType_ == IlluminatedType::BLEND_CONTENT) ||
649         (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
650         brush.SetAntiAlias(true);
651         brush.SetBlendMode(Drawing::BlendMode::OVERLAY);
652         Drawing::SaveLayerOps slo(&contentRRect_.GetRect(), &brush);
653         canvas.SaveLayer(slo);
654         canvas.AttachBrush(brush);
655         canvas.DrawRoundRect(contentRRect_);
656         canvas.DetachBrush();
657         canvas.Restore();
658     } else {
659         canvas.AttachBrush(brush);
660         canvas.DrawRoundRect(contentRRect_);
661         canvas.DetachBrush();
662     }
663 }
664 
DrawBorderLight(Drawing::Canvas & canvas,std::shared_ptr<Drawing::RuntimeShaderBuilder> & lightBuilder,Drawing::Pen & pen,const std::array<float,MAX_LIGHT_SOURCES> & lightIntensityArray) const665 void RSPointLightDrawable::DrawBorderLight(Drawing::Canvas& canvas,
666     std::shared_ptr<Drawing::RuntimeShaderBuilder>& lightBuilder, Drawing::Pen& pen,
667     const std::array<float, MAX_LIGHT_SOURCES>& lightIntensityArray) const
668 {
669     float specularStrengthArr[MAX_LIGHT_SOURCES] = { 0 };
670     for (int i = 0; i < MAX_LIGHT_SOURCES; i++) {
671         specularStrengthArr[i] = lightIntensityArray[i];
672     }
673     lightBuilder->SetUniform("specularStrength", specularStrengthArr, MAX_LIGHT_SOURCES);
674     std::shared_ptr<Drawing::ShaderEffect> shader = lightBuilder->MakeShader(nullptr, false);
675     pen.SetShaderEffect(shader);
676     float borderWidth = std::ceil(borderWidth_);
677     pen.SetWidth(borderWidth);
678     if ((illuminatedType_ == IlluminatedType::BLEND_BORDER) ||
679         (illuminatedType_ == IlluminatedType::BLEND_BORDER_CONTENT)) {
680         Drawing::Brush maskPaint;
681         pen.SetBlendMode(Drawing::BlendMode::OVERLAY);
682         Drawing::SaveLayerOps slo(&borderRRect_.GetRect(), &maskPaint);
683         canvas.SaveLayer(slo);
684         canvas.AttachPen(pen);
685         canvas.DrawRoundRect(borderRRect_);
686         canvas.DetachPen();
687         canvas.Restore();
688     } else {
689         canvas.AttachPen(pen);
690         canvas.DrawRoundRect(borderRRect_);
691         canvas.DetachPen();
692     }
693 }
694 
OnGenerate(const RSRenderNode & node)695 RSDrawable::Ptr RSParticleDrawable::OnGenerate(const RSRenderNode& node)
696 {
697     if (auto ret = std::make_shared<RSParticleDrawable>(); ret->OnUpdate(node)) {
698         return std::move(ret);
699     }
700     return nullptr;
701 };
702 
OnUpdate(const RSRenderNode & node)703 bool RSParticleDrawable::OnUpdate(const RSRenderNode& node)
704 {
705     const RSProperties& properties = node.GetRenderProperties();
706     const auto& particleVector = properties.GetParticles();
707     if (particleVector.GetParticleSize() == 0) {
708         return false;
709     }
710 
711     RSPropertyDrawCmdListUpdater updater(0, 0, this);
712     Drawing::Canvas& canvas = *updater.GetRecordingCanvas();
713     const auto& particles = particleVector.GetParticleVector();
714     auto bounds = properties.GetDrawRegion();
715     auto imageCount = particleVector.GetParticleImageCount();
716     auto imageVector = particleVector.GetParticleImageVector();
717     auto particleDrawable = std::make_shared<RSParticlesDrawable>(particles, imageVector, imageCount);
718     if (particleDrawable != nullptr) {
719         particleDrawable->Draw(canvas, bounds);
720     }
721     return true;
722 }
723 } // namespace DrawableV2
724 } // namespace OHOS::Rosen
725