mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
sw_engine: implement line and curve raster
Change-Id: I22a77892544cd510cfe646aee60093cebb848806
This commit is contained in:
parent
de242b018b
commit
c8d800f6c6
13 changed files with 461 additions and 138 deletions
|
@ -73,6 +73,7 @@ class TIZENVG_EXPORT PaintNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~PaintNode() {}
|
virtual ~PaintNode() {}
|
||||||
|
virtual int dispose(RasterMethod* engine) = 0;
|
||||||
virtual int update(RasterMethod* engine) = 0;
|
virtual int update(RasterMethod* engine) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,6 +91,7 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode
|
||||||
public:
|
public:
|
||||||
~ShapeNode();
|
~ShapeNode();
|
||||||
|
|
||||||
|
int dispose(RasterMethod* engine) noexcept override;
|
||||||
int update(RasterMethod* engine) noexcept override;
|
int update(RasterMethod* engine) noexcept override;
|
||||||
int clear() noexcept;
|
int clear() noexcept;
|
||||||
|
|
||||||
|
@ -121,6 +123,7 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode
|
||||||
public:
|
public:
|
||||||
~SceneNode();
|
~SceneNode();
|
||||||
|
|
||||||
|
int dispose(RasterMethod* engine) noexcept override;
|
||||||
int update(RasterMethod* engine) noexcept override;
|
int update(RasterMethod* engine) noexcept override;
|
||||||
|
|
||||||
int push(std::unique_ptr<ShapeNode> shape) noexcept;
|
int push(std::unique_ptr<ShapeNode> shape) noexcept;
|
||||||
|
|
|
@ -20,14 +20,29 @@
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
#include "tvgGlEngine.h"
|
#include "tvgGlEngine.h"
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* Internal Class Implementation */
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
static GlEngine* pInst = nullptr;
|
static RasterMethodInit engineInit;
|
||||||
|
|
||||||
struct GlShape
|
struct GlShape
|
||||||
{
|
{
|
||||||
//TODO:
|
//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)
|
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)));
|
sdata = static_cast<GlShape*>(calloc(1, sizeof(GlShape)));
|
||||||
assert(sdata);
|
assert(sdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sdata;
|
return sdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GlEngine::init()
|
int GlEngine::init()
|
||||||
{
|
{
|
||||||
if (pInst) return -1;
|
return RasterMethodInit::init(engineInit, new GlEngine);
|
||||||
pInst = new GlEngine();
|
|
||||||
assert(pInst);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GlEngine::term()
|
int GlEngine::term()
|
||||||
{
|
{
|
||||||
if (!pInst) return -1;
|
return RasterMethodInit::term(engineInit);
|
||||||
cout << "GlEngine(" << pInst << ") destroyed!" << endl;
|
}
|
||||||
delete(pInst);
|
|
||||||
pInst = nullptr;
|
|
||||||
return 0;
|
size_t GlEngine::unref()
|
||||||
|
{
|
||||||
|
return RasterMethodInit::unref(engineInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t GlEngine::ref()
|
||||||
|
{
|
||||||
|
return RasterMethodInit::ref(engineInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GlEngine* GlEngine::inst()
|
GlEngine* GlEngine::inst()
|
||||||
{
|
{
|
||||||
assert(pInst);
|
return dynamic_cast<GlEngine*>(RasterMethodInit::inst(engineInit));
|
||||||
return pInst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@ class GlEngine : public RasterMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
|
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 GlEngine* inst();
|
||||||
static int init();
|
static int init();
|
||||||
static int term();
|
static int term();
|
||||||
|
|
|
@ -23,6 +23,8 @@ using namespace tvg;
|
||||||
|
|
||||||
constexpr auto SW_CURVE_TAG_ON = 1;
|
constexpr auto SW_CURVE_TAG_ON = 1;
|
||||||
constexpr auto SW_CURVE_TAG_CUBIC = 2;
|
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;
|
using SwCoord = signed long;
|
||||||
|
|
||||||
|
@ -56,43 +58,41 @@ struct SwOutline
|
||||||
size_t ptsCnt; //number of points in the glyph
|
size_t ptsCnt; //number of points in the glyph
|
||||||
size_t reservedPtsCnt;
|
size_t reservedPtsCnt;
|
||||||
char* tags; //the points flags
|
char* tags; //the points flags
|
||||||
size_t flags; //outline masks
|
uint8_t fillMode; //outline fill mode
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwSpan
|
struct SwSpan
|
||||||
{
|
{
|
||||||
size_t x;
|
uint16_t x, y;
|
||||||
size_t y;
|
uint16_t len;
|
||||||
size_t len;
|
|
||||||
uint8_t coverage;
|
uint8_t coverage;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwRleData
|
struct SwRleData
|
||||||
{
|
{
|
||||||
|
SwSpan *spans;
|
||||||
size_t alloc;
|
size_t alloc;
|
||||||
size_t size;
|
size_t size;
|
||||||
SwSpan *spans;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwBBox
|
struct SwBBox
|
||||||
{
|
{
|
||||||
SwPoint min;
|
SwPoint min, max;
|
||||||
SwPoint max;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwShape
|
struct SwShape
|
||||||
{
|
{
|
||||||
SwOutline* outline;
|
SwOutline* outline;
|
||||||
SwRleData rle;
|
SwRleData* rle;
|
||||||
SwBBox bbox;
|
SwBBox bbox;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void shapeReset(SwShape& sdata);
|
||||||
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
|
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
|
||||||
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
|
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
|
||||||
bool shapeGenRle(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 shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
|
||||||
|
|
||||||
bool rleRender(SwShape& sdata);
|
SwRleData* rleRender(const SwShape& sdata);
|
||||||
|
|
||||||
#endif /* _TVG_SW_COMMON_H_ */
|
#endif /* _TVG_SW_COMMON_H_ */
|
||||||
|
|
|
@ -24,13 +24,22 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
static SwEngine* pInst = nullptr;
|
static RasterMethodInit engineInit;
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* External Class Implementation */
|
/* 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)
|
void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
|
||||||
{
|
{
|
||||||
//prepare shape data
|
//prepare shape data
|
||||||
|
@ -48,11 +57,11 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
|
||||||
if (alpha == 0) return sdata;
|
if (alpha == 0) return sdata;
|
||||||
|
|
||||||
if (flags & UpdateFlag::Path) {
|
if (flags & UpdateFlag::Path) {
|
||||||
|
shapeReset(*sdata);
|
||||||
if (!shapeGenOutline(shape, *sdata)) return sdata;
|
if (!shapeGenOutline(shape, *sdata)) return sdata;
|
||||||
//TODO: From below sequence starts threading?
|
//TODO: From below sequence starts threading?
|
||||||
if (!shapeTransformOutline(shape, *sdata)) return sdata;
|
if (!shapeTransformOutline(shape, *sdata)) return sdata;
|
||||||
if (!shapeGenRle(shape, *sdata)) return sdata;
|
if (!shapeGenRle(shape, *sdata)) return sdata;
|
||||||
shapeDelOutline(shape, *sdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sdata;
|
return sdata;
|
||||||
|
@ -61,28 +70,31 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
|
||||||
|
|
||||||
int SwEngine::init()
|
int SwEngine::init()
|
||||||
{
|
{
|
||||||
if (pInst) return -1;
|
return RasterMethodInit::init(engineInit, new SwEngine);
|
||||||
pInst = new SwEngine();
|
|
||||||
assert(pInst);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SwEngine::term()
|
int SwEngine::term()
|
||||||
{
|
{
|
||||||
if (!pInst) return -1;
|
return RasterMethodInit::term(engineInit);
|
||||||
cout << "SwEngine(" << pInst << ") destroyed!" << endl;
|
}
|
||||||
delete(pInst);
|
|
||||||
pInst = nullptr;
|
|
||||||
return 0;
|
size_t SwEngine::unref()
|
||||||
|
{
|
||||||
|
return RasterMethodInit::unref(engineInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t SwEngine::ref()
|
||||||
|
{
|
||||||
|
return RasterMethodInit::ref(engineInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SwEngine* SwEngine::inst()
|
SwEngine* SwEngine::inst()
|
||||||
{
|
{
|
||||||
assert(pInst);
|
return dynamic_cast<SwEngine*>(RasterMethodInit::inst(engineInit));
|
||||||
return pInst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@ class SwEngine : public RasterMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
|
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 SwEngine* inst();
|
||||||
static int init();
|
static int init();
|
||||||
static int term();
|
static int term();
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <memory.h>
|
||||||
#include "tvgSwCommon.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 PIXEL_BITS = 8; //must be at least 6 bits!
|
||||||
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
|
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
|
||||||
|
|
||||||
|
|
||||||
using Area = long;
|
using Area = long;
|
||||||
|
|
||||||
struct Band
|
struct Band
|
||||||
|
@ -47,6 +47,8 @@ struct Cell
|
||||||
|
|
||||||
struct RleWorker
|
struct RleWorker
|
||||||
{
|
{
|
||||||
|
SwRleData* rle;
|
||||||
|
|
||||||
SwPoint cellPos;
|
SwPoint cellPos;
|
||||||
SwPoint cellMin;
|
SwPoint cellMin;
|
||||||
SwPoint cellMax;
|
SwPoint cellMax;
|
||||||
|
@ -100,13 +102,19 @@ static inline SwPoint DOWNSCALE(const SwPoint& pt)
|
||||||
|
|
||||||
static inline SwPoint TRUNC(const SwPoint& pt)
|
static inline SwPoint TRUNC(const SwPoint& pt)
|
||||||
{
|
{
|
||||||
return { pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS };
|
return {pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline SwCoord TRUNC(const SwCoord x)
|
||||||
|
{
|
||||||
|
return x >> PIXEL_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline SwPoint SUBPIXELS(const SwPoint& pt)
|
static inline SwPoint SUBPIXELS(const SwPoint& pt)
|
||||||
{
|
{
|
||||||
return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS };
|
return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,20 +123,105 @@ static inline SwCoord SUBPIXELS(const SwCoord x)
|
||||||
return (x << PIXEL_BITS);
|
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;
|
if (rw.cellsCnt == 0) return;
|
||||||
|
|
||||||
|
@ -142,26 +235,26 @@ static void sweep(RleWorker& rw)
|
||||||
|
|
||||||
while (cell) {
|
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;
|
cover += cell->cover;
|
||||||
auto area = cover * (ONE_PIXEL * 2) - cell->area;
|
auto area = cover * (ONE_PIXEL * 2) - cell->area;
|
||||||
|
|
||||||
if (area != 0 && cell->x >= 0)
|
if (area != 0 && cell->x >= 0)
|
||||||
horizLine(rw, cell->x, y, area, 1);
|
_horizLine(rw, cell->x, y, area, 1);
|
||||||
|
|
||||||
x = cell->x + 1;
|
x = cell->x + 1;
|
||||||
cell = cell->next;
|
cell = cell->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cover != 0)
|
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;
|
auto x = rw.cellPos.x;
|
||||||
if (x > rw.cellXCnt) x = rw.cellXCnt;
|
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) {
|
if (rw.area | rw.cover) {
|
||||||
auto cell = findCell(rw);
|
auto cell = _findCell(rw);
|
||||||
assert(cell);
|
assert(cell);
|
||||||
cell->area += rw.area;
|
cell->area += rw.area;
|
||||||
cell->cover += rw.cover;
|
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' */
|
/* 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 */
|
/* 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?
|
//Are we moving to a different cell?
|
||||||
if (pos != rw.cellPos) {
|
if (pos != rw.cellPos) {
|
||||||
if (!rw.invalid) recordCell(rw);
|
if (!rw.invalid) _recordCell(rw);
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.area = 0;
|
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.cellMax.x) pos.x = rw.cellMax.x;
|
||||||
if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.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.cellPos = pos - rw.cellMin;
|
||||||
rw.invalid = false;
|
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 */
|
//record current cell, if any */
|
||||||
if (!rw.invalid) recordCell(rw);
|
if (!rw.invalid) _recordCell(rw);
|
||||||
|
|
||||||
//start to a new position
|
//start to a new position
|
||||||
startCell(rw, TRUNC(to));
|
_startCell(rw, TRUNC(to));
|
||||||
|
|
||||||
rw.pos = 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) \
|
#define SW_UDIV(a, b) \
|
||||||
static_cast<SwCoord>(((unsigned long)(a) * (unsigned long)(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
|
//any horizontal line
|
||||||
} else if (diff.y == 0) {
|
} else if (diff.y == 0) {
|
||||||
e1.x = e2.x;
|
e1.x = e2.x;
|
||||||
setCell(rw, e1);
|
_setCell(rw, e1);
|
||||||
} else if (diff.x == 0) {
|
} else if (diff.x == 0) {
|
||||||
//vertical line up
|
//vertical line up
|
||||||
if (diff.y > 0) {
|
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;
|
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||||
f1.y = 0;
|
f1.y = 0;
|
||||||
++e1.y;
|
++e1.y;
|
||||||
setCell(rw, e1);
|
_setCell(rw, e1);
|
||||||
} while(e1.y != e2.y);
|
} while(e1.y != e2.y);
|
||||||
//vertical line down
|
//vertical line down
|
||||||
} else {
|
} else {
|
||||||
|
@ -304,7 +398,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
||||||
rw.area += (f2.y - f1.y) * f1.x * 2;
|
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||||
f1.y = ONE_PIXEL;
|
f1.y = ONE_PIXEL;
|
||||||
--e1.y;
|
--e1.y;
|
||||||
setCell(rw, e1);
|
_setCell(rw, e1);
|
||||||
} while(e1.y != e2.y);
|
} while(e1.y != e2.y);
|
||||||
}
|
}
|
||||||
//any other line
|
//any other line
|
||||||
|
@ -357,7 +451,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
|
||||||
--e1.y;
|
--e1.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCell(rw, e1);
|
_setCell(rw, e1);
|
||||||
|
|
||||||
} while(e1 != e2);
|
} 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;
|
auto outline = rw.outline;
|
||||||
assert(outline);
|
assert(outline);
|
||||||
|
|
||||||
|
@ -402,7 +586,7 @@ static bool decomposeOutline(RleWorker& rw)
|
||||||
/* A contour cannot start with a cubic control point! */
|
/* A contour cannot start with a cubic control point! */
|
||||||
if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline;
|
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) {
|
while (pt < limit) {
|
||||||
assert(++pt);
|
assert(++pt);
|
||||||
|
@ -410,7 +594,7 @@ static bool decomposeOutline(RleWorker& rw)
|
||||||
|
|
||||||
//emit a single line_to
|
//emit a single line_to
|
||||||
if (tags[0] == SW_CURVE_TAG_ON) {
|
if (tags[0] == SW_CURVE_TAG_ON) {
|
||||||
lineTo(rw, UPSCALE(*pt));
|
_lineTo(rw, UPSCALE(*pt));
|
||||||
//tag cubic
|
//tag cubic
|
||||||
} else {
|
} else {
|
||||||
if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
|
if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
|
||||||
|
@ -420,10 +604,10 @@ static bool decomposeOutline(RleWorker& rw)
|
||||||
tags += 2;
|
tags += 2;
|
||||||
|
|
||||||
if (pt <= limit) {
|
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;
|
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;
|
goto close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,13 +626,13 @@ invalid_outline:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool genRle(RleWorker& rw)
|
static bool _genRle(RleWorker& rw)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (setjmp(rw.jmpBuf) == 0) {
|
if (setjmp(rw.jmpBuf) == 0) {
|
||||||
ret = decomposeOutline(rw);
|
ret = _decomposeOutline(rw);
|
||||||
if (!rw.invalid) recordCell(rw);
|
if (!rw.invalid) _recordCell(rw);
|
||||||
} else {
|
} else {
|
||||||
cout << "Memory Overflow" << endl;
|
cout << "Memory Overflow" << endl;
|
||||||
}
|
}
|
||||||
|
@ -460,7 +644,7 @@ static bool genRle(RleWorker& rw)
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
bool rleRender(SwShape& sdata)
|
SwRleData* rleRender(const SwShape& sdata)
|
||||||
{
|
{
|
||||||
constexpr auto RENDER_POOL_SIZE = 16384L;
|
constexpr auto RENDER_POOL_SIZE = 16384L;
|
||||||
constexpr auto BAND_SIZE = 39;
|
constexpr auto BAND_SIZE = 39;
|
||||||
|
@ -468,7 +652,7 @@ bool rleRender(SwShape& sdata)
|
||||||
auto outline = sdata.outline;
|
auto outline = sdata.outline;
|
||||||
assert(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->cntrs && outline->pts);
|
||||||
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
|
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
|
||||||
|
@ -494,6 +678,9 @@ bool rleRender(SwShape& sdata)
|
||||||
rw.outline = outline;
|
rw.outline = outline;
|
||||||
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
|
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
|
||||||
rw.bandShoot = 0;
|
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);
|
//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
|
//Generate RLE
|
||||||
|
@ -547,9 +734,9 @@ bool rleRender(SwShape& sdata)
|
||||||
rw.cellMax.y = band->max;
|
rw.cellMax.y = band->max;
|
||||||
rw.cellYCnt = band->max - band->min;
|
rw.cellYCnt = band->max - band->min;
|
||||||
|
|
||||||
if (!genRle(rw)) return -1;
|
if (!_genRle(rw)) goto error;
|
||||||
|
|
||||||
sweep(rw);
|
_sweep(rw);
|
||||||
--band;
|
--band;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -561,7 +748,7 @@ bool rleRender(SwShape& sdata)
|
||||||
|
|
||||||
/* This is too complex for a single scanline; there must
|
/* This is too complex for a single scanline; there must
|
||||||
be some problems */
|
be some problems */
|
||||||
if (middle == bottom) return -1;
|
if (middle == bottom) goto error;
|
||||||
|
|
||||||
if (bottom - top >= rw.bandSize) ++rw.bandShoot;
|
if (bottom - top >= rw.bandSize) ++rw.bandShoot;
|
||||||
|
|
||||||
|
@ -576,7 +763,12 @@ bool rleRender(SwShape& sdata)
|
||||||
if (rw.bandShoot > 8 && rw.bandSize > 16)
|
if (rw.bandShoot > 8 && rw.bandSize > 16)
|
||||||
rw.bandSize = (rw.bandSize >> 1);
|
rw.bandSize = (rw.bandSize >> 1);
|
||||||
|
|
||||||
return true;
|
return rw.rle;
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(rw.rle);
|
||||||
|
rw.rle = nullptr;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _TVG_SW_RLE_H_ */
|
#endif /* _TVG_SW_RLE_H_ */
|
||||||
|
|
|
@ -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) {
|
if (n == 0) {
|
||||||
free(outline.cntrs);
|
free(outline.cntrs);
|
||||||
|
@ -40,14 +40,14 @@ static void growOutlineContour(SwOutline& outline, size_t n)
|
||||||
}
|
}
|
||||||
if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
|
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.reservedCntrsCnt = n;
|
||||||
outline.cntrs = static_cast<size_t*>(realloc(outline.cntrs, n * sizeof(size_t)));
|
outline.cntrs = static_cast<size_t*>(realloc(outline.cntrs, n * sizeof(size_t)));
|
||||||
assert(outline.cntrs);
|
assert(outline.cntrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void growOutlinePoint(SwOutline& outline, size_t n)
|
static void _growOutlinePoint(SwOutline& outline, size_t n)
|
||||||
{
|
{
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
free(outline.pts);
|
free(outline.pts);
|
||||||
|
@ -61,7 +61,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
|
||||||
|
|
||||||
if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
|
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.reservedPtsCnt = n;
|
||||||
outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
|
outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
|
||||||
assert(outline.pts);
|
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) {
|
if (outline.ptsCnt > 0) {
|
||||||
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
||||||
++outline.cntrsCnt;
|
++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);
|
assert(to);
|
||||||
|
|
||||||
growOutlinePoint(outline, 1);
|
_growOutlinePoint(outline, 1);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
||||||
|
|
||||||
if (outline.ptsCnt > 0) {
|
if (outline.ptsCnt > 0) {
|
||||||
growOutlineContour(outline, 1);
|
_growOutlineContour(outline, 1);
|
||||||
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
||||||
++outline.cntrsCnt;
|
++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);
|
assert(to);
|
||||||
|
|
||||||
growOutlinePoint(outline, 1);
|
_growOutlinePoint(outline, 1);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
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);
|
assert(ctrl1 && ctrl2 && to);
|
||||||
|
|
||||||
growOutlinePoint(outline, 3);
|
_growOutlinePoint(outline, 3);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
|
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;
|
size_t i = 0;
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ static bool outlineClose(SwOutline& outline)
|
||||||
if (outline.ptsCnt == i) return false;
|
if (outline.ptsCnt == i) return false;
|
||||||
|
|
||||||
//Close the path
|
//Close the path
|
||||||
growOutlinePoint(outline, 1);
|
_growOutlinePoint(outline, 1);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = outline.pts[i];
|
outline.pts[outline.ptsCnt] = outline.pts[i];
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
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.min.x = sdata.bbox.min.y = 0;
|
||||||
sdata.bbox.max.x = sdata.bbox.max.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;
|
auto outline = sdata.outline;
|
||||||
assert(outline);
|
assert(outline);
|
||||||
|
@ -172,7 +172,7 @@ static bool updateBBox(SwShape& sdata)
|
||||||
assert(pt);
|
assert(pt);
|
||||||
|
|
||||||
if (outline->ptsCnt <= 0) {
|
if (outline->ptsCnt <= 0) {
|
||||||
initBBox(sdata);
|
_initBBox(sdata);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,33 +201,17 @@ static bool updateBBox(SwShape& sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
void _deleteRle(SwShape& sdata)
|
||||||
/* External Class Implementation */
|
|
||||||
/************************************************************************/
|
|
||||||
|
|
||||||
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
|
|
||||||
{
|
{
|
||||||
//TODO:
|
if (sdata.rle) {
|
||||||
return true;
|
if (sdata.rle->spans) free(sdata.rle->spans);
|
||||||
|
free(sdata.rle);
|
||||||
|
}
|
||||||
|
sdata.rle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
|
void _deleteOutline(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)
|
|
||||||
{
|
{
|
||||||
if (!sdata.outline) return;
|
if (!sdata.outline) return;
|
||||||
|
|
||||||
|
@ -240,11 +224,38 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
|
||||||
sdata.outline = nullptr;
|
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)
|
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
||||||
{
|
{
|
||||||
initBBox(sdata);
|
|
||||||
|
|
||||||
const PathCommand* cmds = nullptr;
|
const PathCommand* cmds = nullptr;
|
||||||
auto cmdCnt = shape.pathCommands(&cmds);
|
auto cmdCnt = shape.pathCommands(&cmds);
|
||||||
|
|
||||||
|
@ -257,7 +268,6 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
||||||
//smart reservation
|
//smart reservation
|
||||||
auto outlinePtsCnt = 0;
|
auto outlinePtsCnt = 0;
|
||||||
auto outlineCntrsCnt = 0;
|
auto outlineCntrsCnt = 0;
|
||||||
// auto closed = false;
|
|
||||||
|
|
||||||
for (auto i = 0; i < cmdCnt; ++i) {
|
for (auto i = 0; i < cmdCnt; ++i) {
|
||||||
switch(*(cmds + i)) {
|
switch(*(cmds + i)) {
|
||||||
|
@ -294,28 +304,28 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Probabry we can copy pts from shape directly.
|
//TODO: Probabry we can copy pts from shape directly.
|
||||||
growOutlinePoint(*outline, outlinePtsCnt);
|
_growOutlinePoint(*outline, outlinePtsCnt);
|
||||||
growOutlineContour(*outline, outlineCntrsCnt);
|
_growOutlineContour(*outline, outlineCntrsCnt);
|
||||||
|
|
||||||
//Generate Outlines
|
//Generate Outlines
|
||||||
while (cmdCnt-- > 0) {
|
while (cmdCnt-- > 0) {
|
||||||
switch(*cmds) {
|
switch(*cmds) {
|
||||||
case PathCommand::Close: {
|
case PathCommand::Close: {
|
||||||
outlineClose(*outline);
|
_outlineClose(*outline);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCommand::MoveTo: {
|
case PathCommand::MoveTo: {
|
||||||
outlineMoveTo(*outline, pts);
|
_outlineMoveTo(*outline, pts);
|
||||||
++pts;
|
++pts;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCommand::LineTo: {
|
case PathCommand::LineTo: {
|
||||||
outlineLineTo(*outline, pts);
|
_outlineLineTo(*outline, pts);
|
||||||
++pts;
|
++pts;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCommand::CubicTo: {
|
case PathCommand::CubicTo: {
|
||||||
outlineCubicTo(*outline, pts, pts + 1, pts + 2);
|
_outlineCubicTo(*outline, pts, pts + 1, pts + 2);
|
||||||
pts += 3;
|
pts += 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -323,7 +333,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
|
||||||
++cmds;
|
++cmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
outlineEnd(*outline);
|
_outlineEnd(*outline);
|
||||||
|
|
||||||
//FIXME:
|
//FIXME:
|
||||||
//outline->flags = SwOutline::FillRule::Winding;
|
//outline->flags = SwOutline::FillRule::Winding;
|
||||||
|
|
|
@ -30,12 +30,13 @@ struct CanvasBase
|
||||||
|
|
||||||
CanvasBase(RasterMethod *pRaster):raster(pRaster)
|
CanvasBase(RasterMethod *pRaster):raster(pRaster)
|
||||||
{
|
{
|
||||||
|
raster->ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
~CanvasBase()
|
~CanvasBase()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
raster->unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
int reserve(size_t n)
|
int reserve(size_t n)
|
||||||
|
@ -48,6 +49,7 @@ struct CanvasBase
|
||||||
int clear()
|
int clear()
|
||||||
{
|
{
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
|
node->dispose(raster);
|
||||||
delete(node);
|
delete(node);
|
||||||
}
|
}
|
||||||
nodes.clear();
|
nodes.clear();
|
||||||
|
|
|
@ -35,6 +35,67 @@ public:
|
||||||
enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
|
enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
|
||||||
virtual ~RasterMethod() {}
|
virtual ~RasterMethod() {}
|
||||||
virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
int SceneNode :: update(RasterMethod* engine) noexcept
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -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
|
int ShapeNode :: update(RasterMethod* engine) noexcept
|
||||||
{
|
{
|
||||||
auto impl = pImpl.get();
|
auto impl = pImpl.get();
|
||||||
|
|
|
@ -89,7 +89,7 @@ SwCanvas::SwCanvas() : pImpl(make_unique<Impl>())
|
||||||
|
|
||||||
SwCanvas::~SwCanvas()
|
SwCanvas::~SwCanvas()
|
||||||
{
|
{
|
||||||
cout << "SwCanvas(" << this << ") destroyed!" << endl;
|
cout << "SwCanvas(" << this << ") destroyed!" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue