diff --git a/README.md b/README.md index 1f6cdbe37..99dd2c999 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ auto shader = glCreateShader(GL_COMPUTE_SHADER); *glbinding* is compatible with OpenGL-compatible windowing toolkits and we provide example integrations for the following ones within the examples: -* [GLFW](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-glfw) -* [GTK 3](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-gtk3) -* [GTK 4](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-gtk4) -* [Qt 5](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-qt) -* [SDL](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-sdl) +* [GLFW OpenGL](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-glfw-gl) +* [GTK 3 OpenGL](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-gtk3-gl) and [GTK 3 OpenGL ES](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-gtk3-gles) (may require `GDK_GL=gles` environment variable) +* [GTK 4 OpenGL](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-gtk4-gl) and [GTK 4 OpenGL ES](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-gtk3-gles) +* [Qt 5 OpenGL](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-qt-gl) and [Qt 5 OpenGL ES](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-qt-gles) +* [SDL OpenGL](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-sdl-gl) and [SDL OpenGL ES](https://github.com/cginternals/glbinding/tree/master/source/examples/cubescape-sdl-gles) # Resources diff --git a/source/examples/CMakeLists.txt b/source/examples/CMakeLists.txt index afcc5c734..aa39c4ee3 100644 --- a/source/examples/CMakeLists.txt +++ b/source/examples/CMakeLists.txt @@ -3,11 +3,6 @@ # Examples # -# General Features -add_subdirectory("callbacks") -add_subdirectory("comparison") -add_subdirectory("multi-context") - # # Cubescape # @@ -21,10 +16,20 @@ add_subdirectory("cubescape-gl") add_subdirectory("cubescape-gles") # Integrations -add_subdirectory("cubescape-glfw") +add_subdirectory("cubescape-glfw-gl") +add_subdirectory("cubescape-glfw-gles") +add_subdirectory("cubescape-qt-gl") +add_subdirectory("cubescape-qt-gles") +add_subdirectory("cubescape-sdl-gl") +add_subdirectory("cubescape-sdl-gles") +add_subdirectory("cubescape-gtk3-gl") +add_subdirectory("cubescape-gtk3-gles") +add_subdirectory("cubescape-gtk4-gl") +add_subdirectory("cubescape-gtk4-gles") add_subdirectory("cubescape-wgl") -add_subdirectory("cubescape-qt") -add_subdirectory("cubescape-sdl") -add_subdirectory("cubescape-gtk3") -add_subdirectory("cubescape-gtk4") + +# General Features +add_subdirectory("callbacks") +add_subdirectory("comparison") +add_subdirectory("multi-context") add_subdirectory("cubescape-log") diff --git a/source/examples/cubescape-gl/CMakeLists.txt b/source/examples/cubescape-gl/CMakeLists.txt index 637e8f1e1..0bc6b9532 100644 --- a/source/examples/cubescape-gl/CMakeLists.txt +++ b/source/examples/cubescape-gl/CMakeLists.txt @@ -17,6 +17,8 @@ set(target cubescape-gl) if (NOT glfw3_FOUND) message("Example ${target} skipped: glfw3 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-gles/CMakeLists.txt b/source/examples/cubescape-gles/CMakeLists.txt index 999e430eb..ca42bb097 100644 --- a/source/examples/cubescape-gles/CMakeLists.txt +++ b/source/examples/cubescape-gles/CMakeLists.txt @@ -17,6 +17,8 @@ set(target cubescape-gles) if (NOT glfw3_FOUND) message("Example ${target} skipped: glfw3 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-glfw/CMakeLists.txt b/source/examples/cubescape-glfw-gl/CMakeLists.txt similarity index 89% rename from source/examples/cubescape-glfw/CMakeLists.txt rename to source/examples/cubescape-glfw-gl/CMakeLists.txt index 5809f84ed..961aac34f 100644 --- a/source/examples/cubescape-glfw/CMakeLists.txt +++ b/source/examples/cubescape-glfw-gl/CMakeLists.txt @@ -11,12 +11,14 @@ find_package(glfw3 QUIET) # # Target name -set(target cubescape-glfw) +set(target cubescape-glfw-gl) # Exit here if required dependencies are not met if (NOT glfw3_FOUND) message("Example ${target} skipped: glfw3 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-glfw/main.cpp b/source/examples/cubescape-glfw-gl/main.cpp similarity index 100% rename from source/examples/cubescape-glfw/main.cpp rename to source/examples/cubescape-glfw-gl/main.cpp diff --git a/source/examples/cubescape-glfw-gles/CMakeLists.txt b/source/examples/cubescape-glfw-gles/CMakeLists.txt new file mode 100644 index 000000000..b3f0b0e04 --- /dev/null +++ b/source/examples/cubescape-glfw-gles/CMakeLists.txt @@ -0,0 +1,137 @@ + +# +# External dependencies +# + +find_package(glfw3 QUIET) + + +# +# Executable name and options +# + +# Target name +set(target cubescape-glfw-gles) + +# Exit here if required dependencies are not met +if (NOT glfw3_FOUND) + message("Example ${target} skipped: glfw3 not found") + return() +else() + message(STATUS "Example ${target}") +endif() + + +# +# Sources +# + +set(sources + main.cpp +) + + +# +# Create executable +# + +# Build executable +add_executable(${target} + MACOSX_BUNDLE + ${sources} +) + +# Create namespaced alias +add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target}) + + +# +# Project options +# + +set_target_properties(${target} + PROPERTIES + ${DEFAULT_PROJECT_OPTIONS} + INSTALL_RPATH "${EXECUTABLE_INSTALL_RPATH}" + FOLDER "${IDE_FOLDER}" +) + + +# +# Include directories +# + +target_include_directories(${target} + PRIVATE + ${DEFAULT_INCLUDE_DIRECTORIES} + ${PROJECT_BINARY_DIR}/source/include + SYSTEM +) + + +# +# Libraries +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LIBRARIES} + glfw + ${META_PROJECT_NAME}::glbinding + ${META_PROJECT_NAME}::glbinding-aux + ${META_PROJECT_NAME}::cubescape-shared-gles +) + + +# +# Compile definitions +# + +target_compile_definitions(${target} + PRIVATE + ${DEFAULT_COMPILE_DEFINITIONS} + GLFW_INCLUDE_NONE +) + + +# +# Compile options +# + +target_compile_options(${target} + PRIVATE + ${DEFAULT_COMPILE_OPTIONS_PRIVATE} + PUBLIC + ${DEFAULT_COMPILE_OPTIONS_PUBLIC} +) + + +# +# Linker options +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LINKER_OPTIONS} +) + + +# +# Target Health +# + +perform_health_checks( + ${target} + ${sources} +) + + +# +# Deployment +# + +# Executable +install(TARGETS ${target} + RUNTIME DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_glfw + BUNDLE DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_glfw +) diff --git a/source/examples/cubescape-glfw-gles/main.cpp b/source/examples/cubescape-glfw-gles/main.cpp new file mode 100644 index 000000000..8e1b6b5c2 --- /dev/null +++ b/source/examples/cubescape-glfw-gles/main.cpp @@ -0,0 +1,134 @@ + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + + +using namespace gl; +using namespace glbinding; + + +namespace +{ + CubeScape * cubescape(nullptr); +} + + +void error(int errnum, const char * errmsg) +{ + std::cerr << errnum << ": " << errmsg << std::endl; +} + + +void framebuffer_size_callback(GLFWwindow * /*window*/, int width, int height) +{ + cubescape->resize(width, height); +} + +void key_callback(GLFWwindow * window, int key, int /*scancode*/, int action, int /*mods*/) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, 1); + + bool numCubesChanged = false; + + if (key == GLFW_KEY_I && (action == GLFW_PRESS || action == GLFW_REPEAT)) + { + cubescape->setNumCubes(cubescape->numCubes() + 1); + numCubesChanged = true; + } + + if (key == GLFW_KEY_D && (action == GLFW_PRESS || action == GLFW_REPEAT)) + { + cubescape->setNumCubes(cubescape->numCubes() - 1); + numCubesChanged = true; + } + + if (numCubesChanged) + { + const int n = cubescape->numCubes(); + std::cout << "#cubes = " << n << " * " << n << " = " << n * n << std::endl; + } +} + + +int main(int, char *[]) +{ + glfwSetErrorCallback(error); + + if (!glfwInit()) + return 1; + + glfwDefaultWindowHints(); + +// #ifdef SYSTEM_DARWIN +// glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); +// glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); +// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true); +// glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +// #endif + + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + + GLFWwindow * window = glfwCreateWindow(640, 480, "", nullptr, nullptr); + if (!window) + { + glfwTerminate(); + return -1; + } + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + glfwMakeContextCurrent(window); + + glbinding::initialize(glfwGetProcAddress, false); // only resolve functions that are actually used (lazy) + glbinding::aux::enableGetErrorCallback(); + + // print some gl infos (query) + + std::cout << std::endl + << "OpenGL ES Version: " << aux::ContextInfo::version() << std::endl + << "OpenGL ES Vendor: " << aux::ContextInfo::vendor() << std::endl + << "OpenGL ES Renderer: " << aux::ContextInfo::renderer() << std::endl; + + std::cout << std::endl + << "Press i or d to either increase or decrease number of cubes." << std::endl << std::endl; + + + cubescape = new CubeScape(); + + int width, height; glfwGetFramebufferSize(window, &width, &height); + cubescape->resize(width, height); + + while (!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + cubescape->draw(); + glfwSwapBuffers(window); + } + + delete cubescape; + cubescape = nullptr; + + glfwTerminate(); + return 0; +} diff --git a/source/examples/cubescape-gtk3/CMakeLists.txt b/source/examples/cubescape-gtk3-gl/CMakeLists.txt similarity index 89% rename from source/examples/cubescape-gtk3/CMakeLists.txt rename to source/examples/cubescape-gtk3-gl/CMakeLists.txt index dc4d3a46a..40640eaa7 100644 --- a/source/examples/cubescape-gtk3/CMakeLists.txt +++ b/source/examples/cubescape-gtk3-gl/CMakeLists.txt @@ -11,12 +11,14 @@ find_package(GTK3 QUIET) # # Target name -set(target cubescape-gtk3) +set(target cubescape-gtk3-gl) # Exit here if required dependencies are not met if (NOT TARGET GTK3::GTK3) message("Example ${target} skipped: GTK 3 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-gtk3/main.cpp b/source/examples/cubescape-gtk3-gl/main.cpp similarity index 100% rename from source/examples/cubescape-gtk3/main.cpp rename to source/examples/cubescape-gtk3-gl/main.cpp diff --git a/source/examples/cubescape-gtk3-gles/CMakeLists.txt b/source/examples/cubescape-gtk3-gles/CMakeLists.txt new file mode 100644 index 000000000..176941501 --- /dev/null +++ b/source/examples/cubescape-gtk3-gles/CMakeLists.txt @@ -0,0 +1,136 @@ + +# +# External dependencies +# + +find_package(GTK3 QUIET) + + +# +# Executable name and options +# + +# Target name +set(target cubescape-gtk3-gles) + +# Exit here if required dependencies are not met +if (NOT TARGET GTK3::GTK3) + message("Example ${target} skipped: GTK 3 not found") + return() +else() + message(STATUS "Example ${target}") +endif() + + +# +# Sources +# + +set(sources + main.cpp +) + + +# +# Create executable +# + +# Build executable +add_executable(${target} + MACOSX_BUNDLE + ${sources} +) + +# Create namespaced alias +add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target}) + + +# +# Project options +# + +set_target_properties(${target} + PROPERTIES + ${DEFAULT_PROJECT_OPTIONS} + INSTALL_RPATH "${EXECUTABLE_INSTALL_RPATH}" + FOLDER "${IDE_FOLDER}" +) + + +# +# Include directories +# + +target_include_directories(${target} + PRIVATE + ${DEFAULT_INCLUDE_DIRECTORIES} + ${PROJECT_BINARY_DIR}/source/include + SYSTEM +) + + +# +# Libraries +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LIBRARIES} + GTK3::GTK3 + ${META_PROJECT_NAME}::glbinding + ${META_PROJECT_NAME}::glbinding-aux + ${META_PROJECT_NAME}::cubescape-shared-gles +) + + +# +# Compile definitions +# + +target_compile_definitions(${target} + PRIVATE + ${DEFAULT_COMPILE_DEFINITIONS} +) + + +# +# Compile options +# + +target_compile_options(${target} + PRIVATE + ${DEFAULT_COMPILE_OPTIONS_PRIVATE} + PUBLIC + ${DEFAULT_COMPILE_OPTIONS_PUBLIC} +) + + +# +# Linker options +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LINKER_OPTIONS} +) + + +# +# Target Health +# + +perform_health_checks( + ${target} + ${sources} +) + + +# +# Deployment +# + +# Executable +install(TARGETS ${target} + RUNTIME DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_sdl + BUNDLE DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_sdl +) diff --git a/source/examples/cubescape-gtk3-gles/main.cpp b/source/examples/cubescape-gtk3-gles/main.cpp new file mode 100644 index 000000000..8bcf4f036 --- /dev/null +++ b/source/examples/cubescape-gtk3-gles/main.cpp @@ -0,0 +1,149 @@ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + + +using namespace gl; +using namespace glbinding; + + +namespace +{ + CubeScape * cubescape(nullptr); + GdkFrameClock * frame_clock; + gint64 start_time; +} + +gboolean key_press(GtkWidget *widget, GdkEventKey *event, gpointer /*user_data*/) { + bool numCubesChanged = false; + + switch (event->keyval) + { + case GDK_KEY_Q: + case GDK_KEY_q: + if (event->state & GDK_CONTROL_MASK) + { + gtk_main_quit(); + return false; + } + break; + + case GDK_KEY_I: + case GDK_KEY_i: + cubescape->setNumCubes(cubescape->numCubes() + 1); + numCubesChanged = true; + + break; + + case GDK_KEY_D: + case GDK_KEY_d: + cubescape->setNumCubes(cubescape->numCubes() - 1); + numCubesChanged = true; + + break; + } + + if (numCubesChanged) + { + const int n = cubescape->numCubes(); + std::cout << "#cubes = " << n << " * " << n << " = " << n * n << std::endl; + } + + return false; +} + +void realize(GtkGLArea *glarea) { + gtk_gl_area_make_current(glarea); + + // initialize glbinding + glbinding::initialize(glbinding::getProcAddress, false); // only resolve functions that are actually used (lazy) + glbinding::aux::enableGetErrorCallback(); + + // print some gl infos (query) + std::cout << std::endl + << "OpenGL ES Version: " << aux::ContextInfo::version() << std::endl + << "OpenGL ES Vendor: " << aux::ContextInfo::vendor() << std::endl + << "OpenGL ES Renderer: " << aux::ContextInfo::renderer() << std::endl; + + std::cout << std::endl + << "Press i or d to either increase or decrease number of cubes." << std::endl << std::endl; + + + cubescape = new CubeScape(); + + // initial size + GtkAllocation* alloc = g_new(GtkAllocation, 1); + gtk_widget_get_allocation(GTK_WIDGET(glarea), alloc); + + const auto width = alloc->width; + const auto height = alloc->height; + + cubescape->resize(width, height); + + g_free(alloc); + // initial size + + GdkWindow * gdk_window = gtk_widget_get_window(GTK_WIDGET(glarea)); + frame_clock = gdk_window_get_frame_clock(gdk_window); + start_time = gdk_frame_clock_get_frame_time(frame_clock); + g_signal_connect_swapped(frame_clock, "update", G_CALLBACK(gtk_gl_area_queue_render), glarea); + gdk_frame_clock_begin_updating(frame_clock); +} + +void resize(GtkGLArea *, GtkAllocation *allocation, gpointer /*user_data*/) { + if (cubescape == nullptr) + { + return; + } + + const auto width = allocation->width; + const auto height = allocation->height; + + cubescape->resize(width, height); +} + +void render(GtkGLArea *glarea, GdkGLContext *context) { + cubescape->draw(); +} + +int main(int argc, char * argv[]) +{ + gtk_init(&argc, &argv); + + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + GtkWidget *glarea = gtk_gl_area_new(); + gtk_gl_area_set_use_es(GTK_GL_AREA(glarea), true); + gtk_gl_area_set_required_version(GTK_GL_AREA(glarea), 3, 2); + gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(glarea), true); + + gtk_container_add(GTK_CONTAINER(window), glarea); + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect(glarea, "realize", G_CALLBACK(realize), NULL); + g_signal_connect(glarea, "size-allocate", G_CALLBACK(resize), NULL); + g_signal_connect(glarea, "render", G_CALLBACK(render), NULL); + g_signal_connect (G_OBJECT(window), "key_press_event", G_CALLBACK(key_press), NULL); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} diff --git a/source/examples/cubescape-gtk4/CMakeLists.txt b/source/examples/cubescape-gtk4-gl/CMakeLists.txt similarity index 89% rename from source/examples/cubescape-gtk4/CMakeLists.txt rename to source/examples/cubescape-gtk4-gl/CMakeLists.txt index 94749f306..2db12d9a0 100644 --- a/source/examples/cubescape-gtk4/CMakeLists.txt +++ b/source/examples/cubescape-gtk4-gl/CMakeLists.txt @@ -11,12 +11,14 @@ find_package(GTK4 QUIET) # # Target name -set(target cubescape-gtk4) +set(target cubescape-gtk4-gl) # Exit here if required dependencies are not met if (NOT TARGET GTK4::GTK4) message("Example ${target} skipped: GTK 4 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-gtk4/main.cpp b/source/examples/cubescape-gtk4-gl/main.cpp similarity index 93% rename from source/examples/cubescape-gtk4/main.cpp rename to source/examples/cubescape-gtk4-gl/main.cpp index 766422d05..8f07d1314 100644 --- a/source/examples/cubescape-gtk4/main.cpp +++ b/source/examples/cubescape-gtk4-gl/main.cpp @@ -135,10 +135,15 @@ void activate(GtkApplication* app, gpointer /*user_data*/) GtkWidget *window; window = gtk_application_window_new (app); - gtk_window_set_title (GTK_WINDOW (window), "Cubescape GTK 4"); + gtk_window_set_title (GTK_WINDOW (window), "Cubescape GTK 4 OpenGL"); gtk_window_set_default_size (GTK_WINDOW (window), 800, 800); glarea = reinterpret_cast(gtk_gl_area_new()); + // until of GTK 4.6 + gtk_gl_area_set_use_es(glarea, false); + gtk_gl_area_set_required_version(glarea, 3, 3); + // as of GTK 4.6 + //gtk_gl_area_set_allowed_apis(glarea, GDK_GL_API_GL); gtk_gl_area_set_has_depth_buffer(glarea, true); gtk_gl_area_set_auto_render(glarea, true); @@ -170,7 +175,7 @@ int main(int argc, char * argv[]) flags = G_APPLICATION_FLAGS_NONE; #endif - app = gtk_application_new("org.glbinding.example-gtk4", flags); + app = gtk_application_new("org.glbinding.example-gtk4-gl", flags); g_signal_connect(app, "activate", G_CALLBACK (activate), NULL); status = g_application_run(G_APPLICATION (app), argc, argv); g_object_unref(app); diff --git a/source/examples/cubescape-gtk4-gles/CMakeLists.txt b/source/examples/cubescape-gtk4-gles/CMakeLists.txt new file mode 100644 index 000000000..06d3fac33 --- /dev/null +++ b/source/examples/cubescape-gtk4-gles/CMakeLists.txt @@ -0,0 +1,136 @@ + +# +# External dependencies +# + +find_package(GTK4 QUIET) + + +# +# Executable name and options +# + +# Target name +set(target cubescape-gtk4-gles) + +# Exit here if required dependencies are not met +if (NOT TARGET GTK4::GTK4) + message("Example ${target} skipped: GTK 4 not found") + return() +else() + message(STATUS "Example ${target}") +endif() + + +# +# Sources +# + +set(sources + main.cpp +) + + +# +# Create executable +# + +# Build executable +add_executable(${target} + MACOSX_BUNDLE + ${sources} +) + +# Create namespaced alias +add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target}) + + +# +# Project options +# + +set_target_properties(${target} + PROPERTIES + ${DEFAULT_PROJECT_OPTIONS} + INSTALL_RPATH "${EXECUTABLE_INSTALL_RPATH}" + FOLDER "${IDE_FOLDER}" +) + + +# +# Include directories +# + +target_include_directories(${target} + PRIVATE + ${DEFAULT_INCLUDE_DIRECTORIES} + ${PROJECT_BINARY_DIR}/source/include + SYSTEM +) + + +# +# Libraries +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LIBRARIES} + GTK4::GTK4 + ${META_PROJECT_NAME}::glbinding + ${META_PROJECT_NAME}::glbinding-aux + ${META_PROJECT_NAME}::cubescape-shared-gles +) + + +# +# Compile definitions +# + +target_compile_definitions(${target} + PRIVATE + ${DEFAULT_COMPILE_DEFINITIONS} +) + + +# +# Compile options +# + +target_compile_options(${target} + PRIVATE + ${DEFAULT_COMPILE_OPTIONS_PRIVATE} + PUBLIC + ${DEFAULT_COMPILE_OPTIONS_PUBLIC} +) + + +# +# Linker options +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LINKER_OPTIONS} +) + + +# +# Target Health +# + +perform_health_checks( + ${target} + ${sources} +) + + +# +# Deployment +# + +# Executable +install(TARGETS ${target} + RUNTIME DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_sdl + BUNDLE DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_sdl +) diff --git a/source/examples/cubescape-gtk4-gles/main.cpp b/source/examples/cubescape-gtk4-gles/main.cpp new file mode 100644 index 000000000..c6a265eda --- /dev/null +++ b/source/examples/cubescape-gtk4-gles/main.cpp @@ -0,0 +1,186 @@ + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + + +using namespace gl; +using namespace glbinding; + + +namespace +{ + GtkApplication *app = nullptr; + CubeScape * cubescape = nullptr; + GtkEventController * controller = nullptr; + GtkGLArea * glarea = nullptr; +} + +gboolean key_press(GtkEventController *controller, guint keyval, guint keycode, GdkModifierType state, GtkEventControllerKey *event_controller) { + bool numCubesChanged = false; + + switch (keyval) + { + case GDK_KEY_Q: + case GDK_KEY_q: + if (state & GDK_CONTROL_MASK) + { + g_application_quit(G_APPLICATION(app)); + return false; + } + break; + + case GDK_KEY_I: + case GDK_KEY_i: + cubescape->setNumCubes(cubescape->numCubes() + 1); + numCubesChanged = true; + + break; + + case GDK_KEY_D: + case GDK_KEY_d: + cubescape->setNumCubes(cubescape->numCubes() - 1); + numCubesChanged = true; + + break; + } + + if (numCubesChanged) + { + const int n = cubescape->numCubes(); + std::cout << "#cubes = " << n << " * " << n << " = " << n * n << std::endl; + + gtk_gl_area_queue_render(glarea); + } + + return false; +} + +void realize(GtkGLArea *glarea) { + gtk_gl_area_make_current(glarea); + + // initialize glbinding + glbinding::initialize(glbinding::getProcAddress, true); // only resolve functions that are actually used (lazy) + glbinding::aux::enableGetErrorCallback(); + + // print some gl infos (query) + std::cout << std::endl + << "OpenGL ES Version: " << aux::ContextInfo::version() << std::endl + << "OpenGL ES Vendor: " << aux::ContextInfo::vendor() << std::endl + << "OpenGL ES Renderer: " << aux::ContextInfo::renderer() << std::endl; + + std::cout << std::endl + << "Press i or d to either increase or decrease number of cubes." << std::endl << std::endl; + + + cubescape = new CubeScape(); + + // initial size + GtkAllocation* alloc = g_new(GtkAllocation, 1); + gtk_widget_get_allocation(GTK_WIDGET(glarea), alloc); + + const auto width = alloc->width; + const auto height = alloc->height; + + g_free(alloc); + + cubescape->resize(width, height); +} + +void resize(GtkGLArea * glarea, int width, int height, gpointer /*user_data*/) { + if (cubescape == nullptr) + { + return; + } + + // gtk_gl_area_make_current(glarea); + + cubescape->resize(width, height); + + gtk_gl_area_queue_render(glarea); +} + +gboolean queue_render(GtkWidget *widget, GdkFrameClock * frame_clock, gpointer data) +{ + gtk_gl_area_queue_render(glarea); + return true; +} + +gboolean render(GtkGLArea *glarea, GdkGLContext * /*context*/) { + // gtk_gl_area_make_current(glarea); + + cubescape->draw(); + + return true; +} + +void activate(GtkApplication* app, gpointer /*user_data*/) +{ + GtkWidget *window; + + window = gtk_application_window_new (app); + gtk_window_set_title (GTK_WINDOW (window), "Cubescape GTK 4 OpenGL ES"); + gtk_window_set_default_size (GTK_WINDOW (window), 800, 800); + + glarea = reinterpret_cast(gtk_gl_area_new()); + // until of GTK 4.6 + gtk_gl_area_set_use_es(glarea, true); + //gtk_gl_area_set_required_version(glarea, 3, 2); + // as of GTK 4.6 + //gtk_gl_area_set_allowed_apis(glarea, GDK_GL_API_GLES); + + gtk_gl_area_set_has_depth_buffer(glarea, true); + gtk_gl_area_set_has_stencil_buffer(glarea, false); + gtk_gl_area_set_auto_render(glarea, true); + + gtk_window_set_child(GTK_WINDOW(window), GTK_WIDGET(glarea)); + + g_signal_connect(G_OBJECT(glarea), "realize", G_CALLBACK(realize), NULL); + g_signal_connect(G_OBJECT(glarea), "resize", G_CALLBACK(resize), NULL); + g_signal_connect(G_OBJECT(glarea), "render", G_CALLBACK (render), NULL); + + controller = gtk_event_controller_key_new(); + g_signal_connect(controller, "key-pressed", G_CALLBACK(key_press), NULL); + gtk_widget_add_controller(GTK_WIDGET(window), controller); + + // Get the frame clock + gtk_widget_add_tick_callback(GTK_WIDGET(glarea), queue_render, NULL, 0); + + gtk_window_present (GTK_WINDOW (window)); +} + +int main(int argc, char * argv[]) +{ + int status; + + GApplicationFlags flags; + + #if GLIB_CHECK_VERSION(2, 74, 0) + flags = G_APPLICATION_DEFAULT_FLAGS; + #else + flags = G_APPLICATION_FLAGS_NONE; + #endif + + app = gtk_application_new("org.glbinding.example-gtk4-gles", flags); + g_signal_connect(app, "activate", G_CALLBACK (activate), NULL); + status = g_application_run(G_APPLICATION (app), argc, argv); + g_object_unref(app); + + return status; +} diff --git a/source/examples/cubescape-log/CMakeLists.txt b/source/examples/cubescape-log/CMakeLists.txt index 2b9dd9cdb..f1c07f85b 100644 --- a/source/examples/cubescape-log/CMakeLists.txt +++ b/source/examples/cubescape-log/CMakeLists.txt @@ -17,6 +17,8 @@ set(target cubescape-log) if (NOT glfw3_FOUND) message("Example ${target} skipped: glfw3 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-qt/CMakeLists.txt b/source/examples/cubescape-qt-gl/CMakeLists.txt similarity index 91% rename from source/examples/cubescape-qt/CMakeLists.txt rename to source/examples/cubescape-qt-gl/CMakeLists.txt index dde0d145e..a4deb6e4f 100644 --- a/source/examples/cubescape-qt/CMakeLists.txt +++ b/source/examples/cubescape-qt-gl/CMakeLists.txt @@ -23,12 +23,14 @@ cmake_policy(SET CMP0020 NEW) # # Target name -set(target cubescape-qt) +set(target cubescape-qt-gl) # Exit here if required dependencies are not met if (NOT Qt5Core_FOUND) message(STATUS "Example ${target} skipped: Qt5 not found") return() +else() + message(STATUS "Example ${target}") endif() # On macOS qt5 fails to link against opengl diff --git a/source/examples/cubescape-qt/Canvas.cpp b/source/examples/cubescape-qt-gl/Canvas.cpp similarity index 100% rename from source/examples/cubescape-qt/Canvas.cpp rename to source/examples/cubescape-qt-gl/Canvas.cpp diff --git a/source/examples/cubescape-qt/Canvas.h b/source/examples/cubescape-qt-gl/Canvas.h similarity index 100% rename from source/examples/cubescape-qt/Canvas.h rename to source/examples/cubescape-qt-gl/Canvas.h diff --git a/source/examples/cubescape-qt/Painter.cpp b/source/examples/cubescape-qt-gl/Painter.cpp similarity index 100% rename from source/examples/cubescape-qt/Painter.cpp rename to source/examples/cubescape-qt-gl/Painter.cpp diff --git a/source/examples/cubescape-qt/Painter.h b/source/examples/cubescape-qt-gl/Painter.h similarity index 100% rename from source/examples/cubescape-qt/Painter.h rename to source/examples/cubescape-qt-gl/Painter.h diff --git a/source/examples/cubescape-qt/Viewer.cpp b/source/examples/cubescape-qt-gl/Viewer.cpp similarity index 100% rename from source/examples/cubescape-qt/Viewer.cpp rename to source/examples/cubescape-qt-gl/Viewer.cpp diff --git a/source/examples/cubescape-qt/Viewer.h b/source/examples/cubescape-qt-gl/Viewer.h similarity index 100% rename from source/examples/cubescape-qt/Viewer.h rename to source/examples/cubescape-qt-gl/Viewer.h diff --git a/source/examples/cubescape-qt/Viewer.ui b/source/examples/cubescape-qt-gl/Viewer.ui similarity index 100% rename from source/examples/cubescape-qt/Viewer.ui rename to source/examples/cubescape-qt-gl/Viewer.ui diff --git a/source/examples/cubescape-qt/main.cpp b/source/examples/cubescape-qt-gl/main.cpp similarity index 100% rename from source/examples/cubescape-qt/main.cpp rename to source/examples/cubescape-qt-gl/main.cpp diff --git a/source/examples/cubescape-qt-gles/CMakeLists.txt b/source/examples/cubescape-qt-gles/CMakeLists.txt new file mode 100644 index 000000000..8785cb09e --- /dev/null +++ b/source/examples/cubescape-qt-gles/CMakeLists.txt @@ -0,0 +1,165 @@ + +# +# External dependencies +# + +find_package(Qt5Core 5.1 QUIET) +find_package(Qt5Gui 5.1 QUIET) +find_package(Qt5Widgets 5.1 QUIET) + + +# Enable automoc +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(AUTOMOC_MOC_OPTIONS PROPERTIES FOLDER CMakeAutomocTargets) +set_property(GLOBAL PROPERTY AUTOMOC_FOLDER CMakeAutomocTargets) + +# ENABLE CMP0020: Automatically link Qt executables to qtmain target on Windows. +cmake_policy(SET CMP0020 NEW) + + +# +# Library name and options +# + +# Target name +set(target cubescape-qt-gles) + +# Exit here if required dependencies are not met +if (NOT Qt5Core_FOUND) + message(STATUS "Example ${target} skipped: Qt5 not found") + return() +else() + message(STATUS "Example ${target}") +endif() + +# On macOS qt5 fails to link against opengl +if(APPLE) + find_package(OpenGL REQUIRED) +endif() + + +# +# Sources +# + +set(sources + main.cpp + + Canvas.cpp + Canvas.h + Painter.cpp + Painter.h + Viewer.cpp + Viewer.h + Viewer.ui +) + + +# +# Create executable +# + +# Build executable +add_executable(${target} + MACOSX_BUNDLE + ${sources} +) + +# Create namespaced alias +add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target}) + + +# +# Project options +# + +set_target_properties(${target} + PROPERTIES + ${DEFAULT_PROJECT_OPTIONS} + INSTALL_RPATH "${EXECUTABLE_INSTALL_RPATH}" + FOLDER "${IDE_FOLDER}" +) + + +# +# Include directories +# + +target_include_directories(${target} + PRIVATE + ${DEFAULT_INCLUDE_DIRECTORIES} + ${PROJECT_BINARY_DIR}/source/include + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} # for UIC generated headers +) + + +# +# Libraries +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LIBRARIES} + ${META_PROJECT_NAME}::glbinding + ${META_PROJECT_NAME}::glbinding-aux + ${META_PROJECT_NAME}::cubescape-shared-gles + Qt5::Core + Qt5::Gui + Qt5::Widgets + "$<$:${OPENGL_gl_LIBRARY}>" +) + + +# +# Compile definitions +# + +target_compile_definitions(${target} + PRIVATE + ${DEFAULT_COMPILE_DEFINITIONS} +) + + +# +# Compile options +# + +target_compile_options(${target} + PRIVATE + ${DEFAULT_COMPILE_OPTIONS_PRIVATE} + PUBLIC + ${DEFAULT_COMPILE_OPTIONS_PUBLIC} +) + + +# +# Linker options +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LINKER_OPTIONS} +) + + +# +# Target Health +# + +perform_health_checks( + ${target} + ${sources} +) + + +# +# Deployment +# + +# Executable +install(TARGETS ${target} + RUNTIME DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_qt + BUNDLE DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_qt +) diff --git a/source/examples/cubescape-qt-gles/Canvas.cpp b/source/examples/cubescape-qt-gles/Canvas.cpp new file mode 100644 index 000000000..fcb47b91d --- /dev/null +++ b/source/examples/cubescape-qt-gles/Canvas.cpp @@ -0,0 +1,294 @@ + +#include "Canvas.h" + +#include + +#ifdef SYSTEM_DARWIN +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "Painter.h" + + +Canvas * Canvas::s_getProcAddressHelper = nullptr; + + +Canvas::Canvas( + const QSurfaceFormat & format +, QScreen * screen) +: QWindow(screen) +, m_context(new QOpenGLContext) +, m_swapInterval(VerticalSyncronization) +, m_repaintTimer(new QBasicTimer()) +, m_swapts(0.0) +, m_swaps(0) +, m_update(false) +, m_continuousRepaint(false) +, m_painter(nullptr) +{ + if (!s_getProcAddressHelper) + { + s_getProcAddressHelper = this; + } + + setSurfaceType(OpenGLSurface); + + create(); + + initializeGL(format); + + qDebug() << "Press i or d to either increase or decrease number of cubes."; + qDebug(); +} + +Canvas::~Canvas() +{ + delete m_painter; +} + +QSurfaceFormat Canvas::format() const +{ + if (!m_context) + return QSurfaceFormat(); + + return m_context->format(); +} + +void Canvas::setContinuousRepaint( + bool enable +, int msec) +{ + if (m_continuousRepaint) + m_repaintTimer->stop(); + + m_continuousRepaint = enable; + + if (m_continuousRepaint) + m_repaintTimer->start(msec, this); +} + +bool Canvas::continuousRepaint() const +{ + return m_continuousRepaint; +} + +void Canvas::initializeGL(const QSurfaceFormat & format) +{ + m_context->setFormat(format); + m_context->create(); + + m_context->makeCurrent(this); + + if (!m_painter) + { + m_painter = new Painter(); + m_painter->initialize(getProcAddress); + + emit numCubesUpdate(m_painter->numCubes()); + } + + // print some gl infos (query) + + qDebug(); +#if (QT_VERSION >= 0x050300) + qDebug() << "OpenGL API: " << (m_context->isOpenGLES() ? "GLES" : "GL"); +#endif + qDebug() << "OpenGL Version: " << qPrintable(QString::fromStdString( + glbinding::aux::ContextInfo::version().toString())); + qDebug() << "OpenGL Vendor: " << qPrintable(QString::fromStdString( + glbinding::aux::ContextInfo::vendor())); + qDebug() << "OpenGL Renderer:" << qPrintable(QString::fromStdString( + glbinding::aux::ContextInfo::renderer())); + qDebug(); + + m_context->doneCurrent(); + + m_fpsTimer.start(); +} + +void Canvas::resizeEvent(QResizeEvent * event) +{ + if (!m_painter) + return; + + m_context->makeCurrent(this); + + m_painter->resize(event->size().width(), event->size().height()); + + m_context->doneCurrent(); + + if (isExposed() && Hidden != visibility()) + paintGL(); +} + +void Canvas::paintGL() +{ + if (!m_painter || !isExposed() || Hidden == visibility()) + return; + + m_context->makeCurrent(this); + + m_painter->draw(); + + m_context->swapBuffers(this); + m_context->doneCurrent(); + + ++m_swaps; + + if (m_fpsTimer.elapsed() - m_swapts >= 1e+3) + { + const float fps = 1e+3f * static_cast(static_cast + (m_swaps) / (m_fpsTimer.elapsed() - m_swapts)); + + emit fpsUpdate(fps); + + m_swapts = m_fpsTimer.elapsed(); + m_swaps = 0; + } +} + +void Canvas::timerEvent(QTimerEvent * event) +{ + assert(m_repaintTimer); + + if(event->timerId() != m_repaintTimer->timerId()) + return; + + paintGL(); +} + +void Canvas::setSwapInterval(SwapInterval swapInterval) +{ + m_context->makeCurrent(this); + + bool result(false); + m_swapInterval = swapInterval; + +#ifdef SYSTEM_WINDOWS + + // ToDo: C++11 - type aliases + typedef bool(WINAPI * SWAPINTERVALEXTPROC) (int); + static SWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; + + if (!wglSwapIntervalEXT) + wglSwapIntervalEXT = reinterpret_cast(m_context->getProcAddress("wglSwapIntervalEXT")); + if (wglSwapIntervalEXT) + result = wglSwapIntervalEXT(swapInterval); + +#elif SYSTEM_DARWIN + + CGLContextObj contextObj; + GLint swapIntervalParam = swapInterval; + + contextObj = CGLGetCurrentContext(); + + CGLError error = CGLSetParameter(contextObj, kCGLCPSwapInterval, &swapIntervalParam); + result = (error == kCGLNoError); + +#else + // ToDo: C++11 - type aliases + typedef int(APIENTRY * SWAPINTERVALEXTPROC) (int); + static SWAPINTERVALEXTPROC glXSwapIntervalSGI = nullptr; + + if (!glXSwapIntervalSGI) + glXSwapIntervalSGI = reinterpret_cast(m_context->getProcAddress("glXSwapIntervalSGI")); + if (glXSwapIntervalSGI) + result = !glXSwapIntervalSGI(swapInterval); + +#endif + + if (!result) + qWarning("Setting swap interval to %s failed." + , qPrintable(swapIntervalToString(swapInterval))); + else + qDebug("Setting swap interval to %s." + , qPrintable(swapIntervalToString(swapInterval))); + + m_context->doneCurrent(); +} + +void Canvas::toggleSwapInterval() +{ + switch (m_swapInterval) + { + case VerticalSyncronization: + setSwapInterval(AdaptiveVerticalSyncronization); + break; + case AdaptiveVerticalSyncronization: + setSwapInterval(NoVerticalSyncronization); + break; + case NoVerticalSyncronization: + default: + setSwapInterval(VerticalSyncronization); + break; + } +} + +const QString Canvas::swapIntervalToString(SwapInterval swapInterval) +{ + switch (swapInterval) + { + case NoVerticalSyncronization: + return QString("NoVerticalSyncronization"); + case VerticalSyncronization: + return QString("VerticalSyncronization"); + case AdaptiveVerticalSyncronization: + return QString("AdaptiveVerticalSyncronization"); + default: + return QString(); + } +} + +void Canvas::keyPressEvent(QKeyEvent * event) +{ + bool numCubesChanged = false; + + if (event->key() == Qt::Key_I) + { + m_painter->setNumCubes(m_painter->numCubes() + 1); + numCubesChanged = true; + } + + if (event->key() == Qt::Key_D) + { + m_painter->setNumCubes(m_painter->numCubes() - 1); + numCubesChanged = true; + } + + if (numCubesChanged) + emit numCubesUpdate(m_painter->numCubes()); + + if (event->isAccepted()) + paintGL(); +} + +ProcAddress Canvas::getProcAddress(const char * name) +{ + if (!s_getProcAddressHelper || name == nullptr) + { + return nullptr; + } + + const auto symbol = std::string(name); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) + const auto qtSymbol = QByteArray::fromStdString(symbol); +#else + const auto qtSymbol = QByteArray::fromRawData(symbol.c_str(), symbol.size()); +#endif + return s_getProcAddressHelper->m_context->getProcAddress(qtSymbol); +} diff --git a/source/examples/cubescape-qt-gles/Canvas.h b/source/examples/cubescape-qt-gles/Canvas.h new file mode 100644 index 000000000..952357394 --- /dev/null +++ b/source/examples/cubescape-qt-gles/Canvas.h @@ -0,0 +1,86 @@ + +#pragma once + +#include + +#include +#include +#include + +class QOpenGLContext; +class QSurfaceFormat; +class QBasicTimer; +class QTimerEvent; +class QKeyEvent; + + +class Painter; + +using ProcAddress = void(*)(); + +class Canvas : public QWindow +{ + Q_OBJECT + +public: + enum SwapInterval + { + NoVerticalSyncronization = 0 + , VerticalSyncronization = 1 ///< WGL_EXT_swap_control, GLX_EXT_swap_control, GLX_SGI_video_sync + , AdaptiveVerticalSyncronization = -1 ///< requires EXT_swap_control_tear + }; + +public: + Canvas( + const QSurfaceFormat & format + , QScreen * screen = nullptr); + + virtual ~Canvas(); + + // from QWindow + virtual QSurfaceFormat format() const; + + void setContinuousRepaint(bool enable, int msec = 1000 / 60); + bool continuousRepaint() const; + + void setSwapInterval(SwapInterval swapInterval); + static const QString swapIntervalToString(SwapInterval swapInterval); + +public slots: + void toggleSwapInterval(); + + +protected: + virtual void initializeGL(const QSurfaceFormat & format); + virtual void paintGL(); + + virtual void resizeEvent(QResizeEvent * event); + virtual void keyPressEvent(QKeyEvent * event); + + void timerEvent(QTimerEvent * event); + +signals: + void fpsUpdate(float fps); + void numCubesUpdate(int numCubes); + +protected: + QScopedPointer m_context; + + SwapInterval m_swapInterval; ///< required for toggle + + QScopedPointer m_repaintTimer; + QElapsedTimer m_fpsTimer; + + long double m_swapts; + unsigned int m_swaps; + + bool m_update; // checked in paintGL, if true, update of program gets triggered + + bool m_continuousRepaint; + + Painter * m_painter; + +protected: + static Canvas * s_getProcAddressHelper; + static ProcAddress getProcAddress(const char * name); +}; diff --git a/source/examples/cubescape-qt-gles/Painter.cpp b/source/examples/cubescape-qt-gles/Painter.cpp new file mode 100644 index 000000000..27c87acdc --- /dev/null +++ b/source/examples/cubescape-qt-gles/Painter.cpp @@ -0,0 +1,52 @@ + +#include "Painter.h" + +#include + +#include + +#include + + +Painter::Painter() + : m_initialized(false) + , m_cubescape(nullptr) +{ +} + +Painter::~Painter() +{ + delete m_cubescape; +} + +void Painter::initialize(ProcAddressGetter procAddressCallback) +{ + if (m_initialized) + return; + + glbinding::initialize(procAddressCallback, false); // only resolve functions that are actually used (lazy) + + m_cubescape = new CubeScape(); + + m_initialized = true; +} + +void Painter::resize(int width, int height) +{ + m_cubescape->resize(width, height); +} + +void Painter::draw() +{ + m_cubescape->draw(); +} + +void Painter::setNumCubes(int numCubes) +{ + m_cubescape->setNumCubes(numCubes); +} + +int Painter::numCubes() const +{ + return m_cubescape->numCubes(); +} diff --git a/source/examples/cubescape-qt-gles/Painter.h b/source/examples/cubescape-qt-gles/Painter.h new file mode 100644 index 000000000..b6822aa9d --- /dev/null +++ b/source/examples/cubescape-qt-gles/Painter.h @@ -0,0 +1,36 @@ + +#pragma once + + +#include + + +class CubeScape; + +// wrapper for cubescape to avoid overlapping qopengl and glbinding includes + +// Note: Qt could use a NO_GL_FUNCTIONS define (similar to GLFW_INCLUDE_NONE), but for +// now the QOpenGLContext is tightly coupled with qopengl.h and QOpenGLFunctions. + +using ProcAddress = void(*)(); +using ProcAddressGetter = ProcAddress(*)(const char*); + +class Painter +{ +public: + Painter(); + ~Painter(); + + void initialize(ProcAddressGetter procAddressCallback); + + void resize(int width, int height); + void draw(); + + void setNumCubes(int numCubes); + int numCubes() const; + +protected: + bool m_initialized; + + CubeScape * m_cubescape; +}; diff --git a/source/examples/cubescape-qt-gles/Viewer.cpp b/source/examples/cubescape-qt-gles/Viewer.cpp new file mode 100644 index 000000000..ab61d5380 --- /dev/null +++ b/source/examples/cubescape-qt-gles/Viewer.cpp @@ -0,0 +1,163 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Canvas.h" +#include "Viewer.h" + +#include "ui_Viewer.h" + + +namespace +{ + const QString SETTINGS_GEOMETRY ("Geometry"); + const QString SETTINGS_STATE ("State"); + + const QString SETTINGS_ADAPTIVE_GRID("ShowAdaptiveGrid"); +} + +Viewer::Viewer( + const QSurfaceFormat & format +, QWidget * parent +, Qt::WindowFlags flags) + +: QMainWindow(parent, flags) +, m_ui(new Ui_Viewer) +, m_canvas(nullptr) +, m_fullscreenShortcut(nullptr) +, m_swapIntervalShortcut(nullptr) +{ + m_ui->setupUi(this); + setWindowTitle(QApplication::applicationDisplayName()); + + setup(); + setupCanvas(format); + + restore(); + + updateAfterFullScreenToggle(); +} + + +Viewer::~Viewer() +{ + store(); + + setCentralWidget(nullptr); + + delete m_canvas; +} + +void Viewer::restore() +{ + QSettings::setDefaultFormat(QSettings::IniFormat); + QSettings s; + + restoreGeometry(s.value(SETTINGS_GEOMETRY).toByteArray()); + restoreState(s.value(SETTINGS_STATE).toByteArray()); +} + +void Viewer::store() +{ + QSettings s; + s.setValue(SETTINGS_GEOMETRY, saveGeometry()); + s.setValue(SETTINGS_STATE, saveState()); +} + +void Viewer::setup() +{ + // ToDo: this seems to be a generic problem (should be done by qt main window itself but....) + // We need to parse all available shortcuts via any menubars and connect those... + + m_fullscreenShortcut.reset(new QShortcut(m_ui->toggleFullScreenAction->shortcut(), this)); + connect(m_fullscreenShortcut.data(), &QShortcut::activated, this, &Viewer::toggleFullScreen); + + m_swapIntervalShortcut.reset(new QShortcut(m_ui->toggleSwapIntervalAction->shortcut(), this)); + connect(m_swapIntervalShortcut.data(), &QShortcut::activated, this, &Viewer::toggleSwapInterval); + + m_fpsLabel = new QLabel(m_ui->statusbar); + m_ui->statusbar->addPermanentWidget(m_fpsLabel); + + m_numLabel = new QLabel(m_ui->statusbar); + m_ui->statusbar->addPermanentWidget(m_numLabel); + +} + +void Viewer::setupCanvas(const QSurfaceFormat & format) +{ + m_canvas = new Canvas(format); + m_canvas->setContinuousRepaint(true, 0); + m_canvas->setSwapInterval(Canvas::VerticalSyncronization); + + connect(m_canvas, &Canvas::fpsUpdate, this, &Viewer::fpsChanged); + connect(m_canvas, &Canvas::numCubesUpdate, this, &Viewer::numCubesChanged); + + QWidget * widget = QWidget::createWindowContainer(m_canvas); + widget->setMinimumSize(1, 1); + widget->setAutoFillBackground(false); // Important for overdraw, not occluding the scene. + widget->setFocusPolicy(Qt::TabFocus); + + setCentralWidget(widget); + show(); +} + +void Viewer::fpsChanged(float fps) +{ + m_fpsLabel->setText(QString(" %1 fps ") + .arg(fps, 2, 'g', 4)); +} + +void Viewer::numCubesChanged(int numCubes) +{ + m_numLabel->setText(QString("#cubes: %2 (%1 x %1)") + .arg(numCubes).arg(numCubes * numCubes)); +} + +void Viewer::on_toggleFullScreenAction_triggered(bool) +{ + toggleFullScreen(); +} + +void Viewer::toggleFullScreen() +{ + if (isFullScreen()) + showNormal(); + else + showFullScreen(); + + updateAfterFullScreenToggle(); +} + +void Viewer::updateAfterFullScreenToggle() +{ + m_ui->menubar->setVisible(isFullScreen()); + m_ui->statusbar->setVisible(isFullScreen()); + + m_ui->menubar->setVisible(!isFullScreen()); + m_ui->statusbar->setVisible(!isFullScreen()); + m_fullscreenShortcut->setEnabled(isFullScreen()); + m_swapIntervalShortcut->setEnabled(isFullScreen()); +} + +void Viewer::on_toggleSwapIntervalAction_triggered(bool) +{ + toggleSwapInterval(); +} + +void Viewer::toggleSwapInterval() +{ + assert(m_canvas); + m_canvas->toggleSwapInterval(); +} + +void Viewer::on_quitAction_triggered(bool) +{ + QApplication::quit(); +} diff --git a/source/examples/cubescape-qt-gles/Viewer.h b/source/examples/cubescape-qt-gles/Viewer.h new file mode 100644 index 000000000..f688e00b4 --- /dev/null +++ b/source/examples/cubescape-qt-gles/Viewer.h @@ -0,0 +1,60 @@ + +#pragma once + +#include +#include + + +class Ui_Viewer; + +class QLabel; +class QSurfaceFormat; +class QShortcut; + +class Canvas; + + +class Viewer : public QMainWindow +{ + Q_OBJECT + +public: + Viewer( + const QSurfaceFormat & format + , QWidget * parent = nullptr + , Qt::WindowFlags flags = Qt::WindowFlags()); + + virtual ~Viewer(); + +public slots: + void fpsChanged(float fps); + void numCubesChanged(int numCubes); + +protected slots: + void on_toggleFullScreenAction_triggered(bool checked); + void toggleFullScreen(); + void on_toggleSwapIntervalAction_triggered(bool checked); + void toggleSwapInterval(); + + void on_quitAction_triggered(bool checked); + +protected: + void setup(); + void setupCanvas(const QSurfaceFormat & format); + + void store(); + void restore(); + + void updateAfterFullScreenToggle(); + +protected: + const QScopedPointer m_ui; + + Canvas * m_canvas; + + QLabel * m_fpsLabel; + QLabel * m_numLabel; + + QScopedPointer m_fullscreenShortcut; + QScopedPointer m_swapIntervalShortcut; +}; diff --git a/source/examples/cubescape-qt-gles/Viewer.ui b/source/examples/cubescape-qt-gles/Viewer.ui new file mode 100644 index 000000000..ac5718f27 --- /dev/null +++ b/source/examples/cubescape-qt-gles/Viewer.ui @@ -0,0 +1,387 @@ + + + Viewer + + + + 0 + 0 + 734 + 541 + + + + + + + + + + 0 + 0 + 734 + 21 + + + + + &View + + + + + + + &File + + + + + + &Help + + + + + + + + + + + true + + + false + + + Toggle &Debug Mode + + + QAction::ApplicationSpecificRole + + + + + true + + + false + + + Toggle &Print Mode + + + QAction::ApplicationSpecificRole + + + + + false + + + true + + + Toggle &Full Screen + + + F11 + + + QAction::ApplicationSpecificRole + + + + + false + + + Specify Resolution ... + + + QAction::ApplicationSpecificRole + + + + + false + + + Capture Camera Path ... + + + QAction::ApplicationSpecificRole + + + + + false + + + About ... + + + QAction::AboutRole + + + + + true + + + &Close + + + QAction::QuitRole + + + + + false + + + &Drive Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + &Play Camera Path ... + + + QAction::ApplicationSpecificRole + + + + + false + + + &Flight Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + &Terrain Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + Track&ball Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + 3D Tree&map Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + FPS Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + &Specify Benchmark ... + + + QAction::ApplicationSpecificRole + + + + + false + + + &Run Benchmarks ... + + + QAction::ApplicationSpecificRole + + + + + false + + + Manage &Configurations ... + + + QAction::ApplicationSpecificRole + + + + + false + + + &Preferences ... + + + QAction::PreferencesRole + + + + + false + + + List of named FBOs + + + + + false + + + &Show Frame Buffers ... + + + + + false + + + &UFO Manipulator + + + QAction::ApplicationSpecificRole + + + + + false + + + Select V&antage Point ... + + + QAction::ApplicationSpecificRole + + + + + false + + + Create Vantage Point + + + QAction::ApplicationSpecificRole + + + + + false + + + Toggle &Logo + + + + + false + + + &Load Presentation ... + + + + + false + + + Capture &Image + + + + + false + + + Capture &Image (Advanced) ... + + + + + false + + + Capture &Movie + + + + + Toggle &Swap Interval + + + F10 + + + + + true + + + true + + + Show Adaptive &Grid + + + G + + + + + &Toggle Time + + + T + + + + + &Restart Time + + + + + + diff --git a/source/examples/cubescape-qt-gles/main.cpp b/source/examples/cubescape-qt-gles/main.cpp new file mode 100644 index 000000000..4875f084a --- /dev/null +++ b/source/examples/cubescape-qt-gles/main.cpp @@ -0,0 +1,28 @@ + +#include +#include + +#include + +#include "Viewer.h" + + +int main(int argc, char * argv[]) +{ + QApplication app(argc, argv); + + QSurfaceFormat format; + format.setDepthBufferSize(16); + +// #ifdef SYSTEM_DARWIN +// format.setVersion(3, 2); +// format.setProfile(QSurfaceFormat::CoreProfile); +// #endif + + format.setVersion(3, 2); + format.setRenderableType(QSurfaceFormat::OpenGLES); + + QScopedPointer viewer(new Viewer(format)); + + return app.exec(); +} diff --git a/source/examples/cubescape-sdl/CMakeLists.txt b/source/examples/cubescape-sdl-gl/CMakeLists.txt similarity index 89% rename from source/examples/cubescape-sdl/CMakeLists.txt rename to source/examples/cubescape-sdl-gl/CMakeLists.txt index a927035a9..550f62107 100644 --- a/source/examples/cubescape-sdl/CMakeLists.txt +++ b/source/examples/cubescape-sdl-gl/CMakeLists.txt @@ -11,12 +11,14 @@ find_package(SDL2 QUIET) # # Target name -set(target cubescape-sdl) +set(target cubescape-sdl-gl) # Exit here if required dependencies are not met if (NOT TARGET SDL2::SDL2) message("Example ${target} skipped: SDL2 not found") return() +else() + message(STATUS "Example ${target}") endif() diff --git a/source/examples/cubescape-sdl/main.cpp b/source/examples/cubescape-sdl-gl/main.cpp similarity index 100% rename from source/examples/cubescape-sdl/main.cpp rename to source/examples/cubescape-sdl-gl/main.cpp diff --git a/source/examples/cubescape-sdl-gles/CMakeLists.txt b/source/examples/cubescape-sdl-gles/CMakeLists.txt new file mode 100644 index 000000000..e78ef9d3d --- /dev/null +++ b/source/examples/cubescape-sdl-gles/CMakeLists.txt @@ -0,0 +1,137 @@ + +# +# External dependencies +# + +find_package(SDL2 QUIET) + + +# +# Executable name and options +# + +# Target name +set(target cubescape-sdl-gles) + +# Exit here if required dependencies are not met +if (NOT TARGET SDL2::SDL2) + message("Example ${target} skipped: SDL2 not found") + return() +else() + message(STATUS "Example ${target}") +endif() + + +# +# Sources +# + +set(sources + main.cpp +) + + +# +# Create executable +# + +# Build executable +add_executable(${target} + MACOSX_BUNDLE + ${sources} +) + +# Create namespaced alias +add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target}) + + +# +# Project options +# + +set_target_properties(${target} + PROPERTIES + ${DEFAULT_PROJECT_OPTIONS} + INSTALL_RPATH "${EXECUTABLE_INSTALL_RPATH}" + FOLDER "${IDE_FOLDER}" +) + + +# +# Include directories +# + +target_include_directories(${target} + PRIVATE + ${DEFAULT_INCLUDE_DIRECTORIES} + ${PROJECT_BINARY_DIR}/source/include + SYSTEM +) + + +# +# Libraries +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LIBRARIES} + SDL2::SDL2 + SDL2::SDL2main + ${META_PROJECT_NAME}::glbinding + ${META_PROJECT_NAME}::glbinding-aux + ${META_PROJECT_NAME}::cubescape-shared-gles +) + + +# +# Compile definitions +# + +target_compile_definitions(${target} + PRIVATE + ${DEFAULT_COMPILE_DEFINITIONS} +) + + +# +# Compile options +# + +target_compile_options(${target} + PRIVATE + ${DEFAULT_COMPILE_OPTIONS_PRIVATE} + PUBLIC + ${DEFAULT_COMPILE_OPTIONS_PUBLIC} +) + + +# +# Linker options +# + +target_link_libraries(${target} + PRIVATE + ${DEFAULT_LINKER_OPTIONS} +) + + +# +# Target Health +# + +perform_health_checks( + ${target} + ${sources} +) + + +# +# Deployment +# + +# Executable +install(TARGETS ${target} + RUNTIME DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_sdl + BUNDLE DESTINATION ${INSTALL_EXAMPLES} COMPONENT examples_sdl +) diff --git a/source/examples/cubescape-sdl-gles/main.cpp b/source/examples/cubescape-sdl-gles/main.cpp new file mode 100644 index 000000000..dea92b3a6 --- /dev/null +++ b/source/examples/cubescape-sdl-gles/main.cpp @@ -0,0 +1,178 @@ + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + + +using namespace gl; +using namespace glbinding; + + +namespace +{ + CubeScape * cubescape(nullptr); + SDL_Window* gWindow = nullptr; + SDL_GLContext gContext; + bool quit = false; +} + + +void framebuffer_resize() +{ + int width, height; + SDL_GL_GetDrawableSize(gWindow, &width, &height); + cubescape->resize(width, height); +} + +void key_callback(SDL_Event e) +{ + const auto key = e.key.keysym.sym; + const auto mod = e.key.keysym.mod; + + bool numCubesChanged = false; + + if (key == SDLK_q && (mod & KMOD_CTRL) && (e.type == SDL_KEYDOWN)) + { + quit = true; + } + + if (key == SDLK_i && (e.type == SDL_KEYDOWN)) + { + cubescape->setNumCubes(cubescape->numCubes() + 1); + numCubesChanged = true; + } + + if (key == SDLK_d && (e.type == SDL_KEYDOWN)) + { + cubescape->setNumCubes(cubescape->numCubes() - 1); + numCubesChanged = true; + } + + if (numCubesChanged) + { + const int n = cubescape->numCubes(); + std::cout << "#cubes = " << n << " * " << n << " = " << n * n << std::endl; + } +} + +int main(int, char *[]) +{ + if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) + { + std::cout << "#SDL2: SDL could not initialize! SDL Error: " << SDL_GetError() << std::endl; + + return 1; + } + + //Use OpenGL ES 3.2 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + + //Create window + gWindow = SDL_CreateWindow( "Cubescape", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1440, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN ); + if( gWindow == nullptr ) + { + std::cout << "#SDL2: Window could not be created! SDL Error: " << SDL_GetError() << std::endl; + + return 1; + } + + SDL_SetWindowResizable(gWindow, SDL_TRUE); + + //Create context + gContext = SDL_GL_CreateContext( gWindow ); + if( gContext == NULL ) + { + std::cout << "#SDL2: OpenGL context could not be created! SDL Error: " << SDL_GetError() << std::endl; + + return 1; + } + + // initialize glbinding + glbinding::initialize(reinterpret_cast(SDL_GL_GetProcAddress), false); // only resolve functions that are actually used (lazy) + glbinding::aux::enableGetErrorCallback(); + + //Use Vsync + if( SDL_GL_SetSwapInterval( 1 ) < 0 ) + { + std::cout << "SDL2: Unable to set VSync! SDL Error: " << SDL_GetError() << std::endl; + } + + // // print some gl infos (query) + + std::cout << std::endl + << "OpenGL ES Version: " << aux::ContextInfo::version() << std::endl + << "OpenGL ES Vendor: " << aux::ContextInfo::vendor() << std::endl + << "OpenGL ES Renderer: " << aux::ContextInfo::renderer() << std::endl; + + std::cout << std::endl + << "Press i or d to either increase or decrease number of cubes." << std::endl << std::endl; + + + cubescape = new CubeScape(); + + int width, height; + SDL_GL_GetDrawableSize(gWindow, &width, &height); + cubescape->resize(width, height); + + //Event handler + SDL_Event e; + + //Enable text input + SDL_StartTextInput(); + + //While application is running + while( !quit ) + { + //Handle events on queue + while(SDL_PollEvent(&e) != 0) + { + //User requests quit + if(e.type == SDL_QUIT) + { + quit = true; + } + else if (e.type == SDL_KEYDOWN) + { + key_callback(e); + } + else if (e.type == SDL_WINDOWEVENT) + { + if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + framebuffer_resize(); + } + } + } + + //Render quad + cubescape->draw(); + + //Update screen + SDL_GL_SwapWindow( gWindow ); + } + + //Disable text input + SDL_StopTextInput(); + + SDL_DestroyWindow(gWindow); + SDL_Quit(); + + return 0; +} diff --git a/source/examples/cubescape-shared-gl/CubeScape.h b/source/examples/cubescape-shared-gl/CubeScape.h index 37905555f..d7e3e8438 100644 --- a/source/examples/cubescape-shared-gl/CubeScape.h +++ b/source/examples/cubescape-shared-gl/CubeScape.h @@ -10,6 +10,7 @@ class CubeScape { + using clock = std::chrono::system_clock; public: CubeScape(); ~CubeScape(); @@ -44,6 +45,5 @@ class CubeScape mat4 m_view; mat4 m_projection; - using clock = std::chrono::system_clock; clock::time_point m_time; }; diff --git a/source/examples/cubescape-shared-gles/CubeScape.cpp b/source/examples/cubescape-shared-gles/CubeScape.cpp index aba1a080f..f4d3d9077 100644 --- a/source/examples/cubescape-shared-gles/CubeScape.cpp +++ b/source/examples/cubescape-shared-gles/CubeScape.cpp @@ -34,15 +34,6 @@ bool readFile(const std::string & filePath, std::string & content) return true; } -// convenience -std::string readFile(const std::string & filePath) -{ - std::string content; - readFile(filePath, content); - - return content; -} - std::string determineDataPath() { #ifdef cpplocate_FOUND @@ -61,10 +52,13 @@ std::string determineDataPath() CubeScape::CubeScape() -: a_vertex(-1) +: m_initialized(false) +, a_vertex(-1) , u_transform(-1) , u_time(-1) , u_numcubes(-1) +, u_terrain(-1) +, u_patches(-1) , m_vao(0) , m_indices(0) , m_vertices(0) @@ -79,9 +73,19 @@ CubeScape::CubeScape() GLuint gs = glCreateShader(GL_GEOMETRY_SHADER); GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); - std::string vertexSource = readFile(dataPath + "/cubescape-gles/cubescape.vert"); - std::string geometrySource = readFile(dataPath + "/cubescape-gles/cubescape.geom"); - std::string fragmentSource = readFile(dataPath + "/cubescape-gles/cubescape.frag"); + std::string vertexSource; + std::string geometrySource; + std::string fragmentSource; + + auto success = readFile(dataPath + "/cubescape-gles/cubescape.vert", vertexSource); + success &= readFile(dataPath + "/cubescape-gles/cubescape.geom", geometrySource); + success &= readFile(dataPath + "/cubescape-gles/cubescape.frag", fragmentSource); + + if (!success) + { + std::cerr << "Could not load shaders in " << dataPath + "/cubescape-gles/cubescape.*" << "." << std::endl; + return; + } const char * vertSource = vertexSource.c_str(); const char * geomSource = geometrySource.c_str(); @@ -108,6 +112,23 @@ CubeScape::CubeScape() glLinkProgram(m_program); link_info(m_program); + glUseProgram(m_program); + + // setup uniforms + + u_transform = glGetUniformLocation(m_program, "modelViewProjection"); + u_time = glGetUniformLocation(m_program, "time"); + u_numcubes = glGetUniformLocation(m_program, "numcubes"); + + m_time = clock::now(); + + u_terrain = glGetUniformLocation(m_program, "terrain"); + u_patches = glGetUniformLocation(m_program, "patches"); + + a_vertex = glGetAttribLocation(m_program, "a_vertex"); + + glUseProgram(0); + // create textures glGenTextures(2, m_textures); @@ -144,7 +165,6 @@ CubeScape::CubeScape() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 64, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, patches.data()); } - // create cube static const GLfloat vertices_data[24] = @@ -173,45 +193,26 @@ CubeScape::CubeScape() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (6 * 3) * sizeof(GLubyte), indices_data, GL_STATIC_DRAW); - // setup uniforms - - a_vertex = glGetAttribLocation(m_program, "a_vertex"); glEnableVertexAttribArray(static_cast(a_vertex)); glVertexAttribPointer(static_cast(a_vertex), 3, GL_FLOAT, GL_FALSE, 0, nullptr); - u_transform = glGetUniformLocation(m_program, "modelViewProjection"); - u_time = glGetUniformLocation(m_program, "time"); - u_numcubes = glGetUniformLocation(m_program, "numcubes"); - - m_time = clock::now(); - - GLint terrain = glGetUniformLocation(m_program, "terrain"); - GLint patches = glGetUniformLocation(m_program, "patches"); - - // since only single program and single data is used, bind only once - - glEnable(GL_DEPTH_TEST); - - glClearColor(0.f, 0.f, 0.f, 1.0f); - - glUseProgram(m_program); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_textures[0]); - glUniform1i(terrain, 0); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_textures[1]); - glUniform1i(patches, 1); + glBindVertexArray(0); // view m_view = mat4::lookAt(0.f, 0.8f,-2.0f, 0.f, -1.2f, 0.f, 0.f, 1.f, 0.f); + + m_initialized = true; } CubeScape::~CubeScape() { + if (!m_initialized) + { + return; + } + glDeleteBuffers(1, &m_vertices); glDeleteBuffers(1, &m_indices); @@ -222,6 +223,7 @@ void CubeScape::setNumCubes(int _numCubes) { m_numcubes = std::min(4096, std::max(1, _numCubes)); } + int CubeScape::numCubes() const { return m_numcubes; @@ -236,8 +238,25 @@ void CubeScape::resize(int width, int height) void CubeScape::draw() { + if (!m_initialized) + { + return; + } + + glClearColor(0.f, 0.f, 0.f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUseProgram(m_program); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textures[0]); + glUniform1i(u_terrain, 0); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textures[1]); + glUniform1i(u_patches, 1); + auto ms = std::chrono::duration_cast(clock::now() - m_time); float t = static_cast(ms.count()) * 1e-3f; @@ -247,5 +266,11 @@ void CubeScape::draw() glUniform1f(u_time, t); glUniform1i(u_numcubes, m_numcubes); + glEnable(GL_DEPTH_TEST); + + glBindVertexArray(m_vao); glDrawElementsInstanced(GL_TRIANGLES, 18, GL_UNSIGNED_BYTE, 0, m_numcubes * m_numcubes); + + glBindVertexArray(0); + glUseProgram(0); } diff --git a/source/examples/cubescape-shared-gles/CubeScape.h b/source/examples/cubescape-shared-gles/CubeScape.h index 68a24d979..ae769d5e3 100644 --- a/source/examples/cubescape-shared-gles/CubeScape.h +++ b/source/examples/cubescape-shared-gles/CubeScape.h @@ -10,6 +10,8 @@ class CubeScape { + using clock = std::chrono::system_clock; + public: CubeScape(); ~CubeScape(); @@ -21,10 +23,14 @@ class CubeScape int numCubes() const; protected: + bool m_initialized; + gl::GLint a_vertex; gl::GLint u_transform; gl::GLint u_time; gl::GLint u_numcubes; + gl::GLint u_terrain; + gl::GLint u_patches; gl::GLuint m_vao; gl::GLuint m_indices; @@ -40,6 +46,5 @@ class CubeScape mat4 m_view; mat4 m_projection; - using clock = std::chrono::system_clock; clock::time_point m_time; }; diff --git a/source/examples/cubescape-wgl/CMakeLists.txt b/source/examples/cubescape-wgl/CMakeLists.txt index 01e3809fe..2a89aa73c 100644 --- a/source/examples/cubescape-wgl/CMakeLists.txt +++ b/source/examples/cubescape-wgl/CMakeLists.txt @@ -28,6 +28,8 @@ endif() if (NOT glfw3_FOUND) message("Example ${target} skipped: glfw3 not found") return() +else() + message(STATUS "Example ${target}") endif()