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