Browse Source

- decorated math functions

- updated font stash
- added end parameter to text (can draw substring)
- text and text measure return advance/width
shared-context
Mikko Mononen 11 years ago
parent
commit
68d27124a8
5 changed files with 380 additions and 334 deletions
  1. +19
    -19
      example/example.c
  2. +303
    -252
      src/fontstash.h
  3. +21
    -39
      src/glnanovg.h
  4. +35
    -22
      src/nanovg.c
  5. +2
    -2
      src/nanovg.h

+ 19
- 19
example/example.c View File

@@ -97,11 +97,11 @@ void drawWindow(struct NVGcontext* vg, const char* title, float x, float y, floa

nvgFontBlur(vg,2);
nvgFillColor(vg, nvgRGBA(0,0,0,128));
nvgText(vg, x+w/2,y+16+1, title);
nvgText(vg, x+w/2,y+16+1, title, NULL);

nvgFontBlur(vg,0);
nvgFillColor(vg, nvgRGBA(220,220,220,160));
nvgText(vg, x+w/2,y+16, title);
nvgText(vg, x+w/2,y+16, title, NULL);

nvgRestore(vg);
}
@@ -128,20 +128,20 @@ void drawSearchBox(struct NVGcontext* vg, const char* text, float x, float y, fl
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon));
nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon), NULL);

nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,32));

nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*1.05f,y+h*0.5f,text);
nvgText(vg, x+h*1.05f,y+h*0.5f,text, NULL);

nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,32));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon));
nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon), NULL);
}

void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
@@ -165,13 +165,13 @@ void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, flo
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,160));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*0.3f,y+h*0.5f,text);
nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);

nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon));
nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon), NULL);
}

void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
@@ -181,7 +181,7 @@ void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float
nvgFillColor(vg, nvgRGBA(255,255,255,128));

nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x,y+h*0.5f,text);
nvgText(vg, x,y+h*0.5f,text, NULL);
}

void drawEditBoxBase(struct NVGcontext* vg, float x, float y, float w, float h)
@@ -209,7 +209,7 @@ void drawEditBox(struct NVGcontext* vg, const char* text, float x, float y, floa
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+h*0.3f,y+h*0.5f,text);
nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
}

void drawEditBoxNum(struct NVGcontext* vg,
@@ -219,19 +219,19 @@ void drawEditBoxNum(struct NVGcontext* vg,

drawEditBoxBase(vg, x,y, w,h);

nvgTextBounds(vg, units, &uw, NULL);
uw = nvgTextBounds(vg, units, NULL, NULL);

nvgFontSize(vg, 18.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,64));
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-h*0.3f,y+h*0.5f,units);
nvgText(vg, x+w-h*0.3f,y+h*0.5f,units, NULL);

nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans");
nvgFillColor(vg, nvgRGBA(255,255,255,128));
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text);
nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text, NULL);
}

void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
@@ -244,7 +244,7 @@ void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, flo
nvgFillColor(vg, nvgRGBA(255,255,255,160));

nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+28,y+h*0.5f,text);
nvgText(vg, x+28,y+h*0.5f,text, NULL);

bg = nvgBoxGradient(vg, x+1,y+(int)(h*0.5f)-9+1, 18,18, 3,3, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,92));
nvgBeginPath(vg);
@@ -256,7 +256,7 @@ void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, flo
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,128));
nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon));
nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon), NULL);
}

void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, unsigned int col)
@@ -283,11 +283,11 @@ void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, f

nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans-bold");
nvgTextBounds(vg, text, &tw, NULL);
tw = nvgTextBounds(vg, text, NULL, NULL);
if (preicon != 0) {
nvgFontSize(vg, h*1.3f);
nvgFontFace(vg, "icons");
nvgTextBounds(vg, cpToUTF8(preicon,icon), &iw, NULL);
iw = nvgTextBounds(vg, cpToUTF8(preicon,icon), NULL, NULL);
iw += h*0.15f;
}

@@ -296,16 +296,16 @@ void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, f
nvgFontFace(vg, "icons");
nvgFillColor(vg, nvgRGBA(255,255,255,96));
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon));
nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon), NULL);
}

nvgFontSize(vg, 20.0f);
nvgFontFace(vg, "sans-bold");
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
nvgFillColor(vg, nvgRGBA(0,0,0,160));
nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text);
nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text, NULL);
nvgFillColor(vg, nvgRGBA(255,255,255,160));
nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text);
nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text, NULL);
}

void drawSlider(struct NVGcontext* vg, float pos, float x, float y, float w, float h)


+ 303
- 252
src/fontstash.h View File

@@ -26,7 +26,7 @@ enum FONSflags {
FONS_ZERO_BOTTOMLEFT = 2,
};

