Browse Source

Merge pull request #229 from jpcima/update-nanovg

Update NanoVG
pull/264/head
JP Cimalando GitHub 3 years ago
parent
commit
6ec074d14d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 9945 additions and 3477 deletions
  1. +9
    -1
      dgl/src/NanoVG.cpp
  2. +176
    -62
      dgl/src/nanovg/fontstash.h
  3. +268
    -94
      dgl/src/nanovg/nanovg.c
  4. +95
    -18
      dgl/src/nanovg/nanovg.h
  5. +197
    -62
      dgl/src/nanovg/nanovg_gl.h
  6. +29
    -7
      dgl/src/nanovg/nanovg_gl_utils.h
  7. +4160
    -1152
      dgl/src/nanovg/stb_image.h
  8. +5011
    -2081
      dgl/src/nanovg/stb_truetype.h

+ 9
- 1
dgl/src/NanoVG.cpp View File

@@ -66,15 +66,23 @@ DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
#if defined(NANOVG_GL2)
# define nvgCreateGL nvgCreateGL2
# define nvgDeleteGL nvgDeleteGL2
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGL2
# define nvglImageHandle nvglImageHandleGL2
#elif defined(NANOVG_GL3)
# define nvgCreateGL nvgCreateGL3
# define nvgDeleteGL nvgDeleteGL3
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGL3
# define nvglImageHandle nvglImageHandleGL3
#elif defined(NANOVG_GLES2)
# define nvgCreateGL nvgCreateGLES2
# define nvgDeleteGL nvgDeleteGLES2
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES2
# define nvglImageHandle nvglImageHandleGLES2
#elif defined(NANOVG_GLES3)
# define nvgCreateGL nvgCreateGLES3
# define nvgDeleteGL nvgDeleteGLES3
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES3
# define nvglImageHandle nvglImageHandleGLES3
#endif

static NVGcontext* nvgCreateGL_helper(int flags)
@@ -922,7 +930,7 @@ void NanoVG::loadSharedResources()

using namespace dpf_resources;

nvgCreateFontMem(fContext, NANOVG_DEJAVU_SANS_TTF, (const uchar*)dejavusans_ttf, dejavusans_ttf_size, 0);
nvgCreateFontMem(fContext, NANOVG_DEJAVU_SANS_TTF, (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0);
}
#endif



+ 176
- 62
dgl/src/nanovg/fontstash.h View File

@@ -38,10 +38,15 @@ enum FONSalign {
FONS_ALIGN_BASELINE = 1<<6, // Default
};

enum FONSglyphBitmap {
FONS_GLYPH_BITMAP_OPTIONAL = 1,
FONS_GLYPH_BITMAP_REQUIRED = 2,
};

enum FONSerrorCode {
// Font atlas is full.
FONS_ATLAS_FULL = 1,
// Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
// Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
FONS_SCRATCH_FULL = 2,
// Calls to fonsPushState has created too large stack, if you need deep state stack bump up FONS_MAX_STATES.
FONS_STATES_OVERFLOW = 3,
@@ -78,6 +83,7 @@ struct FONStextIter {
const char* next;
const char* end;
unsigned int utf8state;
int bitmapOption;
};
typedef struct FONStextIter FONStextIter;

@@ -90,14 +96,14 @@ void fonsDeleteInternal(FONScontext* s);
void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
// Returns current atlas size.
void fonsGetAtlasSize(FONScontext* s, int* width, int* height);
// Expands the atlas size.
// Expands the atlas size.
int fonsExpandAtlas(FONScontext* s, int width, int height);
// Resets the whole stash.
int fonsResetAtlas(FONScontext* stash, int width, int height);

// Add fonts
int fonsAddFont(FONScontext* s, const char* name, const char* path);
int fonsAddFontMem(FONScontext* s, const char* name, const unsigned char* data, int ndata, int freeData);
int fonsAddFont(FONScontext* s, const char* name, const char* path, int fontIndex);
int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData, int fontIndex);
int fonsGetFontByName(FONScontext* s, const char* name);

// State handling
@@ -122,7 +128,7 @@ void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);

// Text iterator
int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end);
int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end, int bitmapOption);
int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad);

// Pull texture changes
@@ -154,20 +160,28 @@ typedef struct FONSttFontImpl FONSttFontImpl;
static FT_Library ftLibrary;

int fons__tt_init(FONScontext *context)
{
{
FT_Error ftError;
FONS_NOTUSED(context);
FONS_NOTUSED(context);
ftError = FT_Init_FreeType(&ftLibrary);
return ftError == 0;
}

int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, const unsigned char *data, int dataSize)
int fons__tt_done(FONScontext *context)
{
FT_Error ftError;
FONS_NOTUSED(context);
ftError = FT_Done_FreeType(ftLibrary);
return ftError == 0;
}

int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
{
FT_Error ftError;
FONS_NOTUSED(context);

//font->font.userdata = stash;
ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, 0, &font->font);
ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, fontIndex, &font->font);
return ftError == 0;
}

@@ -180,7 +194,12 @@ void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, i

float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
{
#if 1
// Note(DPF) maintain pixel-based units for compat after nanovg update
return size / (font->font->ascender - font->font->descender);
#else
return size / font->font->units_per_EM;
#endif
}

int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
@@ -193,16 +212,28 @@ int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float
{
FT_Error ftError;
FT_GlyphSlot ftGlyph;
FT_Fixed advFixed;
FONS_NOTUSED(scale);

#if 1
// Note(DPF) maintain pixel-based units for compat after nanovg update
ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));
#else
ftError = FT_Set_Pixel_Sizes(font->font, 0, size);
#endif
if (ftError) return 0;
#if 1
// Note(DPF) maintain pixel-based units for compat after nanovg update
ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);
#else
ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
#endif
if (ftError) return 0;
ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, (FT_Fixed*)advance);
ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
if (ftError) return 0;
ftGlyph = font->font->glyph;
*lsb = ftGlyph->metrics.horiBearingX;
*advance = (int)advFixed;
*lsb = (int)ftGlyph->metrics.horiBearingX;
*x0 = ftGlyph->bitmap_left;
*x1 = *x0 + ftGlyph->bitmap.width;
*y0 = -ftGlyph->bitmap_top;
@@ -215,7 +246,7 @@ void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int
{
FT_GlyphSlot ftGlyph = font->font->glyph;
int ftGlyphOffset = 0;
int x, y;
unsigned int x, y;
FONS_NOTUSED(outWidth);
FONS_NOTUSED(outHeight);
FONS_NOTUSED(scaleX);
@@ -233,7 +264,7 @@ int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
{
FT_Vector ftKerning;
FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
return ftKerning.x;
return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer
}

#else
@@ -256,13 +287,24 @@ int fons__tt_init(FONScontext *context)
return 1;
}

int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, const unsigned char *data, int dataSize)
int fons__tt_done(FONScontext *context)
{
FONS_NOTUSED(context);
return 1;
}

int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
{
int stbError;
int offset, stbError;
FONS_NOTUSED(dataSize);

font->font.userdata = context;
stbError = stbtt_InitFont(&font->font, data, 0);
offset = stbtt_GetFontOffsetForIndex(data, fontIndex);
if (offset == -1) {
stbError = 0;
} else {
stbError = stbtt_InitFont(&font->font, data, offset);
}
return stbError;
}

@@ -273,7 +315,12 @@ void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, i

float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
{
#if 1
// Note(DPF) maintain pixel-based units for compat after nanovg update
return stbtt_ScaleForPixelHeight(&font->font, size);
#else
return stbtt_ScaleForMappingEmToPixels(&font->font, size);
#endif
}

int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
@@ -304,7 +351,7 @@ int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
#endif

#ifndef FONS_SCRATCH_BUF_SIZE
# define FONS_SCRATCH_BUF_SIZE 16000
# define FONS_SCRATCH_BUF_SIZE 96000
#endif
#ifndef FONS_HASH_LUT_SIZE
# define FONS_HASH_LUT_SIZE 256
@@ -324,6 +371,9 @@ int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
#ifndef FONS_MAX_STATES
# define FONS_MAX_STATES 20
#endif
#ifndef FONS_MAX_FALLBACKS
# define FONS_MAX_FALLBACKS 20
#endif

