4 Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
6 This file is part of simavr.
8 simavr is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 simavr is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with simavr. If not, see <http://www.gnu.org/licenses/>.
23 #define GL_GLEXT_PROTOTYPES
24 #include <GLUT/glut.h>
25 #include <OpenGL/gl.h>
26 #include <OpenGL/glext.h>
28 #define GL_GLEXT_PROTOTYPES
40 #include "c3program.h"
42 #include "c3driver_context.h"
46 #define GLCHECK(_w) {_w; dumpError(#_w);}
48 static int dumpError(const char * what)
52 while ((e = glGetError()) != GL_NO_ERROR) {
53 printf("%s: %s\n", what, gluErrorString(e));
63 if (!p || p->pid || p->log)
67 printf("%s loading %s\n", __func__, p->name->str);
68 for (int si = 0; si < p->shaders.count && !p->log; si++) {
69 c3shader_p s = &p->shaders.e[si];
72 printf("%s compiling shader %s\n", __func__, s->name->str);
74 s->sid = (c3apiobject_t)glCreateShader(s->type);
75 const GLchar * pgm = s->shader->str;
76 glShaderSource((GLuint)s->sid, 1, &pgm, NULL);
78 glCompileShader((GLuint)s->sid);
81 glGetShaderiv((GLuint)s->sid, GL_COMPILE_STATUS, &status);
83 if (status != GL_FALSE)
87 glGetShaderiv((GLuint)s->sid, GL_INFO_LOG_LENGTH, &infoLogLength);
89 p->log = str_alloc(infoLogLength);
90 glGetShaderInfoLog((GLuint)s->sid, infoLogLength, NULL, p->log->str);
92 fprintf(stderr, "%s compile %s: %s\n", __func__, s->name->str, p->log->str);
97 p->pid = (c3apiobject_t)glCreateProgram();
99 for (int si = 0; si < p->shaders.count && !p->log; si++) {
100 c3shader_p s = &p->shaders.e[si];
102 glAttachShader((GLuint)p->pid, (GLuint)s->sid);
104 glLinkProgram((GLuint)p->pid);
107 glGetProgramiv((GLuint)p->pid, GL_LINK_STATUS, &status);
109 for (int si = 0; si < p->shaders.count && !p->log; si++) {
110 c3shader_p s = &p->shaders.e[si];
112 glDetachShader((GLuint)p->pid, (GLuint)s->sid);
113 glDeleteShader((GLuint)s->sid);
117 if (status == GL_FALSE) {
119 glGetProgramiv((GLuint)p->pid, GL_INFO_LOG_LENGTH, &infoLogLength);
121 p->log = str_alloc(infoLogLength);
123 glGetProgramInfoLog((GLuint)p->pid, infoLogLength, NULL, p->log->str);
124 fprintf(stderr, "%s link %s: %s\n", __func__, p->name->str, p->log->str);
128 for (int pi = 0; pi < p->params.count; pi++) {
129 c3program_param_p pa = &p->params.e[pi];
130 pa->pid = (c3apiobject_t)glGetUniformLocation((GLuint)p->pid, pa->name->str);
132 printf("%s %s load parameter '%s'\n", __func__, p->name->str, pa->name->str);
133 if (pa->pid == (c3apiobject_t)-1) {
134 fprintf(stderr, "%s %s: parameter '%s' not found\n",
135 __func__, p->name->str, pa->name->str);
144 glDeleteProgram((GLuint)p->pid);
152 GLuint mode = pix->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
155 printf("%s Creating texture %s %dx%d\n",
156 __func__, pix->name ? pix->name->str : "", pix->w, pix->h);
159 GLCHECK(glEnable(mode));
161 glGenTextures(1, &texID);
162 // glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
163 // GL_MODULATE); //set texture environment parameters
164 // dumpError("glTexEnvf");
166 glPixelStorei(GL_UNPACK_ROW_LENGTH, pix->row / pix->psize);
167 GLCHECK(glTexParameteri(mode, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
168 GLCHECK(glTexParameteri(mode, GL_TEXTURE_MIN_FILTER,
169 pix->normalize ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
170 GLCHECK(glTexParameteri(mode, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER));
171 GLCHECK(glTexParameteri(mode, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER));
173 GLCHECK(glTexParameteri(mode, GL_GENERATE_MIPMAP, GL_TRUE));
176 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
177 //printf("fLargest = %f\n", fLargest);
178 GLCHECK(glTexParameterf(mode, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest));
181 GLCHECK(glGenerateMipmap(mode));
183 pix->texture = (c3apiobject_t)texID;
188 GLCHECK(glBindTexture(mode, (GLuint)pix->texture));
189 glTexImage2D(mode, 0,
190 pix->format == C3PIXEL_A ? GL_ALPHA16 : GL_RGBA8,
192 pix->format == C3PIXEL_A ? GL_ALPHA : GL_BGRA,
195 dumpError("glTexImage2D");
197 GLCHECK(glGenerateMipmap(mode));
201 static void _c3_create_buffer(
209 glGenBuffers(1, &bid);
211 GLCHECK(glBindBuffer(GL_ARRAY_BUFFER, bid));
212 GLCHECK(glBufferData(GL_ARRAY_BUFFER,
216 GLCHECK(glEnableClientState(name));
223 if (!g->vertice.count)
227 glGenVertexArrays(1, &vao);
228 g->bid = (c3apiobject_t)vao;
230 glBindVertexArray((GLuint)g->bid);
233 * Use 'realloc' on the array as it frees the data, but leaves 'count'
234 * unchanged. We neec that for the vertices and the indexes, the others
235 * can have a straight free()
237 if (!g->vertice.buffer.bid && g->vertice.count) {
240 _c3_create_buffer(GL_VERTEX_ARRAY,
241 g->vertice.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
242 g->vertice.e, g->vertice.count * sizeof(g->vertice.e[0]),
244 glVertexPointer(3, GL_FLOAT, 0, (void*)0);
245 g->vertice.buffer.bid = (c3apiobject_t)bid;
246 if (!g->vertice.buffer.mutable)
247 c3vertex_array_realloc(&g->vertice, 0);
248 g->vertice.buffer.dirty = 0;
250 if (!g->textures.buffer.bid && g->textures.count) {
253 _c3_create_buffer(GL_TEXTURE_COORD_ARRAY,
254 g->textures.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
255 g->textures.e, g->textures.count * sizeof(g->textures.e[0]),
257 glTexCoordPointer(2, GL_FLOAT, 0, (void*)0);
258 g->textures.buffer.bid = (c3apiobject_t)bid;
259 if (!g->textures.buffer.mutable)
260 c3tex_array_free(&g->textures);
261 g->textures.buffer.dirty = 0;
263 if (!g->normals.buffer.bid && g->normals.count) {
266 _c3_create_buffer(GL_NORMAL_ARRAY,
267 g->normals.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
268 g->normals.e, g->normals.count * sizeof(g->normals.e[0]),
270 glNormalPointer(GL_FLOAT, 0, (void*) 0);
271 g->normals.buffer.bid = (c3apiobject_t)bid;
272 if (!g->normals.buffer.mutable)
273 c3vertex_array_free(&g->normals);
274 g->normals.buffer.dirty = 0;
276 if (!g->colorf.buffer.bid && g->colorf.count) {
279 _c3_create_buffer(GL_COLOR_ARRAY,
280 g->colorf.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
281 g->colorf.e, g->colorf.count * sizeof(g->colorf.e[0]),
283 glColorPointer(4, GL_FLOAT, 0, (void*) 0);
284 g->colorf.buffer.bid = (c3apiobject_t)bid;
285 if (!g->colorf.buffer.mutable)
286 c3colorf_array_free(&g->colorf);
287 g->colorf.buffer.dirty = 0;
289 if (!g->indices.buffer.bid && g->indices.count) {
291 glGenBuffers(1, &bid);
293 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bid);
294 glBufferData(GL_ELEMENT_ARRAY_BUFFER,
295 g->indices.count * sizeof(g->indices.e[0]),
297 g->indices.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
298 g->indices.buffer.bid = (c3apiobject_t)bid;
299 if (!g->indices.buffer.mutable)
300 c3indices_array_realloc(&g->indices, 0);
301 g->indices.buffer.dirty = 0;
306 _c3_geometry_project(
308 const struct c3driver_context_t * d,
313 _c3_load_pixels(g->mat.texture);
315 _c3_load_program(g->mat.program);
317 switch(g->type.type) {
319 case C3_TRIANGLE_TYPE:
321 g->type.subtype = (c3apiobject_t)GL_TRIANGLES;
323 case C3_TEXTURE_TYPE: {
325 g->type.subtype = (c3apiobject_t)GL_TRIANGLE_FAN;
327 case C3_LIGHT_TYPE: {
328 c3light_p l = (c3light_p)g;
329 GLuint lid = GL_LIGHT0 + (int)l->light_id;
330 if (l->color.specular.w > 0)
331 glLightfv(lid, GL_SPECULAR, l->color.specular.n);
332 if (l->color.ambiant.w > 0)
333 glLightfv(lid, GL_AMBIENT, l->color.ambiant.n);
340 // _c3_update_vbo(g);
342 glBindVertexArray(0);
346 * Thid id the meta function that draws a c3geometry. It looks for normals,
347 * indices, textures and so on and call the glDrawArrays
352 const struct c3driver_context_t *d,
355 c3mat4 eye = c3mat4_mul(
357 &c3context_view_get(g->object->context)->cam.mtx);
358 glLoadMatrixf(eye.n);
360 switch(g->type.type) {
361 case C3_LIGHT_TYPE: {
362 c3light_p l = (c3light_p)g;
363 GLuint lid = GL_LIGHT0 + (int)l->light_id;
364 glLightfv(lid, GL_POSITION, l->position.n);
365 if (c3context_view_get(c)->type != C3_CONTEXT_VIEW_LIGHT)
374 glColor4fv(g->mat.color.n);
375 dumpError("glColor");
377 GLCHECK(glBindVertexArray((GLuint)g->bid));
379 glDisable(GL_TEXTURE_2D);
380 if (g->mat.texture) {
381 GLuint mode = g->mat.texture->normalize ?
382 GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
384 if (g->mat.texture->trace)
385 printf("%s uses texture %s (%d tex)\n",
386 __func__, g->mat.texture->name->str, g->textures.count);
387 // printf("tex mode %d texture %d\n", g->mat.mode, g->mat.texture);
388 dumpError("glEnable texture");
389 glBindTexture(mode, (GLuint)g->mat.texture->texture);
390 dumpError("glBindTexture");
393 GLCHECK(glUseProgram((GLuint)g->mat.program->pid));
395 if (g->indices.buffer.bid) {
396 GLCHECK(glDrawElements((GLuint)g->type.subtype,
397 g->indices.count, GL_UNSIGNED_SHORT,
398 (void*)NULL /*g->indices.e*/));
400 glDrawArrays((GLuint)g->type.subtype, 0, g->vertice.count);
402 glBindVertexArray(0);
405 glDisable(g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB);
410 const c3driver_context_t c3context_driver = {
411 .geometry_project = _c3_geometry_project,
412 .geometry_draw = _c3_geometry_draw,
415 const struct c3driver_context_t *
418 return &c3context_driver;