# include "renderer.h" # if RENDERER(IMGUI_OGL3) # include "platform.h" # include # include // std::intptr_t # include # include # include # include # define STB_IMAGE_WRITE_IMPLEMENTATION # include "../../external/stb_image_latest/stb_image_write.h" # if PLATFORM(WINDOWS) # define NOMINMAX # define WIN32_LEAN_AND_MEAN # include # endif # include "imgui_impl_opengl3.h" # if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) # include // Initialize with gl3wInit() # elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) # include // Initialize with glewInit() # elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) # include // Initialize with gladLoadGL() # elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) # include // Initialize with gladLoadGL(...) or gladLoaderLoadGL() # elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) # define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. # include // Initialize with glbinding::Binding::initialize() # include using namespace gl; # elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) # define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. # include // Initialize with glbinding::initialize() # include using namespace gl; # elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) # include IMGUI_IMPL_OPENGL_LOADER_CUSTOM # else # include "imgui_impl_opengl3_loader.h" # endif struct ImTexture { GLuint TextureID = 0; int Width = 0; int Height = 0; }; struct RendererOpenGL3 final : Renderer { bool Create(Platform& platform) override; void Destroy() override; void NewFrame() override; void RenderDrawData(ImDrawData* drawData) override; void Clear(const ImVec4& color) override; void Present() override; void Resize(int width, int height) override; ImVector::iterator FindTexture(ImTextureID texture); ImTextureID CreateTexture(const void* data, int width, int height) override; void DestroyTexture(ImTextureID texture) override; int GetTextureWidth(ImTextureID texture) override; int GetTextureHeight(ImTextureID texture) override; bool TakeScreenshot(const char* filename) override; Platform* m_Platform = nullptr; ImVector m_Textures; }; std::unique_ptr CreateRenderer() { return std::make_unique(); } bool RendererOpenGL3::Create(Platform& platform) { m_Platform = &platform; // Technically we should initialize OpenGL context here, // but for now we relay on one created by GLFW3 #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) bool err = gl3wInit() != 0; #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) bool err = glewInit() != GLEW_OK; #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) bool err = gladLoadGL() == 0; #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one. #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) bool err = false; glbinding::Binding::initialize(); #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) bool err = false; glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); }); #else bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization. #endif if (err) return false; # if PLATFORM(MACOS) const char* glslVersion = "#version 150"; # else const char* glslVersion = "#version 130"; # endif if (!ImGui_ImplOpenGL3_Init(glslVersion)) return false; m_Platform->SetRenderer(this); return true; } void RendererOpenGL3::Destroy() { if (!m_Platform) return; m_Platform->SetRenderer(nullptr); ImGui_ImplOpenGL3_Shutdown(); } void RendererOpenGL3::NewFrame() { ImGui_ImplOpenGL3_NewFrame(); } void RendererOpenGL3::RenderDrawData(ImDrawData* drawData) { ImGui_ImplOpenGL3_RenderDrawData(drawData); } void RendererOpenGL3::Clear(const ImVec4& color) { glClearColor(color.x, color.y, color.z, color.w); glClear(GL_COLOR_BUFFER_BIT); } void RendererOpenGL3::Present() { } void RendererOpenGL3::Resize(int width, int height) { glViewport(0, 0, width, height); } ImTextureID RendererOpenGL3::CreateTexture(const void* data, int width, int height) { m_Textures.resize(m_Textures.size() + 1); ImTexture& texture = m_Textures.back(); // Upload texture to graphics system GLint last_texture = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); glGenTextures(1, &texture.TextureID); glBindTexture(GL_TEXTURE_2D, texture.TextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glBindTexture(GL_TEXTURE_2D, last_texture); texture.Width = width; texture.Height = height; return reinterpret_cast(static_cast(texture.TextureID)); } ImVector::iterator RendererOpenGL3::FindTexture(ImTextureID texture) { auto textureID = static_cast(reinterpret_cast(texture)); return std::find_if(m_Textures.begin(), m_Textures.end(), [textureID](ImTexture& texture) { return texture.TextureID == textureID; }); } void RendererOpenGL3::DestroyTexture(ImTextureID texture) { auto textureIt = FindTexture(texture); if (textureIt == m_Textures.end()) return; glDeleteTextures(1, &textureIt->TextureID); m_Textures.erase(textureIt); } int RendererOpenGL3::GetTextureWidth(ImTextureID texture) { auto textureIt = FindTexture(texture); if (textureIt != m_Textures.end()) return textureIt->Width; return 0; } int RendererOpenGL3::GetTextureHeight(ImTextureID texture) { auto textureIt = FindTexture(texture); if (textureIt != m_Textures.end()) return textureIt->Height; return 0; } bool RendererOpenGL3::TakeScreenshot(const char* filename) { // Generate filename if not provided std::string fname; if (!filename) { time_t now = time(nullptr); char buffer[64]; strftime(buffer, sizeof(buffer), "screenshot_%Y%m%d_%H%M%S.png", localtime(&now)); fname = buffer; } else fname = filename; // Get viewport size GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); int width = viewport[2]; int height = viewport[3]; // Allocate pixel buffer (RGBA) std::vector pixels(width * height * 4); // Read pixels from framebuffer (OpenGL) // Ensure pixel alignment is 1 byte glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); // Flip vertically (OpenGL is bottom-up) std::vector flipped(width * height * 4); for (int y = 0; y < height; y++) { memcpy(&flipped[y * width * 4], &pixels[(height - 1 - y) * width * 4], width * 4); } // Save using stb_image_write return stbi_write_png(fname.c_str(), width, height, 4, flipped.data(), width * 4); } # endif // RENDERER(IMGUI_OGL3)