blob: cc986d9d1e3b712a8ec39e3d9881d15249736062 [file] [log] [blame]
Brian Paulca1bda52009-10-01 12:58:36 -06001/* */
2
3#define GL_GLEXT_PROTOTYPES
4
5#include <assert.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <GL/gl.h>
9#include <GL/glu.h>
10#include "glm.h"
11#include "readtex.h"
12#include "shaderutil.h"
13
14
15/* defines */
16#define T(x) model->triangles[(x)]
17
18
19/* glmDraw: Renders the model to the current OpenGL context using the
20 * mode specified.
21 *
22 * model - initialized GLMmodel structure
23 * mode - a bitwise OR of values describing what is to be rendered.
24 * GLM_NONE - render with only vertices
25 * GLM_FLAT - render with facet normals
26 * GLM_SMOOTH - render with vertex normals
27 * GLM_TEXTURE - render with texture coords
28 * GLM_COLOR - render with colors (color material)
29 * GLM_MATERIAL - render with materials
30 * GLM_COLOR and GLM_MATERIAL should not both be specified.
31 * GLM_FLAT and GLM_SMOOTH should not both be specified.
32 */
33GLvoid
34glmDraw(GLMmodel* model, GLuint mode)
35{
36 GLuint i;
37 GLMgroup* group;
38
39 assert(model);
40 assert(model->vertices);
41
42 /* do a bit of warning */
43 if (mode & GLM_FLAT && !model->facetnorms) {
44 printf("glmDraw() warning: flat render mode requested "
45 "with no facet normals defined.\n");
46 mode &= ~GLM_FLAT;
47 }
48 if (mode & GLM_SMOOTH && !model->normals) {
49 printf("glmDraw() warning: smooth render mode requested "
50 "with no normals defined.\n");
51 mode &= ~GLM_SMOOTH;
52 }
53 if (mode & GLM_TEXTURE && !model->texcoords) {
54 printf("glmDraw() warning: texture render mode requested "
55 "with no texture coordinates defined.\n");
56 mode &= ~GLM_TEXTURE;
57 }
58 if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
59 printf("glmDraw() warning: flat render mode requested "
60 "and smooth render mode requested (using smooth).\n");
61 mode &= ~GLM_FLAT;
62 }
63 if (mode & GLM_COLOR && !model->materials) {
64 printf("glmDraw() warning: color render mode requested "
65 "with no materials defined.\n");
66 mode &= ~GLM_COLOR;
67 }
68 if (mode & GLM_MATERIAL && !model->materials) {
69 printf("glmDraw() warning: material render mode requested "
70 "with no materials defined.\n");
71 mode &= ~GLM_MATERIAL;
72 }
73 if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
74 printf("glmDraw() warning: color and material render mode requested "
75 "using only material mode\n");
76 mode &= ~GLM_COLOR;
77 }
78 if (mode & GLM_COLOR)
79 glEnable(GL_COLOR_MATERIAL);
80 if (mode & GLM_MATERIAL)
81 glDisable(GL_COLOR_MATERIAL);
82
83 glPushMatrix();
84 glTranslatef(model->position[0], model->position[1], model->position[2]);
85
86 glBegin(GL_TRIANGLES);
87 group = model->groups;
88 while (group) {
89 if (mode & GLM_MATERIAL) {
90 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,
91 model->materials[group->material].ambient);
92 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
93 model->materials[group->material].diffuse);
94 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
95 model->materials[group->material].specular);
96 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,
97 model->materials[group->material].shininess);
98 }
99
100 if (mode & GLM_COLOR) {
101 glColor3fv(model->materials[group->material].diffuse);
102 }
103
104 for (i = 0; i < group->numtriangles; i++) {
105 if (mode & GLM_FLAT)
106 glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]);
107
108 if (mode & GLM_SMOOTH)
109 glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]);
110 if (mode & GLM_TEXTURE)
111 glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]);
112 glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]);
113#if 0
114 printf("%f %f %f\n",
115 model->vertices[3 * T(group->triangles[i]).vindices[0] + X],
116 model->vertices[3 * T(group->triangles[i]).vindices[0] + Y],
117 model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]);
118#endif
119
120 if (mode & GLM_SMOOTH)
121 glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]);
122 if (mode & GLM_TEXTURE)
123 glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]);
124 glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]);
125#if 0
126 printf("%f %f %f\n",
127 model->vertices[3 * T(group->triangles[i]).vindices[1] + X],
128 model->vertices[3 * T(group->triangles[i]).vindices[1] + Y],
129 model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]);
130#endif
131
132 if (mode & GLM_SMOOTH)
133 glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]);
134 if (mode & GLM_TEXTURE)
135 glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]);
136 glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]);
137#if 0
138 printf("%f %f %f\n",
139 model->vertices[3 * T(group->triangles[i]).vindices[2] + X],
140 model->vertices[3 * T(group->triangles[i]).vindices[2] + Y],
141 model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]);
142#endif
143
144 }
145
146 group = group->next;
147 }
148 glEnd();
149
150 glPopMatrix();
151}
152
153
154void
155glmMakeVBOs(GLMmodel *model)
156{
157 uint bytes, vertexFloats, i;
158 float *buffer;
159
160 vertexFloats = 3;
161 model->posOffset = 0;
162
163 if (model->numnormals > 0) {
164 assert(model->numnormals == model->numvertices);
165 model->normOffset = vertexFloats * sizeof(GLfloat);
166 vertexFloats += 3;
167 }
168
169 if (model->numtexcoords > 0) {
170 assert(model->numtexcoords == model->numvertices);
171 model->texOffset = vertexFloats * sizeof(GLfloat);
172 vertexFloats += 2;
173 }
174
175 model->vertexSize = vertexFloats;
176
177 bytes = (model->numvertices + 1) * vertexFloats * sizeof(float);
178
179 buffer = (float *) malloc(bytes);
180 for (i = 0; i < model->numvertices; i++) {
181 /* copy vertex pos */
182 uint j = 0;
183 buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 0];
184 buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 1];
185 buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 2];
186 if (model->numnormals > 0) {
187 buffer[i * vertexFloats + j++] = model->normals[i * 3 + 0];
188 buffer[i * vertexFloats + j++] = model->normals[i * 3 + 1];
189 buffer[i * vertexFloats + j++] = model->normals[i * 3 + 2];
190 }
191 if (model->numtexcoords > 0) {
192 buffer[i * vertexFloats + j++] = model->texcoords[i * 2 + 0];
193 buffer[i * vertexFloats + j++] = model->texcoords[i * 2 + 1];
194 }
195 }
196
197 glGenBuffersARB(1, &model->vbo);
198 glBindBufferARB(GL_ARRAY_BUFFER_ARB, model->vbo);
199 glBufferDataARB(GL_ARRAY_BUFFER_ARB, bytes, buffer, GL_STATIC_DRAW_ARB);
200 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
201
202 free(buffer);
203}
204
205
206static void
207_glmLoadTexture(GLMmaterial *mat)
208{
209 if (mat->map_kd) {
210 GLint imgWidth, imgHeight;
211 GLenum imgFormat;
212 GLubyte *image = NULL;
213
214 glGenTextures(1, &mat->texture_kd);
215
216 image = LoadRGBImage( mat->map_kd, &imgWidth, &imgHeight, &imgFormat );
217 if (!image) {
218 /*fprintf(stderr, "Couldn't open texture %s\n", mat->map_kd);*/
219 free(mat->map_kd);
220 mat->map_kd = NULL;
221 mat->texture_kd = 0;
222 return;
223 }
224 if (0)
225 printf("load texture %s %d x %d\n", mat->map_kd, imgWidth, imgHeight);
226
227 glBindTexture(GL_TEXTURE_2D, mat->texture_kd);
228 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight,
229 imgFormat, GL_UNSIGNED_BYTE, image);
230 free(image);
231
232 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
233 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
234 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
235 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
236 }
237}
238
239void
240glmLoadTextures(GLMmodel *model)
241{
242 uint i;
243
244 for (i = 0; i < model->nummaterials; i++) {
245 GLMmaterial *mat = &model->materials[i];
246 _glmLoadTexture(mat);
247 }
248}
249
250
251void
252glmDrawVBO(GLMmodel *model)
253{
254 GLMgroup* group;
255 int mode = GLM_MATERIAL;
256
257 assert(model->vbo);
258
259 glBindBufferARB(GL_ARRAY_BUFFER_ARB, model->vbo);
260
261 glVertexPointer(3, GL_FLOAT, model->vertexSize * sizeof(float),
262 (void *) model->posOffset);
263 glEnableClientState(GL_VERTEX_ARRAY);
264
265 if (model->numnormals > 0) {
266 glNormalPointer(GL_FLOAT, model->vertexSize * sizeof(float),
267 (void *) model->normOffset);
268 glEnableClientState(GL_NORMAL_ARRAY);
269 }
270
271 if (model->numtexcoords > 0) {
272 glTexCoordPointer(2, GL_FLOAT, model->vertexSize * sizeof(float),
273 (void *) model->texOffset);
274 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
275 }
276
277 glPushMatrix();
278 glTranslatef(model->position[0], model->position[1], model->position[2]);
279 glScalef(model->scale, model->scale, model->scale);
280
281 for (group = model->groups; group; group = group->next) {
282 if (0&&strcmp(group->name, "Fuselage") != 0)
283 continue;
284
285 if (group->numtriangles > 0) {
286
287 if (model->materials && (mode & GLM_MATERIAL)) {
288#if 0
289 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,
290 model->materials[group->material].ambient);
291 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
292 model->materials[group->material].diffuse);
293 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
294 model->materials[group->material].specular);
295 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,
296 model->materials[group->material].shininess);
297#else
298 glmShaderMaterial(&model->materials[group->material]);
299#endif
300 }
301
302
303#if 0
304 glDrawElements(GL_TRIANGLES, 3 * group->numtriangles,
305 GL_UNSIGNED_INT, group->triIndexes);
306#else
307 glDrawRangeElements(GL_TRIANGLES,
308 group->minIndex, group->maxIndex,
309 3 * group->numtriangles,
310 GL_UNSIGNED_INT, group->triIndexes);
311#endif
312
313 glDisable(GL_BLEND);
314 }
315 }
316
317 glPopMatrix();
318
319 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
320 glDisableClientState(GL_VERTEX_ARRAY);
321 glDisableClientState(GL_NORMAL_ARRAY);
322 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
323}
324
325
326
327/* glmList: Generates and returns a display list for the model using
328 * the mode specified.
329 *
330 * model - initialized GLMmodel structure
331 * mode - a bitwise OR of values describing what is to be rendered.
332 * GLM_NONE - render with only vertices
333 * GLM_FLAT - render with facet normals
334 * GLM_SMOOTH - render with vertex normals
335 * GLM_TEXTURE - render with texture coords
336 * GLM_COLOR - render with colors (color material)
337 * GLM_MATERIAL - render with materials
338 * GLM_COLOR and GLM_MATERIAL should not both be specified.
339 * GLM_FLAT and GLM_SMOOTH should not both be specified.
340 */
341GLuint
342glmList(GLMmodel* model, GLuint mode)
343{
344 GLuint list;
345
346 list = glGenLists(1);
347 glNewList(list, GL_COMPILE);
348 glmDraw(model, mode);
349 glEndList();
350
351 return list;
352}
353
354
355
356static const char *VertexShader =
357 "varying vec3 normal; \n"
358 "void main() { \n"
359 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n"
360 " normal = gl_NormalMatrix * gl_Normal; \n"
361 " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
362 "} \n";
363
364/**
365 * Two %s substitutions:
366 * diffuse texture? true/false
367 * specular texture? true/false
368 */
369static const char *TexFragmentShader =
370 "uniform vec4 ambient, diffuse, specular; \n"
371 "uniform vec4 ambientLight, diffuseLight, specularLight; \n"
372 "uniform float shininess; \n"
373 "uniform sampler2D diffTex; \n"
374 "uniform samplerCube specTex; \n"
375 "varying vec3 normal; \n"
376 "\n"
377 "void main() \n"
378 "{ \n"
379 " vec4 diffTerm, specTerm; \n"
380 " float dotProd = max(dot(gl_LightSource[0].position.xyz, \n"
381 " normalize(normal)), 0.0);\n"
382 " float dotProd2 = max(dot(-gl_LightSource[0].position.xyz, \n"
383 " normalize(normal)), 0.0);\n"
384 " dotProd += dotProd2; \n"
385 " \n"
386 " diffTerm = diffuse * diffuseLight * dotProd; \n"
387 " if (%s) \n"
388 " diffTerm *= texture2D(diffTex, gl_TexCoord[0].st); \n"
389 " \n"
390 " specTerm = specular * specularLight * pow(dotProd, shininess); \n"
391 " if (%s) \n"
392 " specTerm *= textureCube(specTex, normal); \n"
393 " \n"
394 " gl_FragColor = ambient * ambientLight + diffTerm + specTerm; \n"
395 "} \n";
396
397
398void
399glmShaderMaterial(GLMmaterial *mat)
400{
401 static const float ambientLight[4] = { 0.1, 0.1, 0.1, 0.0 };
402 static const float diffuseLight[4] = { 0.75, 0.75, 0.75, 1.0 };
403 static const float specularLight[4] = { 1.0, 1.0, 1.0, 0.0 };
404
405 if (!mat->prog) {
406 /* make shader now */
407 char newShader[10000];
408 GLuint vs, fs;
409 const char *diffuseTex = mat->texture_kd ? "true" : "false";
410 const char *specularTex = mat->texture_ks ? "true" : "false";
411 GLint uAmbientLight, uDiffuseLight, uSpecularLight;
412
413 /* replace %d with 0 or 1 */
414 sprintf(newShader, TexFragmentShader, diffuseTex, specularTex);
415 if (0)
416 printf("===== new shader =====\n%s\n============\n", newShader);
417
418 vs = CompileShaderText(GL_VERTEX_SHADER, VertexShader);
419 fs = CompileShaderText(GL_FRAGMENT_SHADER, newShader);
420 mat->prog = LinkShaders(vs, fs);
421 assert(mat->prog);
422
423 glUseProgram(mat->prog);
424
425 mat->uAmbient = glGetUniformLocation(mat->prog, "ambient");
426 mat->uDiffuse = glGetUniformLocation(mat->prog, "diffuse");
427 mat->uSpecular = glGetUniformLocation(mat->prog, "specular");
428 mat->uShininess = glGetUniformLocation(mat->prog, "shininess");
429 mat->uDiffTex = glGetUniformLocation(mat->prog, "diffTex");
430 mat->uSpecTex = glGetUniformLocation(mat->prog, "specTex");
431
432 uAmbientLight = glGetUniformLocation(mat->prog, "ambientLight");
433 uDiffuseLight = glGetUniformLocation(mat->prog, "diffuseLight");
434 uSpecularLight = glGetUniformLocation(mat->prog, "specularLight");
435
436 glUniform4fv(mat->uAmbient, 1, mat->ambient);
437 glUniform4fv(mat->uDiffuse, 1, mat->diffuse);
438 glUniform4fv(mat->uSpecular, 1, mat->specular);
439 glUniform1f(mat->uShininess, mat->shininess);
440 glUniform1i(mat->uDiffTex, 0);
441 glUniform1i(mat->uSpecTex, 1);
442
443 glUniform4fv(uAmbientLight, 1, ambientLight);
444 glUniform4fv(uDiffuseLight, 1, diffuseLight);
445 glUniform4fv(uSpecularLight, 1, specularLight);
446 }
447
448 glActiveTexture(GL_TEXTURE1);
449 if (mat->texture_ks)
450 glBindTexture(GL_TEXTURE_CUBE_MAP, mat->texture_ks);
451 else
452 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
453
454 glActiveTexture(GL_TEXTURE0);
455 if (mat->texture_kd)
456 glBindTexture(GL_TEXTURE_2D, mat->texture_kd);
457 else
458 glBindTexture(GL_TEXTURE_2D, 0);
459
460 if (mat->diffuse[3] < 1.0) {
461 glEnable(GL_BLEND);
462 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
463 }
464 else {
465 glDisable(GL_BLEND);
466 }
467
468 glUseProgram(mat->prog);
469}
470
471
472void
473glmSpecularTexture(GLMmodel *model, uint cubeTex)
474{
475 uint i;
476
477 for (i = 0; i < model->nummaterials; i++) {
478 model->materials[i].texture_ks = cubeTex;
479 }
480}