Im having difficulty with multiple windows in GLFW OpenGL
i have a class called "Form" that points to an instance of a GLFWwindow. i can render my form just fine. i can render multiple instances of Form at the same time just fine.
my problems start if i close a Form's GLFWwindow by calling glfwDestroyWindow and try to assign the form a new instance of GLFWwindow when i want to display the Form again.
currently i have it working but only if i re generate all the shader programs after creating the new window, if i don't the new window only displays there background colour.
if i dispose of all the old shaders by calling glDeleteShader and glDeleteProgram before creating new ones with glCreateShader then i only end up with a black screen and i don't understand why. but if i just recreate new shaders from the original const char* pointers it all works fine, only i feel like it could lead to memory leaks or something by not disposing of things properly.
I'm sure it is simple that I'm just not grasping, I'm not so good with OpenGL and C , usually i write programs in Windows csharp's OnPaint event but i would like to make my program run on my ubuntu computer, hence this basic implementation of the System.Windows.Forms.Form and System.Drawing.Graphics class.
I'm not bothered about Controls and Widgets and the like, I'm fine with rendering everything in the OnPaint event.
bellow is the initialise methods for the Form and Graphics class's that i think show how I'm currently going about it.
i can add more if it would help but the whole class is rather large if i include methods for drawing lines, rectangles, textures, fonts and the like.
any help would be appreciated, feel free to tell me why I'm going about this completely wrong, its mostly just a learning curve anyway.
class Form
{
public: Form()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
}
public: void Show()
{
if (this->window != NULL)
{
glfwFocusWindow(this->window);
return;
}
this->window = glfwCreateWindow(this->width, this->height, this->title, nullptr, nullptr); // Windowed
//this->window = glfwCreateWindow(800, 600, "OpenGL", glfwGetPrimaryMonitor(), nullptr); // Fullscreen
this->graphics.window = this->window;
// store referance to this form in the new windows userPointer field, and set the windows size limits
glfwSetWindowUserPointer(this->window, &*this);
glfwSetWindowSizeLimits(this->window, this->minWidth, this->minHeight, this->maxWidth, this->maxHeight);
// attach calbacks to the window
glfwSetWindowSizeCallback(this->window, window_size_callback);
glfwSetFramebufferSizeCallback(this->window, framebuffer_size_callback);
glfwSetKeyCallback(this->window, key_callback);
glfwSetMouseButtonCallback(this->window, mouse_callback);
glfwSetWindowFocusCallback(this->window, window_focus_callback);
this->MakeCurrent();
// Now all that's left is calling glewInit() after the creation of your window and OpenGL context.
// The glewExperimental line is necessary to force GLEW to use a modern OpenGL method for checking if a function is available.
glewExperimental = GL_TRUE;
glewInit();
// if i initialize the graphics class here all works fine.
this->graphics.Initialize();
// if this is the first time the form is displayed then call the initialize method
if (this->initialized == false)
{
// if i initialize the graphics class here all the forms that were opend when the program initialy runs work fine.
// but any that open after only display the background color and the shaders dont work
//this->graphics.Initialize();
this->OnInitialize();
this->initialized = true;
}
// invalidate the form and call the resize method to draw the form as it show's
this->OnResize();
this->Invalidate();
}
public: void Close()
{
// here i feel i need to dispose of the shaders as the window is closing but if i do all the forms rendering disapears
//this->graphics.Dispose();
glfwDestroyWindow(this->window);
this->window = nullptr;
}
public: virtual void OnInitialize() { }
public: virtual void Dispose()
{
this->Close();
this->graphics.Dispose();
glfwTerminate();
}
}
class Graphics
{
public: Graphics()
{
}
public: void Initialize()
{
// Create and compile the vertex shader
const char* vertexSource1 = R"glsl(
#version 150 core
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main()
{
Texcoord = texcoord;
gl_Position = vec4(position, 0.0, 1.0);
}
)glsl";
this->vertexShader1 = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(this->vertexShader1, 1, &vertexSource1, NULL);
glCompileShader(this->vertexShader1);
// Create and compile the fragment shader
const char* fragmentSource1 = R"glsl(
#version 150 core
in vec2 Texcoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture(tex, Texcoord);
}
)glsl";
this->fragmentShader1 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(this->fragmentShader1, 1, &fragmentSource1, NULL);
glCompileShader(this->fragmentShader1);
// Create Vertex Array Object
glGenVertexArrays(1, &this->vertexArrayObj1);
glBindVertexArray(this->vertexArrayObj1);
// Create a Vertex Buffer Object
glGenBuffers(1, &this->vertexBufferObj1);
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBufferObj1);
// Create a Element Buffer Object
glGenBuffers(1, &this->elementBufferObj1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->elementBufferObj1);
// Create a Texture Object
glGenTextures(1, &this->tex1);
glBindTexture(GL_TEXTURE_2D, this->tex1);
// Link the vertex and fragment shader into a shader program
this->shaderProgram1 = glCreateProgram();
glAttachShader(this->shaderProgram1, this->vertexShader1);
glAttachShader(this->shaderProgram1, this->fragmentShader1);
//glBindFragDataLocation(this->shaderProgram1, 0, "outColor");
glLinkProgram(shaderProgram1);
//
//
// Create and compile the vertex shader
const char* vertexSource2 = R"glsl(
#version 150 core
in vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
)glsl";
this->vertexShader2 = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(this->vertexShader2, 1, &vertexSource2, NULL);
glCompileShader(this->vertexShader2);
// Create and compile the fragment shader
const char* fragmentSource2 = R"glsl(
#version 150 core
uniform vec4 color;
void main()
{
gl_FragColor = color;
}
)glsl";
this->fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(this->fragmentShader2, 1, &fragmentSource2, NULL);
glCompileShader(this->fragmentShader2);
// Create Vertex Array Object
glGenVertexArrays(1, &this->vertexArrayObj2);
glBindVertexArray(this->vertexArrayObj2);
// Create a Vertex Buffer Object
glGenBuffers(1, &this->vertexBufferObj2);
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBufferObj2);
// Create a Element Buffer Object
glGenBuffers(1, &this->elementBufferObj2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->elementBufferObj2);
// Link the vertex and fragment shader into a shader program
this->shaderProgram2 = glCreateProgram();
glAttachShader(this->shaderProgram2, this->vertexShader2);
glAttachShader(this->shaderProgram2, this->fragmentShader2);
//glBindFragDataLocation(this->shaderProgram2, 0, "outColor");
glLinkProgram(this->shaderProgram2);
glUseProgram(this->shaderProgram2);
//glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
//
//
// Create and compile the vertex shader
const char* vertexSource3 = R"glsl(
#version 150 core
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main()
{
Texcoord = texcoord;
gl_Position = vec4(position, 0.0, 1.0);
}
)glsl";
this->vertexShader3 = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(this->vertexShader3, 1, &vertexSource3, NULL);
glCompileShader(this->vertexShader3);
// Create and compile the fragment shader
const char* fragmentSource3 = R"glsl(
#version 150 core
uniform vec4 color;
in vec2 Texcoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = vec4(color.r, color.g, color.b, texture(tex, Texcoord).a);
}
)glsl";
this->fragmentShader3 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(this->fragmentShader3, 1, &fragmentSource3, NULL);
glCompileShader(this->fragmentShader3);
// Create Vertex Array Object
glGenVertexArrays(1, &this->vertexArrayObj3);
glBindVertexArray(this->vertexArrayObj3);
// Create a Vertex Buffer Object
glGenBuffers(1, &this->vertexBufferObj3);
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBufferObj3);
// Create a Element Buffer Object
glGenBuffers(1, &this->elementBufferObj1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->elementBufferObj1);
// Create a Texture Object
glGenTextures(1, &this->tex3);
glBindTexture(GL_TEXTURE_2D, this->tex3);
// Link the vertex and fragment shader into a shader program
this->shaderProgram3 = glCreateProgram();
glAttachShader(this->shaderProgram3, this->vertexShader3);
glAttachShader(this->shaderProgram3, this->fragmentShader3);
//glBindFragDataLocation(this->shaderProgram3, 0, "outColor");
glLinkProgram(shaderProgram3);
this->initialized = true;
}
public: void Dispose()
{
glDeleteProgram(this->shaderProgram1);
glDeleteShader(this->fragmentShader1);
glDeleteShader(this->vertexShader1);
glDeleteVertexArrays(1, &this->vertexArrayObj1);
glDeleteBuffers(1, &this->vertexBufferObj1);
glDeleteBuffers(1, &this->elementBufferObj1);
glDeleteBuffers(1, &this->tex1);
glDeleteProgram(this->shaderProgram2);
glDeleteShader(this->fragmentShader2);
glDeleteShader(this->vertexShader2);
glDeleteVertexArrays(1, &this->vertexArrayObj2);
glDeleteBuffers(1, &this->vertexBufferObj2);
glDeleteBuffers(1, &this->elementBufferObj2);
glDeleteProgram(this->shaderProgram3);
glDeleteShader(this->fragmentShader3);
glDeleteShader(this->vertexShader3);
glDeleteVertexArrays(1, &this->vertexArrayObj3);
glDeleteBuffers(1, &this->vertexBufferObj3);
glDeleteBuffers(1, &this->elementBufferObj3);
glDeleteBuffers(1, &this->tex3);
this->window = NULL;
this->initialized = false;
}
}
CodePudding user response:
You want to make sure to keep the original form window around so that its opengl resources are not deallocated (which causes your current issues).
GLFWwindow * orig_window = glfwCreateWindow(800, 600, "The original window", NULL, NULL);
//init shaders etc. that you want to share between windows...
//for all windows created later, pass the original window as a shared context
GLFWwindow * shared_window = glfwCreateWindow(800, 600, "A shared window", NULL, orig_window);
For more info, check out the GLFW reference here: https://www.glfw.org/docs/3.3/group__window.html#ga5c336fddf2cbb5b92f65f10fb6043344