[contrib] generic computeHkl method
[hkl.git] / gui / hkl-gui-3d-gl.c
blob93869e97890b8440748b0bcd1fd4686abd461673
1 /* $Id: gl.c 127 2009-09-05 19:45:12Z mmmaddd $ */
3 /*
4 G3DViewer - 3D object viewer
6 Copyright (C) 2005, 2006 Markus Dahms <mad@automagically.de>
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.
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.
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
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
27 #include <glib.h>
29 #include <GL/gl.h>
30 #include <GL/glu.h>
32 #include <g3d/types.h>
33 #include <g3d/quat.h>
34 #include <g3d/matrix.h>
35 #include <g3d/vector.h>
36 #include <g3d/face.h>
38 #include "hkl-gui-3d-gl.h"
40 struct _G3DGLRenderState {
41 gint32 gl_dlist, gl_dlist_shadow;
42 G3DMaterial *prev_material;
43 guint32 prev_texid;
46 #if DEBUG > 0
47 #define TIMING
48 #endif
50 #ifdef TIMING
51 static GTimer *timer = NULL;
52 #endif
54 static void gl_init(void)
56 GLenum error;
58 #if DEBUG > 1
59 g_printerr("init OpenGL\n");
60 #endif
63 GLfloat light0_pos[4] = { -50.0, 50.0, 0.0, 0.0 };
64 GLfloat light0_col[4] = { 0.6, 0.6, 0.6, 1.0 };
65 GLfloat light1_pos[4] = { 50.0, 50.0, 0.0, 0.0 };
66 GLfloat light1_col[4] = { 0.4, 0.4, 0.4, 1.0 };
67 GLfloat ambient_lc[4] = { 0.35, 0.35, 0.35, 1.0 };
69 /* transparency and blending */
70 #if 0
71 glAlphaFunc(GL_GREATER, 0.1);
72 #endif
73 glEnable(GL_ALPHA_TEST);
75 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
76 glEnable(GL_BLEND);
78 glDepthFunc(GL_LEQUAL);
79 glDepthMask(GL_TRUE);
80 glEnable(GL_DEPTH_TEST);
83 #if 0
84 glEnable(GL_LINE_SMOOTH);
85 glEnable(GL_POLYGON_SMOOTH);
86 #endif
88 #if 0
89 glDisable(GL_DITHER);
90 #endif
91 glShadeModel(GL_SMOOTH);
93 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
94 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
95 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
97 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient_lc);
98 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
99 #ifdef GL_LIGHT_MODEL_COLOR_CONTROL
100 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
101 #endif
102 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
104 glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
105 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_col);
106 glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);
107 glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_col);
108 glLightfv(GL_LIGHT1, GL_SPECULAR, light1_col);
109 glEnable(GL_LIGHT0);
110 glEnable(GL_LIGHT1);
111 glEnable(GL_LIGHTING);
114 /* colors and materials */
115 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
116 glEnable(GL_COLOR_MATERIAL);
119 /* texture stuff */
120 glEnable(GL_TEXTURE_2D);
123 #ifdef TIMING
124 timer = g_timer_new();
125 #endif
128 void gl_set_twoside(gboolean twoside)
130 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, twoside ? 1 : 0);
131 glColorMaterial(
132 twoside ? GL_FRONT_AND_BACK : GL_FRONT,
133 GL_AMBIENT_AND_DIFFUSE);
136 void gl_set_textures(gboolean textures)
138 if(textures)
139 glEnable(GL_TEXTURE_2D);
140 else
142 glBindTexture(GL_TEXTURE_2D, 0);
143 glDisable(GL_TEXTURE_2D);
147 /* GHFunc */
148 void gl_load_texture(gpointer key, gpointer value, gpointer data)
150 G3DImage *image = (G3DImage *)value;
151 gint32 env;
152 GLenum error;
155 #if 0
156 /* predefined - update object->_tex_images else... */
157 glGenTextures(1, &(image->tex_id));
158 #endif
160 #if DEBUG > 0
161 g_print("gl: loading texture '%s' (%dx%dx%d) - id %d\n",
162 image->name ? image->name : "(null)",
163 image->width, image->height, image->depth,
164 image->tex_id);
165 #endif
167 glBindTexture(GL_TEXTURE_2D, image->tex_id);
168 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
173 GL_LINEAR_MIPMAP_NEAREST);
176 switch(image->tex_env)
178 case G3D_TEXENV_BLEND: env = GL_BLEND; break;
179 case G3D_TEXENV_MODULATE: env = GL_MODULATE; break;
180 case G3D_TEXENV_DECAL: env = GL_DECAL; break;
181 case G3D_TEXENV_REPLACE: env = GL_REPLACE; break;
182 default: env = GL_MODULATE; break;
184 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
185 gluBuild2DMipmaps(
186 GL_TEXTURE_2D,
187 GL_RGBA,
188 image->width,
189 image->height,
190 GL_RGBA,
191 GL_UNSIGNED_BYTE,
192 image->pixeldata);
195 static inline void gl_update_material(G3DGLRenderOptions *options,
196 G3DMaterial *material)
198 GLenum facetype;
199 GLfloat normspec[4] = { 0.0, 0.0, 0.0, 1.0 };
201 g_return_if_fail(material != NULL);
203 if(options->glflags & G3D_FLAG_GL_ALLTWOSIDE)
204 facetype = GL_FRONT_AND_BACK;
205 else
206 facetype = GL_FRONT;
208 if(options->glflags & G3D_FLAG_GL_COLORS)
209 glColor4f(
210 material->r,
211 material->g,
212 material->b,
213 material->a);
214 else
215 glColor4f(0.7, 0.7, 0.7, 1.0);
217 return;
219 if(options->glflags & G3D_FLAG_GL_SPECULAR)
220 glMaterialfv(facetype, GL_SPECULAR, material->specular);
221 else
222 glMaterialfv(facetype, GL_SPECULAR, normspec);
224 if(options->glflags & G3D_FLAG_GL_SHININESS)
225 glMaterialf(facetype, GL_SHININESS, material->shininess * 10);
226 else
227 glMaterialf(facetype, GL_SHININESS, 0.0);
230 static inline void gl_draw_face(G3DGLRenderOptions *options,
231 G3DObject *object, gint32 i, gfloat min_a, gfloat max_a,
232 gboolean *dont_render, gboolean *init, gboolean is_shadow)
234 gint32 j;
236 if(*init)
238 options->state->prev_material = NULL;
239 options->state->prev_texid = 0;
240 *init = FALSE;
243 /* material check */
244 if(!is_shadow && (options->state->prev_material != object->_materials[i]))
246 if((object->_materials[i]->a < min_a) ||
247 (object->_materials[i]->a >= max_a))
249 *dont_render = TRUE;
250 return;
253 *dont_render = FALSE;
255 glEnd();
256 gl_update_material(options, object->_materials[i]);
257 glBegin(GL_TRIANGLES);
258 options->state->prev_material = object->_materials[i];
260 options->state->prev_texid = 0;
263 if(*dont_render) return;
265 /* texture stuff */
266 if(!is_shadow && (options->glflags & G3D_FLAG_GL_TEXTURES) &&
267 (object->_flags[i] & G3D_FLAG_FAC_TEXMAP))
269 /* if texture has changed update to new texture */
270 if(object->_tex_images[i] != options->state->prev_texid) {
271 options->state->prev_texid = object->_tex_images[i];
272 glEnd();
273 glBindTexture(GL_TEXTURE_2D, options->state->prev_texid);
274 glBegin(GL_TRIANGLES);
275 #if DEBUG > 5
276 g_print("gl: binding to texture id %d\n", prev_texid);
277 #endif
281 /* draw triangles */
282 for(j = 0; j < 3; j ++)
284 if(!is_shadow && (options->glflags & G3D_FLAG_GL_TEXTURES) &&
285 (object->_flags[i] & G3D_FLAG_FAC_TEXMAP))
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
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]);
306 } /* 1 .. 3 */
309 static inline void gl_may_end(gint32 ftype)
311 if(ftype != -1)
312 glEnd();
315 static inline void gl_may_begin(gint32 ftype)
317 if(ftype != -1)
318 glBegin(ftype);
321 static inline void gl_draw_face_list(G3DGLRenderOptions *options,
322 G3DObject *object, gfloat min_a, gfloat max_a,
323 gboolean *init, gboolean is_shadow)
325 GSList *fitem;
326 G3DFace *face;
327 G3DVector nx, ny, nz;
328 gint32 prev_ftype = -1;
329 gint32 index, j, ftype;
331 if(*init) {
332 options->state->prev_material = NULL;
333 options->state->prev_texid = 0;
334 *init = FALSE;
337 for(fitem = object->faces; fitem != NULL; fitem = fitem->next) {
338 face = fitem->data;
339 if(!is_shadow && (options->state->prev_material != face->material)) {
340 if((face->material->a < min_a) || (face->material->a >= max_a)) {
341 return;
344 gl_may_end(prev_ftype);
345 gl_update_material(options, face->material);
346 gl_may_begin(prev_ftype);
348 options->state->prev_material = face->material;
350 options->state->prev_texid = 0;
353 /* texture stuff */
354 if(!is_shadow && (options->glflags & G3D_FLAG_GL_TEXTURES) &&
355 (face->flags & G3D_FLAG_FAC_TEXMAP)) {
356 /* if texture has changed update to new texture */
357 if(face->tex_image) {
358 if(face->tex_image->tex_id != options->state->prev_texid) {
359 options->state->prev_texid = face->tex_image->tex_id;
361 gl_may_end(prev_ftype);
362 glBindTexture(GL_TEXTURE_2D, options->state->prev_texid);
363 gl_may_begin(prev_ftype);
364 #if DEBUG > 5
365 g_print("gl: binding to texture id %d\n", prev_texid);
366 #endif
369 } /* texture stuff */
371 switch(face->vertex_count) {
372 case 3: ftype = GL_TRIANGLES; break;
373 case 4: ftype = GL_QUADS; break;
374 case 2: ftype = GL_LINES; break;
375 default: ftype = GL_POLYGON;
376 #if DEBUG > 0
377 g_debug("face vertex count: %d", face->vertex_count);
378 #endif
379 break;
381 if(ftype != prev_ftype) {
382 gl_may_end(prev_ftype);
383 glBegin(ftype);
384 prev_ftype = ftype;
387 if(!(face->flags & G3D_FLAG_FAC_NORMALS)) {
388 face->normals = g_new0(G3DVector, face->vertex_count * 3);
390 g3d_face_get_normal(face, object, &nx, &ny, &nz);
391 g3d_vector_unify(&nx, &ny, &nz);
393 for(j = 0; j < face->vertex_count; j ++) {
394 face->normals[j * 3 + 0] = nx;
395 face->normals[j * 3 + 1] = ny;
396 face->normals[j * 3 + 2] = nz;
398 face->flags |= G3D_FLAG_FAC_NORMALS;
401 for(j = 0; j < face->vertex_count; j ++) {
402 index = face->vertex_indices[j];
404 if(!is_shadow && (options->glflags & G3D_FLAG_GL_TEXTURES) &&
405 (face->flags & G3D_FLAG_FAC_TEXMAP))
407 glTexCoord2f(
408 face->tex_vertex_data[j * 2 + 0],
409 face->tex_vertex_data[j * 2 + 1]);
412 glNormal3f(
413 face->normals[j * 3 + 0],
414 face->normals[j * 3 + 1],
415 face->normals[j * 3 + 2]);
417 glVertex3f(
418 object->vertex_data[index * 3 + 0],
419 object->vertex_data[index * 3 + 1],
420 object->vertex_data[index * 3 + 2]);
423 } /* face loop */
425 gl_may_end(prev_ftype);
429 static inline void gl_draw_objects(G3DGLRenderOptions *options,
430 GSList *objects, gfloat min_a, gfloat max_a, gboolean is_shadow)
432 GSList *olist;
433 int i;
434 G3DObject *object;
435 gboolean dont_render;
436 gboolean init = TRUE;
438 olist = objects;
439 while(olist != NULL)
441 object = (G3DObject *)olist->data;
442 olist = olist->next;
444 dont_render = FALSE;
446 /* don't render invisible objects */
447 if(object->hide) continue;
449 g_return_if_fail(object != NULL);
450 #if DEBUG > 3
451 g_printerr("name: %s {", object->name);
452 #endif
454 #if DEBUG > 2
455 g_printerr("new object\n");
456 #endif
458 glPushMatrix();
460 if(object->transformation)
462 glMultMatrixf(object->transformation->matrix);
465 #define EXPERIMENTAL
466 #ifdef EXPERIMENTAL
467 gl_draw_face_list(options, object, min_a, max_a, &init, is_shadow);
468 #else
469 glBegin(GL_TRIANGLES);
471 for(i = 0; i < object->_num_faces; i ++)
473 gl_draw_face(options, object, i, min_a, max_a,
474 &dont_render, &init, is_shadow);
475 } /* all faces */
477 glEnd();
478 #endif
480 if(!is_shadow && (options->glflags & G3D_FLAG_GL_POINTS)) {
481 glColor4f(0.2, 0.2, 0.2, 1.0);
482 glBegin(GL_POINTS);
483 for(i = 0; i < object->vertex_count; i ++) {
484 glVertex3f(
485 object->vertex_data[i * 3 + 0],
486 object->vertex_data[i * 3 + 1],
487 object->vertex_data[i * 3 + 2]);
489 glEnd();
492 /* handle sub-objects */
493 gl_draw_objects(options, object->objects, min_a, max_a, is_shadow);
495 glPopMatrix();
497 } /* while olist != NULL */
500 static inline void matrix_g3d_to_gl(G3DMatrix *g3dm, GLfloat glm[4][4])
502 guint32 i, j;
504 for(i = 0; i < 4; i ++)
505 for(j = 0; j < 4; j ++)
506 glm[i][j] = g3dm[i * 4 + j];
509 static inline void gl_setup_view(G3DGLRenderOptions *options)
511 GLfloat m[4][4];
512 G3DMatrix *g3dm;
513 G3DFloat w, h;
515 glMatrixMode(GL_PROJECTION);
516 glLoadIdentity();
517 if(options->glflags & G3D_FLAG_GL_ISOMETRIC) {
518 w = 0.5 * options->zoom;
519 h = w / options->aspect;
520 glOrtho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, 1, 100);
521 } else {
522 gluPerspective(options->zoom, options->aspect, 1, 100);
524 /* translation of view */
525 glTranslatef(options->offx, options->offy, 0.0);
527 glMatrixMode(GL_MODELVIEW);
529 glClearColor(
530 options->bgcolor[0],
531 options->bgcolor[1],
532 options->bgcolor[2],
533 options->bgcolor[3]);
534 glClearDepth(1.0);
535 glClearIndex(0.3);
536 glClear(
537 GL_COLOR_BUFFER_BIT |
538 GL_DEPTH_BUFFER_BIT |
539 GL_ACCUM_BUFFER_BIT |
540 GL_STENCIL_BUFFER_BIT);
542 glLoadIdentity();
543 glTranslatef(0, 0, -30);
544 g3dm = g3d_matrix_new();
545 g3d_quat_to_matrix(options->quat, g3dm);
546 matrix_g3d_to_gl(g3dm, m);
548 g3d_matrix_free(g3dm);
549 glMultMatrixf(&m[0][0]);
552 static void gl_setup_shadow_matrix(G3DGLRenderOptions *options,
553 G3DVector *l, G3DVector *p, G3DVector *n)
555 G3DDouble c, d;
556 G3DMatrix *m = options->shadow_matrix;
558 d = n[0] * l[0] + n[1] * l[1] + n[2] * l[2];
559 c = p[0] * n[0] + p[1] * n[1] + p[2] * n[2] - d;
561 m[0 * 4 + 0] = l[0] * n[0] + c;
562 m[1 * 4 + 0] = l[0] * n[1];
563 m[2 * 4 + 0] = l[0] * n[2];
564 m[3 * 4 + 0] = - l[0] * c - l[0] * d;
566 m[0 * 4 + 1] = l[1] * n[0];
567 m[1 * 4 + 1] = l[1] * n[1] + c;
568 m[2 * 4 + 1] = l[1] * n[2];
569 m[3 * 4 + 1] = - l[1] * c - l[1] * d;
571 m[0 * 4 + 2] = l[2] * n[0];
572 m[1 * 4 + 2] = l[2] * n[1];
573 m[2 * 4 + 2] = l[2] * n[2] + c;
574 m[3 * 4 + 2] = - l[2] * c - l[2] * d;
576 m[0 * 4 + 3] = n[0];
577 m[1 * 4 + 3] = n[1];
578 m[2 * 4 + 3] = n[2];
579 m[3 * 4 + 3] = -d;
582 void gl_draw_coord_system(G3DGLRenderOptions *options)
584 if(options->glflags & G3D_FLAG_GL_COORD_AXES) {
585 /* x: red */
586 glColor3f(1.0, 0.0, 0.0);
587 glBegin(GL_LINES);
588 glVertex3f(0.0, 0.0, 0.0);
589 glVertex3f(10.0, 0.0, 0.0);
590 glEnd();
591 /* y: green */
592 glColor3f(0.0, 1.0, 0.0);
593 glBegin(GL_LINES);
594 glVertex3f(0.0, 0.0, 0.0);
595 glVertex3f(0.0, 10.0, 0.0);
596 glEnd();
597 /* z: blue */
598 glColor3f(0.0, 0.0, 1.0);
599 glBegin(GL_LINES);
600 glVertex3f(0.0, 0.0, 0.0);
601 glVertex3f(0.0, 0.0, 10.0);
602 glEnd();
606 static G3DFloat gl_min_y(GSList *objects)
608 G3DFloat min_y = 10.0, tmp_y;
609 GSList *oitem;
610 G3DObject *object;
611 gint32 i;
613 for(oitem = objects; oitem != NULL; oitem = oitem->next) {
614 object = oitem->data;
615 for(i = 0; i < object->vertex_count; i ++)
616 if(object->vertex_data[i * 3 + 1] < min_y)
617 min_y = object->vertex_data[i * 3 + 1];
618 tmp_y = gl_min_y(object->objects);
619 if(tmp_y < min_y)
620 min_y = tmp_y;
622 return min_y;
625 static void gl_draw_plane(G3DGLRenderOptions *options)
627 glBegin(GL_QUADS);
628 glNormal3f(0.0, -1.0, 0.0);
629 #define PLANE_MAX 12
630 glVertex3f(-PLANE_MAX, options->min_y - 0.001, PLANE_MAX);
631 glVertex3f( PLANE_MAX, options->min_y - 0.001, PLANE_MAX);
632 glVertex3f( PLANE_MAX, options->min_y - 0.001, -PLANE_MAX);
633 glVertex3f(-PLANE_MAX, options->min_y - 0.001, -PLANE_MAX);
634 #undef PLANE_MAX
635 glEnd();
638 static void gl_setup_floor_stencil(G3DGLRenderOptions *options)
640 glClear(GL_STENCIL_BUFFER_BIT);
641 glDepthMask(GL_FALSE);
642 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
644 glEnable(GL_STENCIL_TEST);
645 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
646 glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
648 gl_draw_plane(options);
650 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
651 glDepthMask(GL_TRUE);
653 glStencilFunc(GL_EQUAL, 1, 0xffffffff);
654 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
657 static void gl_setup_shadow_stencil(G3DGLRenderOptions *options)
659 glClear(GL_STENCIL_BUFFER_BIT);
660 glDepthMask(GL_FALSE);
661 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
663 glEnable(GL_STENCIL_TEST);
664 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
665 glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
667 glCallList(options->state->gl_dlist_shadow);
669 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
670 glDepthMask(GL_TRUE);
672 glStencilFunc(GL_EQUAL, 1, 0xffffffff);
673 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
676 void gl_draw(G3DGLRenderOptions *options, G3DModel *model)
678 GLenum error;
679 gfloat f;
680 #ifdef TIMING
681 gboolean ignore_timing = FALSE;
682 gulong msec, add;
683 gdouble sec;
684 #endif
685 G3DVector light[3] = { 100.0, 500.0, 20.0 };
686 G3DVector plane[3] = { 0.0, -20.0, 0.0 };
687 G3DVector normal[3] = { 0.0, -1.0, 0.0 };
689 if(!options->initialized)
691 gl_init();
692 options->initialized = TRUE;
693 #ifdef TIMING
694 ignore_timing = TRUE;
695 #endif
698 /* prepare viewport */
699 gl_setup_view(options);
701 /* reset texture */
702 glBindTexture (GL_TEXTURE_2D, 0);
704 if(model == NULL)
705 return;
707 #ifdef TIMING
708 g_timer_start(timer);
709 #endif
711 if(options->updated) {
712 options->updated = FALSE;
713 #ifdef TIMING
714 ignore_timing = TRUE;
715 #endif
716 #if DEBUG > 2
717 g_printerr("[gl] creating new display list\n");
718 #endif
719 options->min_y = gl_min_y(model->objects);
721 /* update render state */
722 if(options->state) {
723 glDeleteLists(options->state->gl_dlist, 1);
724 glDeleteLists(options->state->gl_dlist_shadow, 1);
725 g_free(options->state);
727 options->state = g_new0(G3DGLRenderState, 1);
729 /* create and execute display list */
730 options->state->gl_dlist = glGenLists(1);
731 options->state->gl_dlist_shadow = glGenLists(1);
733 glNewList(options->state->gl_dlist, GL_COMPILE);
734 /* draw all objects */
735 for(f = 1.0; f >= 0.0; f -= 0.2)
736 gl_draw_objects(options, model->objects, f, f + 0.2, FALSE);
737 glEndList();
739 if(options->glflags & G3D_FLAG_GL_SHADOW) {
740 glNewList(options->state->gl_dlist_shadow, GL_COMPILE);
741 gl_draw_objects(options, model->objects, 0.0, 1.0, TRUE);
742 glEndList();
746 g_return_if_fail(options->state != NULL);
748 gl_draw_coord_system(options);
750 if(options->glflags & G3D_FLAG_GL_SHADOW) {
751 plane[1] = options->min_y;
753 /* reflection */
754 glPushMatrix();
755 gl_setup_floor_stencil(options);
756 glTranslatef(0.0, (options->min_y * 2), 0.0);
757 glScalef(1.0, -1.0, 1.0);
758 glCallList(options->state->gl_dlist);
759 glPopMatrix();
761 /* plane */
762 glDisable(GL_LIGHTING);
763 glBindTexture (GL_TEXTURE_2D, 0);
764 glColor4f(0.5, 0.5, 0.5, 0.7);
765 gl_draw_plane(options);
766 glEnable(GL_LIGHTING);
767 /* shadow */
768 glPushMatrix();
769 gl_setup_shadow_matrix(options, light, plane, normal);
770 glBindTexture (GL_TEXTURE_2D, 0);
771 glDisable(GL_LIGHTING);
772 glDisable(GL_DEPTH_TEST);
773 glMultMatrixf(options->shadow_matrix);
774 gl_setup_shadow_stencil(options);
775 glPopMatrix();
776 glPushMatrix();
777 glTranslatef(0.0, 0.001, 0.0);
778 glColor4f(0.3, 0.3, 0.3, 0.7);
779 gl_draw_plane(options);
780 glEnable(GL_DEPTH_TEST);
781 glEnable(GL_LIGHTING);
782 glPopMatrix();
784 glDisable(GL_STENCIL_TEST);
787 /* execute display list */
788 glCallList(options->state->gl_dlist);
790 #ifdef TIMING /* get time to draw one frame to compare algorithms */
791 g_timer_stop(timer);
793 if(!ignore_timing) {
794 if(options->avg_msec == 0) {
795 sec = g_timer_elapsed(timer, &msec);
796 options->avg_msec = (gulong)sec * 1000000 + msec;
797 } else {
798 sec = g_timer_elapsed(timer, &msec);
799 add = (gulong)sec * 1000000 + msec;
800 options->avg_msec = (options->avg_msec + add) / 2;
803 #endif
805 #if DEBUG > 3
806 g_printerr("gl.c: drawn...\n");
807 #endif