blob: c3d5eaa4e4937e05831d2724b912bf2fd63836f2 [file] [log] [blame]
mike@reedtribe.org50e4c722012-10-22 03:59:34 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkPath.h"
12#include "SkRegion.h"
13#include "SkShader.h"
14#include "SkUtils.h"
15#include "SkImage.h"
16#include "SkSurface.h"
17
reed@google.comc83e3522012-10-22 22:00:08 +000018#define FAT_PIXEL_COLOR SK_ColorBLACK
19#define PIXEL_CENTER_SIZE 3
20#define WIRE_FRAME_COLOR 0xFFFF0000 /*0xFF00FFFF*/
21#define WIRE_FRAME_SIZE 1.5f
22
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000023static void erase(SkSurface* surface) {
24 surface->getCanvas()->clear(0);
25}
26
27static SkShader* createChecker() {
28 SkBitmap bm;
29 bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
30 bm.allocPixels();
31 bm.lockPixels();
32 *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(0xFFFDFDFD);
33 *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(0xFFF4F4F4);
34 SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
35 SkShader::kRepeat_TileMode);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +000036
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000037 SkMatrix m;
38 m.setScale(12, 12);
39 s->setLocalMatrix(m);
40 return s;
41}
42
43class FatBits {
44public:
45 FatBits() : fShader(createChecker()) {
46 fAA = false;
47 fStyle = kHair_Style;
48 fGrid = true;
reed@google.comc83e3522012-10-22 22:00:08 +000049 fShowSkeleton = true;
50 fUseGPU = false;
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000051 }
52
reed@google.comc83e3522012-10-22 22:00:08 +000053 int getZoom() const { return fZ; }
54
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000055 bool getAA() const { return fAA; }
56 void setAA(bool aa) { fAA = aa; }
57
58 bool getGrid() const { return fGrid; }
59 void setGrid(bool g) { fGrid = g; }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +000060
reed@google.comc83e3522012-10-22 22:00:08 +000061 bool getShowSkeleton() const { return fShowSkeleton; }
62 void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +000063
reed@google.comc83e3522012-10-22 22:00:08 +000064 bool getUseGPU() const { return fUseGPU; }
65 void setUseGPU(bool ug) { fUseGPU = ug; }
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000066
67 enum Style {
68 kHair_Style,
reed@google.comc83e3522012-10-22 22:00:08 +000069 kStroke_Style,
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000070 };
71 Style getStyle() const { return fStyle; }
72 void setStyle(Style s) { fStyle = s; }
73
74 void setWHZ(int width, int height, int zoom) {
75 fW = width;
76 fH = height;
77 fZ = zoom;
78 fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
79 fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
80 fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
81 fShader->setLocalMatrix(fMatrix);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +000082
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000083 SkImage::Info info = {
84 width, height, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
85 };
86 fMinSurface.reset(SkSurface::NewRaster(info, NULL));
87 info.fWidth *= zoom;
88 info.fHeight *= zoom;
89 fMaxSurface.reset(SkSurface::NewRaster(info, NULL));
90 }
91
92 void drawBG(SkCanvas*);
93 void drawFG(SkCanvas*);
94 void drawLine(SkCanvas*, SkPoint pts[2]);
95 void drawRect(SkCanvas* canvas, SkPoint pts[2]);
96
97private:
reed@google.comc83e3522012-10-22 22:00:08 +000098 bool fAA, fGrid, fShowSkeleton, fUseGPU;
mike@reedtribe.org50e4c722012-10-22 03:59:34 +000099 Style fStyle;
100 int fW, fH, fZ;
101 SkMatrix fMatrix, fInverse;
102 SkRect fBounds;
103 SkAutoTUnref<SkShader> fShader;
104 SkAutoTUnref<SkSurface> fMinSurface;
105 SkAutoTUnref<SkSurface> fMaxSurface;
106
107 void setupPaint(SkPaint* paint) {
108 bool aa = this->getAA();
109 switch (fStyle) {
110 case kHair_Style:
111 paint->setStrokeWidth(0);
112 break;
113 case kStroke_Style:
reed@google.comcdbcb3e2012-10-22 22:10:20 +0000114 paint->setStrokeWidth(SK_Scalar1);
115// paint->setStrokeWidth(SK_Scalar1 + SK_Scalar1/500);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000116 break;
117 }
118 paint->setAntiAlias(aa);
119 }
120
reed@google.comc83e3522012-10-22 22:00:08 +0000121 void setupSkeletonPaint(SkPaint* paint) {
122 paint->setStyle(SkPaint::kStroke_Style);
123 paint->setStrokeWidth(WIRE_FRAME_SIZE);
124 paint->setColor(fShowSkeleton ? WIRE_FRAME_COLOR : 0);
125 paint->setAntiAlias(true);
126 }
127
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000128 void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
129 void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
130 SkPaint paint;
reed@google.comc83e3522012-10-22 22:00:08 +0000131 this->setupSkeletonPaint(&paint);
132 SkPath path;
133
134 if (fUseGPU && fAA) {
135 SkRect rr = r;
136 rr.inset(fZ/2, fZ/2);
137 path.addRect(rr);
138 path.moveTo(rr.fLeft, rr.fTop);
139 path.lineTo(rr.fRight, rr.fBottom);
140 rr = r;
141 rr.inset(-fZ/2, -fZ/2);
142 path.addRect(rr);
143 } else {
144 path.addRect(r);
145 if (fUseGPU) {
146 path.moveTo(r.fLeft, r.fTop);
147 path.lineTo(r.fRight, r.fBottom);
148 }
149 }
150 max->drawPath(path, paint);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000151 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000152
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000153 void copyMinToMax() {
154 erase(fMaxSurface);
155 SkCanvas* canvas = fMaxSurface->getCanvas();
156 canvas->save();
157 canvas->concat(fMatrix);
158 fMinSurface->draw(canvas, 0, 0, NULL);
159 canvas->restore();
160
161 SkPaint paint;
162 paint.setXfermodeMode(SkXfermode::kClear_Mode);
163 for (int iy = 1; iy < fH; ++iy) {
164 SkScalar y = SkIntToScalar(iy * fZ);
165 canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
166 }
167 for (int ix = 1; ix < fW; ++ix) {
168 SkScalar x = SkIntToScalar(ix * fZ);
169 canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
170 }
171 }
172};
173
174void FatBits::drawBG(SkCanvas* canvas) {
175 SkPaint paint;
176
177 paint.setShader(fShader);
178 canvas->drawRect(fBounds, paint);
179 paint.setShader(NULL);
180}
181
182void FatBits::drawFG(SkCanvas* canvas) {
reed@google.comc83e3522012-10-22 22:00:08 +0000183 SkPaint inner, outer;
184
185 inner.setAntiAlias(true);
186 inner.setColor(SK_ColorBLACK);
187 inner.setStrokeWidth(PIXEL_CENTER_SIZE);
188
189 outer.setAntiAlias(true);
190 outer.setColor(SK_ColorWHITE);
191 outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000192
193 SkScalar half = SkIntToScalar(fZ) / 2;
194 for (int iy = 0; iy < fH; ++iy) {
195 SkScalar y = SkIntToScalar(iy * fZ) + half;
196 for (int ix = 0; ix < fW; ++ix) {
197 SkScalar x = SkIntToScalar(ix * fZ) + half;
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000198
reed@google.comc83e3522012-10-22 22:00:08 +0000199 canvas->drawPoint(x, y, outer);
200 canvas->drawPoint(x, y, inner);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000201 }
202 }
203}
204
205void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
206 SkPaint paint;
reed@google.comc83e3522012-10-22 22:00:08 +0000207 this->setupSkeletonPaint(&paint);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000208
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000209 SkPath path;
210 path.moveTo(pts[0]);
211 path.lineTo(pts[1]);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000212
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000213 switch (fStyle) {
214 case kHair_Style:
reed@google.comc83e3522012-10-22 22:00:08 +0000215 if (fUseGPU) {
216 SkPaint p;
217 p.setStyle(SkPaint::kStroke_Style);
218 p.setStrokeWidth(SK_Scalar1 * fZ);
219 SkPath dst;
220 p.getFillPath(path, &dst);
221 path.addPath(dst);
222 }
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000223 break;
224 case kStroke_Style: {
225 SkPaint p;
226 p.setStyle(SkPaint::kStroke_Style);
227 p.setStrokeWidth(SK_Scalar1 * fZ);
228 SkPath dst;
229 p.getFillPath(path, &dst);
230 path = dst;
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000231
reed@google.comc83e3522012-10-22 22:00:08 +0000232 if (fUseGPU) {
233 path.moveTo(dst.getPoint(0));
234 path.lineTo(dst.getPoint(2));
235 }
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000236 } break;
237 }
238 max->drawPath(path, paint);
239}
240
241void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
242 SkPaint paint;
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000243
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000244 fInverse.mapPoints(pts, 2);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000245
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000246 if (fGrid) {
reed@google.comcdbcb3e2012-10-22 22:10:20 +0000247 SkScalar dd = 0;//SK_Scalar1 / 50;
248 pts[0].set(SkScalarRoundToScalar(pts[0].fX) + dd,
249 SkScalarRoundToScalar(pts[0].fY) + dd);
250 pts[1].set(SkScalarRoundToScalar(pts[1].fX) + dd,
251 SkScalarRoundToScalar(pts[1].fY) + dd);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000252 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000253
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000254 erase(fMinSurface);
255 this->setupPaint(&paint);
reed@google.comc83e3522012-10-22 22:00:08 +0000256 paint.setColor(FAT_PIXEL_COLOR);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000257 fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
258 this->copyMinToMax();
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000259
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000260 SkCanvas* max = fMaxSurface->getCanvas();
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000261
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000262 fMatrix.mapPoints(pts, 2);
263 this->drawLineSkeleton(max, pts);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000264
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000265 fMaxSurface->draw(canvas, 0, 0, NULL);
266}
267
268void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
269 SkPaint paint;
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000270
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000271 fInverse.mapPoints(pts, 2);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000272
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000273 if (fGrid) {
274 pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
275 pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
276 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000277
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000278 SkRect r;
279 r.set(pts, 2);
280
281 erase(fMinSurface);
282 this->setupPaint(&paint);
reed@google.comc83e3522012-10-22 22:00:08 +0000283 paint.setColor(FAT_PIXEL_COLOR);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000284 fMinSurface->getCanvas()->drawRect(r, paint);
285 this->copyMinToMax();
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000286
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000287 SkCanvas* max = fMaxSurface->getCanvas();
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000288
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000289 fMatrix.mapPoints(pts, 2);
290 r.set(pts, 2);
291 this->drawRectSkeleton(max, r);
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000292
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000293 fMaxSurface->draw(canvas, 0, 0, NULL);
294}
295
296///////////////////////////////////////////////////////////////////////////////////////////////////
297
298class IndexClick : public SkView::Click {
299 int fIndex;
300public:
301 IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000302
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000303 static int GetIndex(SkView::Click* click) {
304 return ((IndexClick*)click)->fIndex;
305 }
306};
307
308class DrawLineView : public SampleView {
309 FatBits fFB;
310 SkPoint fPts[2];
311 bool fIsRect;
312public:
313 DrawLineView() {
314 fFB.setWHZ(24, 16, 48);
reed@google.comcdbcb3e2012-10-22 22:10:20 +0000315 fPts[0].set(48, 48);
316 fPts[1].set(48 * 5, 48 * 4);
317 fIsRect = false;
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000318 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000319
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000320 void setStyle(FatBits::Style s) {
321 fFB.setStyle(s);
322 this->inval(NULL);
323 }
324
325protected:
326 virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
327 if (SampleCode::TitleQ(*evt)) {
328 SampleCode::TitleR(evt, "FatBits");
329 return true;
330 }
331 SkUnichar uni;
332 if (SampleCode::CharQ(*evt, &uni)) {
333 switch (uni) {
334 case 'r':
335 fIsRect = !fIsRect;
336 this->inval(NULL);
337 return true;
reed@google.comc83e3522012-10-22 22:00:08 +0000338 case 'x':
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000339 fFB.setGrid(!fFB.getGrid());
340 this->inval(NULL);
341 return true;
342 case 's':
343 if (FatBits::kStroke_Style == fFB.getStyle()) {
344 this->setStyle(FatBits::kHair_Style);
345 } else {
346 this->setStyle(FatBits::kStroke_Style);
347 }
348 return true;
349 case 'a':
350 fFB.setAA(!fFB.getAA());
351 this->inval(NULL);
352 return true;
reed@google.comc83e3522012-10-22 22:00:08 +0000353 case 'w':
354 fFB.setShowSkeleton(!fFB.getShowSkeleton());
355 this->inval(NULL);
356 return true;
357 case 'g':
358 fFB.setUseGPU(!fFB.getUseGPU());
359 this->inval(NULL);
360 return true;
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000361 }
362 }
363 return this->INHERITED::onQuery(evt);
364 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000365
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000366 virtual void onDrawContent(SkCanvas* canvas) {
367 fFB.drawBG(canvas);
368 if (fIsRect) {
369 fFB.drawRect(canvas, fPts);
370 } else {
371 fFB.drawLine(canvas, fPts);
372 }
373 fFB.drawFG(canvas);
374 }
375
376 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
377 SkPoint pt = { x, y };
378 int index = -1;
reed@google.comcdbcb3e2012-10-22 22:10:20 +0000379 SkScalar tol = 12;
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000380 if (fPts[0].equalsWithinTolerance(pt, tol)) {
381 index = 0;
382 } else if (fPts[1].equalsWithinTolerance(pt, tol)) {
383 index = 1;
384 }
mike@reedtribe.orgc892a152012-10-23 03:10:46 +0000385 return new IndexClick(this, index);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000386 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000387
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000388 virtual bool onClick(Click* click) {
389 int index = IndexClick::GetIndex(click);
mike@reedtribe.orgc892a152012-10-23 03:10:46 +0000390 if (index >= 0 && index <= 1) {
391 fPts[index] = click->fCurr;
392 } else {
393 SkScalar dx = click->fCurr.fX - click->fPrev.fX;
394 SkScalar dy = click->fCurr.fY - click->fPrev.fY;
395 fPts[0].offset(dx, dy);
396 fPts[1].offset(dx, dy);
397 }
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000398 this->inval(NULL);
399 return true;
400 }
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000401
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000402private:
skia.committer@gmail.com45ba2f72012-10-23 02:01:22 +0000403
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000404 typedef SampleView INHERITED;
405};
406
407//////////////////////////////////////////////////////////////////////////////
408
409static SkView* MyFactory() { return new DrawLineView; }
410static SkViewRegister reg(MyFactory);
411