#include #include #include #include #include #include #include #include "shaders.hpp" #define X 10 #define Y 10 #define GRID_SIZE X *Y GLuint compileShader(GLenum type, const char *src) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, nullptr); glCompileShader(shader); int success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { char infoLog[512]; glGetShaderInfoLog(shader, 512, nullptr, infoLog); std::cerr << "ERROR::SHADER_COMPILATION_ERROR\n" << infoLog << std::endl; } return shader; } GLuint linkProgram(std::vector shaders) { GLuint program = glCreateProgram(); for (auto s : shaders) glAttachShader(program, s); glLinkProgram(program); int success; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { char infoLog[512]; glGetProgramInfoLog(program, 512, nullptr, infoLog); std::cerr << "ERROR::PROGRAM_LINK_ERROR\n" << infoLog << std::endl; } for (auto s : shaders) glDeleteShader(s); return program; } void resizeCall(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); } int main() { if (!glfwInit()) return -1; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); GLFWwindow *w = glfwCreateWindow(800, 600, "game of life", NULL, NULL); if (!w) return -2; glfwMakeContextCurrent(w); if (glewInit() != GLEW_OK) return -3; glfwShowWindow(w); glViewport(0, 0, 800, 600); glfwSetFramebufferSizeCallback(w, resizeCall); /*gen tex*/ GLuint tex[2]; glGenTextures(2, tex); for (int i = 0; i < 2; ++i) { glBindTexture(GL_TEXTURE_2D, tex[i]); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, X, Y); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); } /*rnd noise*/ std::vector data(GRID_SIZE * 4); std::mt19937 rng; std::uniform_int_distribution dist(0, 1); for (int i = 0; i < GRID_SIZE; ++i) { GLubyte v = dist(rng) * 255; data[i * 4 + 0] = v; // R channel data[i * 4 + 1] = v; // G channel data[i * 4 + 2] = v; // B channel data[i * 4 + 3] = 255; // A channel } glBindTexture(GL_TEXTURE_2D, tex[0]); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, X, Y, GL_RGBA, GL_UNSIGNED_BYTE, data.data()); GLuint cmp, rnd, vs, fs; cmp = linkProgram({compileShader(GL_COMPUTE_SHADER, computeShaderSrc)}); vs = compileShader(GL_VERTEX_SHADER, vertexShaderSrc); fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSrc); rnd = linkProgram({vs, fs}); /*vtex*/ GLuint VAO, VBO, EBO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadIndices), quadIndices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); glEnableVertexAttribArray(1); /**/ int ri, wi; ri = 0; wi = 1; while (!glfwWindowShouldClose(w)) { glfwPollEvents(); glClearColor(1.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); /*compute*/ glUseProgram(cmp); glBindImageTexture(0, tex[wi], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); glUniform1i(glGetUniformLocation(cmp, "srcTex"), 0); glUniform1i(glGetUniformLocation(cmp, "X"), X); glUniform1i(glGetUniformLocation(cmp, "Y"), Y); glDispatchCompute(X, Y, 1); glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); /*draw*/ glUseProgram(rnd); glActiveTexture(GL_TEXTURE0); glUniform1i(glGetUniformLocation(rnd, "tex0"), 0); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *)0); std::this_thread::sleep_for(std::chrono::duration(.05)); glfwSwapBuffers(w); std::swap(ri, wi); } glfwTerminate(); return 0; }