awtk/3rd/nanovg/agge/nanovg_agge.cpp

419 lines
12 KiB
C++
Raw Normal View History

2018-09-19 11:21:12 +08:00
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <agge/path.h>
#include <agge/stroke.h>
#include <agge/bitmap.h>
#include <agge/clipper.h>
#include <agge/renderer.h>
#include <agge/rasterizer.h>
#include <agge/raw_bitmap.h>
#include <agge/filling_rules.h>
#include <agge/blenders_generic.h>
#include <agge/vector_rasterizer.h>
#include <agge/stroke_features.h>
#include <agge/nanovg_image_blender.h>
#include <agge/nanovg_vertex.h>
#include <agge/nanovg_agge.h>
template <typename T>
agge::rect<T> mkrect(T x1, T y1, T x2, T y2) {
agge::rect<T> r = {x1, y1, x2, y2};
return r;
}
struct AGGENVGtexture {
int id;
int tex;
int width;
int height;
int type;
int flags;
const uint8_t* data;
};
typedef struct AGGENVGtexture AGGENVGtexture;
struct AGGENVGcontext {
AGGENVGcontext() {
this->w = 0;
this->h = 0;
this->data = NULL;
this->textures = NULL;
this->ntextures = 0;
this->ctextures = 0;
this->textureId = 0;
this->line_style.set_cap(agge::caps::butt());
this->line_style.set_join(agge::joins::bevel());
}
~AGGENVGcontext() {
free(this->textures);
this->textures = NULL;
}
int ntextures;
int ctextures;
int textureId;
AGGENVGtexture* textures;
/*fill/stroke color*/
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
/*frame buffer*/
uint32_t w;
uint32_t h;
uint32_t stride;
2018-09-19 11:21:12 +08:00
uint8_t* data;
2018-10-15 16:19:26 +08:00
enum NVGtexture format;
2018-09-19 11:21:12 +08:00
/*agge related*/
agge::renderer ren;
agge::stroke line_style;
agge::rasterizer<agge::clipper<int> > ras;
};
static int aggenvg__maxi(int a, int b) {
return a > b ? a : b;
}
static AGGENVGtexture* aggenvg__allocTexture(AGGENVGcontext* agge) {
int i;
AGGENVGtexture* tex = NULL;
for (i = 0; i < agge->ntextures; i++) {
if (agge->textures[i].id == 0) {
tex = &agge->textures[i];
break;
}
}
if (tex == NULL) {
if (agge->ntextures + 1 > agge->ctextures) {
AGGENVGtexture* textures;
int ctextures =
aggenvg__maxi(agge->ntextures + 1, 4) + agge->ctextures / 2; // 1.5x Overallocate
textures = (AGGENVGtexture*)realloc(agge->textures, sizeof(AGGENVGtexture) * ctextures);
if (textures == NULL) return NULL;
agge->textures = textures;
agge->ctextures = ctextures;
}
tex = &agge->textures[agge->ntextures++];
}
memset(tex, 0, sizeof(*tex));
tex->id = ++agge->textureId;
return tex;
}
static AGGENVGtexture* aggenvg__findTexture(AGGENVGcontext* agge, int id) {
int i;
for (i = 0; i < agge->ntextures; i++)
if (agge->textures[i].id == id) return &agge->textures[i];
return NULL;
}
static int aggenvg__deleteTexture(AGGENVGcontext* agge, int id) {
int i;
for (i = 0; i < agge->ntextures; i++) {
if (agge->textures[i].id == id) {
memset(&agge->textures[i], 0, sizeof(agge->textures[i]));
return 1;
}
}
return 0;
}
static int aggenvg__renderCreate(void* uptr) {
NVG_NOTUSED(uptr);
return 1;
}
static int aggenvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags,
const unsigned char* data) {
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
AGGENVGtexture* tex = aggenvg__allocTexture(agge);
if (tex == NULL) return 0;
tex->width = w;
tex->height = h;
tex->type = type;
tex->data = data;
tex->flags = imageFlags;
return tex->id;
}
static int aggenvg__renderDeleteTexture(void* uptr, int image) {
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
return aggenvg__deleteTexture(agge, image);
}
static int aggenvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w, int h,
const unsigned char* data) {
NVG_NOTUSED(x);
NVG_NOTUSED(y);
NVG_NOTUSED(w);
NVG_NOTUSED(h);
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
AGGENVGtexture* tex = aggenvg__findTexture(agge, image);
if (tex == NULL) return 0;
tex->data = data;
return 1;
}
static int aggenvg__renderGetTextureSize(void* uptr, int image, int* w, int* h) {
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
AGGENVGtexture* tex = aggenvg__findTexture(agge, image);
if (tex == NULL) return 0;
*w = tex->width;
*h = tex->height;
return 1;
}
2018-10-13 18:40:00 +08:00
static void aggenvg__renderViewport(void* uptr, float width, float height, float devicePixelRatio) {
2018-09-19 11:21:12 +08:00
NVG_NOTUSED(uptr);
NVG_NOTUSED(width);
NVG_NOTUSED(height);
NVG_NOTUSED(devicePixelRatio);
}
static void aggenvg__renderCancel(void* uptr) {
NVG_NOTUSED(uptr);
}
static void aggenvg__renderFlush(void* uptr) {
NVG_NOTUSED(uptr);
}
static void prepareRasterizer(AGGENVGcontext* agge, NVGscissor* scissor, NVGpaint* paint) {
agge::rasterizer<agge::clipper<int> >& ras = agge->ras;
agge::real_t clip_w = scissor->extent[0] * 2;
agge::real_t clip_h = scissor->extent[1] * 2;
agge::real_t clip_x = scissor->xform[4] - scissor->extent[0];
agge::real_t clip_y = scissor->xform[5] - scissor->extent[1];
agge::rect<agge::real_t> clip_r = mkrect(clip_x, clip_y, clip_x + clip_w, clip_y + clip_h);
ras.reset();
if (clip_w > 0 && clip_h > 0) {
ras.set_clipping(clip_r);
}
agge->r = paint->innerColor.r * 0xff;
agge->g = paint->innerColor.g * 0xff;
agge->b = paint->innerColor.b * 0xff;
agge->a = paint->innerColor.a * 0xff;
}
template <typename PixelT>
2018-09-26 15:40:55 +08:00
void renderPaint(AGGENVGcontext* agge, NVGpaint* paint) {
2018-09-19 11:21:12 +08:00
agge::renderer& ren = agge->ren;
agge::rasterizer<agge::clipper<int> >& ras = agge->ras;
agge::bitmap<PixelT, agge::raw_bitmap> surface(agge->w, agge->h, agge->stride, agge->data);
2018-09-19 11:21:12 +08:00
if (paint->image > 0) {
float invxform[6];
AGGENVGtexture* tex = aggenvg__findTexture(agge, paint->image);
nvgTransformInverse(invxform, paint->xform);
switch (tex->type) {
case NVG_TEXTURE_RGBA: {
typedef agge::bitmap<agge::pixel32_rgba, agge::raw_bitmap> rgba_bitmap_t;
rgba_bitmap_t src(tex->width, tex->height, tex->width*4, (uint8_t*)(tex->data));
2018-09-19 11:21:12 +08:00
agge::nanovg_image_blender<PixelT, rgba_bitmap_t> color(&src, (float*)invxform);
ren(surface, 0, ras, color, agge::winding<>());
break;
}
case NVG_TEXTURE_BGRA: {
typedef agge::bitmap<agge::pixel32_bgra, agge::raw_bitmap> bgra_bitmap_t;
bgra_bitmap_t src(tex->width, tex->height, tex->width*4, (uint8_t*)(tex->data));
2018-09-19 11:21:12 +08:00
agge::nanovg_image_blender<PixelT, bgra_bitmap_t> color(&src, (float*)invxform);
ren(surface, 0, ras, color, agge::winding<>());
break;
}
2018-10-10 17:30:59 +08:00
case NVG_TEXTURE_BGR565: {
2018-09-20 10:28:31 +08:00
typedef agge::bitmap<agge::pixel16_bgr565, agge::raw_bitmap> bgr565_bitmap_t;
bgr565_bitmap_t src(tex->width, tex->height, tex->width*2, (uint8_t*)(tex->data));
2018-09-20 10:28:31 +08:00
agge::nanovg_image_blender<PixelT, bgr565_bitmap_t> color(&src, (float*)invxform);
2018-09-19 11:21:12 +08:00
ren(surface, 0, ras, color, agge::winding<>());
break;
}
case NVG_TEXTURE_RGB: {
typedef agge::bitmap<agge::pixel24_rgb, agge::raw_bitmap> rgb_bitmap_t;
rgb_bitmap_t src(tex->width, tex->height, tex->width*3, (uint8_t*)(tex->data));
2018-09-19 11:21:12 +08:00
agge::nanovg_image_blender<PixelT, rgb_bitmap_t> color(&src, (float*)invxform);
ren(surface, 0, ras, color, agge::winding<>());
break;
}
default: {
assert(!"not supported format");
break;
}
}
} else {
agge::blender_solid_color_rgb<PixelT> color(agge->r, agge->g, agge->b, agge->a);
ren(surface, 0, ras, color, agge::winding<>());
}
}
2018-09-26 15:40:55 +08:00
template <typename PixelT>
void renderFill(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation,
NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths,
int npaths) {
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
agge::rasterizer<agge::clipper<int> >& ras = agge->ras;
prepareRasterizer(agge, scissor, paint);
for (int i = 0; i < npaths; i++) {
const NVGpath* p = paths + i;
for (int j = 0; j < p->nfill; j++) {
const NVGvertex* v = p->fill + j;
if (j == 0) {
ras.move_to(v->x, v->y);
} else {
ras.line_to(v->x, v->y);
}
}
ras.close_polygon();
}
ras.sort();
renderPaint<PixelT>(agge, paint);
}
2018-09-19 11:21:12 +08:00
template <typename PixelT>
void renderStroke(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation,
NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths,
int npaths) {
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
agge::stroke& line_style = agge->line_style;
agge::rasterizer<agge::clipper<int> >& ras = agge->ras;
line_style.width(strokeWidth);
prepareRasterizer(agge, scissor, paint);
for (int i = 0; i < npaths; i++) {
const NVGpath* p = paths + i;
agge::nanovg_vertex::iterator iter(p->stroke, p->nstroke);
agge::path_generator_adapter<agge::nanovg_vertex::iterator, agge::stroke> path_gen(iter,
line_style);
add_path(ras, path_gen);
}
ras.sort();
2018-09-26 15:40:55 +08:00
renderPaint<PixelT>(agge, paint);
2018-09-19 11:21:12 +08:00
}
template <typename PixelT>
void renderTriangles(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation,
NVGscissor* scissor, const NVGvertex* verts, int nverts) {
2018-09-26 15:40:55 +08:00
/*XXX: not used yet*/
2018-09-19 11:21:12 +08:00
}
static void aggenvg__renderDelete(void* uptr) {
AGGENVGcontext* agge = (AGGENVGcontext*)uptr;
if (agge == NULL) return;
delete agge;
}
static void nvgInitAGGE(AGGENVGcontext* agge, NVGparams* params, uint32_t w, uint32_t h, uint32_t stride,
2018-10-15 16:19:26 +08:00
enum NVGtexture format, uint8_t* data) {
2018-09-19 11:21:12 +08:00
agge->w = w;
agge->h = h;
agge->data = data;
agge->stride = stride;
2018-09-19 11:21:12 +08:00
agge->format = format;
params->renderTriangles = NULL;
2018-09-19 11:21:12 +08:00
switch (agge->format) {
2018-10-15 16:19:26 +08:00
case NVG_TEXTURE_RGBA: {
2018-09-21 12:31:38 +08:00
params->renderStroke = renderStroke<agge::pixel32_rgba>;
params->renderFill = renderFill<agge::pixel32_rgba>;
2018-09-19 11:21:12 +08:00
break;
}
2018-10-15 16:19:26 +08:00
case NVG_TEXTURE_BGRA: {
2018-09-21 12:31:38 +08:00
params->renderStroke = renderStroke<agge::pixel32_bgra>;
params->renderFill = renderFill<agge::pixel32_bgra>;
2018-09-19 11:21:12 +08:00
break;
}
2018-10-15 16:19:26 +08:00
case NVG_TEXTURE_RGB: {
2018-09-21 12:31:38 +08:00
params->renderStroke = renderStroke<agge::pixel24_rgb>;
params->renderFill = renderFill<agge::pixel24_rgb>;
2018-09-19 11:21:12 +08:00
break;
}
2018-10-15 16:19:26 +08:00
case NVG_TEXTURE_BGR: {
2018-10-10 17:30:59 +08:00
params->renderStroke = renderStroke<agge::pixel24_bgr>;
params->renderFill = renderFill<agge::pixel24_bgr>;
break;
}
2018-10-15 16:19:26 +08:00
case NVG_TEXTURE_BGR565: {
2018-09-21 12:31:38 +08:00
params->renderStroke = renderStroke<agge::pixel16_bgr565>;
params->renderFill = renderFill<agge::pixel16_bgr565>;
2018-09-19 11:21:12 +08:00
break;
}
default: {
assert(!"not supported format");
break;
}
}
2018-09-21 12:31:38 +08:00
}
void nvgReinitAgge(NVGcontext* ctx, uint32_t w, uint32_t h, uint32_t stride, enum NVGtexture format,
2018-09-21 12:31:38 +08:00
uint8_t* data) {
NVGparams* params = nvgGetParams(ctx);
AGGENVGcontext* agge = (AGGENVGcontext*)(params->userPtr);
nvgInitAGGE(agge, params, w, h, stride, format, data);
2018-09-21 12:31:38 +08:00
}
NVGcontext* nvgCreateAGGE(uint32_t w, uint32_t h, uint32_t stride, enum NVGtexture format, uint8_t* data) {
2018-09-21 12:31:38 +08:00
NVGparams params;
NVGcontext* ctx = NULL;
AGGENVGcontext* agge = new AGGENVGcontext();
if (agge == NULL) goto error;
memset(&params, 0, sizeof(params));
params.renderCreate = aggenvg__renderCreate;
params.renderCreateTexture = aggenvg__renderCreateTexture;
params.renderDeleteTexture = aggenvg__renderDeleteTexture;
params.renderUpdateTexture = aggenvg__renderUpdateTexture;
params.renderGetTextureSize = aggenvg__renderGetTextureSize;
params.renderViewport = aggenvg__renderViewport;
params.renderCancel = aggenvg__renderCancel;
params.renderFlush = aggenvg__renderFlush;
params.renderDelete = aggenvg__renderDelete;
params.userPtr = agge;
params.edgeAntiAlias = 1;
nvgInitAGGE(agge, &params, w, h, stride, format, data);
2018-09-19 11:21:12 +08:00
ctx = nvgCreateInternal(&params);
if (ctx == NULL) goto error;
return ctx;
error:
if (ctx != NULL) nvgDeleteInternal(ctx);
return NULL;
}
void nvgDeleteAGGE(NVGcontext* ctx) {
nvgDeleteInternal(ctx);
}