|
@@ -4,17 +4,57 @@
|
|
|
\brief Nviz library -- GLX context manipulation
|
|
|
|
|
|
Based on visualization/nviz/src/togl.c
|
|
|
-
|
|
|
- (C) 2008, 2010 by the GRASS Development Team
|
|
|
+
|
|
|
+ (C) 2008, 2010, 2018 by the GRASS Development Team
|
|
|
This program is free software under the GNU General Public License
|
|
|
(>=v2). Read the file COPYING that comes with GRASS for details.
|
|
|
|
|
|
\author Updated/modified by Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
|
|
|
+ \author Support for framebuffer objects by Huidae Cho <grass4u gmail.com> (July 2018)
|
|
|
*/
|
|
|
|
|
|
#include <grass/glocale.h>
|
|
|
#include <grass/nviz.h>
|
|
|
|
|
|
+#if defined(OPENGL_WINDOWS) && defined(OPENGL_FBO)
|
|
|
+static int gl_funcs_found = 0;
|
|
|
+static PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
|
|
+static PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
|
|
+static PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
|
|
+static PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
|
|
+static PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
|
|
+static PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
|
|
+static PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
|
|
+
|
|
|
+/* https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions */
|
|
|
+static void *GetAnyGLFuncAddress(const char *name)
|
|
|
+{
|
|
|
+ void *p = (void *)wglGetProcAddress(name);
|
|
|
+ if(p == 0 || p == (void*)0x1 || p == (void*)0x2 || p == (void*)0x3 ||
|
|
|
+ p == (void*)-1) {
|
|
|
+ HMODULE module = LoadLibraryA("opengl32.dll");
|
|
|
+ p = (void *)GetProcAddress(module, name);
|
|
|
+ }
|
|
|
+ return p;
|
|
|
+}
|
|
|
+
|
|
|
+static void find_gl_funcs()
|
|
|
+{
|
|
|
+ if (gl_funcs_found)
|
|
|
+ return;
|
|
|
+
|
|
|
+ glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GetAnyGLFuncAddress("glGenFramebuffers");
|
|
|
+ glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GetAnyGLFuncAddress("glBindFramebuffer");
|
|
|
+ glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GetAnyGLFuncAddress("glGenRenderbuffers");
|
|
|
+ glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GetAnyGLFuncAddress("glBindRenderbuffer");
|
|
|
+ glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GetAnyGLFuncAddress("glRenderbufferStorage");
|
|
|
+ glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) GetAnyGLFuncAddress("glFramebufferRenderbuffer");
|
|
|
+ glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) GetAnyGLFuncAddress("glCheckFramebufferStatus");
|
|
|
+
|
|
|
+ gl_funcs_found = 1;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
/*!
|
|
|
\brief Allocate memory for render window
|
|
|
|
|
@@ -44,9 +84,13 @@ void Nviz_init_render_window(struct render_window *rwin)
|
|
|
rwin->pixmap = 0;
|
|
|
rwin->windowId = 0;
|
|
|
#elif defined(OPENGL_AQUA)
|
|
|
+#if defined(OPENGL_AGL)
|
|
|
rwin->pixelFmtId = NULL;
|
|
|
rwin->contextId = NULL;
|
|
|
rwin->windowId = NULL;
|
|
|
+#else
|
|
|
+ rwin->contextId = NULL;
|
|
|
+#endif
|
|
|
#elif defined(OPENGL_WINDOWS)
|
|
|
rwin->displayId = NULL;
|
|
|
rwin->contextId = NULL;
|
|
@@ -69,10 +113,13 @@ void Nviz_destroy_render_window(struct render_window *rwin)
|
|
|
glXDestroyContext(rwin->displayId, rwin->contextId);
|
|
|
XCloseDisplay(rwin->displayId);
|
|
|
#elif defined(OPENGL_AQUA)
|
|
|
+#if defined(OPENGL_AGL)
|
|
|
aglDestroyPixelFormat(rwin->pixelFmtId);
|
|
|
aglDestroyContext(rwin->contextId);
|
|
|
aglDestroyPBuffer(rwin->windowId);
|
|
|
- /* TODO FreePixMap */
|
|
|
+#else
|
|
|
+ CGLDestroyContext(rwin->contextId);
|
|
|
+#endif
|
|
|
#elif defined(OPENGL_WINDOWS)
|
|
|
wglDeleteContext(rwin->contextId);
|
|
|
DeleteDC(rwin->displayId);
|
|
@@ -96,9 +143,16 @@ int Nviz_create_render_window(struct render_window *rwin, void *display,
|
|
|
int width, int height)
|
|
|
{
|
|
|
#if defined(OPENGL_X11)
|
|
|
- int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1,
|
|
|
- GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
|
|
|
- GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, None
|
|
|
+ int attributeList[] = {
|
|
|
+ GLX_RGBA,
|
|
|
+ GLX_RED_SIZE, 1,
|
|
|
+ GLX_GREEN_SIZE, 1,
|
|
|
+ GLX_BLUE_SIZE, 1,
|
|
|
+ GLX_DEPTH_SIZE, 1,
|
|
|
+#if !defined(OPENGL_FBO)
|
|
|
+ GLX_DOUBLEBUFFER,
|
|
|
+#endif
|
|
|
+ None
|
|
|
};
|
|
|
XVisualInfo *v;
|
|
|
|
|
@@ -113,7 +167,7 @@ int Nviz_create_render_window(struct render_window *rwin, void *display,
|
|
|
G_warning(_("Unable to get visual info"));
|
|
|
return -1;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
rwin->contextId = glXCreateContext(rwin->displayId, v, NULL, GL_TRUE);
|
|
|
|
|
|
if (!rwin->contextId) {
|
|
@@ -131,10 +185,19 @@ int Nviz_create_render_window(struct render_window *rwin, void *display,
|
|
|
|
|
|
XFree(v);
|
|
|
#elif defined(OPENGL_AQUA)
|
|
|
- int attributeList[] = { AGL_RGBA, AGL_RED_SIZE, 1,
|
|
|
- AGL_GREEN_SIZE, 1, AGL_BLUE_SIZE, 1,
|
|
|
- AGL_DEPTH_SIZE, 1, AGL_DOUBLEBUFFER, AGL_NONE
|
|
|
+#if defined(OPENGL_AGL)
|
|
|
+ int attributeList[] = {
|
|
|
+ AGL_RGBA,
|
|
|
+ AGL_RED_SIZE, 1,
|
|
|
+ AGL_GREEN_SIZE, 1,
|
|
|
+ AGL_BLUE_SIZE, 1,
|
|
|
+ AGL_DEPTH_SIZE, 1,
|
|
|
+#if !defined(OPENGL_FBO)
|
|
|
+ AGL_DOUBLEBUFFER,
|
|
|
+#endif
|
|
|
+ AGL_NONE
|
|
|
};
|
|
|
+
|
|
|
/* TODO: open mac display */
|
|
|
|
|
|
/* TODO: dev = NULL, ndev = 0 ? */
|
|
@@ -145,28 +208,52 @@ int Nviz_create_render_window(struct render_window *rwin, void *display,
|
|
|
/* create an off-screen AGL rendering area */
|
|
|
aglCreatePBuffer(width, height, GL_TEXTURE_2D, GL_RGBA, 0, &(rwin->windowId));
|
|
|
aglSetPBuffer(rwin->contextId, rwin->windowId, 0, 0, 0);
|
|
|
+#else
|
|
|
+ CGLPixelFormatAttribute attributeList[] = {
|
|
|
+ kCGLPFAColorSize, 24,
|
|
|
+ kCGLPFADepthSize, 32,
|
|
|
+ (CGLPixelFormatAttribute) 0
|
|
|
+ };
|
|
|
+ CGLPixelFormatObj pix;
|
|
|
+ GLint nvirt;
|
|
|
+ CGLError error;
|
|
|
+
|
|
|
+ error = CGLChoosePixelFormat(attributeList, &pix, &nvirt);
|
|
|
+ if (error) {
|
|
|
+ G_warning(_("Unable to choose pixel format (CGL error = %d)"), error);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ error = CGLCreateContext(pix, NULL, &rwin->contextId);
|
|
|
+ if (error) {
|
|
|
+ G_warning(_("Unable to create context (CGL error = %d)"), error);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ CGLDestroyPixelFormat(pix);
|
|
|
+#endif
|
|
|
#elif defined(OPENGL_WINDOWS)
|
|
|
WNDCLASS wc = {0};
|
|
|
HWND hWnd;
|
|
|
PIXELFORMATDESCRIPTOR pfd = {
|
|
|
- sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
|
|
|
- 1, /* version number */
|
|
|
- PFD_DRAW_TO_WINDOW | /* support window */
|
|
|
- PFD_SUPPORT_OPENGL | /* support OpenGL */
|
|
|
- PFD_DOUBLEBUFFER, /* double buffered */
|
|
|
- PFD_TYPE_RGBA, /* RGBA type */
|
|
|
- 24, /* 24-bit color depth */
|
|
|
- 0, 0, 0, 0, 0, 0, /* color bits ignored */
|
|
|
- 0, /* no alpha buffer */
|
|
|
- 0, /* shift bit ignored */
|
|
|
- 0, /* no accumulation buffer */
|
|
|
- 0, 0, 0, 0, /* accum bits ignored */
|
|
|
- 32, /* 32-bit z-buffer */
|
|
|
- 0, /* no stencil buffer */
|
|
|
- 0, /* no auxiliary buffer */
|
|
|
- PFD_MAIN_PLANE, /* main layer */
|
|
|
- 0, /* reserved */
|
|
|
- 0, 0, 0 /* layer masks ignored */
|
|
|
+ sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */
|
|
|
+ 1, /* version number */
|
|
|
+ PFD_DRAW_TO_WINDOW | /* support window */
|
|
|
+ PFD_SUPPORT_OPENGL | /* support OpenGL */
|
|
|
+ PFD_DOUBLEBUFFER, /* double buffered */
|
|
|
+ PFD_TYPE_RGBA, /* RGBA type */
|
|
|
+ 24, /* 24-bit color depth */
|
|
|
+ 0, 0, 0, 0, 0, 0, /* color bits ignored */
|
|
|
+ 0, /* no alpha buffer */
|
|
|
+ 0, /* shift bit ignored */
|
|
|
+ 0, /* no accumulation buffer */
|
|
|
+ 0, 0, 0, 0, /* accum bits ignored */
|
|
|
+ 32, /* 32-bit z-buffer */
|
|
|
+ 0, /* no stencil buffer */
|
|
|
+ 0, /* no auxiliary buffer */
|
|
|
+ PFD_MAIN_PLANE, /* main layer */
|
|
|
+ 0, /* reserved */
|
|
|
+ 0, 0, 0 /* layer masks ignored */
|
|
|
};
|
|
|
int iPixelFormat;
|
|
|
|
|
@@ -218,6 +305,7 @@ int Nviz_make_current_render_window(const struct render_window *rwin)
|
|
|
|
|
|
glXMakeCurrent(rwin->displayId, rwin->windowId, rwin->contextId);
|
|
|
#elif defined(OPENGL_AQUA)
|
|
|
+#if defined(OPENGL_AGL)
|
|
|
if (!rwin->contextId)
|
|
|
return 0;
|
|
|
|
|
@@ -225,6 +313,15 @@ int Nviz_make_current_render_window(const struct render_window *rwin)
|
|
|
return 1;
|
|
|
|
|
|
aglSetCurrentContext(rwin->contextId);
|
|
|
+#else
|
|
|
+ CGLError error;
|
|
|
+
|
|
|
+ error = CGLSetCurrentContext(rwin->contextId);
|
|
|
+ if (error) {
|
|
|
+ G_warning(_("Unable to set current context (CGL error = %d)"), error);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
#elif defined(OPENGL_WINDOWS)
|
|
|
if (!rwin->displayId || !rwin->contextId)
|
|
|
return 0;
|
|
@@ -232,6 +329,38 @@ int Nviz_make_current_render_window(const struct render_window *rwin)
|
|
|
wglMakeCurrent(rwin->displayId, rwin->contextId);
|
|
|
#endif
|
|
|
|
|
|
+#if defined(OPENGL_FBO)
|
|
|
+#if defined(OPENGL_WINDOWS)
|
|
|
+ find_gl_funcs();
|
|
|
+#endif
|
|
|
+
|
|
|
+ GLuint framebuf, renderbuf, depthbuf;
|
|
|
+ GLenum status;
|
|
|
+
|
|
|
+ glGenFramebuffers(1, &framebuf);
|
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuf);
|
|
|
+
|
|
|
+ glGenRenderbuffers(1, &renderbuf);
|
|
|
+ glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
|
|
|
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
|
|
|
+ rwin->width, rwin->height);
|
|
|
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
|
+ GL_RENDERBUFFER, renderbuf);
|
|
|
+
|
|
|
+ glGenRenderbuffers(1, &depthbuf);
|
|
|
+ glBindRenderbuffer(GL_RENDERBUFFER, depthbuf);
|
|
|
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24,
|
|
|
+ rwin->width, rwin->height);
|
|
|
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
|
|
+ GL_RENDERBUFFER, depthbuf);
|
|
|
+
|
|
|
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
|
|
|
+ G_warning(_("Incomplete framebuffer status (status = %d)"), status);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
glViewport(0, 0, rwin->width, rwin->height);
|
|
|
|
|
|
return 1;
|