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
39 #include "c3program.h"
41 #include "c3driver_context.h"
45 #define GLCHECK(_w) {_w; dumpError(#_w);}
47 static int dumpError(const char * what)
51 while ((e = glGetError()) != GL_NO_ERROR) {
52 printf("%s: %s\n", what, gluErrorString(e));
62 if (!p || p->pid || p->log)
66 printf("%s loading %s\n", __func__, p->name->str);
67 for (int si = 0; si < p->shaders.count && !p->log; si++) {
68 c3shader_p s = &p->shaders.e[si];
71 printf("%s compiling shader %s\n", __func__, s->name->str);
73 s->sid = (c3apiobject_t)glCreateShader(s->type);
74 const GLchar * pgm = s->shader->str;
75 glShaderSource((GLuint)s->sid, 1, &pgm, NULL);
77 glCompileShader((GLuint)s->sid);
80 glGetShaderiv((GLuint)s->sid, GL_COMPILE_STATUS, &status);
82 if (status != GL_FALSE)
86 glGetShaderiv((GLuint)s->sid, GL_INFO_LOG_LENGTH, &infoLogLength);
88 p->log = str_alloc(infoLogLength);
89 glGetShaderInfoLog((GLuint)s->sid, infoLogLength, NULL, p->log->str);
91 fprintf(stderr, "%s compile %s: %s\n", __func__, s->name->str, p->log->str);
96 p->pid = (c3apiobject_t)glCreateProgram();
98 for (int si = 0; si < p->shaders.count && !p->log; si++) {
99 c3shader_p s = &p->shaders.e[si];
101 glAttachShader((GLuint)p->pid, (GLuint)s->sid);
103 glLinkProgram((GLuint)p->pid);
106 glGetProgramiv((GLuint)p->pid, GL_LINK_STATUS, &status);
108 for (int si = 0; si < p->shaders.count && !p->log; si++) {
109 c3shader_p s = &p->shaders.e[si];
111 glDetachShader((GLuint)p->pid, (GLuint)s->sid);
112 glDeleteShader((GLuint)s->sid);
116 if (status == GL_FALSE) {
118 glGetProgramiv((GLuint)p->pid, GL_INFO_LOG_LENGTH, &infoLogLength);
120 p->log = str_alloc(infoLogLength);
122 glGetProgramInfoLog((GLuint)p->pid, infoLogLength, NULL, p->log->str);
123 fprintf(stderr, "%s link %s: %s\n", __func__, p->name->str, p->log->str);
127 for (int pi = 0; pi < p->params.count; pi++) {
128 c3program_param_p pa = &p->params.e[pi];
129 pa->pid = (c3apiobject_t)glGetUniformLocation((GLuint)p->pid, pa->name->str);
131 printf("%s %s load parameter '%s'\n", __func__, p->name->str, pa->name->str);
132 if (pa->pid == (c3apiobject_t)-1) {
133 fprintf(stderr, "%s %s: parameter '%s' not found\n",
134 __func__, p->name->str, pa->name->str);
143 glDeleteProgram((GLuint)p->pid);
151 GLuint mode = pix->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
154 printf("%s Creating texture %s %dx%d\n",
155 __func__, pix->name ? pix->name->str : "", pix->w, pix->h);
158 GLCHECK(glEnable(mode));
160 glGenTextures(1, &texID);
161 // glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
162 // GL_MODULATE); //set texture environment parameters
163 // dumpError("glTexEnvf");
165 glPixelStorei(GL_UNPACK_ROW_LENGTH, pix->row / pix->psize);
166 GLCHECK(glTexParameteri(mode, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
167 GLCHECK(glTexParameteri(mode, GL_TEXTURE_MIN_FILTER,
168 pix->normalize ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
169 GLCHECK(glTexParameteri(mode, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER));
170 GLCHECK(glTexParameteri(mode, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER));
172 GLCHECK(glTexParameteri(mode, GL_GENERATE_MIPMAP, GL_TRUE));
175 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
176 //printf("fLargest = %f\n", fLargest);
177 GLCHECK(glTexParameterf(mode, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest));
180 GLCHECK(glGenerateMipmap(mode));
182 pix->texture = (c3apiobject_t)texID;
187 GLCHECK(glBindTexture(mode, (GLuint)pix->texture));
188 glTexImage2D(mode, 0,
189 pix->format == C3PIXEL_A ? GL_ALPHA16 : GL_RGBA8,
191 pix->format == C3PIXEL_A ? GL_ALPHA : GL_BGRA,
194 dumpError("glTexImage2D");
196 GLCHECK(glGenerateMipmap(mode));
200 static void _c3_create_buffer(
208 glGenBuffers(1, &bid);
210 GLCHECK(glBindBuffer(GL_ARRAY_BUFFER, bid));
211 GLCHECK(glBufferData(GL_ARRAY_BUFFER,
215 GLCHECK(glEnableClientState(name));
224 glGenVertexArrays(1, &vao);
225 g->bid = (c3apiobject_t)vao;
227 glBindVertexArray((GLuint)g->bid);
230 * Use 'realloc' on the array as it frees the data, but leaves 'count'
231 * unchanged. We neec that for the vertices and the indexes, the others
232 * can have a straight free()
234 if (!g->vertice.buffer.bid && g->vertice.count) {
237 _c3_create_buffer(GL_VERTEX_ARRAY,
238 g->vertice.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
239 g->vertice.e, g->vertice.count * sizeof(g->vertice.e[0]),
241 glVertexPointer(3, GL_FLOAT, 0, (void*)0);
242 g->vertice.buffer.bid = (c3apiobject_t)bid;
243 if (!g->vertice.buffer.mutable)
244 c3vertex_array_realloc(&g->vertice, 0);
245 g->vertice.buffer.dirty = 0;
247 if (!g->textures.buffer.bid && g->textures.count) {
250 _c3_create_buffer(GL_TEXTURE_COORD_ARRAY,
251 g->textures.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
252 g->textures.e, g->textures.count * sizeof(g->textures.e[0]),
254 glTexCoordPointer(2, GL_FLOAT, 0, (void*)0);
255 g->textures.buffer.bid = (c3apiobject_t)bid;
256 if (!g->textures.buffer.mutable)
257 c3tex_array_free(&g->textures);
258 g->textures.buffer.dirty = 0;
260 if (!g->normals.buffer.bid && g->normals.count) {
263 _c3_create_buffer(GL_NORMAL_ARRAY,
264 g->normals.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
265 g->normals.e, g->normals.count * sizeof(g->normals.e[0]),
267 glNormalPointer(GL_FLOAT, 0, (void*) 0);
268 g->normals.buffer.bid = (c3apiobject_t)bid;
269 if (!g->normals.buffer.mutable)
270 c3vertex_array_free(&g->normals);
271 g->normals.buffer.dirty = 0;
273 if (!g->colorf.buffer.bid && g->colorf.count) {
276 _c3_create_buffer(GL_COLOR_ARRAY,
277 g->colorf.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW,
278 g->colorf.e, g->colorf.count * sizeof(g->colorf.e[0]),
280 glColorPointer(4, GL_FLOAT, 0, (void*) 0);
281 g->colorf.buffer.bid = (c3apiobject_t)bid;
282 if (!g->colorf.buffer.mutable)
283 c3colorf_array_free(&g->colorf);
284 g->colorf.buffer.dirty = 0;
286 if (!g->indices.buffer.bid && g->indices.count) {
288 glGenBuffers(1, &bid);
290 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bid);
291 glBufferData(GL_ELEMENT_ARRAY_BUFFER,
292 g->indices.count * sizeof(g->indices.e[0]),
294 g->indices.buffer.mutable ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
295 g->indices.buffer.bid = (c3apiobject_t)bid;
296 if (!g->indices.buffer.mutable)
297 c3indices_array_realloc(&g->indices, 0);
298 g->indices.buffer.dirty = 0;
303 _c3_geometry_project(
305 const struct c3driver_context_t * d,
310 _c3_load_pixels(g->mat.texture);
312 _c3_load_program(g->mat.program);
314 switch(g->type.type) {
316 case C3_TRIANGLE_TYPE:
318 g->type.subtype = (c3apiobject_t)GL_TRIANGLES;
320 case C3_TEXTURE_TYPE: {
322 g->type.subtype = (c3apiobject_t)GL_TRIANGLE_FAN;
329 // _c3_update_vbo(g);
331 glBindVertexArray(0);
335 * Thid id the meta function that draws a c3geometry. It looks for normals,
336 * indices, textures and so on and call the glDrawArrays
341 const struct c3driver_context_t *d,
344 glColor4fv(g->mat.color.n);
345 dumpError("glColor");
346 // glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, g->mat.color.n);
348 c3mat4 eye = c3mat4_mul(
350 &c3context_view_get(g->object->context)->cam.mtx);
351 glLoadMatrixf(eye.n);
353 GLCHECK(glBindVertexArray((GLuint)g->bid));
355 glDisable(GL_TEXTURE_2D);
356 if (g->mat.texture) {
357 GLuint mode = g->mat.texture->normalize ?
358 GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
360 if (g->mat.texture->trace)
361 printf("%s uses texture %s (%d tex)\n",
362 __func__, g->mat.texture->name->str, g->textures.count);
363 // printf("tex mode %d texture %d\n", g->mat.mode, g->mat.texture);
364 dumpError("glEnable texture");
365 glBindTexture(mode, (GLuint)g->mat.texture->texture);
366 dumpError("glBindTexture");
369 GLCHECK(glUseProgram((GLuint)g->mat.program->pid));
371 if (g->indices.buffer.bid) {
372 GLCHECK(glDrawElements((GLuint)g->type.subtype,
373 g->indices.count, GL_UNSIGNED_SHORT,
374 (void*)NULL /*g->indices.e*/));
376 glDrawArrays((GLuint)g->type.subtype, 0, g->vertice.count);
378 glBindVertexArray(0);
381 glDisable(g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB);
386 const c3driver_context_t c3context_driver = {
387 .geometry_project = _c3_geometry_project,
388 .geometry_draw = _c3_geometry_draw,
391 const struct c3driver_context_t *
394 return &c3context_driver;