Browse Source

Moved image repeat (tiling) from pattern to image creation

- API changed!
- moved image repeat from nvgImagePattern() into image creation
nvgCreateImage*()
- made flip-y and premultiplied common image flags (not just GL)
- removed nvglImageFlags(), flags passed in via
nvglCreateImageFromHandle() flags
- nvgluCreateFramebuffer takes image flags as param
shared-context
Mikko Mononen 10 years ago
parent
commit
994b60b83f
6 changed files with 82 additions and 57 deletions
  1. +1
    -1
      example/demo.c
  2. +3
    -2
      example/example_fbo.c
  3. +1
    -2
      src/nanovg.c
  4. +9
    -12
      src/nanovg.h
  5. +64
    -36
      src/nanovg_gl.h
  6. +4
    -4
      src/nanovg_gl_utils.h

+ 1
- 1
example/demo.c View File

@@ -589,7 +589,7 @@ void drawThumbnails(NVGcontext* vg, float x, float y, float w, float h, const in
if (a < 1.0f)
drawSpinner(vg, tx+thumb/2,ty+thumb/2, thumb*0.25f, t);

imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], NVG_NOREPEAT, a);
imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], a);
nvgBeginPath(vg);
nvgRoundedRect(vg, tx,ty, thumb,thumb, 5);
nvgFillPaint(vg, imgPaint);


+ 3
- 2
example/example_fbo.c View File

@@ -168,7 +168,8 @@ int main()
// Calculate pixel ration for hi-dpi devices.
pxRatio = (float)fbWidth / (float)winWidth;

