From 3cca69183e7fb890579e490744e457d37c0b5805 Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Thu, 22 Oct 2020 16:14:31 +0200 Subject: [PATCH] first version --- mandelbrot.nimble | 12 +++ src/mandelbrot/mandelbrot.nim | 133 ++++++++++++++++++++++++++++++++++ src/mandelbrot/shader.frag | 49 +++++++++++++ src/mandelbrot/shader.vert | 7 ++ 4 files changed, 201 insertions(+) create mode 100644 mandelbrot.nimble create mode 100644 src/mandelbrot/mandelbrot.nim create mode 100644 src/mandelbrot/shader.frag create mode 100644 src/mandelbrot/shader.vert diff --git a/mandelbrot.nimble b/mandelbrot.nimble new file mode 100644 index 0000000..63f49ec --- /dev/null +++ b/mandelbrot.nimble @@ -0,0 +1,12 @@ +# Package + +version = "0.1.0" +author = "Sander Hautvast" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" +bin = @["mandelbrot/mandelbrot"] + +# Dependencies + +requires "nim >= 1.4.0", "nimgl >= 1.1.5" \ No newline at end of file diff --git a/src/mandelbrot/mandelbrot.nim b/src/mandelbrot/mandelbrot.nim new file mode 100644 index 0000000..25c8879 --- /dev/null +++ b/src/mandelbrot/mandelbrot.nim @@ -0,0 +1,133 @@ +import nimgl/[glfw, opengl] + +var GLData: tuple[program, vertexShader, fragmentShader: uint32] +const + WIN_WIDTH = 1000 + WIN_HEIGHT = 800 + + +proc keyProc(window: GLFWWindow, key: int32, scancode: int32, action: int32, mods: int32): void {.cdecl.} = + if key == GLFWKey.ESCAPE and action == GLFWPress: + window.setWindowShouldClose(true) + + +proc logShaderCompilationFailure(shader: uint32, shader_path:string) = + var logSize: int32 + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, logSize.addr) + + var logStr = cast[ptr GLchar](alloc(logSize)) + + glGetShaderInfoLog(shader, logSize, nil, logStr) + echo "Error compiling shader: ", logStr + echo "Shader location: ", shader_path + # Cleanup + dealloc(logStr) + quit(-1) + +proc logProgramLinkingError() = + var logSize: int32 + glGetProgramiv(GLData.program, GL_INFO_LOG_LENGTH, logSize.addr) + + var logStr = cast[ptr GLchar](alloc(logSize)) + glGetProgramInfoLog(GLData.program, logSize, nil, logStr) + echo "Error linking shader program: ", logStr + # Cleanup + dealloc(logStr) + quit(-1) + +proc addShader(shader_path: string, shader_type: GLenum):uint32 = + let + shadercode = readFile(shader_path) + shader = glCreateShader(shader_type) + var shadercodeCString = cstring(shadercode) + glShaderSource(shader, 1, addr shadercodeCString, nil) + glCompileShader(shader) + + var success: int32 + glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) + if success == 0: logShaderCompilationFailure(shader, shader_path) + glAttachShader(GLData.program, shader) + return shader + + +proc initShaders(vertex_shader_path: string, fragment_shader_path: string) = + GLData.program = glCreateProgram() + GLData.vertexShader = addShader(vertex_shader_path, GL_VERTEX_SHADER) + GLData.fragmentShader = addShader(fragment_shader_path, GL_FRAGMENT_SHADER) + + glLinkProgram(GLData.program) + var success: int32 + glGetProgramiv(GLData.program, GL_LINK_STATUS, success.addr) + if success == 0: logProgramLinkingError() + + +proc main() = + assert glfwInit() + + glfwWindowHint(GLFWContextVersionMajor, 4) + glfwWindowHint(GLFWContextVersionMinor, 1) + glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE) # Used for Mac + glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE) + glfwWindowHint(GLFWResizable, GLFW_FALSE) + + let window = glfwCreateWindow(WIN_WIDTH, WIN_HEIGHT, "Simple Mandelbrot fractal") + assert window != nil + + discard window.setKeyCallback(keyProc) + window.makeContextCurrent() + + assert glInit() + + var vertices = @[ + -1.0f, -1.0f, -0.0f, + 1.0f, 1.0f, -0.0f, + -1.0f, 1.0f, -0.0f, + 1.0f, -1.0f, -0.0] + + var indices = @[ + 0'u32, 1'u32, 2'u32, + 0'u32, 3'u32, 1'u32] + # 2---,1 + # | .' | + # 0'---3 + + var mesh: tuple[vao,vbo,ebo: uint32] + + glGenVertexArrays(1, mesh.vao.addr) + glGenBuffers(1, mesh.vbo.addr) + glGenBuffers(1, mesh.ebo.addr) + glBindVertexArray(mesh.vao) + + # bind vertices + glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo) + glBufferData(GL_ARRAY_BUFFER, cint(cfloat.sizeof*vertices.len), vertices[0].addr, GL_STATIC_DRAW) + + # bind indices = elements + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, cint(cuint.sizeof*indices.len), indices[0].addr, GL_STATIC_DRAW) + + glVertexAttribPointer(0'u32, 3, EGL_FLOAT, false, 3 * cfloat.sizeof, nil) + glEnableVertexAttribArray(0) + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindVertexArray(mesh.vao) + initShaders("src/mandelbrot/shader.vert", "src/mandelbrot/shader.frag") + + while not window.windowShouldClose: + glClearColor(0.2, 0.2, 0.2, 0.5) + glUseProgram(GLData.program) + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) + glBindVertexArray(mesh.vao) + glDrawElements(GL_TRIANGLES, indices.len.cint, GL_UNSIGNED_INT, nil) + window.swapBuffers() + glfwPollEvents() + + window.destroyWindow() + glDeleteShader(GLData.vertexShader) + glDeleteShader(GLData.fragmentShader) + glDeleteVertexArrays(1, mesh.vao.addr) + glDeleteBuffers(1, mesh.vbo.addr) + glDeleteBuffers(1, mesh.ebo.addr) + glfwTerminate() + + +main() \ No newline at end of file diff --git a/src/mandelbrot/shader.frag b/src/mandelbrot/shader.frag new file mode 100644 index 0000000..2d1d03e --- /dev/null +++ b/src/mandelbrot/shader.frag @@ -0,0 +1,49 @@ +#version 410 core +in vec4 gl_FragCoord; + +out vec4 frag_color; + +#define MAX_ITERATIONS 500 + +int get_iterations() +{ + float real = (gl_FragCoord.x / 1080.0 - 1.2) * 1.5; + float imag = (gl_FragCoord.y / 1080.0 - 0.7) * 1.5 ; + + int iterations = 0; + float const_real = real; + float const_imag = imag; + + while (iterations < MAX_ITERATIONS) + { + float tmp_real = real; + real = (real * real - imag * imag) + const_real; + imag = (2.0 * tmp_real * imag) + const_imag; + + float dist = real * real + imag * imag; + + if (dist > 4.0) + break; + + ++iterations; + } + return iterations; +} + +vec4 return_color() +{ + int iter = get_iterations(); + if (iter == MAX_ITERATIONS) + { + gl_FragDepth = 0.0f; + return vec4(0.0f, 0.0f, 0.0f, 1.0f); + } + + float iterations = float(iter) / MAX_ITERATIONS; + return vec4(0.0f, iterations, 0.0f, 1.0f); +} + +void main() +{ + frag_color = return_color(); +} \ No newline at end of file diff --git a/src/mandelbrot/shader.vert b/src/mandelbrot/shader.vert new file mode 100644 index 0000000..e4a8b3d --- /dev/null +++ b/src/mandelbrot/shader.vert @@ -0,0 +1,7 @@ +#version 410 core +layout (location = 0) in vec3 pos; + +void main() +{ + gl_Position = vec4(pos.xyz, 1.0); +} \ No newline at end of file