Browse Source

Implements nanovg's framebuffer helper functions. (#869)

This commit ports nanovg's helper functions for rendering stuff in framebuffer defined in `nanovg_gl_utils.h`. Also, a new `nvgState()` function is created for bgfx backend so it is possible to blend between framebuffers, which feature is long requested but not yet supported in original nanovg. The `nvgState()` function can be called between `nvgBeginFrame()` and `nvgEndFrame()`.
Olli Wang 9 years ago
parent
commit
f11d954bc1
2 changed files with 110 additions and 11 deletions
  1. 75 10
      examples/common/nanovg/nanovg_bgfx.cpp
  2. 35 1
      examples/common/nanovg/nanovg_bgfx.h

+ 75 - 10
examples/common/nanovg/nanovg_bgfx.cpp

@@ -548,6 +548,7 @@ namespace
 	static void nvgRenderViewport(void* _userPtr, int width, int height, float devicePixelRatio)
 	{
 		struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
+		gl->state = 0;
 		gl->view[0] = (float)width;
 		gl->view[1] = (float)height;
 		bgfx::setViewRect(gl->m_viewId, 0, 0, width * devicePixelRatio, height * devicePixelRatio);
@@ -722,11 +723,8 @@ namespace
 
 			memcpy(gl->tvb.data, gl->verts, gl->nverts * sizeof(struct NVGvertex) );
 
-			gl->state = 0
-				| BGFX_STATE_RGB_WRITE
-				| BGFX_STATE_ALPHA_WRITE
-				;
-
+			if (gl->state == 0)
+			{
 // 			if (alphaBlend == NVG_PREMULTIPLIED_ALPHA)
 // 			{
 // 				gl->state |= BGFX_STATE_BLEND_FUNC_SEPARATE(
@@ -735,11 +733,11 @@ namespace
 // 								);
 // 			}
 // 			else
-			{
-				gl->state |= BGFX_STATE_BLEND_FUNC(
+				gl->state = BGFX_STATE_BLEND_FUNC(
 								BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA
 								);
 			}
+			gl->state |= BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE;
 
 			bgfx::setUniform(gl->u_viewSize, gl->view);
 
@@ -1089,7 +1087,26 @@ error:
 }
 
 NVGcontext* nvgCreate(int edgeaa, unsigned char _viewId) {
-  return nvgCreate(edgeaa, _viewId, NULL);
+	return nvgCreate(edgeaa, _viewId, NULL);
+}
+
+void nvgDelete(struct NVGcontext* ctx)
+{
+	nvgDeleteInternal(ctx);
+}
+
+void nvgState(struct NVGcontext* ctx, uint64_t state)
+{
+  struct NVGparams* params = nvgInternalParams(ctx);
+  struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr;
+  gl->state = state;
+}
+
+uint8_t nvgViewId(struct NVGcontext* ctx)
+{
+	struct NVGparams* params = nvgInternalParams(ctx);
+	struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr;
+	return gl->m_viewId;
 }
 
 void nvgViewId(struct NVGcontext* ctx, unsigned char _viewId)
@@ -1099,7 +1116,55 @@ void nvgViewId(struct NVGcontext* ctx, unsigned char _viewId)
 	gl->m_viewId = uint8_t(_viewId);
 }
 
-void nvgDelete(struct NVGcontext* ctx)
+bgfx::TextureHandle nvglImageHandle(NVGcontext* ctx, int image)
 {
-	nvgDeleteInternal(ctx);
+	GLNVGcontext* gl = (GLNVGcontext*)nvgInternalParams(ctx)->userPtr;
+	GLNVGtexture* tex = glnvg__findTexture(gl, image);
+	return tex->id;
+}
+
+NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int width,
+																				 int height, int imageFlags) {
+	NVGLUframebuffer* framebuffer = new NVGLUframebuffer;
+	framebuffer->ctx = ctx;
+	framebuffer->image = nvgCreateImageRGBA(ctx, width, height,
+																					imageFlags, NULL);
+	bgfx::TextureHandle texture = nvglImageHandle(ctx, framebuffer->image);
+	if (!bgfx::isValid(texture)) {
+		nvgluDeleteFramebuffer(framebuffer);
+		return NULL;
+	}
+	framebuffer->handle = bgfx::createFrameBuffer(1, &texture, false);
+	if (!bgfx::isValid(framebuffer->handle))
+	{
+		nvgluDeleteFramebuffer(framebuffer);
+		return NULL;
+	}
+	static uint8_t s_ViewId = 1;  // may have a better way to assign new view id
+	framebuffer->viewId = s_ViewId++;
+	bgfx::setViewFrameBuffer(framebuffer->viewId, framebuffer->handle);
+	bgfx::setViewSeq(framebuffer->viewId, true);
+	return framebuffer;
+}
+
+void nvgluBindFramebuffer(NVGLUframebuffer* framebuffer) {
+	static NVGcontext* s_prevCtx = NULL;
+	static uint8_t s_prevViewId;
+	if (framebuffer != NULL) {
+		s_prevCtx = framebuffer->ctx;
+		s_prevViewId = nvgViewId(framebuffer->ctx);
+		nvgViewId(framebuffer->ctx, framebuffer->viewId);
+	} else if (s_prevCtx != NULL) {
+		nvgViewId(s_prevCtx, s_prevViewId);
+	}
+}
+
+void nvgluDeleteFramebuffer(NVGLUframebuffer* framebuffer) {
+	if (framebuffer == NULL)
+		return;
+	if (framebuffer->image >= 0)
+		nvgDeleteImage(framebuffer->ctx, framebuffer->image);
+	if (bgfx::isValid(framebuffer->handle))
+		bgfx::destroyFrameBuffer(framebuffer->handle);
+	delete framebuffer;
 }

