…aaand add PREFIX to the freebsd makefile too
[voxelands-alt.git] / src / graphics / shader.c
blobd6f7e56d1243483534787f5c876c59f3617e03f6
1 /************************************************************************
2 * shader.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #include "graphics.h"
22 #include "file.h"
23 #include "list.h"
25 #include <string.h>
27 static shader_t *shaders = NULL;
28 static shader_t *active = NULL;
30 static GLuint shader_load(file_t *f, GLenum type)
32 GLint i;
33 GLuint s = 0;
35 if (!f)
36 return s;
38 s = glCreateShader(type);
39 glShaderSource(s, 1, (const GLchar**)&f->data,NULL);
40 glCompileShader(s);
41 glGetShaderiv(s,GL_COMPILE_STATUS,&i);
42 if (i == GL_FALSE) {
43 char buff[512];
44 glGetShaderInfoLog(s,512,&i,buff);
45 vlprintf("Shader %s failed to compile: %s",f->name,buff);
46 glDeleteShader(s);
47 s = 0;
50 return s;
53 shader_t *shader_create(char* name)
55 char buff[512];
56 file_t *vert;
57 file_t *geom;
58 file_t *frag;
59 shader_t *s;
60 GLint i;
62 if (snprintf(buff,512,"%s_vertex.glsl",name) < 512)
63 vert = file_load("shader",buff);
64 if (snprintf(buff,512,"%s_geometry.glsl",name) < 512)
65 geom = file_load("shader",buff);
66 if (snprintf(buff,512,"%s_fragment.glsl",name) < 512)
67 frag = file_load("shader",buff);
69 if (!vert && !geom && !frag)
70 return NULL;
72 s = malloc(sizeof(shader_t));
73 if (!s) {
74 if (vert)
75 file_free(vert);
76 if (geom)
77 file_free(geom);
78 if (frag)
79 file_free(frag);
80 return NULL;
83 strncpy(s->name,name,256);
84 s->active = 0;
85 s->program = 0;
86 s->vert = 0;
87 s->geom = 0;
88 s->frag = 0;
90 if (vert)
91 s->vert = shader_load(vert,GL_VERTEX_SHADER);
92 if (geom)
93 s->geom = shader_load(geom,GL_GEOMETRY_SHADER);
94 if (frag)
95 s->frag = shader_load(frag,GL_FRAGMENT_SHADER);
97 if (!s->vert && !s->geom && !s->frag) {
98 if (vert)
99 file_free(vert);
100 if (geom)
101 file_free(geom);
102 if (frag)
103 file_free(frag);
104 free(s);
105 return NULL;
108 s->program = glCreateProgram();
109 if (s->vert)
110 glAttachShader(s->program,s->vert);
111 if (s->geom)
112 glAttachShader(s->program,s->geom);
113 if (s->frag)
114 glAttachShader(s->program,s->frag);
115 glLinkProgram(s->program);
116 glGetProgramiv(s->program, GL_LINK_STATUS, &i);
117 if (i == GL_FALSE) {
118 glGetProgramInfoLog(s->program, 512, &i, buff);
119 vlprintf("Shader failed to link: %s",buff);
122 glValidateProgram(s->program);
124 if (vert)
125 file_free(vert);
126 if (geom)
127 file_free(geom);
128 if (frag)
129 file_free(frag);
131 shaders = list_push(&shaders,s);
133 return s;
136 /* free a shader */
137 void shader_free(shader_t *s)
139 if (!s)
140 return;
142 if (s->active)
143 shader_disable(s);
145 glDetachShader(s->program,s->vert);
146 glDetachShader(s->program,s->frag);
147 glDeleteShader(s->vert);
148 glDeleteShader(s->frag);
149 glDeleteProgram(s->program);
151 free(s);
154 /* bind an attribute to a shader */
155 int shader_attribute(shader_t *s, int att, char* name)
157 if (!s)
158 return 1;
160 glBindAttribLocation(s->program,att,name);
161 glLinkProgram(s->program);
162 glValidateProgram(s->program);
164 return 0;
167 /* set a shader uniform value */
168 int shader_uniform_int(shader_t *s, char* name, int value)
170 GLuint var;
171 if (!s)
172 s = active;
173 if (!s)
174 return 1;
176 var = glGetUniformLocation(s->program,name);
177 glUniform1i(var,value);
179 return 0;
182 /* set a shader uniform value */
183 int shader_uniform_float(shader_t *s, char* name, float value)
185 GLuint var;
186 if (!s)
187 s = active;
188 if (!s)
189 return 1;
191 var = glGetUniformLocation(s->program,name);
192 glUniform1f(var,value);
194 return 0;
197 /* set a shader uniform value */
198 int shader_uniform_v2(shader_t *s, char* name, v2_t *value)
200 GLuint var;
201 if (!s)
202 s = active;
203 if (!s)
204 return 1;
206 var = glGetUniformLocation(s->program,name);
207 glUniform2f(var,value->x,value->y);
209 return 0;
212 /* set a shader uniform value */
213 int shader_uniform_v3(shader_t *s, char* name, v3_t *value)
215 GLuint var;
216 if (!s)
217 s = active;
218 if (!s)
219 return 1;
221 var = glGetUniformLocation(s->program,name);
222 glUniform3f(var,value->x,value->y,value->z);
224 return 0;
227 /* set a shader uniform value */
228 int shader_uniform_matrix(shader_t *s, char* name, matrix_t *value)
230 GLuint var;
231 if (!s)
232 s = active;
233 if (!s)
234 return 1;
236 var = glGetUniformLocation(s->program,name);
237 glUniformMatrix4fv(var,1,GL_FALSE,value->data);
239 return 0;
242 /* use a shader */
243 int shader_enable(shader_t *s)
245 if (!s || s->active)
246 return 1;
248 if (active)
249 shader_disable(active);
251 glUseProgram(s->program);
252 s->active = 1;
254 active = s;
256 return 0;
259 /* stop using a shader */
260 int shader_disable(shader_t *s)
262 if (!s || !s->active)
263 return 1;
265 active = NULL;
267 glUseProgram(0);
268 s->active = 0;
270 return 0;