85 * |
85 * |
86 * The ID of the returned program will be zero when something went wrong. |
86 * The ID of the returned program will be zero when something went wrong. |
87 * |
87 * |
88 * @param shader the shader IDs to link |
88 * @param shader the shader IDs to link |
89 * @param n the number of shaders |
89 * @param n the number of shaders |
90 * @return a compiled program |
90 * @param prog the struct where to store the result |
|
91 * @retval zero success |
|
92 * @retval non-zero failure |
91 */ |
93 */ |
92 static AscShaderProgram asc_shader_link(unsigned shader[], unsigned n) { |
94 static int asc_shader_link(unsigned shader[], unsigned n, AscShaderProgram *prog) { |
93 GLint success; |
95 GLint success; |
94 GLint id = glCreateProgram(); |
96 GLint id = glCreateProgram(); |
95 if (id <= 0) { |
97 if (id <= 0) { |
96 asc_error("glCreateProgram failed: %s", glGetError()); |
98 asc_error("glCreateProgram failed: %s", glGetError()); |
97 return (AscShaderProgram) {0}; |
99 return -1; |
98 } |
100 } |
99 for (unsigned i = 0; i < n; i++) { |
101 for (unsigned i = 0; i < n; i++) { |
100 glAttachShader(id, shader[i]); |
102 glAttachShader(id, shader[i]); |
101 } |
103 } |
102 glLinkProgram(id); |
104 glLinkProgram(id); |
104 for (unsigned i = 0; i < n; i++) { |
106 for (unsigned i = 0; i < n; i++) { |
105 glDeleteShader(shader[i]); |
107 glDeleteShader(shader[i]); |
106 } |
108 } |
107 if (success) { |
109 if (success) { |
108 asc_dprintf("Shader Program %u linked.", id); |
110 asc_dprintf("Shader Program %u linked.", id); |
109 AscShaderProgram prog; |
111 prog->gl_id = id; |
110 prog.id = id; |
|
111 // by convention every shader shall have MVP matrices |
112 // by convention every shader shall have MVP matrices |
112 prog.model = glGetUniformLocation(id, "model"); |
113 prog->model = glGetUniformLocation(id, "model"); |
113 prog.view = glGetUniformLocation(id, "view"); |
114 prog->view = glGetUniformLocation(id, "view"); |
114 prog.projection = glGetUniformLocation(id, "projection"); |
115 prog->projection = glGetUniformLocation(id, "projection"); |
115 return prog; |
116 return 0; |
116 } else { |
117 } else { |
117 char *log = malloc(1024); |
118 char *log = malloc(1024); |
118 glGetProgramInfoLog(id, 1024, NULL, log); |
119 glGetProgramInfoLog(id, 1024, NULL, log); |
119 glDeleteProgram(id); |
120 glDeleteProgram(id); |
120 asc_error("Linking shader program %u failed.\n%s", id, log); |
121 asc_error("Linking shader program %u failed.\n%s", id, log); |
121 free(log); |
122 free(log); |
122 return (AscShaderProgram) {0}; |
123 return -1; |
123 } |
124 } |
124 } |
125 } |
125 |
126 |
126 void asc_shader_program_destroy(AscShaderProgram *program) { |
127 void asc_shader_free(AscShaderProgram *program) { |
127 if (program->id > 0) { |
128 if (program->gl_id > 0) { |
128 asc_dprintf("Delete Shader Program %u", program->id); |
129 asc_dprintf("Delete Shader Program %u", program->gl_id); |
129 glDeleteProgram(program->id); |
130 glDeleteProgram(program->gl_id); |
130 } |
131 } |
131 program->id = 0; |
132 if (program->destr_func) { |
132 } |
133 program->destr_func(program); |
133 |
134 } |
134 AscShaderProgram asc_shader_program_create(AscShaderCodes codes) { |
135 cxFreeDefault(program); |
135 unsigned shader[4]; |
136 } |
|
137 |
|
138 void *asc_shader_create(AscShaderCodes codes, size_t mem_size) { |
|
139 AscShaderProgram *prog = cxZallocDefault(mem_size); |
|
140 unsigned shader[2]; |
136 unsigned n = 0; |
141 unsigned n = 0; |
137 if (codes.vtx) { |
142 if (codes.vtx) { |
138 shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp); |
143 shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp); |
139 } |
144 } |
140 if (codes.frag) { |
145 if (codes.frag) { |
141 shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp); |
146 shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp); |
142 } |
147 } |
143 const AscShaderProgram prog = asc_shader_link(shader, n); |
148 if (asc_shader_link(shader, n, prog)) { |
|
149 cxFreeDefault(prog); |
|
150 prog = NULL; |
|
151 } |
144 for (unsigned i = 0; i < n; i++) { |
152 for (unsigned i = 0; i < n; i++) { |
|
153 asc_dprintf("Delete shader: %u", shader[i]); |
145 glDeleteShader(shader[i]); |
154 glDeleteShader(shader[i]); |
146 } |
155 } |
147 return prog; |
156 return prog; |
148 } |
157 } |
149 |
158 |
150 void asc_shader_program_use(const AscShaderProgram *shader, const AscCamera *camera) { |
159 void asc_shader_use(const AscShaderProgram *shader, const AscCamera *camera) { |
151 glUseProgram(shader->id); |
160 glUseProgram(shader->gl_id); |
152 glUniformMatrix4fv(shader->projection, 1, GL_FALSE, camera->projection); |
161 glUniformMatrix4fv(shader->projection, 1, GL_FALSE, camera->projection); |
153 glUniformMatrix4fv(shader->view, 1, GL_FALSE, camera->view); |
162 glUniformMatrix4fv(shader->view, 1, GL_FALSE, camera->view); |
154 } |
163 } |
155 |
164 |
156 static int asc_shader_load_code_file(const char *filename, char **code) { |
165 static int asc_shader_load_code_file(const char *filename, char **code) { |
183 |
192 |
184 void asc_shader_free_codes(AscShaderCodes codes) { |
193 void asc_shader_free_codes(AscShaderCodes codes) { |
185 cxFreeDefault(codes.vtx); |
194 cxFreeDefault(codes.vtx); |
186 cxFreeDefault(codes.frag); |
195 cxFreeDefault(codes.frag); |
187 } |
196 } |
|
197 |
|
198 AscShaderProgram *asc_shader_register(unsigned int id, asc_shader_create_func create_func) { |
|
199 AscGLContext *glctx = asc_active_glctx; |
|
200 AscShaderProgram *prog = NULL; |
|
201 #ifndef NDEBUG |
|
202 prog = asc_shader_lookup(id); |
|
203 if (prog != NULL) { |
|
204 asc_error("Shader program %u already exists. This is a bug!", id); |
|
205 // still return it, so that the caller does not die immediately |
|
206 return prog; |
|
207 } |
|
208 #endif |
|
209 prog = create_func(); |
|
210 prog->id = id; |
|
211 cxListAdd(glctx->shaders, prog); |
|
212 return prog; |
|
213 } |
|
214 |
|
215 AscShaderProgram *asc_shader_lookup(unsigned int id) { |
|
216 CxIterator iter = cxListIterator(asc_active_glctx->shaders); |
|
217 cx_foreach(AscShaderProgram *, prog, iter) { |
|
218 if (prog->id == id) return prog; |
|
219 } |
|
220 return NULL; |
|
221 } |
|
222 |
|
223 AscShaderProgram *asc_shader_lookup_or_create(unsigned int id, asc_shader_create_func create_func) { |
|
224 AscShaderProgram *prog = asc_shader_lookup(id); |
|
225 if (prog == NULL) { |
|
226 return asc_shader_register(id, create_func); |
|
227 } |
|
228 return prog; |
|
229 } |