skia2/samplecode/SamplePatch.cpp
reed@android.com 6b82d1adc6 add isConvex() hit to SkPath, to be used to speed up fills and opengl
set linewidth in gldevice for hair rects
remove some cruft from samples
add more gl-unimpl messages



git-svn-id: http://skia.googlecode.com/svn/trunk@199 2bbb7eff-a529-9590-31e7-b0007b416f81
2009-06-03 02:35:01 +00:00

419 lines
13 KiB
C++

#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkPath.h"
#include "SkPorterDuff.h"
#include "SkRandom.h"
#include "SkRegion.h"
#include "SkShader.h"
#include "SkUtils.h"
#include "SkXfermode.h"
#include "SkColorPriv.h"
#include "SkColorFilter.h"
#include "SkTime.h"
#include "SkTypeface.h"
#include "SkOSFile.h"
#include "SkStream.h"
#include "SkGeometry.h" // private include :(
static void drawtriangle(SkCanvas* canvas, const SkPaint& paint,
const SkPoint pts[3]) {
SkPath path;
path.moveTo(pts[0]);
path.lineTo(pts[1]);
path.lineTo(pts[2]);
canvas->drawPath(path, paint);
}
static SkShader* make_shader0(SkIPoint* size) {
SkBitmap bm;
// SkImageDecoder::DecodeFile("/skimages/progressivejpg.jpg", &bm);
SkImageDecoder::DecodeFile("/skimages/beach.jpg", &bm);
size->set(bm.width(), bm.height());
return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode);
}
static SkShader* make_shader1(const SkIPoint& size) {
SkPoint pts[] = { 0, 0, SkIntToScalar(size.fX), SkIntToScalar(size.fY) };
SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
return SkGradientShader::CreateLinear(pts, colors, NULL,
SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
}
///////////////////////////////////////////////////////////////////////////////
class Patch {
public:
Patch() { bzero(fPts, sizeof(fPts)); }
~Patch() {}
void setPatch(const SkPoint pts[12]) {
memcpy(fPts, pts, 12 * sizeof(SkPoint));
fPts[12] = pts[0]; // the last shall be first
}
void setBounds(int w, int h) { fW = w; fH = h; }
void draw(SkCanvas*, const SkPaint&, int segsU, int segsV,
bool doTextures, bool doColors);
private:
SkPoint fPts[13];
int fW, fH;
};
static void eval_patch_edge(const SkPoint cubic[], SkPoint samples[], int segs) {
SkScalar t = 0;
SkScalar dt = SK_Scalar1 / segs;
samples[0] = cubic[0];
for (int i = 1; i < segs; i++) {
t += dt;
SkEvalCubicAt(cubic, t, &samples[i], NULL, NULL);
}
}
static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv,
SkPoint* pt) {
const int TL = 0;
const int TR = nu;
const int BR = TR + nv;
const int BL = BR + nu;
SkScalar u = SkIntToScalar(iu) / nu;
SkScalar v = SkIntToScalar(iv) / nv;
SkScalar uv = SkScalarMul(u, v);
SkScalar Uv = SkScalarMul(SK_Scalar1 - u, v);
SkScalar uV = SkScalarMul(u, SK_Scalar1 - v);
SkScalar UV = SkScalarMul(SK_Scalar1 - u, SK_Scalar1 - v);
SkScalar x0 = SkScalarMul(UV, edge[TL].fX) + SkScalarMul(uV, edge[TR].fX) +
SkScalarMul(Uv, edge[BL].fX) + SkScalarMul(uv, edge[BR].fX);
SkScalar y0 = SkScalarMul(UV, edge[TL].fY) + SkScalarMul(uV, edge[TR].fY) +
SkScalarMul(Uv, edge[BL].fY) + SkScalarMul(uv, edge[BR].fY);
SkScalar x = SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fX) +
SkScalarMul(u, edge[TR+iv].fX) +
SkScalarMul(v, edge[BR+nu-iu].fX) +
SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fX) - x0;
SkScalar y = SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fY) +
SkScalarMul(u, edge[TR+iv].fY) +
SkScalarMul(v, edge[BR+nu-iu].fY) +
SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fY) - y0;
pt->set(x, y);
}
static int ScalarTo255(SkScalar v) {
int scale = SkScalarToFixed(v) >> 8;
if (scale < 0) {
scale = 0;
} else if (scale > 255) {
scale = 255;
}
return scale;
}
static SkColor make_color(SkScalar s, SkScalar t) {
int cs = ScalarTo255(s);
int ct = ScalarTo255(t);
return SkColorSetARGB(0xFF, cs, 0, 0) + SkColorSetARGB(0, 0, ct, 0);
}
void Patch::draw(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
bool doTextures, bool doColors) {
if (nu < 1 || nv < 1) {
return;
}
int i, npts = (nu + nv) * 2;
SkAutoSTMalloc<16, SkPoint> storage(npts + 1);
SkPoint* edge0 = storage.get();
SkPoint* edge1 = edge0 + nu;
SkPoint* edge2 = edge1 + nv;
SkPoint* edge3 = edge2 + nu;
// evaluate the edge points
eval_patch_edge(fPts + 0, edge0, nu);
eval_patch_edge(fPts + 3, edge1, nv);
eval_patch_edge(fPts + 6, edge2, nu);
eval_patch_edge(fPts + 9, edge3, nv);
edge3[nv] = edge0[0]; // the last shall be first
for (i = 0; i < npts; i++) {
// canvas->drawLine(edge0[i].fX, edge0[i].fY, edge0[i+1].fX, edge0[i+1].fY, paint);
}
int row, vertCount = (nu + 1) * (nv + 1);
SkAutoTMalloc<SkPoint> vertStorage(vertCount);
SkPoint* verts = vertStorage.get();
// first row
memcpy(verts, edge0, (nu + 1) * sizeof(SkPoint));
// rows
SkPoint* r = verts;
for (row = 1; row < nv; row++) {
r += nu + 1;
r[0] = edge3[nv - row];
for (int col = 1; col < nu; col++) {
eval_sheet(edge0, nu, nv, col, row, &r[col]);
}
r[nu] = edge1[row];
}
// last row
SkPoint* last = verts + nv * (nu + 1);
for (i = 0; i <= nu; i++) {
last[i] = edge2[nu - i];
}
// canvas->drawPoints(verts, vertCount, paint);
int stripCount = (nu + 1) * 2;
SkAutoTMalloc<SkPoint> stripStorage(stripCount * 2);
SkAutoTMalloc<SkColor> colorStorage(stripCount);
SkPoint* strip = stripStorage.get();
SkPoint* tex = strip + stripCount;
SkColor* colors = colorStorage.get();
SkScalar t = 0;
const SkScalar ds = SK_Scalar1 * fW / nu;
const SkScalar dt = SK_Scalar1 * fH / nv;
r = verts;
for (row = 0; row < nv; row++) {
SkPoint* upper = r;
SkPoint* lower = r + nu + 1;
r = lower;
SkScalar s = 0;
for (i = 0; i <= nu; i++) {
strip[i*2 + 0] = *upper++;
strip[i*2 + 1] = *lower++;
tex[i*2 + 0].set(s, t);
tex[i*2 + 1].set(s, t + dt);
colors[i*2 + 0] = make_color(s/fW, t/fH);
colors[i*2 + 1] = make_color(s/fW, (t + dt)/fH);
s += ds;
}
t += dt;
canvas->drawVertices(SkCanvas::kTriangleStrip_VertexMode, stripCount,
strip, doTextures ? tex : NULL,
doColors ? colors : NULL, NULL,
NULL, 0, paint);
}
}
static void drawpatches(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
Patch* patch) {
SkAutoCanvasRestore ar(canvas, true);
patch->draw(canvas, paint, 10, 10, false, false);
canvas->translate(SkIntToScalar(180), 0);
patch->draw(canvas, paint, 10, 10, true, false);
canvas->translate(SkIntToScalar(180), 0);
patch->draw(canvas, paint, 10, 10, false, true);
canvas->translate(SkIntToScalar(180), 0);
patch->draw(canvas, paint, 10, 10, true, true);
}
class PatchView : public SkView {
SkShader* fShader0;
SkShader* fShader1;
SkIPoint fSize0, fSize1;
SkPoint fPts[12];
public:
PatchView() {
fShader0 = make_shader0(&fSize0);
fSize1 = fSize0;
if (fSize0.fX == 0 || fSize0.fY == 0) {
fSize1.set(2, 2);
}
fShader1 = make_shader1(fSize1);
const SkScalar S = SkIntToScalar(50);
const SkScalar T = SkIntToScalar(40);
fPts[0].set(S*0, T);
fPts[1].set(S*1, T);
fPts[2].set(S*2, T);
fPts[3].set(S*3, T);
fPts[4].set(S*3, T*2);
fPts[5].set(S*3, T*3);
fPts[6].set(S*3, T*4);
fPts[7].set(S*2, T*4);
fPts[8].set(S*1, T*4);
fPts[9].set(S*0, T*4);
fPts[10].set(S*0, T*3);
fPts[11].set(S*0, T*2);
}
virtual ~PatchView() {
fShader0->safeUnref();
fShader1->safeUnref();
}
protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) {
if (SampleCode::TitleQ(*evt))
{
SkString str("Patch");
SampleCode::TitleR(evt, str.c_str());
return true;
}
return this->INHERITED::onQuery(evt);
}
void drawBG(SkCanvas* canvas) {
canvas->drawColor(SK_ColorGRAY);
}
virtual void onDraw(SkCanvas* canvas) {
this->drawBG(canvas);
SkPaint paint;
paint.setDither(true);
paint.setFilterBitmap(true);
if (false) {
SkPath p;
p.moveTo(0, 0);
p.lineTo(SkIntToScalar(30000), SkIntToScalar(30000));
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(4));
paint.setAntiAlias(true);
canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
canvas->drawPath(p, paint);
return;
}
if (false) {
for (int dy = -1; dy <= 2; dy++) {
canvas->save();
if (dy == 2) {
canvas->translate(0, SK_Scalar1/2);
} else {
canvas->translate(0, SkIntToScalar(dy)/100);
}
SkBitmap bm;
bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
bm.allocPixels();
SkCanvas c(bm);
SkRect r = { 0, 0, 20*SK_Scalar1, SK_Scalar1 };
for (int y = 0; y < 20; y++) {
SkPaint p;
p.setARGB(0xFF, y*5&0xFF, y*13&0xFF, y*29&0xFF);
c.drawRect(r, p);
r.offset(0, SK_Scalar1);
}
SkIRect src;
SkRect dst;
static const int srcPts[] = {
// 2, 0, 15, 2,
2, 2, 15, 16,
17, 2, 2, 16,
19, 2, 1, 16,
// 2, 18, 15, 2
};
static const double dstPts[] = {
// 7, 262 15, 24.5,
7, 286.5, 15, 16,
22, 286.5, 5, 16,
27, 286.5, 1, 16,
// 7, 302.5, 15, 24.5
};
SkPaint p;
// p.setFilterBitmap(true);
const int* s = srcPts;
const double* d = dstPts;
for (int i = 0; i < 3; i++) {
src.set(s[0], s[1], s[0]+s[2], s[1]+s[3]);
dst.set(SkDoubleToScalar(d[0]),
SkDoubleToScalar(d[1]),
SkDoubleToScalar(d[0]+d[2]),
SkDoubleToScalar(d[1]+d[3]));
canvas->drawBitmapRect(bm, &src, dst, &p);
canvas->translate(SkDoubleToScalar(1), 0);
s += 4;
d += 4;
}
canvas->restore();
canvas->translate(SkIntToScalar(32), 0);
}
return;
}
canvas->translate(SkIntToScalar(20), 0);
Patch patch;
paint.setShader(fShader0);
if (fSize0.fX == 0) {
fSize0.fX = 1;
}
if (fSize0.fY == 0) {
fSize0.fY = 1;
}
patch.setBounds(fSize0.fX, fSize0.fY);
patch.setPatch(fPts);
drawpatches(canvas, paint, 10, 10, &patch);
paint.setShader(NULL);
paint.setAntiAlias(true);
paint.setStrokeWidth(SkIntToScalar(5));
canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts),
fPts, paint);
canvas->translate(0, SkIntToScalar(300));
paint.setAntiAlias(false);
paint.setShader(fShader1);
patch.setBounds(fSize1.fX, fSize1.fY);
drawpatches(canvas, paint, 10, 10, &patch);
}
class PtClick : public Click {
public:
int fIndex;
PtClick(SkView* view, int index) : Click(view), fIndex(index) {}
};
static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
}
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
for (int i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
if (hittest(fPts[i], x, y)) {
return new PtClick(this, i);
}
}
return this->INHERITED::onFindClickHandler(x, y);
}
virtual bool onClick(Click* click) {
fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX, click->fCurr.fY);
this->inval(NULL);
return true;
}
private:
typedef SkView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new PatchView; }
static SkViewRegister reg(MyFactory);