opengl/learn_opengl/ 1_getting_started/ 4_textures
Licence This example has its own licence, rather than Odin's: opengl/learn_opengl/LICENSE
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
Code
main.odin ¶167 linesSource
1package main
2
3import gl "vendor:OpenGL"
4import "vendor:glfw"
5import "core:fmt"
6import "core:os"
7import stbi "vendor:stb/image"
8
9framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) {
10 gl.Viewport(0, 0, width, height)
11}
12
13processInput :: proc "c" (window: glfw.WindowHandle) {
14 if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS {
15 glfw.SetWindowShouldClose(window, true)
16 }
17}
18
19shader_set_bool :: proc(id: u32, name: cstring, value: bool) {
20 gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value))
21}
22
23shader_set_int :: proc(id: u32, name: cstring, value: i32) {
24 gl.Uniform1i(gl.GetUniformLocation(id, name), value)
25}
26
27shader_set_float :: proc(id: u32, name: cstring, value: f32) {
28 gl.Uniform1f(gl.GetUniformLocation(id, name), value)
29}
30
31SCR_WIDTH :: 800
32SCR_HEIGHT :: 600
33
34main :: proc() {
35 glfw.Init()
36 glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3)
37 glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3)
38 glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
39
40 window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil)
41 if window == nil {
42 fmt.println("Failed to create GLFW window")
43 glfw.Terminate()
44 os.exit(-1)
45 }
46 glfw.MakeContextCurrent(window)
47
48 gl.load_up_to(3, 3, glfw.gl_set_proc_address)
49
50 gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT)
51
52 glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback)
53
54 vertices := [?]f32 {
55 0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
56 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
57 -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
58 -0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
59 }
60
61 indices := [?]u32 {
62 0, 1, 3,
63 1, 2, 3,
64 }
65
66 // The shader loading they create can be replaced with just this
67 shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs")
68 if !loaded_ok {
69 os.exit(-1)
70 }
71
72 VBO, VAO, EBO: u32
73 gl.GenVertexArrays(1, &VAO)
74 gl.GenBuffers(1, &VBO)
75 gl.GenBuffers(1, &EBO)
76
77 gl.BindVertexArray(VAO)
78
79 gl.BindBuffer(gl.ARRAY_BUFFER, VBO)
80 gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW)
81
82 gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, EBO)
83 gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, size_of(indices), raw_data(&indices), gl.STATIC_DRAW)
84
85 gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 8 * size_of(f32), 0)
86 gl.EnableVertexAttribArray(0)
87
88 gl.VertexAttribPointer(1, 3, gl.FLOAT, gl.FALSE, 8 * size_of(f32), 3 * size_of(f32))
89 gl.EnableVertexAttribArray(1)
90
91 gl.VertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 8 * size_of(f32), 6 * size_of(f32))
92 gl.EnableVertexAttribArray(2)
93
94 texture1, texture2: u32
95 gl.GenTextures(1, &texture1)
96 gl.BindTexture(gl.TEXTURE_2D, texture1)
97
98 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
99 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
100
101 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
102 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
103
104 width, height, nrChannels: i32
105 stbi.set_flip_vertically_on_load(1)
106
107 data := stbi.load("../res/container.jpg", &width, &height, &nrChannels, 0)
108 if data == nil {
109 fmt.println("Failed to load texture")
110 os.exit(-1)
111 }
112
113 gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, data)
114 gl.GenerateMipmap(gl.TEXTURE_2D)
115
116 stbi.image_free(data)
117
118 gl.GenTextures(1, &texture2)
119 gl.BindTexture(gl.TEXTURE_2D, texture2)
120
121 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
122 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
123
124 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
125 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
126
127 data = stbi.load("../res/awesomeface.png", &width, &height, &nrChannels, 0)
128 if data == nil {
129 fmt.println("Failed to load texture")
130 os.exit(-1)
131 }
132
133 gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
134 gl.GenerateMipmap(gl.TEXTURE_2D)
135
136 stbi.image_free(data)
137
138 gl.UseProgram(shaderProgram)
139 shader_set_int(shaderProgram, "texture1", 0)
140 shader_set_int(shaderProgram, "texture2", 1)
141
142 for !glfw.WindowShouldClose(window) {
143 processInput(window)
144
145 gl.ClearColor(0.2, 0.3, 0.3, 1.0)
146 gl.Clear(gl.COLOR_BUFFER_BIT)
147
148 gl.ActiveTexture(gl.TEXTURE0)
149 gl.BindTexture(gl.TEXTURE_2D, texture1)
150 gl.ActiveTexture(gl.TEXTURE1)
151 gl.BindTexture(gl.TEXTURE_2D, texture2)
152
153 gl.UseProgram(shaderProgram)
154 gl.BindVertexArray(VAO)
155 gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil)
156
157 glfw.SwapBuffers(window)
158 glfw.PollEvents()
159 }
160
161 gl.DeleteVertexArrays(1, &VAO)
162 gl.DeleteBuffers(1, &VBO)
163 gl.DeleteBuffers(1, &EBO)
164 gl.DeleteProgram(shaderProgram)
165
166 glfw.Terminate()
167}
Shaders
res/fragment.fs ¶15 linesSource
#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);
}
res/vertex.vs ¶14 linesSource
#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);
}
Declarations Used 70
- core:fmt println
- core:os exit
- vendor:OpenGL ActiveTexture · ARRAY_BUFFER · BindBuffer · BindTexture · BindVertexArray · BufferData · Clear · ClearColor · COLOR_BUFFER_BIT · DeleteBuffers · DeleteProgram · DeleteVertexArrays · DrawElements · ELEMENT_ARRAY_BUFFER · EnableVertexAttribArray · FALSE · FLOAT · GenBuffers · GenerateMipmap · GenTextures · GenVertexArrays · GetUniformLocation · LINEAR · load_shaders_file · load_up_to · REPEAT · RGB · RGBA · STATIC_DRAW · TexImage2D · TexParameteri · TEXTURE0 · TEXTURE1 · TEXTURE_2D · TEXTURE_MAG_FILTER · TEXTURE_MIN_FILTER · TEXTURE_WRAP_S · TEXTURE_WRAP_T · TRIANGLES · Uniform1f · Uniform1i · UNSIGNED_BYTE · UNSIGNED_INT · UseProgram · VertexAttribPointer · Viewport
- vendor:glfw CONTEXT_VERSION_MAJOR · CONTEXT_VERSION_MINOR · CreateWindow · GetKey · gl_set_proc_address · Init · KEY_ESCAPE · MakeContextCurrent · OPENGL_CORE_PROFILE · OPENGL_PROFILE · PollEvents · PRESS · SetFramebufferSizeCallback · SetWindowShouldClose · SwapBuffers · Terminate · WindowHandle · WindowHint · WindowShouldClose
- vendor:stb/image image_free · load · set_flip_vertically_on_load