skia2/samplecode/SampleAtlas.cpp
Ben Wagner 4d5161135e Defer Sample setup to onOnceBeforeDraw.
The Atlas and BitmapRect samples do a great deal of work in their
constructors. In particular this makes setting breakpoints deep in the
glyph handling code more problematic that it needs to be, since these
will call into the glyph code when they are created which can happen
quite early. A great deal of this code does not need to run in the
constructor in any event, the work only needs to be done once before the
sample is drawn. As a result, defer this work into onOnceBeforeDraw.

Change-Id: I212d3909170bf1cb56769a45e1714f24a496472f
Reviewed-on: https://skia-review.googlesource.com/132927
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2018-06-07 20:37:06 +00:00

256 lines
7.8 KiB
C++

/*
* 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"
typedef void (*DrawAtlasProc)(SkCanvas*, SkImage*, const SkRSXform[], const SkRect[],
const SkColor[], int, const SkRect*, const SkPaint*);
static void draw_atlas(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
const SkPaint* paint) {
canvas->drawAtlas(atlas, xform, tex, colors, count, SkBlendMode::kModulate, cull, paint);
}
static void draw_atlas_sim(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
const SkPaint* paint) {
for (int i = 0; i < count; ++i) {
SkMatrix matrix;
matrix.setRSXform(xform[i]);
canvas->save();
canvas->concat(matrix);
canvas->drawImageRect(atlas, tex[i], tex[i].makeOffset(-tex[i].x(), -tex[i].y()), paint,
SkCanvas::kFast_SrcRectConstraint);
canvas->restore();
}
}
static sk_sp<SkImage> make_atlas(int atlasSize, int cellSize) {
SkImageInfo info = SkImageInfo::MakeN32Premul(atlasSize, atlasSize);
auto surface(SkSurface::MakeRaster(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->makeImageSnapshot();
}
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()) {
if (fVelocity.fY > 0) {
fVelocity.fY = -fVelocity.fY;
}
} else if (fCenter.fY < bounds.top()) {
if (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 {
return SkRSXform::MakeFromRadians(fScale, fRadian, fCenter.x(), fCenter.y(),
SkScalarHalf(kCellSize), SkScalarHalf(kCellSize));
}
};
DrawAtlasProc fProc;
enum {
N = 256,
};
sk_sp<SkImage> fAtlas;
Rec fRec[N];
SkRect fTex[N];
SkRect fBounds;
bool fUseColors;
public:
DrawAtlasDrawable(DrawAtlasProc proc, const SkRect& r)
: fProc(proc), fBounds(r), fUseColors(false)
{
SkRandom rand;
fAtlas = 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() / 16;
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 : nullptr;
fProc(canvas, fAtlas.get(), xform, fTex, colorsPtr, N, &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 {
const char* fName;
DrawAtlasProc fProc;
sk_sp<DrawAtlasDrawable> fDrawable;
public:
DrawAtlasView(const char name[], DrawAtlasProc proc) : fName(name), fProc(proc) { }
protected:
bool onQuery(SkEvent* evt) override {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, fName);
return true;
}
SkUnichar uni;
if (SampleCode::CharQ(*evt, &uni)) {
switch (uni) {
case 'C': fDrawable->toggleUseColors(); return true;
default: break;
}
}
return this->INHERITED::onQuery(evt);
}
void onOnceBeforeDraw() override {
fDrawable = sk_make_sp<DrawAtlasDrawable>(fProc, SkRect::MakeWH(640, 480));
}
void onDrawContent(SkCanvas* canvas) override {
canvas->drawDrawable(fDrawable.get());
}
bool onAnimate(const SkAnimTimer&) override {
return true;
}
#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;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE( return new DrawAtlasView("DrawAtlas", draw_atlas); )
DEF_SAMPLE( return new DrawAtlasView("DrawAtlasSim", draw_atlas_sim); )