41 * |
41 * |
42 * The ID of the returned shader will be zero when something went wrong. |
42 * The ID of the returned shader will be zero when something went wrong. |
43 * |
43 * |
44 * @param type the shader type (use the GL enum) |
44 * @param type the shader type (use the GL enum) |
45 * @param code the source code |
45 * @param code the source code |
|
46 * @param code_pp the optional preprocessor code |
46 * @return the compiled shader |
47 * @return the compiled shader |
47 */ |
48 */ |
48 static unsigned asc_shader_compile(unsigned int type, char const *code) { |
49 static unsigned asc_shader_compile(unsigned int type, const char *code, const char *code_pp) { |
49 GLuint id = glCreateShader(type); |
50 GLuint id = glCreateShader(type); |
50 if (id == 0) { |
51 if (id == 0) { |
51 asc_error("glCreateShader failed: %s", glGetError()); |
52 asc_error("glCreateShader failed: %s", glGetError()); |
52 return 0; |
53 return 0; |
53 } |
54 } |
54 |
55 |
55 GLint success; |
56 GLint success; |
56 int length = (int) strlen(code); // must be int because of OpenGL API |
57 const char *code_array[4]; |
57 glShaderSource(id, 1, &code, &length); |
58 GLint length_array[4]; |
|
59 #define store_str(i, s) do {cxstring cxs = cx_str(s); code_array[i] = cxs.ptr; length_array[i] = (GLint) cxs.length;} while(0) |
|
60 store_str(0, "#version 400 core\n"); |
|
61 store_str(1, code_pp); |
|
62 store_str(2, "\n#line 1\n"); |
|
63 store_str(3, code); |
|
64 #undef store_str |
|
65 |
|
66 // compile |
|
67 glShaderSource(id, cx_nmemb(length_array), code_array, length_array); |
58 glCompileShader(id); |
68 glCompileShader(id); |
59 glGetShaderiv(id, GL_COMPILE_STATUS, &success); |
69 glGetShaderiv(id, GL_COMPILE_STATUS, &success); |
60 if (success) { |
70 if (success) { |
61 asc_dprintf("Shader %u compiled", id); |
71 asc_dprintf("Shader %u compiled", id); |
62 return id; |
72 return id; |
119 glDeleteProgram(program->id); |
129 glDeleteProgram(program->id); |
120 } |
130 } |
121 program->id = 0; |
131 program->id = 0; |
122 } |
132 } |
123 |
133 |
124 int asc_shader_sprite_init(AscShaderSprite *sprite) { |
|
125 AscShaderCodes codes; |
|
126 if (asc_shader_load_code_files((AscShaderCodeFiles){ |
|
127 .vtx = "sprite_vtx.glsl", |
|
128 .frag = "sprite_frag.glsl" |
|
129 }, &codes)) { |
|
130 asc_error("Loading sprite shader failed."); |
|
131 return 1; |
|
132 } |
|
133 sprite->program = asc_shader_program_create(codes); |
|
134 if (asc_has_error()) { |
|
135 asc_shader_free_codes(codes); |
|
136 return 1; |
|
137 } |
|
138 sprite->depth = glGetUniformLocation(sprite->program.id, "depth"); |
|
139 sprite->rect_tex = glGetUniformLocation(sprite->program.id, "rect_tex"); |
|
140 sprite->uv_tex = glGetUniformLocation(sprite->program.id, "uv_tex"); |
|
141 asc_shader_free_codes(codes); |
|
142 return 0; |
|
143 } |
|
144 |
|
145 AscShaderProgram asc_shader_program_create(AscShaderCodes codes) { |
134 AscShaderProgram asc_shader_program_create(AscShaderCodes codes) { |
146 unsigned shader[4]; |
135 unsigned shader[4]; |
147 unsigned n = 0; |
136 unsigned n = 0; |
148 if (codes.vtx) { |
137 if (codes.vtx) { |
149 shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx); |
138 shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp); |
150 } |
139 } |
151 if (codes.frag) { |
140 if (codes.frag) { |
152 shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag); |
141 shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp); |
153 } |
142 } |
154 const AscShaderProgram prog = asc_shader_link(shader, n); |
143 const AscShaderProgram prog = asc_shader_link(shader, n); |
155 for (unsigned i = 0; i < n; i++) { |
144 for (unsigned i = 0; i < n; i++) { |
156 glDeleteShader(shader[i]); |
145 glDeleteShader(shader[i]); |
157 } |
146 } |
158 return prog; |
147 return prog; |
|
148 } |
|
149 |
|
150 void asc_shader_program_use(const AscShaderProgram *shader, const AscCamera *camera) { |
|
151 glUseProgram(shader->id); |
|
152 glUniformMatrix4fv(shader->projection, 1, GL_FALSE, camera->projection); |
|
153 glUniformMatrix4fv(shader->view, 1, GL_FALSE, camera->view); |
159 } |
154 } |
160 |
155 |
161 static int asc_shader_load_code_file(const char *filename, char **code) { |
156 static int asc_shader_load_code_file(const char *filename, char **code) { |
162 if (filename == NULL) { |
157 if (filename == NULL) { |
163 *code = NULL; |
158 *code = NULL; |
175 cxBufferShrink(&buffer, 0); |
170 cxBufferShrink(&buffer, 0); |
176 *code = buffer.space; |
171 *code = buffer.space; |
177 return *code == NULL ? -1 : 0; |
172 return *code == NULL ? -1 : 0; |
178 } |
173 } |
179 |
174 |
180 int asc_shader_load_code_files(AscShaderCodeFiles files, AscShaderCodes *codes) { |
175 int asc_shader_load_code_files(AscShaderCodeInfo info, AscShaderCodes *codes) { |
181 int ret = 0; |
176 int ret = 0; |
182 ret |= asc_shader_load_code_file(files.vtx, &codes->vtx); |
177 ret |= asc_shader_load_code_file(info.files.vtx, &codes->vtx); |
183 ret |= asc_shader_load_code_file(files.frag, &codes->frag); |
178 codes->vtx_pp = info.defines.vtx; |
|
179 ret |= asc_shader_load_code_file(info.files.frag, &codes->frag); |
|
180 codes->frag_pp = info.defines.frag; |
184 return ret; |
181 return ret; |
185 } |
182 } |
186 |
183 |
187 void asc_shader_free_codes(AscShaderCodes codes) { |
184 void asc_shader_free_codes(AscShaderCodes codes) { |
188 cxFreeDefault(codes.vtx); |
185 cxFreeDefault(codes.vtx); |