mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
sw_engine: implement stroke rle part
Current stroke fails to merged shapes case... you can test with testStroke example Change-Id: I488af728949cba1d01b88723eb1dc4c49bac6c9b
This commit is contained in:
parent
41dbd9774a
commit
1686af7643
8 changed files with 271 additions and 141 deletions
|
@ -121,8 +121,6 @@ struct SwStrokeBorder
|
|||
|
||||
struct SwStroke
|
||||
{
|
||||
SwRleData* rle;
|
||||
|
||||
SwFixed angleIn;
|
||||
SwFixed angleOut;
|
||||
SwPoint center;
|
||||
|
@ -146,8 +144,9 @@ struct SwStroke
|
|||
struct SwShape
|
||||
{
|
||||
SwOutline* outline;
|
||||
SwRleData* rle;
|
||||
SwStroke* stroke;
|
||||
SwRleData* rle;
|
||||
SwRleData* strokeRle;
|
||||
SwBBox bbox;
|
||||
};
|
||||
|
||||
|
@ -196,11 +195,13 @@ void shapeFree(SwShape* sdata);
|
|||
|
||||
void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join);
|
||||
bool strokeParseOutline(SwStroke& stroke, SwOutline& outline);
|
||||
SwOutline* strokeExportOutline(SwStroke& stroke);
|
||||
void strokeFree(SwStroke* stroke);
|
||||
|
||||
SwRleData* rleRender(const SwShape& sdata, const SwSize& clip);
|
||||
SwRleData* rleStrokeRender(const SwShape& sdata);
|
||||
SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip);
|
||||
void rleFree(SwRleData* rle);
|
||||
|
||||
bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
|
||||
#endif /* _TVG_SW_COMMON_H_ */
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
constexpr auto CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32
|
||||
constexpr SwCoord CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32
|
||||
|
||||
//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees
|
||||
constexpr static auto ATAN_MAX = 23;
|
||||
|
@ -45,15 +45,14 @@ static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n)
|
|||
}
|
||||
|
||||
|
||||
static SwCoord _downscale(SwCoord x)
|
||||
static SwCoord _downscale(SwFixed x)
|
||||
{
|
||||
//multiply a give value by the CORDIC shrink factor
|
||||
|
||||
abs(x);
|
||||
int64_t t = (x * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL;
|
||||
x = static_cast<SwFixed>(t >> 32);
|
||||
if (x < 0) x = -x;
|
||||
return x;
|
||||
auto s = abs(x);
|
||||
int64_t t = (s * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL;
|
||||
s = static_cast<SwFixed>(t >> 32);
|
||||
if (x < 0) s = -s;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,6 +138,47 @@ static void _polarize(SwPoint& pt)
|
|||
}
|
||||
|
||||
|
||||
static void _rotate(SwPoint& pt, SwFixed theta)
|
||||
{
|
||||
auto v = pt;
|
||||
|
||||
//Rotate inside [-PI/4, PI/4] sector
|
||||
while (theta < -ANGLE_PI4) {
|
||||
auto tmp = v.y;
|
||||
v.y = -v.x;
|
||||
v.x = tmp;
|
||||
theta += ANGLE_PI2;
|
||||
}
|
||||
|
||||
while (theta > ANGLE_PI4) {
|
||||
auto tmp = -v.y;
|
||||
v.y = v.x;
|
||||
v.x = tmp;
|
||||
theta -= ANGLE_PI2;
|
||||
}
|
||||
|
||||
auto atan = ATAN_TBL;
|
||||
uint32_t i;
|
||||
SwFixed j;
|
||||
|
||||
for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
|
||||
if (theta < 0) {
|
||||
auto tmp = v.x + ((v.y + j) >> i);
|
||||
v.y = v.y - ((v.x + j) >> i);
|
||||
v.x = tmp;
|
||||
theta += *atan++;
|
||||
}else {
|
||||
auto tmp = v.x - ((v.y + j) >> i);
|
||||
v.y = v.y + ((v.x + j) >> i);
|
||||
v.x = tmp;
|
||||
theta -= *atan++;
|
||||
}
|
||||
}
|
||||
|
||||
pt = v;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
@ -267,57 +307,26 @@ void mathRotate(SwPoint& pt, SwFixed angle)
|
|||
auto shift = _normalize(v);
|
||||
auto theta = angle;
|
||||
|
||||
//Rotate inside [-PI/4, PI/4] sector
|
||||
while (theta < -ANGLE_PI4) {
|
||||
auto tmp = v.y;
|
||||
v.y = -v.x;
|
||||
v.x = tmp;
|
||||
theta += ANGLE_PI2;
|
||||
}
|
||||
|
||||
while (theta > ANGLE_PI4) {
|
||||
auto tmp = -v.y;
|
||||
v.y = v.x;
|
||||
v.x = tmp;
|
||||
theta -= ANGLE_PI2;
|
||||
}
|
||||
|
||||
auto atan = ATAN_TBL;
|
||||
uint32_t i;
|
||||
SwFixed j;
|
||||
|
||||
for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
|
||||
if (theta < 0) {
|
||||
auto tmp = v.x + ((v.y + j) >> i);
|
||||
v.y = v.y - ((v.x + j) >> i);
|
||||
v.x = tmp;
|
||||
theta += *atan++;
|
||||
}else {
|
||||
auto tmp = v.x - ((v.y + j) >> i);
|
||||
v.y = v.y + ((v.x + j) >> i);
|
||||
v.x = tmp;
|
||||
theta -= *atan++;
|
||||
}
|
||||
}
|
||||
_rotate(v, theta);
|
||||
|
||||
v.x = _downscale(v.x);
|
||||
v.y = _downscale(v.y);
|
||||
|
||||
if (shift > 0) {
|
||||
auto half = static_cast<int32_t>(1L << (shift - 1));
|
||||
v.x = (v.x + half + SATURATE(v.x)) >> shift;
|
||||
v.y = (v.y + half + SATURATE(v.y)) >> shift;
|
||||
pt.x = (v.x + half + SATURATE(v.x)) >> shift;
|
||||
pt.y = (v.y + half + SATURATE(v.y)) >> shift;
|
||||
} else {
|
||||
shift = -shift;
|
||||
v.x = static_cast<SwCoord>((unsigned long)v.x << shift);
|
||||
v.y = static_cast<SwCoord>((unsigned long)v.y << shift);
|
||||
pt.x = static_cast<SwCoord>((unsigned long)v.x << shift);
|
||||
pt.y = static_cast<SwCoord>((unsigned long)v.y << shift);
|
||||
}
|
||||
}
|
||||
|
||||
SwFixed mathTan(SwFixed angle)
|
||||
{
|
||||
SwPoint v = {CORDIC_FACTOR >> 8, 0};
|
||||
mathRotate(v, angle);
|
||||
_rotate(v, angle);
|
||||
return mathDivide(v.y, v.x);
|
||||
}
|
||||
|
||||
|
@ -343,7 +352,7 @@ SwFixed mathSin(SwFixed angle)
|
|||
SwFixed mathCos(SwFixed angle)
|
||||
{
|
||||
SwPoint v = {CORDIC_FACTOR >> 8, 0};
|
||||
mathRotate(v, angle);
|
||||
_rotate(v, angle);
|
||||
return (v.x + 0x80L) >> 8;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,18 +76,13 @@ _rasterSolid(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov)
|
|||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
static bool
|
||||
_rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a)
|
||||
{
|
||||
SwRleData* rle = sdata.rle;
|
||||
if (!rle) return false;
|
||||
|
||||
auto span = rle->spans;
|
||||
auto stride = surface.stride;
|
||||
auto color = COLOR_ARGB_JOIN(r, g, b, a);
|
||||
|
||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||
assert(span);
|
||||
|
@ -103,4 +98,21 @@ bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
{
|
||||
return _rasterRle(surface, sdata.rle, COLOR_ARGB_JOIN(r, g, b, a), a);
|
||||
}
|
||||
|
||||
|
||||
bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
{
|
||||
return _rasterRle(surface, sdata.strokeRle, COLOR_ARGB_JOIN(r, g, b, a), a);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _TVG_SW_RASTER_CPP_ */
|
|
@ -63,16 +63,14 @@ bool SwRenderer::render(const Shape& shape, void *data)
|
|||
if (!sdata) return false;
|
||||
|
||||
size_t r, g, b, a;
|
||||
|
||||
shape.fill(&r, &g, &b, &a);
|
||||
if (a > 0) rasterShape(surface, *sdata, r, g, b, a);
|
||||
|
||||
size_t sa;
|
||||
shape.strokeColor(nullptr, nullptr, nullptr, &sa);
|
||||
shape.strokeColor(&r, &g, &b, &a);
|
||||
if (a > 0) rasterStroke(surface, *sdata, r, g, b, a);
|
||||
|
||||
//invisible?
|
||||
if (a == 0 && sa == 0) return false;
|
||||
|
||||
//TODO: Threading
|
||||
return rasterShape(surface, *sdata, r, g, b, a);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -612,9 +612,7 @@ static bool _decomposeOutline(RleWorker& rw)
|
|||
goto close;
|
||||
}
|
||||
}
|
||||
|
||||
//FIXME: Close the contour with a line segment?
|
||||
//_lineTo(rw, UPSCALE(outline->pts[first]));
|
||||
_lineTo(rw, UPSCALE(outline->pts[first]));
|
||||
close:
|
||||
first = last + 1;
|
||||
}
|
||||
|
@ -646,13 +644,12 @@ static bool _genRle(RleWorker& rw)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
SwRleData* rleRender(const SwShape& sdata, const SwSize& clip)
|
||||
SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip)
|
||||
{
|
||||
//Please adjust when you out of cell memory (default: 16384L)
|
||||
constexpr auto RENDER_POOL_SIZE = 166641L;
|
||||
constexpr auto BAND_SIZE = 40;
|
||||
|
||||
auto outline = sdata.outline;
|
||||
assert(outline);
|
||||
assert(outline->cntrs && outline->pts);
|
||||
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
|
||||
|
@ -671,11 +668,11 @@ SwRleData* rleRender(const SwShape& sdata, const SwSize& clip)
|
|||
rw.area = 0;
|
||||
rw.cover = 0;
|
||||
rw.invalid = true;
|
||||
rw.cellMin = sdata.bbox.min;
|
||||
rw.cellMax = sdata.bbox.max;
|
||||
rw.cellMin = bbox.min;
|
||||
rw.cellMax = bbox.max;
|
||||
rw.cellXCnt = rw.cellMax.x - rw.cellMin.x;
|
||||
rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
|
||||
rw.outline = outline;
|
||||
rw.outline = const_cast<SwOutline*>(outline);
|
||||
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
|
||||
rw.bandShoot = 0;
|
||||
rw.clip = clip;
|
||||
|
@ -770,12 +767,13 @@ error:
|
|||
}
|
||||
|
||||
|
||||
SwRleData* rleStrokeRender(const SwShape& sdata)
|
||||
void rleFree(SwRleData* rle)
|
||||
{
|
||||
auto stroke = sdata.stroke;
|
||||
assert(stroke);
|
||||
|
||||
return nullptr;
|
||||
if (!rle) return;
|
||||
if (rle->spans) free(rle->spans);
|
||||
free(rle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* _TVG_SW_RLE_H_ */
|
||||
|
|
|
@ -64,6 +64,17 @@ static void _growOutlinePoint(SwOutline& outline, uint32_t n)
|
|||
}
|
||||
|
||||
|
||||
static void _freeOutline(SwOutline* outline)
|
||||
{
|
||||
if (!outline) return;
|
||||
|
||||
if (outline->cntrs) free(outline->cntrs);
|
||||
if (outline->pts) free(outline->pts);
|
||||
if (outline->types) free(outline->types);
|
||||
free(outline);
|
||||
}
|
||||
|
||||
|
||||
static void _outlineEnd(SwOutline& outline)
|
||||
{
|
||||
_growOutlineContour(outline, 1);
|
||||
|
@ -153,23 +164,22 @@ static void _outlineClose(SwOutline& outline)
|
|||
}
|
||||
|
||||
|
||||
static void _initBBox(SwShape& sdata)
|
||||
static void _initBBox(SwBBox& bbox)
|
||||
{
|
||||
sdata.bbox.min.x = sdata.bbox.min.y = 0;
|
||||
sdata.bbox.max.x = sdata.bbox.max.y = 0;
|
||||
bbox.min.x = bbox.min.y = 0;
|
||||
bbox.max.x = bbox.max.y = 0;
|
||||
}
|
||||
|
||||
|
||||
static bool _updateBBox(SwShape& sdata)
|
||||
static bool _updateBBox(SwOutline* outline, SwBBox& bbox)
|
||||
{
|
||||
auto outline = sdata.outline;
|
||||
assert(outline);
|
||||
if (!outline) return false;
|
||||
|
||||
auto pt = outline->pts;
|
||||
assert(pt);
|
||||
|
||||
if (outline->ptsCnt <= 0) {
|
||||
_initBBox(sdata);
|
||||
_initBBox(bbox);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -187,10 +197,10 @@ static bool _updateBBox(SwShape& sdata)
|
|||
if (yMin > pt->y) yMin = pt->y;
|
||||
if (yMax < pt->y) yMax = pt->y;
|
||||
}
|
||||
sdata.bbox.min.x = xMin >> 6;
|
||||
sdata.bbox.max.x = (xMax + 63) >> 6;
|
||||
sdata.bbox.min.y = yMin >> 6;
|
||||
sdata.bbox.max.y = (yMax + 63) >> 6;
|
||||
bbox.min.x = xMin >> 6;
|
||||
bbox.max.x = (xMax + 63) >> 6;
|
||||
bbox.min.y = yMin >> 6;
|
||||
bbox.max.y = (yMax + 63) >> 6;
|
||||
|
||||
if (xMax - xMin < 1 || yMax - yMin < 1) return false;
|
||||
|
||||
|
@ -213,16 +223,6 @@ static bool _checkValid(SwShape& sdata, const SwSize& clip)
|
|||
}
|
||||
|
||||
|
||||
static void _deleteRle(SwShape& sdata)
|
||||
{
|
||||
if (!sdata.rle) return;
|
||||
if (sdata.rle->spans) free(sdata.rle->spans);
|
||||
free(sdata.rle);
|
||||
sdata.rle = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
@ -245,10 +245,10 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans
|
|||
|
||||
bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
|
||||
{
|
||||
if (!_updateBBox(sdata)) goto end;
|
||||
if (!_updateBBox(sdata.outline, sdata.bbox)) goto end;
|
||||
if (!_checkValid(sdata, clip)) goto end;
|
||||
|
||||
sdata.rle = rleRender(sdata, clip);
|
||||
sdata.rle = rleRender(sdata.outline, sdata.bbox, clip);
|
||||
|
||||
end:
|
||||
if (sdata.rle) return true;
|
||||
|
@ -259,12 +259,7 @@ end:
|
|||
void shapeDelOutline(SwShape& sdata)
|
||||
{
|
||||
auto outline = sdata.outline;
|
||||
if (!outline) return;
|
||||
|
||||
if (outline->cntrs) free(outline->cntrs);
|
||||
if (outline->pts) free(outline->pts);
|
||||
if (outline->types) free(outline->types);
|
||||
free(outline);
|
||||
_freeOutline(outline);
|
||||
sdata.outline = nullptr;
|
||||
}
|
||||
|
||||
|
@ -272,8 +267,9 @@ void shapeDelOutline(SwShape& sdata)
|
|||
void shapeReset(SwShape& sdata)
|
||||
{
|
||||
shapeDelOutline(sdata);
|
||||
_deleteRle(sdata);
|
||||
_initBBox(sdata);
|
||||
rleFree(sdata.rle);
|
||||
sdata.rle = nullptr;
|
||||
_initBBox(sdata.bbox);
|
||||
}
|
||||
|
||||
|
||||
|
@ -366,8 +362,13 @@ void shapeFree(SwShape* sdata)
|
|||
assert(sdata);
|
||||
|
||||
shapeDelOutline(*sdata);
|
||||
_deleteRle(*sdata);
|
||||
strokeFree(sdata->stroke);
|
||||
rleFree(sdata->rle);
|
||||
|
||||
if (sdata->stroke) {
|
||||
rleFree(sdata->strokeRle);
|
||||
strokeFree(sdata->stroke);
|
||||
}
|
||||
|
||||
free(sdata);
|
||||
}
|
||||
|
||||
|
@ -377,8 +378,9 @@ void shapeResetStroke(const Shape& shape, SwShape& sdata)
|
|||
if (!sdata.stroke) sdata.stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
|
||||
auto stroke = sdata.stroke;
|
||||
assert(stroke);
|
||||
|
||||
strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin());
|
||||
rleFree(sdata.strokeRle);
|
||||
sdata.strokeRle = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -392,6 +394,16 @@ bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
|
|||
|
||||
if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false;
|
||||
|
||||
auto outline = strokeExportOutline(*sdata.stroke);
|
||||
if (!outline) return false;
|
||||
|
||||
SwBBox bbox;
|
||||
_updateBBox(outline, bbox);
|
||||
|
||||
sdata.strokeRle = rleRender(outline, bbox, clip);
|
||||
|
||||
_freeOutline(outline);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
static constexpr auto SW_STROKE_TAG_ON = 1;
|
||||
static constexpr auto SW_STROKE_TAG_POINT = 1;
|
||||
static constexpr auto SW_STROKE_TAG_CUBIC = 2;
|
||||
static constexpr auto SW_STROKE_TAG_BEGIN = 4;
|
||||
static constexpr auto SW_STROKE_TAG_END = 8;
|
||||
|
@ -36,6 +36,8 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s)
|
|||
|
||||
static void _growBorder(SwStrokeBorder* border, uint32_t newPts)
|
||||
{
|
||||
assert(border);
|
||||
|
||||
auto maxOld = border->maxPts;
|
||||
auto maxNew = border->ptsCnt + newPts;
|
||||
|
||||
|
@ -53,8 +55,6 @@ static void _growBorder(SwStrokeBorder* border, uint32_t newPts)
|
|||
assert(border->tags);
|
||||
|
||||
border->maxPts = maxCur;
|
||||
|
||||
printf("realloc border!!! (%u => %u)\n", maxOld, maxCur);
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,7 +111,7 @@ static void _borderClose(SwStrokeBorder* border, bool reverse)
|
|||
|
||||
static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
|
||||
{
|
||||
assert(border->start >= 0);
|
||||
assert(border && border->start >= 0);
|
||||
|
||||
_growBorder(border, 3);
|
||||
|
||||
|
@ -124,9 +124,10 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl
|
|||
|
||||
tag[0] = SW_STROKE_TAG_CUBIC;
|
||||
tag[1] = SW_STROKE_TAG_CUBIC;
|
||||
tag[2] = SW_STROKE_TAG_ON;
|
||||
tag[2] = SW_STROKE_TAG_POINT;
|
||||
|
||||
border->ptsCnt += 3;
|
||||
|
||||
border->movable = false;
|
||||
}
|
||||
|
||||
|
@ -188,13 +189,13 @@ static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable)
|
|||
//move last point
|
||||
border->pts[border->ptsCnt - 1] = to;
|
||||
} else {
|
||||
|
||||
//don't add zero-length line_to
|
||||
auto diff = border->pts[border->ptsCnt - 1] - to;
|
||||
if (border->ptsCnt > 0 && diff.small()) return;
|
||||
if (border->ptsCnt > 0 && (border->pts[border->ptsCnt - 1] - to).small()) return;
|
||||
|
||||
_growBorder(border, 1);
|
||||
border->pts[border->ptsCnt] = to;
|
||||
border->tags[border->ptsCnt] = SW_STROKE_TAG_ON;
|
||||
border->tags[border->ptsCnt] = SW_STROKE_TAG_POINT;
|
||||
border->ptsCnt += 1;
|
||||
}
|
||||
|
||||
|
@ -207,8 +208,7 @@ static void _borderMoveTo(SwStrokeBorder* border, SwPoint& to)
|
|||
assert(border);
|
||||
|
||||
//close current open path if any?
|
||||
if (border->start >= 0)
|
||||
_borderClose(border, false);
|
||||
if (border->start >= 0) _borderClose(border, false);
|
||||
|
||||
border->start = border->ptsCnt;
|
||||
border->movable = false;
|
||||
|
@ -318,8 +318,11 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength)
|
|||
border->movable = false;
|
||||
} else {
|
||||
//compute median angle
|
||||
delta = {mathDivide(stroke.width, mathCos(theta)), 0};
|
||||
mathRotate(delta, stroke.angleIn + theta + rotate);
|
||||
auto phi = stroke.angleIn + theta;
|
||||
auto thcos = mathCos(theta);
|
||||
auto length = mathDivide(stroke.width, thcos);
|
||||
delta = {length, 0};
|
||||
mathRotate(delta, phi + rotate);
|
||||
delta += stroke.center;
|
||||
}
|
||||
|
||||
|
@ -652,11 +655,9 @@ static void _addReverseLeft(SwStroke& stroke, bool opened)
|
|||
|
||||
static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened)
|
||||
{
|
||||
cout << "stroke opened? = " << opened << endl;
|
||||
|
||||
/* We cannot process the first point because there is not enought
|
||||
information regarding its corner/cap. Later, it will be processed
|
||||
in the _strokeEndSubPath() */
|
||||
in the _endSubPath() */
|
||||
|
||||
stroke.firstPt = true;
|
||||
stroke.center = to;
|
||||
|
@ -712,13 +713,13 @@ static void _endSubPath(SwStroke& stroke)
|
|||
if (turn != 0) {
|
||||
|
||||
//when we turn to the right, the inside is 0
|
||||
auto inside = 0;
|
||||
int32_t inside = 0;
|
||||
|
||||
//otherwise, the inside is 1
|
||||
if (turn < 0) inside = 1;
|
||||
|
||||
_inside(stroke, inside, stroke.subPathLineLength); //inside
|
||||
_inside(stroke, 1 - inside, stroke.subPathLineLength); //outside
|
||||
_outside(stroke, 1 - inside, stroke.subPathLineLength); //outside
|
||||
}
|
||||
|
||||
_borderClose(stroke.borders + 0, false);
|
||||
|
@ -727,14 +728,81 @@ static void _endSubPath(SwStroke& stroke)
|
|||
}
|
||||
|
||||
|
||||
static void _deleteRle(SwStroke& stroke)
|
||||
static void _getCounts(SwStrokeBorder* border, uint32_t& ptsCnt, uint32_t& cntrsCnt)
|
||||
{
|
||||
if (!stroke.rle) return;
|
||||
if (stroke.rle->spans) free(stroke.rle->spans);
|
||||
free(stroke.rle);
|
||||
stroke.rle = nullptr;
|
||||
assert(border);
|
||||
|
||||
auto count = border->ptsCnt;
|
||||
auto tags = border->tags;
|
||||
uint32_t _ptsCnt = 0;
|
||||
uint32_t _cntrsCnt = 0;
|
||||
bool inCntr = false;
|
||||
|
||||
while (count > 0) {
|
||||
|
||||
if (tags[0] & SW_STROKE_TAG_BEGIN) {
|
||||
if (inCntr) goto fail;
|
||||
inCntr = true;
|
||||
} else if (!inCntr) goto fail;
|
||||
|
||||
if (tags[0] & SW_STROKE_TAG_END) {
|
||||
inCntr = false;
|
||||
++_cntrsCnt;
|
||||
}
|
||||
--count;
|
||||
++_ptsCnt;
|
||||
++tags;
|
||||
}
|
||||
|
||||
if (inCntr) goto fail;
|
||||
border->valid = true;
|
||||
ptsCnt = _ptsCnt;
|
||||
cntrsCnt = _cntrsCnt;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
ptsCnt = 0;
|
||||
cntrsCnt = 0;
|
||||
}
|
||||
|
||||
|
||||
static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t side)
|
||||
{
|
||||
auto border = stroke.borders + side;
|
||||
assert(border);
|
||||
|
||||
if (!border->valid) return;
|
||||
|
||||
memcpy(outline->pts + outline->ptsCnt, border->pts, border->ptsCnt * sizeof(SwPoint));
|
||||
|
||||
auto cnt = border->ptsCnt;
|
||||
auto src = border->tags;
|
||||
auto tags = outline->types + outline->ptsCnt;
|
||||
auto cntrs = outline->cntrs + outline->cntrsCnt;
|
||||
uint16_t idx = outline->ptsCnt;
|
||||
|
||||
while (cnt > 0) {
|
||||
|
||||
if (*src & SW_STROKE_TAG_POINT) *tags = SW_CURVE_TYPE_POINT;
|
||||
else if (*src & SW_STROKE_TAG_CUBIC) *tags = SW_CURVE_TYPE_CUBIC;
|
||||
else cout << "what type of stroke outline??" << endl;
|
||||
|
||||
if (*src & SW_STROKE_TAG_END) {
|
||||
*cntrs = idx;
|
||||
++cntrs;
|
||||
++outline->cntrsCnt;
|
||||
}
|
||||
|
||||
++src;
|
||||
++tags;
|
||||
++idx;
|
||||
--cnt;
|
||||
}
|
||||
outline->ptsCnt = outline->ptsCnt + border->ptsCnt;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
@ -742,16 +810,20 @@ static void _deleteRle(SwStroke& stroke)
|
|||
void strokeFree(SwStroke* stroke)
|
||||
{
|
||||
if (!stroke) return;
|
||||
_deleteRle(*stroke);
|
||||
|
||||
//free borders
|
||||
if (stroke->borders[0].pts) free(stroke->borders[0].pts);
|
||||
if (stroke->borders[0].tags) free(stroke->borders[0].tags);
|
||||
if (stroke->borders[1].pts) free(stroke->borders[1].pts);
|
||||
if (stroke->borders[1].tags) free(stroke->borders[1].tags);
|
||||
|
||||
free(stroke);
|
||||
}
|
||||
|
||||
|
||||
void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join)
|
||||
{
|
||||
_deleteRle(stroke);
|
||||
|
||||
stroke.width = TO_SWCOORD(width * 0.5f);
|
||||
stroke.width = TO_SWCOORD(width * 0.5);
|
||||
stroke.cap = cap;
|
||||
|
||||
//Save line join: it can be temporarily changed when stroking curves...
|
||||
|
@ -826,4 +898,33 @@ bool strokeParseOutline(SwStroke& stroke, SwOutline& outline)
|
|||
}
|
||||
|
||||
|
||||
SwOutline* strokeExportOutline(SwStroke& stroke)
|
||||
{
|
||||
uint32_t count1, count2, count3, count4;
|
||||
|
||||
_getCounts(stroke.borders + 0, count1, count2);
|
||||
_getCounts(stroke.borders + 1, count3, count4);
|
||||
|
||||
auto ptsCnt = count1 + count3;
|
||||
auto cntrsCnt = count2 + count4;
|
||||
|
||||
auto outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
|
||||
assert(outline);
|
||||
|
||||
outline->pts = static_cast<SwPoint*>(malloc(sizeof(SwPoint) * ptsCnt));
|
||||
assert(outline->pts);
|
||||
|
||||
outline->types = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * ptsCnt));
|
||||
assert(outline->types);
|
||||
|
||||
outline->cntrs = static_cast<uint32_t*>(malloc(sizeof(uint32_t) * cntrsCnt));
|
||||
assert(outline->cntrs);
|
||||
|
||||
_exportBorderOutline(stroke, outline, 0); //left
|
||||
_exportBorderOutline(stroke, outline, 1); //right
|
||||
|
||||
return outline;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _TVG_SW_STROKER_H_ */
|
||||
|
|
|
@ -23,11 +23,10 @@ void tvgtest()
|
|||
|
||||
//Prepare a Shape (Rectangle + Rectangle + Circle + Circle)
|
||||
auto shape1 = tvg::Shape::gen();
|
||||
shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius
|
||||
shape1->appendRect(50, 50, 200, 200, 0); //x, y, w, h, cornerRadius
|
||||
shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius
|
||||
shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH
|
||||
shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH
|
||||
shape1->fill(255, 255, 0, 255); //r, g, b, a
|
||||
shape1->fill(50, 50, 50, 255); //r, g, b, a
|
||||
|
||||
//Stroke Style
|
||||
shape1->stroke(255, 255, 255, 255); //color: r, g, b, a
|
||||
|
|
Loading…
Add table
Reference in a new issue