fb = nvgluCreateFramebuffer(vg, (int)(100*pxRatio), (int)(100*pxRatio));
// The image pattern is tiled, set repeat on x and y.
fb = nvgluCreateFramebuffer(vg, (int)(100*pxRatio), (int)(100*pxRatio), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (fb == NULL) {
printf("Could not create FBO.\n");
return -1;
@@ -215,7 +216,7 @@ int main()

// Use the FBO as image pattern.
if (fb != NULL) {
NVGpaint img = nvgImagePattern(vg, 0, 0, 100, 100, 0, fb->image, NVG_REPEATX|NVG_REPEATY, 1.0f);
NVGpaint img = nvgImagePattern(vg, 0, 0, 100, 100, 0, fb->image, 1.0f);
nvgSave(vg);

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


+ 1
- 2
src/nanovg.c View File

@@ -843,7 +843,7 @@ NVGpaint nvgBoxGradient(NVGcontext* ctx,

NVGpaint nvgImagePattern(NVGcontext* ctx,
float cx, float cy, float w, float h, float angle,
int image, int repeat, float alpha)
int image, float alpha)
{
NVGpaint p;
NVG_NOTUSED(ctx);
@@ -857,7 +857,6 @@ NVGpaint nvgImagePattern(NVGcontext* ctx,
p.extent[1] = h;

p.image = image;
p.repeat = repeat;

p.innerColor = p.outerColor = nvgRGBAf(1,1,1,alpha);



+ 9
- 12
src/nanovg.h View File

@@ -50,7 +50,6 @@ struct NVGpaint {
NVGcolor innerColor;
NVGcolor outerColor;
int image;
int repeat;
};
typedef struct NVGpaint NVGpaint;

@@ -72,12 +71,6 @@ enum NVGlineCap {
NVG_MITER,
};

enum NVGpatternRepeat {
NVG_NOREPEAT = 0,
NVG_REPEATX = 0x01, // Repeat image pattern in X direction
NVG_REPEATY = 0x02, // Repeat image pattern in Y direction
};

enum NVGalign {
// Horizontal align
NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left.
@@ -106,8 +99,12 @@ struct NVGtextRow {
};
typedef struct NVGtextRow NVGtextRow;

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

// Begin drawing a new frame
@@ -309,6 +306,7 @@ float nvgRadToDeg(float rad);
//
// NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering.
// In addition you can upload your own image. The image loading is provided by stb_image.
// The parameter imageFlags is combination of flags defined in NVGimageFlags.

// Creates image by loading it from the disk from specified file name.
// Returns handle to the image.
@@ -358,11 +356,10 @@ NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float
NVGcolor icol, NVGcolor ocol);

// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern,
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render,
// and repeat is combination of NVG_REPEATX and NVG_REPEATY which tells if the image should be repeated across x or y.
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render.
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,
float angle, int image, int repeat, float alpha);
float angle, int image, float alpha);

//
// Scissoring


+ 64
- 36
src/nanovg_gl.h View File

@@ -81,15 +81,13 @@ void nvgDeleteGLES3(NVGcontext* ctx);

#endif

enum NVGLtextureflags {
NVGL_TEXTURE_FLIP_Y = 0x01,
NVGL_TEXTURE_NODELETE = 0x02,
NVGL_TEXTURE_PREMULTIPLIED = 0x04
// These are additional flags on top of NVGimageFlags.
enum NVGimageFlagsGL {
NVG_IMAGE_NODELETE = 1<<16, // Do not delete GL texture handle.
};

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


#ifdef __cplusplus
@@ -238,6 +236,20 @@ typedef struct GLNVGcontext GLNVGcontext;

static int glnvg__maxi(int a, int b) { return a > b ? a : b; }

#ifdef NANOVG_GLES2
static unsigned int glnvg__nearestPow2(unsigned int num)
{
unsigned n = num > 0 ? num - 1 : 0;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
#endif

static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl)
{
GLNVGtexture* tex = NULL;
@@ -281,7 +293,7 @@ static int glnvg__deleteTexture(GLNVGcontext* gl, int id)
int i;
for (i = 0; i < gl->ntextures; i++) {
if (gl->textures[i].id == id) {
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVGL_TEXTURE_NODELETE) == 0)
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVG_IMAGE_NODELETE) == 0)
glDeleteTextures(1, &gl->textures[i].tex);
memset(&gl->textures[i], 0, sizeof(gl->textures[i]));
return 1;
@@ -628,10 +640,27 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im

if (tex == NULL) return 0;

#ifdef NANOVG_GLES2
// Check for non-power of 2.
if (glnvg__nearestPow2(w) != (unsigned int)w || glnvg__nearestPow2(h) == (unsigned int)h) {
// No repeat
if ((imageFlags & NVG_IMAGE_REPEATX) != 0 || (imageFlags & NVG_IMAGE_REPEATY) != 0) {
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.
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;
}
}
#endif

glGenTextures(1, &tex->tex);
tex->width = w;
tex->height = h;
tex->type = type;
tex->flags = imageFlags;
glBindTexture(GL_TEXTURE_2D, tex->tex);

glPixelStorei(GL_UNPACK_ALIGNMENT,1);
@@ -642,10 +671,10 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
#endif

#if defined (NANOVG_GL2)
// GL 1.4 and later has support for generating mipmaps using a tex parameter.
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
}
// GL 1.4 and later has support for generating mipmaps using a tex parameter.
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
}
#endif

if (type == NVG_TEXTURE_RGBA)
@@ -660,15 +689,21 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
#endif

if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

if (imageFlags & NVG_IMAGE_REPEATX)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

if (imageFlags & NVG_IMAGE_REPEATY)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
#ifndef NANOVG_GLES2
@@ -677,11 +712,11 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif

// The new way to build mipmaps on GLES and GL3
// The new way to build mipmaps on GLES and GL3
#if !defined(NANOVG_GL2)
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
glGenerateMipmap(GL_TEXTURE_2D);
}
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {
glGenerateMipmap(GL_TEXTURE_2D);
}
#endif

