Browse Source

Added retina/hi-dpi support

- fixed off-by-one pixels from demo
- added device-pixel-ratio support (retina support)
- added nvgEndFrame()
shared-context
Mikko Mononen 11 years ago
parent
commit
d41083886a
9 changed files with 117 additions and 44 deletions
  1. +4
    -4
      example/demo.c
  2. +13
    -7
      example/example_gl2.c
  3. +13
    -5
      example/example_gl3.c
  4. +13
    -5
      example/example_gles2.c
  5. +13
    -5
      example/example_gles3.c
  6. +34
    -15
      src/nanovg.c
  7. +13
    -3
      src/nanovg.h
  8. +7
    -0
      src/nanovg_gl2.h
  9. +7
    -0
      src/nanovg_gl3.h

+ 4
- 4
example/demo.c View File

@@ -623,8 +623,8 @@ void drawColorwheel(struct NVGcontext* vg, float x, float y, float w, float h, f
}

nvgBeginPath(vg);
nvgCircle(vg, cx,cy, r0-1);
nvgCircle(vg, cx,cy, r1+1);
nvgCircle(vg, cx,cy, r0-0.5f);
nvgCircle(vg, cx,cy, r1+0.5f);
nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
nvgStrokeWidth(vg, 1.0f);
nvgStroke(vg);
@@ -643,8 +643,8 @@ void drawColorwheel(struct NVGcontext* vg, float x, float y, float w, float h, f

paint = nvgBoxGradient(vg, r0-3,-5,r1-r0+6,10, 2,4, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
nvgBeginPath(vg);
nvgRect(vg, r0-3-10,-5-10,r1-r0+6+20,10+20);
nvgRect(vg, r0-3,-5,r1-r0+6,10);
nvgRect(vg, r0-2-10,-4-10,r1-r0+4+20,8+20);
nvgRect(vg, r0-2,-4,r1-r0+4,8);
nvgPathWinding(vg, NVG_HOLE);
nvgFillPaint(vg, paint);
nvgFill(vg);


+ 13
- 7
example/example_gl2.c View File

@@ -103,7 +103,9 @@ int main()
while (!glfwWindowShouldClose(window))
{
double mx, my, t, dt;
int width, height;
int winWidth, winHeight;
int fbWidth, fbHeight;
float pxRatio;

t = glfwGetTime();
dt = t - prevt;
@@ -111,25 +113,29 @@ int main()
updateFPS(&fps, dt);

glfwGetCursorPos(window, &mx, &my);
glfwGetFramebufferSize(window, &width, &height);
glfwGetWindowSize(window, &winWidth, &winHeight);
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);

// Calculate pixel ration for hi-dpi devices.
pxRatio = (float)fbWidth / (float)winWidth;

// Update and render
glViewport(0, 0, width, height);
glViewport(0, 0, fbWidth, fbHeight);
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glColor4ub(255,255,255,255);

nvgBeginFrame(vg, width, height);
nvgBeginFrame(vg, winWidth, winHeight, pxRatio);

renderDemo(vg, mx,my, width,height, t, blowup, &data);
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data);
renderFPS(vg, 5,5, &fps);

nvgEndFrame(vg);

glEnable(GL_DEPTH_TEST);

glfwSwapBuffers(window);


+ 13
- 5
example/example_gl3.c View File

@@ -108,7 +108,9 @@ int main()
while (!glfwWindowShouldClose(window))
{
double mx, my, t, dt;
int width, height;
int winWidth, winHeight;
int fbWidth, fbHeight;
float pxRatio;

t = glfwGetTime();
dt = t - prevt;
@@ -116,22 +118,28 @@ int main()
updateFPS(&fps, dt);

glfwGetCursorPos(window, &mx, &my);
glfwGetFramebufferSize(window, &width, &height);
glfwGetWindowSize(window, &winWidth, &winHeight);
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
// Calculate pixel ration for hi-dpi devices.
pxRatio = (float)fbWidth / (float)winWidth;

// Update and render
glViewport(0, 0, width, height);
glViewport(0, 0, fbWidth, fbHeight);
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);

nvgBeginFrame(vg, width, height);
nvgBeginFrame(vg, winWidth, winHeight, pxRatio);

renderDemo(vg, mx,my, width,height, t, blowup, &data);
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data);
renderFPS(vg, 5,5, &fps);

nvgEndFrame(vg);

glEnable(GL_DEPTH_TEST);

glfwSwapBuffers(window);


+ 13
- 5
example/example_gles2.c View File

@@ -90,7 +90,9 @@ int main()
while (!glfwWindowShouldClose(window))
{
double mx, my, t, dt;
int width, height;
int winWidth, winHeight;
int fbWidth, fbHeight;
float pxRatio;

t = glfwGetTime();
dt = t - prevt;
@@ -98,22 +100,28 @@ int main()
updateFPS(&fps, dt);

glfwGetCursorPos(window, &mx, &my);
glfwGetFramebufferSize(window, &width, &height);
glfwGetWindowSize(window, &winWidth, &winHeight);
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
// Calculate pixel ration for hi-dpi devices.
pxRatio = (float)fbWidth / (float)winWidth;

// Update and render
glViewport(0, 0, width, height);
glViewport(0, 0, fbWidth, fbHeight);
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);