enum FONSaling {
enum FONSalign {
// Horizontal align
FONS_ALIGN_LEFT = 1<<0, // Default
FONS_ALIGN_CENTER = 1<<1,
@@ -60,12 +60,13 @@ struct FONStextIter {
struct FONSfont* font;
struct FONSglyph* prevGlyph;
const char* str;
const char* end;
unsigned int utf8state;
};

// Contructor and destructor.
struct FONScontext* fonsCreate(struct FONSparams* params);
void fonsDelete(struct FONScontext* s);
struct FONScontext* fonsCreateInternal(struct FONSparams* params);
void fonsDeleteInternal(struct FONScontext* s);

// Add fonts
int fonsAddFont(struct FONScontext* s, const char* name, const char* path);
@@ -86,17 +87,17 @@ void fonsSetAlign(struct FONScontext* s, int align);
void fonsSetFont(struct FONScontext* s, int font);

// Draw text
void fonsDrawText(struct FONScontext* s, float x, float y, const char* string, float* dx);
float fonsDrawText(struct FONScontext* s, float x, float y, const char* string, const char* end);

// Measure text
void fonsTextBounds(struct FONScontext* s, const char* string, float* width, float* bounds);
float fonsTextBounds(struct FONScontext* s, const char* string, const char* end, float* bounds);
void fonsVertMetrics(struct FONScontext* s, float* ascender, float* descender, float* lineh);

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

// Pull texture data
// Pull texture changes
const unsigned char* fonsGetTextureData(struct FONScontext* stash, int* width, int* height);
int fonsValidateTexture(struct FONScontext* s, int* dirty);

@@ -158,11 +159,6 @@ static int fons__maxi(int a, int b)
return a > b ? a : b;
}

struct FONSrow
{
short x,y,h;
};

struct FONSglyph
{
unsigned int codepoint;
@@ -199,16 +195,27 @@ struct FONSstate
float spacing;
};

struct FONSrow
{
short x,y,h;
};

struct FONSatlas
{
int width, height;
struct FONSrow* rows;
int crows;
int nrows;
};

struct FONScontext
{
struct FONSparams params;
float itw,ith;
unsigned char* texData;
int dirtyRect[4];
struct FONSrow* rows;
int crows;
int nrows;
struct FONSfont** fonts;
struct FONSatlas* atlas;
int cfonts;
int nfonts;
float verts[FONS_VERTEX_COUNT*2];
@@ -223,10 +230,12 @@ struct FONScontext

static void* fons__tmpalloc(size_t size, void* up)
{
unsigned char* ptr;

struct FONScontext* stash = (struct FONScontext*)up;
if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE)
return NULL;
unsigned char* ptr = stash->scratch + stash->nscratch;
ptr = stash->scratch + stash->nscratch;
stash->nscratch += (int)size;
return ptr;
}
@@ -275,7 +284,102 @@ static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsi
return *state;
}

struct FONScontext* fonsCreate(struct FONSparams* params)
static void fons__deleteAtlas(struct FONSatlas* atlas)
{
if (atlas == NULL) return;
if (atlas->rows != NULL) free(atlas->rows);
free(atlas);
}

static struct FONSatlas* fons__allocAtlas(int w, int h, int rows)
{
struct FONSatlas* atlas = NULL;

// Allocate memory for the font stash.
atlas = (struct FONSatlas*)malloc(sizeof(struct FONSatlas));
if (atlas == NULL) goto error;
memset(atlas, 0, sizeof(struct FONSatlas));

atlas->width = w;
atlas->height = h;

// Allocate space for rows
atlas->rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * rows);
if (atlas->rows == NULL) goto error;
memset(atlas->rows, 0, sizeof(struct FONSrow) * rows);
atlas->crows = rows;
atlas->nrows = 0;

return atlas;

error:
if (atlas) fons__deleteAtlas(atlas);
return NULL;
}

static struct FONSrow* fons__atlasAllocRow(struct FONSatlas* atlas)
{
struct FONSrow* rows = NULL;
if (atlas->nrows+1 > atlas->crows) {
atlas->crows *= 2;
rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * atlas->crows);
if (rows == NULL) return NULL;
memset(rows, 0, sizeof(struct FONSrow) * atlas->crows);
if (atlas->nrows > 0)
memcpy(rows, atlas->rows, sizeof(struct FONSrow) * atlas->nrows);
free(atlas->rows);
atlas->rows = rows;
}
atlas->nrows++;
return &atlas->rows[atlas->nrows-1];
}

static int fons__atlasAddRect(struct FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
{
int i, py;
struct FONSrow* br = NULL;

// Round row height
rh = (rh+7) & ~7;;
// Find row where the glyph can be fit.
for (i = 0; i < atlas->nrows; ++i) {
int rmax = atlas->rows[i].h, rmin = rmax - rmax/4;
if (rh >= rmin && rh <= rmax && (atlas->rows[i].x+rw+1) <= atlas->width) {
br = &atlas->rows[i];
break;
}
}

// If no row found, add new.
if (br == NULL) {
py = 0;
// Check that there is enough space.
if (atlas->nrows > 0) {
py = atlas->rows[atlas->nrows-1].y + atlas->rows[atlas->nrows-1].h+1;
if (py+rh > atlas->height)
return 0;
}
// Init and add row
br = fons__atlasAllocRow(atlas);
if (br == NULL)
return 0;
br->x = 0;
br->y = py;
br->h = rh;
}

*rx = br->x;
*ry = br->y;

// Advance row location.
br->x += rw+1;

return 1;
}


struct FONScontext* fonsCreateInternal(struct FONSparams* params)
{
struct FONScontext* stash = NULL;

@@ -286,15 +390,13 @@ struct FONScontext* fonsCreate(struct FONSparams* params)

stash->params = *params;

if (stash->params.renderCreate != NULL)
if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0) goto error;
if (stash->params.renderCreate != NULL) {
if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
goto error;
}

// Allocate space for rows
stash->rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * FONS_INIT_ROWS);
if (stash->rows == NULL) goto error;
memset(stash->rows, 0, sizeof(struct FONSrow) * FONS_INIT_ROWS);
stash->crows = FONS_INIT_ROWS;
stash->nrows = 0;
stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ROWS);
if (stash->atlas == NULL) goto error;