glnvg__checkError(gl, "create tex");
@@ -810,7 +845,7 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai
if (paint->image != 0) {
tex = glnvg__findTexture(gl, paint->image);
if (tex == NULL) return 0;
if ((tex->flags & NVGL_TEXTURE_FLIP_Y) != 0) {
if ((tex->flags & NVG_IMAGE_FLIPY) != 0) {
float flipped[6];
nvgTransformScale(flipped, 1.0f, -1.0f);
nvgTransformMultiply(flipped, paint->xform);
@@ -821,7 +856,7 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai
frag->type = NSVG_SHADER_FILLIMG;

if (tex->type == NVG_TEXTURE_RGBA)
frag->texType = (tex->flags & NVGL_TEXTURE_PREMULTIPLIED) ? 0 : 1;
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1;
else
frag->texType = 2;
// printf("frag->texType = %d\n", frag->texType);
@@ -1078,7 +1113,7 @@ static void glnvg__renderFlush(void* uptr)
glBindVertexArray(0);
#endif
glDisable(GL_CULL_FACE);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
@@ -1367,7 +1402,7 @@ static void glnvg__renderDelete(void* uptr)
glDeleteBuffers(1, &gl->vertBuf);

for (i = 0; i < gl->ntextures; i++) {
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVGL_TEXTURE_NODELETE) == 0)
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVG_IMAGE_NODELETE) == 0)
glDeleteTextures(1, &gl->textures[i].tex);
}
free(gl->textures);
@@ -1438,7 +1473,7 @@ void nvgDeleteGLES3(NVGcontext* ctx)
nvgDeleteInternal(ctx);
}

int nvglCreateImageFromHandle(NVGcontext* ctx, GLuint textureId, int w, int h, int flags)
int nvglCreateImageFromHandle(NVGcontext* ctx, GLuint textureId, int w, int h, int imageFlags)
{
GLNVGcontext* gl = (GLNVGcontext*)nvgInternalParams(ctx)->userPtr;
GLNVGtexture* tex = glnvg__allocTexture(gl);
@@ -1447,7 +1482,7 @@ int nvglCreateImageFromHandle(NVGcontext* ctx, GLuint textureId, int w, int h, i

tex->type = NVG_TEXTURE_RGBA;
tex->tex = textureId;
tex->flags = flags;
tex->flags = imageFlags;
tex->width = w;
tex->height = h;

@@ -1461,11 +1496,4 @@ GLuint nvglImageHandle(NVGcontext* ctx, int image)
return tex->tex;
}

void nvglImageFlags(NVGcontext* ctx, int image, int flags)
{
GLNVGcontext* gl = (GLNVGcontext*)nvgInternalParams(ctx)->userPtr;
GLNVGtexture* tex = glnvg__findTexture(gl, image);
tex->flags = flags;
}

#endif /* NANOVG_GL_IMPLEMENTATION */

+ 4
- 4
src/nanovg_gl_utils.h View File

@@ -28,7 +28,7 @@ struct NVGLUframebuffer {
typedef struct NVGLUframebuffer NVGLUframebuffer;

// Helper function to create GL frame buffer to render to.
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h);
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags);
void nvgluDeleteFramebuffer(NVGcontext* ctx, NVGLUframebuffer* fb);

#endif // NANOVG_GL_UTILS_H
@@ -46,7 +46,7 @@ void nvgluDeleteFramebuffer(NVGcontext* ctx, NVGLUframebuffer* fb);
# endif
#endif

NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h)
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags)
{
#ifdef NANOVG_FBO_VALID
NVGLUframebuffer* fb = NULL;
@@ -54,9 +54,8 @@ NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h)
if (fb == NULL) goto error;
memset(fb, 0, sizeof(NVGLUframebuffer));

fb->image = nvgCreateImageRGBA(ctx, w, h, 0, NULL);
fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL);
fb->texture = nvglImageHandle(ctx, fb->image);
nvglImageFlags(ctx, fb->image, NVGL_TEXTURE_FLIP_Y | NVGL_TEXTURE_PREMULTIPLIED);

// frame buffer object
glGenFramebuffers(1, &fb->fbo);
@@ -81,6 +80,7 @@ error:
NVG_NOTUSED(ctx);
NVG_NOTUSED(w);
NVG_NOTUSED(h);
NVG_NOTUSED(imageFlags);
return NULL;
#endif
}


Loading…
Cancel
Save