pcb 4.1.1
An interactive printed circuit board layout editor.

hidgl.c

Go to the documentation of this file.
00001 /*
00002  *                            COPYRIGHT
00003  *
00004  *  PCB, interactive printed circuit board design
00005  *  Copyright (C) 2009-2011 PCB Contributers (See ChangeLog for details)
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License along
00018  * with this program; if not, write to the Free Software Foundation, Inc.,
00019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #ifdef HAVE_STRING_H
00030 #include <string.h>
00031 #endif
00032 #include <math.h>
00033 #include <assert.h>
00034 
00035 /* The Linux OpenGL ABI 1.0 spec requires that we define
00036  * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
00037  * in order to get prototypes:
00038  *   http://www.opengl.org/registry/ABI/
00039  */
00040 #define GL_GLEXT_PROTOTYPES 1
00041 
00042 /* This follows autoconf's recommendation for the AX_CHECK_GL macro
00043    https://www.gnu.org/software/autoconf-archive/ax_check_gl.html */
00044 #if defined HAVE_WINDOWS_H && defined _WIN32
00045 #  include <windows.h>
00046 #endif
00047 #if defined HAVE_GL_GL_H
00048 #  include <GL/gl.h>
00049 #elif defined HAVE_OPENGL_GL_H
00050 #  include <OpenGL/gl.h>
00051 #else
00052 #  error autoconf couldnt find gl.h
00053 #endif
00054 
00055 /* This follows autoconf's recommendation for the AX_CHECK_GLU macro
00056    https://www.gnu.org/software/autoconf-archive/ax_check_glu.html */
00057 #if defined HAVE_GL_GLU_H
00058 #  include <GL/glu.h>
00059 #elif defined HAVE_OPENGL_GLU_H
00060 #  include <OpenGL/glu.h>
00061 #else
00062 #  error autoconf couldnt find glu.h
00063 #endif
00064 
00065 #include "action.h"
00066 #include "crosshair.h"
00067 #include "data.h"
00068 #include "error.h"
00069 #include "global.h"
00070 #include "mymem.h"
00071 #include "clip.h"
00072 
00073 #include "hid.h"
00074 #include "hidgl.h"
00075 #include "rtree.h"
00076 
00077 #ifdef HAVE_LIBDMALLOC
00078 #include <dmalloc.h>
00079 #endif
00080 
00081 
00082 triangle_buffer buffer;
00083 float global_depth = 0;
00084 
00085 static void
00086 hidgl_init_triangle_array (triangle_buffer *buffer)
00087 {
00088   buffer->triangle_count = 0;
00089   buffer->coord_comp_count = 0;
00090 }
00091 
00092 void
00093 hidgl_flush_triangles (triangle_buffer *buffer)
00094 {
00095   if (buffer->triangle_count == 0)
00096     return;
00097 
00098   glEnableClientState (GL_VERTEX_ARRAY);
00099   glVertexPointer (3, GL_FLOAT, 0, buffer->triangle_array);
00100   glDrawArrays (GL_TRIANGLES, 0, buffer->triangle_count * 3);
00101   glDisableClientState (GL_VERTEX_ARRAY);
00102 
00103   buffer->triangle_count = 0;
00104   buffer->coord_comp_count = 0;
00105 }
00106 
00107 void
00108 hidgl_ensure_triangle_space (triangle_buffer *buffer, int count)
00109 {
00110   if (count > TRIANGLE_ARRAY_SIZE)
00111     {
00112       fprintf (stderr, "Not enough space in vertex buffer\n");
00113       fprintf (stderr, "Requested %i triangles, %i available\n",
00114                        count, TRIANGLE_ARRAY_SIZE);
00115       exit (1);
00116     }
00117   if (count > TRIANGLE_ARRAY_SIZE - buffer->triangle_count)
00118     hidgl_flush_triangles (buffer);
00119 }
00120 
00121 void
00122 hidgl_set_depth (float depth)
00123 {
00124   global_depth = depth;
00125 }
00126 
00130 void
00131 hidgl_draw_grid (BoxType *drawn_area)
00132 {
00133   static GLfloat *points = 0;
00134   static int npoints = 0;
00135   Coord x1, y1, x2, y2, n, i;
00136   double x, y;
00137 
00138   if (!Settings.DrawGrid)
00139     return; /* grid hidden */
00140 
00141   /* Find the bounding grid points, all others lay between them */
00142   x1 = GridFit (MAX (0, drawn_area->X1), PCB->Grid, PCB->GridOffsetX);
00143   y1 = GridFit (MAX (0, drawn_area->Y1), PCB->Grid, PCB->GridOffsetY);
00144   x2 = GridFit (MIN (PCB->MaxWidth, drawn_area->X2), PCB->Grid, PCB->GridOffsetX);
00145   y2 = GridFit (MIN (PCB->MaxHeight, drawn_area->Y2), PCB->Grid, PCB->GridOffsetY);
00146 
00147   if (x1 > x2)
00148     {
00149       Coord tmp = x1;
00150       x1 = x2;
00151       x2 = tmp;
00152     }
00153 
00154   if (y1 > y2)
00155     {
00156       Coord tmp = y1;
00157       y1 = y2;
00158       y2 = tmp;
00159     }
00160 
00161   n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1; /* Number of points in one row */
00162   if (n > npoints)
00163     { /* [n]points are static, reallocate if we need more memory */
00164       npoints = n + 10;
00165       points = realloc (points, npoints * 3 * sizeof (GLfloat));
00166     }
00167 
00168   glEnableClientState (GL_VERTEX_ARRAY);
00169   glVertexPointer (3, GL_FLOAT, 0, points);
00170 
00171   n = 0;
00172   for (x = x1; x <= x2; x += PCB->Grid)
00173     { /* compute all the x coordinates */
00174       points[3 * n + 0] = x;
00175       points[3 * n + 2] = global_depth;
00176       n++;
00177     }
00178   for (y = y1; y <= y2; y += PCB->Grid)
00179     { /* reuse the row of points at each y */
00180       for (i = 0; i < n; i++)
00181         points[3 * i + 1] = y;
00182       /* draw all the points in a row for a given y */
00183       glDrawArrays (GL_POINTS, 0, n);
00184     }
00185 
00186   glDisableClientState (GL_VERTEX_ARRAY);
00187 }
00188 
00189 #define MAX_PIXELS_ARC_TO_CHORD 0.5
00190 #define MIN_SLICES 6
00191 int calc_slices (float pix_radius, float sweep_angle)
00192 {
00193   float slices;
00194 
00195   if (pix_radius <= MAX_PIXELS_ARC_TO_CHORD)
00196     return MIN_SLICES;
00197 
00198   slices = sweep_angle / acosf (1 - MAX_PIXELS_ARC_TO_CHORD / pix_radius) / 2.;
00199   return (int)ceilf (slices);
00200 }
00201 
00202 #define MIN_TRIANGLES_PER_CAP 3
00203 #define MAX_TRIANGLES_PER_CAP 90
00204 static void draw_cap (Coord width, Coord x, Coord y, Angle angle, double scale)
00205 {
00206   float last_capx, last_capy;
00207   float capx, capy;
00208   float radius = width / 2.;
00209   int slices = calc_slices (radius / scale, M_PI);
00210   int i;
00211 
00212   if (slices < MIN_TRIANGLES_PER_CAP)
00213     slices = MIN_TRIANGLES_PER_CAP;
00214 
00215   if (slices > MAX_TRIANGLES_PER_CAP)
00216     slices = MAX_TRIANGLES_PER_CAP;
00217 
00218   hidgl_ensure_triangle_space (&buffer, slices);
00219 
00220   last_capx =  radius * cosf (angle * M_PI / 180.) + x;
00221   last_capy = -radius * sinf (angle * M_PI / 180.) + y;
00222   for (i = 0; i < slices; i++) {
00223     capx =  radius * cosf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + x;
00224     capy = -radius * sinf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + y;
00225     hidgl_add_triangle (&buffer, last_capx, last_capy, capx, capy, x, y);
00226     last_capx = capx;
00227     last_capy = capy;
00228   }
00229 }
00230 
00231 void
00232 hidgl_draw_line (int cap, Coord width, Coord x1, Coord y1, Coord x2, Coord y2, double scale)
00233 {
00234   double angle;
00235   double deltax, deltay, length;
00236   float wdx, wdy;
00237   int circular_caps = 0;
00238   int hairline = 0;
00239 
00240   if (width == 0.0)
00241     hairline = 1;
00242 
00243   if (width < scale)
00244     width = scale;
00245 
00246   deltax = x2 - x1;
00247   deltay = y2 - y1;
00248 
00249   length = hypot (deltax, deltay);
00250 
00251   if (length == 0) {
00252     /* Assume the orientation of the line is horizontal */
00253     wdx = -width / 2.;
00254     wdy = 0;
00255     length = 1.;
00256     deltax = 1.;
00257     deltay = 0.;
00258   } else {
00259     wdy = deltax * width / 2. / length;
00260     wdx = -deltay * width / 2. / length;
00261   }
00262 
00263   angle = -180. / M_PI * atan2 (deltay, deltax);
00264 
00265   switch (cap) {
00266     case Trace_Cap:
00267     case Round_Cap:
00268       circular_caps = 1;
00269       break;
00270 
00271     case Square_Cap:
00272     case Beveled_Cap:
00273       x1 -= deltax * width / 2. / length;
00274       y1 -= deltay * width / 2. / length;
00275       x2 += deltax * width / 2. / length;
00276       y2 += deltay * width / 2. / length;
00277       break;
00278   }
00279 
00280   hidgl_ensure_triangle_space (&buffer, 2);
00281   hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
00282                                x2 - wdx, y2 - wdy,
00283                                x2 + wdx, y2 + wdy);
00284   hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
00285                                x2 + wdx, y2 + wdy,
00286                                x1 + wdx, y1 + wdy);
00287 
00288   /* Don't bother capping hairlines */
00289   if (circular_caps && !hairline)
00290     {
00291       draw_cap (width, x1, y1, angle + 90., scale);
00292       draw_cap (width, x2, y2, angle - 90., scale);
00293     }
00294 }
00295 
00296 #define MIN_SLICES_PER_ARC 6
00297 #define MAX_SLICES_PER_ARC 360
00298 void
00299 hidgl_draw_arc (Coord width, Coord x, Coord y, Coord rx, Coord ry,
00300                 Angle start_angle, Angle delta_angle, double scale)
00301 {
00302   float last_inner_x, last_inner_y;
00303   float last_outer_x, last_outer_y;
00304   float inner_x, inner_y;
00305   float outer_x, outer_y;
00306   float inner_r;
00307   float outer_r;
00308   float cos_ang, sin_ang;
00309   float start_angle_rad;
00310   float delta_angle_rad;
00311   float angle_incr_rad;
00312   int slices;
00313   int i;
00314   int hairline = 0;
00315 
00316   if (width == 0.0)
00317     hairline = 1;
00318 
00319   if (width < scale)
00320     width = scale;
00321 
00322   inner_r = rx - width / 2.;
00323   outer_r = rx + width / 2.;
00324 
00325   if (delta_angle < 0) {
00326     start_angle += delta_angle;
00327     delta_angle = - delta_angle;
00328   }
00329 
00330   start_angle_rad = start_angle * M_PI / 180.;
00331   delta_angle_rad = delta_angle * M_PI / 180.;
00332 
00333   slices = calc_slices ((rx + width / 2.) / scale, delta_angle_rad);
00334 
00335   if (slices < MIN_SLICES_PER_ARC)
00336     slices = MIN_SLICES_PER_ARC;
00337 
00338   if (slices > MAX_SLICES_PER_ARC)
00339     slices = MAX_SLICES_PER_ARC;
00340 
00341   hidgl_ensure_triangle_space (&buffer, 2 * slices);
00342 
00343   angle_incr_rad = delta_angle_rad / (float)slices;
00344 
00345   cos_ang = cosf (start_angle_rad);
00346   sin_ang = sinf (start_angle_rad);
00347   last_inner_x = -inner_r * cos_ang + x;  last_inner_y = inner_r * sin_ang + y;
00348   last_outer_x = -outer_r * cos_ang + x;  last_outer_y = outer_r * sin_ang + y;
00349   for (i = 1; i <= slices; i++) {
00350     cos_ang = cosf (start_angle_rad + ((float)(i)) * angle_incr_rad);
00351     sin_ang = sinf (start_angle_rad + ((float)(i)) * angle_incr_rad);
00352     inner_x = -inner_r * cos_ang + x;  inner_y = inner_r * sin_ang + y;
00353     outer_x = -outer_r * cos_ang + x;  outer_y = outer_r * sin_ang + y;
00354     hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
00355                                  last_outer_x, last_outer_y,
00356                                  outer_x, outer_y);
00357     hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
00358                                  inner_x, inner_y,
00359                                  outer_x, outer_y);
00360     last_inner_x = inner_x;  last_inner_y = inner_y;
00361     last_outer_x = outer_x;  last_outer_y = outer_y;
00362   }
00363 
00364   /* Don't bother capping hairlines */
00365   if (hairline)
00366     return;
00367 
00368   draw_cap (width, x + rx * -cosf (start_angle_rad),
00369                    y + rx *  sinf (start_angle_rad),
00370                    start_angle, scale);
00371   draw_cap (width, x + rx * -cosf (start_angle_rad + delta_angle_rad),
00372                    y + rx *  sinf (start_angle_rad + delta_angle_rad),
00373                    start_angle + delta_angle + 180., scale);
00374 }
00375 
00376 void
00377 hidgl_draw_rect (Coord x1, Coord y1, Coord x2, Coord y2)
00378 {
00379   glBegin (GL_LINE_LOOP);
00380   glVertex3f (x1, y1, global_depth);
00381   glVertex3f (x1, y2, global_depth);
00382   glVertex3f (x2, y2, global_depth);
00383   glVertex3f (x2, y1, global_depth);
00384   glEnd ();
00385 }
00386 
00387 
00388 void
00389 hidgl_fill_circle (Coord vx, Coord vy, Coord vr, double scale)
00390 {
00391 #define MIN_TRIANGLES_PER_CIRCLE 6
00392 #define MAX_TRIANGLES_PER_CIRCLE 360
00393   float last_x, last_y;
00394   float radius = vr;
00395   int slices;
00396   int i;
00397 
00398   slices = calc_slices (vr / scale, 2 * M_PI);
00399 
00400   if (slices < MIN_TRIANGLES_PER_CIRCLE)
00401     slices = MIN_TRIANGLES_PER_CIRCLE;
00402 
00403   if (slices > MAX_TRIANGLES_PER_CIRCLE)
00404     slices = MAX_TRIANGLES_PER_CIRCLE;
00405 
00406   hidgl_ensure_triangle_space (&buffer, slices);
00407 
00408   last_x = vx + vr;
00409   last_y = vy;
00410 
00411   for (i = 0; i < slices; i++) {
00412     float x, y;
00413     x = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
00414     y = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
00415     hidgl_add_triangle (&buffer, vx, vy, last_x, last_y, x, y);
00416     last_x = x;
00417     last_y = y;
00418   }
00419 }
00420 
00421 #define MAX_COMBINED_MALLOCS 2500
00422 static void *combined_to_free [MAX_COMBINED_MALLOCS];
00423 static int combined_num_to_free = 0;
00424 
00425 static GLenum tessVertexType;
00426 static int stashed_vertices;
00427 static int triangle_comp_idx;
00428 
00429 #ifndef CALLBACK
00430 #define CALLBACK
00431 #endif
00432 
00433 static void CALLBACK
00434 myError (GLenum errno)
00435 {
00436   printf ("gluTess error: %s\n", gluErrorString (errno));
00437 }
00438 
00439 static void CALLBACK
00440 myCombine ( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **dataOut )
00441 {
00442 #define MAX_COMBINED_VERTICES 2500
00443   static GLdouble combined_vertices [3 * MAX_COMBINED_VERTICES];
00444   static int num_combined_vertices = 0;
00445 
00446   GLdouble *new_vertex;
00447 
00448   if (num_combined_vertices < MAX_COMBINED_VERTICES)
00449     {
00450       new_vertex = &combined_vertices [3 * num_combined_vertices];
00451       num_combined_vertices ++;
00452     }
00453   else
00454     {
00455       new_vertex = malloc (3 * sizeof (GLdouble));
00456 
00457       if (combined_num_to_free < MAX_COMBINED_MALLOCS)
00458         combined_to_free [combined_num_to_free ++] = new_vertex;
00459       else
00460         printf ("myCombine leaking %lu bytes of memory\n",
00461                     (unsigned long)3 * sizeof (GLdouble));
00462     }
00463 
00464   new_vertex[0] = coords[0];
00465   new_vertex[1] = coords[1];
00466   new_vertex[2] = coords[2];
00467 
00468   *dataOut = new_vertex;
00469 }
00470 
00471 static void CALLBACK
00472 myBegin (GLenum type)
00473 {
00474   tessVertexType = type;
00475   stashed_vertices = 0;
00476   triangle_comp_idx = 0;
00477 }
00478 
00479 static double global_scale;
00480 
00481 static void CALLBACK
00482 myVertex (GLdouble *vertex_data)
00483 {
00484   static GLfloat triangle_vertices [2 * 3];
00485 
00486   if (tessVertexType == GL_TRIANGLE_STRIP ||
00487       tessVertexType == GL_TRIANGLE_FAN)
00488     {
00489       if (stashed_vertices < 2)
00490         {
00491           triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
00492           triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
00493           stashed_vertices ++;
00494         }
00495       else
00496         {
00497           hidgl_ensure_triangle_space (&buffer, 1);
00498           hidgl_add_triangle (&buffer,
00499                               triangle_vertices [0], triangle_vertices [1],
00500                               triangle_vertices [2], triangle_vertices [3],
00501                               vertex_data [0], vertex_data [1]);
00502 
00503           if (tessVertexType == GL_TRIANGLE_STRIP)
00504             {
00505               /* STRIP saves the last two vertices for re-use in the next triangle */
00506               triangle_vertices [0] = triangle_vertices [2];
00507               triangle_vertices [1] = triangle_vertices [3];
00508             }
00509           /* Both FAN and STRIP save the last vertex for re-use in the next triangle */
00510           triangle_vertices [2] = vertex_data [0];
00511           triangle_vertices [3] = vertex_data [1];
00512         }
00513     }
00514   else if (tessVertexType == GL_TRIANGLES)
00515     {
00516       triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
00517       triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
00518       stashed_vertices ++;
00519       if (stashed_vertices == 3)
00520         {
00521           hidgl_ensure_triangle_space (&buffer, 1);
00522           hidgl_add_triangle (&buffer,
00523                               triangle_vertices [0], triangle_vertices [1],
00524                               triangle_vertices [2], triangle_vertices [3],
00525                               triangle_vertices [4], triangle_vertices [5]);
00526           triangle_comp_idx = 0;
00527           stashed_vertices = 0;
00528         }
00529     }
00530   else
00531     printf ("Vertex received with unknown type\n");
00532 }
00533 
00534 static void
00535 myFreeCombined ()
00536 {
00537   while (combined_num_to_free)
00538     free (combined_to_free [-- combined_num_to_free]);
00539 }
00540 
00541 void
00542 hidgl_fill_polygon (int n_coords, Coord *x, Coord *y)
00543 {
00544   int i;
00545   GLUtesselator *tobj;
00546   GLdouble *vertices;
00547 
00548   assert (n_coords > 0);
00549 
00550   vertices = malloc (sizeof(GLdouble) * n_coords * 3);
00551 
00552   tobj = gluNewTess ();
00553   gluTessCallback(tobj, GLU_TESS_BEGIN,   (_GLUfuncptr)myBegin);
00554   gluTessCallback(tobj, GLU_TESS_VERTEX,  (_GLUfuncptr)myVertex);
00555   gluTessCallback(tobj, GLU_TESS_COMBINE, (_GLUfuncptr)myCombine);
00556   gluTessCallback(tobj, GLU_TESS_ERROR,   (_GLUfuncptr)myError);
00557 
00558   gluTessBeginPolygon (tobj, NULL);
00559   gluTessBeginContour (tobj);
00560 
00561   for (i = 0; i < n_coords; i++)
00562     {
00563       vertices [0 + i * 3] = x[i];
00564       vertices [1 + i * 3] = y[i];
00565       vertices [2 + i * 3] = 0.;
00566       gluTessVertex (tobj, &vertices [i * 3], &vertices [i * 3]);
00567     }
00568 
00569   gluTessEndContour (tobj);
00570   gluTessEndPolygon (tobj);
00571   gluDeleteTess (tobj);
00572 
00573   myFreeCombined ();
00574   free (vertices);
00575 }
00576 
00577 void
00578 tesselate_contour (GLUtesselator *tobj, PLINE *contour, GLdouble *vertices,
00579                    double scale)
00580 {
00581   VNODE *vn = &contour->head;
00582   int offset = 0;
00583 
00584   /* If the contour is round, and hidgl_fill_circle would use
00585    * less slices than we have vertices to draw it, then call
00586    * hidgl_fill_circle to draw this contour.
00587    */
00588   if (contour->is_round) {
00589     double slices = calc_slices (contour->radius / scale, 2 * M_PI);
00590     if (slices < contour->Count) {
00591       hidgl_fill_circle (contour->cx, contour->cy, contour->radius, scale);
00592       return;
00593     }
00594   }
00595 
00596   gluTessBeginPolygon (tobj, NULL);
00597   gluTessBeginContour (tobj);
00598   do {
00599     vertices [0 + offset] = vn->point[0];
00600     vertices [1 + offset] = vn->point[1];
00601     vertices [2 + offset] = 0.;
00602     gluTessVertex (tobj, &vertices [offset], &vertices [offset]);
00603     offset += 3;
00604   } while ((vn = vn->next) != &contour->head);
00605   gluTessEndContour (tobj);
00606   gluTessEndPolygon (tobj);
00607 }
00608 
00609 struct do_hole_info {
00610   GLUtesselator *tobj;
00611   GLdouble *vertices;
00612   double scale;
00613 };
00614 
00615 static int
00616 do_hole (const BoxType *b, void *cl)
00617 {
00618   struct do_hole_info *info = cl;
00619   PLINE *curc = (PLINE *) b;
00620 
00621   /* Ignore the outer contour - we draw it first explicitly*/
00622   if (curc->Flags.orient == PLF_DIR) {
00623     return 0;
00624   }
00625 
00626   tesselate_contour (info->tobj, curc, info->vertices, info->scale);
00627   return 1;
00628 }
00629 
00630 static GLint stencil_bits;
00631 static int dirty_bits = 0;
00632 static int assigned_bits = 0;
00633 
00634 static void
00635 fill_polyarea (POLYAREA *pa, const BoxType *clip_box, double scale)
00636 {
00637   int vertex_count = 0;
00638   PLINE *contour;
00639   struct do_hole_info info;
00640   int stencil_bit;
00641 
00642   info.scale = scale;
00643   global_scale = scale;
00644 
00645   stencil_bit = hidgl_assign_clear_stencil_bit ();
00646   if (!stencil_bit)
00647     {
00648       printf ("hidgl_fill_pcb_polygon: No free stencil bits, aborting polygon\n");
00649       return;
00650     }
00651 
00652   /* Flush out any existing geoemtry to be rendered */
00653   hidgl_flush_triangles (&buffer);
00654 
00655   /* Walk the polygon structure, counting vertices */
00656   /* This gives an upper bound on the amount of storage required */
00657   for (contour = pa->contours; contour != NULL; contour = contour->next)
00658     vertex_count = MAX (vertex_count, contour->Count);
00659 
00660   info.vertices = malloc (sizeof(GLdouble) * vertex_count * 3);
00661   info.tobj = gluNewTess ();
00662   gluTessCallback(info.tobj, GLU_TESS_BEGIN,   (_GLUfuncptr)myBegin);
00663   gluTessCallback(info.tobj, GLU_TESS_VERTEX,  (_GLUfuncptr)myVertex);
00664   gluTessCallback(info.tobj, GLU_TESS_COMBINE, (_GLUfuncptr)myCombine);
00665   gluTessCallback(info.tobj, GLU_TESS_ERROR,   (_GLUfuncptr)myError);
00666 
00667   glPushAttrib (GL_STENCIL_BUFFER_BIT);                 /* Save the write mask etc.. for final restore */
00668   glEnable (GL_STENCIL_TEST);
00669   glPushAttrib (GL_STENCIL_BUFFER_BIT |                 /* Resave the stencil write-mask etc.., and */
00670                 GL_COLOR_BUFFER_BIT);                   /* the colour buffer write mask etc.. for part way restore */
00671   glStencilMask (stencil_bit);                          /* Only write to our stencil bit */
00672   glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit);  /* Always pass stencil test, ref value is our bit */
00673   glColorMask (0, 0, 0, 0);                             /* Disable writting in color buffer */
00674 
00675   glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);           /* Stencil pass => replace stencil value */
00676 
00677   /* Drawing operations now set our reference bit in the stencil buffer */
00678 
00679   r_search (pa->contour_tree, clip_box, NULL, do_hole, &info);
00680   hidgl_flush_triangles (&buffer);
00681 
00682   glPopAttrib ();                               /* Restore the colour and stencil buffer write-mask etc.. */
00683 
00684   glStencilOp (GL_KEEP, GL_KEEP, GL_INVERT);    /* This allows us to toggle the bit on any subcompositing bitplane */
00685                                                 /* If the stencil test has passed, we know that bit is 0, so we're */
00686                                                 /* effectively just setting it to 1. */
00687 
00688   glStencilFunc (GL_GEQUAL, 0, assigned_bits);  /* Pass stencil test if all assigned bits clear, */
00689                                                 /* reference is all assigned bits so we set */
00690                                                 /* any bits permitted by the stencil writemask */
00691 
00692   /* Drawing operations as masked to areas where the stencil buffer is '0' */
00693 
00694   /* Draw the polygon outer */
00695   tesselate_contour (info.tobj, pa->contours, info.vertices, scale);
00696 
00697   hidgl_flush_triangles (&buffer);
00698 
00699   /* Unassign our stencil buffer bit */
00700   hidgl_return_stencil_bit (stencil_bit);
00701 
00702   glPopAttrib ();                               /* Restore the stencil buffer write-mask etc.. */
00703 
00704   gluDeleteTess (info.tobj);
00705   myFreeCombined ();
00706   free (info.vertices);
00707 }
00708 
00709 void
00710 hidgl_fill_pcb_polygon (PolygonType *poly, const BoxType *clip_box, double scale)
00711 {
00712   if (poly->Clipped == NULL)
00713     return;
00714 
00715   fill_polyarea (poly->Clipped, clip_box, scale);
00716 
00717   if (TEST_FLAG (FULLPOLYFLAG, poly))
00718     {
00719       POLYAREA *pa;
00720 
00721       for (pa = poly->Clipped->f; pa != poly->Clipped; pa = pa->f)
00722         fill_polyarea (pa, clip_box, scale);
00723     }
00724 }
00725 
00726 void
00727 hidgl_fill_rect (Coord x1, Coord y1, Coord x2, Coord y2)
00728 {
00729   hidgl_ensure_triangle_space (&buffer, 2);
00730   hidgl_add_triangle (&buffer, x1, y1, x1, y2, x2, y2);
00731   hidgl_add_triangle (&buffer, x2, y1, x2, y2, x1, y1);
00732 }
00733 
00734 void
00735 hidgl_init (void)
00736 {
00737   glGetIntegerv (GL_STENCIL_BITS, &stencil_bits);
00738 
00739   if (stencil_bits == 0)
00740     {
00741       printf ("No stencil bits available.\n"
00742               "Cannot mask polygon holes or subcomposite layers\n");
00743       /* TODO: Flag this to the HID so it can revert to the dicer? */
00744     }
00745   else if (stencil_bits == 1)
00746     {
00747       printf ("Only one stencil bitplane available\n"
00748               "Cannot use stencil buffer to sub-composite layers.\n");
00749       /* Do we need to disable that somewhere? */
00750     }
00751 }
00752 
00753 void
00754 hidgl_start_render (void)
00755 {
00756   hidgl_init ();
00757   hidgl_init_triangle_array (&buffer);
00758 }
00759 
00760 void
00761 hidgl_finish_render (void)
00762 {
00763 }
00764 
00765 int
00766 hidgl_stencil_bits (void)
00767 {
00768   return stencil_bits;
00769 }
00770 
00771 static void
00772 hidgl_clean_unassigned_stencil (void)
00773 {
00774   glPushAttrib (GL_STENCIL_BUFFER_BIT);
00775   glStencilMask (~assigned_bits);
00776   glClearStencil (0);
00777   glClear (GL_STENCIL_BUFFER_BIT);
00778   glPopAttrib ();
00779 }
00780 
00781 int
00782 hidgl_assign_clear_stencil_bit (void)
00783 {
00784   int stencil_bitmask = (1 << stencil_bits) - 1;
00785   int test;
00786   int first_dirty = 0;
00787 
00788   if (assigned_bits == stencil_bitmask)
00789     {
00790       printf ("No more stencil bits available, total of %i already assigned\n",
00791               stencil_bits);
00792       return 0;
00793     }
00794 
00795   /* Look for a bitplane we don't have to clear */
00796   for (test = 1; test & stencil_bitmask; test <<= 1)
00797     {
00798       if (!(test & dirty_bits))
00799         {
00800           assigned_bits |= test;
00801           dirty_bits |= test;
00802           return test;
00803         }
00804       else if (!first_dirty && !(test & assigned_bits))
00805         {
00806           first_dirty = test;
00807         }
00808     }
00809 
00810   /* Didn't find any non dirty planes. Clear those dirty ones which aren't in use */
00811   hidgl_clean_unassigned_stencil ();
00812   assigned_bits |= first_dirty;
00813   dirty_bits = assigned_bits;
00814 
00815   return first_dirty;
00816 }
00817 
00818 void
00819 hidgl_return_stencil_bit (int bit)
00820 {
00821   assigned_bits &= ~bit;
00822 }
00823 
00824 void
00825 hidgl_reset_stencil_usage (void)
00826 {
00827   assigned_bits = 0;
00828   dirty_bits = 0;
00829 }