Initial commit
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
#include "CgeScanline.h"
|
||||
|
||||
#define BEZIER_MAX_DEPTH 64
|
||||
|
||||
typedef struct {
|
||||
CgeScanlineEdge *edge;
|
||||
size_t edgeSize;
|
||||
size_t count;
|
||||
} EdgeAddContext;
|
||||
|
||||
static void edgeAddLineTo(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1,
|
||||
void *userData) {
|
||||
EdgeAddContext *ctx = (EdgeAddContext *)userData;
|
||||
|
||||
if (ctx->count >= ctx->edgeSize)
|
||||
return;
|
||||
ctx->count += CgeScanlineEdgeAdd(ctx->edge + ctx->count, x0, y0, x1, y1);
|
||||
}
|
||||
|
||||
static void addVec(uint32_t a[2], uint32_t b[2], uint32_t c[2]) {
|
||||
c[0] = a[0] + b[0];
|
||||
c[1] = a[1] + b[1];
|
||||
}
|
||||
|
||||
static void shiftVec(uint32_t a[2], uint32_t b[2], int val) {
|
||||
b[0] = a[0] >> val;
|
||||
b[1] = a[1] >> val;
|
||||
}
|
||||
|
||||
static uint64_t distSq(uint32_t x, uint32_t y) {
|
||||
if (x & 0x80000000)
|
||||
x = -x;
|
||||
if (y & 0x80000000)
|
||||
y = -y;
|
||||
|
||||
return ((uint64_t)x * x + (uint64_t)y * y);
|
||||
}
|
||||
|
||||
static uint64_t flatnessCubic(uint32_t p[4][2]) {
|
||||
uint64_t f1, f2;
|
||||
f1 = distSq(p[0][0] - (p[1][0] << 1) + p[2][0],
|
||||
p[0][1] - (p[1][1] << 1) + p[2][1]);
|
||||
f2 = distSq(p[1][0] - (p[2][0] << 1) + p[3][0],
|
||||
p[1][1] - (p[2][1] << 1) + p[3][1]);
|
||||
return f1 > f2 ? f1 : f2;
|
||||
}
|
||||
|
||||
static uint64_t flatnessQuad(uint32_t p[3][2]) {
|
||||
return distSq(p[0][0] - (p[1][0] << 1) + p[2][0],
|
||||
p[0][1] - (p[1][1] << 1) + p[2][1]);
|
||||
}
|
||||
|
||||
static void bezierCubicFlattenRec(uint32_t x0, uint32_t y0, uint32_t x1,
|
||||
uint32_t y1, uint32_t x2, uint32_t y2,
|
||||
uint32_t x3, uint32_t y3, uint64_t flatnessSq,
|
||||
int depth, CgeScanlineLineToCallback lineTo,
|
||||
void *userData) {
|
||||
uint32_t a[4][2] = {{x0, y0}, {x1, y1}, {x2, y2}, {x3, y3}};
|
||||
uint32_t b[3][2];
|
||||
uint32_t c[2][2];
|
||||
uint32_t d[2];
|
||||
|
||||
if (depth < BEZIER_MAX_DEPTH && flatnessCubic(a) > flatnessSq) {
|
||||
addVec(a[0], a[1], b[0]);
|
||||
addVec(a[1], a[2], b[1]);
|
||||
addVec(a[2], a[3], b[2]);
|
||||
addVec(b[0], b[1], c[0]);
|
||||
addVec(b[1], b[2], c[1]);
|
||||
addVec(c[0], c[1], d);
|
||||
shiftVec(b[0], b[0], 1);
|
||||
shiftVec(b[1], b[1], 1);
|
||||
shiftVec(b[2], b[2], 1);
|
||||
shiftVec(c[0], c[0], 2);
|
||||
shiftVec(c[1], c[1], 2);
|
||||
shiftVec(d, d, 3);
|
||||
|
||||
bezierCubicFlattenRec(a[0][0], a[0][1], b[0][0], b[0][1], c[0][0],
|
||||
c[0][1], d[0], d[1], flatnessSq, depth + 1,
|
||||
lineTo, userData);
|
||||
|
||||
bezierCubicFlattenRec(d[0], d[1], c[1][0], c[1][1], b[2][0], b[2][1],
|
||||
a[3][0], a[3][1], flatnessSq, depth + 1,
|
||||
lineTo, userData);
|
||||
} else {
|
||||
lineTo(x0, y0, x3, y3, userData);
|
||||
}
|
||||
}
|
||||
|
||||
static void bezierQuadFlattenRec(uint32_t x0, uint32_t y0, uint32_t x1,
|
||||
uint32_t y1, uint32_t x2, uint32_t y2,
|
||||
uint64_t flatnessSq, int depth,
|
||||
CgeScanlineLineToCallback lineTo,
|
||||
void *userData) {
|
||||
uint32_t a[3][2] = {{x0, y0}, {x1, y1}, {x2, y2}};
|
||||
uint32_t b[2][2];
|
||||
uint32_t c[2];
|
||||
|
||||
if (depth < BEZIER_MAX_DEPTH && flatnessQuad(a) > flatnessSq) {
|
||||
addVec(a[0], a[1], b[0]);
|
||||
addVec(a[1], a[2], b[1]);
|
||||
addVec(b[0], b[1], c);
|
||||
shiftVec(b[0], b[0], 1);
|
||||
shiftVec(b[1], b[1], 1);
|
||||
shiftVec(c, c, 2);
|
||||
|
||||
bezierQuadFlattenRec(a[0][0], a[0][1], b[0][0], b[0][1], c[0], c[1],
|
||||
flatnessSq, depth + 1, lineTo, userData);
|
||||
bezierQuadFlattenRec(c[0], c[1], b[1][0], b[1][1], a[2][0], a[2][1],
|
||||
flatnessSq, depth + 1, lineTo, userData);
|
||||
} else {
|
||||
lineTo(x0, y0, x2, y2, userData);
|
||||
}
|
||||
}
|
||||
|
||||
void CgeScanlineBezierCubicFlatten(uint32_t x0, uint32_t y0, uint32_t x1,
|
||||
uint32_t y1, uint32_t x2, uint32_t y2,
|
||||
uint32_t x3, uint32_t y3, uint32_t flatness,
|
||||
CgeScanlineLineToCallback lineTo,
|
||||
void *userData) {
|
||||
uint64_t flatnessSq = (uint64_t)flatness * (uint64_t)flatness;
|
||||
if (flatnessSq < 1)
|
||||
flatnessSq = 1;
|
||||
bezierCubicFlattenRec(x0, y0, x1, y1, x2, y2, x3, y3,
|
||||
flatnessSq, 0, lineTo, userData);
|
||||
}
|
||||
|
||||
void CgeScanlineBezierQuadFlatten(uint32_t x0, uint32_t y0, uint32_t x1,
|
||||
uint32_t y1, uint32_t x2, uint32_t y2,
|
||||
uint32_t flatness,
|
||||
CgeScanlineLineToCallback lineTo,
|
||||
void *userData) {
|
||||
uint64_t flatnessSq = (uint64_t)flatness * (uint64_t)flatness;
|
||||
if (flatnessSq < 1)
|
||||
flatnessSq = 1;
|
||||
bezierQuadFlattenRec(x0, y0, x1, y1, x2, y2,
|
||||
flatnessSq, 0, lineTo, userData);
|
||||
}
|
||||
|
||||
size_t CgeScanlineBezierCubicEdges(CgeScanlineEdge *edge, size_t edgeSize,
|
||||
uint32_t x0, uint32_t y0, uint32_t x1,
|
||||
uint32_t y1, uint32_t x2, uint32_t y2,
|
||||
uint32_t x3, uint32_t y3,
|
||||
uint32_t flatness) {
|
||||
EdgeAddContext ctx;
|
||||
ctx.edge = edge;
|
||||
ctx.edgeSize = edgeSize;
|
||||
ctx.count = 0;
|
||||
|
||||
CgeScanlineBezierCubicFlatten(x0, y0, x1, y1, x2, y2, x3, y3, flatness,
|
||||
edgeAddLineTo, &ctx);
|
||||
|
||||
return ctx.count;
|
||||
}
|
||||
|
||||
size_t CgeScanlineBezierQuadEdges(CgeScanlineEdge *edge, size_t edgeSize,
|
||||
uint32_t x0, uint32_t y0, uint32_t x1,
|
||||
uint32_t y1, uint32_t x2, uint32_t y2,
|
||||
uint32_t flatness) {
|
||||
EdgeAddContext ctx;
|
||||
ctx.edge = edge;
|
||||
ctx.edgeSize = edgeSize;
|
||||
ctx.count = 0;
|
||||
|
||||
CgeScanlineBezierQuadFlatten(x0, y0, x1, y1, x2, y2, flatness,
|
||||
edgeAddLineTo, &ctx);
|
||||
return ctx.count;
|
||||
}
|
||||
Reference in New Issue
Block a user