pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }