blob: 4d87a9cd5575d210ba095ebb65ec6b8f29c5c391 [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);
36
37 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; }
reed@google.comc83e3522012-10-22 22:00:08 +000060
61 bool getShowSkeleton() const { return fShowSkeleton; }
62 void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
63
64 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);
82
83 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:
114 paint->setStrokeWidth(SK_Scalar1 + SK_Scalar1/500);
115 break;
116 }
117 paint->setAntiAlias(aa);
118 }
119
reed@google.comc83e3522012-10-22 22:00:08 +0000120 void setupSkeletonPaint(SkPaint* paint) {
121 paint->setStyle(SkPaint::kStroke_Style);
122 paint->setStrokeWidth(WIRE_FRAME_SIZE);
123 paint->setColor(fShowSkeleton ? WIRE_FRAME_COLOR : 0);
124 paint->setAntiAlias(true);
125 }
126
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000127 void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
128 void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
129 SkPaint paint;
reed@google.comc83e3522012-10-22 22:00:08 +0000130 this->setupSkeletonPaint(&paint);
131 SkPath path;
132
133 if (fUseGPU && fAA) {
134 SkRect rr = r;
135 rr.inset(fZ/2, fZ/2);
136 path.addRect(rr);
137 path.moveTo(rr.fLeft, rr.fTop);
138 path.lineTo(rr.fRight, rr.fBottom);
139 rr = r;
140 rr.inset(-fZ/2, -fZ/2);
141 path.addRect(rr);
142 } else {
143 path.addRect(r);
144 if (fUseGPU) {
145 path.moveTo(r.fLeft, r.fTop);
146 path.lineTo(r.fRight, r.fBottom);
147 }
148 }
149 max->drawPath(path, paint);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000150 }
151
152 void copyMinToMax() {
153 erase(fMaxSurface);
154 SkCanvas* canvas = fMaxSurface->getCanvas();
155 canvas->save();
156 canvas->concat(fMatrix);
157 fMinSurface->draw(canvas, 0, 0, NULL);
158 canvas->restore();
159
160 SkPaint paint;
161 paint.setXfermodeMode(SkXfermode::kClear_Mode);
162 for (int iy = 1; iy < fH; ++iy) {
163 SkScalar y = SkIntToScalar(iy * fZ);
164 canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
165 }
166 for (int ix = 1; ix < fW; ++ix) {
167 SkScalar x = SkIntToScalar(ix * fZ);
168 canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
169 }
170 }
171};
172
173void FatBits::drawBG(SkCanvas* canvas) {
174 SkPaint paint;
175
176 paint.setShader(fShader);
177 canvas->drawRect(fBounds, paint);
178 paint.setShader(NULL);
179}
180
181void FatBits::drawFG(SkCanvas* canvas) {
reed@google.comc83e3522012-10-22 22:00:08 +0000182 SkPaint inner, outer;
183
184 inner.setAntiAlias(true);
185 inner.setColor(SK_ColorBLACK);
186 inner.setStrokeWidth(PIXEL_CENTER_SIZE);
187
188 outer.setAntiAlias(true);
189 outer.setColor(SK_ColorWHITE);
190 outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000191
192 SkScalar half = SkIntToScalar(fZ) / 2;
193 for (int iy = 0; iy < fH; ++iy) {
194 SkScalar y = SkIntToScalar(iy * fZ) + half;
195 for (int ix = 0; ix < fW; ++ix) {
196 SkScalar x = SkIntToScalar(ix * fZ) + half;
197
reed@google.comc83e3522012-10-22 22:00:08 +0000198 canvas->drawPoint(x, y, outer);
199 canvas->drawPoint(x, y, inner);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000200 }
201 }
202}
203
204void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
205 SkPaint paint;
reed@google.comc83e3522012-10-22 22:00:08 +0000206 this->setupSkeletonPaint(&paint);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000207
208 SkPath path;
209 path.moveTo(pts[0]);
210 path.lineTo(pts[1]);
211
212 switch (fStyle) {
213 case kHair_Style:
reed@google.comc83e3522012-10-22 22:00:08 +0000214 if (fUseGPU) {
215 SkPaint p;
216 p.setStyle(SkPaint::kStroke_Style);
217 p.setStrokeWidth(SK_Scalar1 * fZ);
218 SkPath dst;
219 p.getFillPath(path, &dst);
220 path.addPath(dst);
221 }
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000222 break;
223 case kStroke_Style: {
224 SkPaint p;
225 p.setStyle(SkPaint::kStroke_Style);
226 p.setStrokeWidth(SK_Scalar1 * fZ);
227 SkPath dst;
228 p.getFillPath(path, &dst);
229 path = dst;
reed@google.comc83e3522012-10-22 22:00:08 +0000230
231 if (fUseGPU) {
232 path.moveTo(dst.getPoint(0));
233 path.lineTo(dst.getPoint(2));
234 }
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000235 } break;
236 }
237 max->drawPath(path, paint);
238}
239
240void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
241 SkPaint paint;
242
243 fInverse.mapPoints(pts, 2);
244
245 if (fGrid) {
246 pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
247 pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
248 }
249
250 erase(fMinSurface);
251 this->setupPaint(&paint);
reed@google.comc83e3522012-10-22 22:00:08 +0000252 paint.setColor(FAT_PIXEL_COLOR);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000253 fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
254 this->copyMinToMax();
255
256 SkCanvas* max = fMaxSurface->getCanvas();
257
258 fMatrix.mapPoints(pts, 2);
259 this->drawLineSkeleton(max, pts);
260
261 fMaxSurface->draw(canvas, 0, 0, NULL);
262}
263
264void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
265 SkPaint paint;
266
267 fInverse.mapPoints(pts, 2);
268
269 if (fGrid) {
270 pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
271 pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
272 }
273
274 SkRect r;
275 r.set(pts, 2);
276
277 erase(fMinSurface);
278 this->setupPaint(&paint);
reed@google.comc83e3522012-10-22 22:00:08 +0000279 paint.setColor(FAT_PIXEL_COLOR);
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000280 fMinSurface->getCanvas()->drawRect(r, paint);
281 this->copyMinToMax();
282
283 SkCanvas* max = fMaxSurface->getCanvas();
284
285 fMatrix.mapPoints(pts, 2);
286 r.set(pts, 2);
287 this->drawRectSkeleton(max, r);
288
289 fMaxSurface->draw(canvas, 0, 0, NULL);
290}
291
292///////////////////////////////////////////////////////////////////////////////////////////////////
293
294class IndexClick : public SkView::Click {
295 int fIndex;
296public:
297 IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
298
299 static int GetIndex(SkView::Click* click) {
300 return ((IndexClick*)click)->fIndex;
301 }
302};
303
304class DrawLineView : public SampleView {
305 FatBits fFB;
306 SkPoint fPts[2];
307 bool fIsRect;
308public:
309 DrawLineView() {
310 fFB.setWHZ(24, 16, 48);
311 fPts[0].set(32, 32);
312 fPts[1].set(32 * 5, 32 * 4);
313 fIsRect = true;
314 }
315
316 void setStyle(FatBits::Style s) {
317 fFB.setStyle(s);
318 this->inval(NULL);
319 }
320
321protected:
322 virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
323 if (SampleCode::TitleQ(*evt)) {
324 SampleCode::TitleR(evt, "FatBits");
325 return true;
326 }
327 SkUnichar uni;
328 if (SampleCode::CharQ(*evt, &uni)) {
329 switch (uni) {
330 case 'r':
331 fIsRect = !fIsRect;
332 this->inval(NULL);
333 return true;
reed@google.comc83e3522012-10-22 22:00:08 +0000334 case 'x':
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000335 fFB.setGrid(!fFB.getGrid());
336 this->inval(NULL);
337 return true;
338 case 's':
339 if (FatBits::kStroke_Style == fFB.getStyle()) {
340 this->setStyle(FatBits::kHair_Style);
341 } else {
342 this->setStyle(FatBits::kStroke_Style);
343 }
344 return true;
345 case 'a':
346 fFB.setAA(!fFB.getAA());
347 this->inval(NULL);
348 return true;
reed@google.comc83e3522012-10-22 22:00:08 +0000349 case 'w':
350 fFB.setShowSkeleton(!fFB.getShowSkeleton());
351 this->inval(NULL);
352 return true;
353 case 'g':
354 fFB.setUseGPU(!fFB.getUseGPU());
355 this->inval(NULL);
356 return true;
mike@reedtribe.org50e4c722012-10-22 03:59:34 +0000357 }
358 }
359 return this->INHERITED::onQuery(evt);
360 }
361
362 virtual void onDrawContent(SkCanvas* canvas) {
363 fFB.drawBG(canvas);
364 if (fIsRect) {
365 fFB.drawRect(canvas, fPts);
366 } else {
367 fFB.drawLine(canvas, fPts);
368 }
369 fFB.drawFG(canvas);
370 }
371
372 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
373 SkPoint pt = { x, y };
374 int index = -1;
375 SkScalar tol = 8;
376 if (fPts[0].equalsWithinTolerance(pt, tol)) {
377 index = 0;
378 } else if (fPts[1].equalsWithinTolerance(pt, tol)) {
379 index = 1;
380 }
381 return index >= 0 ? new IndexClick(this, index) : NULL;
382 }
383
384 virtual bool onClick(Click* click) {
385 int index = IndexClick::GetIndex(click);
386 SkASSERT(index >= 0 && index <= 1);
387 fPts[index] = click->fCurr;
388 this->inval(NULL);
389 return true;
390 }
391
392private:
393
394 typedef SampleView INHERITED;
395};
396
397//////////////////////////////////////////////////////////////////////////////
398
399static SkView* MyFactory() { return new DrawLineView; }
400static SkViewRegister reg(MyFactory);
401