hid/gtk (GL): I think the polygon renderer works in mask mode now
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blob158c37ee3188eb97baf782c7df7422186379dfc3
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
7 #include "crosshair.h"
8 #include "clip.h"
9 #include "../hidint.h"
10 #include "gui.h"
11 #include "draw.h"
12 #include "draw_funcs.h"
13 #include "rtree.h"
14 #include "polygon.h"
15 #include "gui-pinout-preview.h"
17 /* The Linux OpenGL ABI 1.0 spec requires that we define
18 * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
19 * in order to get prototypes:
20 * http://www.opengl.org/registry/ABI/
23 #define GL_GLEXT_PROTOTYPES 1
24 #ifdef HAVE_OPENGL_GL_H
25 # include <OpenGL/gl.h>
26 #else
27 # include <GL/gl.h>
28 #endif
30 #include <gtk/gtkgl.h>
31 #include "hid/common/hidgl.h"
33 #include "hid/common/draw_helpers.h"
34 #include "hid/common/trackball.h"
36 #ifdef HAVE_LIBDMALLOC
37 #include <dmalloc.h>
38 #endif
40 extern HID ghid_hid;
41 extern HID_DRAW ghid_graphics;
42 extern HID_DRAW_CLASS ghid_graphics_class;
44 static hidGC current_gc = NULL;
46 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
48 #define USE_GC(gc) if (!use_gc(gc)) return
50 static enum mask_mode cur_mask = HID_MASK_OFF;
51 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
52 {0.0, 1.0, 0.0, 0.0},
53 {0.0, 0.0, 1.0, 0.0},
54 {0.0, 0.0, 0.0, 1.0}};
55 static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
56 {0.0, 1.0, 0.0, 0.0},
57 {0.0, 0.0, 1.0, 0.0},
58 {0.0, 0.0, 0.0, 1.0}};
59 static int global_view_2d = 1;
61 typedef struct render_priv {
62 GdkGLConfig *glconfig;
63 bool trans_lines;
64 bool in_context;
65 int subcomposite_stencil_bit;
66 char *current_colorname;
67 double current_alpha_mult;
68 GTimer *time_since_expose;
70 /* Feature for leading the user to a particular location */
71 guint lead_user_timeout;
72 GTimer *lead_user_timer;
73 bool lead_user;
74 Coord lead_user_radius;
75 Coord lead_user_x;
76 Coord lead_user_y;
78 hidgl_instance *hidgl;
79 GList *active_gc_list;
80 double edit_depth;
82 } render_priv;
84 typedef struct gtk_gc_struct
86 struct hidgl_gc_struct hidgl_gc; /* Parent */
88 const char *colorname;
89 double alpha_mult;
90 Coord width;
91 gint cap, join;
92 } *gtkGC;
94 static void draw_lead_user (hidGC gc, render_priv *priv);
95 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
98 #define BOARD_THICKNESS MM_TO_COORD(1.60)
99 #define MASK_COPPER_SPACING MM_TO_COORD(0.05)
100 #define SILK_MASK_SPACING MM_TO_COORD(0.01)
101 static int
102 compute_depth (int group)
104 static int last_depth_computed = 0;
106 int top_group;
107 int bottom_group;
108 int min_copper_group;
109 int max_copper_group;
110 int num_copper_groups;
111 int middle_copper_group;
112 int depth;
114 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
115 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
117 min_copper_group = MIN (bottom_group, top_group);
118 max_copper_group = MAX (bottom_group, top_group);
119 num_copper_groups = max_copper_group - min_copper_group + 1;
120 middle_copper_group = min_copper_group + num_copper_groups / 2;
122 if (group >= 0 && group < max_group) {
123 if (group >= min_copper_group && group <= max_copper_group) {
124 /* XXX: IS THIS INCORRECT FOR REVERSED GROUP ORDERINGS? */
125 depth = -(group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups;
126 } else {
127 depth = 0;
130 } else if (SL_TYPE (group) == SL_MASK) {
131 if (SL_SIDE (group) == SL_TOP_SIDE) {
132 depth = -((min_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups - MASK_COPPER_SPACING);
133 } else {
134 depth = -((max_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups + MASK_COPPER_SPACING);
136 } else if (SL_TYPE (group) == SL_SILK) {
137 if (SL_SIDE (group) == SL_TOP_SIDE) {
138 depth = -((min_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups - MASK_COPPER_SPACING - SILK_MASK_SPACING);
139 } else {
140 depth = -((max_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups + MASK_COPPER_SPACING + SILK_MASK_SPACING);
143 } else if (SL_TYPE (group) == SL_INVISIBLE) {
144 /* Same as silk, but for the back-side layer */
145 if (Settings.ShowBottomSide) {
146 depth = -((min_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups - MASK_COPPER_SPACING - SILK_MASK_SPACING);
147 } else {
148 depth = -((max_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups + MASK_COPPER_SPACING + SILK_MASK_SPACING);
150 } else if (SL_TYPE (group) == SL_RATS ||
151 SL_TYPE (group) == SL_PDRILL ||
152 SL_TYPE (group) == SL_UDRILL) {
153 /* Draw these at the depth we last rendered at */
154 depth = last_depth_computed;
155 } else if (SL_TYPE (group) == SL_PASTE ||
156 SL_TYPE (group) == SL_FAB ||
157 SL_TYPE (group) == SL_ASSY) {
158 /* Layer types we don't use, which draw.c asks us about, so
159 * we just return _something_ to avoid the warnign below. */
160 depth = last_depth_computed;
161 } else {
162 /* DEFAULT CASE */
163 printf ("Unknown layer group to set depth for: %i\n", group);
164 depth = last_depth_computed;
167 last_depth_computed = depth;
168 return depth;
171 static void
172 start_subcomposite (hidgl_instance *hidgl)
174 render_priv *priv = gport->render_priv;
175 int stencil_bit;
177 /* Flush out any existing geoemtry to be rendered */
178 hidgl_flush_triangles (hidgl);
180 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
181 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
183 stencil_bit = hidgl_assign_clear_stencil_bit (hidgl); /* Get a new (clean) bitplane to stencil with */
184 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
185 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */
187 priv->subcomposite_stencil_bit = stencil_bit;
190 static void
191 end_subcomposite (hidgl_instance *hidgl)
193 render_priv *priv = gport->render_priv;
195 /* Flush out any existing geoemtry to be rendered */
196 hidgl_flush_triangles (hidgl);
198 hidgl_return_stencil_bit (hidgl, priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */
200 glStencilMask (0);
201 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */
202 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
204 priv->subcomposite_stencil_bit = 0;
207 static void
208 set_depth_on_all_active_gc (render_priv *priv, float depth)
210 GList *iter;
212 for (iter = priv->active_gc_list;
213 iter != NULL;
214 iter = g_list_next (iter))
216 hidGC gc = iter->data;
218 hidgl_set_depth (gc, depth);
222 /* Compute group visibility based upon on copper layers only */
223 static bool
224 is_layer_group_visible (int group)
226 int entry;
227 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
229 int layer_idx = PCB->LayerGroups.Entries[group][entry];
230 if (layer_idx >= 0 && layer_idx < max_copper_layer &&
231 LAYER_PTR (layer_idx)->On)
232 return true;
234 return false;
238 ghid_set_layer (const char *name, int group, int empty)
240 render_priv *priv = gport->render_priv;
241 hidgl_instance *hidgl = priv->hidgl;
242 bool group_visible = false;
243 bool subcomposite = true;
245 if (group >= 0 && group < max_group)
247 priv->trans_lines = true;
248 subcomposite = true;
249 group_visible = is_layer_group_visible (group);
251 else
253 switch (SL_TYPE (group))
255 case SL_INVISIBLE:
256 priv->trans_lines = false;
257 subcomposite = false;
258 group_visible = PCB->InvisibleObjectsOn;
259 break;
260 case SL_MASK:
261 priv->trans_lines = true;
262 subcomposite = false;
263 group_visible = TEST_FLAG (SHOWMASKFLAG, PCB);
264 break;
265 case SL_SILK:
266 priv->trans_lines = true;
267 subcomposite = true;
268 group_visible = PCB->ElementOn;
269 break;
270 case SL_ASSY:
271 break;
272 case SL_PDRILL:
273 case SL_UDRILL:
274 priv->trans_lines = true;
275 subcomposite = true;
276 group_visible = true;
277 break;
278 case SL_RATS:
279 priv->trans_lines = true;
280 subcomposite = false;
281 group_visible = PCB->RatOn;
282 break;
286 end_subcomposite (hidgl);
288 if (group_visible && subcomposite)
289 start_subcomposite (hidgl);
291 /* Drawing is already flushed by {start,end}_subcomposite */
292 set_depth_on_all_active_gc (priv, compute_depth (group));
294 return group_visible;
297 static void
298 ghid_end_layer ()
300 render_priv *priv = gport->render_priv;
301 hidgl_instance *hidgl = priv->hidgl;
303 end_subcomposite (hidgl);
306 void
307 ghid_destroy_gc (hidGC gc)
309 render_priv *priv = gport->render_priv;
311 priv->active_gc_list = g_list_remove (priv->active_gc_list, gc);
313 hidgl_finish_gc (gc);
314 g_free (gc);
317 hidGC
318 ghid_make_gc (void)
320 render_priv *priv = gport->render_priv;
321 hidGC gc = (hidGC) g_new0 (struct gtk_gc_struct, 1);
322 gtkGC gtk_gc = (gtkGC)gc;
324 gc->hid = &ghid_hid;
325 gc->hid_draw = &ghid_graphics;
327 hidgl_init_gc (priv->hidgl, gc);
329 gtk_gc->colorname = Settings.BackgroundColor;
330 gtk_gc->alpha_mult = 1.0;
332 priv->active_gc_list = g_list_prepend (priv->active_gc_list, gc);
334 return gc;
337 static void
338 ghid_draw_grid (hidGC gc, BoxType *drawn_area)
340 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
341 return;
343 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
345 gport->grid_color.red ^= gport->bg_color.red;
346 gport->grid_color.green ^= gport->bg_color.green;
347 gport->grid_color.blue ^= gport->bg_color.blue;
350 glDisable (GL_STENCIL_TEST);
351 glEnable (GL_COLOR_LOGIC_OP);
352 glLogicOp (GL_XOR);
354 glColor3f (gport->grid_color.red / 65535.,
355 gport->grid_color.green / 65535.,
356 gport->grid_color.blue / 65535.);
358 hidgl_draw_grid (gc, drawn_area);
360 glDisable (GL_COLOR_LOGIC_OP);
361 glEnable (GL_STENCIL_TEST);
364 static void
365 ghid_draw_bg_image (void)
367 static GLuint texture_handle = 0;
369 if (!ghidgui->bg_pixbuf)
370 return;
372 if (texture_handle == 0)
374 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
375 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
376 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
377 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
378 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
379 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
381 g_warn_if_fail (bits_per_sample == 8);
382 g_warn_if_fail (rowstride == width * n_channels);
384 glGenTextures (1, &texture_handle);
385 glBindTexture (GL_TEXTURE_2D, texture_handle);
387 /* XXX: We should proabbly determine what the maxmimum texture supported is,
388 * and if our image is larger, shrink it down using GDK pixbuf routines
389 * rather than having it fail below.
392 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
393 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
396 glBindTexture (GL_TEXTURE_2D, texture_handle);
398 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
399 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
400 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
401 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
402 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
403 glEnable (GL_TEXTURE_2D);
405 /* Render a quad with the background as a texture */
407 glBegin (GL_QUADS);
408 glTexCoord2d (0., 0.);
409 glVertex3i (0, 0, 0);
410 glTexCoord2d (1., 0.);
411 glVertex3i (PCB->MaxWidth, 0, 0);
412 glTexCoord2d (1., 1.);
413 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
414 glTexCoord2d (0., 1.);
415 glVertex3i (0, PCB->MaxHeight, 0);
416 glEnd ();
418 glDisable (GL_TEXTURE_2D);
421 void
422 ghid_use_mask (enum mask_mode mode)
424 render_priv *priv = gport->render_priv;
425 hidgl_instance *hidgl = priv->hidgl;
426 static int stencil_bit = 0;
428 if (mode == cur_mask)
429 return;
431 /* Flush out any existing geoemtry to be rendered */
432 hidgl_flush_triangles (hidgl);
434 switch (mode)
436 case HID_MASK_BEFORE:
437 /* The HID asks not to receive this mask type, so warn if we get it */
438 g_return_if_reached ();
440 case HID_MASK_CLEAR:
441 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
442 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
443 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
444 stencil_bit = hidgl_assign_clear_stencil_bit (hidgl); /* Get a new (clean) bitplane to stencil with */
445 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */
446 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
447 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
448 break;
450 case HID_MASK_AFTER:
451 /* Drawing operations as masked to areas where the stencil buffer is '0' */
452 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
453 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */
454 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */
455 break;
457 case HID_MASK_OFF:
458 /* Disable stenciling */
459 hidgl_return_stencil_bit (hidgl, stencil_bit); /* Relinquish any bitplane we previously used */
460 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
461 break;
463 cur_mask = mode;
467 /* Config helper functions for when the user changes color preferences.
468 | set_special colors used in the gtkhid.
470 static void
471 set_special_grid_color (void)
473 if (!gport->colormap)
474 return;
475 gport->grid_color.red ^= gport->bg_color.red;
476 gport->grid_color.green ^= gport->bg_color.green;
477 gport->grid_color.blue ^= gport->bg_color.blue;
480 void
481 ghid_set_special_colors (HID_Attribute * ha)
483 if (!ha->name || !ha->value)
484 return;
485 if (!strcmp (ha->name, "background-color"))
487 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
488 set_special_grid_color ();
490 else if (!strcmp (ha->name, "off-limit-color"))
492 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
494 else if (!strcmp (ha->name, "grid-color"))
496 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
497 set_special_grid_color ();
501 typedef struct
503 int color_set;
504 GdkColor color;
505 double red;
506 double green;
507 double blue;
508 } ColorCache;
510 static void
511 set_gl_color_for_gc (hidGC gc)
513 gtkGC gtk_gc = (gtkGC)gc;
514 render_priv *priv = gport->render_priv;
515 static void *cache = NULL;
516 hidval cval;
517 ColorCache *cc;
518 double r, g, b, a;
520 if (priv->current_colorname != NULL &&
521 strcmp (priv->current_colorname, gtk_gc->colorname) == 0 &&
522 priv->current_alpha_mult == gtk_gc->alpha_mult)
523 return;
525 free (priv->current_colorname);
526 priv->current_colorname = NULL;
528 /* If we can't set the GL colour right now, quit with
529 * current_colorname set to NULL, so we don't NOOP the
530 * next set_gl_color_for_gc call.
532 if (!priv->in_context)
533 return;
535 priv->current_colorname = strdup (gtk_gc->colorname);
536 priv->current_alpha_mult = gtk_gc->alpha_mult;
538 if (gport->colormap == NULL)
539 gport->colormap = gtk_widget_get_colormap (gport->top_window);
540 if (strcmp (gtk_gc->colorname, "erase") == 0)
542 r = gport->bg_color.red / 65535.;
543 g = gport->bg_color.green / 65535.;
544 b = gport->bg_color.blue / 65535.;
545 a = 1.0;
547 else if (strcmp (gtk_gc->colorname, "drill") == 0)
549 r = gport->offlimits_color.red / 65535.;
550 g = gport->offlimits_color.green / 65535.;
551 b = gport->offlimits_color.blue / 65535.;
552 a = 0.85;
554 else
556 if (hid_cache_color (0, gtk_gc->colorname, &cval, &cache))
557 cc = (ColorCache *) cval.ptr;
558 else
560 cc = (ColorCache *) malloc (sizeof (ColorCache));
561 memset (cc, 0, sizeof (*cc));
562 cval.ptr = cc;
563 hid_cache_color (1, gtk_gc->colorname, &cval, &cache);
566 if (!cc->color_set)
568 if (gdk_color_parse (gtk_gc->colorname, &cc->color))
569 gdk_color_alloc (gport->colormap, &cc->color);
570 else
571 gdk_color_white (gport->colormap, &cc->color);
572 cc->red = cc->color.red / 65535.;
573 cc->green = cc->color.green / 65535.;
574 cc->blue = cc->color.blue / 65535.;
575 cc->color_set = 1;
577 r = cc->red;
578 g = cc->green;
579 b = cc->blue;
580 a = 0.7;
582 if (1) {
583 double maxi, mult;
584 a *= gtk_gc->alpha_mult;
585 if (!priv->trans_lines)
586 a = 1.0;
587 maxi = r;
588 if (g > maxi) maxi = g;
589 if (b > maxi) maxi = b;
590 mult = MIN (1 / a, 1 / maxi);
591 #if 1
592 r = r * mult;
593 g = g * mult;
594 b = b * mult;
595 #endif
598 hidgl_flush_triangles (gtk_gc->hidgl_gc.hidgl);
599 glColor4d (r, g, b, a);
602 void
603 ghid_set_color (hidGC gc, const char *name)
605 gtkGC gtk_gc = (gtkGC)gc;
607 gtk_gc->colorname = name;
608 set_gl_color_for_gc (gc);
611 void
612 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
614 gtkGC gtk_gc = (gtkGC)gc;
616 gtk_gc->alpha_mult = alpha_mult;
617 set_gl_color_for_gc (gc);
620 void
621 ghid_set_line_cap (hidGC gc, EndCapStyle style)
623 gtkGC gtk_gc = (gtkGC)gc;
625 gtk_gc->cap = style;
628 void
629 ghid_set_line_width (hidGC gc, Coord width)
631 gtkGC gtk_gc = (gtkGC)gc;
633 gtk_gc->width = width;
637 void
638 ghid_set_draw_xor (hidGC gc, int xor)
640 /* NOT IMPLEMENTED */
642 /* Only presently called when setting up a crosshair GC.
643 * We manage our own drawing model for that anyway. */
646 void
647 ghid_set_draw_faded (hidGC gc, int faded)
649 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
652 void
653 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
655 printf ("ghid_set_line_cap_angle() -- not implemented\n");
658 static void
659 ghid_invalidate_current_gc (void)
661 current_gc = NULL;
664 static int
665 use_gc (hidGC gc)
667 if (gc->hid != &ghid_hid)
669 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
670 abort ();
673 if (current_gc == gc)
674 return 1;
676 current_gc = gc;
678 set_gl_color_for_gc (gc);
679 return 1;
682 void
683 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
685 gtkGC gtk_gc = (gtkGC)gc;
686 USE_GC (gc);
688 hidgl_draw_line (gc, gtk_gc->cap, gtk_gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
691 void
692 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
693 Angle start_angle, Angle delta_angle)
695 gtkGC gtk_gc = (gtkGC)gc;
696 USE_GC (gc);
698 hidgl_draw_arc (gc, gtk_gc->width, cx, cy, xradius, yradius,
699 start_angle, delta_angle, gport->view.coord_per_px);
702 void
703 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
705 USE_GC (gc);
707 hidgl_draw_rect (gc, x1, y1, x2, y2);
711 void
712 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
714 USE_GC (gc);
716 hidgl_fill_circle (gc, cx, cy, radius, gport->view.coord_per_px);
720 void
721 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
723 USE_GC (gc);
725 hidgl_fill_polygon (gc, n_coords, x, y);
728 void
729 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
731 USE_GC (gc);
733 hidgl_fill_pcb_polygon (gc, poly, clip_box, gport->view.coord_per_px);
736 void
737 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
739 gtkGC gtk_gc = (gtkGC)gc;
741 double old_alpha_mult = gtk_gc->alpha_mult;
742 common_thindraw_pcb_polygon (gc, poly, clip_box);
743 ghid_set_alpha_mult (gc, gtk_gc->alpha_mult * 0.25);
744 hid_draw_fill_pcb_polygon (gc, poly, clip_box);
745 ghid_set_alpha_mult (gc, old_alpha_mult);
748 void
749 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
751 USE_GC (gc);
753 hidgl_fill_rect (gc, x1, y1, x2, y2);
756 void
757 ghid_invalidate_lr (int left, int right, int top, int bottom)
759 ghid_invalidate_all ();
762 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
763 void
764 ghid_invalidate_all ()
766 render_priv *priv = gport->render_priv;
767 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
769 ghid_draw_area_update (gport, NULL);
771 if (elapsed > MAX_ELAPSED)
772 gdk_window_process_all_updates ();
775 void
776 ghid_notify_crosshair_change (bool changes_complete)
778 /* We sometimes get called before the GUI is up */
779 if (gport->drawing_area == NULL)
780 return;
782 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
783 ghid_invalidate_all ();
786 void
787 ghid_notify_mark_change (bool changes_complete)
789 /* We sometimes get called before the GUI is up */
790 if (gport->drawing_area == NULL)
791 return;
793 /* FIXME: We could just invalidate the bounds of the mark? */
794 ghid_invalidate_all ();
797 static void
798 draw_right_cross (gint x, gint y, gint z)
800 glVertex3i (x, 0, z);
801 glVertex3i (x, PCB->MaxHeight, z);
802 glVertex3i (0, y, z);
803 glVertex3i (PCB->MaxWidth, y, z);
806 static void
807 draw_slanted_cross (gint x, gint y, gint z)
809 gint x0, y0, x1, y1;
811 x0 = x + (PCB->MaxHeight - y);
812 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
813 x1 = x - y;
814 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
815 y0 = y + (PCB->MaxWidth - x);
816 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
817 y1 = y - x;
818 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
819 glVertex3i (x0, y0, z);
820 glVertex3i (x1, y1, z);
822 x0 = x - (PCB->MaxHeight - y);
823 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
824 x1 = x + y;
825 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
826 y0 = y + x;
827 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
828 y1 = y - (PCB->MaxWidth - x);
829 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
830 glVertex3i (x0, y0, z);
831 glVertex3i (x1, y1, z);
834 static void
835 draw_dozen_cross (gint x, gint y, gint z)
837 gint x0, y0, x1, y1;
838 gdouble tan60 = sqrt (3);
840 x0 = x + (PCB->MaxHeight - y) / tan60;
841 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
842 x1 = x - y / tan60;
843 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
844 y0 = y + (PCB->MaxWidth - x) * tan60;
845 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
846 y1 = y - x * tan60;
847 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
848 glVertex3i (x0, y0, z);
849 glVertex3i (x1, y1, z);
851 x0 = x + (PCB->MaxHeight - y) * tan60;
852 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
853 x1 = x - y * tan60;
854 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
855 y0 = y + (PCB->MaxWidth - x) / tan60;
856 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
857 y1 = y - x / tan60;
858 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
859 glVertex3i (x0, y0, z);
860 glVertex3i (x1, y1, z);
862 x0 = x - (PCB->MaxHeight - y) / tan60;
863 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
864 x1 = x + y / tan60;
865 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
866 y0 = y + x * tan60;
867 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
868 y1 = y - (PCB->MaxWidth - x) * tan60;
869 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
870 glVertex3i (x0, y0, z);
871 glVertex3i (x1, y1, z);
873 x0 = x - (PCB->MaxHeight - y) * tan60;
874 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
875 x1 = x + y * tan60;
876 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
877 y0 = y + x / tan60;
878 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
879 y1 = y - (PCB->MaxWidth - x) / tan60;
880 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
881 glVertex3i (x0, y0, z);
882 glVertex3i (x1, y1, z);
885 static void
886 draw_crosshair (hidGC gc, render_priv *priv)
888 gtkGC gtk_gc = (gtkGC)gc;
889 gint x, y, z;
890 static int done_once = 0;
891 static GdkColor cross_color;
893 if (!priv->in_context)
894 return;
896 if (!done_once)
898 done_once = 1;
899 /* FIXME: when CrossColor changed from config */
900 ghid_map_color_string (Settings.CrossColor, &cross_color);
903 x = gport->crosshair_x;
904 y = gport->crosshair_y;
905 z = gtk_gc->hidgl_gc.depth;
907 glEnable (GL_COLOR_LOGIC_OP);
908 glLogicOp (GL_XOR);
910 glColor3f (cross_color.red / 65535.,
911 cross_color.green / 65535.,
912 cross_color.blue / 65535.);
914 glBegin (GL_LINES);
916 draw_right_cross (x, y, z);
917 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
918 draw_slanted_cross (x, y, z);
919 if (Crosshair.shape == Dozen_Crosshair_Shape)
920 draw_dozen_cross (x, y, z);
922 glEnd ();
924 glDisable (GL_COLOR_LOGIC_OP);
927 void
928 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
930 render_priv *priv;
932 port->render_priv = priv = g_new0 (render_priv, 1);
934 priv->time_since_expose = g_timer_new ();
936 gtk_gl_init(argc, argv);
938 /* setup GL-context */
939 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA |
940 GDK_GL_MODE_STENCIL |
941 GDK_GL_MODE_DOUBLE);
942 if (!priv->glconfig)
944 printf ("Could not setup GL-context!\n");
945 return; /* Should we abort? */
948 hidgl_init ();
949 priv->hidgl = hidgl_new_instance ();
951 /* Setup HID function pointers specific to the GL renderer*/
952 ghid_graphics_class.end_layer = ghid_end_layer;
953 ghid_graphics_class.fill_pcb_polygon = ghid_fill_pcb_polygon;
954 ghid_graphics_class.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
957 void
958 ghid_shutdown_renderer (GHidPort *port)
960 render_priv *priv = port->render_priv;
962 hidgl_free_instance (priv->hidgl);
964 ghid_cancel_lead_user ();
965 g_free (port->render_priv);
966 port->render_priv = NULL;
969 void
970 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
972 render_priv *priv = port->render_priv;
974 gtk_widget_set_gl_capability (widget,
975 priv->glconfig,
976 NULL,
977 TRUE,
978 GDK_GL_RGBA_TYPE);
981 void
982 ghid_drawing_area_configure_hook (GHidPort *port)
986 gboolean
987 ghid_start_drawing (GHidPort *port, GtkWidget *widget)
989 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
990 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
992 /* make GL-context "current" */
993 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
994 return FALSE;
996 port->render_priv->in_context = true;
998 hidgl_start_render (port->render_priv->hidgl);
1000 return TRUE;
1003 void
1004 ghid_end_drawing (GHidPort *port, GtkWidget *widget)
1006 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
1008 hidgl_finish_render (port->render_priv->hidgl);
1010 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1011 gdk_gl_drawable_swap_buffers (pGlDrawable);
1012 else
1013 glFlush ();
1015 port->render_priv->in_context = false;
1017 /* end drawing to current GL-context */
1018 gdk_gl_drawable_gl_end (pGlDrawable);
1021 void
1022 ghid_screen_update (void)
1026 static int
1027 EMark_callback (const BoxType * b, void *cl)
1029 ElementType *element = (ElementType *) b;
1031 DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element));
1032 return 1;
1035 static void
1036 set_object_color (AnyObjectType *obj, char *warn_color, char *selected_color,
1037 char *connected_color, char *found_color, char *normal_color)
1039 char *color;
1041 if (warn_color != NULL && TEST_FLAG (WARNFLAG, obj)) color = warn_color;
1042 else if (selected_color != NULL && TEST_FLAG (SELECTEDFLAG, obj)) color = selected_color;
1043 else if (connected_color != NULL && TEST_FLAG (CONNECTEDFLAG, obj)) color = connected_color;
1044 else if (found_color != NULL && TEST_FLAG (FOUNDFLAG, obj)) color = found_color;
1045 else color = normal_color;
1047 hid_draw_set_color (Output.fgGC, color);
1050 static void
1051 set_layer_object_color (LayerType *layer, AnyObjectType *obj)
1053 set_object_color (obj, NULL, layer->SelectedColor, PCB->ConnectedColor, PCB->FoundColor, layer->Color);
1056 static void
1057 set_pv_inlayer_color (PinType *pv, LayerType *layer, int type)
1059 if (TEST_FLAG (WARNFLAG, pv)) hid_draw_set_color (Output.fgGC, PCB->WarnColor);
1060 else if (TEST_FLAG (SELECTEDFLAG, pv)) hid_draw_set_color (Output.fgGC, (type == VIA_TYPE) ? PCB->ViaSelectedColor
1061 : PCB->PinSelectedColor);
1062 else if (TEST_FLAG (CONNECTEDFLAG, pv)) hid_draw_set_color (Output.fgGC, PCB->ConnectedColor);
1063 else if (TEST_FLAG (FOUNDFLAG, pv)) hid_draw_set_color (Output.fgGC, PCB->FoundColor);
1064 else
1066 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1067 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1068 int this_group = GetLayerGroupNumberByPointer (layer);
1070 if (this_group == top_group || this_group == bottom_group)
1071 hid_draw_set_color (Output.fgGC, (SWAP_IDENT == (this_group == bottom_group)) ?
1072 PCB->ViaColor : PCB->InvisibleObjectsColor);
1073 else
1074 hid_draw_set_color (Output.fgGC, layer->Color);
1078 static void
1079 _draw_pv_name (PinType *pv)
1081 BoxType box;
1082 bool vert;
1083 TextType text;
1085 if (!pv->Name || !pv->Name[0])
1086 text.TextString = EMPTY (pv->Number);
1087 else
1088 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name);
1090 vert = TEST_FLAG (EDGE2FLAG, pv);
1092 if (vert)
1094 box.X1 = pv->X - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
1095 box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX;
1097 else
1099 box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX;
1100 box.Y1 = pv->Y - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
1103 hid_draw_set_color (Output.fgGC, PCB->PinNameColor);
1105 text.Flags = NoFlags ();
1106 /* Set font height to approx 56% of pin thickness */
1107 text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT;
1108 text.X = box.X1;
1109 text.Y = box.Y1;
1110 text.Direction = vert ? 1 : 0;
1112 hid_draw_pcb_text (Output.fgGC, &text, 0);
1115 static void
1116 _draw_pv (PinType *pv, bool draw_hole)
1118 if (TEST_FLAG (THINDRAWFLAG, PCB))
1119 hid_draw_thin_pcb_pv (Output.fgGC, Output.fgGC, pv, draw_hole, false);
1120 else
1121 hid_draw_fill_pcb_pv (Output.fgGC, Output.bgGC, pv, draw_hole, false);
1123 if (!TEST_FLAG (HOLEFLAG, pv) && TEST_FLAG (DISPLAYNAMEFLAG, pv))
1124 _draw_pv_name (pv);
1127 static void
1128 draw_pin (PinType *pin, bool draw_hole)
1130 set_object_color ((AnyObjectType *) pin, PCB->WarnColor, PCB->PinSelectedColor,
1131 PCB->ConnectedColor, PCB->FoundColor, PCB->PinColor);
1133 _draw_pv (pin, draw_hole);
1136 static int
1137 pin_callback (const BoxType * b, void *cl)
1139 PinType *pin = (PinType *) b;
1141 if (!TEST_FLAG (HOLEFLAG, pin) && TEST_FLAG (DISPLAYNAMEFLAG, pin))
1142 _draw_pv_name (pin);
1143 draw_pin (pin, TEST_FLAG (THINDRAWFLAG, PCB));
1144 return 1;
1147 static int
1148 pin_name_callback (const BoxType * b, void *cl)
1150 PinType *pin = (PinType *) b;
1152 if (!TEST_FLAG (HOLEFLAG, pin) && TEST_FLAG (DISPLAYNAMEFLAG, pin))
1153 _draw_pv_name (pin);
1154 return 1;
1157 static int
1158 pin_inlayer_callback (const BoxType * b, void *cl)
1160 set_pv_inlayer_color ((PinType *) b, cl, PIN_TYPE);
1161 _draw_pv ((PinType *) b, false);
1162 return 1;
1165 static void
1166 draw_via (PinType *via, bool draw_hole)
1168 set_object_color ((AnyObjectType *) via, PCB->WarnColor, PCB->ViaSelectedColor,
1169 PCB->ConnectedColor, PCB->FoundColor, PCB->ViaColor);
1171 _draw_pv (via, draw_hole);
1174 static int
1175 via_callback (const BoxType * b, void *cl)
1177 draw_via ((PinType *)b, TEST_FLAG (THINDRAWFLAG, PCB));
1178 return 1;
1181 static int
1182 via_inlayer_callback (const BoxType * b, void *cl)
1184 set_pv_inlayer_color ((PinType *) b, cl, VIA_TYPE);
1185 _draw_pv ((PinType *) b, TEST_FLAG (THINDRAWFLAG, PCB));
1186 return 1;
1189 static void
1190 draw_pad_name (PadType *pad)
1192 BoxType box;
1193 bool vert;
1194 TextType text;
1196 if (!pad->Name || !pad->Name[0])
1197 text.TextString = EMPTY (pad->Number);
1198 else
1199 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name);
1201 /* should text be vertical ? */
1202 vert = (pad->Point1.X == pad->Point2.X);
1204 if (vert)
1206 box.X1 = pad->Point1.X - pad->Thickness / 2;
1207 box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2;
1208 box.X1 += Settings.PinoutTextOffsetY;
1209 box.Y1 -= Settings.PinoutTextOffsetX;
1211 else
1213 box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2;
1214 box.Y1 = pad->Point1.Y - pad->Thickness / 2;
1215 box.X1 += Settings.PinoutTextOffsetX;
1216 box.Y1 += Settings.PinoutTextOffsetY;
1219 hid_draw_set_color (Output.fgGC, PCB->PinNameColor);
1221 text.Flags = NoFlags ();
1222 /* Set font height to approx 90% of pad thickness */
1223 text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT;
1224 text.X = box.X1;
1225 text.Y = box.Y1;
1226 text.Direction = vert ? 1 : 0;
1228 hid_draw_pcb_text (Output.fgGC, &text, 0);
1231 static void
1232 _draw_pad (hidGC gc, PadType *pad, bool clear, bool mask)
1234 if (clear && !mask && pad->Clearance <= 0)
1235 return;
1237 if (TEST_FLAG (THINDRAWFLAG, PCB) ||
1238 (clear && TEST_FLAG (THINDRAWPOLYFLAG, PCB)))
1239 hid_draw_thin_pcb_pad (gc, pad, clear, mask);
1240 else
1241 hid_draw_fill_pcb_pad (gc, pad, clear, mask);
1244 static void
1245 draw_pad (PadType *pad)
1247 set_object_color ((AnyObjectType *)pad, PCB->WarnColor,
1248 PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor,
1249 FRONT (pad) ? PCB->PinColor : PCB->InvisibleObjectsColor);
1251 _draw_pad (Output.fgGC, pad, false, false);
1253 if (TEST_FLAG (DISPLAYNAMEFLAG, pad))
1254 draw_pad_name (pad);
1257 static int
1258 pad_callback (const BoxType * b, void *cl)
1260 PadType *pad = (PadType *) b;
1261 int *side = cl;
1263 if (ON_SIDE (pad, *side)) {
1264 if (TEST_FLAG (DISPLAYNAMEFLAG, pad))
1265 draw_pad_name (pad);
1266 draw_pad (pad);
1268 return 1;
1272 static int
1273 hole_callback (const BoxType * b, void *cl)
1275 PinType *pv = (PinType *) b;
1276 int plated = cl ? *(int *) cl : -1;
1278 if ((plated == 0 && !TEST_FLAG (HOLEFLAG, pv)) ||
1279 (plated == 1 && TEST_FLAG (HOLEFLAG, pv)))
1280 return 1;
1282 if (TEST_FLAG (THINDRAWFLAG, PCB))
1284 if (!TEST_FLAG (HOLEFLAG, pv))
1286 hid_draw_set_line_cap (Output.fgGC, Round_Cap);
1287 hid_draw_set_line_width (Output.fgGC, 0);
1288 hid_draw_arc (Output.fgGC, pv->X, pv->Y,
1289 pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360);
1292 else
1293 hid_draw_fill_circle (Output.bgGC, pv->X, pv->Y, pv->DrillingHole / 2);
1295 if (TEST_FLAG (HOLEFLAG, pv))
1297 set_object_color ((AnyObjectType *) pv, PCB->WarnColor,
1298 PCB->ViaSelectedColor, NULL, NULL, Settings.BlackColor);
1300 hid_draw_set_line_cap (Output.fgGC, Round_Cap);
1301 hid_draw_set_line_width (Output.fgGC, 0);
1302 hid_draw_arc (Output.fgGC, pv->X, pv->Y,
1303 pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360);
1305 return 1;
1308 static int
1309 line_callback (const BoxType * b, void *cl)
1311 LayerType *layer = cl;
1312 LineType *line = (LineType *)b;
1314 set_layer_object_color (layer, (AnyObjectType *) line);
1315 hid_draw_pcb_line (Output.fgGC, line);
1316 return 1;
1319 static int
1320 arc_callback (const BoxType * b, void *cl)
1322 LayerType *layer = cl;
1323 ArcType *arc = (ArcType *)b;
1325 set_layer_object_color (layer, (AnyObjectType *) arc);
1326 hid_draw_pcb_arc (Output.fgGC, arc);
1327 return 1;
1330 static int
1331 text_callback (const BoxType * b, void *cl)
1333 LayerType *layer = cl;
1334 TextType *text = (TextType *)b;
1335 int min_silk_line;
1337 if (TEST_FLAG (SELECTEDFLAG, text))
1338 hid_draw_set_color (Output.fgGC, layer->SelectedColor);
1339 else
1340 hid_draw_set_color (Output.fgGC, layer->Color);
1341 if (layer == &PCB->Data->SILKLAYER ||
1342 layer == &PCB->Data->BACKSILKLAYER)
1343 min_silk_line = PCB->minSlk;
1344 else
1345 min_silk_line = PCB->minWid;
1346 hid_draw_pcb_text (Output.fgGC, text, min_silk_line);
1347 return 1;
1350 struct poly_info
1352 LayerType *layer;
1353 const BoxType *drawn_area;
1356 static int
1357 poly_callback (const BoxType * b, void *cl)
1359 struct poly_info *i = (struct poly_info *) cl;
1360 PolygonType *polygon = (PolygonType *)b;
1362 set_layer_object_color (i->layer, (AnyObjectType *) polygon);
1363 hid_draw_pcb_polygon (Output.fgGC, polygon, i->drawn_area);
1364 return 1;
1367 static int
1368 clearPin_callback (const BoxType * b, void *cl)
1370 PinType *pin = (PinType *) b;
1371 if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
1372 hid_draw_thin_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
1373 else
1374 hid_draw_fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
1375 return 1;
1378 static int
1379 clearPad_callback (const BoxType * b, void *cl)
1381 PadType *pad = (PadType *) b;
1382 int *side = cl;
1383 if (ON_SIDE (pad, *side) && pad->Mask)
1384 _draw_pad (Output.pmGC, pad, true, true);
1385 return 1;
1388 static int
1389 clearPin_callback_solid (const BoxType * b, void *cl)
1391 PinType *pin = (PinType *) b;
1392 hid_draw_fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
1393 return 1;
1396 static int
1397 clearPad_callback_solid (const BoxType * b, void *cl)
1399 PadType *pad = (PadType *) b;
1400 int *side = cl;
1401 if (ON_SIDE (pad, *side) && pad->Mask)
1402 hid_draw_fill_pcb_pad (Output.pmGC, pad, true, true);
1403 return 1;
1406 static void
1407 GhidDrawMask (int side, BoxType * screen)
1409 int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
1410 LayerType *Layer = LAYER_PTR (side == TOP_SIDE ? top_soldermask_layer : bottom_soldermask_layer);
1411 struct poly_info info;
1412 PolygonType polygon;
1414 OutputType *out = &Output;
1416 if (thin)
1418 hid_draw_set_line_width (Output.pmGC, 0);
1419 hid_draw_set_color (Output.pmGC, PCB->MaskColor);
1420 r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, NULL);
1421 r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, NULL);
1422 r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &side);
1423 hid_draw_set_color (Output.pmGC, "erase");
1426 hid_draw_use_mask (&ghid_graphics, HID_MASK_CLEAR);
1428 info.layer = Layer;
1429 info.drawn_area = screen;
1430 r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
1431 r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
1432 r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
1433 r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
1435 r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback_solid, NULL);
1436 r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback_solid, NULL);
1437 r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback_solid, &side);
1439 hid_draw_use_mask (&ghid_graphics, HID_MASK_AFTER);
1440 hid_draw_set_color (out->fgGC, PCB->MaskColor);
1441 ghid_set_alpha_mult (out->fgGC, thin ? 0.35 : 1.0);
1443 if (!PCB->Data->outline_valid) {
1445 if (PCB->Data->outline != NULL)
1446 poly_Free (&PCB->Data->outline);
1448 PCB->Data->outline = board_outline_poly ();
1449 PCB->Data->outline_valid = true;
1452 memset (&polygon, 0, sizeof (polygon));
1453 polygon.Clipped = PCB->Data->outline;
1454 polygon.BoundingBox = *screen;
1455 polygon.Flags = NoFlags ();
1456 SET_FLAG (FULLPOLYFLAG, &polygon);
1457 hid_draw_fill_pcb_polygon (out->fgGC, &polygon, screen);
1458 poly_FreeContours (&polygon.NoHoles);
1459 ghid_set_alpha_mult (out->fgGC, 1.0);
1461 hid_draw_use_mask (&ghid_graphics, HID_MASK_OFF);
1464 static int
1465 GhidDrawLayerGroup (int group, const BoxType * screen)
1467 render_priv *priv = gport->render_priv;
1468 int i;
1469 int layernum;
1470 int side;
1471 struct poly_info info;
1472 LayerType *Layer;
1473 int n_entries = PCB->LayerGroups.Number[group];
1474 Cardinal *layers = PCB->LayerGroups.Entries[group];
1475 int first_run = 1;
1476 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1477 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1478 bool is_outline;
1480 if (!hid_draw_set_layer (&ghid_graphics, 0, group, 0))
1481 return 0;
1483 /* HACK: Subcomposite each layer in a layer group separately */
1484 for (i = n_entries - 1; i >= 0; i--) {
1485 layernum = layers[i];
1486 Layer = PCB->Data->Layer + layers[i];
1488 is_outline = strcmp (Layer->Name, "outline") == 0 ||
1489 strcmp (Layer->Name, "route") == 0;
1491 if (layernum < max_copper_layer && Layer->On) {
1493 if (!first_run)
1494 hid_draw_set_layer (&ghid_graphics, 0, group, 0);
1496 first_run = 0;
1498 if (!is_outline && !TEST_FLAG (THINDRAWFLAG, PCB)) {
1499 /* Mask out drilled holes on this layer */
1500 hidgl_flush_triangles (priv->hidgl);
1501 glPushAttrib (GL_COLOR_BUFFER_BIT);
1502 glColorMask (0, 0, 0, 0);
1503 hid_draw_set_color (Output.bgGC, PCB->MaskColor);
1504 if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, hole_callback, NULL);
1505 if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, hole_callback, NULL);
1506 hidgl_flush_triangles (priv->hidgl);
1507 glPopAttrib ();
1510 /* draw all polygons on this layer */
1511 if (Layer->PolygonN) {
1512 info.layer = Layer;
1513 info.drawn_area = screen;
1514 r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
1516 /* HACK: Subcomposite polygons separately from other layer primitives */
1517 /* Reset the compositing */
1518 hid_draw_end_layer (&ghid_graphics);
1519 hid_draw_set_layer (&ghid_graphics, 0, group, 0);
1521 if (!is_outline && !TEST_FLAG (THINDRAWFLAG, PCB)) {
1522 hidgl_flush_triangles (priv->hidgl);
1523 glPushAttrib (GL_COLOR_BUFFER_BIT);
1524 glColorMask (0, 0, 0, 0);
1525 /* Mask out drilled holes on this layer */
1526 if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, hole_callback, NULL);
1527 if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, hole_callback, NULL);
1528 hidgl_flush_triangles (priv->hidgl);
1529 glPopAttrib ();
1533 /* Draw pins, vias and pads on this layer */
1534 if (!global_view_2d && !is_outline) {
1535 if (PCB->PinOn &&
1536 (group == bottom_group || group == top_group))
1537 r_search (PCB->Data->pin_tree, screen, NULL, pin_name_callback, Layer);
1538 if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, pin_inlayer_callback, Layer);
1539 if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, via_inlayer_callback, Layer);
1540 if (PCB->PinOn && group == top_group)
1542 side = TOP_SIDE;
1543 r_search (PCB->Data->pad_tree, screen, NULL, pad_callback, &side);
1545 if (PCB->PinOn && group == bottom_group)
1547 side = BOTTOM_SIDE;
1548 r_search (PCB->Data->pad_tree, screen, NULL, pad_callback, &side);
1552 if (TEST_FLAG (CHECKPLANESFLAG, PCB))
1553 continue;
1555 r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
1556 r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
1557 r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
1561 hid_draw_end_layer (&ghid_graphics);
1563 return (n_entries > 1);
1566 static void
1567 DrawDrillChannel (hidGC gc, int vx, int vy, int vr, int from_layer, int to_layer, double scale)
1569 #define PIXELS_PER_CIRCLINE 5.
1570 #define MIN_FACES_PER_CYL 6
1571 #define MAX_FACES_PER_CYL 360
1572 float radius = vr;
1573 float x1, y1;
1574 float x2, y2;
1575 float z1, z2;
1576 int i;
1577 int slices;
1579 slices = M_PI * 2 * vr / scale / PIXELS_PER_CIRCLINE;
1581 if (slices < MIN_FACES_PER_CYL)
1582 slices = MIN_FACES_PER_CYL;
1584 if (slices > MAX_FACES_PER_CYL)
1585 slices = MAX_FACES_PER_CYL;
1587 z1 = compute_depth (from_layer);
1588 z2 = compute_depth (to_layer);
1590 x1 = vx + vr;
1591 y1 = vy;
1593 hidgl_ensure_triangle_space (gc, 2 * slices);
1594 for (i = 0; i < slices; i++)
1596 x2 = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
1597 y2 = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
1598 hidgl_add_triangle_3D (gc, x1, y1, z1, x2, y2, z1, x1, y1, z2);
1599 hidgl_add_triangle_3D (gc, x2, y2, z1, x1, y1, z2, x2, y2, z2);
1600 x1 = x2;
1601 y1 = y2;
1605 struct cyl_info {
1606 int from_layer;
1607 int to_layer;
1608 double scale;
1611 static int
1612 draw_hole_cyl (PinType *Pin, struct cyl_info *info, int Type)
1614 char *color;
1616 if (TEST_FLAG (WARNFLAG, Pin))
1617 color = PCB->WarnColor;
1618 else if (TEST_FLAG (SELECTEDFLAG, Pin))
1619 color = (Type == VIA_TYPE) ? PCB->ViaSelectedColor : PCB->PinSelectedColor;
1620 else if (TEST_FLAG (CONNECTEDFLAG, Pin))
1621 color = PCB->ConnectedColor;
1622 else if (TEST_FLAG (FOUNDFLAG, Pin))
1623 color = PCB->FoundColor;
1624 else
1625 color = "drill";
1627 hid_draw_set_color (Output.fgGC, color);
1628 DrawDrillChannel (Output.fgGC, Pin->X, Pin->Y, Pin->DrillingHole / 2, info->from_layer, info->to_layer, info->scale);
1629 return 0;
1632 static int
1633 pin_hole_cyl_callback (const BoxType * b, void *cl)
1635 return draw_hole_cyl ((PinType *)b, (struct cyl_info *)cl, PIN_TYPE);
1638 static int
1639 via_hole_cyl_callback (const BoxType * b, void *cl)
1641 return draw_hole_cyl ((PinType *)b, (struct cyl_info *)cl, VIA_TYPE);
1644 void
1645 ghid_draw_everything (BoxType *drawn_area)
1647 render_priv *priv = gport->render_priv;
1648 int i, ngroups;
1649 int number_phys_on_top;
1650 int side;
1651 /* This is the list of layer groups we will draw. */
1652 int do_group[MAX_LAYER];
1653 /* This is the reverse of the order in which we draw them. */
1654 int drawn_groups[MAX_LAYER];
1655 struct cyl_info cyl_info;
1656 int reverse_layers;
1657 int save_show_solder;
1658 int top_group;
1659 int bottom_group;
1660 int min_phys_group;
1661 int max_phys_group;
1663 priv->current_colorname = NULL;
1665 /* Test direction of rendering */
1666 /* Look at sign of eye coordinate system z-coord when projecting a
1667 world vector along +ve Z axis, (0, 0, 1). */
1668 /* XXX: This isn't strictly correct, as I've ignored the matrix
1669 elements for homogeneous coordinates. */
1670 /* NB: last_modelview_matrix is transposed in memory! */
1671 reverse_layers = (last_modelview_matrix[2][2] < 0);
1673 save_show_solder = Settings.ShowBottomSide;
1674 Settings.ShowBottomSide = reverse_layers;
1676 PCB->Data->SILKLAYER.Color = PCB->ElementColor;
1677 PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
1679 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1680 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1682 min_phys_group = MIN (bottom_group, top_group);
1683 max_phys_group = MAX (bottom_group, top_group);
1685 memset (do_group, 0, sizeof (do_group));
1686 if (global_view_2d) {
1687 /* Draw in layer stack order when in 2D view */
1688 for (ngroups = 0, i = 0; i < max_copper_layer; i++) {
1689 int group = GetLayerGroupNumberByNumber (LayerStack[i]);
1691 if (!do_group[group]) {
1692 do_group[group] = 1;
1693 drawn_groups[ngroups++] = group;
1696 } else {
1697 /* Draw in group order when in 3D view */
1698 for (ngroups = 0, i = 0; i < max_group; i++) {
1699 int group = reverse_layers ? max_group - 1 - i : i;
1701 if (!do_group[group]) {
1702 do_group[group] = 1;
1703 drawn_groups[ngroups++] = group;
1709 * first draw all 'invisible' stuff
1711 side = SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE;
1713 if (!TEST_FLAG (CHECKPLANESFLAG, PCB) &&
1714 hid_draw_set_layer (&ghid_graphics, "invisible", SL (INVISIBLE, 0), 0)) {
1715 DrawSilk (&ghid_graphics, side, drawn_area);
1717 if (global_view_2d)
1718 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
1720 hid_draw_end_layer (&ghid_graphics);
1722 /* Draw the reverse-side solder mask if turned on */
1723 if (!global_view_2d &&
1724 hid_draw_set_layer (&ghid_graphics, SWAP_IDENT ? "componentmask" : "soldermask",
1725 SWAP_IDENT ? SL (MASK, TOP) : SL (MASK, BOTTOM), 0)) {
1726 GhidDrawMask (side, drawn_area);
1727 hid_draw_end_layer (&ghid_graphics);
1731 /* draw all layers in layerstack order */
1732 #define FADE_FACTOR 1
1733 number_phys_on_top = max_phys_group - min_phys_group;
1734 for (i = ngroups - 1; i >= 0; i--) {
1735 bool is_this_physical = drawn_groups[i] >= min_phys_group &&
1736 drawn_groups[i] <= max_phys_group;
1737 bool is_next_physical = i > 0 &&
1738 drawn_groups[i - 1] >= min_phys_group &&
1739 drawn_groups[i - 1] <= max_phys_group;
1741 double alpha_mult = global_view_2d ? pow (FADE_FACTOR, i) :
1742 (is_this_physical ? pow (FADE_FACTOR, number_phys_on_top) : 1.);
1744 if (is_this_physical)
1745 number_phys_on_top --;
1747 ghid_set_alpha_mult (Output.fgGC, alpha_mult);
1748 GhidDrawLayerGroup (drawn_groups [i], drawn_area);
1750 #if 1
1751 if (!global_view_2d && is_this_physical && is_next_physical) {
1752 cyl_info.from_layer = drawn_groups[i];
1753 cyl_info.to_layer = drawn_groups[i - 1];
1754 cyl_info.scale = gport->view.coord_per_px;
1755 hid_draw_set_color (Output.fgGC, "drill");
1756 ghid_set_alpha_mult (Output.fgGC, alpha_mult * 0.75);
1757 if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_hole_cyl_callback, &cyl_info);
1758 if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_hole_cyl_callback, &cyl_info);
1760 #endif
1762 #undef FADE_FACTOR
1764 ghid_set_alpha_mult (Output.fgGC, 1.0);
1766 if (TEST_FLAG (CHECKPLANESFLAG, PCB))
1767 return;
1769 side = SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE;
1771 /* Draw pins, pads, vias below silk */
1772 if (global_view_2d) {
1773 start_subcomposite (priv->hidgl);
1775 if (!TEST_FLAG (THINDRAWFLAG, PCB)) {
1776 /* Mask out drilled holes */
1777 hidgl_flush_triangles (priv->hidgl);
1778 glPushAttrib (GL_COLOR_BUFFER_BIT);
1779 glColorMask (0, 0, 0, 0);
1780 if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
1781 if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
1782 hidgl_flush_triangles (priv->hidgl);
1783 glPopAttrib ();
1786 if (PCB->PinOn) r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
1787 if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
1788 if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
1790 end_subcomposite (priv->hidgl);
1793 /* Draw the solder mask if turned on */
1794 if (hid_draw_set_layer (&ghid_graphics, SWAP_IDENT ? "soldermask" : "componentmask",
1795 SWAP_IDENT ? SL (MASK, BOTTOM) : SL (MASK, TOP), 0)) {
1796 GhidDrawMask (side, drawn_area);
1797 hid_draw_end_layer (&ghid_graphics);
1800 if (hid_draw_set_layer (&ghid_graphics, SWAP_IDENT ? "bottomsilk" : "topsilk",
1801 SWAP_IDENT ? SL (SILK, BOTTOM) : SL (SILK, TOP), 0)) {
1802 DrawSilk (&ghid_graphics, side, drawn_area);
1803 hid_draw_end_layer (&ghid_graphics);
1806 /* Draw element Marks */
1807 if (PCB->PinOn)
1808 r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback, NULL);
1810 /* Draw rat lines on top */
1811 if (PCB->RatOn && hid_draw_set_layer (&ghid_graphics, "rats", SL (RATS, 0), 0)) {
1812 DrawRats (&ghid_graphics, drawn_area);
1813 hid_draw_end_layer (&ghid_graphics);
1816 Settings.ShowBottomSide = save_show_solder;
1819 #define Z_NEAR 3.0
1820 gboolean
1821 ghid_drawing_area_expose_cb (GtkWidget *widget,
1822 GdkEventExpose *ev,
1823 GHidPort *port)
1825 render_priv *priv = port->render_priv;
1826 GtkAllocation allocation;
1827 BoxType region;
1828 Coord min_x, min_y;
1829 Coord max_x, max_y;
1830 Coord new_x, new_y;
1831 Coord min_depth;
1832 Coord max_depth;
1834 gtk_widget_get_allocation (widget, &allocation);
1836 ghid_start_drawing (port, widget);
1838 Output.fgGC = hid_draw_make_gc (&ghid_graphics);
1839 Output.bgGC = hid_draw_make_gc (&ghid_graphics);
1840 Output.pmGC = hid_draw_make_gc (&ghid_graphics);
1842 /* If we don't have any stencil bits available,
1843 we can't use the hidgl polygon drawing routine */
1844 /* TODO: We could use the GLU tessellator though */
1845 if (hidgl_stencil_bits (priv->hidgl) == 0)
1846 ghid_graphics_class.fill_pcb_polygon = common_fill_pcb_polygon;
1848 glEnable (GL_BLEND);
1849 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1851 glViewport (0, 0, allocation.width, allocation.height);
1853 glEnable (GL_SCISSOR_TEST);
1854 glScissor (ev->area.x,
1855 allocation.height - ev->area.height - ev->area.y,
1856 ev->area.width, ev->area.height);
1858 glMatrixMode (GL_PROJECTION);
1859 glLoadIdentity ();
1860 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1861 glMatrixMode (GL_MODELVIEW);
1862 glLoadIdentity ();
1863 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
1864 glMultMatrixf ((GLfloat *)view_matrix);
1865 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
1866 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1867 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1868 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
1869 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1870 -port->view.x0,
1871 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1872 -port->view.y0, 0);
1873 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
1875 glEnable (GL_STENCIL_TEST);
1876 glClearColor (port->offlimits_color.red / 65535.,
1877 port->offlimits_color.green / 65535.,
1878 port->offlimits_color.blue / 65535.,
1879 1.);
1880 glStencilMask (~0);
1881 glClearStencil (0);
1882 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1883 hidgl_reset_stencil_usage (priv->hidgl);
1885 /* Disable the stencil test until we need it - otherwise it gets dirty */
1886 glDisable (GL_STENCIL_TEST);
1887 glStencilMask (0);
1888 glStencilFunc (GL_ALWAYS, 0, 0);
1890 /* Test the 8 corners of a cube spanning the event */
1891 min_depth = -50 + compute_depth (0); /* FIXME: NEED TO USE PHYSICAL GROUPS */
1892 max_depth = 50 + compute_depth (max_copper_layer - 1); /* FIXME: NEED TO USE PHYSICAL GROUPS */
1894 ghid_unproject_to_z_plane (ev->area.x,
1895 ev->area.y,
1896 min_depth, &new_x, &new_y);
1897 max_x = min_x = new_x;
1898 max_y = min_y = new_y;
1900 ghid_unproject_to_z_plane (ev->area.x,
1901 ev->area.y,
1902 max_depth, &new_x, &new_y);
1903 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1904 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1906 /* */
1907 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
1908 ev->area.y,
1909 min_depth, &new_x, &new_y);
1910 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1911 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1913 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
1914 max_depth, &new_x, &new_y);
1915 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1916 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1918 /* */
1919 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
1920 ev->area.y + ev->area.height,
1921 min_depth, &new_x, &new_y);
1922 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1923 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1925 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
1926 ev->area.y + ev->area.height,
1927 max_depth, &new_x, &new_y);
1928 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1929 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1931 /* */
1932 ghid_unproject_to_z_plane (ev->area.x,
1933 ev->area.y + ev->area.height,
1934 min_depth,
1935 &new_x, &new_y);
1936 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1937 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1939 ghid_unproject_to_z_plane (ev->area.x,
1940 ev->area.y + ev->area.height,
1941 max_depth,
1942 &new_x, &new_y);
1943 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1944 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1946 region.X1 = min_x; region.X2 = max_x + 1;
1947 region.Y1 = min_y; region.Y2 = max_y + 1;
1949 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1950 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1951 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1952 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1954 glColor3f (port->bg_color.red / 65535.,
1955 port->bg_color.green / 65535.,
1956 port->bg_color.blue / 65535.);
1958 ghid_invalidate_current_gc ();
1960 /* Setup stenciling */
1961 /* Drawing operations set the stencil buffer to '1' */
1962 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
1963 /* Drawing operations as masked to areas where the stencil buffer is '0' */
1964 /* glStencilFunc (GL_GREATER, 1, 1); */ /* Draw only where stencil buffer is 0 */
1966 if (global_view_2d) {
1967 glBegin (GL_QUADS);
1968 glVertex3i (0, 0, 0);
1969 glVertex3i (PCB->MaxWidth, 0, 0);
1970 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
1971 glVertex3i (0, PCB->MaxHeight, 0);
1972 glEnd ();
1973 } else {
1974 int top_group;
1975 int bottom_group;
1976 int min_phys_group;
1977 int max_phys_group;
1978 int i;
1980 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1981 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1983 min_phys_group = MIN (bottom_group, top_group);
1984 max_phys_group = MAX (bottom_group, top_group);
1986 glBegin (GL_QUADS);
1987 for (i = min_phys_group; i <= max_phys_group; i++) {
1988 int depth = compute_depth (i);
1989 glVertex3i (0, 0, depth);
1990 glVertex3i (PCB->MaxWidth, 0, depth);
1991 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, depth);
1992 glVertex3i (0, PCB->MaxHeight, depth);
1994 glEnd ();
1997 ghid_draw_bg_image ();
1999 /* hid_expose_callback (&ghid_graphics, &region, 0); */
2000 ghid_draw_everything (&region);
2001 hidgl_flush_triangles (priv->hidgl);
2003 /* Set the current depth to the right value for the layer we are editing */
2004 priv->edit_depth = compute_depth (GetLayerGroupNumberByNumber (INDEXOFCURRENT));
2005 hidgl_set_depth (Output.fgGC, priv->edit_depth);
2007 ghid_draw_grid (Output.fgGC, &region);
2009 ghid_invalidate_current_gc ();
2011 DrawAttached (Output.fgGC);
2012 DrawMark (Output.fgGC);
2013 hidgl_flush_triangles (priv->hidgl);
2015 draw_crosshair (Output.fgGC, priv);
2016 hidgl_flush_triangles (priv->hidgl);
2018 draw_lead_user (Output.fgGC, priv);
2020 ghid_end_drawing (port, widget);
2022 hid_draw_destroy_gc (Output.fgGC);
2023 hid_draw_destroy_gc (Output.bgGC);
2024 hid_draw_destroy_gc (Output.pmGC);
2026 Output.fgGC = NULL;
2027 Output.bgGC = NULL;
2028 Output.pmGC = NULL;
2029 g_timer_start (priv->time_since_expose);
2031 return FALSE;
2034 /* This realize callback is used to work around a crash bug in some mesa
2035 * versions (observed on a machine running the intel i965 driver. It isn't
2036 * obvious why it helps, but somehow fiddling with the GL context here solves
2037 * the issue. The problem appears to have been fixed in recent mesa versions.
2039 void
2040 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
2042 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
2043 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
2045 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
2046 return;
2048 gdk_gl_drawable_gl_end (gldrawable);
2049 return;
2052 gboolean
2053 ghid_pinout_preview_expose (GtkWidget *widget,
2054 GdkEventExpose *ev)
2056 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
2057 render_priv *priv = gport->render_priv;
2058 GtkAllocation allocation;
2059 view_data save_view;
2060 int save_width, save_height;
2061 Coord save_max_width;
2062 Coord save_max_height;
2063 double xz, yz;
2065 save_view = gport->view;
2066 save_width = gport->width;
2067 save_height = gport->height;
2068 save_max_width = PCB->MaxWidth;
2069 save_max_height = PCB->MaxHeight;
2071 /* Setup zoom factor for drawing routines */
2073 gtk_widget_get_allocation (widget, &allocation);
2074 xz = (double) pinout->x_max / allocation.width;
2075 yz = (double) pinout->y_max / allocation.height;
2076 if (xz > yz)
2077 gport->view.coord_per_px = xz;
2078 else
2079 gport->view.coord_per_px = yz;
2081 gport->width = allocation.width;
2082 gport->height = allocation.height;
2083 gport->view.width = allocation.width * gport->view.coord_per_px;
2084 gport->view.height = allocation.height * gport->view.coord_per_px;
2085 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
2086 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
2087 PCB->MaxWidth = pinout->x_max;
2088 PCB->MaxHeight = pinout->y_max;
2090 ghid_start_drawing (gport, widget);
2092 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not
2093 * call set_layer() as appropriate for us to sub-composite rendering
2094 * from each layer when drawing a single element. If we leave alpha-
2095 * blending on, it means text and overlapping pads are rendered ugly.
2098 glEnable (GL_BLEND);
2099 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2100 #endif
2102 glViewport (0, 0, allocation.width, allocation.height);
2104 #if 0 /* We disable the scissor test here, as it is interacting badly with
2105 * being handed expose events which don't cover the whole window.
2106 * As we have a double-buffered GL window, we end up with unintialised
2107 * contents remaining in the unpainted areas (outside the scissor
2108 * region), and these are being flipped onto the screen.
2110 * The debugging code below shows multiple expose events when the
2111 * window is shown the first time, some of which are very small.
2113 * XXX: There is clearly a perforamnce issue here, in that we may
2114 * be rendering the preview more times, and over a larger area
2115 * than is really required.
2118 glEnable (GL_SCISSOR_TEST);
2119 glScissor (ev->area.x,
2120 allocation.height - ev->area.height - ev->area.y,
2121 ev->area.width, ev->area.height);
2122 #endif
2124 #ifdef DEBUG
2125 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
2126 ev->area.x, ev->area.y, ev->area.width, ev->area.height,
2127 (double)ev->area.x,
2128 (double)(allocation.height - ev->area.height - ev->area.y),
2129 (double)ev->area.width,
2130 (double)ev->area.height);
2131 #endif
2133 glMatrixMode (GL_PROJECTION);
2134 glLoadIdentity ();
2135 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
2136 glMatrixMode (GL_MODELVIEW);
2137 glLoadIdentity ();
2138 glTranslatef (0.0f, 0.0f, -Z_NEAR);
2140 glClearColor (gport->bg_color.red / 65535.,
2141 gport->bg_color.green / 65535.,
2142 gport->bg_color.blue / 65535.,
2143 1.);
2144 glStencilMask (~0);
2145 glClearStencil (0);
2146 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2147 hidgl_reset_stencil_usage (priv->hidgl);
2149 /* Disable the stencil test until we need it - otherwise it gets dirty */
2150 glDisable (GL_STENCIL_TEST);
2151 glStencilMask (0);
2152 glStencilFunc (GL_ALWAYS, 0, 0);
2154 /* call the drawing routine */
2155 ghid_invalidate_current_gc ();
2156 glPushMatrix ();
2157 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
2158 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
2159 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
2160 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
2161 -gport->view.x0,
2162 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
2163 -gport->view.y0, 0);
2165 hid_expose_callback (&ghid_graphics, NULL, pinout->element);
2166 hidgl_flush_triangles (priv->hidgl);
2167 glPopMatrix ();
2169 ghid_end_drawing (gport, widget);
2171 gport->view = save_view;
2172 gport->width = save_width;
2173 gport->height = save_height;
2174 PCB->MaxWidth = save_max_width;
2175 PCB->MaxHeight = save_max_height;
2177 return FALSE;
2181 GdkPixmap *
2182 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
2184 render_priv *priv = gport->render_priv;
2185 GdkGLConfig *glconfig;
2186 GdkPixmap *pixmap;
2187 GdkGLPixmap *glpixmap;
2188 GdkGLContext* glcontext;
2189 GdkGLDrawable* gldrawable;
2190 view_data save_view;
2191 int save_width, save_height;
2192 BoxType region;
2194 save_view = gport->view;
2195 save_width = gport->width;
2196 save_height = gport->height;
2198 /* Setup rendering context for drawing routines
2201 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
2202 GDK_GL_MODE_STENCIL |
2203 GDK_GL_MODE_SINGLE);
2205 pixmap = gdk_pixmap_new (NULL, width, height, depth);
2206 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
2207 gldrawable = GDK_GL_DRAWABLE (glpixmap);
2208 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
2210 /* Setup zoom factor for drawing routines */
2212 gport->view.coord_per_px = zoom;
2213 gport->width = width;
2214 gport->height = height;
2215 gport->view.width = width * gport->view.coord_per_px;
2216 gport->view.height = height * gport->view.coord_per_px;
2217 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
2218 gport->view.x0 -= gport->view.height / 2;
2219 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
2220 gport->view.y0 -= gport->view.width / 2;
2222 /* make GL-context "current" */
2223 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
2224 return NULL;
2226 hidgl_start_render (priv->hidgl);
2227 gport->render_priv->in_context = true;
2229 glEnable (GL_BLEND);
2230 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2232 glViewport (0, 0, width, height);
2234 glEnable (GL_SCISSOR_TEST);
2235 glScissor (0, 0, width, height);
2237 glMatrixMode (GL_PROJECTION);
2238 glLoadIdentity ();
2239 glOrtho (0, width, height, 0, -100000, 100000);
2240 glMatrixMode (GL_MODELVIEW);
2241 glLoadIdentity ();
2242 glTranslatef (0.0f, 0.0f, -Z_NEAR);
2244 glClearColor (gport->bg_color.red / 65535.,
2245 gport->bg_color.green / 65535.,
2246 gport->bg_color.blue / 65535.,
2247 1.);
2248 glStencilMask (~0);
2249 glClearStencil (0);
2250 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2251 hidgl_reset_stencil_usage (priv->hidgl);
2253 /* Disable the stencil test until we need it - otherwise it gets dirty */
2254 glDisable (GL_STENCIL_TEST);
2255 glStencilMask (0);
2256 glStencilFunc (GL_ALWAYS, 0, 0);
2258 /* call the drawing routine */
2259 ghid_invalidate_current_gc ();
2260 glPushMatrix ();
2261 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
2262 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
2263 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
2264 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
2265 -gport->view.x0,
2266 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
2267 -gport->view.y0, 0);
2269 region.X1 = MIN(Px(0), Px(gport->width + 1));
2270 region.Y1 = MIN(Py(0), Py(gport->height + 1));
2271 region.X2 = MAX(Px(0), Px(gport->width + 1));
2272 region.Y2 = MAX(Py(0), Py(gport->height + 1));
2274 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
2275 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
2276 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
2277 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
2279 hid_expose_callback (&ghid_graphics, &region, NULL);
2280 hidgl_flush_triangles (priv->hidgl);
2281 glPopMatrix ();
2283 glFlush ();
2285 hidgl_finish_render (priv->hidgl);
2287 /* end drawing to current GL-context */
2288 gport->render_priv->in_context = false;
2289 gdk_gl_drawable_gl_end (gldrawable);
2291 gdk_pixmap_unset_gl_capability (pixmap);
2293 g_object_unref (glconfig);
2294 g_object_unref (glcontext);
2296 gport->view = save_view;
2297 gport->width = save_width;
2298 gport->height = save_height;
2300 return pixmap;
2303 HID_DRAW *
2304 ghid_request_debug_draw (void)
2306 GHidPort *port = gport;
2307 GtkWidget *widget = port->drawing_area;
2308 GtkAllocation allocation;
2310 gtk_widget_get_allocation (widget, &allocation);
2312 ghid_start_drawing (port, widget);
2314 glViewport (0, 0, allocation.width, allocation.height);
2316 glMatrixMode (GL_PROJECTION);
2317 glLoadIdentity ();
2318 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
2319 glMatrixMode (GL_MODELVIEW);
2320 glLoadIdentity ();
2321 glTranslatef (0.0f, 0.0f, -Z_NEAR);
2323 ghid_invalidate_current_gc ();
2325 /* Setup stenciling */
2326 glDisable (GL_STENCIL_TEST);
2328 glPushMatrix ();
2329 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
2330 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
2331 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
2332 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
2333 -port->view.x0,
2334 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
2335 -port->view.y0, 0);
2337 return &ghid_graphics;
2340 void
2341 ghid_flush_debug_draw (void)
2343 render_priv *priv = gport->render_priv;
2344 GtkWidget *widget = gport->drawing_area;
2345 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
2347 hidgl_flush_triangles (priv->hidgl);
2349 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
2350 gdk_gl_drawable_swap_buffers (pGlDrawable);
2351 else
2352 glFlush ();
2355 void
2356 ghid_finish_debug_draw (void)
2358 render_priv *priv = gport->render_priv;
2360 hidgl_flush_triangles (priv->hidgl);
2361 glPopMatrix ();
2363 ghid_end_drawing (gport, gport->drawing_area);
2366 static float
2367 determinant_2x2 (float m[2][2])
2369 float det;
2370 det = m[0][0] * m[1][1] -
2371 m[0][1] * m[1][0];
2372 return det;
2375 #if 0
2376 static float
2377 determinant_4x4 (float m[4][4])
2379 float det;
2380 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] -
2381 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
2382 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
2383 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
2384 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
2385 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
2386 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
2387 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
2388 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
2389 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
2390 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
2391 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
2392 return det;
2394 #endif
2396 static void
2397 invert_2x2 (float m[2][2], float out[2][2])
2399 float scale = 1 / determinant_2x2 (m);
2400 out[0][0] = m[1][1] * scale;
2401 out[0][1] = -m[0][1] * scale;
2402 out[1][0] = -m[1][0] * scale;
2403 out[1][1] = m[0][0] * scale;
2406 #if 0
2407 static void
2408 invert_4x4 (float m[4][4], float out[4][4])
2410 float scale = 1 / determinant_4x4 (m);
2412 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
2413 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
2414 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
2415 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
2416 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
2417 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
2418 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
2419 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
2420 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
2421 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
2422 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
2423 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
2424 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
2425 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
2426 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
2427 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
2428 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
2429 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
2430 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
2431 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
2432 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
2433 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
2434 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
2435 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
2436 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
2437 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
2438 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
2439 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
2440 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
2441 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
2442 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
2443 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
2444 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
2445 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
2446 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
2447 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
2448 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
2449 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
2450 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
2451 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
2452 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
2453 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
2454 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
2455 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
2456 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
2457 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
2458 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
2459 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
2461 #endif
2464 static void
2465 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
2467 float mat[2][2];
2468 float inv_mat[2][2];
2469 float x, y;
2472 ex = view_matrix[0][0] * vx +
2473 view_matrix[0][1] * vy +
2474 view_matrix[0][2] * vz +
2475 view_matrix[0][3] * 1;
2476 ey = view_matrix[1][0] * vx +
2477 view_matrix[1][1] * vy +
2478 view_matrix[1][2] * vz +
2479 view_matrix[1][3] * 1;
2480 UNKNOWN ez = view_matrix[2][0] * vx +
2481 view_matrix[2][1] * vy +
2482 view_matrix[2][2] * vz +
2483 view_matrix[2][3] * 1;
2485 ex - view_matrix[0][3] * 1
2486 - view_matrix[0][2] * vz
2487 = view_matrix[0][0] * vx +
2488 view_matrix[0][1] * vy;
2490 ey - view_matrix[1][3] * 1
2491 - view_matrix[1][2] * vz
2492 = view_matrix[1][0] * vx +
2493 view_matrix[1][1] * vy;
2496 /* NB: last_modelview_matrix is transposed in memory! */
2497 x = (float)ex - last_modelview_matrix[3][0] * 1
2498 - last_modelview_matrix[2][0] * pcb_z;
2500 y = (float)ey - last_modelview_matrix[3][1] * 1
2501 - last_modelview_matrix[2][1] * pcb_z;
2504 x = view_matrix[0][0] * vx +
2505 view_matrix[0][1] * vy;
2507 y = view_matrix[1][0] * vx +
2508 view_matrix[1][1] * vy;
2510 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
2511 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
2514 mat[0][0] = last_modelview_matrix[0][0];
2515 mat[0][1] = last_modelview_matrix[1][0];
2516 mat[1][0] = last_modelview_matrix[0][1];
2517 mat[1][1] = last_modelview_matrix[1][1];
2519 /* if (determinant_2x2 (mat) < 0.00001) */
2520 /* printf ("Determinant is quite small\n"); */
2522 invert_2x2 (mat, inv_mat);
2524 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
2525 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
2529 bool
2530 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
2532 render_priv *priv = gport->render_priv;
2534 ghid_unproject_to_z_plane (event_x, event_y, priv->edit_depth, pcb_x, pcb_y);
2536 return true;
2539 bool
2540 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
2542 render_priv *priv = gport->render_priv;
2544 /* NB: last_modelview_matrix is transposed in memory */
2545 float w = last_modelview_matrix[0][3] * (float)pcb_x +
2546 last_modelview_matrix[1][3] * (float)pcb_y +
2547 last_modelview_matrix[2][3] * 0. +
2548 last_modelview_matrix[3][3] * 1.;
2550 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
2551 last_modelview_matrix[1][0] * (float)pcb_y +
2552 last_modelview_matrix[2][0] * priv->edit_depth +
2553 last_modelview_matrix[3][0] * 1.) / w;
2554 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
2555 last_modelview_matrix[1][1] * (float)pcb_y +
2556 last_modelview_matrix[2][1] * priv->edit_depth +
2557 last_modelview_matrix[3][1] * 1.) / w;
2559 return true;
2562 void
2563 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
2565 global_view_2d = view_2d;
2566 ghid_invalidate_all ();
2569 void
2570 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
2572 #ifdef DEBUG_ROTATE
2573 int row, column;
2574 #endif
2576 build_rotmatrix (view_matrix, quarternion);
2578 #ifdef DEBUG_ROTATE
2579 for (row = 0; row < 4; row++) {
2580 printf ("[ %f", view_matrix[row][0]);
2581 for (column = 1; column < 4; column++) {
2582 printf (",\t%f", view_matrix[row][column]);
2584 printf ("\t]\n");
2586 printf ("\n");
2587 #endif
2589 ghid_invalidate_all ();
2593 #define LEAD_USER_WIDTH 0.2 /* millimeters */
2594 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
2595 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
2596 #define LEAD_USER_ARC_COUNT 3
2597 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
2598 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
2599 #define LEAD_USER_COLOR_R 1.
2600 #define LEAD_USER_COLOR_G 1.
2601 #define LEAD_USER_COLOR_B 0.
2603 static void
2604 draw_lead_user (hidGC gc, render_priv *priv)
2606 gtkGC gtk_gc = (gtkGC)gc;
2607 int i;
2608 double radius = priv->lead_user_radius;
2609 double width = MM_TO_COORD (LEAD_USER_WIDTH);
2610 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
2612 if (!priv->lead_user)
2613 return;
2615 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
2616 glEnable (GL_COLOR_LOGIC_OP);
2617 glLogicOp (GL_XOR);
2618 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
2621 /* arcs at the approrpriate radii */
2623 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
2625 if (radius < width)
2626 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
2628 /* Draw an arc at radius */
2629 hidgl_draw_arc (gc, width, priv->lead_user_x, priv->lead_user_y,
2630 radius, radius, 0, 360, gport->view.coord_per_px);
2633 hidgl_flush_triangles (gtk_gc->hidgl_gc.hidgl);
2634 glPopAttrib ();
2637 gboolean
2638 lead_user_cb (gpointer data)
2640 render_priv *priv = data;
2641 Coord step;
2642 double elapsed_time;
2644 /* Queue a redraw */
2645 ghid_invalidate_all ();
2647 /* Update radius */
2648 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
2649 g_timer_start (priv->lead_user_timer);
2651 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
2652 if (priv->lead_user_radius > step)
2653 priv->lead_user_radius -= step;
2654 else
2655 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
2657 return TRUE;
2660 void
2661 ghid_lead_user_to_location (Coord x, Coord y)
2663 render_priv *priv = gport->render_priv;
2665 ghid_cancel_lead_user ();
2667 priv->lead_user = true;
2668 priv->lead_user_x = x;
2669 priv->lead_user_y = y;
2670 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
2671 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
2672 priv->lead_user_timer = g_timer_new ();
2675 void
2676 ghid_cancel_lead_user (void)
2678 render_priv *priv = gport->render_priv;
2680 if (priv->lead_user_timeout)
2681 g_source_remove (priv->lead_user_timeout);
2683 if (priv->lead_user_timer)
2684 g_timer_destroy (priv->lead_user_timer);
2686 if (priv->lead_user)
2687 ghid_invalidate_all ();
2689 priv->lead_user_timeout = 0;
2690 priv->lead_user_timer = NULL;
2691 priv->lead_user = false;