implemented grid thickness
[geda-pcb.git] / src / hid / common / hidgl.c
blob6983902f6b7785cc711faea13890d4a4d875d35e
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 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.
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
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
45 # include <windows.h>
46 #endif
47 #if defined HAVE_GL_GL_H
48 # include <GL/gl.h>
49 #elif defined HAVE_OPENGL_GL_H
50 # include <OpenGL/gl.h>
51 #else
52 # error autoconf couldnt find gl.h
53 #endif
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
58 # include <GL/glu.h>
59 #elif defined HAVE_OPENGL_GLU_H
60 # include <OpenGL/glu.h>
61 #else
62 # error autoconf couldnt find glu.h
63 #endif
65 #include "action.h"
66 #include "crosshair.h"
67 #include "data.h"
68 #include "error.h"
69 #include "global.h"
70 #include "mymem.h"
71 #include "clip.h"
73 #include "hid.h"
74 #include "hidgl.h"
75 #include "rtree.h"
77 #ifdef HAVE_LIBDMALLOC
78 #include <dmalloc.h>
79 #endif
82 triangle_buffer buffer;
83 float global_depth = 0;
85 static void
86 hidgl_init_triangle_array (triangle_buffer *buffer)
88 buffer->triangle_count = 0;
89 buffer->coord_comp_count = 0;
92 void
93 hidgl_flush_triangles (triangle_buffer *buffer)
95 if (buffer->triangle_count == 0)
96 return;
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;
107 void
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);
115 exit (1);
117 if (count > TRIANGLE_ARRAY_SIZE - buffer->triangle_count)
118 hidgl_flush_triangles (buffer);
121 void
122 hidgl_set_depth (float depth)
124 global_depth = depth;
128 * \brief Draw the grid on the 3D canvas
130 void
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;
136 double x, y;
137 double pixels;
138 double grid_px;
139 double point_size;
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);
150 if (x1 > x2)
152 Coord tmp = x1;
153 x1 = x2;
154 x2 = tmp;
157 if (y1 > y2)
159 Coord tmp = y1;
160 y1 = y2;
161 y2 = tmp;
164 n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1; /* Number of points in one row */
165 if (n > npoints)
166 { /* [n]points are static, reallocate if we need more memory */
167 npoints = n + 10;
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 */
175 if (point_size > 4)
177 point_size = 4;
179 else if (point_size < 1)
181 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);
190 n = 0;
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;
195 n++;
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);
206 glPointSize (1);
209 #define MAX_PIXELS_ARC_TO_CHORD 0.5
210 #define MIN_SLICES 6
211 int calc_slices (float pix_radius, float sweep_angle)
213 float slices;
215 if (pix_radius <= MAX_PIXELS_ARC_TO_CHORD)
216 return MIN_SLICES;
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;
227 float capx, capy;
228 float radius = width / 2.;
229 int slices = calc_slices (radius / scale, M_PI);
230 int i;
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);
246 last_capx = capx;
247 last_capy = capy;
251 void
252 hidgl_draw_line (int cap, Coord width, Coord x1, Coord y1, Coord x2, Coord y2, double scale)
254 double angle;
255 double deltax, deltay, length;
256 float wdx, wdy;
257 int circular_caps = 0;
258 int hairline = 0;
260 if (width == 0.0)
261 hairline = 1;
263 if (width < scale)
264 width = scale;
266 deltax = x2 - x1;
267 deltay = y2 - y1;
269 length = hypot (deltax, deltay);
271 if (length == 0) {
272 /* Assume the orientation of the line is horizontal */
273 wdx = -width / 2.;
274 wdy = 0;
275 length = 1.;
276 deltax = 1.;
277 deltay = 0.;
278 } else {
279 wdy = deltax * width / 2. / length;
280 wdx = -deltay * width / 2. / length;
283 angle = -180. / M_PI * atan2 (deltay, deltax);
285 switch (cap) {
286 case Trace_Cap:
287 case Round_Cap:
288 circular_caps = 1;
289 break;
291 case Square_Cap:
292 case Beveled_Cap:
293 x1 -= deltax * width / 2. / length;
294 y1 -= deltay * width / 2. / length;
295 x2 += deltax * width / 2. / length;
296 y2 += deltay * width / 2. / length;
297 break;
300 hidgl_ensure_triangle_space (&buffer, 2);
301 hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
302 x2 - wdx, y2 - wdy,
303 x2 + wdx, y2 + wdy);
304 hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
305 x2 + wdx, y2 + wdy,
306 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
318 void
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;
326 float inner_r;
327 float outer_r;
328 float cos_ang, sin_ang;
329 float start_angle_rad;
330 float delta_angle_rad;
331 float angle_incr_rad;
332 int slices;
333 int i;
334 int hairline = 0;
336 if (width == 0.0)
337 hairline = 1;
339 if (width < scale)
340 width = scale;
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,
376 outer_x, outer_y);
377 hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
378 inner_x, inner_y,
379 outer_x, outer_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 */
385 if (hairline)
386 return;
388 draw_cap (width, x + rx * -cosf (start_angle_rad),
389 y + rx * sinf (start_angle_rad),
390 start_angle, scale);
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);
396 void
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);
404 glEnd ();
408 void
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;
414 float radius = vr;
415 int slices;
416 int i;
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);
428 last_x = vx + vr;
429 last_y = vy;
431 for (i = 0; i < slices; i++) {
432 float x, y;
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);
436 last_x = x;
437 last_y = 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;
449 #ifndef CALLBACK
450 #define CALLBACK
451 #endif
453 static void CALLBACK
454 myError (GLenum errno)
456 printf ("gluTess error: %s\n", gluErrorString (errno));
459 static void CALLBACK
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 ++;
473 else
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;
479 else
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;
491 static void CALLBACK
492 myBegin (GLenum type)
494 tessVertexType = type;
495 stashed_vertices = 0;
496 triangle_comp_idx = 0;
499 static double global_scale;
501 static void CALLBACK
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];
513 stashed_vertices ++;
515 else
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];
538 stashed_vertices ++;
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;
550 else
551 printf ("Vertex received with unknown type\n");
554 static void
555 myFreeCombined ()
557 while (combined_num_to_free)
558 free (combined_to_free [-- combined_num_to_free]);
561 void
562 hidgl_fill_polygon (int n_coords, Coord *x, Coord *y)
564 int i;
565 GLUtesselator *tobj;
566 GLdouble *vertices;
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);
593 myFreeCombined ();
594 free (vertices);
597 void
598 tesselate_contour (GLUtesselator *tobj, PLINE *contour, GLdouble *vertices,
599 double scale)
601 VNODE *vn = &contour->head;
602 int offset = 0;
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);
612 return;
616 gluTessBeginPolygon (tobj, NULL);
617 gluTessBeginContour (tobj);
618 do {
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]);
623 offset += 3;
624 } while ((vn = vn->next) != &contour->head);
625 gluTessEndContour (tobj);
626 gluTessEndPolygon (tobj);
629 struct do_hole_info {
630 GLUtesselator *tobj;
631 GLdouble *vertices;
632 double scale;
635 static int
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) {
643 return 0;
646 tesselate_contour (info->tobj, curc, info->vertices, info->scale);
647 return 1;
650 static GLint stencil_bits;
651 static int dirty_bits = 0;
652 static int assigned_bits = 0;
654 static void
655 fill_polyarea (POLYAREA *pa, const BoxType *clip_box, double scale)
657 int vertex_count = 0;
658 PLINE *contour;
659 struct do_hole_info info;
660 int stencil_bit;
662 info.scale = scale;
663 global_scale = scale;
665 stencil_bit = hidgl_assign_clear_stencil_bit ();
666 if (!stencil_bit)
668 printf ("hidgl_fill_pcb_polygon: No free stencil bits, aborting polygon\n");
669 return;
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);
725 myFreeCombined ();
726 free (info.vertices);
729 void
730 hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale)
732 if (poly->Clipped == NULL)
733 return;
735 fill_polyarea (poly->Clipped, clip_box, scale);
737 if (TEST_FLAG (FULLPOLYFLAG, poly))
739 POLYAREA *pa;
741 for (pa = poly->Clipped->f; pa != poly->Clipped; pa = pa->f)
742 fill_polyarea (pa, clip_box, scale);
746 void
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);
754 void
755 hidgl_init (void)
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? */
773 void
774 hidgl_start_render (void)
776 hidgl_init ();
777 hidgl_init_triangle_array (&buffer);
780 void
781 hidgl_finish_render (void)
786 hidgl_stencil_bits (void)
788 return stencil_bits;
791 static void
792 hidgl_clean_unassigned_stencil (void)
794 glPushAttrib (GL_STENCIL_BUFFER_BIT);
795 glStencilMask (~assigned_bits);
796 glClearStencil (0);
797 glClear (GL_STENCIL_BUFFER_BIT);
798 glPopAttrib ();
802 hidgl_assign_clear_stencil_bit (void)
804 int stencil_bitmask = (1 << stencil_bits) - 1;
805 int test;
806 int first_dirty = 0;
808 if (assigned_bits == stencil_bitmask)
810 printf ("No more stencil bits available, total of %i already assigned\n",
811 stencil_bits);
812 return 0;
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;
821 dirty_bits |= test;
822 return test;
824 else if (!first_dirty && !(test & assigned_bits))
826 first_dirty = test;
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;
835 return first_dirty;
838 void
839 hidgl_return_stencil_bit (int bit)
841 assigned_bits &= ~bit;
844 void
845 hidgl_reset_stencil_usage (void)
847 assigned_bits = 0;
848 dirty_bits = 0;