3 * Copyright 2014 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
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"
19 #include "SkTypeface.h"
20 #include "SkWriteBuffer.h"
24 ///////////////////////////////////////////////////////////////////////////////
26 class DCShader : public SkShader {
28 DCShader(const SkMatrix& matrix) : fDeviceMatrix(matrix) {}
30 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DCShader);
32 void flatten(SkWriteBuffer& buf) const SK_OVERRIDE {
33 buf.writeMatrix(fDeviceMatrix);
36 bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& viewM,
37 const SkMatrix* localMatrix, GrColor* color,
38 GrFragmentProcessor** fp) const SK_OVERRIDE;
40 #ifndef SK_IGNORE_TO_STRING
41 void toString(SkString* str) const SK_OVERRIDE {
42 str->appendf("DCShader: ()");
47 const SkMatrix fDeviceMatrix;
50 SkFlattenable* DCShader::CreateProc(SkReadBuffer& buf) {
52 buf.readMatrix(&matrix);
53 return SkNEW_ARGS(DCShader, (matrix));
56 class DCFP : public GrFragmentProcessor {
58 DCFP(const SkMatrix& m) : fDeviceTransform(kDevice_GrCoordSet, m) {
59 this->addCoordTransform(&fDeviceTransform);
60 this->initClassID<DCFP>();
63 void getGLProcessorKey(const GrGLCaps& caps,
64 GrProcessorKeyBuilder* b) const SK_OVERRIDE {}
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,"
80 "distance(r, vec2(15.0)) / 20.0 + 0.2);");
81 fpb->codeAppendf("color.rgb *= color.a;"
83 outputColor, GrGLSLExpr4(inputColor).c_str());
85 void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
90 const char* name() const SK_OVERRIDE { return "DCFP"; }
92 void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
93 inout->mulByUnknownFourComponents();
97 bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
99 GrCoordTransform fDeviceTransform;
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());
110 class DCShaderGM : public GM {
113 this->setBGColor(0xFFAABBCC);
116 ~DCShaderGM() SK_OVERRIDE {
117 for (int i = 0; i < fPrims.count(); ++i) {
124 SkString onShortName() SK_OVERRIDE {
125 return SkString("dcshader");
128 SkISize onISize() SK_OVERRIDE { return SkISize::Make(1000, 900); }
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);
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);
147 struct RRect : public Prim {
148 SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
150 rrect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 10, 10);
151 canvas->drawRRect(rrect, paint);
152 return rrect.getBounds();
156 struct DRRect : public Prim {
157 SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
159 outerRRect.setRectXY(SkRect::MakeXYWH(0, 0, 50, 50), 5, 5);
161 innerRRect.setRectXY(SkRect::MakeXYWH(5, 8, 35, 30), 8, 3);
162 canvas->drawDRRect(outerRRect, innerRRect, paint);
163 return outerRRect.getBounds();
166 struct Path : public Prim {
167 SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
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();
177 struct Points : public Prim {
178 Points(SkCanvas::PointMode mode) : fMode(mode) {}
180 SkRect draw(SkCanvas* canvas, const SkPaint& paint) SK_OVERRIDE {
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);
188 for (int p = 0; p < count; ++p) {
189 points[p].fX = random.nextUScalar1() * bounds.width();
190 points[p].fY = random.nextUScalar1() * bounds.width();
192 canvas->drawPoints(fMode, count, points, paint);
195 SkCanvas::PointMode fMode;
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);
207 paint.measureText(text, strlen(text), &bounds);
208 bounds.offset(offset);
212 virtual void setFont(SkPaint* paint) {
213 sk_tool_utils::set_portable_typeface(paint);
216 virtual const char* text() const { return "Hello, Skia!"; }
219 struct BmpText : public Text {
220 void setFont(SkPaint* paint) SK_OVERRIDE {
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 "
229 fTypeface.reset(SkTypeface::CreateFromStream(stream.detach()));
231 paint->setTypeface(fTypeface);
234 const char* text() const SK_OVERRIDE { return "Hi, Skia!"; }
236 SkAutoTUnref<SkTypeface> fTypeface;
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));
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);
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);
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);
271 canvas->translate(10, 20);
273 SkScalar tx = 0, maxTy = 0;
274 static const SkScalar kW = 900;
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));
283 canvas->concat(viewMats[k]);
284 SkRect bounds = fPrims[i]->draw(canvas, paint);
286 viewMats[k].mapRect(&bounds);
289 bounds.fBottom += 20;
290 canvas->translate(bounds.fRight, 0);
292 maxTy = SkTMax(bounds.fBottom, maxTy);
296 canvas->translate(0, maxTy);
310 virtual SkRect draw(SkCanvas*, const SkPaint&) = 0;
313 SkTArray<Prim*> fPrims;
315 typedef GM INHERITED;
318 DEF_GM( return SkNEW(DCShaderGM); )