| // Copyright 2024 Google LLC | |
| // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | |
| #include "tools/fiddle/examples.h" | |
| REG_FIDDLE(SkSL_RawImageShaders, 384, 128, false, 0) { | |
| static sk_sp<SkImage> make_image(sk_sp<SkRuntimeEffect> effect, | |
| const SkImageInfo& info) { | |
| sk_sp<SkSurface> surface = SkSurfaces::Raster(info); | |
| SkCanvas* canvas = surface->getCanvas(); | |
| auto shader = effect->makeShader(/*uniforms=*/ nullptr, /*children=*/ {}); | |
| if (!shader) { | |
| return nullptr; | |
| } | |
| SkPaint paint; | |
| paint.setShader(std::move(shader)); | |
| paint.setBlendMode(SkBlendMode::kSrc); | |
| canvas->drawPaint(paint); | |
| return surface->makeImageSnapshot(); | |
| } | |
| void draw(SkCanvas* canvas) { | |
| // Make a hemispherical normal map image: | |
| auto imageInfo = SkImageInfo::MakeN32Premul(128, 128); | |
| auto imageShader = SkRuntimeEffect::MakeForShader(SkString(R"( | |
| vec4 main(vec2 p) { | |
| p = (p / 128) * 2 - 1; | |
| float len2 = dot(p, p); | |
| vec3 v = (len2 > 1) ? vec3(0, 0, 1) : vec3(p, sqrt(1 - len2)); | |
| return (v * 0.5 + 0.5).xyz1; | |
| })")).effect; | |
| auto normalImage = make_image(imageShader, imageInfo); | |
| // Make a simple lighting effect: | |
| auto litEffect = SkRuntimeEffect::MakeForShader(SkString(R"( | |
| uniform shader normals; | |
| vec4 main(vec2 p) { | |
| vec3 n = normalize(normals.eval(p).xyz * 2 - 1); | |
| vec3 l = normalize(vec3(-1, -1, 0.5)); | |
| return saturate(dot(n, l)).xxx1; | |
| })")).effect; | |
| SkRuntimeShaderBuilder builder(litEffect); | |
| SkPaint paint; | |
| // FIRST: Draw the lighting to our (not color managed) canvas. | |
| // This is our CORRECT, reference result: | |
| builder.child("normals") = normalImage->makeShader(SkSamplingOptions{}); | |
| paint.setShader(builder.makeShader()); | |
| canvas->drawRect({0,0,128,128}, paint); | |
| // Make an offscreen surface with a wide gamut: | |
| auto rec2020 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, | |
| SkNamedGamut::kRec2020); | |
| auto info = SkImageInfo::Make(128, 128, kRGBA_F16_SkColorType, | |
| kPremul_SkAlphaType, rec2020); | |
| auto surface = SkSurfaces::Raster(info); | |
| // SECOND: Draw the lighting to the offscreen surface. Color management | |
| // changes the normals, producing INCORRECT (wrong direction) lighting: | |
| surface->getCanvas()->drawPaint(paint); | |
| canvas->drawImage(surface->makeImageSnapshot(), 128, 0); | |
| // THIRD: Convert the normals to a raw image shader. This ignores color | |
| // management for that image, so we get CORRECT lighting again: | |
| builder.child("normals") = normalImage->makeRawShader(SkSamplingOptions{}); | |
| paint.setShader(builder.makeShader()); | |
| surface->getCanvas()->drawPaint(paint); | |
| canvas->drawImage(surface->makeImageSnapshot(), 256, 0); | |
| } | |
| } // END FIDDLE |