diff --git a/CMakeLists.txt b/CMakeLists.txt index 88ad875c1..77dc97b95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ cmake_policy(SET CMP0054 NEW) # don't implicitly dereference inside if() # Backend set(POLYSCOPE_BACKEND_OPENGL3_GLFW "ON" CACHE BOOL "Enable openGL3_glfw backend") set(POLYSCOPE_BACKEND_OPENGL_MOCK "ON" CACHE BOOL "Enable openGL_mock backend") +set(POLYSCOPE_BACKEND_OPENGL3_EGL "AUTO" CACHE STRING "Enable openGL3_egl backend") # 'AUTO' means "if we're on linux and EGL.h is available" ### Do anything needed for dependencies and bring their stuff in to scope add_subdirectory(deps) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index 34bf039c4..ac3b19b2b 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -439,7 +439,9 @@ class ShaderProgram { class Engine { public: - // Options + + Engine(); + virtual ~Engine(); // High-level control virtual void checkError(bool fatal = false) = 0; @@ -505,13 +507,16 @@ class Engine { virtual std::string getClipboardText() = 0; virtual void setClipboardText(std::string text) = 0; - // ImGui + // === ImGui + + // NOTE: the imgui backend depends on the window manager (e.g. GLFW), so these must be implemented by the lowest-level concrete engine implementation virtual void initializeImGui() = 0; virtual void shutdownImGui() = 0; - void setImGuiStyle(); - ImFontAtlas* getImGuiGlobalFontAtlas(); virtual void ImGuiNewFrame() = 0; virtual void ImGuiRender() = 0; + + void setImGuiStyle(); + ImFontAtlas* getImGuiGlobalFontAtlas(); virtual void showTextureInImGuiWindow(std::string windowName, TextureBuffer* buffer); diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index eb09de71e..ba57b9bd1 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -6,36 +6,27 @@ #include "polyscope/render/engine.h" #include "polyscope/utilities.h" +#include + +// Note: DO NOT include this header throughout polyscope, and do not directly make openGL calls. This header should only +// be used to construct an instance of Engine. engine.h gives the render API, all render calls should pass through that. + #ifdef __APPLE__ +// this means this file can only compile openGL on apple if we are also using glfw, but that's fine, because we only +// ever use the two together on apple #define GLFW_INCLUDE_GLCOREARB #include "GLFW/glfw3.h" #else #include "glad/glad.h" -// glad must come first -#include "GLFW/glfw3.h" #endif #ifdef _WIN32 #undef APIENTRY -#define GLFW_EXPOSE_NATIVE_WIN32 -#define GLFW_EXPOSE_NATIVE_WGL -#include #endif -#include "imgui.h" -#define IMGUI_IMPL_OPENGL_LOADER_GLAD -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_opengl3.h" - -#include - -// Note: DO NOT include this header throughout polyscope, and do not directly make openGL calls. This header should only -// be used to construct an instance of Engine. engine.h gives the render API, all render calls should pass through that. - - namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // Some very nice typdefs typedef GLuint TextureBufferHandle; @@ -377,12 +368,11 @@ class GLShaderProgram : public ShaderProgram { class GLEngine : public Engine { public: GLEngine(); + virtual ~GLEngine(); // High-level control - void initialize(); void checkError(bool fatal = false) override; - void swapDisplayBuffers() override; std::vector readDisplayBuffer() override; // Manage render state @@ -391,28 +381,6 @@ class GLEngine : public Engine { void setColorMask(std::array mask = {true, true, true, true}) override; void setBackfaceCull(bool newVal) override; - // === Windowing and framework things - void makeContextCurrent() override; - void focusWindow() override; - void showWindow() override; - void hideWindow() override; - void updateWindowSize(bool force = false) override; - void applyWindowSize() override; - void setWindowResizable(bool newVal) override; - bool getWindowResizable() override; - std::tuple getWindowPos() override; - bool windowRequestsClose() override; - void pollEvents() override; - bool isKeyPressed(char c) override; // for lowercase a-z and 0-9 only - int getKeyCode(char c) override; // for lowercase a-z and 0-9 only - std::string getClipboardText() override; - void setClipboardText(std::string text) override; - - // ImGui - void initializeImGui() override; - void shutdownImGui() override; - void ImGuiNewFrame() override; - void ImGuiRender() override; // === Factory methods @@ -462,9 +430,6 @@ class GLEngine : public Engine { // Helpers virtual void createSlicePlaneFliterRule(std::string name) override; - // Internal windowing and engine details - GLFWwindow* mainWindow = nullptr; - // Shader program & rule caches std::unordered_map, DrawMode>> registeredShaderPrograms; std::unordered_map registeredShaderRules; @@ -478,6 +443,6 @@ class GLEngine : public Engine { ShaderReplacementDefaults defaults); }; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/gl_engine_egl.h b/include/polyscope/render/opengl/gl_engine_egl.h new file mode 100644 index 000000000..24d93ef38 --- /dev/null +++ b/include/polyscope/render/opengl/gl_engine_egl.h @@ -0,0 +1,80 @@ +// Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run + +#pragma once + +#include "polyscope/options.h" +#include "polyscope/render/engine.h" +#include "polyscope/utilities.h" + +#ifdef __APPLE__ +#error "EGL backend is not supported on macOS. Disable it in the CMake build options." +#else +#include "glad/glad.h" +// glad must come first +#include +#endif + + +#include "imgui.h" + +#include "polyscope/render/opengl/gl_engine.h" + +#include + +// Note: DO NOT include this header throughout polyscope, and do not directly make openGL calls. This header should only +// be used to construct an instance of Engine. engine.h gives the render API, all render calls should pass through that. + + +namespace polyscope { +namespace render { +namespace backend_openGL3 { + + +class GLEngineEGL : public GLEngine { + +public: + GLEngineEGL(); + virtual ~GLEngineEGL(); + + // High-level control + void initialize(); + void swapDisplayBuffers() override; + void checkError(bool fatal = false) override; + + // === Windowing and framework things + + void makeContextCurrent() override; + void pollEvents() override; + + void focusWindow() override; + void showWindow() override; + void hideWindow() override; + void updateWindowSize(bool force = false) override; + void applyWindowSize() override; + void setWindowResizable(bool newVal) override; + bool getWindowResizable() override; + std::tuple getWindowPos() override; + bool windowRequestsClose() override; + + bool isKeyPressed(char c) override; // for lowercase a-z and 0-9 only + int getKeyCode(char c) override; // for lowercase a-z and 0-9 only + std::string getClipboardText() override; + void setClipboardText(std::string text) override; + + + // === ImGui + + void initializeImGui() override; + void shutdownImGui() override; + void ImGuiNewFrame() override; + void ImGuiRender() override; + +protected: + // Internal windowing and engine details + EGLDisplay eglDisplay; + EGLContext eglContext; +}; + +} // namespace backend_openGL3 +} // namespace render +} // namespace polyscope diff --git a/include/polyscope/render/opengl/gl_engine_glfw.h b/include/polyscope/render/opengl/gl_engine_glfw.h new file mode 100644 index 000000000..59cc24bb7 --- /dev/null +++ b/include/polyscope/render/opengl/gl_engine_glfw.h @@ -0,0 +1,91 @@ +// Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run + +#pragma once + +#include "polyscope/options.h" +#include "polyscope/render/engine.h" +#include "polyscope/utilities.h" + +#ifdef __APPLE__ +#define GLFW_INCLUDE_GLCOREARB +#include "GLFW/glfw3.h" +#else +#include "glad/glad.h" +// glad must come first +#include "GLFW/glfw3.h" +#endif + +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif + +#include "imgui.h" +#define IMGUI_IMPL_OPENGL_LOADER_GLAD +#include "backends/imgui_impl_glfw.h" +#include "backends/imgui_impl_opengl3.h" + +#include "polyscope/render/opengl/gl_engine.h" + +#include + +// Note: DO NOT include this header throughout polyscope, and do not directly make openGL calls. This header should only +// be used to construct an instance of Engine. engine.h gives the render API, all render calls should pass through that. + + +namespace polyscope { +namespace render { +namespace backend_openGL3 { + + +class GLEngineGLFW : public GLEngine { + +public: + + GLEngineGLFW(); + virtual ~GLEngineGLFW(); + + // High-level control + void initialize(); + void swapDisplayBuffers() override; + + // === Windowing and framework things + + void makeContextCurrent() override; + void pollEvents() override; + + void focusWindow() override; + void showWindow() override; + void hideWindow() override; + void updateWindowSize(bool force = false) override; + void applyWindowSize() override; + void setWindowResizable(bool newVal) override; + bool getWindowResizable() override; + std::tuple getWindowPos() override; + bool windowRequestsClose() override; + + bool isKeyPressed(char c) override; // for lowercase a-z and 0-9 only + int getKeyCode(char c) override; // for lowercase a-z and 0-9 only + std::string getClipboardText() override; + void setClipboardText(std::string text) override; + + + // === ImGui + + void initializeImGui() override; + void shutdownImGui() override; + void ImGuiNewFrame() override; + void ImGuiRender() override; + +protected: + + // Internal windowing and engine details + GLFWwindow* mainWindow = nullptr; + +}; + +} // namespace backend_openGL3 +} // namespace render +} // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/common.h b/include/polyscope/render/opengl/shaders/common.h index 6c6f5372f..4d2bcd8ac 100644 --- a/include/polyscope/render/opengl/shaders/common.h +++ b/include/polyscope/render/opengl/shaders/common.h @@ -8,10 +8,10 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { extern const char* shaderCommonSource; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/cylinder_shaders.h b/include/polyscope/render/opengl/shaders/cylinder_shaders.h index 3802dab5b..ce63d6381 100644 --- a/include/polyscope/render/opengl/shaders/cylinder_shaders.h +++ b/include/polyscope/render/opengl/shaders/cylinder_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification FLEX_CYLINDER_VERT_SHADER; @@ -23,6 +23,6 @@ extern const ShaderReplacementRule CYLINDER_CULLPOS_FROM_MID; extern const ShaderReplacementRule CYLINDER_VARIABLE_SIZE; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/gizmo_shaders.h b/include/polyscope/render/opengl/shaders/gizmo_shaders.h index bd121e481..9015a18d1 100644 --- a/include/polyscope/render/opengl/shaders/gizmo_shaders.h +++ b/include/polyscope/render/opengl/shaders/gizmo_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // Stages extern const ShaderStageSpecification TRANSFORMATION_GIZMO_ROT_VERT; @@ -17,6 +17,6 @@ extern const ShaderStageSpecification SLICE_PLANE_FRAG_SHADER; // Rules extern const ShaderReplacementRule TRANSFORMATION_GIZMO_VEC; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/grid_shaders.h b/include/polyscope/render/opengl/shaders/grid_shaders.h index 1c887769b..225891c20 100644 --- a/include/polyscope/render/opengl/shaders/grid_shaders.h +++ b/include/polyscope/render/opengl/shaders/grid_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification FLEX_GRIDCUBE_VERT_SHADER; @@ -24,6 +24,6 @@ extern const ShaderReplacementRule GRIDCUBE_CONSTANT_PICK; extern const ShaderReplacementRule GRIDCUBE_CULLPOS_FROM_CENTER; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/ground_plane_shaders.h b/include/polyscope/render/opengl/shaders/ground_plane_shaders.h index 0fe1163f9..019d33213 100644 --- a/include/polyscope/render/opengl/shaders/ground_plane_shaders.h +++ b/include/polyscope/render/opengl/shaders/ground_plane_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { extern const ShaderStageSpecification GROUND_PLANE_VERT_SHADER; extern const ShaderStageSpecification GROUND_PLANE_TILE_FRAG_SHADER; @@ -16,6 +16,6 @@ extern const ShaderStageSpecification GROUND_PLANE_SHADOW_FRAG_SHADER; // Rules // extern const ShaderReplacementRule RULE_NAME; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/histogram_shaders.h b/include/polyscope/render/opengl/shaders/histogram_shaders.h index 00b4c79ac..9f5403e5f 100644 --- a/include/polyscope/render/opengl/shaders/histogram_shaders.h +++ b/include/polyscope/render/opengl/shaders/histogram_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification HISTOGRAM_VERT_SHADER; @@ -15,6 +15,6 @@ extern const ShaderStageSpecification HISTOGRAM_FRAG_SHADER; // Rules // extern const ShaderReplacementRule RULE_NAME; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/lighting_shaders.h b/include/polyscope/render/opengl/shaders/lighting_shaders.h index 4323fe32f..9122bb3cb 100644 --- a/include/polyscope/render/opengl/shaders/lighting_shaders.h +++ b/include/polyscope/render/opengl/shaders/lighting_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification MAP_LIGHT_FRAG_SHADER; @@ -24,6 +24,6 @@ extern const ShaderReplacementRule TRANSPARENCY_STRUCTURE; extern const ShaderReplacementRule TRANSPARENCY_PEEL_STRUCTURE; extern const ShaderReplacementRule TRANSPARENCY_PEEL_GROUND; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/ribbon_shaders.h b/include/polyscope/render/opengl/shaders/ribbon_shaders.h index 558e298f8..c97ff5ca0 100644 --- a/include/polyscope/render/opengl/shaders/ribbon_shaders.h +++ b/include/polyscope/render/opengl/shaders/ribbon_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification RIBBON_VERT_SHADER; @@ -16,6 +16,6 @@ extern const ShaderStageSpecification RIBBON_FRAG_SHADER; // Rules // extern const ShaderReplacementRule RULE_NAME; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/rules.h b/include/polyscope/render/opengl/shaders/rules.h index 1fe39694d..1e24766df 100644 --- a/include/polyscope/render/opengl/shaders/rules.h +++ b/include/polyscope/render/opengl/shaders/rules.h @@ -8,7 +8,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { extern const ShaderReplacementRule GLSL_VERSION; extern const ShaderReplacementRule GLOBAL_FRAGMENT_FILTER; @@ -44,6 +44,6 @@ ShaderReplacementRule generateVolumeGridSlicePlaneRule(std::string uniquePostfix // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/sphere_shaders.h b/include/polyscope/render/opengl/shaders/sphere_shaders.h index a5a10ee64..a447e2e6a 100644 --- a/include/polyscope/render/opengl/shaders/sphere_shaders.h +++ b/include/polyscope/render/opengl/shaders/sphere_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification FLEX_SPHERE_VERT_SHADER; @@ -26,6 +26,6 @@ extern const ShaderReplacementRule SPHERE_CULLPOS_FROM_CENTER; extern const ShaderReplacementRule SPHERE_CULLPOS_FROM_CENTER_QUAD; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/surface_mesh_shaders.h b/include/polyscope/render/opengl/shaders/surface_mesh_shaders.h index a3e64bfbc..34a87ca5e 100644 --- a/include/polyscope/render/opengl/shaders/surface_mesh_shaders.h +++ b/include/polyscope/render/opengl/shaders/surface_mesh_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification FLEX_MESH_VERT_SHADER; @@ -36,6 +36,6 @@ extern const ShaderReplacementRule MESH_PROPAGATE_PICK_SIMPLE; extern const ShaderReplacementRule MESH_PROPAGATE_TYPE_AND_BASECOLOR2_SHADE; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/texture_draw_shaders.h b/include/polyscope/render/opengl/shaders/texture_draw_shaders.h index c9fe9060c..b156d4d8a 100644 --- a/include/polyscope/render/opengl/shaders/texture_draw_shaders.h +++ b/include/polyscope/render/opengl/shaders/texture_draw_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { extern const ShaderStageSpecification TEXTURE_DRAW_VERT_SHADER; extern const ShaderStageSpecification TEXTURE_DRAW_UPPERLEFT_VERT_SHADER; @@ -50,6 +50,6 @@ extern const ShaderReplacementRule SHADE_NORMAL_FROM_VIEWPOS_VAR; extern const ShaderStageSpecification TEXTURE_DRAW_VERT_SHADER; extern const ShaderStageSpecification SPHEREBG_DRAW_VERT_SHADER; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/vector_shaders.h b/include/polyscope/render/opengl/shaders/vector_shaders.h index 0c5d1e153..80e95fc2d 100644 --- a/include/polyscope/render/opengl/shaders/vector_shaders.h +++ b/include/polyscope/render/opengl/shaders/vector_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification FLEX_VECTOR_VERT_SHADER; @@ -18,6 +18,6 @@ extern const ShaderStageSpecification FLEX_VECTOR_FRAG_SHADER; extern const ShaderReplacementRule VECTOR_PROPAGATE_COLOR; extern const ShaderReplacementRule VECTOR_CULLPOS_FROM_TAIL; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/shaders/volume_mesh_shaders.h b/include/polyscope/render/opengl/shaders/volume_mesh_shaders.h index c093845c6..d07256347 100644 --- a/include/polyscope/render/opengl/shaders/volume_mesh_shaders.h +++ b/include/polyscope/render/opengl/shaders/volume_mesh_shaders.h @@ -6,7 +6,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // High level pipeline extern const ShaderStageSpecification SLICE_TETS_VERT_SHADER; @@ -19,6 +19,6 @@ extern const ShaderReplacementRule SLICE_TETS_PROPAGATE_VECTOR; extern const ShaderReplacementRule SLICE_TETS_VECTOR_COLOR; -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 76477c5d9..9d03d9675 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,21 +5,23 @@ endif() SET(INCLUDE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../include/polyscope/") +# We need the shared openGL backend if either of these backends are enabled +if(POLYSCOPE_BACKEND_OPENGL3_GLFW OR POLYSCOPE_BACKEND_OPENGL3_EGL) + SET(POLYSCOPE_BACKEND_OPENGL3 TRUE) + add_definitions(-DPOLYSCOPE_BACKEND_OPENGL3_ENABLED) +else() + SET(POLYSCOPE_BACKEND_OPENGL3 FALSE) +endif() + # Lists that will be populated for the render backend # Add the main _engine file no matter what. All of the interesting parts are ifdef'd out, and this # allows us to resolve stubs. list (APPEND BACKEND_SRCS render/opengl/gl_engine.cpp + render/opengl/gl_engine_glfw.cpp + render/opengl/gl_engine_egl.cpp render/mock_opengl/mock_gl_engine.cpp -) - -# Configure the render backend -if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") - message("Polyscope backend openGL3_glfw enabled") - - list (APPEND BACKEND_SRCS - render/opengl/gl_engine.cpp render/opengl/shaders/texture_draw_shaders.cpp render/opengl/shaders/lighting_shaders.cpp render/opengl/shaders/grid_shaders.cpp @@ -34,10 +36,14 @@ if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") render/opengl/shaders/cylinder_shaders.cpp render/opengl/shaders/rules.cpp render/opengl/shaders/common.cpp - ) +) + +# Configure the render backend(s) +if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") + message("Polyscope backend openGL3_glfw enabled") list(APPEND BACKEND_HEADERS - ${INCLUDE_ROOT}render/opengl/gl_engine.h + ${INCLUDE_ROOT}render/opengl/gl_engine_glfw.h ${INCLUDE_ROOT}render/opengl/shaders/common.h ) @@ -69,37 +75,77 @@ if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") add_definitions(-DPOLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED) endif() -if("${POLYSCOPE_BACKEND_OPENGL_MOCK}") - message("Polyscope backend openGL_mock enabled") +## some logic to decide whether or not EGL is available and whether we want to build with it +include(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX("EGL/egl.h" HAVE_EGL_LIB) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(IS_LINUX TRUE) +else() + set(IS_LINUX FALSE) +endif() - list (APPEND BACKEND_SRCS - render/mock_opengl/mock_gl_engine.cpp - render/opengl/shaders/texture_draw_shaders.cpp - render/opengl/shaders/lighting_shaders.cpp - render/opengl/shaders/grid_shaders.cpp - render/opengl/shaders/ground_plane_shaders.cpp - render/opengl/shaders/gizmo_shaders.cpp - render/opengl/shaders/histogram_shaders.cpp - render/opengl/shaders/surface_mesh_shaders.cpp - render/opengl/shaders/volume_mesh_shaders.cpp - render/opengl/shaders/vector_shaders.cpp - render/opengl/shaders/sphere_shaders.cpp - render/opengl/shaders/ribbon_shaders.cpp - render/opengl/shaders/cylinder_shaders.cpp - render/opengl/shaders/rules.cpp - render/opengl/shaders/common.cpp - ) +if(POLYSCOPE_BACKEND_OPENGL3_EGL STREQUAL "AUTO") + if(IS_LINUX AND HAVE_EGL_LIB) # "AUTO" policy: only enable if we're on linux and EGL libs seem to be present + set(POLYSCOPE_BACKEND_OPENGL3_EGL ON) + else() + set(POLYSCOPE_BACKEND_OPENGL3_EGL OFF) + endif() +elseif(POLYSCOPE_BACKEND_OPENGL3_EGL) # if "TRUE" (or "ON" or "YES" etc etc) + # sanity check that we can actually use the EGL backend + if(NOT IS_LINUX) + message(FATAL_ERROR "EGL backend is only supported on linux. Disable it with POLYSCOPE_BACKEND_OPENGL3_EGL=False") + endif() + if(NOT HAVE_EGL_LIB) + message(FATAL_ERROR "EGL backend requires EGL headers, but 'EGL/egl.h' was not found. On Ubuntu, try 'apt-get install libegl1-mesa-dev'") + endif() + + # we should be good-to-go for EGL + +else() + # nothing to do, already disabled +endif() + + + + +if("${POLYSCOPE_BACKEND_OPENGL3_EGL}") + message("Polyscope backend openGL3_egl enabled") + + # this only supports headless rendering, and as of Mar 2024 headless rendering seems to only be available on nvidia drivers. list(APPEND BACKEND_HEADERS - ${INCLUDE_ROOT}render/mock_opengl/mock_gl_engine.h + ${INCLUDE_ROOT}render/opengl/gl_engine_egl.h ${INCLUDE_ROOT}render/opengl/shaders/common.h ) - # Link settings - list(APPEND BACKEND_LIBS + if(APPLE) + message(FATAL_ERROR "Compiling EGL backed on APPLE is not supported. Set POLYSCOPE_BACKEND_OPENGL3_EGL=False") + else() + + # On Windows/Linux, use the glad openGL loader + list(APPEND BACKEND_LIBS glad) + + if(WIN32) + message(FATAL_ERROR "Compiling EGL backed on Windows is not supported. Set POLYSCOPE_BACKEND_OPENGL3_EGL=False") + else() # linux + # only linux is actually supported for EGL + list(APPEND BACKEND_LIBS EGL) + endif() + + endif() + + add_definitions(-DPOLYSCOPE_BACKEND_OPENGL3_EGL_ENABLED) +endif() + +if("${POLYSCOPE_BACKEND_OPENGL_MOCK}") + message("Polyscope backend openGL_mock enabled") + + list(APPEND BACKEND_HEADERS + ${INCLUDE_ROOT}render/mock_opengl/mock_gl_engine.h + ${INCLUDE_ROOT}render/opengl/shaders/common.h ) -add_definitions(-DPOLYSCOPE_BACKEND_OPENGL_MOCK_ENABLED) + add_definitions(-DPOLYSCOPE_BACKEND_OPENGL_MOCK_ENABLED) endif() diff --git a/src/render/engine.cpp b/src/render/engine.cpp index a2f5d4ed1..1fd11b5d6 100644 --- a/src/render/engine.cpp +++ b/src/render/engine.cpp @@ -270,6 +270,10 @@ ShaderProgram::ShaderProgram(DrawMode dm) : drawMode(dm), uniqueID(render::engin } } + +Engine::Engine() {} +Engine::~Engine() {} + void Engine::buildEngineGui() { ImGui::SetNextItemOpen(false, ImGuiCond_FirstUseEver); diff --git a/src/render/initialize_backend.cpp b/src/render/initialize_backend.cpp index a8bc03c8e..b90557fef 100644 --- a/src/render/initialize_backend.cpp +++ b/src/render/initialize_backend.cpp @@ -1,8 +1,11 @@ // Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run #include "polyscope/messages.h" +#include "polyscope/options.h" #include "polyscope/render/engine.h" +#include + namespace polyscope { namespace render { @@ -14,41 +17,79 @@ std::string engineBackendName = ""; // Forward-declaration of initialize routines // we don't want to just include the appropriate headers, because they may define conflicting symbols -namespace backend_openGL3_glfw { -void initializeRenderEngine(); -} +namespace backend_openGL3 { +void initializeRenderEngine_glfw(); +void initializeRenderEngine_egl(); +} // namespace backend_openGL3 namespace backend_openGL_mock { void initializeRenderEngine(); } -// void initializeRenderEngine_openGL_mock(); void initializeRenderEngine(std::string backend) { // Handle default backends - // (the string is getting overwritten, so lower on the list means higher priority) if (backend == "") { + backend = "auto"; // treat "" as "auto" + } -#ifdef POLYSCOPE_BACKEND_OPENGL_MOCK_ENABLED - // Don't set it one by default, since it's probably a mistake; better to throw the exception below. - // backend = "mock_openGL"; -#endif + engineBackendName = backend; + + // Initialize the appropriate backend + if (backend == "openGL3_glfw") { + backend_openGL3::initializeRenderEngine_glfw(); + } else if (backend == "openGL3_egl") { + backend_openGL3::initializeRenderEngine_egl(); + } else if (backend == "openGL_mock") { + backend_openGL_mock::initializeRenderEngine(); + } else if (backend == "auto") { + + // Attempt to automatically initialize by trynig + + bool initSucces = false; #ifdef POLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED + // First try GLFW, if available backend = "openGL3_glfw"; + try { + backend_openGL3::initializeRenderEngine_glfw(); + initSucces = true; + } catch (const std::exception& e) { + if (options::verbosity > 0) { + info("Attempting automatic initialization. Could not initialize backend [openGL3_glfw]. Message: " + + std::string(e.what())); + } + } + if (initSucces) return; #endif - if (backend == "") { - exception("no Polyscope backends available"); +#ifdef POLYSCOPE_BACKEND_OPENGL3_EGL_ENABLED + // Then, try EGL if available + backend = "openGL3_egl"; + try { + backend_openGL3::initializeRenderEngine_egl(); + initSucces = true; + } catch (const std::exception& e) { + if (options::verbosity > 0) { + info("Attempting automatic initialization. Could not initialize backend [openGL3_egl]. Message: " + + std::string(e.what())); + } } - } + if (initSucces) { + if (options::verbosity > 0) { + info("Automatic initialization could not create an interactive backend, and created a headless backend " + "instead. This likely means no displays are available. With the headless backend, you can still run " + "Polyscope and even render, for instance to record screenshots. However no interactive windows can be " + "created."); + } + return; + } +#endif - engineBackendName = backend; + // Don't bother trying the 'mock' backend, it is unlikely to be what the user wants from the 'auto' option + + // Failure + exception("Automatic initialization: no Polyscope backends could be initialized successfully."); - // Initialize the appropriate backend - if (backend == "openGL3_glfw") { - backend_openGL3_glfw::initializeRenderEngine(); - } else if (backend == "openGL_mock") { - backend_openGL_mock::initializeRenderEngine(); } else { exception("unrecognized Polyscope backend " + backend); } diff --git a/src/render/mock_opengl/mock_gl_engine.cpp b/src/render/mock_opengl/mock_gl_engine.cpp index ab008783b..5d3626040 100644 --- a/src/render/mock_opengl/mock_gl_engine.cpp +++ b/src/render/mock_opengl/mock_gl_engine.cpp @@ -1883,7 +1883,7 @@ void MockGLEngine::registerShaderRule(const std::string& name, const ShaderRepla void MockGLEngine::populateDefaultShadersAndRules() { - using namespace backend_openGL3_glfw; + using namespace backend_openGL3; // WARNING: duplicated from gl_engine.cpp @@ -2032,7 +2032,7 @@ void MockGLEngine::populateDefaultShadersAndRules() { void MockGLEngine::createSlicePlaneFliterRule(std::string uniquePostfix) { - using namespace backend_openGL3_glfw; + using namespace backend_openGL3; registeredShaderRules.insert({"SLICE_PLANE_CULL_" + uniquePostfix, generateSlicePlaneRule(uniquePostfix)}); registeredShaderRules.insert( {"SLICE_PLANE_VOLUMEGRID_CULL_" + uniquePostfix, generateVolumeGridSlicePlaneRule(uniquePostfix)}); diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index 044b907cd..f493ca19f 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -1,9 +1,8 @@ // Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run -#include "backends/imgui_impl_opengl3.h" #include "polyscope/render/engine.h" -#ifdef POLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED +#ifdef POLYSCOPE_BACKEND_OPENGL3_ENABLED #include "polyscope/render/opengl/gl_engine.h" #include "polyscope/messages.h" @@ -37,17 +36,10 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { GLEngine* glEngine = nullptr; // alias for global engine pointer -void initializeRenderEngine() { - glEngine = new GLEngine(); - engine = glEngine; - glEngine->initialize(); - engine->allocateGlobalBuffersAndPrograms(); -} - // == Map enums to native values // clang-format off @@ -169,11 +161,14 @@ void checkGLError(bool fatal = true) { case GL_INVALID_OPERATION: errText = "Invalid operation"; break; - // case GL_STACK_OVERFLOW: std::cerr << "Stack overflow"; break; - // case GL_STACK_UNDERFLOW: std::cerr << "Stack underflow"; break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + errText = "Invalid framebuffer operation"; + break; case GL_OUT_OF_MEMORY: errText = "Out of memory"; break; + // case GL_STACK_OVERFLOW: std::cerr << "Stack overflow"; break; + // case GL_STACK_UNDERFLOW: std::cerr << "Stack underflow"; break; default: errText = "Unknown error " + std::to_string(static_cast(err)); } @@ -2114,101 +2109,9 @@ void GLShaderProgram::draw() { } GLEngine::GLEngine() {} +GLEngine::~GLEngine() {} -void GLEngine::initialize() { - // Small callback function for GLFW errors - auto error_print_callback = [](int error, const char* description) { - if (polyscope::options::verbosity > 0) { - std::cout << "GLFW emitted error: " << description << std::endl; - } - }; - - // === Initialize glfw - glfwSetErrorCallback(error_print_callback); - if (!glfwInit()) { - exception(options::printPrefix + "ERROR: Failed to initialize glfw"); - } - - // OpenGL version things - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#if __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - - // Create the window with context - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); - glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE); - mainWindow = glfwCreateWindow(view::windowWidth, view::windowHeight, options::programName.c_str(), NULL, NULL); - glfwMakeContextCurrent(mainWindow); - glfwSetWindowPos(mainWindow, view::initWindowPosX, view::initWindowPosY); - - // Set initial window size - int newBufferWidth, newBufferHeight, newWindowWidth, newWindowHeight; - glfwGetFramebufferSize(mainWindow, &newBufferWidth, &newBufferHeight); - glfwGetWindowSize(mainWindow, &newWindowWidth, &newWindowHeight); - view::bufferWidth = newBufferWidth; - view::bufferHeight = newBufferHeight; - view::windowWidth = newWindowWidth; - view::windowHeight = newWindowHeight; - - setWindowResizable(view::windowResizable); - -// === Initialize openGL -// Load openGL functions (using GLAD) -#ifndef __APPLE__ - if (!gladLoadGL()) { - exception(options::printPrefix + "ERROR: Failed to load openGL using GLAD"); - } -#endif - if (options::verbosity > 0) { - std::cout << options::printPrefix << "Backend: openGL3_glfw -- " - << "Loaded openGL version: " << glGetString(GL_VERSION) << std::endl; - } - -#ifdef __APPLE__ - // Hack to classify the process as interactive - glfwPollEvents(); -#endif - - { // Manually create the screen frame buffer - GLFrameBuffer* glScreenBuffer = new GLFrameBuffer(view::bufferWidth, view::bufferHeight, true); - displayBuffer.reset(glScreenBuffer); - glScreenBuffer->bind(); - glClearColor(1., 1., 1., 0.); - // glClearColor(0., 0., 0., 0.); - // glClearDepth(1.); - } - - populateDefaultShadersAndRules(); -} - - -void GLEngine::initializeImGui() { - bindDisplay(); - - ImGui::CreateContext(); // must call once at start - - // Set up ImGUI glfw bindings - ImGui_ImplGlfw_InitForOpenGL(mainWindow, true); - const char* glsl_version = "#version 150"; - ImGui_ImplOpenGL3_Init(glsl_version); - - configureImGui(); -} - -void GLEngine::shutdownImGui() { - // ImGui shutdown things - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); -} - -void GLEngine::swapDisplayBuffers() { - bindDisplay(); - glfwSwapBuffers(mainWindow); -} +void GLEngine::checkError(bool fatal) { checkGLError(fatal); } std::vector GLEngine::readDisplayBuffer() { // TODO do we need to bind here? @@ -2231,111 +2134,6 @@ std::vector GLEngine::readDisplayBuffer() { } -void GLEngine::checkError(bool fatal) { checkGLError(fatal); } - -void GLEngine::makeContextCurrent() { - glfwMakeContextCurrent(mainWindow); - glfwSwapInterval(options::enableVSync ? 1 : 0); -} - -void GLEngine::focusWindow() { glfwFocusWindow(mainWindow); } - -void GLEngine::showWindow() { glfwShowWindow(mainWindow); } - -void GLEngine::hideWindow() { - glfwHideWindow(mainWindow); - glfwPollEvents(); // this shouldn't be necessary, but seems to be needed at least on macOS. Perhaps realted to a - // glfw bug? e.g. https://github.com/glfw/glfw/issues/1300 and related bugs -} - -void GLEngine::updateWindowSize(bool force) { - int newBufferWidth, newBufferHeight, newWindowWidth, newWindowHeight; - glfwGetFramebufferSize(mainWindow, &newBufferWidth, &newBufferHeight); - glfwGetWindowSize(mainWindow, &newWindowWidth, &newWindowHeight); - if (force || newBufferWidth != view::bufferWidth || newBufferHeight != view::bufferHeight || - newWindowHeight != view::windowHeight || newWindowWidth != view::windowWidth) { - // Basically a resize callback - requestRedraw(); - - // prevent any division by zero for e.g. aspect ratio calcs - if (newBufferHeight == 0) newBufferHeight = 1; - if (newWindowHeight == 0) newWindowHeight = 1; - - view::bufferWidth = newBufferWidth; - view::bufferHeight = newBufferHeight; - view::windowWidth = newWindowWidth; - view::windowHeight = newWindowHeight; - - render::engine->resizeScreenBuffers(); - render::engine->setScreenBufferViewports(); - } -} - - -void GLEngine::applyWindowSize() { - glfwSetWindowSize(mainWindow, view::windowWidth, view::windowHeight); - - // on some platform size changes are asynchonous, need to ensure it completes - // we don't want to just retry until the resize has happened, because it could be impossible - // TODO it seems like on X11 sometimes even this isn't enough? - glfwWaitEvents(); - - updateWindowSize(true); -} - - -void GLEngine::setWindowResizable(bool newVal) { - glfwSetWindowAttrib(mainWindow, GLFW_RESIZABLE, newVal ? GLFW_TRUE : GLFW_FALSE); -} - -bool GLEngine::getWindowResizable() { return glfwGetWindowAttrib(mainWindow, GLFW_RESIZABLE); } - -std::tuple GLEngine::getWindowPos() { - int x, y; - glfwGetWindowPos(mainWindow, &x, &y); - return std::tuple{x, y}; -} - -bool GLEngine::windowRequestsClose() { - bool shouldClose = glfwWindowShouldClose(mainWindow); - if (shouldClose) { - glfwSetWindowShouldClose(mainWindow, false); // un-set the state bit so we can close again - return true; - } - return false; -} - -void GLEngine::pollEvents() { glfwPollEvents(); } - -bool GLEngine::isKeyPressed(char c) { - if (c >= '0' && c <= '9') return ImGui::IsKeyPressed(static_cast(ImGuiKey_0 + (c - '0'))); - if (c >= 'a' && c <= 'z') return ImGui::IsKeyPressed(static_cast(ImGuiKey_A + (c - 'a'))); - if (c >= 'A' && c <= 'Z') return ImGui::IsKeyPressed(static_cast(ImGuiKey_A + (c - 'A'))); - exception("keyPressed only supports 0-9, a-z, A-Z"); - return false; -} - -int GLEngine::getKeyCode(char c) { - if (c >= '0' && c <= '9') return static_cast(ImGuiKey_0) + (c - '0'); - if (c >= 'a' && c <= 'z') return static_cast(ImGuiKey_A) + (c - 'a'); - if (c >= 'A' && c <= 'Z') return static_cast(ImGuiKey_A) + (c - 'A'); - exception("getKeyCode only supports 0-9, a-z, A-Z"); - return -1; -} - -void GLEngine::ImGuiNewFrame() { - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // ImGui::ShowDemoWindow(); -} - -void GLEngine::ImGuiRender() { - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); -} - void GLEngine::setDepthMode(DepthMode newMode) { switch (newMode) { case DepthMode::Less: @@ -2418,13 +2216,6 @@ void GLEngine::setBackfaceCull(bool newVal) { } } -std::string GLEngine::getClipboardText() { - std::string clipboardData = ImGui::GetClipboardText(); - return clipboardData; -} - -void GLEngine::setClipboardText(std::string text) { ImGui::SetClipboardText(text.c_str()); } - void GLEngine::applyTransparencySettings() { // Remove any old transparency-related rules switch (transparencyMode) { @@ -2805,22 +2596,8 @@ void GLEngine::createSlicePlaneFliterRule(std::string uniquePostfix) { } -} // namespace backend_openGL3_glfw -} // namespace render -} // namespace polyscope - -#else - -#include - -#include "polyscope/messages.h" - -namespace polyscope { -namespace render { -namespace backend_openGL3_glfw { -void initializeRenderEngine() { exception("Polyscope was not compiled with support for backend: openGL3_glfw"); } -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope -#endif +#endif // POLYSCOPE_BACKEND_OPENGL_ENABLED diff --git a/src/render/opengl/gl_engine_egl.cpp b/src/render/opengl/gl_engine_egl.cpp new file mode 100644 index 000000000..76a957a01 --- /dev/null +++ b/src/render/opengl/gl_engine_egl.cpp @@ -0,0 +1,357 @@ +// Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run + +#ifdef POLYSCOPE_BACKEND_OPENGL3_EGL_ENABLED + +#include "polyscope/polyscope.h" + +#include "polyscope/render/opengl/gl_engine_egl.h" + +#include "backends/imgui_impl_opengl3.h" +#include "polyscope/render/engine.h" + +#include "stb_image.h" + +#include +#include + +namespace polyscope { +namespace render { +namespace backend_openGL3 { + +GLEngineEGL* glEngineEGL = nullptr; // alias for global engine pointer +extern GLEngine* glEngine; // defined in gl_engine.h + +namespace { // anonymous helpers + +void checkEGLError(bool fatal = true) { + + if (!options::enableRenderErrorChecks) { + return; + } + + // Map the GL error enums to strings + EGLint err = eglGetError(); + + if (err == EGL_SUCCESS) return; + + std::string errText; + switch (err) { + + case EGL_SUCCESS: + errText = "The last function succeeded without error."; + break; + + case EGL_NOT_INITIALIZED: + errText = "EGL is not initialized, or could not be initialized, for the specified EGL display connection."; + break; + + case EGL_BAD_ACCESS: + errText = "EGL cannot access a requested resource (for example a context is bound in another thread)."; + break; + + case EGL_BAD_ALLOC: + errText = "EGL failed to allocate resources for the requested operation."; + break; + + case EGL_BAD_ATTRIBUTE: + errText = "An unrecognized attribute or attribute value was passed in the attribute list."; + break; + + case EGL_BAD_CONTEXT: + errText = "An EGLContext argument does not name a valid EGL rendering context."; + break; + + case EGL_BAD_CONFIG: + errText = "An EGLConfig argument does not name a valid EGL frame buffer configuration."; + break; + + case EGL_BAD_CURRENT_SURFACE: + errText = "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid."; + break; + + case EGL_BAD_DISPLAY: + errText = "An EGLDisplay argument does not name a valid EGL display connection."; + break; + + case EGL_BAD_SURFACE: + errText = "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL " + "rendering."; + break; + + case EGL_BAD_MATCH: + errText = + "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface)."; + break; + + case EGL_BAD_PARAMETER: + errText = "One or more argument values are invalid."; + break; + + case EGL_BAD_NATIVE_PIXMAP: + errText = "A NativePixmapType argument does not refer to a valid native pixmap."; + break; + + case EGL_BAD_NATIVE_WINDOW: + errText = "A NativeWindowType argument does not refer to a valid native window."; + break; + + case EGL_CONTEXT_LOST: + errText = "A power management event has occurred. The application must destroy all contexts and reinitialise " + "OpenGL ES state and objects to continue rendering."; + break; + + default: + errText = "Unknown error " + std::to_string(static_cast(err)); + break; + } + + if (polyscope::options::verbosity > 0) { + std::cout << polyscope::options::printPrefix << "EGL Error! Type: " << errText << std::endl; + } + if (fatal) { + exception("EGL error occurred. Text: " + errText); + } +} +} // namespace + +void initializeRenderEngine_egl() { + + glEngineEGL = new GLEngineEGL(); // create the new global engine object + + engine = glEngineEGL; // we keep a few copies of this pointer with various types + glEngine = glEngineEGL; + + // initialize + glEngineEGL->initialize(); + engine->allocateGlobalBuffersAndPrograms(); + glEngineEGL->applyWindowSize(); +} + +GLEngineEGL::GLEngineEGL() {} +GLEngineEGL::~GLEngineEGL() { + // eglTerminate(eglDisplay) // TODO handle termination +} + +void GLEngineEGL::initialize() { + + // === Initialize EGL + + // Get the default display + eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == EGL_NO_DISPLAY) { + exception("ERROR: Failed to initialize EGL, could not get default display"); + } + + // Configure + EGLint majorVer, minorVer; + bool success = eglInitialize(eglDisplay, &majorVer, &minorVer); + if (!success) { + checkEGLError(false); + exception("ERROR: Failed to initialize EGL"); + } + checkEGLError(); + + + // this has something to do with the EGL configuration, I don't understand exactly what + // clang-format off + const EGLint configAttribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, // this is important, it gets us openGL rather than openGL ES + EGL_NONE}; + // clang-format on + + + EGLint numConfigs; + EGLConfig eglCfg; + eglChooseConfig(eglDisplay, configAttribs, &eglCfg, 1, &numConfigs); + checkEGLError(); + + eglBindAPI(EGL_OPENGL_API); + checkEGLError(); + + // requested context configuration (openGL 3.3 core profile) + // clang-format off + EGLint contextAttribs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_MINOR_VERSION, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + EGL_NONE }; + // clang-format on + + eglContext = eglCreateContext(eglDisplay, eglCfg, EGL_NO_CONTEXT, contextAttribs); + checkEGLError(); + + makeContextCurrent(); + + view::bufferWidth = view::windowWidth; + view::bufferHeight = view::windowHeight; + + +// === Initialize openGL +// Load openGL functions (using GLAD) +// +// NOTE: right now this is using the same glad loader as the standard gl_engine_glfw.cpp uses, which was generated with +// the "OpenGL" specification setting rather than the "EGL" option. One would think we should use the "EGL" +// specification, however this one seems to work and that one does not. +// +#ifndef __APPLE__ + if (!gladLoadGL()) { + exception(options::printPrefix + "ERROR: Failed to load openGL using GLAD"); + } +#endif + if (options::verbosity > 0) { + std::cout << options::printPrefix << "Backend: openGL3_egl -- " + << "Loaded openGL version: " << glGetString(GL_VERSION) << " -- " + << "EGL version: " << majorVer << "." << minorVer << std::endl; + } + + { // Manually create the screen frame buffer + // NOTE: important difference here, we manually create both the framebuffer and and its render buffer, since + // headless EGL means we are not getting them from a window + displayBuffer = generateFrameBuffer(view::bufferWidth, view::bufferHeight); + displayBuffer->addColorBuffer( + generateRenderBuffer(RenderBufferType::Float4, view::bufferWidth, view::bufferHeight)); + displayBuffer->addDepthBuffer(generateRenderBuffer(RenderBufferType::Depth, view::bufferWidth, view::bufferHeight)); + displayBuffer->setDrawBuffers(); + checkError(); + + displayBuffer->bind(); + glClearColor(1., 1., 1., 0.); + + checkError(); + } + + populateDefaultShadersAndRules(); + checkError(); +} + + +void GLEngineEGL::initializeImGui() { + + // headless mode uses the "null" imgui backed, which essentially does nothing and just passes-through inputs to all + // functions + + ImGui::CreateContext(); + configureImGui(); +} + +void GLEngineEGL::shutdownImGui() { ImGui::DestroyContext(); } + +void GLEngineEGL::ImGuiNewFrame() { + + // ImGUI has an error check which fires unless we do this + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize.x = view::bufferWidth; + io.DisplaySize.y = view::bufferHeight; + + ImGui::NewFrame(); +} + +void GLEngineEGL::ImGuiRender() { ImGui::Render(); } + + +void GLEngineEGL::swapDisplayBuffers() { + // not defined in headless mode +} + +void GLEngineEGL::checkError(bool fatal) { + checkEGLError(fatal); + GLEngine::checkError(fatal); // call the parent version (checks openGL error) +} + +void GLEngineEGL::makeContextCurrent() { + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext); + checkEGLError(); +} + +void GLEngineEGL::focusWindow() { + // not defined in headless mode +} + +void GLEngineEGL::showWindow() { + // not defined in headless mode +} + +void GLEngineEGL::hideWindow() { + // not defined in headless mode +} + +void GLEngineEGL::updateWindowSize(bool force) { + // does nothing + // (this function is for updating polyscope's internal window & buffer info in response to the user resizing the + // window at the OS level, but in headless mode there is no interactable window for the user to change size of) +} + + +void GLEngineEGL::applyWindowSize() { + view::bufferWidth = view::windowWidth; + view::bufferHeight = view::windowHeight; + + render::engine->resizeScreenBuffers(); + render::engine->setScreenBufferViewports(); +} + + +void GLEngineEGL::setWindowResizable(bool newVal) { + // not defined in headless mode +} + +bool GLEngineEGL::getWindowResizable() { return false; } + +std::tuple GLEngineEGL::getWindowPos() { + // not defined in headless mode + return std::tuple{-1, -1}; +} + +bool GLEngineEGL::windowRequestsClose() { + // not defined in headless mode + return false; +} + +void GLEngineEGL::pollEvents() { + // does nothing +} + +bool GLEngineEGL::isKeyPressed(char c) { + // not defined in headless mode + return false; +} + +int GLEngineEGL::getKeyCode(char c) { + // not defined in headless mode + return -1; +} + +std::string GLEngineEGL::getClipboardText() { + // not defined in headless mode + return ""; +} + +void GLEngineEGL::setClipboardText(std::string text) { + // not defined in headless mode +} + +} // namespace backend_openGL3 +} // namespace render +} // namespace polyscope + +#else // POLYSCOPE_BACKEND_OPENGL3_EGL_ENABLED + +#include "polyscope/messages.h" + +namespace polyscope { +namespace render { +namespace backend_openGL3 { + +void initializeRenderEngine_egl() { exception("Polyscope was not compiled with support for backend: openGL3_egl"); } + + +} // namespace backend_openGL3 +} // namespace render +} // namespace polyscope + +#endif diff --git a/src/render/opengl/gl_engine_glfw.cpp b/src/render/opengl/gl_engine_glfw.cpp new file mode 100644 index 000000000..4eede7aac --- /dev/null +++ b/src/render/opengl/gl_engine_glfw.cpp @@ -0,0 +1,262 @@ +// Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run + +#ifdef POLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED + +#include "polyscope/render/opengl/gl_engine_glfw.h" + +#include "backends/imgui_impl_opengl3.h" +#include "polyscope/polyscope.h" +#include "polyscope/render/engine.h" + +#include "stb_image.h" + +#include +#include + +namespace polyscope { +namespace render { +namespace backend_openGL3 { + +GLEngineGLFW* glEngineGLFW = nullptr; // alias for global engine pointer +extern GLEngine* glEngine; // defined in gl_engine.h + +void initializeRenderEngine_glfw() { + + glEngineGLFW = new GLEngineGLFW(); // create the new global engine object + + engine = glEngineGLFW; // we keep a few copies of this pointer with various types + glEngine = glEngineGLFW; + + // initialize + glEngineGLFW->initialize(); + engine->allocateGlobalBuffersAndPrograms(); +} + +GLEngineGLFW::GLEngineGLFW() {} +GLEngineGLFW::~GLEngineGLFW() {} + +void GLEngineGLFW::initialize() { + + // Small callback function for GLFW errors + auto error_print_callback = [](int error, const char* description) { + if (polyscope::options::verbosity > 0) { + std::cout << "GLFW emitted error: " << description << std::endl; + } + }; + + // === Initialize glfw + glfwSetErrorCallback(error_print_callback); + if (!glfwInit()) { + exception("ERROR: Failed to initialize glfw"); + } + + // OpenGL version things + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +#if __APPLE__ + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#endif + + // Create the window with context + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE); + mainWindow = glfwCreateWindow(view::windowWidth, view::windowHeight, options::programName.c_str(), NULL, NULL); + glfwMakeContextCurrent(mainWindow); + glfwSetWindowPos(mainWindow, view::initWindowPosX, view::initWindowPosY); + + // Set initial window size + int newBufferWidth, newBufferHeight, newWindowWidth, newWindowHeight; + glfwGetFramebufferSize(mainWindow, &newBufferWidth, &newBufferHeight); + glfwGetWindowSize(mainWindow, &newWindowWidth, &newWindowHeight); + view::bufferWidth = newBufferWidth; + view::bufferHeight = newBufferHeight; + view::windowWidth = newWindowWidth; + view::windowHeight = newWindowHeight; + + setWindowResizable(view::windowResizable); + +// === Initialize openGL +// Load openGL functions (using GLAD) +#ifndef __APPLE__ + if (!gladLoadGL()) { + exception("ERROR: Failed to load openGL using GLAD"); + } +#endif + if (options::verbosity > 0) { + std::cout << options::printPrefix << "Backend: openGL3_glfw -- " + << "Loaded openGL version: " << glGetString(GL_VERSION) << std::endl; + } + +#ifdef __APPLE__ + // Hack to classify the process as interactive + glfwPollEvents(); +#endif + + { // Manually create the screen frame buffer + GLFrameBuffer* glScreenBuffer = new GLFrameBuffer(view::bufferWidth, view::bufferHeight, true); + displayBuffer.reset(glScreenBuffer); + glScreenBuffer->bind(); + glClearColor(1., 1., 1., 0.); + // glClearColor(0., 0., 0., 0.); + // glClearDepth(1.); + } + + populateDefaultShadersAndRules(); +} + + +void GLEngineGLFW::initializeImGui() { + bindDisplay(); + + ImGui::CreateContext(); // must call once at start + + // Set up ImGUI glfw bindings + ImGui_ImplGlfw_InitForOpenGL(mainWindow, true); + const char* glsl_version = "#version 150"; + ImGui_ImplOpenGL3_Init(glsl_version); + + configureImGui(); +} + +void GLEngineGLFW::shutdownImGui() { + // ImGui shutdown things + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); +} + +void GLEngineGLFW::ImGuiNewFrame() { + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); +} + +void GLEngineGLFW::ImGuiRender() { + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + + +void GLEngineGLFW::swapDisplayBuffers() { + bindDisplay(); + glfwSwapBuffers(mainWindow); +} + + +void GLEngineGLFW::makeContextCurrent() { + glfwMakeContextCurrent(mainWindow); + glfwSwapInterval(options::enableVSync ? 1 : 0); +} + +void GLEngineGLFW::focusWindow() { glfwFocusWindow(mainWindow); } + +void GLEngineGLFW::showWindow() { glfwShowWindow(mainWindow); } + +void GLEngineGLFW::hideWindow() { + glfwHideWindow(mainWindow); + glfwPollEvents(); // this shouldn't be necessary, but seems to be needed at least on macOS. Perhaps realted to a + // glfw bug? e.g. https://github.com/glfw/glfw/issues/1300 and related bugs +} + +void GLEngineGLFW::updateWindowSize(bool force) { + int newBufferWidth, newBufferHeight, newWindowWidth, newWindowHeight; + glfwGetFramebufferSize(mainWindow, &newBufferWidth, &newBufferHeight); + glfwGetWindowSize(mainWindow, &newWindowWidth, &newWindowHeight); + if (force || newBufferWidth != view::bufferWidth || newBufferHeight != view::bufferHeight || + newWindowHeight != view::windowHeight || newWindowWidth != view::windowWidth) { + // Basically a resize callback + requestRedraw(); + + // prevent any division by zero for e.g. aspect ratio calcs + if (newBufferHeight == 0) newBufferHeight = 1; + if (newWindowHeight == 0) newWindowHeight = 1; + + view::bufferWidth = newBufferWidth; + view::bufferHeight = newBufferHeight; + view::windowWidth = newWindowWidth; + view::windowHeight = newWindowHeight; + + render::engine->resizeScreenBuffers(); + render::engine->setScreenBufferViewports(); + } +} + + +void GLEngineGLFW::applyWindowSize() { + glfwSetWindowSize(mainWindow, view::windowWidth, view::windowHeight); + + // on some platform size changes are asynchonous, need to ensure it completes + // we don't want to just retry until the resize has happened, because it could be impossible + // TODO it seems like on X11 sometimes even this isn't enough? + glfwWaitEvents(); + + updateWindowSize(true); +} + + +void GLEngineGLFW::setWindowResizable(bool newVal) { + glfwSetWindowAttrib(mainWindow, GLFW_RESIZABLE, newVal ? GLFW_TRUE : GLFW_FALSE); +} + +bool GLEngineGLFW::getWindowResizable() { return glfwGetWindowAttrib(mainWindow, GLFW_RESIZABLE); } + +std::tuple GLEngineGLFW::getWindowPos() { + int x, y; + glfwGetWindowPos(mainWindow, &x, &y); + return std::tuple{x, y}; +} + +bool GLEngineGLFW::windowRequestsClose() { + bool shouldClose = glfwWindowShouldClose(mainWindow); + if (shouldClose) { + glfwSetWindowShouldClose(mainWindow, false); // un-set the state bit so we can close again + return true; + } + return false; +} + +void GLEngineGLFW::pollEvents() { glfwPollEvents(); } + +bool GLEngineGLFW::isKeyPressed(char c) { + if (c >= '0' && c <= '9') return ImGui::IsKeyPressed(static_cast(ImGuiKey_0 + (c - '0'))); + if (c >= 'a' && c <= 'z') return ImGui::IsKeyPressed(static_cast(ImGuiKey_A + (c - 'a'))); + if (c >= 'A' && c <= 'Z') return ImGui::IsKeyPressed(static_cast(ImGuiKey_A + (c - 'A'))); + exception("keyPressed only supports 0-9, a-z, A-Z"); + return false; +} + +int GLEngineGLFW::getKeyCode(char c) { + if (c >= '0' && c <= '9') return static_cast(ImGuiKey_0) + (c - '0'); + if (c >= 'a' && c <= 'z') return static_cast(ImGuiKey_A) + (c - 'a'); + if (c >= 'A' && c <= 'Z') return static_cast(ImGuiKey_A) + (c - 'A'); + exception("getKeyCode only supports 0-9, a-z, A-Z"); + return -1; +} + +std::string GLEngineGLFW::getClipboardText() { + std::string clipboardData = ImGui::GetClipboardText(); + return clipboardData; +} + +void GLEngineGLFW::setClipboardText(std::string text) { ImGui::SetClipboardText(text.c_str()); } + +} // namespace backend_openGL3 +} // namespace render +} // namespace polyscope + +#else // POLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED + +#include "polyscope/messages.h" + +namespace polyscope { +namespace render { +namespace backend_openGL3 { + +void initializeRenderEngine_glfw() { exception("Polyscope was not compiled with support for backend: openGL3_glfw"); } + +} // namespace backend_openGL3 +} // namespace render +} // namespace polyscope + +#endif diff --git a/src/render/opengl/shaders/common.cpp b/src/render/opengl/shaders/common.cpp index 8ccd6cf00..45f37fd60 100644 --- a/src/render/opengl/shaders/common.cpp +++ b/src/render/opengl/shaders/common.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { const char* shaderCommonSource = R"( diff --git a/src/render/opengl/shaders/cylinder_shaders.cpp b/src/render/opengl/shaders/cylinder_shaders.cpp index aea1adc8a..6b5797605 100644 --- a/src/render/opengl/shaders/cylinder_shaders.cpp +++ b/src/render/opengl/shaders/cylinder_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -479,6 +479,6 @@ const ShaderReplacementRule CYLINDER_VARIABLE_SIZE ( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/gizmo_shaders.cpp b/src/render/opengl/shaders/gizmo_shaders.cpp index 2df6f92b5..7f6a6e766 100644 --- a/src/render/opengl/shaders/gizmo_shaders.cpp +++ b/src/render/opengl/shaders/gizmo_shaders.cpp @@ -4,7 +4,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -280,6 +280,6 @@ R"( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/grid_shaders.cpp b/src/render/opengl/shaders/grid_shaders.cpp index 7ca81c5cd..8c858d95c 100644 --- a/src/render/opengl/shaders/grid_shaders.cpp +++ b/src/render/opengl/shaders/grid_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off diff --git a/src/render/opengl/shaders/ground_plane_shaders.cpp b/src/render/opengl/shaders/ground_plane_shaders.cpp index 5d6d7a60f..d07820285 100644 --- a/src/render/opengl/shaders/ground_plane_shaders.cpp +++ b/src/render/opengl/shaders/ground_plane_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -323,6 +323,6 @@ R"( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/histogram_shaders.cpp b/src/render/opengl/shaders/histogram_shaders.cpp index db9ff2806..eb6d2b344 100644 --- a/src/render/opengl/shaders/histogram_shaders.cpp +++ b/src/render/opengl/shaders/histogram_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -87,6 +87,6 @@ R"( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/lighting_shaders.cpp b/src/render/opengl/shaders/lighting_shaders.cpp index 5b0d1a711..b2e009ee1 100644 --- a/src/render/opengl/shaders/lighting_shaders.cpp +++ b/src/render/opengl/shaders/lighting_shaders.cpp @@ -8,7 +8,7 @@ namespace polyscope { namespace render{ -namespace backend_openGL3_glfw { +namespace backend_openGL3 { const ShaderStageSpecification MAP_LIGHT_FRAG_SHADER = { @@ -304,6 +304,6 @@ const ShaderReplacementRule TRANSPARENCY_PEEL_GROUND ( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/ribbon_shaders.cpp b/src/render/opengl/shaders/ribbon_shaders.cpp index 681013e49..f4b79a531 100644 --- a/src/render/opengl/shaders/ribbon_shaders.cpp +++ b/src/render/opengl/shaders/ribbon_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -204,6 +204,6 @@ R"( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/rules.cpp b/src/render/opengl/shaders/rules.cpp index 42ac462ab..da510e4cf 100644 --- a/src/render/opengl/shaders/rules.cpp +++ b/src/render/opengl/shaders/rules.cpp @@ -4,7 +4,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -465,6 +465,6 @@ ShaderReplacementRule generateVolumeGridSlicePlaneRule(std::string uniquePostfix // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/sphere_shaders.cpp b/src/render/opengl/shaders/sphere_shaders.cpp index 69df2776a..b140a95b3 100644 --- a/src/render/opengl/shaders/sphere_shaders.cpp +++ b/src/render/opengl/shaders/sphere_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -522,6 +522,6 @@ const ShaderReplacementRule SPHERE_VARIABLE_SIZE ( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/surface_mesh_shaders.cpp b/src/render/opengl/shaders/surface_mesh_shaders.cpp index 2469f0881..97643655b 100644 --- a/src/render/opengl/shaders/surface_mesh_shaders.cpp +++ b/src/render/opengl/shaders/surface_mesh_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -646,6 +646,6 @@ const ShaderReplacementRule MESH_PROPAGATE_PICK_SIMPLE ( // this one does faces // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/texture_draw_shaders.cpp b/src/render/opengl/shaders/texture_draw_shaders.cpp index 27bb3f066..28742ec0b 100644 --- a/src/render/opengl/shaders/texture_draw_shaders.cpp +++ b/src/render/opengl/shaders/texture_draw_shaders.cpp @@ -8,7 +8,7 @@ namespace polyscope { namespace render{ -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // this uses the default openGL convention of origin in the lower left const ShaderStageSpecification TEXTURE_DRAW_VERT_SHADER = { @@ -790,6 +790,6 @@ const ShaderReplacementRule SHADE_NORMAL_FROM_VIEWPOS_VAR ( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/vector_shaders.cpp b/src/render/opengl/shaders/vector_shaders.cpp index 4e9637404..61e0f3bc2 100644 --- a/src/render/opengl/shaders/vector_shaders.cpp +++ b/src/render/opengl/shaders/vector_shaders.cpp @@ -5,7 +5,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { // clang-format off @@ -333,6 +333,6 @@ const ShaderReplacementRule VECTOR_CULLPOS_FROM_TAIL( // clang-format on -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render } // namespace polyscope diff --git a/src/render/opengl/shaders/volume_mesh_shaders.cpp b/src/render/opengl/shaders/volume_mesh_shaders.cpp index 1a0d9f006..243947495 100644 --- a/src/render/opengl/shaders/volume_mesh_shaders.cpp +++ b/src/render/opengl/shaders/volume_mesh_shaders.cpp @@ -4,7 +4,7 @@ namespace polyscope { namespace render { -namespace backend_openGL3_glfw { +namespace backend_openGL3 { const ShaderStageSpecification SLICE_TETS_VERT_SHADER = { @@ -391,6 +391,6 @@ const ShaderReplacementRule SLICE_TETS_PROPAGATE_VALUE( }, /* textures */ {}); -} // namespace backend_openGL3_glfw +} // namespace backend_openGL3 } // namespace render }; // namespace polyscope diff --git a/test/include/polyscope_test.h b/test/include/polyscope_test.h index 42fc16342..c5b4a6e98 100644 --- a/test/include/polyscope_test.h +++ b/test/include/polyscope_test.h @@ -29,10 +29,10 @@ class PolyscopeTest : public ::testing::Test { // Called before the first test in this test suite. // Can be omitted if not needed. static void SetUpTestSuite() { - polyscope::init(testBackend); polyscope::options::enableRenderErrorChecks = true; polyscope::options::errorsThrowExceptions = true; polyscope::options::hideWindowAfterShow = false; + polyscope::init(testBackend); } // Per-test-suite tear-down. diff --git a/test/src/basics_test.cpp b/test/src/basics_test.cpp index fb66fd752..9c1efb58a 100644 --- a/test/src/basics_test.cpp +++ b/test/src/basics_test.cpp @@ -99,6 +99,9 @@ TEST_F(PolyscopeTest, EmptyBuffer) { polyscope::removeAllStructures(); } +TEST_F(PolyscopeTest, Screenshot) { + polyscope::screenshot("test_screeshot.png"); +} // ============================================================ // =============== Ground plane tests diff --git a/test/src/volume_grid_test.cpp b/test/src/volume_grid_test.cpp index c10d4a233..b05a56278 100644 --- a/test/src/volume_grid_test.cpp +++ b/test/src/volume_grid_test.cpp @@ -1,5 +1,6 @@ // Copyright 2017-2023, Nicholas Sharp and the Polyscope contributors. https://polyscope.run +#include "polyscope/slice_plane.h" #include "polyscope_test.h" @@ -176,5 +177,6 @@ TEST_F(PolyscopeTest, VolumeGridScalarIsosurfaceAndOpts) { q->registerIsosurfaceAsMesh(); polyscope::show(3); + polyscope::removeLastSceneSlicePlane(); polyscope::removeAllStructures(); }