]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/shader.c
Make texture batching optional (for OpenGL 3.3 compat)
[dragonblocks_alpha.git] / src / client / shader.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include "client/client_config.h"
6 #include "client/opengl.h"
7 #include "client/shader.h"
8
9 static GLuint compile_shader(GLenum type, const char *path, const char *name, GLuint program, const char *def)
10 {
11         char full_path[strlen(path) + 1 + strlen(name) + 1 + 4 + 1];
12         sprintf(full_path, "%s/%s.glsl", path, name);
13
14         FILE *file = fopen(full_path, "r");
15         if (!file) {
16                 perror("fopen");
17                 return 0;
18         }
19
20         if (fseek(file, 0, SEEK_END) == -1) {
21                 perror("fseek");
22                 fclose(file);
23                 return 0;
24         }
25
26         long size = ftell(file);
27
28         if (size == 1) {
29                 perror("ftell");
30                 fclose(file);
31                 return 0;
32         }
33
34         if (fseek(file, 0, SEEK_SET) == -1) {
35                 perror("fseek");
36                 fclose(file);
37                 return 0;
38         }
39
40         char code[size];
41
42         if (fread(code, 1, size, file) != (size_t) size) {
43                 perror("fread");
44                 fclose(file);
45                 return 0;
46         }
47
48         fclose(file);
49
50         GLuint id = glCreateShader(type); GL_DEBUG
51
52         const char *version = client_config.texture_batching
53                 ? "#version 400 core\n"
54                 : "#version 330 core\n";
55
56         const char *code_list[3] = {
57                 version,
58                 def,
59                 code,
60         };
61
62         int size_list[3] = {
63                 18,
64                 strlen(def),
65                 size,
66         };
67
68         glShaderSource(id, 3, code_list, size_list); GL_DEBUG
69
70         glCompileShader(id); GL_DEBUG
71
72         GLint success;
73         glGetShaderiv(id, GL_COMPILE_STATUS, &success); GL_DEBUG
74         if (!success) {
75                 char errbuf[BUFSIZ];
76                 glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG
77                 fprintf(stderr, "[error] failed to compile shader %s: %s", full_path, errbuf);
78                 glDeleteShader(id); GL_DEBUG
79                 return 0;
80         }
81
82         glAttachShader(program, id); GL_DEBUG
83
84         return id;
85 }
86
87 GLuint shader_program_create(const char *path, const char *def)
88 {
89         GLuint id = glCreateProgram(); GL_DEBUG
90
91         if (!def)
92                 def = "";
93
94         GLuint vert, frag;
95
96         if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, def))) {
97                 glDeleteProgram(id); GL_DEBUG
98                 abort();
99         }
100
101         if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, def))) {
102                 glDeleteShader(vert); GL_DEBUG
103                 glDeleteProgram(id); GL_DEBUG
104                 abort();
105         }
106
107         glLinkProgram(id); GL_DEBUG
108         glDeleteShader(vert); GL_DEBUG
109         glDeleteShader(frag); GL_DEBUG
110
111         GLint success;
112         glGetProgramiv(id, GL_LINK_STATUS, &success); GL_DEBUG
113         if (!success) {
114                 char errbuf[BUFSIZ];
115                 glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG
116                 fprintf(stderr, "[error] failed to link shader program %s: %s\n", path, errbuf);
117                 glDeleteProgram(id); GL_DEBUG
118                 return false;
119         }
120
121         return id;
122 }