sw_engine: implement line and curve raster

Change-Id: I22a77892544cd510cfe646aee60093cebb848806
This commit is contained in:
Hermet Park 2020-04-18 13:48:37 +09:00
parent de242b018b
commit c8d800f6c6
13 changed files with 461 additions and 138 deletions

View file

@ -73,6 +73,7 @@ class TIZENVG_EXPORT PaintNode
{
public:
virtual ~PaintNode() {}
virtual int dispose(RasterMethod* engine) = 0;
virtual int update(RasterMethod* engine) = 0;
};
@ -90,6 +91,7 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode
public:
~ShapeNode();
int dispose(RasterMethod* engine) noexcept override;
int update(RasterMethod* engine) noexcept override;
int clear() noexcept;
@ -121,6 +123,7 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode
public:
~SceneNode();
int dispose(RasterMethod* engine) noexcept override;
int update(RasterMethod* engine) noexcept override;
int push(std::unique_ptr<ShapeNode> shape) noexcept;

View file

@ -20,14 +20,29 @@
#include "tvgCommon.h"
#include "tvgGlEngine.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
static GlEngine* pInst = nullptr;
static RasterMethodInit engineInit;
struct GlShape
{
//TODO:
};
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
void* GlEngine::dispose(const ShapeNode& shape, void *data)
{
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) return nullptr;
free(sdata);
return nullptr;
}
void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
{
@ -37,35 +52,37 @@ void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
sdata = static_cast<GlShape*>(calloc(1, sizeof(GlShape)));
assert(sdata);
}
return sdata;
}
int GlEngine::init()
{
if (pInst) return -1;
pInst = new GlEngine();
assert(pInst);
return 0;
return RasterMethodInit::init(engineInit, new GlEngine);
}
int GlEngine::term()
{
if (!pInst) return -1;
cout << "GlEngine(" << pInst << ") destroyed!" << endl;
delete(pInst);
pInst = nullptr;
return 0;
return RasterMethodInit::term(engineInit);
}
size_t GlEngine::unref()
{
return RasterMethodInit::unref(engineInit);
}
size_t GlEngine::ref()
{
return RasterMethodInit::ref(engineInit);
}
GlEngine* GlEngine::inst()
{
assert(pInst);
return pInst;
return dynamic_cast<GlEngine*>(RasterMethodInit::inst(engineInit));
}

View file

@ -24,6 +24,10 @@ class GlEngine : public RasterMethod
{
public:
void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
void* dispose(const ShapeNode& shape, void *data) override;
size_t ref() override;
size_t unref() override;
static GlEngine* inst();
static int init();
static int term();

View file

@ -23,6 +23,8 @@ using namespace tvg;
constexpr auto SW_CURVE_TAG_ON = 1;
constexpr auto SW_CURVE_TAG_CUBIC = 2;
constexpr auto SW_OUTLINE_FILL_WINDING = 0;
constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1;
using SwCoord = signed long;
@ -56,43 +58,41 @@ struct SwOutline
size_t ptsCnt; //number of points in the glyph
size_t reservedPtsCnt;
char* tags; //the points flags
size_t flags; //outline masks
uint8_t fillMode; //outline fill mode
};
struct SwSpan
{
size_t x;
size_t y;
size_t len;
uint16_t x, y;
uint16_t len;
uint8_t coverage;
};
struct SwRleData
{
SwSpan *spans;
size_t alloc;
size_t size;
SwSpan *spans;
};
struct SwBBox
{
SwPoint min;
SwPoint max;
SwPoint min, max;
};
struct SwShape
{
SwOutline* outline;
SwRleData rle;
SwRleData* rle;
SwBBox bbox;
};
void shapeReset(SwShape& sdata);
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata);
void shapeDelRle(const ShapeNode& shape, SwShape& sdata);
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
bool rleRender(SwShape& sdata);
SwRleData* rleRender(const SwShape& sdata);
#endif /* _TVG_SW_COMMON_H_ */

View file

