4b8f5eddc7492cf961b5d7e913fe20ab2145074a
[platform/upstream/libSkiaSharp.git] / gm / dcshader.cpp
1
2 /*
3  * Copyright 2014 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 #include "gm.h"
10 #if SK_SUPPORT_GPU
11 #include "GrFragmentProcessor.h"
12 #include "GrCoordTransform.h"
13 #include "gl/GrGLProcessor.h"
14 #include "gl/builders/GrGLProgramBuilder.h"
15 #include "Resources.h"
16 #include "SkReadBuffer.h"
17 #include "SkShader.h"
18 #include "SkStream.h"
19 #include "SkTypeface.h"
20 #include "SkWriteBuffer.h"
21
22 namespace skiagm {
23
24 ///////////////////////////////////////////////////////////////////////////////
25
26 class DCShader : public SkShader {
27 public:
28     DCShader(const SkMatrix& matrix) : fDeviceMatrix(matrix) {}
29
30     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DCShader);
31
32     void flatten(SkWriteBuffer& buf) const SK_OVERRIDE {
33         buf.writeMatrix(fDeviceMatrix);
34     }
35
36     bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM,
37                              const SkMatrix* localMatrix, GrColor* color,
38                              GrFragmentProcessor** fp) const SK_OVERRIDE;
39
40 #ifndef SK_IGNORE_TO_STRING
41     void toString(SkString* str) const SK_OVERRIDE {
42         str->appendf("DCShader: ()");
43     }
44 #endif
45
46 private:
47     const SkMatrix fDeviceMatrix;
48 };
49
50 SkFlattenable* DCShader::CreateProc(SkReadBuffer& buf) {
51     SkMatrix matrix;
52     buf.readMatrix(&matrix);
53     return SkNEW_ARGS(DCShader, (matrix));
54 }
55
56 class DCFP : public GrFragmentProcessor {
57 public:
58     DCFP(const SkMatrix& m) : fDeviceTransform(kDevice_GrCoordSet, m) {
59         this->addCoordTransform(&fDeviceTransform);
60         this->initClassID<DCFP>();
61     }
62
63     void getGLProcessorKey(const GrGLCaps& caps,
64                             GrProcessorKeyBuilder* b) const SK_OVERRIDE {}
65
66     GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
67         class DCGLFP : public GrGLFragmentProcessor {
68             void emitCode(GrGLFPBuilder* builder,
69                             const GrFragmentProcessor& fp,
70                             const char* outputColor,
71                             const char* inputColor,
72                             const TransformedCoordsArray& coords,
73                             const TextureSamplerArray& samplers) {
74                 GrGLFPFragmentBuilder* fpb = builder->getFragmentShaderBuilder();
75                 fpb->codeAppendf("vec2 c = %s;", fpb->ensureFSCoords2D(coords, 0).c_str());
76                 fpb->codeAppend("vec2 r = mod(c, vec2(20.0));");
77                 fpb->codeAppend("vec4 color = vec4(0.5*sin(c.x / 15.0) + 0.5,"
78                                                     "0.5*cos((c.x + c.y) / 15.0) + 0.5,"
79                                                     "(r.x + r.y) / 20.0,"
80                                                     "distance(r, vec2(15.0)) / 20.0 + 0.2);");
81                 fpb->codeAppendf("color.rgb *= color.a;"
82                                     "%s = color * %s;",
83                                     outputColor, GrGLSLExpr4(inputColor).c_str());
84             }
85             void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
86         };
87         return SkNEW(DCGLFP);
88     }
89
90     const char* name() const SK_OVERRIDE { return "DCFP"; }
91
92     void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
93         inout->mulByUnknownFourComponents();
94     }
95
96 private:
97     bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
98
99     GrCoordTransform fDeviceTransform;
100 };
101
102 bool DCShader::asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM,
103                                    const SkMatrix* localMatrix, GrColor* color,
104                                    GrFragmentProcessor** fp) const {
105     *fp = SkNEW_ARGS(DCFP, (fDeviceMatrix));
106     *color = GrColorPackA4(paint.getAlpha());
107     return true;
108 }
109
110 class DCShaderGM : public GM {
111 public:
112     DCShaderGM() {
113         this->setBGColor(0xFFAABBCC);
114     }
115
116     ~DCShaderGM() SK_OVERRIDE {
117         for (int i = 0; i < fPrims.count(); ++i) {
118             SkDELETE(fPrims[i]);
119         }
120     }
121
122 protected:
123
124     SkString onShortName() SK_OVERRIDE {
125         return SkString("dcshader");
126     }
127
128     SkISize onISize() SK_OVERRIDE { return SkISize::Make(1000, 900); }
129
130     void onOnceBeforeDraw() SK_OVERRIDE {
131         struct Rect : public Prim {
132             SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
133                 SkRect rect = SkRect::MakeXYWH(0, 0, 50, 50);
134                 canvas->drawRect(rect, paint);
135                 return rect;
136             }
137         };
138
139         struct Circle : public Prim {
140             SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
141                 static const SkScalar radius = 25;
142                 canvas->drawCircle(radius, radius, radius, paint);
143                 return SkRect::MakeXYWH(0, 0, 2 * radius, 2 * radius);
144             }
145         };
146
147         struct RRect : public Prim {
148             SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
149                 SkRRect rrect;
150                 rrect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 10, 10);
151                 canvas->drawRRect(rrect, paint);
152                 return rrect.getBounds();
153             }
154         };
155
156         struct DRRect : public Prim {
157             SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
158                 SkRRect outerRRect;
159                 outerRRect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 5, 5);
160                 SkRRect innerRRect;
161                 innerRRect.setRectXY(SkRect::MakeXYWH(5, 8, 35, 30), 8, 3);
162                 canvas->drawDRRect(outerRRect, innerRRect, paint);
163                 return outerRRect.getBounds();
164             }
165         };
166         struct Path : public Prim {
167             SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
168                 SkPath path;
169                 path.addCircle(15, 15, 10);
170                 path.addOval(SkRect::MakeXYWH(2, 2, 22, 37));
171                 path.setFillType(SkPath::kEvenOdd_FillType);
172                 canvas->drawPath(path, paint);
173                 return path.getBounds();
174             }
175         };
176
177         struct Points : public Prim {
178             Points(SkCanvas::PointMode mode) : fMode(mode) {}
179
180             SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
181                 SkRandom random;
182                 SkPoint points[500];
183                 SkRect bounds = SkRect::MakeWH(50, 50);
184                 int count = SkToInt(SK_ARRAY_COUNT(points));
185                 if (SkCanvas::kPoints_PointMode != fMode) {
186                     count = SkTMin(count, 10);
187                 }
188                 for (int p = 0; p < count; ++p) {
189                     points[p].fX = random.nextUScalar1() * bounds.width();
190                     points[p].fY = random.nextUScalar1() * bounds.width();
191                 }
192                 canvas->drawPoints(fMode, count, points, paint);
193                 return bounds;
194             }
195             SkCanvas::PointMode fMode;
196         };
197
198         struct Text : public Prim {
199             SkRect draw(SkCanvas* canvas, const SkPaint& origPaint) SK_OVERRIDE {
200                 SkPaint paint = origPaint;
201                 paint.setTextSize(30.f);
202                 this->setFont(&paint);
203                 const char* text = this->text();
204                 static const SkVector offset = SkVector::Make(10, 10);
205                 canvas->drawText(text, strlen(text), offset.fX, offset.fY, paint);
206                 SkRect bounds;
207                 paint.measureText(text, strlen(text), &bounds);
208                 bounds.offset(offset);
209                 return bounds;
210             }
211
212             virtual void setFont(SkPaint* paint) {
213                 sk_tool_utils::set_portable_typeface(paint);
214             }
215
216             virtual const char* text() const { return "Hello, Skia!"; }
217         };
218
219         struct BmpText : public Text {
220            void setFont(SkPaint* paint) SK_OVERRIDE {
221                if (!fTypeface) {
222                     SkString filename = GetResourcePath("/Funkster.ttf");
223                     SkAutoTDelete<SkFILEStream> stream(new SkFILEStream(filename.c_str()));
224                     if (!stream->isValid()) {
225                         SkDebugf("Could not find Funkster.ttf, please set --resourcePath "
226                                  "correctly.\n");
227                         return;
228                     }
229                     fTypeface.reset(SkTypeface::CreateFromStream(stream.detach()));
230                }
231                paint->setTypeface(fTypeface);
232             }
233
234             const char* text() const SK_OVERRIDE { return "Hi, Skia!"; }
235
236             SkAutoTUnref<SkTypeface> fTypeface;
237         };
238         fPrims.push_back(SkNEW(Rect));
239         fPrims.push_back(SkNEW(Circle));
240         fPrims.push_back(SkNEW(RRect));
241         fPrims.push_back(SkNEW(DRRect));
242         fPrims.push_back(SkNEW(Path));
243         fPrims.push_back(SkNEW(Points(SkCanvas::kPoints_PointMode)));
244         fPrims.push_back(SkNEW(Points(SkCanvas::kLines_PointMode)));
245         fPrims.push_back(SkNEW(Points(SkCanvas::kPolygon_PointMode)));
246         fPrims.push_back(SkNEW(Text));
247         fPrims.push_back(SkNEW(BmpText));
248     }
249
250     void onDraw(SkCanvas* canvas) SK_OVERRIDE {
251         // This GM exists to test a specific feature of the GPU backend. It does not work with the
252         // sw rasterizer, tile modes, etc.
253         if (NULL == canvas->getGrContext()) {
254             this->drawGpuOnlyMessage(canvas);
255             return;
256         }
257         SkPaint paint;
258         SkTArray<SkMatrix> devMats;
259         devMats.push_back().reset();
260         devMats.push_back().setRotate(45, 500, 500);
261         devMats.push_back().setRotate(-30, 200, 200);
262         devMats.back().setPerspX(-SK_Scalar1 / 2000);
263         devMats.back().setPerspY(SK_Scalar1 / 1000);
264
265
266         SkTArray<SkMatrix> viewMats;
267         viewMats.push_back().setScale(0.75f, 0.75f);
268         viewMats.push_back().setRotate(45, 50, 50);
269         viewMats.back().postScale(0.5f, 1.1f);
270
271         canvas->translate(10, 20);
272         canvas->save();
273         SkScalar tx = 0, maxTy = 0;
274         static const SkScalar kW = 900;
275
276         for (int aa = 0; aa < 2; ++aa) {
277             for (int i = 0; i < fPrims.count(); ++i) {
278                 for (int j = 0; j < devMats.count(); ++j) {
279                     for (int k = 0; k < viewMats.count(); ++k) {
280                         paint.setShader(SkNEW_ARGS(DCShader, (devMats[j])))->unref();
281                         paint.setAntiAlias(SkToBool(aa));
282                         canvas->save();
283                         canvas->concat(viewMats[k]);
284                         SkRect bounds = fPrims[i]->draw(canvas, paint);
285                         canvas->restore();
286                         viewMats[k].mapRect(&bounds);
287                         // add margins
288                         bounds.fRight += 20;
289                         bounds.fBottom += 20;
290                         canvas->translate(bounds.fRight, 0);
291                         tx += bounds.fRight;
292                         maxTy = SkTMax(bounds.fBottom, maxTy);
293                         if (tx > kW) {
294                             tx = 0;
295                             canvas->restore();
296                             canvas->translate(0, maxTy);
297                             canvas->save();
298                             maxTy = 0;
299                         }
300                     }
301                 }
302             }
303         }
304         canvas->restore();
305     }
306
307 private:
308     struct Prim {
309         virtual ~Prim() {}
310         virtual SkRect draw(SkCanvas*, const SkPaint&) = 0;
311     };
312
313     SkTArray<Prim*> fPrims;
314
315     typedef GM INHERITED;
316 };
317
318 DEF_GM( return SkNEW(DCShaderGM); )
319 }
320 #endif