pcb 4.1.1
An interactive printed circuit board layout editor.

gtkhid-gl.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <stdio.h>
00006 
00007 #include "crosshair.h"
00008 #include "clip.h"
00009 #include "../hidint.h"
00010 #include "gui.h"
00011 #include "gui-pinout-preview.h"
00012 
00013 /* The Linux OpenGL ABI 1.0 spec requires that we define
00014  * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
00015  * in order to get prototypes:
00016  *   http://www.opengl.org/registry/ABI/
00017  */
00018 #define GL_GLEXT_PROTOTYPES 1
00019 
00020 /* This follows autoconf's recommendation for the AX_CHECK_GL macro
00021    https://www.gnu.org/software/autoconf-archive/ax_check_gl.html */
00022 #if defined HAVE_WINDOWS_H && defined _WIN32
00023 #  include <windows.h>
00024 #endif
00025 #if defined HAVE_GL_GL_H
00026 #  include <GL/gl.h>
00027 #elif defined HAVE_OPENGL_GL_H
00028 #  include <OpenGL/gl.h>
00029 #else
00030 #  error autoconf couldnt find gl.h
00031 #endif
00032 
00033 #include <gtk/gtkgl.h>
00034 #include "hid/common/hidgl.h"
00035 
00036 #include "hid/common/draw_helpers.h"
00037 #include "hid/common/trackball.h"
00038 
00039 #ifdef HAVE_LIBDMALLOC
00040 #include <dmalloc.h>
00041 #endif
00042 
00043 extern HID ghid_hid;
00044 extern HID_DRAW ghid_graphics;
00045 
00046 static hidGC current_gc = NULL;
00047 
00048 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
00049 */
00050 #define USE_GC(gc) if (!use_gc(gc)) return
00051 
00052 static enum mask_mode cur_mask = HID_MASK_OFF;
00053 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
00054                                     {0.0, 1.0, 0.0, 0.0},
00055                                     {0.0, 0.0, 1.0, 0.0},
00056                                     {0.0, 0.0, 0.0, 1.0}};
00057 static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
00058                                               {0.0, 1.0, 0.0, 0.0},
00059                                               {0.0, 0.0, 1.0, 0.0},
00060                                               {0.0, 0.0, 0.0, 1.0}};
00061 static int global_view_2d = 1;
00062 
00063 typedef struct render_priv {
00064   GdkGLConfig *glconfig;
00065   bool trans_lines;
00066   bool in_context;
00067   int subcomposite_stencil_bit;
00068   char *current_colorname;
00069   double current_alpha_mult;
00070   GTimer *time_since_expose;
00071 
00072   /* Feature for leading the user to a particular location */
00073   guint lead_user_timeout;
00074   GTimer *lead_user_timer;
00075   bool lead_user;
00076   Coord lead_user_radius;
00077   Coord lead_user_x;
00078   Coord lead_user_y;
00079 
00080   hidGC crosshair_gc;
00081 } render_priv;
00082 
00083 
00084 typedef struct hid_gc_struct
00085 {
00086   HID *me_pointer;
00087 
00088   const char *colorname;
00089   double alpha_mult;
00090   Coord width;
00091   gint cap, join;
00092 }
00093 hid_gc_struct;
00094 
00095 
00096 static void draw_lead_user (render_priv *priv);
00097 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
00098 
00099 
00100 static void
00101 start_subcomposite (void)
00102 {
00103   render_priv *priv = gport->render_priv;
00104   int stencil_bit;
00105 
00106   /* Flush out any existing geoemtry to be rendered */
00107   hidgl_flush_triangles (&buffer);
00108 
00109   glEnable (GL_STENCIL_TEST);                                 /* Enable Stencil test */
00110   glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);                 /* Stencil pass => replace stencil value (with 1) */
00111 
00112   stencil_bit = hidgl_assign_clear_stencil_bit();             /* Get a new (clean) bitplane to stencil with */
00113   glStencilMask (stencil_bit);                                /* Only write to our subcompositing stencil bitplane */
00114   glStencilFunc (GL_GREATER, stencil_bit, stencil_bit);       /* Pass stencil test if our assigned bit is clear */
00115 
00116   priv->subcomposite_stencil_bit = stencil_bit;
00117 }
00118 
00119 static void
00120 end_subcomposite (void)
00121 {
00122   render_priv *priv = gport->render_priv;
00123 
00124   /* Flush out any existing geoemtry to be rendered */
00125   hidgl_flush_triangles (&buffer);
00126 
00127   hidgl_return_stencil_bit (priv->subcomposite_stencil_bit);  /* Relinquish any bitplane we previously used */
00128 
00129   glStencilMask (0);
00130   glStencilFunc (GL_ALWAYS, 0, 0);                            /* Always pass stencil test */
00131   glDisable (GL_STENCIL_TEST);                                /* Disable Stencil test */
00132 
00133   priv->subcomposite_stencil_bit = 0;
00134 }
00135 
00136 
00137 int
00138 ghid_set_layer (const char *name, int group, int empty)
00139 {
00140   render_priv *priv = gport->render_priv;
00141   int idx = group;
00142   if (idx >= 0 && idx < max_group)
00143     {
00144       int n = PCB->LayerGroups.Number[group];
00145       for (idx = 0; idx < n-1; idx ++)
00146         {
00147           int ni = PCB->LayerGroups.Entries[group][idx];
00148           if (ni >= 0 && ni < max_copper_layer + SILK_LAYER
00149               && PCB->Data->Layer[ni].On)
00150             break;
00151         }
00152       idx = PCB->LayerGroups.Entries[group][idx];
00153   }
00154 
00155   end_subcomposite ();
00156   start_subcomposite ();
00157 
00158   if (idx >= 0 && idx < max_copper_layer + SILK_LAYER)
00159     {
00160       priv->trans_lines = true;
00161       return PCB->Data->Layer[idx].On;
00162     }
00163   if (idx < 0)
00164     {
00165       switch (SL_TYPE (idx))
00166         {
00167         case SL_INVISIBLE:
00168           return PCB->InvisibleObjectsOn;
00169         case SL_MASK:
00170           if (SL_MYSIDE (idx))
00171             return TEST_FLAG (SHOWMASKFLAG, PCB);
00172           return 0;
00173         case SL_SILK:
00174           priv->trans_lines = true;
00175           if (SL_MYSIDE (idx))
00176             return PCB->ElementOn;
00177           return 0;
00178         case SL_ASSY:
00179           return 0;
00180         case SL_PDRILL:
00181         case SL_UDRILL:
00182           return 1;
00183         case SL_RATS:
00184           if (PCB->RatOn)
00185             priv->trans_lines = true;
00186           return PCB->RatOn;
00187         }
00188     }
00189   return 0;
00190 }
00191 
00192 static void
00193 ghid_end_layer (void)
00194 {
00195   end_subcomposite ();
00196 }
00197 
00198 void
00199 ghid_destroy_gc (hidGC gc)
00200 {
00201   g_free (gc);
00202 }
00203 
00204 hidGC
00205 ghid_make_gc (void)
00206 {
00207   hidGC rv;
00208 
00209   rv = g_new0 (hid_gc_struct, 1);
00210   rv->me_pointer = &ghid_hid;
00211   rv->colorname = Settings.BackgroundColor;
00212   rv->alpha_mult = 1.0;
00213   return rv;
00214 }
00215 
00216 void
00217 ghid_draw_grid (BoxType *drawn_area)
00218 {
00219   if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
00220     return;
00221 
00222   if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
00223     {
00224       gport->grid_color.red ^= gport->bg_color.red;
00225       gport->grid_color.green ^= gport->bg_color.green;
00226       gport->grid_color.blue ^= gport->bg_color.blue;
00227     }
00228 
00229   glEnable (GL_COLOR_LOGIC_OP);
00230   glLogicOp (GL_XOR);
00231 
00232   glColor3f (gport->grid_color.red / 65535.,
00233              gport->grid_color.green / 65535.,
00234              gport->grid_color.blue / 65535.);
00235 
00236   hidgl_draw_grid (drawn_area);
00237 
00238   glDisable (GL_COLOR_LOGIC_OP);
00239 }
00240 
00241 static void
00242 ghid_draw_bg_image (void)
00243 {
00244   static GLuint texture_handle = 0;
00245 
00246   if (!ghidgui->bg_pixbuf)
00247     return;
00248 
00249   if (texture_handle == 0)
00250     {
00251       int width =             gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
00252       int height =            gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
00253       int rowstride =         gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
00254       int bits_per_sample =   gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
00255       int n_channels =        gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
00256       unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
00257 
00258       g_warn_if_fail (bits_per_sample == 8);
00259       g_warn_if_fail (rowstride == width * n_channels);
00260 
00261       glGenTextures (1, &texture_handle);
00262       glBindTexture (GL_TEXTURE_2D, texture_handle);
00263 
00264       /* XXX: We should proabbly determine what the maxmimum texture supported is,
00265        *      and if our image is larger, shrink it down using GDK pixbuf routines
00266        *      rather than having it fail below.
00267        */
00268 
00269       glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
00270                     (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
00271     }
00272 
00273   glBindTexture (GL_TEXTURE_2D, texture_handle);
00274 
00275   glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
00276   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00277   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00278   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00279   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00280   glEnable (GL_TEXTURE_2D);
00281 
00282   /* Render a quad with the background as a texture */
00283 
00284   glBegin (GL_QUADS);
00285   glTexCoord2d (0., 0.);
00286   glVertex3i (0,             0,              0);
00287   glTexCoord2d (1., 0.);
00288   glVertex3i (PCB->MaxWidth, 0,              0);
00289   glTexCoord2d (1., 1.);
00290   glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
00291   glTexCoord2d (0., 1.);
00292   glVertex3i (0,             PCB->MaxHeight, 0);
00293   glEnd ();
00294 
00295   glDisable (GL_TEXTURE_2D);
00296 }
00297 
00298 void
00299 ghid_use_mask (enum mask_mode mode)
00300 {
00301   static int stencil_bit = 0;
00302 
00303   if (mode == cur_mask)
00304     return;
00305 
00306   /* Flush out any existing geoemtry to be rendered */
00307   hidgl_flush_triangles (&buffer);
00308 
00309   switch (mode)
00310     {
00311     case HID_MASK_BEFORE:
00312       /* The HID asks not to receive this mask type, so warn if we get it */
00313       g_return_if_reached ();
00314 
00315     case HID_MASK_CLEAR:
00316       /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
00317       glColorMask (0, 0, 0, 0);                             /* Disable writting in color buffer */
00318       glEnable (GL_STENCIL_TEST);                           /* Enable Stencil test */
00319       stencil_bit = hidgl_assign_clear_stencil_bit();       /* Get a new (clean) bitplane to stencil with */
00320       glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit);  /* Always pass stencil test, write stencil_bit */
00321       glStencilMask (stencil_bit);                          /* Only write to our subcompositing stencil bitplane */
00322       glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);           /* Stencil pass => replace stencil value (with 1) */
00323       break;
00324 
00325     case HID_MASK_AFTER:
00326       /* Drawing operations as masked to areas where the stencil buffer is '0' */
00327       glColorMask (1, 1, 1, 1);                   /* Enable drawing of r, g, b & a */
00328       glStencilFunc (GL_GEQUAL, 0, stencil_bit);  /* Draw only where our bit of the stencil buffer is clear */
00329       glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);    /* Stencil buffer read only */
00330       break;
00331 
00332     case HID_MASK_OFF:
00333       /* Disable stenciling */
00334       hidgl_return_stencil_bit (stencil_bit);     /* Relinquish any bitplane we previously used */
00335       glDisable (GL_STENCIL_TEST);                /* Disable Stencil test */
00336       break;
00337     }
00338   cur_mask = mode;
00339 }
00340 
00341 
00342   /* Config helper functions for when the user changes color preferences.
00343      |  set_special colors used in the gtkhid.
00344    */
00345 static void
00346 set_special_grid_color (void)
00347 {
00348   if (!gport->colormap)
00349     return;
00350   gport->grid_color.red ^= gport->bg_color.red;
00351   gport->grid_color.green ^= gport->bg_color.green;
00352   gport->grid_color.blue ^= gport->bg_color.blue;
00353 }
00354 
00355 void
00356 ghid_set_special_colors (HID_Attribute * ha)
00357 {
00358   if (!ha->name || !ha->value)
00359     return;
00360   if (!strcmp (ha->name, "background-color"))
00361     {
00362       ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
00363       set_special_grid_color ();
00364     }
00365   else if (!strcmp (ha->name, "off-limit-color"))
00366   {
00367       ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
00368     }
00369   else if (!strcmp (ha->name, "grid-color"))
00370     {
00371       ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
00372       set_special_grid_color ();
00373     }
00374 }
00375 
00376 typedef struct
00377 {
00378   int color_set;
00379   GdkColor color;
00380   double red;
00381   double green;
00382   double blue;
00383 } ColorCache;
00384 
00385 static void
00386 set_gl_color_for_gc (hidGC gc)
00387 {
00388   render_priv *priv = gport->render_priv;
00389   static void *cache = NULL;
00390   hidval cval;
00391   ColorCache *cc;
00392   double r, g, b, a;
00393 
00394   if (priv->current_colorname != NULL &&
00395       strcmp (priv->current_colorname, gc->colorname) == 0 &&
00396       priv->current_alpha_mult == gc->alpha_mult)
00397     return;
00398 
00399   free (priv->current_colorname);
00400   priv->current_colorname = strdup (gc->colorname);
00401   priv->current_alpha_mult = gc->alpha_mult;
00402 
00403   if (gport->colormap == NULL)
00404     gport->colormap = gtk_widget_get_colormap (gport->top_window);
00405   if (strcmp (gc->colorname, "erase") == 0)
00406     {
00407       r = gport->bg_color.red   / 65535.;
00408       g = gport->bg_color.green / 65535.;
00409       b = gport->bg_color.blue  / 65535.;
00410       a = 1.0;
00411     }
00412   else if (strcmp (gc->colorname, "drill") == 0)
00413     {
00414       r = gport->offlimits_color.red   / 65535.;
00415       g = gport->offlimits_color.green / 65535.;
00416       b = gport->offlimits_color.blue  / 65535.;
00417       a = 0.85;
00418     }
00419   else
00420     {
00421       if (hid_cache_color (0, gc->colorname, &cval, &cache))
00422         cc = (ColorCache *) cval.ptr;
00423       else
00424         {
00425           cc = (ColorCache *) malloc (sizeof (ColorCache));
00426           memset (cc, 0, sizeof (*cc));
00427           cval.ptr = cc;
00428           hid_cache_color (1, gc->colorname, &cval, &cache);
00429         }
00430 
00431       if (!cc->color_set)
00432         {
00433           if (gdk_color_parse (gc->colorname, &cc->color))
00434             gdk_color_alloc (gport->colormap, &cc->color);
00435           else
00436             gdk_color_white (gport->colormap, &cc->color);
00437           cc->red   = cc->color.red   / 65535.;
00438           cc->green = cc->color.green / 65535.;
00439           cc->blue  = cc->color.blue  / 65535.;
00440           cc->color_set = 1;
00441         }
00442       r = cc->red;
00443       g = cc->green;
00444       b = cc->blue;
00445       a = 0.7;
00446     }
00447   if (1) {
00448     double maxi, mult;
00449     a *= gc->alpha_mult;
00450     if (!priv->trans_lines)
00451       a = 1.0;
00452     maxi = r;
00453     if (g > maxi) maxi = g;
00454     if (b > maxi) maxi = b;
00455     mult = MIN (1 / a, 1 / maxi);
00456 #if 1
00457     r = r * mult;
00458     g = g * mult;
00459     b = b * mult;
00460 #endif
00461   }
00462 
00463   if(!priv->in_context)
00464     return;
00465 
00466   hidgl_flush_triangles (&buffer);
00467   glColor4d (r, g, b, a);
00468 }
00469 
00470 void
00471 ghid_set_color (hidGC gc, const char *name)
00472 {
00473   gc->colorname = name;
00474   set_gl_color_for_gc (gc);
00475 }
00476 
00477 void
00478 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
00479 {
00480   gc->alpha_mult = alpha_mult;
00481   set_gl_color_for_gc (gc);
00482 }
00483 
00484 void
00485 ghid_set_line_cap (hidGC gc, EndCapStyle style)
00486 {
00487   gc->cap = style;
00488 }
00489 
00490 void
00491 ghid_set_line_width (hidGC gc, Coord width)
00492 {
00493   gc->width = width;
00494 }
00495 
00496 
00497 void
00498 ghid_set_draw_xor (hidGC gc, int xor)
00499 {
00500   /* NOT IMPLEMENTED */
00501 
00502   /* Only presently called when setting up a crosshair GC.
00503    * We manage our own drawing model for that anyway. */
00504 }
00505 
00506 void
00507 ghid_set_draw_faded (hidGC gc, int faded)
00508 {
00509   printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
00510 }
00511 
00512 void
00513 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
00514 {
00515   printf ("ghid_set_line_cap_angle() -- not implemented\n");
00516 }
00517 
00518 static void
00519 ghid_invalidate_current_gc (void)
00520 {
00521   current_gc = NULL;
00522 }
00523 
00524 static int
00525 use_gc (hidGC gc)
00526 {
00527   if (gc->me_pointer != &ghid_hid)
00528     {
00529       fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
00530       abort ();
00531     }
00532 
00533   if (current_gc == gc)
00534     return 1;
00535 
00536   current_gc = gc;
00537 
00538   set_gl_color_for_gc (gc);
00539   return 1;
00540 }
00541 
00542 void
00543 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
00544 {
00545   USE_GC (gc);
00546 
00547   hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
00548 }
00549 
00550 void
00551 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
00552                          Angle start_angle, Angle delta_angle)
00553 {
00554   USE_GC (gc);
00555 
00556   hidgl_draw_arc (gc->width, cx, cy, xradius, yradius,
00557                   start_angle, delta_angle, gport->view.coord_per_px);
00558 }
00559 
00560 void
00561 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
00562 {
00563   USE_GC (gc);
00564 
00565   hidgl_draw_rect (x1, y1, x2, y2);
00566 }
00567 
00568 
00569 void
00570 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
00571 {
00572   USE_GC (gc);
00573 
00574   hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px);
00575 }
00576 
00577 
00578 void
00579 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
00580 {
00581   USE_GC (gc);
00582 
00583   hidgl_fill_polygon (n_coords, x, y);
00584 }
00585 
00586 void
00587 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
00588 {
00589   USE_GC (gc);
00590 
00591   hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px);
00592 }
00593 
00594 void
00595 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
00596 {
00597   common_thindraw_pcb_polygon (gc, poly, clip_box);
00598   ghid_set_alpha_mult (gc, 0.25);
00599   gui->graphics->fill_pcb_polygon (gc, poly, clip_box);
00600   ghid_set_alpha_mult (gc, 1.0);
00601 }
00602 
00603 void
00604 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
00605 {
00606   USE_GC (gc);
00607 
00608   hidgl_fill_rect (x1, y1, x2, y2);
00609 }
00610 
00611 void
00612 ghid_invalidate_lr (Coord left, Coord right, Coord top, Coord bottom)
00613 {
00614   ghid_invalidate_all ();
00615 }
00616 
00617 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
00618 void
00619 ghid_invalidate_all ()
00620 {
00621   render_priv *priv = gport->render_priv;
00622   double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
00623 
00624   ghid_draw_area_update (gport, NULL);
00625 
00626   if (elapsed > MAX_ELAPSED)
00627     gdk_window_process_all_updates ();
00628 }
00629 
00630 void
00631 ghid_notify_crosshair_change (bool changes_complete)
00632 {
00633   /* We sometimes get called before the GUI is up */
00634   if (gport->drawing_area == NULL)
00635     return;
00636 
00637   /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
00638   if (changes_complete) ghid_invalidate_all ();
00639 }
00640 
00641 void
00642 ghid_notify_mark_change (bool changes_complete)
00643 {
00644   /* We sometimes get called before the GUI is up */
00645   if (gport->drawing_area == NULL)
00646     return;
00647 
00648   /* FIXME: We could just invalidate the bounds of the mark? */
00649   if (changes_complete) ghid_invalidate_all ();
00650 }
00651 
00652 static void
00653 draw_right_cross (gint x, gint y, gint z)
00654 {
00655   glVertex3i (x, 0, z);
00656   glVertex3i (x, PCB->MaxHeight, z);
00657   glVertex3i (0, y, z);
00658   glVertex3i (PCB->MaxWidth, y, z);
00659 }
00660 
00661 static void
00662 draw_slanted_cross (gint x, gint y, gint z)
00663 {
00664   gint x0, y0, x1, y1;
00665 
00666   x0 = x + (PCB->MaxHeight - y);
00667   x0 = MAX(0, MIN (x0, PCB->MaxWidth));
00668   x1 = x - y;
00669   x1 = MAX(0, MIN (x1, PCB->MaxWidth));
00670   y0 = y + (PCB->MaxWidth - x);
00671   y0 = MAX(0, MIN (y0, PCB->MaxHeight));
00672   y1 = y - x;
00673   y1 = MAX(0, MIN (y1, PCB->MaxHeight));
00674   glVertex3i (x0, y0, z);
00675   glVertex3i (x1, y1, z);
00676 
00677   x0 = x - (PCB->MaxHeight - y);
00678   x0 = MAX(0, MIN (x0, PCB->MaxWidth));
00679   x1 = x + y;
00680   x1 = MAX(0, MIN (x1, PCB->MaxWidth));
00681   y0 = y + x;
00682   y0 = MAX(0, MIN (y0, PCB->MaxHeight));
00683   y1 = y - (PCB->MaxWidth - x);
00684   y1 = MAX(0, MIN (y1, PCB->MaxHeight));
00685   glVertex3i (x0, y0, z);
00686   glVertex3i (x1, y1, z);
00687 }
00688 
00689 static void
00690 draw_dozen_cross (gint x, gint y, gint z)
00691 {
00692   gint x0, y0, x1, y1;
00693   gdouble tan60 = sqrt (3);
00694 
00695   x0 = x + (PCB->MaxHeight - y) / tan60;
00696   x0 = MAX(0, MIN (x0, PCB->MaxWidth));
00697   x1 = x - y / tan60;
00698   x1 = MAX(0, MIN (x1, PCB->MaxWidth));
00699   y0 = y + (PCB->MaxWidth - x) * tan60;
00700   y0 = MAX(0, MIN (y0, PCB->MaxHeight));
00701   y1 = y - x * tan60;
00702   y1 = MAX(0, MIN (y1, PCB->MaxHeight));
00703   glVertex3i (x0, y0, z);
00704   glVertex3i (x1, y1, z);
00705 
00706   x0 = x + (PCB->MaxHeight - y) * tan60;
00707   x0 = MAX(0, MIN (x0, PCB->MaxWidth));
00708   x1 = x - y * tan60;
00709   x1 = MAX(0, MIN (x1, PCB->MaxWidth));
00710   y0 = y + (PCB->MaxWidth - x) / tan60;
00711   y0 = MAX(0, MIN (y0, PCB->MaxHeight));
00712   y1 = y - x / tan60;
00713   y1 = MAX(0, MIN (y1, PCB->MaxHeight));
00714   glVertex3i (x0, y0, z);
00715   glVertex3i (x1, y1, z);
00716 
00717   x0 = x - (PCB->MaxHeight - y) / tan60;
00718   x0 = MAX(0, MIN (x0, PCB->MaxWidth));
00719   x1 = x + y / tan60;
00720   x1 = MAX(0, MIN (x1, PCB->MaxWidth));
00721   y0 = y + x * tan60;
00722   y0 = MAX(0, MIN (y0, PCB->MaxHeight));
00723   y1 = y - (PCB->MaxWidth - x) * tan60;
00724   y1 = MAX(0, MIN (y1, PCB->MaxHeight));
00725   glVertex3i (x0, y0, z);
00726   glVertex3i (x1, y1, z);
00727 
00728   x0 = x - (PCB->MaxHeight - y) * tan60;
00729   x0 = MAX(0, MIN (x0, PCB->MaxWidth));
00730   x1 = x + y * tan60;
00731   x1 = MAX(0, MIN (x1, PCB->MaxWidth));
00732   y0 = y + x / tan60;
00733   y0 = MAX(0, MIN (y0, PCB->MaxHeight));
00734   y1 = y - (PCB->MaxWidth - x) / tan60;
00735   y1 = MAX(0, MIN (y1, PCB->MaxHeight));
00736   glVertex3i (x0, y0, z);
00737   glVertex3i (x1, y1, z);
00738 }
00739 
00740 static void
00741 draw_crosshair (render_priv *priv)
00742 {
00743   gint x, y, z;
00744   static int done_once = 0;
00745   static GdkColor cross_color;
00746 
00747   if (!done_once)
00748     {
00749       done_once = 1;
00750       /* FIXME: when CrossColor changed from config */
00751       ghid_map_color_string (Settings.CrossColor, &cross_color);
00752     }
00753 
00754   x = gport->crosshair_x;
00755   y = gport->crosshair_y;
00756   z = 0;
00757 
00758   glEnable (GL_COLOR_LOGIC_OP);
00759   glLogicOp (GL_XOR);
00760 
00761   glColor3f (cross_color.red / 65535.,
00762              cross_color.green / 65535.,
00763              cross_color.blue / 65535.);
00764 
00765   glBegin (GL_LINES);
00766 
00767   draw_right_cross (x, y, z);
00768   if (Crosshair.shape == Union_Jack_Crosshair_Shape)
00769     draw_slanted_cross (x, y, z);
00770   if (Crosshair.shape == Dozen_Crosshair_Shape)
00771     draw_dozen_cross (x, y, z);
00772 
00773   glEnd ();
00774 
00775   glDisable (GL_COLOR_LOGIC_OP);
00776 }
00777 
00778 void
00779 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
00780 {
00781   render_priv *priv;
00782 
00783   port->render_priv = priv = g_new0 (render_priv, 1);
00784   port->render_priv->crosshair_gc = gui->graphics->make_gc ();
00785 
00786   priv->time_since_expose = g_timer_new ();
00787 
00788   gtk_gl_init(argc, argv);
00789 
00790   /* setup GL-context */
00791   priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA    |
00792                                               GDK_GL_MODE_STENCIL |
00793                                               GDK_GL_MODE_DOUBLE);
00794   if (!priv->glconfig)
00795     {
00796       printf ("Could not setup GL-context!\n");
00797       return; /* Should we abort? */
00798     }
00799 
00800   /* Setup HID function pointers specific to the GL renderer*/
00801   ghid_hid.end_layer = ghid_end_layer;
00802   ghid_graphics.fill_pcb_polygon = ghid_fill_pcb_polygon;
00803   ghid_graphics.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
00804 }
00805 
00806 void
00807 ghid_shutdown_renderer (GHidPort *port)
00808 {
00809   render_priv *priv = port->render_priv;
00810 
00811   gui->graphics->destroy_gc (priv->crosshair_gc);
00812   ghid_cancel_lead_user ();
00813   g_free (port->render_priv);
00814   port->render_priv = NULL;
00815 }
00816 
00817 void
00818 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
00819 {
00820   render_priv *priv = port->render_priv;
00821 
00822   gtk_widget_set_gl_capability (widget,
00823                                 priv->glconfig,
00824                                 NULL,
00825                                 TRUE,
00826                                 GDK_GL_RGBA_TYPE);
00827 }
00828 
00829 void
00830 ghid_drawing_area_configure_hook (GHidPort *port)
00831 {
00832 }
00833 
00834 gboolean
00835 ghid_start_drawing (GHidPort *port, GtkWidget *widget)
00836 {
00837   GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
00838   GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
00839 
00840   /* make GL-context "current" */
00841   if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
00842     return FALSE;
00843 
00844   port->render_priv->in_context = true;
00845 
00846   return TRUE;
00847 }
00848 
00849 void
00850 ghid_end_drawing (GHidPort *port, GtkWidget *widget)
00851 {
00852   GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
00853 
00854   if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
00855     gdk_gl_drawable_swap_buffers (pGlDrawable);
00856   else
00857     glFlush ();
00858 
00859   port->render_priv->in_context = false;
00860 
00861   /* end drawing to current GL-context */
00862   gdk_gl_drawable_gl_end (pGlDrawable);
00863 }
00864 
00865 void
00866 ghid_screen_update (void)
00867 {
00868 }
00869 
00870 #define Z_NEAR 3.0
00871 gboolean
00872 ghid_drawing_area_expose_cb (GtkWidget *widget,
00873                              GdkEventExpose *ev,
00874                              GHidPort *port)
00875 {
00876   render_priv *priv = port->render_priv;
00877   GtkAllocation allocation;
00878   BoxType region;
00879   Coord min_x, min_y;
00880   Coord max_x, max_y;
00881   Coord new_x, new_y;
00882   Coord min_depth;
00883   Coord max_depth;
00884 
00885   gtk_widget_get_allocation (widget, &allocation);
00886 
00887   ghid_start_drawing (port, widget);
00888   hidgl_start_render ();
00889 
00890   /* If we don't have any stencil bits available,
00891      we can't use the hidgl polygon drawing routine */
00892   /* TODO: We could use the GLU tessellator though */
00893   if (hidgl_stencil_bits() == 0)
00894     ghid_graphics.fill_pcb_polygon = common_fill_pcb_polygon;
00895 
00896   glEnable (GL_BLEND);
00897   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00898 
00899   glViewport (0, 0, allocation.width, allocation.height);
00900 
00901   glEnable (GL_SCISSOR_TEST);
00902   glScissor (ev->area.x,
00903              allocation.height - ev->area.height - ev->area.y,
00904              ev->area.width, ev->area.height);
00905 
00906   glMatrixMode (GL_PROJECTION);
00907   glLoadIdentity ();
00908   glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
00909   glMatrixMode (GL_MODELVIEW);
00910   glLoadIdentity ();
00911   glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
00912   glMultMatrixf ((GLfloat *)view_matrix);
00913   glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
00914   glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
00915             (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
00916             ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
00917   glTranslatef (port->view.flip_x ?  port->view.x0 - PCB->MaxWidth  :
00918                                     -port->view.x0,
00919                 port->view.flip_y ?  port->view.y0 - PCB->MaxHeight :
00920                                     -port->view.y0, 0);
00921   glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
00922 
00923   glEnable (GL_STENCIL_TEST);
00924   glClearColor (port->offlimits_color.red / 65535.,
00925                 port->offlimits_color.green / 65535.,
00926                 port->offlimits_color.blue / 65535.,
00927                 1.);
00928   glStencilMask (~0);
00929   glClearStencil (0);
00930   glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
00931   hidgl_reset_stencil_usage ();
00932 
00933   /* Disable the stencil test until we need it - otherwise it gets dirty */
00934   glDisable (GL_STENCIL_TEST);
00935   glStencilMask (0);
00936   glStencilFunc (GL_ALWAYS, 0, 0);
00937 
00938   /* Test the 8 corners of a cube spanning the event */
00939   min_depth = -50; /* FIXME */
00940   max_depth =  0;  /* FIXME */
00941 
00942   ghid_unproject_to_z_plane (ev->area.x,
00943                              ev->area.y,
00944                              min_depth, &new_x, &new_y);
00945   max_x = min_x = new_x;
00946   max_y = min_y = new_y;
00947 
00948   ghid_unproject_to_z_plane (ev->area.x,
00949                              ev->area.y,
00950                              max_depth, &new_x, &new_y);
00951   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00952   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00953 
00954   /* */
00955   ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
00956                              ev->area.y,
00957                              min_depth, &new_x, &new_y);
00958   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00959   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00960 
00961   ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
00962                              max_depth, &new_x, &new_y);
00963   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00964   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00965 
00966   /* */
00967   ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
00968                              ev->area.y + ev->area.height,
00969                              min_depth, &new_x, &new_y);
00970   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00971   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00972 
00973   ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
00974                              ev->area.y + ev->area.height,
00975                              max_depth, &new_x, &new_y);
00976   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00977   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00978 
00979   /* */
00980   ghid_unproject_to_z_plane (ev->area.x,
00981                              ev->area.y + ev->area.height,
00982                              min_depth,
00983                              &new_x, &new_y);
00984   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00985   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00986 
00987   ghid_unproject_to_z_plane (ev->area.x,
00988                              ev->area.y + ev->area.height,
00989                              max_depth,
00990                              &new_x, &new_y);
00991   min_x = MIN (min_x, new_x);  max_x = MAX (max_x, new_x);
00992   min_y = MIN (min_y, new_y);  max_y = MAX (max_y, new_y);
00993 
00994   region.X1 = min_x;  region.X2 = max_x + 1;
00995   region.Y1 = min_y;  region.Y2 = max_y + 1;
00996 
00997   region.X1 = MAX (0, MIN (PCB->MaxWidth,  region.X1));
00998   region.X2 = MAX (0, MIN (PCB->MaxWidth,  region.X2));
00999   region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
01000   region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
01001 
01002   glColor3f (port->bg_color.red / 65535.,
01003              port->bg_color.green / 65535.,
01004              port->bg_color.blue / 65535.);
01005 
01006   glBegin (GL_QUADS);
01007   glVertex3i (0,             0,              -50);
01008   glVertex3i (PCB->MaxWidth, 0,              -50);
01009   glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50);
01010   glVertex3i (0,             PCB->MaxHeight, -50);
01011   glEnd ();
01012 
01013   ghid_draw_bg_image ();
01014 
01015   ghid_invalidate_current_gc ();
01016   hid_expose_callback (&ghid_hid, &region, 0);
01017   hidgl_flush_triangles (&buffer);
01018 
01019   ghid_graphics.draw_grid (&region);
01020 
01021   ghid_invalidate_current_gc ();
01022 
01023   DrawAttached (priv->crosshair_gc);
01024   DrawMark (priv->crosshair_gc);
01025   hidgl_flush_triangles (&buffer);
01026 
01027   draw_crosshair (priv);
01028   hidgl_flush_triangles (&buffer);
01029 
01030   draw_lead_user (priv);
01031 
01032   hidgl_finish_render ();
01033   ghid_end_drawing (port, widget);
01034 
01035   g_timer_start (priv->time_since_expose);
01036 
01037   return FALSE;
01038 }
01039 
01040 /* This realize callback is used to work around a crash bug in some mesa
01041  * versions (observed on a machine running the intel i965 driver. It isn't
01042  * obvious why it helps, but somehow fiddling with the GL context here solves
01043  * the issue. The problem appears to have been fixed in recent mesa versions.
01044  */
01045 void
01046 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
01047 {
01048   GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
01049   GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
01050 
01051   if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
01052     return;
01053 
01054   gdk_gl_drawable_gl_end (gldrawable);
01055   return;
01056 }
01057 
01058 gboolean
01059 ghid_pinout_preview_expose (GtkWidget *widget,
01060                             GdkEventExpose *ev)
01061 {
01062   GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
01063   GtkAllocation allocation;
01064   view_data save_view;
01065   int save_width, save_height;
01066   Coord save_max_width;
01067   Coord save_max_height;
01068   double xz, yz;
01069 
01070   save_view = gport->view;
01071   save_width = gport->width;
01072   save_height = gport->height;
01073   save_max_width = PCB->MaxWidth;
01074   save_max_height = PCB->MaxHeight;
01075 
01076   /* Setup zoom factor for drawing routines */
01077 
01078   gtk_widget_get_allocation (widget, &allocation);
01079   xz = (double) pinout->x_max / allocation.width;
01080   yz = (double) pinout->y_max / allocation.height;
01081   if (xz > yz)
01082     gport->view.coord_per_px = xz;
01083   else
01084     gport->view.coord_per_px = yz;
01085 
01086   gport->width = allocation.width;
01087   gport->height = allocation.height;
01088   gport->view.width = allocation.width * gport->view.coord_per_px;
01089   gport->view.height = allocation.height * gport->view.coord_per_px;
01090   gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
01091   gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
01092   PCB->MaxWidth = pinout->x_max;
01093   PCB->MaxHeight = pinout->y_max;
01094 
01095   ghid_start_drawing (gport, widget);
01096   hidgl_start_render ();
01097 
01098 #if 0  /* We disable alpha blending here, as hid_expose_callback() does not
01099         * call set_layer() as appropriate for us to sub-composite rendering
01100         * from each layer when drawing a single element. If we leave alpha-
01101         * blending on, it means text and overlapping pads are rendered ugly.
01102         */
01103 
01104   glEnable (GL_BLEND);
01105   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01106 #endif
01107 
01108   glViewport (0, 0, allocation.width, allocation.height);
01109 
01110 #if 0  /* We disable the scissor test here, as it is interacting badly with
01111         * being handed expose events which don't cover the whole window.
01112         * As we have a double-buffered GL window, we end up with unintialised
01113         * contents remaining in the unpainted areas (outside the scissor
01114         * region), and these are being flipped onto the screen.
01115         *
01116         * The debugging code below shows multiple expose events when the
01117         * window is shown the first time, some of which are very small.
01118         *
01119         * XXX: There is clearly a perforamnce issue here, in that we may
01120         *      be rendering the preview more times, and over a larger area
01121         *      than is really required.
01122         */
01123 
01124   glEnable (GL_SCISSOR_TEST);
01125   glScissor (ev->area.x,
01126              allocation.height - ev->area.height - ev->area.y,
01127              ev->area.width, ev->area.height);
01128 #endif
01129 
01130 #ifdef DEBUG
01131   printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
01132           ev->area.x, ev->area.y, ev->area.width, ev->area.height,
01133              (double)ev->area.x,
01134              (double)(allocation.height - ev->area.height - ev->area.y),
01135              (double)ev->area.width,
01136              (double)ev->area.height);
01137 #endif
01138 
01139   glMatrixMode (GL_PROJECTION);
01140   glLoadIdentity ();
01141   glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
01142   glMatrixMode (GL_MODELVIEW);
01143   glLoadIdentity ();
01144   glTranslatef (0.0f, 0.0f, -Z_NEAR);
01145 
01146   glClearColor (gport->bg_color.red / 65535.,
01147                 gport->bg_color.green / 65535.,
01148                 gport->bg_color.blue / 65535.,
01149                 1.);
01150   glStencilMask (~0);
01151   glClearStencil (0);
01152   glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01153   hidgl_reset_stencil_usage ();
01154 
01155   /* Disable the stencil test until we need it - otherwise it gets dirty */
01156   glDisable (GL_STENCIL_TEST);
01157   glStencilMask (0);
01158   glStencilFunc (GL_ALWAYS, 0, 0);
01159 
01160   /* call the drawing routine */
01161   ghid_invalidate_current_gc ();
01162   glPushMatrix ();
01163   glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
01164             (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
01165             ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
01166   glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth  :
01167                                     -gport->view.x0,
01168                 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
01169                                     -gport->view.y0, 0);
01170 
01171   hid_expose_callback (&ghid_hid, NULL, pinout->element);
01172   hidgl_flush_triangles (&buffer);
01173   glPopMatrix ();
01174 
01175   hidgl_finish_render ();
01176   ghid_end_drawing (gport, widget);
01177 
01178   gport->view = save_view;
01179   gport->width = save_width;
01180   gport->height = save_height;
01181   PCB->MaxWidth = save_max_width;
01182   PCB->MaxHeight = save_max_height;
01183 
01184   return FALSE;
01185 }
01186 
01187 
01188 GdkPixmap *
01189 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
01190 {
01191   GdkGLConfig *glconfig;
01192   GdkPixmap *pixmap;
01193   GdkGLPixmap *glpixmap;
01194   GdkGLContext* glcontext;
01195   GdkGLDrawable* gldrawable;
01196   view_data save_view;
01197   int save_width, save_height;
01198   BoxType region;
01199 
01200   save_view = gport->view;
01201   save_width = gport->width;
01202   save_height = gport->height;
01203 
01204   /* Setup rendering context for drawing routines
01205    */
01206 
01207   glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB     |
01208                                         GDK_GL_MODE_STENCIL |
01209                                         GDK_GL_MODE_SINGLE);
01210 
01211   pixmap = gdk_pixmap_new (NULL, width, height, depth);
01212   glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
01213   gldrawable = GDK_GL_DRAWABLE (glpixmap);
01214   glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
01215 
01216   /* Setup zoom factor for drawing routines */
01217 
01218   gport->view.coord_per_px = zoom;
01219   gport->width = width;
01220   gport->height = height;
01221   gport->view.width = width * gport->view.coord_per_px;
01222   gport->view.height = height * gport->view.coord_per_px;
01223   gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
01224   gport->view.x0 -= gport->view.height / 2;
01225   gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
01226   gport->view.y0 -= gport->view.width / 2;
01227 
01228   /* make GL-context "current" */
01229   if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
01230     return NULL;
01231   }
01232   hidgl_start_render ();
01233   gport->render_priv->in_context = true;
01234 
01235   glEnable (GL_BLEND);
01236   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01237 
01238   glViewport (0, 0, width, height);
01239 
01240   glEnable (GL_SCISSOR_TEST);
01241   glScissor (0, 0, width, height);
01242 
01243   glMatrixMode (GL_PROJECTION);
01244   glLoadIdentity ();
01245   glOrtho (0, width, height, 0, -100000, 100000);
01246   glMatrixMode (GL_MODELVIEW);
01247   glLoadIdentity ();
01248   glTranslatef (0.0f, 0.0f, -Z_NEAR);
01249 
01250   glClearColor (gport->bg_color.red / 65535.,
01251                 gport->bg_color.green / 65535.,
01252                 gport->bg_color.blue / 65535.,
01253                 1.);
01254   glStencilMask (~0);
01255   glClearStencil (0);
01256   glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01257   hidgl_reset_stencil_usage ();
01258 
01259   /* Disable the stencil test until we need it - otherwise it gets dirty */
01260   glDisable (GL_STENCIL_TEST);
01261   glStencilMask (0);
01262   glStencilFunc (GL_ALWAYS, 0, 0);
01263 
01264   /* call the drawing routine */
01265   ghid_invalidate_current_gc ();
01266   glPushMatrix ();
01267   glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
01268             (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
01269             ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
01270   glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth  :
01271                                     -gport->view.x0,
01272                 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
01273                                     -gport->view.y0, 0);
01274 
01275   region.X1 = MIN(Px(0), Px(gport->width + 1));
01276   region.Y1 = MIN(Py(0), Py(gport->height + 1));
01277   region.X2 = MAX(Px(0), Px(gport->width + 1));
01278   region.Y2 = MAX(Py(0), Py(gport->height + 1));
01279 
01280   region.X1 = MAX (0, MIN (PCB->MaxWidth,  region.X1));
01281   region.X2 = MAX (0, MIN (PCB->MaxWidth,  region.X2));
01282   region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
01283   region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
01284 
01285   hid_expose_callback (&ghid_hid, &region, NULL);
01286   hidgl_flush_triangles (&buffer);
01287   glPopMatrix ();
01288 
01289   glFlush ();
01290 
01291   hidgl_finish_render ();
01292 
01293   /* end drawing to current GL-context */
01294   gport->render_priv->in_context = false;
01295   gdk_gl_drawable_gl_end (gldrawable);
01296 
01297   gdk_pixmap_unset_gl_capability (pixmap);
01298 
01299   g_object_unref (glconfig);
01300   g_object_unref (glcontext);
01301 
01302   gport->view = save_view;
01303   gport->width = save_width;
01304   gport->height = save_height;
01305 
01306   return pixmap;
01307 }
01308 
01309 HID_DRAW *
01310 ghid_request_debug_draw (void)
01311 {
01312   GHidPort *port = gport;
01313   GtkWidget *widget = port->drawing_area;
01314   GtkAllocation allocation;
01315 
01316   gtk_widget_get_allocation (widget, &allocation);
01317 
01318   ghid_start_drawing (port, widget);
01319   hidgl_start_render ();
01320 
01321   glViewport (0, 0, allocation.width, allocation.height);
01322 
01323   glMatrixMode (GL_PROJECTION);
01324   glLoadIdentity ();
01325   glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
01326   glMatrixMode (GL_MODELVIEW);
01327   glLoadIdentity ();
01328   glTranslatef (0.0f, 0.0f, -Z_NEAR);
01329 
01330   ghid_invalidate_current_gc ();
01331 
01332   /* Setup stenciling */
01333   glDisable (GL_STENCIL_TEST);
01334 
01335   glPushMatrix ();
01336   glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
01337             (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
01338             ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
01339   glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth  :
01340                              -port->view.x0,
01341                 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
01342                              -port->view.y0, 0);
01343 
01344   return ghid_hid.graphics;
01345 }
01346 
01347 void
01348 ghid_flush_debug_draw (void)
01349 {
01350   GtkWidget *widget = gport->drawing_area;
01351   GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
01352 
01353   hidgl_flush_triangles (&buffer);
01354 
01355   if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
01356     gdk_gl_drawable_swap_buffers (pGlDrawable);
01357   else
01358     glFlush ();
01359 }
01360 
01361 void
01362 ghid_finish_debug_draw (void)
01363 {
01364   hidgl_flush_triangles (&buffer);
01365   glPopMatrix ();
01366 
01367   hidgl_finish_render ();
01368   ghid_end_drawing (gport, gport->drawing_area);
01369 }
01370 
01371 static float
01372 determinant_2x2 (float m[2][2])
01373 {
01374   float det;
01375   det = m[0][0] * m[1][1] -
01376         m[0][1] * m[1][0];
01377   return det;
01378 }
01379 
01380 #if 0
01381 static float
01382 determinant_4x4 (float m[4][4])
01383 {
01384   float det;
01385   det = m[0][3] * m[1][2] * m[2][1] * m[3][0]-m[0][2] * m[1][3] * m[2][1] * m[3][0] -
01386         m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
01387         m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
01388         m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
01389         m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
01390         m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
01391         m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
01392         m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
01393         m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
01394         m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
01395         m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
01396         m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
01397    return det;
01398 }
01399 #endif
01400 
01401 static void
01402 invert_2x2 (float m[2][2], float out[2][2])
01403 {
01404   float scale = 1 / determinant_2x2 (m);
01405   out[0][0] =  m[1][1] * scale;
01406   out[0][1] = -m[0][1] * scale;
01407   out[1][0] = -m[1][0] * scale;
01408   out[1][1] =  m[0][0] * scale;
01409 }
01410 
01411 #if 0
01412 static void
01413 invert_4x4 (float m[4][4], float out[4][4])
01414 {
01415   float scale = 1 / determinant_4x4 (m);
01416 
01417   out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
01418                m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
01419                m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
01420   out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
01421                m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
01422                m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
01423   out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
01424                m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
01425                m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
01426   out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
01427                m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
01428                m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
01429   out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
01430                m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
01431                m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
01432   out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
01433                m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
01434                m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
01435   out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
01436                m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
01437                m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
01438   out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
01439                m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
01440                m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
01441   out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
01442                m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
01443                m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
01444   out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
01445                m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
01446                m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
01447   out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
01448                m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
01449                m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
01450   out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
01451                m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
01452                m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
01453   out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
01454                m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
01455                m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
01456   out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
01457                m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
01458                m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
01459   out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
01460                m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
01461                m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
01462   out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
01463                m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
01464                m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
01465 }
01466 #endif
01467 
01468 
01469 static void
01470 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
01471 {
01472   float mat[2][2];
01473   float inv_mat[2][2];
01474   float x, y;
01475 
01476   /*
01477     ex = view_matrix[0][0] * vx +
01478          view_matrix[0][1] * vy +
01479          view_matrix[0][2] * vz +
01480          view_matrix[0][3] * 1;
01481     ey = view_matrix[1][0] * vx +
01482          view_matrix[1][1] * vy +
01483          view_matrix[1][2] * vz +
01484          view_matrix[1][3] * 1;
01485     UNKNOWN ez = view_matrix[2][0] * vx +
01486                  view_matrix[2][1] * vy +
01487                  view_matrix[2][2] * vz +
01488                  view_matrix[2][3] * 1;
01489 
01490     ex - view_matrix[0][3] * 1
01491        - view_matrix[0][2] * vz
01492       = view_matrix[0][0] * vx +
01493         view_matrix[0][1] * vy;
01494 
01495     ey - view_matrix[1][3] * 1
01496        - view_matrix[1][2] * vz
01497       = view_matrix[1][0] * vx +
01498         view_matrix[1][1] * vy;
01499   */
01500 
01501   /* NB: last_modelview_matrix is transposed in memory! */
01502   x = (float)ex - last_modelview_matrix[3][0] * 1
01503                 - last_modelview_matrix[2][0] * pcb_z;
01504 
01505   y = (float)ey - last_modelview_matrix[3][1] * 1
01506                 - last_modelview_matrix[2][1] * pcb_z;
01507 
01508   /*
01509     x = view_matrix[0][0] * vx +
01510         view_matrix[0][1] * vy;
01511 
01512     y = view_matrix[1][0] * vx +
01513         view_matrix[1][1] * vy;
01514 
01515     [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
01516     [view_matrix[1][0] view_matrix[1][1]] [vy]   [y]
01517   */
01518 
01519   mat[0][0] = last_modelview_matrix[0][0];
01520   mat[0][1] = last_modelview_matrix[1][0];
01521   mat[1][0] = last_modelview_matrix[0][1];
01522   mat[1][1] = last_modelview_matrix[1][1];
01523 
01524   /*    if (determinant_2x2 (mat) < 0.00001)       */
01525   /*      printf ("Determinant is quite small\n"); */
01526 
01527   invert_2x2 (mat, inv_mat);
01528 
01529   *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
01530   *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
01531 }
01532 
01533 
01534 bool
01535 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
01536 {
01537   ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y);
01538 
01539   return true;
01540 }
01541 
01542 bool
01543 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
01544 {
01545   /* NB: last_modelview_matrix is transposed in memory */
01546   float w = last_modelview_matrix[0][3] * (float)pcb_x +
01547             last_modelview_matrix[1][3] * (float)pcb_y +
01548             last_modelview_matrix[2][3] * 0. +
01549             last_modelview_matrix[3][3] * 1.;
01550 
01551   *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
01552               last_modelview_matrix[1][0] * (float)pcb_y +
01553               last_modelview_matrix[2][0] * 0. +
01554               last_modelview_matrix[3][0] * 1.) / w;
01555   *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
01556               last_modelview_matrix[1][1] * (float)pcb_y +
01557               last_modelview_matrix[2][1] * 0. +
01558               last_modelview_matrix[3][1] * 1.) / w;
01559 
01560   return true;
01561 }
01562 
01563 void
01564 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
01565 {
01566   global_view_2d = view_2d;
01567   ghid_invalidate_all ();
01568 }
01569 
01570 void
01571 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
01572 {
01573 #ifdef DEBUG_ROTATE
01574   int row, column;
01575 #endif
01576 
01577   build_rotmatrix (view_matrix, quarternion);
01578 
01579 #ifdef DEBUG_ROTATE
01580   for (row = 0; row < 4; row++) {
01581     printf ("[ %f", view_matrix[row][0]);
01582     for (column = 1; column < 4; column++) {
01583       printf (",\t%f", view_matrix[row][column]);
01584     }
01585     printf ("\t]\n");
01586   }
01587   printf ("\n");
01588 #endif
01589 
01590   ghid_invalidate_all ();
01591 }
01592 
01593 
01594 #define LEAD_USER_WIDTH           0.2          /* millimeters */
01595 #define LEAD_USER_PERIOD          (1000 / 20)  /* 20fps (in ms) */
01596 #define LEAD_USER_VELOCITY        3.           /* millimeters per second */
01597 #define LEAD_USER_ARC_COUNT       3
01598 #define LEAD_USER_ARC_SEPARATION  3.           /* millimeters */
01599 #define LEAD_USER_INITIAL_RADIUS  10.          /* millimetres */
01600 #define LEAD_USER_COLOR_R         1.
01601 #define LEAD_USER_COLOR_G         1.
01602 #define LEAD_USER_COLOR_B         0.
01603 
01604 static void
01605 draw_lead_user (render_priv *priv)
01606 {
01607   int i;
01608   double radius = priv->lead_user_radius;
01609   double width = MM_TO_COORD (LEAD_USER_WIDTH);
01610   double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
01611 
01612   if (!priv->lead_user)
01613     return;
01614 
01615   glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
01616   glEnable (GL_COLOR_LOGIC_OP);
01617   glLogicOp (GL_XOR);
01618   glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
01619 
01620 
01621   /* arcs at the approrpriate radii */
01622 
01623   for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
01624     {
01625       if (radius < width)
01626         radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
01627 
01628       /* Draw an arc at radius */
01629       hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y,
01630                       radius, radius, 0, 360, gport->view.coord_per_px);
01631     }
01632 
01633   hidgl_flush_triangles (&buffer);
01634   glPopAttrib ();
01635 }
01636 
01637 gboolean
01638 lead_user_cb (gpointer data)
01639 {
01640   render_priv *priv = data;
01641   Coord step;
01642   double elapsed_time;
01643 
01644   /* Queue a redraw */
01645   ghid_invalidate_all ();
01646 
01647   /* Update radius */
01648   elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
01649   g_timer_start (priv->lead_user_timer);
01650 
01651   step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
01652   if (priv->lead_user_radius > step)
01653     priv->lead_user_radius -= step;
01654   else
01655     priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
01656 
01657   return TRUE;
01658 }
01659 
01660 void
01661 ghid_lead_user_to_location (Coord x, Coord y)
01662 {
01663   render_priv *priv = gport->render_priv;
01664 
01665   ghid_cancel_lead_user ();
01666 
01667   priv->lead_user = true;
01668   priv->lead_user_x = x;
01669   priv->lead_user_y = y;
01670   priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
01671   priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
01672   priv->lead_user_timer = g_timer_new ();
01673 }
01674 
01675 void
01676 ghid_cancel_lead_user (void)
01677 {
01678   render_priv *priv = gport->render_priv;
01679 
01680   if (priv->lead_user_timeout)
01681     g_source_remove (priv->lead_user_timeout);
01682 
01683   if (priv->lead_user_timer)
01684     g_timer_destroy (priv->lead_user_timer);
01685 
01686   if (priv->lead_user)
01687     ghid_invalidate_all ();
01688 
01689   priv->lead_user_timeout = 0;
01690   priv->lead_user_timer = NULL;
01691   priv->lead_user = false;
01692 }