+ 35 - 1
examples/common/nanovg/nanovg_bgfx.h

@@ -6,13 +6,47 @@
 #ifndef NANOVG_BGFX_H_HEADER_GUARD
 #define NANOVG_BGFX_H_HEADER_GUARD
 
+#include "bgfx/bgfx.h"
+
 namespace bx { struct AllocatorI; }
 
 struct NVGcontext;
 
+struct NVGLUframebuffer {
+  NVGcontext* ctx;
+  bgfx::FrameBufferHandle handle;
+  int image;
+  uint8_t viewId;
+};
+typedef struct NVGLUframebuffer NVGLUframebuffer;
+
 NVGcontext* nvgCreate(int edgeaa, unsigned char _viewId, bx::AllocatorI* _allocator);
 NVGcontext* nvgCreate(int edgeaa, unsigned char _viewId);
-void nvgViewId(struct NVGcontext* ctx, unsigned char _viewId);
 void nvgDelete(struct NVGcontext* ctx);
+void nvgState(struct NVGcontext* ctx, uint64_t state);
+uint8_t nvgViewId(struct NVGcontext* ctx);
+void nvgViewId(struct NVGcontext* ctx, unsigned char _viewId);
+
+// Helper functions to create bgfx framebuffer to render to.
+// Example:
+//		float scale = 2;
+//		NVGLUframebuffer* fb = nvgluCreateFramebuffer(ctx, 100 * scale, 100 * scale, 0);
+//		nvgluBindFramebuffer(fb);
+//		nvgBeginFrame(ctx, 100, 100, scale);
+//		// renders anything offscreen
+//		nvgEndFrame(ctx);
+//		nvgluBindFramebuffer(NULL);
+//
+//		// Pastes the framebuffer rendering.
+//		nvgBeginFrame(ctx, 1024, 768, scale);
+//		NVGpaint paint = nvgImagePattern(ctx, 0, 0, 100, 100, 0, fb->image, 1);
+//		nvgBeginPath(ctx);
+//		nvgRect(ctx, 0, 0, 100, 100);
+//		nvgFillPaint(ctx, paint);
+//		nvgFill(ctx);
+//		nvgEndFrame(ctx);
+NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int width, int height, int imageFlags);
+void nvgluBindFramebuffer(NVGLUframebuffer* framebuffer);
+void nvgluDeleteFramebuffer(NVGLUframebuffer* framebuffer);
 
 #endif // NANOVG_BGFX_H_HEADER_GUARD