diff --git a/examples/python/anari_tutorial.py b/examples/python/anari_tutorial.py index 560d789c..e9197b4a 100644 --- a/examples/python/anari_tutorial.py +++ b/examples/python/anari_tutorial.py @@ -81,6 +81,7 @@ def anari_status(device, source, sourceType, severity, code, message): anariCommitParameters(device, mesh) material = anariNewMaterial(device, 'matte') +anariSetParameter(device, material, 'color', ANARI_STRING, 'color') anariCommitParameters(device, material) surface = anariNewSurface(device) diff --git a/examples/viewer/SceneSelector.cpp b/examples/viewer/SceneSelector.cpp index 5832f28e..aa026f39 100644 --- a/examples/viewer/SceneSelector.cpp +++ b/examples/viewer/SceneSelector.cpp @@ -25,7 +25,7 @@ static void buildUISceneHandle( /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -SceneSelector::SceneSelector(const char *name) : Window(name, true) +SceneSelector::SceneSelector(Application *app, const char *name) : Window(app, name, true) { m_categories = anari::scenes::getAvailableSceneCategories(); m_scenes.resize(m_categories.size()); diff --git a/examples/viewer/SceneSelector.h b/examples/viewer/SceneSelector.h index af44e2c3..05afeefa 100644 --- a/examples/viewer/SceneSelector.h +++ b/examples/viewer/SceneSelector.h @@ -18,7 +18,7 @@ using SceneSelectionCallback = std::function; struct SceneSelector : public Window { - SceneSelector(const char *name = "Scene"); + SceneSelector(Application *app, const char *name = "Scene"); ~SceneSelector(); void buildUI() override; diff --git a/examples/viewer/main.cpp b/examples/viewer/main.cpp index ac6b0d17..019dfd38 100644 --- a/examples/viewer/main.cpp +++ b/examples/viewer/main.cpp @@ -107,12 +107,12 @@ struct Application : public anari_viewer::Application if (g_useDefaultLayout) ImGui::LoadIniSettingsFromMemory(getDefaultUILayout()); - auto *viewport = new anari_viewer::windows::Viewport(g_device, "Viewport"); + auto *viewport = new anari_viewer::windows::Viewport(this, g_device, "Viewport"); viewport->setManipulator(&m_state.manipulator); - auto *leditor = new anari_viewer::windows::LightsEditor(g_device); + auto *leditor = new anari_viewer::windows::LightsEditor(this, g_device); - auto *sselector = new anari_viewer::windows::SceneSelector(); + auto *sselector = new anari_viewer::windows::SceneSelector(this); sselector->setCallback([=](const char *category, const char *scene) { try { auto s = anari::scenes::createScene(g_device, category, scene); diff --git a/src/anari_viewer/Application.cpp b/src/anari_viewer/Application.cpp index ce2528d8..ebec83d9 100644 --- a/src/anari_viewer/Application.cpp +++ b/src/anari_viewer/Application.cpp @@ -2,14 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 #include "Application.h" -// glad -#include "glad/glad.h" -// glfw -#include +#include "windows/Window.h" +// sdl +#include +#include // imgui #define IMGUI_DISABLE_INCLUDE_IMCONFIG_H -#include "imgui_impl_glfw.h" -#include "imgui_impl_opengl2.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_sdlrenderer3.h" // std #include #include @@ -18,14 +18,10 @@ namespace anari_viewer { -static void glfw_error_callback(int error, const char *description) -{ - fprintf(stderr, "Glfw Error %d: %s\n", error, description); -} - struct AppImpl { - GLFWwindow *window{nullptr}; + SDL_Window *window{nullptr}; + SDL_Renderer *sdl_renderer{nullptr}; int width{0}; int height{0}; bool windowResized{true}; @@ -44,7 +40,6 @@ struct AppImpl Application::Application() { m_impl = std::make_shared(); - glfwSetErrorCallback(glfw_error_callback); } void Application::uiFrameStart() @@ -57,6 +52,11 @@ void Application::uiFrameEnd() // no-op } +SDL_Renderer* Application::sdlRenderer() +{ + return m_impl->sdl_renderer; +} + void Application::run(int width, int height, const char *name) { m_impl->width = width; @@ -87,19 +87,28 @@ void Application::mainLoop() { auto window = m_impl->window; - while (!glfwWindowShouldClose(window)) { + bool open = true; + while (open) { m_impl->frameStartTime = m_impl->frameEndTime; m_impl->frameEndTime = std::chrono::steady_clock::now(); - glfwPollEvents(); - - ImGui_ImplOpenGL2_NewFrame(); - ImGui_ImplGlfw_NewFrame(); + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL3_ProcessEvent(&event); + if (event.type == SDL_EVENT_QUIT) + open = false; + if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) + open = false; + } + + ImGui_ImplSDLRenderer3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); ImGui::NewFrame(); ImGuiIO &io = ImGui::GetIO(); - if (io.KeysDown[GLFW_KEY_Q] && io.KeysDown[GLFW_KEY_LEFT_CONTROL]) - glfwSetWindowShouldClose(window, 1); + // if (io.KeysDown[GLFW_KEY_Q] && io.KeysDown[GLFW_KEY_LEFT_CONTROL]) + // open = false; uiFrameStart(); @@ -128,12 +137,15 @@ void Application::mainLoop() ImGui::End(); ImGui::Render(); + m_impl->width = io.DisplaySize.x; + m_impl->height = io.DisplaySize.y; - glClearColor(0.1f, 0.1f, 0.1f, 1.f); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); + auto sdl_renderer = m_impl->sdl_renderer; + SDL_SetRenderDrawColorFloat(sdl_renderer, 0.1f, 0.1f, 0.1f, 1.f); + SDL_RenderClear(sdl_renderer); + ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), sdl_renderer); + SDL_RenderPresent(sdl_renderer); - glfwSwapBuffers(window); m_impl->windowResized = false; uiFrameEnd(); @@ -142,38 +154,33 @@ void Application::mainLoop() void AppImpl::init() { - if (!glfwInit()) - throw std::runtime_error("failed to initialize GLFW"); + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) + throw std::runtime_error("failed to initialize SDL"); - glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE); - window = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); - if (window == nullptr) - throw std::runtime_error("failed to create GLFW window"); + Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + window = SDL_CreateWindow(name.c_str(), width, height, window_flags); - glfwSetWindowUserPointer(window, this); + if (window == nullptr) + throw std::runtime_error("failed to create SDL window"); - glfwMakeContextCurrent(window); - glfwSwapInterval(1); + sdl_renderer = SDL_CreateRenderer(window, nullptr); - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - glfwTerminate(); - throw std::runtime_error("Failed to load GL"); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + if (sdl_renderer == nullptr) + { + SDL_DestroyWindow(window); + SDL_Quit(); + throw std::runtime_error("Failed to create SDL renderer"); } - glfwSetFramebufferSizeCallback( - window, [](GLFWwindow *w, int newWidth, int newHeight) { - auto *app = (AppImpl *)glfwGetWindowUserPointer(w); - app->width = newWidth; - app->height = newHeight; - app->windowResized = true; - }); + SDL_ShowWindow(window); ImGui::CreateContext(); ImGui::StyleColorsDark(); - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL2_Init(); + ImGui_ImplSDL3_InitForSDLRenderer(window, sdl_renderer); + ImGui_ImplSDLRenderer3_Init(sdl_renderer); ImGuiIO &io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; @@ -204,13 +211,13 @@ void AppImpl::cleanup() { windows.clear(); - ImGui_ImplOpenGL2_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - + ImGui_ImplSDLRenderer3_Shutdown(); + ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); - glfwDestroyWindow(window); - glfwTerminate(); + SDL_DestroyRenderer(sdl_renderer); + SDL_DestroyWindow(window); + SDL_Quit(); window = nullptr; } diff --git a/src/anari_viewer/Application.h b/src/anari_viewer/Application.h index 940dd6a7..871f1894 100644 --- a/src/anari_viewer/Application.h +++ b/src/anari_viewer/Application.h @@ -3,7 +3,7 @@ #pragma once -#include "windows/Window.h" +#include // std #include #include @@ -12,6 +12,10 @@ namespace anari_viewer { struct AppImpl; + +namespace windows { +struct Window; +} using WindowArray = std::vector>; class Application @@ -29,6 +33,8 @@ class Application // Allow teardown of objects before application destruction virtual void teardown() = 0; + SDL_Renderer* sdlRenderer(); + // Start the application run loop void run(int width, int height, const char *name); diff --git a/src/anari_viewer/CMakeLists.txt b/src/anari_viewer/CMakeLists.txt index 3bf6a510..1bb00a55 100644 --- a/src/anari_viewer/CMakeLists.txt +++ b/src/anari_viewer/CMakeLists.txt @@ -53,7 +53,7 @@ project_include_directories(INTERFACE ${CMAKE_CURRENT_LIST_DIR}/..) project_link_libraries(INTERFACE anari::anari anari_viewer_glad - anari_viewer_imgui_glfw + anari_viewer_imgui_sdl anari_viewer_nfd anari_viewer_stb_image ) diff --git a/src/anari_viewer/external/imgui/CMakeLists.txt b/src/anari_viewer/external/imgui/CMakeLists.txt index 9dcdf732..e1555a29 100644 --- a/src/anari_viewer/external/imgui/CMakeLists.txt +++ b/src/anari_viewer/external/imgui/CMakeLists.txt @@ -1,39 +1,39 @@ ## Copyright 2023-2024 The Khronos Group ## SPDX-License-Identifier: Apache-2.0 -project(anari_viewer_imgui_glfw LANGUAGES CXX) +project(anari_viewer_imgui_sdl LANGUAGES CXX) anari_sdk_fetch_project( NAME ${PROJECT_NAME} - URL https://github.com/ocornut/imgui/archive/refs/tags/v1.91.0-docking.zip - MD5 8098badecdd791acb0ac6056da4161a6 + URL https://github.com/ocornut/imgui/archive/refs/tags/v1.91.7-docking.zip + MD5 2cfbf7b7790076d6debe5060ec1fb47f ) include(CMakeFindDependencyMacro) set(OpenGL_GL_PREFERENCE "LEGACY") find_dependency(OpenGL 4 REQUIRED) -find_dependency(glfw3 REQUIRED) +find_dependency(SDL3 REQUIRED) project_add_library(INTERFACE) project_sources( INTERFACE - ${anari_viewer_imgui_glfw_LOCATION}/imgui.cpp - ${anari_viewer_imgui_glfw_LOCATION}/imgui_draw.cpp - ${anari_viewer_imgui_glfw_LOCATION}/imgui_demo.cpp - ${anari_viewer_imgui_glfw_LOCATION}/imgui_tables.cpp - ${anari_viewer_imgui_glfw_LOCATION}/imgui_widgets.cpp - ${anari_viewer_imgui_glfw_LOCATION}/backends/imgui_impl_glfw.cpp - ${anari_viewer_imgui_glfw_LOCATION}/backends/imgui_impl_opengl2.cpp - ${anari_viewer_imgui_glfw_LOCATION}/misc/cpp/imgui_stdlib.cpp + ${anari_viewer_imgui_sdl_LOCATION}/imgui.cpp + ${anari_viewer_imgui_sdl_LOCATION}/imgui_draw.cpp + ${anari_viewer_imgui_sdl_LOCATION}/imgui_demo.cpp + ${anari_viewer_imgui_sdl_LOCATION}/imgui_tables.cpp + ${anari_viewer_imgui_sdl_LOCATION}/imgui_widgets.cpp + ${anari_viewer_imgui_sdl_LOCATION}/backends/imgui_impl_sdl3.cpp + ${anari_viewer_imgui_sdl_LOCATION}/backends/imgui_impl_sdlrenderer3.cpp + ${anari_viewer_imgui_sdl_LOCATION}/misc/cpp/imgui_stdlib.cpp ) -project_link_libraries(INTERFACE glfw OpenGL::GL) +project_link_libraries(INTERFACE SDL3::SDL3 OpenGL::GL) project_include_directories( INTERFACE - ${anari_viewer_imgui_glfw_LOCATION} - ${anari_viewer_imgui_glfw_LOCATION}/backends - ${anari_viewer_imgui_glfw_LOCATION}/misc/cpp + ${anari_viewer_imgui_sdl_LOCATION} + ${anari_viewer_imgui_sdl_LOCATION}/backends + ${anari_viewer_imgui_sdl_LOCATION}/misc/cpp ) diff --git a/src/anari_viewer/windows/LightsEditor.cpp b/src/anari_viewer/windows/LightsEditor.cpp index 9136741e..0757c8f2 100644 --- a/src/anari_viewer/windows/LightsEditor.cpp +++ b/src/anari_viewer/windows/LightsEditor.cpp @@ -26,8 +26,8 @@ static const char *lightToType(Light::LightType type) } } -LightsEditor::LightsEditor(std::vector devices, const char *name) - : Window(name, true), m_devices(devices) +LightsEditor::LightsEditor(Application *app, std::vector devices, const char *name) + : Window(app, name, true), m_devices(devices) { for (auto d : m_devices) anari::retain(d, d); @@ -35,8 +35,8 @@ LightsEditor::LightsEditor(std::vector devices, const char *name) m_worlds.resize(m_devices.size(), nullptr); } -LightsEditor::LightsEditor(anari::Device device, const char *name) - : LightsEditor(std::vector{device}, name) +LightsEditor::LightsEditor(Application *app, anari::Device device, const char *name) + : LightsEditor(app, std::vector{device}, name) {} LightsEditor::~LightsEditor() diff --git a/src/anari_viewer/windows/LightsEditor.h b/src/anari_viewer/windows/LightsEditor.h index 010d5018..8252d889 100644 --- a/src/anari_viewer/windows/LightsEditor.h +++ b/src/anari_viewer/windows/LightsEditor.h @@ -36,9 +36,9 @@ struct Light struct LightsEditor : public Window { - LightsEditor( + LightsEditor(Application *app, std::vector devices, const char *name = "Lights Editor"); - LightsEditor(anari::Device device, const char *name = "Lights Editor"); + LightsEditor(Application *app, anari::Device device, const char *name = "Lights Editor"); ~LightsEditor(); void buildUI() override; diff --git a/src/anari_viewer/windows/Viewport.cpp b/src/anari_viewer/windows/Viewport.cpp index 40557a9f..1edf5f72 100644 --- a/src/anari_viewer/windows/Viewport.cpp +++ b/src/anari_viewer/windows/Viewport.cpp @@ -13,8 +13,8 @@ namespace anari_viewer::windows { // Viewport definitions /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -Viewport::Viewport(anari::Device device, const char *name) - : Window(name, true), m_device(device) +Viewport::Viewport(Application *app, anari::Device device, const char *name) + : Window(app, name, true), m_device(device) { setManipulator(nullptr); @@ -24,23 +24,13 @@ Viewport::Viewport(anari::Device device, const char *name) m_contextMenuName = "vpContextMenu_"; m_contextMenuName += name; - // GL // - - glGenTextures(1, &m_framebufferTexture); - glBindTexture(GL_TEXTURE_2D, m_framebufferTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA8, - m_viewportSize.x, - m_viewportSize.y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - 0); + auto renderer = m_app->sdlRenderer(); + m_framebufferTexture = SDL_CreateTexture( + renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + m_viewportSize.x, + m_viewportSize.y); // ANARI // @@ -102,7 +92,7 @@ void Viewport::buildUI() updateImage(); updateCamera(); - ImGui::Image((void *)(intptr_t)m_framebufferTexture, + ImGui::Image((ImTextureID)(intptr_t)m_framebufferTexture, ImGui::GetContentRegionAvail(), ImVec2(1, 0), ImVec2(0, 1)); @@ -175,18 +165,18 @@ void Viewport::reshape(anari::math::int2 newSize) m_viewportSize = newSize; - glViewport(0, 0, newSize.x, newSize.y); + auto renderer = m_app->sdlRenderer(); - glBindTexture(GL_TEXTURE_2D, m_framebufferTexture); - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA8, - newSize.x, - newSize.y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - 0); + SDL_DestroyTexture(m_framebufferTexture); + + m_framebufferTexture = SDL_CreateTexture( + renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + m_viewportSize.x, + m_viewportSize.y); + + updateFrame(); updateFrame(); updateCamera(true); @@ -275,27 +265,30 @@ void Viewport::updateImage() const bool isByteChannles = fb.pixelType == ANARI_UFIXED8_RGBA_SRGB || fb.pixelType == ANARI_UFIXED8_VEC4; if (isByteChannles) { - glBindTexture(GL_TEXTURE_2D, m_framebufferTexture); - glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - fb.width, - fb.height, - GL_RGBA, - GL_UNSIGNED_BYTE, - fb.data); + SDL_UpdateTexture(m_framebufferTexture, nullptr, fb.data, fb.width*4); + // glBindTexture(GL_TEXTURE_2D, m_framebufferTexture); + // glTexSubImage2D(GL_TEXTURE_2D, + // 0, + // 0, + // 0, + // fb.width, + // fb.height, + // GL_RGBA, + // GL_UNSIGNED_BYTE, + // fb.data); + + } else { - glBindTexture(GL_TEXTURE_2D, m_framebufferTexture); - glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - fb.width, - fb.height, - GL_RGBA, - GL_FLOAT, - fb.data); + // glBindTexture(GL_TEXTURE_2D, m_framebufferTexture); + // glTexSubImage2D(GL_TEXTURE_2D, + // 0, + // 0, + // 0, + // fb.width, + // fb.height, + // GL_RGBA, + // GL_FLOAT, + // fb.data); } } else { printf("mapped bad frame: %p | %i x %i\n", fb.data, fb.width, fb.height); @@ -329,10 +322,10 @@ void Viewport::ui_handleInput() const bool dolly = ImGui::IsMouseDown(ImGuiMouseButton_Right) || (ImGui::IsMouseDown(ImGuiMouseButton_Left) - && io.KeysDown[GLFW_KEY_LEFT_SHIFT]); + && io.KeyShift); const bool pan = ImGui::IsMouseDown(ImGuiMouseButton_Middle) || (ImGui::IsMouseDown(ImGuiMouseButton_Left) - && io.KeysDown[GLFW_KEY_LEFT_ALT]); + && io.KeyAlt); const bool orbit = ImGui::IsMouseDown(ImGuiMouseButton_Left); const bool anyMovement = dolly || pan || orbit; diff --git a/src/anari_viewer/windows/Viewport.h b/src/anari_viewer/windows/Viewport.h index d29329cf..c3850321 100644 --- a/src/anari_viewer/windows/Viewport.h +++ b/src/anari_viewer/windows/Viewport.h @@ -6,9 +6,7 @@ #include "../Orbit.h" #include "../ui_anari.h" // glad -#include "glad/glad.h" -// glfw -#include +#include // anari #include #include @@ -22,7 +20,7 @@ namespace anari_viewer::windows { struct Viewport : public Window { - Viewport(anari::Device device, const char *name = "Viewport"); + Viewport(Application *app, anari::Device device, const char *name = "Viewport"); ~Viewport(); void buildUI() override; @@ -92,7 +90,7 @@ struct Viewport : public Window // OpenGL + display - GLuint m_framebufferTexture{0}; + SDL_Texture *m_framebufferTexture; anari::math::int2 m_viewportSize{1920, 1080}; anari::math::int2 m_renderSize{1920, 1080}; diff --git a/src/anari_viewer/windows/Window.cpp b/src/anari_viewer/windows/Window.cpp index e1eef0b3..e157485d 100644 --- a/src/anari_viewer/windows/Window.cpp +++ b/src/anari_viewer/windows/Window.cpp @@ -5,8 +5,8 @@ namespace anari_viewer::windows { -Window::Window(const char *name, bool startShown, bool wrapBeginEnd) - : m_name(name), m_visible(startShown), m_wrapBeginEnd(wrapBeginEnd) +Window::Window(Application *app, const char *name, bool startShown, bool wrapBeginEnd) + : m_app(app), m_name(name), m_visible(startShown), m_wrapBeginEnd(wrapBeginEnd) {} void Window::renderUI() diff --git a/src/anari_viewer/windows/Window.h b/src/anari_viewer/windows/Window.h index 5db92c91..1ccc984f 100644 --- a/src/anari_viewer/windows/Window.h +++ b/src/anari_viewer/windows/Window.h @@ -11,11 +11,13 @@ #include #include +#include "../Application.h" + namespace anari_viewer::windows { struct Window { - Window(const char *name, bool startShown = false, bool wrapBeginEnd = true); + Window(Application *app, const char *name, bool startShown = false, bool wrapBeginEnd = true); virtual ~Window() = default; void renderUI(); @@ -31,6 +33,7 @@ struct Window protected: virtual void buildUI() = 0; + Application *const m_app; private: std::string m_name;