diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index e8bff0b7..a890579b 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -367,6 +367,7 @@ DLL_HEADER void ExportGeom2d(py::module &m) ([] (shared_ptr self) { ng_geometry = self; + py::module::import("netgen").attr("Redraw")(); }) ) diff --git a/libsrc/include/incopengl.hpp b/libsrc/include/incopengl.hpp index dc4c469f..8cff36af 100644 --- a/libsrc/include/incopengl.hpp +++ b/libsrc/include/incopengl.hpp @@ -6,7 +6,8 @@ # if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_NSOPENGL) #define GL_SILENCE_DEPRECATION -# include +#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED +# include # include # else # include @@ -28,6 +29,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 +41,16 @@ 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 (*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); #endif DLL_HEADER void LoadOpenGLFunctionPointers(); #endif // INCOPENGL_HPP___ diff --git a/libsrc/visualization/mvdraw.cpp b/libsrc/visualization/mvdraw.cpp index 07d9aec4..65b89b05 100644 --- a/libsrc/visualization/mvdraw.cpp +++ b/libsrc/visualization/mvdraw.cpp @@ -25,6 +25,8 @@ namespace netgen DLL_HEADER Point3d VisualScene :: center; DLL_HEADER double VisualScene :: rad; DLL_HEADER GLdouble VisualScene :: backcolor; + DLL_HEADER VisualScene visual_scene_cross; + DLL_HEADER VisualScene *visual_scene = &visual_scene_cross; /* #if TOGL_MAJOR_VERSION!=2 @@ -779,6 +781,66 @@ namespace netgen VisualScene::MouseMove(oldx, oldy, newx, newy, mode); } + std::vector Snapshot( int w, int h ) + { + // save current settings + GLint viewport[4]; + glGetIntegerv (GL_VIEWPORT, viewport); + + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + double pnear = 0.1; + double pfar = 10; + + gluPerspective(20.0f, double(w) / h, pnear, pfar); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glViewport(0,0,w,h); + + GLuint fb = 0; + glGenFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb); + + // create, reserve and attach color and depth renderbuffer + GLuint rbs[2]; + glGenRenderbuffers(2, rbs); + glBindRenderbuffer(GL_RENDERBUFFER, rbs[0]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, w, h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[0]); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[1]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbs[1]); + + // check if framebuffer status is complete + if(int fbstatus; (fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) + cerr << "no frame buffer " << fbstatus << endl; + + visual_scene->DrawScene(); + glFinish(); + + std::vector buffer(w*h*3); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glPixelStorei(GL_PACK_ALIGNMENT,1); + glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buffer[0]); + + glDeleteRenderbuffers(2, rbs); + glDeleteFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // restore previous settings + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + return buffer; + } + #ifdef PARALLELGL void VisualScene :: InitParallelGL () diff --git a/libsrc/visualization/mvdraw.hpp b/libsrc/visualization/mvdraw.hpp index 264dd6a4..cae7c792 100644 --- a/libsrc/visualization/mvdraw.hpp +++ b/libsrc/visualization/mvdraw.hpp @@ -83,6 +83,8 @@ namespace netgen DLL_HEADER extern void MyOpenGLText (const char * text); DLL_HEADER extern void Set_OpenGLText_Callback ( void (*fun) (const char * text) ); + DLL_HEADER extern VisualScene visual_scene_cross; + DLL_HEADER extern VisualScene *visual_scene; @@ -247,6 +249,7 @@ namespace netgen PointIndex & selpoint2, int & locpi); + DLL_HEADER std::vector Snapshot( int w, int h ); } diff --git a/libsrc/visualization/vsmesh.cpp b/libsrc/visualization/vsmesh.cpp index ed04a128..21a2f43e 100644 --- a/libsrc/visualization/vsmesh.cpp +++ b/libsrc/visualization/vsmesh.cpp @@ -3536,6 +3536,7 @@ namespace netgen #ifdef NG_PYTHON #include <../general/ngpython.hpp> +#include "../include/nginterface.h" DLL_HEADER void ExportMeshVis(py::module &m) { @@ -3577,6 +3578,32 @@ DLL_HEADER void ExportMeshVis(py::module &m) ([] () { return vsmesh.GetMesh(); })); + m.def ("_Redraw", + ([](bool blocking, double fr) + { + static auto last_time = std::chrono::system_clock::now()-std::chrono::seconds(10); + auto now = std::chrono::system_clock::now(); + double elapsed = std::chrono::duration(now-last_time).count(); + if (elapsed * fr > 1) + { + Ng_Redraw(blocking); + last_time = std::chrono::system_clock::now(); + return true; + } + return false; + }), + py::arg("blocking")=false, py::arg("fr") = 25, R"raw_string( +Redraw all + +Parameters: + +blocking : bool + input blocking + +fr : double + input framerate + +)raw_string"); } // BOOST_PYTHON_MODULE(libvisual) // { diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index 2a61662b..d0aa8468 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -4890,6 +4890,17 @@ 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 (*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); + DLL_HEADER void LoadOpenGLFunctionPointers() { #ifdef USE_BUFFERS glBindBuffer = (decltype(glBindBuffer)) wglGetProcAddress("glBindBuffer"); @@ -4899,6 +4910,16 @@ 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"); + glGenFramebuffers = (decltype(glGenFramebuffers )) wglGetProcAddress("glGenFramebuffers"); + glGenRenderbuffers = (decltype(glGenRenderbuffers )) wglGetProcAddress("glGenRenderbuffers"); + glRenderbufferStorage = (decltype(glRenderbufferStorage )) wglGetProcAddress("glRenderbufferStorage"); + glFramebufferRenderbuffer = (decltype(glFramebufferRenderbuffer )) wglGetProcAddress("glFramebufferRenderbuffer"); } #else // WIN32 DLL_HEADER void LoadOpenGLFunctionPointers() { } diff --git a/ng/demoview.cpp b/ng/demoview.cpp index 81fb329f..996082ce 100644 --- a/ng/demoview.cpp +++ b/ng/demoview.cpp @@ -20,7 +20,6 @@ #include namespace netgen { - extern VisualScene *vs; #include "demoview.hpp" @@ -422,7 +421,7 @@ namespace netgen { */ - vs -> LookAt ( Point<3>( campos.Evaluate (time)), + visual_scene -> LookAt ( Point<3>( campos.Evaluate (time)), Point<3>(campoint.Evaluate (time)), Point<3>( camup.Evaluate (time)) ); 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/ng/ngpkg.cpp b/ng/ngpkg.cpp index aed8161d..afd4d0e1 100644 --- a/ng/ngpkg.cpp +++ b/ng/ngpkg.cpp @@ -103,7 +103,6 @@ namespace netgen // visualization scenes, pointer vs selects which one is drawn: - static VisualScene vscross; DLL_HEADER extern VisualSceneSurfaceMeshing vssurfacemeshing; DLL_HEADER extern VisualSceneMeshDoctor vsmeshdoc; @@ -111,7 +110,8 @@ namespace netgen - VisualScene *vs = &vscross; + DLL_HEADER extern VisualScene *visual_scene; + DLL_HEADER extern VisualScene visual_scene_cross; @@ -1973,7 +1973,8 @@ namespace netgen { const char * vismode = vispar.selectvisual; // Tcl_GetVar (interp, "selectvisual", 0); - vs = &vscross; + VisualScene *& vs = visual_scene; + vs = &visual_scene_cross; if (GetVisualizationScenes().Used(vismode)) { vs = GetVisualizationScenes()[vismode]; @@ -2049,7 +2050,7 @@ namespace netgen glMatrixMode(GL_MODELVIEW); SetVisualScene (Togl_Interp(togl)); - vs->DrawScene(); + visual_scene->DrawScene(); Set_OpenGLText_Callback (&MyOpenGLText_GUI); return TCL_OK; } @@ -2069,7 +2070,7 @@ namespace netgen glPushMatrix(); glLoadIdentity(); - vs->DrawScene(); + visual_scene->DrawScene(); Togl_SwapBuffers(togl); glPopMatrix(); @@ -2290,7 +2291,7 @@ namespace netgen newy = atoi (argv[4]); SetVisualScene(interp); - vs->MouseMove (oldx, oldy, newx, newy, argv[5][0]); + visual_scene->MouseMove (oldx, oldy, newx, newy, argv[5][0]); return TCL_OK; } @@ -2304,7 +2305,7 @@ namespace netgen int py = Togl_PixelScale(togl)*atoi (argv[2]); SetVisualScene(interp); - vs->MouseDblClick (px, py); + visual_scene->MouseDblClick (px, py); return TCL_OK; } @@ -2315,7 +2316,7 @@ namespace netgen int argc, tcl_const char *argv[]) { SetVisualScene(interp); - vs->BuildScene (1); + visual_scene->BuildScene (1); return TCL_OK; } @@ -2326,7 +2327,7 @@ namespace netgen int argc, tcl_const char *argv[]) { SetVisualScene(interp); - vs->BuildScene (2); + visual_scene->BuildScene (2); return TCL_OK; } @@ -2337,7 +2338,7 @@ namespace netgen int argc, tcl_const char *argv[]) { SetVisualScene(interp); - vs->StandardRotation (argv[1]); + visual_scene->StandardRotation (argv[1]); return TCL_OK; } @@ -2356,7 +2357,7 @@ namespace netgen vec.Append(Vec3d(atof(argv[i+1]),atof(argv[i+2]),atof(argv[i+3]))); } - vs->ArbitraryRotation (alpha,vec); + visual_scene->ArbitraryRotation (alpha,vec); return TCL_OK; } diff --git a/python/__init__.py b/python/__init__.py index e74d1a49..0981769c 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -11,3 +11,14 @@ del sys del os from . import libngpy + +def Redraw(*args, **kwargs): + if libngpy.meshvis._Redraw(*args, **kwargs): + try: + import netgen + import tkinter + cnt = 0 + while(netgen.gui.win.tk.dooneevent(tkinter._tkinter.DONT_WAIT) and cnt < 100): + cnt += 1 + except: + pass diff --git a/python/gui.py b/python/gui.py index 959b2fd3..7f317144 100644 --- a/python/gui.py +++ b/python/gui.py @@ -24,3 +24,15 @@ if not netgen.libngpy._meshing._netgen_executable_started: StartGUI() except: pass + +def Snapshot(w,h, filename=None): + netgen.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