// Allocate space for fonts.
stash->fonts = (struct FONSfont**)malloc(sizeof(struct FONSfont*) * FONS_INIT_FONTS);
@@ -321,7 +423,7 @@ struct FONScontext* fonsCreate(struct FONSparams* params)
return stash;

error:
fonsDelete(stash);
fonsDeleteInternal(stash);
return NULL;
}

@@ -387,34 +489,6 @@ void fonsClearState(struct FONScontext* stash)
state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
}



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

// Read in the font data.
fp = fopen(path, "rb");
if (!fp) goto error;
fseek(fp,0,SEEK_END);
dataSize = (int)ftell(fp);
fseek(fp,0,SEEK_SET);
data = (unsigned char*)malloc(dataSize);
if (data == NULL) goto error;
fread(data, 1, dataSize, fp);
fclose(fp);
fp = 0;

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

error:
if (data) free(data);
if (fp) fclose(fp);
return 0;
}

static void fons__freeFont(struct FONSfont* font)
{
if (font == NULL) return;
@@ -456,6 +530,32 @@ error:
return FONS_INVALID;
}

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

// Read in the font data.
fp = fopen(path, "rb");
if (!fp) goto error;
fseek(fp,0,SEEK_END);
dataSize = (int)ftell(fp);
fseek(fp,0,SEEK_SET);
data = (unsigned char*)malloc(dataSize);
if (data == NULL) goto error;
fread(data, 1, dataSize, fp);
fclose(fp);
fp = 0;

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

error:
if (data) free(data);
if (fp) fclose(fp);
return 0;
}

int fonsAddFontMem(struct FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData)
{
int i, ascent, descent, fh, lineGap;
@@ -510,48 +610,6 @@ int fonsGetFontByName(struct FONScontext* s, const char* name)
return FONS_INVALID;
}

const unsigned char* fonsGetTextureData(struct FONScontext* stash, int* width, int* height)
{
if (width != NULL)
*width = stash->params.width;
if (height != NULL)
*height = stash->params.height;
return stash->texData;
}

int fonsValidateTexture(struct FONScontext* stash, int* dirty)
{
if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
dirty[0] = stash->dirtyRect[0];
dirty[1] = stash->dirtyRect[1];
dirty[2] = stash->dirtyRect[2];
dirty[3] = stash->dirtyRect[3];
// Reset dirty rect
stash->dirtyRect[0] = stash->params.width;
stash->dirtyRect[1] = stash->params.height;
stash->dirtyRect[2] = 0;
stash->dirtyRect[3] = 0;
return 1;
}
return 0;
}

static struct FONSrow* fons__allocRow(struct FONScontext* stash)
{
struct FONSrow* rows = NULL;
if (stash->nrows+1 > stash->crows) {
stash->crows *= 2;
rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * stash->crows);
if (rows == NULL) return NULL;
memset(rows, 0, sizeof(struct FONSrow) * stash->crows);
if (stash->nrows > 0)
memcpy(rows, stash->rows, sizeof(struct FONSrow) * stash->nrows);
free(stash->rows);
stash->rows = rows;
}
stash->nrows++;
return &stash->rows[stash->nrows-1];
}

static struct FONSglyph* fons__allocGlyph(struct FONSfont* font)
{
@@ -570,98 +628,81 @@ static struct FONSglyph* fons__allocGlyph(struct FONSfont* font)
return &font->glyphs[font->nglyphs-1];
}

static int fons__clamp(int a, int amin, int amax) { return a < amin ? amin : (a > amax ? amax : a); }