static unsigned int fons__hashint(unsigned int a)
{
@@ -361,7 +411,7 @@ struct FONSfont
{
FONSttFontImpl font;
char name[64];
const unsigned char* data;
unsigned char* data;
int dataSize;
unsigned char freeData;
float ascender;
@@ -371,6 +421,8 @@ struct FONSfont
int cglyphs;
int nglyphs;
int lut[FONS_HASH_LUT_SIZE];
int fallbacks[FONS_MAX_FALLBACKS];
int nfallbacks;
};
typedef struct FONSfont FONSfont;

@@ -421,6 +473,8 @@ struct FONScontext
void* errorUptr;
};

#ifdef STB_TRUETYPE_IMPLEMENTATION

static void* fons__tmpalloc(size_t size, void* up)
{
unsigned char* ptr;
@@ -446,6 +500,8 @@ static void fons__tmpfree(void* ptr, void* up)
// empty
}

#endif // STB_TRUETYPE_IMPLEMENTATION

// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

@@ -751,6 +807,27 @@ static FONSstate* fons__getState(FONScontext* stash)
return &stash->states[stash->nstates-1];
}

int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
{
FONSfont* baseFont = stash->fonts[base];
if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
return 1;
}
return 0;
}

void fonsResetFallbackFont(FONScontext* stash, int base)
{
int i;

FONSfont* baseFont = stash->fonts[base];
baseFont->nfallbacks = 0;
baseFont->nglyphs = 0;
for (i = 0; i < FONS_HASH_LUT_SIZE; i++)
baseFont->lut[i] = -1;
}

void fonsSetSize(FONScontext* stash, float size)
{
fons__getState(stash)->size = size;
@@ -818,7 +895,7 @@ static void fons__freeFont(FONSfont* font)
{
if (font == NULL) return;
if (font->glyphs) free(font->glyphs);
if (font->freeData && font->data) free((void*)font->data);
if (font->freeData && font->data) free(font->data);
free(font);
}

@@ -849,12 +926,12 @@ error:
return FONS_INVALID;
}

int fonsAddFont(FONScontext* stash, const char* name, const char* path)
int fonsAddFont(FONScontext* stash, const char* name, const char* path, int fontIndex)
{
FILE* fp = 0;
int dataSize = 0;
size_t readed;
unsigned char* data = NULL;
size_t ignore;

// Read in the font data.
fp = fopen(path, "rb");
@@ -864,21 +941,20 @@ int fonsAddFont(FONScontext* stash, const char* name, const char* path)
fseek(fp,0,SEEK_SET);
data = (unsigned char*)malloc(dataSize);
if (data == NULL) goto error;
ignore = fread(data, 1, dataSize, fp);
readed = fread(data, 1, dataSize, fp);
fclose(fp);
fp = 0;
if (readed != (size_t)dataSize) goto error;

return fonsAddFontMem(stash, name, data, dataSize, 1);
return fonsAddFontMem(stash, name, data, dataSize, 1, fontIndex);

error:
if (data) free(data);
if (fp) fclose(fp);
return FONS_INVALID;

FONS_NOTUSED(ignore);
}

int fonsAddFontMem(FONScontext* stash, const char* name, const unsigned char* data, int dataSize, int freeData)
int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData, int fontIndex)
{
int i, ascent, descent, fh, lineGap;
FONSfont* font;
@@ -903,15 +979,16 @@ int fonsAddFontMem(FONScontext* stash, const char* name, const unsigned char* da

// Init font
stash->nscratch = 0;
if (!fons__tt_loadFont(stash, &font->font, data, dataSize)) goto error;
if (!fons__tt_loadFont(stash, &font->font, data, dataSize, fontIndex)) goto error;

// Store normalized line height. The real line height is got
// by multiplying the lineh by font size.
fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
ascent += lineGap;
fh = ascent - descent;
font->ascender = (float)ascent / (float)fh;
font->descender = (float)descent / (float)fh;
font->lineh = (float)(fh + lineGap) / (float)fh;
font->lineh = font->ascender - font->descender;

return idx;

@@ -1010,7 +1087,7 @@ static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int
}

static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
short isize, short iblur)
short isize, short iblur, int bitmapOption)
{
int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
float scale;
@@ -1020,6 +1097,7 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
int pad, added;
unsigned char* bdst;
unsigned char* dst;
FONSfont* renderFont = font;

if (isize < 2) return NULL;
if (iblur > 20) iblur = 20;
@@ -1032,32 +1110,66 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
i = font->lut[h];
while (i != -1) {
if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur)
return &font->glyphs[i];
if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur) {
glyph = &font->glyphs[i];
if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL || (glyph->x0 >= 0 && glyph->y0 >= 0)) {
return glyph;
}
// At this point, glyph exists but the bitmap data is not yet created.
break;
}
i = font->glyphs[i].next;
}

// Could not find glyph, create it.
scale = fons__tt_getPixelHeightScale(&font->font, size);
// Create a new glyph or rasterize bitmap data for a cached glyph.
g = fons__tt_getGlyphIndex(&font->font, codepoint);
fons__tt_buildGlyphBitmap(&font->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
// Try to find the glyph in fallback fonts.
if (g == 0) {
for (i = 0; i < font->nfallbacks; ++i) {
FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
if (fallbackIndex != 0) {
g = fallbackIndex;
renderFont = fallbackFont;
break;
}
}
// It is possible that we did not find a fallback glyph.
// In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
}
scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
gw = x1-x0 + pad*2;
gh = y1-y0 + pad*2;

// Find free spot for the rect in the atlas
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
if (added == 0 && stash->handleError != NULL) {
// Atlas is full, let the user to resize the atlas (or not), and try again.
stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
// Determines the spot to draw glyph in the atlas.
if (bitmapOption == FONS_GLYPH_BITMAP_REQUIRED) {
// Find free spot for the rect in the atlas
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
if (added == 0 && stash->handleError != NULL) {
// Atlas is full, let the user to resize the atlas (or not), and try again.
stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
}
if (added == 0) return NULL;
} else {
// Negative coordinate indicates there is no bitmap data created.
gx = -1;
gy = -1;
}
if (added == 0) return NULL;

// Init glyph.
glyph = fons__allocGlyph(font);
glyph->codepoint = codepoint;
glyph->size = isize;
glyph->blur = iblur;
if (glyph == NULL) {
glyph = fons__allocGlyph(font);
glyph->codepoint = codepoint;
glyph->size = isize;
glyph->blur = iblur;
glyph->next = 0;

// Insert char to hash lookup.
glyph->next = font->lut[h];
font->lut[h] = font->nglyphs-1;
}
glyph->index = g;
glyph->x0 = (short)gx;
glyph->y0 = (short)gy;
@@ -1066,15 +1178,14 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
glyph->xadv = (short)(scale * advance * 10.0f);
glyph->xoff = (short)(x0 - pad);
glyph->yoff = (short)(y0 - pad);
glyph->next = 0;

// Insert char to hash lookup.
glyph->next = font->lut[h];
font->lut[h] = font->nglyphs-1;
if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL) {
return glyph;
}

// Rasterize
dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
fons__tt_renderGlyphBitmap(&font->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g);
fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale, scale, g);

// Make sure there is one pixel empty border.
dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
@@ -1101,7 +1212,7 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
if (iblur > 0) {
stash->nscratch = 0;
bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
fons__blur(stash, bdst, gw, gh, stash->params.width, iblur);
}

stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
@@ -1134,8 +1245,8 @@ static void fons__getQuad(FONScontext* stash, FONSfont* font,
y1 = (float)(glyph->y1-1);

if (stash->params.flags & FONS_ZERO_TOPLEFT) {
rx = (float)(int)(*x + xoff);
ry = (float)(int)(*y + yoff);
rx = floorf(*x + xoff);
ry = floorf(*y + yoff);

q->x0 = rx;
q->y0 = ry;
@@ -1147,8 +1258,8 @@ static void fons__getQuad(FONScontext* stash, FONSfont* font,
q->s1 = x1 * stash->itw;
q->t1 = y1 * stash->ith;
} else {
rx = (float)(int)(*x + xoff);
ry = (float)(int)(*y - yoff);
rx = floorf(*x + xoff);
ry = floorf(*y - yoff);

q->x0 = rx;
q->y0 = ry;
@@ -1226,7 +1337,7 @@ float fonsDrawText(FONScontext* stash,
const char* str, const char* end)
{
FONSstate* state = fons__getState(stash);
unsigned int codepoint = 0;
unsigned int codepoint;
unsigned int utf8state = 0;
FONSglyph* glyph = NULL;
FONSquad q;
@@ -1263,7 +1374,7 @@ float fonsDrawText(FONScontext* stash,
for (; str != end; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_REQUIRED);
if (glyph != NULL) {
fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);

@@ -1286,7 +1397,7 @@ float fonsDrawText(FONScontext* stash,
}

int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
float x, float y, const char* str, const char* end)
float x, float y, const char* str, const char* end, int bitmapOption)
{
FONSstate* state = fons__getState(stash);
float width;
@@ -1326,6 +1437,7 @@ int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
iter->end = end;
iter->codepoint = 0;
iter->prevGlyphIndex = -1;
iter->bitmapOption = bitmapOption;

return 1;
}
@@ -1346,7 +1458,8 @@ int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
// Get glyph and quad
iter->x = iter->nextx;
iter->y = iter->nexty;
glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur);
glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur, iter->bitmapOption);
// If the iterator was initialized with FONS_GLYPH_BITMAP_OPTIONAL, then the UV coordinates of the quad will be invalid.
if (glyph != NULL)
fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1;
@@ -1406,12 +1519,12 @@ void fonsDrawDebug(FONScontext* stash, float x, float y)
}

