add external APIs to GL backend to get native Texture Id.shared-context
@@ -24,6 +24,7 @@ | |||
#include "nanovg.h" | |||
#define NANOVG_GL2_IMPLEMENTATION | |||
#include "nanovg_gl.h" | |||
#include "nanovg_gl_utils.h" | |||
#include "demo.h" | |||
#include "perf.h" | |||
@@ -56,8 +57,10 @@ int main() | |||
GLFWwindow* window; | |||
struct DemoData data; | |||
struct NVGcontext* vg = NULL; | |||
struct NVGLUframebuffer fb; | |||
struct PerfGraph fps; | |||
double prevt = 0; | |||
int hasFBO; | |||
if (!glfwInit()) { | |||
printf("Failed to init GLFW."); | |||
@@ -74,7 +77,7 @@ int main() | |||
glfwWindowHint(GLFW_SAMPLES, 4); | |||
#endif | |||
window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL); | |||
window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL); | |||
// window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL); | |||
if (!window) { | |||
glfwTerminate(); | |||
@@ -109,6 +112,8 @@ int main() | |||
glfwSetTime(0); | |||
prevt = glfwGetTime(); | |||
hasFBO = nvgluCreateFramebuffer(vg, &fb, 600, 600); | |||
while (!glfwWindowShouldClose(window)) | |||
{ | |||
double mx, my, t, dt; | |||
@@ -116,6 +121,20 @@ int main() | |||
int fbWidth, fbHeight; | |||
float pxRatio; | |||
if (hasFBO) { | |||
int fboWidth, fboHeight; | |||
nvgImageSize(vg, fb.image, &fboWidth, &fboHeight); | |||
// Draw some stull to an FBO as a test | |||
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo); | |||
glViewport(0, 0, fboWidth, fboHeight); | |||
glClearColor(0, 0, 0, 0); | |||
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); | |||
nvgBeginFrame(vg, fboWidth, fboHeight, pxRatio, NVG_PREMULTIPLIED_ALPHA); | |||
renderDemo(vg, mx, my, fboWidth, fboHeight, t, blowup, &data); | |||
nvgEndFrame(vg); | |||
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |||
} | |||
t = glfwGetTime(); | |||
dt = t - prevt; | |||
prevt = t; | |||
@@ -141,6 +160,15 @@ int main() | |||
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data); | |||
renderGraph(vg, 5,5, &fps); | |||
if (hasFBO) { | |||
struct NVGpaint img = nvgImagePattern(vg, 0, 0, 150, 150, 0, fb.image, 0); | |||
nvgBeginPath(vg); | |||
nvgTranslate(vg, 540, 300); | |||
nvgRect(vg, 0, 0, 150, 150); | |||
nvgFillPaint(vg, img); | |||
nvgFill(vg); | |||
} | |||
nvgEndFrame(vg); | |||
if (screenshot) { | |||
@@ -154,6 +182,7 @@ int main() | |||
freeDemoData(vg, &data); | |||
nvgluDeleteFramebuffer(vg, &fb); | |||
nvgDeleteGL2(vg); | |||
glfwTerminate(); | |||
@@ -236,6 +236,11 @@ error: | |||
return 0; | |||
} | |||
struct NVGparams* nvgInternalParams(struct NVGcontext* ctx) | |||
{ | |||
return &ctx->params; | |||
} | |||
void nvgDeleteInternal(struct NVGcontext* ctx) | |||
{ | |||
if (ctx == NULL) return; | |||
@@ -580,6 +580,8 @@ struct NVGparams { | |||
struct NVGcontext* nvgCreateInternal(struct NVGparams* params); | |||
void nvgDeleteInternal(struct NVGcontext* ctx); | |||
struct NVGparams* nvgInternalParams(struct NVGcontext* ctx); | |||
// Debug function to dump cached path data. | |||
void nvgDebugDumpPathCache(struct NVGcontext* ctx); | |||
@@ -15,8 +15,8 @@ | |||
// misrepresented as being the original software. | |||
// 3. This notice may not be removed or altered from any source distribution. | |||
// | |||
#ifndef NANOVG_GL3_H | |||
#define NANOVG_GL3_H | |||
#ifndef NANOVG_GL_H | |||
#define NANOVG_GL_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
@@ -38,7 +38,7 @@ extern "C" { | |||
# define NANOVG_GLES3 1 | |||
# define NANOVG_GL_IMPLEMENTATION 1 | |||
#endif | |||
#if defined NANOVG_GL2 | |||
@@ -62,11 +62,21 @@ void nvgDeleteGLES3(struct NVGcontext* ctx); | |||
#endif | |||
enum NVGLtextureflags { | |||
NVGL_TEXTURE_FLIP_Y = 0x01, | |||
NVGL_TEXTURE_NODELETE = 0x02, | |||
}; | |||
int nvglCreateImageFromHandle(struct NVGcontext* ctx, GLuint textureId, int flags); | |||
GLuint nvglImageHandle(struct NVGcontext* ctx, int image); | |||
void nvglImageFlags(struct NVGcontext* ctx, int image, int flags); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif | |||
#endif /* NANOVG_GL_H */ | |||
#ifdef NANOVG_GL_IMPLEMENTATION | |||
@@ -123,6 +133,7 @@ struct GLNVGtexture { | |||
GLuint tex; | |||
int width, height; | |||
int type; | |||
int flags; | |||
}; | |||
enum GLNVGcallType { | |||
@@ -242,7 +253,7 @@ static int glnvg__deleteTexture(struct 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) | |||
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVGL_TEXTURE_NODELETE) == 0) | |||
glDeleteTextures(1, &gl->textures[i].tex); | |||
memset(&gl->textures[i], 0, sizeof(gl->textures[i])); | |||
return 1; | |||
@@ -707,9 +718,6 @@ static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms | |||
frag->innerCol = paint->innerColor; | |||
frag->outerCol = paint->outerColor; | |||
nvgTransformInverse(invxform, paint->xform); | |||
glnvg__xformToMat3x4(frag->paintMat, invxform); | |||
if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) { | |||
memset(frag->scissorMat, 0, sizeof(frag->scissorMat)); | |||
frag->scissorExt[0] = 1.0f; | |||
@@ -724,19 +732,32 @@ static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms | |||
frag->scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]) / fringe; | |||
frag->scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]) / fringe; | |||
} | |||
memcpy(frag->extent, paint->extent, sizeof(frag->extent)); | |||
frag->strokeMult = (width*0.5f + fringe*0.5f) / fringe; | |||
if (paint->image != 0) { | |||
tex = glnvg__findTexture(gl, paint->image); | |||
if (tex == NULL) return 0; | |||
if ((tex->flags & NVGL_TEXTURE_FLIP_Y) != 0) { | |||
float flipped[6]; | |||
nvgTransformScale(flipped, 1.0f, -1.0f); | |||
nvgTransformMultiply(flipped, paint->xform); | |||
nvgTransformInverse(invxform, flipped); | |||
} else { | |||
nvgTransformInverse(invxform, paint->xform); | |||
} | |||
frag->type = NSVG_SHADER_FILLIMG; | |||
frag->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; | |||
} else { | |||
frag->type = NSVG_SHADER_FILLGRAD; | |||
frag->radius = paint->radius; | |||
frag->feather = paint->feather; | |||
nvgTransformInverse(invxform, paint->xform); | |||
} | |||
glnvg__xformToMat3x4(frag->paintMat, invxform); | |||
return 1; | |||
} | |||
@@ -1226,7 +1247,7 @@ static void glnvg__renderDelete(void* uptr) | |||
glDeleteBuffers(1, &gl->vertBuf); | |||
for (i = 0; i < gl->ntextures; i++) { | |||
if (gl->textures[i].tex != 0) | |||
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVGL_TEXTURE_NODELETE) == 0) | |||
glDeleteTextures(1, &gl->textures[i].tex); | |||
} | |||
free(gl->textures); | |||
@@ -1294,4 +1315,36 @@ void nvgDeleteGLES3(struct NVGcontext* ctx) | |||
nvgDeleteInternal(ctx); | |||
} | |||
#endif | |||
int nvglCreateImageFromHandle(struct NVGcontext* ctx, GLuint textureId, int flags) | |||
{ | |||
struct GLNVGcontext* gl = (struct GLNVGcontext*)nvgInternalParams(ctx)->userPtr; | |||
struct GLNVGtexture* tex = glnvg__allocTexture(gl); | |||
if (tex == NULL) return 0; | |||
tex->tex = textureId; | |||
tex->type = NVG_TEXTURE_RGBA; | |||
tex->flags = 0; | |||
glBindTexture(GL_TEXTURE_2D, tex->tex); | |||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &tex->width); | |||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &tex->height); | |||
glBindTexture(GL_TEXTURE_2D, 0); | |||
return tex->id; | |||
} | |||
GLuint nvglImageHandle(struct NVGcontext* ctx, int image) | |||
{ | |||
struct GLNVGcontext* gl = (struct GLNVGcontext*)nvgInternalParams(ctx)->userPtr; | |||
struct GLNVGtexture* tex = glnvg__findTexture(gl, image); | |||
return tex->tex; | |||
} | |||
void nvglImageFlags(struct NVGcontext* ctx, int image, int flags) | |||
{ | |||
struct GLNVGcontext* gl = (struct GLNVGcontext*)nvgInternalParams(ctx)->userPtr; | |||
struct GLNVGtexture* tex = glnvg__findTexture(gl, image); | |||
tex->flags = flags; | |||
} | |||
#endif /* NANOVG_GL_IMPLEMENTATION */ |
@@ -0,0 +1,61 @@ | |||
#ifndef gl_utils_h | |||
#define gl_utils_h | |||
struct NVGLUframebuffer { | |||
struct NVGcontext* ctx; | |||
GLuint fbo; | |||
GLuint rbo; | |||
GLuint texture; | |||
int image; | |||
}; | |||
int nvgluCreateFramebuffer(struct NVGcontext* ctx, struct NVGLUframebuffer* fb, int w, int h); | |||
void nvgluDeleteFramebuffer(struct NVGcontext* ctx, struct NVGLUframebuffer* fb); | |||
#endif /* gl_utils_h */ | |||
#ifdef NANOVG_GL_IMPLEMENTATION | |||
int nvgluCreateFramebuffer(struct NVGcontext* ctx, struct NVGLUframebuffer* fb, int w, int h) { | |||
fb->image = nvgCreateImageRGBA(ctx, w, h, NULL); | |||
fb->texture = nvglImageHandle(ctx, fb->image); | |||
nvglImageFlags(ctx, fb->image, NVGL_TEXTURE_FLIP_Y); | |||
/* frame buffer object */ | |||
glGenFramebuffers(1, &fb->fbo); | |||
glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo); | |||
/* render buffer object */ | |||
glGenRenderbuffers(1, &fb->rbo); | |||
glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo); | |||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); | |||
/* combine all */ | |||
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) { | |||
nvgluDeleteFramebuffer(ctx, fb); | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
void nvgluDeleteFramebuffer(struct NVGcontext* ctx, struct NVGLUframebuffer* fb) { | |||
if (fb->fbo != 0) | |||
glDeleteFramebuffers(1, &fb->fbo); | |||
if (fb->rbo != 0) | |||
glDeleteRenderbuffers(1, &fb->rbo); | |||
if (fb->image >= 0) | |||
nvgDeleteImage(ctx, fb->image); | |||
fb->fbo = 0; | |||
fb->rbo = 0; | |||
fb->texture = 0; | |||
fb->image = -1; | |||
} | |||
#endif /* NANOVG_GL_IMPLEMENTATION */ | |||
/* vim: set ft=c nu noet ts=4 sw=4 : */ |