aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/drawatlas.cpp103
-rw-r--r--gm/spritebitmap.cpp6
-rw-r--r--gyp/SampleApp.gyp1
-rw-r--r--include/core/SkCanvas.h30
-rw-r--r--include/core/SkDevice.h5
-rw-r--r--include/core/SkMatrix.h4
-rw-r--r--include/core/SkRSXform.h49
-rw-r--r--include/utils/SkDeferredCanvas.h2
-rw-r--r--samplecode/SampleAtlas.cpp234
-rw-r--r--src/core/SkCanvas.cpp31
-rw-r--r--src/core/SkDevice.cpp33
-rw-r--r--src/core/SkMatrix.cpp29
-rw-r--r--src/core/SkPictureFlat.h8
-rw-r--r--src/core/SkPicturePlayback.cpp20
-rw-r--r--src/core/SkPictureRecord.cpp38
-rw-r--r--src/core/SkPictureRecord.h2
-rw-r--r--src/core/SkRecordDraw.cpp11
-rw-r--r--src/core/SkRecorder.cpp13
-rw-r--r--src/core/SkRecorder.h2
-rw-r--r--src/core/SkRecords.h21
-rw-r--r--src/pipe/SkGPipePriv.h6
-rw-r--r--src/pipe/SkGPipeRead.cpp31
-rw-r--r--src/pipe/SkGPipeWrite.cpp45
-rw-r--r--src/utils/SkDeferredCanvas.cpp16
24 files changed, 732 insertions, 8 deletions
diff --git a/gm/drawatlas.cpp b/gm/drawatlas.cpp
new file mode 100644
index 0000000000..89bd49c0a2
--- /dev/null
+++ b/gm/drawatlas.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkRSXform.h"
+#include "SkSurface.h"
+
+class DrawAtlasGM : public skiagm::GM {
+ static SkImage* MakeAtlas(SkCanvas* caller, const SkRect& target) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
+ SkAutoTUnref<SkSurface> surface(caller->newSurface(info));
+ if (NULL == surface) {
+ surface.reset(SkSurface::NewRaster(info));
+ }
+ SkCanvas* canvas = surface->getCanvas();
+ // draw red everywhere, but we don't expect to see it in the draw, testing the notion
+ // that drawAtlas draws a subset-region of the atlas.
+ canvas->clear(SK_ColorRED);
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ SkRect r(target);
+ r.inset(-1, -1);
+ // zero out a place (with a 1-pixel border) to land our drawing.
+ canvas->drawRect(r, paint);
+ paint.setXfermode(NULL);
+ paint.setColor(SK_ColorBLUE);
+ paint.setAntiAlias(true);
+ canvas->drawOval(target, paint);
+ return surface->newImageSnapshot();
+ }
+
+ SkAutoTUnref<SkImage> fAtlas;
+
+public:
+ DrawAtlasGM() {}
+
+protected:
+
+ SkString onShortName() override {
+ return SkString("draw-atlas");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(640, 480);
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ const SkRect target = { 50, 50, 80, 90 };
+ if (NULL == fAtlas) {
+ fAtlas.reset(MakeAtlas(canvas, target));
+ }
+
+ const struct {
+ SkScalar fScale;
+ SkScalar fDegrees;
+ SkScalar fTx;
+ SkScalar fTy;
+
+ void apply(SkRSXform* xform) const {
+ const SkScalar rad = SkDegreesToRadians(fDegrees);
+ xform->fSCos = fScale * SkScalarCos(rad);
+ xform->fSSin = fScale * SkScalarSin(rad);
+ xform->fTx = fTx;
+ xform->fTy = fTy;
+ }
+ } rec[] = {
+ { 1, 0, 10, 10 }, // just translate
+ { 2, 0, 110, 10 }, // scale + translate
+ { 1, 30, 210, 10 }, // rotate + translate
+ { 2, -30, 310, 30 }, // scale + rotate + translate
+ };
+
+ const int N = SK_ARRAY_COUNT(rec);
+ SkRSXform xform[N];
+ SkRect tex[N];
+ SkColor colors[N];
+
+ for (int i = 0; i < N; ++i) {
+ rec[i].apply(&xform[i]);
+ tex[i] = target;
+ colors[i] = 0x80FF0000 + (i * 40 * 256);
+ }
+
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setAntiAlias(true);
+
+ canvas->drawAtlas(fAtlas, xform, tex, N, NULL, &paint);
+ canvas->translate(0, 100);
+ canvas->drawAtlas(fAtlas, xform, tex, colors, N, SkXfermode::kSrcIn_Mode, NULL, &paint);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+DEF_GM( return new DrawAtlasGM; )
+
diff --git a/gm/spritebitmap.cpp b/gm/spritebitmap.cpp
index 7c8677d143..9e1bb87810 100644
--- a/gm/spritebitmap.cpp
+++ b/gm/spritebitmap.cpp
@@ -8,6 +8,8 @@
#include "gm.h"
#include "SkCanvas.h"
#include "SkBlurImageFilter.h"
+#include "SkRSXform.h"
+#include "SkSurface.h"
static void make_bm(SkBitmap* bm) {
bm->allocN32Pixels(100, 100);
@@ -93,7 +95,5 @@ protected:
private:
typedef GM INHERITED;
};
-
-//////////////////////////////////////////////////////////////////////////////
-
DEF_GM( return new SpriteBitmapGM; )
+
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index 3a96e2b92c..69c80ad261 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -45,6 +45,7 @@
'../samplecode/SampleAnimBlur.cpp',
'../samplecode/SampleApp.cpp',
'../samplecode/SampleArc.cpp',
+ '../samplecode/SampleAtlas.cpp',
'../samplecode/SampleBigBlur.cpp',
'../samplecode/SampleBigGradient.cpp',
'../samplecode/SampleBitmapRect.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 42627daf51..7bdb6d219c 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -28,6 +28,7 @@ class SkImage;
class SkMetaData;
class SkPicture;
class SkRRect;
+struct SkRSXform;
class SkSurface;
class SkSurface_Base;
class SkTextBlob;
@@ -1024,6 +1025,32 @@ public:
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
/**
+ * Draw a set of sprites from the atlas. Each is specified by a tex rectangle in the
+ * coordinate space of the atlas, and a corresponding xform which transforms the tex rectangle
+ * into a quad.
+ *
+ * xform maps [0, 0, tex.width, tex.height] -> quad
+ *
+ * The color array is optional. When specified, each color modulates the pixels in its
+ * corresponding quad (via the specified SkXfermode::Mode).
+ *
+ * The cullRect is optional. When specified, it must be a conservative bounds of all of the
+ * resulting transformed quads, allowing the canvas to skip drawing if the cullRect does not
+ * intersect the current clip.
+ *
+ * The paint is optional. If specified, its antialiasing, alpha, color-filter, image-filter
+ * and xfermode are used to affect each of the quads.
+ */
+ void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+ const SkColor colors[], int count, SkXfermode::Mode, const SkRect* cullRect,
+ const SkPaint* paint);
+
+ void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count,
+ const SkRect* cullRect, const SkPaint* paint) {
+ this->drawAtlas(atlas, xform, tex, NULL, count, SkXfermode::kDst_Mode, cullRect, paint);
+ }
+
+ /**
* Draw the contents of this drawable into the canvas. If the canvas is async
* (e.g. it is recording into a picture) then the drawable will be referenced instead,
* to have its draw() method called when the picture is finalized.
@@ -1197,6 +1224,9 @@ protected:
virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount, const SkPaint&);
+
+ virtual void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
+ int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*);
virtual void onDrawPath(const SkPath&, const SkPaint&);
virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*);
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index daca805416..2db685a96e 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -245,6 +245,11 @@ protected:
// default implementation calls drawVertices
virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
+
+ // default implementation calls drawPath
+ virtual void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[],
+ const SkColor[], int count, SkXfermode::Mode, const SkPaint&);
+
/** The SkDevice passed will be an SkDevice which was returned by a call to
onCreateDevice on this device with kNeverTile_TileExpectation.
*/
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index dc482b888e..79ee001514 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -12,6 +12,7 @@
#include "SkRect.h"
+struct SkRSXform;
class SkString;
/** \class SkMatrix
@@ -244,6 +245,9 @@ public:
/** Set the matrix to rotate by the specified sine and cosine values.
*/
void setSinCos(SkScalar sinValue, SkScalar cosValue);
+
+ SkMatrix& setRSXform(const SkRSXform&);
+
/** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
The pivot point is the coordinate that should remain unchanged by the
specified transformation.
diff --git a/include/core/SkRSXform.h b/include/core/SkRSXform.h
new file mode 100644
index 0000000000..5dffdc25d9
--- /dev/null
+++ b/include/core/SkRSXform.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRSXform_DEFINED
+#define SkRSXform_DEFINED
+
+#include "SkScalar.h"
+
+/**
+ * A compressed form of a rotation+scale matrix.
+ *
+ * [ fSCos -fSSin fTx ]
+ * [ fSSin fSCos fTy ]
+ * [ 0 0 1 ]
+ */
+struct SkRSXform {
+ SkScalar fSCos;
+ SkScalar fSSin;
+ SkScalar fTx;
+ SkScalar fTy;
+
+ bool rectStaysRect() const {
+ return 0 == fSCos || 0 == fSSin;
+ }
+
+ void setIdentity() {
+ fSCos = 1;
+ fSSin = fTx = fTy = 0;
+ }
+
+ void set(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) {
+ fSCos = scos;
+ fSSin = ssin;
+ fTx = tx;
+ fTy = ty;
+ }
+
+ void toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const;
+ void toQuad(const SkSize& size, SkPoint quad[4]) const {
+ this->toQuad(size.width(), size.height(), quad);
+ }
+};
+
+#endif
+
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index 413f03e7c8..4ace35f22f 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -186,6 +186,8 @@ protected:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint&) override;
+ void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
+ SkXfermode::Mode, const SkRect* cullRect, const SkPaint*) override;
void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
diff --git a/samplecode/SampleAtlas.cpp b/samplecode/SampleAtlas.cpp
new file mode 100644
index 0000000000..adf3f5e3a4
--- /dev/null
+++ b/samplecode/SampleAtlas.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkAnimTimer.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDrawable.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRSXform.h"
+#include "SkSurface.h"
+
+static SkImage* make_atlas(int atlasSize, int cellSize) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(atlasSize, atlasSize);
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
+ SkCanvas* canvas = surface->getCanvas();
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkRandom rand;
+
+ const SkScalar half = cellSize * SK_ScalarHalf;
+ const char* s = "01234567890!@#$%^&*=+<>?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ paint.setTextSize(28);
+ paint.setTextAlign(SkPaint::kCenter_Align);
+ int i = 0;
+ for (int y = 0; y < atlasSize; y += cellSize) {
+ for (int x = 0; x < atlasSize; x += cellSize) {
+ paint.setColor(rand.nextU());
+ paint.setAlpha(0xFF);
+ int index = i % strlen(s);
+ canvas->drawText(&s[index], 1, x + half, y + half + half/2, paint);
+ i += 1;
+ }
+ }
+ return surface->newImageSnapshot();
+}
+
+class DrawAtlasDrawable : public SkDrawable {
+ enum {
+ kMaxScale = 2,
+ kCellSize = 32,
+ kAtlasSize = 512,
+ };
+
+ struct Rec {
+ SkPoint fCenter;
+ SkVector fVelocity;
+ SkScalar fScale;
+ SkScalar fDScale;
+ SkScalar fRadian;
+ SkScalar fDRadian;
+ SkScalar fAlpha;
+ SkScalar fDAlpha;
+
+ void advance(const SkRect& bounds) {
+ fCenter += fVelocity;
+ if (fCenter.fX > bounds.right()) {
+ SkASSERT(fVelocity.fX > 0);
+ fVelocity.fX = -fVelocity.fX;
+ } else if (fCenter.fX < bounds.left()) {
+ SkASSERT(fVelocity.fX < 0);
+ fVelocity.fX = -fVelocity.fX;
+ }
+ if (fCenter.fY > bounds.bottom()) {
+ SkASSERT(fVelocity.fY > 0);
+ fVelocity.fY = -fVelocity.fY;
+ } else if (fCenter.fY < bounds.top()) {
+ SkASSERT(fVelocity.fY < 0);
+ fVelocity.fY = -fVelocity.fY;
+ }
+
+ fScale += fDScale;
+ if (fScale > 2 || fScale < SK_Scalar1/2) {
+ fDScale = -fDScale;
+ }
+
+ fRadian += fDRadian;
+ fRadian = SkScalarMod(fRadian, 2 * SK_ScalarPI);
+
+ fAlpha += fDAlpha;
+ if (fAlpha > 1) {
+ fAlpha = 1;
+ fDAlpha = -fDAlpha;
+ } else if (fAlpha < 0) {
+ fAlpha = 0;
+ fDAlpha = -fDAlpha;
+ }
+ }
+
+ SkRSXform asRSXform() const {
+ SkMatrix m;
+ m.setTranslate(-8, -8);
+ m.postScale(fScale, fScale);
+ m.postRotate(SkRadiansToDegrees(fRadian));
+ m.postTranslate(fCenter.fX, fCenter.fY);
+
+ SkRSXform x;
+ x.fSCos = m.getScaleX();
+ x.fSSin = m.getSkewY();
+ x.fTx = m.getTranslateX();
+ x.fTy = m.getTranslateY();
+ return x;
+ }
+ };
+
+ enum {
+ N = 256,
+ };
+
+ SkAutoTUnref<SkImage> fAtlas;
+ Rec fRec[N];
+ SkRect fTex[N];
+ SkRect fBounds;
+ bool fUseColors;
+
+public:
+ DrawAtlasDrawable(const SkRect& r) : fBounds(r), fUseColors(false) {
+ SkRandom rand;
+ fAtlas.reset(make_atlas(kAtlasSize, kCellSize));
+ const SkScalar kMaxSpeed = 5;
+ const SkScalar cell = SkIntToScalar(kCellSize);
+ int i = 0;
+ for (int y = 0; y < kAtlasSize; y += kCellSize) {
+ for (int x = 0; x < kAtlasSize; x += kCellSize) {
+ const SkScalar sx = SkIntToScalar(x);
+ const SkScalar sy = SkIntToScalar(y);
+ fTex[i].setXYWH(sx, sy, cell, cell);
+
+ fRec[i].fCenter.set(sx + cell/2, sy + 3*cell/4);
+ fRec[i].fVelocity.fX = rand.nextSScalar1() * kMaxSpeed;
+ fRec[i].fVelocity.fY = rand.nextSScalar1() * kMaxSpeed;
+ fRec[i].fScale = 1;
+ fRec[i].fDScale = rand.nextSScalar1() / 4;
+ fRec[i].fRadian = 0;
+ fRec[i].fDRadian = rand.nextSScalar1() / 8;
+ fRec[i].fAlpha = rand.nextUScalar1();
+ fRec[i].fDAlpha = rand.nextSScalar1() / 10;
+ i += 1;
+ }
+ }
+ }
+
+ void toggleUseColors() {
+ fUseColors = !fUseColors;
+ }
+
+protected:
+ void onDraw(SkCanvas* canvas) override {
+ SkRSXform xform[N];
+ SkColor colors[N];
+
+ for (int i = 0; i < N; ++i) {
+ fRec[i].advance(fBounds);
+ xform[i] = fRec[i].asRSXform();
+ if (fUseColors) {
+ colors[i] = SkColorSetARGB((int)(fRec[i].fAlpha * 0xFF), 0xFF, 0xFF, 0xFF);
+ }
+ }
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality);
+
+ const SkRect cull = this->getBounds();
+ const SkColor* colorsPtr = fUseColors ? colors : NULL;
+ canvas->drawAtlas(fAtlas, xform, fTex, colorsPtr, N, SkXfermode::kModulate_Mode,
+ &cull, &paint);
+ }
+
+ SkRect onGetBounds() override {
+ const SkScalar border = kMaxScale * kCellSize;
+ SkRect r = fBounds;
+ r.outset(border, border);
+ return r;
+ }
+
+private:
+ typedef SkDrawable INHERITED;
+};
+
+class DrawAtlasView : public SampleView {
+ DrawAtlasDrawable* fDrawable;
+
+public:
+ DrawAtlasView() {
+ fDrawable = new DrawAtlasDrawable(SkRect::MakeWH(640, 480));
+ }
+
+ ~DrawAtlasView() override {
+ fDrawable->unref();
+ }
+
+protected:
+ bool onQuery(SkEvent* evt) override {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "DrawAtlas");
+ return true;
+ }
+ SkUnichar uni;
+ if (SampleCode::CharQ(*evt, &uni)) {
+ switch (uni) {
+ case 'C': fDrawable->toggleUseColors(); this->inval(NULL); return true;
+ default: break;
+ }
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->drawDrawable(fDrawable);
+ this->inval(NULL);
+ }
+
+#if 0
+ // TODO: switch over to use this for our animation
+ bool onAnimate(const SkAnimTimer& timer) override {
+ SkScalar angle = SkDoubleToScalar(fmod(timer.secs() * 360 / 24, 360));
+ fAnimatingDrawable->setSweep(angle);
+ return true;
+ }
+#endif
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DrawAtlasView; }
+static SkViewRegister reg(MyFactory);
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index fcfb641407..d7c62e8e11 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1801,6 +1801,18 @@ void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPai
this->onDrawSprite(bitmap, left, top, paint);
}
+void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+ const SkColor colors[], int count, SkXfermode::Mode mode,
+ const SkRect* cull, const SkPaint* paint) {
+ if (count <= 0) {
+ return;
+ }
+ SkASSERT(atlas);
+ SkASSERT(xform);
+ SkASSERT(tex);
+ this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
+}
+
//////////////////////////////////////////////////////////////////////////////
// These are the virtual drawing methods
//////////////////////////////////////////////////////////////////////////////
@@ -2449,6 +2461,25 @@ void SkCanvas::onDrawDrawable(SkDrawable* dr) {
dr->draw(this);
}
+void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+ const SkColor colors[], int count, SkXfermode::Mode mode,
+ const SkRect* cull, const SkPaint* paint) {
+ if (cull && this->quickReject(*cull)) {
+ return;
+ }
+
+ SkPaint pnt;
+ if (paint) {
+ pnt = *paint;
+ }
+
+ LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, NULL)
+ while (iter.next()) {
+ iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
+ }
+ LOOPER_END
+}
+
//////////////////////////////////////////////////////////////////////////////
// These methods are NOT virtual, and therefore must call back into virtual
// methods, rather than actually drawing themselves.
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 15cd7eef3b..8f7f50c863 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "SkColorFilter.h"
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkDrawFilter.h"
@@ -13,6 +14,7 @@
#include "SkPatchUtils.h"
#include "SkPathMeasure.h"
#include "SkRasterClip.h"
+#include "SkRSXform.h"
#include "SkShader.h"
#include "SkTextBlob.h"
#include "SkTextToPathIter.h"
@@ -159,6 +161,37 @@ void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const
}
}
+void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[],
+ const SkRect tex[], const SkColor colors[], int count,
+ SkXfermode::Mode mode, const SkPaint& paint) {
+ SkPath path;
+ path.setIsVolatile(true);
+
+ for (int i = 0; i < count; ++i) {
+ SkPoint quad[4];
+ xform[i].toQuad(tex[i].width(), tex[i].height(), quad);
+
+ SkMatrix localM;
+ localM.setRSXform(xform[i]);
+ localM.preTranslate(-tex[i].left(), -tex[i].top());
+
+ SkPaint pnt(paint);
+ pnt.setShader(atlas->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
+ &localM))->unref();
+ if (colors && colors[i] != SK_ColorWHITE) {
+ SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(colors[i], mode));
+ pnt.setColorFilter(cf);
+ }
+
+ path.rewind();
+ path.addPoly(quad, 4, true);
+ path.setConvexity(SkPath::kConvex_Convexity);
+ this->drawPath(draw, path, pnt, NULL, true);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
#ifdef SK_DEBUG
SkASSERT(info.width() > 0 && info.height() > 0);
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index b47770a23b..49cffa45f5 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -7,6 +7,7 @@
#include "SkMatrix.h"
#include "SkFloatBits.h"
+#include "SkRSXform.h"
#include "SkString.h"
#include "SkNx.h"
@@ -440,6 +441,22 @@ void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py)
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
+SkMatrix& SkMatrix::setRSXform(const SkRSXform& xform) {
+ fMat[kMScaleX] = xform.fSCos;
+ fMat[kMSkewX] = -xform.fSSin;
+ fMat[kMTransX] = xform.fTx;
+
+ fMat[kMSkewY] = xform.fSSin;
+ fMat[kMScaleY] = xform.fSCos;
+ fMat[kMTransY] = xform.fTy;
+
+ fMat[kMPersp0] = fMat[kMPersp1] = 0;
+ fMat[kMPersp2] = 1;
+
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
+ return *this;
+}
+
void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
fMat[kMScaleX] = cosV;
fMat[kMSkewX] = -sinV;
@@ -1823,3 +1840,15 @@ bool SkDecomposeUpper2x2(const SkMatrix& matrix,
return true;
}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
+ quad[0].set(0, 0);
+ quad[1].set(width, 0);
+ quad[2].set(width, height);
+ quad[3].set(0, height);
+ SkMatrix m;
+ m.setRSXform(*this).mapPoints(quad, quad, 4);
+}
+
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 8720e19751..07411002ae 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -71,8 +71,9 @@ enum DrawType {
DRAW_TEXT_BLOB,
DRAW_IMAGE,
DRAW_IMAGE_RECT,
+ DRAW_ATLAS,
- LAST_DRAWTYPE_ENUM = DRAW_IMAGE_RECT
+ LAST_DRAWTYPE_ENUM = DRAW_ATLAS
};
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
@@ -85,6 +86,11 @@ enum DrawVertexFlags {
DRAW_VERTICES_HAS_XFER = 0x08,
};
+enum DrawAtlasFlags {
+ DRAW_ATLAS_HAS_COLORS = 1 << 0,
+ DRAW_ATLAS_HAS_CULL = 1 << 1,
+};
+
///////////////////////////////////////////////////////////////////////////////
// clipparams are packed in 5 bits
// doAA:1 | regionOp:4
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index ac71c27d22..a1bb1ba293 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -11,6 +11,7 @@
#include "SkPicturePlayback.h"
#include "SkPictureRecord.h"
#include "SkReader32.h"
+#include "SkRSXform.h"
#include "SkTextBlob.h"
#include "SkTDArray.h"
#include "SkTypes.h"
@@ -156,6 +157,25 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
canvas->concat(matrix);
break;
}
+ case DRAW_ATLAS: {
+ const SkPaint* paint = fPictureData->getPaint(reader);
+ const SkImage* atlas = fPictureData->getImage(reader);
+ const uint32_t flags = reader->readU32();
+ const int count = reader->readU32();
+ const SkRSXform* xform = (const SkRSXform*)reader->skip(count * sizeof(SkRSXform));
+ const SkRect* tex = (const SkRect*)reader->skip(count * sizeof(SkRect));
+ const SkColor* colors = NULL;
+ SkXfermode::Mode mode = SkXfermode::kDst_Mode;
+ if (flags & DRAW_ATLAS_HAS_COLORS) {
+ colors = (const SkColor*)reader->skip(count * sizeof(SkColor));
+ mode = (SkXfermode::Mode)reader->readU32();
+ }
+ const SkRect* cull = NULL;
+ if (flags & DRAW_ATLAS_HAS_CULL) {
+ cull = (const SkRect*)reader->skip(sizeof(SkRect));
+ }
+ canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
+ } break;
case DRAW_BITMAP: {
const SkPaint* paint = fPictureData->getPaint(reader);
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 32033b52db..0fbf98089a 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -11,6 +11,7 @@
#include "SkPatchUtils.h"
#include "SkPixelRef.h"
#include "SkRRect.h"
+#include "SkRSXform.h"
#include "SkTextBlob.h"
#include "SkTSearch.h"
@@ -99,6 +100,7 @@ static inline size_t get_paint_offset(DrawType op, size_t opSize) {
1, // DRAW_TEXT_BLOB- right after op code
1, // DRAW_IMAGE - right after op code
1, // DRAW_IMAGE_RECT - right after op code
+ 1, // DRAW_ATLAS - right after op code
};
SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
@@ -834,6 +836,42 @@ void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors
this->validate(initialOffset, size);
}
+void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+ const SkColor colors[], int count, SkXfermode::Mode mode,
+ const SkRect* cull, const SkPaint* paint) {
+ // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
+ size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
+ uint32_t flags = 0;
+ if (colors) {
+ flags |= DRAW_ATLAS_HAS_COLORS;
+ size += count * sizeof(SkColor);
+ size += sizeof(uint32_t); // xfermode::mode
+ }
+ if (cull) {
+ flags |= DRAW_ATLAS_HAS_CULL;
+ size += sizeof(SkRect);
+ }
+
+ size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
+ SkASSERT(initialOffset+get_paint_offset(DRAW_ATLAS, size) == fWriter.bytesWritten());
+ this->addPaintPtr(paint);
+ this->addImage(atlas);
+ this->addInt(flags);
+ this->addInt(count);
+ fWriter.write(xform, count * sizeof(SkRSXform));
+ fWriter.write(tex, count * sizeof(SkRect));
+
+ // write optional parameters
+ if (colors) {
+ fWriter.write(colors, count * sizeof(SkColor));
+ this->addInt(mode);
+ }
+ if (cull) {
+ fWriter.write(cull, sizeof(SkRect));
+ }
+ this->validate(initialOffset, size);
+}
+
///////////////////////////////////////////////////////////////////////////////
SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 0b6ef8b931..cee5ea35f5 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -173,6 +173,8 @@ protected:
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) override;
+ void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
+ SkXfermode::Mode, const SkRect*, const SkPaint*) override;
void onDrawPaint(const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 7db7680e28..944443c8ee 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -111,6 +111,7 @@ DRAW(DrawSprite, drawSprite(r.bitmap.shallowCopy(), r.left, r.top, r.paint));
DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint));
DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
+DRAW(DrawAtlas, drawAtlas(r.atlas, r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
r.xmode.get(), r.indices, r.indexCount, r.paint));
#undef DRAW
@@ -451,7 +452,15 @@ private:
dst.set(op.vertices, op.vertexCount);
return this->adjustAndMap(dst, &op.paint);
}
-
+
+ Bounds bounds(const DrawAtlas& op) const {
+ if (op.cull) {
+ return this->adjustAndMap(*op.cull, op.paint);
+ } else {
+ return fCurrentClipBounds;
+ }
+ }
+
Bounds bounds(const DrawPicture& op) const {
SkRect dst = op.picture->cullRect();
op.matrix.mapRect(&dst);
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 4562a87f67..812fd9d49c 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -299,6 +299,19 @@ void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
xmode);
}
+void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+ const SkColor colors[], int count, SkXfermode::Mode mode,
+ const SkRect* cull, const SkPaint* paint) {
+ APPEND(DrawAtlas, this->copy(paint),
+ atlas,
+ this->copy(xform, count),
+ this->copy(tex, count),
+ this->copy(colors, count),
+ count,
+ mode,
+ this->copy(cull));
+}
+
void SkRecorder::willSave() {
APPEND(Save);
}
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 7fab62d023..53c658fa6f 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -108,6 +108,8 @@ public:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint&) override;
+ void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
+ int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override;
void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override;
void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index f4de5bdc3b..381f91438b 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -12,6 +12,7 @@
#include "SkDrawable.h"
#include "SkPathPriv.h"
#include "SkPicture.h"
+#include "SkRSXform.h"
#include "SkTextBlob.h"
namespace SkRecords {
@@ -58,6 +59,7 @@ namespace SkRecords {
M(DrawRect) \
M(DrawSprite) \
M(DrawTextBlob) \
+ M(DrawAtlas) \
M(DrawVertices)
// Defines SkRecords::Type, an enum of all record types.
@@ -121,6 +123,15 @@ struct T { \
A a; B b; C c; D d; E e; \
};
+#define RECORD8(T, A, a, B, b, C, c, D, d, E, e, F, f, G, g, H, h) \
+struct T { \
+ static const Type kType = T##_Type; \
+ T() {} \
+ template <typename Z, typename Y, typename X, typename W, typename V, typename U, typename S, typename R> \
+ T(Z a, Y b, X c, W d, V e, U f, S g, R h) : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {} \
+ A a; B b; C c; D d; E e; F f; G g; H h; \
+};
+
#define ACT_AS_PTR(ptr) \
operator T*() const { return ptr; } \
T* operator->() const { return ptr; }
@@ -317,6 +328,15 @@ RECORD5(DrawPatch, SkPaint, paint,
PODArray<SkPoint>, texCoords,
RefBox<SkXfermode>, xmode);
+RECORD8(DrawAtlas, Optional<SkPaint>, paint,
+ RefBox<const SkImage>, atlas,
+ PODArray<SkRSXform>, xforms,
+ PODArray<SkRect>, texs,
+ PODArray<SkColor>, colors,
+ int, count,
+ SkXfermode::Mode, mode,
+ Optional<SkRect>, cull);
+
// This guy is so ugly we just write it manually.
struct DrawVertices {
static const Type kType = DrawVertices_Type;
@@ -357,6 +377,7 @@ struct DrawVertices {
#undef RECORD3
#undef RECORD4
#undef RECORD5
+#undef RECORD8
} // namespace SkRecords
diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index 5f6e45b158..2f246e452c 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -39,6 +39,7 @@ enum DrawOps {
kClipRect_DrawOp,
kClipRRect_DrawOp,
kConcat_DrawOp,
+ kDrawAtlas_DrawOp,
kDrawBitmap_DrawOp,
kDrawBitmapNine_DrawOp,
kDrawBitmapRectToRect_DrawOp,
@@ -144,6 +145,11 @@ enum {
kDrawVertices_HasIndices_DrawOpFlag = 1 << 2,
kDrawVertices_HasXfermode_DrawOpFlag = 1 << 3,
};
+enum {
+ kDrawAtlas_HasPaint_DrawOpFlag = 1 << 0,
+ kDrawAtlas_HasColors_DrawOpFlag = 1 << 1,
+ kDrawAtlas_HasCull_DrawOpFlag = 1 << 2,
+};
// These are shared between drawbitmap and drawimage
enum {
kDrawBitmap_HasPaint_DrawOpFlag = 1 << 0,
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 917bb50976..8d3048d76f 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -20,11 +20,12 @@
#include "SkDrawLooper.h"
#include "SkImageFilter.h"
#include "SkMaskFilter.h"
-#include "SkReadBuffer.h"
#include "SkPatchUtils.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
+#include "SkReadBuffer.h"
#include "SkRRect.h"
+#include "SkRSXform.h"
#include "SkShader.h"
#include "SkTextBlob.h"
#include "SkTypeface.h"
@@ -479,6 +480,33 @@ static void drawVertices_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
}
}
+static void drawAtlas_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) {
+ unsigned flags = DrawOp_unpackFlags(op32);
+
+ const SkPaint* paint = NULL;
+ if (flags & kDrawAtlas_HasPaint_DrawOpFlag) {
+ paint = &state->paint();
+ }
+ const int slot = reader->readU32();
+ const SkImage* atlas = state->getImage(slot);
+ const int count = reader->readU32();
+ SkXfermode::Mode mode = (SkXfermode::Mode)reader->readU32();
+ const SkRSXform* xform = skip<SkRSXform>(reader, count);
+ const SkRect* tex = skip<SkRect>(reader, count);
+ const SkColor* colors = NULL;
+ if (flags & kDrawAtlas_HasColors_DrawOpFlag) {
+ colors = skip<SkColor>(reader, count);
+ }
+ const SkRect* cull = NULL;
+ if (flags & kDrawAtlas_HasCull_DrawOpFlag) {
+ cull = skip<SkRect>(reader, 1);
+ }
+
+ if (state->shouldDraw()) {
+ canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
static void drawText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -831,6 +859,7 @@ static const ReadProc gReadTable[] = {
clipRect_rp,
clipRRect_rp,
concat_rp,
+ drawAtlas_rp,
drawBitmap_rp,
drawBitmapNine_rp,
drawBitmapRect_rp,
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 2c11c41444..f2aaaae216 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -16,6 +16,7 @@
#include "SkGPipePriv.h"
#include "SkImageFilter.h"
#include "SkMaskFilter.h"
+#include "SkRSXform.h"
#include "SkWriteBuffer.h"
#include "SkPaint.h"
#include "SkPatchUtils.h"
@@ -287,6 +288,8 @@ protected:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint&) override;
+ void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
+ int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override;
void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
@@ -1096,6 +1099,48 @@ void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
}
}
+void SkGPipeCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+ const SkColor colors[], int count, SkXfermode::Mode mode,
+ const SkRect* cull, const SkPaint* paint) {
+ NOTIFY_SETUP(this);
+ unsigned flags = 0; // packs with the op, so needs no extra space
+
+ if (paint) {
+ flags |= kDrawAtlas_HasPaint_DrawOpFlag;
+ this->writePaint(*paint);
+ }
+
+ size_t size = 4; // image-slot
+ size += 4; // count
+ size += 4; // mode
+ size += count * sizeof(SkRSXform); // xform
+ size += count * sizeof(SkRect); // tex
+ if (colors) {
+ flags |= kDrawAtlas_HasColors_DrawOpFlag;
+ size += count * sizeof(SkColor); // colors
+ }
+ if (cull) {
+ flags |= kDrawAtlas_HasCull_DrawOpFlag;
+ size += sizeof(SkRect); // cull
+ }
+
+ if (this->needOpBytes(size)) {
+ this->writeOp(kDrawAtlas_DrawOp, flags, 0);
+ int32_t slot = fImageHeap->insert(atlas);
+ fWriter.write32(slot);
+ fWriter.write32(count);
+ fWriter.write32(mode);
+ fWriter.write(xform, count * sizeof(SkRSXform));
+ fWriter.write(tex, count * sizeof(SkRect));
+ if (colors) {
+ fWriter.write(colors, count * sizeof(SkColor));
+ }
+ if (cull) {
+ fWriter.writeRect(*cull);
+ }
+ }
+}
+
void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) {
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 5b6a06863a..ccf0b012b1 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -251,6 +251,10 @@ protected:
const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) override
{SkASSERT(0);}
+ void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[],
+ const SkColor[], int count, SkXfermode::Mode, const SkPaint&) override
+ {SkASSERT(0);}
+
void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
const SkPaint&) override
{SkASSERT(0);}
@@ -356,8 +360,7 @@ bool SkDeferredDevice::hasPendingCommands() {
return fPipeController.hasPendingCommands();
}
-void SkDeferredDevice::aboutToDraw()
-{
+void SkDeferredDevice::aboutToDraw() {
if (fNotificationClient) {
fNotificationClient->prepareForDraw();
}
@@ -989,6 +992,15 @@ void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor color
this->recordedDrawCommand();
}
+void SkDeferredCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[],
+ const SkRect tex[], const SkColor colors[], int count,
+ SkXfermode::Mode mode, const SkRect* cullRect,
+ const SkPaint* paint) {
+ AutoImmediateDrawIfNeeded autoDraw(*this, paint);
+ this->drawingCanvas()->drawAtlas(atlas, xform, tex, colors, count, mode, cullRect, paint);
+ this->recordedDrawCommand();
+}
+
SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
this->drawingCanvas()->setDrawFilter(filter);
this->INHERITED::setDrawFilter(filter);