drawatlas.cpp revision c465d13e6fca5e171bde45d35b2dd43117f4702e
1/* 2 * Copyright 2015 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 "gm.h" 9 10#include "SkAutoMalloc.h" 11#include "SkCanvas.h" 12#include "SkRSXform.h" 13#include "SkSurface.h" 14 15class DrawAtlasGM : public skiagm::GM { 16 static sk_sp<SkImage> MakeAtlas(SkCanvas* caller, const SkRect& target) { 17 SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 18 auto surface(caller->makeSurface(info)); 19 if (nullptr == surface) { 20 surface = SkSurface::MakeRaster(info); 21 } 22 SkCanvas* canvas = surface->getCanvas(); 23 // draw red everywhere, but we don't expect to see it in the draw, testing the notion 24 // that drawAtlas draws a subset-region of the atlas. 25 canvas->clear(SK_ColorRED); 26 27 SkPaint paint; 28 paint.setBlendMode(SkBlendMode::kClear); 29 SkRect r(target); 30 r.inset(-1, -1); 31 // zero out a place (with a 1-pixel border) to land our drawing. 32 canvas->drawRect(r, paint); 33 paint.setBlendMode(SkBlendMode::kSrcOver); 34 paint.setColor(SK_ColorBLUE); 35 paint.setAntiAlias(true); 36 canvas->drawOval(target, paint); 37 return surface->makeImageSnapshot(); 38 } 39 40public: 41 DrawAtlasGM() {} 42 43protected: 44 45 SkString onShortName() override { 46 return SkString("draw-atlas"); 47 } 48 49 SkISize onISize() override { 50 return SkISize::Make(640, 480); 51 } 52 53 void onDraw(SkCanvas* canvas) override { 54 const SkRect target = { 50, 50, 80, 90 }; 55 auto atlas = MakeAtlas(canvas, target); 56 57 const struct { 58 SkScalar fScale; 59 SkScalar fDegrees; 60 SkScalar fTx; 61 SkScalar fTy; 62 63 void apply(SkRSXform* xform) const { 64 const SkScalar rad = SkDegreesToRadians(fDegrees); 65 xform->fSCos = fScale * SkScalarCos(rad); 66 xform->fSSin = fScale * SkScalarSin(rad); 67 xform->fTx = fTx; 68 xform->fTy = fTy; 69 } 70 } rec[] = { 71 { 1, 0, 10, 10 }, // just translate 72 { 2, 0, 110, 10 }, // scale + translate 73 { 1, 30, 210, 10 }, // rotate + translate 74 { 2, -30, 310, 30 }, // scale + rotate + translate 75 }; 76 77 const int N = SK_ARRAY_COUNT(rec); 78 SkRSXform xform[N]; 79 SkRect tex[N]; 80 SkColor colors[N]; 81 82 for (int i = 0; i < N; ++i) { 83 rec[i].apply(&xform[i]); 84 tex[i] = target; 85 colors[i] = 0x80FF0000 + (i * 40 * 256); 86 } 87 88 SkPaint paint; 89 paint.setFilterQuality(kLow_SkFilterQuality); 90 paint.setAntiAlias(true); 91 92 canvas->drawAtlas(atlas.get(), xform, tex, N, nullptr, &paint); 93 canvas->translate(0, 100); 94 canvas->drawAtlas(atlas.get(), xform, tex, colors, N, SkBlendMode::kSrcIn, nullptr, &paint); 95 } 96 97private: 98 typedef GM INHERITED; 99}; 100DEF_GM( return new DrawAtlasGM; ) 101 102/////////////////////////////////////////////////////////////////////////////////////////////////// 103#include "SkPath.h" 104#include "SkPathMeasure.h" 105 106static void draw_text_on_path_rigid(SkCanvas* canvas, const void* text, size_t length, 107 const SkPoint xy[], const SkPath& path, const SkPaint& paint) { 108 SkPathMeasure meas(path, false); 109 110 int count = paint.countText(text, length); 111 size_t size = count * (sizeof(SkRSXform) + sizeof(SkScalar)); 112 SkAutoSMalloc<512> storage(size); 113 SkRSXform* xform = (SkRSXform*)storage.get(); 114 SkScalar* widths = (SkScalar*)(xform + count); 115 116 paint.getTextWidths(text, length, widths); 117 118 for (int i = 0; i < count; ++i) { 119 // we want to position each character on the center of its advance 120 const SkScalar offset = SkScalarHalf(widths[i]); 121 SkPoint pos; 122 SkVector tan; 123 if (!meas.getPosTan(xy[i].x() + offset, &pos, &tan)) { 124 pos = xy[i]; 125 tan.set(1, 0); 126 } 127 xform[i].fSCos = tan.x(); 128 xform[i].fSSin = tan.y(); 129 xform[i].fTx = pos.x() - tan.y() * xy[i].y() - tan.x() * offset; 130 xform[i].fTy = pos.y() + tan.x() * xy[i].y() - tan.y() * offset; 131 } 132 133 // Compute a conservative bounds so we can cull the draw 134 const SkRect font = paint.getFontBounds(); 135 const SkScalar max = SkTMax(SkTMax(SkScalarAbs(font.fLeft), SkScalarAbs(font.fRight)), 136 SkTMax(SkScalarAbs(font.fTop), SkScalarAbs(font.fBottom))); 137 const SkRect bounds = path.getBounds().makeOutset(max, max); 138 139 canvas->drawTextRSXform(text, length, &xform[0], &bounds, paint); 140 141 if (true) { 142 SkPaint p; 143 p.setStyle(SkPaint::kStroke_Style); 144 canvas->drawRect(bounds, p); 145 } 146} 147 148DEF_SIMPLE_GM(drawTextRSXform, canvas, 860, 860) { 149 const char text0[] = "ABCDFGHJKLMNOPQRSTUVWXYZ"; 150 const int N = sizeof(text0) - 1; 151 SkPoint pos[N]; 152 153 SkPaint paint; 154 paint.setAntiAlias(true); 155 paint.setTextSize(100); 156 157 SkScalar x = 0; 158 for (int i = 0; i < N; ++i) { 159 pos[i].set(x, 0); 160 x += paint.measureText(&text0[i], 1); 161 } 162 163 SkPath path; 164 path.addOval(SkRect::MakeXYWH(160, 160, 540, 540)); 165 166 draw_text_on_path_rigid(canvas, text0, N, pos, path, paint); 167 168 paint.setStyle(SkPaint::kStroke_Style); 169 canvas->drawPath(path, paint); 170} 171 172#include "Resources.h" 173#include "SkColorFilter.h" 174#include "SkVertices.h" 175 176static sk_sp<SkVertices> make_vertices(sk_sp<SkImage> image, const SkRect& r, 177 SkColor color) { 178 SkPoint pos[4]; 179 r.toQuad(pos); 180 SkColor colors[4] = { color, color, color, color }; 181 return SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, 182 pos, pos, colors); 183} 184 185/* 186 * drawAtlas and drawVertices have several things in common: 187 * - can create compound "shaders", combining texture and colors 188 * - these are combined via an explicit blendmode 189 * - like drawImage, they only respect parts of the paint 190 * - colorfilter, imagefilter, blendmode, alpha 191 * 192 * This GM produces a series of pairs of images (atlas | vertices). 193 * Each pair should look the same, and each set shows a different combination 194 * of alpha | colorFilter | mode 195 */ 196DEF_SIMPLE_GM(compare_atlas_vertices, canvas, 560, 585) { 197 const SkRect tex = SkRect::MakeWH(128, 128); 198 const SkRSXform xform = SkRSXform::Make(1, 0, 0, 0); 199 const SkColor color = 0x884488CC; 200 201 auto image = GetResourceAsImage("images/mandrill_128.png"); 202 auto verts = make_vertices(image, tex, color); 203 const sk_sp<SkColorFilter> filters[] = { 204 nullptr, 205 SkColorFilter::MakeModeFilter(0xFF00FF88, SkBlendMode::kModulate), 206 }; 207 const SkBlendMode modes[] = { 208 SkBlendMode::kSrcOver, 209 SkBlendMode::kPlus, 210 }; 211 212 canvas->translate(10, 10); 213 SkPaint paint; 214 for (SkBlendMode mode : modes) { 215 for (int alpha : { 0xFF, 0x7F }) { 216 paint.setAlpha(alpha); 217 canvas->save(); 218 for (auto cf : filters) { 219 paint.setColorFilter(cf); 220 canvas->drawAtlas(image, &xform, &tex, &color, 1, 221 mode, &tex, &paint); 222 canvas->translate(128, 0); 223 paint.setShader(image->makeShader()); 224 canvas->drawVertices(verts, mode, paint); 225 paint.setShader(nullptr); 226 canvas->translate(145, 0); 227 } 228 canvas->restore(); 229 canvas->translate(0, 145); 230 } 231 } 232} 233