float fonsTextBounds(FONScontext* stash,
float x, float y,
float x, float y,
const char* str, const char* end,
float* bounds)
{
FONSstate* state = fons__getState(stash);
unsigned int codepoint = 0;
unsigned int codepoint;
unsigned int utf8state = 0;
FONSquad q;
FONSglyph* glyph = NULL;
@@ -1443,7 +1556,7 @@ float fonsTextBounds(FONScontext* stash,
for (; str != end; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL);
if (glyph != NULL) {
fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
if (q.x0 < minx) minx = q.x0;
@@ -1568,6 +1681,7 @@ void fonsDeleteInternal(FONScontext* stash)
if (stash->texData) free(stash->texData);
if (stash->scratch) free(stash->scratch);
free(stash);
fons__tt_done(stash);
}

void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
@@ -1594,7 +1708,7 @@ int fonsExpandAtlas(FONScontext* stash, int width, int height)
height = fons__maxi(height, stash->params.height);

if (width == stash->params.width && height == stash->params.height)
return 1;
return 1;

// Flush pending glyphs.
fons__flush(stash);


+ 268
- 94
dgl/src/nanovg/nanovg.c View File

@@ -16,8 +16,11 @@
// 3. This notice may not be removed or altered from any source distribution.
//

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <memory.h>

#include "nanovg.h"
#define FONTSTASH_IMPLEMENTATION
#include "fontstash.h"
@@ -63,6 +66,8 @@ enum NVGpointFlags
};

struct NVGstate {
NVGcompositeOperationState compositeOperation;
int shapeAntiAlias;
NVGpaint fill;
NVGpaint stroke;
float strokeWidth;
@@ -200,6 +205,84 @@ static void nvg__setDevicePixelRatio(NVGcontext* ctx, float ratio)
ctx->devicePxRatio = ratio;
}

static NVGcompositeOperationState nvg__compositeOperationState(int op)
{
int sfactor, dfactor;

if (op == NVG_SOURCE_OVER)
{
sfactor = NVG_ONE;
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
}
else if (op == NVG_SOURCE_IN)
{
sfactor = NVG_DST_ALPHA;
dfactor = NVG_ZERO;
}
else if (op == NVG_SOURCE_OUT)
{
sfactor = NVG_ONE_MINUS_DST_ALPHA;
dfactor = NVG_ZERO;
}
else if (op == NVG_ATOP)
{
sfactor = NVG_DST_ALPHA;
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
}
else if (op == NVG_DESTINATION_OVER)
{
sfactor = NVG_ONE_MINUS_DST_ALPHA;
dfactor = NVG_ONE;
}
else if (op == NVG_DESTINATION_IN)
{
sfactor = NVG_ZERO;
dfactor = NVG_SRC_ALPHA;
}
else if (op == NVG_DESTINATION_OUT)
{
sfactor = NVG_ZERO;
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
}
else if (op == NVG_DESTINATION_ATOP)
{
sfactor = NVG_ONE_MINUS_DST_ALPHA;
dfactor = NVG_SRC_ALPHA;
}
else if (op == NVG_LIGHTER)
{
sfactor = NVG_ONE;
dfactor = NVG_ONE;
}
else if (op == NVG_COPY)
{
sfactor = NVG_ONE;
dfactor = NVG_ZERO;
}
else if (op == NVG_XOR)
{
sfactor = NVG_ONE_MINUS_DST_ALPHA;
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
}
else
{
sfactor = NVG_ONE;
dfactor = NVG_ZERO;
}

NVGcompositeOperationState state;
state.srcRGB = sfactor;
state.dstRGB = dfactor;
state.srcAlpha = sfactor;
state.dstAlpha = dfactor;
return state;
}

static NVGstate* nvg__getState(NVGcontext* ctx)
{
return &ctx->states[ctx->nstates-1];
}

NVGcontext* nvgCreateInternal(NVGparams* params)
{
FONSparams fontParams;
@@ -280,7 +363,7 @@ void nvgDeleteInternal(NVGcontext* ctx)
free(ctx);
}

void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio)
void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio)
{
/* printf("Tris: draws:%d fill:%d stroke:%d text:%d TOT:%d\n",
ctx->drawCallCount, ctx->fillTriCount, ctx->strokeTriCount, ctx->textTriCount,
@@ -291,8 +374,8 @@ void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float dev
nvgReset(ctx);

nvg__setDevicePixelRatio(ctx, devicePixelRatio);
ctx->params.renderViewport(ctx->params.userPtr, windowWidth, windowHeight);
ctx->params.renderViewport(ctx->params.userPtr, windowWidth, windowHeight, devicePixelRatio);

ctx->drawCallCount = 0;
ctx->fillTriCount = 0;
@@ -383,7 +466,7 @@ NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u)
{
int i;
float oneminu;
NVGcolor cint;
NVGcolor cint = {{{0}}};

u = nvg__clampf(u, 0.0f, 1.0f);
oneminu = 1.0f - u;
@@ -391,7 +474,7 @@ NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u)
{
cint.rgba[i] = c0.rgba[i] * oneminu + c1.rgba[i] * u;
}
return cint;
}

@@ -430,12 +513,6 @@ NVGcolor nvgHSLA(float h, float s, float l, unsigned char a)
return col;
}


static NVGstate* nvg__getState(NVGcontext* ctx)
{
return &ctx->states[ctx->nstates-1];
}

void nvgTransformIdentity(float* t)
{
t[0] = 1.0f; t[1] = 0.0f;
@@ -568,6 +645,8 @@ void nvgReset(NVGcontext* ctx)

nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255));
nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255));
state->compositeOperation = nvg__compositeOperationState(NVG_SOURCE_OVER);
state->shapeAntiAlias = 1;
state->strokeWidth = 1.0f;
state->miterLimit = 10.0f;
state->lineCap = NVG_BUTT;
@@ -587,6 +666,12 @@ void nvgReset(NVGcontext* ctx)
}

// State setting
void nvgShapeAntiAlias(NVGcontext* ctx, int enabled)
{
NVGstate* state = nvg__getState(ctx);
state->shapeAntiAlias = enabled;
}

void nvgStrokeWidth(NVGcontext* ctx, float width)
{
NVGstate* state = nvg__getState(ctx);
@@ -719,7 +804,7 @@ int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags)
return image;
}

int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, const unsigned char* data, int ndata)
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata)
{
int w, h, n, image;
unsigned char* img = stbi_load_from_memory(data, ndata, &w, &h, &n, 4);
@@ -913,7 +998,7 @@ void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h)
}

// Transform the current scissor rect into current transform space.
// If there is difference in rotation, this will be approximation.
// If there is difference in rotation, this will be approximation.
memcpy(pxform, state->scissor.xform, sizeof(float)*6);
ex = state->scissor.extent[0];
ey = state->scissor.extent[1];
@@ -936,6 +1021,30 @@ void nvgResetScissor(NVGcontext* ctx)
state->scissor.extent[1] = -1.0f;
}

// Global composite operation.
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op)
{
NVGstate* state = nvg__getState(ctx);
state->compositeOperation = nvg__compositeOperationState(op);
}

void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor)
{
nvgGlobalCompositeBlendFuncSeparate(ctx, sfactor, dfactor, sfactor, dfactor);
}

void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
{
NVGcompositeOperationState op;
op.srcRGB = srcRGB;
op.dstRGB = dstRGB;
op.srcAlpha = srcAlpha;
op.dstAlpha = dstAlpha;

NVGstate* state = nvg__getState(ctx);
state->compositeOperation = op;
}

static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
{
float dx = x2 - x1;
@@ -1173,7 +1282,7 @@ static void nvg__tesselateBezier(NVGcontext* ctx,
{
float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
float dx,dy,d2,d3;
if (level > 10) return;

x12 = (x1+x2)*0.5f;
@@ -1205,8 +1314,8 @@ static void nvg__tesselateBezier(NVGcontext* ctx,
x1234 = (x123+x234)*0.5f;
y1234 = (y123+y234)*0.5f;

nvg__tesselateBezier(ctx, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
nvg__tesselateBezier(ctx, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
nvg__tesselateBezier(ctx, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
nvg__tesselateBezier(ctx, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
}

static void nvg__flattenPaths(NVGcontext* ctx)
@@ -1331,7 +1440,8 @@ static void nvg__chooseBevel(int bevel, NVGpoint* p0, NVGpoint* p1, float w,
}

static NVGvertex* nvg__roundJoin(NVGvertex* dst, NVGpoint* p0, NVGpoint* p1,
float lw, float rw, float lu, float ru, int ncap, float fringe)
float lw, float rw, float lu, float ru, int ncap,
float fringe)
{
int i, n;
float dlx0 = p0->dy;
@@ -1464,36 +1574,39 @@ static NVGvertex* nvg__bevelJoin(NVGvertex* dst, NVGpoint* p0, NVGpoint* p1,
}

static NVGvertex* nvg__buttCapStart(NVGvertex* dst, NVGpoint* p,
float dx, float dy, float w, float d, float aa)
float dx, float dy, float w, float d,
float aa, float u0, float u1)
{
float px = p->x - dx*d;
float py = p->y - dy*d;
float dlx = dy;
float dly = -dx;
nvg__vset(dst, px + dlx*w - dx*aa, py + dly*w - dy*aa, 0,0); dst++;
nvg__vset(dst, px - dlx*w - dx*aa, py - dly*w - dy*aa, 1,0); dst++;
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;
nvg__vset(dst, px + dlx*w - dx*aa, py + dly*w - dy*aa, u0,0); dst++;
nvg__vset(dst, px - dlx*w - dx*aa, py - dly*w - dy*aa, u1,0); dst++;
nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
return dst;
}

static NVGvertex* nvg__buttCapEnd(NVGvertex* dst, NVGpoint* p,
float dx, float dy, float w, float d, float aa)
float dx, float dy, float w, float d,
float aa, float u0, float u1)
{
float px = p->x + dx*d;
float py = p->y + dy*d;
float dlx = dy;
float dly = -dx;
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;
nvg__vset(dst, px + dlx*w + dx*aa, py + dly*w + dy*aa, 0,0); dst++;
nvg__vset(dst, px - dlx*w + dx*aa, py - dly*w + dy*aa, 1,0); dst++;
nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
nvg__vset(dst, px + dlx*w + dx*aa, py + dly*w + dy*aa, u0,0); dst++;
nvg__vset(dst, px - dlx*w + dx*aa, py - dly*w + dy*aa, u1,0); dst++;
return dst;
}


static NVGvertex* nvg__roundCapStart(NVGvertex* dst, NVGpoint* p,
float dx, float dy, float w, int ncap, float aa)
float dx, float dy, float w, int ncap,
float aa, float u0, float u1)
{
int i;
float px = p->x;
@@ -1504,16 +1617,17 @@ static NVGvertex* nvg__roundCapStart(NVGvertex* dst, NVGpoint* p,
for (i = 0; i < ncap; i++) {
float a = i/(float)(ncap-1)*NVG_PI;
float ax = cosf(a) * w, ay = sinf(a) * w;
nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, 0,1); dst++;
nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, u0,1); dst++;
nvg__vset(dst, px, py, 0.5f,1); dst++;
}
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;
nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
return dst;
}

static NVGvertex* nvg__roundCapEnd(NVGvertex* dst, NVGpoint* p,
float dx, float dy, float w, int ncap, float aa)
float dx, float dy, float w, int ncap,
float aa, float u0, float u1)
{
int i;
float px = p->x;
@@ -1521,13 +1635,13 @@ static NVGvertex* nvg__roundCapEnd(NVGvertex* dst, NVGpoint* p,
float dlx = dy;
float dly = -dx;
NVG_NOTUSED(aa);
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++;
nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
for (i = 0; i < ncap; i++) {
float a = i/(float)(ncap-1)*NVG_PI;
float ax = cosf(a) * w, ay = sinf(a) * w;
nvg__vset(dst, px, py, 0.5f,1); dst++;
nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, 0,1); dst++;
nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, u0,1); dst++;
}
return dst;
}
@@ -1603,15 +1717,24 @@ static void nvg__calculateJoins(NVGcontext* ctx, float w, int lineJoin, float mi
}


static int nvg__expandStroke(NVGcontext* ctx, float w, int lineCap, int lineJoin, float miterLimit)
{
static int nvg__expandStroke(NVGcontext* ctx, float w, float fringe, int lineCap, int lineJoin, float miterLimit)
{
NVGpathCache* cache = ctx->cache;
NVGvertex* verts;
NVGvertex* dst;
int cverts, i, j;
float aa = ctx->fringeWidth;
float aa = fringe;//ctx->fringeWidth;
float u0 = 0.0f, u1 = 1.0f;
int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol); // Calculate divisions per half circle.

w += aa * 0.5f;

// Disable the gradient used for antialiasing when antialiasing is not used.
if (aa == 0.0f) {
u0 = 0.5f;
u1 = 0.5f;
}

nvg__calculateJoins(ctx, w, lineJoin, miterLimit);

// Calculate max vertex usage.
@@ -1672,42 +1795,42 @@ static int nvg__expandStroke(NVGcontext* ctx, float w, int lineCap, int lineJoin
dy = p1->y - p0->y;
nvg__normalize(&dx, &dy);
if (lineCap == NVG_BUTT)
dst = nvg__buttCapStart(dst, p0, dx, dy, w, -aa*0.5f, aa);
dst = nvg__buttCapStart(dst, p0, dx, dy, w, -aa*0.5f, aa, u0, u1);
else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE)
dst = nvg__buttCapStart(dst, p0, dx, dy, w, w-aa, aa);
dst = nvg__buttCapStart(dst, p0, dx, dy, w, w-aa, aa, u0, u1);
else if (lineCap == NVG_ROUND)
dst = nvg__roundCapStart(dst, p0, dx, dy, w, ncap, aa);
dst = nvg__roundCapStart(dst, p0, dx, dy, w, ncap, aa, u0, u1);
}

for (j = s; j < e; ++j) {
if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) {
if (lineJoin == NVG_ROUND) {
dst = nvg__roundJoin(dst, p0, p1, w, w, 0, 1, ncap, aa);
dst = nvg__roundJoin(dst, p0, p1, w, w, u0, u1, ncap, aa);
} else {
dst = nvg__bevelJoin(dst, p0, p1, w, w, 0, 1, aa);
dst = nvg__bevelJoin(dst, p0, p1, w, w, u0, u1, aa);
}
} else {
nvg__vset(dst, p1->x + (p1->dmx * w), p1->y + (p1->dmy * w), 0,1); dst++;
nvg__vset(dst, p1->x - (p1->dmx * w), p1->y - (p1->dmy * w), 1,1); dst++;
nvg__vset(dst, p1->x + (p1->dmx * w), p1->y + (p1->dmy * w), u0,1); dst++;
nvg__vset(dst, p1->x - (p1->dmx * w), p1->y - (p1->dmy * w), u1,1); dst++;
}
p0 = p1++;
}

if (loop) {
// Loop it
nvg__vset(dst, verts[0].x, verts[0].y, 0,1); dst++;
nvg__vset(dst, verts[1].x, verts[1].y, 1,1); dst++;
nvg__vset(dst, verts[0].x, verts[0].y, u0,1); dst++;
nvg__vset(dst, verts[1].x, verts[1].y, u1,1); dst++;
} else {
// Add cap
dx = p1->x - p0->x;
dy = p1->y - p0->y;
nvg__normalize(&dx, &dy);
if (lineCap == NVG_BUTT)
dst = nvg__buttCapEnd(dst, p1, dx, dy, w, -aa*0.5f, aa);
dst = nvg__buttCapEnd(dst, p1, dx, dy, w, -aa*0.5f, aa, u0, u1);
else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE)
dst = nvg__buttCapEnd(dst, p1, dx, dy, w, w-aa, aa);
dst = nvg__buttCapEnd(dst, p1, dx, dy, w, w-aa, aa, u0, u1);
else if (lineCap == NVG_ROUND)
dst = nvg__roundCapEnd(dst, p1, dx, dy, w, ncap, aa);
dst = nvg__roundCapEnd(dst, p1, dx, dy, w, ncap, aa, u0, u1);
}

path->nstroke = (int)(dst - verts);
@@ -1868,7 +1991,7 @@ void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y)
{
float x0 = ctx->commandx;
float y0 = ctx->commandy;
float vals[] = { NVG_BEZIERTO,
float vals[] = { NVG_BEZIERTO,
x0 + 2.0f/3.0f*(cx - x0), y0 + 2.0f/3.0f*(cy - y0),
x + 2.0f/3.0f*(cx - x), y + 2.0f/3.0f*(cy - y),
x, y };
@@ -1950,7 +2073,7 @@ void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, in
float px = 0, py = 0, ptanx = 0, ptany = 0;
float vals[3 + 5*7 + 100];
int i, ndivs, nvals;
int move = ctx->ncommands > 0 ? NVG_LINETO : NVG_MOVETO;
int move = ctx->ncommands > 0 ? NVG_LINETO : NVG_MOVETO;

// Clamp angles
da = a1 - a0;
@@ -2022,22 +2145,31 @@ void nvgRect(NVGcontext* ctx, float x, float y, float w, float h)

void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r)
{
if (r < 0.1f) {
nvgRect(ctx, x,y,w,h);
nvgRoundedRectVarying(ctx, x, y, w, h, r, r, r, r);
}

void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft)
{
if(radTopLeft < 0.1f && radTopRight < 0.1f && radBottomRight < 0.1f && radBottomLeft < 0.1f) {
nvgRect(ctx, x, y, w, h);
return;
}
else {
float rx = nvg__minf(r, nvg__absf(w)*0.5f) * nvg__signf(w), ry = nvg__minf(r, nvg__absf(h)*0.5f) * nvg__signf(h);
} else {
float halfw = nvg__absf(w)*0.5f;
float halfh = nvg__absf(h)*0.5f;
float rxBL = nvg__minf(radBottomLeft, halfw) * nvg__signf(w), ryBL = nvg__minf(radBottomLeft, halfh) * nvg__signf(h);
float rxBR = nvg__minf(radBottomRight, halfw) * nvg__signf(w), ryBR = nvg__minf(radBottomRight, halfh) * nvg__signf(h);
float rxTR = nvg__minf(radTopRight, halfw) * nvg__signf(w), ryTR = nvg__minf(radTopRight, halfh) * nvg__signf(h);
float rxTL = nvg__minf(radTopLeft, halfw) * nvg__signf(w), ryTL = nvg__minf(radTopLeft, halfh) * nvg__signf(h);
float vals[] = {
NVG_MOVETO, x, y+ry,
NVG_LINETO, x, y+h-ry,
NVG_BEZIERTO, x, y+h-ry*(1-NVG_KAPPA90), x+rx*(1-NVG_KAPPA90), y+h, x+rx, y+h,
NVG_LINETO, x+w-rx, y+h,
NVG_BEZIERTO, x+w-rx*(1-NVG_KAPPA90), y+h, x+w, y+h-ry*(1-NVG_KAPPA90), x+w, y+h-ry,
NVG_LINETO, x+w, y+ry,
NVG_BEZIERTO, x+w, y+ry*(1-NVG_KAPPA90), x+w-rx*(1-NVG_KAPPA90), y, x+w-rx, y,
NVG_LINETO, x+rx, y,
NVG_BEZIERTO, x+rx*(1-NVG_KAPPA90), y, x, y+ry*(1-NVG_KAPPA90), x, y+ry,
NVG_MOVETO, x, y + ryTL,
NVG_LINETO, x, y + h - ryBL,
NVG_BEZIERTO, x, y + h - ryBL*(1 - NVG_KAPPA90), x + rxBL*(1 - NVG_KAPPA90), y + h, x + rxBL, y + h,
NVG_LINETO, x + w - rxBR, y + h,
NVG_BEZIERTO, x + w - rxBR*(1 - NVG_KAPPA90), y + h, x + w, y + h - ryBR*(1 - NVG_KAPPA90), x + w, y + h - ryBR,
NVG_LINETO, x + w, y + ryTR,
NVG_BEZIERTO, x + w, y + ryTR*(1 - NVG_KAPPA90), x + w - rxTR*(1 - NVG_KAPPA90), y, x + w - rxTR, y,
NVG_LINETO, x + rxTL, y,
NVG_BEZIERTO, x + rxTL*(1 - NVG_KAPPA90), y, x, y + ryTL*(1 - NVG_KAPPA90), x, y + ryTL,
NVG_CLOSE
};
nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
@@ -2092,7 +2224,7 @@ void nvgFill(NVGcontext* ctx)
int i;

nvg__flattenPaths(ctx);
if (ctx->params.edgeAntiAlias)
if (ctx->params.edgeAntiAlias && state->shapeAntiAlias)
nvg__expandFill(ctx, ctx->fringeWidth, NVG_MITER, 2.4f);
else
nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f);
@@ -2101,7 +2233,7 @@ void nvgFill(NVGcontext* ctx)
fillPaint.innerColor.a *= state->alpha;
fillPaint.outerColor.a *= state->alpha;

ctx->params.renderFill(ctx->params.userPtr, &fillPaint, &state->scissor, ctx->fringeWidth,
ctx->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth,
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths);

// Count triangles
@@ -2122,6 +2254,7 @@ void nvgStroke(NVGcontext* ctx)
const NVGpath* path;
int i;


if (strokeWidth < ctx->fringeWidth) {
// If the stroke width is less than pixel size, use alpha to emulate coverage.
// Since coverage is area, scale by alpha*alpha.
@@ -2137,12 +2270,12 @@ void nvgStroke(NVGcontext* ctx)

nvg__flattenPaths(ctx);

if (ctx->params.edgeAntiAlias)
nvg__expandStroke(ctx, strokeWidth*0.5f + ctx->fringeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit);
if (ctx->params.edgeAntiAlias && state->shapeAntiAlias)
nvg__expandStroke(ctx, strokeWidth*0.5f, ctx->fringeWidth, state->lineCap, state->lineJoin, state->miterLimit);
else
nvg__expandStroke(ctx, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit);
nvg__expandStroke(ctx, strokeWidth*0.5f, 0.0f, state->lineCap, state->lineJoin, state->miterLimit);

ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, &state->scissor, ctx->fringeWidth,
ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, state->compositeOperation, &state->scissor, ctx->fringeWidth,
strokeWidth, ctx->cache->paths, ctx->cache->npaths);

// Count triangles
@@ -2154,14 +2287,24 @@ void nvgStroke(NVGcontext* ctx)
}

// Add fonts
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* path)
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename)
{
return fonsAddFont(ctx->fs, name, path);
return fonsAddFont(ctx->fs, name, filename, 0);
}

int nvgCreateFontMem(NVGcontext* ctx, const char* name, const unsigned char* data, int ndata, int freeData)
int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex)
{
return fonsAddFontMem(ctx->fs, name, data, ndata, freeData);
return fonsAddFont(ctx->fs, name, filename, fontIndex);
}

int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData)
{
return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, 0);
}

int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex)
{
return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, fontIndex);
}

int nvgFindFont(NVGcontext* ctx, const char* name)
@@ -2170,6 +2313,28 @@ int nvgFindFont(NVGcontext* ctx, const char* name)
return fonsGetFontByName(ctx->fs, name);
}


int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont)
{
if(baseFont == -1 || fallbackFont == -1) return 0;
return fonsAddFallbackFont(ctx->fs, baseFont, fallbackFont);
}

int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont)
{
return nvgAddFallbackFontId(ctx, nvgFindFont(ctx, baseFont), nvgFindFont(ctx, fallbackFont));
}

void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont)
{
fonsResetFallbackFont(ctx->fs, baseFont);
}

void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont)
{
nvgResetFallbackFontsId(ctx, nvgFindFont(ctx, baseFont));
}

// State setting
void nvgFontSize(NVGcontext* ctx, float size)
{
@@ -2278,7 +2443,7 @@ static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts)
paint.innerColor.a *= state->alpha;
paint.outerColor.a *= state->alpha;

ctx->params.renderTriangles(ctx->params.userPtr, &paint, &state->scissor, verts, nverts);
ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts, ctx->fringeWidth);

ctx->drawCallCount++;
ctx->textTriCount += nverts/3;
@@ -2310,17 +2475,17 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char*
verts = nvg__allocTempVerts(ctx, cverts);
if (verts == NULL) return x;

fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end);
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED);
prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) {
float c[4*2];
if (iter.prevGlyphIndex == -1) { // can not retrieve glyph?
if (!nvg__allocTextAtlas(ctx))
break; // no memory :(
if (nverts != 0) {
nvg__renderText(ctx, verts, nverts);
nverts = 0;
}
if (!nvg__allocTextAtlas(ctx))
break; // no memory :(
iter = prevIter;
fonsTextIterNext(ctx->fs, &iter, &q); // try again
if (iter.prevGlyphIndex == -1) // still can not find glyph?
@@ -2343,12 +2508,12 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char*
}
}

// TODO: add back-end bit to do this just once per frame.
// TODO: add back-end bit to do this just once per frame.
nvg__flushTextTexture(ctx);

nvg__renderText(ctx, verts, nverts);

return iter.x;
return iter.nextx / scale;
}

void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end)
@@ -2407,7 +2572,7 @@ int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string,
fonsSetAlign(ctx->fs, state->textAlign);
fonsSetFont(ctx->fs, state->fontId);

fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end);
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) {
if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph?
@@ -2431,6 +2596,7 @@ enum NVGcodepointType {
NVG_SPACE,
NVG_NEWLINE,
NVG_CHAR,
NVG_CJK_CHAR,
};

int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows)
@@ -2472,7 +2638,7 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa

breakRowWidth *= scale;

fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end);
fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) {
if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph?
@@ -2498,7 +2664,15 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa
type = NVG_NEWLINE;
break;
default:
type = NVG_CHAR;
if ((iter.codepoint >= 0x4E00 && iter.codepoint <= 0x9FFF) ||
(iter.codepoint >= 0x3000 && iter.codepoint <= 0x30FF) ||
(iter.codepoint >= 0xFF00 && iter.codepoint <= 0xFFEF) ||
(iter.codepoint >= 0x1100 && iter.codepoint <= 0x11FF) ||
(iter.codepoint >= 0x3130 && iter.codepoint <= 0x318F) ||
(iter.codepoint >= 0xAC00 && iter.codepoint <= 0xD7AF))
type = NVG_CJK_CHAR;
else
type = NVG_CHAR;
break;
}

@@ -2525,12 +2699,12 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa
} else {
if (rowStart == NULL) {
// Skip white space until the beginning of the line
if (type == NVG_CHAR) {
if (type == NVG_CHAR || type == NVG_CJK_CHAR) {
// The current char is the row so far
rowStartX = iter.x;
rowStart = iter.str;
rowEnd = iter.next;
rowWidth = iter.nextx - rowStartX; // q.x1 - rowStartX;
rowWidth = iter.nextx - rowStartX;
rowMinX = q.x0 - rowStartX;
rowMaxX = q.x1 - rowStartX;
wordStart = iter.str;
@@ -2545,26 +2719,26 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa
float nextWidth = iter.nextx - rowStartX;

// track last non-white space character
if (type == NVG_CHAR) {
if (type == NVG_CHAR || type == NVG_CJK_CHAR) {
rowEnd = iter.next;
rowWidth = iter.nextx - rowStartX;
rowMaxX = q.x1 - rowStartX;
}
// track last end of a word
if (ptype == NVG_CHAR && type == NVG_SPACE) {
if (((ptype == NVG_CHAR || ptype == NVG_CJK_CHAR) && type == NVG_SPACE) || type == NVG_CJK_CHAR) {
breakEnd = iter.str;
breakWidth = rowWidth;
breakMaxX = rowMaxX;
}
// track last beginning of a word
if (ptype == NVG_SPACE && type == NVG_CHAR) {
if ((ptype == NVG_SPACE && (type == NVG_CHAR || type == NVG_CJK_CHAR)) || type == NVG_CJK_CHAR) {
wordStart = iter.str;
wordStartX = iter.x;
wordMinX = q.x0 - rowStartX;
wordMinX = q.x0;
}

// Break to new line when a character is beyond break width.
if (type == NVG_CHAR && nextWidth > breakRowWidth) {
if ((type == NVG_CHAR || type == NVG_CJK_CHAR) && nextWidth > breakRowWidth) {
// The run length is too long, need to break to new line.
if (breakEnd == rowStart) {
// The current word is longer than the row length, just break it from here.
@@ -2597,13 +2771,13 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa
nrows++;
if (nrows >= maxRows)
return nrows;
// Update row
rowStartX = wordStartX;
rowStart = wordStart;
rowEnd = iter.next;
rowWidth = iter.nextx - rowStartX;
rowMinX = wordMinX;
rowMinX = wordMinX - rowStartX;
rowMaxX = q.x1 - rowStartX;
// No change to the word start
}
// Set null break point
breakEnd = rowStart;


+ 95
- 18
dgl/src/nanovg/nanovg.h View File

@@ -79,10 +79,46 @@ enum NVGalign {
// Vertical align
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top.
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle.
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
};

enum NVGblendFactor {
NVG_ZERO = 1<<0,
NVG_ONE = 1<<1,
NVG_SRC_COLOR = 1<<2,
NVG_ONE_MINUS_SRC_COLOR = 1<<3,
NVG_DST_COLOR = 1<<4,
NVG_ONE_MINUS_DST_COLOR = 1<<5,
NVG_SRC_ALPHA = 1<<6,
NVG_ONE_MINUS_SRC_ALPHA = 1<<7,
NVG_DST_ALPHA = 1<<8,
NVG_ONE_MINUS_DST_ALPHA = 1<<9,
NVG_SRC_ALPHA_SATURATE = 1<<10,
};

enum NVGcompositeOperation {
NVG_SOURCE_OVER,
NVG_SOURCE_IN,
NVG_SOURCE_OUT,
NVG_ATOP,
NVG_DESTINATION_OVER,
NVG_DESTINATION_IN,
NVG_DESTINATION_OUT,
NVG_DESTINATION_ATOP,
NVG_LIGHTER,
NVG_COPY,
NVG_XOR,
};

struct NVGcompositeOperationState {
int srcRGB;
int dstRGB;
int srcAlpha;
int dstAlpha;
};
typedef struct NVGcompositeOperationState NVGcompositeOperationState;

struct NVGglyphPosition {
const char* str; // Position of the glyph in the input string.
float x; // The x-coordinate of the logical glyph position.
@@ -100,11 +136,12 @@ struct NVGtextRow {
typedef struct NVGtextRow NVGtextRow;

enum NVGimageFlags {
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image.
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image.
NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction.
NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction.
NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered.
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear
};

// Begin drawing a new frame
@@ -115,7 +152,7 @@ enum NVGimageFlags {
// For example, GLFW returns two dimension for an opened window: window size and
// frame buffer size. In that case you would set windowWidth/Height to the window size
// devicePixelRatio to: frameBufferWidth / windowWidth.
void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio);
void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio);

// Cancels drawing the current frame.
void nvgCancelFrame(NVGcontext* ctx);
@@ -123,6 +160,22 @@ void nvgCancelFrame(NVGcontext* ctx);
// Ends drawing flushing remaining render state.
void nvgEndFrame(NVGcontext* ctx);

//
// Composite operation
//
// The composite operations in NanoVG are modeled after HTML Canvas API, and
// the blend func is based on OpenGL (see corresponding manuals for more info).
// The colors in the blending state have premultiplied alpha.

// Sets the composite operation. The op parameter should be one of NVGcompositeOperation.
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op);

// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor.
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor);

// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor.
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);

//
// Color utils
//
@@ -183,7 +236,10 @@ void nvgReset(NVGcontext* ctx);
// Solid color is simply defined as a color value, different kinds of paints can be created
// using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern().
//
// Current render style can be saved and restored using nvgSave() and nvgRestore().
// Current render style can be saved and restored using nvgSave() and nvgRestore().

// Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default.
void nvgShapeAntiAlias(NVGcontext* ctx, int enabled);

// Sets current stroke style to a solid color.
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color);
@@ -231,7 +287,7 @@ void nvgGlobalAlpha(NVGcontext* ctx, float alpha);
// Apart from nvgResetTransform(), each transformation function first creates
// specific transformation matrix and pre-multiplies the current transformation by it.
//
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().

// Resets current transform to a identity matrix.
void nvgResetTransform(NVGcontext* ctx);
@@ -317,7 +373,7 @@ int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags);

// Creates image by loading it from the specified chunk of memory.
// Returns handle to the image.
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, const unsigned char* data, int ndata);
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata);

// Creates image from specified image data.
// Returns handle to the image.
@@ -368,7 +424,7 @@ NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey
// Scissoring
//
// Scissoring allows you to clip the rendering into a rectangle. This is useful for various
// user interface cases like rendering a text edit or a timeline.
// user interface cases like rendering a text edit or a timeline.

// Sets the current scissor rectangle.
// The scissor rectangle is transformed by the current transform.
@@ -423,7 +479,7 @@ void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float rad
// Closes current sub-path with a line segment.
void nvgClosePath(NVGcontext* ctx);

// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
void nvgPathWinding(NVGcontext* ctx, int dir);

// Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r,
@@ -437,10 +493,13 @@ void nvgRect(NVGcontext* ctx, float x, float y, float w, float h);
// Creates new rounded rectangle shaped sub-path.
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r);

// Creates new rounded rectangle shaped sub-path with varying radii for each corner.
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);

// Creates new ellipse shaped sub-path.
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry);

// Creates new circle shaped sub-path.
// Creates new circle shaped sub-path.
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r);

// Fills the current path with current fill style.
@@ -487,13 +546,31 @@ void nvgStroke(NVGcontext* ctx);
// Returns handle to the font.
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename);

// Creates image by loading it from the specified memory chunk.
// fontIndex specifies which font face to load from a .ttf/.ttc file.
int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex);

// Creates font by loading it from the specified memory chunk.
// Returns handle to the font.
int nvgCreateFontMem(NVGcontext* ctx, const char* name, const unsigned char* data, int ndata, int freeData);
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData);

// fontIndex specifies which font face to load from a .ttf/.ttc file.
int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex);

// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found.
int nvgFindFont(NVGcontext* ctx, const char* name);

// Adds a fallback font by handle.
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont);

// Adds a fallback font by name.
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont);

// Resets fallback fonts by handle.
void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont);

// Resets fallback fonts by name.
void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont);

// Sets the font size of current text style.
void nvgFontSize(NVGcontext* ctx, float size);

@@ -503,7 +580,7 @@ void nvgFontBlur(NVGcontext* ctx, float blur);
// Sets the letter spacing of current text style.
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing);

// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight);

// Sets the text align of current text style, see NVGalign for options.
@@ -588,12 +665,12 @@ struct NVGparams {
int (*renderDeleteTexture)(void* uptr, int image);
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data);
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);
void (*renderViewport)(void* uptr, int width, int height);
void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio);
void (*renderCancel)(void* uptr);
void (*renderFlush)(void* uptr);
void (*renderFill)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts);
void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts, float fringe);
void (*renderDelete)(void* uptr);
};
typedef struct NVGparams NVGparams;


+ 197
- 62
dgl/src/nanovg/nanovg_gl.h View File

@@ -59,6 +59,9 @@ enum NVGcreateFlags {
NVGcontext* nvgCreateGL2(int flags);
void nvgDeleteGL2(NVGcontext* ctx);

int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
GLuint nvglImageHandleGL2(NVGcontext* ctx, int image);

#endif

#if defined NANOVG_GL3
@@ -66,6 +69,9 @@ void nvgDeleteGL2(NVGcontext* ctx);
NVGcontext* nvgCreateGL3(int flags);
void nvgDeleteGL3(NVGcontext* ctx);

int nvglCreateImageFromHandleGL3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
GLuint nvglImageHandleGL3(NVGcontext* ctx, int image);

#endif

#if defined NANOVG_GLES2
@@ -73,6 +79,9 @@ void nvgDeleteGL3(NVGcontext* ctx);
NVGcontext* nvgCreateGLES2(int flags);
void nvgDeleteGLES2(NVGcontext* ctx);

int nvglCreateImageFromHandleGLES2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
GLuint nvglImageHandleGLES2(NVGcontext* ctx, int image);

#endif

#if defined NANOVG_GLES3
@@ -80,6 +89,9 @@ void nvgDeleteGLES2(NVGcontext* ctx);
NVGcontext* nvgCreateGLES3(int flags);
void nvgDeleteGLES3(NVGcontext* ctx);

int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
GLuint nvglImageHandleGLES3(NVGcontext* ctx, int image);

#endif

// These are additional flags on top of NVGimageFlags.
@@ -87,10 +99,6 @@ enum NVGimageFlagsGL {
NVG_IMAGE_NODELETE = 1<<16, // Do not delete GL texture handle.
};

int nvglCreateImageFromHandle(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
GLuint nvglImageHandle(NVGcontext* ctx, int image);


#ifdef __cplusplus
}
#endif
@@ -142,6 +150,15 @@ struct GLNVGtexture {
};
typedef struct GLNVGtexture GLNVGtexture;

struct GLNVGblend
{
GLenum srcRGB;
GLenum dstRGB;
GLenum srcAlpha;
GLenum dstAlpha;
};
typedef struct GLNVGblend GLNVGblend;

enum GLNVGcallType {
GLNVG_NONE = 0,
GLNVG_FILL,
@@ -158,6 +175,7 @@ struct GLNVGcall {
int triangleOffset;
int triangleCount;
int uniformOffset;
GLNVGblend blendFunc;
};
typedef struct GLNVGcall GLNVGcall;

@@ -248,7 +266,10 @@ struct GLNVGcontext {
GLenum stencilFunc;
GLint stencilFuncRef;
GLuint stencilFuncMask;
GLNVGblend blendFunc;
#endif

int dummyTex;
};
typedef struct GLNVGcontext GLNVGcontext;

@@ -298,7 +319,7 @@ static void glnvg__stencilFunc(GLNVGcontext* gl, GLenum func, GLint ref, GLuint
if ((gl->stencilFunc != func) ||
(gl->stencilFuncRef != ref) ||
(gl->stencilFuncMask != mask)) {
gl->stencilFunc = func;
gl->stencilFuncRef = ref;
gl->stencilFuncMask = mask;
@@ -308,6 +329,21 @@ static void glnvg__stencilFunc(GLNVGcontext* gl, GLenum func, GLint ref, GLuint
glStencilFunc(func, ref, mask);
#endif
}
static void glnvg__blendFuncSeparate(GLNVGcontext* gl, const GLNVGblend* blend)
{
#if NANOVG_GL_USE_STATE_FILTER
if ((gl->blendFunc.srcRGB != blend->srcRGB) ||
(gl->blendFunc.dstRGB != blend->dstRGB) ||
(gl->blendFunc.srcAlpha != blend->srcAlpha) ||
(gl->blendFunc.dstAlpha != blend->dstAlpha)) {

gl->blendFunc = *blend;
glBlendFuncSeparate(blend->srcRGB, blend->dstRGB, blend->srcAlpha,blend->dstAlpha);
}
#else
glBlendFuncSeparate(blend->srcRGB, blend->dstRGB, blend->srcAlpha,blend->dstAlpha);
#endif
}

static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl)
{
@@ -331,10 +367,10 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl)
}
tex = &gl->textures[gl->ntextures++];
}
memset(tex, 0, sizeof(*tex));
tex->id = ++gl->textureId;
return tex;
}

@@ -363,8 +399,8 @@ static int glnvg__deleteTexture(GLNVGcontext* gl, int id)

static void glnvg__dumpShaderError(GLuint shader, const char* name, const char* type)
{
char str[512+1];
int len = 0;
GLchar str[512+1];
GLsizei len = 0;
glGetShaderInfoLog(shader, 512, &len, str);
if (len > 512) len = 512;
str[len] = '\0';
@@ -373,8 +409,8 @@ static void glnvg__dumpShaderError(GLuint shader, const char* name, const char*

static void glnvg__dumpProgramError(GLuint prog, const char* name)
{
char str[512+1];
int len = 0;
GLchar str[512+1];
GLsizei len = 0;
glGetProgramInfoLog(prog, 512, &len, str);
if (len > 512) len = 512;
str[len] = '\0';
@@ -466,6 +502,8 @@ static void glnvg__getUniforms(GLNVGshader* shader)
#endif
}

static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data);

static int glnvg__renderCreate(void* uptr)
{
GLNVGcontext* gl = (GLNVGcontext*)uptr;
@@ -514,7 +552,7 @@ static int glnvg__renderCreate(void* uptr)
" gl_Position = vec4(2.0*vertex.x/viewSize.x - 1.0, 1.0 - 2.0*vertex.y/viewSize.y, 0, 1);\n"
"}\n";

static const char* fillFragShader =
static const char* fillFragShader =
"#ifdef GL_ES\n"
"#if defined(GL_FRAGMENT_PRECISION_HIGH) || defined(NANOVG_GL3)\n"
" precision highp float;\n"
@@ -592,6 +630,7 @@ static int glnvg__renderCreate(void* uptr)
" float scissor = scissorMask(fpos);\n"
"#ifdef EDGE_AA\n"
" float strokeAlpha = strokeMask();\n"
" if (strokeAlpha < strokeThr) discard;\n"
"#else\n"
" float strokeAlpha = 1.0;\n"
"#endif\n"
@@ -631,9 +670,6 @@ static int glnvg__renderCreate(void* uptr)
" color *= scissor;\n"
" result = color * innerCol;\n"
" }\n"
"#ifdef EDGE_AA\n"
" if (strokeAlpha < strokeThr) discard;\n"
"#endif\n"
"#ifdef NANOVG_GL3\n"
" outColor = result;\n"
"#else\n"
@@ -663,11 +699,15 @@ static int glnvg__renderCreate(void* uptr)
#if NANOVG_GL_USE_UNIFORMBUFFER
// Create UBOs
glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_FRAG], GLNVG_FRAG_BINDING);
glGenBuffers(1, &gl->fragBuf);
glGenBuffers(1, &gl->fragBuf);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align);
#endif
gl->fragSize = sizeof(GLNVGfragUniforms) + align - sizeof(GLNVGfragUniforms) % align;

// Some platforms does not allow to have samples to unset textures.
// Create empty one which is bound when there's no texture specified.
gl->dummyTex = glnvg__renderCreateTexture(gl, NVG_TEXTURE_ALPHA, 1, 1, 0, NULL);

glnvg__checkError(gl, "create done");

glFinish();
@@ -690,7 +730,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
printf("Repeat X/Y is not supported for non power-of-two textures (%d x %d)\n", w, h);
imageFlags &= ~(NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
}
// No mips.
// No mips.
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
printf("Mip-maps is not support for non power-of-two textures (%d x %d)\n", w, h);
imageFlags &= ~NVG_IMAGE_GENERATE_MIPMAPS;
@@ -722,7 +762,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
if (type == NVG_TEXTURE_RGBA)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
else
#if defined(NANOVG_GLES2)
#if defined(NANOVG_GLES2) || defined (NANOVG_GL2)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
#elif defined(NANOVG_GLES3)
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data);
@@ -731,11 +771,24 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
#endif

if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
if (imageFlags & NVG_IMAGE_NEAREST) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
} else {
if (imageFlags & NVG_IMAGE_NEAREST) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
}

if (imageFlags & NVG_IMAGE_NEAREST) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

if (imageFlags & NVG_IMAGE_REPEATX)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -801,7 +854,7 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w
if (tex->type == NVG_TEXTURE_RGBA)
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data);
else
#ifdef NANOVG_GLES2
#if defined(NANOVG_GLES2) || defined(NANOVG_GL2)
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
#else
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data);
@@ -887,19 +940,30 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai
tex = glnvg__findTexture(gl, paint->image);
if (tex == NULL) return 0;
if ((tex->flags & NVG_IMAGE_FLIPY) != 0) {
float flipped[6];
nvgTransformScale(flipped, 1.0f, -1.0f);
nvgTransformMultiply(flipped, paint->xform);
nvgTransformInverse(invxform, flipped);
float m1[6], m2[6];
nvgTransformTranslate(m1, 0.0f, frag->extent[1] * 0.5f);
nvgTransformMultiply(m1, paint->xform);
nvgTransformScale(m2, 1.0f, -1.0f);
nvgTransformMultiply(m2, m1);
nvgTransformTranslate(m1, 0.0f, -frag->extent[1] * 0.5f);
nvgTransformMultiply(m1, m2);
nvgTransformInverse(invxform, m1);
} else {
nvgTransformInverse(invxform, paint->xform);
}
frag->type = NSVG_SHADER_FILLIMG;

#if NANOVG_GL_USE_UNIFORMBUFFER
if (tex->type == NVG_TEXTURE_RGBA)
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1;
else
frag->texType = 2;
#else
if (tex->type == NVG_TEXTURE_RGBA)
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f;
else
frag->texType = 2.0f;
#endif
// printf("frag->texType = %d\n", frag->texType);
} else {
frag->type = NSVG_SHADER_FILLGRAD;
@@ -917,6 +981,7 @@ static GLNVGfragUniforms* nvg__fragUniformPtr(GLNVGcontext* gl, int i);

static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image)
{
GLNVGtexture* tex = NULL;
#if NANOVG_GL_USE_UNIFORMBUFFER
glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_FRAG_BINDING, gl->fragBuf, uniformOffset, sizeof(GLNVGfragUniforms));
#else
@@ -925,19 +990,22 @@ static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image)
#endif

if (image != 0) {
GLNVGtexture* tex = glnvg__findTexture(gl, image);
glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0);
glnvg__checkError(gl, "tex paint tex");
} else {
glnvg__bindTexture(gl, 0);
tex = glnvg__findTexture(gl, image);
}
// If no image is set, use empty texture
if (tex == NULL) {
tex = glnvg__findTexture(gl, gl->dummyTex);
}
glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0);
glnvg__checkError(gl, "tex paint tex");
}

static void glnvg__renderViewport(void* uptr, int width, int height)
static void glnvg__renderViewport(void* uptr, float width, float height, float devicePixelRatio)
{
NVG_NOTUSED(devicePixelRatio);
GLNVGcontext* gl = (GLNVGcontext*)uptr;
gl->view[0] = (float)width;
gl->view[1] = (float)height;
gl->view[0] = width;
gl->view[1] = height;
}

static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call)
@@ -979,7 +1047,7 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call)
// Draw fill
glnvg__stencilFunc(gl, GL_NOTEQUAL, 0x0, 0xff);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount);
glDrawArrays(GL_TRIANGLE_STRIP, call->triangleOffset, call->triangleCount);

glDisable(GL_STENCIL_TEST);
}
@@ -992,12 +1060,12 @@ static void glnvg__convexFill(GLNVGcontext* gl, GLNVGcall* call)
glnvg__setUniforms(gl, call->uniformOffset, call->image);
glnvg__checkError(gl, "convex fill");

for (i = 0; i < npaths; i++)
for (i = 0; i < npaths; i++) {