diff --git a/libsrc/include/incopengl.hpp b/libsrc/include/incopengl.hpp index dc4c469f..d8c3bcea 100644 --- a/libsrc/include/incopengl.hpp +++ b/libsrc/include/incopengl.hpp @@ -28,6 +28,11 @@ #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_STATIC_DRAW 0x88E4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_COLOR_ATTACHMENT0 0x8CE0 typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; extern void (*glBindBuffer) (GLenum a, GLuint b); @@ -35,6 +40,18 @@ extern void (*glDeleteBuffers) (GLsizei a, const GLuint *b); extern void (*glGenBuffers) (GLsizei a, GLuint *b); extern void (*glBufferData) (GLenum a, GLsizeiptr b, const GLvoid *c, GLenum d); extern void (*glBufferSubData) (GLenum a, GLintptr b, GLsizeiptr c, const GLvoid *d); + +extern GLenum (*glCheckFramebufferStatus) (GLenum target); +extern void (*glBindFramebuffer) (GLenum target, GLuint framebuffer); +extern void (*glBindRenderbuffer) (GLenum target, GLuint renderbuffer); +extern void (*glDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers); +extern void (*glDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers); +extern void (*glFramebufferTexture) (GLenum target, GLenum attachment, GLuint texture, GLint level); +extern void (*glGenFramebuffers) (GLsizei n, GLuint *framebuffers); +extern void (*glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers); +extern void (*glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +extern void (*glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +extern void (*glNamedFramebufferReadBuffer) ( GLuint framebuffer, GLenum mode); #endif DLL_HEADER void LoadOpenGLFunctionPointers(); #endif // INCOPENGL_HPP___ diff --git a/libsrc/visualization/mvdraw.cpp b/libsrc/visualization/mvdraw.cpp index 07d9aec4..b9c5f4dc 100644 --- a/libsrc/visualization/mvdraw.cpp +++ b/libsrc/visualization/mvdraw.cpp @@ -779,6 +779,64 @@ namespace netgen VisualScene::MouseMove(oldx, oldy, newx, newy, mode); } + std::vector Snapshot( int w, int h ) + { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + double pnear = 0.1; + double pfar = 10; + + gluPerspective(20.0f, double(w) / h, pnear, pfar); + + glMatrixMode(GL_MODELVIEW); + + GLuint fb = 0; + glGenFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb); + + GLuint tex; + glGenTextures(1, &tex); + + glBindTexture(GL_TEXTURE_2D, tex); + + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, w, h, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + GLuint depthrenderbuffer; + glGenRenderbuffers(1, &depthrenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer); + + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0); + + if(int fbstatus; (fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) + cerr << "no frame buffer " << fbstatus << endl; + + glBindFramebuffer(GL_FRAMEBUFFER, fb); + glViewport(0,0,w,h); + + glPushMatrix(); + GetVSSolution().DrawScene(); + glFinish(); + glPopMatrix(); + + std::vector buffer(w*h*3); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glPixelStorei(GL_PACK_ALIGNMENT,1); + glNamedFramebufferReadBuffer( fb, GL_COLOR_ATTACHMENT0 ); + glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buffer[0]); + + glDeleteRenderbuffers(1, &depthrenderbuffer); + glDeleteTextures(1, &tex); + glDeleteFramebuffers(1, &fb); + + return buffer; + } + #ifdef PARALLELGL void VisualScene :: InitParallelGL () diff --git a/libsrc/visualization/mvdraw.hpp b/libsrc/visualization/mvdraw.hpp index 264dd6a4..7a0045a5 100644 --- a/libsrc/visualization/mvdraw.hpp +++ b/libsrc/visualization/mvdraw.hpp @@ -247,6 +247,7 @@ namespace netgen PointIndex & selpoint2, int & locpi); + DLL_HEADER std::vector Snapshot( int w, int h ); } diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index 2a61662b..624e95f7 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -4890,6 +4890,19 @@ void (*glDeleteBuffers) (GLsizei a, const GLuint *b); void (*glGenBuffers) (GLsizei a, GLuint *b); void (*glBufferData) (GLenum a, GLsizeiptr b, const GLvoid *c, GLenum d); void (*glBufferSubData) (GLenum a, GLintptr b, GLsizeiptr c, const GLvoid *d); + +GLenum (*glCheckFramebufferStatus) (GLenum target); +void (*glBindFramebuffer) (GLenum target, GLuint framebuffer); +void (*glBindRenderbuffer) (GLenum target, GLuint renderbuffer); +void (*glDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers); +void (*glDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers); +void (*glFramebufferTexture) (GLenum target, GLenum attachment, GLuint texture, GLint level); +void (*glGenFramebuffers) (GLsizei n, GLuint *framebuffers); +void (*glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers); +void (*glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +void (*glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +void (*glNamedFramebufferReadBuffer) ( GLuint framebuffer, GLenum mode); + DLL_HEADER void LoadOpenGLFunctionPointers() { #ifdef USE_BUFFERS glBindBuffer = (decltype(glBindBuffer)) wglGetProcAddress("glBindBuffer"); @@ -4899,6 +4912,18 @@ DLL_HEADER void LoadOpenGLFunctionPointers() { glGenBuffers = (decltype(glGenBuffers)) wglGetProcAddress("glGenBuffers"); if(!glBindBuffer) throw std::runtime_error("Could not load OpenGL functions!"); #endif + + glCheckFramebufferStatus = (decltype(glCheckFramebufferStatus )) wglGetProcAddress("glCheckFramebufferStatus"); + glBindFramebuffer = (decltype(glBindFramebuffer )) wglGetProcAddress("glBindFramebuffer"); + glBindRenderbuffer = (decltype(glBindRenderbuffer )) wglGetProcAddress("glBindRenderbuffer"); + glDeleteFramebuffers = (decltype(glDeleteFramebuffers )) wglGetProcAddress("glDeleteFramebuffers"); + glDeleteRenderbuffers = (decltype(glDeleteRenderbuffers )) wglGetProcAddress("glDeleteRenderbuffers"); + glFramebufferTexture = (decltype(glFramebufferTexture )) wglGetProcAddress("glFramebufferTexture"); + glGenFramebuffers = (decltype(glGenFramebuffers )) wglGetProcAddress("glGenFramebuffers"); + glGenRenderbuffers = (decltype(glGenRenderbuffers )) wglGetProcAddress("glGenRenderbuffers"); + glRenderbufferStorage = (decltype(glRenderbufferStorage )) wglGetProcAddress("glRenderbufferStorage"); + glFramebufferRenderbuffer = (decltype(glFramebufferRenderbuffer )) wglGetProcAddress("glFramebufferRenderbuffer"); + glNamedFramebufferReadBuffer = (decltype(glNamedFramebufferReadBuffer )) wglGetProcAddress("glNamedFramebufferReadBuffer"); } #else // WIN32 DLL_HEADER void LoadOpenGLFunctionPointers() { } diff --git a/ng/netgenpy.cpp b/ng/netgenpy.cpp index d9d8a5c2..2b68e408 100644 --- a/ng/netgenpy.cpp +++ b/ng/netgenpy.cpp @@ -20,6 +20,10 @@ void DLL_HEADER ExportSTLVis(py::module &m); #ifdef OCCGEOMETRY void DLL_HEADER ExportNgOCC(py::module &m); #endif // OCCGEOMETRY +namespace netgen +{ + std::vector DLL_HEADER Snapshot( int w, int h ); +} PYBIND11_MODULE(libngpy, ngpy) { @@ -43,6 +47,7 @@ PYBIND11_MODULE(libngpy, ngpy) ExportCSGVis(csgvis); py::module stlvis = ngpy.def_submodule("stlvis", "pybind stlvis module"); ExportSTLVis(stlvis); + ngpy.def("Snapshot", netgen::Snapshot); #endif // OPENGL } diff --git a/python/gui.py b/python/gui.py index 959b2fd3..d43c9473 100644 --- a/python/gui.py +++ b/python/gui.py @@ -24,3 +24,16 @@ if not netgen.libngpy._meshing._netgen_executable_started: StartGUI() except: pass + +def Snapshot(w,h, filename=None): + import ngsolve + ngsolve.Redraw(blocking=True) + import numpy + image = netgen.libngpy.Snapshot(w, h) + image = numpy.array(image, dtype=numpy.uint8).reshape(h, w, 3) + image = image[::-1,:,:] + if filename: + import PIL.Image + im = PIL.Image.fromarray(image) + im.save(filename) + return image