mariojmartin wrote on Thursday, October 10, 2013:
I am trying to understand how to use the opaque window handler. If I understand correctly, it is an incomplete struct. So I have made a simple code to experiment with, but something wrong is meshing with the memory.
This example opens three windows in a separated thread. It is working fine until the windows are closed and an unhandled error is triggered in glfwDestroyWindow().
Any suggestions?
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <string.h>
#include <stdio.h>
#include "GLFW/glfw3.h"
#define MAX_NUMBER_WINDOWS 8
#define OPEN_WINDOW 1
#define CLOSE_WINDOW 2
#define FREEZE_WINDOW 3
#define TERMINATE 4
#define FRAMERATE_MILISECONDS 20
struct UserDefined
{
int id;
};
struct WindowHandler
{
GLFWwindow* window;
int status;
};
WindowHandler window_handler[MAX_NUMBER_WINDOWS] = {{NULL, 0}};
/* GLFW error callback, when an error is reported */
static void error_callback( int error, const char* description )
{
printf( "%s\n", description );
}
/* Callback that is triggered everytime the keyboard inputs */
static void callback_keyboard( GLFWwindow* window, int key, int scancode, int action, int mods )
{
UserDefined* p = (UserDefined*)glfwGetWindowUserPointer( window );
if (p != NULL){
printf("[%i] %c\n", p->id, (char)key);
}
}
static GLFWwindow* create_window( const int window_number )
{
/* Create the render context */
char title[32];
sprintf( title, "Window %i", window_number );
GLFWwindow* window = glfwCreateWindow(640, 640, title, NULL, NULL);
UserDefined* p = new(UserDefined);
p->id = window_number;
glfwSetWindowUserPointer( window, p );
if ( window == NULL ){
return NULL;
}
glfwMakeContextCurrent( window );
glfwSetKeyCallback( window, callback_keyboard );
return window;
}
static void ow_glfw_render_loop()
{
std::mutex mutex;
glfwSetErrorCallback(error_callback);
if (glfwInit() == GL_FALSE){
return;
}
while(1)
{
clock_t start_clock = clock();
for (int slot = 0; slot < MAX_NUMBER_WINDOWS; slot++)
{
WindowHandler* handler = &(window_handler[slot]);
if (handler->status == OPEN_WINDOW){
/* Creates a new render context */
mutex.lock();
handler->window = create_window( slot );
handler->status = 0;
mutex.unlock();
}
if (handler->status == CLOSE_WINDOW)
{
/* Destroys the render context */
mutex.lock();
UserDefined* p = (UserDefined*)glfwGetWindowUserPointer( handler->window );
if (p != NULL){
delete(p);
}
glfwDestroyWindow( handler->window );
handler->window = NULL;
handler->status = 0;
mutex.unlock();
}
if (handler->window != NULL && handler->status == 0)
{
glfwMakeContextCurrent( handler->window );
/* Display goes here */
glfwSwapBuffers( handler->window );
if (glfwWindowShouldClose( handler->window ) == GL_TRUE){
mutex.lock();
handler->status = CLOSE_WINDOW;
mutex.unlock();
}
}
}
glfwPollEvents();
clock_t end_clock = clock();
clock_t sleep_time = FRAMERATE_MILISECONDS
+ ((start_clock - end_clock)* 1000)/CLOCKS_PER_SEC;
if (sleep_time > 0){
std::this_thread::sleep_for
( std::chrono::milliseconds( sleep_time ));
}
}
glfwTerminate();
}
int main(int argc, char *argv[])
{
/* Launch the main loop in a thread */
std::thread render_thread_loop(ow_glfw_render_loop);
render_thread_loop.detach();
std::mutex mutex;
mutex.lock();
window_handler[0].status = OPEN_WINDOW;
window_handler[1].status = OPEN_WINDOW;
window_handler[2].status = OPEN_WINDOW;
mutex.unlock();
getchar();
}