add quadclipping utility, plus sample test
git-svn-id: http://skia.googlecode.com/svn/trunk@429 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
4e753558fc
commit
77f0ef726f
@ -59,9 +59,9 @@ int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValues[1]);
|
||||
Depending on what is returned, dst[] is treated as follows
|
||||
1 dst[0..2] is the original quad
|
||||
2 dst[0..2] and dst[2..4] are the two new quads
|
||||
If dst == null, it is ignored and only the count is returned.
|
||||
*/
|
||||
int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]);
|
||||
int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5]);
|
||||
|
||||
/** Given 3 points on a quadratic bezier, divide it into 2 quadratics
|
||||
if the point of maximum curvature exists on the quad segment.
|
||||
|
@ -13,21 +13,87 @@
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkTime.h"
|
||||
#include "SkRandom.h"
|
||||
|
||||
#include "SkLineClipper.h"
|
||||
#include "SkQuadClipper.h"
|
||||
|
||||
static void drawQuad(SkCanvas* canvas, const SkPoint pts[3], const SkPaint& p) {
|
||||
SkPath path;
|
||||
path.moveTo(pts[0]);
|
||||
path.quadTo(pts[1], pts[2]);
|
||||
canvas->drawPath(path, p);
|
||||
}
|
||||
|
||||
typedef void (*clipper_proc)(const SkPoint src[], const SkRect& clip,
|
||||
SkCanvas*, const SkPaint&, const SkPaint&);
|
||||
|
||||
static void check_clipper(int count, const SkPoint pts[], const SkRect& clip) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
SkASSERT(pts[i].fX >= clip.fLeft);
|
||||
SkASSERT(pts[i].fX <= clip.fRight);
|
||||
SkASSERT(pts[i].fY >= clip.fTop);
|
||||
SkASSERT(pts[i].fY <= clip.fBottom);
|
||||
}
|
||||
}
|
||||
|
||||
static void line_clipper(const SkPoint src[], const SkRect& clip,
|
||||
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, src, p1);
|
||||
|
||||
SkPoint dst[SkLineClipper::kMaxPoints];
|
||||
int count = SkLineClipper::ClipLine(src, clip, dst);
|
||||
for (int i = 0; i < count; i++) {
|
||||
check_clipper(2, &dst[i], clip);
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, &dst[i], p0);
|
||||
}
|
||||
}
|
||||
|
||||
static void quad_clipper(const SkPoint src[], const SkRect& clip,
|
||||
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
|
||||
drawQuad(canvas, src, p1);
|
||||
|
||||
SkQuadClipper2 clipper;
|
||||
if (clipper.clipQuad(src, clip)) {
|
||||
SkPoint pts[3];
|
||||
SkPath::Verb verb;
|
||||
while ((verb = clipper.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p0);
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
drawQuad(canvas, pts, p0);
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"unexpected verb");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const clipper_proc gProcs[] = {
|
||||
line_clipper,
|
||||
quad_clipper
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum {
|
||||
W = 640/4,
|
||||
H = 480/4
|
||||
W = 640/3,
|
||||
H = 480/3
|
||||
};
|
||||
|
||||
class LineClipperView : public SkView {
|
||||
int fProcIndex;
|
||||
SkRect fClip;
|
||||
SkRandom fRand;
|
||||
SkPoint fPts[2];
|
||||
SkPoint fPts[4];
|
||||
|
||||
void randPts() {
|
||||
fPts[0].set(fRand.nextUScalar1() * 640, fRand.nextUScalar1() * 480);
|
||||
fPts[1].set(fRand.nextUScalar1() * 640, fRand.nextUScalar1() * 480);
|
||||
for (int i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
|
||||
fPts[i].set(fRand.nextUScalar1() * 640,
|
||||
fRand.nextUScalar1() * 480);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -36,6 +102,8 @@ public:
|
||||
int y = (480 - H)/2;
|
||||
fClip.set(x, y, x + W, y + H);
|
||||
this->randPts();
|
||||
|
||||
fProcIndex = 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -60,22 +128,10 @@ protected:
|
||||
canvas->drawLine(-999, y, 999, y, paint);
|
||||
}
|
||||
|
||||
static void check_lineclipper(int count, const SkPoint pts[],
|
||||
const SkRect& clip) {
|
||||
if (count > 0) {
|
||||
for (int i = 0; i <= count; i++) {
|
||||
SkASSERT(pts[i].fX >= clip.fLeft);
|
||||
SkASSERT(pts[i].fX <= clip.fRight);
|
||||
SkASSERT(pts[i].fY >= clip.fTop);
|
||||
SkASSERT(pts[i].fY <= clip.fBottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
this->drawBG(canvas);
|
||||
|
||||
SkPaint paint;
|
||||
SkPaint paint, paint1;
|
||||
|
||||
drawVLine(canvas, fClip.fLeft + SK_ScalarHalf, paint);
|
||||
drawVLine(canvas, fClip.fRight - SK_ScalarHalf, paint);
|
||||
@ -87,18 +143,14 @@ protected:
|
||||
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
paint.setStrokeWidth(SkIntToScalar(3));
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
// paint.setStrokeWidth(SkIntToScalar(3));
|
||||
paint.setStrokeCap(SkPaint::kRound_Cap);
|
||||
SkPoint pts[SkLineClipper::kMaxPoints];
|
||||
int count = SkLineClipper::ClipLine(fPts, fClip, pts);
|
||||
check_lineclipper(count, pts, fClip);
|
||||
for (int i = 0; i < count; i++) {
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, &pts[i], paint);
|
||||
}
|
||||
|
||||
paint.setColor(SK_ColorRED);
|
||||
paint.setStrokeWidth(0);
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, paint);
|
||||
|
||||
paint1.setAntiAlias(true);
|
||||
paint1.setColor(SK_ColorRED);
|
||||
paint1.setStyle(SkPaint::kStroke_Style);
|
||||
gProcs[fProcIndex](fPts, fClip, canvas, paint, paint1);
|
||||
|
||||
if (true) {
|
||||
this->randPts();
|
||||
@ -107,7 +159,10 @@ protected:
|
||||
}
|
||||
|
||||
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
|
||||
this->randPts();
|
||||
// fProcIndex = (fProcIndex + 1) % SK_ARRAY_COUNT(gProcs);
|
||||
if (x < 50 && y < 50) {
|
||||
this->randPts();
|
||||
}
|
||||
this->inval(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -260,22 +260,14 @@ static inline void flatten_double_quad_extrema(SkScalar coords[14])
|
||||
coords[2] = coords[6] = coords[4];
|
||||
}
|
||||
|
||||
static inline void force_quad_monotonic_in_y(SkPoint pts[3])
|
||||
{
|
||||
// zap pts[1].fY to the nearest value
|
||||
SkScalar ab = SkScalarAbs(pts[0].fY - pts[1].fY);
|
||||
SkScalar bc = SkScalarAbs(pts[1].fY - pts[2].fY);
|
||||
pts[1].fY = ab < bc ? pts[0].fY : pts[2].fY;
|
||||
}
|
||||
|
||||
/* Returns 0 for 1 quad, and 1 for two quads, either way the answer is
|
||||
stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
|
||||
*/
|
||||
stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
|
||||
*/
|
||||
int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
|
||||
{
|
||||
SkASSERT(src);
|
||||
SkASSERT(dst);
|
||||
|
||||
|
||||
#if 0
|
||||
static bool once = true;
|
||||
if (once)
|
||||
@ -288,11 +280,11 @@ int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
|
||||
SkDebugf("chop=%d, Y=[%x %x %x %x %x %x]\n", n, d[0].fY, d[1].fY, d[2].fY, d[3].fY, d[4].fY, d[5].fY);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
SkScalar a = src[0].fY;
|
||||
SkScalar b = src[1].fY;
|
||||
SkScalar c = src[2].fY;
|
||||
|
||||
|
||||
if (is_not_monotonic(a, b, c))
|
||||
{
|
||||
SkScalar tValue;
|
||||
@ -312,6 +304,35 @@ int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 for 1 quad, and 1 for two quads, either way the answer is
|
||||
stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
|
||||
*/
|
||||
int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5])
|
||||
{
|
||||
SkASSERT(src);
|
||||
SkASSERT(dst);
|
||||
|
||||
SkScalar a = src[0].fX;
|
||||
SkScalar b = src[1].fX;
|
||||
SkScalar c = src[2].fX;
|
||||
|
||||
if (is_not_monotonic(a, b, c)) {
|
||||
SkScalar tValue;
|
||||
if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
|
||||
SkChopQuadAt(src, dst, tValue);
|
||||
flatten_double_quad_extrema(&dst[0].fX);
|
||||
return 1;
|
||||
}
|
||||
// if we get here, we need to force dst to be monotonic, even though
|
||||
// we couldn't compute a unit_divide value (probably underflow).
|
||||
b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
|
||||
}
|
||||
dst[0].set(a, src[0].fY);
|
||||
dst[1].set(b, src[1].fY);
|
||||
dst[2].set(c, src[2].fY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// F(t) = a (1 - t) ^ 2 + 2 b t (1 - t) + c t ^ 2
|
||||
// F'(t) = 2 (b - a) + 2 (a - 2b + c) t
|
||||
// F''(t) = 2 (a - 2b + c)
|
||||
|
@ -17,14 +17,15 @@
|
||||
#include "SkQuadClipper.h"
|
||||
#include "SkGeometry.h"
|
||||
|
||||
static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
|
||||
static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
|
||||
SkScalar target, SkScalar* t) {
|
||||
/* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
|
||||
* We solve for t, using quadratic equation, hence we have to rearrange
|
||||
* our cooefficents to look like At^2 + Bt + C
|
||||
*/
|
||||
SkScalar A = pts[0].fY - pts[1].fY - pts[1].fY + pts[2].fY;
|
||||
SkScalar B = 2*(pts[1].fY - pts[0].fY);
|
||||
SkScalar C = pts[0].fY - y;
|
||||
SkScalar A = c0 - c1 - c1 + c2;
|
||||
SkScalar B = 2*(c1 - c0);
|
||||
SkScalar C = c0 - target;
|
||||
|
||||
SkScalar roots[2]; // we only expect one, but make room for 2 for safety
|
||||
int count = SkFindUnitQuadRoots(A, B, C, roots);
|
||||
@ -35,6 +36,14 @@ static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
|
||||
return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
|
||||
}
|
||||
|
||||
static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
|
||||
return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
|
||||
}
|
||||
|
||||
SkQuadClipper::SkQuadClipper() {}
|
||||
|
||||
void SkQuadClipper::setClip(const SkIRect& clip) {
|
||||
@ -111,3 +120,215 @@ bool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Modify pts[] in place so that it is clipped in Y to the clip rect
|
||||
static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
|
||||
SkScalar t;
|
||||
SkPoint tmp[5]; // for SkChopQuadAt
|
||||
|
||||
// are we partially above
|
||||
if (pts[0].fY < clip.fTop) {
|
||||
if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
|
||||
// take the 2nd chopped quad
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
pts[0] = tmp[2];
|
||||
pts[1] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the top
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pts[i].fY < clip.fTop) {
|
||||
pts[i].fY = clip.fTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially below
|
||||
if (pts[2].fY > clip.fBottom) {
|
||||
if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
pts[1] = tmp[1];
|
||||
pts[2] = tmp[2];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the bottom
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pts[i].fY > clip.fBottom) {
|
||||
pts[i].fY = clip.fBottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* src[] must be monotonic in Y. This routine copies src into dst, and sorts
|
||||
it to be increasing in Y. If it had to reverse the order of the points,
|
||||
it returns true, otherwise it returns false
|
||||
*/
|
||||
static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[]) {
|
||||
// we need the data to be monotonically increasing in Y
|
||||
if (src[0].fY > src[2].fY) {
|
||||
SkASSERT(src[0].fY >= src[1].fY);
|
||||
SkASSERT(src[1].fY >= src[2].fY);
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
return true;
|
||||
} else {
|
||||
SkASSERT(src[2].fY >= src[1].fY);
|
||||
SkASSERT(src[1].fY >= src[0].fY);
|
||||
memcpy(dst, src, 3 * sizeof(SkPoint));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// srcPts[] must be monotonic in X and Y
|
||||
void SkQuadClipper2::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
SkPoint pts[3];
|
||||
bool reverse = sort_increasing_Y(pts, srcPts);
|
||||
|
||||
// are we completely above or below
|
||||
if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now chop so that pts is contained within clip in Y
|
||||
chop_quad_in_Y(pts, clip);
|
||||
|
||||
if (pts[0].fX > pts[2].fX) {
|
||||
SkTSwap<SkPoint>(pts[0], pts[2]);
|
||||
reverse = !reverse;
|
||||
}
|
||||
SkASSERT(pts[0].fX <= pts[1].fX);
|
||||
SkASSERT(pts[1].fX <= pts[2].fX);
|
||||
|
||||
// Now chop in X has needed, and record the segments
|
||||
|
||||
if (pts[2].fX <= clip.fLeft) { // wholly to the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
|
||||
return;
|
||||
}
|
||||
if (pts[0].fX >= clip.fRight) { // wholly to the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar t;
|
||||
SkPoint tmp[5]; // for SkChopQuadAt
|
||||
|
||||
// are we partially to the left
|
||||
if (pts[0].fX < clip.fLeft) {
|
||||
if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
|
||||
pts[0] = tmp[2];
|
||||
pts[1] = tmp[3];
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the left
|
||||
this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// are we partially to the right
|
||||
if (pts[2].fX > clip.fRight) {
|
||||
if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
|
||||
SkChopQuadAt(pts, tmp, t);
|
||||
this->appendQuad(tmp, reverse);
|
||||
this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
|
||||
} else {
|
||||
// if chopMonoQuadAtY failed, then we may have hit inexact numerics
|
||||
// so we just clamp against the right
|
||||
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
|
||||
}
|
||||
} else { // wholly inside the clip
|
||||
this->appendQuad(pts, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
static bool quick_reject_quad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
return (srcPts[0].fY <= clip.fTop &&
|
||||
srcPts[1].fY <= clip.fTop &&
|
||||
srcPts[2].fY <= clip.fTop)
|
||||
||
|
||||
(srcPts[0].fY >= clip.fBottom &&
|
||||
srcPts[1].fY >= clip.fBottom &&
|
||||
srcPts[2].fY >= clip.fBottom);
|
||||
}
|
||||
|
||||
bool SkQuadClipper2::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
|
||||
if (!quick_reject_quad(srcPts, clip)) {
|
||||
SkPoint monoY[5];
|
||||
int countY = SkChopQuadAtYExtrema(srcPts, monoY);
|
||||
for (int y = 0; y <= countY; y++) {
|
||||
SkPoint monoX[5];
|
||||
int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
|
||||
SkASSERT(countY + countX <= 3);
|
||||
for (int x = 0; x <= countX; x++) {
|
||||
this->clipMonoQuad(&monoX[x * 2], clip);
|
||||
SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
|
||||
SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fCurrVerb = SkPath::kDone_Verb;
|
||||
fCurrPoint = fPoints;
|
||||
fCurrVerb = fVerbs;
|
||||
return SkPath::kDone_Verb != fVerbs[0];
|
||||
}
|
||||
|
||||
void SkQuadClipper2::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
|
||||
bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kLine_Verb;
|
||||
|
||||
if (reverse) {
|
||||
SkTSwap<SkScalar>(y0, y1);
|
||||
}
|
||||
fCurrPoint[0].set(x, y0);
|
||||
fCurrPoint[1].set(x, y1);
|
||||
fCurrPoint += 2;
|
||||
}
|
||||
|
||||
void SkQuadClipper2::appendQuad(const SkPoint pts[3], bool reverse) {
|
||||
*fCurrVerb++ = SkPath::kQuad_Verb;
|
||||
|
||||
if (reverse) {
|
||||
fCurrPoint[0] = pts[2];
|
||||
fCurrPoint[2] = pts[0];
|
||||
} else {
|
||||
fCurrPoint[0] = pts[0];
|
||||
fCurrPoint[2] = pts[2];
|
||||
}
|
||||
fCurrPoint[1] = pts[1];
|
||||
fCurrPoint += 3;
|
||||
}
|
||||
|
||||
SkPath::Verb SkQuadClipper2::next(SkPoint pts[]) {
|
||||
SkPath::Verb verb = *fCurrVerb;
|
||||
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
|
||||
fCurrPoint += 2;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
|
||||
fCurrPoint += 3;
|
||||
fCurrVerb += 1;
|
||||
break;
|
||||
case SkPath::kDone_Verb:
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"unexpected verb in quadclippper2 iter");
|
||||
break;
|
||||
}
|
||||
return verb;
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,7 @@
|
||||
#ifndef SkQuadClipper_DEFINED
|
||||
#define SkQuadClipper_DEFINED
|
||||
|
||||
#include "SkPoint.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkPath.h"
|
||||
|
||||
/** This class is initialized with a clip rectangle, and then can be fed quads,
|
||||
which must already be monotonic in Y.
|
||||
@ -31,11 +30,37 @@ public:
|
||||
SkQuadClipper();
|
||||
|
||||
void setClip(const SkIRect& clip);
|
||||
|
||||
bool clipQuad(const SkPoint src[3], SkPoint dst[3]);
|
||||
|
||||
bool clipQuad(const SkPoint src[3], SkPoint dst[3]);
|
||||
|
||||
private:
|
||||
SkRect fClip;
|
||||
};
|
||||
|
||||
/** Iterator that returns the clipped segements of a quad clipped to a rect.
|
||||
The segments will be either lines or quads (based on SkPath::Verb), and
|
||||
will all be monotonic in Y
|
||||
*/
|
||||
class SkQuadClipper2 {
|
||||
public:
|
||||
bool clipQuad(const SkPoint pts[3], const SkRect& clip);
|
||||
|
||||
SkPath::Verb next(SkPoint pts[]);
|
||||
|
||||
private:
|
||||
SkPoint* fCurrPoint;
|
||||
SkPath::Verb* fCurrVerb;
|
||||
|
||||
enum {
|
||||
kMaxVerbs = 10,
|
||||
kMaxPoints = 21
|
||||
};
|
||||
SkPoint fPoints[kMaxPoints];
|
||||
SkPath::Verb fVerbs[kMaxVerbs];
|
||||
|
||||
void clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip);
|
||||
void appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse);
|
||||
void appendQuad(const SkPoint pts[3], bool reverse);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user