static void fons__hblur(unsigned char* dst, int dstStride, unsigned char* src, int srcStride,
int w, int h, int blur, unsigned short* idx)
{
int x,y,acc;
int d = 1 + 2*blur;
int w1 = w-1;
idx += blur;
// Based on Exponential blur, Jani Huhtanen, 2006

for (x = -blur; x <= w+blur; x++) {
idx[x] = fons__clamp(x,0,w1);
}
#define APREC 16
#define ZPREC 7

for (y = 0; y < h; y++) {
// warm up accumulator
acc = 0;
for (x = -blur; x < blur; x++)
acc += src[idx[x]];
for (x = 0; x < w; x++) {
acc += src[idx[x+blur]];
dst[x] = (unsigned char)(acc / d);
acc -= src[idx[x-blur]];
static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha)
{
int x, y;
for (y = 0; y < h; y++) {
int z = 0; // force zero border
for (x = 1; x < w; x++) {
z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
dst[x] = (unsigned char)(z >> ZPREC);
}
dst[w-1] = 0; // force zero border
z = 0;
for (x = w-2; x >= 0; x--) {
z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
dst[x] = (unsigned char)(z >> ZPREC);
}
src += srcStride;
dst[0] = 0; // force zero border
dst += dstStride;
}

}

static void fons__vblur(unsigned char* dst, int dstStride, unsigned char* src, int srcStride,
int w, int h, int blur, unsigned short* idx)
static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha)
{
int x,y,acc;
int d = 1 + 2*blur;
int h1 = h-1;
idx += blur;

for (y = -blur; y <= h+blur; y++)
idx[y] = fons__clamp(y,0,h1) * srcStride;

for (x = 0; x < w; x++) {
// warm up accumulator
acc = 0;
for (y = -blur; y < blur; y++)
acc += src[idx[y]];
for (y = 0; y < h; y++) {
acc += src[idx[y+blur]];
dst[y*dstStride] = (unsigned char)(acc / d);
acc -= src[idx[y-blur]];
int x, y;
for (x = 0; x < w; x++) {
int z = 0; // force zero border
for (y = dstStride; y < h*dstStride; y += dstStride) {
z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
dst[y] = (unsigned char)(z >> ZPREC);
}
dst[(h-1)*dstStride] = 0; // force zero border
z = 0;
for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
dst[y] = (unsigned char)(z >> ZPREC);
}
src++;
dst[0] = 0; // force zero border
dst++;
}
}


static void fons__blur(struct FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
{
// It is possible that our scratch is too small for blurring (16k scratch can handle about 120x120 blur).
int bufStride = w;
unsigned short* idx;
unsigned char* buf;
buf = (unsigned char*)fons__tmpalloc(w*h, stash);
if (buf == NULL) {
return;
}
idx = (unsigned short*)fons__tmpalloc((1+2*blur+fons__maxi(w,h))*sizeof(unsigned short), stash);
if (idx == NULL) {
return;
}
int alpha;
float sigma;

// Tent.
int b1 = (blur+1)/2, b2 = blur-b1;
fons__hblur(buf,bufStride, dst,dstStride, w,h, b1, idx);
fons__vblur(dst,dstStride, buf,bufStride, w,h, b1, idx);
if (b2 > 0) {
fons__hblur(buf,bufStride, dst,dstStride, w,h, b2, idx);
fons__vblur(dst,dstStride, buf,bufStride, w,h, b2, idx);
}
if (blur < 1)
return;
// Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
fons__blurRows(dst, w, h, dstStride, alpha);
fons__blurCols(dst, w, h, dstStride, alpha);
fons__blurRows(dst, w, h, dstStride, alpha);
fons__blurCols(dst, w, h, dstStride, alpha);
// fons__blurrows(dst, w, h, dstStride, alpha);
// fons__blurcols(dst, w, h, dstStride, alpha);
}


static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfont* font, unsigned int codepoint,
short isize, short iblur)
{
int i, g, advance, lsb, x0, y0, x1, y1, gw, gh;
int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
float scale;
struct FONSglyph* glyph = NULL;
unsigned int h;
float size = isize/10.0f;
int rh, pad, x, y;
struct FONSrow* br;
int pad;
unsigned char* bdst;
unsigned char* dst;

if (isize < 2) return NULL;
@@ -688,34 +729,9 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo
gw = x1-x0 + pad*2;
gh = y1-y0 + pad*2;

// Find row where the glyph can be fit.
br = NULL;
rh = (gh+7) & ~7;
for (i = 0; i < stash->nrows; ++i) {
int rmax = stash->rows[i].h, rmin = rmax - rmax/4;
if (rh >= rmin && rh <= rmax && (stash->rows[i].x+gw) <= stash->params.width) {
br = &stash->rows[i];
break;
}
}

// If no row found, add new.
if (br == NULL) {
short py = 0;
// Check that there is enough space.
if (stash->nrows > 0) {
py = stash->rows[stash->nrows-1].y + stash->rows[stash->nrows-1].h;
if (py+rh > stash->params.height)
return NULL;
}
// Init and add row
br = fons__allocRow(stash);
if (br == NULL)
return NULL;
br->x = 0;
br->y = py;
br->h = rh;
}
// Find free spot for the rect in the atlas
if (fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy) == 0)
return NULL;

// Init glyph.
glyph = fons__allocGlyph(font);
@@ -723,8 +739,8 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo
glyph->size = isize;
glyph->blur = iblur;
glyph->index = g;
glyph->x0 = br->x;
glyph->y0 = br->y;
glyph->x0 = gx;
glyph->y0 = gy;
glyph->x1 = glyph->x0+gw;
glyph->y1 = glyph->y0+gh;
glyph->xadv = (short)(scale * advance * 10.0f);
@@ -732,9 +748,6 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo
glyph->yoff = y0 - pad;
glyph->next = 0;

// Advance row location.
br->x += gw+1;

// Insert char to hash lookup.
glyph->next = font->lut[h];
font->lut[h] = font->nglyphs-1;
@@ -754,27 +767,30 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo
dst[x + (gh-1)*stash->params.width] = 0;
}

/*
// Debug code to color the glyph background
/* dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
int x,y;
unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
for (y = 0; y < gh; y++) {
for (x = 0; x < gw; x++) {
int a = (int)dst[x+y*stash->params.width] + 20;
int a = (int)fdst[x+y*stash->params.width] + 20;
if (a > 255) a = 255;
dst[x+y*stash->params.width] = a;
fdst[x+y*stash->params.width] = a;
}
}*/
}
*/

// Blur
if (iblur > 0) {
stash->nscratch = 0;
dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
fons__blur(stash, dst, gw,gh, stash->params.width, iblur);
bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
}

stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], fons__maxi(0, glyph->x0-1));
stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], fons__maxi(0, glyph->y0-1));
stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], fons__mini(glyph->x1+1, stash->params.width));
stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], fons__mini(glyph->y1+1, stash->params.height));
stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);

