1 /*
2  * Copyright (c) 2023 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 "property/rs_point_light_manager.h"
17 
18 #include "common/rs_common_def.h"
19 #include "common/rs_obj_abs_geometry.h"
20 #include "pipeline/rs_render_node.h"
21 #include "property/rs_properties_def.h"
22 #include "screen_manager/screen_types.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 constexpr int TWO = 2;
27 
Instance()28 RSPointLightManager* RSPointLightManager::Instance()
29 {
30     static RSPointLightManager instance;
31     return &instance;
32 }
33 
RegisterLightSource(const std::shared_ptr<RSRenderNode> & renderNode)34 void RSPointLightManager::RegisterLightSource(const std::shared_ptr<RSRenderNode>& renderNode)
35 {
36     NodeId nodeId = renderNode->GetId();
37     lightSourceNodeMap_.emplace(nodeId, renderNode->weak_from_this());
38 }
39 
RegisterIlluminated(const std::shared_ptr<RSRenderNode> & renderNode)40 void RSPointLightManager::RegisterIlluminated(const std::shared_ptr<RSRenderNode>& renderNode)
41 {
42     NodeId nodeId = renderNode->GetId();
43     illuminatedNodeMap_.emplace(nodeId, renderNode->weak_from_this());
44 }
45 
UnRegisterLightSource(const std::shared_ptr<RSRenderNode> & renderNode)46 void RSPointLightManager::UnRegisterLightSource(const std::shared_ptr<RSRenderNode>& renderNode)
47 {
48     NodeId nodeId = renderNode->GetId();
49     lightSourceNodeMap_.erase(nodeId);
50 }
UnRegisterIlluminated(const std::shared_ptr<RSRenderNode> & renderNode)51 void RSPointLightManager::UnRegisterIlluminated(const std::shared_ptr<RSRenderNode>& renderNode)
52 {
53     NodeId nodeId = renderNode->GetId();
54     illuminatedNodeMap_.erase(nodeId);
55 }
AddDirtyLightSource(std::weak_ptr<RSRenderNode> renderNode)56 void RSPointLightManager::AddDirtyLightSource(std::weak_ptr<RSRenderNode> renderNode)
57 {
58     dirtyLightSourceList_.emplace_back(renderNode);
59 }
AddDirtyIlluminated(std::weak_ptr<RSRenderNode> renderNode)60 void RSPointLightManager::AddDirtyIlluminated(std::weak_ptr<RSRenderNode> renderNode)
61 {
62     dirtyIlluminatedList_.emplace_back(renderNode);
63 }
ClearDirtyList()64 void RSPointLightManager::ClearDirtyList()
65 {
66     dirtyLightSourceList_.clear();
67     dirtyIlluminatedList_.clear();
68 }
PrepareLight()69 void RSPointLightManager::PrepareLight()
70 {
71     for (auto &[_, weakPtr] : illuminatedNodeMap_) {
72         if (auto node = weakPtr.lock()) {
73             node->UpdatePointLightDirtySlot();
74         }
75     }
76     if (lightSourceNodeMap_.empty() || illuminatedNodeMap_.empty()) {
77         ClearDirtyList();
78         return;
79     }
80     if ((dirtyIlluminatedList_.empty() && dirtyLightSourceList_.empty())) {
81         return;
82     }
83     for (const auto& illuminatedWeakPtr : dirtyIlluminatedList_) {
84         auto illuminatedNodePtr = illuminatedWeakPtr.lock();
85         if (illuminatedNodePtr) {
86             illuminatedNodePtr->GetRenderProperties().GetIlluminated()->ClearLightSourcesAndPosMap();
87         }
88     }
89     PrepareLight(lightSourceNodeMap_, dirtyIlluminatedList_, false);
90     PrepareLight(illuminatedNodeMap_, dirtyLightSourceList_, true);
91     ClearDirtyList();
92 }
PrepareLight(std::unordered_map<NodeId,std::weak_ptr<RSRenderNode>> & map,std::vector<std::weak_ptr<RSRenderNode>> & dirtyList,bool isLightSourceDirty)93 void RSPointLightManager::PrepareLight(std::unordered_map<NodeId, std::weak_ptr<RSRenderNode>>& map,
94     std::vector<std::weak_ptr<RSRenderNode>>& dirtyList, bool isLightSourceDirty)
95 {
96     EraseIf(map, [this, isLightSourceDirty, &dirtyList](const auto& pair) -> bool {
97         auto mapElm = pair.second.lock();
98         if (!mapElm) {
99             return true;
100         }
101         if (!mapElm->IsOnTheTree()) { // skip check when node is not on the tree
102             return false;
103         }
104         for (const auto& weakPtr : dirtyList) {
105             auto dirtyNodePtr = weakPtr.lock();
106             if (!dirtyNodePtr) {
107                 continue;
108             }
109             std::shared_ptr<RSRenderNode> lightSourceNode = isLightSourceDirty ? dirtyNodePtr : mapElm;
110             std::shared_ptr<RSRenderNode> illuminatedNode = isLightSourceDirty ? mapElm : dirtyNodePtr;
111             CheckIlluminated(lightSourceNode, illuminatedNode);
112         }
113         return false;
114     });
115 }
CheckIlluminated(const std::shared_ptr<RSRenderNode> & lightSourceNode,const std::shared_ptr<RSRenderNode> & illuminatedNode)116 void RSPointLightManager::CheckIlluminated(
117     const std::shared_ptr<RSRenderNode>& lightSourceNode, const std::shared_ptr<RSRenderNode>& illuminatedNode)
118 {
119     const auto& geoPtr = (illuminatedNode->GetRenderProperties().GetBoundsGeometry());
120     auto lightSourcePtr = lightSourceNode->GetRenderProperties().GetLightSource();
121     if (!geoPtr || geoPtr->IsEmpty() || !lightSourcePtr) {
122         return;
123     }
124     RectI illuminatedAbsRect = geoPtr->GetAbsRect();
125     int radius = static_cast<int>(lightSourcePtr->GetLightRadius());
126     auto illuminatedRange = RectI(illuminatedAbsRect.left_ - radius, illuminatedAbsRect.top_ - radius,
127         illuminatedAbsRect.width_ + TWO * radius, illuminatedAbsRect.height_ + TWO * radius);
128     const auto& lightSourceAbsPosition = lightSourcePtr->GetAbsLightPosition();
129     auto lightAbsPositionX = static_cast<int>(lightSourceAbsPosition[0]);
130     auto lightAbsPositionY = static_cast<int>(lightSourceAbsPosition[1]);
131     auto rotation = GetScreenRotation();
132     auto inIlluminatedRange = false;
133     if (rotation == ScreenRotation::ROTATION_0 || rotation == ScreenRotation::ROTATION_180) {
134         inIlluminatedRange = illuminatedRange.Intersect(lightAbsPositionX, lightAbsPositionY);
135     } else if (rotation == ScreenRotation::ROTATION_90 || rotation == ScreenRotation::ROTATION_270) {
136         inIlluminatedRange = illuminatedRange.Intersect(lightAbsPositionY, lightAbsPositionX);
137     }
138     auto illuminatedRootNodeId = illuminatedNode->GetInstanceRootNodeId();
139     auto lightSourceRootNodeId = lightSourceNode->GetInstanceRootNodeId();
140     if (inIlluminatedRange && illuminatedRootNodeId == lightSourceRootNodeId) {
141         auto lightPos = CalculateLightPosForIlluminated(*lightSourcePtr, geoPtr->GetAbsRect());
142         illuminatedNode->GetRenderProperties().GetIlluminated()->AddLightSourcesAndPos(lightSourcePtr, lightPos);
143         illuminatedNode->SetDirty();
144     }
145 }
146 
CalculateLightPosForIlluminated(const RSLightSource & lightSource,const RectI & illuminatedAbsRect)147 Vector4f RSPointLightManager::CalculateLightPosForIlluminated(
148     const RSLightSource& lightSource, const RectI& illuminatedAbsRect)
149 {
150     Vector4f lightPos;
151     auto lightSourceAbsPosition = lightSource.GetAbsLightPosition();
152     auto lightPosition = lightSource.GetLightPosition();
153     auto rotation = GetScreenRotation();
154     switch (rotation) {
155         case ScreenRotation::ROTATION_0:
156             lightPos.x_ = lightSourceAbsPosition.x_ - illuminatedAbsRect.GetLeft();
157             lightPos.y_ = lightSourceAbsPosition.y_ - illuminatedAbsRect.GetTop();
158             break;
159         case ScreenRotation::ROTATION_90:
160             lightPos.x_ = illuminatedAbsRect.GetBottom() - lightSourceAbsPosition.x_;
161             lightPos.y_ = lightSourceAbsPosition.y_ - illuminatedAbsRect.GetLeft();
162             break;
163         case ScreenRotation::ROTATION_180:
164             lightPos.x_ = illuminatedAbsRect.GetRight() - lightSourceAbsPosition.x_;
165             lightPos.y_ = illuminatedAbsRect.GetBottom() - lightSourceAbsPosition.y_;
166             break;
167         case ScreenRotation::ROTATION_270:
168             lightPos.x_ = lightSourceAbsPosition.x_ - illuminatedAbsRect.GetTop();
169             lightPos.y_ = illuminatedAbsRect.GetRight() - lightSourceAbsPosition.y_;
170             break;
171         default:
172             break;
173     }
174     lightPos.z_ = lightPosition.z_;
175     lightPos.w_ = lightPosition.w_;
176     return lightPos;
177 }
178 
179 } // namespace Rosen
180 } // namespace OHOS