diff options
Diffstat (limited to 'src/others/mimesh/gl.c')
-rw-r--r-- | src/others/mimesh/gl.c | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/src/others/mimesh/gl.c b/src/others/mimesh/gl.c new file mode 100644 index 0000000..9c6f996 --- /dev/null +++ b/src/others/mimesh/gl.c | |||
@@ -0,0 +1,518 @@ | |||
1 | /* $Id: gl.c 61 2006-11-09 15:31:12Z mmmaddd $ */ | ||
2 | |||
3 | /* | ||
4 | G3DViewer - 3D object viewer | ||
5 | |||
6 | Copyright (C) 2005, 2006 Markus Dahms <mad@automagically.de> | ||
7 | |||
8 | This program 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 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program 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. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <math.h> | ||
26 | |||
27 | #include <glib.h> | ||
28 | |||
29 | #include <GL/gl.h> | ||
30 | #include <GL/glu.h> | ||
31 | |||
32 | #include <g3d/types.h> | ||
33 | |||
34 | #if 0 | ||
35 | #include "main.h" | ||
36 | #endif | ||
37 | #include "gl.h" | ||
38 | #include "trackball.h" | ||
39 | |||
40 | #if DEBUG > 1 | ||
41 | #define TIMING | ||
42 | #endif | ||
43 | |||
44 | static int _initialized = 0; | ||
45 | |||
46 | #ifdef TIMING | ||
47 | static GTimer *timer = NULL; | ||
48 | static gulong avg_msec = 0; | ||
49 | #endif | ||
50 | |||
51 | GLuint evil; | ||
52 | |||
53 | void gl_init(void) | ||
54 | { | ||
55 | #if DEBUG > 1 | ||
56 | g_printerr("init OpenGL\n"); | ||
57 | #endif | ||
58 | |||
59 | GLfloat light0_pos[4] = { -50.0, 50.0, 0.0, 0.0 }; | ||
60 | GLfloat light0_col[4] = { 0.6, 0.6, 0.6, 1.0 }; | ||
61 | GLfloat light1_pos[4] = { 50.0, 50.0, 0.0, 0.0 }; | ||
62 | GLfloat light1_col[4] = { 0.4, 0.4, 0.4, 1.0 }; | ||
63 | GLfloat ambient_lc[4] = { 0.35, 0.35, 0.35, 1.0 }; | ||
64 | |||
65 | #if 0 | ||
66 | glEnable(GL_CULL_FACE); | ||
67 | #endif | ||
68 | |||
69 | /* transparency and blending */ | ||
70 | #if 0 | ||
71 | glAlphaFunc(GL_GREATER, 0.1); | ||
72 | #endif | ||
73 | glEnable(GL_ALPHA_TEST); | ||
74 | |||
75 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
76 | glEnable(GL_BLEND); | ||
77 | |||
78 | glDepthFunc(GL_LEQUAL); | ||
79 | glEnable(GL_DEPTH_TEST); | ||
80 | |||
81 | #if 0 | ||
82 | glEnable(GL_LINE_SMOOTH); | ||
83 | glEnable(GL_POLYGON_SMOOTH); | ||
84 | #endif | ||
85 | |||
86 | #if 0 | ||
87 | glDisable(GL_DITHER); | ||
88 | #endif | ||
89 | glShadeModel(GL_SMOOTH); | ||
90 | |||
91 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); | ||
92 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | ||
93 | glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); | ||
94 | |||
95 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient_lc); | ||
96 | glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); | ||
97 | glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); | ||
98 | glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); | ||
99 | |||
100 | glLightfv(GL_LIGHT0, GL_POSITION, light0_pos); | ||
101 | glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_col); | ||
102 | glLightfv(GL_LIGHT1, GL_POSITION, light1_pos); | ||
103 | glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_col); | ||
104 | glLightfv(GL_LIGHT1, GL_SPECULAR, light1_col); | ||
105 | glEnable(GL_LIGHT0); | ||
106 | glEnable(GL_LIGHT1); | ||
107 | glEnable(GL_LIGHTING); | ||
108 | |||
109 | /* colors and materials */ | ||
110 | glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); | ||
111 | glEnable(GL_COLOR_MATERIAL); | ||
112 | |||
113 | /* texture stuff */ | ||
114 | glEnable(GL_TEXTURE_2D); | ||
115 | |||
116 | #ifdef TIMING | ||
117 | timer = g_timer_new(); | ||
118 | #endif | ||
119 | } | ||
120 | |||
121 | void gl_set_twoside(gboolean twoside) | ||
122 | { | ||
123 | glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, twoside ? 1 : 0); | ||
124 | glColorMaterial( | ||
125 | twoside ? GL_FRONT_AND_BACK : GL_FRONT, | ||
126 | GL_AMBIENT_AND_DIFFUSE); | ||
127 | } | ||
128 | |||
129 | void gl_set_textures(gboolean textures) | ||
130 | { | ||
131 | if(textures) | ||
132 | glEnable(GL_TEXTURE_2D); | ||
133 | else | ||
134 | { | ||
135 | glBindTexture(GL_TEXTURE_2D, 0); | ||
136 | glDisable(GL_TEXTURE_2D); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /* GHFunc */ | ||
141 | void gl_load_texture(gpointer key, gpointer value, gpointer data) | ||
142 | { | ||
143 | G3DImage *image = (G3DImage *)value; | ||
144 | gint32 env; | ||
145 | |||
146 | #if 0 | ||
147 | /* predefined - update object->_tex_images else... */ | ||
148 | glGenTextures(1, &(image->gl_texid)); | ||
149 | #endif | ||
150 | |||
151 | #if DEBUG > 0 | ||
152 | g_print("gl: loading texture '%s' (%dx%dx%d) - id %d\n", | ||
153 | image->name ? image->name : "(null)", | ||
154 | image->width, image->height, image->depth, | ||
155 | image->tex_id); | ||
156 | #endif | ||
157 | |||
158 | glBindTexture(GL_TEXTURE_2D, image->tex_id); | ||
159 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||
160 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | ||
161 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | ||
162 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
163 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | ||
164 | GL_LINEAR_MIPMAP_NEAREST); | ||
165 | |||
166 | switch(image->tex_env) | ||
167 | { | ||
168 | case G3D_TEXENV_BLEND: env = GL_BLEND; break; | ||
169 | case G3D_TEXENV_MODULATE: env = GL_MODULATE; break; | ||
170 | case G3D_TEXENV_DECAL: env = GL_DECAL; break; | ||
171 | case G3D_TEXENV_REPLACE: env = GL_REPLACE; break; | ||
172 | default: env = GL_BLEND; break; | ||
173 | } | ||
174 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env); | ||
175 | |||
176 | glTexImage2D( | ||
177 | GL_TEXTURE_2D /* target */, | ||
178 | 0 /* level */, | ||
179 | GL_RGBA /* internalFormat */, | ||
180 | image->width /* width */, | ||
181 | image->height /* height */, | ||
182 | 0 /* border */, | ||
183 | GL_RGBA /* format */, | ||
184 | GL_UNSIGNED_BYTE /* type */, | ||
185 | image->pixeldata /* pixels */); | ||
186 | gluBuild2DMipmaps( | ||
187 | GL_TEXTURE_2D, | ||
188 | GL_RGBA, | ||
189 | image->width, | ||
190 | image->height, | ||
191 | GL_RGBA, | ||
192 | GL_UNSIGNED_BYTE, | ||
193 | image->pixeldata); | ||
194 | } | ||
195 | |||
196 | void gl_update_material(gint32 glflags, G3DMaterial *material) | ||
197 | { | ||
198 | GLenum facetype; | ||
199 | GLfloat normspec[4] = { 0.0, 0.0, 0.0, 1.0 }; | ||
200 | |||
201 | // g_return_if_fail(material != NULL); | ||
202 | |||
203 | if(glflags & G3D_FLAG_GL_ALLTWOSIDE) | ||
204 | facetype = GL_FRONT_AND_BACK; | ||
205 | else | ||
206 | facetype = GL_FRONT; | ||
207 | |||
208 | glColor4f( | ||
209 | material->r, | ||
210 | material->g, | ||
211 | material->b, | ||
212 | material->a); | ||
213 | |||
214 | return; | ||
215 | |||
216 | if(glflags & G3D_FLAG_GL_SPECULAR) | ||
217 | glMaterialfv(facetype, GL_SPECULAR, material->specular); | ||
218 | else | ||
219 | glMaterialfv(facetype, GL_SPECULAR, normspec); | ||
220 | |||
221 | if(glflags & G3D_FLAG_GL_SHININESS) | ||
222 | glMaterialf(facetype, GL_SHININESS, material->shininess * 10); | ||
223 | else | ||
224 | glMaterialf(facetype, GL_SHININESS, 0.0); | ||
225 | } | ||
226 | |||
227 | static void gl_draw_face(gint32 glflags, G3DObject *object, gint32 i, | ||
228 | G3DFloat min_a, G3DFloat max_a, gboolean *dont_render, gboolean *init) | ||
229 | { | ||
230 | static G3DMaterial *prev_material = NULL; | ||
231 | static guint32 prev_texid = 0; | ||
232 | gint32 j; | ||
233 | |||
234 | if(*init) | ||
235 | { | ||
236 | prev_material = NULL; | ||
237 | prev_texid = 0; | ||
238 | *init = FALSE; | ||
239 | } | ||
240 | |||
241 | /* material check */ | ||
242 | if(prev_material != object->_materials[i]) | ||
243 | { | ||
244 | if((object->_materials[i]->a < min_a) || | ||
245 | (object->_materials[i]->a >= max_a)) | ||
246 | { | ||
247 | *dont_render = TRUE; | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | *dont_render = FALSE; | ||
252 | |||
253 | glEnd(); | ||
254 | gl_update_material(glflags, object->_materials[i]); | ||
255 | glBegin(GL_TRIANGLES); | ||
256 | prev_material = object->_materials[i]; | ||
257 | |||
258 | prev_texid = 0; | ||
259 | } | ||
260 | |||
261 | if(*dont_render) return; | ||
262 | |||
263 | /* texture stuff */ | ||
264 | if((glflags & G3D_FLAG_GL_TEXTURES) && | ||
265 | (object->_flags[i] & G3D_FLAG_FAC_TEXMAP)) | ||
266 | { | ||
267 | /* if texture has changed update to new texture */ | ||
268 | if(object->_tex_images[i] != prev_texid) | ||
269 | { | ||
270 | prev_texid = object->_tex_images[i]; | ||
271 | glEnd(); | ||
272 | glBindTexture(GL_TEXTURE_2D, prev_texid); | ||
273 | glBegin(GL_TRIANGLES); | ||
274 | #if DEBUG > 5 | ||
275 | g_print("gl: binding to texture id %d\n", prev_texid); | ||
276 | #endif | ||
277 | } | ||
278 | } | ||
279 | |||
280 | |||
281 | /* draw triangles */ | ||
282 | for(j = 0; j < 3; j ++) | ||
283 | { | ||
284 | if((glflags & G3D_FLAG_GL_TEXTURES) && | ||
285 | (object->_flags[i] & G3D_FLAG_FAC_TEXMAP)) | ||
286 | { | ||
287 | glTexCoord2f( | ||
288 | object->_tex_coords[(i * 3 + j) * 2 + 0], | ||
289 | object->_tex_coords[(i * 3 + j) * 2 + 1]); | ||
290 | #if DEBUG > 5 | ||
291 | g_print("gl: setting texture coords: %f, %f\n", | ||
292 | object->_tex_coords[(i * 3 + j) * 2 + 0], | ||
293 | object->_tex_coords[(i * 3 + j) * 2 + 1]); | ||
294 | #endif | ||
295 | } | ||
296 | |||
297 | glNormal3f( | ||
298 | object->_normals[(i*3+j)*3+0], | ||
299 | object->_normals[(i*3+j)*3+1], | ||
300 | object->_normals[(i*3+j)*3+2]); | ||
301 | glVertex3f( | ||
302 | object->vertex_data[object->_indices[i*3+j]*3+0], | ||
303 | object->vertex_data[object->_indices[i*3+j]*3+1], | ||
304 | object->vertex_data[object->_indices[i*3+j]*3+2]); | ||
305 | |||
306 | } /* 1 .. 3 */ | ||
307 | } | ||
308 | |||
309 | static void gl_draw_objects(gint32 glflags, GSList *objects, | ||
310 | G3DFloat min_a, G3DFloat max_a) | ||
311 | { | ||
312 | GSList *olist; | ||
313 | int i; | ||
314 | G3DObject *object; | ||
315 | gboolean dont_render; | ||
316 | gboolean init = TRUE; | ||
317 | |||
318 | olist = objects; | ||
319 | while(olist != NULL) | ||
320 | { | ||
321 | object = (G3DObject *)olist->data; | ||
322 | olist = olist->next; | ||
323 | |||
324 | dont_render = FALSE; | ||
325 | |||
326 | /* don't render invisible objects */ | ||
327 | if(object->hide) continue; | ||
328 | |||
329 | g_return_if_fail(object != NULL); | ||
330 | #if DEBUG > 3 | ||
331 | g_printerr("name: %s {", object->name); | ||
332 | #endif | ||
333 | |||
334 | #if DEBUG > 2 | ||
335 | g_printerr("new object\n"); | ||
336 | #endif | ||
337 | |||
338 | glPushMatrix(); | ||
339 | |||
340 | if(object->transformation) | ||
341 | { | ||
342 | #if G3D_FLOAT_IS_DOUBLE | ||
343 | glMultMatrixd(object->transformation->matrix); | ||
344 | #else | ||
345 | glMultMatrixf(object->transformation->matrix); | ||
346 | #endif | ||
347 | } | ||
348 | |||
349 | glBegin(GL_TRIANGLES); | ||
350 | |||
351 | for(i = 0; i < object->_num_faces; i ++) | ||
352 | { | ||
353 | gl_draw_face(glflags, object, i, min_a, max_a, | ||
354 | &dont_render, &init); | ||
355 | } /* all faces */ | ||
356 | |||
357 | glEnd(); | ||
358 | |||
359 | /* handle sub-objects */ | ||
360 | gl_draw_objects(glflags, object->objects, min_a, max_a); | ||
361 | |||
362 | glPopMatrix(); | ||
363 | |||
364 | } /* while olist != NULL */ | ||
365 | } | ||
366 | |||
367 | void gl_draw_model(G3DModel *model) | ||
368 | { | ||
369 | G3DFloat f; | ||
370 | gint32 glflags = | ||
371 | /* G3D_FLAG_GL_SPECULAR | */ | ||
372 | G3D_FLAG_GL_SHININESS | | ||
373 | G3D_FLAG_GL_ALLTWOSIDE | | ||
374 | G3D_FLAG_GL_TEXTURES; | ||
375 | |||
376 | /* draw all objects */ | ||
377 | for(f = 1.0; f >= 0.0; f -= 0.2) | ||
378 | gl_draw_objects(glflags, model->objects, f, f + 0.2); | ||
379 | } | ||
380 | |||
381 | void gl_draw_model_with_flags(gint32 glflags, G3DModel *model) | ||
382 | { | ||
383 | G3DFloat f; | ||
384 | |||
385 | /* draw all objects */ | ||
386 | for(f = 1.0; f >= 0.0; f -= 0.2) | ||
387 | gl_draw_objects(glflags, model->objects, f, f + 0.2); | ||
388 | } | ||
389 | |||
390 | void gl_draw(gint32 glflags, G3DFloat zoom, G3DFloat aspect, G3DFloat *bgcolor, | ||
391 | G3DFloat *quat, G3DModel *model) | ||
392 | { | ||
393 | #if G3D_FLOAT_IS_DOUBLE | ||
394 | GLdouble m[4][4]; | ||
395 | #else | ||
396 | GLfloat m[4][4]; | ||
397 | #endif | ||
398 | static gchar *previous_name = NULL; | ||
399 | static gint32 previous_glflags = -1; | ||
400 | static gint32 dlist = -1; | ||
401 | GLenum error; | ||
402 | // G3DFloat f; | ||
403 | |||
404 | if(! _initialized) | ||
405 | { | ||
406 | gl_init(); | ||
407 | _initialized = 1; | ||
408 | } | ||
409 | |||
410 | /* draw scene... */ | ||
411 | glMatrixMode(GL_PROJECTION); | ||
412 | glLoadIdentity(); | ||
413 | gluPerspective(zoom, aspect, 1, 100); | ||
414 | glMatrixMode(GL_MODELVIEW); | ||
415 | |||
416 | glClearColor( | ||
417 | bgcolor[0], | ||
418 | bgcolor[1], | ||
419 | bgcolor[2], | ||
420 | bgcolor[3]); | ||
421 | glClearDepth(1.0); | ||
422 | glClearIndex(0.3); | ||
423 | glClear( | ||
424 | GL_COLOR_BUFFER_BIT | | ||
425 | GL_DEPTH_BUFFER_BIT | | ||
426 | GL_ACCUM_BUFFER_BIT | | ||
427 | GL_STENCIL_BUFFER_BIT); | ||
428 | |||
429 | glLoadIdentity(); | ||
430 | glTranslatef(0, 0, -30); | ||
431 | build_rotmatrix(m, quat); | ||
432 | #if G3D_FLOAT_IS_DOUBLE | ||
433 | glMultMatrixd(&m[0][0]); | ||
434 | #else | ||
435 | glMultMatrixf(&m[0][0]); | ||
436 | #endif | ||
437 | |||
438 | /* reset texture */ | ||
439 | glBindTexture (GL_TEXTURE_2D, 0); | ||
440 | |||
441 | if(model == NULL) | ||
442 | return; | ||
443 | |||
444 | #ifdef TIMING | ||
445 | g_timer_start(timer); | ||
446 | #endif | ||
447 | |||
448 | /* FIXME: better detection of new model */ | ||
449 | if((dlist < 0) || (glflags != previous_glflags) || | ||
450 | (previous_name == NULL) || strcmp(previous_name, model->filename)) | ||
451 | { | ||
452 | #if DEBUG > 0 | ||
453 | g_printerr("[gl] creating new display list\n"); | ||
454 | #endif | ||
455 | /* create and execute display list */ | ||
456 | if(dlist >= 0) | ||
457 | glDeleteLists(dlist, 1); | ||
458 | dlist = glGenLists(1); | ||
459 | |||
460 | glNewList(dlist, GL_COMPILE); | ||
461 | /* draw all objects */ | ||
462 | // for(f = 1.0; f >= 0.0; f -= 0.2) | ||
463 | // gl_draw_objects(glflags, model->objects, f, f + 0.2); | ||
464 | gl_draw_model_with_flags(glflags, model); | ||
465 | glEndList(); | ||
466 | |||
467 | if(previous_name) g_free(previous_name); | ||
468 | previous_name = g_strdup(model->filename); | ||
469 | previous_glflags = glflags; | ||
470 | } | ||
471 | |||
472 | /* execute display list */ | ||
473 | glCallList(dlist); | ||
474 | |||
475 | error = glGetError(); | ||
476 | if(error != GL_NO_ERROR) | ||
477 | g_printerr("[gl] E: %d\n", error); | ||
478 | |||
479 | #ifdef TIMING /* get time to draw one frame to compare algorithms */ | ||
480 | g_timer_stop(timer); | ||
481 | |||
482 | if(avg_msec == 0) | ||
483 | { | ||
484 | gulong msec; | ||
485 | gdouble sec; | ||
486 | |||
487 | sec = g_timer_elapsed(timer, &msec); | ||
488 | avg_msec = (gulong)sec * 1000000 + msec; | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | gulong msec, add; | ||
493 | gdouble sec; | ||
494 | |||
495 | sec = g_timer_elapsed(timer, &msec); | ||
496 | add = (gulong)sec * 1000000 + msec; | ||
497 | avg_msec = (avg_msec + add) / 2; | ||
498 | } | ||
499 | |||
500 | g_printerr("average time to render frame: %lu µs\n", avg_msec); | ||
501 | #endif | ||
502 | |||
503 | #if DEBUG > 3 | ||
504 | g_printerr("gl.c: drawn...\n"); | ||
505 | #endif | ||
506 | } | ||
507 | |||
508 | |||
509 | int texture_load_all_textures(G3DModel *model) | ||
510 | { | ||
511 | if(model == NULL) return EXIT_FAILURE; | ||
512 | |||
513 | if(model->tex_images != NULL) | ||
514 | g_hash_table_foreach(model->tex_images, gl_load_texture, NULL); | ||
515 | |||
516 | return EXIT_SUCCESS; | ||
517 | } | ||
518 | |||