add SkCanvas::drawAtlas

BUG=skia:

Review URL: https://codereview.chromium.org/1181913003
This commit is contained in:
reed 2015-06-24 10:29:17 -07:00 committed by Commit bot
parent 52d4deb128
commit 71c3c760a8
24 changed files with 732 additions and 8 deletions

103
gm/drawatlas.cpp Normal file
View File

@ -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; )

View File

@ -8,6 +8,8 @@
#include "gm.h" #include "gm.h"
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkBlurImageFilter.h" #include "SkBlurImageFilter.h"
#include "SkRSXform.h"
#include "SkSurface.h"
static void make_bm(SkBitmap* bm) { static void make_bm(SkBitmap* bm) {
bm->allocN32Pixels(100, 100); bm->allocN32Pixels(100, 100);
@ -93,7 +95,5 @@ protected:
private: private:
typedef GM INHERITED; typedef GM INHERITED;
}; };
//////////////////////////////////////////////////////////////////////////////
DEF_GM( return new SpriteBitmapGM; ) DEF_GM( return new SpriteBitmapGM; )

View File

@ -45,6 +45,7 @@
'../samplecode/SampleAnimBlur.cpp', '../samplecode/SampleAnimBlur.cpp',
'../samplecode/SampleApp.cpp', '../samplecode/SampleApp.cpp',
'../samplecode/SampleArc.cpp', '../samplecode/SampleArc.cpp',
'../samplecode/SampleAtlas.cpp',
'../samplecode/SampleBigBlur.cpp', '../samplecode/SampleBigBlur.cpp',
'../samplecode/SampleBigGradient.cpp', '../samplecode/SampleBigGradient.cpp',
'../samplecode/SampleBitmapRect.cpp', '../samplecode/SampleBitmapRect.cpp',

View File

@ -28,6 +28,7 @@ class SkImage;
class SkMetaData; class SkMetaData;
class SkPicture; class SkPicture;
class SkRRect; class SkRRect;
struct SkRSXform;
class SkSurface; class SkSurface;
class SkSurface_Base; class SkSurface_Base;
class SkTextBlob; class SkTextBlob;
@ -1023,6 +1024,32 @@ public:
void drawPatch(const SkPoint cubics[12], const SkColor colors[4], void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint); 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 * 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, * (e.g. it is recording into a picture) then the drawable will be referenced instead,
@ -1197,6 +1224,9 @@ protected:
virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[], virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkXfermode*, const SkPoint texs[], const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount, const SkPaint&); 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 onDrawPath(const SkPath&, const SkPaint&);
virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*); virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*); virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*);

View File

@ -245,6 +245,11 @@ protected:
// default implementation calls drawVertices // default implementation calls drawVertices
virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4], virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint); 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 /** The SkDevice passed will be an SkDevice which was returned by a call to
onCreateDevice on this device with kNeverTile_TileExpectation. onCreateDevice on this device with kNeverTile_TileExpectation.
*/ */

View File

