diff --git a/opengl/learn_opengl/1_getting_started/1_hello_window/main.odin b/opengl/learn_opengl/1_getting_started/1_hello_window/main.odin new file mode 100644 index 0000000..4072531 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/1_hello_window/main.odin @@ -0,0 +1,49 @@ +package main + +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } +} + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(800, 600, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, 800, 600) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + + for !glfw.WindowShouldClose(window) { + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT) + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/2_hello_triangle/main.odin b/opengl/learn_opengl/1_getting_started/2_hello_triangle/main.odin new file mode 100644 index 0000000..43f1b41 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/2_hello_triangle/main.odin @@ -0,0 +1,146 @@ +package main + +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" +import "core:c" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } +} + +vertexShaderSource: cstring = +`#version 330 core +layout (location = 0) in vec3 aPos; +void main() +{ + gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); +}` + +fragmentShaderSource: cstring = +`#version 330 core +out vec4 FragColor; + +void main() +{ + FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); +}` + +SCR_WIDTH :: 800 +SCR_HEIGHT :: 600 + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + + success: i32 + infoLog: [512]c.char + + vertexShader := gl.CreateShader(gl.VERTEX_SHADER) + gl.ShaderSource(vertexShader, 1, &vertexShaderSource, nil) + gl.CompileShader(vertexShader) + + gl.GetShaderiv(vertexShader, gl.COMPILE_STATUS, &success) + if success != 1 { + gl.GetShaderInfoLog(vertexShader, 512, nil, raw_data(&infoLog)) + } + + fragmentShader := gl.CreateShader(gl.FRAGMENT_SHADER) + gl.ShaderSource(fragmentShader, 1, &fragmentShaderSource, nil) + gl.CompileShader(fragmentShader) + + gl.GetShaderiv(fragmentShader, gl.COMPILE_STATUS, &success) + if success != 1 { + gl.GetShaderInfoLog(fragmentShader, 512, nil, raw_data(&infoLog)) + os.exit(-1) + } + + shaderProgram := gl.CreateProgram() + gl.AttachShader(shaderProgram, vertexShader) + gl.AttachShader(shaderProgram, fragmentShader) + gl.LinkProgram(shaderProgram) + + gl.GetProgramiv(fragmentShader, gl.LINK_STATUS, &success) + if success != 1 { + gl.GetProgramInfoLog(fragmentShader, 512, nil, raw_data(&infoLog)) + os.exit(-1) + } + + gl.DeleteShader(vertexShader) + gl.DeleteShader(fragmentShader) + + vertices := [?]f32 { + 0.5, 0.5, 0.0, + 0.5, -0.5, 0.0, + -0.5, -0.5, 0.0, + -0.5, 0.5, 0.0, + } + + indices := [?]u32 { + 0, 1, 3, + 1, 2, 3, + } + + VBO, VAO, EBO: u32 + gl.GenVertexArrays(1, &VAO) + gl.GenBuffers(1, &VBO) + gl.GenBuffers(1, &EBO) + + gl.BindVertexArray(VAO) + + gl.BindBuffer(gl.ARRAY_BUFFER, VBO) + gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW) + + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, EBO) + gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, size_of(indices), raw_data(&indices), gl.STATIC_DRAW) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 3 * size_of(f32), 0) + gl.EnableVertexAttribArray(0) + + gl.BindBuffer(gl.ARRAY_BUFFER, 0) + gl.BindVertexArray(0) + + for !glfw.WindowShouldClose(window) { + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT) + + gl.UseProgram(shaderProgram) + gl.BindVertexArray(VAO) + gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + gl.DeleteVertexArrays(1, &VAO) + gl.DeleteBuffers(1, &VBO) + gl.DeleteBuffers(1, &EBO) + gl.DeleteProgram(shaderProgram) + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/3_shaders/main.odin b/opengl/learn_opengl/1_getting_started/3_shaders/main.odin new file mode 100644 index 0000000..f62c946 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/3_shaders/main.odin @@ -0,0 +1,99 @@ +package main + +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } +} + +shader_set_bool :: proc(id: u32, name: cstring, value: bool) { + gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value)) +} + +shader_set_int :: proc(id: u32, name: cstring, value: i32) { + gl.Uniform1i(gl.GetUniformLocation(id, name), value) +} + +shader_set_float :: proc(id: u32, name: cstring, value: f32) { + gl.Uniform1f(gl.GetUniformLocation(id, name), value) +} + +SCR_WIDTH :: 800 +SCR_HEIGHT :: 600 + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + + vertices := [?]f32 { + 0.5, -0.5, 0.0, 1.0, 0.0, 0.0, + -0.5, -0.5, 0.0, 0.0, 1.0, 0.0, + 0.0, 0.5, 0.0, 0.0, 0.0, 1.0, + } + + // The shader loading they create can be replaced with just this + shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs") + if !loaded_ok { + os.exit(-1) + } + + VBO, VAO: u32 + gl.GenVertexArrays(1, &VAO) + gl.GenBuffers(1, &VBO) + + gl.BindVertexArray(VAO) + + gl.BindBuffer(gl.ARRAY_BUFFER, VBO) + gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 6 * size_of(f32), 0) + gl.EnableVertexAttribArray(0) + + gl.VertexAttribPointer(1, 3, gl.FLOAT, gl.FALSE, 6 * size_of(f32), 3 * size_of(f32)) + gl.EnableVertexAttribArray(1) + + for !glfw.WindowShouldClose(window) { + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT) + + gl.UseProgram(shaderProgram) + gl.BindVertexArray(VAO) + gl.DrawArrays(gl.TRIANGLES, 0, 3) + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + gl.DeleteVertexArrays(1, &VAO) + gl.DeleteBuffers(1, &VBO) + gl.DeleteProgram(shaderProgram) + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/3_shaders/res/fragment.fs b/opengl/learn_opengl/1_getting_started/3_shaders/res/fragment.fs new file mode 100644 index 0000000..b76871b --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/3_shaders/res/fragment.fs @@ -0,0 +1,8 @@ +#version 330 core +out vec4 FragColor; +in vec3 ourColor; + +void main() +{ + FragColor = vec4(ourColor, 1.0); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/3_shaders/res/vertex.vs b/opengl/learn_opengl/1_getting_started/3_shaders/res/vertex.vs new file mode 100644 index 0000000..d4e4927 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/3_shaders/res/vertex.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec3 aPos; // the position variable has attribute position 0 +layout (location = 1) in vec3 aColor; // the color variable has attribute position 1 + +out vec3 ourColor; // output a color to the fragment shader + +void main() +{ + gl_Position = vec4(aPos, 1.0); + ourColor = aColor; // set ourColor to the input color we got from the vertex data +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/4_textures/main.odin b/opengl/learn_opengl/1_getting_started/4_textures/main.odin new file mode 100644 index 0000000..59e8294 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/4_textures/main.odin @@ -0,0 +1,167 @@ +package main + +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" +import stbi "vendor:stb/image" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } +} + +shader_set_bool :: proc(id: u32, name: cstring, value: bool) { + gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value)) +} + +shader_set_int :: proc(id: u32, name: cstring, value: i32) { + gl.Uniform1i(gl.GetUniformLocation(id, name), value) +} + +shader_set_float :: proc(id: u32, name: cstring, value: f32) { + gl.Uniform1f(gl.GetUniformLocation(id, name), value) +} + +SCR_WIDTH :: 800 +SCR_HEIGHT :: 600 + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + + vertices := [?]f32 { + 0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, + 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, + -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, + -0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, + } + + indices := [?]u32 { + 0, 1, 3, + 1, 2, 3, + } + + // The shader loading they create can be replaced with just this + shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs") + if !loaded_ok { + os.exit(-1) + } + + VBO, VAO, EBO: u32 + gl.GenVertexArrays(1, &VAO) + gl.GenBuffers(1, &VBO) + gl.GenBuffers(1, &EBO) + + gl.BindVertexArray(VAO) + + gl.BindBuffer(gl.ARRAY_BUFFER, VBO) + gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW) + + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, EBO) + gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, size_of(indices), raw_data(&indices), gl.STATIC_DRAW) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 8 * size_of(f32), 0) + gl.EnableVertexAttribArray(0) + + gl.VertexAttribPointer(1, 3, gl.FLOAT, gl.FALSE, 8 * size_of(f32), 3 * size_of(f32)) + gl.EnableVertexAttribArray(1) + + gl.VertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 8 * size_of(f32), 6 * size_of(f32)) + gl.EnableVertexAttribArray(2) + + texture1, texture2: u32 + gl.GenTextures(1, &texture1) + gl.BindTexture(gl.TEXTURE_2D, texture1) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + width, height, nrChannels: i32 + stbi.set_flip_vertically_on_load(1) + + data := stbi.load("../res/container.jpg", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.GenTextures(1, &texture2) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + data = stbi.load("../res/awesomeface.png", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.UseProgram(shaderProgram) + shader_set_int(shaderProgram, "texture1", 0) + shader_set_int(shaderProgram, "texture2", 1) + + for !glfw.WindowShouldClose(window) { + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT) + + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, texture1) + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.UseProgram(shaderProgram) + gl.BindVertexArray(VAO) + gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + gl.DeleteVertexArrays(1, &VAO) + gl.DeleteBuffers(1, &VBO) + gl.DeleteBuffers(1, &EBO) + gl.DeleteProgram(shaderProgram) + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/4_textures/res/fragment.fs b/opengl/learn_opengl/1_getting_started/4_textures/res/fragment.fs new file mode 100644 index 0000000..9fef202 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/4_textures/res/fragment.fs @@ -0,0 +1,15 @@ +#version 330 core +out vec4 FragColor; + +in vec3 ourColor; +in vec2 TexCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/4_textures/res/vertex.vs b/opengl/learn_opengl/1_getting_started/4_textures/res/vertex.vs new file mode 100644 index 0000000..4fd6603 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/4_textures/res/vertex.vs @@ -0,0 +1,14 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aColor; +layout (location = 2) in vec2 aTexCoord; + +out vec3 ourColor; +out vec2 TexCoord; + +void main() +{ + gl_Position = vec4(aPos, 1.0); + ourColor = aColor; + TexCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/5_transformations/main.odin b/opengl/learn_opengl/1_getting_started/5_transformations/main.odin new file mode 100644 index 0000000..1bd94e8 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/5_transformations/main.odin @@ -0,0 +1,159 @@ +package main + +import "core:math/linalg/glsl" +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" +import stbi "vendor:stb/image" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } +} + +SCR_WIDTH :: 800 +SCR_HEIGHT :: 600 + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + + vertices := [?]f32 { + 0.5, 0.5, 0.0, 1.0, 1.0, + 0.5, -0.5, 0.0, 1.0, 0.0, + -0.5, -0.5, 0.0, 0.0, 0.0, + -0.5, 0.5, 0.0, 0.0, 1.0, + } + + indices := [?]u32 { + 0, 1, 3, + 1, 2, 3, + } + + // The shader loading they create can be replaced with just this + shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs") + if !loaded_ok { + os.exit(-1) + } + + VBO, VAO, EBO: u32 + gl.GenVertexArrays(1, &VAO) + gl.GenBuffers(1, &VBO) + gl.GenBuffers(1, &EBO) + + gl.BindVertexArray(VAO) + + gl.BindBuffer(gl.ARRAY_BUFFER, VBO) + gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW) + + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, EBO) + gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, size_of(indices), raw_data(&indices), gl.STATIC_DRAW) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 0) + gl.EnableVertexAttribArray(0) + + gl.VertexAttribPointer(1, 2, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 3 * size_of(f32)) + gl.EnableVertexAttribArray(1) + + texture1, texture2: u32 + gl.GenTextures(1, &texture1) + gl.BindTexture(gl.TEXTURE_2D, texture1) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + width, height, nrChannels: i32 + stbi.set_flip_vertically_on_load(1) + + data := stbi.load("../res/container.jpg", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.GenTextures(1, &texture2) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + data = stbi.load("../res/awesomeface.png", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.UseProgram(shaderProgram) + shader_set_int(shaderProgram, "texture1", 0) + shader_set_int(shaderProgram, "texture2", 1) + + for !glfw.WindowShouldClose(window) { + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT) + + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, texture1) + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + transform: glsl.mat4 = 1 + transform *= glsl.mat4Translate({0.5, -0.5, 0.0}) + transform *= glsl.mat4Rotate({0, 0, 1}, f32(glfw.GetTime())) + + gl.UseProgram(shaderProgram) + shader_set_mat4(shaderProgram, "transform", transform) + + gl.BindVertexArray(VAO) + gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + gl.DeleteVertexArrays(1, &VAO) + gl.DeleteBuffers(1, &VBO) + gl.DeleteBuffers(1, &EBO) + gl.DeleteProgram(shaderProgram) + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/5_transformations/res/fragment.fs b/opengl/learn_opengl/1_getting_started/5_transformations/res/fragment.fs new file mode 100644 index 0000000..44839bc --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/5_transformations/res/fragment.fs @@ -0,0 +1,14 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/5_transformations/res/vertex.vs b/opengl/learn_opengl/1_getting_started/5_transformations/res/vertex.vs new file mode 100644 index 0000000..709bef9 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/5_transformations/res/vertex.vs @@ -0,0 +1,13 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoord; + +uniform mat4 transform; + +void main() +{ + gl_Position = transform * vec4(aPos, 1.0); + TexCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/5_transformations/shader.odin b/opengl/learn_opengl/1_getting_started/5_transformations/shader.odin new file mode 100644 index 0000000..c8e6f72 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/5_transformations/shader.odin @@ -0,0 +1,73 @@ +package main + +import gl "vendor:OpenGL" +import "core:math/linalg/glsl" + +shader_set_bool :: proc(id: u32, name: cstring, value: bool) { + gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value)) +} + +shader_set_int :: proc(id: u32, name: cstring, value: i32) { + gl.Uniform1i(gl.GetUniformLocation(id, name), value) +} + +shader_set_float :: proc(id: u32, name: cstring, value: f32) { + gl.Uniform1f(gl.GetUniformLocation(id, name), value) +} + +shader_set_vec2_v :: proc(id: u32, name: cstring, value: glsl.vec2) { + lc := value + gl.Uniform2fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec2_f :: proc(id: u32, name: cstring, x, y: f32) { + gl.Uniform2f(gl.GetUniformLocation(id, name), x, y) +} + +shader_set_vec2 :: proc { + shader_set_vec2_v, + shader_set_vec2_f, +} + +shader_set_vec3_v :: proc(id: u32, name: cstring, value: glsl.vec3) { + lc := value + gl.Uniform3fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec3_f :: proc(id: u32, name: cstring, x, y, z: f32) { + gl.Uniform3f(gl.GetUniformLocation(id, name), x, y, z) +} + +shader_set_vec3 :: proc { + shader_set_vec3_v, + shader_set_vec3_f, +} + +shader_set_vec4_v :: proc(id: u32, name: cstring, value: glsl.vec4) { + lc := value + gl.Uniform4fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec4_f :: proc(id: u32, name: cstring, x, y, z, w: f32) { + gl.Uniform4f(gl.GetUniformLocation(id, name), x, y, z, w) +} + +shader_set_vec4 :: proc { + shader_set_vec4_v, + shader_set_vec4_f, +} + +shader_set_mat2 :: proc(id: u32, name: cstring, mat: glsl.mat2) { + lc := mat + gl.UniformMatrix2fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} + +shader_set_mat3 :: proc(id: u32, name: cstring, mat: glsl.mat3) { + lc := mat + gl.UniformMatrix3fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} + +shader_set_mat4 :: proc(id: u32, name: cstring, mat: glsl.mat4) { + lc := mat + gl.UniformMatrix4fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/6_coordinate_systems/main.odin b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/main.odin new file mode 100644 index 0000000..3e713cd --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/main.odin @@ -0,0 +1,213 @@ +package main + +import "core:math/linalg/glsl" +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" +import stbi "vendor:stb/image" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } +} + +SCR_WIDTH :: 800 +SCR_HEIGHT :: 600 + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + + gl.Enable(gl.DEPTH_TEST) + + vertices := [?]f32 { + -0.5, -0.5, -0.5, 0.0, 0.0, + 0.5, -0.5, -0.5, 1.0, 0.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 0.0, + + -0.5, -0.5, 0.5, 0.0, 0.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + + -0.5, 0.5, 0.5, 1.0, 0.0, + -0.5, 0.5, -0.5, 1.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, 0.5, 1.0, 0.0, + + 0.5, 0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, 0.5, 0.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + + -0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, -0.5, 1.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + + -0.5, 0.5, -0.5, 0.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + -0.5, 0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, -0.5, 0.0, 1.0, + } + + cubePositions := [?]glsl.vec3{ + {0.0, 0.0, 0.0}, + {2.0, 5.0, -15.0}, + {-1.5, -2.2, -2.5}, + {-3.8, -2.0, -12.3}, + {2.4, -0.4, -3.5}, + {-1.7, 3.0, -7.5}, + {1.3, -2.0, -2.5}, + {1.5, 2.0, -2.5}, + {1.5, 0.2, -1.5}, + {-1.3, 1.0, -1.5}, + } + + // The shader loading they create can be replaced with just this + shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs") + if !loaded_ok { + os.exit(-1) + } + + VBO, VAO: u32 + gl.GenVertexArrays(1, &VAO) + gl.GenBuffers(1, &VBO) + + gl.BindVertexArray(VAO) + + gl.BindBuffer(gl.ARRAY_BUFFER, VBO) + gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 0) + gl.EnableVertexAttribArray(0) + + gl.VertexAttribPointer(1, 2, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 3 * size_of(f32)) + gl.EnableVertexAttribArray(1) + + texture1, texture2: u32 + gl.GenTextures(1, &texture1) + gl.BindTexture(gl.TEXTURE_2D, texture1) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + width, height, nrChannels: i32 + stbi.set_flip_vertically_on_load(1) + + data := stbi.load("../res/container.jpg", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.GenTextures(1, &texture2) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + data = stbi.load("../res/awesomeface.png", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.UseProgram(shaderProgram) + shader_set_int(shaderProgram, "texture1", 0) + shader_set_int(shaderProgram, "texture2", 1) + + for !glfw.WindowShouldClose(window) { + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, texture1) + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.UseProgram(shaderProgram) + + view: glsl.mat4 = 1 + view *= glsl.mat4Translate({0.0, 0.0, -3.0}) + + projection: glsl.mat4 = 1 + projection *= glsl.mat4Perspective(glsl.radians_f32(45), f32(f32(SCR_WIDTH) / f32(SCR_HEIGHT)), 0.1, 100) + + shader_set_mat4(shaderProgram, "projection", projection) + shader_set_mat4(shaderProgram, "view", view) + + gl.BindVertexArray(VAO) + for position, i in cubePositions { + model: glsl.mat4 = 1 + model *= glsl.mat4Translate(position) + angle := 20.0 * f32(i) + model *= glsl.mat4Rotate({1.0, 0.3, 0.5}, glsl.radians(angle)) + shader_set_mat4(shaderProgram, "model", model) + + gl.DrawArrays(gl.TRIANGLES, 0, 36) + } + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + gl.DeleteVertexArrays(1, &VAO) + gl.DeleteBuffers(1, &VBO) + gl.DeleteProgram(shaderProgram) + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/6_coordinate_systems/res/fragment.fs b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/res/fragment.fs new file mode 100644 index 0000000..c631503 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/res/fragment.fs @@ -0,0 +1,13 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoord; + +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2); +} + diff --git a/opengl/learn_opengl/1_getting_started/6_coordinate_systems/res/vertex.vs b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/res/vertex.vs new file mode 100644 index 0000000..523e2a8 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/res/vertex.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0f); + TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/6_coordinate_systems/shader.odin b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/shader.odin new file mode 100644 index 0000000..c8e6f72 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/6_coordinate_systems/shader.odin @@ -0,0 +1,73 @@ +package main + +import gl "vendor:OpenGL" +import "core:math/linalg/glsl" + +shader_set_bool :: proc(id: u32, name: cstring, value: bool) { + gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value)) +} + +shader_set_int :: proc(id: u32, name: cstring, value: i32) { + gl.Uniform1i(gl.GetUniformLocation(id, name), value) +} + +shader_set_float :: proc(id: u32, name: cstring, value: f32) { + gl.Uniform1f(gl.GetUniformLocation(id, name), value) +} + +shader_set_vec2_v :: proc(id: u32, name: cstring, value: glsl.vec2) { + lc := value + gl.Uniform2fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec2_f :: proc(id: u32, name: cstring, x, y: f32) { + gl.Uniform2f(gl.GetUniformLocation(id, name), x, y) +} + +shader_set_vec2 :: proc { + shader_set_vec2_v, + shader_set_vec2_f, +} + +shader_set_vec3_v :: proc(id: u32, name: cstring, value: glsl.vec3) { + lc := value + gl.Uniform3fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec3_f :: proc(id: u32, name: cstring, x, y, z: f32) { + gl.Uniform3f(gl.GetUniformLocation(id, name), x, y, z) +} + +shader_set_vec3 :: proc { + shader_set_vec3_v, + shader_set_vec3_f, +} + +shader_set_vec4_v :: proc(id: u32, name: cstring, value: glsl.vec4) { + lc := value + gl.Uniform4fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec4_f :: proc(id: u32, name: cstring, x, y, z, w: f32) { + gl.Uniform4f(gl.GetUniformLocation(id, name), x, y, z, w) +} + +shader_set_vec4 :: proc { + shader_set_vec4_v, + shader_set_vec4_f, +} + +shader_set_mat2 :: proc(id: u32, name: cstring, mat: glsl.mat2) { + lc := mat + gl.UniformMatrix2fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} + +shader_set_mat3 :: proc(id: u32, name: cstring, mat: glsl.mat3) { + lc := mat + gl.UniformMatrix3fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} + +shader_set_mat4 :: proc(id: u32, name: cstring, mat: glsl.mat4) { + lc := mat + gl.UniformMatrix4fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/7_camera/main.odin b/opengl/learn_opengl/1_getting_started/7_camera/main.odin new file mode 100644 index 0000000..9291243 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/7_camera/main.odin @@ -0,0 +1,297 @@ +package main + +import "core:math/linalg/glsl" +import gl "vendor:OpenGL" +import "vendor:glfw" +import "core:fmt" +import "core:os" +import stbi "vendor:stb/image" +import "core:math" + +framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) { + gl.Viewport(0, 0, width, height) +} + +processInput :: proc "c" (window: glfw.WindowHandle) { + if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS { + glfw.SetWindowShouldClose(window, true) + } + + cameraSpeed := f32(deltaTime * 2.5) + if glfw.GetKey(window, glfw.KEY_W) == glfw.PRESS { + cameraPos += cameraSpeed * cameraFront + } + if glfw.GetKey(window, glfw.KEY_S) == glfw.PRESS { + cameraPos -= cameraSpeed * cameraFront + } + if glfw.GetKey(window, glfw.KEY_A) == glfw.PRESS { + cameraPos -= glsl.normalize(glsl.cross(cameraFront, cameraUp)) * cameraSpeed + } + if glfw.GetKey(window, glfw.KEY_D) == glfw.PRESS { + cameraPos += glsl.normalize(glsl.cross(cameraFront, cameraUp)) * cameraSpeed + } +} + +mouse_callback :: proc "c" (window: glfw.WindowHandle, xposIn: f64, yposIn: f64) { + xpos := f32(xposIn) + ypos := f32(yposIn) + + if firstMouse { + lastX = xpos + lastY = ypos + firstMouse = false + } + + xoffset := xpos - lastX + yoffset := lastY - ypos + lastX = xpos + lastY = ypos + + sensitivity: f32 = 0.1 + xoffset *= sensitivity + yoffset *= sensitivity + + yaw += xoffset + pitch += yoffset + + if pitch > 89 { + pitch = 89 + } + if pitch < -89 { + pitch = -89 + } + + front := glsl.vec3{ + math.cos(glsl.radians(yaw)) * math.cos(glsl.radians(pitch)), + math.sin(glsl.radians(pitch)), + math.sin(glsl.radians(yaw)) * glsl.cos(glsl.radians(pitch)), + } + cameraFront = glsl.normalize(front) +} + +scroll_callback := proc "c" (window: glfw.WindowHandle, xoffset: f64, yoffset: f64) { + fov -= f32(yoffset) + if fov < 1 { + fov = 1 + } + if fov > 45 { + fov = 45 + } +} + +SCR_WIDTH :: 800 +SCR_HEIGHT :: 600 + +cameraPos := glsl.vec3{0, 0, 3} +cameraFront := glsl.vec3{0, 0, -1} +cameraUp := glsl.vec3{0, 1, 0} + +firstMouse := true +yaw: f32 = -90 +pitch: f32 = 0 +lastX: f32 = 800 / 2 +lastY: f32 = 600 / 2 +fov: f32 = 45 + +deltaTime: f32 = 0 +lastFrame: f32 = 0 + +main :: proc() { + glfw.Init() + glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3) + glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) + + window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil) + if window == nil { + fmt.println("Failed to create GLFW window") + glfw.Terminate() + os.exit(-1) + } + glfw.MakeContextCurrent(window) + + gl.load_up_to(3, 3, glfw.gl_set_proc_address) + + gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT) + + glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback) + glfw.SetCursorPosCallback(window, mouse_callback) + glfw.SetScrollCallback(window, scroll_callback) + + glfw.SetInputMode(window, glfw.CURSOR, glfw.CURSOR_DISABLED) + + vertices := [?]f32 { + -0.5, -0.5, -0.5, 0.0, 0.0, + 0.5, -0.5, -0.5, 1.0, 0.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 0.0, + + -0.5, -0.5, 0.5, 0.0, 0.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + + -0.5, 0.5, 0.5, 1.0, 0.0, + -0.5, 0.5, -0.5, 1.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, 0.5, 1.0, 0.0, + + 0.5, 0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, 0.5, 0.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + + -0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, -0.5, 1.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + + -0.5, 0.5, -0.5, 0.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + -0.5, 0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, -0.5, 0.0, 1.0, + } + + cubePositions := [?]glsl.vec3{ + {0.0, 0.0, 0.0}, + {2.0, 5.0, -15.0}, + {-1.5, -2.2, -2.5}, + {-3.8, -2.0, -12.3}, + {2.4, -0.4, -3.5}, + {-1.7, 3.0, -7.5}, + {1.3, -2.0, -2.5}, + {1.5, 2.0, -2.5}, + {1.5, 0.2, -1.5}, + {-1.3, 1.0, -1.5}, + } + + gl.Enable(gl.DEPTH_TEST) + + // The shader loading they create can be replaced with just this + shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs") + if !loaded_ok { + os.exit(-1) + } + + VBO, VAO: u32 + gl.GenVertexArrays(1, &VAO) + gl.GenBuffers(1, &VBO) + + gl.BindVertexArray(VAO) + + gl.BindBuffer(gl.ARRAY_BUFFER, VBO) + gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 0) + gl.EnableVertexAttribArray(0) + + gl.VertexAttribPointer(1, 2, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 3 * size_of(f32)) + gl.EnableVertexAttribArray(1) + + texture1, texture2: u32 + gl.GenTextures(1, &texture1) + gl.BindTexture(gl.TEXTURE_2D, texture1) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + width, height, nrChannels: i32 + stbi.set_flip_vertically_on_load(1) + + data := stbi.load("../res/container.jpg", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.GenTextures(1, &texture2) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + data = stbi.load("../res/awesomeface.png", &width, &height, &nrChannels, 0) + if data == nil { + fmt.println("Failed to load texture") + os.exit(-1) + } + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) + gl.GenerateMipmap(gl.TEXTURE_2D) + + stbi.image_free(data) + + gl.UseProgram(shaderProgram) + shader_set_int(shaderProgram, "texture1", 0) + shader_set_int(shaderProgram, "texture2", 1) + + for !glfw.WindowShouldClose(window) { + currentFrame := f32(glfw.GetTime()) + deltaTime = currentFrame - lastFrame + lastFrame = currentFrame + + processInput(window) + + gl.ClearColor(0.2, 0.3, 0.3, 1.0) + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, texture1) + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, texture2) + + gl.UseProgram(shaderProgram) + + view: glsl.mat4 = 1 + view *= glsl.mat4LookAt(cameraPos, cameraPos + cameraFront, cameraUp) + + projection: glsl.mat4 = 1 + projection *= glsl.mat4Perspective(glsl.radians_f32(45), f32(f32(SCR_WIDTH) / f32(SCR_HEIGHT)), 0.1, 100) + + shader_set_mat4(shaderProgram, "projection", projection) + shader_set_mat4(shaderProgram, "view", view) + + gl.BindVertexArray(VAO) + for position, i in cubePositions { + model: glsl.mat4 = 1 + model *= glsl.mat4Translate(position) + angle := 20.0 * f32(i) + model *= glsl.mat4Rotate({1.0, 0.3, 0.5}, glsl.radians(angle)) + shader_set_mat4(shaderProgram, "model", model) + + gl.DrawArrays(gl.TRIANGLES, 0, 36) + } + + glfw.SwapBuffers(window) + glfw.PollEvents() + } + + gl.DeleteVertexArrays(1, &VAO) + gl.DeleteBuffers(1, &VBO) + gl.DeleteProgram(shaderProgram) + + glfw.Terminate() +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/7_camera/res/fragment.fs b/opengl/learn_opengl/1_getting_started/7_camera/res/fragment.fs new file mode 100644 index 0000000..44839bc --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/7_camera/res/fragment.fs @@ -0,0 +1,14 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoord; + +// texture samplers +uniform sampler2D texture1; +uniform sampler2D texture2; + +void main() +{ + // linearly interpolate between both textures (80% container, 20% awesomeface) + FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/7_camera/res/vertex.vs b/opengl/learn_opengl/1_getting_started/7_camera/res/vertex.vs new file mode 100644 index 0000000..e91af6d --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/7_camera/res/vertex.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0f); + TexCoord = vec2(aTexCoord.x, aTexCoord.y); +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/7_camera/shader.odin b/opengl/learn_opengl/1_getting_started/7_camera/shader.odin new file mode 100644 index 0000000..c8e6f72 --- /dev/null +++ b/opengl/learn_opengl/1_getting_started/7_camera/shader.odin @@ -0,0 +1,73 @@ +package main + +import gl "vendor:OpenGL" +import "core:math/linalg/glsl" + +shader_set_bool :: proc(id: u32, name: cstring, value: bool) { + gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value)) +} + +shader_set_int :: proc(id: u32, name: cstring, value: i32) { + gl.Uniform1i(gl.GetUniformLocation(id, name), value) +} + +shader_set_float :: proc(id: u32, name: cstring, value: f32) { + gl.Uniform1f(gl.GetUniformLocation(id, name), value) +} + +shader_set_vec2_v :: proc(id: u32, name: cstring, value: glsl.vec2) { + lc := value + gl.Uniform2fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec2_f :: proc(id: u32, name: cstring, x, y: f32) { + gl.Uniform2f(gl.GetUniformLocation(id, name), x, y) +} + +shader_set_vec2 :: proc { + shader_set_vec2_v, + shader_set_vec2_f, +} + +shader_set_vec3_v :: proc(id: u32, name: cstring, value: glsl.vec3) { + lc := value + gl.Uniform3fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec3_f :: proc(id: u32, name: cstring, x, y, z: f32) { + gl.Uniform3f(gl.GetUniformLocation(id, name), x, y, z) +} + +shader_set_vec3 :: proc { + shader_set_vec3_v, + shader_set_vec3_f, +} + +shader_set_vec4_v :: proc(id: u32, name: cstring, value: glsl.vec4) { + lc := value + gl.Uniform4fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc)) +} + +shader_set_vec4_f :: proc(id: u32, name: cstring, x, y, z, w: f32) { + gl.Uniform4f(gl.GetUniformLocation(id, name), x, y, z, w) +} + +shader_set_vec4 :: proc { + shader_set_vec4_v, + shader_set_vec4_f, +} + +shader_set_mat2 :: proc(id: u32, name: cstring, mat: glsl.mat2) { + lc := mat + gl.UniformMatrix2fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} + +shader_set_mat3 :: proc(id: u32, name: cstring, mat: glsl.mat3) { + lc := mat + gl.UniformMatrix3fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} + +shader_set_mat4 :: proc(id: u32, name: cstring, mat: glsl.mat4) { + lc := mat + gl.UniformMatrix4fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc)) +} \ No newline at end of file diff --git a/opengl/learn_opengl/1_getting_started/res/awesomeface.png b/opengl/learn_opengl/1_getting_started/res/awesomeface.png new file mode 100644 index 0000000..9840caf Binary files /dev/null and b/opengl/learn_opengl/1_getting_started/res/awesomeface.png differ diff --git a/opengl/learn_opengl/1_getting_started/res/container.jpg b/opengl/learn_opengl/1_getting_started/res/container.jpg new file mode 100644 index 0000000..d07bee4 Binary files /dev/null and b/opengl/learn_opengl/1_getting_started/res/container.jpg differ diff --git a/opengl/learn_opengl/LICENSE b/opengl/learn_opengl/LICENSE new file mode 100644 index 0000000..f178ef1 --- /dev/null +++ b/opengl/learn_opengl/LICENSE @@ -0,0 +1,3 @@ +LearnOpenGL.com © 2025 by Joey de Vries is licensed under CC BY-NC 4.0. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc/4.0/ +https://learnopengl.com +https://x.com/JoeyDeVriez \ No newline at end of file