Added pool alloc for active edges, improved tesselation algo, better guessing of image size
- added pool alloc for active edges - improved tesselation algo - better guessing of image size - reverted tiger to default state
This commit is contained in:
parent
ad2841fccb
commit
8e47686015
@ -3,7 +3,7 @@
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="800" height="800">
|
||||
height="800">
|
||||
<g transform="translate(200,200)" style="fill-opacity:1; fill:none;">
|
||||
<g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
|
||||
<path d="M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z"/>
|
||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
@ -26,6 +26,39 @@
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvgrast.h"
|
||||
|
||||
static float minf(float a, float b) { return a < b ? a : b; }
|
||||
static float maxf(float a, float b) { return a > b ? a : b; }
|
||||
|
||||
static void calcBounds(struct NSVGimage* image, float* bounds)
|
||||
{
|
||||
struct NSVGshape* shape;
|
||||
struct NSVGpath* path;
|
||||
int i;
|
||||
bounds[0] = FLT_MAX;
|
||||
bounds[1] = FLT_MAX;
|
||||
bounds[2] = -FLT_MAX;
|
||||
bounds[3] = -FLT_MAX;
|
||||
for (shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||
for (path = shape->paths; path != NULL; path = path->next) {
|
||||
for (i = 0; i < path->npts; i++) {
|
||||
float* p = &path->pts[i*2];
|
||||
bounds[0] = minf(bounds[0], p[0]);
|
||||
bounds[1] = minf(bounds[1], p[1]);
|
||||
bounds[2] = maxf(bounds[2], p[0]);
|
||||
bounds[3] = maxf(bounds[3], p[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getImageSize(struct NSVGimage *image, int* w, int* h)
|
||||
{
|
||||
float bounds[4];
|
||||
if (image->width < 1 || image->height < 1)
|
||||
calcBounds(image, bounds);
|
||||
*w = image->width < 1 ? (bounds[2]+1) : image->width;
|
||||
*h = image->height < 1 ? (bounds[3]+1) : image->height;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
@ -39,8 +72,7 @@ int main()
|
||||
printf("Could not open SVG image.\n");
|
||||
goto error;
|
||||
}
|
||||
w = image->width;
|
||||
h = image->height;
|
||||
getImageSize(image, &w, &h);
|
||||
if (w < 1 || h < 1) {
|
||||
printf("Size of SVG not specified.\n");
|
||||
goto error;
|
||||
@ -63,9 +95,7 @@ int main()
|
||||
stbi_write_png("svg.png", w, h, 4, img, w*4);
|
||||
|
||||
error:
|
||||
printf("delete rast\n");
|
||||
nsvgDeleteRasterizer(rast);
|
||||
printf("delete image\n");
|
||||
nsvgDelete(image);
|
||||
|
||||
return 0;
|
||||
|
@ -27,26 +27,30 @@ void nsvgDeleteRasterizer(struct NSVGrasterizer*);
|
||||
|
||||
// The polygon rasterization is heavily based on stb_truetype rasterizer by Sean Barrett - http://nothings.org/
|
||||
|
||||
#define NSVG__SUBSAMPLES 5
|
||||
|
||||
#define NSVG__FIXSHIFT 10
|
||||
#define NSVG__FIX (1 << NSVG__FIXSHIFT)
|
||||
#define NSVG__FIXMASK (NSVG__FIX-1)
|
||||
|
||||
#define NSVG__SUBSAMPLES 5
|
||||
#define NSVG__FIXSHIFT 10
|
||||
#define NSVG__FIX (1 << NSVG__FIXSHIFT)
|
||||
#define NSVG__FIXMASK (NSVG__FIX-1)
|
||||
#define NSVG__MEMPAGE_SIZE 1024
|
||||
|
||||
struct NSVGedge {
|
||||
float x0,y0, x1,y1;
|
||||
int dir;
|
||||
// struct NSVGedge* next;
|
||||
struct NSVGedge* next;
|
||||
};
|
||||
|
||||
struct NSVGactedge {
|
||||
struct NSVGactiveEdge {
|
||||
int x,dx;
|
||||
float ey;
|
||||
int dir;
|
||||
struct NSVGactedge *next;
|
||||
struct NSVGactiveEdge *next;
|
||||
};
|
||||
|
||||
struct NSVGmemPage {
|
||||
unsigned char mem[NSVG__MEMPAGE_SIZE];
|
||||
int size;
|
||||
struct NSVGmemPage* next;
|
||||
};
|
||||
|
||||
struct NSVGrasterizer
|
||||
{
|
||||
@ -56,10 +60,9 @@ struct NSVGrasterizer
|
||||
int nedges;
|
||||
int cedges;
|
||||
|
||||
struct NSVGactedge* actedges;
|
||||
int nactedges;
|
||||
int cactedges;
|
||||
struct NSVGactedge* freelist;
|
||||
struct NSVGactiveEdge* freelist;
|
||||
struct NSVGmemPage* pages;
|
||||
struct NSVGmemPage* curpage;
|
||||
|
||||
unsigned char* scanline;
|
||||
int cscanline;
|
||||
@ -73,6 +76,7 @@ struct NSVGrasterizer* nsvgCreateRasterizer()
|
||||
struct NSVGrasterizer* r = (struct NSVGrasterizer*)malloc(sizeof(struct NSVGrasterizer));
|
||||
if (r == NULL) goto error;
|
||||
memset(r, 0, sizeof(struct NSVGrasterizer));
|
||||
|
||||
return r;
|
||||
|
||||
error:
|
||||
@ -82,13 +86,67 @@ error:
|
||||
|
||||
void nsvgDeleteRasterizer(struct NSVGrasterizer* r)
|
||||
{
|
||||
struct NSVGmemPage* p;
|
||||
|
||||
if (r == NULL) return;
|
||||
|
||||
p = r->pages;
|
||||
while (p != NULL) {
|
||||
struct NSVGmemPage* next = p->next;
|
||||
free(p);
|
||||
p = next;
|
||||
}
|
||||
|
||||
if (r->edges) free(r->edges);
|
||||
if (r->actedges) free(r->actedges);
|
||||
if (r->scanline) free(r->scanline);
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
static struct NSVGmemPage* nsvg__nextPage(struct NSVGrasterizer* r, struct NSVGmemPage* cur)
|
||||
{
|
||||
struct NSVGmemPage *newp;
|
||||
|
||||
// If using existing chain, return the next page in chain
|
||||
if (cur != NULL && cur->next != NULL) {
|
||||
return cur->next;
|
||||
}
|
||||
|
||||
// Alloc new page
|
||||
newp = (struct NSVGmemPage*)malloc(sizeof(struct NSVGmemPage));
|
||||
if (newp == NULL) return NULL;
|
||||
memset(newp, 0, sizeof(struct NSVGmemPage));
|
||||
|
||||
// Add to linked list
|
||||
if (cur != NULL)
|
||||
cur->next = newp;
|
||||
else
|
||||
r->pages = newp;
|
||||
|
||||
return newp;
|
||||
}
|
||||
|
||||
static void nsvg__resetPool(struct NSVGrasterizer* r)
|
||||
{
|
||||
struct NSVGmemPage* p = r->pages;
|
||||
while (p != NULL) {
|
||||
p->size = 0;
|
||||
p = p->next;
|
||||
}
|
||||
r->curpage = r->pages;
|
||||
}
|
||||
|
||||
static unsigned char* nsvg__alloc(struct NSVGrasterizer* r, int size)
|
||||
{
|
||||
unsigned char* buf;
|
||||
if (size > NSVG__MEMPAGE_SIZE) return NULL;
|
||||
if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
|
||||
r->curpage = nsvg__nextPage(r, r->curpage);
|
||||
}
|
||||
buf = &r->curpage->mem[r->curpage->size];
|
||||
r->curpage->size += size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void nsvg__addEdge(struct NSVGrasterizer* r, float x0, float y0, float x1, float y1)
|
||||
{
|
||||
@ -122,22 +180,7 @@ static void nsvg__addEdge(struct NSVGrasterizer* r, float x0, float y0, float x1
|
||||
}
|
||||
}
|
||||
|
||||
static float nsvg__distPtSeg(float x, float y, float px, float py, float qx, float qy)
|
||||
{
|
||||
float pqx, pqy, dx, dy, d, t;
|
||||
pqx = qx-px;
|
||||
pqy = qy-py;
|
||||
dx = x-px;
|
||||
dy = y-py;
|
||||
d = pqx*pqx + pqy*pqy;
|
||||
t = pqx*dx + pqy*dy;
|
||||
if (d > 0) t /= d;
|
||||
if (t < 0) t = 0;
|
||||
else if (t > 1) t = 1;
|
||||
dx = px + t*pqx - x;
|
||||
dy = py + t*pqy - y;
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
static float nsvg__absf(float x) { return x < 0 ? -x : x; }
|
||||
|
||||
static void nsvg__flattenCubicBez(struct NSVGrasterizer* r,
|
||||
float x1, float y1, float x2, float y2,
|
||||
@ -145,9 +188,15 @@ static void nsvg__flattenCubicBez(struct NSVGrasterizer* r,
|
||||
float tol, int level)
|
||||
{
|
||||
float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
|
||||
float d;
|
||||
|
||||
if (level > 12) return;
|
||||
if (level > 10) return;
|
||||
|
||||
if (nsvg__absf(x1+x3-x2-x2) + nsvg__absf(y1+y3-y2-y2) + nsvg__absf(x2+x4-x3-x3) + nsvg__absf(y2+y4-y3-y3) < tol) {
|
||||
nsvg__addEdge(r, r->px, r->py, x4, y4);
|
||||
r->px = x4;
|
||||
r->py = y4;
|
||||
return;
|
||||
}
|
||||
|
||||
x12 = (x1+x2)*0.5f;
|
||||
y12 = (y1+y2)*0.5f;
|
||||
@ -162,14 +211,27 @@ static void nsvg__flattenCubicBez(struct NSVGrasterizer* r,
|
||||
x1234 = (x123+x234)*0.5f;
|
||||
y1234 = (y123+y234)*0.5f;
|
||||
|
||||
d = nsvg__distPtSeg(x1234, y1234, x1,y1, x4,y4);
|
||||
if (d > tol*tol) {
|
||||
nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1);
|
||||
nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1);
|
||||
} else {
|
||||
nsvg__addEdge(r, r->px, r->py, x4, y4);
|
||||
r->px = x4;
|
||||
r->py = y4;
|
||||
nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1);
|
||||
nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1);
|
||||
}
|
||||
|
||||
static void nsvg__flattenShape(struct NSVGrasterizer* r,
|
||||
struct NSVGshape* shape, float tx, float ty, float scale)
|
||||
{
|
||||
struct NSVGpath* path;
|
||||
float tol = 0.5f * 4.0f / scale;
|
||||
int i;
|
||||
|
||||
for (path = shape->paths; path != NULL; path = path->next) {
|
||||
// Flatten path
|
||||
r->px = path->pts[0];
|
||||
r->py = path->pts[1];
|
||||
for (i = 0; i < path->npts-1; i += 3) {
|
||||
float* p = &path->pts[i*2];
|
||||
nsvg__flattenCubicBez(r, p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], tol, 0);
|
||||
}
|
||||
// Close path
|
||||
nsvg__addEdge(r, r->px,r->py, path->pts[0],path->pts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,9 +246,9 @@ static int nsvg__cmpEdge(const void *p, const void *q)
|
||||
}
|
||||
|
||||
|
||||
static struct NSVGactedge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVGedge* e, float startPoint)
|
||||
static struct NSVGactiveEdge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVGedge* e, float startPoint)
|
||||
{
|
||||
struct NSVGactedge* z;
|
||||
struct NSVGactiveEdge* z;
|
||||
|
||||
if (r->freelist != NULL) {
|
||||
// Restore from freelist.
|
||||
@ -194,13 +256,8 @@ static struct NSVGactedge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVG
|
||||
r->freelist = z->next;
|
||||
} else {
|
||||
// Alloc new edge.
|
||||
if (r->nactedges+1 > r->cactedges) {
|
||||
r->cactedges = r->cactedges > 0 ? r->cactedges * 2 : 64;
|
||||
r->actedges = (struct NSVGactedge*)realloc(r->actedges, sizeof(struct NSVGactedge) * r->cactedges);
|
||||
if (r->actedges == NULL) return NULL;
|
||||
}
|
||||
z = &r->actedges[r->nactedges];
|
||||
r->nactedges++;
|
||||
z = (struct NSVGactiveEdge*)nsvg__alloc(r, sizeof(struct NSVGactiveEdge));
|
||||
if (z == NULL) return NULL;
|
||||
}
|
||||
|
||||
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
|
||||
@ -219,7 +276,7 @@ static struct NSVGactedge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVG
|
||||
return z;
|
||||
}
|
||||
|
||||
static void nsvg__freeActive(struct NSVGrasterizer* r, struct NSVGactedge* z)
|
||||
static void nsvg__freeActive(struct NSVGrasterizer* r, struct NSVGactiveEdge* z)
|
||||
{
|
||||
z->next = r->freelist;
|
||||
r->freelist = z;
|
||||
@ -228,7 +285,7 @@ static void nsvg__freeActive(struct NSVGrasterizer* r, struct NSVGactedge* z)
|
||||
// note: this routine clips fills that extend off the edges... ideally this
|
||||
// wouldn't happen, but it could happen if the truetype glyph bounding boxes
|
||||
// are wrong, or if the user supplies a too-small bitmap
|
||||
static void nsvg__fillActiveEdges(unsigned char* scanline, int len, struct NSVGactedge* e, int maxWeight, int* xmin, int* xmax)
|
||||
static void nsvg__fillActiveEdges(unsigned char* scanline, int len, struct NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax)
|
||||
{
|
||||
// non-zero winding fill
|
||||
int x0 = 0, w = 0;
|
||||
@ -306,7 +363,7 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co
|
||||
|
||||
static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int color)
|
||||
{
|
||||
struct NSVGactedge *active = NULL;
|
||||
struct NSVGactiveEdge *active = NULL;
|
||||
int y, s;
|
||||
int e = 0;
|
||||
int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
|
||||
@ -319,12 +376,12 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
|
||||
for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
|
||||
// find center of pixel for this scanline
|
||||
float scany = y*NSVG__SUBSAMPLES + s + 0.5f;
|
||||
struct NSVGactedge **step = &active;
|
||||
struct NSVGactiveEdge **step = &active;
|
||||
|
||||
// update all active edges;
|
||||
// remove all active edges that terminate before the center of this scanline
|
||||
while (*step) {
|
||||
struct NSVGactedge *z = *step;
|
||||
struct NSVGactiveEdge *z = *step;
|
||||
if (z->ey <= scany) {
|
||||
*step = z->next; // delete from list
|
||||
// NSVG__assert(z->valid);
|
||||
@ -341,8 +398,8 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
|
||||
step = &active;
|
||||
while (*step && (*step)->next) {
|
||||
if ((*step)->x > (*step)->next->x) {
|
||||
struct NSVGactedge* t = *step;
|
||||
struct NSVGactedge* q = t->next;
|
||||
struct NSVGactiveEdge* t = *step;
|
||||
struct NSVGactiveEdge* q = t->next;
|
||||
t->next = q->next;
|
||||
q->next = t;
|
||||
*step = q;
|
||||
@ -356,7 +413,7 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
|
||||
// insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
|
||||
while (e < r->nedges && r->edges[e].y0 <= scany) {
|
||||
if (r->edges[e].y1 > scany) {
|
||||
struct NSVGactedge* z = nsvg__addActive(r, &r->edges[e], scany);
|
||||
struct NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
|
||||
if (z == NULL) break;
|
||||
// find insertion point
|
||||
if (active == NULL) {
|
||||
@ -367,7 +424,7 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
|
||||
active = z;
|
||||
} else {
|
||||
// find thing to insert AFTER
|
||||
struct NSVGactedge* p = active;
|
||||
struct NSVGactiveEdge* p = active;
|
||||
while (p->next && p->next->x < z->x)
|
||||
p = p->next;
|
||||
// at this point, p->next->x is NOT < z->x
|
||||
@ -390,26 +447,6 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
|
||||
|
||||
}
|
||||
|
||||
static void nsvg__flattenShape(struct NSVGrasterizer* r,
|
||||
struct NSVGshape* shape, float tx, float ty, float scale)
|
||||
{
|
||||
struct NSVGpath* path;
|
||||
float tol = 0.5f * scale;
|
||||
int i;
|
||||
|
||||
for (path = shape->paths; path != NULL; path = path->next) {
|
||||
// Flatten path
|
||||
r->px = path->pts[0];
|
||||
r->py = path->pts[1];
|
||||
for (i = 0; i < path->npts-1; i += 3) {
|
||||
float* p = &path->pts[i*2];
|
||||
nsvg__flattenCubicBez(r, p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], tol, 0);
|
||||
}
|
||||
// Close path
|
||||
nsvg__addEdge(r, r->px,r->py, path->pts[0],path->pts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
|
||||
{
|
||||
int x,y;
|
||||
@ -496,9 +533,9 @@ void nsvgRasterize(struct NSVGrasterizer* r,
|
||||
if (!shape->hasFill)
|
||||
continue;
|
||||
|
||||
r->nedges = 0;
|
||||
r->nactedges = 0;
|
||||
nsvg__resetPool(r);
|
||||
r->freelist = NULL;
|
||||
r->nedges = 0;
|
||||
|
||||
nsvg__flattenShape(r, shape, tx,ty,scale);
|
||||
|
||||
@ -526,4 +563,4 @@ void nsvgRasterize(struct NSVGrasterizer* r,
|
||||
r->stride = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user