opengl/learn_opengl/1_getting_started/6_coordinate_systems

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 ¶
213 linesSource

1package main
2
3import "core:math/linalg/glsl"
4import gl "vendor:OpenGL"
5import "vendor:glfw"
6import "core:fmt"
7import "core:os"
8import stbi "vendor:stb/image"
9
10framebuffer_size_callback :: proc "c" (window: glfw.WindowHandle, width: i32, height: i32) {
11	gl.Viewport(0, 0, width, height)
12}
13
14processInput :: proc "c" (window: glfw.WindowHandle) {
15	if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS {
16		glfw.SetWindowShouldClose(window, true)
17	}
18}
19
20SCR_WIDTH :: 800
21SCR_HEIGHT :: 600
22
23main :: proc() {
24	glfw.Init()
25	glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3)
26	glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3)
27	glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
28
29	window := glfw.CreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nil, nil)
30	if window == nil {
31		fmt.println("Failed to create GLFW window")
32		glfw.Terminate()
33		os.exit(-1)
34	}
35	glfw.MakeContextCurrent(window)
36
37	gl.load_up_to(3, 3, glfw.gl_set_proc_address)
38
39	gl.Viewport(0, 0, SCR_WIDTH, SCR_HEIGHT)
40
41	glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback)
42
43	gl.Enable(gl.DEPTH_TEST)
44
45	vertices := [?]f32 {
46        -0.5, -0.5, -0.5,  0.0, 0.0,
47         0.5, -0.5, -0.5,  1.0, 0.0,
48         0.5,  0.5, -0.5,  1.0, 1.0,
49         0.5,  0.5, -0.5,  1.0, 1.0,
50        -0.5,  0.5, -0.5,  0.0, 1.0,
51        -0.5, -0.5, -0.5,  0.0, 0.0,
52
53        -0.5, -0.5,  0.5,  0.0, 0.0,
54         0.5, -0.5,  0.5,  1.0, 0.0,
55         0.5,  0.5,  0.5,  1.0, 1.0,
56         0.5,  0.5,  0.5,  1.0, 1.0,
57        -0.5,  0.5,  0.5,  0.0, 1.0,
58        -0.5, -0.5,  0.5,  0.0, 0.0,
59
60        -0.5,  0.5,  0.5,  1.0, 0.0,
61        -0.5,  0.5, -0.5,  1.0, 1.0,
62        -0.5, -0.5, -0.5,  0.0, 1.0,
63        -0.5, -0.5, -0.5,  0.0, 1.0,
64        -0.5, -0.5,  0.5,  0.0, 0.0,
65        -0.5,  0.5,  0.5,  1.0, 0.0,
66
67         0.5,  0.5,  0.5,  1.0, 0.0,
68         0.5,  0.5, -0.5,  1.0, 1.0,
69         0.5, -0.5, -0.5,  0.0, 1.0,
70         0.5, -0.5, -0.5,  0.0, 1.0,
71         0.5, -0.5,  0.5,  0.0, 0.0,
72         0.5,  0.5,  0.5,  1.0, 0.0,
73
74        -0.5, -0.5, -0.5,  0.0, 1.0,
75         0.5, -0.5, -0.5,  1.0, 1.0,
76         0.5, -0.5,  0.5,  1.0, 0.0,
77         0.5, -0.5,  0.5,  1.0, 0.0,
78        -0.5, -0.5,  0.5,  0.0, 0.0,
79        -0.5, -0.5, -0.5,  0.0, 1.0,
80
81        -0.5,  0.5, -0.5,  0.0, 1.0,
82         0.5,  0.5, -0.5,  1.0, 1.0,
83         0.5,  0.5,  0.5,  1.0, 0.0,
84         0.5,  0.5,  0.5,  1.0, 0.0,
85        -0.5,  0.5,  0.5,  0.0, 0.0,
86        -0.5,  0.5, -0.5,  0.0, 1.0,
87	}
88
89	cubePositions := [?]glsl.vec3{
90		{0.0, 0.0, 0.0},
91		{2.0, 5.0, -15.0},
92		{-1.5, -2.2, -2.5},
93		{-3.8, -2.0, -12.3},
94		{2.4, -0.4, -3.5},
95		{-1.7, 3.0, -7.5},
96		{1.3, -2.0, -2.5},
97		{1.5, 2.0, -2.5},
98		{1.5, 0.2, -1.5},
99		{-1.3, 1.0, -1.5},
100	}
101
102	// The shader loading they create can be replaced with just this
103	shaderProgram, loaded_ok := gl.load_shaders_file("./res/vertex.vs", "./res/fragment.fs")
104	if !loaded_ok {
105		os.exit(-1)
106	}
107
108	VBO, VAO: u32
109	gl.GenVertexArrays(1, &VAO)
110	gl.GenBuffers(1, &VBO)
111
112	gl.BindVertexArray(VAO)
113
114	gl.BindBuffer(gl.ARRAY_BUFFER, VBO)
115	gl.BufferData(gl.ARRAY_BUFFER, size_of(vertices), raw_data(&vertices), gl.STATIC_DRAW)
116
117	gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 0)
118	gl.EnableVertexAttribArray(0)
119
120	gl.VertexAttribPointer(1, 2, gl.FLOAT, gl.FALSE, 5 * size_of(f32), 3 * size_of(f32))
121	gl.EnableVertexAttribArray(1)
122
123	texture1, texture2: u32
124	gl.GenTextures(1, &texture1)
125	gl.BindTexture(gl.TEXTURE_2D, texture1)
126
127	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
128	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
129
130	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
131	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
132
133	width, height, nrChannels: i32
134	stbi.set_flip_vertically_on_load(1)
135
136	data := stbi.load("../res/container.jpg", &width, &height, &nrChannels, 0)
137	if data == nil {
138		fmt.println("Failed to load texture")
139		os.exit(-1)
140	}
141
142	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, data)
143	gl.GenerateMipmap(gl.TEXTURE_2D)
144
145	stbi.image_free(data)
146
147	gl.GenTextures(1, &texture2)
148	gl.BindTexture(gl.TEXTURE_2D, texture2)
149
150	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
151	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
152
153	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
154	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
155
156	data = stbi.load("../res/awesomeface.png", &width, &height, &nrChannels, 0)
157	if data == nil {
158		fmt.println("Failed to load texture")
159		os.exit(-1)
160	}
161
162	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
163	gl.GenerateMipmap(gl.TEXTURE_2D)
164
165	stbi.image_free(data)
166
167	gl.UseProgram(shaderProgram)
168	shader_set_int(shaderProgram, "texture1", 0)
169	shader_set_int(shaderProgram, "texture2", 1)
170
171	for !glfw.WindowShouldClose(window) {
172		processInput(window)
173
174		gl.ClearColor(0.2, 0.3, 0.3, 1.0)
175		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
176
177		gl.ActiveTexture(gl.TEXTURE0)
178		gl.BindTexture(gl.TEXTURE_2D, texture1)
179		gl.ActiveTexture(gl.TEXTURE1)
180		gl.BindTexture(gl.TEXTURE_2D, texture2)
181
182		gl.UseProgram(shaderProgram)
183
184		view: glsl.mat4 = 1
185		view *= glsl.mat4Translate({0.0, 0.0, -3.0})
186
187		projection: glsl.mat4 = 1
188		projection *= glsl.mat4Perspective(glsl.radians_f32(45), f32(f32(SCR_WIDTH) / f32(SCR_HEIGHT)), 0.1, 100)
189
190		shader_set_mat4(shaderProgram, "projection", projection)
191		shader_set_mat4(shaderProgram, "view", view)
192
193		gl.BindVertexArray(VAO)
194		for position, i in cubePositions {
195			model: glsl.mat4 = 1
196			model *= glsl.mat4Translate(position)
197			angle := 20.0 * f32(i)
198			model *= glsl.mat4Rotate({1.0, 0.3, 0.5}, glsl.radians(angle))
199			shader_set_mat4(shaderProgram, "model", model)
200
201			gl.DrawArrays(gl.TRIANGLES, 0, 36)
202		}
203
204		glfw.SwapBuffers(window)
205		glfw.PollEvents()
206	}
207
208	gl.DeleteVertexArrays(1, &VAO)
209	gl.DeleteBuffers(1, &VBO)
210	gl.DeleteProgram(shaderProgram)
211
212	glfw.Terminate()
213}

