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 glEnable(GL_CULL_FACE
);
78 /* glClearDepth(1.0f); */
79 glDepthFunc(GL_LEQUAL
);
81 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
;
155 /* predefined - update object->_tex_images else... */
156 glGenTextures(1, &(image
->tex_id
));
160 g_print("gl: loading texture '%s' (%dx%dx%d) - id %d\n",
161 image
->name
? image
->name
: "(null)",
162 image
->width
, image
->height
, image
->depth
,
166 glBindTexture(GL_TEXTURE_2D
, image
->tex_id
);
167 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
168 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
169 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
170 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
171 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
172 GL_LINEAR_MIPMAP_NEAREST
);
175 switch(image
->tex_env
)
177 case G3D_TEXENV_BLEND
: env
= GL_BLEND
; break;
178 case G3D_TEXENV_MODULATE
: env
= GL_MODULATE
; break;
179 case G3D_TEXENV_DECAL
: env
= GL_DECAL
; break;
180 case G3D_TEXENV_REPLACE
: env
= GL_REPLACE
; break;
181 default: env
= GL_MODULATE
; break;
183 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, env
);
194 static inline void gl_update_material(G3DGLRenderOptions
*options
,
195 G3DMaterial
*material
)
198 GLfloat normspec
[4] = { 0.0, 0.0, 0.0, 1.0 };
200 g_return_if_fail(material
!= NULL
);
202 if(options
->glflags
& G3D_FLAG_GL_ALLTWOSIDE
)
203 facetype
= GL_FRONT_AND_BACK
;
207 if(options
->glflags
& G3D_FLAG_GL_COLORS
)
214 glColor4f(0.7, 0.7, 0.7, 1.0);
218 if(options
->glflags
& G3D_FLAG_GL_SPECULAR
)
219 glMaterialfv(facetype
, GL_SPECULAR
, material
->specular
);
221 glMaterialfv(facetype
, GL_SPECULAR
, normspec
);
223 if(options
->glflags
& G3D_FLAG_GL_SHININESS
)
224 glMaterialf(facetype
, GL_SHININESS
, material
->shininess
* 10);
226 glMaterialf(facetype
, GL_SHININESS
, 0.0);
229 static inline void gl_draw_face(G3DGLRenderOptions
*options
,
230 G3DObject
*object
, gint32 i
, gfloat min_a
, gfloat max_a
,
231 gboolean
*dont_render
, gboolean
*init
, gboolean is_shadow
)
237 options
->state
->prev_material
= NULL
;
238 options
->state
->prev_texid
= 0;
243 if(!is_shadow
&& (options
->state
->prev_material
!= object
->_materials
[i
]))
245 if((object
->_materials
[i
]->a
< min_a
) ||
246 (object
->_materials
[i
]->a
>= max_a
))
252 *dont_render
= FALSE
;
255 gl_update_material(options
, object
->_materials
[i
]);
256 glBegin(GL_TRIANGLES
);
257 options
->state
->prev_material
= object
->_materials
[i
];
259 options
->state
->prev_texid
= 0;
262 if(*dont_render
) return;
265 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
266 (object
->_flags
[i
] & G3D_FLAG_FAC_TEXMAP
))
268 /* if texture has changed update to new texture */
269 if(object
->_tex_images
[i
] != options
->state
->prev_texid
) {
270 options
->state
->prev_texid
= object
->_tex_images
[i
];
272 glBindTexture(GL_TEXTURE_2D
, options
->state
->prev_texid
);
273 glBegin(GL_TRIANGLES
);
275 g_print("gl: binding to texture id %d\n", prev_texid
);
281 for(j
= 0; j
< 3; j
++)
283 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
284 (object
->_flags
[i
] & G3D_FLAG_FAC_TEXMAP
))
287 object
->_tex_coords
[(i
* 3 + j
) * 2 + 0],
288 object
->_tex_coords
[(i
* 3 + j
) * 2 + 1]);
290 g_print("gl: setting texture coords: %f, %f\n",
291 object
->_tex_coords
[(i
* 3 + j
) * 2 + 0],
292 object
->_tex_coords
[(i
* 3 + j
) * 2 + 1]);
297 object
->_normals
[(i
*3+j
)*3+0],
298 object
->_normals
[(i
*3+j
)*3+1],
299 object
->_normals
[(i
*3+j
)*3+2]);
301 object
->vertex_data
[object
->_indices
[i
*3+j
]*3+0],
302 object
->vertex_data
[object
->_indices
[i
*3+j
]*3+1],
303 object
->vertex_data
[object
->_indices
[i
*3+j
]*3+2]);
308 static inline void gl_may_end(gint32 ftype
)
314 static inline void gl_may_begin(gint32 ftype
)
320 static inline void gl_draw_face_list(G3DGLRenderOptions
*options
,
321 G3DObject
*object
, gfloat min_a
, gfloat max_a
,
322 gboolean
*init
, gboolean is_shadow
)
326 G3DVector nx
, ny
, nz
;
327 gint32 prev_ftype
= -1;
328 gint32 index
, j
, ftype
;
331 options
->state
->prev_material
= NULL
;
332 options
->state
->prev_texid
= 0;
336 for(fitem
= object
->faces
; fitem
!= NULL
; fitem
= fitem
->next
) {
338 if(!is_shadow
&& (options
->state
->prev_material
!= face
->material
)) {
339 if((face
->material
->a
< min_a
) || (face
->material
->a
>= max_a
)) {
343 gl_may_end(prev_ftype
);
344 gl_update_material(options
, face
->material
);
345 gl_may_begin(prev_ftype
);
347 options
->state
->prev_material
= face
->material
;
349 options
->state
->prev_texid
= 0;
353 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
354 (face
->flags
& G3D_FLAG_FAC_TEXMAP
)) {
355 /* if texture has changed update to new texture */
356 if(face
->tex_image
) {
357 if(face
->tex_image
->tex_id
!= options
->state
->prev_texid
) {
358 options
->state
->prev_texid
= face
->tex_image
->tex_id
;
360 gl_may_end(prev_ftype
);
361 glBindTexture(GL_TEXTURE_2D
, options
->state
->prev_texid
);
362 gl_may_begin(prev_ftype
);
364 g_print("gl: binding to texture id %d\n", prev_texid
);
368 } /* texture stuff */
370 switch(face
->vertex_count
) {
371 case 3: ftype
= GL_TRIANGLES
; break;
372 case 4: ftype
= GL_QUADS
; break;
373 case 2: ftype
= GL_LINES
; break;
374 default: ftype
= GL_POLYGON
;
376 g_debug("face vertex count: %d", face
->vertex_count
);
380 if(ftype
!= prev_ftype
) {
381 gl_may_end(prev_ftype
);
386 if(!(face
->flags
& G3D_FLAG_FAC_NORMALS
)) {
387 face
->normals
= g_new0(G3DVector
, face
->vertex_count
* 3);
389 g3d_face_get_normal(face
, object
, &nx
, &ny
, &nz
);
390 g3d_vector_unify(&nx
, &ny
, &nz
);
392 for(j
= 0; j
< face
->vertex_count
; j
++) {
393 face
->normals
[j
* 3 + 0] = nx
;
394 face
->normals
[j
* 3 + 1] = ny
;
395 face
->normals
[j
* 3 + 2] = nz
;
397 face
->flags
|= G3D_FLAG_FAC_NORMALS
;
400 for(j
= 0; j
< face
->vertex_count
; j
++) {
401 index
= face
->vertex_indices
[j
];
403 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_TEXTURES
) &&
404 (face
->flags
& G3D_FLAG_FAC_TEXMAP
))
407 face
->tex_vertex_data
[j
* 2 + 0],
408 face
->tex_vertex_data
[j
* 2 + 1]);
412 face
->normals
[j
* 3 + 0],
413 face
->normals
[j
* 3 + 1],
414 face
->normals
[j
* 3 + 2]);
417 object
->vertex_data
[index
* 3 + 0],
418 object
->vertex_data
[index
* 3 + 1],
419 object
->vertex_data
[index
* 3 + 2]);
424 gl_may_end(prev_ftype
);
428 static inline void gl_draw_objects(G3DGLRenderOptions
*options
,
429 GSList
*objects
, gfloat min_a
, gfloat max_a
, gboolean is_shadow
)
434 gboolean init
= TRUE
;
439 object
= (G3DObject
*)olist
->data
;
442 /* don't render invisible objects */
443 if(object
->hide
) continue;
445 g_return_if_fail(object
!= NULL
);
447 g_printerr("name: %s {", object
->name
);
451 g_printerr("new object\n");
456 if(object
->transformation
)
458 glMultMatrixf(object
->transformation
->matrix
);
463 gl_draw_face_list(options
, object
, min_a
, max_a
, &init
, is_shadow
);
465 glBegin(GL_TRIANGLES
);
467 for(i
= 0; i
< object
->_num_faces
; i
++)
469 gl_draw_face(options
, object
, i
, min_a
, max_a
,
470 &dont_render
, &init
, is_shadow
);
476 if(!is_shadow
&& (options
->glflags
& G3D_FLAG_GL_POINTS
)) {
477 glColor4f(0.2, 0.2, 0.2, 1.0);
479 for(i
= 0; i
< object
->vertex_count
; i
++) {
481 object
->vertex_data
[i
* 3 + 0],
482 object
->vertex_data
[i
* 3 + 1],
483 object
->vertex_data
[i
* 3 + 2]);
488 /* handle sub-objects */
489 gl_draw_objects(options
, object
->objects
, min_a
, max_a
, is_shadow
);
493 } /* while olist != NULL */
496 static inline void matrix_g3d_to_gl(G3DMatrix
*g3dm
, GLfloat glm
[4][4])
500 for(i
= 0; i
< 4; i
++)
501 for(j
= 0; j
< 4; j
++)
502 glm
[i
][j
] = g3dm
[i
* 4 + j
];
505 static inline void gl_setup_view(G3DGLRenderOptions
*options
)
511 glMatrixMode(GL_PROJECTION
);
513 if(options
->glflags
& G3D_FLAG_GL_ISOMETRIC
) {
514 w
= 0.5 * options
->zoom
;
515 h
= w
/ options
->aspect
;
516 glOrtho(-w
/ 2.0, w
/ 2.0, -h
/ 2.0, h
/ 2.0, 1, 100);
518 gluPerspective(options
->zoom
, options
->aspect
, 1, 100);
520 /* translation of view */
521 glTranslatef(options
->offx
, options
->offy
, 0.0);
523 glMatrixMode(GL_MODELVIEW
);
529 options
->bgcolor
[3]);
533 GL_COLOR_BUFFER_BIT
|
534 GL_DEPTH_BUFFER_BIT
|
535 GL_ACCUM_BUFFER_BIT
|
536 GL_STENCIL_BUFFER_BIT
);
539 glTranslatef(0, 0, -30);
540 g3dm
= g3d_matrix_new();
541 g3d_quat_to_matrix(options
->quat
, g3dm
);
542 matrix_g3d_to_gl(g3dm
, m
);
544 g3d_matrix_free(g3dm
);
545 glMultMatrixf(&m
[0][0]);
548 static void gl_setup_shadow_matrix(G3DGLRenderOptions
*options
,
549 G3DVector
*l
, G3DVector
*p
, G3DVector
*n
)
552 G3DMatrix
*m
= options
->shadow_matrix
;
554 d
= n
[0] * l
[0] + n
[1] * l
[1] + n
[2] * l
[2];
555 c
= p
[0] * n
[0] + p
[1] * n
[1] + p
[2] * n
[2] - d
;
557 m
[0 * 4 + 0] = l
[0] * n
[0] + c
;
558 m
[1 * 4 + 0] = l
[0] * n
[1];
559 m
[2 * 4 + 0] = l
[0] * n
[2];
560 m
[3 * 4 + 0] = - l
[0] * c
- l
[0] * d
;
562 m
[0 * 4 + 1] = l
[1] * n
[0];
563 m
[1 * 4 + 1] = l
[1] * n
[1] + c
;
564 m
[2 * 4 + 1] = l
[1] * n
[2];
565 m
[3 * 4 + 1] = - l
[1] * c
- l
[1] * d
;
567 m
[0 * 4 + 2] = l
[2] * n
[0];
568 m
[1 * 4 + 2] = l
[2] * n
[1];
569 m
[2 * 4 + 2] = l
[2] * n
[2] + c
;
570 m
[3 * 4 + 2] = - l
[2] * c
- l
[2] * d
;
578 void gl_draw_coord_system(G3DGLRenderOptions
*options
)
580 if(options
->glflags
& G3D_FLAG_GL_COORD_AXES
) {
582 glColor3f(1.0, 0.0, 0.0);
584 glVertex3f(0.0, 0.0, 0.0);
585 glVertex3f(10.0, 0.0, 0.0);
588 glColor3f(0.0, 1.0, 0.0);
590 glVertex3f(0.0, 0.0, 0.0);
591 glVertex3f(0.0, 10.0, 0.0);
594 glColor3f(0.0, 0.0, 1.0);
596 glVertex3f(0.0, 0.0, 0.0);
597 glVertex3f(0.0, 0.0, 10.0);
602 static G3DFloat
gl_min_y(GSList
*objects
)
604 G3DFloat min_y
= 10.0, tmp_y
;
609 for(oitem
= objects
; oitem
!= NULL
; oitem
= oitem
->next
) {
610 object
= oitem
->data
;
611 for(i
= 0; i
< object
->vertex_count
; i
++)
612 if(object
->vertex_data
[i
* 3 + 1] < min_y
)
613 min_y
= object
->vertex_data
[i
* 3 + 1];
614 tmp_y
= gl_min_y(object
->objects
);
621 static void gl_draw_plane(G3DGLRenderOptions
*options
)
624 glNormal3f(0.0, -1.0, 0.0);
626 glVertex3f(-PLANE_MAX
, options
->min_y
- 0.001, PLANE_MAX
);
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
);
634 static void gl_setup_floor_stencil(G3DGLRenderOptions
*options
)
636 glClear(GL_STENCIL_BUFFER_BIT
);
637 glDepthMask(GL_FALSE
);
638 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
640 glEnable(GL_STENCIL_TEST
);
641 glStencilOp(GL_REPLACE
, GL_REPLACE
, GL_REPLACE
);
642 glStencilFunc(GL_ALWAYS
, 1, 0xffffffff);
644 gl_draw_plane(options
);
646 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
647 glDepthMask(GL_TRUE
);
649 glStencilFunc(GL_EQUAL
, 1, 0xffffffff);
650 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
653 static void gl_setup_shadow_stencil(G3DGLRenderOptions
*options
)
655 glClear(GL_STENCIL_BUFFER_BIT
);
656 glDepthMask(GL_FALSE
);
657 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
659 glEnable(GL_STENCIL_TEST
);
660 glStencilOp(GL_REPLACE
, GL_REPLACE
, GL_REPLACE
);
661 glStencilFunc(GL_ALWAYS
, 1, 0xffffffff);
663 glCallList(options
->state
->gl_dlist_shadow
);
665 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
666 glDepthMask(GL_TRUE
);
668 glStencilFunc(GL_EQUAL
, 1, 0xffffffff);
669 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
672 void gl_draw(G3DGLRenderOptions
*options
, G3DModel
*model
)
676 gboolean ignore_timing
= FALSE
;
680 G3DVector light
[3] = { 100.0, 500.0, 20.0 };
681 G3DVector plane
[3] = { 0.0, -20.0, 0.0 };
682 G3DVector normal
[3] = { 0.0, -1.0, 0.0 };
684 if(!options
->initialized
)
687 options
->initialized
= TRUE
;
689 ignore_timing
= TRUE
;
693 /* prepare viewport */
694 gl_setup_view(options
);
697 glBindTexture (GL_TEXTURE_2D
, 0);
703 g_timer_start(timer
);
706 if(options
->updated
) {
707 options
->updated
= FALSE
;
709 ignore_timing
= TRUE
;
712 g_printerr("[gl] creating new display list\n");
714 options
->min_y
= gl_min_y(model
->objects
);
716 /* update render state */
718 glDeleteLists(options
->state
->gl_dlist
, 1);
719 glDeleteLists(options
->state
->gl_dlist_shadow
, 1);
720 g_free(options
->state
);
722 options
->state
= g_new0(G3DGLRenderState
, 1);
724 /* create and execute display list */
725 options
->state
->gl_dlist
= glGenLists(1);
726 options
->state
->gl_dlist_shadow
= glGenLists(1);
728 glNewList(options
->state
->gl_dlist
, GL_COMPILE
);
729 /* draw all objects */
730 for(f
= 1.0; f
>= 0.0; f
-= 0.2)
731 gl_draw_objects(options
, model
->objects
, f
, f
+ 0.2, FALSE
);
734 if(options
->glflags
& G3D_FLAG_GL_SHADOW
) {
735 glNewList(options
->state
->gl_dlist_shadow
, GL_COMPILE
);
736 gl_draw_objects(options
, model
->objects
, 0.0, 1.0, TRUE
);
741 g_return_if_fail(options
->state
!= NULL
);
743 gl_draw_coord_system(options
);
745 if(options
->glflags
& G3D_FLAG_GL_SHADOW
) {
746 plane
[1] = options
->min_y
;
750 gl_setup_floor_stencil(options
);
751 glTranslatef(0.0, (options
->min_y
* 2), 0.0);
752 glScalef(1.0, -1.0, 1.0);
753 glCallList(options
->state
->gl_dlist
);
757 glDisable(GL_LIGHTING
);
758 glBindTexture (GL_TEXTURE_2D
, 0);
759 glColor4f(0.5, 0.5, 0.5, 0.7);
760 gl_draw_plane(options
);
761 glEnable(GL_LIGHTING
);
764 gl_setup_shadow_matrix(options
, light
, plane
, normal
);
765 glBindTexture (GL_TEXTURE_2D
, 0);
766 glDisable(GL_LIGHTING
);
767 glDisable(GL_DEPTH_TEST
);
768 glMultMatrixf(options
->shadow_matrix
);
769 gl_setup_shadow_stencil(options
);
772 glTranslatef(0.0, 0.001, 0.0);
773 glColor4f(0.3, 0.3, 0.3, 0.7);
774 gl_draw_plane(options
);
775 glEnable(GL_DEPTH_TEST
);
776 glEnable(GL_LIGHTING
);
779 glDisable(GL_STENCIL_TEST
);
782 /* execute display list */
783 glCallList(options
->state
->gl_dlist
);
785 #ifdef TIMING /* get time to draw one frame to compare algorithms */
789 if(options
->avg_msec
== 0) {
790 sec
= g_timer_elapsed(timer
, &msec
);
791 options
->avg_msec
= (gulong
)sec
* 1000000 + msec
;
793 sec
= g_timer_elapsed(timer
, &msec
);
794 add
= (gulong
)sec
* 1000000 + msec
;
795 options
->avg_msec
= (options
->avg_msec
+ add
) / 2;
801 g_printerr("gl.c: drawn...\n");