1 /* $Id: gl.c 127 2009-09-05 19:45:12Z mmmaddd $ */
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
32 #include <g3d/types.h>
34 #include <g3d/matrix.h>
35 #include <g3d/vector.h>
38 #include "hkl-gui-3d-gl.h"
40 struct _G3DGLRenderState
{
41 gint32 gl_dlist
, gl_dlist_shadow
;
42 G3DMaterial
*prev_material
;
51 static GTimer
*timer
= NULL
;
54 static void gl_init(void)
57 g_printerr("init OpenGL\n");
61 GLfloat light0_pos
[4] = { -50.0, 50.0, 0.0, 0.0 };
62 GLfloat light0_col
[4] = { 0.6, 0.6, 0.6, 1.0 };
63 GLfloat light1_pos
[4] = { 50.0, 50.0, 0.0, 0.0 };
64 GLfloat light1_col
[4] = { 0.4, 0.4, 0.4, 1.0 };
65 GLfloat ambient_lc
[4] = { 0.35, 0.35, 0.35, 1.0 };
67 /* transparency and blending */
69 glAlphaFunc(GL_GREATER
, 0.1);
71 glEnable(GL_ALPHA_TEST
);
73 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
76 glDepthFunc(GL_LEQUAL
);
78 glEnable(GL_DEPTH_TEST
);
82 glEnable(GL_LINE_SMOOTH
);
83 glEnable(GL_POLYGON_SMOOTH
);
89 glShadeModel(GL_SMOOTH
);
91 glHint(GL_PERSPECTIVE_CORRECTION_HINT
, GL_NICEST
);
92 glHint(GL_LINE_SMOOTH_HINT
, GL_NICEST
);
93 glHint(GL_POLYGON_SMOOTH_HINT
, GL_NICEST
);
95 glLightModelfv(GL_LIGHT_MODEL_AMBIENT
, ambient_lc
);
96 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE
, 0);
97 #ifdef GL_LIGHT_MODEL_COLOR_CONTROL
98 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL
, GL_SEPARATE_SPECULAR_COLOR
);
100 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER
, 1);
102 glLightfv(GL_LIGHT0
, GL_POSITION
, light0_pos
);
103 glLightfv(GL_LIGHT0
, GL_DIFFUSE
, light0_col
);
104 glLightfv(GL_LIGHT1
, GL_POSITION
, light1_pos
);
105 glLightfv(GL_LIGHT1
, GL_DIFFUSE
, light1_col
);
106 glLightfv(GL_LIGHT1
, GL_SPECULAR
, light1_col
);
109 glEnable(GL_LIGHTING
);
112 /* colors and materials */
113 glColorMaterial(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
);
114 glEnable(GL_COLOR_MATERIAL
);
118 glEnable(GL_TEXTURE_2D
);
122 timer
= g_timer_new();
126 void gl_set_twoside(gboolean twoside
)
128 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE
, twoside
? 1 : 0);
130 twoside
? GL_FRONT_AND_BACK
: GL_FRONT
,
131 GL_AMBIENT_AND_DIFFUSE
);
134 void gl_set_textures(gboolean textures
)
137 glEnable(GL_TEXTURE_2D
);
140 glBindTexture(GL_TEXTURE_2D
, 0);
141 glDisable(GL_TEXTURE_2D
);
146 void gl_load_texture(gpointer key
, gpointer value
, gpointer data
)
148 G3DImage
*image
= (G3DImage
*)value
;
153 /* predefined - update object->_tex_images else... */
154 glGenTextures(1, &(image
->tex_id
));
158 g_print("gl: loading texture '%s' (%dx%dx%d) - id %d\n",
159 image
->name
? image
->name
: "(null)",
160 image
->width
, image
->height
, image
->depth
,
164 glBindTexture(GL_TEXTURE_2D
, image
->tex_id
);
165 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
166 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
167 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
168 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
169 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
170 GL_LINEAR_MIPMAP_NEAREST
);
173 switch(image
->tex_env
)
175 case G3D_TEXENV_BLEND
: env
= GL_BLEND
; break;
176 case G3D_TEXENV_MODULATE
: env
= GL_MODULATE
; break;
177 case G3D_TEXENV_DECAL
: env
= GL_DECAL
; break;
178 case G3D_TEXENV_REPLACE
: env
= GL_REPLACE
; break;
179 default: env
= GL_MODULATE
; break;
181 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, env
);
192 static inline void gl_update_material(G3DGLRenderOptions
*options
,
193 G3DMaterial
*material
)
196 GLfloat normspec
[4] = { 0.0, 0.0, 0.0, 1.0 };
198 g_return_if_fail(material
!= NULL
);
200 if(options
->glflags
& G3D_FLAG_GL_ALLTWOSIDE
)
201 facetype
= GL_FRONT_AND_BACK
;
205 if(options
->glflags
& G3D_FLAG_GL_COLORS
)
212 glColor4f(0.7, 0.7, 0.7, 1.0);
216 if(options
->glflags
& G3D_FLAG_GL_SPECULAR
)
217 glMaterialfv(facetype
, GL_SPECULAR
, material
->specular
);
219 glMaterialfv(facetype
, GL_SPECULAR
, normspec
);
221 if(options
->glflags
& G3D_FLAG_GL_SHININESS
)
222 glMaterialf(facetype
, GL_SHININESS
, material
->shininess
* 10);
224 glMaterialf(facetype
, GL_SHININESS
, 0.0);
227 static inline void gl_draw_face(G3DGLRenderOptions
*options
,
228 G3DObject
*object
, gint32 i
, gfloat min_a
, gfloat max_a
,
229 gboolean
*dont_render
, gboolean
*init
, gboolean is_shadow
)
235 options
->state
->prev_material
= NULL
;
236 options
->state
->prev_texid
= 0;
241 if(!is_shadow
&& (options
->state
->prev_material
!= object
->_materials
[i
]))
243 if((object
->_materials
[i
]->a
< min_a
) ||
244 (object
->_materials
[i
]->a
>= max_a
))
250 *dont_render
= FALSE
;
253 gl_update_material(options
, object
->_materials
[i
]);
254 glBegin(GL_TRIANGLES
);
255 options
->state
->prev_material
= object
->_materials
[i
];
257 options
->state
->prev_texid
= 0;
260 if(*dont_render
) return;
263 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
264 (object
->_flags
[i
] & G3D_FLAG_FAC_TEXMAP
))
266 /* if texture has changed update to new texture */
267 if(object
->_tex_images
[i
] != options
->state
->prev_texid
) {
268 options
->state
->prev_texid
= object
->_tex_images
[i
];
270 glBindTexture(GL_TEXTURE_2D
, options
->state
->prev_texid
);
271 glBegin(GL_TRIANGLES
);
273 g_print("gl: binding to texture id %d\n", prev_texid
);
279 for(j
= 0; j
< 3; j
++)
281 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
282 (object
->_flags
[i
] & G3D_FLAG_FAC_TEXMAP
))
285 object
->_tex_coords
[(i
* 3 + j
) * 2 + 0],
286 object
->_tex_coords
[(i
* 3 + j
) * 2 + 1]);
288 g_print("gl: setting texture coords: %f, %f\n",
289 object
->_tex_coords
[(i
* 3 + j
) * 2 + 0],
290 object
->_tex_coords
[(i
* 3 + j
) * 2 + 1]);
295 object
->_normals
[(i
*3+j
)*3+0],
296 object
->_normals
[(i
*3+j
)*3+1],
297 object
->_normals
[(i
*3+j
)*3+2]);
299 object
->vertex_data
[object
->_indices
[i
*3+j
]*3+0],
300 object
->vertex_data
[object
->_indices
[i
*3+j
]*3+1],
301 object
->vertex_data
[object
->_indices
[i
*3+j
]*3+2]);
306 static inline void gl_may_end(gint32 ftype
)
312 static inline void gl_may_begin(gint32 ftype
)
318 static inline void gl_draw_face_list(G3DGLRenderOptions
*options
,
319 G3DObject
*object
, gfloat min_a
, gfloat max_a
,
320 gboolean
*init
, gboolean is_shadow
)
324 G3DVector nx
, ny
, nz
;
325 gint32 prev_ftype
= -1;
326 gint32 index
, j
, ftype
;
329 options
->state
->prev_material
= NULL
;
330 options
->state
->prev_texid
= 0;
334 for(fitem
= object
->faces
; fitem
!= NULL
; fitem
= fitem
->next
) {
336 if(!is_shadow
&& (options
->state
->prev_material
!= face
->material
)) {
337 if((face
->material
->a
< min_a
) || (face
->material
->a
>= max_a
)) {
341 gl_may_end(prev_ftype
);
342 gl_update_material(options
, face
->material
);
343 gl_may_begin(prev_ftype
);
345 options
->state
->prev_material
= face
->material
;
347 options
->state
->prev_texid
= 0;
351 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
352 (face
->flags
& G3D_FLAG_FAC_TEXMAP
)) {
353 /* if texture has changed update to new texture */
354 if(face
->tex_image
) {
355 if(face
->tex_image
->tex_id
!= options
->state
->prev_texid
) {
356 options
->state
->prev_texid
= face
->tex_image
->tex_id
;
358 gl_may_end(prev_ftype
);
359 glBindTexture(GL_TEXTURE_2D
, options
->state
->prev_texid
);
360 gl_may_begin(prev_ftype
);
362 g_print("gl: binding to texture id %d\n", prev_texid
);
366 } /* texture stuff */
368 switch(face
->vertex_count
) {
369 case 3: ftype
= GL_TRIANGLES
; break;
370 case 4: ftype
= GL_QUADS
; break;
371 case 2: ftype
= GL_LINES
; break;
372 default: ftype
= GL_POLYGON
;
374 g_debug("face vertex count: %d", face
->vertex_count
);
378 if(ftype
!= prev_ftype
) {
379 gl_may_end(prev_ftype
);
384 if(!(face
->flags
& G3D_FLAG_FAC_NORMALS
)) {
385 face
->normals
= g_new0(G3DVector
, face
->vertex_count
* 3);
387 g3d_face_get_normal(face
, object
, &nx
, &ny
, &nz
);
388 g3d_vector_unify(&nx
, &ny
, &nz
);
390 for(j
= 0; j
< face
->vertex_count
; j
++) {
391 face
->normals
[j
* 3 + 0] = nx
;
392 face
->normals
[j
* 3 + 1] = ny
;
393 face
->normals
[j
* 3 + 2] = nz
;
395 face
->flags
|= G3D_FLAG_FAC_NORMALS
;
398 for(j
= 0; j
< face
->vertex_count
; j
++) {
399 index
= face
->vertex_indices
[j
];
401 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
402 (face
->flags
& G3D_FLAG_FAC_TEXMAP
))
405 face
->tex_vertex_data
[j
* 2 + 0],
406 face
->tex_vertex_data
[j
* 2 + 1]);
410 face
->normals
[j
* 3 + 0],
411 face
->normals
[j
* 3 + 1],
412 face
->normals
[j
* 3 + 2]);
415 object
->vertex_data
[index
* 3 + 0],
416 object
->vertex_data
[index
* 3 + 1],
417 object
->vertex_data
[index
* 3 + 2]);
422 gl_may_end(prev_ftype
);
426 static inline void gl_draw_objects(G3DGLRenderOptions
*options
,
427 GSList
*objects
, gfloat min_a
, gfloat max_a
, gboolean is_shadow
)
432 gboolean dont_render
;
433 gboolean init
= TRUE
;
438 object
= (G3DObject
*)olist
->data
;
443 /* don't render invisible objects */
444 if(object
->hide
) continue;
446 g_return_if_fail(object
!= NULL
);
448 g_printerr("name: %s {", object
->name
);
452 g_printerr("new object\n");
457 if(object
->transformation
)
459 glMultMatrixf(object
->transformation
->matrix
);
464 gl_draw_face_list(options
, object
, min_a
, max_a
, &init
, is_shadow
);
466 glBegin(GL_TRIANGLES
);
468 for(i
= 0; i
< object
->_num_faces
; i
++)
470 gl_draw_face(options
, object
, i
, min_a
, max_a
,
471 &dont_render
, &init
, is_shadow
);
477 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_POINTS
)) {
478 glColor4f(0.2, 0.2, 0.2, 1.0);
480 for(i
= 0; i
< object
->vertex_count
; i
++) {
482 object
->vertex_data
[i
* 3 + 0],
483 object
->vertex_data
[i
* 3 + 1],
484 object
->vertex_data
[i
* 3 + 2]);
489 /* handle sub-objects */
490 gl_draw_objects(options
, object
->objects
, min_a
, max_a
, is_shadow
);
494 } /* while olist != NULL */
497 static inline void matrix_g3d_to_gl(G3DMatrix
*g3dm
, GLfloat glm
[4][4])
501 for(i
= 0; i
< 4; i
++)
502 for(j
= 0; j
< 4; j
++)
503 glm
[i
][j
] = g3dm
[i
* 4 + j
];
506 static inline void gl_setup_view(G3DGLRenderOptions
*options
)
512 glMatrixMode(GL_PROJECTION
);
514 if(options
->glflags
& G3D_FLAG_GL_ISOMETRIC
) {
515 w
= 0.5 * options
->zoom
;
516 h
= w
/ options
->aspect
;
517 glOrtho(-w
/ 2.0, w
/ 2.0, -h
/ 2.0, h
/ 2.0, 1, 100);
519 gluPerspective(options
->zoom
, options
->aspect
, 1, 100);
521 /* translation of view */
522 glTranslatef(options
->offx
, options
->offy
, 0.0);
524 glMatrixMode(GL_MODELVIEW
);
530 options
->bgcolor
[3]);
534 GL_COLOR_BUFFER_BIT
|
535 GL_DEPTH_BUFFER_BIT
|
536 GL_ACCUM_BUFFER_BIT
|
537 GL_STENCIL_BUFFER_BIT
);
540 glTranslatef(0, 0, -30);
541 g3dm
= g3d_matrix_new();
542 g3d_quat_to_matrix(options
->quat
, g3dm
);
543 matrix_g3d_to_gl(g3dm
, m
);
545 g3d_matrix_free(g3dm
);
546 glMultMatrixf(&m
[0][0]);
549 static void gl_setup_shadow_matrix(G3DGLRenderOptions
*options
,
550 G3DVector
*l
, G3DVector
*p
, G3DVector
*n
)
553 G3DMatrix
*m
= options
->shadow_matrix
;
555 d
= n
[0] * l
[0] + n
[1] * l
[1] + n
[2] * l
[2];
556 c
= p
[0] * n
[0] + p
[1] * n
[1] + p
[2] * n
[2] - d
;
558 m
[0 * 4 + 0] = l
[0] * n
[0] + c
;
559 m
[1 * 4 + 0] = l
[0] * n
[1];
560 m
[2 * 4 + 0] = l
[0] * n
[2];
561 m
[3 * 4 + 0] = - l
[0] * c
- l
[0] * d
;
563 m
[0 * 4 + 1] = l
[1] * n
[0];
564 m
[1 * 4 + 1] = l
[1] * n
[1] + c
;
565 m
[2 * 4 + 1] = l
[1] * n
[2];
566 m
[3 * 4 + 1] = - l
[1] * c
- l
[1] * d
;
568 m
[0 * 4 + 2] = l
[2] * n
[0];
569 m
[1 * 4 + 2] = l
[2] * n
[1];
570 m
[2 * 4 + 2] = l
[2] * n
[2] + c
;
571 m
[3 * 4 + 2] = - l
[2] * c
- l
[2] * d
;
579 void gl_draw_coord_system(G3DGLRenderOptions
*options
)
581 if(options
->glflags
& G3D_FLAG_GL_COORD_AXES
) {
583 glColor3f(1.0, 0.0, 0.0);
585 glVertex3f(0.0, 0.0, 0.0);
586 glVertex3f(10.0, 0.0, 0.0);
589 glColor3f(0.0, 1.0, 0.0);
591 glVertex3f(0.0, 0.0, 0.0);
592 glVertex3f(0.0, 10.0, 0.0);
595 glColor3f(0.0, 0.0, 1.0);
597 glVertex3f(0.0, 0.0, 0.0);
598 glVertex3f(0.0, 0.0, 10.0);
603 static G3DFloat
gl_min_y(GSList
*objects
)
605 G3DFloat min_y
= 10.0, tmp_y
;
610 for(oitem
= objects
; oitem
!= NULL
; oitem
= oitem
->next
) {
611 object
= oitem
->data
;
612 for(i
= 0; i
< object
->vertex_count
; i
++)
613 if(object
->vertex_data
[i
* 3 + 1] < min_y
)
614 min_y
= object
->vertex_data
[i
* 3 + 1];
615 tmp_y
= gl_min_y(object
->objects
);
622 static void gl_draw_plane(G3DGLRenderOptions
*options
)
625 glNormal3f(0.0, -1.0, 0.0);
627 glVertex3f(-PLANE_MAX
, options
->min_y
- 0.001, PLANE_MAX
);
628 glVertex3f( PLANE_MAX
, options
->min_y
- 0.001, PLANE_MAX
);
629 glVertex3f( PLANE_MAX
, options
->min_y
- 0.001, -PLANE_MAX
);
630 glVertex3f(-PLANE_MAX
, options
->min_y
- 0.001, -PLANE_MAX
);
635 static void gl_setup_floor_stencil(G3DGLRenderOptions
*options
)
637 glClear(GL_STENCIL_BUFFER_BIT
);
638 glDepthMask(GL_FALSE
);
639 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
641 glEnable(GL_STENCIL_TEST
);
642 glStencilOp(GL_REPLACE
, GL_REPLACE
, GL_REPLACE
);
643 glStencilFunc(GL_ALWAYS
, 1, 0xffffffff);
645 gl_draw_plane(options
);
647 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
648 glDepthMask(GL_TRUE
);
650 glStencilFunc(GL_EQUAL
, 1, 0xffffffff);
651 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
654 static void gl_setup_shadow_stencil(G3DGLRenderOptions
*options
)
656 glClear(GL_STENCIL_BUFFER_BIT
);
657 glDepthMask(GL_FALSE
);
658 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
660 glEnable(GL_STENCIL_TEST
);
661 glStencilOp(GL_REPLACE
, GL_REPLACE
, GL_REPLACE
);
662 glStencilFunc(GL_ALWAYS
, 1, 0xffffffff);
664 glCallList(options
->state
->gl_dlist_shadow
);
666 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
667 glDepthMask(GL_TRUE
);
669 glStencilFunc(GL_EQUAL
, 1, 0xffffffff);
670 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
673 void gl_draw(G3DGLRenderOptions
*options
, G3DModel
*model
)
677 gboolean ignore_timing
= FALSE
;
681 G3DVector light
[3] = { 100.0, 500.0, 20.0 };
682 G3DVector plane
[3] = { 0.0, -20.0, 0.0 };
683 G3DVector normal
[3] = { 0.0, -1.0, 0.0 };
685 if(!options
->initialized
)
688 options
->initialized
= TRUE
;
690 ignore_timing
= TRUE
;
694 /* prepare viewport */
695 gl_setup_view(options
);
698 glBindTexture (GL_TEXTURE_2D
, 0);
704 g_timer_start(timer
);
707 if(options
->updated
) {
708 options
->updated
= FALSE
;
710 ignore_timing
= TRUE
;
713 g_printerr("[gl] creating new display list\n");
715 options
->min_y
= gl_min_y(model
->objects
);
717 /* update render state */
719 glDeleteLists(options
->state
->gl_dlist
, 1);
720 glDeleteLists(options
->state
->gl_dlist_shadow
, 1);
721 g_free(options
->state
);
723 options
->state
= g_new0(G3DGLRenderState
, 1);
725 /* create and execute display list */
726 options
->state
->gl_dlist
= glGenLists(1);
727 options
->state
->gl_dlist_shadow
= glGenLists(1);
729 glNewList(options
->state
->gl_dlist
, GL_COMPILE
);
730 /* draw all objects */
731 for(f
= 1.0; f
>= 0.0; f
-= 0.2)
732 gl_draw_objects(options
, model
->objects
, f
, f
+ 0.2, FALSE
);
735 if(options
->glflags
& G3D_FLAG_GL_SHADOW
) {
736 glNewList(options
->state
->gl_dlist_shadow
, GL_COMPILE
);
737 gl_draw_objects(options
, model
->objects
, 0.0, 1.0, TRUE
);
742 g_return_if_fail(options
->state
!= NULL
);
744 gl_draw_coord_system(options
);
746 if(options
->glflags
& G3D_FLAG_GL_SHADOW
) {
747 plane
[1] = options
->min_y
;
751 gl_setup_floor_stencil(options
);
752 glTranslatef(0.0, (options
->min_y
* 2), 0.0);
753 glScalef(1.0, -1.0, 1.0);
754 glCallList(options
->state
->gl_dlist
);
758 glDisable(GL_LIGHTING
);
759 glBindTexture (GL_TEXTURE_2D
, 0);
760 glColor4f(0.5, 0.5, 0.5, 0.7);
761 gl_draw_plane(options
);
762 glEnable(GL_LIGHTING
);
765 gl_setup_shadow_matrix(options
, light
, plane
, normal
);
766 glBindTexture (GL_TEXTURE_2D
, 0);
767 glDisable(GL_LIGHTING
);
768 glDisable(GL_DEPTH_TEST
);
769 glMultMatrixf(options
->shadow_matrix
);
770 gl_setup_shadow_stencil(options
);
773 glTranslatef(0.0, 0.001, 0.0);
774 glColor4f(0.3, 0.3, 0.3, 0.7);
775 gl_draw_plane(options
);
776 glEnable(GL_DEPTH_TEST
);
777 glEnable(GL_LIGHTING
);
780 glDisable(GL_STENCIL_TEST
);
783 /* execute display list */
784 glCallList(options
->state
->gl_dlist
);
786 #ifdef TIMING /* get time to draw one frame to compare algorithms */
790 if(options
->avg_msec
== 0) {
791 sec
= g_timer_elapsed(timer
, &msec
);
792 options
->avg_msec
= (gulong
)sec
* 1000000 + msec
;
794 sec
= g_timer_elapsed(timer
, &msec
);
795 add
= (gulong
)sec
* 1000000 + msec
;
796 options
->avg_msec
= (options
->avg_msec
+ add
) / 2;
802 g_printerr("gl.c: drawn...\n");