dragonpilot 0.7.10

This commit is contained in:
Rick Lan
2020-10-30 11:38:41 +10:00
parent 8369e11417
commit a8f732edb4
138 changed files with 14889 additions and 3028 deletions
+114 -35
View File
@@ -38,6 +38,11 @@ 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,
@@ -78,6 +83,7 @@ struct FONStextIter {
const char* next;
const char* end;
unsigned int utf8state;
int bitmapOption;
};
typedef struct FONStextIter FONStextIter;
@@ -87,6 +93,8 @@ typedef struct FONScontext FONScontext;
FONScontext* fonsCreateInternal(FONSparams* params);
void fonsDeleteInternal(FONScontext* s);
void fontsDeleteFontByName(FONScontext* stash, const char* name);
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);
@@ -122,7 +130,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
@@ -156,11 +164,19 @@ 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_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)
{
FT_Error ftError;
@@ -198,7 +214,7 @@ int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float
ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));
if (ftError) return 0;
ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);
ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
if (ftError) return 0;
ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
if (ftError) return 0;
@@ -258,6 +274,12 @@ int fons__tt_init(FONScontext *context)
return 1;
}
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 stbError;
@@ -265,6 +287,7 @@ int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char
font->font.userdata = context;
stbError = stbtt_InitFont(&font->font, data, 0);
return stbError;
}
@@ -306,7 +329,7 @@ int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
#endif
#ifndef FONS_SCRATCH_BUF_SIZE
# define FONS_SCRATCH_BUF_SIZE 64000
# define FONS_SCRATCH_BUF_SIZE 96000
#endif
#ifndef FONS_HASH_LUT_SIZE
# define FONS_HASH_LUT_SIZE 256
@@ -869,7 +892,6 @@ error:
return FONS_INVALID;
}
int fonsAddFont(FONScontext* stash, const char* name, const char* path)
{
FILE* fp = 0;
@@ -922,7 +944,7 @@ int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, in
// Init font
stash->nscratch = 0;
if (!fons__tt_loadFont(stash, &font->font, data, dataSize)) 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);
@@ -1028,7 +1050,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;
@@ -1038,6 +1060,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;
@@ -1050,41 +1073,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);
// Try to find the glyph in fallback fonts.
if (g == 0) {
for (i = 0; i < font->nfallbacks; ++i) {
FONSglyph* fallbackGlyph = fons__getGlyph(stash, stash->fonts[font->fallbacks[i]], codepoint, isize, iblur);
if (fallbackGlyph != NULL && fallbackGlyph->index != 0) {
return fallbackGlyph;
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.
}
fons__tt_buildGlyphBitmap(&font->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
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;
@@ -1093,15 +1141,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];
@@ -1128,7 +1175,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);
@@ -1290,7 +1337,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);
@@ -1313,7 +1360,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;
@@ -1353,6 +1400,7 @@ int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
iter->end = end;
iter->codepoint = 0;
iter->prevGlyphIndex = -1;
iter->bitmapOption = bitmapOption;
return 1;
}
@@ -1373,7 +1421,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;
@@ -1470,7 +1519,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;
@@ -1579,6 +1628,35 @@ int fonsValidateTexture(FONScontext* stash, int* dirty)
return 0;
}
void fontsDeleteFontByName(FONScontext* stash, const char* name)
{
int id = 0;
if (stash == NULL) return;
if(name == NULL) {
for (id = 0; id < stash->nfonts; ++id) {
fons__freeFont(stash->fonts[id]);
}
stash->nfonts = 0;
}
else {
id = fonsGetFontByName(stash, name);
if(id >= 0) {
fons__freeFont(stash->fonts[id]);
for(; id < stash->nfonts; id++) {
if(id + 1 < stash->nfonts) {
stash->fonts[id] = stash->fonts[id + 1];
}
else {
stash->fonts[id] = NULL;
break;
}
}
stash->nfonts--;
}
}
}
void fonsDeleteInternal(FONScontext* stash)
{
int i;
@@ -1595,6 +1673,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)
+497 -65
View File
@@ -1,4 +1,4 @@
//
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
@@ -17,15 +17,20 @@
//
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include "nanovg.h"
#ifdef WITH_NANOVG_GPU
#include <stdio.h>
#include <memory.h>
#define FONTSTASH_IMPLEMENTATION
#include "fontstash.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#else
#include <string.h>
#define printf(...)
#endif/*WITH_NANOVG_GPU*/
#ifdef _MSC_VER
#pragma warning(disable: 4100) // unreferenced formal parameter
@@ -67,6 +72,7 @@ enum NVGpointFlags
struct NVGstate {
NVGcompositeOperationState compositeOperation;
int shapeAntiAlias;
NVGpaint fill;
NVGpaint stroke;
float strokeWidth;
@@ -140,7 +146,7 @@ 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 int nvg__clampi(int a, int mn, int mx) { return a < mn ? mn : (a > mx ? mx : a); }
__attribute__((unused)) static int nvg__clampi(int a, int mn, int mx) { return a < mn ? mn : (a > mx ? mx : a); }
static float nvg__minf(float a, float b) { return a < b ? a : b; }
static float nvg__maxf(float a, float b) { return a > b ? a : b; }
static float nvg__absf(float a) { return a >= 0.0f ? a : -a; }
@@ -263,6 +269,11 @@ static NVGcompositeOperationState nvg__compositeOperationState(int op)
sfactor = NVG_ONE_MINUS_DST_ALPHA;
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
}
else
{
sfactor = NVG_ONE;
dfactor = NVG_ZERO;
}
NVGcompositeOperationState state;
state.srcRGB = sfactor;
@@ -277,9 +288,19 @@ static NVGstate* nvg__getState(NVGcontext* ctx)
return &ctx->states[ctx->nstates-1];
}
void nvgGetStateXfrom(NVGcontext* ctx, float* xform)
{
if(xform != NULL) {
memcpy(xform, &(ctx->states[ctx->nstates-1].xform), sizeof(float) * 6);
}
}
NVGcontext* nvgCreateInternal(NVGparams* params)
{
#ifdef WITH_NANOVG_GPU
FONSparams fontParams;
#endif/*WITH_NANOVG_GPU*/
NVGcontext* ctx = (NVGcontext*)malloc(sizeof(NVGcontext));
int i;
if (ctx == NULL) goto error;
@@ -304,6 +325,7 @@ NVGcontext* nvgCreateInternal(NVGparams* params)
if (ctx->params.renderCreate(ctx->params.userPtr) == 0) goto error;
#ifdef WITH_NANOVG_GPU
// Init font rendering
memset(&fontParams, 0, sizeof(fontParams));
fontParams.width = NVG_INIT_FONTIMAGE_SIZE;
@@ -318,9 +340,10 @@ NVGcontext* nvgCreateInternal(NVGparams* params)
if (ctx->fs == NULL) goto error;
// Create font texture
ctx->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL);
ctx->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, 0, NULL);
if (ctx->fontImages[0] == 0) goto error;
ctx->fontImageIdx = 0;
#endif/*WITH_NANOVG_GPU*/
return ctx;
@@ -341,6 +364,7 @@ void nvgDeleteInternal(NVGcontext* ctx)
if (ctx->commands != NULL) free(ctx->commands);
if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache);
#ifdef WITH_NANOVG_GPU
if (ctx->fs)
fonsDeleteInternal(ctx->fs);
@@ -350,6 +374,9 @@ void nvgDeleteInternal(NVGcontext* ctx)
ctx->fontImages[i] = 0;
}
}
#else
(void)i;
#endif/*WITH_NANOVG_GPU*/
if (ctx->params.renderDelete != NULL)
ctx->params.renderDelete(ctx->params.userPtr);
@@ -357,7 +384,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,
@@ -384,8 +411,7 @@ void nvgCancelFrame(NVGcontext* ctx)
void nvgEndFrame(NVGcontext* ctx)
{
NVGstate* state = nvg__getState(ctx);
ctx->params.renderFlush(ctx->params.userPtr, state->compositeOperation);
ctx->params.renderFlush(ctx->params.userPtr);
if (ctx->fontImageIdx != 0) {
int fontImage = ctx->fontImages[ctx->fontImageIdx];
int i, j, iw, ih;
@@ -461,7 +487,7 @@ NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u)
{
int i;
float oneminu;
NVGcolor cint = {0};
NVGcolor cint = {{{0}}};
u = nvg__clampf(u, 0.0f, 1.0f);
oneminu = 1.0f - u;
@@ -641,6 +667,7 @@ 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;
@@ -660,6 +687,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);
@@ -676,12 +709,20 @@ void nvgLineCap(NVGcontext* ctx, int cap)
{
NVGstate* state = nvg__getState(ctx);
state->lineCap = cap;
if(ctx->params.setLineJoin != NULL)
{
ctx->params.setLineCap(ctx->params.userPtr, cap);
}
}
void nvgLineJoin(NVGcontext* ctx, int join)
{
NVGstate* state = nvg__getState(ctx);
state->lineJoin = join;
if(ctx->params.setLineJoin != NULL)
{
ctx->params.setLineJoin(ctx->params.userPtr, join);
}
}
void nvgGlobalAlpha(NVGcontext* ctx, float alpha)
@@ -776,6 +817,7 @@ void nvgFillPaint(NVGcontext* ctx, NVGpaint paint)
nvgTransformMultiply(state->fill.xform, state->xform);
}
#ifdef WITH_NANOVG_GPU
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags)
{
int w, h, n, image;
@@ -804,10 +846,21 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int
stbi_image_free(img);
return image;
}
#else
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags)
{
return -1;
}
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata)
{
return -1;
}
#endif/*WITH_NANOVG_GPU*/
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data)
{
return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, imageFlags, data);
return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, w * 4, imageFlags, data);
}
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data)
@@ -822,6 +875,15 @@ void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h)
ctx->params.renderGetTextureSize(ctx->params.userPtr, image, w, h);
}
void nvgDeleteFontByName(NVGcontext* ctx, const char* name)
{
#ifdef WITH_NANOVG_GPU
if (ctx->fs) {
fontsDeleteFontByName(ctx->fs, name);
}
#endif
}
void nvgDeleteImage(NVGcontext* ctx, int image)
{
ctx->params.renderDeleteTexture(ctx->params.userPtr, image);
@@ -948,7 +1010,12 @@ void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h)
w = nvg__maxf(0.0f, w);
h = nvg__maxf(0.0f, h);
/* 消除着色器精度不够引起的漏出颜色的问题 */
if (w == 0.0f || h == 0.0f) {
w = 0.0f;
h = 0.0f;
}
nvgTransformIdentity(state->scissor.xform);
state->scissor.xform[4] = x+w*0.5f;
state->scissor.xform[5] = y+h*0.5f;
@@ -972,6 +1039,66 @@ static void nvg__isectRects(float* dst,
dst[3] = nvg__maxf(0.0f, maxy - miny);
}
void nvgIntersectScissorForOtherRect(NVGcontext* ctx, float x, float y, float w, float h, float dx, float dy, float dw, float dh)
{
NVGstate* state = nvg__getState(ctx);
float rect[4];
float invxorm[6];
float ex = 0.0f, ey = 0.0f, tex = 0.0f, tey = 0.0f;
/* 因为脏矩形默认坐标系就是没有旋转没有缩放没有平移的状态 */
float pxform[6] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
ex = dw * 0.5f;
ey = dh * 0.5f;
pxform[4] = dx + dw * 0.5f;
pxform[5] = dy + dh * 0.5f;
memset(invxorm, 0, sizeof(float) * 6);
nvgTransformInverse(invxorm, state->xform);
nvgTransformMultiply(pxform, invxorm);
tex = ex*nvg__absf(pxform[0]) + ey*nvg__absf(pxform[2]);
tey = ex*nvg__absf(pxform[1]) + ey*nvg__absf(pxform[3]);
// Intersect rects.
nvg__isectRects(rect, pxform[4] - tex, pxform[5] - tey, tex * 2, tey * 2, x, y, w, h);
nvgScissor(ctx, rect[0], rect[1], rect[2], rect[3]);
}
void nvgIntersectScissor_ex(NVGcontext* ctx, float* x, float* y, float* w, float* h)
{
NVGstate* state = nvg__getState(ctx);
float pxform[6], invxorm[6];
float rect[4];
float ex, ey, tex, tey;
// If no previous scissor has been set, set the scissor as current scissor.
if (state->scissor.extent[0] < 0) {
nvgScissor(ctx, *x, *y, *w, *h);
return;
}
// Transform the current scissor rect into current transform space.
// 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];
nvgTransformInverse(invxorm, state->xform);
nvgTransformMultiply(pxform, invxorm);
tex = ex*nvg__absf(pxform[0]) + ey*nvg__absf(pxform[2]);
tey = ex*nvg__absf(pxform[1]) + ey*nvg__absf(pxform[3]);
// Intersect rects.
nvg__isectRects(rect, pxform[4]-tex,pxform[5]-tey,tex*2,tey*2, *x, *y, *w, *h);
*x = rect[0];
*y = rect[1];
*w = rect[2];
*h = rect[3];
nvgScissor(ctx, rect[0], rect[1], rect[2], rect[3]);
}
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h)
{
NVGstate* state = nvg__getState(ctx);
@@ -1411,6 +1538,7 @@ static int nvg__curveDivs(float r, float arc, float tol)
return nvg__maxi(2, (int)ceilf(arc / da));
}
#ifdef WITH_NANOVG_GPU
static void nvg__chooseBevel(int bevel, NVGpoint* p0, NVGpoint* p1, float w,
float* x0, float* y0, float* x1, float* y1)
{
@@ -1428,7 +1556,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;
@@ -1561,36 +1690,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;
@@ -1601,16 +1733,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;
@@ -1618,13 +1751,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;
}
@@ -1700,15 +1833,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.
@@ -1769,42 +1911,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);
@@ -1935,6 +2077,197 @@ static int nvg__expandFill(NVGcontext* ctx, float w, int lineJoin, float miterLi
return 1;
}
#else
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 = 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;
}
// Calculate max vertex usage.
cverts = 0;
for (i = 0; i < cache->npaths; i++) {
NVGpath* path = &cache->paths[i];
int loop = (path->closed == 0) ? 0 : 1;
cverts += (path->count + path->nbevel*5 + 1) * 2; // plus one for loop
if (loop == 0) {
// space for caps
if (lineCap == NVG_ROUND) {
cverts += (ncap*2 + 2)*2;
} else {
cverts += (3+3)*2;
}
}
}
verts = nvg__allocTempVerts(ctx, cverts);
if (verts == NULL) return 0;
for (i = 0; i < cache->npaths; i++) {
NVGpath* path = &cache->paths[i];
NVGpoint* pts = &cache->points[path->first];
NVGpoint* p0;
NVGpoint* p1;
int s, e, loop;
path->fill = 0;
path->nfill = 0;
// Calculate fringe or stroke
loop = (path->closed == 0) ? 0 : 1;
dst = verts;
path->stroke = dst;
if (loop) {
// Looping
p0 = &pts[path->count-1];
p1 = &pts[0];
s = 0;
e = path->count;
} else {
// Add cap
p0 = &pts[0];
p1 = &pts[1];
s = 1;
e = path->count-1;
}
if (loop == 0) {
// Add cap
nvg__vset(dst, p0->x, p0->y, u0,1); dst++;
}
for (j = s; j < e; ++j) {
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, u0,1); dst++;
nvg__vset(dst, verts[1].x, verts[1].y, u1,1); dst++;
} else {
// Add cap
nvg__vset(dst, p1->x, p1->y, u0,1); dst++;
}
path->nstroke = (int)(dst - verts);
verts = dst;
}
return 1;
}
static int nvg__expandFill(NVGcontext* ctx, float w, int lineJoin, float miterLimit)
{
NVGpathCache* cache = ctx->cache;
NVGvertex* verts;
NVGvertex* dst;
int cverts, convex, i, j;
float aa = ctx->fringeWidth;
int fringe = w > 0.0f;
// Calculate max vertex usage.
cverts = 0;
for (i = 0; i < cache->npaths; i++) {
NVGpath* path = &cache->paths[i];
cverts += path->count + path->nbevel + 1;
if (fringe)
cverts += (path->count + path->nbevel*5 + 1) * 2; // plus one for loop
}
verts = nvg__allocTempVerts(ctx, cverts);
if (verts == NULL) return 0;
convex = cache->npaths == 1 && cache->paths[0].convex;
for (i = 0; i < cache->npaths; i++) {
NVGpath* path = &cache->paths[i];
NVGpoint* pts = &cache->points[path->first];
NVGpoint* p0;
NVGpoint* p1;
float rw, lw, woff;
float ru, lu;
// Calculate shape vertices.
woff = 0.5f*aa;
dst = verts;
path->fill = dst;
if (fringe) {
// Looping
p0 = &pts[path->count-1];
p1 = &pts[0];
for (j = 0; j < path->count; ++j) {
nvg__vset(dst, p1->x + (p1->dmx * woff), p1->y + (p1->dmy * woff), 0.5f,1); dst++;
p0 = p1++;
}
} else {
for (j = 0; j < path->count; ++j) {
nvg__vset(dst, pts[j].x, pts[j].y, 0.5f,1);
dst++;
}
}
path->nfill = (int)(dst - verts);
verts = dst;
// Calculate fringe
if (fringe) {
lw = w + woff;
rw = w - woff;
lu = 0;
ru = 1;
dst = verts;
path->stroke = dst;
// Create only half a fringe for convex shapes so that
// the shape can be rendered without stenciling.
if (convex) {
lw = woff; // This should generate the same vertex as fill inset above.
lu = 0.5f; // Set outline fade at middle.
}
// Looping
p0 = &pts[path->count-1];
p1 = &pts[0];
for (j = 0; j < path->count; ++j) {
nvg__vset(dst, p1->x + (p1->dmx * lw), p1->y + (p1->dmy * lw), lu,1); dst++;
nvg__vset(dst, p1->x - (p1->dmx * rw), p1->y - (p1->dmy * rw), ru,1); dst++;
p0 = p1++;
}
// Loop it
nvg__vset(dst, verts[0].x, verts[0].y, lu,1); dst++;
nvg__vset(dst, verts[1].x, verts[1].y, ru,1); dst++;
path->nstroke = (int)(dst - verts);
verts = dst;
} else {
path->stroke = NULL;
path->nstroke = 0;
}
}
return 1;
}
#endif/*WITH_NANOVG_GPU*/
// Draw
void nvgBeginPath(NVGcontext* ctx)
@@ -2168,6 +2501,14 @@ void nvgCircle(NVGcontext* ctx, float cx, float cy, float r)
nvgEllipse(ctx, cx,cy, r,r);
}
int nvgClearCache(NVGcontext* ctx) {
if(ctx->params.clearCache != NULL) {
ctx->params.clearCache(ctx->params.userPtr);
}
return 0;
}
#ifdef WITH_NANOVG_GPU
void nvgDebugDumpPathCache(NVGcontext* ctx)
{
const NVGpath* path;
@@ -2189,6 +2530,7 @@ void nvgDebugDumpPathCache(NVGcontext* ctx)
}
}
}
#endif/*WITH_NANOVG_GPU*/
void nvgFill(NVGcontext* ctx)
{
@@ -2198,7 +2540,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);
@@ -2207,7 +2549,12 @@ 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,
/* 把 nanovg 的坐标系传入到适量画布算法中 */
if(ctx->params.setStateXfrom != NULL) {
ctx->params.setStateXfrom(ctx->params.userPtr, state->xform);
}
ctx->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth,
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths);
// Count triangles
@@ -2228,6 +2575,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.
@@ -2243,12 +2591,17 @@ 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,
/* 把 nanovg 的坐标系传入到适量画布算法中 */
if(ctx->params.setStateXfrom != NULL) {
ctx->params.setStateXfrom(ctx->params.userPtr, state->xform);
}
ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, state->compositeOperation, &state->scissor, ctx->fringeWidth,
strokeWidth, ctx->cache->paths, ctx->cache->npaths);
// Count triangles
@@ -2259,6 +2612,7 @@ void nvgStroke(NVGcontext* ctx)
}
}
#ifdef WITH_NANOVG_GPU
// Add fonts
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* path)
{
@@ -2377,7 +2731,7 @@ static int nvg__allocTextAtlas(NVGcontext* ctx)
iw *= 2;
if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE)
iw = ih = NVG_MAX_FONTIMAGE_SIZE;
ctx->fontImages[ctx->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL);
ctx->fontImages[ctx->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, 0, NULL);
}
++ctx->fontImageIdx;
fonsResetAtlas(ctx->fs, iw, ih);
@@ -2396,7 +2750,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->drawCallCount++;
ctx->textTriCount += nverts/3;
@@ -2428,17 +2782,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?
@@ -2466,7 +2820,7 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char*
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)
@@ -2525,7 +2879,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?
@@ -2549,6 +2903,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)
@@ -2590,7 +2945,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?
@@ -2616,7 +2971,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;
}
@@ -2643,7 +3006,7 @@ 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;
@@ -2663,26 +3026,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;
}
// 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.
@@ -2867,4 +3230,73 @@ void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* l
if (lineh != NULL)
*lineh *= invscale;
}
#else
// State setting
void nvgFontSize(NVGcontext* ctx, float size)
{
NVGstate* state = nvg__getState(ctx);
state->fontSize = size;
}
void nvgFontBlur(NVGcontext* ctx, float blur)
{
}
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing)
{
}
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight)
{
}
void nvgTextAlign(NVGcontext* ctx, int align)
{
}
void nvgFontFaceId(NVGcontext* ctx, int font)
{
}
void nvgFontFace(NVGcontext* ctx, const char* font)
{
}
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData)
{
return 0;
}
int nvgFindFont(NVGcontext* ctx, const char* name) {
return 0;
}
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end) {
return 0;
}
float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds)
{
return 0;
}
#endif/*WITH_NANOVG_GPU*/
NVGparams* nvgGetParams(NVGcontext* ctx) {
return &(ctx->params);
}
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int format, int stride, int imageFlags, const unsigned char* data)
{
return ctx->params.renderCreateTexture(ctx->params.userPtr, format, w, h, stride, imageFlags, data);
}
int nvgFindTextureRaw(NVGcontext* ctx, const void* data)
{
if(ctx->params.findTexture != NULL) {
return ctx->params.findTexture(ctx->params.userPtr, data);
}
return -1;
}
// vim: ft=c nu noet ts=4
+76 -10
View File
@@ -1,4 +1,4 @@
//
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
@@ -24,6 +24,7 @@ extern "C" {
#endif
#define NVG_PI 3.14159265358979323846264338327f
#define WITH_NANOVG_GPU
#ifdef _MSC_VER
#pragma warning(push)
@@ -141,6 +142,7 @@ enum NVGimageFlags {
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_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear
};
// Begin drawing a new frame
@@ -151,7 +153,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);
@@ -237,6 +239,9 @@ void nvgReset(NVGcontext* ctx);
//
// 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);
@@ -384,6 +389,9 @@ void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h);
// Deletes created image.
void nvgDeleteImage(NVGcontext* ctx, int image);
// Deletes font's assets for font's name.
void nvgDeleteFontByName(NVGcontext* ctx, const char* name);
//
// Paints
//
@@ -416,6 +424,9 @@ NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,
float angle, int image, float alpha);
// get xfrom data
void nvgGetStateXfrom(NVGcontext* ctx, float* xform);
//
// Scissoring
//
@@ -434,9 +445,45 @@ void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h);
// transform space. The resulting shape is always rectangle.
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h);
/**
* @method nvgIntersectScissor_ex
* 设置一个与前一个裁剪区做交集的矩形裁剪区。
* 输入要设置的裁剪区,做交集后把新的裁剪区返回来给用户。
*
* @annotation ["scriptable"]
* @param {NVGcontext*} ctx nanovg的对象
* @param {float_t} x 裁剪区x坐标。
* @param {float_t} y 裁剪区y坐标。
* @param {float_t} w 裁剪区宽度。
* @param {float_t} h 裁剪区高度。
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
void nvgIntersectScissor_ex(NVGcontext* ctx, float* x, float* y, float* w, float* h);
// Reset and disables scissoring.
void nvgResetScissor(NVGcontext* ctx);
/**
* @method nvgIntersectScissorForOtherRect
* 设置一个裁剪区,但是该裁剪区收到脏矩形的影响
* 首先会把脏矩形根据当前 nanovg 的坐标系转换为新的脏矩形区域,再和裁剪区做交集,把交集设为新的裁剪区
*
* @annotation ["scriptable"]
* @param {NVGcontext*} ctx nanovg的对象
* @param {float_t} x 裁剪区x坐标。
* @param {float_t} y 裁剪区y坐标。
* @param {float_t} w 裁剪区宽度。
* @param {float_t} h 裁剪区高度。
* @param {float_t} dx 脏矩形x坐标。
* @param {float_t} dy 脏矩形y坐标。
* @param {float_t} dw 脏矩形宽度。
* @param {float_t} dh 脏矩形高度。
*
*/
void nvgIntersectScissorForOtherRect(NVGcontext* ctx, float x, float y, float w, float h, float dx, float dy, float dw, float dh);
//
// Paths
//
@@ -612,8 +659,13 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa
// Internal Render API
//
enum NVGtexture {
NVG_TEXTURE_ALPHA = 0x01,
NVG_TEXTURE_RGBA = 0x02,
NVG_TEXTURE_ALPHA = 1,
NVG_TEXTURE_RGBA = 2,
NVG_TEXTURE_BGRA = 4,
NVG_TEXTURE_RGB = 8,
NVG_TEXTURE_BGR = 16,
NVG_TEXTURE_RGB565 = 32,
NVG_TEXTURE_BGR565 = 64
};
struct NVGscissor {
@@ -644,17 +696,24 @@ typedef struct NVGpath NVGpath;
struct NVGparams {
void* userPtr;
int edgeAntiAlias;
void (*setLineCap)(void* uptr, int lineCap);
void (*setLineJoin)(void* uptr, int lineJoin);
int (*clearCache)(void* uptr);
int (*renderCreate)(void* uptr);
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data);
int (*findTexture)(void* uptr, const void* data);
void (*setStateXfrom)(void* uptr, float* xform);
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int stride, int imageFlags, const unsigned char* data);
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, float devicePixelRatio);
void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio);
void (*renderCancel)(void* uptr);
void (*renderFlush)(void* uptr, NVGcompositeOperationState compositeOperation);
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 (*renderFlush)(void* uptr);
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);
void (*renderDelete)(void* uptr);
};
typedef struct NVGparams NVGparams;
@@ -674,6 +733,13 @@ void nvgDebugDumpPathCache(NVGcontext* ctx);
#define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; }
NVGparams* nvgGetParams(NVGcontext* ctx);
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int format, int stride, int imageFlags, const unsigned char* data);
int nvgFindTextureRaw(NVGcontext* ctx, const void* data);
int nvgClearCache(NVGcontext* ctx);
#ifdef __cplusplus
}
#endif
+1260 -1132
View File
File diff suppressed because it is too large Load Diff
+30 -1
View File
@@ -49,6 +49,16 @@ void nvgluDeleteFramebuffer(NVGLUframebuffer* fb);
static GLint defaultFBO = -1;
int nvgluGetCurrFramebuffer() {
#ifdef NANOVG_FBO_VALID
GLint defaultFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
return defaultFBO;
#else
return -1;
#endif
}
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags)
{
#ifdef NANOVG_FBO_VALID
@@ -90,7 +100,18 @@ NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imag
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) goto error;
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
#ifdef GL_DEPTH24_STENCIL8
// If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback.
// Some graphics cards require a depth buffer along with a stencil.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
#endif // GL_DEPTH24_STENCIL8
goto error;
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
@@ -119,6 +140,14 @@ void nvgluBindFramebuffer(NVGLUframebuffer* fb)
#endif
}
void nvgluReadCurrentFramebufferData(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int width, unsigned int height, void* pixels)
{
if(x + w <= width && y + h <= height && pixels != NULL) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
}
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb)
{
#ifdef NANOVG_FBO_VALID
+1 -1
View File
@@ -411,7 +411,7 @@ extern "C" {
#endif
#ifdef STB_IMAGE_STATIC
#define STBIDEF static
#define STBIDEF static inline
#else
#define STBIDEF extern
#endif