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