* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include "ge_log.h"
#include "ge_shader_diagnostics.h"
#include "ge_wavy_ripple_light_shader.h"
namespace OHOS {
namespace Rosen {
GEWavyRippleLightShader::GEWavyRippleLightShader() {}
GEWavyRippleLightShader::GEWavyRippleLightShader(Drawing::GEWavyRippleLightShaderParams& param)
{
wavyRippleLightParams_ = param;
}
void GEWavyRippleLightShader::MakeDrawingShader(const Drawing::Rect& rect, float progress)
{
drShader_ = MakeWavyRippleLightShader(rect);
}
std::shared_ptr<Drawing::RuntimeShaderBuilder> GEWavyRippleLightShader::GetWavyRippleLightBuilder()
{
thread_local std::shared_ptr<Drawing::RuntimeEffect> wavyRippleLightShaderEffect_ = nullptr;
if (wavyRippleLightShaderEffect_ == nullptr) {
static constexpr char prog[] = R"(
uniform vec2 iResolution;
uniform vec2 center;
uniform float radius;
uniform float thickness;
const float noiseScale = 0.3;
const float waveScale = 0.5;
const float freqX = 4.0;
const float freqY = 6.0;
const float freqDiag = 8.0;
float shapeSDF(vec2 p, float radius)
{
float dist = length(p);
float noise = 0.0;
noise += sin(p.x * freqX) * 0.25;
noise += sin(p.y * freqY) * 0.35;
noise += sin((p.x + p.y) * freqDiag) * 0.1;
float distortedDist = dist + noise * noiseScale;
float attenuation = waveScale / (1.0 + distortedDist * 5.0);
float wave = sin(distortedDist * 30.0) * attenuation;
return distortedDist - radius + wave * 0.05;
}
vec4 main(vec2 fragCoord)
{
vec2 uv = fragCoord.xy / iResolution.xy;
float aspect = iResolution.x / iResolution.y;
vec3 color = vec3(0.0);
vec2 p = uv * 2.0 - 1.0;
p.x *= aspect;
vec2 c = center * 2.0 - 1.0;
c.x *= aspect;
vec2 delta = p - c;
float dist0 = length(c - vec2(-aspect, -1.0));
float dist1 = length(c - vec2(-aspect, 1.0));
float dist2 = length(c - vec2(aspect, -1.0));
float dist3 = length(c - vec2(aspect, 1.0));
float maxRadius = thickness + max(max(dist0, dist1), max(dist2, dist3));
float currentRadius = maxRadius * radius;
float d = abs(shapeSDF(delta, currentRadius));
float mask = smoothstep(thickness, 0.0, d);
vec3 baseColor = vec3(0.8, 0.5, 1.0);
color = baseColor * mask;
return vec4(color, mask);
}
)";
wavyRippleLightShaderEffect_ = GECreateRuntimeEffectForShader(prog);
}
if (wavyRippleLightShaderEffect_ == nullptr) {
GE_LOGE("GEWavyRippleLightShader::GetWavyRippleLightBuilder wavyRippleLightShaderEffect_ is nullptr.");
return nullptr;
}
return std::make_shared<Drawing::RuntimeShaderBuilder>(wavyRippleLightShaderEffect_);
}
std::shared_ptr<Drawing::ShaderEffect> GEWavyRippleLightShader::MakeWavyRippleLightShader(const Drawing::Rect& rect)
{
auto width = rect.GetWidth();
auto height = rect.GetHeight();
builder_ = GetWavyRippleLightBuilder();
if (builder_ == nullptr) {
GE_LOGE("GEWavyRippleLightShader::MakeWavyRippleLightShader builder_ is nullptr.");
return nullptr;
}
builder_->SetUniform("iResolution", width, height);
builder_->SetUniform("center", wavyRippleLightParams_.center_.first,
wavyRippleLightParams_.center_.second);
builder_->SetUniform("radius", std::max(0.0f, wavyRippleLightParams_.radius_));
builder_->SetUniform("thickness", std::max(0.01f, wavyRippleLightParams_.thickness_));
auto wavyRippleLightShader = builder_->MakeShader(nullptr, false);
if (wavyRippleLightShader == nullptr) {
GE_LOGE("GEWavyRippleLightShader::MakeWavyRippleLightShader wavyRippleLightShader is nullptr.");
return nullptr;
}
return wavyRippleLightShader;
}
}
}