hid/common/hidgl.c: Make (polygon->clipped == NULL) test silent
[geda-pcb/pcjc2.git] / src / hid / common / hidgl.c
blob73e85ce7472a1413f8db3a4e3a7659bc21d2bcc9
1 /*
2 * COPYRIGHT
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
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
32 #include <math.h>
33 #include <assert.h>
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
41 #ifdef HAVE_OPENGL_GL_H
42 # include <OpenGL/gl.h>
43 #else
44 # include <GL/gl.h>
45 #endif
47 #ifdef HAVE_OPENGL_GLU_H
48 # include <OpenGL/glu.h>
49 #else
50 # include <GL/glu.h>
51 #endif
53 #include "action.h"
54 #include "crosshair.h"
55 #include "data.h"
56 #include "error.h"
57 #include "global.h"
58 #include "mymem.h"
59 #include "clip.h"
61 #include "hid.h"
62 #include "hidgl.h"
63 #include "rtree.h"
65 #ifdef HAVE_LIBDMALLOC
66 #include <dmalloc.h>
67 #endif
70 triangle_buffer buffer;
71 float global_depth = 0;
73 static void
74 hidgl_init_triangle_array (triangle_buffer *buffer)
76 buffer->triangle_count = 0;
77 buffer->coord_comp_count = 0;
80 void
81 hidgl_flush_triangles (triangle_buffer *buffer)
83 if (buffer->triangle_count == 0)
84 return;
86 glEnableClientState (GL_VERTEX_ARRAY);
87 glVertexPointer (3, GL_FLOAT, 0, buffer->triangle_array);
88 glDrawArrays (GL_TRIANGLES, 0, buffer->triangle_count * 3);
89 glDisableClientState (GL_VERTEX_ARRAY);
91 buffer->triangle_count = 0;
92 buffer->coord_comp_count = 0;
95 void
96 hidgl_ensure_triangle_space (triangle_buffer *buffer, int count)
98 if (count > TRIANGLE_ARRAY_SIZE)
100 fprintf (stderr, "Not enough space in vertex buffer\n");
101 fprintf (stderr, "Requested %i triangles, %i available\n",
102 count, TRIANGLE_ARRAY_SIZE);
103 exit (1);
105 if (count > TRIANGLE_ARRAY_SIZE - buffer->triangle_count)
106 hidgl_flush_triangles (buffer);
109 void
110 hidgl_set_depth (float depth)
112 global_depth = depth;
115 void
116 hidgl_draw_grid (BoxType *drawn_area)
118 static GLfloat *points = 0;
119 static int npoints = 0;
120 Coord x1, y1, x2, y2, n, i;
121 double x, y;
123 if (!Settings.DrawGrid)
124 return;
126 x1 = GridFit (MAX (0, drawn_area->X1), PCB->Grid, PCB->GridOffsetX);
127 y1 = GridFit (MAX (0, drawn_area->Y1), PCB->Grid, PCB->GridOffsetY);
128 x2 = GridFit (MIN (PCB->MaxWidth, drawn_area->X2), PCB->Grid, PCB->GridOffsetX);
129 y2 = GridFit (MIN (PCB->MaxHeight, drawn_area->Y2), PCB->Grid, PCB->GridOffsetY);
131 if (x1 > x2)
133 Coord tmp = x1;
134 x1 = x2;
135 x2 = tmp;
138 if (y1 > y2)
140 Coord tmp = y1;
141 y1 = y2;
142 y2 = tmp;
145 n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
146 if (n > npoints)
148 npoints = n + 10;
149 points = realloc (points, npoints * 3 * sizeof (GLfloat));
152 glEnableClientState (GL_VERTEX_ARRAY);
153 glVertexPointer (3, GL_FLOAT, 0, points);
155 n = 0;
156 for (x = x1; x <= x2; x += PCB->Grid)
158 points[3 * n + 0] = x;
159 points[3 * n + 2] = global_depth;
160 n++;
162 for (y = y1; y <= y2; y += PCB->Grid)
164 for (i = 0; i < n; i++)
165 points[3 * i + 1] = y;
166 glDrawArrays (GL_POINTS, 0, n);
169 glDisableClientState (GL_VERTEX_ARRAY);
172 #define MAX_PIXELS_ARC_TO_CHORD 0.5
173 #define MIN_SLICES 6
174 int calc_slices (float pix_radius, float sweep_angle)
176 float slices;
178 if (pix_radius <= MAX_PIXELS_ARC_TO_CHORD)
179 return MIN_SLICES;
181 slices = sweep_angle / acosf (1 - MAX_PIXELS_ARC_TO_CHORD / pix_radius) / 2.;
182 return (int)ceilf (slices);
185 #define MIN_TRIANGLES_PER_CAP 3
186 #define MAX_TRIANGLES_PER_CAP 90
187 static void draw_cap (Coord width, Coord x, Coord y, Angle angle, double scale)
189 float last_capx, last_capy;
190 float capx, capy;
191 float radius = width / 2.;
192 int slices = calc_slices (radius / scale, M_PI);
193 int i;
195 if (slices < MIN_TRIANGLES_PER_CAP)
196 slices = MIN_TRIANGLES_PER_CAP;
198 if (slices > MAX_TRIANGLES_PER_CAP)
199 slices = MAX_TRIANGLES_PER_CAP;
201 hidgl_ensure_triangle_space (&buffer, slices);
203 last_capx = radius * cosf (angle * M_PI / 180.) + x;
204 last_capy = -radius * sinf (angle * M_PI / 180.) + y;
205 for (i = 0; i < slices; i++) {
206 capx = radius * cosf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + x;
207 capy = -radius * sinf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + y;
208 hidgl_add_triangle (&buffer, last_capx, last_capy, capx, capy, x, y);
209 last_capx = capx;
210 last_capy = capy;
214 void
215 hidgl_draw_line (int cap, Coord width, Coord x1, Coord y1, Coord x2, Coord y2, double scale)
217 double angle;
218 double deltax, deltay, length;
219 float wdx, wdy;
220 int circular_caps = 0;
221 int hairline = 0;
223 if (width == 0.0)
224 hairline = 1;
226 if (width < scale)
227 width = scale;
229 deltax = x2 - x1;
230 deltay = y2 - y1;
232 length = sqrt (deltax * deltax + deltay * deltay);
234 if (length == 0) {
235 /* Assume the orientation of the line is horizontal */
236 wdx = -width / 2.;
237 wdy = 0;
238 length = 1.;
239 deltax = 1.;
240 deltay = 0.;
241 } else {
242 wdy = deltax * width / 2. / length;
243 wdx = -deltay * width / 2. / length;
246 angle = -180. / M_PI * atan2 (deltay, deltax);
248 switch (cap) {
249 case Trace_Cap:
250 case Round_Cap:
251 circular_caps = 1;
252 break;
254 case Square_Cap:
255 case Beveled_Cap:
256 x1 -= deltax * width / 2. / length;
257 y1 -= deltay * width / 2. / length;
258 x2 += deltax * width / 2. / length;
259 y2 += deltay * width / 2. / length;
260 break;
263 hidgl_ensure_triangle_space (&buffer, 2);
264 hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
265 x2 - wdx, y2 - wdy,
266 x2 + wdx, y2 + wdy);
267 hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
268 x2 + wdx, y2 + wdy,
269 x1 + wdx, y1 + wdy);
271 /* Don't bother capping hairlines */
272 if (circular_caps && !hairline)
274 draw_cap (width, x1, y1, angle + 90., scale);
275 draw_cap (width, x2, y2, angle - 90., scale);
279 #define MIN_SLICES_PER_ARC 6
280 #define MAX_SLICES_PER_ARC 360
281 void
282 hidgl_draw_arc (Coord width, Coord x, Coord y, Coord rx, Coord ry,
283 Angle start_angle, Angle delta_angle, double scale)
285 float last_inner_x, last_inner_y;
286 float last_outer_x, last_outer_y;
287 float inner_x, inner_y;
288 float outer_x, outer_y;
289 float inner_r;
290 float outer_r;
291 float cos_ang, sin_ang;
292 float start_angle_rad;
293 float delta_angle_rad;
294 float angle_incr_rad;
295 int slices;
296 int i;
297 int hairline = 0;
299 if (width == 0.0)
300 hairline = 1;
302 if (width < scale)
303 width = scale;
305 inner_r = rx - width / 2.;
306 outer_r = rx + width / 2.;
308 if (delta_angle < 0) {
309 start_angle += delta_angle;
310 delta_angle = - delta_angle;
313 start_angle_rad = start_angle * M_PI / 180.;
314 delta_angle_rad = delta_angle * M_PI / 180.;
316 slices = calc_slices ((rx + width / 2.) / scale, delta_angle_rad);
318 if (slices < MIN_SLICES_PER_ARC)
319 slices = MIN_SLICES_PER_ARC;
321 if (slices > MAX_SLICES_PER_ARC)
322 slices = MAX_SLICES_PER_ARC;
324 hidgl_ensure_triangle_space (&buffer, 2 * slices);
326 angle_incr_rad = delta_angle_rad / (float)slices;
328 cos_ang = cosf (start_angle_rad);
329 sin_ang = sinf (start_angle_rad);
330 last_inner_x = -inner_r * cos_ang + x; last_inner_y = inner_r * sin_ang + y;
331 last_outer_x = -outer_r * cos_ang + x; last_outer_y = outer_r * sin_ang + y;
332 for (i = 1; i <= slices; i++) {
333 cos_ang = cosf (start_angle_rad + ((float)(i)) * angle_incr_rad);
334 sin_ang = sinf (start_angle_rad + ((float)(i)) * angle_incr_rad);
335 inner_x = -inner_r * cos_ang + x; inner_y = inner_r * sin_ang + y;
336 outer_x = -outer_r * cos_ang + x; outer_y = outer_r * sin_ang + y;
337 hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
338 last_outer_x, last_outer_y,
339 outer_x, outer_y);
340 hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
341 inner_x, inner_y,
342 outer_x, outer_y);
343 last_inner_x = inner_x; last_inner_y = inner_y;
344 last_outer_x = outer_x; last_outer_y = outer_y;
347 /* Don't bother capping hairlines */
348 if (hairline)
349 return;
351 draw_cap (width, x + rx * -cosf (start_angle_rad),
352 y + rx * sinf (start_angle_rad),
353 start_angle, scale);
354 draw_cap (width, x + rx * -cosf (start_angle_rad + delta_angle_rad),
355 y + rx * sinf (start_angle_rad + delta_angle_rad),
356 start_angle + delta_angle + 180., scale);
359 void
360 hidgl_draw_rect (Coord x1, Coord y1, Coord x2, Coord y2)
362 glBegin (GL_LINE_LOOP);
363 glVertex3f (x1, y1, global_depth);
364 glVertex3f (x1, y2, global_depth);
365 glVertex3f (x2, y2, global_depth);
366 glVertex3f (x2, y1, global_depth);
367 glEnd ();
371 void
372 hidgl_fill_circle (Coord vx, Coord vy, Coord vr, double scale)
374 #define MIN_TRIANGLES_PER_CIRCLE 6
375 #define MAX_TRIANGLES_PER_CIRCLE 360
376 float last_x, last_y;
377 float radius = vr;
378 int slices;
379 int i;
381 slices = calc_slices (vr / scale, 2 * M_PI);
383 if (slices < MIN_TRIANGLES_PER_CIRCLE)
384 slices = MIN_TRIANGLES_PER_CIRCLE;
386 if (slices > MAX_TRIANGLES_PER_CIRCLE)
387 slices = MAX_TRIANGLES_PER_CIRCLE;
389 hidgl_ensure_triangle_space (&buffer, slices);
391 last_x = vx + vr;
392 last_y = vy;
394 for (i = 0; i < slices; i++) {
395 float x, y;
396 x = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
397 y = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
398 hidgl_add_triangle (&buffer, vx, vy, last_x, last_y, x, y);
399 last_x = x;
400 last_y = y;
404 #define MAX_COMBINED_MALLOCS 2500
405 static void *combined_to_free [MAX_COMBINED_MALLOCS];
406 static int combined_num_to_free = 0;
408 static GLenum tessVertexType;
409 static int stashed_vertices;
410 static int triangle_comp_idx;
412 #ifndef CALLBACK
413 #define CALLBACK
414 #endif
416 static void CALLBACK
417 myError (GLenum errno)
419 printf ("gluTess error: %s\n", gluErrorString (errno));
422 static void CALLBACK
423 myCombine ( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **dataOut )
425 #define MAX_COMBINED_VERTICES 2500
426 static GLdouble combined_vertices [3 * MAX_COMBINED_VERTICES];
427 static int num_combined_vertices = 0;
429 GLdouble *new_vertex;
431 if (num_combined_vertices < MAX_COMBINED_VERTICES)
433 new_vertex = &combined_vertices [3 * num_combined_vertices];
434 num_combined_vertices ++;
436 else
438 new_vertex = malloc (3 * sizeof (GLdouble));
440 if (combined_num_to_free < MAX_COMBINED_MALLOCS)
441 combined_to_free [combined_num_to_free ++] = new_vertex;
442 else
443 printf ("myCombine leaking %lu bytes of memory\n", 3 * sizeof (GLdouble));
446 new_vertex[0] = coords[0];
447 new_vertex[1] = coords[1];
448 new_vertex[2] = coords[2];
450 *dataOut = new_vertex;
453 static void CALLBACK
454 myBegin (GLenum type)
456 tessVertexType = type;
457 stashed_vertices = 0;
458 triangle_comp_idx = 0;
461 static double global_scale;
463 static void CALLBACK
464 myVertex (GLdouble *vertex_data)
466 static GLfloat triangle_vertices [2 * 3];
468 if (tessVertexType == GL_TRIANGLE_STRIP ||
469 tessVertexType == GL_TRIANGLE_FAN)
471 if (stashed_vertices < 2)
473 triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
474 triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
475 stashed_vertices ++;
477 else
479 hidgl_ensure_triangle_space (&buffer, 1);
480 hidgl_add_triangle (&buffer,
481 triangle_vertices [0], triangle_vertices [1],
482 triangle_vertices [2], triangle_vertices [3],
483 vertex_data [0], vertex_data [1]);
485 if (tessVertexType == GL_TRIANGLE_STRIP)
487 /* STRIP saves the last two vertices for re-use in the next triangle */
488 triangle_vertices [0] = triangle_vertices [2];
489 triangle_vertices [1] = triangle_vertices [3];
491 /* Both FAN and STRIP save the last vertex for re-use in the next triangle */
492 triangle_vertices [2] = vertex_data [0];
493 triangle_vertices [3] = vertex_data [1];
496 else if (tessVertexType == GL_TRIANGLES)
498 triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
499 triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
500 stashed_vertices ++;
501 if (stashed_vertices == 3)
503 hidgl_ensure_triangle_space (&buffer, 1);
504 hidgl_add_triangle (&buffer,
505 triangle_vertices [0], triangle_vertices [1],
506 triangle_vertices [2], triangle_vertices [3],
507 triangle_vertices [4], triangle_vertices [5]);
508 triangle_comp_idx = 0;
509 stashed_vertices = 0;
512 else
513 printf ("Vertex received with unknown type\n");
516 static void
517 myFreeCombined ()
519 while (combined_num_to_free)
520 free (combined_to_free [-- combined_num_to_free]);
523 void
524 hidgl_fill_polygon (int n_coords, Coord *x, Coord *y)
526 int i;
527 GLUtesselator *tobj;
528 GLdouble *vertices;
530 assert (n_coords > 0);
532 vertices = malloc (sizeof(GLdouble) * n_coords * 3);
534 tobj = gluNewTess ();
535 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)myBegin);
536 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)myVertex);
537 gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)myCombine);
538 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)myError);
540 gluTessBeginPolygon (tobj, NULL);
541 gluTessBeginContour (tobj);
543 for (i = 0; i < n_coords; i++)
545 vertices [0 + i * 3] = x[i];
546 vertices [1 + i * 3] = y[i];
547 vertices [2 + i * 3] = 0.;
548 gluTessVertex (tobj, &vertices [i * 3], &vertices [i * 3]);
551 gluTessEndContour (tobj);
552 gluTessEndPolygon (tobj);
553 gluDeleteTess (tobj);
555 myFreeCombined ();
556 free (vertices);
559 void
560 tesselate_contour (GLUtesselator *tobj, PLINE *contour, GLdouble *vertices,
561 double scale)
563 VNODE *vn = &contour->head;
564 int offset = 0;
566 /* If the contour is round, and hidgl_fill_circle would use
567 * less slices than we have vertices to draw it, then call
568 * hidgl_fill_circle to draw this contour.
570 if (contour->is_round) {
571 double slices = calc_slices (contour->radius / scale, 2 * M_PI);
572 if (slices < contour->Count) {
573 hidgl_fill_circle (contour->cx, contour->cy, contour->radius, scale);
574 return;
578 gluTessBeginPolygon (tobj, NULL);
579 gluTessBeginContour (tobj);
580 do {
581 vertices [0 + offset] = vn->point[0];
582 vertices [1 + offset] = vn->point[1];
583 vertices [2 + offset] = 0.;
584 gluTessVertex (tobj, &vertices [offset], &vertices [offset]);
585 offset += 3;
586 } while ((vn = vn->next) != &contour->head);
587 gluTessEndContour (tobj);
588 gluTessEndPolygon (tobj);
591 struct do_hole_info {
592 GLUtesselator *tobj;
593 GLdouble *vertices;
594 double scale;
597 static int
598 do_hole (const BoxType *b, void *cl)
600 struct do_hole_info *info = cl;
601 PLINE *curc = (PLINE *) b;
603 /* Ignore the outer contour - we draw it first explicitly*/
604 if (curc->Flags.orient == PLF_DIR) {
605 return 0;
608 tesselate_contour (info->tobj, curc, info->vertices, info->scale);
609 return 1;
612 static GLint stencil_bits;
613 static int dirty_bits = 0;
614 static int assigned_bits = 0;
616 /* FIXME: JUST DRAWS THE FIRST PIECE.. TODO: SUPPORT FOR FULLPOLY POLYGONS */
617 void
618 hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale)
620 int vertex_count = 0;
621 PLINE *contour;
622 struct do_hole_info info;
623 int stencil_bit;
625 info.scale = scale;
626 global_scale = scale;
628 if (poly->Clipped == NULL)
629 return;
631 stencil_bit = hidgl_assign_clear_stencil_bit ();
632 if (!stencil_bit)
634 printf ("hidgl_fill_pcb_polygon: No free stencil bits, aborting polygon\n");
635 return;
638 /* Flush out any existing geoemtry to be rendered */
639 hidgl_flush_triangles (&buffer);
641 /* Walk the polygon structure, counting vertices */
642 /* This gives an upper bound on the amount of storage required */
643 for (contour = poly->Clipped->contours;
644 contour != NULL; contour = contour->next)
645 vertex_count = MAX (vertex_count, contour->Count);
647 info.vertices = malloc (sizeof(GLdouble) * vertex_count * 3);
648 info.tobj = gluNewTess ();
649 gluTessCallback(info.tobj, GLU_TESS_BEGIN, (_GLUfuncptr)myBegin);
650 gluTessCallback(info.tobj, GLU_TESS_VERTEX, (_GLUfuncptr)myVertex);
651 gluTessCallback(info.tobj, GLU_TESS_COMBINE, (_GLUfuncptr)myCombine);
652 gluTessCallback(info.tobj, GLU_TESS_ERROR, (_GLUfuncptr)myError);
654 glPushAttrib (GL_STENCIL_BUFFER_BIT); /* Save the write mask etc.. for final restore */
655 glEnable (GL_STENCIL_TEST);
656 glPushAttrib (GL_STENCIL_BUFFER_BIT | /* Resave the stencil write-mask etc.., and */
657 GL_COLOR_BUFFER_BIT); /* the colour buffer write mask etc.. for part way restore */
658 glStencilMask (stencil_bit); /* Only write to our stencil bit */
659 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, ref value is our bit */
660 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
662 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value */
664 /* Drawing operations now set our reference bit in the stencil buffer */
666 r_search (poly->Clipped->contour_tree, clip_box, NULL, do_hole, &info);
667 hidgl_flush_triangles (&buffer);
669 glPopAttrib (); /* Restore the colour and stencil buffer write-mask etc.. */
671 glStencilOp (GL_KEEP, GL_KEEP, GL_INVERT); /* This allows us to toggle the bit on any subcompositing bitplane */
672 /* If the stencil test has passed, we know that bit is 0, so we're */
673 /* effectively just setting it to 1. */
675 glStencilFunc (GL_GEQUAL, 0, assigned_bits); /* Pass stencil test if all assigned bits clear, */
676 /* reference is all assigned bits so we set */
677 /* any bits permitted by the stencil writemask */
679 /* Drawing operations as masked to areas where the stencil buffer is '0' */
681 /* Draw the polygon outer */
682 tesselate_contour (info.tobj, poly->Clipped->contours, info.vertices, scale);
683 hidgl_flush_triangles (&buffer);
685 /* Unassign our stencil buffer bit */
686 hidgl_return_stencil_bit (stencil_bit);
688 glPopAttrib (); /* Restore the stencil buffer write-mask etc.. */
690 gluDeleteTess (info.tobj);
691 myFreeCombined ();
692 free (info.vertices);
695 void
696 hidgl_fill_rect (Coord x1, Coord y1, Coord x2, Coord y2)
698 hidgl_ensure_triangle_space (&buffer, 2);
699 hidgl_add_triangle (&buffer, x1, y1, x1, y2, x2, y2);
700 hidgl_add_triangle (&buffer, x2, y1, x2, y2, x1, y1);
703 void
704 hidgl_init (void)
706 glGetIntegerv (GL_STENCIL_BITS, &stencil_bits);
708 if (stencil_bits == 0)
710 printf ("No stencil bits available.\n"
711 "Cannot mask polygon holes or subcomposite layers\n");
712 /* TODO: Flag this to the HID so it can revert to the dicer? */
714 else if (stencil_bits == 1)
716 printf ("Only one stencil bitplane avilable\n"
717 "Cannot use stencil buffer to sub-composite layers.\n");
718 /* Do we need to disable that somewhere? */
722 void
723 hidgl_start_render (void)
725 hidgl_init ();
726 hidgl_init_triangle_array (&buffer);
729 void
730 hidgl_finish_render (void)
735 hidgl_stencil_bits (void)
737 return stencil_bits;
740 static void
741 hidgl_clean_unassigned_stencil (void)
743 glPushAttrib (GL_STENCIL_BUFFER_BIT);
744 glStencilMask (~assigned_bits);
745 glClearStencil (0);
746 glClear (GL_STENCIL_BUFFER_BIT);
747 glPopAttrib ();
751 hidgl_assign_clear_stencil_bit (void)
753 int stencil_bitmask = (1 << stencil_bits) - 1;
754 int test;
755 int first_dirty = 0;
757 if (assigned_bits == stencil_bitmask)
759 printf ("No more stencil bits available, total of %i already assigned\n",
760 stencil_bits);
761 return 0;
764 /* Look for a bitplane we don't have to clear */
765 for (test = 1; test & stencil_bitmask; test <<= 1)
767 if (!(test & dirty_bits))
769 assigned_bits |= test;
770 dirty_bits |= test;
771 return test;
773 else if (!first_dirty && !(test & assigned_bits))
775 first_dirty = test;
779 /* Didn't find any non dirty planes. Clear those dirty ones which aren't in use */
780 hidgl_clean_unassigned_stencil ();
781 assigned_bits |= first_dirty;
782 dirty_bits = assigned_bits;
784 return first_dirty;
787 void
788 hidgl_return_stencil_bit (int bit)
790 assigned_bits &= ~bit;
793 void
794 hidgl_reset_stencil_usage (void)
796 assigned_bits = 0;
797 dirty_bits = 0;