diff options
-rw-r--r-- | gm/drawatlas.cpp | 103 | ||||
-rw-r--r-- | gm/spritebitmap.cpp | 6 | ||||
-rw-r--r-- | gyp/SampleApp.gyp | 1 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 30 | ||||
-rw-r--r-- | include/core/SkDevice.h | 5 | ||||
-rw-r--r-- | include/core/SkMatrix.h | 4 | ||||
-rw-r--r-- | include/core/SkRSXform.h | 49 | ||||
-rw-r--r-- | include/utils/SkDeferredCanvas.h | 2 | ||||
-rw-r--r-- | samplecode/SampleAtlas.cpp | 234 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 31 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 33 | ||||
-rw-r--r-- | src/core/SkMatrix.cpp | 29 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 8 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 20 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 38 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 2 | ||||
-rw-r--r-- | src/core/SkRecordDraw.cpp | 11 | ||||
-rw-r--r-- | src/core/SkRecorder.cpp | 13 | ||||
-rw-r--r-- | src/core/SkRecorder.h | 2 | ||||
-rw-r--r-- | src/core/SkRecords.h | 21 | ||||
-rw-r--r-- | src/pipe/SkGPipePriv.h | 6 | ||||
-rw-r--r-- | src/pipe/SkGPipeRead.cpp | 31 | ||||
-rw-r--r-- | src/pipe/SkGPipeWrite.cpp | 45 | ||||
-rw-r--r-- | src/utils/SkDeferredCanvas.cpp | 16 |
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); |