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