mirror of
https://github.com/memononen/nanovg
synced 2026-09-26 16:19:07 +03:00
Merge branch 'master' of https://github.com/damiles/nanovg
This commit is contained in:
commit
61fb55ac19
9 changed files with 437 additions and 69 deletions
92
example/LICENSE_OFL.txt
Normal file
92
example/LICENSE_OFL.txt
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font
|
||||
creation efforts of academic and linguistic communities, and to
|
||||
provide a free and open framework in which fonts may be shared and
|
||||
improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply to
|
||||
any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software
|
||||
components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to,
|
||||
deleting, or substituting -- in part or in whole -- any of the
|
||||
components of the Original Version, by changing formats or by porting
|
||||
the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed,
|
||||
modify, redistribute, and sell modified and unmodified copies of the
|
||||
Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in
|
||||
Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the
|
||||
corresponding Copyright Holder. This restriction only applies to the
|
||||
primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created using
|
||||
the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
example/NotoEmoji-Regular.ttf
Normal file
BIN
example/NotoEmoji-Regular.ttf
Normal file
Binary file not shown.
|
|
@ -834,6 +834,13 @@ int loadDemoData(NVGcontext* vg, DemoData* data)
|
|||
printf("Could not add font bold.\n");
|
||||
return -1;
|
||||
}
|
||||
data->fontEmoji = nvgCreateFont(vg, "emoji", "../example/NotoEmoji-Regular.ttf");
|
||||
if (data->fontEmoji == -1) {
|
||||
printf("Could not add font emoji.\n");
|
||||
return -1;
|
||||
}
|
||||
nvgAddFallbackFontId(vg, data->fontNormal, data->fontEmoji);
|
||||
nvgAddFallbackFontId(vg, data->fontBold, data->fontEmoji);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -853,7 +860,7 @@ void drawParagraph(NVGcontext* vg, float x, float y, float width, float height,
|
|||
{
|
||||
NVGtextRow rows[3];
|
||||
NVGglyphPosition glyphs[100];
|
||||
const char* text = "This is longer chunk of text.\n \n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
|
||||
const char* text = "This is longer chunk of text.\n \n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.🎉";
|
||||
const char* start;
|
||||
const char* end;
|
||||
int nrows, i, nglyphs, j, lnum = 0;
|
||||
|
|
@ -1191,8 +1198,8 @@ static void flipHorizontal(unsigned char* image, int w, int h, int stride)
|
|||
{
|
||||
int i = 0, j = h-1, k;
|
||||
while (i < j) {
|
||||
unsigned char* ri = &image[i * stride];
|
||||
unsigned char* rj = &image[j * stride];
|
||||
unsigned char* ri = &image[i * stride];
|
||||
unsigned char* rj = &image[j * stride];
|
||||
for (k = 0; k < w*4; k++) {
|
||||
unsigned char t = ri[k];
|
||||
ri[k] = rj[k];
|
||||
|
|
@ -1217,4 +1224,3 @@ void saveScreenShot(int w, int h, int premult, const char* name)
|
|||
stbi_write_png(name, w, h, 4, image, w*4);
|
||||
free(image);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct DemoData {
|
||||
int fontNormal, fontBold, fontIcons;
|
||||
int fontNormal, fontBold, fontIcons, fontEmoji;
|
||||
int images[12];
|
||||
};
|
||||
typedef struct DemoData DemoData;
|
||||
|
|
@ -23,4 +23,4 @@ void saveScreenShot(int w, int h, int premult, const char* name);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif // DEMO_H
|
||||
#endif // DEMO_H
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 966 KiB |
|
|
@ -193,16 +193,18 @@ int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float
|
|||
{
|
||||
FT_Error ftError;
|
||||
FT_GlyphSlot ftGlyph;
|
||||
FT_Fixed advFixed;
|
||||
FONS_NOTUSED(scale);
|
||||
|
||||
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);
|
||||
if (ftError) return 0;
|
||||
ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, (FT_Fixed*)advance);
|
||||
ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
|
||||
if (ftError) return 0;
|
||||
ftGlyph = font->font->glyph;
|
||||
*lsb = ftGlyph->metrics.horiBearingX;
|
||||
*advance = (int)advFixed;
|
||||
*lsb = (int)ftGlyph->metrics.horiBearingX;
|
||||
*x0 = ftGlyph->bitmap_left;
|
||||
*x1 = *x0 + ftGlyph->bitmap.width;
|
||||
*y0 = -ftGlyph->bitmap_top;
|
||||
|
|
@ -233,7 +235,7 @@ int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
|
|||
{
|
||||
FT_Vector ftKerning;
|
||||
FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
|
||||
return ftKerning.x;
|
||||
return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
@ -324,6 +326,9 @@ int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
|
|||
#ifndef FONS_MAX_STATES
|
||||
# define FONS_MAX_STATES 20
|
||||
#endif
|
||||
#ifndef FONS_MAX_FALLBACKS
|
||||
# define FONS_MAX_FALLBACKS 20
|
||||
#endif
|
||||
|
||||
static unsigned int fons__hashint(unsigned int a)
|
||||
{
|
||||
|
|
@ -371,6 +376,8 @@ struct FONSfont
|
|||
int cglyphs;
|
||||
int nglyphs;
|
||||
int lut[FONS_HASH_LUT_SIZE];
|
||||
int fallbacks[FONS_MAX_FALLBACKS];
|
||||
int nfallbacks;
|
||||
};
|
||||
typedef struct FONSfont FONSfont;
|
||||
|
||||
|
|
@ -421,6 +428,8 @@ struct FONScontext
|
|||
void* errorUptr;
|
||||
};
|
||||
|
||||
#ifdef STB_TRUETYPE_IMPLEMENTATION
|
||||
|
||||
static void* fons__tmpalloc(size_t size, void* up)
|
||||
{
|
||||
unsigned char* ptr;
|
||||
|
|
@ -446,6 +455,8 @@ static void fons__tmpfree(void* ptr, void* up)
|
|||
// empty
|
||||
}
|
||||
|
||||
#endif // STB_TRUETYPE_IMPLEMENTATION
|
||||
|
||||
// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
|
||||
|
|
@ -751,6 +762,16 @@ static FONSstate* fons__getState(FONScontext* stash)
|
|||
return &stash->states[stash->nstates-1];
|
||||
}
|
||||
|
||||
int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
|
||||
{
|
||||
FONSfont* baseFont = stash->fonts[base];
|
||||
if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
|
||||
baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fonsSetSize(FONScontext* stash, float size)
|
||||
{
|
||||
fons__getState(stash)->size = size;
|
||||
|
|
@ -852,7 +873,7 @@ error:
|
|||
int fonsAddFont(FONScontext* stash, const char* name, const char* path)
|
||||
{
|
||||
FILE* fp = 0;
|
||||
int dataSize = 0;
|
||||
int dataSize = 0, readed;
|
||||
unsigned char* data = NULL;
|
||||
|
||||
// Read in the font data.
|
||||
|
|
@ -863,9 +884,10 @@ int fonsAddFont(FONScontext* stash, const char* name, const char* path)
|
|||
fseek(fp,0,SEEK_SET);
|
||||
data = (unsigned char*)malloc(dataSize);
|
||||
if (data == NULL) goto error;
|
||||
fread(data, 1, dataSize, fp);
|
||||
readed = fread(data, 1, dataSize, fp);
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
if (readed != dataSize) goto error;
|
||||
|
||||
return fonsAddFontMem(stash, name, data, dataSize, 1);
|
||||
|
||||
|
|
@ -1017,6 +1039,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;
|
||||
|
|
@ -1035,9 +1058,23 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
|
|||
}
|
||||
|
||||
// Could not find glyph, create it.
|
||||
scale = fons__tt_getPixelHeightScale(&font->font, size);
|
||||
g = fons__tt_getGlyphIndex(&font->font, codepoint);
|
||||
fons__tt_buildGlyphBitmap(&font->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
|
||||
// Try to find the glyph in fallback fonts.
|
||||
if (g == 0) {
|
||||
for (i = 0; i < font->nfallbacks; ++i) {
|
||||
FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
|
||||
int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
|
||||
if (fallbackIndex != 0) {
|
||||
g = fallbackIndex;
|
||||
renderFont = fallbackFont;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// It is possible that we did not find a fallback glyph.
|
||||
// In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
|
||||
}
|
||||
scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
|
||||
fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
|
||||
gw = x1-x0 + pad*2;
|
||||
gh = y1-y0 + pad*2;
|
||||
|
||||
|
|
@ -1071,7 +1108,7 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
|
|||
|
||||
// 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];
|
||||
|
|
|
|||
187
src/nanovg.c
187
src/nanovg.c
|
|
@ -66,6 +66,7 @@ enum NVGpointFlags
|
|||
};
|
||||
|
||||
struct NVGstate {
|
||||
NVGcompositeOperationState compositeOperation;
|
||||
NVGpaint fill;
|
||||
NVGpaint stroke;
|
||||
float strokeWidth;
|
||||
|
|
@ -203,6 +204,84 @@ static void nvg__setDevicePixelRatio(NVGcontext* ctx, float ratio)
|
|||
ctx->devicePxRatio = ratio;
|
||||
}
|
||||
|
||||
static NVGcompositeOperationState nvg__compositeOperationState(int op)
|
||||
{
|
||||
int sfactor, dfactor;
|
||||
|
||||
if (op == NVG_SOURCE_OVER)
|
||||
{
|
||||
sfactor = NVG_ONE;
|
||||
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
else if (op == NVG_SOURCE_IN)
|
||||
{
|
||||
sfactor = NVG_DST_ALPHA;
|
||||
dfactor = NVG_ZERO;
|
||||
}
|
||||
else if (op == NVG_SOURCE_OUT)
|
||||
{
|
||||
sfactor = NVG_ONE_MINUS_DST_ALPHA;
|
||||
dfactor = NVG_ZERO;
|
||||
}
|
||||
else if (op == NVG_ATOP)
|
||||
{
|
||||
sfactor = NVG_DST_ALPHA;
|
||||
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
else if (op == NVG_DESTINATION_OVER)
|
||||
{
|
||||
sfactor = NVG_ONE_MINUS_DST_ALPHA;
|
||||
dfactor = NVG_ONE;
|
||||
}
|
||||
else if (op == NVG_DESTINATION_IN)
|
||||
{
|
||||
sfactor = NVG_ZERO;
|
||||
dfactor = NVG_SRC_ALPHA;
|
||||
}
|
||||
else if (op == NVG_DESTINATION_OUT)
|
||||
{
|
||||
sfactor = NVG_ZERO;
|
||||
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
else if (op == NVG_DESTINATION_ATOP)
|
||||
{
|
||||
sfactor = NVG_ONE_MINUS_DST_ALPHA;
|
||||
dfactor = NVG_SRC_ALPHA;
|
||||
}
|
||||
else if (op == NVG_LIGHTER)
|
||||
{
|
||||
sfactor = NVG_ONE;
|
||||
dfactor = NVG_ONE;
|
||||
}
|
||||
else if (op == NVG_COPY)
|
||||
{
|
||||
sfactor = NVG_ONE;
|
||||
dfactor = NVG_ZERO;
|
||||
}
|
||||
else if (op == NVG_XOR)
|
||||
{
|
||||
sfactor = NVG_ONE_MINUS_DST_ALPHA;
|
||||
dfactor = NVG_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
else
|
||||
{
|
||||
sfactor = NVG_ONE;
|
||||
dfactor = NVG_ZERO;
|
||||
}
|
||||
|
||||
NVGcompositeOperationState state;
|
||||
state.srcRGB = sfactor;
|
||||
state.dstRGB = dfactor;
|
||||
state.srcAlpha = sfactor;
|
||||
state.dstAlpha = dfactor;
|
||||
return state;
|
||||
}
|
||||
|
||||
static NVGstate* nvg__getState(NVGcontext* ctx)
|
||||
{
|
||||
return &ctx->states[ctx->nstates-1];
|
||||
}
|
||||
|
||||
NVGcontext* nvgCreateInternal(NVGparams* params)
|
||||
{
|
||||
FONSparams fontParams;
|
||||
|
|
@ -295,7 +374,7 @@ void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float dev
|
|||
|
||||
nvg__setDevicePixelRatio(ctx, devicePixelRatio);
|
||||
|
||||
ctx->params.renderViewport(ctx->params.userPtr, windowWidth, windowHeight);
|
||||
ctx->params.renderViewport(ctx->params.userPtr, windowWidth, windowHeight, devicePixelRatio);
|
||||
|
||||
ctx->drawCallCount = 0;
|
||||
ctx->fillTriCount = 0;
|
||||
|
|
@ -310,7 +389,8 @@ void nvgCancelFrame(NVGcontext* ctx)
|
|||
|
||||
void nvgEndFrame(NVGcontext* ctx)
|
||||
{
|
||||
ctx->params.renderFlush(ctx->params.userPtr);
|
||||
NVGstate* state = nvg__getState(ctx);
|
||||
ctx->params.renderFlush(ctx->params.userPtr, state->compositeOperation);
|
||||
if (ctx->fontImageIdx != 0) {
|
||||
int fontImage = ctx->fontImages[ctx->fontImageIdx];
|
||||
int i, j, iw, ih;
|
||||
|
|
@ -386,7 +466,7 @@ NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u)
|
|||
{
|
||||
int i;
|
||||
float oneminu;
|
||||
NVGcolor cint;
|
||||
NVGcolor cint = {{{0}}};
|
||||
|
||||
u = nvg__clampf(u, 0.0f, 1.0f);
|
||||
oneminu = 1.0f - u;
|
||||
|
|
@ -433,12 +513,6 @@ NVGcolor nvgHSLA(float h, float s, float l, unsigned char a)
|
|||
return col;
|
||||
}
|
||||
|
||||
|
||||
static NVGstate* nvg__getState(NVGcontext* ctx)
|
||||
{
|
||||
return &ctx->states[ctx->nstates-1];
|
||||
}
|
||||
|
||||
void nvgTransformIdentity(float* t)
|
||||
{
|
||||
t[0] = 1.0f; t[1] = 0.0f;
|
||||
|
|
@ -571,6 +645,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->strokeWidth = 1.0f;
|
||||
state->miterLimit = 10.0f;
|
||||
state->lineCap = NVG_BUTT;
|
||||
|
|
@ -939,6 +1014,30 @@ void nvgResetScissor(NVGcontext* ctx)
|
|||
state->scissor.extent[1] = -1.0f;
|
||||
}
|
||||
|
||||
// Global composite operation.
|
||||
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op)
|
||||
{
|
||||
NVGstate* state = nvg__getState(ctx);
|
||||
state->compositeOperation = nvg__compositeOperationState(op);
|
||||
}
|
||||
|
||||
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor)
|
||||
{
|
||||
nvgGlobalCompositeBlendFuncSeparate(ctx, sfactor, dfactor, sfactor, dfactor);
|
||||
}
|
||||
|
||||
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
|
||||
{
|
||||
NVGcompositeOperationState op;
|
||||
op.srcRGB = srcRGB;
|
||||
op.dstRGB = dstRGB;
|
||||
op.srcAlpha = srcAlpha;
|
||||
op.dstAlpha = dstAlpha;
|
||||
|
||||
NVGstate* state = nvg__getState(ctx);
|
||||
state->compositeOperation = op;
|
||||
}
|
||||
|
||||
static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
|
||||
{
|
||||
float dx = x2 - x1;
|
||||
|
|
@ -2025,22 +2124,31 @@ void nvgRect(NVGcontext* ctx, float x, float y, float w, float h)
|
|||
|
||||
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r)
|
||||
{
|
||||
if (r < 0.1f) {
|
||||
nvgRect(ctx, x,y,w,h);
|
||||
nvgRoundedRectVarying(ctx, x, y, w, h, r, r, r, r);
|
||||
}
|
||||
|
||||
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft)
|
||||
{
|
||||
if(radTopLeft < 0.1f && radTopRight < 0.1f && radBottomRight < 0.1f && radBottomLeft < 0.1f) {
|
||||
nvgRect(ctx, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
float rx = nvg__minf(r, nvg__absf(w)*0.5f) * nvg__signf(w), ry = nvg__minf(r, nvg__absf(h)*0.5f) * nvg__signf(h);
|
||||
} else {
|
||||
float halfw = nvg__absf(w)*0.5f;
|
||||
float halfh = nvg__absf(h)*0.5f;
|
||||
float rxBL = nvg__minf(radBottomLeft, halfw) * nvg__signf(w), ryBL = nvg__minf(radBottomLeft, halfh) * nvg__signf(h);
|
||||
float rxBR = nvg__minf(radBottomRight, halfw) * nvg__signf(w), ryBR = nvg__minf(radBottomRight, halfh) * nvg__signf(h);
|
||||
float rxTR = nvg__minf(radTopRight, halfw) * nvg__signf(w), ryTR = nvg__minf(radTopRight, halfh) * nvg__signf(h);
|
||||
float rxTL = nvg__minf(radTopLeft, halfw) * nvg__signf(w), ryTL = nvg__minf(radTopLeft, halfh) * nvg__signf(h);
|
||||
float vals[] = {
|
||||
NVG_MOVETO, x, y+ry,
|
||||
NVG_LINETO, x, y+h-ry,
|
||||
NVG_BEZIERTO, x, y+h-ry*(1-NVG_KAPPA90), x+rx*(1-NVG_KAPPA90), y+h, x+rx, y+h,
|
||||
NVG_LINETO, x+w-rx, y+h,
|
||||
NVG_BEZIERTO, x+w-rx*(1-NVG_KAPPA90), y+h, x+w, y+h-ry*(1-NVG_KAPPA90), x+w, y+h-ry,
|
||||
NVG_LINETO, x+w, y+ry,
|
||||
NVG_BEZIERTO, x+w, y+ry*(1-NVG_KAPPA90), x+w-rx*(1-NVG_KAPPA90), y, x+w-rx, y,
|
||||
NVG_LINETO, x+rx, y,
|
||||
NVG_BEZIERTO, x+rx*(1-NVG_KAPPA90), y, x, y+ry*(1-NVG_KAPPA90), x, y+ry,
|
||||
NVG_MOVETO, x, y + ryTL,
|
||||
NVG_LINETO, x, y + h - ryBL,
|
||||
NVG_BEZIERTO, x, y + h - ryBL*(1 - NVG_KAPPA90), x + rxBL*(1 - NVG_KAPPA90), y + h, x + rxBL, y + h,
|
||||
NVG_LINETO, x + w - rxBR, y + h,
|
||||
NVG_BEZIERTO, x + w - rxBR*(1 - NVG_KAPPA90), y + h, x + w, y + h - ryBR*(1 - NVG_KAPPA90), x + w, y + h - ryBR,
|
||||
NVG_LINETO, x + w, y + ryTR,
|
||||
NVG_BEZIERTO, x + w, y + ryTR*(1 - NVG_KAPPA90), x + w - rxTR*(1 - NVG_KAPPA90), y, x + w - rxTR, y,
|
||||
NVG_LINETO, x + rxTL, y,
|
||||
NVG_BEZIERTO, x + rxTL*(1 - NVG_KAPPA90), y, x, y + ryTL*(1 - NVG_KAPPA90), x, y + ryTL,
|
||||
NVG_CLOSE
|
||||
};
|
||||
nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
|
||||
|
|
@ -2173,6 +2281,18 @@ int nvgFindFont(NVGcontext* ctx, const char* name)
|
|||
return fonsGetFontByName(ctx->fs, name);
|
||||
}
|
||||
|
||||
|
||||
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont)
|
||||
{
|
||||
if(baseFont == -1 || fallbackFont == -1) return 0;
|
||||
return fonsAddFallbackFont(ctx->fs, baseFont, fallbackFont);
|
||||
}
|
||||
|
||||
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont)
|
||||
{
|
||||
return nvgAddFallbackFontId(ctx, nvgFindFont(ctx, baseFont), nvgFindFont(ctx, fallbackFont));
|
||||
}
|
||||
|
||||
// State setting
|
||||
void nvgFontSize(NVGcontext* ctx, float size)
|
||||
{
|
||||
|
|
@ -2434,6 +2554,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)
|
||||
|
|
@ -2501,7 +2622,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;
|
||||
}
|
||||
|
||||
|
|
@ -2528,7 +2657,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;
|
||||
|
|
@ -2548,26 +2677,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.
|
||||
|
|
|
|||
81
src/nanovg.h
81
src/nanovg.h
|
|
@ -79,10 +79,46 @@ enum NVGalign {
|
|||
// Vertical align
|
||||
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top.
|
||||
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle.
|
||||
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
|
||||
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
|
||||
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
|
||||
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
|
||||
};
|
||||
|
||||
enum NVGblendFactor {
|
||||
NVG_ZERO = 1<<0,
|
||||
NVG_ONE = 1<<1,
|
||||
NVG_SRC_COLOR = 1<<2,
|
||||
NVG_ONE_MINUS_SRC_COLOR = 1<<3,
|
||||
NVG_DST_COLOR = 1<<4,
|
||||
NVG_ONE_MINUS_DST_COLOR = 1<<5,
|
||||
NVG_SRC_ALPHA = 1<<6,
|
||||
NVG_ONE_MINUS_SRC_ALPHA = 1<<7,
|
||||
NVG_DST_ALPHA = 1<<8,
|
||||
NVG_ONE_MINUS_DST_ALPHA = 1<<9,
|
||||
NVG_SRC_ALPHA_SATURATE = 1<<10,
|
||||
};
|
||||
|
||||
enum NVGcompositeOperation {
|
||||
NVG_SOURCE_OVER,
|
||||
NVG_SOURCE_IN,
|
||||
NVG_SOURCE_OUT,
|
||||
NVG_ATOP,
|
||||
NVG_DESTINATION_OVER,
|
||||
NVG_DESTINATION_IN,
|
||||
NVG_DESTINATION_OUT,
|
||||
NVG_DESTINATION_ATOP,
|
||||
NVG_LIGHTER,
|
||||
NVG_COPY,
|
||||
NVG_XOR,
|
||||
};
|
||||
|
||||
struct NVGcompositeOperationState {
|
||||
int srcRGB;
|
||||
int dstRGB;
|
||||
int srcAlpha;
|
||||
int dstAlpha;
|
||||
};
|
||||
typedef struct NVGcompositeOperationState NVGcompositeOperationState;
|
||||
|
||||
struct NVGglyphPosition {
|
||||
const char* str; // Position of the glyph in the input string.
|
||||
float x; // The x-coordinate of the logical glyph position.
|
||||
|
|
@ -124,6 +160,22 @@ void nvgCancelFrame(NVGcontext* ctx);
|
|||
// Ends drawing flushing remaining render state.
|
||||
void nvgEndFrame(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Composite operation
|
||||
//
|
||||
// The composite operations in NanoVG are modeled after HTML Canvas API, and
|
||||
// the blend func is based on OpenGL (see corresponding manuals for more info).
|
||||
// The colors in the blending state have premultiplied alpha.
|
||||
|
||||
// Sets the composite operation. The op parameter should be one of NVGcompositeOperation.
|
||||
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op);
|
||||
|
||||
// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor.
|
||||
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor);
|
||||
|
||||
// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor.
|
||||
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
|
||||
|
||||
//
|
||||
// Color utils
|
||||
//
|
||||
|
|
@ -184,7 +236,7 @@ void nvgReset(NVGcontext* ctx);
|
|||
// Solid color is simply defined as a color value, different kinds of paints can be created
|
||||
// using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern().
|
||||
//
|
||||
// Current render style can be saved and restored using nvgSave() and nvgRestore().
|
||||
// Current render style can be saved and restored using nvgSave() and nvgRestore().
|
||||
|
||||
// Sets current stroke style to a solid color.
|
||||
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color);
|
||||
|
|
@ -232,7 +284,7 @@ void nvgGlobalAlpha(NVGcontext* ctx, float alpha);
|
|||
// Apart from nvgResetTransform(), each transformation function first creates
|
||||
// specific transformation matrix and pre-multiplies the current transformation by it.
|
||||
//
|
||||
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().
|
||||
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().
|
||||
|
||||
// Resets current transform to a identity matrix.
|
||||
void nvgResetTransform(NVGcontext* ctx);
|
||||
|
|
@ -369,7 +421,7 @@ NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey
|
|||
// Scissoring
|
||||
//
|
||||
// Scissoring allows you to clip the rendering into a rectangle. This is useful for various
|
||||
// user interface cases like rendering a text edit or a timeline.
|
||||
// user interface cases like rendering a text edit or a timeline.
|
||||
|
||||
// Sets the current scissor rectangle.
|
||||
// The scissor rectangle is transformed by the current transform.
|
||||
|
|
@ -424,7 +476,7 @@ void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float rad
|
|||
// Closes current sub-path with a line segment.
|
||||
void nvgClosePath(NVGcontext* ctx);
|
||||
|
||||
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
|
||||
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
|
||||
void nvgPathWinding(NVGcontext* ctx, int dir);
|
||||
|
||||
// Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r,
|
||||
|
|
@ -438,10 +490,13 @@ void nvgRect(NVGcontext* ctx, float x, float y, float w, float h);
|
|||
// Creates new rounded rectangle shaped sub-path.
|
||||
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r);
|
||||
|
||||
// Creates new rounded rectangle shaped sub-path with varying radii for each corner.
|
||||
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);
|
||||
|
||||
// Creates new ellipse shaped sub-path.
|
||||
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry);
|
||||
|
||||
// Creates new circle shaped sub-path.
|
||||
// Creates new circle shaped sub-path.
|
||||
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r);
|
||||
|
||||
// Fills the current path with current fill style.
|
||||
|
|
@ -495,6 +550,12 @@ int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int
|
|||
// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found.
|
||||
int nvgFindFont(NVGcontext* ctx, const char* name);
|
||||
|
||||
// Adds a fallback font by handle.
|
||||
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont);
|
||||
|
||||
// Adds a fallback font by name.
|
||||
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont);
|
||||
|
||||
// Sets the font size of current text style.
|
||||
void nvgFontSize(NVGcontext* ctx, float size);
|
||||
|
||||
|
|
@ -504,7 +565,7 @@ void nvgFontBlur(NVGcontext* ctx, float blur);
|
|||
// Sets the letter spacing of current text style.
|
||||
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing);
|
||||
|
||||
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
|
||||
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
|
||||
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight);
|
||||
|
||||
// Sets the text align of current text style, see NVGalign for options.
|
||||
|
|
@ -589,9 +650,9 @@ struct NVGparams {
|
|||
int (*renderDeleteTexture)(void* uptr, int image);
|
||||
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data);
|
||||
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);
|
||||
void (*renderViewport)(void* uptr, int width, int height);
|
||||
void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio);
|
||||
void (*renderCancel)(void* uptr);
|
||||
void (*renderFlush)(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);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ NVGcontext* nvgCreateGL2(int flags);
|
|||
void nvgDeleteGL2(NVGcontext* ctx);
|
||||
|
||||
int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
|
||||
GLuint nvglImageFromHandleGL2(NVGcontext* ctx, int image);
|
||||
GLuint nvglImageHandleGL2(NVGcontext* ctx, int image);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -306,7 +306,7 @@ static void glnvg__stencilFunc(GLNVGcontext* gl, GLenum func, GLint ref, GLuint
|
|||
if ((gl->stencilFunc != func) ||
|
||||
(gl->stencilFuncRef != ref) ||
|
||||
(gl->stencilFuncMask != mask)) {
|
||||
|
||||
|
||||
gl->stencilFunc = func;
|
||||
gl->stencilFuncRef = ref;
|
||||
gl->stencilFuncMask = mask;
|
||||
|
|
@ -339,10 +339,10 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl)
|
|||
}
|
||||
tex = &gl->textures[gl->ntextures++];
|
||||
}
|
||||
|
||||
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
tex->id = ++gl->textureId;
|
||||
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
|
|
@ -522,7 +522,7 @@ static int glnvg__renderCreate(void* uptr)
|
|||
" gl_Position = vec4(2.0*vertex.x/viewSize.x - 1.0, 1.0 - 2.0*vertex.y/viewSize.y, 0, 1);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* fillFragShader =
|
||||
static const char* fillFragShader =
|
||||
"#ifdef GL_ES\n"
|
||||
"#if defined(GL_FRAGMENT_PRECISION_HIGH) || defined(NANOVG_GL3)\n"
|
||||
" precision highp float;\n"
|
||||
|
|
@ -671,7 +671,7 @@ static int glnvg__renderCreate(void* uptr)
|
|||
#if NANOVG_GL_USE_UNIFORMBUFFER
|
||||
// Create UBOs
|
||||
glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_FRAG], GLNVG_FRAG_BINDING);
|
||||
glGenBuffers(1, &gl->fragBuf);
|
||||
glGenBuffers(1, &gl->fragBuf);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align);
|
||||
#endif
|
||||
gl->fragSize = sizeof(GLNVGfragUniforms) + align - sizeof(GLNVGfragUniforms) % align;
|
||||
|
|
@ -698,7 +698,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
|
|||
printf("Repeat X/Y is not supported for non power-of-two textures (%d x %d)\n", w, h);
|
||||
imageFlags &= ~(NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
|
||||
}
|
||||
// No mips.
|
||||
// No mips.
|
||||
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
|
||||
printf("Mip-maps is not support for non power-of-two textures (%d x %d)\n", w, h);
|
||||
imageFlags &= ~NVG_IMAGE_GENERATE_MIPMAPS;
|
||||
|
|
@ -908,10 +908,14 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai
|
|||
tex = glnvg__findTexture(gl, paint->image);
|
||||
if (tex == NULL) return 0;
|
||||
if ((tex->flags & NVG_IMAGE_FLIPY) != 0) {
|
||||
float flipped[6];
|
||||
nvgTransformScale(flipped, 1.0f, -1.0f);
|
||||
nvgTransformMultiply(flipped, paint->xform);
|
||||
nvgTransformInverse(invxform, flipped);
|
||||
float m1[6], m2[6];
|
||||
nvgTransformTranslate(m1, 0.0f, frag->extent[1] * 0.5f);
|
||||
nvgTransformMultiply(m1, paint->xform);
|
||||
nvgTransformScale(m2, 1.0f, -1.0f);
|
||||
nvgTransformMultiply(m2, m1);
|
||||
nvgTransformTranslate(m1, 0.0f, -frag->extent[1] * 0.5f);
|
||||
nvgTransformMultiply(m1, m2);
|
||||
nvgTransformInverse(invxform, m1);
|
||||
} else {
|
||||
nvgTransformInverse(invxform, paint->xform);
|
||||
}
|
||||
|
|
@ -954,7 +958,7 @@ static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image)
|
|||
}
|
||||
}
|
||||
|
||||
static void glnvg__renderViewport(void* uptr, int width, int height)
|
||||
static void glnvg__renderViewport(void* uptr, int width, int height, float devicePixelRatio)
|
||||
{
|
||||
GLNVGcontext* gl = (GLNVGcontext*)uptr;
|
||||
gl->view[0] = (float)width;
|
||||
|
|
@ -1047,7 +1051,7 @@ static void glnvg__stroke(GLNVGcontext* gl, GLNVGcall* call)
|
|||
for (i = 0; i < npaths; i++)
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount);
|
||||
|
||||
// Clear stencil buffer.
|
||||
// Clear stencil buffer.
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
glnvg__stencilFunc(gl, GL_ALWAYS, 0x0, 0xff);
|
||||
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
|
||||
|
|
@ -1085,7 +1089,46 @@ static void glnvg__renderCancel(void* uptr) {
|
|||
gl->nuniforms = 0;
|
||||
}
|
||||
|
||||
static void glnvg__renderFlush(void* uptr)
|
||||
static GLenum glnvg_convertBlendFuncFactor(int factor)
|
||||
{
|
||||
if (factor == NVG_ZERO)
|
||||
return GL_ZERO;
|
||||
if (factor == NVG_ONE)
|
||||
return GL_ONE;
|
||||
if (factor == NVG_SRC_COLOR)
|
||||
return GL_SRC_COLOR;
|
||||
if (factor == NVG_ONE_MINUS_SRC_COLOR)
|
||||
return GL_ONE_MINUS_SRC_COLOR;
|
||||
if (factor == NVG_DST_COLOR)
|
||||
return GL_DST_COLOR;
|
||||
if (factor == NVG_ONE_MINUS_DST_COLOR)
|
||||
return GL_ONE_MINUS_DST_COLOR;
|
||||
if (factor == NVG_SRC_ALPHA)
|
||||
return GL_SRC_ALPHA;
|
||||
if (factor == NVG_ONE_MINUS_SRC_ALPHA)
|
||||
return GL_ONE_MINUS_SRC_ALPHA;
|
||||
if (factor == NVG_DST_ALPHA)
|
||||
return GL_DST_ALPHA;
|
||||
if (factor == NVG_ONE_MINUS_DST_ALPHA)
|
||||
return GL_ONE_MINUS_DST_ALPHA;
|
||||
if (factor == NVG_SRC_ALPHA_SATURATE)
|
||||
return GL_SRC_ALPHA_SATURATE;
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
static void glnvg__blendCompositeOperation(NVGcompositeOperationState op)
|
||||
{
|
||||
GLenum srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB);
|
||||
GLenum dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB);
|
||||
GLenum srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha);
|
||||
GLenum dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha);
|
||||
if (srcRGB == GL_INVALID_ENUM || dstRGB == GL_INVALID_ENUM || srcAlpha == GL_INVALID_ENUM || dstAlpha == GL_INVALID_ENUM)
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
static void glnvg__renderFlush(void* uptr, NVGcompositeOperationState compositeOperation)
|
||||
{
|
||||
GLNVGcontext* gl = (GLNVGcontext*)uptr;
|
||||
int i;
|
||||
|
|
@ -1095,7 +1138,7 @@ static void glnvg__renderFlush(void* uptr)
|
|||
// Setup require GL state.
|
||||
glUseProgram(gl->shader.prog);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glnvg__blendCompositeOperation(compositeOperation);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CCW);
|
||||
|
|
@ -1157,7 +1200,7 @@ static void glnvg__renderFlush(void* uptr)
|
|||
glDisableVertexAttribArray(1);
|
||||
#if defined NANOVG_GL3
|
||||
glBindVertexArray(0);
|
||||
#endif
|
||||
#endif
|
||||
glDisable(GL_CULL_FACE);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glUseProgram(0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue