summaryrefslogtreecommitdiff
path: root/in_practice/breakout/shader.c
blob: 2fff3c4f6a2452c0a7aa6a6bc2ad9b295b63bfda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "shader.h"
#include "sys.h"

#include <GL/glew.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

shader_t shaders[MAX_SHADERS] = {0};

static u32 compile_shader(GLenum type, const char *dir, const char *filename)
{
	char path[512] = {0};
	snprintf(path, 512, "%s/%s", (dir ? dir : "."), filename);
	const char *src = (const char *)read_entire_file(path);
	if (!src) {
		info("failed to read the file \"%s\"", path);
		return 0;
	}
	u32 id = glCreateShader(type);
	glShaderSource(id, 1, &src, 0);
	free((void *)src);
	glCompileShader(id);
	i32 status;
	glGetShaderiv(id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		char log[512];
		glGetShaderInfoLog(id, 512, 0, log);
		info("failed to compile \"%s\"\n%s", path, log);
	} else {
		info("\"%s\" compiled successfully", path);
	}
	return id;
}

u32 load_shader(const char *dir, const char *vertex_filename, const char *fragment_filename, const char *geometry_filename, const char *name)
{
	if (get_shader(name)) {
		info("shader \"%s\" already exist", name);
		return 0;
	}
	u32 id = glCreateProgram();
	u32 vert = compile_shader(GL_VERTEX_SHADER, dir, vertex_filename);
	glAttachShader(id, vert);
	u32 frag = compile_shader(GL_FRAGMENT_SHADER, dir, fragment_filename);
	glAttachShader(id, frag);
	u32 geom = 0;
	if (geometry_filename) {
		geom = compile_shader(GL_GEOMETRY_SHADER, dir, geometry_filename);
		glAttachShader(id, geom);
	}
	glLinkProgram(id);
	i32 success;
	glGetProgramiv(id, GL_LINK_STATUS, &success);
	if (success == GL_FALSE) {
		char log[512];
		glGetProgramInfoLog(id, 512, 0, log);
		info("failed to link shader:\n%s", log);
	}
	glDeleteShader(vert);
	glDeleteShader(frag);
	if (geometry_filename)
		glDeleteShader(geom);
	shader_t shader = {id, name};
	i32 i;
	for (i = 0; i < MAX_SHADERS; i++) {
		if (!shaders[i].id) {
			shaders[i] = shader;
			return id;
		}
	}
	info("shader limit (%d) reached", MAX_SHADERS);
	glDeleteProgram(id);
	return 0;
}

u32 get_shader(const char *name)
{
	for (i32 i = 0; i < MAX_SHADERS; i++)
		if (shaders[i].name && strstr(shaders[i].name, name))
			return shaders[i].id;
	return 0;
}

void uniform_f32(u32 id, const char *name, f32 v)
{
	u32 loc = glGetUniformLocation(id, name);
	glUniform1f(loc, v);
}

void uniform_v3(u32 id, const char *name, v3 v)
{
	u32 loc = glGetUniformLocation(id, name);
	glUniform3fv(loc, 1, (const f32 *)&v);
}

void uniform_mat(u32 id, const char *name, mat m)
{
	u32 loc = glGetUniformLocation(id, name);
	glUniformMatrix4fv(loc, 1, 0, (const f32 *)&m);
}