| Stan Iliev | 021693b | 2016-10-17 16:26:15 -0400 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2016 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #pragma once | 
|  | 18 |  | 
| Stan Iliev | 021693b | 2016-10-17 16:26:15 -0400 | [diff] [blame] | 19 | #include <SkCanvas.h> | 
|  | 20 | #include <SkDrawable.h> | 
| Derek Sollenberger | df301aa | 2020-12-17 11:06:03 -0500 | [diff] [blame] | 21 | #include <SkRuntimeEffect.h> | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 22 | #include <math.h> | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 23 | #include <utils/RefBase.h> | 
|  | 24 | #include "CanvasProperty.h" | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 25 | #include "CanvasTransform.h" | 
| Stan Iliev | 021693b | 2016-10-17 16:26:15 -0400 | [diff] [blame] | 26 |  | 
|  | 27 | namespace android { | 
|  | 28 | namespace uirenderer { | 
|  | 29 | namespace skiapipeline { | 
|  | 30 |  | 
|  | 31 | class AnimatedRoundRect : public SkDrawable { | 
|  | 32 | public: | 
|  | 33 | AnimatedRoundRect(uirenderer::CanvasPropertyPrimitive* left, | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 34 | uirenderer::CanvasPropertyPrimitive* top, | 
|  | 35 | uirenderer::CanvasPropertyPrimitive* right, | 
|  | 36 | uirenderer::CanvasPropertyPrimitive* bottom, | 
|  | 37 | uirenderer::CanvasPropertyPrimitive* rx, | 
|  | 38 | uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p) | 
|  | 39 | : mLeft(left), mTop(top), mRight(right), mBottom(bottom), mRx(rx), mRy(ry), mPaint(p) {} | 
| Stan Iliev | 021693b | 2016-10-17 16:26:15 -0400 | [diff] [blame] | 40 |  | 
|  | 41 | protected: | 
|  | 42 | virtual SkRect onGetBounds() override { | 
|  | 43 | return SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value); | 
|  | 44 | } | 
|  | 45 | virtual void onDraw(SkCanvas* canvas) override { | 
|  | 46 | SkRect rect = SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value); | 
|  | 47 | canvas->drawRoundRect(rect, mRx->value, mRy->value, mPaint->value); | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | private: | 
|  | 51 | sp<uirenderer::CanvasPropertyPrimitive> mLeft; | 
|  | 52 | sp<uirenderer::CanvasPropertyPrimitive> mTop; | 
|  | 53 | sp<uirenderer::CanvasPropertyPrimitive> mRight; | 
|  | 54 | sp<uirenderer::CanvasPropertyPrimitive> mBottom; | 
|  | 55 | sp<uirenderer::CanvasPropertyPrimitive> mRx; | 
|  | 56 | sp<uirenderer::CanvasPropertyPrimitive> mRy; | 
|  | 57 | sp<uirenderer::CanvasPropertyPaint> mPaint; | 
|  | 58 | }; | 
|  | 59 |  | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 60 | struct RippleDrawableParams { | 
|  | 61 | sp<uirenderer::CanvasPropertyPrimitive> x; | 
|  | 62 | sp<uirenderer::CanvasPropertyPrimitive> y; | 
|  | 63 | sp<uirenderer::CanvasPropertyPrimitive> radius; | 
|  | 64 | sp<uirenderer::CanvasPropertyPrimitive> progress; | 
|  | 65 | sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase; | 
|  | 66 | SkColor color; | 
|  | 67 | sp<uirenderer::CanvasPropertyPaint> paint; | 
|  | 68 | SkRuntimeShaderBuilder effectBuilder; | 
|  | 69 | }; | 
| Derek Sollenberger | df301aa | 2020-12-17 11:06:03 -0500 | [diff] [blame] | 70 |  | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 71 | class AnimatedRippleDrawable { | 
|  | 72 | public: | 
|  | 73 | static void draw(SkCanvas* canvas, const RippleDrawableParams& params) { | 
|  | 74 | auto& effectBuilder = const_cast<SkRuntimeShaderBuilder&>(params.effectBuilder); | 
|  | 75 |  | 
|  | 76 | setUniform2f(effectBuilder, "in_origin", params.x->value, params.y->value); | 
|  | 77 | setUniform(effectBuilder, "in_radius", params.radius); | 
|  | 78 | setUniform(effectBuilder, "in_progress", params.progress); | 
|  | 79 | setUniform(effectBuilder, "in_turbulencePhase", params.turbulencePhase); | 
| Lucas Dupin | fdda357 | 2021-05-17 13:33:38 -0700 | [diff] [blame] | 80 | setUniform(effectBuilder, "in_noisePhase", params.turbulencePhase->value * 0.001); | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 81 |  | 
|  | 82 | SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform("in_color"); | 
|  | 83 | if (uniform.fVar != nullptr) { | 
|  | 84 | uniform = SkV4{SkColorGetR(params.color) / 255.0f, SkColorGetG(params.color) / 255.0f, | 
|  | 85 | SkColorGetB(params.color) / 255.0f, SkColorGetA(params.color) / 255.0f}; | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55); | 
|  | 89 | const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55); | 
|  | 90 | const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45); | 
|  | 91 | const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45); | 
|  | 92 | const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35); | 
|  | 93 | const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35); | 
| Derek Sollenberger | df301aa | 2020-12-17 11:06:03 -0500 | [diff] [blame] | 94 |  | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 95 | // | 
|  | 96 | // Keep in sync with: | 
|  | 97 | // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java | 
|  | 98 | // | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 99 | const float turbulencePhase = params.turbulencePhase->value; | 
|  | 100 | setUniform2f(effectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1), | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 101 | SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1)); | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 102 | setUniform2f(effectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2), | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 103 | SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2)); | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 104 | setUniform2f(effectBuilder, "in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3), | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 105 | SCALE + (turbulencePhase * CIRCLE_Y_3)); | 
|  | 106 | const float rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * PI; | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 107 | setUniform2f(effectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1)); | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 108 | const float rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * PI; | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 109 | setUniform2f(effectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2)); | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 110 | const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI; | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 111 | setUniform2f(effectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3)); | 
| Derek Sollenberger | df301aa | 2020-12-17 11:06:03 -0500 | [diff] [blame] | 112 |  | 
| Brian Osman | bb7c43d | 2022-02-03 14:48:12 -0500 | [diff] [blame] | 113 | params.paint->value.setShader(effectBuilder.makeShader()); | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 114 | canvas->drawCircle(params.x->value, params.y->value, params.radius->value, | 
|  | 115 | params.paint->value); | 
| Derek Sollenberger | df301aa | 2020-12-17 11:06:03 -0500 | [diff] [blame] | 116 | } | 
|  | 117 |  | 
|  | 118 | private: | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 119 | static constexpr float PI = 3.1415926535897932384626; | 
|  | 120 | static constexpr float PI_ROTATE_RIGHT = PI * 0.0078125; | 
|  | 121 | static constexpr float PI_ROTATE_LEFT = PI * -0.0078125; | 
|  | 122 | static constexpr float SCALE = 1.5; | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 123 |  | 
| Lucas Dupin | fdda357 | 2021-05-17 13:33:38 -0700 | [diff] [blame] | 124 | static void setUniform(SkRuntimeShaderBuilder& effectBuilder, const char* name, | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 125 | sp<uirenderer::CanvasPropertyPrimitive> property) { | 
| Lucas Dupin | fdda357 | 2021-05-17 13:33:38 -0700 | [diff] [blame] | 126 | SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name); | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 127 | if (uniform.fVar != nullptr) { | 
|  | 128 | uniform = property->value; | 
|  | 129 | } | 
|  | 130 | } | 
|  | 131 |  | 
| Lucas Dupin | fdda357 | 2021-05-17 13:33:38 -0700 | [diff] [blame] | 132 | static void setUniform(SkRuntimeShaderBuilder& effectBuilder, const char* name, float value) { | 
|  | 133 | SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name); | 
|  | 134 | if (uniform.fVar != nullptr) { | 
|  | 135 | uniform = value; | 
|  | 136 | } | 
|  | 137 | } | 
|  | 138 |  | 
|  | 139 | static void setUniform2f(SkRuntimeShaderBuilder& effectBuilder, const char* name, float a, | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 140 | float b) { | 
| Lucas Dupin | fdda357 | 2021-05-17 13:33:38 -0700 | [diff] [blame] | 141 | SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name); | 
| Lucas Dupin | 6d1601a | 2021-04-15 08:39:50 -0700 | [diff] [blame] | 142 | if (uniform.fVar != nullptr) { | 
|  | 143 | uniform = SkV2{a, b}; | 
|  | 144 | } | 
|  | 145 | } | 
| Derek Sollenberger | df301aa | 2020-12-17 11:06:03 -0500 | [diff] [blame] | 146 | }; | 
|  | 147 |  | 
| Stan Iliev | 021693b | 2016-10-17 16:26:15 -0400 | [diff] [blame] | 148 | class AnimatedCircle : public SkDrawable { | 
|  | 149 | public: | 
|  | 150 | AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y, | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 151 | uirenderer::CanvasPropertyPrimitive* radius, | 
|  | 152 | uirenderer::CanvasPropertyPaint* paint) | 
|  | 153 | : mX(x), mY(y), mRadius(radius), mPaint(paint) {} | 
| Stan Iliev | 021693b | 2016-10-17 16:26:15 -0400 | [diff] [blame] | 154 |  | 
|  | 155 | protected: | 
|  | 156 | virtual SkRect onGetBounds() override { | 
|  | 157 | const float x = mX->value; | 
|  | 158 | const float y = mY->value; | 
|  | 159 | const float radius = mRadius->value; | 
|  | 160 | return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius); | 
|  | 161 | } | 
|  | 162 | virtual void onDraw(SkCanvas* canvas) override { | 
|  | 163 | canvas->drawCircle(mX->value, mY->value, mRadius->value, mPaint->value); | 
|  | 164 | } | 
|  | 165 |  | 
|  | 166 | private: | 
|  | 167 | sp<uirenderer::CanvasPropertyPrimitive> mX; | 
|  | 168 | sp<uirenderer::CanvasPropertyPrimitive> mY; | 
|  | 169 | sp<uirenderer::CanvasPropertyPrimitive> mRadius; | 
|  | 170 | sp<uirenderer::CanvasPropertyPaint> mPaint; | 
|  | 171 | }; | 
|  | 172 |  | 
| Chris Blume | 7b8a808 | 2018-11-30 15:51:58 -0800 | [diff] [blame] | 173 | }  // namespace skiapipeline | 
|  | 174 | }  // namespace uirenderer | 
|  | 175 | }  // namespace android |