Having this simple code:
#include <iostream>
#include <imgui/imgui.h>
#include <imgui/backends/imgui_impl_glfw.h>
#include <imgui/backends/imgui_impl_opengl3.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
void ImguiOnUpdate(int width, int height){
// 1.1 set window size for imgui
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(width, height);
// 1.2 new frame
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
// 1.3 imgui demo window
static bool show = true;
ImGui::ShowDemoWindow(&show);
// 1.4 imgui render
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
int main() {
// ===OPENGL===
int width = 1600;
int height = 900;
glfwInit();
GLFWwindow *window = glfwCreateWindow(width, height, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr) {
std::cerr << "failed to create GLFW window\n";
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, [](GLFWwindow *_, int width, int height) {
glViewport(0, 0, width, height);
});
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
std::cerr << "failed to initialize GLAD\n";
}
uint32_t va_, vb_, ib_;
glGenVertexArrays(1, &va_);
glBindVertexArray(va_);
glGenBuffers(1, &vb_);
glBindBuffer(GL_ARRAY_BUFFER, vb_);
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glGenBuffers(1, &ib_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib_);
int indices[] = {0, 1, 2};
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// ===IMGUI===
// 1.1 Imgui Context
ImGui::CreateContext();
ImGui::StyleColorsDark();
// 1.2 Imgui flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
// 1.3 Imgui init for opengl
ImGui_ImplOpenGL3_Init("#version 330");
while(!glfwWindowShouldClose(window)){
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(va_);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
ImguiOnUpdate(width, height);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
Without calling ImguiOnUpdate(width, height)
in main loop, it shows triangle. But when I want to render triangle AND the imgui window (as a very common scenario with imgui, where you "debug" the scene - triangle for example - by tweaking the parameters in imgui window). But when I add the ImguiOnUpdate()
, the triangle just flash in the beginning and then I can only see the imgui window, but not the triangle. So how to render both (as a usual case anyway)?
You seem to be relying on some default shader program to render your triangle for you. Apparently your driver provides that initially, but stops doing so when you use a shader (as part of ImGUI).
You need to compile, link and use an explicit program to render your triangle and then the rendering should work:
static const char* vertex_shader_text =
R"glsl(#version 400 core
in vec3 vPos;
void main()
{
gl_Position = vec4(vPos, 1.0);
})glsl";
static const char* fragment_shader_text =
R"glsl(#version 400 core
out vec4 outColor;
void main()
{
outColor = vec4(1.0, 0.0, 0.0, 1.0);
})glsl";
GLuint loadProgram() {
GLint status;
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
cerr << "Error compiling vertex shader" << endl;
char buffer[512];
glGetShaderInfoLog(vertex_shader, 512, NULL, buffer);
cerr << buffer << endl;
}
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
cerr << "Error compiling fragment shader" << endl;
char buffer[512];
glGetShaderInfoLog(fragment_shader, 512, NULL, buffer);
cerr << buffer << endl;
}
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
return program;
}
Inside main
:
GLuint program = loadProgram();
and inside your loop, call glUseProgram(program);
before you render.
Unrelated, you also need to call ImGui_ImplGlfw_NewFrame();
inside ImGuiOnUpdate()
to process input events.