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 #include "ge_magnifier_shader_filter.h"
16
17 #include "ge_log.h"
18
19 namespace OHOS {
20 namespace Rosen {
21
22 namespace {
23 constexpr static uint8_t COLOR_CHANNEL = 4; // 4 len of rgba
24 } // namespace
25
26 std::shared_ptr<Drawing::RuntimeEffect> GEMagnifierShaderFilter::g_magnifierShaderEffect = nullptr;
27
GEMagnifierShaderFilter(const Drawing::GEMagnifierShaderFilterParams & params)28 GEMagnifierShaderFilter::GEMagnifierShaderFilter(const Drawing::GEMagnifierShaderFilterParams& params)
29 {
30 magnifierPara_ = std::make_shared<GEMagnifierParams>();
31 if (!magnifierPara_) {
32 return;
33 }
34 magnifierPara_->factor_ = params.factor;
35 magnifierPara_->width_ = params.width;
36 magnifierPara_->height_ = params.height;
37 magnifierPara_->cornerRadius_ = params.cornerRadius;
38 magnifierPara_->borderWidth_ = params.borderWidth;
39 magnifierPara_->shadowOffsetX_ = params.shadowOffsetX;
40 magnifierPara_->shadowOffsetY_ = params.shadowOffsetY;
41 magnifierPara_->shadowSize_ = params.shadowSize;
42 magnifierPara_->shadowStrength_ = params.shadowStrength;
43 magnifierPara_->gradientMaskColor1_ = params.gradientMaskColor1;
44 magnifierPara_->gradientMaskColor2_ = params.gradientMaskColor2;
45 magnifierPara_->outerContourColor1_ = params.outerContourColor1;
46 magnifierPara_->outerContourColor2_ = params.outerContourColor2;
47 magnifierPara_->rotateDegree_ = params.rotateDegree;
48 }
49
ProcessImage(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> image,const Drawing::Rect & src,const Drawing::Rect & dst)50 std::shared_ptr<Drawing::Image> GEMagnifierShaderFilter::ProcessImage(Drawing::Canvas& canvas,
51 const std::shared_ptr<Drawing::Image> image, const Drawing::Rect& src, const Drawing::Rect& dst)
52 {
53 if (image == nullptr || magnifierPara_ == nullptr) {
54 LOGE("GEMagnifierShaderFilter::ProcessImage image or para is null");
55 return image;
56 }
57
58 Drawing::Matrix matrix;
59 matrix.Rotate(magnifierPara_->rotateDegree_, src.GetLeft() + src.GetWidth() / 2.0f,
60 src.GetTop() + src.GetHeight() / 2.0f); // 2.0 center of rect
61 auto imageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
62 Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
63 float imageWidth = image->GetWidth();
64 float imageHeight = image->GetHeight();
65 auto builder = MakeMagnifierShader(imageShader, imageWidth, imageHeight);
66 if (builder == nullptr) {
67 LOGE("GEMagnifierShaderFilter::ProcessImage builder is null");
68 return image;
69 }
70
71 Drawing::Matrix invMatrix;
72 invMatrix.Rotate(-magnifierPara_->rotateDegree_, src.GetLeft() + src.GetWidth() / 2.0f,
73 src.GetTop() + src.GetHeight() / 2.0f); // 2.0 center of rect
74 auto resultImage = builder->MakeImage(canvas.GetGPUContext().get(), &invMatrix, image->GetImageInfo(), false);
75 if (resultImage == nullptr) {
76 LOGE("GEMagnifierShaderFilter::ProcessImage resultImage is null");
77 return image;
78 }
79
80 return resultImage;
81 }
82
MakeMagnifierShader(std::shared_ptr<Drawing::ShaderEffect> imageShader,float imageWidth,float imageHeight)83 std::shared_ptr<Drawing::RuntimeShaderBuilder> GEMagnifierShaderFilter::MakeMagnifierShader(
84 std::shared_ptr<Drawing::ShaderEffect> imageShader, float imageWidth, float imageHeight)
85 {
86 if (g_magnifierShaderEffect == nullptr) {
87 if (!InitMagnifierEffect()) {
88 LOGE("GEMagnifierShaderFilter::failed when initializing MagnifierEffect.");
89 return nullptr;
90 }
91 }
92
93 if (magnifierPara_ == nullptr) {
94 return nullptr;
95 }
96 std::shared_ptr<Drawing::RuntimeShaderBuilder> builder =
97 std::make_shared<Drawing::RuntimeShaderBuilder>(g_magnifierShaderEffect);
98 builder->SetChild("imageShader", imageShader);
99 builder->SetUniform("iResolution", imageWidth, imageHeight);
100
101 builder->SetUniform("factor", magnifierPara_->factor_);
102 builder->SetUniform("size", magnifierPara_->width_, magnifierPara_->height_);
103 builder->SetUniform("cornerRadius", magnifierPara_->cornerRadius_);
104 builder->SetUniform("borderWidth", magnifierPara_->borderWidth_);
105
106 builder->SetUniform("shadowOffset", magnifierPara_->shadowOffsetX_, magnifierPara_->shadowOffsetY_);
107 builder->SetUniform("shadowSize", magnifierPara_->shadowSize_);
108 builder->SetUniform("shadowStrength", magnifierPara_->shadowStrength_);
109
110 float maskColor1[COLOR_CHANNEL] = { 0.0f };
111 float maskColor2[COLOR_CHANNEL] = { 0.0f };
112 float outColor1[COLOR_CHANNEL] = { 0.0f };
113 float outColor2[COLOR_CHANNEL] = { 0.0f };
114 ConvertToRgba(magnifierPara_->gradientMaskColor1_, maskColor1, COLOR_CHANNEL);
115 ConvertToRgba(magnifierPara_->gradientMaskColor2_, maskColor2, COLOR_CHANNEL);
116 ConvertToRgba(magnifierPara_->outerContourColor1_, outColor1, COLOR_CHANNEL);
117 ConvertToRgba(magnifierPara_->outerContourColor2_, outColor2, COLOR_CHANNEL);
118 builder->SetUniform("gradientMaskColor1", maskColor1, COLOR_CHANNEL);
119 builder->SetUniform("gradientMaskColor2", maskColor2, COLOR_CHANNEL);
120 builder->SetUniform("outerContourColor1", outColor1, COLOR_CHANNEL);
121 builder->SetUniform("outerContourColor2", outColor2, COLOR_CHANNEL);
122
123 return builder;
124 }
125
InitMagnifierEffect()126 bool GEMagnifierShaderFilter::InitMagnifierEffect()
127 {
128 if (g_magnifierShaderEffect == nullptr) {
129 static constexpr char prog[] = R"(
130 uniform shader imageShader;
131 uniform float2 iResolution;
132
133 uniform float factor;
134 uniform float borderWidth;
135 uniform float cornerRadius;
136 uniform float2 size;
137
138 uniform float2 shadowOffset;
139 uniform float shadowSize;
140 uniform float shadowStrength;
141
142 uniform vec4 gradientMaskColor1;
143 uniform vec4 gradientMaskColor2;
144 uniform vec4 outerContourColor1;
145 uniform vec4 outerContourColor2;
146
147 // refraction
148 const float refractionStrength = 0.02; // 0.02 refraction strength
149 const float epsilon = 1e-4;
150
151 vec4 sdfRect(vec2 position, vec2 R1, float R2, float curvature, out float isInBorder)
152 {
153 // calculate normal
154 vec2 d = max(abs(position) - R1, 0.0);
155 float dist = length(d) / R2;
156 vec2 dir = normalize(sign(position) * d);
157 float borderHeightRatio = min(size.x, size.y) / (borderWidth * 2.8); // 2.8 borderWidth
158 float posInBorder = mix(1.0 - borderHeightRatio, 1.0, dist);
159 float weight = max(posInBorder, 0.0);
160 vec3 normal = normalize(mix(vec3(0.0, 0.0, 1.0), vec3(dir, 0.0), weight));
161 isInBorder = smoothstep(0.0, 0.3, posInBorder); // 0.3 alpha threshold
162
163 // calculate shadow
164 position -= shadowOffset / iResolution.x;
165 float R2Shadow = R2 + 0.5 * shadowSize / iResolution.x; // 0.5 half of shader size
166 float distShadow = length(max(abs(position) - R1, 0.)) / R2Shadow;
167 float shadowSizeHeightRatio = min(size.x, size.y) / (shadowSize / (curvature + epsilon) * 2.0);
168 float weightShadow = max(mix(1.0 - shadowSizeHeightRatio, 1.0, distShadow), 0.0);
169 float shadow = mix(1.0 - shadowStrength, 1.0, min(abs(weightShadow - 0.5) * 2.0, 1.0)); // 0.5 2.0 num
170
171 return vec4(normal, shadow);
172 }
173
174 vec4 main(float2 fragCoord)
175 {
176 vec2 uv = fragCoord.xy / iResolution.x;
177 vec2 boxPosition = iResolution / 2.0 / iResolution.x; // 2.0 center of rect
178 vec2 halfBoxSize = size / iResolution.x / 2.0; // 2.0 half of resolution
179 float curvature = cornerRadius / min(size.x, size.y) * 2.0; // 2.0 double of radius
180 float mn = min(halfBoxSize.x, halfBoxSize.y) * (curvature + epsilon);
181
182 float isInBorder = 0;
183 vec4 magnifyingGlass = sdfRect(uv - boxPosition, halfBoxSize - vec2(mn), mn, curvature, isInBorder);
184 vec4 finalColor = vec4(outerContourColor1.xyz, 1.0);
185
186 // add refraction
187 float red = magnifyingGlass.x;
188 float green = magnifyingGlass.y;
189 float offsetX = refractionStrength * sign(red) * red * red;
190 float offsetY = -refractionStrength * sign(green) * green * green;
191 vec2 sampleUV = (uv - boxPosition) / factor + boxPosition;
192 vec4 refraction = imageShader.eval((sampleUV + vec2(offsetX, offsetY)) * iResolution.x);
193
194 // add gradient mask
195 float yDistToCenter = (uv.y - boxPosition.y) / halfBoxSize.y;
196 float yValue = (yDistToCenter + 1.0) / 2.0; // 2.0 half of height
197 vec4 gradientMask = mix(gradientMaskColor1, gradientMaskColor2, yValue);
198 refraction.xyz = mix(refraction.xyz, gradientMask.xyz, gradientMask.w);
199
200 // only apply refraction if z-value is not zero
201 float mask = smoothstep(0.0, 0.3, magnifyingGlass.z); // 0.3 alpha threshold
202 finalColor = mix(finalColor, refraction, mask);
203
204 // add outer_contour color
205 float xValue = (uv.x - boxPosition.x) / halfBoxSize.x;
206 vec4 gradientContour = mix(outerContourColor1, outerContourColor2, abs(xValue));
207 finalColor.xyz = mix(finalColor.xyz, gradientContour.xyz, gradientContour.w * isInBorder * mask);
208
209 // add shadow
210 finalColor.xyz *= magnifyingGlass.w;
211 vec4 shadowColor = vec4(0.0, 0.0, 0.0, 1.0) * (1.0 - magnifyingGlass.w);
212 finalColor = mix(shadowColor, finalColor, mask);
213
214 return finalColor;
215 }
216 )";
217
218 g_magnifierShaderEffect = Drawing::RuntimeEffect::CreateForShader(prog);
219 if (g_magnifierShaderEffect == nullptr) {
220 LOGE("MakeMagnifierShader::RuntimeShader effect error\n");
221 return false;
222 }
223 }
224 return true;
225 }
226
ConvertToRgba(uint32_t rgba,float * color,int tupleSize)227 void GEMagnifierShaderFilter::ConvertToRgba(uint32_t rgba, float* color, int tupleSize)
228 {
229 if (!color || tupleSize < 4) { // 4 len of rgba
230 return;
231 }
232 int16_t alpha = static_cast<int16_t>(rgba & 0xFF); // 0xff byte mask
233 int16_t red = static_cast<int16_t>((rgba & 0xFF000000) >> 24); // 0xff000000 red mask, 24 red shift
234 int16_t green = static_cast<int16_t>((rgba & 0x00FF0000) >> 16); // 0x00ff0000 green mask, 16 green shift
235 int16_t blue = static_cast<int16_t>((rgba & 0x0000FF00) >> 8); // 0x0000ff00 blue mask, 8 blue shift
236
237 color[0] = red * 1.0f / 255.0f; // 255.0f is the max value, 0 red
238 color[1] = green * 1.0f / 255.0f; // 255.0f is the max value, 1 green
239 color[2] = blue * 1.0f / 255.0f; // 255.0f is the max value, 2 blue
240 color[3] = alpha * 1.0f / 255.0f; // 255.0f is the max value, 3 alpha
241 }
242
GetDescription() const243 const std::string GEMagnifierShaderFilter::GetDescription() const
244 {
245 return "GEMagnifierShaderFilter";
246 }
247
248 } // namespace Rosen
249 } // namespace OHOS
250