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 "render_data_store_default_light.h"
17 
18 #include <cstdint>
19 
20 #include <3d/render/default_material_constants.h>
21 #include <3d/render/render_data_defines_3d.h>
22 #include <base/containers/array_view.h>
23 #include <core/log.h>
24 #include <render/resource_handle.h>
25 
26 CORE3D_BEGIN_NAMESPACE()
27 using namespace BASE_NS;
28 using namespace RENDER_NS;
29 
RenderDataStoreDefaultLight(const string_view name)30 RenderDataStoreDefaultLight::RenderDataStoreDefaultLight(const string_view name) : name_(name) {}
31 
PostRender()32 void RenderDataStoreDefaultLight::PostRender()
33 {
34     Clear();
35 }
36 
Clear()37 void RenderDataStoreDefaultLight::Clear()
38 {
39     lights_.clear();
40     lightCounts_ = {};
41 }
42 
SetShadowTypes(const ShadowTypes & shadowTypes,const uint32_t flags)43 void RenderDataStoreDefaultLight::SetShadowTypes(const ShadowTypes& shadowTypes, const uint32_t flags)
44 {
45     shadowTypes_ = shadowTypes;
46 }
47 
GetShadowTypes() const48 IRenderDataStoreDefaultLight::ShadowTypes RenderDataStoreDefaultLight::GetShadowTypes() const
49 {
50     return shadowTypes_;
51 }
52 
SetShadowQualityResolutions(const ShadowQualityResolutions & resolutions,const uint32_t flags)53 void RenderDataStoreDefaultLight::SetShadowQualityResolutions(
54     const ShadowQualityResolutions& resolutions, const uint32_t flags)
55 {
56     resolutions_ = resolutions;
57 }
58 
GetShadowQualityResolution() const59 Math::UVec2 RenderDataStoreDefaultLight::GetShadowQualityResolution() const
60 {
61     if (shadowTypes_.shadowQuality == ShadowQuality::LOW) {
62         return resolutions_.low;
63     } else if (shadowTypes_.shadowQuality == ShadowQuality::NORMAL) {
64         return resolutions_.normal;
65     } else if (shadowTypes_.shadowQuality == ShadowQuality::HIGH) {
66         return resolutions_.high;
67     } else {
68         return resolutions_.ultra;
69     }
70 }
71 
AddLight(const RenderLight & light)72 void RenderDataStoreDefaultLight::AddLight(const RenderLight& light)
73 {
74     // drop light that has all components below zero (negative light)
75     constexpr float lightIntensityEpsilon { 0.0001f };
76     if (((light.color.x < 0.0f) && (light.color.y < 0.0f) && (light.color.z < 0.0f)) ||
77         (light.color.w < lightIntensityEpsilon)) {
78         return;
79     }
80 
81     RenderLight renderLight = light; // copy
82     // we do not support negative color values for lights
83     renderLight.color.x = Math::max(0.0f, renderLight.color.x);
84     renderLight.color.y = Math::max(0.0f, renderLight.color.y);
85     renderLight.color.z = Math::max(0.0f, renderLight.color.z);
86     const uint32_t lightCount = lightCounts_.directional + lightCounts_.spot + lightCounts_.point;
87 #if (CORE3D_VALIDATION_ENABLED == 1)
88     if (lightCount >= DefaultMaterialLightingConstants::MAX_LIGHT_COUNT) {
89         CORE_LOG_ONCE_W("drop_light_count_", "CORE3D_VALIDATION: light dropped (max count: %u)",
90             DefaultMaterialLightingConstants::MAX_LIGHT_COUNT);
91     }
92 #endif
93     if (lightCount < DefaultMaterialLightingConstants::MAX_LIGHT_COUNT) {
94         if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
95             lightCounts_.directional++;
96         } else if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
97             lightCounts_.spot++;
98         } else if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_POINT_LIGHT_BIT) {
99             lightCounts_.point++;
100         }
101         if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_SHADOW_LIGHT_BIT) {
102             const uint32_t shadowCount = lightCounts_.dirShadow + lightCounts_.spotShadow;
103             if (shadowCount < DefaultMaterialLightingConstants::MAX_SHADOW_COUNT) {
104                 if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
105                     lightCounts_.dirShadow++;
106                 } else if (renderLight.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
107                     lightCounts_.spotShadow++;
108                 }
109                 renderLight.shadowIndex = shadowCount; // shadow index in atlas
110                 lightCounts_.shadowCount = lightCounts_.spotShadow + lightCounts_.dirShadow;
111             }
112         }
113         lights_.push_back(move(renderLight));
114     }
115 }
116 
GetLights() const117 array_view<const RenderLight> RenderDataStoreDefaultLight::GetLights() const
118 {
119     return array_view<const RenderLight>(lights_);
120 }
121 
GetLightCounts() const122 IRenderDataStoreDefaultLight::LightCounts RenderDataStoreDefaultLight::GetLightCounts() const
123 {
124     return lightCounts_;
125 }
126 
GetLightingFlags() const127 IRenderDataStoreDefaultLight::LightingFlags RenderDataStoreDefaultLight::GetLightingFlags() const
128 {
129     LightingFlags lightingSpecializationFlags = 0u;
130     if (shadowTypes_.shadowType == IRenderDataStoreDefaultLight::ShadowType::VSM) {
131         lightingSpecializationFlags |= LightingFlagBits::LIGHTING_SHADOW_TYPE_VSM_BIT;
132     }
133     if (lightCounts_.point > 0u) {
134         lightingSpecializationFlags |= LightingFlagBits::LIGHTING_POINT_ENABLED_BIT;
135     }
136     if (lightCounts_.spot > 0u) {
137         lightingSpecializationFlags |= LightingFlagBits::LIGHTING_SPOT_ENABLED_BIT;
138     }
139     return lightingSpecializationFlags;
140 }
141 
142 // for plugin / factory interface
Create(RENDER_NS::IRenderContext &,char const * name)143 RENDER_NS::IRenderDataStore* RenderDataStoreDefaultLight::Create(RENDER_NS::IRenderContext&, char const* name)
144 {
145     // engine not needed
146     return new RenderDataStoreDefaultLight(name);
147 }
148 
Destroy(IRenderDataStore * instance)149 void RenderDataStoreDefaultLight::Destroy(IRenderDataStore* instance)
150 {
151     delete static_cast<RenderDataStoreDefaultLight*>(instance);
152 }
153 CORE3D_END_NAMESPACE()
154