From 1686af7643cdfbe02859ab6323396f439d228756 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 1 Jun 2020 20:27:43 +0900 Subject: [PATCH] sw_engine: implement stroke rle part Current stroke fails to merged shapes case... you can test with testStroke example Change-Id: I488af728949cba1d01b88723eb1dc4c49bac6c9b --- src/lib/sw_engine/tvgSwCommon.h | 11 +- src/lib/sw_engine/tvgSwMath.cpp | 101 +++++++++--------- src/lib/sw_engine/tvgSwRaster.cpp | 26 +++-- src/lib/sw_engine/tvgSwRenderer.cpp | 12 +-- src/lib/sw_engine/tvgSwRle.cpp | 24 ++--- src/lib/sw_engine/tvgSwShape.cpp | 80 ++++++++------- src/lib/sw_engine/tvgSwStroke.cpp | 153 +++++++++++++++++++++++----- test/testStroke.cpp | 5 +- 8 files changed, 271 insertions(+), 141 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index b942ca18..cfb15bdf 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -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_ */ diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 919fe1ed..d2fcc4ee 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -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(CORDIC_FACTOR)) + 0x100000000UL; - x = static_cast(t >> 32); - if (x < 0) x = -x; - return x; + auto s = abs(x); + int64_t t = (s * static_cast(CORDIC_FACTOR)) + 0x100000000UL; + s = static_cast(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(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((unsigned long)v.x << shift); - v.y = static_cast((unsigned long)v.y << shift); + pt.x = static_cast((unsigned long)v.x << shift); + pt.y = static_cast((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; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index ba7c6a35..78d507b5 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -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_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index bf97c9b3..3ec882e2 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.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; } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 7bbc3265..b22b2331 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -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(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_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index f1ab06e0..e8e19965 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -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(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; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index a0a25738..8477d7cd 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -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(calloc(1, sizeof(SwOutline))); + assert(outline); + + outline->pts = static_cast(malloc(sizeof(SwPoint) * ptsCnt)); + assert(outline->pts); + + outline->types = static_cast(malloc(sizeof(uint8_t) * ptsCnt)); + assert(outline->types); + + outline->cntrs = static_cast(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_ */ diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 1f865d68..d978b6fc 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -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