I'm working on a GLFW application and I noticed a problem when resizing the window.
While the user is scaling the window, the glfwPollEvents() function waits until the user finishes. This means that, during the scaling of the window, the render function isn't called and horrible artifacts are created.
I've worked around this by calling the render function from the main loop as well as the window resize callback:
#include <GLFW/glfw3.h>
static void render(GLFWwindow* window) {
glfwMakeContextCurrent(window);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}
static void window_size_callback(GLFWwindow* window, int width, int height) {
render(window);
glViewport(0, 0, width, height);
}
int main(void) {
if (!glfwInit()) {
return -1;
}
GLFWwindow* window = glfwCreateWindow(640, 480, "Terrain chunk render", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwSetWindowSizeCallback(window, window_size_callback);
while (!glfwWindowShouldClose(window)) {
render(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
However, this means that the render function isn't called when the user is holding down the mouse button after having scaled the window without actually moving it. Is there an efficient way of working around this and having the render function called more consistently?
Use two threads, one for polling events and one for rendering. You also might want to use glfwWaitEvents intstead of glfwPollEvents to block the event thread until events are available.
You should move the glfwSetWindowSizeCallback(window, window_size_callback); into your while loop so that the render function is called while you are re-sizing the window. I had the same problem a long time ago.
Edit: It's not recommended to set callbacks in the loop. The frames just need to be redrawn while the window is being resized.
Related
I am trying to create an app, where the user can run a (time-consuming) backend physics simulation with the press of a button. But at the same time, I would like the rest of the GUI to remain functional and not to "freeze" until the simulation is over. Now I know that it is not a good idea to combine many threads for rendering in OpenGL, so my thought is rather simple : 1) Use one thread (I suppose the default one) to run everything apart from the physics. 2) Use another thread, only to run the physics which I have limited in one function as you will see. But even like this, the whole GUI still "freezes" and as a result it is useless until the physics ends. How can I fix that issue?
Below follows the code that I thought it would work. It renders a "Test button" in order to check if I can actually press it while the physics is running and the "Run physics" button that triggers a heavy computation.
#include"imgui.h"
#include"imgui_impl_glfw.h"
#include"imgui_impl_opengl3.h"
#include<GL/glew.h>
#include<GLFW/glfw3.h>
#include<cstdio>
#include<cmath>
#include<thread>
//Hypothetical "heavy" computation
void run_physics()
{
for (double z = 0.0; z < 10000.0; z += 0.001)
{
double y = exp(sin(sqrt(z*abs(z)+ cos(z))));
}
return;
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(800,600, "Test", NULL, NULL);
if (window == NULL)
{
printf("Failed to open a glfw window. Exiting...\n");
return 0;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
printf("Failed to initialize glew. Exiting...\n");
return 0;
}
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
(void)io;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 330");
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Test");
ImGui::Button("Test button");
if (ImGui::Button("Run physics"))
{
//This pauses the render loop until run_physics is done. Good.
//run_physics();
//This also pauses the render loop. Why?
std::thread thr(run_physics);
thr.join();
}
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
glfwPollEvents();
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwTerminate();
return 0;
}
The problem is the thr.join() call, which will block until the thread exits.
There are a couple of ways to solve this. For example you can create an atomic status flag that is polled in the render thread. When the thread is done it sets the flag just before it exits. If the main rendering thread sees that the flag it set, then it calls the join call and fetches the result, which should happen pretty quickly.
I have the following function:
void introMenu(unsigned int texture,Shader shader, unsigned int VAO){
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
shader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
I call it after the following function:
int buildWindow(GLint WINDOW_WIDTH,GLint WINDOW_HEIGHT,char *windowTitle,GLint focused, bool fullscreen){
if(window!=NULL){
glfwDestroyWindow(window);
}
glfwWindowHint(GLFW_RESIZABLE,GLFW_TRUE);
glfwWindowHint(GLFW_VISIBLE,GLFW_TRUE);
glfwWindowHint(GLFW_DECORATED,GLFW_TRUE);
glfwWindowHint(GLFW_FOCUSED,GLFW_TRUE);
glfwWindowHint(GLFW_FLOATING,focused);
glfwWindowHint(GLFW_MAXIMIZED,GLFW_FALSE);
glfwWindowHint(GLFW_CENTER_CURSOR,GLFW_FALSE);
glfwWindowHint(GLFW_SCALE_TO_MONITOR,GLFW_TRUE);
glfwWindowHint(GLFW_SAMPLES,4);
glfwWindowHint(GLFW_DOUBLEBUFFER,GLFW_TRUE);
glfwWindowHint(GLFW_REFRESH_RATE,GLFW_DONT_CARE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
if(!fullscreen){
window=glfwCreateWindow(WINDOW_WIDTH,WINDOW_HEIGHT,windowTitle,NULL,NULL);
}
else{
window=glfwCreateWindow(WINDOW_WIDTH,WINDOW_HEIGHT,windowTitle,glfwGetPrimaryMonitor(),NULL);
}
if(window==NULL){
fprintf(stderr,"Failed to open GLFW window, possibly because of your Intel GPU\n");
getchar();
glfwTerminate();
return -1;
}
//get monitor size
const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
int monitorX, monitorY;
glfwGetMonitorPos(glfwGetPrimaryMonitor(), &monitorX, &monitorY);
//get window size
int windowWidth, windowHeight;
glfwGetWindowSize(window, &windowWidth, &windowHeight);
//center window
glfwSetWindowPos(window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
//window icon
GLFWimage icon[1];
icon[0].pixels = stbi_load("images/icon/icon.png", &icon[0].width, &icon[0].height, 0, 4);
glfwSetWindowIcon(window, 1, icon);
stbi_image_free(icon[0].pixels);
//make window contest
glfwMakeContextCurrent(window);
return 0;
}
, which I use to resize the window and/or set its parameters. I start by destroying the current one and then, create a new one. When I call the first function after this one the following error occurs: OpenGL nvoglv32.dll error
If I don't call the buildWindow function, it works fine.
Why does it happen and how do I solve this issue?
In GLFW, the GL context is tied to the window, and when you destroy the window, you destroy the GL context - and all the GL objects with it: textures, buffers, shaders, VAOs, whatever. And all the GL object names your code still holds become invalid. If you re-create the window, you have to re-create all of your GL objects with it.
There is no easy way around that in GLFW. You can fiddle around with shared contexts - but even shared contexts only share the "heavy" state objects like textures and buffers, but not the "light-weight" state containers like VAOs.
Note that the underlying GL binding APIs (wgl, glX, egl, ...) do not have such restrictions - windows and GL contexts are distinct entities there, and destroying the window will not affect the GL context, you can later bind it to another window, but you have to make sure that the window is comaptible to the context (with varying rules depending on the platform you work on).
I'm new to learning OpenGL in fact I just started following along a great resource called "learningopengl", This resources teaches how to setup GLFW and GLAD to use OpenGL on visual studio 2017. However, I've noticed when running even just an extremely basic program that only builds a blank window, that can be resized (following along the learning material) it takes visual studio consistently 40 or so seconds to actually load the program. it runs fine once its up, it simply takes an annoyingly long time to open.
I know this isn't supposed to take so long because through my searching around and looking at videos of people using these same libs/includes when they run there sample programs they load up instantly.
I was hoping I could find out why this is the case. for reference the sample code I'm running is show below.
#include <glad/glad.h>
#include <GLFW\glfw3.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main() {
// glfw: initialize and configure
// -----------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all openGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// render loop
// -----------
while (!glfwWindowShouldClose(window)) {
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc
// -----------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// glfw: terminate, clearing all perviously allocated glfw recourses
// -----------------------------------------------------------------
glfwTerminate();
return 0;
}
// glfw: whenever the window size is changed (by OS or user resize) this callback function executes
// ------------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger then specified on retina displays.
glViewport(0, 0, width, height);
}
Just a finial clarification, I do not mean that any kind of frame rate is slow, I mean from the time I tell visual studio to run the project (Ctrl+f5 or run the debugger) to the time I can see the actual OpenGL window i'm trying to make takes approximately 40 seconds or more.
Also when I run the code a cmd prompt runs behind it I was also wondering why that happens and if there is a way to prevent it or if it happens because of a setting.
I have a GLFW3 window that I am trying to change from resizable to not resizable.
I tried changing the Window Hint after the window was created but this doesn't do anything as the hints only affect window to be created.
what I tried:
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE)
Is this possible? One way of doing it that I thought of was having a onResize function that changes the window size back to the current size after being set not resizable. This seems very hacky.
Your approach works as of GLFW 3.2.1-1 in Ubuntu 18.10:
main.cpp
#include <GLFW/glfw3.h>
int main(void) {
GLFWwindow* window;
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
window = glfwCreateWindow(640, 480, __FILE__, NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
while (!glfwWindowShouldClose(window)) {
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Compile and run:
g++ -std=c++11 -Wall -Wextra -pedantic-errors -o main.out main.cpp -lglfw
./main.out
As I hover the borders of the created window, the cursor never changes to resize mode.
GLFW currently has no API for changing that state after the window is created.
When you want to use GLFW, I see two options:
The workaround you already have.
Create a new window when you switch that state.
Use the GLFW native access to obtain the real window handles and implement the feature for each platform (you care about).
All variants don't seem too appealing to me. Option 2 is especially bad because of the way GL contexts are tied to windows in GLFW, it should be possible by using an extra (invisible) window and shared GL contexts, but it will be ugly.
Option 3 has the advantage that it should work flawlessly once it is implemented for all relevant platforms. As GLFW is open source, this enables also option 3b): implement this directly in GLFW and extend the API. You might even be able to get this integrated into the official GLFW version.
You can change the GLFW_RESIZABLE attribute of an existing window with the following code:
bool enable;
glfwSetWindowAttrib(window, GLFW_RESIZABLE, enable);
This works but I highly recommend the other solutions, as this is only if you strictly need to be able to toggle it.
IntBuffer wid = BufferUtils.createIntBuffer(1);
IntBuffer hei = BufferUtils.createIntBuffer(1);
glfwGetWindowSize(window, wid, hei);
int windowWidth = wid.get();
int windowHeight = hei.get(); // I recommend making this public
while(!glfwWindowShouldClose(window)) {
glfwSetWindowSize(window, windowWidth, windowHeight);
// People can still maximize the window ... Comment if you have a solution :)
}
My solution:
// before create:
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
// create window
// ...
// after create
void setResizable(arg) {
if(arg)
glfwSetWindowSizeLimits(window, 0, 0, 0xffff, 0xffff);
else {
int w, h;
glfwGetWindowSize(window, &w, &h);
glfwSetWindowSizeLimits(window, w, h, w, h);
}
}
This worked to me with GLFW 3.3 but be carefull to put it after glfwInit()
int main( void )
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return -1;
}
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
...
}
I am having some issues with GLFW's window creation. I am wanting to have a program capable of toggling between windowed and fullscreen mode. To do this in GLFW 2.7.8 one must first destroy the active window, then create a new one. I read that version 3.0 has support for multiple windows, but it is still in development.
I have provided my own function to handle keyboard input. Using the initial 400 by 400 window, the program functions as expected; it will enter fullscreen on f or F, will exit when the escape key is pressed, and will complain when anything else is pressed.
However, when fullscreen mode is entered, the window becomes unresponsive with regards to my provided keyboard function. It will continue to run through the loop in main() and will respond to something like the glfwGetKey(GLFW_KEY_ESC) test. Regardless of if I have the mouse cursor enabled or not, the cursor does not appear.
Again, the fullscreen window is created and the KeyboardCallback function returns back into the main loop. I wish to understand why the fullscreen window is not working with my keyboard function, and why it is not displaying properly.
I am not drawing anything to the window, as I am trying to get some experience with various window abstraction libraries specifically. Drawing a simple triangle did nothing to solve he problem, and the fullscreen window remains black.
My code is as follows:
#include <stdio.h>
#include <stdlib.h>
// glfw32 - 2.7.8
#include <GL\glfw.h>
#pragma comment (lib, "GLFW.lib")
#pragma comment (lib, "opengl32.lib")
using namespace std;
// constants and globals
const int WINDOW_WIDTH=400, WINDOW_HEIGHT=400;
static bool fullscreen=false;
// function declarations
void GLFWCALL KeyboardCallback(int key, int action);
void FatalError(const char* msg) {
fprintf(stderr, "ERROR: Failure in \"%s\"\n", msg);
exit(1);
}
int main() {
// ititialize GLFW
glfwInit();
glfwEnable(GLFW_MOUSE_CURSOR);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);
// initial window, 400x400 with 32-bit depth buffer in windowed mode
glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 0,0,0,0, 32, 0, GLFW_WINDOW);
glfwSetWindowTitle("Simple Title");
glfwSetWindowPos(0, 0);
// set custom keyboard callback
glfwSetKeyCallback(KeyboardCallback);
while (true) { // loop until exit
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers();
// debug
//printf("Looping...\n");
if ( glfwGetKey(GLFW_KEY_ESC) ) {break;}
}
glfwTerminate();
printf("\nHave a nice day\n");
return 0;
}
void GLFWCALL KeyboardCallback(int key, int action) {
//printf("In keyboard function\n");
if (action) { // if key DOWN,
switch(key) { // do something...
case 'f':
case 'F': {
fullscreen = !fullscreen;
printf("Toggle Fullscreen: %s\n", (fullscreen ? "On" : "Off"));
glfwCloseWindow();
if (! glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 0,0,0,0, 32, 0,
fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW)) {
FatalError("toggle fullscreen");
}
glfwSetWindowTitle("New Title");
break;
}
case GLFW_KEY_ESC: {
printf("\nGoodbye cruel world...\n");
glfwTerminate();
exit(0);
}
default: {
printf("Key not implemented: %c\n", key);
break;
}
}
}
printf("Exiting keyboard function\n");
}
I tried James' approach from here but to no effect. Are there GLFW flags I am forgetting to set?
EDIT------- 5/20
I had a thought. Perhaps my callback was being unregistered when the window is destroyed. Turns out that re-registering my function when the new window is created made the window responsive.
While this solves my original problem, I now face a new one. I cannot render to the new window properly. I can insert glClear( GL_COLOR_BUFFER_BIT ); into my main loop, which will successfully set a background colour for the new window. For some reason it does not interact with my arrays and buffers to draw the image.
Code with attempted drawing
EDIT------- 5/21
I converted my code to GLFW 3.0.0. The window management is much cleaner (albeit more complex) and I do not have the rendering issue. Probably because I explicitly have to state the current context to use.
I would still like to solve the rendering issue, both out of curiosity and for if/when I return to 2.7.
Right now the event queue of GLFW is not pumped. You must either set the GLFW_AUTO_POLL_EVENTS option so that glfwSwapBuffers pumps the event queue, or you call glfwPollEvents at the start of a main event loop iteration.