return glyph;
}
@@ -784,9 +800,10 @@ static void fons__getQuad(struct FONScontext* stash, struct FONSfont* font,
float scale, float spacing, float* x, float* y, struct FONSquad* q)
{
int rx,ry,xoff,yoff,x0,y0,x1,y1;

if (prevGlyph) {
float adv = stbtt_GetGlyphKernAdvance(&font->font, prevGlyph->index, glyph->index) * scale;
*x += (int)(adv+0.5f);
*x += adv;
}

// Each glyph has 2px border to allow good interpolation,
@@ -851,7 +868,7 @@ static void fons__flush(struct FONScontext* stash)
}
}

static inline void fons__vertex(struct FONScontext* stash, float x, float y, float s, float t, unsigned int c)
static __inline void fons__vertex(struct FONScontext* stash, float x, float y, float s, float t, unsigned int c)
{
stash->verts[stash->nverts*2+0] = x;
stash->verts[stash->nverts*2+1] = y;
@@ -887,9 +904,9 @@ static float fons__getVertAlign(struct FONScontext* stash, struct FONSfont* font
return 0.0;
}

void fonsDrawText(struct FONScontext* stash,
float x, float y,
const char* s, float* dx)
float fonsDrawText(struct FONScontext* stash,
float x, float y,
const char* str, const char* end)
{
struct FONSstate* state = fons__getState(stash);
unsigned int codepoint;
@@ -901,33 +918,36 @@ void fonsDrawText(struct FONScontext* stash,
short iblur = (short)state->blur;
float scale;
struct FONSfont* font;
float width;

if (stash == NULL) return;
if (state->font < 0 || state->font >= stash->nfonts) return;
if (stash == NULL) return x;
if (state->font < 0 || state->font >= stash->nfonts) return x;
font = stash->fonts[state->font];
if (!font->data) return;
if (!font->data) return x;

scale = stbtt_ScaleForPixelHeight(&font->font, (float)isize/10.0f);

float width;
// Align horizontally
if (state->align & FONS_ALIGN_LEFT) {
// empty
} else if (state->align & FONS_ALIGN_RIGHT) {
fonsTextBounds(stash, s, &width, NULL);
width = fonsTextBounds(stash, str, end, NULL);
x -= width;
} else if (state->align & FONS_ALIGN_CENTER) {
fonsTextBounds(stash, s, &width, NULL);
width = fonsTextBounds(stash, str, end, NULL);
x -= width * 0.5f;
}
// Align vertically.
y += fons__getVertAlign(stash, font, state->align, isize);

for (; *s; ++s) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)s))
if (end == NULL)
end = str + strlen(str);

