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)
59 g_printerr("init OpenGL\n");
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 */
71 glAlphaFunc(GL_GREATER
, 0.1);
73 glEnable(GL_ALPHA_TEST
);
75 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
78 glDepthFunc(GL_LEQUAL
);
80 glEnable(GL_DEPTH_TEST
);
84 glEnable(GL_LINE_SMOOTH
);
85 glEnable(GL_POLYGON_SMOOTH
);
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
);
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
);
111 glEnable(GL_LIGHTING
);
114 /* colors and materials */
115 glColorMaterial(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
);
116 glEnable(GL_COLOR_MATERIAL
);
120 glEnable(GL_TEXTURE_2D
);
124 timer
= g_timer_new();
128 void gl_set_twoside(gboolean twoside
)
130 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE
, twoside
? 1 : 0);
132 twoside
? GL_FRONT_AND_BACK
: GL_FRONT
,
133 GL_AMBIENT_AND_DIFFUSE
);
136 void gl_set_textures(gboolean textures
)
139 glEnable(GL_TEXTURE_2D
);
142 glBindTexture(GL_TEXTURE_2D
, 0);
143 glDisable(GL_TEXTURE_2D
);
148 void gl_load_texture(gpointer key
, gpointer value
, gpointer data
)
150 G3DImage
*image
= (G3DImage
*)value
;
156 /* predefined - update object->_tex_images else... */
157 glGenTextures(1, &(image
->tex_id
));
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
,
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
);
195 static inline void gl_update_material(G3DGLRenderOptions
*options
,
196 G3DMaterial
*material
)
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
;
208 if(options
->glflags
& G3D_FLAG_GL_COLORS
)
215 glColor4f(0.7, 0.7, 0.7, 1.0);
219 if(options
->glflags
& G3D_FLAG_GL_SPECULAR
)
220 glMaterialfv(facetype
, GL_SPECULAR
, material
->specular
);
222 glMaterialfv(facetype
, GL_SPECULAR
, normspec
);
224 if(options
->glflags
& G3D_FLAG_GL_SHININESS
)
225 glMaterialf(facetype
, GL_SHININESS
, material
->shininess
* 10);
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
)
238 options
->state
->prev_material
= NULL
;
239 options
->state
->prev_texid
= 0;
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
))
253 *dont_render
= FALSE
;
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;
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
];
273 glBindTexture(GL_TEXTURE_2D
, options
->state
->prev_texid
);
274 glBegin(GL_TRIANGLES
);
276 g_print("gl: binding to texture id %d\n", prev_texid
);
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
))
288 object
->_tex_coords
[(i
* 3 + j
) * 2 + 0],
289 object
->_tex_coords
[(i
* 3 + j
) * 2 + 1]);
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]);
298 object
->_normals
[(i
*3+j
)*3+0],
299 object
->_normals
[(i
*3+j
)*3+1],
300 object
->_normals
[(i
*3+j
)*3+2]);
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]);
309 static inline void gl_may_end(gint32 ftype
)
315 static inline void gl_may_begin(gint32 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
)
327 G3DVector nx
, ny
, nz
;
328 gint32 prev_ftype
= -1;
329 gint32 index
, j
, ftype
;
332 options
->state
->prev_material
= NULL
;
333 options
->state
->prev_texid
= 0;
337 for(fitem
= object
->faces
; fitem
!= NULL
; fitem
= fitem
->next
) {
339 if(!is_shadow
&& (options
->state
->prev_material
!= face
->material
)) {
340 if((face
->material
->a
< min_a
) || (face
->material
->a
>= max_a
)) {
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;
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
);
365 g_print("gl: binding to texture id %d\n", prev_texid
);
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
;
377 g_debug("face vertex count: %d", face
->vertex_count
);
381 if(ftype
!= prev_ftype
) {
382 gl_may_end(prev_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
))
408 face
->tex_vertex_data
[j
* 2 + 0],
409 face
->tex_vertex_data
[j
* 2 + 1]);
413 face
->normals
[j
* 3 + 0],
414 face
->normals
[j
* 3 + 1],
415 face
->normals
[j
* 3 + 2]);
418 object
->vertex_data
[index
* 3 + 0],
419 object
->vertex_data
[index
* 3 + 1],
420 object
->vertex_data
[index
* 3 + 2]);
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
)
435 gboolean dont_render
;
436 gboolean init
= TRUE
;
441 object
= (G3DObject
*)olist
->data
;
446 /* don't render invisible objects */
447 if(object
->hide
) continue;
449 g_return_if_fail(object
!= NULL
);
451 g_printerr("name: %s {", object
->name
);
455 g_printerr("new object\n");
460 if(object
->transformation
)
462 glMultMatrixf(object
->transformation
->matrix
);
467 gl_draw_face_list(options
, object
, min_a
, max_a
, &init
, is_shadow
);
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
);
480 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_POINTS
)) {
481 glColor4f(0.2, 0.2, 0.2, 1.0);
483 for(i
= 0; i
< object
->vertex_count
; i
++) {
485 object
->vertex_data
[i
* 3 + 0],
486 object
->vertex_data
[i
* 3 + 1],
487 object
->vertex_data
[i
* 3 + 2]);
492 /* handle sub-objects */
493 gl_draw_objects(options
, object
->objects
, min_a
, max_a
, is_shadow
);
497 } /* while olist != NULL */
500 static inline void matrix_g3d_to_gl(G3DMatrix
*g3dm
, GLfloat glm
[4][4])
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
)
515 glMatrixMode(GL_PROJECTION
);
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);
522 gluPerspective(options
->zoom
, options
->aspect
, 1, 100);
524 /* translation of view */
525 glTranslatef(options
->offx
, options
->offy
, 0.0);
527 glMatrixMode(GL_MODELVIEW
);
533 options
->bgcolor
[3]);
537 GL_COLOR_BUFFER_BIT
|
538 GL_DEPTH_BUFFER_BIT
|
539 GL_ACCUM_BUFFER_BIT
|
540 GL_STENCIL_BUFFER_BIT
);
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
)
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
;
582 void gl_draw_coord_system(G3DGLRenderOptions
*options
)
584 if(options
->glflags
& G3D_FLAG_GL_COORD_AXES
) {
586 glColor3f(1.0, 0.0, 0.0);
588 glVertex3f(0.0, 0.0, 0.0);
589 glVertex3f(10.0, 0.0, 0.0);
592 glColor3f(0.0, 1.0, 0.0);
594 glVertex3f(0.0, 0.0, 0.0);
595 glVertex3f(0.0, 10.0, 0.0);
598 glColor3f(0.0, 0.0, 1.0);
600 glVertex3f(0.0, 0.0, 0.0);
601 glVertex3f(0.0, 0.0, 10.0);
606 static G3DFloat
gl_min_y(GSList
*objects
)
608 G3DFloat min_y
= 10.0, tmp_y
;
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
);
625 static void gl_draw_plane(G3DGLRenderOptions
*options
)
628 glNormal3f(0.0, -1.0, 0.0);
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
);
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
)
681 gboolean ignore_timing
= FALSE
;
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
)
692 options
->initialized
= TRUE
;
694 ignore_timing
= TRUE
;
698 /* prepare viewport */
699 gl_setup_view(options
);
702 glBindTexture (GL_TEXTURE_2D
, 0);
708 g_timer_start(timer
);
711 if(options
->updated
) {
712 options
->updated
= FALSE
;
714 ignore_timing
= TRUE
;
717 g_printerr("[gl] creating new display list\n");
719 options
->min_y
= gl_min_y(model
->objects
);
721 /* update render 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
);
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
);
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
;
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
);
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
);
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
);
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
);
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 */
794 if(options
->avg_msec
== 0) {
795 sec
= g_timer_elapsed(timer
, &msec
);
796 options
->avg_msec
= (gulong
)sec
* 1000000 + msec
;
798 sec
= g_timer_elapsed(timer
, &msec
);
799 add
= (gulong
)sec
* 1000000 + msec
;
800 options
->avg_msec
= (options
->avg_msec
+ add
) / 2;
806 g_printerr("gl.c: drawn...\n");