1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci* Copyright 2019 Google LLC 3cb93a386Sopenharmony_ci* 4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci* found in the LICENSE file. 6cb93a386Sopenharmony_ci*/ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "tools/viewer/SkSLSlide.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 12cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h" 13cb93a386Sopenharmony_ci#include "include/effects/SkPerlinNoiseShader.h" 14cb93a386Sopenharmony_ci#include "src/core/SkEnumerate.h" 15cb93a386Sopenharmony_ci#include "tools/Resources.h" 16cb93a386Sopenharmony_ci#include "tools/viewer/Viewer.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci#include <algorithm> 19cb93a386Sopenharmony_ci#include <cstdio> 20cb93a386Sopenharmony_ci#include "imgui.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ciusing namespace sk_app; 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_cistatic int InputTextCallback(ImGuiInputTextCallbackData* data) { 27cb93a386Sopenharmony_ci if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { 28cb93a386Sopenharmony_ci SkString* s = (SkString*)data->UserData; 29cb93a386Sopenharmony_ci SkASSERT(data->Buf == s->writable_str()); 30cb93a386Sopenharmony_ci SkString tmp(data->Buf, data->BufTextLen); 31cb93a386Sopenharmony_ci s->swap(tmp); 32cb93a386Sopenharmony_ci data->Buf = s->writable_str(); 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci return 0; 35cb93a386Sopenharmony_ci} 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ciSkSLSlide::SkSLSlide() { 38cb93a386Sopenharmony_ci // Register types for serialization 39cb93a386Sopenharmony_ci fName = "SkSL"; 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci fSkSL = 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci "uniform shader child;\n" 44cb93a386Sopenharmony_ci "\n" 45cb93a386Sopenharmony_ci "half4 main(float2 p) {\n" 46cb93a386Sopenharmony_ci " return child.eval(p);\n" 47cb93a386Sopenharmony_ci "}\n"; 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci fCodeIsDirty = true; 50cb93a386Sopenharmony_ci} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_civoid SkSLSlide::load(SkScalar winWidth, SkScalar winHeight) { 53cb93a386Sopenharmony_ci SkPoint points[] = { { 0, 0 }, { 256, 0 } }; 54cb93a386Sopenharmony_ci SkColor colors[] = { SK_ColorRED, SK_ColorGREEN }; 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci sk_sp<SkShader> shader; 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci fShaders.push_back(std::make_pair("Null", nullptr)); 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci shader = SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp); 61cb93a386Sopenharmony_ci fShaders.push_back(std::make_pair("Linear Gradient", shader)); 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci shader = SkGradientShader::MakeRadial({ 256, 256 }, 256, colors, nullptr, 2, 64cb93a386Sopenharmony_ci SkTileMode::kClamp); 65cb93a386Sopenharmony_ci fShaders.push_back(std::make_pair("Radial Gradient", shader)); 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci shader = SkGradientShader::MakeSweep(256, 256, colors, nullptr, 2); 68cb93a386Sopenharmony_ci fShaders.push_back(std::make_pair("Sweep Gradient", shader)); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci shader = GetResourceAsImage("images/mandrill_256.png")->makeShader(SkSamplingOptions()); 71cb93a386Sopenharmony_ci fShaders.push_back(std::make_pair("Mandrill", shader)); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci fResolution = { winWidth, winHeight, 1.0f }; 74cb93a386Sopenharmony_ci} 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_civoid SkSLSlide::unload() { 77cb93a386Sopenharmony_ci fEffect.reset(); 78cb93a386Sopenharmony_ci fInputs.reset(); 79cb93a386Sopenharmony_ci fChildren.reset(); 80cb93a386Sopenharmony_ci fShaders.reset(); 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_cibool SkSLSlide::rebuild() { 84cb93a386Sopenharmony_ci // Some of the standard shadertoy inputs: 85cb93a386Sopenharmony_ci SkString sksl("uniform float3 iResolution;\n" 86cb93a386Sopenharmony_ci "uniform float iTime;\n" 87cb93a386Sopenharmony_ci "uniform float4 iMouse;\n"); 88cb93a386Sopenharmony_ci sksl.append(fSkSL); 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci // It shouldn't happen, but it's possible to assert in the compiler, especially mid-edit. 91cb93a386Sopenharmony_ci // To guard against losing your work, write out the shader to a backup file, then remove it 92cb93a386Sopenharmony_ci // when we compile successfully. 93cb93a386Sopenharmony_ci constexpr char kBackupFile[] = "sksl.bak"; 94cb93a386Sopenharmony_ci FILE* backup = fopen(kBackupFile, "w"); 95cb93a386Sopenharmony_ci if (backup) { 96cb93a386Sopenharmony_ci fwrite(fSkSL.c_str(), 1, fSkSL.size(), backup); 97cb93a386Sopenharmony_ci fclose(backup); 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForShader(sksl); 100cb93a386Sopenharmony_ci if (backup) { 101cb93a386Sopenharmony_ci std::remove(kBackupFile); 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci if (!effect) { 105cb93a386Sopenharmony_ci Viewer::ShaderErrorHandler()->compileError(sksl.c_str(), errorText.c_str()); 106cb93a386Sopenharmony_ci return false; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci size_t oldSize = fEffect ? fEffect->uniformSize() : 0; 110cb93a386Sopenharmony_ci fInputs.realloc(effect->uniformSize()); 111cb93a386Sopenharmony_ci if (effect->uniformSize() > oldSize) { 112cb93a386Sopenharmony_ci memset(fInputs.get() + oldSize, 0, effect->uniformSize() - oldSize); 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci fChildren.resize_back(effect->children().size()); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci fEffect = effect; 117cb93a386Sopenharmony_ci fCodeIsDirty = false; 118cb93a386Sopenharmony_ci return true; 119cb93a386Sopenharmony_ci} 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_civoid SkSLSlide::draw(SkCanvas* canvas) { 122cb93a386Sopenharmony_ci canvas->clear(SK_ColorWHITE); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci ImGui::Begin("SkSL", nullptr, ImGuiWindowFlags_AlwaysVerticalScrollbar); 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci // Edit box for shader code 127cb93a386Sopenharmony_ci ImGuiInputTextFlags flags = ImGuiInputTextFlags_CallbackResize; 128cb93a386Sopenharmony_ci ImVec2 boxSize(-1.0f, ImGui::GetTextLineHeight() * 30); 129cb93a386Sopenharmony_ci if (ImGui::InputTextMultiline("Code", fSkSL.writable_str(), fSkSL.size() + 1, boxSize, flags, 130cb93a386Sopenharmony_ci InputTextCallback, &fSkSL)) { 131cb93a386Sopenharmony_ci fCodeIsDirty = true; 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci if (fCodeIsDirty || !fEffect) { 135cb93a386Sopenharmony_ci this->rebuild(); 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci if (!fEffect) { 139cb93a386Sopenharmony_ci ImGui::End(); 140cb93a386Sopenharmony_ci return; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci // Update fMousePos 144cb93a386Sopenharmony_ci ImVec2 mousePos = ImGui::GetMousePos(); 145cb93a386Sopenharmony_ci if (ImGui::IsMouseDown(0)) { 146cb93a386Sopenharmony_ci fMousePos.x = mousePos.x; 147cb93a386Sopenharmony_ci fMousePos.y = mousePos.y; 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci if (ImGui::IsMouseClicked(0)) { 150cb93a386Sopenharmony_ci fMousePos.z = mousePos.x; 151cb93a386Sopenharmony_ci fMousePos.w = mousePos.y; 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci fMousePos.z = abs(fMousePos.z) * (ImGui::IsMouseDown(0) ? 1 : -1); 154cb93a386Sopenharmony_ci fMousePos.w = abs(fMousePos.w) * (ImGui::IsMouseClicked(0) ? 1 : -1); 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci for (const auto& v : fEffect->uniforms()) { 157cb93a386Sopenharmony_ci char* data = fInputs.get() + v.offset; 158cb93a386Sopenharmony_ci if (v.name.equals("iResolution")) { 159cb93a386Sopenharmony_ci memcpy(data, &fResolution, sizeof(fResolution)); 160cb93a386Sopenharmony_ci continue; 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci if (v.name.equals("iTime")) { 163cb93a386Sopenharmony_ci memcpy(data, &fSeconds, sizeof(fSeconds)); 164cb93a386Sopenharmony_ci continue; 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci if (v.name.equals("iMouse")) { 167cb93a386Sopenharmony_ci memcpy(data, &fMousePos, sizeof(fMousePos)); 168cb93a386Sopenharmony_ci continue; 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci switch (v.type) { 171cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat: 172cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat2: 173cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat3: 174cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat4: { 175cb93a386Sopenharmony_ci int rows = ((int)v.type - (int)SkRuntimeEffect::Uniform::Type::kFloat) + 1; 176cb93a386Sopenharmony_ci float* f = reinterpret_cast<float*>(data); 177cb93a386Sopenharmony_ci for (int c = 0; c < v.count; ++c, f += rows) { 178cb93a386Sopenharmony_ci SkString name = v.isArray() ? SkStringPrintf("%s[%d]", v.name.c_str(), c) 179cb93a386Sopenharmony_ci : v.name; 180cb93a386Sopenharmony_ci ImGui::PushID(c); 181cb93a386Sopenharmony_ci ImGui::DragScalarN(name.c_str(), ImGuiDataType_Float, f, rows, 1.0f); 182cb93a386Sopenharmony_ci ImGui::PopID(); 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci break; 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat2x2: 187cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat3x3: 188cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kFloat4x4: { 189cb93a386Sopenharmony_ci int rows = ((int)v.type - (int)SkRuntimeEffect::Uniform::Type::kFloat2x2) + 2; 190cb93a386Sopenharmony_ci int cols = rows; 191cb93a386Sopenharmony_ci float* f = reinterpret_cast<float*>(data); 192cb93a386Sopenharmony_ci for (int e = 0; e < v.count; ++e) { 193cb93a386Sopenharmony_ci for (int c = 0; c < cols; ++c, f += rows) { 194cb93a386Sopenharmony_ci SkString name = v.isArray() 195cb93a386Sopenharmony_ci ? SkStringPrintf("%s[%d][%d]", v.name.c_str(), e, c) 196cb93a386Sopenharmony_ci : SkStringPrintf("%s[%d]", v.name.c_str(), c); 197cb93a386Sopenharmony_ci ImGui::DragScalarN(name.c_str(), ImGuiDataType_Float, f, rows, 1.0f); 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci break; 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kInt: 203cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kInt2: 204cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kInt3: 205cb93a386Sopenharmony_ci case SkRuntimeEffect::Uniform::Type::kInt4: { 206cb93a386Sopenharmony_ci int rows = ((int)v.type - (int)SkRuntimeEffect::Uniform::Type::kInt) + 1; 207cb93a386Sopenharmony_ci int* i = reinterpret_cast<int*>(data); 208cb93a386Sopenharmony_ci for (int c = 0; c < v.count; ++c, i += rows) { 209cb93a386Sopenharmony_ci SkString name = v.isArray() ? SkStringPrintf("%s[%d]", v.name.c_str(), c) 210cb93a386Sopenharmony_ci : v.name; 211cb93a386Sopenharmony_ci ImGui::PushID(c); 212cb93a386Sopenharmony_ci ImGui::DragScalarN(name.c_str(), ImGuiDataType_S32, i, rows, 1.0f); 213cb93a386Sopenharmony_ci ImGui::PopID(); 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci break; 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci } 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci for (const auto& c : fEffect->children()) { 221cb93a386Sopenharmony_ci auto curShader = 222cb93a386Sopenharmony_ci std::find_if(fShaders.begin(), fShaders.end(), [tgt = fChildren[c.index]](auto p) { 223cb93a386Sopenharmony_ci return p.second == tgt; 224cb93a386Sopenharmony_ci }); 225cb93a386Sopenharmony_ci SkASSERT(curShader != fShaders.end()); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci if (ImGui::BeginCombo(c.name.c_str(), curShader->first)) { 228cb93a386Sopenharmony_ci for (const auto& namedShader : fShaders) { 229cb93a386Sopenharmony_ci if (ImGui::Selectable(namedShader.first, curShader->second == namedShader.second)) { 230cb93a386Sopenharmony_ci fChildren[c.index] = namedShader.second; 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci ImGui::EndCombo(); 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci static SkColor4f gPaintColor { 1.0f, 1.0f, 1.0f , 1.0f }; 238cb93a386Sopenharmony_ci ImGui::ColorEdit4("Paint Color", gPaintColor.vec()); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci ImGui::RadioButton("Fill", &fGeometry, kFill); ImGui::SameLine(); 241cb93a386Sopenharmony_ci ImGui::RadioButton("Circle", &fGeometry, kCircle); ImGui::SameLine(); 242cb93a386Sopenharmony_ci ImGui::RadioButton("RoundRect", &fGeometry, kRoundRect); ImGui::SameLine(); 243cb93a386Sopenharmony_ci ImGui::RadioButton("Capsule", &fGeometry, kCapsule); ImGui::SameLine(); 244cb93a386Sopenharmony_ci ImGui::RadioButton("Text", &fGeometry, kText); 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci ImGui::End(); 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci auto inputs = SkData::MakeWithoutCopy(fInputs.get(), fEffect->uniformSize()); 249cb93a386Sopenharmony_ci auto shader = fEffect->makeShader(std::move(inputs), fChildren.data(), fChildren.count(), 250cb93a386Sopenharmony_ci nullptr, false); 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci SkPaint p; 253cb93a386Sopenharmony_ci p.setColor4f(gPaintColor); 254cb93a386Sopenharmony_ci p.setShader(std::move(shader)); 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci switch (fGeometry) { 257cb93a386Sopenharmony_ci case kFill: 258cb93a386Sopenharmony_ci canvas->drawPaint(p); 259cb93a386Sopenharmony_ci break; 260cb93a386Sopenharmony_ci case kCircle: 261cb93a386Sopenharmony_ci canvas->drawCircle({ 256, 256 }, 256, p); 262cb93a386Sopenharmony_ci break; 263cb93a386Sopenharmony_ci case kRoundRect: 264cb93a386Sopenharmony_ci canvas->drawRoundRect({ 0, 0, 512, 512 }, 64, 64, p); 265cb93a386Sopenharmony_ci break; 266cb93a386Sopenharmony_ci case kCapsule: 267cb93a386Sopenharmony_ci canvas->drawRoundRect({ 0, 224, 512, 288 }, 32, 32, p); 268cb93a386Sopenharmony_ci break; 269cb93a386Sopenharmony_ci case kText: { 270cb93a386Sopenharmony_ci SkFont font; 271cb93a386Sopenharmony_ci font.setSize(SkIntToScalar(96)); 272cb93a386Sopenharmony_ci canvas->drawSimpleText("Hello World", strlen("Hello World"), SkTextEncoding::kUTF8, 0, 273cb93a386Sopenharmony_ci 256, font, p); 274cb93a386Sopenharmony_ci } break; 275cb93a386Sopenharmony_ci default: break; 276cb93a386Sopenharmony_ci } 277cb93a386Sopenharmony_ci} 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_cibool SkSLSlide::animate(double nanos) { 280cb93a386Sopenharmony_ci fSeconds = static_cast<float>(nanos * 1E-9); 281cb93a386Sopenharmony_ci return true; 282cb93a386Sopenharmony_ci} 283