for (; *str; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
if (glyph != NULL) {
if (glyph) {
fons__getQuad(stash, font, prevGlyph, glyph, scale, state->spacing, &x, &y, &q);

if (stash->nverts+6 > FONS_VERTEX_COUNT)
@@ -944,11 +964,12 @@ void fonsDrawText(struct FONScontext* stash,
prevGlyph = glyph;
}
fons__flush(stash);
if (dx) *dx = x;

return x;
}

int fonsTextIterInit(struct FONScontext* stash, struct FONStextIter* iter,
float x, float y, const char* s)
float x, float y, const char* str, const char* end)
{
struct FONSstate* state = fons__getState(stash);
float width;
@@ -968,19 +989,23 @@ int fonsTextIterInit(struct FONScontext* stash, struct FONStextIter* iter,
if (state->align & FONS_ALIGN_LEFT) {
// empty
} else if (state->align & FONS_ALIGN_RIGHT) {
fonsTextBounds(stash, s, &width, NULL);
width = fonsTextBounds(stash, str, end, NULL);
x -= width;
} else if (state->align & FONS_ALIGN_CENTER) {
fonsTextBounds(stash, s, &width, NULL);
width = fonsTextBounds(stash, str, end, NULL);
x -= width * 0.5f;
}
// Align vertically.
y += fons__getVertAlign(stash, iter->font, state->align, iter->isize);

if (end == NULL)
end = str + strlen(str);

iter->x = x;
iter->y = y;
iter->spacing = state->spacing;
iter->str = s;
iter->str = str;
iter->end = end;

return 1;
}
@@ -989,18 +1014,15 @@ int fonsTextIterNext(struct FONScontext* stash, struct FONStextIter* iter, struc
{
struct FONSglyph* glyph = NULL;
unsigned int codepoint = 0;
const char* s = iter->str;
const char* str = iter->str;

if (*s == '\0')
if (*str == '\0')
return 0;

for (; *s; s++) {
if (fons__decutf8(&iter->utf8state, &codepoint, *(const unsigned char*)s))
for (; str != iter->end; str++) {
if (fons__decutf8(&iter->utf8state, &codepoint, *(const unsigned char*)str))
continue;
s++;

// printf("%c", codepoint);

str++;
// Get glyph and quad
glyph = fons__getGlyph(stash, iter->font, codepoint, iter->isize, iter->iblur);
if (glyph != NULL)
@@ -1008,7 +1030,7 @@ int fonsTextIterNext(struct FONScontext* stash, struct FONStextIter* iter, struc
iter->prevGlyph = glyph;
break;
}
iter->str = s;
iter->str = str;

return 1;
}
@@ -1027,13 +1049,11 @@ void fonsDrawDebug(struct FONScontext* stash, float x, float y)
fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff);
fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);

fons__flush(stash);
}

void fonsTextBounds(struct FONScontext* stash,
const char* s,
float* width, float* bounds)
float fonsTextBounds(struct FONScontext* stash,
const char* str, const char* end,
float* bounds)
{
struct FONSstate* state = fons__getState(stash);
unsigned int codepoint;
@@ -1047,10 +1067,10 @@ void fonsTextBounds(struct FONScontext* stash,
struct FONSfont* font;
float x = 0, y = 0, minx, miny, maxx, maxy;

if (stash == NULL) return;
if (state->font < 0 || state->font >= stash->nfonts) return;
if (stash == NULL) return 0;
if (state->font < 0 || state->font >= stash->nfonts) return 0;
font = stash->fonts[state->font];
if (!font->data) return;
if (!font->data) return 0;

scale = stbtt_ScaleForPixelHeight(&font->font, (float)isize/10.0f);

@@ -1060,12 +1080,15 @@ void fonsTextBounds(struct FONScontext* stash,
minx = maxx = x;
miny = maxy = y;

for (; *s; ++s) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)s))
if (end == NULL)
end = str + strlen(str);

for (; *str; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
if (glyph) {
fons__getQuad(stash, font, prevGlyph, glyph, scale, state->spacing, &x, &y, &q);
fons__getQuad(stash, font, prevGlyph, glyph, state->spacing, scale, &x, &y, &q);
if (q.x0 < minx) minx = q.x0;
if (q.x1 > maxx) maxx = q.x1;
if (q.y1 < miny) miny = q.y1;
@@ -1073,9 +1096,6 @@ void fonsTextBounds(struct FONScontext* stash,
}
prevGlyph = glyph;
}
if (width) {
*width = x;
}

// Align horizontally
if (state->align & FONS_ALIGN_LEFT) {
@@ -1094,16 +1114,21 @@ void fonsTextBounds(struct FONScontext* stash,
bounds[2] = maxx;
bounds[3] = maxy;
}

return x;
}

void fonsVertMetrics(struct FONScontext* stash,
float* ascender, float* descender, float* lineh)
{
struct FONSfont* font;
struct FONSstate* state = fons__getState(stash);
short isize;

if (stash == NULL) return;
if (state->font < 0 || state->font >= stash->nfonts) return;
struct FONSfont* font = stash->fonts[state->font];
short isize = (short)(state->size*10.0f);
font = stash->fonts[state->font];
isize = (short)(state->size*10.0f);
if (!font->data) return;

if (ascender)
@@ -1114,19 +1139,45 @@ void fonsVertMetrics(struct FONScontext* stash,
*lineh = font->lineh*isize/10.0f;
}

void fonsDelete(struct FONScontext* stash)
const unsigned char* fonsGetTextureData(struct FONScontext* stash, int* width, int* height)
{
if (width != NULL)
*width = stash->params.width;
if (height != NULL)
*height = stash->params.height;
return stash->texData;
}

int fonsValidateTexture(struct FONScontext* stash, int* dirty)
{
if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
dirty[0] = stash->dirtyRect[0];
dirty[1] = stash->dirtyRect[1];
dirty[2] = stash->dirtyRect[2];
dirty[3] = stash->dirtyRect[3];
// Reset dirty rect
stash->dirtyRect[0] = stash->params.width;
stash->dirtyRect[1] = stash->params.height;
stash->dirtyRect[2] = 0;
stash->dirtyRect[3] = 0;
return 1;
}
return 0;
}

void fonsDeleteInternal(struct FONScontext* stash)
{
int i;
if (stash == NULL) return;

if (stash->params.renderDelete != NULL)
if (stash->params.renderDelete)
stash->params.renderDelete(stash->params.userPtr);

for (i = 0; i < stash->nfonts; ++i)
fons__freeFont(stash->fonts[i]);

if (stash->atlas) fons__deleteAtlas(stash->atlas);
if (stash->fonts) free(stash->fonts);
if (stash->rows) free(stash->rows);
if (stash->texData) free(stash->texData);
free(stash);
}


+ 21
- 39
src/glnanovg.h View File

@@ -195,6 +195,20 @@ static void glnvg__deleteShader(struct GLNVGshader* shader)
glDeleteShader(shader->frag);
}

static void glnvg__getUniforms(struct GLNVGshader* shader)
{
shader->loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(shader->prog, "scissorMat");
shader->loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(shader->prog, "scissorExt");
shader->loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(shader->prog, "paintMat");
shader->loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(shader->prog, "extent");
shader->loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(shader->prog, "radius");
shader->loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(shader->prog, "feather");
shader->loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(shader->prog, "innerCol");
shader->loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(shader->prog, "outerCol");
shader->loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(shader->prog, "strokeMult");
shader->loc[GLNVG_LOC_TEX] = glGetUniformLocation(shader->prog, "tex");
}

static int glnvg__renderCreate(void* uptr)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
@@ -273,38 +287,14 @@ static int glnvg__renderCreate(void* uptr)

if (glnvg__createShader(&gl->gradShader, "grad", fillVertShader, fillFragGradShader) == 0)
return 0;

glnvg__checkError("grad");

gl->gradShader.loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(gl->gradShader.prog, "scissorMat");
gl->gradShader.loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(gl->gradShader.prog, "scissorExt");
gl->gradShader.loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(gl->gradShader.prog, "paintMat");
gl->gradShader.loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(gl->gradShader.prog, "extent");
gl->gradShader.loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(gl->gradShader.prog, "radius");
gl->gradShader.loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(gl->gradShader.prog, "feather");
gl->gradShader.loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(gl->gradShader.prog, "innerCol");
gl->gradShader.loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(gl->gradShader.prog, "outerCol");
gl->gradShader.loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(gl->gradShader.prog, "strokeMult");

glnvg__checkError("grad loc");

if (glnvg__createShader(&gl->imgShader, "image", fillVertShader, fillFragImgShader) == 0)
return 0;

glnvg__checkError("image");
glnvg__checkError("uniform locations");
glnvg__getUniforms(&gl->gradShader);
glnvg__getUniforms(&gl->imgShader);

gl->imgShader.loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(gl->imgShader.prog, "scissorMat");
gl->imgShader.loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(gl->imgShader.prog, "scissorExt");
gl->imgShader.loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(gl->imgShader.prog, "paintMat");
gl->imgShader.loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(gl->imgShader.prog, "extent");
// gl->gradShader.loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(gl->gradShader.prog, "radius");
// gl->gradShader.loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(gl->gradShader.prog, "feather");
// gl->gradShader.loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(gl->gradShader.prog, "innerCol");
// gl->gradShader.loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(gl->gradShader.prog, "outerCol");
gl->imgShader.loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(gl->imgShader.prog, "strokeMult");
gl->imgShader.loc[GLNVG_LOC_TEX] = glGetUniformLocation(gl->imgShader.prog, "tex");

glnvg__checkError("image loc");
glnvg__checkError("done");

return 1;
}
@@ -453,14 +443,10 @@ static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, st
glUniform2f(gl->imgShader.loc[GLNVG_LOC_EXTENT], paint->extent[0], paint->extent[1]);
glUniform1f(gl->imgShader.loc[GLNVG_LOC_STROKEMULT], width*0.5f + aasize*0.5f);
glUniform1i(gl->imgShader.loc[GLNVG_LOC_TEX], 0);

glnvg__checkError("tex paint loc");

glnvg__checkError("tex paint loc");
glBindTexture(GL_TEXTURE_2D, tex->tex);
glEnable(GL_TEXTURE_2D);

glnvg__checkError("tex paint tex");

glnvg__checkError("tex paint tex");
} else {
glUseProgram(gl->gradShader.prog);
glUniformMatrix3fv(gl->gradShader.loc[GLNVG_LOC_SCISSORMAT], 1, GL_FALSE, scissorMat);
@@ -472,8 +458,7 @@ static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, st
glUniform4fv(gl->gradShader.loc[GLNVG_LOC_INNERCOL], 1, innerCol);
glUniform4fv(gl->gradShader.loc[GLNVG_LOC_OUTERCOL], 1, outerCol);
glUniform1f(gl->gradShader.loc[GLNVG_LOC_STROKEMULT], width*0.5f + aasize*0.5f);

glnvg__checkError("grad paint loc");
glnvg__checkError("grad paint loc");
}
return 1;
}
@@ -555,9 +540,6 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
glStencilFunc(GL_NOTEQUAL, 0x0, 0xff);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);

