• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 
4 #include "experimental/sorttoy/Cmds.h"
5 #include "experimental/sorttoy/Fake.h"
6 #include "experimental/sorttoy/SortKey.h"
7 
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkRRect.h"
13 #include "include/effects/SkGradientShader.h"
14 
15 
16 //------------------------------------------------------------------------------------------------
getKey()17 SortKey SaveCmd::getKey() {
18     SkASSERT(0);
19     return {};
20 }
21 
execute(FakeCanvas * f) const22 void SaveCmd::execute(FakeCanvas* f) const {
23     f->save();
24 }
25 
execute(SkCanvas * c) const26 void SaveCmd::execute(SkCanvas* c) const {
27     c->save();
28 }
29 
30 //------------------------------------------------------------------------------------------------
getKey()31 SortKey RestoreCmd::getKey() {
32     SkASSERT(0);
33     return {};
34 }
35 
execute(FakeCanvas * f) const36 void RestoreCmd::execute(FakeCanvas* f) const {
37     f->restore();
38 }
39 
execute(SkCanvas * c) const40 void RestoreCmd::execute(SkCanvas* c) const {
41     c->restore();
42 }
43 
44 //------------------------------------------------------------------------------------------------
DrawCmd(ID id,Shape shape,SkIRect r,const FakePaint & p)45 DrawCmd::DrawCmd(ID id,
46                  Shape shape,
47                  SkIRect r,
48                  const FakePaint& p)
49     : Cmd(id)
50     , fShape(shape)
51     , fRect(r)
52     , fPaint(p) {
53 }
54 
DrawCmd(ID id,PaintersOrder paintersOrder,Shape shape,SkIRect r,const FakePaint & p,sk_sp<FakeMCBlob> state)55 DrawCmd::DrawCmd(ID id,
56                  PaintersOrder paintersOrder,
57                  Shape shape,
58                  SkIRect r,
59                  const FakePaint& p,
60                  sk_sp<FakeMCBlob> state)
61     : Cmd(id)
62     , fPaintersOrder(paintersOrder)
63     , fShape(shape)
64     , fRect(r)
65     , fPaint(p)
66     , fMCState(std::move(state)) {
67 }
68 
shared_contains(int x,int y,Shape s,SkIRect r)69 static bool shared_contains(int x, int y, Shape s, SkIRect r) {
70     if (s == Shape::kRect) {
71         return r.contains(x, y);
72     } else {
73         float a = r.width() / 2.0f;   // horizontal radius
74         float b = r.height() / 2.0f;  // vertical radius
75         float h = 0.5f * (r.fLeft + r.fRight); // center X
76         float k = 0.5f * (r.fTop + r.fBottom); // center Y
77 
78         float xTerm = x + 0.5f - h;
79         float yTerm = y + 0.5f - k;
80 
81         return (xTerm * xTerm) / (a * a) + (yTerm * yTerm) / (b * b) < 1.0f;
82     }
83 }
84 
contains(int x,int y) const85 bool DrawCmd::contains(int x, int y) const {
86     return shared_contains(x, y, fShape, fRect);
87 }
88 
getSortZ() const89 uint32_t DrawCmd::getSortZ() const {
90     return fPaintersOrder.toUInt();
91 }
92 
93 // Opaque and transparent draws both write their painter's index to the depth buffer
getDrawZ() const94 uint32_t DrawCmd::getDrawZ() const {
95     return fPaintersOrder.toUInt();
96 }
97 
getKey()98 SortKey DrawCmd::getKey() {
99     return SortKey(fPaint.isTransparent(), this->getSortZ(), fPaint.toID());
100 }
101 
execute(FakeCanvas * c) const102 void DrawCmd::execute(FakeCanvas* c) const {
103     c->drawShape(fID, fShape, fRect, fPaint);
104 }
105 
execute(SkCanvas * c) const106 void DrawCmd::execute(SkCanvas* c) const {
107 
108     SkColor4f colors[2] = {
109         SkColor4f::FromColor(fPaint.c0()),
110         SkColor4f::FromColor(fPaint.c1())
111     };
112 
113     SkPaint p;
114     if (fPaint.toID() == kSolidMat) {
115         p.setColor(fPaint.c0());
116     } else if (fPaint.toID() == kLinearMat) {
117         SkPoint pts[] = { { 0.0f, 0.0f, }, { 256.0f, 256.0f } };
118         p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, nullptr, 2,
119                                                  SkTileMode::kClamp));
120     } else {
121         SkASSERT(fPaint.toID() == kRadialMat);
122 
123         auto shader = SkGradientShader::MakeRadial(SkPoint::Make(128.0f, 128.0f),
124                                                    128.0f,
125                                                    colors,
126                                                    nullptr,
127                                                    nullptr,
128                                                    2,
129                                                    SkTileMode::kRepeat);
130         p.setShader(std::move(shader));
131     }
132 
133     if (fShape == Shape::kRect) {
134         c->drawRect(SkRect::Make(fRect), p);
135     } else {
136         c->drawOval(SkRect::Make(fRect), p);
137     }
138 }
139 
is_opaque(SkColor c)140 static bool is_opaque(SkColor c) {
141     return 0xFF == SkColorGetA(c);
142 }
143 
rasterize(uint32_t zBuffer[256][256],SkBitmap * dstBM) const144 void DrawCmd::rasterize(uint32_t zBuffer[256][256], SkBitmap* dstBM) const {
145 
146     uint32_t z = this->getDrawZ();
147     SkIRect scissor = fMCState->scissor();
148 
149     for (int y = fRect.fTop; y < fRect.fBottom; ++y) {
150         for (int x = fRect.fLeft; x < fRect.fRight; ++x) {
151             if (!scissor.contains(x, y)) {
152                 continue;
153             }
154 
155             if (!this->contains(x, y)) {
156                 continue;
157             }
158 
159             if (z > zBuffer[x][y]) {
160                 zBuffer[x][y] = z;
161 
162                 SkColor c = fPaint.evalColor(x, y);
163 
164                 if (is_opaque(c)) {
165                     *dstBM->getAddr32(x, y) = c;
166                 } else {
167                     SkColor4f bot = SkColor4f::FromColor(*dstBM->getAddr32(x, y));
168                     SkColor4f top = SkColor4f::FromColor(c);
169                     SkColor4f result = {
170                         top.fA * top.fR + (1.0f - top.fA) * bot.fR,
171                         top.fA * top.fG + (1.0f - top.fA) * bot.fG,
172                         top.fA * top.fB + (1.0f - top.fA) * bot.fB,
173                                  top.fA + (1.0f - top.fA) * bot.fA
174                     };
175                     *dstBM->getAddr32(x, y) = result.toSkColor();
176                 }
177             }
178         }
179     }
180 }
181 
182 //------------------------------------------------------------------------------------------------
ClipCmd(ID id,Shape shape,SkIRect r)183 ClipCmd::ClipCmd(ID id, Shape shape, SkIRect r)
184         : Cmd(id)
185         , fShape(shape)
186         , fRect(r) {
187 }
188 
ClipCmd(ID id,PaintersOrder paintersOrderWhenAdded,Shape shape,SkIRect r)189 ClipCmd::ClipCmd(ID id, PaintersOrder paintersOrderWhenAdded, Shape shape, SkIRect r)
190         : Cmd(id)
191         , fShape(shape)
192         , fRect(r)
193         , fPaintersOrderWhenAdded(paintersOrderWhenAdded) {
194 }
195 
~ClipCmd()196 ClipCmd::~ClipCmd() {}
197 
contains(int x,int y) const198 bool ClipCmd::contains(int x, int y) const {
199     return shared_contains(x, y, fShape, fRect);
200 }
201 
getSortZ() const202 uint32_t ClipCmd::getSortZ() const {
203     SkASSERT(fPaintersOrderWhenAdded.isValid());
204 
205     return fPaintersOrderWhenAdded.toUInt();
206 }
207 
208 // A clip writes the painter's index corresponding to when it's "popped" off the clip stack
getDrawZ() const209 uint32_t ClipCmd::getDrawZ() const {
210     SkASSERT(fPaintersOrderWhenPopped.isValid());
211 
212     return fPaintersOrderWhenPopped.toUInt();
213 }
214 
getKey()215 SortKey ClipCmd::getKey() {
216     return SortKey(false, this->getSortZ(), kInvalidMat);
217 }
218 
onAboutToBePopped(PaintersOrder paintersOrderWhenPopped)219 void ClipCmd::onAboutToBePopped(PaintersOrder paintersOrderWhenPopped) {
220     SkASSERT(!fPaintersOrderWhenPopped.isValid() && paintersOrderWhenPopped.isValid());
221     fPaintersOrderWhenPopped = paintersOrderWhenPopped;
222 }
223 
execute(FakeCanvas * c) const224 void ClipCmd::execute(FakeCanvas* c) const {
225     // This call is creating the 'real' ClipCmd for the "actual" case
226     SkASSERT(!fPaintersOrderWhenAdded.isValid() && !fPaintersOrderWhenPopped.isValid());
227 
228     c->clipShape(fID, fShape, fRect);
229 }
230 
execute(SkCanvas * c) const231 void ClipCmd::execute(SkCanvas* c) const {
232     if (fShape == Shape::kRect) {
233         c->clipRect(SkRect::Make(fRect));
234     } else {
235         c->clipRRect(SkRRect::MakeOval(SkRect::Make(fRect)));
236     }
237 }
238 
rasterize(uint32_t zBuffer[256][256],SkBitmap *) const239 void ClipCmd::rasterize(uint32_t zBuffer[256][256], SkBitmap* /* dstBM */) const {
240     uint32_t drawZ = this->getDrawZ();
241 
242     // TODO: limit this via the scissor!
243     for (int y = 0; y < 256; ++y) {
244         for (int x = 0; x < 256; ++x) {
245             if (!this->contains(x, y) && drawZ > zBuffer[x][y]) {
246                 zBuffer[x][y] = drawZ;
247             }
248         }
249     }
250 }
251 
252 //------------------------------------------------------------------------------------------------
253