├── .gitignore ├── 01-GettingStarted ├── 01-HelloWindow │ ├── HelloWindow.nim │ └── build-all.sh ├── 02-HelloTriangle │ ├── Exercises │ │ ├── Exercise1.nim │ │ ├── Exercise2.nim │ │ └── Exercise3.nim │ ├── HelloRectangle.nim │ ├── HelloTriangle.nim │ └── build-all.sh ├── 03-Shaders │ ├── Exercises │ │ ├── Exercise1.nim │ │ ├── Exercise2.nim │ │ ├── Exercise3.nim │ │ ├── exercise1.fs │ │ ├── exercise1.vs │ │ ├── exercise2.fs │ │ ├── exercise2.vs │ │ ├── exercise3.fs │ │ └── exercise3.vs │ ├── Shader1.nim │ ├── Shader2.nim │ ├── Shader3.nim │ ├── build-all.sh │ ├── shader1.fs │ ├── shader1.vs │ ├── shader2.fs │ ├── shader2.vs │ ├── shader3.fs │ └── shader3.vs ├── 04-Textures │ ├── Container1.nim │ ├── Container2.nim │ ├── Container3.nim │ ├── Data │ │ ├── awesomeface.jpg │ │ └── container.jpg │ ├── Exercises │ │ ├── Exercise1.nim │ │ ├── Exercise2.nim │ │ ├── Exercise3.nim │ │ ├── Exercise4.nim │ │ ├── exercise1.fs │ │ ├── exercise1.vs │ │ ├── exercise2.fs │ │ ├── exercise2.vs │ │ ├── exercise3.fs │ │ ├── exercise3.vs │ │ ├── exercise4.fs │ │ └── exercise4.vs │ ├── build-all.sh │ ├── container1.fs │ ├── container1.vs │ ├── container2.fs │ ├── container2.vs │ ├── container3.fs │ └── container3.vs ├── 05-Transformations │ ├── Data │ │ ├── awesomeface.jpg │ │ └── container.jpg │ ├── Exercises │ │ ├── Exercise1.nim │ │ ├── Exercise2.nim │ │ ├── exercise1.fs │ │ ├── exercise1.vs │ │ ├── exercise2.fs │ │ └── exercise2.vs │ ├── Transform │ ├── Transform1.nim │ ├── Transform2.nim │ ├── build-all.sh │ ├── transform1.fs │ ├── transform1.vs │ ├── transform2.fs │ └── transform2.vs ├── 06-CoordinateSystems │ ├── Coords1.nim │ ├── Coords2.nim │ ├── Coords3.nim │ ├── Data │ │ ├── awesomeface.jpg │ │ └── container.jpg │ ├── Exercises │ │ ├── Exercise3.nim │ │ ├── exercise3.fs │ │ └── exercise3.vs │ ├── build-all.sh │ ├── coords1.fs │ ├── coords1.vs │ ├── coords2.fs │ ├── coords2.vs │ ├── coords3.fs │ └── coords3.vs ├── 07-Camera │ ├── Camera1.nim │ ├── Camera2.nim │ ├── Camera3.nim │ ├── Camera4.nim │ ├── Data │ │ ├── awesomeface.jpg │ │ └── container.jpg │ ├── build-all.sh │ ├── camera1.fs │ ├── camera1.vs │ ├── camera2.fs │ ├── camera2.vs │ ├── camera3.fs │ ├── camera3.vs │ ├── camera4.fs │ └── camera4.vs └── build-all.sh ├── 02-Lighting ├── 01-Colors │ ├── Colors.nim │ ├── build-all.sh │ ├── colors.fs │ ├── colors.vs │ ├── lamp.fs │ └── lamp.vs ├── 02-BasicLighting │ ├── BasicLighting1.nim │ ├── BasicLighting2.nim │ ├── Exercises │ │ ├── Exercise1.nim │ │ ├── Exercise3.nim │ │ ├── exercise1.fs │ │ ├── exercise1.vs │ │ ├── exercise3.fs │ │ ├── exercise3.vs │ │ ├── lamp.fs │ │ └── lamp.vs │ ├── basiclighting1.fs │ ├── basiclighting1.vs │ ├── basiclighting2.fs │ ├── basiclighting2.vs │ ├── build-all.sh │ ├── lamp.fs │ └── lamp.vs └── build-all.sh ├── Common ├── FpsCamera.nim └── Shader.nim ├── README.md ├── TODO ├── glad └── gl.nim └── nim.cfg /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache 2 | *~ 3 | *.swp 4 | .DS_Store 5 | ._* 6 | *.exe 7 | -------------------------------------------------------------------------------- /01-GettingStarted/01-HelloWindow/HelloWindow.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Hello-Window 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | 10 | 11 | proc draw() = 12 | glClearColor(0.2, 0.3, 0.3, 1.0) 13 | glClear(GL_COLOR_BUFFER_BIT) 14 | 15 | 16 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 17 | modKeys: set[ModifierKey]) = 18 | 19 | if action != kaUp: 20 | if key == keyEscape: 21 | win.shouldClose = true 22 | 23 | 24 | proc main() = 25 | # Initialise GLFW 26 | glfw.initialize() 27 | 28 | # Create window 29 | var cfg = DefaultOpenglWindowConfig 30 | cfg.size = (w: 800, h: 600) 31 | cfg.title = "01-HelloWindow/HelloWindow" 32 | cfg.resizable = false 33 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 34 | cfg.version = glv33 35 | cfg.profile = opCoreProfile 36 | cfg.forwardCompat = true 37 | 38 | var win = newWindow(cfg) 39 | 40 | # Initialise OpenGL 41 | glfw.makeContextCurrent(win) 42 | 43 | if not gladLoadGL(getProcAddress): 44 | quit "Error initialising OpenGL" 45 | 46 | # Define viewport dimensions 47 | var width, height: int 48 | (width, height) = framebufferSize(win) 49 | glViewport(0, 0, GLint(width), GLint(height)) 50 | 51 | # Turn on vsync (0 turns it off) 52 | glfw.swapInterval(1) 53 | 54 | # Setup callbacks 55 | win.keyCb = keyCb 56 | 57 | # Game loop 58 | while not win.shouldClose: 59 | glfw.pollEvents() 60 | draw() 61 | glfw.swapBuffers(win) 62 | 63 | # Destroy window 64 | win.destroy() 65 | 66 | # Terminate GLFW, clearing any allocated resources 67 | glfw.terminate() 68 | 69 | 70 | main() 71 | 72 | -------------------------------------------------------------------------------- /01-GettingStarted/01-HelloWindow/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c HelloWindow.nim 2 | -------------------------------------------------------------------------------- /01-GettingStarted/02-HelloTriangle/Exercises/Exercise1.nim: -------------------------------------------------------------------------------- 1 | # Try to draw 2 triangles next to each other using glDrawArrays by adding more 2 | # vertices to your data. 3 | # 4 | # Read the accompanying article at 5 | # https://learnopengl.com/#!Getting-started/Hello-Triangle 6 | 7 | import math 8 | 9 | import glm 10 | import glad/gl 11 | import glfw 12 | 13 | 14 | var vertices = [ 15 | GLfloat(-0.7), -0.3, 0.0, 16 | -0.1, -0.3, 0.0, 17 | -0.4, 0.3, 0.0, 18 | 19 | 0.1 , -0.3, 0.0, 20 | 0.7, -0.3, 0.0, 21 | 0.4, 0.3, 0.0 22 | ] 23 | 24 | let vertexShaderSource = """ 25 | #version 330 core 26 | 27 | layout (location = 0) in vec3 position; 28 | 29 | void main() 30 | { 31 | gl_Position = vec4(position.x, position.y, position.z, 1.0); 32 | } 33 | """ 34 | 35 | let fragmentShaderSource = """ 36 | #version 330 core 37 | 38 | out vec4 color; 39 | 40 | void main() 41 | { 42 | color = vec4(1.0f, 0.5f, 0.2f, 1.0f); 43 | } 44 | """ 45 | 46 | var 47 | vao, vbo, shaderProgram: GLuint 48 | 49 | 50 | proc compileShader(shaderType: GLenum, source: string): GLuint = 51 | var 52 | shader = glCreateShader(shaderType) 53 | sourceArr = [cstring(source)] 54 | 55 | glShaderSource(shader, 1, cast[cstringArray](sourceArr.addr), nil) 56 | glCompileShader(shader) 57 | result = shader 58 | 59 | 60 | proc getShaderCompilationResult(shader: GLuint): tuple[success: bool, 61 | error: string] = 62 | var 63 | success: GLint 64 | infoLog = newString(1024) 65 | 66 | glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) 67 | 68 | if success == 0: 69 | glGetShaderInfoLog(shader, GLsizei(infoLog.len), nil, infoLog) 70 | result = (success: false, error: $infoLog) 71 | else: 72 | result = (success: true, error: "") 73 | 74 | 75 | proc getProgramLinkingResult(program: GLuint): tuple[success: bool, 76 | error: string] = 77 | var 78 | success: GLint 79 | infoLog = newString(1024) 80 | 81 | glGetProgramiv(program, GL_LINK_STATUS, success.addr) 82 | 83 | if success == 0: 84 | glGetShaderInfoLog(program, GLsizei(infoLog.len), nil, infoLog) 85 | result = (success: false, error: $infoLog) 86 | else: 87 | result = (success: true, error: "") 88 | 89 | 90 | proc createShaderProgram(vertexShaderSource, 91 | fragmentShaderSource: string): GLuint = 92 | # Compile shaders 93 | let 94 | vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource) 95 | fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource) 96 | 97 | var res = getShaderCompilationResult(vertexShader) 98 | if not res.success: 99 | echo "ERROR: vertex shader compilation failed: " & res.error 100 | 101 | res = getShaderCompilationResult(fragmentShader) 102 | if not res.success: 103 | echo "ERROR: fragment shader compilation failed: " & res.error 104 | 105 | # Create shader program 106 | let shaderProgram = glCreateProgram() 107 | glAttachShader(shaderProgram, vertexShader) 108 | glAttachShader(shaderProgram, fragmentShader) 109 | glLinkProgram(shaderProgram) 110 | 111 | res = getProgramLinkingResult(shaderProgram) 112 | if not res.success: 113 | echo "ERROR: shader program linking failed: " & res.error 114 | 115 | # We don't need the compiled shaders anymore, just the program 116 | glDeleteShader(vertexShader) 117 | glDeleteShader(fragmentShader) 118 | 119 | result = shaderProgram 120 | 121 | 122 | proc setup() = 123 | shaderProgram = createShaderProgram(vertexShaderSource, 124 | fragmentShaderSource) 125 | 126 | # Create Vertex Array Object 127 | glGenVertexArrays(1, vao.addr) 128 | 129 | # Create Vertex Buffer Object 130 | glGenBuffers(1, vbo.addr) 131 | 132 | # Bind the Vertex Array Object first, then bind and set vertex buffer(s) 133 | # and attribute pointer(s) 134 | glBindVertexArray(vao) 135 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 136 | 137 | # Copy vertex data from CPU memory into GPU memory 138 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 139 | vertices.addr, GL_STATIC_DRAW) 140 | 141 | # Tell OpenGL how it should interpret the vertex data 142 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 143 | normalized = false, 144 | stride = 3 * sizeof(GLfloat), 145 | pointer = cast[pointer](0)) 146 | 147 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 148 | # by default) 149 | glEnableVertexAttribArray(index = 0) 150 | 151 | # Note that this is allowed; the call to glVertexAttribPointer registered 152 | # VBO as the currently bound vertex buffer object so afterwards we can 153 | # safely unbind 154 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 155 | 156 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 157 | # strange bugs) 158 | glBindVertexArray(GL_NONE) 159 | 160 | 161 | proc cleanup() = 162 | glDeleteVertexArrays(1, vao.addr) 163 | glDeleteBuffers(1, vbo.addr) 164 | 165 | 166 | proc draw() = 167 | # Clear the color buffer 168 | glClearColor(0.2, 0.3, 0.3, 1.0) 169 | glClear(GL_COLOR_BUFFER_BIT) 170 | 171 | # Draw triangles 172 | glUseProgram(shaderProgram) 173 | glBindVertexArray(vao) 174 | glDrawArrays(GL_TRIANGLES, first = 0, count = 6) 175 | glBindVertexArray(GL_NONE) 176 | 177 | 178 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 179 | modKeys: set[ModifierKey]) = 180 | 181 | if action != kaUp: 182 | if key == keyEscape: 183 | win.shouldClose = true 184 | 185 | 186 | proc main() = 187 | # Initialise GLFW 188 | glfw.initialize() 189 | 190 | # Create window 191 | var cfg = DefaultOpenglWindowConfig 192 | cfg.size = (w: 800, h: 600) 193 | cfg.title = "02-HelloTriangle/Exercise1" 194 | cfg.resizable = false 195 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 196 | cfg.version = glv33 197 | cfg.profile = opCoreProfile 198 | cfg.forwardCompat = true 199 | 200 | var win = newWindow(cfg) 201 | 202 | # Initialise OpenGL 203 | glfw.makeContextCurrent(win) 204 | 205 | if not gladLoadGL(getProcAddress): 206 | quit "Error initialising OpenGL" 207 | 208 | # Define viewport dimensions 209 | var width, height: int 210 | (width, height) = framebufferSize(win) 211 | glViewport(0, 0, GLint(width), GLint(height)) 212 | 213 | # Turn on vsync (0 turns it off) 214 | glfw.swapInterval(1) 215 | 216 | # Setup callbacks 217 | win.keyCb = keyCb 218 | 219 | # Setup shaders and various OpenGL objects 220 | setup() 221 | 222 | # Game loop 223 | while not win.shouldClose: 224 | glfw.pollEvents() 225 | draw() 226 | glfw.swapBuffers(win) 227 | 228 | # Properly de-allocate all resources once they've outlived their purpose 229 | cleanup() 230 | 231 | # Destroy window 232 | win.destroy() 233 | 234 | # Terminate GLFW, clearing any allocated resources 235 | glfw.terminate() 236 | 237 | 238 | main() 239 | 240 | -------------------------------------------------------------------------------- /01-GettingStarted/02-HelloTriangle/Exercises/Exercise2.nim: -------------------------------------------------------------------------------- 1 | # Now create the same 2 triangles using two different VAOs and VBOs for their 2 | # data. 3 | # 4 | # Read the accompanying article at 5 | # https://learnopengl.com/#!Getting-started/Hello-Triangle 6 | 7 | import math 8 | 9 | import glm 10 | import glad/gl 11 | import glfw 12 | 13 | 14 | var vertices1 = [ 15 | GLfloat(-0.7),-0.3, 0.0, 16 | -0.1, -0.3, 0.0, 17 | -0.4, 0.3, 0.0 18 | ] 19 | 20 | var vertices2 = [ 21 | GLfloat( 0.1),-0.3, 0.0, 22 | 0.7, -0.3, 0.0, 23 | 0.4, 0.3, 0.0 24 | ] 25 | 26 | let vertexShaderSource = """ 27 | #version 330 core 28 | 29 | layout (location = 0) in vec3 position; 30 | 31 | void main() 32 | { 33 | gl_Position = vec4(position.x, position.y, position.z, 1.0); 34 | } 35 | """ 36 | 37 | let fragmentShaderSource = """ 38 | #version 330 core 39 | 40 | out vec4 color; 41 | 42 | void main() 43 | { 44 | color = vec4(1.0f, 0.5f, 0.2f, 1.0f); 45 | } 46 | """ 47 | 48 | var 49 | vao1, vao2, vbo1, vbo2, shaderProgram: GLuint 50 | 51 | 52 | proc compileShader(shaderType: GLenum, source: string): GLuint = 53 | var 54 | shader = glCreateShader(shaderType) 55 | sourceArr = [cstring(source)] 56 | 57 | glShaderSource(shader, 1, cast[cstringArray](sourceArr.addr), nil) 58 | glCompileShader(shader) 59 | result = shader 60 | 61 | 62 | proc getShaderCompilationResult(shader: GLuint): tuple[success: bool, 63 | error: string] = 64 | var 65 | success: GLint 66 | infoLog = newString(1024) 67 | 68 | glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) 69 | 70 | if success == 0: 71 | glGetShaderInfoLog(shader, GLsizei(infoLog.len), nil, infoLog) 72 | result = (success: false, error: $infoLog) 73 | else: 74 | result = (success: true, error: "") 75 | 76 | 77 | proc getProgramLinkingResult(program: GLuint): tuple[success: bool, 78 | error: string] = 79 | var 80 | success: GLint 81 | infoLog = newString(1024) 82 | 83 | glGetProgramiv(program, GL_LINK_STATUS, success.addr) 84 | 85 | if success == 0: 86 | glGetShaderInfoLog(program, GLsizei(infoLog.len), nil, infoLog) 87 | result = (success: false, error: $infoLog) 88 | else: 89 | result = (success: true, error: "") 90 | 91 | 92 | proc createShaderProgram(vertexShaderSource, 93 | fragmentShaderSource: string): GLuint = 94 | # Compile shaders 95 | let 96 | vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource) 97 | fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource) 98 | 99 | var res = getShaderCompilationResult(vertexShader) 100 | if not res.success: 101 | echo "ERROR: vertex shader compilation failed: " & res.error 102 | 103 | res = getShaderCompilationResult(fragmentShader) 104 | if not res.success: 105 | echo "ERROR: fragment shader compilation failed: " & res.error 106 | 107 | # Create shader program 108 | let shaderProgram = glCreateProgram() 109 | glAttachShader(shaderProgram, vertexShader) 110 | glAttachShader(shaderProgram, fragmentShader) 111 | glLinkProgram(shaderProgram) 112 | 113 | res = getProgramLinkingResult(shaderProgram) 114 | if not res.success: 115 | echo "ERROR: shader program linking failed: " & res.error 116 | 117 | # We don't need the compiled shaders anymore, just the program 118 | glDeleteShader(vertexShader) 119 | glDeleteShader(fragmentShader) 120 | 121 | result = shaderProgram 122 | 123 | 124 | proc setupVertexData(vao, vbo: ptr GLuint, 125 | vertices: ptr GLfloat, numVertices: GLsizeiptr) = 126 | 127 | # Create Vertex Array Object 128 | glGenVertexArrays(1, vao) 129 | 130 | # Create Vertex Buffer Object 131 | glGenBuffers(1, vbo) 132 | 133 | # Bind the Vertex Array Object first, then bind and set vertex buffer(s) 134 | # and attribute pointer(s) 135 | glBindVertexArray(vao[]) 136 | glBindBuffer(GL_ARRAY_BUFFER, vbo[]) 137 | 138 | # Copy vertex data from CPU memory into GPU memory 139 | glBufferData(GL_ARRAY_BUFFER, numVertices, vertices, GL_STATIC_DRAW) 140 | 141 | # Tell OpenGL how it should interpret the vertex data 142 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 143 | normalized = false, 144 | stride = 3 * sizeof(GLfloat), 145 | pointer = cast[pointer](0)) 146 | 147 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 148 | # by default) 149 | glEnableVertexAttribArray(index = 0) 150 | 151 | # Note that this is allowed; the call to glVertexAttribPointer registered 152 | # VBO as the currently bound vertex buffer object so afterwards we can 153 | # safely unbind 154 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 155 | 156 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 157 | # strange bugs) 158 | glBindVertexArray(GL_NONE) 159 | 160 | 161 | proc setup() = 162 | shaderProgram = createShaderProgram(vertexShaderSource, 163 | fragmentShaderSource) 164 | 165 | setupVertexData(vao1.addr, vbo1.addr, 166 | vertices1[0].addr, GLsizeiptr(sizeof(vertices1))) 167 | 168 | setupVertexData(vao2.addr, vbo2.addr, 169 | vertices2[0].addr, GLsizeiptr(sizeof(vertices2))) 170 | 171 | 172 | proc cleanup() = 173 | glDeleteVertexArrays(1, vao1.addr) 174 | glDeleteVertexArrays(1, vao2.addr) 175 | 176 | glDeleteBuffers(1, vbo1.addr) 177 | glDeleteBuffers(1, vbo2.addr) 178 | 179 | 180 | proc draw() = 181 | # Clear the color buffer 182 | glClearColor(0.2, 0.3, 0.3, 1.0) 183 | glClear(GL_COLOR_BUFFER_BIT) 184 | 185 | # Draw triangles 186 | glUseProgram(shaderProgram) 187 | 188 | glBindVertexArray(vao1) 189 | glDrawArrays(GL_TRIANGLES, first = 0, count = 6) 190 | 191 | glBindVertexArray(vao2) 192 | glDrawArrays(GL_TRIANGLES, first = 0, count = 6) 193 | 194 | glBindVertexArray(GL_NONE) 195 | 196 | 197 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 198 | modKeys: set[ModifierKey]) = 199 | 200 | if action != kaUp: 201 | if key == keyEscape: 202 | win.shouldClose = true 203 | 204 | 205 | proc main() = 206 | # Initialise GLFW 207 | glfw.initialize() 208 | 209 | # Create window 210 | var cfg = DefaultOpenglWindowConfig 211 | cfg.size = (w: 800, h: 600) 212 | cfg.title = "02-HelloTriangle/Exercise2" 213 | cfg.resizable = false 214 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 215 | cfg.version = glv33 216 | cfg.profile = opCoreProfile 217 | cfg.forwardCompat = true 218 | 219 | var win = newWindow(cfg) 220 | 221 | # Initialise OpenGL 222 | glfw.makeContextCurrent(win) 223 | 224 | if not gladLoadGL(getProcAddress): 225 | quit "Error initialising OpenGL" 226 | 227 | # Define viewport dimensions 228 | var width, height: int 229 | (width, height) = framebufferSize(win) 230 | glViewport(0, 0, GLint(width), GLint(height)) 231 | 232 | # Turn on vsync (0 turns it off) 233 | glfw.swapInterval(1) 234 | 235 | # Setup callbacks 236 | win.keyCb = keyCb 237 | 238 | # Setup shaders and various OpenGL objects 239 | setup() 240 | 241 | # Game loop 242 | while not win.shouldClose: 243 | glfw.pollEvents() 244 | draw() 245 | glfw.swapBuffers(win) 246 | 247 | # Properly de-allocate all resources once they've outlived their purpose 248 | cleanup() 249 | 250 | # Destroy window 251 | win.destroy() 252 | 253 | # Terminate GLFW, clearing any allocated resources 254 | glfw.terminate() 255 | 256 | 257 | main() 258 | 259 | -------------------------------------------------------------------------------- /01-GettingStarted/02-HelloTriangle/Exercises/Exercise3.nim: -------------------------------------------------------------------------------- 1 | # Create two shader programs where the second program uses a different 2 | # fragment shader that outputs the color yellow; draw both triangles again 3 | # where one outputs the color yellow. 4 | # 5 | # Read the accompanying article at 6 | # https://learnopengl.com/#!Getting-started/Hello-Triangle 7 | 8 | import math 9 | 10 | import glm 11 | import glad/gl 12 | import glfw 13 | 14 | 15 | var vertices1 = [ 16 | GLfloat(-0.7),-0.3, 0.0, 17 | -0.1, -0.3, 0.0, 18 | -0.4, 0.3, 0.0 19 | ] 20 | 21 | var vertices2 = [ 22 | GLfloat( 0.1),-0.3, 0.0, 23 | 0.7, -0.3, 0.0, 24 | 0.4, 0.3, 0.0 25 | ] 26 | 27 | let vertexShaderSource = """ 28 | #version 330 core 29 | 30 | layout (location = 0) in vec3 position; 31 | 32 | void main() 33 | { 34 | gl_Position = vec4(position.x, position.y, position.z, 1.0); 35 | } 36 | """ 37 | 38 | let fragmentShaderSource1 = """ 39 | #version 330 core 40 | 41 | out vec4 color; 42 | 43 | void main() 44 | { 45 | color = vec4(1.0f, 0.5f, 0.2f, 1.0f); 46 | } 47 | """ 48 | 49 | let fragmentShaderSource2 = """ 50 | #version 330 core 51 | 52 | out vec4 color; 53 | 54 | void main() 55 | { 56 | color = vec4(1.0f, 1.0f, 0.2f, 1.0f); 57 | } 58 | """ 59 | 60 | var 61 | vao1, vao2, vbo1, vbo2, shaderProgram1, shaderProgram2: GLuint 62 | 63 | 64 | proc compileShader(shaderType: GLenum, source: string): GLuint = 65 | var 66 | shader = glCreateShader(shaderType) 67 | sourceArr = [cstring(source)] 68 | 69 | glShaderSource(shader, 1, cast[cstringArray](sourceArr.addr), nil) 70 | glCompileShader(shader) 71 | result = shader 72 | 73 | 74 | proc getShaderCompilationResult(shader: GLuint): tuple[success: bool, 75 | error: string] = 76 | var 77 | success: GLint 78 | infoLog = newString(1024) 79 | 80 | glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) 81 | 82 | if success == 0: 83 | glGetShaderInfoLog(shader, GLsizei(infoLog.len), nil, infoLog) 84 | result = (success: false, error: $infoLog) 85 | else: 86 | result = (success: true, error: "") 87 | 88 | 89 | proc getProgramLinkingResult(program: GLuint): tuple[success: bool, 90 | error: string] = 91 | var 92 | success: GLint 93 | infoLog = newString(1024) 94 | 95 | glGetProgramiv(program, GL_LINK_STATUS, success.addr) 96 | 97 | if success == 0: 98 | glGetShaderInfoLog(program, GLsizei(infoLog.len), nil, infoLog) 99 | result = (success: false, error: $infoLog) 100 | else: 101 | result = (success: true, error: "") 102 | 103 | 104 | proc createShaderProgram(vertexShaderSource, 105 | fragmentShaderSource: string): GLuint = 106 | # Compile shaders 107 | let 108 | vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource) 109 | fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource) 110 | 111 | var res = getShaderCompilationResult(vertexShader) 112 | if not res.success: 113 | echo "ERROR: vertex shader compilation failed: " & res.error 114 | 115 | res = getShaderCompilationResult(fragmentShader) 116 | if not res.success: 117 | echo "ERROR: fragment shader compilation failed: " & res.error 118 | 119 | # Create shader program 120 | let shaderProgram = glCreateProgram() 121 | glAttachShader(shaderProgram, vertexShader) 122 | glAttachShader(shaderProgram, fragmentShader) 123 | glLinkProgram(shaderProgram) 124 | 125 | res = getProgramLinkingResult(shaderProgram) 126 | if not res.success: 127 | echo "ERROR: shader program linking failed: " & res.error 128 | 129 | # We don't need the compiled shaders anymore, just the program 130 | glDeleteShader(vertexShader) 131 | glDeleteShader(fragmentShader) 132 | 133 | result = shaderProgram 134 | 135 | 136 | proc setupVertexData(vao, vbo: ptr GLuint, 137 | vertices: ptr GLfloat, numVertices: GLsizeiptr) = 138 | 139 | # Create Vertex Array Object 140 | glGenVertexArrays(1, vao) 141 | 142 | # Create Vertex Buffer Object 143 | glGenBuffers(1, vbo) 144 | 145 | # Bind the Vertex Array Object first, then bind and set vertex buffer(s) 146 | # and attribute pointer(s) 147 | glBindVertexArray(vao[]) 148 | glBindBuffer(GL_ARRAY_BUFFER, vbo[]) 149 | 150 | # Copy vertex data from CPU memory into GPU memory 151 | glBufferData(GL_ARRAY_BUFFER, numVertices, vertices, GL_STATIC_DRAW) 152 | 153 | # Tell OpenGL how it should interpret the vertex data 154 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 155 | normalized = false, 156 | stride = 3 * sizeof(GLfloat), 157 | pointer = cast[pointer](0)) 158 | 159 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 160 | # by default) 161 | glEnableVertexAttribArray(index = 0) 162 | 163 | # Note that this is allowed; the call to glVertexAttribPointer registered 164 | # VBO as the currently bound vertex buffer object so afterwards we can 165 | # safely unbind 166 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 167 | 168 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 169 | # strange bugs) 170 | glBindVertexArray(GL_NONE) 171 | 172 | 173 | proc setup() = 174 | shaderProgram1 = createShaderProgram(vertexShaderSource, 175 | fragmentShaderSource1) 176 | 177 | shaderProgram2 = createShaderProgram(vertexShaderSource, 178 | fragmentShaderSource2) 179 | 180 | setupVertexData(vao1.addr, vbo1.addr, 181 | vertices1[0].addr, GLsizeiptr(sizeof(vertices1))) 182 | 183 | setupVertexData(vao2.addr, vbo2.addr, 184 | vertices2[0].addr, GLsizeiptr(sizeof(vertices2))) 185 | 186 | 187 | proc cleanup() = 188 | glDeleteVertexArrays(1, vao1.addr) 189 | glDeleteVertexArrays(1, vao2.addr) 190 | 191 | glDeleteBuffers(1, vbo1.addr) 192 | glDeleteBuffers(1, vbo2.addr) 193 | 194 | 195 | proc draw() = 196 | # Clear the color buffer 197 | glClearColor(0.2, 0.3, 0.3, 1.0) 198 | glClear(GL_COLOR_BUFFER_BIT) 199 | 200 | # Draw orange triangle 201 | glUseProgram(shaderProgram1) 202 | glBindVertexArray(vao1) 203 | glDrawArrays(GL_TRIANGLES, first = 0, count = 6) 204 | 205 | # Draw yellow triangle 206 | glUseProgram(shaderProgram2) 207 | glBindVertexArray(vao2) 208 | glDrawArrays(GL_TRIANGLES, first = 0, count = 6) 209 | 210 | glBindVertexArray(GL_NONE) 211 | 212 | 213 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 214 | modKeys: set[ModifierKey]) = 215 | 216 | if action != kaUp: 217 | if key == keyEscape: 218 | win.shouldClose = true 219 | 220 | 221 | proc main() = 222 | # Initialise GLFW 223 | glfw.initialize() 224 | 225 | # Create window 226 | var cfg = DefaultOpenglWindowConfig 227 | cfg.size = (w: 800, h: 600) 228 | cfg.title = "02-HelloTriangle/Exercise3" 229 | cfg.resizable = false 230 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 231 | cfg.version = glv33 232 | cfg.profile = opCoreProfile 233 | cfg.forwardCompat = true 234 | 235 | var win = newWindow(cfg) 236 | 237 | # Initialise OpenGL 238 | glfw.makeContextCurrent(win) 239 | 240 | if not gladLoadGL(getProcAddress): 241 | quit "Error initialising OpenGL" 242 | 243 | # Define viewport dimensions 244 | var width, height: int 245 | (width, height) = framebufferSize(win) 246 | glViewport(0, 0, GLint(width), GLint(height)) 247 | 248 | # Turn on vsync (0 turns it off) 249 | glfw.swapInterval(1) 250 | 251 | # Setup callbacks 252 | win.keyCb = keyCb 253 | 254 | # Setup shaders and various OpenGL objects 255 | setup() 256 | 257 | # Game loop 258 | while not win.shouldClose: 259 | glfw.pollEvents() 260 | draw() 261 | glfw.swapBuffers(win) 262 | 263 | # Properly de-allocate all resources once they've outlived their purpose 264 | cleanup() 265 | 266 | # Destroy window 267 | win.destroy() 268 | 269 | # Terminate GLFW, clearing any allocated resources 270 | glfw.terminate() 271 | 272 | 273 | main() 274 | 275 | -------------------------------------------------------------------------------- /01-GettingStarted/02-HelloTriangle/HelloRectangle.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Hello-Triangle 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | 10 | 11 | var vertices = [ 12 | GLfloat(0.5), 0.5, 0.0, # top right 13 | 0.5, -0.5, 0.0, # bottom right 14 | -0.5, -0.5, 0.0, # bottom left 15 | -0.5, 0.5, 0.0 # top left 16 | ] 17 | 18 | var indices = [ 19 | GLuint(0), 1, 3, # first triangle 20 | 1, 2, 3 # second triangle 21 | ] 22 | 23 | let vertexShaderSource = """ 24 | #version 330 core 25 | 26 | layout (location = 0) in vec3 position; 27 | 28 | void main() 29 | { 30 | gl_Position = vec4(position.x, position.y, position.z, 1.0); 31 | } 32 | """ 33 | 34 | let fragmentShaderSource = """ 35 | #version 330 core 36 | 37 | out vec4 color; 38 | 39 | void main() 40 | { 41 | color = vec4(1.0f, 0.5f, 0.2f, 1.0f); 42 | } 43 | """ 44 | 45 | var 46 | ebo, vao, vbo, shaderProgram: GLuint 47 | 48 | 49 | proc compileShader(shaderType: GLenum, source: string): GLuint = 50 | var 51 | shader = glCreateShader(shaderType) 52 | sourceArr = [cstring(source)] 53 | 54 | glShaderSource(shader, 1, cast[cstringArray](sourceArr.addr), nil) 55 | glCompileShader(shader) 56 | result = shader 57 | 58 | 59 | proc getShaderCompilationResult(shader: GLuint): tuple[success: bool, 60 | error: string] = 61 | var 62 | success: GLint 63 | infoLog = newString(1024) 64 | 65 | glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) 66 | 67 | if success == 0: 68 | glGetShaderInfoLog(shader, GLsizei(infoLog.len), nil, infoLog) 69 | result = (success: false, error: $infoLog) 70 | else: 71 | result = (success: true, error: "") 72 | 73 | 74 | proc getProgramLinkingResult(program: GLuint): tuple[success: bool, 75 | error: string] = 76 | var 77 | success: GLint 78 | infoLog = newString(1024) 79 | 80 | glGetProgramiv(program, GL_LINK_STATUS, success.addr) 81 | 82 | if success == 0: 83 | glGetShaderInfoLog(program, GLsizei(infoLog.len), nil, infoLog) 84 | result = (success: false, error: $infoLog) 85 | else: 86 | result = (success: true, error: "") 87 | 88 | 89 | proc createShaderProgram(vertexShaderSource, 90 | fragmentShaderSource: string): GLuint = 91 | # Compile shaders 92 | let 93 | vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource) 94 | fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource) 95 | 96 | var res = getShaderCompilationResult(vertexShader) 97 | if not res.success: 98 | echo "ERROR: vertex shader compilation failed: " & res.error 99 | 100 | res = getShaderCompilationResult(fragmentShader) 101 | if not res.success: 102 | echo "ERROR: fragment shader compilation failed: " & res.error 103 | 104 | # Create shader program 105 | let shaderProgram = glCreateProgram() 106 | glAttachShader(shaderProgram, vertexShader) 107 | glAttachShader(shaderProgram, fragmentShader) 108 | glLinkProgram(shaderProgram) 109 | 110 | res = getProgramLinkingResult(shaderProgram) 111 | if not res.success: 112 | echo "ERROR: shader program linking failed: " & res.error 113 | 114 | # We don't need the compiled shaders anymore, just the program 115 | glDeleteShader(vertexShader) 116 | glDeleteShader(fragmentShader) 117 | 118 | result = shaderProgram 119 | 120 | 121 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 122 | modKeys: set[ModifierKey]) = 123 | 124 | if action != kaUp: 125 | if key == keyEscape: 126 | win.shouldClose = true 127 | 128 | 129 | proc setup() = 130 | shaderProgram = createShaderProgram(vertexShaderSource, 131 | fragmentShaderSource) 132 | 133 | # Create Vertex Array Object 134 | glGenVertexArrays(1, vao.addr) 135 | 136 | # Create Element Buffer Object 137 | glGenBuffers(1, ebo.addr) 138 | 139 | # Create Vertex Buffer Object 140 | glGenBuffers(1, vbo.addr) 141 | 142 | # Bind the Vertex Array Object first, then bind and set vertex & element 143 | # buffer(s) and attribute pointer(s) 144 | glBindVertexArray(vao) 145 | 146 | # Copy vertex data from CPU memory into GPU memory 147 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 148 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 149 | vertices.addr, GL_STATIC_DRAW) 150 | 151 | # Tell OpenGL how it should interpret the vertex data 152 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 153 | normalized = false, 154 | stride = 3 * sizeof(GLfloat), 155 | pointer = cast[pointer](0)) 156 | 157 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 158 | # by default) 159 | glEnableVertexAttribArray(index = 0) 160 | 161 | # Copy element data from CPU memory into GPU memory 162 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo) 163 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 164 | indices.addr, GL_STATIC_DRAW) 165 | 166 | # Note that this is allowed; the call to glVertexAttribPointer registered 167 | # VBO as the currently bound vertex buffer object so afterwards we can 168 | # safely unbind 169 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 170 | 171 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 172 | # strange bugs) 173 | glBindVertexArray(GL_NONE) 174 | 175 | 176 | proc cleanup() = 177 | glDeleteVertexArrays(1, vao.addr) 178 | glDeleteBuffers(1, vbo.addr) 179 | glDeleteBuffers(1, ebo.addr) 180 | 181 | 182 | proc draw() = 183 | # Clear the color buffer 184 | glClearColor(0.2, 0.3, 0.3, 1.0) 185 | glClear(GL_COLOR_BUFFER_BIT) 186 | 187 | # Draw triangle 188 | glUseProgram(shaderProgram) 189 | glBindVertexArray(vao) 190 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 191 | indices = GLvoid(nil)) 192 | glBindVertexArray(GL_NONE) 193 | 194 | 195 | proc main() = 196 | # Initialise GLFW 197 | glfw.initialize() 198 | 199 | # Create window 200 | var cfg = DefaultOpenglWindowConfig 201 | cfg.size = (w: 800, h: 600) 202 | cfg.title = "02-HelloTriangle/HelloRectangle" 203 | cfg.resizable = false 204 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 205 | cfg.version = glv33 206 | cfg.profile = opCoreProfile 207 | cfg.forwardCompat = true 208 | 209 | var win = newWindow(cfg) 210 | 211 | # Initialise OpenGL 212 | glfw.makeContextCurrent(win) 213 | 214 | if not gladLoadGL(getProcAddress): 215 | quit "Error initialising OpenGL" 216 | 217 | # Define viewport dimensions 218 | var width, height: int 219 | (width, height) = framebufferSize(win) 220 | glViewport(0, 0, GLint(width), GLint(height)) 221 | 222 | # Turn on vsync (0 turns it off) 223 | glfw.swapInterval(1) 224 | 225 | # Setup callbacks 226 | win.keyCb = keyCb 227 | 228 | # Setup shaders and various OpenGL objects 229 | setup() 230 | 231 | # Game loop 232 | while not win.shouldClose: 233 | glfw.pollEvents() 234 | draw() 235 | glfw.swapBuffers(win) 236 | 237 | # Properly de-allocate all resources once they've outlived their purpose 238 | cleanup() 239 | 240 | # Destroy window 241 | win.destroy() 242 | 243 | # Terminate GLFW, clearing any allocated resources 244 | glfw.terminate() 245 | 246 | 247 | main() 248 | 249 | -------------------------------------------------------------------------------- /01-GettingStarted/02-HelloTriangle/HelloTriangle.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Hello-Triangle 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | 10 | 11 | var vertices = [ 12 | GLFloat(-0.5), -0.5, 0.0, 13 | 0.5, -0.5, 0.0, 14 | 0.0, 0.5, 0.0 15 | ] 16 | 17 | let vertexShaderSource = """ 18 | #version 330 core 19 | 20 | layout (location = 0) in vec3 position; 21 | 22 | void main() 23 | { 24 | gl_Position = vec4(position.x, position.y, position.z, 1.0); 25 | } 26 | """ 27 | 28 | let fragmentShaderSource = """ 29 | #version 330 core 30 | 31 | out vec4 color; 32 | 33 | void main() 34 | { 35 | color = vec4(1.0f, 0.5f, 0.2f, 1.0f); 36 | } 37 | """ 38 | 39 | var 40 | vao, vbo, shaderProgram: GLuint 41 | 42 | 43 | proc compileShader(shaderType: GLenum, source: string): GLuint = 44 | var 45 | shader = glCreateShader(shaderType) 46 | sourceArr = [cstring(source)] 47 | 48 | glShaderSource(shader, 1, cast[cstringArray](sourceArr.addr), nil) 49 | glCompileShader(shader) 50 | result = shader 51 | 52 | 53 | proc getShaderCompilationResult(shader: GLuint): tuple[success: bool, 54 | error: string] = 55 | var 56 | success: GLint 57 | infoLog = newString(1024) 58 | 59 | glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) 60 | 61 | if success == 0: 62 | glGetShaderInfoLog(shader, GLsizei(infoLog.len), nil, infoLog) 63 | result = (success: false, error: $infoLog) 64 | else: 65 | result = (success: true, error: "") 66 | 67 | 68 | proc getProgramLinkingResult(program: GLuint): tuple[success: bool, 69 | error: string] = 70 | var 71 | success: GLint 72 | infoLog = newString(1024) 73 | 74 | glGetProgramiv(program, GL_LINK_STATUS, success.addr) 75 | 76 | if success == 0: 77 | glGetShaderInfoLog(program, GLsizei(infoLog.len), nil, infoLog) 78 | result = (success: false, error: $infoLog) 79 | else: 80 | result = (success: true, error: "") 81 | 82 | 83 | proc createShaderProgram(vertexShaderSource, 84 | fragmentShaderSource: string): GLuint = 85 | # Compile shaders 86 | let 87 | vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource) 88 | fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource) 89 | 90 | var res = getShaderCompilationResult(vertexShader) 91 | if not res.success: 92 | echo "ERROR: vertex shader compilation failed: " & res.error 93 | 94 | res = getShaderCompilationResult(fragmentShader) 95 | if not res.success: 96 | echo "ERROR: fragment shader compilation failed: " & res.error 97 | 98 | # Create shader program 99 | let shaderProgram = glCreateProgram() 100 | glAttachShader(shaderProgram, vertexShader) 101 | glAttachShader(shaderProgram, fragmentShader) 102 | glLinkProgram(shaderProgram) 103 | 104 | res = getProgramLinkingResult(shaderProgram) 105 | if not res.success: 106 | echo "ERROR: shader program linking failed: " & res.error 107 | 108 | # We don't need the compiled shaders anymore, just the program 109 | glDeleteShader(vertexShader) 110 | glDeleteShader(fragmentShader) 111 | 112 | result = shaderProgram 113 | 114 | 115 | proc setup() = 116 | shaderProgram = createShaderProgram(vertexShaderSource, 117 | fragmentShaderSource) 118 | 119 | # Create Vertex Array Object 120 | glGenVertexArrays(1, vao.addr) 121 | 122 | # Create Vertex Buffer Object 123 | glGenBuffers(1, vbo.addr) 124 | 125 | # Bind the Vertex Array Object first, then bind and set vertex buffer(s) 126 | # and attribute pointer(s) 127 | glBindVertexArray(vao) 128 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 129 | 130 | # Copy vertex data from CPU memory into GPU memory 131 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 132 | vertices.addr, GL_STATIC_DRAW) 133 | 134 | # Tell OpenGL how it should interpret the vertex data 135 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 136 | normalized = false, 137 | stride = 3 * sizeof(GLfloat), 138 | pointer = cast[pointer](0)) 139 | 140 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 141 | # by default) 142 | glEnableVertexAttribArray(index = 0) 143 | 144 | # Note that this is allowed; the call to glVertexAttribPointer registered 145 | # VBO as the currently bound vertex buffer object so afterwards we can 146 | # safely unbind 147 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 148 | 149 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 150 | # strange bugs) 151 | glBindVertexArray(GL_NONE) 152 | 153 | 154 | proc cleanup() = 155 | glDeleteVertexArrays(1, vao.addr) 156 | glDeleteBuffers(1, vbo.addr) 157 | 158 | 159 | proc draw() = 160 | # Clear the color buffer 161 | glClearColor(0.2, 0.3, 0.3, 1.0) 162 | glClear(GL_COLOR_BUFFER_BIT) 163 | 164 | # Draw triangle 165 | glUseProgram(shaderProgram) 166 | glBindVertexArray(vao) 167 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 168 | glBindVertexArray(GL_NONE) 169 | 170 | 171 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 172 | modKeys: set[ModifierKey]) = 173 | 174 | if action != kaUp: 175 | if key == keyEscape: 176 | win.shouldClose = true 177 | 178 | 179 | proc main() = 180 | # Initialise GLFW 181 | glfw.initialize() 182 | 183 | # Create window 184 | var cfg = DefaultOpenglWindowConfig 185 | cfg.size = (w: 800, h: 600) 186 | cfg.title = "02-HelloTriangle/HelloTriangle" 187 | cfg.resizable = false 188 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 189 | cfg.version = glv33 190 | cfg.profile = opCoreProfile 191 | cfg.forwardCompat = true 192 | 193 | var win = newWindow(cfg) 194 | 195 | # Initialise OpenGL 196 | glfw.makeContextCurrent(win) 197 | 198 | if not gladLoadGL(getProcAddress): 199 | quit "Error initialising OpenGL" 200 | 201 | # Define viewport dimensions 202 | var width, height: int 203 | (width, height) = framebufferSize(win) 204 | glViewport(0, 0, GLint(width), GLint(height)) 205 | 206 | # Turn on vsync (0 turns it off) 207 | glfw.swapInterval(1) 208 | 209 | # Setup callbacks 210 | win.keyCb = keyCb 211 | 212 | # Setup shaders and various OpenGL objects 213 | setup() 214 | 215 | # Game loop 216 | while not win.shouldClose: 217 | glfw.pollEvents() 218 | draw() 219 | glfw.swapBuffers(win) 220 | 221 | # Properly de-allocate all resources once they've outlived their purpose 222 | cleanup() 223 | 224 | # Destroy window 225 | win.destroy() 226 | 227 | # Terminate GLFW, clearing any allocated resources 228 | glfw.terminate() 229 | 230 | 231 | main() 232 | 233 | -------------------------------------------------------------------------------- /01-GettingStarted/02-HelloTriangle/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c HelloRectangle.nim && \ 2 | nim c HelloTriangle.nim && \ 3 | nim c Exercises/Exercise1.nim && \ 4 | nim c Exercises/Exercise2.nim && \ 5 | nim c Exercises/Exercise3.nim 6 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/Exercise1.nim: -------------------------------------------------------------------------------- 1 | # Adjust the vertex shader so that the triangle is upside down. 2 | # 3 | # Read the accompanying article at 4 | # https://learnopengl.com/#!Getting-started/Shaders 5 | 6 | import math 7 | 8 | import glm 9 | import glad/gl 10 | import glfw 11 | 12 | import common/shader 13 | 14 | 15 | var vertices = [ 16 | # Positions # Colors 17 | GLfloat(-0.5),-0.5, 0.0, 1.0, 0.0, 0.0, # Bottom Right 18 | 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, # Bottom Left 19 | 0.0, 0.5, 0.0, 0.0, 0.0, 1.0 # Top 20 | ] 21 | 22 | var 23 | vao, vbo, shaderProgram: GLuint 24 | 25 | 26 | proc setup() = 27 | shaderProgram = createShaderProgramFromFile("exercise1.vs", "exercise1.fs") 28 | 29 | # Create Vertex Array Object 30 | glGenVertexArrays(1, vao.addr) 31 | 32 | # Create Vertex Buffer Object 33 | glGenBuffers(1, vbo.addr) 34 | 35 | # Bind the Vertex Array Object first, then bind and set vertex & element 36 | # buffer(s) and attribute pointer(s) 37 | glBindVertexArray(vao) 38 | 39 | # Copy vertex data from CPU memory into GPU memory 40 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 41 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 42 | vertices.addr, GL_STATIC_DRAW) 43 | 44 | # Position attribute 45 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 46 | normalized = false, 47 | stride = 6 * sizeof(GLfloat), 48 | pointer = cast[pointer](0)) 49 | 50 | glEnableVertexAttribArray(index = 0) 51 | 52 | # Color attribute 53 | glVertexAttribPointer(index = 1, size = 3, type = cGL_FLOAT, 54 | normalized = false, 55 | stride = 6 * sizeof(GLfloat), 56 | pointer = cast[pointer](3 * sizeof(GLfloat))) 57 | 58 | glEnableVertexAttribArray(index = 1) 59 | 60 | # Note that this is allowed; the call to glVertexAttribPointer registered 61 | # VBO as the currently bound vertex buffer object so afterwards we can 62 | # safely unbind 63 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 64 | 65 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 66 | # strange bugs) 67 | glBindVertexArray(GL_NONE) 68 | 69 | 70 | proc cleanup() = 71 | glDeleteVertexArrays(1, vao.addr) 72 | glDeleteBuffers(1, vbo.addr) 73 | 74 | 75 | proc draw() = 76 | # Clear the color buffer 77 | glClearColor(0.2, 0.3, 0.3, 1.0) 78 | glClear(GL_COLOR_BUFFER_BIT) 79 | 80 | # Draw the triangle 81 | shaderProgram.use() 82 | glBindVertexArray(vao) 83 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 84 | glBindVertexArray(GL_NONE) 85 | 86 | 87 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 88 | modKeys: set[ModifierKey]) = 89 | 90 | if action != kaUp: 91 | if key == keyEscape: 92 | win.shouldClose = true 93 | 94 | 95 | proc main() = 96 | # Initialise GLFW 97 | glfw.initialize() 98 | 99 | # Create window 100 | var cfg = DefaultOpenglWindowConfig 101 | cfg.size = (w: 800, h: 600) 102 | cfg.title = "03-Shaders/Exercise1" 103 | cfg.resizable = false 104 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 105 | cfg.version = glv33 106 | cfg.profile = opCoreProfile 107 | cfg.forwardCompat = true 108 | 109 | var win = newWindow(cfg) 110 | 111 | # Initialise OpenGL 112 | glfw.makeContextCurrent(win) 113 | 114 | if not gladLoadGL(getProcAddress): 115 | quit "Error initialising OpenGL" 116 | 117 | # Define viewport dimensions 118 | var width, height: int 119 | (width, height) = framebufferSize(win) 120 | glViewport(0, 0, GLint(width), GLint(height)) 121 | 122 | # Turn on vsync (0 turns it off) 123 | glfw.swapInterval(1) 124 | 125 | # Setup callbacks 126 | win.keyCb = keyCb 127 | 128 | # Setup shaders and various OpenGL objects 129 | setup() 130 | 131 | # Game loop 132 | while not win.shouldClose: 133 | glfw.pollEvents() 134 | draw() 135 | glfw.swapBuffers(win) 136 | 137 | # Properly de-allocate all resources once they've outlived their purpose 138 | cleanup() 139 | 140 | # Destroy window 141 | win.destroy() 142 | 143 | # Terminate GLFW, clearing any allocated resources 144 | glfw.terminate() 145 | 146 | 147 | main() 148 | 149 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/Exercise2.nim: -------------------------------------------------------------------------------- 1 | # Specify a horizontal offset via a uniform and move the triangle to the right 2 | # side of the screen in the vertex shader using this offset value. 3 | # 4 | # Read the accompanying article at 5 | # https://learnopengl.com/#!Getting-started/Shaders 6 | 7 | import math 8 | 9 | import glm 10 | import glad/gl 11 | import glfw 12 | 13 | import common/shader 14 | 15 | 16 | var vertices = [ 17 | # Positions # Colors 18 | GLfloat(-0.5),-0.5, 0.0, 1.0, 0.0, 0.0, # Bottom Right 19 | 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, # Bottom Left 20 | 0.0, 0.5, 0.0, 0.0, 0.0, 1.0 # Top 21 | ] 22 | 23 | var 24 | vao, vbo, shaderProgram: GLuint 25 | 26 | 27 | proc setup() = 28 | shaderProgram = createShaderProgramFromFile("exercise2.vs", "exercise2.fs") 29 | 30 | # Create Vertex Array Object 31 | glGenVertexArrays(1, vao.addr) 32 | 33 | # Create Vertex Buffer Object 34 | glGenBuffers(1, vbo.addr) 35 | 36 | # Bind the Vertex Array Object first, then bind and set vertex & element 37 | # buffer(s) and attribute pointer(s) 38 | glBindVertexArray(vao) 39 | 40 | # Copy vertex data from CPU memory into GPU memory 41 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 42 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 43 | vertices.addr, GL_STATIC_DRAW) 44 | 45 | # Position attribute 46 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 47 | normalized = false, 48 | stride = 6 * sizeof(GLfloat), 49 | pointer = cast[pointer](0)) 50 | 51 | glEnableVertexAttribArray(index = 0) 52 | 53 | # Color attribute 54 | glVertexAttribPointer(index = 1, size = 3, type = cGL_FLOAT, 55 | normalized = false, 56 | stride = 6 * sizeof(GLfloat), 57 | pointer = cast[pointer](3 * sizeof(GLfloat))) 58 | 59 | glEnableVertexAttribArray(index = 1) 60 | 61 | # Note that this is allowed; the call to glVertexAttribPointer registered 62 | # VBO as the currently bound vertex buffer object so afterwards we can 63 | # safely unbind 64 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 65 | 66 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 67 | # strange bugs) 68 | glBindVertexArray(GL_NONE) 69 | 70 | 71 | proc cleanup() = 72 | glDeleteVertexArrays(1, vao.addr) 73 | glDeleteBuffers(1, vbo.addr) 74 | 75 | 76 | proc draw() = 77 | # Clear the color buffer 78 | glClearColor(0.2, 0.3, 0.3, 1.0) 79 | glClear(GL_COLOR_BUFFER_BIT) 80 | 81 | # Draw the triangle 82 | shaderProgram.use() 83 | 84 | var horizOffsetLocation = glGetUniformLocation(shaderProgram, "horizOffset") 85 | glUniform1f(horizOffsetLocation, 0.5) 86 | 87 | glBindVertexArray(vao) 88 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 89 | glBindVertexArray(GL_NONE) 90 | 91 | 92 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 93 | modKeys: set[ModifierKey]) = 94 | 95 | if action != kaUp: 96 | if key == keyEscape: 97 | win.shouldClose = true 98 | 99 | 100 | proc main() = 101 | # Initialise GLFW 102 | glfw.initialize() 103 | 104 | # Create window 105 | var cfg = DefaultOpenglWindowConfig 106 | cfg.size = (w: 800, h: 600) 107 | cfg.title = "03-Shaders/Exercise2" 108 | cfg.resizable = false 109 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 110 | cfg.version = glv33 111 | cfg.profile = opCoreProfile 112 | cfg.forwardCompat = true 113 | 114 | var win = newWindow(cfg) 115 | 116 | # Initialise OpenGL 117 | glfw.makeContextCurrent(win) 118 | 119 | if not gladLoadGL(getProcAddress): 120 | quit "Error initialising OpenGL" 121 | 122 | # Define viewport dimensions 123 | var width, height: int 124 | (width, height) = framebufferSize(win) 125 | glViewport(0, 0, GLint(width), GLint(height)) 126 | 127 | # Turn on vsync (0 turns it off) 128 | glfw.swapInterval(1) 129 | 130 | # Setup callbacks 131 | win.keyCb = keyCb 132 | 133 | # Setup shaders and various OpenGL objects 134 | setup() 135 | 136 | # Game loop 137 | while not win.shouldClose: 138 | glfw.pollEvents() 139 | draw() 140 | glfw.swapBuffers(win) 141 | 142 | # Properly de-allocate all resources once they've outlived their purpose 143 | cleanup() 144 | 145 | # Destroy window 146 | win.destroy() 147 | 148 | # Terminate GLFW, clearing any allocated resources 149 | glfw.terminate() 150 | 151 | 152 | main() 153 | 154 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/Exercise3.nim: -------------------------------------------------------------------------------- 1 | # Output the vertex position to the fragment shader using the out keyword and 2 | # set the fragment's color equal to this vertex position (see how even the 3 | # vertex position values are interpolated across the triangle). Once you 4 | # managed to do this; try to answer the following question: why is the 5 | # bottom-left side of our triangle black? 6 | # 7 | # Read the accompanying article at 8 | # https://learnopengl.com/#!Getting-started/Shaders 9 | 10 | import math 11 | 12 | import glm 13 | import glad/gl 14 | import glfw 15 | 16 | import common/shader 17 | 18 | 19 | var vertices = [ 20 | GLfloat(-0.5),-0.5, 0.0, 21 | 0.5, -0.5, 0.0, 22 | 0.0, 0.5, 0.0 23 | ] 24 | 25 | var 26 | vao, vbo, shaderProgram: GLuint 27 | 28 | 29 | proc setup() = 30 | shaderProgram = createShaderProgramFromFile("exercise3.vs", "exercise3.fs") 31 | 32 | # Create Vertex Array Object 33 | glGenVertexArrays(1, vao.addr) 34 | 35 | # Create Vertex Buffer Object 36 | glGenBuffers(1, vbo.addr) 37 | 38 | # Bind the Vertex Array Object first, then bind and set vertex & element 39 | # buffer(s) and attribute pointer(s) 40 | glBindVertexArray(vao) 41 | 42 | # Copy vertex data from CPU memory into GPU memory 43 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 44 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 45 | vertices.addr, GL_STATIC_DRAW) 46 | 47 | # Tell OpenGL how it should interpret the vertex data 48 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 49 | normalized = false, 50 | stride = 3 * sizeof(GLfloat), 51 | pointer = cast[pointer](0)) 52 | 53 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 54 | # by default) 55 | glEnableVertexAttribArray(index = 0) 56 | 57 | # Note that this is allowed; the call to glVertexAttribPointer registered 58 | # VBO as the currently bound vertex buffer object so afterwards we can 59 | # safely unbind 60 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 61 | 62 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 63 | # strange bugs) 64 | glBindVertexArray(GL_NONE) 65 | 66 | 67 | proc cleanup() = 68 | glDeleteVertexArrays(1, vao.addr) 69 | glDeleteBuffers(1, vbo.addr) 70 | 71 | 72 | proc draw() = 73 | # Clear the color buffer 74 | glClearColor(0.2, 0.3, 0.3, 1.0) 75 | glClear(GL_COLOR_BUFFER_BIT) 76 | 77 | # Draw triangle 78 | shaderProgram.use() 79 | glBindVertexArray(vao) 80 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 81 | glBindVertexArray(GL_NONE) 82 | 83 | 84 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 85 | modKeys: set[ModifierKey]) = 86 | 87 | if action != kaUp: 88 | if key == keyEscape: 89 | win.shouldClose = true 90 | 91 | 92 | proc main() = 93 | # Initialise GLFW 94 | glfw.initialize() 95 | 96 | # Create window 97 | var cfg = DefaultOpenglWindowConfig 98 | cfg.size = (w: 800, h: 600) 99 | cfg.title = "03-Shaders/Exercise3" 100 | cfg.resizable = false 101 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 102 | cfg.version = glv33 103 | cfg.profile = opCoreProfile 104 | cfg.forwardCompat = true 105 | 106 | var win = newWindow(cfg) 107 | 108 | # Initialise OpenGL 109 | glfw.makeContextCurrent(win) 110 | 111 | if not gladLoadGL(getProcAddress): 112 | quit "Error initialising OpenGL" 113 | 114 | # Define viewport dimensions 115 | var width, height: int 116 | (width, height) = framebufferSize(win) 117 | glViewport(0, 0, GLint(width), GLint(height)) 118 | 119 | # Turn on vsync (0 turns it off) 120 | glfw.swapInterval(1) 121 | 122 | # Setup callbacks 123 | win.keyCb = keyCb 124 | 125 | # Setup shaders and various OpenGL objects 126 | setup() 127 | 128 | # Game loop 129 | while not win.shouldClose: 130 | glfw.pollEvents() 131 | draw() 132 | glfw.swapBuffers(win) 133 | 134 | # Properly de-allocate all resources once they've outlived their purpose 135 | cleanup() 136 | 137 | # Destroy window 138 | win.destroy() 139 | 140 | # Terminate GLFW, clearing any allocated resources 141 | glfw.terminate() 142 | 143 | 144 | main() 145 | 146 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/exercise1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 ourColor; 4 | out vec4 color; 5 | 6 | void main() 7 | { 8 | color = vec4(ourColor, 1.0f); 9 | } 10 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/exercise1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | // The position variable has attribute position 0 4 | layout (location = 0) in vec3 position; 5 | 6 | // The color variable has attribute position 1 7 | layout (location = 1) in vec3 color; 8 | 9 | // Output a color to the fragment shader 10 | out vec3 ourColor; 11 | 12 | void main() 13 | { 14 | gl_Position = vec4(position.x, -position.y, position.z, 1.0f); 15 | 16 | // Set ourColor to the input color we got from the vertex data 17 | ourColor = color; 18 | } 19 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/exercise2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 ourColor; 4 | out vec4 color; 5 | 6 | void main() 7 | { 8 | color = vec4(ourColor, 1.0f); 9 | } 10 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/exercise2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | // The position variable has attribute position 0 4 | layout (location = 0) in vec3 position; 5 | 6 | // The color variable has attribute position 1 7 | layout (location = 1) in vec3 color; 8 | 9 | // Output a color to the fragment shader 10 | out vec3 ourColor; 11 | 12 | uniform float horizOffset; 13 | 14 | void main() 15 | { 16 | gl_Position = vec4(position.x + horizOffset, position.yz, 1.0f); 17 | 18 | // Set ourColor to the input color we got from the vertex data 19 | ourColor = color; 20 | } 21 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/exercise3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec4 vertexPos; 4 | 5 | out vec4 color; 6 | 7 | void main() 8 | { 9 | color = vertexPos; 10 | } 11 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Exercises/exercise3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | // The position variable has attribute position 0 4 | layout (location = 0) in vec3 position; 5 | 6 | out vec4 vertexPos; 7 | 8 | void main() 9 | { 10 | // See how we directly give a vec3 to vec4's constructor 11 | gl_Position = vec4(position, 1.0f); 12 | 13 | vertexPos = gl_Position; 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Shader1.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Shaders 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | 10 | import common/shader 11 | 12 | 13 | var vertices = [ 14 | GLfloat(-0.5),-0.5, 0.0, 15 | 0.5, -0.5, 0.0, 16 | 0.0, 0.5, 0.0 17 | ] 18 | 19 | var 20 | vao, vbo, shaderProgram: GLuint 21 | 22 | 23 | proc setup() = 24 | shaderProgram = createShaderProgramFromFile("shader1.vs", "shader1.fs") 25 | 26 | # Create Vertex Array Object 27 | glGenVertexArrays(1, vao.addr) 28 | 29 | # Create Vertex Buffer Object 30 | glGenBuffers(1, vbo.addr) 31 | 32 | # Bind the Vertex Array Object first, then bind and set vertex & element 33 | # buffer(s) and attribute pointer(s) 34 | glBindVertexArray(vao) 35 | 36 | # Copy vertex data from CPU memory into GPU memory 37 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 38 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 39 | vertices.addr, GL_STATIC_DRAW) 40 | 41 | # Tell OpenGL how it should interpret the vertex data 42 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 43 | normalized = false, 44 | stride = 3 * sizeof(GLfloat), 45 | pointer = cast[pointer](0)) 46 | 47 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 48 | # by default) 49 | glEnableVertexAttribArray(index = 0) 50 | 51 | # Note that this is allowed; the call to glVertexAttribPointer registered 52 | # VBO as the currently bound vertex buffer object so afterwards we can 53 | # safely unbind 54 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 55 | 56 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 57 | # strange bugs) 58 | glBindVertexArray(GL_NONE) 59 | 60 | 61 | proc cleanup() = 62 | glDeleteVertexArrays(1, vao.addr) 63 | glDeleteBuffers(1, vbo.addr) 64 | 65 | 66 | proc draw() = 67 | # Clear the color buffer 68 | glClearColor(0.2, 0.3, 0.3, 1.0) 69 | glClear(GL_COLOR_BUFFER_BIT) 70 | 71 | # Draw triangle 72 | shaderProgram.use() 73 | glBindVertexArray(vao) 74 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 75 | glBindVertexArray(GL_NONE) 76 | 77 | 78 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 79 | modKeys: set[ModifierKey]) = 80 | 81 | if action != kaUp: 82 | if key == keyEscape: 83 | win.shouldClose = true 84 | 85 | 86 | proc main() = 87 | # Initialise GLFW 88 | glfw.initialize() 89 | 90 | # Create window 91 | var cfg = DefaultOpenglWindowConfig 92 | cfg.size = (w: 800, h: 600) 93 | cfg.title = "03-Shaders/Shader1" 94 | cfg.resizable = false 95 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 96 | cfg.version = glv33 97 | cfg.profile = opCoreProfile 98 | cfg.forwardCompat = true 99 | 100 | var win = newWindow(cfg) 101 | 102 | # Initialise OpenGL 103 | glfw.makeContextCurrent(win) 104 | 105 | if not gladLoadGL(getProcAddress): 106 | quit "Error initialising OpenGL" 107 | 108 | # Define viewport dimensions 109 | var width, height: int 110 | (width, height) = framebufferSize(win) 111 | glViewport(0, 0, GLint(width), GLint(height)) 112 | 113 | # Turn on vsync (0 turns it off) 114 | glfw.swapInterval(1) 115 | 116 | # Setup callbacks 117 | win.keyCb = keyCb 118 | 119 | # Setup shaders and various OpenGL objects 120 | setup() 121 | 122 | # Game loop 123 | while not win.shouldClose: 124 | glfw.pollEvents() 125 | draw() 126 | glfw.swapBuffers(win) 127 | 128 | # Properly de-allocate all resources once they've outlived their purpose 129 | cleanup() 130 | 131 | # Destroy window 132 | win.destroy() 133 | 134 | # Terminate GLFW, clearing any allocated resources 135 | glfw.terminate() 136 | 137 | 138 | main() 139 | 140 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Shader2.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Shaders 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | 10 | import common/shader 11 | 12 | 13 | var vertices = [ 14 | GLfloat(-0.5),-0.5, 0.0, 15 | 0.5, -0.5, 0.0, 16 | 0.0, 0.5, 0.0 17 | ] 18 | 19 | var 20 | vao, vbo, shaderProgram: GLuint 21 | 22 | 23 | proc setup() = 24 | shaderProgram = createShaderProgramFromFile("shader2.vs", "shader2.fs") 25 | 26 | # Create Vertex Array Object 27 | glGenVertexArrays(1, vao.addr) 28 | 29 | # Create Vertex Buffer Object 30 | glGenBuffers(1, vbo.addr) 31 | 32 | # Bind the Vertex Array Object first, then bind and set vertex & element 33 | # buffer(s) and attribute pointer(s) 34 | glBindVertexArray(vao) 35 | 36 | # Copy vertex data from CPU memory into GPU memory 37 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 38 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 39 | vertices.addr, GL_STATIC_DRAW) 40 | 41 | # Tell OpenGL how it should interpret the vertex data 42 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 43 | normalized = false, 44 | stride = 3 * sizeof(GLfloat), 45 | pointer = cast[pointer](0)) 46 | 47 | # Enable vertex attribute at location 0 (all vertex attributes are disabled 48 | # by default) 49 | glEnableVertexAttribArray(index = 0) 50 | 51 | # Note that this is allowed; the call to glVertexAttribPointer registered 52 | # VBO as the currently bound vertex buffer object so afterwards we can 53 | # safely unbind 54 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 55 | 56 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 57 | # strange bugs) 58 | glBindVertexArray(GL_NONE) 59 | 60 | 61 | proc cleanup() = 62 | glDeleteVertexArrays(1, vao.addr) 63 | glDeleteBuffers(1, vbo.addr) 64 | 65 | 66 | proc draw() = 67 | # Clear the color buffer 68 | glClearColor(0.2, 0.3, 0.3, 1.0) 69 | glClear(GL_COLOR_BUFFER_BIT) 70 | 71 | # Activate the shader 72 | shaderProgram.use() 73 | 74 | # Update the uniform color 75 | var 76 | t = getTime() 77 | greenValue = sin(t) / 2 + 0.5 78 | vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor") 79 | 80 | glUniform4f(vertexColorLocation, 0.0, greenValue, 0.0, 1.0) 81 | 82 | # Draw the triangle 83 | glBindVertexArray(vao) 84 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 85 | glBindVertexArray(GL_NONE) 86 | 87 | 88 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 89 | modKeys: set[ModifierKey]) = 90 | 91 | if action != kaUp: 92 | if key == keyEscape: 93 | win.shouldClose = true 94 | 95 | 96 | proc main() = 97 | # Initialise GLFW 98 | glfw.initialize() 99 | 100 | # Create window 101 | var cfg = DefaultOpenglWindowConfig 102 | cfg.size = (w: 800, h: 600) 103 | cfg.title = "03-Shaders/Shader2" 104 | cfg.resizable = false 105 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 106 | cfg.version = glv33 107 | cfg.profile = opCoreProfile 108 | cfg.forwardCompat = true 109 | 110 | var win = newWindow(cfg) 111 | 112 | # Initialise OpenGL 113 | glfw.makeContextCurrent(win) 114 | 115 | if not gladLoadGL(getProcAddress): 116 | quit "Error initialising OpenGL" 117 | 118 | # Define viewport dimensions 119 | var width, height: int 120 | (width, height) = framebufferSize(win) 121 | glViewport(0, 0, GLint(width), GLint(height)) 122 | 123 | # Turn on vsync (0 turns it off) 124 | glfw.swapInterval(1) 125 | 126 | # Setup callbacks 127 | win.keyCb = keyCb 128 | 129 | # Setup shaders and various OpenGL objects 130 | setup() 131 | 132 | # Game loop 133 | while not win.shouldClose: 134 | glfw.pollEvents() 135 | draw() 136 | glfw.swapBuffers(win) 137 | 138 | # Properly de-allocate all resources once they've outlived their purpose 139 | cleanup() 140 | 141 | # Destroy window 142 | win.destroy() 143 | 144 | # Terminate GLFW, clearing any allocated resources 145 | glfw.terminate() 146 | 147 | 148 | main() 149 | 150 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/Shader3.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Shaders 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | 10 | import common/shader 11 | 12 | 13 | var vertices = [ 14 | # Positions # Colors 15 | GLfloat(-0.5),-0.5, 0.0, 1.0, 0.0, 0.0, # Bottom Right 16 | 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, # Bottom Left 17 | 0.0, 0.5, 0.0, 0.0, 0.0, 1.0 # Top 18 | ] 19 | 20 | var 21 | vao, vbo, shaderProgram: GLuint 22 | 23 | 24 | proc setup() = 25 | shaderProgram = createShaderProgramFromFile("shader3.vs", "shader3.fs") 26 | 27 | # Create Vertex Array Object 28 | glGenVertexArrays(1, vao.addr) 29 | 30 | # Create Vertex Buffer Object 31 | glGenBuffers(1, vbo.addr) 32 | 33 | # Bind the Vertex Array Object first, then bind and set vertex & element 34 | # buffer(s) and attribute pointer(s) 35 | glBindVertexArray(vao) 36 | 37 | # Copy vertex data from CPU memory into GPU memory 38 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 39 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 40 | vertices.addr, GL_STATIC_DRAW) 41 | 42 | # Position attribute 43 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 44 | normalized = false, 45 | stride = 6 * sizeof(GLfloat), 46 | pointer = cast[pointer](0)) 47 | 48 | glEnableVertexAttribArray(index = 0) 49 | 50 | # Color attribute 51 | glVertexAttribPointer(index = 1, size = 3, type = cGL_FLOAT, 52 | normalized = false, 53 | stride = 6 * sizeof(GLfloat), 54 | pointer = cast[pointer](3 * sizeof(GLfloat))) 55 | 56 | glEnableVertexAttribArray(index = 1) 57 | 58 | # Note that this is allowed; the call to glVertexAttribPointer registered 59 | # VBO as the currently bound vertex buffer object so afterwards we can 60 | # safely unbind 61 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 62 | 63 | # Unbind VAO (it's always a good thing to unbind any buffer/array to prevent 64 | # strange bugs) 65 | glBindVertexArray(GL_NONE) 66 | 67 | 68 | proc cleanup() = 69 | glDeleteVertexArrays(1, vao.addr) 70 | glDeleteBuffers(1, vbo.addr) 71 | 72 | 73 | proc draw() = 74 | # Clear the color buffer 75 | glClearColor(0.2, 0.3, 0.3, 1.0) 76 | glClear(GL_COLOR_BUFFER_BIT) 77 | 78 | # Draw the triangle 79 | shaderProgram.use() 80 | glBindVertexArray(vao) 81 | glDrawArrays(GL_TRIANGLES, first = 0, count = 3) 82 | glBindVertexArray(GL_NONE) 83 | 84 | 85 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 86 | modKeys: set[ModifierKey]) = 87 | 88 | if action != kaUp: 89 | if key == keyEscape: 90 | win.shouldClose = true 91 | 92 | 93 | proc main() = 94 | # Initialise GLFW 95 | glfw.initialize() 96 | 97 | # Create window 98 | var cfg = DefaultOpenglWindowConfig 99 | cfg.size = (w: 800, h: 600) 100 | cfg.title = "03-Shaders/Shader3" 101 | cfg.resizable = false 102 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 103 | cfg.version = glv33 104 | cfg.profile = opCoreProfile 105 | cfg.forwardCompat = true 106 | 107 | var win = newWindow(cfg) 108 | 109 | # Initialise OpenGL 110 | glfw.makeContextCurrent(win) 111 | 112 | if not gladLoadGL(getProcAddress): 113 | quit "Error initialising OpenGL" 114 | 115 | # Define viewport dimensions 116 | var width, height: int 117 | (width, height) = framebufferSize(win) 118 | glViewport(0, 0, GLint(width), GLint(height)) 119 | 120 | # Turn on vsync (0 turns it off) 121 | glfw.swapInterval(1) 122 | 123 | # Setup callbacks 124 | win.keyCb = keyCb 125 | 126 | # Setup shaders and various OpenGL objects 127 | setup() 128 | 129 | # Game loop 130 | while not win.shouldClose: 131 | glfw.pollEvents() 132 | draw() 133 | glfw.swapBuffers(win) 134 | 135 | # Properly de-allocate all resources once they've outlived their purpose 136 | cleanup() 137 | 138 | # Destroy window 139 | win.destroy() 140 | 141 | # Terminate GLFW, clearing any allocated resources 142 | glfw.terminate() 143 | 144 | 145 | main() 146 | 147 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c Shader1.nim && \ 2 | nim c Shader2.nim && \ 3 | nim c Shader3.nim && \ 4 | nim c Exercises/Exercise1.nim && \ 5 | nim c Exercises/Exercise2.nim && \ 6 | nim c Exercises/Exercise3.nim 7 | 8 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/shader1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | // The input variable from the vertex shader (same name and same type) 4 | in vec4 vertexColor; 5 | 6 | out vec4 color; 7 | 8 | void main() 9 | { 10 | color = vertexColor; 11 | } 12 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/shader1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | // The position variable has attribute position 0 4 | layout (location = 0) in vec3 position; 5 | 6 | // Specify a color output to the fragment shader 7 | out vec4 vertexColor; 8 | 9 | void main() 10 | { 11 | // See how we directly give a vec3 to vec4's constructor 12 | gl_Position = vec4(position, 1.0f); 13 | 14 | // Set the output variable to a dark-red color 15 | vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/shader2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | out vec4 color; 4 | 5 | uniform vec4 ourColor; 6 | 7 | void main() 8 | { 9 | color = ourColor; 10 | } 11 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/shader2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | 5 | void main() 6 | { 7 | gl_Position = vec4(position, 1.0f); 8 | } 9 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/shader3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 ourColor; 4 | out vec4 color; 5 | 6 | void main() 7 | { 8 | color = vec4(ourColor, 1.0f); 9 | } 10 | -------------------------------------------------------------------------------- /01-GettingStarted/03-Shaders/shader3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | // The position variable has attribute position 0 4 | layout (location = 0) in vec3 position; 5 | 6 | // The color variable has attribute position 1 7 | layout (location = 1) in vec3 color; 8 | 9 | // Output a color to the fragment shader 10 | out vec3 ourColor; 11 | 12 | void main() 13 | { 14 | gl_Position = vec4(position, 1.0f); 15 | 16 | // Set ourColor to the input color we got from the vertex data 17 | ourColor = color; 18 | } 19 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Container1.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Textures 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Colors # Texture Coords 16 | GLfloat(0.5), 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, # Top Right 17 | 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, # Bottom Right 18 | -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, # Bottom Left 19 | -0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0 # Top Left 20 | ] 21 | 22 | var indices = [ 23 | GLuint(0), 1, 3, # First Triangle 24 | 1, 2, 3 # Second Triangle 25 | ] 26 | 27 | var 28 | vao, vbo, ebo, texture, shaderProgram: GLuint 29 | 30 | 31 | proc setup() = 32 | shaderProgram = createShaderProgramFromFile("container1.vs", 33 | "container1.fs") 34 | 35 | glGenVertexArrays(1, vao.addr) 36 | glGenBuffers(1, vbo.addr) 37 | glGenBuffers(1, ebo.addr) 38 | 39 | glBindVertexArray(vao) 40 | 41 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 42 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 43 | vertices.addr, GL_STATIC_DRAW) 44 | 45 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 46 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 47 | indices.addr, GL_STATIC_DRAW); 48 | 49 | # Position attribute 50 | var stride = GLsizei(8 * sizeof(GLfloat)) 51 | 52 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 53 | normalized = false, stride, 54 | pointer = cast[pointer](0)) 55 | 56 | glEnableVertexAttribArray(0) 57 | 58 | # Color attribute 59 | glVertexAttribPointer(index = 1, size = 3, type = cGL_FLOAT, 60 | normalized = false, stride, 61 | pointer = cast[pointer](3 * sizeof(GLfloat))) 62 | 63 | glEnableVertexAttribArray(1) 64 | 65 | # TexCoord attribute 66 | glVertexAttribPointer(index = 2, size = 2, type = cGL_FLOAT, 67 | normalized = false, stride, 68 | pointer = cast[pointer](6 * sizeof(GLfloat))) 69 | 70 | glEnableVertexAttribArray(2) 71 | 72 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 73 | glBindVertexArray(GL_NONE) 74 | 75 | # Load and create a texture 76 | 77 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 78 | # object 79 | glGenTextures(1, texture.addr) 80 | glBindTexture(GL_TEXTURE_2D, texture) 81 | 82 | # Set the texture wrapping parameters 83 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 86 | 87 | # Set texture filtering parameters 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 89 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 90 | 91 | # Load image 92 | var 93 | width, height, channels: int 94 | data: seq[uint8] 95 | 96 | data = stbi.load("Data/container.jpg", width, height, channels, 97 | stbi.Default) 98 | 99 | # Create texture 100 | glTexImage2D(GL_TEXTURE_2D, level = 0, 101 | internalFormat = GLint(GL_RGB), 102 | GLsizei(width), GLsizei(height), border = 0, 103 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 104 | cast[pointer](data[0].addr)) 105 | 106 | glGenerateMipmap(GL_TEXTURE_2D) 107 | glBindTexture(GL_TEXTURE_2D, 0) 108 | 109 | 110 | proc cleanup() = 111 | glDeleteVertexArrays(1, vao.addr) 112 | glDeleteBuffers(1, vbo.addr) 113 | glDeleteBuffers(1, ebo.addr) 114 | 115 | 116 | proc draw() = 117 | # Clear the color buffer 118 | glClearColor(0.2, 0.3, 0.3, 1.0) 119 | glClear(GL_COLOR_BUFFER_BIT) 120 | 121 | glBindTexture(GL_TEXTURE_2D, texture) 122 | 123 | shaderProgram.use() 124 | 125 | glBindVertexArray(vao) 126 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 127 | indices = GLvoid(nil)) 128 | glBindVertexArray(GL_NONE) 129 | 130 | 131 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 132 | modKeys: set[ModifierKey]) = 133 | 134 | if action != kaUp: 135 | if key == keyEscape: 136 | win.shouldClose = true 137 | 138 | 139 | proc main() = 140 | # Initialise GLFW 141 | glfw.initialize() 142 | 143 | # Create window 144 | var cfg = DefaultOpenglWindowConfig 145 | cfg.size = (w: 800, h: 600) 146 | cfg.title = "04-Textures/Container1" 147 | cfg.resizable = false 148 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 149 | cfg.version = glv33 150 | cfg.profile = opCoreProfile 151 | cfg.forwardCompat = true 152 | 153 | var win = newWindow(cfg) 154 | 155 | # Initialise OpenGL 156 | glfw.makeContextCurrent(win) 157 | 158 | if not gladLoadGL(getProcAddress): 159 | quit "Error initialising OpenGL" 160 | 161 | # Define viewport dimensions 162 | var width, height: int 163 | (width, height) = framebufferSize(win) 164 | glViewport(0, 0, GLint(width), GLint(height)) 165 | 166 | # Turn on vsync (0 turns it off) 167 | glfw.swapInterval(1) 168 | 169 | # Setup callbacks 170 | win.keyCb = keyCb 171 | 172 | # Setup shaders and various OpenGL objects 173 | setup() 174 | 175 | # Game loop 176 | while not win.shouldClose: 177 | glfw.pollEvents() 178 | draw() 179 | glfw.swapBuffers(win) 180 | 181 | # Properly de-allocate all resources once they've outlived their purpose 182 | cleanup() 183 | 184 | # Destroy window 185 | win.destroy() 186 | 187 | # Terminate GLFW, clearing any allocated resources 188 | glfw.terminate() 189 | 190 | 191 | main() 192 | 193 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Container2.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Textures 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Colors # Texture Coords 16 | GLfloat(0.5), 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, # Top Right 17 | 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, # Bottom Right 18 | -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, # Bottom Left 19 | -0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0 # Top Left 20 | ] 21 | 22 | var indices = [ 23 | GLuint(0), 1, 3, # First Triangle 24 | 1, 2, 3 # Second Triangle 25 | ] 26 | 27 | var 28 | vao, vbo, ebo, texture, shaderProgram: GLuint 29 | 30 | 31 | proc setup() = 32 | shaderProgram = createShaderProgramFromFile("container2.vs", 33 | "container2.fs") 34 | 35 | glGenVertexArrays(1, vao.addr) 36 | glGenBuffers(1, vbo.addr) 37 | glGenBuffers(1, ebo.addr) 38 | 39 | glBindVertexArray(vao) 40 | 41 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 42 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 43 | vertices.addr, GL_STATIC_DRAW) 44 | 45 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 46 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 47 | indices.addr, GL_STATIC_DRAW); 48 | 49 | # Position attribute 50 | var stride = GLsizei(8 * sizeof(GLfloat)) 51 | 52 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 53 | normalized = false, stride, 54 | pointer = cast[pointer](0)) 55 | 56 | glEnableVertexAttribArray(0) 57 | 58 | # Color attribute 59 | glVertexAttribPointer(index = 1, size = 3, type = cGL_FLOAT, 60 | normalized = false, stride, 61 | pointer = cast[pointer](3 * sizeof(GLfloat))) 62 | 63 | glEnableVertexAttribArray(1) 64 | 65 | # TexCoord attribute 66 | glVertexAttribPointer(index = 2, size = 2, type = cGL_FLOAT, 67 | normalized = false, stride, 68 | pointer = cast[pointer](6 * sizeof(GLfloat))) 69 | 70 | glEnableVertexAttribArray(2) 71 | 72 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 73 | glBindVertexArray(GL_NONE) 74 | 75 | # Load and create a texture 76 | 77 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 78 | # object 79 | glGenTextures(1, texture.addr) 80 | glBindTexture(GL_TEXTURE_2D, texture) 81 | 82 | # Set the texture wrapping parameters 83 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 86 | 87 | # Set texture filtering parameters 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 89 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 90 | 91 | # Load image 92 | var 93 | width, height, channels: int 94 | data: seq[uint8] 95 | 96 | data = stbi.load("Data/container.jpg", width, height, channels, 97 | stbi.Default) 98 | 99 | # Create texture 100 | glTexImage2D(GL_TEXTURE_2D, level = 0, 101 | internalFormat = GLint(GL_RGB), 102 | GLsizei(width), GLsizei(height), border = 0, 103 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 104 | cast[pointer](data[0].addr)) 105 | 106 | glGenerateMipmap(GL_TEXTURE_2D) 107 | glBindTexture(GL_TEXTURE_2D, 0) 108 | 109 | 110 | proc cleanup() = 111 | glDeleteVertexArrays(1, vao.addr) 112 | glDeleteBuffers(1, vbo.addr) 113 | glDeleteBuffers(1, ebo.addr) 114 | 115 | 116 | proc draw() = 117 | # Clear the color buffer 118 | glClearColor(0.2, 0.3, 0.3, 1.0) 119 | glClear(GL_COLOR_BUFFER_BIT) 120 | 121 | glBindTexture(GL_TEXTURE_2D, texture) 122 | 123 | shaderProgram.use() 124 | 125 | glBindVertexArray(vao) 126 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 127 | indices = GLvoid(nil)) 128 | glBindVertexArray(GL_NONE) 129 | 130 | 131 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 132 | modKeys: set[ModifierKey]) = 133 | 134 | if action != kaUp: 135 | if key == keyEscape: 136 | win.shouldClose = true 137 | 138 | 139 | proc main() = 140 | # Initialise GLFW 141 | glfw.initialize() 142 | 143 | # Create window 144 | var cfg = DefaultOpenglWindowConfig 145 | cfg.size = (w: 800, h: 600) 146 | cfg.title = "04-Textures/Container2" 147 | cfg.resizable = false 148 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 149 | cfg.version = glv33 150 | cfg.profile = opCoreProfile 151 | cfg.forwardCompat = true 152 | 153 | var win = newWindow(cfg) 154 | 155 | # Initialise OpenGL 156 | glfw.makeContextCurrent(win) 157 | 158 | if not gladLoadGL(getProcAddress): 159 | quit "Error initialising OpenGL" 160 | 161 | # Define viewport dimensions 162 | var width, height: int 163 | (width, height) = framebufferSize(win) 164 | glViewport(0, 0, GLint(width), GLint(height)) 165 | 166 | # Turn on vsync (0 turns it off) 167 | glfw.swapInterval(1) 168 | 169 | # Setup callbacks 170 | win.keyCb = keyCb 171 | 172 | # Setup shaders and various OpenGL objects 173 | setup() 174 | 175 | # Game loop 176 | while not win.shouldClose: 177 | glfw.pollEvents() 178 | draw() 179 | glfw.swapBuffers(win) 180 | 181 | # Properly de-allocate all resources once they've outlived their purpose 182 | cleanup() 183 | 184 | # Destroy window 185 | win.destroy() 186 | 187 | # Terminate GLFW, clearing any allocated resources 188 | glfw.terminate() 189 | 190 | 191 | main() 192 | 193 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Container3.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Textures 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Texture Coords 16 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 17 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 18 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 19 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 20 | ] 21 | 22 | var indices = [ 23 | GLuint(0), 1, 3, # First Triangle 24 | 1, 2, 3 # Second Triangle 25 | ] 26 | 27 | var 28 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 29 | 30 | 31 | proc setup() = 32 | shaderProgram = createShaderProgramFromFile("container3.vs", 33 | "container3.fs") 34 | 35 | glGenVertexArrays(1, vao.addr) 36 | glGenBuffers(1, vbo.addr) 37 | glGenBuffers(1, ebo.addr) 38 | 39 | glBindVertexArray(vao) 40 | 41 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 42 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 43 | vertices.addr, GL_STATIC_DRAW) 44 | 45 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 46 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 47 | indices.addr, GL_STATIC_DRAW); 48 | 49 | # Position attribute 50 | var stride = GLsizei(5 * sizeof(GLfloat)) 51 | 52 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 53 | normalized = false, stride, 54 | pointer = cast[pointer](0)) 55 | 56 | glEnableVertexAttribArray(0) 57 | 58 | # TexCoord attribute 59 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 60 | normalized = false, stride, 61 | pointer = cast[pointer](3 * sizeof(GLfloat))) 62 | 63 | glEnableVertexAttribArray(1) 64 | 65 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 66 | glBindVertexArray(GL_NONE) 67 | 68 | # Load and create the textures 69 | 70 | # Texture 1 71 | # --------- 72 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 73 | # object 74 | glGenTextures(1, texture1.addr) 75 | glBindTexture(GL_TEXTURE_2D, texture1) 76 | 77 | # Set the texture wrapping parameters 78 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 79 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 80 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 81 | 82 | # Set texture filtering parameters 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 85 | 86 | # Load image 87 | var 88 | width, height, channels: int 89 | data: seq[uint8] 90 | 91 | data = stbi.load("Data/container.jpg", width, height, channels, 92 | stbi.Default) 93 | 94 | # Create texture 95 | glTexImage2D(GL_TEXTURE_2D, level = 0, 96 | internalFormat = GLint(GL_RGB), 97 | GLsizei(width), GLsizei(height), border = 0, 98 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 99 | cast[pointer](data[0].addr)) 100 | 101 | glGenerateMipmap(GL_TEXTURE_2D) 102 | glBindTexture(GL_TEXTURE_2D, 0) 103 | 104 | # Texture 2 105 | # --------- 106 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 107 | # object 108 | glGenTextures(1, texture2.addr) 109 | glBindTexture(GL_TEXTURE_2D, texture2) 110 | 111 | # Set the texture wrapping parameters 112 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 113 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 114 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 115 | 116 | # Set texture filtering parameters 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 119 | 120 | # Load image 121 | data = stbi.load("Data/awesomeface.jpg", width, height, channels, 122 | stbi.Default) 123 | 124 | # Create texture 125 | glTexImage2D(GL_TEXTURE_2D, level = 0, 126 | internalFormat = GLint(GL_RGB), 127 | GLsizei(width), GLsizei(height), border = 0, 128 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 129 | cast[pointer](data[0].addr)) 130 | 131 | glGenerateMipmap(GL_TEXTURE_2D) 132 | glBindTexture(GL_TEXTURE_2D, 0) 133 | 134 | 135 | proc cleanup() = 136 | glDeleteVertexArrays(1, vao.addr) 137 | glDeleteBuffers(1, vbo.addr) 138 | glDeleteBuffers(1, ebo.addr) 139 | 140 | 141 | proc draw() = 142 | # Clear the color buffer 143 | glClearColor(0.2, 0.3, 0.3, 1.0) 144 | glClear(GL_COLOR_BUFFER_BIT) 145 | 146 | shaderProgram.use() 147 | 148 | # Bind textures using texture units 149 | glActiveTexture(GL_TEXTURE0) 150 | glBindTexture(GL_TEXTURE_2D, texture1) 151 | shaderProgram.setUniform1i("tex1", 0) 152 | 153 | glActiveTexture(GL_TEXTURE1) 154 | glBindTexture(GL_TEXTURE_2D, texture2) 155 | shaderProgram.setUniform1i("tex2", 1) 156 | 157 | # Draw container 158 | glBindVertexArray(vao) 159 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 160 | indices = GLvoid(nil)) 161 | glBindVertexArray(GL_NONE) 162 | 163 | 164 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 165 | modKeys: set[ModifierKey]) = 166 | 167 | if action != kaUp: 168 | if key == keyEscape: 169 | win.shouldClose = true 170 | 171 | 172 | proc main() = 173 | # Initialise GLFW 174 | glfw.initialize() 175 | 176 | # Create window 177 | var cfg = DefaultOpenglWindowConfig 178 | cfg.size = (w: 800, h: 600) 179 | cfg.title = "04-Textures/Container3" 180 | cfg.resizable = false 181 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 182 | cfg.version = glv33 183 | cfg.profile = opCoreProfile 184 | cfg.forwardCompat = true 185 | 186 | var win = newWindow(cfg) 187 | 188 | # Initialise OpenGL 189 | glfw.makeContextCurrent(win) 190 | 191 | if not gladLoadGL(getProcAddress): 192 | quit "Error initialising OpenGL" 193 | 194 | # Define viewport dimensions 195 | var width, height: int 196 | (width, height) = framebufferSize(win) 197 | glViewport(0, 0, GLint(width), GLint(height)) 198 | 199 | # Turn on vsync (0 turns it off) 200 | glfw.swapInterval(1) 201 | 202 | # Setup callbacks 203 | win.keyCb = keyCb 204 | 205 | # Setup shaders and various OpenGL objects 206 | setup() 207 | 208 | # Game loop 209 | while not win.shouldClose: 210 | glfw.pollEvents() 211 | draw() 212 | glfw.swapBuffers(win) 213 | 214 | # Properly de-allocate all resources once they've outlived their purpose 215 | cleanup() 216 | 217 | # Destroy window 218 | win.destroy() 219 | 220 | # Terminate GLFW, clearing any allocated resources 221 | glfw.terminate() 222 | 223 | 224 | main() 225 | 226 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Data/awesomeface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/04-Textures/Data/awesomeface.jpg -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Data/container.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/04-Textures/Data/container.jpg -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/Exercise1.nim: -------------------------------------------------------------------------------- 1 | # Make sure only the happy face looks in the other/reverse direction by 2 | # changing the fragment shader. 3 | # 4 | # Read the accompanying article at 5 | # https://learnopengl.com/#!Getting-started/Textures 6 | 7 | import math 8 | 9 | import glm 10 | import glad/gl 11 | import glfw 12 | import stb_image/read as stbi 13 | 14 | import common/shader 15 | 16 | 17 | var vertices = [ 18 | # Positions # Texture Coords 19 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 20 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 21 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 22 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 23 | ] 24 | 25 | var indices = [ 26 | GLuint(0), 1, 3, # First Triangle 27 | 1, 2, 3 # Second Triangle 28 | ] 29 | 30 | var 31 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 32 | 33 | 34 | proc setup() = 35 | shaderProgram = createShaderProgramFromFile("exercise1.vs", 36 | "exercise1.fs") 37 | 38 | glGenVertexArrays(1, vao.addr) 39 | glGenBuffers(1, vbo.addr) 40 | glGenBuffers(1, ebo.addr) 41 | 42 | glBindVertexArray(vao) 43 | 44 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 45 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 46 | vertices.addr, GL_STATIC_DRAW) 47 | 48 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 49 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 50 | indices.addr, GL_STATIC_DRAW); 51 | 52 | # Position attribute 53 | var stride = GLsizei(5 * sizeof(GLfloat)) 54 | 55 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 56 | normalized = false, stride, 57 | pointer = cast[pointer](0)) 58 | 59 | glEnableVertexAttribArray(0) 60 | 61 | # TexCoord attribute 62 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 63 | normalized = false, stride, 64 | pointer = cast[pointer](3 * sizeof(GLfloat))) 65 | 66 | glEnableVertexAttribArray(1) 67 | 68 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 69 | glBindVertexArray(GL_NONE) 70 | 71 | # Load and create the textures 72 | 73 | # Texture 1 74 | # --------- 75 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 76 | # object 77 | glGenTextures(1, texture1.addr) 78 | glBindTexture(GL_TEXTURE_2D, texture1) 79 | 80 | # Set the texture wrapping parameters 81 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 82 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 84 | 85 | # Set texture filtering parameters 86 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 88 | 89 | # Load image 90 | var 91 | width, height, channels: int 92 | data: seq[uint8] 93 | 94 | data = stbi.load("../Data/container.jpg", width, height, channels, 95 | stbi.Default) 96 | 97 | # Create texture 98 | glTexImage2D(GL_TEXTURE_2D, level = 0, 99 | internalFormat = GLint(GL_RGB), 100 | GLsizei(width), GLsizei(height), border = 0, 101 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 102 | cast[pointer](data[0].addr)) 103 | 104 | glGenerateMipmap(GL_TEXTURE_2D) 105 | glBindTexture(GL_TEXTURE_2D, 0) 106 | 107 | # Texture 2 108 | # --------- 109 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 110 | # object 111 | glGenTextures(1, texture2.addr) 112 | glBindTexture(GL_TEXTURE_2D, texture2) 113 | 114 | # Set the texture wrapping parameters 115 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 116 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 118 | 119 | # Set texture filtering parameters 120 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 121 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 122 | 123 | # Load image 124 | data = stbi.load("../Data/awesomeface.jpg", width, height, channels, 125 | stbi.Default) 126 | 127 | # Create texture 128 | glTexImage2D(GL_TEXTURE_2D, level = 0, 129 | internalFormat = GLint(GL_RGB), 130 | GLsizei(width), GLsizei(height), border = 0, 131 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 132 | cast[pointer](data[0].addr)) 133 | 134 | glGenerateMipmap(GL_TEXTURE_2D) 135 | glBindTexture(GL_TEXTURE_2D, 0) 136 | 137 | 138 | proc cleanup() = 139 | glDeleteVertexArrays(1, vao.addr) 140 | glDeleteBuffers(1, vbo.addr) 141 | glDeleteBuffers(1, ebo.addr) 142 | 143 | 144 | proc draw() = 145 | # Clear the color buffer 146 | glClearColor(0.2, 0.3, 0.3, 1.0) 147 | glClear(GL_COLOR_BUFFER_BIT) 148 | 149 | shaderProgram.use() 150 | 151 | # Bind textures using texture units 152 | glActiveTexture(GL_TEXTURE0) 153 | glBindTexture(GL_TEXTURE_2D, texture1) 154 | shaderProgram.setUniform1i("tex1", 0) 155 | 156 | glActiveTexture(GL_TEXTURE1) 157 | glBindTexture(GL_TEXTURE_2D, texture2) 158 | shaderProgram.setUniform1i("tex2", 1) 159 | 160 | # Draw container 161 | glBindVertexArray(vao) 162 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 163 | indices = GLvoid(nil)) 164 | glBindVertexArray(GL_NONE) 165 | 166 | 167 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 168 | modKeys: set[ModifierKey]) = 169 | 170 | if action != kaUp: 171 | if key == keyEscape: 172 | win.shouldClose = true 173 | 174 | 175 | proc main() = 176 | # Initialise GLFW 177 | glfw.initialize() 178 | 179 | # Create window 180 | var cfg = DefaultOpenglWindowConfig 181 | cfg.size = (w: 800, h: 600) 182 | cfg.title = "04-Textures/Exercise1" 183 | cfg.resizable = false 184 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 185 | cfg.version = glv33 186 | cfg.profile = opCoreProfile 187 | cfg.forwardCompat = true 188 | 189 | var win = newWindow(cfg) 190 | 191 | # Initialise OpenGL 192 | glfw.makeContextCurrent(win) 193 | 194 | if not gladLoadGL(getProcAddress): 195 | quit "Error initialising OpenGL" 196 | 197 | # Define viewport dimensions 198 | var width, height: int 199 | (width, height) = framebufferSize(win) 200 | glViewport(0, 0, GLint(width), GLint(height)) 201 | 202 | # Turn on vsync (0 turns it off) 203 | glfw.swapInterval(1) 204 | 205 | # Setup callbacks 206 | win.keyCb = keyCb 207 | 208 | # Setup shaders and various OpenGL objects 209 | setup() 210 | 211 | # Game loop 212 | while not win.shouldClose: 213 | glfw.pollEvents() 214 | draw() 215 | glfw.swapBuffers(win) 216 | 217 | # Properly de-allocate all resources once they've outlived their purpose 218 | cleanup() 219 | 220 | # Destroy window 221 | win.destroy() 222 | 223 | # Terminate GLFW, clearing any allocated resources 224 | glfw.terminate() 225 | 226 | 227 | main() 228 | 229 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/Exercise2.nim: -------------------------------------------------------------------------------- 1 | # Experiment with the different texture wrapping methods by specifying texture 2 | # coordinates in the range 0.0f to 2.0f instead of 0.0f to 1.0f. See if you 3 | # can display 4 smiley faces on a single container image clamped at its edge. 4 | # 5 | # Read the accompanying article at 6 | # https://learnopengl.com/#!Getting-started/Textures 7 | 8 | import math 9 | 10 | import glm 11 | import glad/gl 12 | import glfw 13 | import stb_image/read as stbi 14 | 15 | import common/shader 16 | 17 | 18 | var vertices = [ 19 | # Positions # Texture Coords 20 | GLfloat(0.5), 0.5, 0.0, 2.0, 2.0, # Top Right 21 | 0.5, -0.5, 0.0, 2.0, 0.0, # Bottom Right 22 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 23 | -0.5, 0.5, 0.0, 0.0, 2.0 # Top Left 24 | ] 25 | 26 | var indices = [ 27 | GLuint(0), 1, 3, # First Triangle 28 | 1, 2, 3 # Second Triangle 29 | ] 30 | 31 | var 32 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 33 | 34 | 35 | proc setup() = 36 | shaderProgram = createShaderProgramFromFile("exercise2.vs", 37 | "exercise2.fs") 38 | 39 | glGenVertexArrays(1, vao.addr) 40 | glGenBuffers(1, vbo.addr) 41 | glGenBuffers(1, ebo.addr) 42 | 43 | glBindVertexArray(vao) 44 | 45 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 46 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 47 | vertices.addr, GL_STATIC_DRAW) 48 | 49 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 50 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 51 | indices.addr, GL_STATIC_DRAW); 52 | 53 | # Position attribute 54 | var stride = GLsizei(5 * sizeof(GLfloat)) 55 | 56 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 57 | normalized = false, stride, 58 | pointer = cast[pointer](0)) 59 | 60 | glEnableVertexAttribArray(0) 61 | 62 | # TexCoord attribute 63 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 64 | normalized = false, stride, 65 | pointer = cast[pointer](3 * sizeof(GLfloat))) 66 | 67 | glEnableVertexAttribArray(1) 68 | 69 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 70 | glBindVertexArray(GL_NONE) 71 | 72 | # Load and create the textures 73 | 74 | # Texture 1 75 | # --------- 76 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 77 | # object 78 | glGenTextures(1, texture1.addr) 79 | glBindTexture(GL_TEXTURE_2D, texture1) 80 | 81 | # Set the texture wrapping parameters 82 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 85 | 86 | # Set texture filtering parameters 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 89 | 90 | # Load image 91 | var 92 | width, height, channels: int 93 | data: seq[uint8] 94 | 95 | data = stbi.load("../Data/container.jpg", width, height, channels, 96 | stbi.Default) 97 | 98 | # Create texture 99 | glTexImage2D(GL_TEXTURE_2D, level = 0, 100 | internalFormat = GLint(GL_RGB), 101 | GLsizei(width), GLsizei(height), border = 0, 102 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 103 | cast[pointer](data[0].addr)) 104 | 105 | glGenerateMipmap(GL_TEXTURE_2D) 106 | glBindTexture(GL_TEXTURE_2D, 0) 107 | 108 | # Texture 2 109 | # --------- 110 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 111 | # object 112 | glGenTextures(1, texture2.addr) 113 | glBindTexture(GL_TEXTURE_2D, texture2) 114 | 115 | # Set the texture wrapping parameters 116 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 119 | 120 | # Set texture filtering parameters 121 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 122 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 123 | 124 | # Load image 125 | data = stbi.load("../Data/awesomeface.jpg", width, height, channels, 126 | stbi.Default) 127 | 128 | # Create texture 129 | glTexImage2D(GL_TEXTURE_2D, level = 0, 130 | internalFormat = GLint(GL_RGB), 131 | GLsizei(width), GLsizei(height), border = 0, 132 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 133 | cast[pointer](data[0].addr)) 134 | 135 | glGenerateMipmap(GL_TEXTURE_2D) 136 | glBindTexture(GL_TEXTURE_2D, 0) 137 | 138 | 139 | proc cleanup() = 140 | glDeleteVertexArrays(1, vao.addr) 141 | glDeleteBuffers(1, vbo.addr) 142 | glDeleteBuffers(1, ebo.addr) 143 | 144 | 145 | proc draw() = 146 | # Clear the color buffer 147 | glClearColor(0.2, 0.3, 0.3, 1.0) 148 | glClear(GL_COLOR_BUFFER_BIT) 149 | 150 | shaderProgram.use() 151 | 152 | # Bind textures using texture units 153 | glActiveTexture(GL_TEXTURE0) 154 | glBindTexture(GL_TEXTURE_2D, texture1) 155 | shaderProgram.setUniform1i("tex1", 0) 156 | 157 | glActiveTexture(GL_TEXTURE1) 158 | glBindTexture(GL_TEXTURE_2D, texture2) 159 | shaderProgram.setUniform1i("tex2", 1) 160 | 161 | # Draw container 162 | glBindVertexArray(vao) 163 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 164 | indices = GLvoid(nil)) 165 | glBindVertexArray(GL_NONE) 166 | 167 | 168 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 169 | modKeys: set[ModifierKey]) = 170 | 171 | if action != kaUp: 172 | if key == keyEscape: 173 | win.shouldClose = true 174 | 175 | 176 | proc main() = 177 | # Initialise GLFW 178 | glfw.initialize() 179 | 180 | # Create window 181 | var cfg = DefaultOpenglWindowConfig 182 | cfg.size = (w: 800, h: 600) 183 | cfg.title = "04-Textures/Exercise2" 184 | cfg.resizable = false 185 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 186 | cfg.version = glv33 187 | cfg.profile = opCoreProfile 188 | cfg.forwardCompat = true 189 | 190 | var win = newWindow(cfg) 191 | 192 | # Initialise OpenGL 193 | glfw.makeContextCurrent(win) 194 | 195 | if not gladLoadGL(getProcAddress): 196 | quit "Error initialising OpenGL" 197 | 198 | # Define viewport dimensions 199 | var width, height: int 200 | (width, height) = framebufferSize(win) 201 | glViewport(0, 0, GLint(width), GLint(height)) 202 | 203 | # Turn on vsync (0 turns it off) 204 | glfw.swapInterval(1) 205 | 206 | # Setup callbacks 207 | win.keyCb = keyCb 208 | 209 | # Setup shaders and various OpenGL objects 210 | setup() 211 | 212 | # Game loop 213 | while not win.shouldClose: 214 | glfw.pollEvents() 215 | draw() 216 | glfw.swapBuffers(win) 217 | 218 | # Properly de-allocate all resources once they've outlived their purpose 219 | cleanup() 220 | 221 | # Destroy window 222 | win.destroy() 223 | 224 | # Terminate GLFW, clearing any allocated resources 225 | glfw.terminate() 226 | 227 | 228 | main() 229 | 230 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/Exercise3.nim: -------------------------------------------------------------------------------- 1 | # Try to display only the center pixels of the texture image on the rectangle 2 | # in such a way that the individual pixels are getting visible by changing the 3 | # texture coordinates. Try to set the texture filtering method to GL_NEAREST 4 | # to see the pixels more clearly. 5 | # 6 | # Read the accompanying article at 7 | # https://learnopengl.com/#!Getting-started/Textures 8 | 9 | import math 10 | 11 | import glm 12 | import glad/gl 13 | import glfw 14 | import stb_image/read as stbi 15 | 16 | import common/shader 17 | 18 | 19 | var vertices = [ 20 | # Positions # Texture Coords 21 | GLfloat(0.5), 0.5, 0.0, 0.51, 0.51, # Top Right 22 | 0.5, -0.5, 0.0, 0.51, 0.49, # Bottom Right 23 | -0.5, -0.5, 0.0, 0.49, 0.49, # Bottom Left 24 | -0.5, 0.5, 0.0, 0.49, 0.51 # Top Left 25 | ] 26 | 27 | var indices = [ 28 | GLuint(0), 1, 3, # First Triangle 29 | 1, 2, 3 # Second Triangle 30 | ] 31 | 32 | var 33 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 34 | 35 | 36 | proc setup() = 37 | shaderProgram = createShaderProgramFromFile("exercise3.vs", 38 | "exercise3.fs") 39 | 40 | glGenVertexArrays(1, vao.addr) 41 | glGenBuffers(1, vbo.addr) 42 | glGenBuffers(1, ebo.addr) 43 | 44 | glBindVertexArray(vao) 45 | 46 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 47 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 48 | vertices.addr, GL_STATIC_DRAW) 49 | 50 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 51 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 52 | indices.addr, GL_STATIC_DRAW); 53 | 54 | # Position attribute 55 | var stride = GLsizei(5 * sizeof(GLfloat)) 56 | 57 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 58 | normalized = false, stride, 59 | pointer = cast[pointer](0)) 60 | 61 | glEnableVertexAttribArray(0) 62 | 63 | # TexCoord attribute 64 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 65 | normalized = false, stride, 66 | pointer = cast[pointer](3 * sizeof(GLfloat))) 67 | 68 | glEnableVertexAttribArray(1) 69 | 70 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 71 | glBindVertexArray(GL_NONE) 72 | 73 | # Load and create the textures 74 | 75 | # Texture 1 76 | # --------- 77 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 78 | # object 79 | glGenTextures(1, texture1.addr) 80 | glBindTexture(GL_TEXTURE_2D, texture1) 81 | 82 | # Set the texture wrapping parameters 83 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 86 | 87 | # Set texture filtering parameters 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 89 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 90 | 91 | # Load image 92 | var 93 | width, height, channels: int 94 | data: seq[uint8] 95 | 96 | data = stbi.load("../Data/container.jpg", width, height, channels, 97 | stbi.Default) 98 | 99 | # Create texture 100 | glTexImage2D(GL_TEXTURE_2D, level = 0, 101 | internalFormat = GLint(GL_RGB), 102 | GLsizei(width), GLsizei(height), border = 0, 103 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 104 | cast[pointer](data[0].addr)) 105 | 106 | glGenerateMipmap(GL_TEXTURE_2D) 107 | glBindTexture(GL_TEXTURE_2D, 0) 108 | 109 | # Texture 2 110 | # --------- 111 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 112 | # object 113 | glGenTextures(1, texture2.addr) 114 | glBindTexture(GL_TEXTURE_2D, texture2) 115 | 116 | # Set the texture wrapping parameters 117 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 119 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 120 | 121 | # Set texture filtering parameters 122 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 123 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 124 | 125 | # Load image 126 | data = stbi.load("../Data/awesomeface.jpg", width, height, channels, 127 | stbi.Default) 128 | 129 | # Create texture 130 | glTexImage2D(GL_TEXTURE_2D, level = 0, 131 | internalFormat = GLint(GL_RGB), 132 | GLsizei(width), GLsizei(height), border = 0, 133 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 134 | cast[pointer](data[0].addr)) 135 | 136 | glGenerateMipmap(GL_TEXTURE_2D) 137 | glBindTexture(GL_TEXTURE_2D, 0) 138 | 139 | 140 | proc cleanup() = 141 | glDeleteVertexArrays(1, vao.addr) 142 | glDeleteBuffers(1, vbo.addr) 143 | glDeleteBuffers(1, ebo.addr) 144 | 145 | 146 | proc draw() = 147 | # Clear the color buffer 148 | glClearColor(0.2, 0.3, 0.3, 1.0) 149 | glClear(GL_COLOR_BUFFER_BIT) 150 | 151 | shaderProgram.use() 152 | 153 | # Bind textures using texture units 154 | glActiveTexture(GL_TEXTURE0) 155 | glBindTexture(GL_TEXTURE_2D, texture1) 156 | shaderProgram.setUniform1i("tex1", 0) 157 | 158 | glActiveTexture(GL_TEXTURE1) 159 | glBindTexture(GL_TEXTURE_2D, texture2) 160 | shaderProgram.setUniform1i("tex2", 1) 161 | 162 | # Draw container 163 | glBindVertexArray(vao) 164 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 165 | indices = GLvoid(nil)) 166 | glBindVertexArray(GL_NONE) 167 | 168 | 169 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 170 | modKeys: set[ModifierKey]) = 171 | 172 | if action != kaUp: 173 | if key == keyEscape: 174 | win.shouldClose = true 175 | 176 | 177 | proc main() = 178 | # Initialise GLFW 179 | glfw.initialize() 180 | 181 | # Create window 182 | var cfg = DefaultOpenglWindowConfig 183 | cfg.size = (w: 800, h: 600) 184 | cfg.title = "04-Textures/Exercise3" 185 | cfg.resizable = false 186 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 187 | cfg.version = glv33 188 | cfg.profile = opCoreProfile 189 | cfg.forwardCompat = true 190 | 191 | var win = newWindow(cfg) 192 | 193 | # Initialise OpenGL 194 | glfw.makeContextCurrent(win) 195 | 196 | if not gladLoadGL(getProcAddress): 197 | quit "Error initialising OpenGL" 198 | 199 | # Define viewport dimensions 200 | var width, height: int 201 | (width, height) = framebufferSize(win) 202 | glViewport(0, 0, GLint(width), GLint(height)) 203 | 204 | # Turn on vsync (0 turns it off) 205 | glfw.swapInterval(1) 206 | 207 | # Setup callbacks 208 | win.keyCb = keyCb 209 | 210 | # Setup shaders and various OpenGL objects 211 | setup() 212 | 213 | # Game loop 214 | while not win.shouldClose: 215 | glfw.pollEvents() 216 | draw() 217 | glfw.swapBuffers(win) 218 | 219 | # Properly de-allocate all resources once they've outlived their purpose 220 | cleanup() 221 | 222 | # Destroy window 223 | win.destroy() 224 | 225 | # Terminate GLFW, clearing any allocated resources 226 | glfw.terminate() 227 | 228 | 229 | main() 230 | 231 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/Exercise4.nim: -------------------------------------------------------------------------------- 1 | # Use a uniform variable as the mix function's third parameter to vary the 2 | # amount the two textures are visible. Use the up and down arrow keys to 3 | # change how much the container or the smiley face is visible. 4 | # 5 | # Read the accompanying article at 6 | # https://learnopengl.com/#!Getting-started/Textures 7 | 8 | import math 9 | 10 | import glm 11 | import glad/gl 12 | import glfw 13 | import stb_image/read as stbi 14 | 15 | import common/shader 16 | 17 | 18 | const TEX_MIX_FACTOR_DELTA = 0.02 19 | 20 | var texMixFactor = GLfloat(0.3) 21 | 22 | var vertices = [ 23 | # Positions # Texture Coords 24 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 25 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 26 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 27 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 28 | ] 29 | 30 | var indices = [ 31 | GLuint(0), 1, 3, # First Triangle 32 | 1, 2, 3 # Second Triangle 33 | ] 34 | 35 | var 36 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 37 | 38 | 39 | proc setup() = 40 | shaderProgram = createShaderProgramFromFile("exercise4.vs", 41 | "exercise4.fs") 42 | 43 | glGenVertexArrays(1, vao.addr) 44 | glGenBuffers(1, vbo.addr) 45 | glGenBuffers(1, ebo.addr) 46 | 47 | glBindVertexArray(vao) 48 | 49 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 50 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 51 | vertices.addr, GL_STATIC_DRAW) 52 | 53 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 54 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 55 | indices.addr, GL_STATIC_DRAW); 56 | 57 | # Position attribute 58 | var stride = GLsizei(5 * sizeof(GLfloat)) 59 | 60 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 61 | normalized = false, stride, 62 | pointer = cast[pointer](0)) 63 | 64 | glEnableVertexAttribArray(0) 65 | 66 | # TexCoord attribute 67 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 68 | normalized = false, stride, 69 | pointer = cast[pointer](3 * sizeof(GLfloat))) 70 | 71 | glEnableVertexAttribArray(1) 72 | 73 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 74 | glBindVertexArray(GL_NONE) 75 | 76 | # Load and create the textures 77 | 78 | # Texture 1 79 | # --------- 80 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 81 | # object 82 | glGenTextures(1, texture1.addr) 83 | glBindTexture(GL_TEXTURE_2D, texture1) 84 | 85 | # Set the texture wrapping parameters 86 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 89 | 90 | # Set texture filtering parameters 91 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 92 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 93 | 94 | # Load image 95 | var 96 | width, height, channels: int 97 | data: seq[uint8] 98 | 99 | data = stbi.load("../Data/container.jpg", width, height, channels, 100 | stbi.Default) 101 | 102 | # Create texture 103 | glTexImage2D(GL_TEXTURE_2D, level = 0, 104 | internalFormat = GLint(GL_RGB), 105 | GLsizei(width), GLsizei(height), border = 0, 106 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 107 | cast[pointer](data[0].addr)) 108 | 109 | glGenerateMipmap(GL_TEXTURE_2D) 110 | glBindTexture(GL_TEXTURE_2D, 0) 111 | 112 | # Texture 2 113 | # --------- 114 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 115 | # object 116 | glGenTextures(1, texture2.addr) 117 | glBindTexture(GL_TEXTURE_2D, texture2) 118 | 119 | # Set the texture wrapping parameters 120 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 121 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 122 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 123 | 124 | # Set texture filtering parameters 125 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 126 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 127 | 128 | # Load image 129 | data = stbi.load("../Data/awesomeface.jpg", width, height, channels, 130 | stbi.Default) 131 | 132 | # Create texture 133 | glTexImage2D(GL_TEXTURE_2D, level = 0, 134 | internalFormat = GLint(GL_RGB), 135 | GLsizei(width), GLsizei(height), border = 0, 136 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 137 | cast[pointer](data[0].addr)) 138 | 139 | glGenerateMipmap(GL_TEXTURE_2D) 140 | glBindTexture(GL_TEXTURE_2D, 0) 141 | 142 | 143 | proc cleanup() = 144 | glDeleteVertexArrays(1, vao.addr) 145 | glDeleteBuffers(1, vbo.addr) 146 | glDeleteBuffers(1, ebo.addr) 147 | 148 | 149 | proc draw() = 150 | # Clear the color buffer 151 | glClearColor(0.2, 0.3, 0.3, 1.0) 152 | glClear(GL_COLOR_BUFFER_BIT) 153 | 154 | shaderProgram.use() 155 | 156 | # Bind textures using texture units 157 | glActiveTexture(GL_TEXTURE0) 158 | glBindTexture(GL_TEXTURE_2D, texture1) 159 | shaderProgram.setUniform1i("tex1", 0) 160 | 161 | glActiveTexture(GL_TEXTURE1) 162 | glBindTexture(GL_TEXTURE_2D, texture2) 163 | shaderProgram.setUniform1i("tex2", 1) 164 | 165 | # Set texture mix factor 166 | shaderProgram.setUniform1f("texMixFactor", texMixFactor) 167 | 168 | # Draw container 169 | glBindVertexArray(vao) 170 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 171 | indices = GLvoid(nil)) 172 | glBindVertexArray(GL_NONE) 173 | 174 | 175 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 176 | modKeys: set[ModifierKey]) = 177 | 178 | if action != kaUp: 179 | case key: 180 | of keyEscape: win.shouldClose = true 181 | of keyUp: texMixFactor = min(texMixFactor + TEX_MIX_FACTOR_DELTA, 1.0) 182 | of keyDown: texMixFactor = max(texMixFactor - TEX_MIX_FACTOR_DELTA, 0.0) 183 | else: 184 | discard 185 | 186 | 187 | proc main() = 188 | # Initialise GLFW 189 | glfw.initialize() 190 | 191 | # Create window 192 | var cfg = DefaultOpenglWindowConfig 193 | cfg.size = (w: 800, h: 600) 194 | cfg.title = "04-Textures/Exercise4" 195 | cfg.resizable = false 196 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 197 | cfg.version = glv33 198 | cfg.profile = opCoreProfile 199 | cfg.forwardCompat = true 200 | 201 | var win = newWindow(cfg) 202 | 203 | # Initialise OpenGL 204 | glfw.makeContextCurrent(win) 205 | 206 | if not gladLoadGL(getProcAddress): 207 | quit "Error initialising OpenGL" 208 | 209 | # Define viewport dimensions 210 | var width, height: int 211 | (width, height) = framebufferSize(win) 212 | glViewport(0, 0, GLint(width), GLint(height)) 213 | 214 | # Turn on vsync (0 turns it off) 215 | glfw.swapInterval(1) 216 | 217 | # Setup callbacks 218 | win.keyCb = keyCb 219 | 220 | # Setup shaders and various OpenGL objects 221 | setup() 222 | 223 | # Game loop 224 | while not win.shouldClose: 225 | glfw.pollEvents() 226 | draw() 227 | glfw.swapBuffers(win) 228 | 229 | # Properly de-allocate all resources once they've outlived their purpose 230 | cleanup() 231 | 232 | # Destroy window 233 | win.destroy() 234 | 235 | # Terminate GLFW, clearing any allocated resources 236 | glfw.terminate() 237 | 238 | 239 | main() 240 | 241 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, vec2(1.0f - textureCoord.x, textureCoord.y)), 14 | 0.2); 15 | } 16 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(position, 1.0f); 11 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 12 | } 13 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, vec2(1.0f - textureCoord.x, textureCoord.y)), 14 | 0.2); 15 | } 16 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(position, 1.0f); 11 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 12 | } 13 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, vec2(1.0f - textureCoord.x, textureCoord.y)), 14 | 0.2); 15 | } 16 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(position, 1.0f); 11 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 12 | } 13 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise4.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | uniform float texMixFactor; 10 | 11 | void main() 12 | { 13 | color = mix(texture(tex1, textureCoord), 14 | texture(tex2, vec2(1.0f - textureCoord.x, textureCoord.y)), 15 | texMixFactor); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/Exercises/exercise4.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(position, 1.0f); 11 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 12 | } 13 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c Container1.nim && \ 2 | nim c Container2.nim && \ 3 | nim c Container3.nim && \ 4 | nim c Exercises/Exercise1.nim && \ 5 | nim c Exercises/Exercise2.nim && \ 6 | nim c Exercises/Exercise3.nim && \ 7 | nim c Exercises/Exercise4.nim 8 | 9 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/container1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 vertexColor; 4 | in vec2 textureCoord; 5 | 6 | out vec4 color; 7 | 8 | uniform sampler2D tex; 9 | 10 | void main() 11 | { 12 | color = texture(tex, textureCoord); 13 | } 14 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/container1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec3 color; 5 | layout (location = 2) in vec2 texCoord; 6 | 7 | out vec3 vertexColor; 8 | out vec2 textureCoord; 9 | 10 | void main() 11 | { 12 | gl_Position = vec4(position, 1.0f); 13 | vertexColor = color; 14 | textureCoord = texCoord; 15 | } 16 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/container2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 vertexColor; 4 | in vec2 textureCoord; 5 | 6 | out vec4 color; 7 | 8 | uniform sampler2D tex; 9 | 10 | void main() 11 | { 12 | color = texture(tex, textureCoord) * vec4(vertexColor, 1.0f); 13 | } 14 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/container2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec3 color; 5 | layout (location = 2) in vec2 texCoord; 6 | 7 | out vec3 vertexColor; 8 | out vec2 textureCoord; 9 | 10 | void main() 11 | { 12 | gl_Position = vec4(position, 1.0f); 13 | vertexColor = color; 14 | textureCoord = texCoord; 15 | } 16 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/container3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/04-Textures/container3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(position, 1.0f); 11 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 12 | } 13 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Data/awesomeface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/05-Transformations/Data/awesomeface.jpg -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Data/container.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/05-Transformations/Data/container.jpg -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Exercises/Exercise1.nim: -------------------------------------------------------------------------------- 1 | # Using the last transformation on the container, try switching the order 2 | # around by first rotating and then translating. See what happens and try to 3 | # reason why this happens. 4 | # 5 | # Read the accompanying article at 6 | # https://learnopengl.com/#!Getting-started/Transformations 7 | 8 | import math 9 | 10 | import glm 11 | import glad/gl 12 | import glfw 13 | import stb_image/read as stbi 14 | 15 | import common/shader 16 | 17 | 18 | var vertices = [ 19 | # Positions # Texture Coords 20 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 21 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 22 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 23 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 24 | ] 25 | 26 | var indices = [ 27 | GLuint(0), 1, 3, # First Triangle 28 | 1, 2, 3 # Second Triangle 29 | ] 30 | 31 | var 32 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 33 | 34 | 35 | proc setup() = 36 | shaderProgram = createShaderProgramFromFile("exercise1.vs", 37 | "exercise1.fs") 38 | 39 | glGenVertexArrays(1, vao.addr) 40 | glGenBuffers(1, vbo.addr) 41 | glGenBuffers(1, ebo.addr) 42 | 43 | glBindVertexArray(vao) 44 | 45 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 46 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 47 | vertices.addr, GL_STATIC_DRAW) 48 | 49 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 50 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 51 | indices.addr, GL_STATIC_DRAW); 52 | 53 | # Position attribute 54 | var stride = GLsizei(5 * sizeof(GLfloat)) 55 | 56 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 57 | normalized = false, stride, 58 | pointer = cast[pointer](0)) 59 | 60 | glEnableVertexAttribArray(0) 61 | 62 | # TexCoord attribute 63 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 64 | normalized = false, stride, 65 | pointer = cast[pointer](3 * sizeof(GLfloat))) 66 | 67 | glEnableVertexAttribArray(1) 68 | 69 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 70 | glBindVertexArray(GL_NONE) 71 | 72 | # Load and create the textures 73 | 74 | # Texture 1 75 | # --------- 76 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 77 | # object 78 | glGenTextures(1, texture1.addr) 79 | glBindTexture(GL_TEXTURE_2D, texture1) 80 | 81 | # Set the texture wrapping parameters 82 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 85 | 86 | # Set texture filtering parameters 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 89 | 90 | # Load image 91 | var 92 | width, height, channels: int 93 | data: seq[uint8] 94 | 95 | data = stbi.load("../Data/container.jpg", width, height, channels, 96 | stbi.Default) 97 | 98 | # Create texture 99 | glTexImage2D(GL_TEXTURE_2D, level = 0, 100 | internalFormat = GLint(GL_RGB), 101 | GLsizei(width), GLsizei(height), border = 0, 102 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 103 | cast[pointer](data[0].addr)) 104 | 105 | glGenerateMipmap(GL_TEXTURE_2D) 106 | glBindTexture(GL_TEXTURE_2D, 0) 107 | 108 | # Texture 2 109 | # --------- 110 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 111 | # object 112 | glGenTextures(1, texture2.addr) 113 | glBindTexture(GL_TEXTURE_2D, texture2) 114 | 115 | # Set the texture wrapping parameters 116 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 119 | 120 | # Set texture filtering parameters 121 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 122 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 123 | 124 | # Load image 125 | data = stbi.load("../Data/awesomeface.jpg", width, height, channels, 126 | stbi.Default) 127 | 128 | # Create texture 129 | glTexImage2D(GL_TEXTURE_2D, level = 0, 130 | internalFormat = GLint(GL_RGB), 131 | GLsizei(width), GLsizei(height), border = 0, 132 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 133 | cast[pointer](data[0].addr)) 134 | 135 | glGenerateMipmap(GL_TEXTURE_2D) 136 | glBindTexture(GL_TEXTURE_2D, 0) 137 | 138 | 139 | proc cleanup() = 140 | glDeleteVertexArrays(1, vao.addr) 141 | glDeleteBuffers(1, vbo.addr) 142 | glDeleteBuffers(1, ebo.addr) 143 | 144 | 145 | proc draw() = 146 | # Clear the color buffer 147 | glClearColor(0.2, 0.3, 0.3, 1.0) 148 | glClear(GL_COLOR_BUFFER_BIT) 149 | 150 | shaderProgram.use() 151 | 152 | # Bind textures using texture units 153 | glActiveTexture(GL_TEXTURE0) 154 | glBindTexture(GL_TEXTURE_2D, texture1) 155 | shaderProgram.setUniform1i("tex1", 0) 156 | 157 | glActiveTexture(GL_TEXTURE1) 158 | glBindTexture(GL_TEXTURE_2D, texture2) 159 | shaderProgram.setUniform1i("tex2", 1) 160 | 161 | # Set transform matrix 162 | var transform = mat4(GLfloat(1.0)) 163 | .rotate(getTime(), vec3(GLfloat(0.0), 0.0, 1.0)) 164 | .translate(vec3(GLfloat(0.5), -0.5, 0.0)) 165 | 166 | shaderProgram.setUniformMatrix4fv("transform", transform.caddr) 167 | 168 | # Draw container 169 | glBindVertexArray(vao) 170 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 171 | indices = GLvoid(nil)) 172 | glBindVertexArray(GL_NONE) 173 | 174 | 175 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 176 | modKeys: set[ModifierKey]) = 177 | 178 | if action != kaUp: 179 | if key == keyEscape: 180 | win.shouldClose = true 181 | 182 | 183 | proc main() = 184 | # Initialise GLFW 185 | glfw.initialize() 186 | 187 | # Create window 188 | var cfg = DefaultOpenglWindowConfig 189 | cfg.size = (w: 800, h: 600) 190 | cfg.title = "05-Transformations/Exercise1" 191 | cfg.resizable = false 192 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 193 | cfg.version = glv33 194 | cfg.profile = opCoreProfile 195 | cfg.forwardCompat = true 196 | 197 | var win = newWindow(cfg) 198 | 199 | # Initialise OpenGL 200 | glfw.makeContextCurrent(win) 201 | 202 | if not gladLoadGL(getProcAddress): 203 | quit "Error initialising OpenGL" 204 | 205 | # Define viewport dimensions 206 | var width, height: int 207 | (width, height) = framebufferSize(win) 208 | glViewport(0, 0, GLint(width), GLint(height)) 209 | 210 | # Turn on vsync (0 turns it off) 211 | glfw.swapInterval(1) 212 | 213 | # Setup callbacks 214 | win.keyCb = keyCb 215 | 216 | # Setup shaders and various OpenGL objects 217 | setup() 218 | 219 | # Game loop 220 | while not win.shouldClose: 221 | glfw.pollEvents() 222 | draw() 223 | glfw.swapBuffers(win) 224 | 225 | # Properly de-allocate all resources once they've outlived their purpose 226 | cleanup() 227 | 228 | # Destroy window 229 | win.destroy() 230 | 231 | # Terminate GLFW, clearing any allocated resources 232 | glfw.terminate() 233 | 234 | 235 | main() 236 | 237 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Exercises/Exercise2.nim: -------------------------------------------------------------------------------- 1 | # Try drawing a second container with another call to glDrawElements but place 2 | # it at a different position using transformations only. Make sure this second 3 | # container is placed at the top-left of the window and instead of rotating, 4 | # scale it over time (using the sin function is useful here; note that using 5 | # sin will cause the object to invert as soon as a negative scale is applied). 6 | # 7 | # Read the accompanying article at 8 | # https://learnopengl.com/#!Getting-started/Transformations 9 | 10 | import math 11 | 12 | import glm 13 | import glad/gl 14 | import glfw 15 | import stb_image/read as stbi 16 | 17 | import common/shader 18 | 19 | 20 | var vertices = [ 21 | # Positions # Texture Coords 22 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 23 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 24 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 25 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 26 | ] 27 | 28 | var indices = [ 29 | GLuint(0), 1, 3, # First Triangle 30 | 1, 2, 3 # Second Triangle 31 | ] 32 | 33 | var 34 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 35 | 36 | 37 | proc setup() = 38 | shaderProgram = createShaderProgramFromFile("exercise2.vs", 39 | "exercise2.fs") 40 | 41 | glGenVertexArrays(1, vao.addr) 42 | glGenBuffers(1, vbo.addr) 43 | glGenBuffers(1, ebo.addr) 44 | 45 | glBindVertexArray(vao) 46 | 47 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 48 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 49 | vertices.addr, GL_STATIC_DRAW) 50 | 51 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 52 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 53 | indices.addr, GL_STATIC_DRAW); 54 | 55 | # Position attribute 56 | var stride = GLsizei(5 * sizeof(GLfloat)) 57 | 58 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 59 | normalized = false, stride, 60 | pointer = cast[pointer](0)) 61 | 62 | glEnableVertexAttribArray(0) 63 | 64 | # TexCoord attribute 65 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 66 | normalized = false, stride, 67 | pointer = cast[pointer](3 * sizeof(GLfloat))) 68 | 69 | glEnableVertexAttribArray(1) 70 | 71 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 72 | glBindVertexArray(GL_NONE) 73 | 74 | # Load and create the textures 75 | 76 | # Texture 1 77 | # --------- 78 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 79 | # object 80 | glGenTextures(1, texture1.addr) 81 | glBindTexture(GL_TEXTURE_2D, texture1) 82 | 83 | # Set the texture wrapping parameters 84 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 86 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 87 | 88 | # Set texture filtering parameters 89 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 90 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 91 | 92 | # Load image 93 | var 94 | width, height, channels: int 95 | data: seq[uint8] 96 | 97 | data = stbi.load("../Data/container.jpg", width, height, channels, 98 | stbi.Default) 99 | 100 | # Create texture 101 | glTexImage2D(GL_TEXTURE_2D, level = 0, 102 | internalFormat = GLint(GL_RGB), 103 | GLsizei(width), GLsizei(height), border = 0, 104 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 105 | cast[pointer](data[0].addr)) 106 | 107 | glGenerateMipmap(GL_TEXTURE_2D) 108 | glBindTexture(GL_TEXTURE_2D, 0) 109 | 110 | # Texture 2 111 | # --------- 112 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 113 | # object 114 | glGenTextures(1, texture2.addr) 115 | glBindTexture(GL_TEXTURE_2D, texture2) 116 | 117 | # Set the texture wrapping parameters 118 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 119 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 120 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 121 | 122 | # Set texture filtering parameters 123 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 124 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 125 | 126 | # Load image 127 | data = stbi.load("../Data/awesomeface.jpg", width, height, channels, 128 | stbi.Default) 129 | 130 | # Create texture 131 | glTexImage2D(GL_TEXTURE_2D, level = 0, 132 | internalFormat = GLint(GL_RGB), 133 | GLsizei(width), GLsizei(height), border = 0, 134 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 135 | cast[pointer](data[0].addr)) 136 | 137 | glGenerateMipmap(GL_TEXTURE_2D) 138 | glBindTexture(GL_TEXTURE_2D, 0) 139 | 140 | 141 | proc cleanup() = 142 | glDeleteVertexArrays(1, vao.addr) 143 | glDeleteBuffers(1, vbo.addr) 144 | glDeleteBuffers(1, ebo.addr) 145 | 146 | 147 | proc draw() = 148 | # Clear the color buffer 149 | glClearColor(0.2, 0.3, 0.3, 1.0) 150 | glClear(GL_COLOR_BUFFER_BIT) 151 | 152 | shaderProgram.use() 153 | 154 | # Bind textures using texture units 155 | glActiveTexture(GL_TEXTURE0) 156 | glBindTexture(GL_TEXTURE_2D, texture1) 157 | shaderProgram.setUniform1i("tex1", 0) 158 | 159 | glActiveTexture(GL_TEXTURE1) 160 | glBindTexture(GL_TEXTURE_2D, texture2) 161 | shaderProgram.setUniform1i("tex2", 1) 162 | 163 | # Draw two containers 164 | glBindVertexArray(vao) 165 | 166 | # Container 1 167 | # Set transform matrix 168 | var transform = mat4(GLfloat(1.0)) 169 | .rotate(getTime(), vec3(GLfloat(0.0), 0.0, 1.0)) 170 | .translate(vec3(GLfloat(0.5), -0.5, 0.0)) 171 | 172 | shaderProgram.setUniformMatrix4fv("transform", transform.caddr) 173 | 174 | # Draw container 175 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 176 | indices = GLvoid(nil)) 177 | 178 | # Container 2 179 | # Set transform matrix 180 | let s = GLfloat(sin(getTime()) * 0.25 + 0.75) # map to [0.5, 1] range 181 | transform = mat4(GLfloat(1.0)) 182 | .translate(vec3(GLfloat(-0.5), 0.5, 0.0)) 183 | .scale(vec3(s, s, s)) 184 | 185 | glUniformMatrix4fv( 186 | glGetUniformLocation(shaderProgram, "transform"), 187 | count = 1, transpose = false, transform.caddr) 188 | 189 | # Draw container 190 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 191 | indices = GLvoid(nil)) 192 | 193 | glBindVertexArray(GL_NONE) 194 | 195 | 196 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 197 | modKeys: set[ModifierKey]) = 198 | 199 | if action != kaUp: 200 | if key == keyEscape: 201 | win.shouldClose = true 202 | 203 | 204 | proc main() = 205 | # Initialise GLFW 206 | glfw.initialize() 207 | 208 | # Create window 209 | var cfg = DefaultOpenglWindowConfig 210 | cfg.size = (w: 800, h: 600) 211 | cfg.title = "05-Transformations/Exercise2" 212 | cfg.resizable = false 213 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 214 | cfg.version = glv33 215 | cfg.profile = opCoreProfile 216 | cfg.forwardCompat = true 217 | 218 | var win = newWindow(cfg) 219 | 220 | # Initialise OpenGL 221 | glfw.makeContextCurrent(win) 222 | 223 | if not gladLoadGL(getProcAddress): 224 | quit "Error initialising OpenGL" 225 | 226 | # Define viewport dimensions 227 | var width, height: int 228 | (width, height) = framebufferSize(win) 229 | glViewport(0, 0, GLint(width), GLint(height)) 230 | 231 | # Turn on vsync (0 turns it off) 232 | glfw.swapInterval(1) 233 | 234 | # Setup callbacks 235 | win.keyCb = keyCb 236 | 237 | # Setup shaders and various OpenGL objects 238 | setup() 239 | 240 | # Game loop 241 | while not win.shouldClose: 242 | glfw.pollEvents() 243 | draw() 244 | glfw.swapBuffers(win) 245 | 246 | # Properly de-allocate all resources once they've outlived their purpose 247 | cleanup() 248 | 249 | # Destroy window 250 | win.destroy() 251 | 252 | # Terminate GLFW, clearing any allocated resources 253 | glfw.terminate() 254 | 255 | 256 | main() 257 | 258 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Exercises/exercise1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Exercises/exercise1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 transform; 9 | 10 | void main() 11 | { 12 | gl_Position = transform * vec4(position, 1.0f); 13 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Exercises/exercise2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Exercises/exercise2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 transform; 9 | 10 | void main() 11 | { 12 | gl_Position = transform * vec4(position, 1.0f); 13 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Transform: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/05-Transformations/Transform -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Transform1.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Transformations 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Texture Coords 16 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 17 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 18 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 19 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 20 | ] 21 | 22 | var indices = [ 23 | GLuint(0), 1, 3, # First Triangle 24 | 1, 2, 3 # Second Triangle 25 | ] 26 | 27 | var 28 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 29 | transform: Mat4[GLfloat] 30 | 31 | 32 | proc setup() = 33 | shaderProgram = createShaderProgramFromFile("transform1.vs", 34 | "transform1.fs") 35 | 36 | glGenVertexArrays(1, vao.addr) 37 | glGenBuffers(1, vbo.addr) 38 | glGenBuffers(1, ebo.addr) 39 | 40 | glBindVertexArray(vao) 41 | 42 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 43 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 44 | vertices.addr, GL_STATIC_DRAW) 45 | 46 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 47 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 48 | indices.addr, GL_STATIC_DRAW); 49 | 50 | # Position attribute 51 | var stride = GLsizei(5 * sizeof(GLfloat)) 52 | 53 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 54 | normalized = false, stride, 55 | pointer = cast[pointer](0)) 56 | 57 | glEnableVertexAttribArray(0) 58 | 59 | # TexCoord attribute 60 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 61 | normalized = false, stride, 62 | pointer = cast[pointer](3 * sizeof(GLfloat))) 63 | 64 | glEnableVertexAttribArray(1) 65 | 66 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 67 | glBindVertexArray(GL_NONE) 68 | 69 | # Load and create the textures 70 | 71 | # Texture 1 72 | # --------- 73 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 74 | # object 75 | glGenTextures(1, texture1.addr) 76 | glBindTexture(GL_TEXTURE_2D, texture1) 77 | 78 | # Set the texture wrapping parameters 79 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 80 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 81 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 82 | 83 | # Set texture filtering parameters 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 86 | 87 | # Load image 88 | var 89 | width, height, channels: int 90 | data: seq[uint8] 91 | 92 | data = stbi.load("Data/container.jpg", width, height, channels, 93 | stbi.Default) 94 | 95 | # Create texture 96 | glTexImage2D(GL_TEXTURE_2D, level = 0, 97 | internalFormat = GLint(GL_RGB), 98 | GLsizei(width), GLsizei(height), border = 0, 99 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 100 | cast[pointer](data[0].addr)) 101 | 102 | glGenerateMipmap(GL_TEXTURE_2D) 103 | glBindTexture(GL_TEXTURE_2D, 0) 104 | 105 | # Texture 2 106 | # --------- 107 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 108 | # object 109 | glGenTextures(1, texture2.addr) 110 | glBindTexture(GL_TEXTURE_2D, texture2) 111 | 112 | # Set the texture wrapping parameters 113 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 114 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 115 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 116 | 117 | # Set texture filtering parameters 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 119 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 120 | 121 | # Load image 122 | data = stbi.load("Data/awesomeface.jpg", width, height, channels, 123 | stbi.Default) 124 | 125 | # Create texture 126 | glTexImage2D(GL_TEXTURE_2D, level = 0, 127 | internalFormat = GLint(GL_RGB), 128 | GLsizei(width), GLsizei(height), border = 0, 129 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 130 | cast[pointer](data[0].addr)) 131 | 132 | glGenerateMipmap(GL_TEXTURE_2D) 133 | glBindTexture(GL_TEXTURE_2D, 0) 134 | 135 | # Transform matrix 136 | transform = mat4(GLfloat(1.0)) 137 | .rotate(degToRad(90.0), vec3(GLfloat(0.0), 0.0, 1.0)) 138 | .scale(vec3(GLfloat(0.5), 0.5, 0.5)) 139 | 140 | 141 | proc cleanup() = 142 | glDeleteVertexArrays(1, vao.addr) 143 | glDeleteBuffers(1, vbo.addr) 144 | glDeleteBuffers(1, ebo.addr) 145 | 146 | 147 | proc draw() = 148 | # Clear the color buffer 149 | glClearColor(0.2, 0.3, 0.3, 1.0) 150 | glClear(GL_COLOR_BUFFER_BIT) 151 | 152 | shaderProgram.use() 153 | 154 | # Bind textures using texture units 155 | glActiveTexture(GL_TEXTURE0) 156 | glBindTexture(GL_TEXTURE_2D, texture1) 157 | shaderProgram.setUniform1i("tex1", 0) 158 | 159 | glActiveTexture(GL_TEXTURE1) 160 | glBindTexture(GL_TEXTURE_2D, texture2) 161 | shaderProgram.setUniform1i("tex2", 1) 162 | 163 | # Set transform matrix 164 | glUniformMatrix4fv( 165 | glGetUniformLocation(shaderProgram, "transform"), 166 | count = 1, transpose = false, transform.caddr) 167 | 168 | # Draw container 169 | glBindVertexArray(vao) 170 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 171 | indices = GLvoid(nil)) 172 | glBindVertexArray(GL_NONE) 173 | 174 | 175 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 176 | modKeys: set[ModifierKey]) = 177 | 178 | if action != kaUp: 179 | if key == keyEscape: 180 | win.shouldClose = true 181 | 182 | 183 | proc main() = 184 | # Initialise GLFW 185 | glfw.initialize() 186 | 187 | # Create window 188 | var cfg = DefaultOpenglWindowConfig 189 | cfg.size = (w: 800, h: 600) 190 | cfg.title = "05-Transformations/Transform1" 191 | cfg.resizable = false 192 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 193 | cfg.version = glv33 194 | cfg.profile = opCoreProfile 195 | cfg.forwardCompat = true 196 | 197 | var win = newWindow(cfg) 198 | 199 | # Initialise OpenGL 200 | glfw.makeContextCurrent(win) 201 | 202 | if not gladLoadGL(getProcAddress): 203 | quit "Error initialising OpenGL" 204 | 205 | # Define viewport dimensions 206 | var width, height: int 207 | (width, height) = framebufferSize(win) 208 | glViewport(0, 0, GLint(width), GLint(height)) 209 | 210 | # Turn on vsync (0 turns it off) 211 | glfw.swapInterval(1) 212 | 213 | # Setup callbacks 214 | win.keyCb = keyCb 215 | 216 | # Setup shaders and various OpenGL objects 217 | setup() 218 | 219 | # Game loop 220 | while not win.shouldClose: 221 | glfw.pollEvents() 222 | draw() 223 | glfw.swapBuffers(win) 224 | 225 | # Properly de-allocate all resources once they've outlived their purpose 226 | cleanup() 227 | 228 | # Destroy window 229 | win.destroy() 230 | 231 | # Terminate GLFW, clearing any allocated resources 232 | glfw.terminate() 233 | 234 | 235 | main() 236 | 237 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/Transform2.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Transformations 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Texture Coords 16 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 17 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 18 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 19 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 20 | ] 21 | 22 | var indices = [ 23 | GLuint(0), 1, 3, # First Triangle 24 | 1, 2, 3 # Second Triangle 25 | ] 26 | 27 | var 28 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 29 | 30 | 31 | proc setup() = 32 | shaderProgram = createShaderProgramFromFile("transform2.vs", 33 | "transform2.fs") 34 | 35 | glGenVertexArrays(1, vao.addr) 36 | glGenBuffers(1, vbo.addr) 37 | glGenBuffers(1, ebo.addr) 38 | 39 | glBindVertexArray(vao) 40 | 41 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 42 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 43 | vertices.addr, GL_STATIC_DRAW) 44 | 45 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 46 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 47 | indices.addr, GL_STATIC_DRAW); 48 | 49 | # Position attribute 50 | var stride = GLsizei(5 * sizeof(GLfloat)) 51 | 52 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 53 | normalized = false, stride, 54 | pointer = cast[pointer](0)) 55 | 56 | glEnableVertexAttribArray(0) 57 | 58 | # TexCoord attribute 59 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 60 | normalized = false, stride, 61 | pointer = cast[pointer](3 * sizeof(GLfloat))) 62 | 63 | glEnableVertexAttribArray(1) 64 | 65 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 66 | glBindVertexArray(GL_NONE) 67 | 68 | # Load and create the textures 69 | 70 | # Texture 1 71 | # --------- 72 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 73 | # object 74 | glGenTextures(1, texture1.addr) 75 | glBindTexture(GL_TEXTURE_2D, texture1) 76 | 77 | # Set the texture wrapping parameters 78 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 79 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 80 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 81 | 82 | # Set texture filtering parameters 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 85 | 86 | # Load image 87 | var 88 | width, height, channels: int 89 | data: seq[uint8] 90 | 91 | data = stbi.load("Data/container.jpg", width, height, channels, 92 | stbi.Default) 93 | 94 | # Create texture 95 | glTexImage2D(GL_TEXTURE_2D, level = 0, 96 | internalFormat = GLint(GL_RGB), 97 | GLsizei(width), GLsizei(height), border = 0, 98 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 99 | cast[pointer](data[0].addr)) 100 | 101 | glGenerateMipmap(GL_TEXTURE_2D) 102 | glBindTexture(GL_TEXTURE_2D, 0) 103 | 104 | # Texture 2 105 | # --------- 106 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 107 | # object 108 | glGenTextures(1, texture2.addr) 109 | glBindTexture(GL_TEXTURE_2D, texture2) 110 | 111 | # Set the texture wrapping parameters 112 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 113 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 114 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 115 | 116 | # Set texture filtering parameters 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 119 | 120 | # Load image 121 | data = stbi.load("Data/awesomeface.jpg", width, height, channels, 122 | stbi.Default) 123 | 124 | # Create texture 125 | glTexImage2D(GL_TEXTURE_2D, level = 0, 126 | internalFormat = GLint(GL_RGB), 127 | GLsizei(width), GLsizei(height), border = 0, 128 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 129 | cast[pointer](data[0].addr)) 130 | 131 | glGenerateMipmap(GL_TEXTURE_2D) 132 | glBindTexture(GL_TEXTURE_2D, 0) 133 | 134 | 135 | proc cleanup() = 136 | glDeleteVertexArrays(1, vao.addr) 137 | glDeleteBuffers(1, vbo.addr) 138 | glDeleteBuffers(1, ebo.addr) 139 | 140 | 141 | proc draw() = 142 | # Clear the color buffer 143 | glClearColor(0.2, 0.3, 0.3, 1.0) 144 | glClear(GL_COLOR_BUFFER_BIT) 145 | 146 | shaderProgram.use() 147 | 148 | # Bind textures using texture units 149 | glActiveTexture(GL_TEXTURE0) 150 | glBindTexture(GL_TEXTURE_2D, texture1) 151 | shaderProgram.setUniform1i("tex1", 0) 152 | 153 | glActiveTexture(GL_TEXTURE1) 154 | glBindTexture(GL_TEXTURE_2D, texture2) 155 | shaderProgram.setUniform1i("tex2", 1) 156 | 157 | # Set transform matrix 158 | var transform = mat4(GLfloat(1.0)) 159 | .translate(vec3(GLfloat(0.5), -0.5, 0.0)) 160 | .rotate(getTime(), vec3(GLfloat(0.0), 0.0, 1.0)) 161 | 162 | shaderProgram.setUniformMatrix4fv("transform", transform.caddr) 163 | 164 | # Draw container 165 | glBindVertexArray(vao) 166 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 167 | indices = GLvoid(nil)) 168 | glBindVertexArray(GL_NONE) 169 | 170 | 171 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 172 | modKeys: set[ModifierKey]) = 173 | 174 | if action != kaUp: 175 | if key == keyEscape: 176 | win.shouldClose = true 177 | 178 | 179 | proc main() = 180 | # Initialise GLFW 181 | glfw.initialize() 182 | 183 | # Create window 184 | var cfg = DefaultOpenglWindowConfig 185 | cfg.size = (w: 800, h: 600) 186 | cfg.title = "05-Transformations/Transform2" 187 | cfg.resizable = false 188 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 189 | cfg.version = glv33 190 | cfg.profile = opCoreProfile 191 | cfg.forwardCompat = true 192 | 193 | var win = newWindow(cfg) 194 | 195 | # Initialise OpenGL 196 | glfw.makeContextCurrent(win) 197 | 198 | if not gladLoadGL(getProcAddress): 199 | quit "Error initialising OpenGL" 200 | 201 | # Define viewport dimensions 202 | var width, height: int 203 | (width, height) = framebufferSize(win) 204 | glViewport(0, 0, GLint(width), GLint(height)) 205 | 206 | # Turn on vsync (0 turns it off) 207 | glfw.swapInterval(1) 208 | 209 | # Setup callbacks 210 | win.keyCb = keyCb 211 | 212 | # Setup shaders and various OpenGL objects 213 | setup() 214 | 215 | # Game loop 216 | while not win.shouldClose: 217 | glfw.pollEvents() 218 | draw() 219 | glfw.swapBuffers(win) 220 | 221 | # Properly de-allocate all resources once they've outlived their purpose 222 | cleanup() 223 | 224 | # Destroy window 225 | win.destroy() 226 | 227 | # Terminate GLFW, clearing any allocated resources 228 | glfw.terminate() 229 | 230 | 231 | main() 232 | 233 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c Transform1.nim && \ 2 | nim c Transform2.nim && \ 3 | nim c Exercises/Exercise1.nim && \ 4 | nim c Exercises/Exercise2.nim 5 | 6 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/transform1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/transform1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 transform; 9 | 10 | void main() 11 | { 12 | gl_Position = transform * vec4(position, 1.0f); 13 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/transform2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/05-Transformations/transform2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 transform; 9 | 10 | void main() 11 | { 12 | gl_Position = transform * vec4(position, 1.0f); 13 | textureCoord = vec2(texCoord.x, 1.0f - texCoord.y); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/Coords1.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Coordinate-Systems 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Texture Coords 16 | GLfloat(0.5), 0.5, 0.0, 1.0, 1.0, # Top Right 17 | 0.5, -0.5, 0.0, 1.0, 0.0, # Bottom Right 18 | -0.5, -0.5, 0.0, 0.0, 0.0, # Bottom Left 19 | -0.5, 0.5, 0.0, 0.0, 1.0 # Top Left 20 | ] 21 | 22 | var indices = [ 23 | GLuint(0), 1, 3, # First Triangle 24 | 1, 2, 3 # Second Triangle 25 | ] 26 | 27 | var 28 | vao, vbo, ebo, texture1, texture2, shaderProgram: GLuint 29 | 30 | const 31 | SCREEN_WIDTH = 800 32 | SCREEN_HEIGHT = 600 33 | 34 | 35 | proc setup() = 36 | shaderProgram = createShaderProgramFromFile("coords1.vs", 37 | "coords1.fs") 38 | 39 | glGenVertexArrays(1, vao.addr) 40 | glGenBuffers(1, vbo.addr) 41 | glGenBuffers(1, ebo.addr) 42 | 43 | glBindVertexArray(vao) 44 | 45 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 46 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 47 | vertices.addr, GL_STATIC_DRAW) 48 | 49 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 50 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size = GLsizeiptr(sizeof(indices)), 51 | indices.addr, GL_STATIC_DRAW); 52 | 53 | # Position attribute 54 | var stride = GLsizei(5 * sizeof(GLfloat)) 55 | 56 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 57 | normalized = false, stride, 58 | pointer = cast[pointer](0)) 59 | 60 | glEnableVertexAttribArray(0) 61 | 62 | # TexCoord attribute 63 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 64 | normalized = false, stride, 65 | pointer = cast[pointer](3 * sizeof(GLfloat))) 66 | 67 | glEnableVertexAttribArray(1) 68 | 69 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 70 | glBindVertexArray(GL_NONE) 71 | 72 | # Load and create the textures 73 | 74 | # Texture 1 75 | # --------- 76 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 77 | # object 78 | glGenTextures(1, texture1.addr) 79 | glBindTexture(GL_TEXTURE_2D, texture1) 80 | 81 | # Set the texture wrapping parameters 82 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 85 | 86 | # Set texture filtering parameters 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 89 | 90 | # Load image 91 | var 92 | width, height, channels: int 93 | data: seq[uint8] 94 | 95 | data = stbi.load("Data/container.jpg", width, height, channels, 96 | stbi.Default) 97 | 98 | # Create texture 99 | glTexImage2D(GL_TEXTURE_2D, level = 0, 100 | internalFormat = GLint(GL_RGB), 101 | GLsizei(width), GLsizei(height), border = 0, 102 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 103 | cast[pointer](data[0].addr)) 104 | 105 | glGenerateMipmap(GL_TEXTURE_2D) 106 | glBindTexture(GL_TEXTURE_2D, 0) 107 | 108 | # Texture 2 109 | # --------- 110 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 111 | # object 112 | glGenTextures(1, texture2.addr) 113 | glBindTexture(GL_TEXTURE_2D, texture2) 114 | 115 | # Set the texture wrapping parameters 116 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 117 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 118 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 119 | 120 | # Set texture filtering parameters 121 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 122 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 123 | 124 | # Load image 125 | data = stbi.load("Data/awesomeface.jpg", width, height, channels, 126 | stbi.Default) 127 | 128 | # Create texture 129 | glTexImage2D(GL_TEXTURE_2D, level = 0, 130 | internalFormat = GLint(GL_RGB), 131 | GLsizei(width), GLsizei(height), border = 0, 132 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 133 | cast[pointer](data[0].addr)) 134 | 135 | glGenerateMipmap(GL_TEXTURE_2D) 136 | glBindTexture(GL_TEXTURE_2D, 0) 137 | 138 | 139 | proc cleanup() = 140 | glDeleteVertexArrays(1, vao.addr) 141 | glDeleteBuffers(1, vbo.addr) 142 | glDeleteBuffers(1, ebo.addr) 143 | 144 | 145 | proc draw() = 146 | # Clear the color buffer 147 | glClearColor(0.2, 0.3, 0.3, 1.0) 148 | glClear(GL_COLOR_BUFFER_BIT) 149 | 150 | shaderProgram.use() 151 | 152 | # Bind textures using texture units 153 | glActiveTexture(GL_TEXTURE0) 154 | glBindTexture(GL_TEXTURE_2D, texture1) 155 | shaderProgram.setUniform1i("tex1", 0) 156 | 157 | glActiveTexture(GL_TEXTURE1) 158 | glBindTexture(GL_TEXTURE_2D, texture2) 159 | shaderProgram.setUniform1i("tex2", 1) 160 | 161 | # Set model matrix 162 | var model = mat4(GLfloat(1.0)) 163 | .rotate(degToRad(-55.0), vec3(GLfloat(1.0), 0.0, 0.0)) 164 | 165 | shaderProgram.setUniformMatrix4fv("model", model.caddr) 166 | 167 | # Set view matrix 168 | var view = mat4(GLfloat(1.0)) 169 | .translate(vec3(GLfloat(0.0), 0.0, -3.0)) 170 | 171 | shaderProgram.setUniformMatrix4fv("view", view.caddr) 172 | 173 | # Set projection matrix 174 | var projection = perspective[GLfloat]( 175 | fovy = degToRad(45.0), 176 | aspect = SCREEN_WIDTH / SCREEN_HEIGHT, 177 | zNear = 0.1, zFar = 100.0) 178 | 179 | shaderProgram.setUniformMatrix4fv("projection", projection.caddr) 180 | 181 | # Draw container 182 | glBindVertexArray(vao) 183 | glDrawElements(GL_TRIANGLES, count = GLsizei(6), GL_UNSIGNED_INT, 184 | indices = GLvoid(nil)) 185 | glBindVertexArray(GL_NONE) 186 | 187 | 188 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 189 | modKeys: set[ModifierKey]) = 190 | 191 | if action != kaUp: 192 | if key == keyEscape: 193 | win.shouldClose = true 194 | 195 | 196 | proc main() = 197 | # Initialise GLFW 198 | glfw.initialize() 199 | 200 | # Create window 201 | var cfg = DefaultOpenglWindowConfig 202 | cfg.size = (w: SCREEN_WIDTH, h: SCREEN_HEIGHT) 203 | cfg.title = "06-CoordinateSystems/Coords1" 204 | cfg.resizable = false 205 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 206 | cfg.version = glv33 207 | cfg.profile = opCoreProfile 208 | cfg.forwardCompat = true 209 | 210 | var win = newWindow(cfg) 211 | 212 | # Initialise OpenGL 213 | glfw.makeContextCurrent(win) 214 | 215 | if not gladLoadGL(getProcAddress): 216 | quit "Error initialising OpenGL" 217 | 218 | # Define viewport dimensions 219 | var width, height: int 220 | (width, height) = framebufferSize(win) 221 | glViewport(0, 0, GLint(width), GLint(height)) 222 | 223 | # Turn on vsync (0 turns it off) 224 | glfw.swapInterval(1) 225 | 226 | # Setup callbacks 227 | win.keyCb = keyCb 228 | 229 | # Setup shaders and various OpenGL objects 230 | setup() 231 | 232 | # Game loop 233 | while not win.shouldClose: 234 | glfw.pollEvents() 235 | draw() 236 | glfw.swapBuffers(win) 237 | 238 | # Properly de-allocate all resources once they've outlived their purpose 239 | cleanup() 240 | 241 | # Destroy window 242 | win.destroy() 243 | 244 | # Terminate GLFW, clearing any allocated resources 245 | glfw.terminate() 246 | 247 | 248 | main() 249 | 250 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/Coords2.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Coordinate-Systems 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | 13 | 14 | var vertices = [ 15 | # Positions # Texture Coords 16 | GLfloat(-0.5),-0.5, -0.5, 0.0, 0.0, 17 | 0.5, -0.5, -0.5, 1.0, 0.0, 18 | 0.5, 0.5, -0.5, 1.0, 1.0, 19 | 0.5, 0.5, -0.5, 1.0, 1.0, 20 | -0.5, 0.5, -0.5, 0.0, 1.0, 21 | -0.5, -0.5, -0.5, 0.0, 0.0, 22 | 23 | -0.5, -0.5, 0.5, 0.0, 0.0, 24 | 0.5, -0.5, 0.5, 1.0, 0.0, 25 | 0.5, 0.5, 0.5, 1.0, 1.0, 26 | 0.5, 0.5, 0.5, 1.0, 1.0, 27 | -0.5, 0.5, 0.5, 0.0, 1.0, 28 | -0.5, -0.5, 0.5, 0.0, 0.0, 29 | 30 | -0.5, 0.5, 0.5, 1.0, 0.0, 31 | -0.5, 0.5, -0.5, 1.0, 1.0, 32 | -0.5, -0.5, -0.5, 0.0, 1.0, 33 | -0.5, -0.5, -0.5, 0.0, 1.0, 34 | -0.5, -0.5, 0.5, 0.0, 0.0, 35 | -0.5, 0.5, 0.5, 1.0, 0.0, 36 | 37 | 0.5, 0.5, 0.5, 1.0, 0.0, 38 | 0.5, 0.5, -0.5, 1.0, 1.0, 39 | 0.5, -0.5, -0.5, 0.0, 1.0, 40 | 0.5, -0.5, -0.5, 0.0, 1.0, 41 | 0.5, -0.5, 0.5, 0.0, 0.0, 42 | 0.5, 0.5, 0.5, 1.0, 0.0, 43 | 44 | -0.5, -0.5, -0.5, 0.0, 1.0, 45 | 0.5, -0.5, -0.5, 1.0, 1.0, 46 | 0.5, -0.5, 0.5, 1.0, 0.0, 47 | 0.5, -0.5, 0.5, 1.0, 0.0, 48 | -0.5, -0.5, 0.5, 0.0, 0.0, 49 | -0.5, -0.5, -0.5, 0.0, 1.0, 50 | 51 | -0.5, 0.5, -0.5, 0.0, 1.0, 52 | 0.5, 0.5, -0.5, 1.0, 1.0, 53 | 0.5, 0.5, 0.5, 1.0, 0.0, 54 | 0.5, 0.5, 0.5, 1.0, 0.0, 55 | -0.5, 0.5, 0.5, 0.0, 0.0, 56 | -0.5, 0.5, -0.5, 0.0, 1.0 57 | ] 58 | 59 | var 60 | vao, vbo, texture1, texture2, shaderProgram: GLuint 61 | 62 | const 63 | SCREEN_WIDTH = 800 64 | SCREEN_HEIGHT = 600 65 | 66 | 67 | proc setup() = 68 | shaderProgram = createShaderProgramFromFile("coords2.vs", 69 | "coords2.fs") 70 | 71 | glGenVertexArrays(1, vao.addr) 72 | glGenBuffers(1, vbo.addr) 73 | 74 | glBindVertexArray(vao) 75 | 76 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 77 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 78 | vertices.addr, GL_STATIC_DRAW) 79 | 80 | # Position attribute 81 | var stride = GLsizei(5 * sizeof(GLfloat)) 82 | 83 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 84 | normalized = false, stride, 85 | pointer = cast[pointer](0)) 86 | 87 | glEnableVertexAttribArray(0) 88 | 89 | # TexCoord attribute 90 | glVertexAttribPointer(index = 1, size = 2, type = cGL_FLOAT, 91 | normalized = false, stride, 92 | pointer = cast[pointer](3 * sizeof(GLfloat))) 93 | 94 | glEnableVertexAttribArray(1) 95 | 96 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 97 | glBindVertexArray(GL_NONE) 98 | 99 | # Load and create the textures 100 | 101 | # Texture 1 102 | # --------- 103 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 104 | # object 105 | glGenTextures(1, texture1.addr) 106 | glBindTexture(GL_TEXTURE_2D, texture1) 107 | 108 | # Set the texture wrapping parameters 109 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 110 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 111 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 112 | 113 | # Set texture filtering parameters 114 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_NEAREST)) 115 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_NEAREST)) 116 | 117 | # Load image 118 | var 119 | width, height, channels: int 120 | data: seq[uint8] 121 | 122 | data = stbi.load("Data/container.jpg", width, height, channels, 123 | stbi.Default) 124 | 125 | # Create texture 126 | glTexImage2D(GL_TEXTURE_2D, level = 0, 127 | internalFormat = GLint(GL_RGB), 128 | GLsizei(width), GLsizei(height), border = 0, 129 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 130 | cast[pointer](data[0].addr)) 131 | 132 | glGenerateMipmap(GL_TEXTURE_2D) 133 | glBindTexture(GL_TEXTURE_2D, 0) 134 | 135 | # Texture 2 136 | # --------- 137 | # All upcoming GL_TEXTURE_2D operations now have effect on this texture 138 | # object 139 | glGenTextures(1, texture2.addr) 140 | glBindTexture(GL_TEXTURE_2D, texture2) 141 | 142 | # Set the texture wrapping parameters 143 | # Set texture wrapping to GL_REPEAT (usually basic wrapping method) 144 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLint(GL_REPEAT)) 145 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLint(GL_REPEAT)) 146 | 147 | # Set texture filtering parameters 148 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(GL_LINEAR)) 149 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(GL_LINEAR)) 150 | 151 | # Load image 152 | data = stbi.load("Data/awesomeface.jpg", width, height, channels, 153 | stbi.Default) 154 | 155 | # Create texture 156 | glTexImage2D(GL_TEXTURE_2D, level = 0, 157 | internalFormat = GLint(GL_RGB), 158 | GLsizei(width), GLsizei(height), border = 0, 159 | format = GL_RGB, type = GL_UNSIGNED_BYTE, 160 | cast[pointer](data[0].addr)) 161 | 162 | glGenerateMipmap(GL_TEXTURE_2D) 163 | glBindTexture(GL_TEXTURE_2D, 0) 164 | 165 | # Enable depth test 166 | glEnable(GL_DEPTH_TEST) 167 | 168 | 169 | proc cleanup() = 170 | glDeleteVertexArrays(1, vao.addr) 171 | glDeleteBuffers(1, vbo.addr) 172 | 173 | 174 | proc draw() = 175 | # Clear the color buffer 176 | glClearColor(0.2, 0.3, 0.3, 1.0) 177 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 178 | 179 | shaderProgram.use() 180 | 181 | # Bind textures using texture units 182 | glActiveTexture(GL_TEXTURE0) 183 | glBindTexture(GL_TEXTURE_2D, texture1) 184 | shaderProgram.setUniform1i("tex1", 0) 185 | 186 | glActiveTexture(GL_TEXTURE1) 187 | glBindTexture(GL_TEXTURE_2D, texture2) 188 | shaderProgram.setUniform1i("tex2", 1) 189 | 190 | # Set model matrix 191 | var model = mat4(GLfloat(1.0)) 192 | .rotate(getTime(), vec3(GLfloat(0.5), 1.0, 0.0)) 193 | 194 | shaderProgram.setUniformMatrix4fv("model", model.caddr) 195 | 196 | # Set view matrix 197 | var view = mat4(GLfloat(1.0)) 198 | .translate(vec3(GLfloat(0.0), 0.0, -3.0)) 199 | 200 | shaderProgram.setUniformMatrix4fv("view", view.caddr) 201 | 202 | # Set projection matrix 203 | var projection = perspective[GLfloat]( 204 | fovy = degToRad(45.0), 205 | aspect = SCREEN_WIDTH / SCREEN_HEIGHT, 206 | zNear = 0.1, zFar = 100.0) 207 | 208 | shaderProgram.setUniformMatrix4fv("projection", projection.caddr) 209 | 210 | # Draw container 211 | glBindVertexArray(vao) 212 | glDrawArrays(GL_TRIANGLES, first = 0, count = 36) 213 | glBindVertexArray(GL_NONE) 214 | 215 | 216 | proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction, 217 | modKeys: set[ModifierKey]) = 218 | 219 | if action != kaUp: 220 | if key == keyEscape: 221 | win.shouldClose = true 222 | 223 | 224 | proc main() = 225 | # Initialise GLFW 226 | glfw.initialize() 227 | 228 | # Create window 229 | var cfg = DefaultOpenglWindowConfig 230 | cfg.size = (w: SCREEN_WIDTH, h: SCREEN_HEIGHT) 231 | cfg.title = "06-CoordinateSystems/Coords2" 232 | cfg.resizable = false 233 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 234 | cfg.version = glv33 235 | cfg.profile = opCoreProfile 236 | cfg.forwardCompat = true 237 | 238 | var win = newWindow(cfg) 239 | 240 | # Initialise OpenGL 241 | glfw.makeContextCurrent(win) 242 | 243 | if not gladLoadGL(getProcAddress): 244 | quit "Error initialising OpenGL" 245 | 246 | # Define viewport dimensions 247 | var width, height: int 248 | (width, height) = framebufferSize(win) 249 | glViewport(0, 0, GLint(width), GLint(height)) 250 | 251 | # Turn on vsync (0 turns it off) 252 | glfw.swapInterval(1) 253 | 254 | # Setup callbacks 255 | win.keyCb = keyCb 256 | 257 | # Setup shaders and various OpenGL objects 258 | setup() 259 | 260 | # Game loop 261 | while not win.shouldClose: 262 | glfw.pollEvents() 263 | draw() 264 | glfw.swapBuffers(win) 265 | 266 | # Properly de-allocate all resources once they've outlived their purpose 267 | cleanup() 268 | 269 | # Destroy window 270 | win.destroy() 271 | 272 | # Terminate GLFW, clearing any allocated resources 273 | glfw.terminate() 274 | 275 | 276 | main() 277 | 278 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/Data/awesomeface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/06-CoordinateSystems/Data/awesomeface.jpg -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/Data/container.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/06-CoordinateSystems/Data/container.jpg -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/Exercises/exercise3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/Exercises/exercise3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c Coords1.nim && \ 2 | nim c Coords2.nim && \ 3 | nim c Coords3.nim && \ 4 | nim c Exercises/Exercise3.nim 5 | 6 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/coords1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/coords1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/coords2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/coords2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/coords3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/06-CoordinateSystems/coords3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/Data/awesomeface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/07-Camera/Data/awesomeface.jpg -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/Data/container.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnnovak/learnopengl-nim/b1b9ff2633fb564d9c2c887197be3bcd2843f308/01-GettingStarted/07-Camera/Data/container.jpg -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c Camera1.nim && \ 2 | nim c Camera2.nim && \ 3 | nim c Camera3.nim && \ 4 | nim c Camera4.nim 5 | 6 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera4.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec2 textureCoord; 4 | 5 | out vec4 color; 6 | 7 | uniform sampler2D tex1; 8 | uniform sampler2D tex2; 9 | 10 | void main() 11 | { 12 | color = mix(texture(tex1, textureCoord), 13 | texture(tex2, textureCoord), 0.2); 14 | } 15 | -------------------------------------------------------------------------------- /01-GettingStarted/07-Camera/camera4.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | void main() 13 | { 14 | gl_Position = projection * view * model * vec4(position, 1.0); 15 | textureCoord = vec2(texCoord.x, 1.0 - texCoord.y); 16 | } 17 | -------------------------------------------------------------------------------- /01-GettingStarted/build-all.sh: -------------------------------------------------------------------------------- 1 | (cd 01-HelloWindow && ./build-all.sh) && \ 2 | (cd 02-HelloTriangle && ./build-all.sh) && \ 3 | (cd 03-Shaders && ./build-all.sh) && \ 4 | (cd 04-Textures && ./build-all.sh) && \ 5 | (cd 05-Transformations && ./build-all.sh) && \ 6 | (cd 06-CoordinateSystems && ./build-all.sh) && \ 7 | (cd 07-Camera && ./build-all.sh) 8 | 9 | -------------------------------------------------------------------------------- /02-Lighting/01-Colors/Colors.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Camera 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | import common/fpscamera 13 | 14 | 15 | var vertices = [ 16 | # Positions 17 | GLfloat(-0.5),-0.5, -0.5, 18 | 0.5, -0.5, -0.5, 19 | 0.5, 0.5, -0.5, 20 | 0.5, 0.5, -0.5, 21 | -0.5, 0.5, -0.5, 22 | -0.5, -0.5, -0.5, 23 | 24 | -0.5, -0.5, 0.5, 25 | 0.5, -0.5, 0.5, 26 | 0.5, 0.5, 0.5, 27 | 0.5, 0.5, 0.5, 28 | -0.5, 0.5, 0.5, 29 | -0.5, -0.5, 0.5, 30 | 31 | -0.5, 0.5, 0.5, 32 | -0.5, 0.5, -0.5, 33 | -0.5, -0.5, -0.5, 34 | -0.5, -0.5, -0.5, 35 | -0.5, -0.5, 0.5, 36 | -0.5, 0.5, 0.5, 37 | 38 | 0.5, 0.5, 0.5, 39 | 0.5, 0.5, -0.5, 40 | 0.5, -0.5, -0.5, 41 | 0.5, -0.5, -0.5, 42 | 0.5, -0.5, 0.5, 43 | 0.5, 0.5, 0.5, 44 | 45 | -0.5, -0.5, -0.5, 46 | 0.5, -0.5, -0.5, 47 | 0.5, -0.5, 0.5, 48 | 0.5, -0.5, 0.5, 49 | -0.5, -0.5, 0.5, 50 | -0.5, -0.5, -0.5, 51 | 52 | -0.5, 0.5, -0.5, 53 | 0.5, 0.5, -0.5, 54 | 0.5, 0.5, 0.5, 55 | 0.5, 0.5, 0.5, 56 | -0.5, 0.5, 0.5, 57 | -0.5, 0.5, -0.5 58 | ] 59 | 60 | var 61 | containerVao, lightVao, vbo, lightingShader, lampShader: GLuint 62 | 63 | const 64 | SCREEN_WIDTH = 800 65 | SCREEN_HEIGHT = 600 66 | 67 | var 68 | lastXPos = 0.0 69 | lastYPos = 0.0 70 | lastFrameTime = 0.0 71 | 72 | let 73 | camera = newFpsCamera(pos = vec3[GLfloat](-4.0, 0.0, 3.0), 74 | yaw = 60.0, pitch = 0.0) 75 | 76 | lightPos = vec3[GLfloat](1.2, 1.0, 2.0) 77 | 78 | 79 | proc setup() = 80 | lightingShader = createShaderProgramFromFile("colors.vs", "colors.fs") 81 | lampShader = createShaderProgramFromFile("lamp.vs", "lamp.fs") 82 | 83 | glGenBuffers(1, vbo.addr) 84 | 85 | # Configure the container object's VAO 86 | glGenVertexArrays(1, containerVao.addr) 87 | glBindVertexArray(containerVao) 88 | 89 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 90 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 91 | vertices.addr, GL_STATIC_DRAW) 92 | 93 | # Position attribute 94 | var stride = GLsizei(3 * sizeof(GLfloat)) 95 | 96 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 97 | normalized = false, stride, 98 | pointer = cast[pointer](0)) 99 | 100 | glEnableVertexAttribArray(0) 101 | 102 | # Configure the light object's VAO (VBO stays the same; the vertices are the 103 | # same for the light object which is also a 3D cube) 104 | glGenVertexArrays(1, lightVao.addr) 105 | glBindVertexArray(lightVao) 106 | 107 | # We only need to bind to the VBO (to link it with glVertexAttribPointer), 108 | # no need to fill it; the VBO's data already contains all we need (it's 109 | # already bound, but we do it again for educational purposes) 110 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 111 | 112 | # Position attribute 113 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 114 | normalized = false, stride, 115 | pointer = cast[pointer](0)) 116 | 117 | glEnableVertexAttribArray(0) 118 | 119 | # Unbind VBO and VAO 120 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 121 | glBindVertexArray(GL_NONE) 122 | 123 | # Enable depth test 124 | glEnable(GL_DEPTH_TEST) 125 | 126 | 127 | proc cleanup() = 128 | glDeleteVertexArrays(1, containerVao.addr) 129 | glDeleteBuffers(1, vbo.addr) 130 | 131 | 132 | proc draw() = 133 | # Clear the color buffer 134 | glClearColor(0.1, 0.1, 0.1, 1.0) 135 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 136 | 137 | # Draw container 138 | lightingShader.use() 139 | lightingShader.setUniform3f("objectColor", 1.0, 0.5, 0.3) 140 | lightingShader.setUniform3f("lightColor", 1.0, 1.0, 1.0) 141 | 142 | # Set model matrix 143 | var model = mat4(GLfloat(1.0)) 144 | lightingShader.setUniformMatrix4fv("model", model.caddr) 145 | 146 | # Set view matrix 147 | var view = camera.getViewMatrix() 148 | lightingShader.setUniformMatrix4fv("view", view.caddr) 149 | 150 | # Set projection matrix 151 | var projection = perspective[GLfloat]( 152 | fovy = degToRad(camera.fov), 153 | aspect = SCREEN_WIDTH / SCREEN_HEIGHT, 154 | zNear = 0.1, zFar = 100.0) 155 | 156 | lightingShader.setUniformMatrix4fv("projection", projection.caddr) 157 | 158 | glBindVertexArray(containerVao) 159 | glDrawArrays(GL_TRIANGLES, first = 0, count = 36) 160 | 161 | # Draw lamp 162 | lampShader.use() 163 | lampShader.setUniformMatrix4fv("projection", projection.caddr) 164 | lampShader.setUniformMatrix4fv("view", view.caddr) 165 | 166 | model = mat4(GLfloat(1.0)) 167 | .translate(lightPos) 168 | .scale(vec3[GLfloat](0.2)) 169 | 170 | lampShader.setUniformMatrix4fv("model", model.caddr) 171 | 172 | glBindVertexArray(lightVao) 173 | glDrawArrays(GL_TRIANGLES, first = 0, count = 36) 174 | 175 | # Unvind VAO 176 | glBindVertexArray(GL_NONE) 177 | 178 | 179 | proc cursorPosCb(win: Window, pos: tuple[x, y: float64]) = 180 | let 181 | xoffs = pos.x - lastXPos 182 | yoffs = pos.y - lastYPos 183 | 184 | lastXPos = pos.x 185 | lastYPos = pos.y 186 | 187 | camera.headLook(xoffs, yoffs) 188 | 189 | 190 | proc scrollCb(win: Window, offset: tuple[x, y: float64]) = 191 | camera.zoom(offset.y) 192 | 193 | 194 | proc processInput(win: Window) = 195 | let 196 | currFrameTime = getTime() 197 | dt = currFrameTime - lastFrameTime 198 | 199 | lastFrameTime = currFrameTime 200 | 201 | if win.isKeyDown(keyEscape): 202 | win.shouldClose = true 203 | 204 | if win.isKeyDown(keyW): 205 | camera.move(cmForward, dt) 206 | if win.isKeyDown(keyS): 207 | camera.move(cmBackward, dt) 208 | if win.isKeyDown(keyA): 209 | camera.move(cmLeft, dt) 210 | if win.isKeyDown(keyD): 211 | camera.move(cmRight, dt) 212 | 213 | 214 | proc main() = 215 | # Initialise GLFW 216 | glfw.initialize() 217 | 218 | # Create window 219 | var cfg = DefaultOpenglWindowConfig 220 | cfg.size = (w: SCREEN_WIDTH, h: SCREEN_HEIGHT) 221 | cfg.title = "01-Colors/Colors" 222 | cfg.resizable = false 223 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 224 | cfg.version = glv33 225 | cfg.profile = opCoreProfile 226 | cfg.forwardCompat = true 227 | 228 | var win = newWindow(cfg) 229 | 230 | # Initialise OpenGL 231 | glfw.makeContextCurrent(win) 232 | 233 | if not gladLoadGL(getProcAddress): 234 | quit "Error initialising OpenGL" 235 | 236 | # Define viewport dimensions 237 | var width, height: int 238 | (width, height) = framebufferSize(win) 239 | glViewport(0, 0, GLint(width), GLint(height)) 240 | 241 | # Hide and capture mouse cursor 242 | win.cursorMode = cmDisabled 243 | 244 | # Turn on vsync (0 turns it off) 245 | glfw.swapInterval(1) 246 | 247 | # Setup callbacks 248 | win.cursorPositionCb = cursorPosCb 249 | win.scrollCb = scrollCb 250 | 251 | # Setup shaders and various OpenGL objects 252 | setup() 253 | 254 | # Game loop 255 | while not win.shouldClose: 256 | glfw.pollEvents() 257 | processInput(win) 258 | draw() 259 | glfw.swapBuffers(win) 260 | 261 | # Properly de-allocate all resources once they've outlived their purpose 262 | cleanup() 263 | 264 | # Destroy window 265 | win.destroy() 266 | 267 | # Terminate GLFW, clearing any allocated resources 268 | glfw.terminate() 269 | 270 | 271 | main() 272 | 273 | -------------------------------------------------------------------------------- /02-Lighting/01-Colors/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c Colors.nim 2 | 3 | -------------------------------------------------------------------------------- /02-Lighting/01-Colors/colors.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | out vec4 color; 4 | 5 | uniform vec3 objectColor; 6 | uniform vec3 lightColor; 7 | 8 | void main() 9 | { 10 | color = vec4(objectColor * lightColor, 1.0); 11 | } 12 | -------------------------------------------------------------------------------- /02-Lighting/01-Colors/colors.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | 5 | uniform mat4 model; 6 | uniform mat4 view; 7 | uniform mat4 projection; 8 | 9 | void main() 10 | { 11 | gl_Position = projection * view * model * vec4(position, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /02-Lighting/01-Colors/lamp.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | out vec4 color; 4 | 5 | void main() 6 | { 7 | color = vec4(1.0); 8 | } 9 | -------------------------------------------------------------------------------- /02-Lighting/01-Colors/lamp.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | 5 | uniform mat4 model; 6 | uniform mat4 view; 7 | uniform mat4 projection; 8 | 9 | void main() 10 | { 11 | gl_Position = projection * view * model * vec4(position, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/BasicLighting1.nim: -------------------------------------------------------------------------------- 1 | # Read the accompanying article at 2 | # https://learnopengl.com/#!Getting-started/Camera 3 | 4 | import math 5 | 6 | import glm 7 | import glad/gl 8 | import glfw 9 | import stb_image/read as stbi 10 | 11 | import common/shader 12 | import common/fpscamera 13 | 14 | 15 | var vertices = [ 16 | # Positions # Normals 17 | GLfloat(-0.5),-0.5, -0.5, 0.0, 0.0, -1.0, 18 | 0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 19 | 0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 20 | 0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 21 | -0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 22 | -0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 23 | 24 | -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 25 | 0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 26 | 0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 27 | 0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 28 | -0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 29 | -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 30 | 31 | -0.5, 0.5, 0.5, -1.0, 0.0, 0.0, 32 | -0.5, 0.5, -0.5, -1.0, 0.0, 0.0, 33 | -0.5, -0.5, -0.5, -1.0, 0.0, 0.0, 34 | -0.5, -0.5, -0.5, -1.0, 0.0, 0.0, 35 | -0.5, -0.5, 0.5, -1.0, 0.0, 0.0, 36 | -0.5, 0.5, 0.5, -1.0, 0.0, 0.0, 37 | 38 | 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 39 | 0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 40 | 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 41 | 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 42 | 0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 43 | 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 44 | 45 | -0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 46 | 0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 47 | 0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 48 | 0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 49 | -0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 50 | -0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 51 | 52 | -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 53 | 0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 54 | 0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 55 | 0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 56 | -0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 57 | -0.5, 0.5, -0.5, 0.0, 1.0, 0.0 58 | ] 59 | 60 | var 61 | containerVao, lightVao, vbo, lightingShader, lampShader: GLuint 62 | 63 | const 64 | SCREEN_WIDTH = 800 65 | SCREEN_HEIGHT = 600 66 | 67 | var 68 | lastXPos = 0.0 69 | lastYPos = 0.0 70 | lastFrameTime = 0.0 71 | 72 | camera = newFpsCamera(pos = vec3[GLfloat](-4.0, 0.0, 3.0), 73 | yaw = 60.0, pitch = 0.0) 74 | 75 | lightPos = vec3[GLfloat](1.2, 1.0, 2.0) 76 | 77 | 78 | proc setup() = 79 | lightingShader = createShaderProgramFromFile("basiclighting1.vs", 80 | "basiclighting1.fs") 81 | lampShader = createShaderProgramFromFile("lamp.vs", "lamp.fs") 82 | 83 | glGenBuffers(1, vbo.addr) 84 | 85 | # Configure the container object's VAO 86 | glGenVertexArrays(1, containerVao.addr) 87 | glBindVertexArray(containerVao) 88 | 89 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 90 | glBufferData(GL_ARRAY_BUFFER, size = GLsizeiptr(sizeof(vertices)), 91 | vertices.addr, GL_STATIC_DRAW) 92 | 93 | # Position attribute 94 | var stride = GLsizei(6 * sizeof(GLfloat)) 95 | 96 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 97 | normalized = false, stride, 98 | pointer = cast[pointer](0)) 99 | 100 | glEnableVertexAttribArray(0) 101 | 102 | # Normal attribute 103 | stride = GLsizei(6 * sizeof(GLfloat)) 104 | 105 | glVertexAttribPointer(index = 1, size = 3, type = cGL_FLOAT, 106 | normalized = false, stride, 107 | pointer = cast[pointer](3 * sizeof(GLfloat))) 108 | 109 | glEnableVertexAttribArray(1) 110 | 111 | # Configure the light object's VAO (VBO stays the same; the vertices are the 112 | # same for the light object which is also a 3D cube) 113 | glGenVertexArrays(1, lightVao.addr) 114 | glBindVertexArray(lightVao) 115 | 116 | # We only need to bind to the VBO (to link it with glVertexAttribPointer), 117 | # no need to fill it; the VBO's data already contains all we need (it's 118 | # already bound, but we do it again for educational purposes) 119 | glBindBuffer(GL_ARRAY_BUFFER, vbo) 120 | 121 | # Position attribute 122 | glVertexAttribPointer(index = 0, size = 3, type = cGL_FLOAT, 123 | normalized = false, stride, 124 | pointer = cast[pointer](0)) 125 | 126 | glEnableVertexAttribArray(0) 127 | 128 | # Unbind VBO and VAO 129 | glBindBuffer(GL_ARRAY_BUFFER, GL_NONE) 130 | glBindVertexArray(GL_NONE) 131 | 132 | # Enable depth test 133 | glEnable(GL_DEPTH_TEST) 134 | 135 | 136 | proc cleanup() = 137 | glDeleteVertexArrays(1, containerVao.addr) 138 | glDeleteBuffers(1, vbo.addr) 139 | 140 | 141 | proc draw() = 142 | # Clear the color buffer 143 | glClearColor(0.1, 0.1, 0.1, 1.0) 144 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 145 | 146 | # Draw container 147 | lightingShader.use() 148 | lightingShader.setUniform3f("objectColor", 1.0, 0.5, 0.3) 149 | lightingShader.setUniform3f("lightColor", 1.0, 1.0, 1.0) 150 | lightingShader.setUniform3fv("lightPos", lightPos) 151 | 152 | # Set model matrix 153 | var model = mat4(GLfloat(1.0)) 154 | lightingShader.setUniformMatrix4fv("model", model.caddr) 155 | 156 | # Set view matrix 157 | var view = camera.getViewMatrix() 158 | lightingShader.setUniformMatrix4fv("view", view.caddr) 159 | 160 | # Set projection matrix 161 | var projection = perspective[GLfloat]( 162 | fovy = degToRad(camera.fov), 163 | aspect = SCREEN_WIDTH / SCREEN_HEIGHT, 164 | zNear = 0.1, zFar = 100.0) 165 | 166 | lightingShader.setUniformMatrix4fv("projection", projection.caddr) 167 | 168 | glBindVertexArray(containerVao) 169 | glDrawArrays(GL_TRIANGLES, first = 0, count = 36) 170 | 171 | # Draw lamp 172 | lampShader.use() 173 | lampShader.setUniformMatrix4fv("projection", projection.caddr) 174 | lampShader.setUniformMatrix4fv("view", view.caddr) 175 | 176 | model = mat4(GLfloat(1.0)) 177 | .translate(lightPos) 178 | .scale(vec3[GLfloat](0.2)) 179 | 180 | lampShader.setUniformMatrix4fv("model", model.caddr) 181 | 182 | glBindVertexArray(lightVao) 183 | glDrawArrays(GL_TRIANGLES, first = 0, count = 36) 184 | 185 | # Unvind VAO 186 | glBindVertexArray(GL_NONE) 187 | 188 | 189 | proc cursorPosCb(win: Window, pos: tuple[x, y: float64]) = 190 | let 191 | xoffs = pos.x - lastXPos 192 | yoffs = pos.y - lastYPos 193 | 194 | lastXPos = pos.x 195 | lastYPos = pos.y 196 | 197 | camera.headLook(xoffs, yoffs) 198 | 199 | 200 | proc scrollCb(win: Window, offset: tuple[x, y: float64]) = 201 | camera.zoom(offset.y) 202 | 203 | 204 | proc processInput(win: Window) = 205 | let 206 | currFrameTime = getTime() 207 | dt = currFrameTime - lastFrameTime 208 | 209 | lastFrameTime = currFrameTime 210 | 211 | if win.isKeyDown(keyEscape): 212 | win.shouldClose = true 213 | 214 | if win.isKeyDown(keyW): 215 | camera.move(cmForward, dt) 216 | if win.isKeyDown(keyS): 217 | camera.move(cmBackward, dt) 218 | if win.isKeyDown(keyA): 219 | camera.move(cmLeft, dt) 220 | if win.isKeyDown(keyD): 221 | camera.move(cmRight, dt) 222 | 223 | 224 | proc main() = 225 | # Initialise GLFW 226 | glfw.initialize() 227 | 228 | # Create window 229 | var cfg = DefaultOpenglWindowConfig 230 | cfg.size = (w: SCREEN_WIDTH, h: SCREEN_HEIGHT) 231 | cfg.title = "02-BasicLighting/BasicLighting1" 232 | cfg.resizable = false 233 | cfg.bits = (r: 8, g: 8, b: 8, a: 8, stencil: 8, depth: 16) 234 | cfg.version = glv33 235 | cfg.profile = opCoreProfile 236 | cfg.forwardCompat = true 237 | 238 | var win = newWindow(cfg) 239 | 240 | # Initialise OpenGL 241 | glfw.makeContextCurrent(win) 242 | 243 | if not gladLoadGL(getProcAddress): 244 | quit "Error initialising OpenGL" 245 | 246 | # Define viewport dimensions 247 | var width, height: int 248 | (width, height) = framebufferSize(win) 249 | glViewport(0, 0, GLint(width), GLint(height)) 250 | 251 | # Hide and capture mouse cursor 252 | win.cursorMode = cmDisabled 253 | 254 | # Turn on vsync (0 turns it off) 255 | glfw.swapInterval(1) 256 | 257 | # Setup callbacks 258 | win.cursorPositionCb = cursorPosCb 259 | win.scrollCb = scrollCb 260 | 261 | # Setup shaders and various OpenGL objects 262 | setup() 263 | 264 | # Game loop 265 | while not win.shouldClose: 266 | glfw.pollEvents() 267 | processInput(win) 268 | draw() 269 | glfw.swapBuffers(win) 270 | 271 | # Properly de-allocate all resources once they've outlived their purpose 272 | cleanup() 273 | 274 | # Destroy window 275 | win.destroy() 276 | 277 | # Terminate GLFW, clearing any allocated resources 278 | glfw.terminate() 279 | 280 | 281 | main() 282 | 283 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/Exercises/exercise1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 normal; 4 | in vec3 fragPos; 5 | 6 | out vec4 color; 7 | 8 | uniform vec3 lightPos; 9 | uniform vec3 viewPos; 10 | uniform vec3 lightColor; 11 | uniform vec3 objectColor; 12 | 13 | void main() 14 | { 15 | float ambientStrength = 0.1; 16 | float specularStrength = 0.5; 17 | 18 | vec3 lightDir = normalize(lightPos - fragPos); 19 | vec3 viewDir = normalize(viewPos - fragPos); 20 | vec3 reflectDir = reflect(-lightDir, normal); 21 | 22 | vec3 ambient = ambientStrength * lightColor; 23 | 24 | float diff = max(dot(normal, lightDir), 0.0); 25 | vec3 diffuse = diff * lightColor; 26 | 27 | float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); 28 | vec3 specular = specularStrength * spec * lightColor; 29 | 30 | vec3 col = (ambient + diffuse + specular) * objectColor; 31 | color = vec4(col, 1.0); 32 | } 33 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/Exercises/exercise1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 aPos; 4 | layout (location = 1) in vec3 aNormal; 5 | 6 | out vec3 normal; 7 | out vec3 fragPos; 8 | 9 | uniform mat4 model; 10 | uniform mat4 view; 11 | uniform mat4 projection; 12 | 13 | void main() 14 | { 15 | fragPos = vec3(model * vec4(aPos, 1.0)); 16 | 17 | // Calculating the inverse tranpose of the model matrix should be done 18 | // once on the CPU and sent to the shader via an uniform; this is for 19 | // learning purposes only. 20 | normal = mat3(transpose(inverse(model))) * aNormal; 21 | 22 | gl_Position = projection * view * vec4(fragPos, 1.0); 23 | } 24 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/Exercises/exercise3.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 normal; 4 | in vec3 fragPos; 5 | 6 | out vec4 color; 7 | 8 | uniform vec3 lightPos; 9 | uniform vec3 lightColor; 10 | uniform vec3 objectColor; 11 | 12 | uniform float ambientStrength; 13 | uniform float specularStrength; 14 | uniform float diffuseStrength; 15 | uniform float shininessFactor; 16 | 17 | void main() 18 | { 19 | vec3 lightPos = vec3(0.0, 0.0, 0.0); 20 | vec3 lightDir = normalize(lightPos - fragPos); 21 | vec3 viewDir = normalize(viewPos - fragPos); 22 | vec3 reflectDir = reflect(-lightDir, normal); 23 | 24 | vec3 ambient = ambientStrength * lightColor; 25 | 26 | float diff = max(dot(normal, lightDir), 0.0); 27 | vec3 diffuse = diffuseStrength * diff * lightColor; 28 | 29 | float spec = pow(max(dot(viewDir, reflectDir), 0.0), 30 | shininessFactor); 31 | 32 | vec3 specular = specularStrength * spec * lightColor; 33 | 34 | vec3 col = (ambient + diffuse + specular) * objectColor; 35 | color = vec4(col, 1.0); 36 | } 37 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/Exercises/exercise3.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 aPos; 4 | layout (location = 1) in vec3 aNormal; 5 | 6 | out vec3 normal; 7 | out vec3 fragPos; 8 | 9 | uniform mat4 model; 10 | uniform mat4 view; 11 | uniform mat4 projection; 12 | 13 | void main() 14 | { 15 | mat4 modelView = view * model 16 | fragPos = vec3(modelView * vec4(aPos, 1.0)); 17 | 18 | // Calculating the inverse transpose of the model-view matrix should be 19 | // done once on the CPU and sent to the shader via an uniform; this is for 20 | // learning purposes only. 21 | normal = mat3(transpose(inverse(modelView))) * aNormal; 22 | 23 | gl_Position = projection * vec4(fragPos, 1.0); 24 | } 25 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/Exercises/lamp.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | out vec4 color; 4 | 5 | void main() 6 | { 7 | color = vec4(1.0); 8 | } 9 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/Exercises/lamp.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | 5 | uniform mat4 model; 6 | uniform mat4 view; 7 | uniform mat4 projection; 8 | 9 | void main() 10 | { 11 | gl_Position = projection * view * model * vec4(position, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/basiclighting1.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 normal; 4 | in vec3 fragPos; 5 | 6 | out vec4 color; 7 | 8 | uniform vec3 objectColor; 9 | uniform vec3 lightColor; 10 | uniform vec3 lightPos; 11 | 12 | void main() 13 | { 14 | float ambientStrength = 0.1; 15 | vec3 ambient = ambientStrength * lightColor; 16 | 17 | vec3 lightDir = normalize(lightPos - fragPos); 18 | 19 | float diff = max(dot(normal, lightDir), 0.0); 20 | vec3 diffuse = diff * lightColor; 21 | 22 | vec3 col = (ambient + diffuse) * objectColor; 23 | color = vec4(col, 1.0); 24 | } 25 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/basiclighting1.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 aPosition; 4 | layout (location = 1) in vec3 aNormal; 5 | 6 | out vec3 normal; 7 | out vec3 fragPos; 8 | 9 | uniform mat4 model; 10 | uniform mat4 view; 11 | uniform mat4 projection; 12 | 13 | void main() 14 | { 15 | gl_Position = projection * view * model * vec4(aPosition, 1.0); 16 | fragPos = vec3(model * vec4(aNormal, 1.0)); 17 | 18 | // Calculating the inverse transpose of the model matrix should be done 19 | // once on the CPU and sent to the shader via an uniform; this is for 20 | // learning purposes only. 21 | normal = mat3(transpose(inverse(model))) * aNormal; 22 | } 23 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/basiclighting2.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 normal; 4 | in vec3 fragPos; 5 | 6 | out vec4 color; 7 | 8 | uniform vec3 lightPos; 9 | uniform vec3 viewPos; 10 | uniform vec3 lightColor; 11 | uniform vec3 objectColor; 12 | 13 | void main() 14 | { 15 | float ambientStrength = 0.1; 16 | float specularStrength = 0.5; 17 | 18 | vec3 lightDir = normalize(lightPos - fragPos); 19 | vec3 viewDir = normalize(viewPos - fragPos); 20 | vec3 reflectDir = reflect(-lightDir, normal); 21 | 22 | vec3 ambient = ambientStrength * lightColor; 23 | 24 | float diff = max(dot(normal, lightDir), 0.0); 25 | vec3 diffuse = diff * lightColor; 26 | 27 | float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); 28 | vec3 specular = specularStrength * spec * lightColor; 29 | 30 | vec3 col = (ambient + diffuse + specular) * objectColor; 31 | color = vec4(col, 1.0); 32 | } 33 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/basiclighting2.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 aPos; 4 | layout (location = 1) in vec3 aNormal; 5 | 6 | out vec3 normal; 7 | out vec3 fragPos; 8 | 9 | uniform mat4 model; 10 | uniform mat4 view; 11 | uniform mat4 projection; 12 | 13 | void main() 14 | { 15 | fragPos = vec3(model * vec4(aPos, 1.0)); 16 | 17 | // Calculating the inverse transpose of the model matrix should be done 18 | // once on the CPU and sent to the shader via an uniform; this is for 19 | // learning purposes only. 20 | normal = mat3(transpose(inverse(model))) * aNormal; 21 | 22 | gl_Position = projection * view * vec4(fragPos, 1.0); 23 | } 24 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/build-all.sh: -------------------------------------------------------------------------------- 1 | nim c BasicLighting1.nim && \ 2 | nim c BasicLighting2.nim 3 | 4 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/lamp.fs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | out vec4 color; 4 | 5 | void main() 6 | { 7 | color = vec4(1.0); 8 | } 9 | -------------------------------------------------------------------------------- /02-Lighting/02-BasicLighting/lamp.vs: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (location = 0) in vec3 position; 4 | 5 | uniform mat4 model; 6 | uniform mat4 view; 7 | uniform mat4 projection; 8 | 9 | void main() 10 | { 11 | gl_Position = projection * view * model * vec4(position, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /02-Lighting/build-all.sh: -------------------------------------------------------------------------------- 1 | (cd 01-Colors && ./build-all.sh) && \ 2 | (cd 02-BasicLighting && ./build-all.sh) 3 | -------------------------------------------------------------------------------- /Common/FpsCamera.nim: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import glm 4 | import glad/gl 5 | 6 | 7 | const 8 | YAW = -90.0 9 | PITCH = 0.0 10 | CURSOR_SENSITIVITY = 0.1 11 | MOVEMENT_SPEED = 2.5 12 | MIN_FOV = 1.0 13 | MAX_FOV = 45.0 14 | FOV = 45.0 15 | 16 | type 17 | FpsCamera* = ref object 18 | pos*, front*, up*: Vec3[GLfloat] 19 | movementSpeed*: float 20 | yaw*, pitch*: float 21 | fov*: float 22 | 23 | CameraMovement* = enum 24 | cmForward, cmBackward, cmLeft, cmRight 25 | 26 | 27 | proc updateCameraVectors(c: FpsCamera) = 28 | const 29 | yAxis = vec3[GLfloat](1.0, 0.0, 0.0) 30 | xAxis = vec3[GLfloat](0.0, 1.0, 0.0) 31 | 32 | let tx = mat4(GLfloat(1.0)).rotate(degToRad(c.pitch), yAxis) 33 | .rotate(degToRad(c.yaw), xAxis) 34 | 35 | const frontStart = vec3[GLfloat](0.0, 0.0, -1.0) 36 | 37 | c.front = (vec4(frontStart, 0.0) * tx).xyz 38 | 39 | 40 | proc newFpsCamera*(pos: Vec3[GLfloat] = vec3[GLfloat](0.0, 0.0, 0.0), 41 | up: Vec3[GLfloat] = vec3[GLfloat](0.0, 1.0, 0.0), 42 | yaw: float = YAW, 43 | pitch: float = PITCH): FpsCamera = 44 | new(result) 45 | 46 | result.fov = FOV 47 | result.movementSpeed = MOVEMENT_SPEED 48 | 49 | result.pos = pos 50 | result.up = up 51 | result.yaw = yaw 52 | result.pitch = pitch 53 | result.front = vec3[GLfloat](0.0, 0.0, -1.0) 54 | 55 | result.updateCameraVectors() 56 | 57 | 58 | proc newFpsCamera*(posX, posY, posZ: float, 59 | upX, upY, upZ: float, 60 | yaw: float = YAW, 61 | pitch: float = PITCH): FpsCamera = 62 | 63 | newFpsCamera(vec3[GLfloat](posX, posY, posZ), 64 | vec3[GLfloat](upX, upY, upZ), 65 | yaw, pitch) 66 | 67 | 68 | proc move*(c: FpsCamera, m: CameraMovement, deltaTime: float) = 69 | let velocity = c.movementSpeed * deltaTime 70 | 71 | case m: 72 | of cmForward: c.pos += c.front * velocity 73 | of cmBackward: c.pos -= c.front * velocity 74 | of cmLeft: c.pos += normalize(cross(c.up, c.front)) * velocity 75 | of cmRight: c.pos -= normalize(cross(c.up, c.front)) * velocity 76 | 77 | c.updateCameraVectors() 78 | 79 | 80 | proc headLook*(c: FpsCamera, xoffs, yoffs: float) = 81 | let 82 | dx = xoffs * CURSOR_SENSITIVITY 83 | dy = yoffs * CURSOR_SENSITIVITY 84 | 85 | c.yaw += dx 86 | if c.yaw > 360.0: 87 | c.yaw -= 360.0 88 | if c.yaw < -360: 89 | c.yaw += 360.0 90 | 91 | c.pitch = max(min(c.pitch + dy, 89.0), -89.0) 92 | c.updateCameraVectors() 93 | 94 | 95 | proc zoom*(c: FpsCamera, offs: float) = 96 | c.fov = max(min(c.fov - offs, MAX_FOV), MIN_FOV) 97 | 98 | 99 | proc getViewMatrix*(c: FpsCamera): Mat4[GLfloat] = 100 | lookAt(c.pos, c.pos + c.front, c.up) 101 | 102 | -------------------------------------------------------------------------------- /Common/Shader.nim: -------------------------------------------------------------------------------- 1 | import glm 2 | import glad/gl 3 | 4 | 5 | proc compileShader(shaderType: GLenum, source: string): GLuint = 6 | var 7 | shader = glCreateShader(shaderType) 8 | sourceArr = [cstring(source)] 9 | 10 | glShaderSource(shader, 1, cast[cstringArray](sourceArr.addr), nil) 11 | glCompileShader(shader) 12 | result = shader 13 | 14 | 15 | proc getShaderCompilationResult(shader: GLuint): tuple[success: bool, 16 | error: string] = 17 | var 18 | success: GLint 19 | infoLog = newString(1024) 20 | 21 | glGetShaderiv(shader, GL_COMPILE_STATUS, success.addr) 22 | 23 | if success == 0: 24 | glGetShaderInfoLog(shader, GLsizei(infoLog.len), nil, infoLog) 25 | result = (success: false, error: $infoLog) 26 | else: 27 | result = (success: true, error: "") 28 | 29 | 30 | proc getProgramLinkingResult(program: GLuint): tuple[success: bool, 31 | error: string] = 32 | var 33 | success: GLint 34 | infoLog = newString(1024) 35 | 36 | glGetProgramiv(program, GL_LINK_STATUS, success.addr) 37 | 38 | if success == 0: 39 | glGetShaderInfoLog(program, GLsizei(infoLog.len), nil, infoLog) 40 | result = (success: false, error: $infoLog) 41 | else: 42 | result = (success: true, error: "") 43 | 44 | 45 | proc createShaderProgram*(vertexShaderSource, 46 | fragmentShaderSource: string): GLuint = 47 | # Compile shaders 48 | let 49 | vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource) 50 | fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource) 51 | 52 | var res = getShaderCompilationResult(vertexShader) 53 | if not res.success: 54 | quit "ERROR: vertex shader compilation failed: " & res.error 55 | 56 | res = getShaderCompilationResult(fragmentShader) 57 | if not res.success: 58 | quit "ERROR: fragment shader compilation failed: " & res.error 59 | 60 | # Create shader program 61 | let shaderProgram = glCreateProgram() 62 | glAttachShader(shaderProgram, vertexShader) 63 | glAttachShader(shaderProgram, fragmentShader) 64 | glLinkProgram(shaderProgram) 65 | 66 | res = getProgramLinkingResult(shaderProgram) 67 | if not res.success: 68 | quit "ERROR: shader program linking failed: " & res.error 69 | 70 | # We don't need the compiled shaders anymore, just the program 71 | glDeleteShader(vertexShader) 72 | glDeleteShader(fragmentShader) 73 | 74 | result = shaderProgram 75 | 76 | 77 | proc createShaderProgramFromFile*(vertexShaderFn, 78 | fragmentShaderFn: string): GLuint = 79 | var f: File 80 | 81 | if not open(f, vertexShaderFn): 82 | quit "ERROR: cannot open vertex shader file '" & vertexShaderFn & "'" 83 | 84 | var vertexShaderSource = f.readAll() 85 | close(f) 86 | 87 | if not open(f, fragmentShaderFn): 88 | quit "ERROR: cannot open fragment shader file '" & vertexShaderFn & "'" 89 | 90 | var fragmentShaderSource = f.readAll() 91 | close(f) 92 | 93 | result = createShaderProgram(vertexShaderSource, fragmentShaderSource) 94 | 95 | 96 | proc use*(shaderProgram: GLuint) = 97 | glUseProgram(shaderProgram) 98 | 99 | 100 | proc setUniform1i*(shaderProgram: GLuint, name: string, v0: GLint) = 101 | let location = glGetUniformLocation(shaderProgram, name) 102 | glUniform1i(location, v0) 103 | 104 | proc setUniform2i*(shaderProgram: GLuint, name: string, v0, v1: GLint) = 105 | let location = glGetUniformLocation(shaderProgram, name) 106 | glUniform2i(location, v0, v1) 107 | 108 | proc setUniform3i*(shaderProgram: GLuint, name: string, v0, v1, v2: GLint) = 109 | let location = glGetUniformLocation(shaderProgram, name) 110 | glUniform3i(location, v0, v1, v2) 111 | 112 | proc setUniform4i*(shaderProgram: GLuint, name: string, 113 | v0, v1, v2, v3: GLint) = 114 | let location = glGetUniformLocation(shaderProgram, name) 115 | glUniform4i(location, v0, v1, v2, v3) 116 | 117 | 118 | proc setUniform1f*(shaderProgram: GLuint, name: string, v0: GLfloat) = 119 | let location = glGetUniformLocation(shaderProgram, name) 120 | glUniform1f(location, v0) 121 | 122 | proc setUniform2f*(shaderProgram: GLuint, name: string, v0, v1: GLfloat) = 123 | let location = glGetUniformLocation(shaderProgram, name) 124 | glUniform2f(location, v0, v1) 125 | 126 | proc setUniform3f*(shaderProgram: GLuint, name: string, v0, v1, v2: GLfloat) = 127 | let location = glGetUniformLocation(shaderProgram, name) 128 | glUniform3f(location, v0, v1, v2) 129 | 130 | proc setUniform4f*(shaderProgram: GLuint, name: string, 131 | v0, v1, v2, v3: GLfloat) = 132 | let location = glGetUniformLocation(shaderProgram, name) 133 | glUniform4f(location, v0, v1, v2, v3) 134 | 135 | 136 | # TODO do the rest 137 | proc setUniform3fv*(shaderProgram: GLuint, name: string, 138 | v: var Vec3[GLfloat]) = 139 | let location = glGetUniformLocation(shaderProgram, name) 140 | glUniform3fv(location, count = 1, v.caddr) 141 | 142 | 143 | # TODO use glm types 144 | proc setUniformMatrix2fv*(shaderProgram: GLuint, name: string, 145 | data: ptr GLfloat) = 146 | let location = glGetUniformLocation(shaderProgram, name) 147 | glUniformMatrix3fv(location, count = 1, transpose = false, data) 148 | 149 | proc setUniformMatrix3fv*(shaderProgram: GLuint, name: string, 150 | data: ptr GLfloat) = 151 | let location = glGetUniformLocation(shaderProgram, name) 152 | glUniformMatrix3fv(location, count = 1, transpose = false, data) 153 | 154 | proc setUniformMatrix4fv*(shaderProgram: GLuint, name: string, 155 | data: ptr GLfloat) = 156 | let location = glGetUniformLocation(shaderProgram, name) 157 | glUniformMatrix4fv(location, count = 1, transpose = false, data) 158 | 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn OpenGL in Nim 2 | 3 | Example programs and exercises from 4 | [learnopengl.com](https://learnopengl.com/) translated to 5 | [Nim](https://nim-lang.org/). A work in progress. 6 | 7 | Requires [nim-glfw](https://github.com/ephja/nim-glfw) and 8 | [nim-glm](https://github.com/stavenko/nim-glm). 9 | 10 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 01-GettingStarted/07-Camera: 2 | 3 | * do the exercises 4 | * understand & implement the yaw & pitch to direction vector conversion 5 | 6 | -------------------------------------------------------------------------------- /nim.cfg: -------------------------------------------------------------------------------- 1 | path="." 2 | define="glfwStaticLib" 3 | 4 | --------------------------------------------------------------------------------