diff --git a/.travis.yml b/.travis.yml index 099f2e56..7a97920f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,11 @@ os: compiler: - gcc - clang - + +jobs: + include: + - os: windows + addons: apt: packages: @@ -22,10 +26,22 @@ before_script: - cd test - mkdir build - cd build - - cmake -DCMAKE_BUILD_TYPE=Debug -DPOLYSCOPE_BACKEND=MOCK_OPENGL .. + - cmake -DCMAKE_BUILD_TYPE=Debug -DPOLYSCOPE_BACKEND_OPENGL3_GLFW=ON -DPOLYSCOPE_BACKEND_OPENGL_MOCK=ON .. script: - - make - - ./bin/polyscope-test --gtest_catch_exceptions=0 - - cmake -DCMAKE_BUILD_TYPE=Debug -DPOLYSCOPE_BACKEND=OPENGL3_GLFW .. - - make + - | + if [ "$TRAVIS_OS_NAME" = "linux" ]; then + make + ./bin/polyscope-test --gtest_catch_exceptions=0 backend=openGL_mock + fi + - | + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + make + ./bin/polyscope-test --gtest_catch_exceptions=0 backend=openGL_mock + fi + - | + if [ "$TRAVIS_OS_NAME" = "windows" ]; then + cmake --build "." + ls + ./bin/Debug/polyscope-test.exe --gtest_catch_exceptions=0 backend=openGL_mock + fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e4557cc..819357ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,15 +8,8 @@ cmake_policy(SET CMP0054 NEW) # don't implicitly dereference inside if() ## Project options # Backend -set(POLYSCOPE_BACKEND "OPENGL3_GLFW" CACHE STRING "Which graphics and windowing backend to use") -set_property(CACHE POLYSCOPE_BACKEND PROPERTY STRINGS "OPENGL3_GLFW" "MOCK_OPENGL") -if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") - message("Using polyscope backend: ${POLYSCOPE_BACKEND}") -elseif("${POLYSCOPE_BACKEND}" STREQUAL "MOCK_OPENGL") - message("Using polyscope backend: ${POLYSCOPE_BACKEND}") -else() - message(FATAL_ERROR "Unrecognized polyscope backend from POLYSCOPE_BACKEND option, value is [${POLYSCOPE_BACKEND}]" ) -endif() +set(POLYSCOPE_BACKEND_OPENGL3_GLFW "ON" CACHE BOOL "Enable openGL3_glfw backend") +set(POLYSCOPE_BACKEND_OPENGL_MOCK "ON" CACHE BOOL "Enable openGL_mock backend") ### Do anything needed for dependencies and bring their stuff in to scope add_subdirectory(deps) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 6139a44f..1f0238a8 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8.9) -if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") +if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") ## Glad add_subdirectory(glad) @@ -11,8 +11,9 @@ if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(GLFW_INSTALL OFF CACHE BOOL "" FORCE) add_subdirectory(glfw) +endif() -elseif("${POLYSCOPE_BACKEND}" STREQUAL "MOCK_OPENGL") +if("${POLYSCOPE_BACKEND_OPENGL_MOCK}") endif() ## Imgui diff --git a/deps/imgui/CMakeLists.txt b/deps/imgui/CMakeLists.txt index f98db6db..68536ae8 100644 --- a/deps/imgui/CMakeLists.txt +++ b/deps/imgui/CMakeLists.txt @@ -12,7 +12,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STR endif() -if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") +if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") set(SRCS imgui/imgui.cpp imgui/imgui_draw.cpp imgui/imgui_widgets.cpp imgui/imgui_demo.cpp imgui/examples/imgui_impl_glfw.cpp imgui/examples/imgui_impl_opengl3.cpp) @@ -32,7 +32,7 @@ if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") add_definitions(-DIMGUI_IMPL_OPENGL_LOADER_GLAD) endif() -elseif("${POLYSCOPE_BACKEND}" STREQUAL "MOCK_OPENGL") +elseif("${POLYSCOPE_BACKEND_OPENGL_MOCK}") # Disable every platform-specific thing I can find in imgui add_definitions(-DIMGUI_DISABLE_OSX_FUNCTIONS) diff --git a/include/polyscope/polyscope.h b/include/polyscope/polyscope.h index 5c04dce3..a319494b 100644 --- a/include/polyscope/polyscope.h +++ b/include/polyscope/polyscope.h @@ -19,10 +19,10 @@ namespace polyscope { // forward declarations class Structure; -// Initialize polyscope, including windowing system and openGL. Should be -// called exactly once at the beginning of a program. If initialization -// fails in any way, an exception will be thrown. -void init(); +// Initialize polyscope, including windowing system and openGL. Should be called exactly once at the beginning of a +// program. If initialization fails in any way, an exception will be thrown. +// The backend string sets which rendering backend to use. If "", a reasonable default backend will be chosen. +void init(std::string backend = ""); // Give control to the polyscope GUI. Blocks until the user returns control via // the GUI, possibly by exiting the window. diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index b1be2e0a..94fd93e7 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -322,6 +322,7 @@ class Engine { // === Windowing and framework things virtual void makeContextCurrent() = 0; + virtual void showWindow() = 0; virtual void updateWindowSize(bool force = false) = 0; virtual std::tuple getWindowPos() = 0; virtual bool windowRequestsClose() = 0; @@ -450,7 +451,8 @@ inline void ShaderProgram::setAttribute(std::string name, const std::vector getWindowPos() override; bool windowRequestsClose() override; @@ -261,5 +260,6 @@ class MockGLEngine : public Engine { protected: }; +} } // namespace render } // namespace polyscope diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index 8ff065ec..782c63fb 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -33,6 +33,7 @@ namespace polyscope { namespace render { +namespace backend_openGL3_glfw { // Some very nice typdefs typedef GLuint TextureBufferHandle; @@ -262,6 +263,7 @@ class GLEngine : public Engine { // === Windowing and framework things void makeContextCurrent() override; + void showWindow() override; void updateWindowSize(bool force = false) override; std::tuple getWindowPos() override; bool windowRequestsClose() override; @@ -312,5 +314,6 @@ class GLEngine : public Engine { GLFWwindow* mainWindow = nullptr; }; +} // namespace backend_openGL3_glfw } // namespace render } // namespace polyscope diff --git a/include/polyscope/utilities.h b/include/polyscope/utilities.h index dc869db5..82b6a496 100644 --- a/include/polyscope/utilities.h +++ b/include/polyscope/utilities.h @@ -9,6 +9,7 @@ #include #include #include +#include #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1de5f059..73ab04d1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,10 +7,20 @@ endif() SET(INCLUDE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../include/polyscope/") +# 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/mock_opengl/mock_gl_engine.cpp +) + # Configure the render backend -if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") +if("${POLYSCOPE_BACKEND_OPENGL3_GLFW}") + message("Polyscope backend openGL3_glfw enabled") - SET(BACKEND_SRCS + list (APPEND BACKEND_SRCS render/opengl/gl_engine.cpp render/opengl/shaders/texture_draw_shaders.cpp render/opengl/shaders/lighting_shaders.cpp @@ -23,18 +33,18 @@ if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") render/opengl/shaders/cylinder_shaders.cpp ) - SET(BACKEND_HEADERS + list(APPEND BACKEND_HEADERS ${INCLUDE_ROOT}render/opengl/gl_engine.h ${INCLUDE_ROOT}render/opengl/shaders/common.h ) - SET(BACKEND_INCLUDE_DIRS + list(APPEND BACKEND_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../deps/glad/include ${CMAKE_CURRENT_SOURCE_DIR}/../deps/glfw/include ) # Link settings - SET(BACKEND_LIBS + list(APPEND BACKEND_LIBS glfw ${GLFW_LIBRARIES} ) @@ -51,10 +61,14 @@ if("${POLYSCOPE_BACKEND}" STREQUAL "OPENGL3_GLFW") else() list(APPEND BACKEND_LIBS glad) endif() + + add_definitions(-DPOLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED) +endif() -elseif("${POLYSCOPE_BACKEND}" STREQUAL "MOCK_OPENGL") +if("${POLYSCOPE_BACKEND_OPENGL_MOCK}") + message("Polyscope backend openGL_mock enabled") - SET(BACKEND_SRCS + list (APPEND BACKEND_SRCS render/mock_opengl/mock_gl_engine.cpp render/opengl/shaders/texture_draw_shaders.cpp render/opengl/shaders/lighting_shaders.cpp @@ -67,18 +81,19 @@ elseif("${POLYSCOPE_BACKEND}" STREQUAL "MOCK_OPENGL") render/opengl/shaders/cylinder_shaders.cpp ) - SET(BACKEND_HEADERS + list(APPEND BACKEND_HEADERS ${INCLUDE_ROOT}render/mock_opengl/mock_gl_engine.h ${INCLUDE_ROOT}render/opengl/shaders/common.h ) - SET(BACKEND_INCLUDE_DIRS + list(APPEND BACKEND_INCLUDE_DIRS ) # Link settings - SET(BACKEND_LIBS + list(APPEND BACKEND_LIBS ) +add_definitions(-DPOLYSCOPE_BACKEND_OPENGL_MOCK_ENABLED) endif() @@ -98,6 +113,7 @@ SET(SRCS render/color_maps.cpp render/ground_plane.cpp render/materials.cpp + render/initialize_backend.cpp # General utilities disjoint_sets.cpp diff --git a/src/polyscope.cpp b/src/polyscope.cpp index b144d95c..198446b1 100644 --- a/src/polyscope.cpp +++ b/src/polyscope.cpp @@ -137,7 +137,7 @@ void writePrefsFile() { // === Core global functions -void init() { +void init(std::string backend) { if (state::initialized) { throw std::logic_error(options::printPrefix + "Initialize called twice"); } @@ -147,7 +147,7 @@ void init() { } // Initialize the rendering engine - render::initializeRenderEngine(); + render::initializeRenderEngine(backend); // Initialie ImGUI IMGUI_CHECKVERSION(); @@ -602,6 +602,8 @@ void show(size_t forFrames) { "must initialize Polyscope with polyscope::init() before calling polyscope::show()."); } + render::engine->showWindow(); + // Main loop while (!render::engine->windowRequestsClose() && forFrames > 0) { mainLoopIteration(); diff --git a/src/render/initialize_backend.cpp b/src/render/initialize_backend.cpp new file mode 100644 index 00000000..5ba1b9dc --- /dev/null +++ b/src/render/initialize_backend.cpp @@ -0,0 +1,51 @@ +#include "polyscope/render/engine.h" + +namespace polyscope { +namespace render { + +// Storage for the global engine pointer +Engine* engine = nullptr; + +// 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_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 == "") { + +#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 + +#ifdef POLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED + backend = "openGL3_glfw"; +#endif + + if (backend == "") { + throw std::runtime_error("no Polyscope backends available"); + } + } + + // Initialize the appropriate backend + if (backend == "openGL3_glfw") { + backend_openGL3_glfw::initializeRenderEngine(); + } else if (backend == "openGL_mock") { + backend_openGL_mock::initializeRenderEngine(); + } else { + throw std::runtime_error("unrecognized Polyscope backend " + backend); + } +} + +} // namespace render +} // namespace polyscope + diff --git a/src/render/mock_opengl/mock_gl_engine.cpp b/src/render/mock_opengl/mock_gl_engine.cpp index 53162733..7c657af1 100644 --- a/src/render/mock_opengl/mock_gl_engine.cpp +++ b/src/render/mock_opengl/mock_gl_engine.cpp @@ -1,4 +1,5 @@ // Copyright 2017-2019, Nicholas Sharp and the Polyscope contributors. http://polyscope.run. +#ifdef POLYSCOPE_BACKEND_OPENGL_MOCK_ENABLED #include "polyscope/render/mock_opengl/mock_gl_engine.h" #include "polyscope/messages.h" @@ -12,10 +13,11 @@ namespace polyscope { namespace render { +namespace backend_openGL_mock { + + +MockGLEngine* glEngine = nullptr; // alias for engine pointer -// == Storage and initialization for the global engine -Engine* engine = nullptr; -MockGLEngine* glEngine = nullptr; // alias for engine above void initializeRenderEngine() { glEngine = new MockGLEngine(); glEngine->initialize(); @@ -1100,7 +1102,14 @@ void GLShaderProgram::draw() { MockGLEngine::MockGLEngine() {} -void MockGLEngine::initialize() { updateWindowSize(); } +void MockGLEngine::initialize() { + + if (options::verbosity > 0) { + std::cout << options::printPrefix << "Backend: openGL_mock" << std::endl; + } + + updateWindowSize(); +} void MockGLEngine::initializeImGui() { @@ -1146,6 +1155,8 @@ void MockGLEngine::checkError(bool fatal) { checkGLError(fatal); } void MockGLEngine::makeContextCurrent() {} +void MockGLEngine::showWindow() {} + void MockGLEngine::updateWindowSize(bool force) { int newBufferWidth = 400; int newBufferHeight = 600; @@ -1165,7 +1176,7 @@ void MockGLEngine::updateWindowSize(bool force) { std::tuple MockGLEngine::getWindowPos() { int x = 20; int y = 40; - return std::tuple{x, y}; + return std::tuple{x, y}; } bool MockGLEngine::windowRequestsClose() { return false; } @@ -1252,5 +1263,23 @@ std::shared_ptr MockGLEngine::generateShaderProgram(const std::ve return std::shared_ptr(newP); } +} // namespace backend_openGL_mock +} // namespace render +} // namespace polyscope + +#else + +#include + +namespace polyscope { +namespace render { +namespace backend_openGL_mock { +void initializeRenderEngine() { + throw std::runtime_error("Polyscope was not compiled with support for backend: openGL_mock"); +} +} // namespace backend_openGL_mock } // namespace render } // namespace polyscope + +#endif + diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index c3b3f235..9f1db2c2 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -1,4 +1,5 @@ // Copyright 2017-2019, Nicholas Sharp and the Polyscope contributors. http://polyscope.run. +#ifdef POLYSCOPE_BACKEND_OPENGL3_GLFW_ENABLED #include "polyscope/render/opengl/gl_engine.h" #include "polyscope/messages.h" @@ -14,9 +15,15 @@ namespace polyscope { namespace render { -// == Storage and initialization for the global engine -Engine* engine = nullptr; -GLEngine* glEngine = nullptr; // alias for engine above +// Forward declare compressed binary font functions +unsigned int getCousineRegularCompressedSize(); +const unsigned int* getCousineRegularCompressedData(); + +namespace backend_openGL3_glfw { + + +GLEngine* glEngine = nullptr; // alias for global engine pointer + void initializeRenderEngine() { glEngine = new GLEngine(); glEngine->initialize(); @@ -1605,6 +1612,8 @@ void GLEngine::initialize() { #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); glfwSwapInterval(1); // Enable vsync @@ -1627,7 +1636,8 @@ void GLEngine::initialize() { } #endif if (options::verbosity > 0) { - std::cout << options::printPrefix << "Loaded openGL version: " << glGetString(GL_VERSION) << std::endl; + std::cout << options::printPrefix << "Backend: openGL3_glfw -- " + << "Loaded openGL version: " << glGetString(GL_VERSION) << std::endl; } #ifdef __APPLE__ @@ -1648,10 +1658,6 @@ void GLEngine::initialize() { } -// Forward declare compressed binary font functions -unsigned int getCousineRegularCompressedSize(); -const unsigned int* getCousineRegularCompressedData(); - void GLEngine::initializeImGui() { bindDisplay(); @@ -1713,6 +1719,8 @@ void GLEngine::checkError(bool fatal) { checkGLError(fatal); } void GLEngine::makeContextCurrent() { glfwMakeContextCurrent(mainWindow); } +void GLEngine::showWindow() { glfwShowWindow(mainWindow); } + void GLEngine::updateWindowSize(bool force) { int newBufferWidth, newBufferHeight, newWindowWidth, newWindowHeight; glfwGetFramebufferSize(mainWindow, &newBufferWidth, &newBufferHeight); @@ -1734,7 +1742,7 @@ void GLEngine::updateWindowSize(bool force) { std::tuple GLEngine::getWindowPos() { int x, y; glfwGetWindowPos(mainWindow, &x, &y); - return std::tuple{x, y}; + return std::tuple{x, y}; } bool GLEngine::windowRequestsClose() { @@ -1877,5 +1885,23 @@ std::shared_ptr GLEngine::generateShaderProgram(const std::vector return std::shared_ptr(newP); } + +} // namespace backend_openGL3_glfw +} // namespace render +} // namespace polyscope + +#else + +#include + +namespace polyscope { +namespace render { +namespace backend_openGL3_glfw { +void initializeRenderEngine() { + throw std::runtime_error("Polyscope was not compiled with support for backend: openGL3_glfw"); +} +} // namespace backend_openGL3_glfw } // namespace render } // namespace polyscope + +#endif diff --git a/test/include/polyscope_test.h b/test/include/polyscope_test.h new file mode 100644 index 00000000..8b4a06ca --- /dev/null +++ b/test/include/polyscope_test.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +// Which polyscope backend to use for testing +extern std::string testBackend; diff --git a/test/src/basics_test.cpp b/test/src/basics_test.cpp index fe98d66b..e9589a09 100644 --- a/test/src/basics_test.cpp +++ b/test/src/basics_test.cpp @@ -1,4 +1,5 @@ -#include "gtest/gtest.h" + +#include "polyscope_test.h" #include "polyscope/curve_network.h" #include "polyscope/pick.h" @@ -6,6 +7,8 @@ #include "polyscope/polyscope.h" #include "polyscope/surface_mesh.h" +#include "gtest/gtest.h" + #include #include #include @@ -21,7 +24,7 @@ class PolyscopeTest : public ::testing::Test { // Per-test-suite set-up. // Called before the first test in this test suite. // Can be omitted if not needed. - static void SetUpTestSuite() { polyscope::init(); } + static void SetUpTestSuite() { polyscope::init(testBackend); } // Per-test-suite tear-down. // Called after the last test in this test suite. diff --git a/test/src/main_test.cpp b/test/src/main_test.cpp index 4f230a7b..2f718006 100644 --- a/test/src/main_test.cpp +++ b/test/src/main_test.cpp @@ -1,11 +1,17 @@ -#include -#include + +#include "polyscope_test.h" #include "gtest/gtest.h" +#include +#include + using std::cout; using std::endl; +// The global polyscope backend setting for tests +std::string testBackend = "openGL_mock"; + TEST(BasicTest, HelloWorldTest) { int two = 2; int four = two + two; @@ -14,5 +20,24 @@ TEST(BasicTest, HelloWorldTest) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + + // Process custom test args + for (int i = 1; i < argc; ++i) { + std::string arg(argv[i]); + std::cout << "got arg " << arg << std::endl; + + { // look for a backend setting + std::string prefix = "backend="; + auto p = arg.rfind(prefix, 0); + if (p == 0) { + std::string val = arg.substr(prefix.size(), std::string::npos); + testBackend = val; + continue; + } + } + + throw std::runtime_error("unrecognized argument " + arg); + } + return RUN_ALL_TESTS(); }