src/shader.c

changeset 139
5d655459db85
parent 137
f8e6e0ae61a8
equal deleted inserted replaced
138:2ceb0368b02d 139:5d655459db85
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 }

mercurial