nvgBeginFrame(vg, width, height);
nvgBeginFrame(vg, winWidth, winHeight, pxRatio);

renderDemo(vg, mx,my, width,height, t, blowup, &data);
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data);
renderFPS(vg, 5,5, &fps);

nvgEndFrame(vg);

glEnable(GL_DEPTH_TEST);

glfwSwapBuffers(window);


+ 13
- 5
example/example_gles3.c View File

@@ -90,7 +90,9 @@ int main()
while (!glfwWindowShouldClose(window))
{
double mx, my, t, dt;
int width, height;
int winWidth, winHeight;
int fbWidth, fbHeight;
float pxRatio;

t = glfwGetTime();
dt = t - prevt;
@@ -98,22 +100,28 @@ int main()
updateFPS(&fps, dt);

glfwGetCursorPos(window, &mx, &my);
glfwGetFramebufferSize(window, &width, &height);
glfwGetWindowSize(window, &winWidth, &winHeight);
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
// Calculate pixel ration for hi-dpi devices.
pxRatio = (float)fbWidth / (float)winWidth;

// Update and render
glViewport(0, 0, width, height);
glViewport(0, 0, fbWidth, fbHeight);
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);

nvgBeginFrame(vg, width, height);
nvgBeginFrame(vg, winWidth, winHeight, pxRatio);

renderDemo(vg, mx,my, width,height, t, blowup, &data);
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data);
renderFPS(vg, 5,5, &fps);

nvgEndFrame(vg);

glEnable(GL_DEPTH_TEST);

glfwSwapBuffers(window);


+ 34
- 15
src/nanovg.c View File

@@ -28,7 +28,6 @@
#define NVG_INIT_PATH_SIZE 256
#define NVG_MAX_STATES 32

#define NVG_AA 1.0f
#define NVG_KAPPA90 0.5522847493f // Lenght proportional to radius of a cubic bezier handle for 90deg arcs.

#define NVG_COUNTOF(arr) (sizeof(arr) / sizeof(0[arr]))
@@ -101,6 +100,8 @@ struct NVGcontext {
struct NVGpathCache* cache;
float tessTol;
float distTol;
float fringeWidth;
float devicePxRatio;
struct FONScontext* fs;
int fontImage;
int drawCallCount;
@@ -173,6 +174,13 @@ error:
return NULL;
}

static void nvg__setDevicePixelRatio(struct NVGcontext* ctx, float ratio)
{
ctx->tessTol = 0.3f * 4.0f / ratio;
ctx->distTol = 0.01f / ratio;
ctx->fringeWidth = 1.0f / ratio;
ctx->devicePxRatio = ratio;
}

struct NVGcontext* nvgCreateInternal(struct NVGparams* params)
{
@@ -194,8 +202,7 @@ struct NVGcontext* nvgCreateInternal(struct NVGparams* params)
nvgSave(ctx);
nvgReset(ctx);

ctx->tessTol = 0.3f * 4.0f;
ctx->distTol = 0.01f;
nvg__setDevicePixelRatio(ctx, 1.0f);

if (ctx->params.renderCreate(ctx->params.userPtr) == 0) goto error;

@@ -238,13 +245,19 @@ void nvgDeleteInternal(struct NVGcontext* ctx)
free(ctx);
}

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

ctx->nstates = 0;
nvgSave(ctx);
nvgReset(ctx);

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

ctx->drawCallCount = 0;
ctx->fillTriCount = 0;
@@ -252,6 +265,11 @@ void nvgBeginFrame(struct NVGcontext* ctx, int width, int height)
ctx->textTriCount = 0;
}

void nvgEndFrame(struct NVGcontext* ctx)
{
ctx->params.renderFlush(ctx->params.userPtr);
}

unsigned int nvgRGB(unsigned char r, unsigned char g, unsigned char b)
{
return nvgRGBA(r,g,b,255);
@@ -1084,6 +1102,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
int convex = 0;
int i, j, s, e;
float wo = 0;
float aa = ctx->fringeWidth;

// Calculate max vertex usage.
cverts = 0;
@@ -1110,7 +1129,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)

