// Modern OpenGL (3.3 core): a spinning, colorful triangle drawn with shaders. // Shows structs of numbers going to the GPU, C out-parameters with addr(), and // pointers made from numbers with ptr(...). Needs GLFW and OpenGL (in shell.nix). import "opengl.h" link "glfw" link "GL" fn compileShader(u32 kind, str source) -> u32 { shader := glCreateShader(kind) src := source.ptr glShaderSource(shader, 1, addr(src), null) glCompileShader(shader) i32 ok glGetShaderiv(shader, GL_COMPILE_STATUS, addr(ok)) if ok == 0 { log := " ".repeat(1024) glGetShaderInfoLog(shader, 1024, null, log) print("shader error:", str(log.ptr)) exit(1) } return shader } fn makeProgram() -> u32 { vertex := "#version 330 core\n" + "layout(location = 0) in vec2 pos;\n" + "layout(location = 1) in vec3 color;\n" + "uniform float time;\n" + "out vec3 vColor;\n" + "void main() {\n" + " float c = cos(time), s = sin(time);\n" + " gl_Position = vec4(c * pos.x - s * pos.y, s * pos.x + c * pos.y, 0.0, 1.0);\n" + " vColor = color;\n" + "}\n" fragment := "#version 330 core\n" + "in vec3 vColor;\n" + "out vec4 outColor;\n" + "void main() { outColor = vec4(vColor, 1.0); }\n" vs := compileShader(GL_VERTEX_SHADER, vertex) fs := compileShader(GL_FRAGMENT_SHADER, fragment) program := glCreateProgram() glAttachShader(program, vs) glAttachShader(program, fs) glLinkProgram(program) glDeleteShader(vs) glDeleteShader(fs) return program } fn main() { if glfwInit() == 0 { print("could not start GLFW") return } defer glfwTerminate() glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE) window := glfwCreateWindow(800, 600, "Finch + OpenGL", null, null) if window == null { print("could not open a window (does your GPU support OpenGL 3.3?)") return } glfwMakeContextCurrent(window) glfwSwapInterval(1) print("OpenGL", str(glGetString(GL_VERSION)), "on", str(glGetString(GL_RENDERER))) // x, y, r, g, b for each corner []f32 vertices = [ 0.0, 0.6, 1.0, 0.48, 0.1, -0.6, -0.4, 0.2, 0.6, 1.0, 0.6, -0.4, 0.6, 1.0, 0.4, ] u32 vao u32 vbo glGenVertexArrays(1, addr(vao)) glGenBuffers(1, addr(vbo)) glBindVertexArray(vao) glBindBuffer(GL_ARRAY_BUFFER, vbo) glBufferData(GL_ARRAY_BUFFER, vertices.len * 4, vertices.ptr, GL_STATIC_DRAW) i32 stride = 5 * 4 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, ptr(0)) glEnableVertexAttribArray(0) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, ptr(2 * 4)) glEnableVertexAttribArray(1) program := makeProgram() timeLoc := glGetUniformLocation(program, "time") while glfwWindowShouldClose(window) == 0 { glClearColor(0.106, 0.122, 0.165, 1.0) glClear(GL_COLOR_BUFFER_BIT) glUseProgram(program) glUniform1f(timeLoc, f32(glfwGetTime())) glDrawArrays(GL_TRIANGLES, 0, 3) glfwSwapBuffers(window) glfwPollEvents() } glDeleteBuffers(1, addr(vbo)) glDeleteVertexArrays(1, addr(vao)) glDeleteProgram(program) }