@ -24,13 +24,22 @@
/* Internal Class Implementation */
/************************************************************************/
static SwEngine* pInst = nullptr;
static RasterMethodInit engineInit;
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
void* SwEngine::dispose(const ShapeNode& shape, void *data)
{
SwShape* sdata = static_cast<SwShape*>(data);
if (!sdata) return nullptr;
shapeReset(*sdata);
free(sdata);
return nullptr;
}
void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
{
//prepare shape data
@ -48,11 +57,11 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
if (alpha == 0) return sdata;
if (flags & UpdateFlag::Path) {
shapeReset(*sdata);
if (!shapeGenOutline(shape, *sdata)) return sdata;
//TODO: From below sequence starts threading?
if (!shapeTransformOutline(shape, *sdata)) return sdata;
if (!shapeGenRle(shape, *sdata)) return sdata;
shapeDelOutline(shape, *sdata);
}
return sdata;
@ -61,28 +70,31 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
int SwEngine::init()
{
if (pInst) return -1;
pInst = new SwEngine();
assert(pInst);
return 0;
return RasterMethodInit::init(engineInit, new SwEngine);
}
int SwEngine::term()
{
if (!pInst) return -1;
cout << "SwEngine(" << pInst << ") destroyed!" << endl;
delete(pInst);
pInst = nullptr;
return 0;
return RasterMethodInit::term(engineInit);
}
size_t SwEngine::unref()
{
return RasterMethodInit::unref(engineInit);
}
size_t SwEngine::ref()
{
return RasterMethodInit::ref(engineInit);
}
SwEngine* SwEngine::inst()
{
assert(pInst);
return pInst;
return dynamic_cast<SwEngine*>(RasterMethodInit::inst(engineInit));
}

View file

@ -21,6 +21,10 @@ class SwEngine : public RasterMethod
{
public:
void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
void* dispose(const ShapeNode& shape, void *data) override;
size_t ref() override;
size_t unref() override;
static SwEngine* inst();
static int init();
static int term();

View file

@ -19,6 +19,7 @@
#include <setjmp.h>
#include <limits.h>
#include <memory.h>
#include "tvgSwCommon.h"
/************************************************************************/
@ -29,7 +30,6 @@ constexpr auto MAX_SPANS = 256;
constexpr auto PIXEL_BITS = 8; //must be at least 6 bits!
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
using Area = long;
struct Band
@ -47,6 +47,8 @@ struct Cell
struct RleWorker
{
SwRleData* rle;
SwPoint cellPos;
SwPoint cellMin;
SwPoint cellMax;
@ -104,6 +106,12 @@ static inline SwPoint TRUNC(const SwPoint& pt)
}
static inline SwCoord TRUNC(const SwCoord x)
{
return x >> PIXEL_BITS;
}
static inline SwPoint SUBPIXELS(const SwPoint& pt)
{
return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS};
@ -115,20 +123,105 @@ static inline SwCoord SUBPIXELS(const SwCoord x)
return (x << PIXEL_BITS);
}
static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
/*
* Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
* algorithm. We use alpha = 1, beta = 3/8, giving us results with a
* largest error less than 7% compared to the exact value.
*/
static inline SwCoord HYPOT(SwPoint pt)
{
//TODO:
if (pt.x < 0) pt.x = -pt.x;
if (pt.y < 0) pt.y = -pt.y;
return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3)));
}
static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count)
{
assert(rle && spans);
auto newSize = rle->size + count;
/* allocate enough memory for new spans */
/* alloc is required to prevent free and reallocation */
/* when the rle needs to be regenerated because of attribute change. */
if (rle->alloc < newSize) {
rle->spans = static_cast<SwSpan*>(realloc(rle->spans, newSize * sizeof(SwSpan)));
assert(rle->spans);
rle->alloc = newSize;
}
//copy the new spans to the allocated memory
SwSpan* lastSpan = rle->spans + rle->size;
assert(lastSpan);
memcpy(lastSpan, spans, count * sizeof(SwSpan));
rle->size = newSize;
}
static void genSpan(RleWorker& rw)
static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
{
//TODO:
/* compute the coverage line's coverage, depending on the outline fill rule */
/* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
auto coverage = static_cast<int>(area >> (PIXEL_BITS * 2 + 1 - 8)); //range 0 - 256
if (coverage < 0) coverage = -coverage;
if (rw.outline->fillMode == SW_OUTLINE_FILL_EVEN_ODD) {
coverage &= 511;
if (coverage > 256) coverage = 512 - coverage;
else if (coverage == 256) coverage = 255;
} else {
//normal non-zero winding rule
if (coverage >= 256) coverage = 255;
}
x += rw.cellMin.x;
y += rw.cellMin.y;
//span has ushort coordinates. check limit overflow
if (x >= SHRT_MAX) {
cout << "x(" << x << ") coordinate overflow!" << endl;
x = SHRT_MAX;
}
if (y >= SHRT_MAX) {
cout << "y(" << y << ") coordinate overflow!" << endl;
y = SHRT_MAX;
}
if (coverage) {
auto count = rw.spansCnt;
auto span = rw.spans + count - 1;
assert(span);
//see whether we can add this span to the current list
if ((count > 0) && (rw.ySpan == y) &&
(span->x + span->len == x) && (span->coverage == coverage)) {
span->len = span->len + acount;
return;
}
if (count >= MAX_SPANS) {
_genSpan(rw.rle, rw.spans, count);
rw.spansCnt = 0;
span = rw.spans;
assert(span);
} else {
++span;
assert(span);
}
//add a span to the current list
span->x = x;
span->y = y;
span->len = acount;
span->coverage = coverage;
++rw.spansCnt;
}
}
static void sweep(RleWorker& rw)
static void _sweep(RleWorker& rw)
{
if (rw.cellsCnt == 0) return;
@ -142,26 +235,26 @@ static void sweep(RleWorker& rw)
while (cell) {
horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x);
_horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x);
cover += cell->cover;
auto area = cover * (ONE_PIXEL * 2) - cell->area;
if (area != 0 && cell->x >= 0)
horizLine(rw, cell->x, y, area, 1);
_horizLine(rw, cell->x, y, area, 1);
x = cell->x + 1;
cell = cell->next;
}
if (cover != 0)
horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
_horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
}
if (rw.spansCnt > 0) genSpan(rw);
if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt);
}
static Cell* findCell(RleWorker& rw)
static Cell* _findCell(RleWorker& rw)
{
auto x = rw.cellPos.x;
if (x > rw.cellXCnt) x = rw.cellXCnt;
@ -190,17 +283,18 @@ static Cell* findCell(RleWorker& rw)
}
static void recordCell(RleWorker& rw)
static void _recordCell(RleWorker& rw)
{
if (rw.area | rw.cover) {
auto cell = findCell(rw);
auto cell = _findCell(rw);
assert(cell);
cell->area += rw.area;
cell->cover += rw.cover;
}
}
static void setCell(RleWorker& rw, SwPoint pos)
static void _setCell(RleWorker& rw, SwPoint pos)
{
/* Move the cell pointer to a new position. We set the `invalid' */
/* flag to indicate that the cell isn't part of those we're interested */
@ -222,7 +316,7 @@ static void setCell(RleWorker& rw, SwPoint pos)
//Are we moving to a different cell?
if (pos != rw.cellPos) {
if (!rw.invalid) recordCell(rw);
if (!rw.invalid) _recordCell(rw);
}
rw.area = 0;
@ -232,7 +326,7 @@ static void setCell(RleWorker& rw, SwPoint pos)
}
static void startCell(RleWorker& rw, SwPoint pos)
static void _startCell(RleWorker& rw, SwPoint pos)
{
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x;
@ -242,23 +336,23 @@ static void startCell(RleWorker& rw, SwPoint pos)
rw.cellPos = pos - rw.cellMin;
rw.invalid = false;
setCell(rw, pos);
_setCell(rw, pos);
}
static void moveTo(RleWorker& rw, const SwPoint& to)
static void _moveTo(RleWorker& rw, const SwPoint& to)
{
//record current cell, if any */
if (!rw.invalid) recordCell(rw);
if (!rw.invalid) _recordCell(rw);
//start to a new position
startCell(rw, TRUNC(to));
_startCell(rw, TRUNC(to));
rw.pos = to;
}
static void lineTo(RleWorker& rw, const SwPoint& to)
static void _lineTo(RleWorker& rw, const SwPoint& to)
{
#define SW_UDIV(a, b) \
static_cast<SwCoord>(((unsigned long)(a) * (unsigned long)(b)) >> \
@ -284,7 +378,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
//any horizontal line
} else if (diff.y == 0) {
e1.x = e2.x;
setCell(rw, e1);
_setCell(rw, e1);
} else if (diff.x == 0) {
//vertical line up
if (diff.y > 0) {
@ -294,7 +388,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
rw.area += (f2.y - f1.y) * f1.x * 2;
f1.y = 0;
++e1.y;
setCell(rw, e1);
_setCell(rw, e1);
} while(e1.y != e2.y);
//vertical line down
} else {
@ -304,7 +398,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
rw.area += (f2.y - f1.y) * f1.x * 2;
f1.y = ONE_PIXEL;
--e1.y;
setCell(rw, e1);
_setCell(rw, e1);
} while(e1.y != e2.y);
}
//any other line
@ -357,7 +451,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
--e1.y;
}
setCell(rw, e1);
_setCell(rw, e1);
} while(e1 != e2);
}
@ -369,21 +463,111 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
}
static bool renderCubic(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
static void _splitCubic(SwPoint* base)
{
return true;
assert(base);
SwCoord a, b, c, d;
base[6].x = base[3].x;
c = base[1].x;
d = base[2].x;
base[1].x = a = (base[0].x + c) / 2;
base[5].x = b = (base[3].x + d) / 2;
c = (c + d) / 2;
base[2].x = a = (a + c) / 2;
base[4].x = b = (b + c) / 2;
base[3].x = (a + b) / 2;
base[6].y = base[3].y;
c = base[1].y;
d = base[2].y;
base[1].y = a = (base[0].y + c) / 2;
base[5].y = b = (base[3].y + d) / 2;
c = (c + d) / 2;
base[2].y = a = (a + c) / 2;
base[4].y = b = (b + c) / 2;
base[3].y = (a + b) / 2;
}
static bool cubicTo(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to)
{
return renderCubic(rw, ctrl1, ctrl2, to);
auto arc = rw.bezStack;
assert(arc);
arc[0] = to;
arc[1] = ctrl2;
arc[2] = ctrl1;
arc[3] = rw.pos;
//Short-cut the arc that crosses the current band
auto min = arc[0].y;
auto max = arc[0].y;
SwCoord y;
for (auto i = 1; i < 4; ++i) {
y = arc[i].y;
if (y < min) min = y;
if (y > max) max = y;
}
if (TRUNC(min) >= rw.cellMax.y || TRUNC(max) < rw.cellMin.y) goto draw;
/* Decide whether to split or draw. See `Rapid Termination */
/* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
/* F. Hain, at */
/* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
while (true) {
{
//diff is the P0 - P3 chord vector
auto diff = arc[3] - arc[0];
auto L = HYPOT(diff);
//avoid possible arithmetic overflow below by splitting
if (L > SHRT_MAX) goto split;
//max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1)
auto sLimit = L * (ONE_PIXEL / 6);
auto diff1 = arc[1] - arc[0];
auto s = diff.y * diff1.x - diff.x * diff1.y;
if (s < 0) s = -s;
if (s > sLimit) goto split;
//s is L * the perpendicular distance from P2 to the line P0 - P3
auto diff2 = arc[2] - arc[0];
s = diff.y * diff2.x - diff.x * diff2.y;
if (s < 0) s = -s;
if (s > sLimit) goto split;
/* Split super curvy segments where the off points are so far
from the chord that the angles P0-P1-P3 or P0-P2-P3 become
acute as detected by appropriate dot products */
if (diff1.x * (diff1.x - diff.x) + diff1.y * (diff1.y - diff.y) > 0 ||
diff2.x * (diff2.x - diff.x) + diff2.y * (diff2.y - diff.y) > 0)
goto split;
//no reason to split
goto draw;
}
split:
_splitCubic(arc);
arc += 3;
continue;
draw:
_lineTo(rw, arc[0]);
if (arc == rw.bezStack) return;
arc -= 3;
}
}
static bool decomposeOutline(RleWorker& rw)
static bool _decomposeOutline(RleWorker& rw)
{
// printf("decomposOutline\n");
auto outline = rw.outline;
assert(outline);
@ -402,7 +586,7 @@ static bool decomposeOutline(RleWorker& rw)
/* A contour cannot start with a cubic control point! */
if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline;
moveTo(rw, UPSCALE(outline->pts[first]));
_moveTo(rw, UPSCALE(outline->pts[first]));
while (pt < limit) {
assert(++pt);
@ -410,7 +594,7 @@ static bool decomposeOutline(RleWorker& rw)
//emit a single line_to
if (tags[0] == SW_CURVE_TAG_ON) {
lineTo(rw, UPSCALE(*pt));
_lineTo(rw, UPSCALE(*pt));
//tag cubic
} else {
if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
@ -420,10 +604,10 @@ static bool decomposeOutline(RleWorker& rw)
tags += 2;
if (pt <= limit) {
if (!cubicTo(rw, pt[-2], pt[-1], pt[0])) return false;
_cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0]));
continue;
}
if (!cubicTo(rw, pt[-2], pt[-1], outline->pts[first])) return false;
_cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(outline->pts[first]));
goto close;
}
}
@ -442,13 +626,13 @@ invalid_outline:
}
static bool genRle(RleWorker& rw)
static bool _genRle(RleWorker& rw)
{
bool ret = false;
if (setjmp(rw.jmpBuf) == 0) {
ret = decomposeOutline(rw);
if (!rw.invalid) recordCell(rw);
ret = _decomposeOutline(rw);
if (!rw.invalid) _recordCell(rw);
} else {
cout << "Memory Overflow" << endl;
}
@ -460,7 +644,7 @@ static bool genRle(RleWorker& rw)
/* External Class Implementation */
/************************************************************************/
bool rleRender(SwShape& sdata)
SwRleData* rleRender(const SwShape& sdata)
{
constexpr auto RENDER_POOL_SIZE = 16384L;
constexpr auto BAND_SIZE = 39;
@ -468,7 +652,7 @@ bool rleRender(SwShape& sdata)
auto outline = sdata.outline;
assert(outline);
if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false;
if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr;
assert(outline->cntrs && outline->pts);
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
@ -494,6 +678,9 @@ bool rleRender(SwShape& sdata)
rw.outline = outline;
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
rw.bandShoot = 0;
rw.rle = reinterpret_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
assert(rw.rle);
//printf("bufferSize = %d, bbox(%f %f %f %f), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize);
//Generate RLE
@ -547,9 +734,9 @@ bool rleRender(SwShape& sdata)
rw.cellMax.y = band->max;
rw.cellYCnt = band->max - band->min;
if (!genRle(rw)) return -1;
if (!_genRle(rw)) goto error;
sweep(rw);
_sweep(rw);
--band;
continue;
@ -561,7 +748,7 @@ bool rleRender(SwShape& sdata)
/* This is too complex for a single scanline; there must
be some problems */
if (middle == bottom) return -1;
if (middle == bottom) goto error;
if (bottom - top >= rw.bandSize) ++rw.bandShoot;
@ -576,7 +763,12 @@ bool rleRender(SwShape& sdata)
if (rw.bandShoot > 8 && rw.bandSize > 16)
rw.bandSize = (rw.bandSize >> 1);
return true;
return rw.rle;
error:
free(rw.rle);
rw.rle = nullptr;
return nullptr;
}
#endif /* _TVG_SW_RLE_H_ */

View file

@ -29,7 +29,7 @@ static inline SwPoint TO_SWPOINT(const Point* pt)
}
static void growOutlineContour(SwOutline& outline, size_t n)
static void _growOutlineContour(SwOutline& outline, size_t n)
{
if (n == 0) {
free(outline.cntrs);
@ -40,14 +40,14 @@ static void growOutlineContour(SwOutline& outline, size_t n)
}
if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
//cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
outline.reservedCntrsCnt = n;
outline.cntrs = static_cast<size_t*>(realloc(outline.cntrs, n * sizeof(size_t)));
assert(outline.cntrs);
}
static void growOutlinePoint(SwOutline& outline, size_t n)
static void _growOutlinePoint(SwOutline& outline, size_t n)
{
if (n == 0) {
free(outline.pts);
@ -61,7 +61,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
//cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
outline.reservedPtsCnt = n;
outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
assert(outline.pts);
@ -70,9 +70,9 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
}
static void outlineEnd(SwOutline& outline)
static void _outlineEnd(SwOutline& outline)
{
growOutlineContour(outline, 1);
_growOutlineContour(outline, 1);
if (outline.ptsCnt > 0) {
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
++outline.cntrsCnt;
@ -80,17 +80,17 @@ static void outlineEnd(SwOutline& outline)
}
static void outlineMoveTo(SwOutline& outline, const Point* to)
static void _outlineMoveTo(SwOutline& outline, const Point* to)
{
assert(to);
growOutlinePoint(outline, 1);
_growOutlinePoint(outline, 1);
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
if (outline.ptsCnt > 0) {
growOutlineContour(outline, 1);
_growOutlineContour(outline, 1);
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
++outline.cntrsCnt;
}
@ -99,11 +99,11 @@ static void outlineMoveTo(SwOutline& outline, const Point* to)
}
static void outlineLineTo(SwOutline& outline, const Point* to)
static void _outlineLineTo(SwOutline& outline, const Point* to)
{
assert(to);
growOutlinePoint(outline, 1);
_growOutlinePoint(outline, 1);
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
@ -112,11 +112,11 @@ static void outlineLineTo(SwOutline& outline, const Point* to)
}
static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
{
assert(ctrl1 && ctrl2 && to);
growOutlinePoint(outline, 3);
_growOutlinePoint(outline, 3);
outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
@ -132,7 +132,7 @@ static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point*
}
static bool outlineClose(SwOutline& outline)
static bool _outlineClose(SwOutline& outline)
{
size_t i = 0;
@ -146,7 +146,7 @@ static bool outlineClose(SwOutline& outline)
if (outline.ptsCnt == i) return false;
//Close the path
growOutlinePoint(outline, 1);
_growOutlinePoint(outline, 1);
outline.pts[outline.ptsCnt] = outline.pts[i];
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
@ -156,14 +156,14 @@ static bool outlineClose(SwOutline& outline)
}
static void initBBox(SwShape& sdata)
static void _initBBox(SwShape& sdata)
{
sdata.bbox.min.x = sdata.bbox.min.y = 0;
sdata.bbox.max.x = sdata.bbox.max.y = 0;
}
static bool updateBBox(SwShape& sdata)
static bool _updateBBox(SwShape& sdata)
{
auto outline = sdata.outline;
assert(outline);
@ -172,7 +172,7 @@ static bool updateBBox(SwShape& sdata)
assert(pt);
if (outline->ptsCnt <= 0) {
initBBox(sdata);
_initBBox(sdata);
return false;
}
@ -201,33 +201,17 @@ static bool updateBBox(SwShape& sdata)
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
void _deleteRle(SwShape& sdata)
{
//TODO:
return true;
if (sdata.rle) {
if (sdata.rle->spans) free(sdata.rle->spans);
free(sdata.rle);
}
sdata.rle = nullptr;
}
void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
{
if (sdata.rle.spans) free(sdata.rle.spans);
sdata.rle.spans = nullptr;
}
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
{
shapeDelRle(shape, sdata);
if (!updateBBox(sdata)) return false;
return rleRender(sdata);
}
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
void _deleteOutline(SwShape& sdata)
{
if (!sdata.outline) return;
@ -240,11 +224,38 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
sdata.outline = nullptr;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
{
//TODO:
return true;
}
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
{
if (!_updateBBox(sdata)) goto end;
sdata.rle = rleRender(sdata);
_deleteOutline(sdata);
end:
if (sdata.rle) return true;
return false;
}
void shapeReset(SwShape& sdata)
{
_deleteOutline(sdata);
_deleteRle(sdata);
_initBBox(sdata);
}
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
{
initBBox(sdata);
const PathCommand* cmds = nullptr;
auto cmdCnt = shape.pathCommands(&cmds);
@ -257,7 +268,6 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
//smart reservation
auto outlinePtsCnt = 0;
auto outlineCntrsCnt = 0;
// auto closed = false;
for (auto i = 0; i < cmdCnt; ++i) {
switch(*(cmds + i)) {
@ -294,28 +304,28 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
}
//TODO: Probabry we can copy pts from shape directly.
growOutlinePoint(*outline, outlinePtsCnt);
growOutlineContour(*outline, outlineCntrsCnt);
_growOutlinePoint(*outline, outlinePtsCnt);
_growOutlineContour(*outline, outlineCntrsCnt);
//Generate Outlines
while (cmdCnt-- > 0) {
switch(*cmds) {
case PathCommand::Close: {
outlineClose(*outline);
_outlineClose(*outline);
break;
}
case PathCommand::MoveTo: {
outlineMoveTo(*outline, pts);
_outlineMoveTo(*outline, pts);
++pts;
break;
}
case PathCommand::LineTo: {
outlineLineTo(*outline, pts);
_outlineLineTo(*outline, pts);
++pts;
break;
}
case PathCommand::CubicTo: {
outlineCubicTo(*outline, pts, pts + 1, pts + 2);
_outlineCubicTo(*outline, pts, pts + 1, pts + 2);
pts += 3;
break;
}
@ -323,7 +333,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
++cmds;
}
outlineEnd(*outline);
_outlineEnd(*outline);
//FIXME:
//outline->flags = SwOutline::FillRule::Winding;

View file

@ -30,12 +30,13 @@ struct CanvasBase
CanvasBase(RasterMethod *pRaster):raster(pRaster)
{
raster->ref();
}
~CanvasBase()
{
clear();
raster->unref();
}
int reserve(size_t n)
@ -48,6 +49,7 @@ struct CanvasBase
int clear()
{
for (auto node : nodes) {
node->dispose(raster);
delete(node);
}
nodes.clear();

View file

@ -35,6 +35,67 @@ public:
enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
virtual ~RasterMethod() {}
virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0;
virtual void* dispose(const ShapeNode& shape, void *data) = 0;
virtual size_t ref() = 0;
virtual size_t unref() = 0;
};
struct RasterMethodInit
{
RasterMethod* pInst = nullptr;
size_t refCnt = 0;
bool initted = false;
static int init(RasterMethodInit& initter, RasterMethod* engine)
{
assert(engine);
if (initter.pInst || initter.refCnt > 0) return -1;
initter.pInst = engine;
initter.refCnt = 0;
initter.initted = true;
return 0;
}
static int term(RasterMethodInit& initter)
{
if (!initter.pInst || !initter.initted) return -1;
initter.initted = false;
//Still it's refered....
if (initter.refCnt > 0) return 0;
delete(initter.pInst);
initter.pInst = nullptr;
return 0;
}
static size_t unref(RasterMethodInit& initter)
{
assert(initter.refCnt > 0);
--initter.refCnt;
//engine has been requested to termination
if (!initter.initted && initter.refCnt == 0) {
if (initter.pInst) {
delete(initter.pInst);
initter.pInst = nullptr;
}
}
return initter.refCnt;
}
static RasterMethod* inst(RasterMethodInit& initter)
{
assert(initter.pInst);
return initter.pInst;
}
static size_t ref(RasterMethodInit& initter)
{
return ++initter.refCnt;
}
};
}

View file

@ -58,6 +58,13 @@ int SceneNode :: push(unique_ptr<ShapeNode> shape) noexcept
}
int SceneNode :: dispose(RasterMethod* engine) noexcept
{
return 0;
}
int SceneNode :: update(RasterMethod* engine) noexcept
{

View file

@ -84,6 +84,17 @@ unique_ptr<ShapeNode> ShapeNode::gen() noexcept
}
int ShapeNode :: dispose(RasterMethod* engine) noexcept
{
auto impl = pImpl.get();
assert(impl);
impl->edata = engine->dispose(*this, impl->edata);
if (impl->edata) return -1;
return 0;
}
int ShapeNode :: update(RasterMethod* engine) noexcept
{
auto impl = pImpl.get();