// Calculate shape vertices.
if (feats & NVG_FILL) {
wo = 0.5f;
wo = 0.5f*aa;
dst = verts;
path->fill = dst;

@@ -1196,8 +1215,8 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
nvg__normalize(&dx, &dy);
dlx = dy;
dly = -dx;
nvg__vset(dst, p0->x + dlx*rw - dx*NVG_AA, p0->y + dly*rw - dy*NVG_AA, u0,0); dst++;
nvg__vset(dst, p0->x - dlx*lw - dx*NVG_AA, p0->y - dly*lw - dy*NVG_AA, u1,0); dst++;
nvg__vset(dst, p0->x + dlx*rw - dx*aa, p0->y + dly*rw - dy*aa, u0,0); dst++;
nvg__vset(dst, p0->x - dlx*lw - dx*aa, p0->y - dly*lw - dy*aa, u1,0); dst++;
nvg__vset(dst, p0->x + dlx*rw, p0->y + dly * rw, u0,1); dst++;
nvg__vset(dst, p0->x - dlx*lw, p0->y - dly * lw, u1,1); dst++;
}
@@ -1252,8 +1271,8 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
dly = -dx;
nvg__vset(dst, p1->x + dlx*rw, p1->y + dly * rw, u0,1); dst++;
nvg__vset(dst, p1->x - dlx*lw, p1->y - dly * lw, u1,1); dst++;
nvg__vset(dst, p1->x + dlx*rw + dx*NVG_AA, p1->y + dly*rw + dy*NVG_AA, u0,0); dst++;
nvg__vset(dst, p1->x - dlx*lw + dx*NVG_AA, p1->y - dly*lw + dy*NVG_AA, u1,0); dst++;
nvg__vset(dst, p1->x + dlx*rw + dx*aa, p1->y + dly*rw + dy*aa, u0,0); dst++;
nvg__vset(dst, p1->x - dlx*lw + dx*aa, p1->y - dly*lw + dy*aa, u1,0); dst++;
}

path->nstroke = (int)(dst - verts);
@@ -1488,11 +1507,11 @@ void nvgFill(struct NVGcontext* ctx)

nvg__flattenPaths(ctx, state->miterLimit);
if (ctx->params.edgeAntiAlias)
nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, NVG_AA);
nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, ctx->fringeWidth);
else
nvg__expandStrokeAndFill(ctx, NVG_FILL, 0.0f);

ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, NVG_AA,
ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, 1.0f,
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths);

// Count triangles
@@ -1514,11 +1533,11 @@ void nvgStroke(struct NVGcontext* ctx)

nvg__flattenPaths(ctx, state->miterLimit);
if (ctx->params.edgeAntiAlias)
nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + NVG_AA/2.0f);
nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + ctx->fringeWidth/2.0f);
else
nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f);

ctx->params.renderStroke(ctx->params.userPtr, &state->stroke, &state->scissor, NVG_AA,
ctx->params.renderStroke(ctx->params.userPtr, &state->stroke, &state->scissor, 1.0f,
strokeWidth, ctx->cache->paths, ctx->cache->npaths);

// Count triangles
@@ -1599,7 +1618,7 @@ float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, cons
struct FONStextIter iter;
struct FONSquad q;
struct NVGvertex* verts;
float scale = nvg__getFontScale(state);
float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
float invscale = 1.0f / scale;
int dirty[4];
int cverts = 0;


+ 13
- 3
src/nanovg.h View File

@@ -66,9 +66,18 @@ enum NVGaling {
};


// Called at the beginning of a frame.
//
void nvgBeginFrame(struct NVGcontext* ctx, int width, int height);
// Begin drawing a new frame
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame()
// nvgBeginFrame() defines the size of the window to render to in relation currently
// set viewport (i.e. glViewport on GL backends). Device pixel ration allows to
// control the rendering on Hi-DPI devices.
// 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(struct NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio);

// Ends drawing flushing remaining render state.
void nvgEndFrame(struct NVGcontext* ctx);

//
// Color utils
@@ -405,6 +414,7 @@ struct NVGparams {
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 (*renderFlush)(void* uptr);
void (*renderFill)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, const float* bounds, const struct NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, float strokeWidth, const struct NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, int image, const struct NVGvertex* verts, int nverts);


+ 7
- 0
src/nanovg_gl2.h View File

@@ -609,6 +609,12 @@ static void glnvg__renderViewport(void* uptr, int width, int height)
gl->viewHeight = height;
}

static void glnvg__renderFlush(void* uptr)
{
// struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
// empty
}

static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths)
{
int i, count = 0;
@@ -883,6 +889,7 @@ struct NVGcontext* nvgCreateGL2(int atlasw, int atlash, int edgeaa)
params.renderUpdateTexture = glnvg__renderUpdateTexture;
params.renderGetTextureSize = glnvg__renderGetTextureSize;
params.renderViewport = glnvg__renderViewport;
params.renderFlush = glnvg__renderFlush;
params.renderFill = glnvg__renderFill;
params.renderStroke = glnvg__renderStroke;
params.renderTriangles = glnvg__renderTriangles;


+ 7
- 0
src/nanovg_gl3.h View File

@@ -611,6 +611,12 @@ static void glnvg__renderViewport(void* uptr, int width, int height)
gl->viewHeight = height;
}

static void glnvg__renderFlush(void* uptr)
{
// struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
// empty
}

static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths)
{
int i, count = 0;
@@ -889,6 +895,7 @@ struct NVGcontext* nvgCreateGL3(int atlasw, int atlash, int edgeaa)
params.renderUpdateTexture = glnvg__renderUpdateTexture;
params.renderGetTextureSize = glnvg__renderGetTextureSize;
params.renderViewport = glnvg__renderViewport;
params.renderFlush = glnvg__renderFlush;
params.renderFill = glnvg__renderFill;
params.renderStroke = glnvg__renderStroke;
params.renderTriangles = glnvg__renderTriangles;


Loading…
Cancel
Save