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