97 } |
97 } |
98 |
98 |
99 /** |
99 /** |
100 * This function links shaders into a program. |
100 * This function links shaders into a program. |
101 * |
101 * |
102 * The ID of the returned program will be zero when something went wrong. |
102 * The OpenGL ID of the program will be zero when something went wrong. |
103 * |
103 * |
104 * @param shader the shader IDs to link |
104 * @param shader the shader IDs to link |
105 * @param n the number of shaders |
105 * @param n the number of shaders |
106 * @param prog the struct where to store the result |
106 * @param prog the struct where to store the result |
107 * @retval zero success |
|
108 * @retval non-zero failure |
|
109 */ |
107 */ |
110 static int asc_shader_link(unsigned shader[], unsigned n, AscShaderProgram *prog) { |
108 static void asc_shader_link(unsigned shader[], unsigned n, AscShaderProgram *prog) { |
|
109 prog->gl_id = 0; |
111 GLint success; |
110 GLint success; |
112 GLint id = glCreateProgram(); |
111 GLint id = glCreateProgram(); |
113 if (id <= 0) { |
112 if (id <= 0) { |
|
113 for (unsigned i = 0; i < n; i++) { |
|
114 asc_dprintf("Delete shader: %u", shader[i]); |
|
115 glDeleteShader(shader[i]); |
|
116 } |
114 asc_error("glCreateProgram failed: %s", glGetError()); |
117 asc_error("glCreateProgram failed: %s", glGetError()); |
115 return -1; |
118 return; |
116 } |
119 } |
117 for (unsigned i = 0; i < n; i++) { |
120 for (unsigned i = 0; i < n; i++) { |
118 glAttachShader(id, shader[i]); |
121 glAttachShader(id, shader[i]); |
119 } |
122 } |
120 glLinkProgram(id); |
123 glLinkProgram(id); |
121 glGetProgramiv(id, GL_LINK_STATUS, &success); |
124 glGetProgramiv(id, GL_LINK_STATUS, &success); |
122 for (unsigned i = 0; i < n; i++) { |
125 for (unsigned i = 0; i < n; i++) { |
|
126 asc_dprintf("Delete shader: %u", shader[i]); |
123 glDeleteShader(shader[i]); |
127 glDeleteShader(shader[i]); |
124 } |
128 } |
125 if (success) { |
129 if (success) { |
126 asc_dprintf("Shader Program %u linked.", id); |
130 asc_dprintf("Shader Program %u linked.", id); |
127 prog->gl_id = id; |
131 prog->gl_id = id; |
128 // by convention every shader shall have MVP matrices |
132 // by convention every shader shall have MVP matrices |
129 prog->model = glGetUniformLocation(id, "model"); |
133 prog->model = glGetUniformLocation(id, "model"); |
130 prog->view = glGetUniformLocation(id, "view"); |
134 prog->view = glGetUniformLocation(id, "view"); |
131 prog->projection = glGetUniformLocation(id, "projection"); |
135 prog->projection = glGetUniformLocation(id, "projection"); |
132 return 0; |
|
133 } else { |
136 } else { |
134 char *log = malloc(1024); |
137 char *log = malloc(1024); |
135 glGetProgramInfoLog(id, 1024, NULL, log); |
138 glGetProgramInfoLog(id, 1024, NULL, log); |
136 glDeleteProgram(id); |
139 glDeleteProgram(id); |
137 asc_error("Linking shader program %u failed.\n%s", id, log); |
140 asc_error("Linking shader program %u failed.\n%s", id, log); |
138 free(log); |
141 free(log); |
139 return -1; |
|
140 } |
142 } |
141 } |
143 } |
142 |
144 |
143 void asc_shader_free(AscShaderProgram *program) { |
145 void asc_shader_free(AscShaderProgram *program) { |
144 if (program->gl_id > 0) { |
146 if (program->gl_id > 0) { |
149 program->destr_func(program); |
151 program->destr_func(program); |
150 } |
152 } |
151 cxFreeDefault(program); |
153 cxFreeDefault(program); |
152 } |
154 } |
153 |
155 |
|
156 bool asc_shader_invalid(const AscShaderProgram *program) { |
|
157 return program == NULL || program->gl_id == 0; |
|
158 } |
|
159 |
154 void *asc_shader_create(AscShaderCodes codes, size_t mem_size) { |
160 void *asc_shader_create(AscShaderCodes codes, size_t mem_size) { |
155 AscShaderProgram *prog = cxZallocDefault(mem_size); |
161 AscShaderProgram *prog = cxZallocDefault(mem_size); |
156 unsigned shader[2]; |
162 unsigned shader[2]; |
157 unsigned n = 0; |
163 unsigned n = 0; |
158 bool shader_compile_error = false; |
|
159 // TODO: clean up this pp mess by introducing proper nested structs |
164 // TODO: clean up this pp mess by introducing proper nested structs |
160 if (codes.vtx) { |
165 if (codes.vtx) { |
161 shader[n] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp, codes.vtx_pp_list, codes.vtx_pp_list_select); |
166 shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp, codes.vtx_pp_list, codes.vtx_pp_list_select); |
162 shader_compile_error |= shader[n] == 0; |
|
163 n++; |
|
164 } |
167 } |
165 if (codes.frag) { |
168 if (codes.frag) { |
166 shader[n] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp, codes.frag_pp_list, codes.frag_pp_list_select); |
169 shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp, codes.frag_pp_list, codes.frag_pp_list_select); |
167 shader_compile_error |= shader[n] == 0; |
170 } |
168 n++; |
171 asc_shader_link(shader, n, prog); |
169 } |
|
170 if (shader_compile_error || asc_shader_link(shader, n, prog)) { |
|
171 cxFreeDefault(prog); |
|
172 prog = NULL; |
|
173 } |
|
174 for (unsigned i = 0; i < n; i++) { |
|
175 if (shader[i] > 0) { |
|
176 asc_dprintf("Delete shader: %u", shader[i]); |
|
177 glDeleteShader(shader[i]); |
|
178 } |
|
179 } |
|
180 return prog; |
172 return prog; |
181 } |
173 } |
182 |
174 |
183 void asc_shader_use(const AscShaderProgram *shader, const AscCamera *camera) { |
175 void asc_shader_use(const AscShaderProgram *shader, const AscCamera *camera) { |
184 if (shader == NULL) { |
176 if (shader == NULL) { |