@ -12,6 +12,7 @@
#include "SkRect.h" #include "SkRect.h"
struct SkRSXform;
class SkString; class SkString;
/** \class SkMatrix /** \class SkMatrix
@ -244,6 +245,9 @@ public:
/** Set the matrix to rotate by the specified sine and cosine values. /** Set the matrix to rotate by the specified sine and cosine values.
*/ */
void setSinCos(SkScalar sinValue, SkScalar cosValue); 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). /** 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 The pivot point is the coordinate that should remain unchanged by the
specified transformation. specified transformation.

49
include/core/SkRSXform.h Normal file
View File

@ -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

View File

@ -186,6 +186,8 @@ protected:
const SkColor colors[], SkXfermode* xmode, const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount, const uint16_t indices[], int indexCount,
const SkPaint&) override; 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 onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;

234
samplecode/SampleAtlas.cpp Normal file
View File

@ -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);

View File

@ -1801,6 +1801,18 @@ void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPai
this->onDrawSprite(bitmap, left, top, paint); 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 // These are the virtual drawing methods
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -2449,6 +2461,25 @@ void SkCanvas::onDrawDrawable(SkDrawable* dr) {
dr->draw(this); 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 // These methods are NOT virtual, and therefore must call back into virtual
// methods, rather than actually drawing themselves. // methods, rather than actually drawing themselves.

View File

@ -5,6 +5,7 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "SkColorFilter.h"
#include "SkDevice.h" #include "SkDevice.h"
#include "SkDraw.h" #include "SkDraw.h"
#include "SkDrawFilter.h" #include "SkDrawFilter.h"
@ -13,6 +14,7 @@
#include "SkPatchUtils.h" #include "SkPatchUtils.h"
#include "SkPathMeasure.h" #include "SkPathMeasure.h"
#include "SkRasterClip.h" #include "SkRasterClip.h"
#include "SkRSXform.h"
#include "SkShader.h" #include "SkShader.h"
#include "SkTextBlob.h" #include "SkTextBlob.h"
#include "SkTextToPathIter.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) { bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
#ifdef SK_DEBUG #ifdef SK_DEBUG
SkASSERT(info.width() > 0 && info.height() > 0); SkASSERT(info.width() > 0 && info.height() > 0);

View File

@ -7,6 +7,7 @@
#include "SkMatrix.h" #include "SkMatrix.h"
#include "SkFloatBits.h" #include "SkFloatBits.h"
#include "SkRSXform.h"
#include "SkString.h" #include "SkString.h"
#include "SkNx.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); 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) { void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
fMat[kMScaleX] = cosV; fMat[kMScaleX] = cosV;
fMat[kMSkewX] = -sinV; fMat[kMSkewX] = -sinV;
@ -1823,3 +1840,15 @@ bool SkDecomposeUpper2x2(const SkMatrix& matrix,
return true; 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);
}

View File

@ -71,8 +71,9 @@ enum DrawType {
DRAW_TEXT_BLOB, DRAW_TEXT_BLOB,
DRAW_IMAGE, DRAW_IMAGE,
DRAW_IMAGE_RECT, 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* // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
@ -85,6 +86,11 @@ enum DrawVertexFlags {
DRAW_VERTICES_HAS_XFER = 0x08, 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 // clipparams are packed in 5 bits
// doAA:1 | regionOp:4 // doAA:1 | regionOp:4

View File

@ -11,6 +11,7 @@
#include "SkPicturePlayback.h" #include "SkPicturePlayback.h"
#include "SkPictureRecord.h" #include "SkPictureRecord.h"
#include "SkReader32.h" #include "SkReader32.h"
#include "SkRSXform.h"
#include "SkTextBlob.h" #include "SkTextBlob.h"
#include "SkTDArray.h" #include "SkTDArray.h"
#include "SkTypes.h" #include "SkTypes.h"
@ -156,6 +157,25 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
canvas->concat(matrix); canvas->concat(matrix);
break; 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: { case DRAW_BITMAP: {
const SkPaint* paint = fPictureData->getPaint(reader); const SkPaint* paint = fPictureData->getPaint(reader);
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader)); const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));

View File

@ -11,6 +11,7 @@
#include "SkPatchUtils.h" #include "SkPatchUtils.h"
#include "SkPixelRef.h" #include "SkPixelRef.h"
#include "SkRRect.h" #include "SkRRect.h"
#include "SkRSXform.h"
#include "SkTextBlob.h" #include "SkTextBlob.h"
#include "SkTSearch.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_TEXT_BLOB- right after op code
1, // DRAW_IMAGE - right after op code 1, // DRAW_IMAGE - right after op code
1, // DRAW_IMAGE_RECT - 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, 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); 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&) { SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {

View File

@ -173,6 +173,8 @@ protected:
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) override; 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 onDrawPaint(const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;

View File

@ -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(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
DRAW(DrawTextBlob, drawTextBlob(r.blob, 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(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, DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
r.xmode.get(), r.indices, r.indexCount, r.paint)); r.xmode.get(), r.indices, r.indexCount, r.paint));
#undef DRAW #undef DRAW
@ -452,6 +453,14 @@ private:
return this->adjustAndMap(dst, &op.paint); 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 { Bounds bounds(const DrawPicture& op) const {
SkRect dst = op.picture->cullRect(); SkRect dst = op.picture->cullRect();
op.matrix.mapRect(&dst); op.matrix.mapRect(&dst);

View File

@ -299,6 +299,19 @@ void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
xmode); 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() { void SkRecorder::willSave() {
APPEND(Save); APPEND(Save);
} }

View File

@ -108,6 +108,8 @@ public:
const SkColor colors[], SkXfermode* xmode, const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount, const uint16_t indices[], int indexCount,
const SkPaint&) override; 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 onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override;
void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override; void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override;

View File

@ -12,6 +12,7 @@
#include "SkDrawable.h" #include "SkDrawable.h"
#include "SkPathPriv.h" #include "SkPathPriv.h"
#include "SkPicture.h" #include "SkPicture.h"
#include "SkRSXform.h"
#include "SkTextBlob.h" #include "SkTextBlob.h"
namespace SkRecords { namespace SkRecords {
@ -58,6 +59,7 @@ namespace SkRecords {
M(DrawRect) \ M(DrawRect) \
M(DrawSprite) \ M(DrawSprite) \
M(DrawTextBlob) \ M(DrawTextBlob) \
M(DrawAtlas) \
M(DrawVertices) M(DrawVertices)
// Defines SkRecords::Type, an enum of all record types. // 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; \ 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) \ #define ACT_AS_PTR(ptr) \
operator T*() const { return ptr; } \ operator T*() const { return ptr; } \
T* operator->() const { return ptr; } T* operator->() const { return ptr; }
@ -317,6 +328,15 @@ RECORD5(DrawPatch, SkPaint, paint,
PODArray<SkPoint>, texCoords, PODArray<SkPoint>, texCoords,
RefBox<SkXfermode>, xmode); 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. // This guy is so ugly we just write it manually.
struct DrawVertices { struct DrawVertices {
static const Type kType = DrawVertices_Type; static const Type kType = DrawVertices_Type;
@ -357,6 +377,7 @@ struct DrawVertices {
#undef RECORD3 #undef RECORD3
#undef RECORD4 #undef RECORD4
#undef RECORD5 #undef RECORD5
#undef RECORD8
} // namespace SkRecords } // namespace SkRecords

View File

@ -39,6 +39,7 @@ enum DrawOps {
kClipRect_DrawOp, kClipRect_DrawOp,
kClipRRect_DrawOp, kClipRRect_DrawOp,
kConcat_DrawOp, kConcat_DrawOp,
kDrawAtlas_DrawOp,
kDrawBitmap_DrawOp, kDrawBitmap_DrawOp,
kDrawBitmapNine_DrawOp, kDrawBitmapNine_DrawOp,
kDrawBitmapRectToRect_DrawOp, kDrawBitmapRectToRect_DrawOp,
@ -144,6 +145,11 @@ enum {
kDrawVertices_HasIndices_DrawOpFlag = 1 << 2, kDrawVertices_HasIndices_DrawOpFlag = 1 << 2,
kDrawVertices_HasXfermode_DrawOpFlag = 1 << 3, 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 // These are shared between drawbitmap and drawimage
enum { enum {
kDrawBitmap_HasPaint_DrawOpFlag = 1 << 0, kDrawBitmap_HasPaint_DrawOpFlag = 1 << 0,

View File

@ -20,11 +20,12 @@
#include "SkDrawLooper.h" #include "SkDrawLooper.h"
#include "SkImageFilter.h" #include "SkImageFilter.h"
#include "SkMaskFilter.h" #include "SkMaskFilter.h"
#include "SkReadBuffer.h"
#include "SkPatchUtils.h" #include "SkPatchUtils.h"
#include "SkPathEffect.h" #include "SkPathEffect.h"
#include "SkRasterizer.h" #include "SkRasterizer.h"
#include "SkReadBuffer.h"
#include "SkRRect.h" #include "SkRRect.h"
#include "SkRSXform.h"
#include "SkShader.h" #include "SkShader.h"
#include "SkTextBlob.h" #include "SkTextBlob.h"
#include "SkTypeface.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, static void drawText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@ -831,6 +859,7 @@ static const ReadProc gReadTable[] = {
clipRect_rp, clipRect_rp,
clipRRect_rp, clipRRect_rp,
concat_rp, concat_rp,
drawAtlas_rp,
drawBitmap_rp, drawBitmap_rp,
drawBitmapNine_rp, drawBitmapNine_rp,
drawBitmapRect_rp, drawBitmapRect_rp,

View File

@ -16,6 +16,7 @@
#include "SkGPipePriv.h" #include "SkGPipePriv.h"
#include "SkImageFilter.h" #include "SkImageFilter.h"
#include "SkMaskFilter.h" #include "SkMaskFilter.h"
#include "SkRSXform.h"
#include "SkWriteBuffer.h" #include "SkWriteBuffer.h"
#include "SkPaint.h" #include "SkPaint.h"
#include "SkPatchUtils.h" #include "SkPatchUtils.h"
@ -287,6 +288,8 @@ protected:
const SkColor colors[], SkXfermode* xmode, const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount, const uint16_t indices[], int indexCount,
const SkPaint&) override; 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 onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipPath(const SkPath&, 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], void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) { const SkPaint& paint) {

View File

@ -251,6 +251,10 @@ protected:
const SkPoint texCoords[4], SkXfermode* xmode, const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) override const SkPaint& paint) override
{SkASSERT(0);} {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, void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
const SkPaint&) override const SkPaint&) override
{SkASSERT(0);} {SkASSERT(0);}
@ -356,8 +360,7 @@ bool SkDeferredDevice::hasPendingCommands() {
return fPipeController.hasPendingCommands(); return fPipeController.hasPendingCommands();
} }
void SkDeferredDevice::aboutToDraw() void SkDeferredDevice::aboutToDraw() {
{
if (fNotificationClient) { if (fNotificationClient) {
fNotificationClient->prepareForDraw(); fNotificationClient->prepareForDraw();
} }
@ -989,6 +992,15 @@ void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor color
this->recordedDrawCommand(); 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) { SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
this->drawingCanvas()->setDrawFilter(filter); this->drawingCanvas()->setDrawFilter(filter);
this->INHERITED::setDrawFilter(filter); this->INHERITED::setDrawFilter(filter);