// glUseProgram(0);
// glColor4ub(255,0,0,128);

glBegin(GL_QUADS);
glTexCoord2f(0.5f,1.0f);
glVertex2f(bounds[0], bounds[3]);


+ 35
- 22
src/nanovg.c View File

@@ -109,6 +109,14 @@ struct NVGcontext {
int textTriCount;
};

static float nvg__sqrtf(float a) { return sqrtf(a); }
static float nvg__modf(float a, float b) { return fmodf(a, b); }
static float nvg__sinf(float a) { return sinf(a); }
static float nvg__cosf(float a) { return cosf(a); }
static float nvg__tanf(float a) { return tanf(a); }
static float nvg__atan2f(float a,float b) { return atan2f(a, b); }
static float nvg__acosf(float a) { return acosf(a); }

static int nvg__mini(int a, int b) { return a < b ? a : b; }
static int nvg__maxi(int a, int b) { return a > b ? a : b; }
static float nvg__minf(float a, float b) { return a < b ? a : b; }
@@ -119,7 +127,7 @@ static float nvg__cross(float dx0, float dy0, float dx1, float dy1) { return dx1

static float nvg__normalize(float *x, float* y)
{
float d = sqrtf((*x)*(*x) + (*y)*(*y));
float d = nvg__sqrtf((*x)*(*x) + (*y)*(*y));
if (d > 1e-6f) {
d = 1.0f / d;
*x *= d;
@@ -201,7 +209,7 @@ struct NVGcontext* nvgCreateInternal(struct NVGparams* params)
fontParams.renderDraw = NULL;
fontParams.renderDelete = NULL;
fontParams.userPtr = NULL;
ctx->fs = fonsCreate(&fontParams);
ctx->fs = fonsCreateInternal(&fontParams);
if (ctx->fs == NULL) goto error;

// Create font texture
@@ -222,7 +230,7 @@ void nvgDeleteInternal(struct NVGcontext* ctx)
if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache);

if (ctx->fs)
fonsDelete(ctx->fs);
fonsDeleteInternal(ctx->fs);

if (ctx->params.renderDelete != NULL)
ctx->params.renderDelete(ctx->params.userPtr);
@@ -282,7 +290,7 @@ static float nvg__hue(float h, float m1, float m2)

unsigned int nvgHSLA(float h, float s, float l, unsigned char a)
{
h = fmod(h, 1.0f);
h = nvg__modf(h, 1.0f);
if (h < 0.0f) h += 1.0f;
s = nvg__clampf(s, 0.0f, 1.0f);
l = nvg__clampf(l, 0.0f, 1.0f);
@@ -323,7 +331,7 @@ static void nvg__xformScale(float* t, float sx, float sy)

static void nvg__xformRotate(float* t, float a)
{
float cs = cosf(a), sn = sinf(a);
float cs = nvg__cosf(a), sn = nvg__sinf(a);
t[0] = cs; t[1] = sn;
t[2] = -sn; t[3] = cs;
t[4] = 0.0f; t[5] = 0.0f;
@@ -1280,8 +1288,8 @@ void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, fl
dy1 = y2-y1;
nvg__normalize(&dx0,&dy0);
nvg__normalize(&dx1,&dy1);
a = acosf(dx0*dx1 + dy0*dy1);
d = radius / tanf(a/2.0f);
a = nvg__acosf(dx0*dx1 + dy0*dy1);
d = radius / nvg__tanf(a/2.0f);

if (d > 10000.0f) {
nvgLineTo(ctx, x1,y1);
@@ -1291,14 +1299,14 @@ void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, fl
if (nvg__cross(dx0,dy0, dx1,dy1) > 0.0f) {
cx = x1 + dx0*d + dy0*radius;
cy = y1 + dy0*d + -dx0*radius;
a0 = atan2f(dx0, -dy0);
a1 = atan2f(-dx1, dy1);
a0 = nvg__atan2f(dx0, -dy0);
a1 = nvg__atan2f(-dx1, dy1);
dir = NVG_CW;
} else {
cx = x1 + dx0*d + -dy0*radius;
cy = y1 + dy0*d + dx0*radius;
a0 = atan2f(-dx0, dy0);
a1 = atan2f(dx1, -dy1);
a0 = nvg__atan2f(-dx0, dy0);
a1 = nvg__atan2f(dx1, -dy1);
dir = NVG_CCW;
}

@@ -1345,7 +1353,7 @@ void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float
// Split arc into max 90 degree segments.
ndivs = nvg__maxi(1, nvg__mini((int)(nvg__absf(da) / (NVG_PI*0.5f) + 0.5f), 5));
hda = (da / (float)ndivs) / 2.0f;
kappa = nvg__absf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
kappa = nvg__absf(4.0f / 3.0f * (1.0f - nvg__cosf(hda)) / nvg__sinf(hda));

if (dir == NVG_CCW)
kappa = -kappa;
@@ -1353,8 +1361,8 @@ void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float
nvals = 0;
for (i = 0; i <= ndivs; i++) {
a = a0 + da * (i/(float)ndivs);
dx = cosf(a);
dy = sinf(a);
dx = nvg__cosf(a);
dy = nvg__sinf(a);
x = cx + dx*r;
y = cy + dy*r;
tanx = -dy*r*kappa;
@@ -1526,7 +1534,7 @@ void nvgFontFace(struct NVGcontext* ctx, const char* font)
state->fontId = fonsGetFontByName(ctx->fs, font);
}

void nvgText(struct NVGcontext* ctx, float x, float y, const char* string)
float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end)
{
struct NVGstate* state = nvg__getState(ctx);
struct FONStextIter iter;
@@ -1538,7 +1546,10 @@ void nvgText(struct NVGcontext* ctx, float x, float y, const char* string)
int cverts = 0;
int nverts = 0;

if (state->fontId == FONS_INVALID) return;
if (end == NULL)
end = string + strlen(string);

if (state->fontId == FONS_INVALID) return x;

fonsSetSize(ctx->fs, state->fontSize*scale);
fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
@@ -1546,11 +1557,11 @@ void nvgText(struct NVGcontext* ctx, float x, float y, const char* string)
fonsSetAlign(ctx->fs, state->textAlign);
fonsSetFont(ctx->fs, state->fontId);

cverts = nvg__maxi(2, strlen(string)) * 6; // conservative estimate.
cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate.
verts = nvg__allocTempVerts(ctx, cverts);
if (verts == NULL) return;
if (verts == NULL) return x;

fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string);
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end);
while (fonsTextIterNext(ctx->fs, &iter, &q)) {
// Trasnform corners.
float c[4*2];
@@ -1587,12 +1598,14 @@ void nvgText(struct NVGcontext* ctx, float x, float y, const char* string)

ctx->drawCallCount++;
ctx->textTriCount += nverts/3;

return iter.x;
}

void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, float* bounds)
float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, float* bounds)
{
struct NVGstate* state = nvg__getState(ctx);
if (state->fontId == FONS_INVALID) return;
if (state->fontId == FONS_INVALID) return 0;

fonsSetSize(ctx->fs, state->fontSize);
fonsSetSpacing(ctx->fs, state->letterSpacing);
@@ -1600,7 +1613,7 @@ void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, flo
fonsSetAlign(ctx->fs, state->textAlign);
fonsSetFont(ctx->fs, state->fontId);

fonsTextBounds(ctx->fs, string, width, bounds);
return fonsTextBounds(ctx->fs, string, end, bounds);
}

void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh)


+ 2
- 2
src/nanovg.h View File

@@ -186,10 +186,10 @@ void nvgFontFaceId(struct NVGcontext* ctx, int font);
void nvgFontFace(struct NVGcontext* ctx, const char* font);

// Draw text
void nvgText(struct NVGcontext* ctx, float x, float y, const char* string);
float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end);

// Measure text
void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, float* bounds);
float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, float* bounds);
void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh);




Loading…
Cancel
Save