shader.odin ¶
73 linesSource

1package main
2
3import gl "vendor:OpenGL"
4import "core:math/linalg/glsl"
5
6shader_set_bool :: proc(id: u32, name: cstring, value: bool) {
7	gl.Uniform1i(gl.GetUniformLocation(id, name), i32(value))
8}
9
10shader_set_int :: proc(id: u32, name: cstring, value: i32) {
11	gl.Uniform1i(gl.GetUniformLocation(id, name), value)
12}
13
14shader_set_float :: proc(id: u32, name: cstring, value: f32) {
15	gl.Uniform1f(gl.GetUniformLocation(id, name), value)
16}
17
18shader_set_vec2_v :: proc(id: u32, name: cstring, value: glsl.vec2) {
19	lc := value
20	gl.Uniform2fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc))
21}
22
23shader_set_vec2_f :: proc(id: u32, name: cstring, x, y: f32) {
24	gl.Uniform2f(gl.GetUniformLocation(id, name), x, y)
25}
26
27shader_set_vec2 :: proc {
28	shader_set_vec2_v,
29	shader_set_vec2_f,
30}
31
32shader_set_vec3_v :: proc(id: u32, name: cstring, value: glsl.vec3) {
33	lc := value
34	gl.Uniform3fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc))
35}
36
37shader_set_vec3_f :: proc(id: u32, name: cstring, x, y, z: f32) {
38	gl.Uniform3f(gl.GetUniformLocation(id, name), x, y, z)
39}
40
41shader_set_vec3 :: proc {
42	shader_set_vec3_v,
43	shader_set_vec3_f,
44}
45
46shader_set_vec4_v :: proc(id: u32, name: cstring, value: glsl.vec4) {
47	lc := value
48	gl.Uniform4fv(gl.GetUniformLocation(id, name), 1, raw_data(&lc))
49}
50
51shader_set_vec4_f :: proc(id: u32, name: cstring, x, y, z, w: f32) {
52	gl.Uniform4f(gl.GetUniformLocation(id, name), x, y, z, w)
53}
54
55shader_set_vec4 :: proc {
56	shader_set_vec4_v,
57	shader_set_vec4_f,
58}
59
60shader_set_mat2 :: proc(id: u32, name: cstring, mat: glsl.mat2) {
61	lc := mat
62	gl.UniformMatrix2fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc))
63}
64
65shader_set_mat3 :: proc(id: u32, name: cstring, mat: glsl.mat3) {
66	lc := mat
67	gl.UniformMatrix3fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc))
68}
69
70shader_set_mat4 :: proc(id: u32, name: cstring, mat: glsl.mat4) {
71	lc := mat
72	gl.UniformMatrix4fv(gl.GetUniformLocation(id, name), 1, gl.FALSE, raw_data(&lc))
73}

Shaders

res/fragment.fs ¶
13 linesSource

#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);
}

res/vertex.vs ¶
15 linesSource

#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);
}

Declarations Used 91