Closed paulocoutinhox closed 7 months ago
I tried made the code work from samples, changing context, but it simply freeze:
#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <chrono>
#include <filesystem>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <opencv2/opencv.hpp>
namespace fs = std::filesystem;
struct ImageTexture {
GLuint textureID;
int width, height;
};
// Function to load texture from image
ImageTexture LoadTextureFromImage(const char* imagePath) {
ImageTexture imgTexture = {0, 0, 0};
int width, height, channels;
unsigned char* data = stbi_load(imagePath, &width, &height, &channels, 0);
if (data == nullptr) {
std::cerr << "Error loading image: " << imagePath << std::endl;
return imgTexture;
}
glGenTextures(1, &imgTexture.textureID);
glBindTexture(GL_TEXTURE_2D, imgTexture.textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, channels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
imgTexture.width = width;
imgTexture.height = height;
return imgTexture;
}
void windowCloseCallback(GLFWwindow* window) {
glfwDestroyWindow(window);
}
void windowKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
auto altF4 = (key == GLFW_KEY_W && mods == GLFW_MOD_SUPER);
auto commandQ = (key == GLFW_KEY_F4 && mods == GLFW_MOD_ALT && action == GLFW_PRESS);
if (altF4 || commandQ) {
glfwDestroyWindow(window);
}
}
int main() {
if (!glfwInit()) {
std::cerr << "Error initializing GLFW." << std::endl;
return -1;
}
// GLFW window creation
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// Main window
GLFWwindow* window = glfwCreateWindow(1024, 768, "Image Grid with ImGui", nullptr, nullptr);
if (window == nullptr) {
std::cerr << "Error creating GLFW window." << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// Video window
GLFWwindow* videoWindow = glfwCreateWindow(1024, 768, "Video Player", nullptr, nullptr);
if (videoWindow == nullptr) {
std::cerr << "Error creating GLFW video window." << std::endl;
glfwTerminate();
return -1;
}
glfwSetWindowCloseCallback(videoWindow, windowCloseCallback);
glfwSetKeyCallback(videoWindow, windowKeyCallback);
// ImGui initialization
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init();
// Load images from directory
std::vector<ImageTexture> textures;
std::string pathToImages = "images";
for (const auto& entry : fs::directory_iterator(pathToImages)) {
if (entry.is_regular_file()) {
textures.push_back(LoadTextureFromImage(entry.path().string().c_str()));
}
}
// Open video file
cv::VideoCapture video("videos/video1.mp4");
if (!video.isOpened()) {
std::cerr << "Error opening video." << std::endl;
return -1;
}
cv::Mat frame;
GLuint videoTexture = 0;
int videoWidth = 0;
int videoHeight = 0;
double fps = video.get(cv::CAP_PROP_FPS);
auto frameDuration = std::chrono::milliseconds(static_cast<int>(1000 / fps));
std::chrono::steady_clock::time_point lastFrameTime = std::chrono::steady_clock::now();
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
// Get video frame
auto currentTime = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastFrameTime) >= frameDuration) {
if (video.read(frame)) {
// Convert BGR to RGBA
cv::Mat frameRGBA;
cv::cvtColor(frame, frameRGBA, cv::COLOR_BGR2RGBA);
// Update video texture
if (videoTexture == 0) {
glGenTextures(1, &videoTexture);
glBindTexture(GL_TEXTURE_2D, videoTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glBindTexture(GL_TEXTURE_2D, videoTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frameRGBA.cols, frameRGBA.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, frameRGBA.data);
if (videoWidth == 0 || videoHeight == 0) {
videoWidth = frame.cols;
videoHeight = frame.rows;
}
lastFrameTime = currentTime;
} else {
// Restart video playback when reaching the end
video.set(cv::CAP_PROP_POS_FRAMES, 0);
}
}
// Main window
glfwMakeContextCurrent(window);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Render image grid
ImGui::Begin("Images");
float windowWidth = ImGui::GetContentRegionAvail().x;
int imagesPerRow = std::max(1, static_cast<int>(windowWidth / 100.0f));
float imageSize = windowWidth / imagesPerRow;
for (int i = 0; i < textures.size(); ++i) {
float aspectRatio = static_cast<float>(textures[i].width) / textures[i].height;
ImGui::Image((void*)(intptr_t)textures[i].textureID, ImVec2(imageSize, imageSize / aspectRatio));
if ((i + 1) % imagesPerRow != 0) ImGui::SameLine();
}
ImGui::End();
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
// Render video
if (videoWindow) {
glfwMakeContextCurrent(videoWindow);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
if (videoTexture != 0) {
ImGui::Begin("Video Player", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
// Get total window dimensions from ImGui
ImVec2 windowSize = ImGui::GetContentRegionAvail();
// Calculate video aspect ratio
float videoAspectRatio = (float)videoWidth / (float)videoHeight;
// Calculate image size based on video and window aspect ratio
ImVec2 imageSize;
if (windowSize.x / windowSize.y > videoAspectRatio) {
// Window is wider than video
imageSize.x = windowSize.y * videoAspectRatio;
imageSize.y = windowSize.y;
} else {
// Window is taller than video
imageSize.x = windowSize.x;
imageSize.y = windowSize.x / videoAspectRatio;
}
// Calculate position to center the image in the window
ImVec2 imagePos = ImVec2(
ImGui::GetCursorPos().x + (windowSize.x - imageSize.x) * 0.5f, // X position for centering
ImGui::GetCursorPos().y + (windowSize.y - imageSize.y) * 0.5f // Y position for centering
);
// Apply calculated position
ImGui::SetCursorPos(imagePos);
// Render video image with adjusted size and position
ImGui::Image((void*)(intptr_t)videoTexture, imageSize);
ImGui::End();
}
// Render ImGui
ImGui::Render();
int displayW, displayH;
glfwGetFramebufferSize(videoWindow, &displayW, &displayH);
glViewport(0, 0, displayW, displayH);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(videoWindow);
}
// Cleanup
if (videoTexture != 0) {
glDeleteTextures(1, &videoTexture);
}
for (auto& texture : textures) {
glDeleteTextures(1, &texture.textureID);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
if (videoWindow) {
glfwDestroyWindow(videoWindow);
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
It'll be simpler if you switch to the docking
branch and enable multi-viewports, then you can move imgui windows anywhere.
I am not sure what your "freeze" is because, since you are not providing more information, but AFAIK the stock GLFW backend doesn't currently support multi-context because of how glfwPollEvents() dispatch information you don't have a chance to change context. This is behind discussed in #7186 #7155 #5671
Switching to use multi-viewports should fix the issue for you.
Hi,
But in my case when the user open the app, it will the main window, and when it select an image, video or text a new window will open in the datashow (second monitor) with a video in BG and text on Foreground.
We can't drag/drop it manually to other monitor.
You can use imgui API to position windows wherever you want.
Another problem is with font on it. When i add font TTF, it apply for everything, but i want only in my function TextCenteredWithOutline
:
#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <chrono>
#include <filesystem>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <opencv2/opencv.hpp>
namespace fs = std::filesystem;
struct ImageTexture {
GLuint textureID;
int width, height;
};
// Function to load texture from image
ImageTexture LoadTextureFromImage(const char* imagePath) {
ImageTexture imgTexture = {0, 0, 0};
int width, height, channels;
unsigned char* data = stbi_load(imagePath, &width, &height, &channels, 0);
if (data == nullptr) {
std::cerr << "Error loading image: " << imagePath << std::endl;
return imgTexture;
}
glGenTextures(1, &imgTexture.textureID);
glBindTexture(GL_TEXTURE_2D, imgTexture.textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, channels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
imgTexture.width = width;
imgTexture.height = height;
return imgTexture;
}
void TextCenteredWithOutline(const std::string& text, float fontSize, ImFont* font) {
ImGuiIO& io = ImGui::GetIO();
if (font) {
ImGui::PushFont(font);
}
ImVec2 textSize = ImGui::CalcTextSize(text.c_str(), NULL, true, io.DisplaySize.x);
ImVec2 screenSize = io.DisplaySize;
float text_indentation = (screenSize.x - textSize.x) * 0.5f;
float textPos_y = (screenSize.y - textSize.y) * 0.5f;
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
ImVec2 textPos = ImVec2(text_indentation > 0 ? text_indentation : 0, textPos_y);
ImColor outlineColor = ImColor(0, 0, 0, 255);
ImColor textColor = ImColor(50, 45, 255, 255);
float outlineThickness = 1.0f;
for (int x = -outlineThickness; x <= outlineThickness; ++x) {
for (int y = -outlineThickness; y <= outlineThickness; ++y) {
if (x != 0 || y != 0) {
draw_list->AddText(font, fontSize, ImVec2(textPos.x + x, textPos.y + y), outlineColor, text.c_str());
}
}
}
draw_list->AddText(font, fontSize, textPos, textColor, text.c_str());
if (font) {
ImGui::PopFont();
}
}
void windowCloseCallback(GLFWwindow* window) {
glfwDestroyWindow(window);
}
void windowKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
auto altF4 = (key == GLFW_KEY_W && mods == GLFW_MOD_SUPER);
auto commandQ = (key == GLFW_KEY_F4 && mods == GLFW_MOD_ALT && action == GLFW_PRESS);
if (altF4 || commandQ) {
glfwDestroyWindow(window);
}
}
int main() {
if (!glfwInit()) {
std::cerr << "Error initializing GLFW." << std::endl;
return -1;
}
// GLFW window creation
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// Main window
GLFWwindow* window = glfwCreateWindow(1024, 768, "Image Grid with ImGui", nullptr, nullptr);
if (window == nullptr) {
std::cerr << "Error creating GLFW window." << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// Video window
GLFWwindow* videoWindow = nullptr;
/*
GLFWwindow* videoWindow = glfwCreateWindow(1024, 768, "Video Player", nullptr, nullptr);
if (videoWindow == nullptr) {
std::cerr << "Error creating GLFW video window." << std::endl;
glfwTerminate();
return -1;
}
glfwSetWindowCloseCallback(videoWindow, windowCloseCallback);
glfwSetKeyCallback(videoWindow, windowKeyCallback);
*/
// ImGui initialization
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
ImFont* myFont = io.Fonts->AddFontFromFileTTF("fonts/Poppins-Bold.ttf", 40);
if (!myFont) {
std::cerr << "Error while load font." << std::endl;
}
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init();
// Load images from directory
std::vector<ImageTexture> textures;
std::string pathToImages = "images";
for (const auto& entry : fs::directory_iterator(pathToImages)) {
if (entry.is_regular_file()) {
textures.push_back(LoadTextureFromImage(entry.path().string().c_str()));
}
}
// Open video file
cv::VideoCapture video("videos/video1.mp4");
if (!video.isOpened()) {
std::cerr << "Error opening video." << std::endl;
return -1;
}
cv::Mat frame;
GLuint videoTexture = 0;
int videoWidth = 0;
int videoHeight = 0;
double fps = video.get(cv::CAP_PROP_FPS);
auto frameDuration = std::chrono::milliseconds(static_cast<int>(1000 / fps));
std::chrono::steady_clock::time_point lastFrameTime = std::chrono::steady_clock::now();
ImVec2 pos = ImVec2(100, 100); // Posição inicial do texto na tela
const char* text = "Texto com Contorno"; // O texto que você quer desenhar
ImFont* pFont = ImGui::GetFont();
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
// Get video frame
auto currentTime = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastFrameTime) >= frameDuration) {
if (video.read(frame)) {
// Convert BGR to RGBA
cv::Mat frameRGBA;
cv::cvtColor(frame, frameRGBA, cv::COLOR_BGR2RGBA);
// Update video texture
if (videoTexture == 0) {
glGenTextures(1, &videoTexture);
glBindTexture(GL_TEXTURE_2D, videoTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glBindTexture(GL_TEXTURE_2D, videoTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frameRGBA.cols, frameRGBA.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, frameRGBA.data);
if (videoWidth == 0 || videoHeight == 0) {
videoWidth = frame.cols;
videoHeight = frame.rows;
}
lastFrameTime = currentTime;
} else {
// Restart video playback when reaching the end
video.set(cv::CAP_PROP_POS_FRAMES, 0);
}
}
// Main window
glfwMakeContextCurrent(window);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Desenha o contorno em preto
//TextCenteredWithOutline("Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test", 40, myFont);
// Render image grid
ImGui::Begin("Images");
float windowWidth = ImGui::GetContentRegionAvail().x;
int imagesPerRow = std::max(1, static_cast<int>(windowWidth / 100.0f));
float imageSize = windowWidth / imagesPerRow;
for (int i = 0; i < textures.size(); ++i) {
float aspectRatio = static_cast<float>(textures[i].width) / textures[i].height;
ImGui::Image((void*)(intptr_t)textures[i].textureID, ImVec2(imageSize, imageSize / aspectRatio));
if ((i + 1) % imagesPerRow != 0) ImGui::SameLine();
}
ImGui::End();
// Render video
if (videoWindow) {
glfwMakeContextCurrent(videoWindow);
glfwPollEvents();
}
if (videoTexture != 0) {
ImGui::Begin("Video Player", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
// Get total window dimensions from ImGui
ImVec2 windowSize = ImGui::GetContentRegionAvail();
// Calculate video aspect ratio
float videoAspectRatio = (float)videoWidth / (float)videoHeight;
// Calculate image size based on video and window aspect ratio
ImVec2 imageSize;
if (windowSize.x / windowSize.y > videoAspectRatio) {
// Window is wider than video
imageSize.x = windowSize.y * videoAspectRatio;
imageSize.y = windowSize.y;
} else {
// Window is taller than video
imageSize.x = windowSize.x;
imageSize.y = windowSize.x / videoAspectRatio;
}
// Calculate position to center the image in the window
ImVec2 imagePos = ImVec2(
ImGui::GetCursorPos().x + (windowSize.x - imageSize.x) * 0.5f, // X position for centering
ImGui::GetCursorPos().y + (windowSize.y - imageSize.y) * 0.5f // Y position for centering
);
// Apply calculated position
ImGui::SetCursorPos(imagePos);
// Render video image with adjusted size and position
ImGui::Image((void*)(intptr_t)videoTexture, imageSize);
ImGui::End();
}
// Render ImGui
ImGui::Render();
int displayW, displayH;
glfwGetFramebufferSize(window, &displayW, &displayH);
glViewport(0, 0, displayW, displayH);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
// Cleanup
if (videoTexture != 0) {
glDeleteTextures(1, &videoTexture);
}
for (auto& texture : textures) {
glDeleteTextures(1, &texture.textureID);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
if (videoWindow) {
glfwDestroyWindow(videoWindow);
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
Also, i use your docking branch, but it is very strange uhauhahuaahu:
#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <chrono>
#include <filesystem>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <opencv2/opencv.hpp>
namespace fs = std::filesystem;
struct ImageTexture {
GLuint textureID;
int width, height;
};
// Function to load texture from image
ImageTexture LoadTextureFromImage(const char* imagePath) {
ImageTexture imgTexture = {0, 0, 0};
int width, height, channels;
unsigned char* data = stbi_load(imagePath, &width, &height, &channels, 0);
if (data == nullptr) {
std::cerr << "Error loading image: " << imagePath << std::endl;
return imgTexture;
}
glGenTextures(1, &imgTexture.textureID);
glBindTexture(GL_TEXTURE_2D, imgTexture.textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, channels == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
imgTexture.width = width;
imgTexture.height = height;
return imgTexture;
}
void TextCenteredWithOutline(const std::string& text, float fontSize, ImFont* font) {
ImGuiIO& io = ImGui::GetIO();
if (font) {
ImGui::PushFont(font);
}
// Configuração para quebra de texto
float wrap_width = io.DisplaySize.x * 0.9f; // Define a largura máxima para quebra de texto
// Calcula a posição centralizada baseado na largura máxima do texto
ImVec2 textSize = ImGui::CalcTextSize(text.c_str(), NULL, true, wrap_width);
ImVec2 pos = ImVec2((io.DisplaySize.x - textSize.x) * 0.5f, (io.DisplaySize.y - textSize.y) * 0.5f);
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
ImVec2 textPos = ImVec2(pos.x, pos.y);
ImColor outlineColor = ImColor(0, 0, 0, 255); // Cor do contorno
ImColor textColor = ImColor(255, 255, 255, 255); // Cor do texto
// Desenha o contorno
float outlineThickness = 2.0f;
for (int x = -outlineThickness; x <= outlineThickness; ++x) {
for (int y = -outlineThickness; y <= outlineThickness; ++y) {
if (x != 0 || y != 0) {
// Adiciona cada letra do texto com um pequeno deslocamento para criar o efeito de contorno
draw_list->AddText(NULL, fontSize, ImVec2(textPos.x + x, textPos.y + y), outlineColor, text.c_str(), NULL, wrap_width);
}
}
}
// Desenha o texto principal
draw_list->AddText(NULL, fontSize, textPos, textColor, text.c_str(), NULL, wrap_width);
if (font) {
ImGui::PopFont();
}
}
void windowCloseCallback(GLFWwindow* window) {
glfwDestroyWindow(window);
}
void windowKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
auto altF4 = (key == GLFW_KEY_W && mods == GLFW_MOD_SUPER);
auto commandQ = (key == GLFW_KEY_F4 && mods == GLFW_MOD_ALT && action == GLFW_PRESS);
if (altF4 || commandQ) {
glfwDestroyWindow(window);
}
}
int main() {
if (!glfwInit()) {
std::cerr << "Error initializing GLFW." << std::endl;
return -1;
}
// GLFW window creation
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// Main window
GLFWwindow* window = glfwCreateWindow(1024, 768, "Image Grid with ImGui", nullptr, nullptr);
if (window == nullptr) {
std::cerr << "Error creating GLFW window." << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// Video window
GLFWwindow* videoWindow = nullptr;
/*
GLFWwindow* videoWindow = glfwCreateWindow(1024, 768, "Video Player", nullptr, nullptr);
if (videoWindow == nullptr) {
std::cerr << "Error creating GLFW video window." << std::endl;
glfwTerminate();
return -1;
}
glfwSetWindowCloseCallback(videoWindow, windowCloseCallback);
glfwSetKeyCallback(videoWindow, windowKeyCallback);
*/
// ImGui initialization
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
ImFont* myFont = io.Fonts->AddFontFromFileTTF("fonts/Poppins-Bold.ttf", 20);
if (!myFont) {
std::cerr << "Error while load font." << std::endl;
}
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init();
// Load images from directory
std::vector<ImageTexture> textures;
std::string pathToImages = "images";
for (const auto& entry : fs::directory_iterator(pathToImages)) {
if (entry.is_regular_file()) {
textures.push_back(LoadTextureFromImage(entry.path().string().c_str()));
}
}
// Open video file
cv::VideoCapture video("videos/video1.mp4");
if (!video.isOpened()) {
std::cerr << "Error opening video." << std::endl;
return -1;
}
cv::Mat frame;
GLuint videoTexture = 0;
int videoWidth = 0;
int videoHeight = 0;
double fps = video.get(cv::CAP_PROP_FPS);
auto frameDuration = std::chrono::milliseconds(static_cast<int>(1000 / fps));
std::chrono::steady_clock::time_point lastFrameTime = std::chrono::steady_clock::now();
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
// Get video frame
auto currentTime = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastFrameTime) >= frameDuration) {
if (video.read(frame)) {
// Convert BGR to RGBA
cv::Mat frameRGBA;
cv::cvtColor(frame, frameRGBA, cv::COLOR_BGR2RGBA);
// Update video texture
if (videoTexture == 0) {
glGenTextures(1, &videoTexture);
glBindTexture(GL_TEXTURE_2D, videoTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glBindTexture(GL_TEXTURE_2D, videoTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frameRGBA.cols, frameRGBA.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, frameRGBA.data);
if (videoWidth == 0 || videoHeight == 0) {
videoWidth = frame.cols;
videoHeight = frame.rows;
}
lastFrameTime = currentTime;
} else {
// Restart video playback when reaching the end
video.set(cv::CAP_PROP_POS_FRAMES, 0);
}
}
// Main window
glfwMakeContextCurrent(window);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Desenha o contorno em preto
TextCenteredWithOutline("Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test Demo Test", 100, myFont);
// Render image grid
ImGui::Begin("Images", nullptr, ImGuiWindowFlags_NoDocking);
float windowWidth = ImGui::GetContentRegionAvail().x;
int imagesPerRow = std::max(1, static_cast<int>(windowWidth / 100.0f));
float imageSize = windowWidth / imagesPerRow;
for (int i = 0; i < textures.size(); ++i) {
float aspectRatio = static_cast<float>(textures[i].width) / textures[i].height;
ImGui::Image((void*)(intptr_t)textures[i].textureID, ImVec2(imageSize, imageSize / aspectRatio));
if ((i + 1) % imagesPerRow != 0) ImGui::SameLine();
}
ImGui::End();
// Render video
if (videoWindow) {
glfwMakeContextCurrent(videoWindow);
glfwPollEvents();
}
if (videoTexture != 0) {
ImGui::Begin("Video Player", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
// Get total window dimensions from ImGui
ImVec2 windowSize = ImGui::GetContentRegionAvail();
// Calculate video aspect ratio
float videoAspectRatio = (float)videoWidth / (float)videoHeight;
// Calculate image size based on video and window aspect ratio
ImVec2 imageSize;
if (windowSize.x / windowSize.y > videoAspectRatio) {
// Window is wider than video
imageSize.x = windowSize.y * videoAspectRatio;
imageSize.y = windowSize.y;
} else {
// Window is taller than video
imageSize.x = windowSize.x;
imageSize.y = windowSize.x / videoAspectRatio;
}
// Calculate position to center the image in the window
ImVec2 imagePos = ImVec2(
ImGui::GetCursorPos().x + (windowSize.x - imageSize.x) * 0.5f, // X position for centering
ImGui::GetCursorPos().y + (windowSize.y - imageSize.y) * 0.5f // Y position for centering
);
// Apply calculated position
ImGui::SetCursorPos(imagePos);
// Render video image with adjusted size and position
ImGui::Image((void*)(intptr_t)videoTexture, imageSize);
ImGui::End();
}
// Render ImGui
ImGui::Render();
int displayW, displayH;
glfwGetFramebufferSize(window, &displayW, &displayH);
glViewport(0, 0, displayW, displayH);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
glfwSwapBuffers(window);
}
// Cleanup
if (videoTexture != 0) {
glDeleteTextures(1, &videoTexture);
}
for (auto& texture : textures) {
glDeleteTextures(1, &texture.textureID);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
if (videoWindow) {
glfwDestroyWindow(videoWindow);
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
Another problem is with font on it. When i add font TTF, it apply for everything, but i want only in my function
TextCenteredWithOutline
:
The default font is loaded automatically only when no other font is specified, so you are replacing it. If you want both, you need to explicitly add the default font first and then add your own as a second font.
For specifics, here is a link to the font documentation: https://github.com/ocornut/imgui/blob/master/docs/FONTS.md
Another problem is with font on it. When i add font TTF, it apply for everything, but i want only in my function
TextCenteredWithOutline
:The default font is loaded automatically only when no other font is specified, so you are replacing it. If you want both, you need to explicitly add the default font first and then add your own as a second font.
For specifics, here is a link to the font documentation: https://github.com/ocornut/imgui/blob/master/docs/FONTS.md
Ok, thanks, i read it but in my tests i put AddFontDefault
after, now i put before and work.
I am not sure what your "freeze" is because, since you are not providing more information, but AFAIK the stock GLFW backend doesn't currently support multi-context because of how glfwPollEvents() dispatch information you don't have a chance to change context. This is behind discussed in #7186 #7155 #5671
Switching to use multi-viewports should fix the issue for you.
I will wait for the GLFW multi window support and will stop the project migration now until it be ready.
This is not a chat room, you are sending messages to a mailing list 1000+ people and we can't debug your code expecially if you spam a thread with code variations. Please do more research before opening new issue.
I will wait for the GLFW multi window support and will stop the project migration now until it be ready.
Sounds like a XY Problem reaction. You should be able to use multi-viewports for this.
Dude, you are very stressed and assume a lot of things. I just said in a friendly and laughing way that the viewport solution is weird, it's awkward to use and that I prefer the separate windows solution because that's how I do it with Qt and the user experience (UX) is much better. I tested it locally and found the multi-viewport feature strange.
If the window solution doesn't come out, this should be the only option.
You said "it is very strange uhauhahuaahu:" without clarifying precisely what was your issue is with it, then immediately went out finding an alternative instead of pursuing the suggested route. So (1) You are not actually explaining your issue (2) you are immediately giving up right after I told you can you solve your problem with it. How are we supposed to help more?
I prefer the separate windows solution
Multi-viewports ARE separate windows. You are not specifying what your problem actually is so we could help you understand the options and features, instead you are being vague with your statement and throwing hundreds of lines of code in repeated manner.
There are nearly 1000 issues open and we're providing this service for free to you. If you want help you need to learn to ask questions and discuss problems clearly, not fire multiple messages in a row which suggests you are posting without doing researches.
If your question was explicit and precise, e.g. "I would prefer if separate window had an OS title bar instead of a Dear ImGui title bar, is that possible?" we would provide you answer. But your question being "it is awkward to use, i'm giving up" I am not sure how I am supposed to help you.
Hi,
I put the code to draw "video player" window in the second monitor, it is working, but it is the "correct way" to do?
if (starting) {
if (monitorsCount > 1) {
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
int monitorPosX, monitorPosY, monitorWidth, monitorHeight;
glfwGetMonitorWorkarea(monitors[1], &monitorPosX, &monitorPosY, &monitorWidth, &monitorHeight);
videoWinPos = ImVec2(monitorPosX, monitorPosY);
videoWinSize = ImVec2(monitorWidth, monitorHeight);
videoFlags = videoFlags | ImGuiWindowFlags_NoDecoration;
} else {
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
videoWinPos = ImVec2(ImGui::GetCursorPos().x + 50, ImGui::GetCursorPos().y + 300);
videoWinSize = ImVec2(400, 200);
}
} else {
if (monitorsCount > 1) {
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
int monitorPosX, monitorPosY, monitorWidth, monitorHeight;
glfwGetMonitorWorkarea(monitors[1], &monitorPosX, &monitorPosY, &monitorWidth, &monitorHeight);
videoWinPos = ImVec2(monitorPosX, monitorPosY);
videoWinSize = ImVec2(monitorWidth, monitorHeight);
videoFlags = videoFlags | ImGuiWindowFlags_NoDecoration;
} else {
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
videoWinPos = ImVec2(ImGui::GetCursorPos().x + 50, ImGui::GetCursorPos().y + 300);
videoWinSize = ImVec2(400, 200);
}
}
Now, im trying "block" the other window (image grid, for example) to don't be moved outside the main system window, i don't want that other windows be moved outside the main window, only the video player. I tried the flag ImGuiWindowFlags_NoDocking
but it don't work. There is any option to this? Because if i enable viewport all window can be dragged outside the main window. Because this, i prefer the solution of multiple system window, understand.
Also, when i have only one monitor, the "video player window" need be inside main system window, without dragged outside. And when the monitor is > 1, the video player go to this second monitor.
My code is working and doing it, the main problem is disable the drag to outside of main window.
I only can reach this adding or removing flags from io:
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_ViewportsEnable
or
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
But what i want is disable the floating window from main system window for individual imgui windows.
Can you help me?
Version/Branch of Dear ImGui:
Version 1.90.2
Back-ends:
imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp
Compiler, OS:
macOS
Full config/build information:
any
Details:
How to use multiple GLFW window for my datashow application?
I have an app today https://github.com/paulocoutinhox/prprojector that i want port to ImGUI.
My problem now is understand how to render the video in a second Window that will appear on a second monitor.
My code is below and the project is hosted here: https://github.com/paulocoutinhox/imgui-image-grid-demo
The project is working with everything in the same window.
The "videoWindow" is commented and need be uncommented.
Screenshots/Video:
Minimal, Complete and Verifiable Example code: