mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
implement rle path parts.
Change-Id: I7200d80320404d6e7fb722042b8f330961bee76d
This commit is contained in:
parent
70c9860d8f
commit
2a39617527
4 changed files with 399 additions and 126 deletions
|
@ -20,12 +20,33 @@
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
|
|
||||||
using namespace tvg;
|
using namespace tvg;
|
||||||
using SwPoint = Point;
|
|
||||||
|
|
||||||
constexpr auto SW_CURVE_TAG_CONIC = 0;
|
|
||||||
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;
|
||||||
|
|
||||||
|
using SwCoord = signed long;
|
||||||
|
|
||||||
|
struct SwPoint
|
||||||
|
{
|
||||||
|
SwCoord x, y;
|
||||||
|
|
||||||
|
SwPoint operator+(const SwPoint& rhs) const {
|
||||||
|
return {x + rhs.x, y + rhs.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
SwPoint operator-(const SwPoint& rhs) const {
|
||||||
|
return {x - rhs.x, y - rhs.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SwPoint& rhs ) const {
|
||||||
|
return (x == rhs.x && y == rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const SwPoint& rhs) const {
|
||||||
|
return (x != rhs.x || y != rhs.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SwOutline
|
struct SwOutline
|
||||||
{
|
{
|
||||||
size_t* cntrs; //the contour end points
|
size_t* cntrs; //the contour end points
|
||||||
|
@ -55,8 +76,8 @@ struct SwRleData
|
||||||
|
|
||||||
struct SwBBox
|
struct SwBBox
|
||||||
{
|
{
|
||||||
size_t xMin, yMin;
|
SwPoint min;
|
||||||
size_t xMax, yMax;
|
SwPoint max;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwShape
|
struct SwShape
|
||||||
|
|
|
@ -18,58 +18,57 @@
|
||||||
#define _TVG_SW_RLE_H_
|
#define _TVG_SW_RLE_H_
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
#include <limits.h>
|
||||||
#include "tvgSwCommon.h"
|
#include "tvgSwCommon.h"
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
constexpr auto MAX_SPANS = 256;
|
constexpr auto MAX_SPANS = 256;
|
||||||
|
constexpr auto PIXEL_BITS = 8; //must be at least 6 bits!
|
||||||
|
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
|
||||||
|
|
||||||
using SwPtrDist = ptrdiff_t;
|
|
||||||
using TPos = long;
|
|
||||||
using TCoord = long;
|
|
||||||
using TArea = int;
|
|
||||||
|
|
||||||
struct TBand
|
using Area = long;
|
||||||
|
|
||||||
|
struct Band
|
||||||
{
|
{
|
||||||
TPos min, max;
|
SwCoord min, max;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TCell
|
struct Cell
|
||||||
{
|
{
|
||||||
TPos x;
|
SwCoord x;
|
||||||
TCoord cover;
|
SwCoord cover;
|
||||||
TArea area;
|
Area area;
|
||||||
TCell *next;
|
Cell *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RleWorker
|
struct RleWorker
|
||||||
{
|
{
|
||||||
TCoord ex, ey;
|
SwPoint cellPos;
|
||||||
TPos exMin, exMax;
|
SwPoint cellMin;
|
||||||
TPos eyMin, eyMax;
|
SwPoint cellMax;
|
||||||
TPos exCnt, eyCnt;
|
SwCoord cellXCnt;
|
||||||
|
SwCoord cellYCnt;
|
||||||
|
|
||||||
TArea area;
|
Area area;
|
||||||
TCoord cover;
|
SwCoord cover;
|
||||||
|
|
||||||
TCell* cells;
|
Cell* cells;
|
||||||
SwPtrDist maxCells;
|
ptrdiff_t maxCells;
|
||||||
SwPtrDist numCells;
|
ptrdiff_t cellsCnt;
|
||||||
|
|
||||||
TPos x, y;
|
SwPoint pos;
|
||||||
|
|
||||||
Point bezStack[32 * 3 + 1];
|
SwPoint bezStack[32 * 3 + 1];
|
||||||
int levStack[32];
|
int levStack[32];
|
||||||
|
|
||||||
SwOutline* outline;
|
SwOutline* outline;
|
||||||
//SwBBox clipBox;
|
|
||||||
|
|
||||||
SwSpan spans[MAX_SPANS];
|
SwSpan spans[MAX_SPANS];
|
||||||
int spansCnt;
|
int spansCnt;
|
||||||
|
|
||||||
//render_span
|
|
||||||
//render_span_data;
|
|
||||||
int ySpan;
|
int ySpan;
|
||||||
|
|
||||||
int bandSize;
|
int bandSize;
|
||||||
|
@ -80,42 +79,311 @@ struct RleWorker
|
||||||
void* buffer;
|
void* buffer;
|
||||||
long bufferSize;
|
long bufferSize;
|
||||||
|
|
||||||
TCell** yCells;
|
Cell** yCells;
|
||||||
TPos yCnt;
|
SwCoord yCnt;
|
||||||
|
|
||||||
bool invalid;
|
bool invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool rleSweep(RleWorker& rw)
|
|
||||||
|
static inline SwPoint UPSCALE(const SwPoint& pt)
|
||||||
|
{
|
||||||
|
return {pt.x << (PIXEL_BITS - 6), pt.y << (PIXEL_BITS - 6)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline SwPoint DOWNSCALE(const SwPoint& pt)
|
||||||
|
{
|
||||||
|
return {pt.x >> (PIXEL_BITS - 6), pt.y >> (PIXEL_BITS - 6)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline SwPoint TRUNC(const SwPoint& pt)
|
||||||
|
{
|
||||||
|
return { pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline SwPoint SUBPIXELS(const SwPoint& pt)
|
||||||
|
{
|
||||||
|
return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline SwCoord SUBPIXELS(const SwCoord x)
|
||||||
|
{
|
||||||
|
return (x << PIXEL_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
|
||||||
{
|
{
|
||||||
//TODO:
|
//TODO:
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool moveTo(SwPoint& pt)
|
|
||||||
|
static void genSpan(RleWorker& rw)
|
||||||
|
{
|
||||||
|
//TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sweep(RleWorker& rw)
|
||||||
|
{
|
||||||
|
if (rw.cellsCnt == 0) return;
|
||||||
|
|
||||||
|
rw.spansCnt = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < rw.yCnt; ++y) {
|
||||||
|
|
||||||
|
auto cover = 0;
|
||||||
|
auto x = 0;
|
||||||
|
auto cell = rw.yCells[y];
|
||||||
|
|
||||||
|
while (cell) {
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
x = cell->x + 1;
|
||||||
|
cell = cell->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cover != 0)
|
||||||
|
horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rw.spansCnt > 0) genSpan(rw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Cell* findCell(RleWorker& rw)
|
||||||
|
{
|
||||||
|
auto x = rw.cellPos.x;
|
||||||
|
if (x > rw.cellXCnt) x = rw.cellXCnt;
|
||||||
|
|
||||||
|
auto pcell = &rw.yCells[rw.cellPos.y];
|
||||||
|
assert(pcell);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
Cell* cell = *pcell;
|
||||||
|
if (!cell || cell->x > x) break;
|
||||||
|
if (cell->x == x) return cell;
|
||||||
|
pcell = &cell->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rw.cellsCnt >= rw.maxCells) longjmp(rw.jmpBuf, 1);
|
||||||
|
|
||||||
|
auto cell = rw.cells + rw.cellsCnt++;
|
||||||
|
assert(cell);
|
||||||
|
cell->x = x;
|
||||||
|
cell->area = 0;
|
||||||
|
cell->cover = 0;
|
||||||
|
cell->next = *pcell;
|
||||||
|
*pcell = cell;
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recordCell(RleWorker& rw)
|
||||||
|
{
|
||||||
|
if (rw.area | rw.cover) {
|
||||||
|
auto cell = findCell(rw);
|
||||||
|
assert(cell);
|
||||||
|
cell->area += rw.area;
|
||||||
|
cell->cover += rw.cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
/* in during the render phase. This means that: */
|
||||||
|
/* */
|
||||||
|
/* . the new vertical position must be within min_ey..max_ey-1. */
|
||||||
|
/* . the new horizontal position must be strictly less than max_ex */
|
||||||
|
/* */
|
||||||
|
/* Note that if a cell is to the left of the clipping region, it is */
|
||||||
|
/* actually set to the (min_ex-1) horizontal position. */
|
||||||
|
|
||||||
|
/* All cells that are on the left of the clipping region go to the
|
||||||
|
min_ex - 1 horizontal position. */
|
||||||
|
pos.y -= rw.cellMin.y;
|
||||||
|
|
||||||
|
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
|
||||||
|
pos.x -= rw.cellMin.x;
|
||||||
|
if (pos.x < 0) pos.x = -1;
|
||||||
|
|
||||||
|
//Are we moving to a different cell?
|
||||||
|
if (pos != rw.cellPos) {
|
||||||
|
if (!rw.invalid) recordCell(rw);
|
||||||
|
}
|
||||||
|
|
||||||
|
rw.area = 0;
|
||||||
|
rw.cover = 0;
|
||||||
|
rw.cellPos = pos;
|
||||||
|
rw.invalid = ((unsigned)pos.y >= (unsigned)rw.cellYCnt || pos.x >= rw.cellXCnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
rw.area = 0;
|
||||||
|
rw.cover = 0;
|
||||||
|
rw.cellPos = pos - rw.cellMin;
|
||||||
|
rw.invalid = false;
|
||||||
|
|
||||||
|
setCell(rw, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void moveTo(RleWorker& rw, const SwPoint& to)
|
||||||
|
{
|
||||||
|
//record current cell, if any */
|
||||||
|
if (!rw.invalid) recordCell(rw);
|
||||||
|
|
||||||
|
//start to a new position
|
||||||
|
startCell(rw, TRUNC(to));
|
||||||
|
|
||||||
|
rw.pos = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void lineTo(RleWorker& rw, const SwPoint& to)
|
||||||
|
{
|
||||||
|
#define SW_UDIV(a, b) \
|
||||||
|
static_cast<SwCoord>(((unsigned long)(a) * (unsigned long)(b)) >> \
|
||||||
|
(sizeof(long) * CHAR_BIT - PIXEL_BITS))
|
||||||
|
|
||||||
|
auto e1 = TRUNC(rw.pos);
|
||||||
|
auto e2 = TRUNC(to);
|
||||||
|
|
||||||
|
//vertical clipping
|
||||||
|
if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) ||
|
||||||
|
(e1.y < rw.cellMin.y && e2.y >= rw.cellMin.y)) {
|
||||||
|
rw.pos = to;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto diff = to - rw.pos;
|
||||||
|
auto f1 = rw.pos - SUBPIXELS(e1);
|
||||||
|
SwPoint f2;
|
||||||
|
|
||||||
|
//inside one cell
|
||||||
|
if (e1 == e2) {
|
||||||
|
;
|
||||||
|
//any horizontal line
|
||||||
|
} else if (diff.y == 0) {
|
||||||
|
e1.x = e2.x;
|
||||||
|
setCell(rw, e1);
|
||||||
|
} else if (diff.x == 0) {
|
||||||
|
//vertical line up
|
||||||
|
if (diff.y > 0) {
|
||||||
|
do {
|
||||||
|
f2.y = ONE_PIXEL;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||||
|
f1.y = 0;
|
||||||
|
++e1.y;
|
||||||
|
setCell(rw, e1);
|
||||||
|
} while(e1.y != e2.y);
|
||||||
|
//vertical line down
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
f2.y = 0;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||||
|
f1.y = ONE_PIXEL;
|
||||||
|
--e1.y;
|
||||||
|
setCell(rw, e1);
|
||||||
|
} while(e1.y != e2.y);
|
||||||
|
}
|
||||||
|
//any other line
|
||||||
|
} else {
|
||||||
|
Area prod = diff.x * f1.y - diff.y * f1.x;
|
||||||
|
|
||||||
|
/* These macros speed up repetitive divisions by replacing them
|
||||||
|
with multiplications and right shifts. */
|
||||||
|
auto dx_r = (ULONG_MAX >> PIXEL_BITS) / (diff.x);
|
||||||
|
auto dy_r = (ULONG_MAX >> PIXEL_BITS) / (diff.y);
|
||||||
|
|
||||||
|
/* The fundamental value `prod' determines which side and the */
|
||||||
|
/* exact coordinate where the line exits current cell. It is */
|
||||||
|
/* also easily updated when moving from one cell to the next. */
|
||||||
|
do {
|
||||||
|
auto px = diff.x * ONE_PIXEL;
|
||||||
|
auto py = diff.y * ONE_PIXEL;
|
||||||
|
|
||||||
|
//left
|
||||||
|
if (prod <= 0 && prod - px) {
|
||||||
|
f2 = {0, SW_UDIV(-prod, -dx_r)};
|
||||||
|
prod -= py;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {ONE_PIXEL, f2.y};
|
||||||
|
--e1.x;
|
||||||
|
//up
|
||||||
|
} else if (prod - px <= 0 && prod - px + py > 0) {
|
||||||
|
prod -= px;
|
||||||
|
f2 = {SW_UDIV(-prod, dy_r), ONE_PIXEL};
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {f2.x, 0};
|
||||||
|
++e1.y;
|
||||||
|
//right
|
||||||
|
} else if (prod - px + py <= 0 && prod + py >= 0) {
|
||||||
|
prod += py;
|
||||||
|
f2 = {ONE_PIXEL, SW_UDIV(prod, dx_r)};
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {0, f2.y};
|
||||||
|
++e1.x;
|
||||||
|
//down
|
||||||
|
} else {
|
||||||
|
f2 = {SW_UDIV(prod, -dy_r), 0};
|
||||||
|
prod += px;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {f2.x, ONE_PIXEL};
|
||||||
|
--e1.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCell(rw, e1);
|
||||||
|
|
||||||
|
} while(e1 != e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 = {to.x - SUBPIXELS(e2.x), to.y - SUBPIXELS(e2.y)};
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
rw.pos = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool renderCubic(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
|
||||||
{
|
{
|
||||||
printf("moveTo = %f %f\n", pt.x, pt.y);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool lineTo(SwPoint& pt)
|
static bool cubicTo(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
|
||||||
{
|
{
|
||||||
printf("lineTo = %f %f\n", pt.x, pt.y);
|
return renderCubic(rw, ctrl1, ctrl2, to);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool cubicTo(SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& pt)
|
|
||||||
{
|
|
||||||
printf("cubicTo = ctrl1(%f %f) ctrl2(%f %f) pt(%f %f)\n", ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, pt.x, pt.y);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool decomposeOutline(RleWorker& rw)
|
static bool decomposeOutline(RleWorker& rw)
|
||||||
{
|
{
|
||||||
printf("decomposOutline\n");
|
// printf("decomposOutline\n");
|
||||||
auto outline = rw.outline;
|
auto outline = rw.outline;
|
||||||
assert(outline);
|
assert(outline);
|
||||||
|
|
||||||
|
@ -134,7 +402,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;
|
||||||
|
|
||||||
if (!moveTo(outline->pts[first])) return false;
|
moveTo(rw, UPSCALE(outline->pts[first]));
|
||||||
|
|
||||||
while (pt < limit) {
|
while (pt < limit) {
|
||||||
assert(++pt);
|
assert(++pt);
|
||||||
|
@ -142,8 +410,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) {
|
||||||
if (!lineTo(*pt)) return false;
|
lineTo(rw, UPSCALE(*pt));
|
||||||
continue;
|
|
||||||
//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)
|
||||||
|
@ -153,16 +420,16 @@ static bool decomposeOutline(RleWorker& rw)
|
||||||
tags += 2;
|
tags += 2;
|
||||||
|
|
||||||
if (pt <= limit) {
|
if (pt <= limit) {
|
||||||
if (!cubicTo(pt[-2], pt[-1], pt[0])) return false;
|
if (!cubicTo(rw, pt[-2], pt[-1], pt[0])) return false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!cubicTo(pt[-2], pt[-1], outline->pts[first])) return false;
|
if (!cubicTo(rw, pt[-2], pt[-1], outline->pts[first])) return false;
|
||||||
goto close;
|
goto close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Close the contour with a line segment?
|
//Close the contour with a line segment?
|
||||||
//if (!lineTo(outline->pts[first]));
|
//if (!lineTo(rw, outline->pts[first]));
|
||||||
close:
|
close:
|
||||||
first = last + 1;
|
first = last + 1;
|
||||||
}
|
}
|
||||||
|
@ -175,24 +442,6 @@ invalid_outline:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static TCell* findCell(RleWorker& rw)
|
|
||||||
{
|
|
||||||
//TODO:
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void recordCell(RleWorker& rw)
|
|
||||||
{
|
|
||||||
if (rw.area | rw.cover) {
|
|
||||||
TCell* cell = findCell(rw);
|
|
||||||
assert(cell);
|
|
||||||
cell->area += rw.area;
|
|
||||||
cell->cover += rw.cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool genRle(RleWorker& rw)
|
static bool genRle(RleWorker& rw)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
@ -214,7 +463,7 @@ static bool genRle(RleWorker& rw)
|
||||||
bool rleRender(SwShape& sdata)
|
bool rleRender(SwShape& sdata)
|
||||||
{
|
{
|
||||||
constexpr auto RENDER_POOL_SIZE = 16384L;
|
constexpr auto RENDER_POOL_SIZE = 16384L;
|
||||||
constexpr auto BAND_SIZE = 40;
|
constexpr auto BAND_SIZE = 39;
|
||||||
|
|
||||||
auto outline = sdata.outline;
|
auto outline = sdata.outline;
|
||||||
assert(outline);
|
assert(outline);
|
||||||
|
@ -226,42 +475,39 @@ bool rleRender(SwShape& sdata)
|
||||||
|
|
||||||
//TODO: We can preserve several static workers in advance
|
//TODO: We can preserve several static workers in advance
|
||||||
RleWorker rw;
|
RleWorker rw;
|
||||||
TCell buffer[RENDER_POOL_SIZE / sizeof(TCell)];
|
Cell buffer[RENDER_POOL_SIZE / sizeof(Cell)];
|
||||||
|
|
||||||
//Init Cells
|
//Init Cells
|
||||||
rw.buffer = buffer;
|
rw.buffer = buffer;
|
||||||
rw.bufferSize = sizeof(buffer);
|
rw.bufferSize = sizeof(buffer);
|
||||||
rw.yCells = reinterpret_cast<TCell**>(buffer);
|
rw.yCells = reinterpret_cast<Cell**>(buffer);
|
||||||
rw.cells = nullptr;
|
rw.cells = nullptr;
|
||||||
rw.maxCells = 0;
|
rw.maxCells = 0;
|
||||||
rw.numCells = 0;
|
rw.cellsCnt = 0;
|
||||||
rw.area = 0;
|
rw.area = 0;
|
||||||
rw.cover = 0;
|
rw.cover = 0;
|
||||||
rw.invalid = true;
|
rw.invalid = true;
|
||||||
rw.exMin = sdata.bbox.xMin;
|
rw.cellMin = sdata.bbox.min;
|
||||||
rw.exMax = sdata.bbox.xMax;
|
rw.cellMax = sdata.bbox.max;
|
||||||
rw.eyMin = sdata.bbox.yMin;
|
rw.cellXCnt = rw.cellMax.x - rw.cellMin.x;
|
||||||
rw.eyMax = sdata.bbox.yMax;
|
rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
|
||||||
rw.exCnt = rw.exMax - rw.exMin;
|
|
||||||
rw.eyCnt = rw.eyMax - rw.eyMin;
|
|
||||||
rw.outline = outline;
|
rw.outline = outline;
|
||||||
rw.bandSize = rw.bufferSize / (sizeof(TCell) * 8); //bandSize: 64
|
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
|
||||||
rw.bandShoot = 0;
|
rw.bandShoot = 0;
|
||||||
//printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%d), eyCnt(%d), 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
|
||||||
TBand bands[BAND_SIZE];
|
Band bands[BAND_SIZE];
|
||||||
TBand* band;
|
Band* band;
|
||||||
|
|
||||||
/* set up vertical bands */
|
/* set up vertical bands */
|
||||||
auto bandCnt = (rw.eyMax - rw.eyMin) / rw.bandSize;
|
auto bandCnt = static_cast<int>((rw.cellMax.y - rw.cellMin.y) / rw.bandSize);
|
||||||
if (bandCnt == 0) bandCnt = 1;
|
if (bandCnt == 0) bandCnt = 1;
|
||||||
else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE - 1;
|
else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE;
|
||||||
|
|
||||||
auto min = rw.eyMin;
|
auto min = rw.cellMin.y;
|
||||||
auto yMax = rw.eyMax;
|
auto yMax = rw.cellMax.y;
|
||||||
TPos max;
|
SwCoord max;
|
||||||
//printf("bandCnt(%d)\n", bandCnt);
|
|
||||||
|
|
||||||
for (int n = 0; n < bandCnt; ++n, min = max) {
|
for (int n = 0; n < bandCnt; ++n, min = max) {
|
||||||
max = min + rw.bandSize;
|
max = min + rw.bandSize;
|
||||||
|
@ -272,20 +518,20 @@ bool rleRender(SwShape& sdata)
|
||||||
band = bands;
|
band = bands;
|
||||||
|
|
||||||
while (band >= bands) {
|
while (band >= bands) {
|
||||||
rw.yCells = static_cast<TCell**>(rw.buffer);
|
rw.yCells = static_cast<Cell**>(rw.buffer);
|
||||||
rw.yCnt = band->max - band->min;
|
rw.yCnt = band->max - band->min;
|
||||||
|
|
||||||
auto cellStart = sizeof(TCell*) * rw.yCnt;
|
auto cellStart = sizeof(Cell*) * (int)rw.yCnt;
|
||||||
auto cellMod = cellStart % sizeof(TCell);
|
auto cellMod = cellStart % sizeof(Cell);
|
||||||
|
|
||||||
if (cellMod > 0) cellStart += sizeof(TCell) - cellMod;
|
if (cellMod > 0) cellStart += sizeof(Cell) - cellMod;
|
||||||
|
|
||||||
auto cellEnd = rw.bufferSize;
|
auto cellEnd = rw.bufferSize;
|
||||||
cellEnd -= cellEnd % sizeof(TCell);
|
cellEnd -= cellEnd % sizeof(Cell);
|
||||||
//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod);
|
//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod);
|
||||||
|
|
||||||
auto cellsMax = reinterpret_cast<TCell*>((char*)rw.buffer + cellEnd);
|
auto cellsMax = reinterpret_cast<Cell*>((char*)rw.buffer + cellEnd);
|
||||||
rw.cells = reinterpret_cast<TCell*>((char*)rw.buffer + cellStart);
|
rw.cells = reinterpret_cast<Cell*>((char*)rw.buffer + cellStart);
|
||||||
|
|
||||||
if (rw.cells >= cellsMax) goto reduce_bands;
|
if (rw.cells >= cellsMax) goto reduce_bands;
|
||||||
|
|
||||||
|
@ -295,15 +541,15 @@ bool rleRender(SwShape& sdata)
|
||||||
for (auto y = 0; y < rw.yCnt; ++y)
|
for (auto y = 0; y < rw.yCnt; ++y)
|
||||||
rw.yCells[y] = nullptr;
|
rw.yCells[y] = nullptr;
|
||||||
|
|
||||||
rw.numCells = 0;
|
rw.cellsCnt = 0;
|
||||||
rw.invalid = true;
|
rw.invalid = true;
|
||||||
rw.eyMin = band->min;
|
rw.cellMin.y = band->min;
|
||||||
rw.eyMax = band->max;
|
rw.cellMax.y = band->max;
|
||||||
rw.eyCnt = band->max - band->min;
|
rw.cellYCnt = band->max - band->min;
|
||||||
|
|
||||||
if (!genRle(rw)) return -1;
|
if (!genRle(rw)) return -1;
|
||||||
|
|
||||||
rleSweep(rw);
|
sweep(rw);
|
||||||
--band;
|
--band;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -328,7 +574,7 @@ bool rleRender(SwShape& sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rw.bandShoot > 8 && rw.bandSize > 16)
|
if (rw.bandShoot > 8 && rw.bandSize > 16)
|
||||||
rw.bandSize = rw.bandSize / 2;
|
rw.bandSize = (rw.bandSize >> 1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,12 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
static inline SwPoint TO_SWPOINT(const Point* pt)
|
||||||
|
{
|
||||||
|
return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void growOutlineContour(SwOutline& outline, size_t n)
|
static void growOutlineContour(SwOutline& outline, size_t n)
|
||||||
{
|
{
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
@ -57,7 +63,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
|
||||||
|
|
||||||
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<Point*>(realloc(outline.pts, n * sizeof(Point)));
|
outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
|
||||||
assert(outline.pts);
|
assert(outline.pts);
|
||||||
outline.tags = static_cast<char*>(realloc(outline.tags, n * sizeof(char)));
|
outline.tags = static_cast<char*>(realloc(outline.tags, n * sizeof(char)));
|
||||||
assert(outline.tags);
|
assert(outline.tags);
|
||||||
|
@ -74,13 +80,13 @@ static void outlineEnd(SwOutline& outline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void outlineMoveTo(SwOutline& outline, const Point* pt)
|
static void outlineMoveTo(SwOutline& outline, const Point* to)
|
||||||
{
|
{
|
||||||
assert(pt);
|
assert(to);
|
||||||
|
|
||||||
growOutlinePoint(outline, 1);
|
growOutlinePoint(outline, 1);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = *pt;
|
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) {
|
||||||
|
@ -93,34 +99,34 @@ static void outlineMoveTo(SwOutline& outline, const Point* pt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void outlineLineTo(SwOutline& outline, const Point* pt)
|
static void outlineLineTo(SwOutline& outline, const Point* to)
|
||||||
{
|
{
|
||||||
assert(pt);
|
assert(to);
|
||||||
|
|
||||||
growOutlinePoint(outline, 1);
|
growOutlinePoint(outline, 1);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = *pt;
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
||||||
|
|
||||||
++outline.ptsCnt;
|
++outline.ptsCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* pt)
|
static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
|
||||||
{
|
{
|
||||||
assert(ctrl1 && ctrl2 && pt);
|
assert(ctrl1 && ctrl2 && to);
|
||||||
|
|
||||||
growOutlinePoint(outline, 3);
|
growOutlinePoint(outline, 3);
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = *ctrl1;
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
|
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
|
||||||
++outline.ptsCnt;
|
++outline.ptsCnt;
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = *ctrl2;
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
|
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
|
||||||
++outline.ptsCnt;
|
++outline.ptsCnt;
|
||||||
|
|
||||||
outline.pts[outline.ptsCnt] = *ctrl1;
|
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
|
||||||
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
|
||||||
++outline.ptsCnt;
|
++outline.ptsCnt;
|
||||||
}
|
}
|
||||||
|
@ -152,8 +158,8 @@ static bool outlineClose(SwOutline& outline)
|
||||||
|
|
||||||
static void initBBox(SwShape& sdata)
|
static void initBBox(SwShape& sdata)
|
||||||
{
|
{
|
||||||
sdata.bbox.xMin = sdata.bbox.yMin = 0;
|
sdata.bbox.min.x = sdata.bbox.min.y = 0;
|
||||||
sdata.bbox.xMax = sdata.bbox.yMax = 0;
|
sdata.bbox.max.x = sdata.bbox.max.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,7 +177,7 @@ static bool updateBBox(SwShape& sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto xMin = pt->x;
|
auto xMin = pt->x;
|
||||||
auto xMax = pt->y;
|
auto xMax = pt->x;
|
||||||
auto yMin = pt->y;
|
auto yMin = pt->y;
|
||||||
auto yMax = pt->y;
|
auto yMax = pt->y;
|
||||||
|
|
||||||
|
@ -180,14 +186,14 @@ static bool updateBBox(SwShape& sdata)
|
||||||
for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
|
for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
|
||||||
assert(pt);
|
assert(pt);
|
||||||
if (xMin > pt->x) xMin = pt->x;
|
if (xMin > pt->x) xMin = pt->x;
|
||||||
if (xMax < pt->y) xMax = pt->x;
|
if (xMax < pt->x) xMax = pt->x;
|
||||||
if (yMin > pt->y) yMin = pt->y;
|
if (yMin > pt->y) yMin = pt->y;
|
||||||
if (yMax < pt->y) yMax = pt->y;
|
if (yMax < pt->y) yMax = pt->y;
|
||||||
}
|
}
|
||||||
sdata.bbox.xMin = round(xMin - 0.49);
|
sdata.bbox.min.x = xMin >> 6;
|
||||||
sdata.bbox.xMax = round(xMax + 0.49);
|
sdata.bbox.max.x = (xMax + 63) >> 6;
|
||||||
sdata.bbox.yMin = round(yMin - 0.49);
|
sdata.bbox.min.y = yMin >> 6;
|
||||||
sdata.bbox.yMax = round(yMax + 0.49);
|
sdata.bbox.max.y = (yMax + 63) >> 6;
|
||||||
|
|
||||||
if (xMax - xMin < 1 || yMax - yMin < 1) return false;
|
if (xMax - xMin < 1 || yMax - yMin < 1) return false;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ int main(int argc, char **argv)
|
||||||
//Prepare a Shape (Rectangle)
|
//Prepare a Shape (Rectangle)
|
||||||
auto shape1 = tvg::ShapeNode::gen();
|
auto shape1 = tvg::ShapeNode::gen();
|
||||||
shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius
|
shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, corner_radius
|
||||||
shape1->fill(0, 255, 0, 255); //r, g, b, a
|
shape1->fill(0, 255, 0, 255); //r, g, b, a
|
||||||
|
|
||||||
/* Push the shape into the Canvas drawing list
|
/* Push the shape into the Canvas drawing list
|
||||||
When this shape is into the canvas list, the shape could update & prepare
|
When this shape is into the canvas list, the shape could update & prepare
|
||||||
|
|
Loading…
Add table
Reference in a new issue