diff --git a/tests/sharing.c b/tests/sharing.c index a7f1a319..40254cf6 100644 --- a/tests/sharing.c +++ b/tests/sharing.c @@ -33,11 +33,34 @@ #include #include -#define WIDTH 400 -#define HEIGHT 400 -#define OFFSET 50 +#include "linmath.h" -static GLFWwindow* windows[2]; +static const char* vertex_shader_text = +"uniform mat4 MVP;\n" +"attribute vec2 vPos;\n" +"varying vec2 texcoord;\n" +"void main()\n" +"{\n" +" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n" +" texcoord = vPos;\n" +"}\n"; + +static const char* fragment_shader_text = +"uniform sampler2D texture;\n" +"uniform vec3 color;\n" +"varying vec2 texcoord;\n" +"void main()\n" +"{\n" +" gl_FragColor = vec4(color * tex2D(texture, texcoord).rgb, 1.0);\n" +"}\n"; + +static const vec2 vertices[4] = +{ + { 0.f, 0.f }, + { 1.f, 0.f }, + { 1.f, 1.f }, + { 0.f, 1.f } +}; static void error_callback(int error, const char* description) { @@ -50,132 +73,155 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, glfwSetWindowShouldClose(window, GLFW_TRUE); } -static GLFWwindow* open_window(const char* title, GLFWwindow* share, int posX, int posY) -{ - GLFWwindow* window; - - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); - window = glfwCreateWindow(WIDTH, HEIGHT, title, NULL, share); - if (!window) - return NULL; - - glfwMakeContextCurrent(window); - gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); - glfwSwapInterval(1); - glfwSetWindowPos(window, posX, posY); - glfwShowWindow(window); - - glfwSetKeyCallback(window, key_callback); - - return window; -} - -static GLuint create_texture(void) -{ - int x, y; - char pixels[256 * 256]; - GLuint texture; - - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - for (y = 0; y < 256; y++) - { - for (x = 0; x < 256; x++) - pixels[y * 256 + x] = rand() % 256; - } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 256, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - return texture; -} - -static void draw_quad(GLuint texture) -{ - int width, height; - glfwGetFramebufferSize(glfwGetCurrentContext(), &width, &height); - - glViewport(0, 0, width, height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.f, 1.f, 0.f, 1.f, 0.f, 1.f); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texture); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glBegin(GL_QUADS); - - glTexCoord2f(0.f, 0.f); - glVertex2f(0.f, 0.f); - - glTexCoord2f(1.f, 0.f); - glVertex2f(1.f, 0.f); - - glTexCoord2f(1.f, 1.f); - glVertex2f(1.f, 1.f); - - glTexCoord2f(0.f, 1.f); - glVertex2f(0.f, 1.f); - - glEnd(); -} - int main(int argc, char** argv) { - int x, y, width; - GLuint texture; + GLFWwindow* windows[2]; + GLuint texture, vertex_shader, fragment_shader, program, vertex_buffer; + GLint mvp_location, vpos_location, color_location, texture_location; glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - windows[0] = open_window("First", NULL, OFFSET, OFFSET); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + + windows[0] = glfwCreateWindow(400, 400, "First", NULL, NULL); if (!windows[0]) { glfwTerminate(); exit(EXIT_FAILURE); } - // This is the one and only time we create a texture - // It is created inside the first context, created above - // It will then be shared with the second context, created below - texture = create_texture(); + glfwSetKeyCallback(windows[0], key_callback); - glfwGetWindowPos(windows[0], &x, &y); - glfwGetWindowSize(windows[0], &width, NULL); + glfwMakeContextCurrent(windows[0]); - // Put the second window to the right of the first one - windows[1] = open_window("Second", windows[0], x + width + OFFSET, y); + // Only enable vsync for the first of the windows to be swapped to + // avoid waiting out the interval for each window + glfwSwapInterval(1); + + // The contexts are created with the same APIs so the function + // pointers should be re-usable between them + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + + // Create the OpenGL objects inside the first context, created above + // All objects will be shared with the second context, created below + { + int x, y; + char pixels[256 * 256]; + GLuint vertex_shader, fragment_shader; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + for (y = 0; y < 256; y++) + { + for (x = 0; x < 256; x++) + pixels[y * 256 + x] = rand() % 256; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 256, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); + glCompileShader(vertex_shader); + + fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); + glCompileShader(fragment_shader); + + program = glCreateProgram(); + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + glLinkProgram(program); + + mvp_location = glGetUniformLocation(program, "MVP"); + color_location = glGetUniformLocation(program, "color"); + texture_location = glGetUniformLocation(program, "texture"); + vpos_location = glGetAttribLocation(program, "vPos"); + + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + } + + glUseProgram(program); + glUniform1i(texture_location, 0); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture); + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glEnableVertexAttribArray(vpos_location); + glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE, + sizeof(vertices[0]), (void*) 0); + + windows[1] = glfwCreateWindow(400, 400, "Second", NULL, windows[0]); if (!windows[1]) { glfwTerminate(); exit(EXIT_FAILURE); } - // Set drawing color for both contexts - glfwMakeContextCurrent(windows[0]); - glColor3f(0.6f, 0.f, 0.6f); - glfwMakeContextCurrent(windows[1]); - glColor3f(0.6f, 0.6f, 0.f); + // Place the second window to the right of the first + { + int xpos, ypos, left, right, width; - glfwMakeContextCurrent(windows[0]); + glfwGetWindowSize(windows[0], &width, NULL); + glfwGetWindowFrameSize(windows[0], &left, NULL, &right, NULL); + glfwGetWindowPos(windows[0], &xpos, &ypos); + + glfwSetWindowPos(windows[1], xpos + width + left + right, ypos); + } + + glfwSetKeyCallback(windows[1], key_callback); + + glfwMakeContextCurrent(windows[1]); + + // While objects are shared, the global context state is not and will + // need to be set up for each context + + glUseProgram(program); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture); + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glEnableVertexAttribArray(vpos_location); + glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE, + sizeof(vertices[0]), (void*) 0); while (!glfwWindowShouldClose(windows[0]) && !glfwWindowShouldClose(windows[1])) { - glfwMakeContextCurrent(windows[0]); - draw_quad(texture); + int i; + const vec3 colors[2] = + { + { 0.6f, 0.6f, 0.f }, + { 0.6f, 0.f, 0.6f } + }; - glfwMakeContextCurrent(windows[1]); - draw_quad(texture); + for (i = 0; i < 2; i++) + { + int width, height; + mat4x4 mvp; - glfwSwapBuffers(windows[0]); - glfwSwapBuffers(windows[1]); + glfwGetFramebufferSize(windows[i], &width, &height); + glfwMakeContextCurrent(windows[i]); + + glViewport(0, 0, width, height); + + mat4x4_ortho(mvp, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f); + glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp); + glUniform3fv(color_location, 1, colors[i]); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glfwSwapBuffers(windows[i]); + } glfwWaitEvents(); }