4 * PCB, interactive printed circuit board design
5 * Copyright (C) 2009-2011 PCB Contributers (See ChangeLog for details)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 /* The Linux OpenGL ABI 1.0 spec requires that we define
36 * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
37 * in order to get prototypes:
38 * http://www.opengl.org/registry/ABI/
40 #define GL_GLEXT_PROTOTYPES 1
42 /* This follows autoconf's recommendation for the AX_CHECK_GL macro
43 https://www.gnu.org/software/autoconf-archive/ax_check_gl.html */
44 #if defined HAVE_WINDOWS_H && defined _WIN32
47 #if defined HAVE_GL_GL_H
49 #elif defined HAVE_OPENGL_GL_H
50 # include <OpenGL/gl.h>
52 # error autoconf couldnt find gl.h
55 /* This follows autoconf's recommendation for the AX_CHECK_GLU macro
56 https://www.gnu.org/software/autoconf-archive/ax_check_glu.html */
57 #if defined HAVE_GL_GLU_H
59 #elif defined HAVE_OPENGL_GLU_H
60 # include <OpenGL/glu.h>
62 # error autoconf couldnt find glu.h
66 #include "crosshair.h"
77 #ifdef HAVE_LIBDMALLOC
82 triangle_buffer buffer
;
83 float global_depth
= 0;
86 hidgl_init_triangle_array (triangle_buffer
*buffer
)
88 buffer
->triangle_count
= 0;
89 buffer
->coord_comp_count
= 0;
93 hidgl_flush_triangles (triangle_buffer
*buffer
)
95 if (buffer
->triangle_count
== 0)
98 glEnableClientState (GL_VERTEX_ARRAY
);
99 glVertexPointer (3, GL_FLOAT
, 0, buffer
->triangle_array
);
100 glDrawArrays (GL_TRIANGLES
, 0, buffer
->triangle_count
* 3);
101 glDisableClientState (GL_VERTEX_ARRAY
);
103 buffer
->triangle_count
= 0;
104 buffer
->coord_comp_count
= 0;
108 hidgl_ensure_triangle_space (triangle_buffer
*buffer
, int count
)
110 if (count
> TRIANGLE_ARRAY_SIZE
)
112 fprintf (stderr
, "Not enough space in vertex buffer\n");
113 fprintf (stderr
, "Requested %i triangles, %i available\n",
114 count
, TRIANGLE_ARRAY_SIZE
);
117 if (count
> TRIANGLE_ARRAY_SIZE
- buffer
->triangle_count
)
118 hidgl_flush_triangles (buffer
);
122 hidgl_set_depth (float depth
)
124 global_depth
= depth
;
128 * \brief Draw the grid on the 3D canvas
131 hidgl_draw_grid (BoxType
*drawn_area
, double coord_per_px
)
133 static GLfloat
*points
= 0;
134 static int npoints
= 0;
135 Coord x1
, y1
, x2
, y2
, n
, i
;
141 if (!Settings
.DrawGrid
)
142 return; /* grid hidden */
144 /* Find the bounding grid points, all others lay between them */
145 x1
= GridFit (MAX (0, drawn_area
->X1
), PCB
->Grid
, PCB
->GridOffsetX
);
146 y1
= GridFit (MAX (0, drawn_area
->Y1
), PCB
->Grid
, PCB
->GridOffsetY
);
147 x2
= GridFit (MIN (PCB
->MaxWidth
, drawn_area
->X2
), PCB
->Grid
, PCB
->GridOffsetX
);
148 y2
= GridFit (MIN (PCB
->MaxHeight
, drawn_area
->Y2
), PCB
->Grid
, PCB
->GridOffsetY
);
164 n
= (int) ((x2
- x1
) / PCB
->Grid
+ 0.5) + 1; /* Number of points in one row */
166 { /* [n]points are static, reallocate if we need more memory */
168 points
= realloc (points
, npoints
* 3 * sizeof (GLfloat
));
171 pixels
= (x2
- x1
) / coord_per_px
; /* visible grid area in pixels */
172 grid_px
= pixels
/ n
; /* distance between grid dots in pixels */
173 point_size
= 1.0 + grid_px
/ 30.0;
174 /* limit the maximum and minimum size of the grid dot - these should really be taken from settings */
179 else if (point_size
< 1)
183 /* ensure grid point size is an integer value to prevent moira artefacts */
184 point_size
= (int)(point_size
+ 0.5);
186 glPointSize (point_size
);
187 glEnableClientState (GL_VERTEX_ARRAY
);
188 glVertexPointer (3, GL_FLOAT
, 0, points
);
191 for (x
= x1
; x
<= x2
; x
+= PCB
->Grid
)
192 { /* compute all the x coordinates */
193 points
[3 * n
+ 0] = x
;
194 points
[3 * n
+ 2] = global_depth
;
197 for (y
= y1
; y
<= y2
; y
+= PCB
->Grid
)
198 { /* reuse the row of points at each y */
199 for (i
= 0; i
< n
; i
++)
200 points
[3 * i
+ 1] = y
;
201 /* draw all the points in a row for a given y */
202 glDrawArrays (GL_POINTS
, 0, n
);
205 glDisableClientState (GL_VERTEX_ARRAY
);
209 #define MAX_PIXELS_ARC_TO_CHORD 0.5
211 int calc_slices (float pix_radius
, float sweep_angle
)
215 if (pix_radius
<= MAX_PIXELS_ARC_TO_CHORD
)
218 slices
= sweep_angle
/ acosf (1 - MAX_PIXELS_ARC_TO_CHORD
/ pix_radius
) / 2.;
219 return (int)ceilf (slices
);
222 #define MIN_TRIANGLES_PER_CAP 3
223 #define MAX_TRIANGLES_PER_CAP 90
224 static void draw_cap (Coord width
, Coord x
, Coord y
, Angle angle
, double scale
)
226 float last_capx
, last_capy
;
228 float radius
= width
/ 2.;
229 int slices
= calc_slices (radius
/ scale
, M_PI
);
232 if (slices
< MIN_TRIANGLES_PER_CAP
)
233 slices
= MIN_TRIANGLES_PER_CAP
;
235 if (slices
> MAX_TRIANGLES_PER_CAP
)
236 slices
= MAX_TRIANGLES_PER_CAP
;
238 hidgl_ensure_triangle_space (&buffer
, slices
);
240 last_capx
= radius
* cosf (angle
* M_PI
/ 180.) + x
;
241 last_capy
= -radius
* sinf (angle
* M_PI
/ 180.) + y
;
242 for (i
= 0; i
< slices
; i
++) {
243 capx
= radius
* cosf (angle
* M_PI
/ 180. + ((float)(i
+ 1)) * M_PI
/ (float)slices
) + x
;
244 capy
= -radius
* sinf (angle
* M_PI
/ 180. + ((float)(i
+ 1)) * M_PI
/ (float)slices
) + y
;
245 hidgl_add_triangle (&buffer
, last_capx
, last_capy
, capx
, capy
, x
, y
);
252 hidgl_draw_line (int cap
, Coord width
, Coord x1
, Coord y1
, Coord x2
, Coord y2
, double scale
)
255 double deltax
, deltay
, length
;
257 int circular_caps
= 0;
269 length
= hypot (deltax
, deltay
);
272 /* Assume the orientation of the line is horizontal */
279 wdy
= deltax
* width
/ 2. / length
;
280 wdx
= -deltay
* width
/ 2. / length
;
283 angle
= -180. / M_PI
* atan2 (deltay
, deltax
);
293 x1
-= deltax
* width
/ 2. / length
;
294 y1
-= deltay
* width
/ 2. / length
;
295 x2
+= deltax
* width
/ 2. / length
;
296 y2
+= deltay
* width
/ 2. / length
;
300 hidgl_ensure_triangle_space (&buffer
, 2);
301 hidgl_add_triangle (&buffer
, x1
- wdx
, y1
- wdy
,
304 hidgl_add_triangle (&buffer
, x1
- wdx
, y1
- wdy
,
308 /* Don't bother capping hairlines */
309 if (circular_caps
&& !hairline
)
311 draw_cap (width
, x1
, y1
, angle
+ 90., scale
);
312 draw_cap (width
, x2
, y2
, angle
- 90., scale
);
316 #define MIN_SLICES_PER_ARC 6
317 #define MAX_SLICES_PER_ARC 360
319 hidgl_draw_arc (Coord width
, Coord x
, Coord y
, Coord rx
, Coord ry
,
320 Angle start_angle
, Angle delta_angle
, double scale
)
322 float last_inner_x
, last_inner_y
;
323 float last_outer_x
, last_outer_y
;
324 float inner_x
, inner_y
;
325 float outer_x
, outer_y
;
328 float cos_ang
, sin_ang
;
329 float start_angle_rad
;
330 float delta_angle_rad
;
331 float angle_incr_rad
;
342 inner_r
= rx
- width
/ 2.;
343 outer_r
= rx
+ width
/ 2.;
345 if (delta_angle
< 0) {
346 start_angle
+= delta_angle
;
347 delta_angle
= - delta_angle
;
350 start_angle_rad
= start_angle
* M_PI
/ 180.;
351 delta_angle_rad
= delta_angle
* M_PI
/ 180.;
353 slices
= calc_slices ((rx
+ width
/ 2.) / scale
, delta_angle_rad
);
355 if (slices
< MIN_SLICES_PER_ARC
)
356 slices
= MIN_SLICES_PER_ARC
;
358 if (slices
> MAX_SLICES_PER_ARC
)
359 slices
= MAX_SLICES_PER_ARC
;
361 hidgl_ensure_triangle_space (&buffer
, 2 * slices
);
363 angle_incr_rad
= delta_angle_rad
/ (float)slices
;
365 cos_ang
= cosf (start_angle_rad
);
366 sin_ang
= sinf (start_angle_rad
);
367 last_inner_x
= -inner_r
* cos_ang
+ x
; last_inner_y
= inner_r
* sin_ang
+ y
;
368 last_outer_x
= -outer_r
* cos_ang
+ x
; last_outer_y
= outer_r
* sin_ang
+ y
;
369 for (i
= 1; i
<= slices
; i
++) {
370 cos_ang
= cosf (start_angle_rad
+ ((float)(i
)) * angle_incr_rad
);
371 sin_ang
= sinf (start_angle_rad
+ ((float)(i
)) * angle_incr_rad
);
372 inner_x
= -inner_r
* cos_ang
+ x
; inner_y
= inner_r
* sin_ang
+ y
;
373 outer_x
= -outer_r
* cos_ang
+ x
; outer_y
= outer_r
* sin_ang
+ y
;
374 hidgl_add_triangle (&buffer
, last_inner_x
, last_inner_y
,
375 last_outer_x
, last_outer_y
,
377 hidgl_add_triangle (&buffer
, last_inner_x
, last_inner_y
,
380 last_inner_x
= inner_x
; last_inner_y
= inner_y
;
381 last_outer_x
= outer_x
; last_outer_y
= outer_y
;
384 /* Don't bother capping hairlines */
388 draw_cap (width
, x
+ rx
* -cosf (start_angle_rad
),
389 y
+ rx
* sinf (start_angle_rad
),
391 draw_cap (width
, x
+ rx
* -cosf (start_angle_rad
+ delta_angle_rad
),
392 y
+ rx
* sinf (start_angle_rad
+ delta_angle_rad
),
393 start_angle
+ delta_angle
+ 180., scale
);
397 hidgl_draw_rect (Coord x1
, Coord y1
, Coord x2
, Coord y2
)
399 glBegin (GL_LINE_LOOP
);
400 glVertex3f (x1
, y1
, global_depth
);
401 glVertex3f (x1
, y2
, global_depth
);
402 glVertex3f (x2
, y2
, global_depth
);
403 glVertex3f (x2
, y1
, global_depth
);
409 hidgl_fill_circle (Coord vx
, Coord vy
, Coord vr
, double scale
)
411 #define MIN_TRIANGLES_PER_CIRCLE 6
412 #define MAX_TRIANGLES_PER_CIRCLE 360
413 float last_x
, last_y
;
418 slices
= calc_slices (vr
/ scale
, 2 * M_PI
);
420 if (slices
< MIN_TRIANGLES_PER_CIRCLE
)
421 slices
= MIN_TRIANGLES_PER_CIRCLE
;
423 if (slices
> MAX_TRIANGLES_PER_CIRCLE
)
424 slices
= MAX_TRIANGLES_PER_CIRCLE
;
426 hidgl_ensure_triangle_space (&buffer
, slices
);
431 for (i
= 0; i
< slices
; i
++) {
433 x
= radius
* cosf (((float)(i
+ 1)) * 2. * M_PI
/ (float)slices
) + vx
;
434 y
= radius
* sinf (((float)(i
+ 1)) * 2. * M_PI
/ (float)slices
) + vy
;
435 hidgl_add_triangle (&buffer
, vx
, vy
, last_x
, last_y
, x
, y
);
441 #define MAX_COMBINED_MALLOCS 2500
442 static void *combined_to_free
[MAX_COMBINED_MALLOCS
];
443 static int combined_num_to_free
= 0;
445 static GLenum tessVertexType
;
446 static int stashed_vertices
;
447 static int triangle_comp_idx
;
454 myError (GLenum errno
)
456 printf ("gluTess error: %s\n", gluErrorString (errno
));
460 myCombine ( GLdouble coords
[3], void *vertex_data
[4], GLfloat weight
[4], void **dataOut
)
462 #define MAX_COMBINED_VERTICES 2500
463 static GLdouble combined_vertices
[3 * MAX_COMBINED_VERTICES
];
464 static int num_combined_vertices
= 0;
466 GLdouble
*new_vertex
;
468 if (num_combined_vertices
< MAX_COMBINED_VERTICES
)
470 new_vertex
= &combined_vertices
[3 * num_combined_vertices
];
471 num_combined_vertices
++;
475 new_vertex
= malloc (3 * sizeof (GLdouble
));
477 if (combined_num_to_free
< MAX_COMBINED_MALLOCS
)
478 combined_to_free
[combined_num_to_free
++] = new_vertex
;
480 printf ("myCombine leaking %lu bytes of memory\n",
481 (unsigned long)3 * sizeof (GLdouble
));
484 new_vertex
[0] = coords
[0];
485 new_vertex
[1] = coords
[1];
486 new_vertex
[2] = coords
[2];
488 *dataOut
= new_vertex
;
492 myBegin (GLenum type
)
494 tessVertexType
= type
;
495 stashed_vertices
= 0;
496 triangle_comp_idx
= 0;
499 static double global_scale
;
502 myVertex (GLdouble
*vertex_data
)
504 static GLfloat triangle_vertices
[2 * 3];
506 if (tessVertexType
== GL_TRIANGLE_STRIP
||
507 tessVertexType
== GL_TRIANGLE_FAN
)
509 if (stashed_vertices
< 2)
511 triangle_vertices
[triangle_comp_idx
++] = vertex_data
[0];
512 triangle_vertices
[triangle_comp_idx
++] = vertex_data
[1];
517 hidgl_ensure_triangle_space (&buffer
, 1);
518 hidgl_add_triangle (&buffer
,
519 triangle_vertices
[0], triangle_vertices
[1],
520 triangle_vertices
[2], triangle_vertices
[3],
521 vertex_data
[0], vertex_data
[1]);
523 if (tessVertexType
== GL_TRIANGLE_STRIP
)
525 /* STRIP saves the last two vertices for re-use in the next triangle */
526 triangle_vertices
[0] = triangle_vertices
[2];
527 triangle_vertices
[1] = triangle_vertices
[3];
529 /* Both FAN and STRIP save the last vertex for re-use in the next triangle */
530 triangle_vertices
[2] = vertex_data
[0];
531 triangle_vertices
[3] = vertex_data
[1];
534 else if (tessVertexType
== GL_TRIANGLES
)
536 triangle_vertices
[triangle_comp_idx
++] = vertex_data
[0];
537 triangle_vertices
[triangle_comp_idx
++] = vertex_data
[1];
539 if (stashed_vertices
== 3)
541 hidgl_ensure_triangle_space (&buffer
, 1);
542 hidgl_add_triangle (&buffer
,
543 triangle_vertices
[0], triangle_vertices
[1],
544 triangle_vertices
[2], triangle_vertices
[3],
545 triangle_vertices
[4], triangle_vertices
[5]);
546 triangle_comp_idx
= 0;
547 stashed_vertices
= 0;
551 printf ("Vertex received with unknown type\n");
557 while (combined_num_to_free
)
558 free (combined_to_free
[-- combined_num_to_free
]);
562 hidgl_fill_polygon (int n_coords
, Coord
*x
, Coord
*y
)
568 assert (n_coords
> 0);
570 vertices
= malloc (sizeof(GLdouble
) * n_coords
* 3);
572 tobj
= gluNewTess ();
573 gluTessCallback(tobj
, GLU_TESS_BEGIN
, (_GLUfuncptr
)myBegin
);
574 gluTessCallback(tobj
, GLU_TESS_VERTEX
, (_GLUfuncptr
)myVertex
);
575 gluTessCallback(tobj
, GLU_TESS_COMBINE
, (_GLUfuncptr
)myCombine
);
576 gluTessCallback(tobj
, GLU_TESS_ERROR
, (_GLUfuncptr
)myError
);
578 gluTessBeginPolygon (tobj
, NULL
);
579 gluTessBeginContour (tobj
);
581 for (i
= 0; i
< n_coords
; i
++)
583 vertices
[0 + i
* 3] = x
[i
];
584 vertices
[1 + i
* 3] = y
[i
];
585 vertices
[2 + i
* 3] = 0.;
586 gluTessVertex (tobj
, &vertices
[i
* 3], &vertices
[i
* 3]);
589 gluTessEndContour (tobj
);
590 gluTessEndPolygon (tobj
);
591 gluDeleteTess (tobj
);
598 tesselate_contour (GLUtesselator
*tobj
, PLINE
*contour
, GLdouble
*vertices
,
601 VNODE
*vn
= &contour
->head
;
604 /* If the contour is round, and hidgl_fill_circle would use
605 * less slices than we have vertices to draw it, then call
606 * hidgl_fill_circle to draw this contour.
608 if (contour
->is_round
) {
609 double slices
= calc_slices (contour
->radius
/ scale
, 2 * M_PI
);
610 if (slices
< contour
->Count
) {
611 hidgl_fill_circle (contour
->cx
, contour
->cy
, contour
->radius
, scale
);
616 gluTessBeginPolygon (tobj
, NULL
);
617 gluTessBeginContour (tobj
);
619 vertices
[0 + offset
] = vn
->point
[0];
620 vertices
[1 + offset
] = vn
->point
[1];
621 vertices
[2 + offset
] = 0.;
622 gluTessVertex (tobj
, &vertices
[offset
], &vertices
[offset
]);
624 } while ((vn
= vn
->next
) != &contour
->head
);
625 gluTessEndContour (tobj
);
626 gluTessEndPolygon (tobj
);
629 struct do_hole_info
{
636 do_hole (const BoxType
*b
, void *cl
)
638 struct do_hole_info
*info
= cl
;
639 PLINE
*curc
= (PLINE
*) b
;
641 /* Ignore the outer contour - we draw it first explicitly*/
642 if (curc
->Flags
.orient
== PLF_DIR
) {
646 tesselate_contour (info
->tobj
, curc
, info
->vertices
, info
->scale
);
650 static GLint stencil_bits
;
651 static int dirty_bits
= 0;
652 static int assigned_bits
= 0;
655 fill_polyarea (POLYAREA
*pa
, const BoxType
*clip_box
, double scale
)
657 int vertex_count
= 0;
659 struct do_hole_info info
;
663 global_scale
= scale
;
665 stencil_bit
= hidgl_assign_clear_stencil_bit ();
668 printf ("hidgl_fill_pcb_polygon: No free stencil bits, aborting polygon\n");
672 /* Flush out any existing geoemtry to be rendered */
673 hidgl_flush_triangles (&buffer
);
675 /* Walk the polygon structure, counting vertices */
676 /* This gives an upper bound on the amount of storage required */
677 for (contour
= pa
->contours
; contour
!= NULL
; contour
= contour
->next
)
678 vertex_count
= MAX (vertex_count
, contour
->Count
);
680 info
.vertices
= malloc (sizeof(GLdouble
) * vertex_count
* 3);
681 info
.tobj
= gluNewTess ();
682 gluTessCallback(info
.tobj
, GLU_TESS_BEGIN
, (_GLUfuncptr
)myBegin
);
683 gluTessCallback(info
.tobj
, GLU_TESS_VERTEX
, (_GLUfuncptr
)myVertex
);
684 gluTessCallback(info
.tobj
, GLU_TESS_COMBINE
, (_GLUfuncptr
)myCombine
);
685 gluTessCallback(info
.tobj
, GLU_TESS_ERROR
, (_GLUfuncptr
)myError
);
687 glPushAttrib (GL_STENCIL_BUFFER_BIT
); /* Save the write mask etc.. for final restore */
688 glEnable (GL_STENCIL_TEST
);
689 glPushAttrib (GL_STENCIL_BUFFER_BIT
| /* Resave the stencil write-mask etc.., and */
690 GL_COLOR_BUFFER_BIT
); /* the colour buffer write mask etc.. for part way restore */
691 glStencilMask (stencil_bit
); /* Only write to our stencil bit */
692 glStencilFunc (GL_ALWAYS
, stencil_bit
, stencil_bit
); /* Always pass stencil test, ref value is our bit */
693 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
695 glStencilOp (GL_KEEP
, GL_KEEP
, GL_REPLACE
); /* Stencil pass => replace stencil value */
697 /* Drawing operations now set our reference bit in the stencil buffer */
699 r_search (pa
->contour_tree
, clip_box
, NULL
, do_hole
, &info
);
700 hidgl_flush_triangles (&buffer
);
702 glPopAttrib (); /* Restore the colour and stencil buffer write-mask etc.. */
704 glStencilOp (GL_KEEP
, GL_KEEP
, GL_INVERT
); /* This allows us to toggle the bit on any subcompositing bitplane */
705 /* If the stencil test has passed, we know that bit is 0, so we're */
706 /* effectively just setting it to 1. */
708 glStencilFunc (GL_GEQUAL
, 0, assigned_bits
); /* Pass stencil test if all assigned bits clear, */
709 /* reference is all assigned bits so we set */
710 /* any bits permitted by the stencil writemask */
712 /* Drawing operations as masked to areas where the stencil buffer is '0' */
714 /* Draw the polygon outer */
715 tesselate_contour (info
.tobj
, pa
->contours
, info
.vertices
, scale
);
717 hidgl_flush_triangles (&buffer
);
719 /* Unassign our stencil buffer bit */
720 hidgl_return_stencil_bit (stencil_bit
);
722 glPopAttrib (); /* Restore the stencil buffer write-mask etc.. */
724 gluDeleteTess (info
.tobj
);
726 free (info
.vertices
);
730 hidgl_fill_pcb_polygon (PolygonType
*poly
, const BoxType
*clip_box
, double scale
)
732 if (poly
->Clipped
== NULL
)
735 fill_polyarea (poly
->Clipped
, clip_box
, scale
);
737 if (TEST_FLAG (FULLPOLYFLAG
, poly
))
741 for (pa
= poly
->Clipped
->f
; pa
!= poly
->Clipped
; pa
= pa
->f
)
742 fill_polyarea (pa
, clip_box
, scale
);
747 hidgl_fill_rect (Coord x1
, Coord y1
, Coord x2
, Coord y2
)
749 hidgl_ensure_triangle_space (&buffer
, 2);
750 hidgl_add_triangle (&buffer
, x1
, y1
, x1
, y2
, x2
, y2
);
751 hidgl_add_triangle (&buffer
, x2
, y1
, x2
, y2
, x1
, y1
);
757 glGetIntegerv (GL_STENCIL_BITS
, &stencil_bits
);
759 if (stencil_bits
== 0)
761 printf ("No stencil bits available.\n"
762 "Cannot mask polygon holes or subcomposite layers\n");
763 /* TODO: Flag this to the HID so it can revert to the dicer? */
765 else if (stencil_bits
== 1)
767 printf ("Only one stencil bitplane available\n"
768 "Cannot use stencil buffer to sub-composite layers.\n");
769 /* Do we need to disable that somewhere? */
774 hidgl_start_render (void)
777 hidgl_init_triangle_array (&buffer
);
781 hidgl_finish_render (void)
786 hidgl_stencil_bits (void)
792 hidgl_clean_unassigned_stencil (void)
794 glPushAttrib (GL_STENCIL_BUFFER_BIT
);
795 glStencilMask (~assigned_bits
);
797 glClear (GL_STENCIL_BUFFER_BIT
);
802 hidgl_assign_clear_stencil_bit (void)
804 int stencil_bitmask
= (1 << stencil_bits
) - 1;
808 if (assigned_bits
== stencil_bitmask
)
810 printf ("No more stencil bits available, total of %i already assigned\n",
815 /* Look for a bitplane we don't have to clear */
816 for (test
= 1; test
& stencil_bitmask
; test
<<= 1)
818 if (!(test
& dirty_bits
))
820 assigned_bits
|= test
;
824 else if (!first_dirty
&& !(test
& assigned_bits
))
830 /* Didn't find any non dirty planes. Clear those dirty ones which aren't in use */
831 hidgl_clean_unassigned_stencil ();
832 assigned_bits
|= first_dirty
;
833 dirty_bits
= assigned_bits
;
839 hidgl_return_stencil_bit (int bit
)
841 assigned_bits
&= ~bit
;
845 hidgl_reset_stencil_usage (void)