/* * 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 #include "ge_log.h" #include "ge_wave_gradient_shader_mask.h" namespace OHOS { namespace Rosen { namespace Drawing { GEWaveGradientShaderMask::GEWaveGradientShaderMask(GEWaveGradientShaderMaskParams param) : param_(param) {} std::shared_ptr GEWaveGradientShaderMask::GenerateDrawingShader(float width, float height) const { std::shared_ptr builder = nullptr; builder = GetWaveGradientShaderMaskBuilder(); if (!builder) { LOGE("GEWaveGradientShaderMask::GenerateDrawingShaderHas builder error"); return nullptr; } builder->SetUniform("iResolution", width, height); builder->SetUniform("waveCenter", param_.center_.first, param_.center_.second); builder->SetUniform("waveWidth", param_.width_); builder->SetUniform("turbulenceStrength", param_.turbulenceStrength_); builder->SetUniform("blurRadius", param_.blurRadius_); builder->SetUniform("propagationRadius", param_.propagationRadius_); auto waveMaskEffectShader = builder->MakeShader(nullptr, false); if (!waveMaskEffectShader) { LOGE("GEWaveGradientShaderMask::GenerateDrawingShader effect build failed"); } return waveMaskEffectShader; } std::shared_ptr GEWaveGradientShaderMask::GetWaveGradientShaderMaskBuilder() const { thread_local std::shared_ptr waveShaderMaskBuilder = nullptr; if (waveShaderMaskBuilder) { return waveShaderMaskBuilder; } static constexpr char prog[] = R"( uniform half2 iResolution; uniform half2 waveCenter; uniform half waveWidth; uniform half turbulenceStrength; uniform half blurRadius; uniform half propagationRadius; vec2 random2(vec2 st) { // Magic constants for dot products: chosen to avoid grid artifacts and ensure good distribution return fract(sin(vec2(dot(st, vec2(127.1, 311.7)), dot(st, vec2(269.5, 183.3)))) * 43758.5453) * 2.0 - 1.0; } float noise(vec2 st) { vec2 i = floor(st); vec2 f = fract(st); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(dot(random2(i), f), dot(random2(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), mix(dot(random2(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(random2(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 st) { float value = 0.0; float amp = 0.5; value += amp * noise(st); st *= 2.0; amp = 0.25; // half of origin value value += amp * noise(st); return value; } half4 main(vec2 fragCoord) { vec2 uv = fragCoord.xy / iResolution.xy; float aspect = iResolution.x / iResolution.y; vec2 center = vec2(waveCenter.x * aspect, waveCenter.y); float currentRadius = propagationRadius; float turbulenceTime = currentRadius * 5.0 + sin(currentRadius * 6.28) * 2.0; float n1 = fbm(uv * 3.0 + vec2(turbulenceTime, 0.0)); float n2 = fbm(uv * 3.0 + vec2(0.0, turbulenceTime)); vec2 turbulenceOffset = vec2(n1, n2) * turbulenceStrength; vec2 uvWarped = uv + turbulenceOffset; vec2 uvCorrectedWarped = vec2(uvWarped.x * aspect, uvWarped.y); vec2 dirWarped = uvCorrectedWarped - center; float distWarped = length(dirWarped); float mask; if (waveWidth < 0.0001) { float outer = currentRadius + blurRadius; mask = 1.0 - smoothstep(currentRadius - blurRadius, outer, distWarped); } else { float inner = currentRadius - waveWidth - blurRadius; float outer = currentRadius + waveWidth + blurRadius; mask = smoothstep(inner, inner + blurRadius, distWarped) - smoothstep(outer - blurRadius, outer, distWarped); } return half4(mask); } )"; auto waveShaderMaskEffect = Drawing::RuntimeEffect::CreateForShader(prog); if (!waveShaderMaskEffect) { LOGE("GEWaveGradientShaderMask::GetWaveShaderMaskBuilder effect error"); return nullptr; } waveShaderMaskBuilder = std::make_shared(waveShaderMaskEffect); return waveShaderMaskBuilder; } std::shared_ptr GEWaveGradientShaderMask::GenerateDrawingShaderHasNormal(float width, float height) const { std::shared_ptr builder = nullptr; builder = GetWaveGradientShaderNormalMaskBuilder(); if (!builder) { LOGE("GEWaveGradientShaderMask::GenerateDrawingShaderHasNormal builder error"); return nullptr; } builder->SetUniform("iResolution", width, height); builder->SetUniform("waveCenter", param_.center_.first, param_.center_.second); builder->SetUniform("waveWidth", param_.width_); builder->SetUniform("turbulenceStrength", param_.turbulenceStrength_); builder->SetUniform("blurRadius", param_.blurRadius_); builder->SetUniform("propagationRadius", param_.propagationRadius_); auto waveMaskEffectShader = builder->MakeShader(nullptr, false); if (!waveMaskEffectShader) { LOGE("GEWaveGradientShaderMask::GenerateDrawingShaderHasNormal effect error"); } return waveMaskEffectShader; } std::shared_ptr GEWaveGradientShaderMask::GetWaveGradientShaderNormalMaskBuilder() const { thread_local std::shared_ptr waveShaderMaskNormalBuilder = nullptr; if (waveShaderMaskNormalBuilder) { return waveShaderMaskNormalBuilder; } static constexpr char prog[] = R"( uniform half2 iResolution; uniform half2 waveCenter; uniform half waveWidth; uniform half turbulenceStrength; uniform half blurRadius; uniform half propagationRadius; vec2 random2(vec2 st) { // Magic constants for dot products: chosen to avoid grid artifacts and ensure good distribution return fract(sin(vec2(dot(st, vec2(127.1, 311.7)), dot(st, vec2(269.5, 183.3)))) * 43758.5453) * 2.0 - 1.0; } float noise(vec2 st) { vec2 i = floor(st); vec2 f = fract(st); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(dot(random2(i), f), dot(random2(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), mix(dot(random2(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(random2(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 st) { float value = 0.0; float amp = 0.5; value += amp * noise(st); st *= 2.0; amp = 0.25; // half of origin value value += amp * noise(st); return value; } half4 main(vec2 fragCoord) { vec2 uv = fragCoord.xy / iResolution.xy; float aspect = iResolution.x / iResolution.y; vec2 center = vec2(waveCenter.x * aspect, waveCenter.y); float currentRadius = propagationRadius; float turbulenceTime = currentRadius * 5.0 + sin(currentRadius * 6.28) * 2.0; float n1 = fbm(uv * 3.0 + vec2(turbulenceTime, 0.0)); float n2 = fbm(uv * 3.0 + vec2(0.0, turbulenceTime)); vec2 turbulenceOffset = vec2(n1, n2) * turbulenceStrength; vec2 uvWarped = uv + turbulenceOffset; vec2 uvCorrectedWarped = vec2(uvWarped.x * aspect, uvWarped.y); vec2 dirWarped = uvCorrectedWarped - center; float distWarped = length(dirWarped); float mask; if (waveWidth < 0.0001) { float outer = currentRadius + blurRadius; mask = 1.0 - smoothstep(currentRadius - blurRadius, outer, distWarped); } else { float inner = currentRadius - waveWidth - blurRadius; float outer = currentRadius + waveWidth + blurRadius; mask = smoothstep(inner, inner + blurRadius, distWarped) - smoothstep(outer - blurRadius, outer, distWarped); } vec2 direction = vec2(0.0); if (mask > 0.001) { vec2 radialDir = normalize(dirWarped); vec2 turbulentDir = normalize(turbulenceOffset + 0.0001); direction = radialDir * 0.4 + turbulentDir * turbulenceStrength * 3.0; direction *= mask; } direction = clamp(direction, -1.0, 1.0); vec2 normalizedDirection = direction * 0.5 + 0.5; return half4(normalizedDirection, 1.0, mask); } )"; auto waveShaderMaskNormalEffect = Drawing::RuntimeEffect::CreateForShader(prog); if (!waveShaderMaskNormalEffect) { LOGE("GEWaveGradientShaderMask::GetWaveShaderNormalMaskBuilder effect error"); return nullptr; } waveShaderMaskNormalBuilder = std::make_shared(waveShaderMaskNormalEffect); return waveShaderMaskNormalBuilder; } } // namespace Drawing } // namespace Rosen } // namespace OHOS