gtk/gl: Play with layer translucency
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blob14204eba2d07bc0c49747ffb0aa120ebcf75fb6e
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 "gui-pinout-preview.h"
16 /* The Linux OpenGL ABI 1.0 spec requires that we define
17 * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
18 * in order to get prototypes:
19 * http://www.opengl.org/registry/ABI/
22 #define GL_GLEXT_PROTOTYPES 1
23 #ifdef HAVE_OPENGL_GL_H
24 # include <OpenGL/gl.h>
25 #else
26 # include <GL/gl.h>
27 #endif
29 #include <gtk/gtkgl.h>
30 #include "hid/common/hidgl.h"
32 #include "hid/common/draw_helpers.h"
33 #include "hid/common/trackball.h"
35 #ifdef HAVE_LIBDMALLOC
36 #include <dmalloc.h>
37 #endif
39 extern HID ghid_hid;
40 extern HID_DRAW ghid_graphics;
41 extern HID_DRAW_CLASS ghid_graphics_class;
43 static hidGC current_gc = NULL;
45 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
47 #define USE_GC(gc) if (!use_gc(gc)) return
49 static enum mask_mode cur_mask = HID_MASK_OFF;
50 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
51 {0.0, 1.0, 0.0, 0.0},
52 {0.0, 0.0, 1.0, 0.0},
53 {0.0, 0.0, 0.0, 1.0}};
54 static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
55 {0.0, 1.0, 0.0, 0.0},
56 {0.0, 0.0, 1.0, 0.0},
57 {0.0, 0.0, 0.0, 1.0}};
58 static int global_view_2d = 1;
60 typedef struct render_priv {
61 GdkGLConfig *glconfig;
62 bool trans_lines;
63 bool in_context;
64 int subcomposite_stencil_bit;
65 char *current_colorname;
66 double current_alpha_mult;
67 GTimer *time_since_expose;
69 /* Feature for leading the user to a particular location */
70 guint lead_user_timeout;
71 GTimer *lead_user_timer;
72 bool lead_user;
73 Coord lead_user_radius;
74 Coord lead_user_x;
75 Coord lead_user_y;
77 hidgl_instance *hidgl;
78 GList *active_gc_list;
79 double edit_depth;
81 } render_priv;
83 typedef struct gtk_gc_struct
85 struct hidgl_gc_struct hidgl_gc; /* Parent */
87 const char *colorname;
88 double alpha_mult;
89 Coord width;
90 gint cap, join;
91 } *gtkGC;
93 static void draw_lead_user (hidGC gc, render_priv *priv);
94 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
97 #define BOARD_THICKNESS MM_TO_COORD(1.60)
98 #define MASK_COPPER_SPACING MM_TO_COORD(0.05)
99 #define SILK_MASK_SPACING MM_TO_COORD(0.01)
100 static int
101 compute_depth (int group)
103 static int last_depth_computed = 0;
105 int top_group;
106 int bottom_group;
107 int min_copper_group;
108 int max_copper_group;
109 int num_copper_groups;
110 int middle_copper_group;
111 int depth;
113 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
114 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
116 min_copper_group = MIN (bottom_group, top_group);
117 max_copper_group = MAX (bottom_group, top_group);
118 num_copper_groups = max_copper_group - min_copper_group + 1;
119 middle_copper_group = min_copper_group + num_copper_groups / 2;
121 if (group >= 0 && group < max_group) {
122 if (group >= min_copper_group && group <= max_copper_group) {
123 /* XXX: IS THIS INCORRECT FOR REVERSED GROUP ORDERINGS? */
124 depth = -(group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups;
125 } else {
126 depth = 0;
129 } else if (SL_TYPE (group) == SL_MASK) {
130 if (SL_SIDE (group) == SL_TOP_SIDE) {
131 depth = -((min_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups - MASK_COPPER_SPACING);
132 } else {
133 depth = -((max_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups + MASK_COPPER_SPACING);
135 } else if (SL_TYPE (group) == SL_SILK) {
136 if (SL_SIDE (group) == SL_TOP_SIDE) {
137 depth = -((min_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups - MASK_COPPER_SPACING - SILK_MASK_SPACING);
138 } else {
139 depth = -((max_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups + MASK_COPPER_SPACING + SILK_MASK_SPACING);
142 } else if (SL_TYPE (group) == SL_INVISIBLE) {
143 /* Same as silk, but for the back-side layer */
144 if (Settings.ShowBottomSide) {
145 depth = -((min_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups - MASK_COPPER_SPACING - SILK_MASK_SPACING);
146 } else {
147 depth = -((max_copper_group - middle_copper_group) * BOARD_THICKNESS / num_copper_groups + MASK_COPPER_SPACING + SILK_MASK_SPACING);
149 } else if (SL_TYPE (group) == SL_RATS ||
150 SL_TYPE (group) == SL_PDRILL ||
151 SL_TYPE (group) == SL_UDRILL) {
152 /* Draw these at the depth we last rendered at */
153 depth = last_depth_computed;
154 } else if (SL_TYPE (group) == SL_PASTE ||
155 SL_TYPE (group) == SL_FAB ||
156 SL_TYPE (group) == SL_ASSY) {
157 /* Layer types we don't use, which draw.c asks us about, so
158 * we just return _something_ to avoid the warnign below. */
159 depth = last_depth_computed;
160 } else {
161 /* DEFAULT CASE */
162 printf ("Unknown layer group to set depth for: %i\n", group);
163 depth = last_depth_computed;
166 last_depth_computed = depth;
167 return depth;
170 static void
171 start_subcomposite (hidgl_instance *hidgl)
173 render_priv *priv = gport->render_priv;
174 int stencil_bit;
176 /* Flush out any existing geoemtry to be rendered */
177 hidgl_flush_triangles (hidgl);
179 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
180 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
182 stencil_bit = hidgl_assign_clear_stencil_bit (hidgl); /* Get a new (clean) bitplane to stencil with */
183 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
184 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */
186 priv->subcomposite_stencil_bit = stencil_bit;
189 static void
190 end_subcomposite (hidgl_instance *hidgl)
192 render_priv *priv = gport->render_priv;
194 /* Flush out any existing geoemtry to be rendered */
195 hidgl_flush_triangles (hidgl);
197 hidgl_return_stencil_bit (hidgl, priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */
199 glStencilMask (0);
200 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */
201 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
203 priv->subcomposite_stencil_bit = 0;
206 static void
207 set_depth_on_all_active_gc (render_priv *priv, float depth)
209 GList *iter;
211 for (iter = priv->active_gc_list;
212 iter != NULL;
213 iter = g_list_next (iter))
215 hidGC gc = iter->data;
217 hidgl_set_depth (gc, depth);
221 /* Compute group visibility based upon on copper layers only */
222 static bool
223 is_layer_group_visible (int group)
225 int entry;
226 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
228 int layer_idx = PCB->LayerGroups.Entries[group][entry];
229 if (layer_idx >= 0 && layer_idx < max_copper_layer &&
230 LAYER_PTR (layer_idx)->On)
231 return true;
233 return false;
237 ghid_set_layer (const char *name, int group, int empty)
239 render_priv *priv = gport->render_priv;
240 hidgl_instance *hidgl = priv->hidgl;
241 bool group_visible = false;
242 bool subcomposite = true;
244 if (group >= 0 && group < max_group)
246 priv->trans_lines = true;
247 subcomposite = true;
248 group_visible = is_layer_group_visible (group);
250 else
252 switch (SL_TYPE (group))
254 case SL_INVISIBLE:
255 priv->trans_lines = false;
256 subcomposite = false;
257 group_visible = PCB->InvisibleObjectsOn;
258 break;
259 case SL_MASK:
260 priv->trans_lines = true;
261 subcomposite = false;
262 group_visible = TEST_FLAG (SHOWMASKFLAG, PCB);
263 break;
264 case SL_SILK:
265 priv->trans_lines = true;
266 subcomposite = true;
267 group_visible = PCB->ElementOn;
268 break;
269 case SL_ASSY:
270 break;
271 case SL_PDRILL:
272 case SL_UDRILL:
273 priv->trans_lines = true;
274 subcomposite = true;
275 group_visible = true;
276 break;
277 case SL_RATS:
278 priv->trans_lines = true;
279 subcomposite = false;
280 group_visible = PCB->RatOn;
281 break;
285 end_subcomposite (hidgl);
287 if (group_visible && subcomposite)
288 start_subcomposite (hidgl);
290 /* Drawing is already flushed by {start,end}_subcomposite */
291 set_depth_on_all_active_gc (priv, compute_depth (group));
293 return group_visible;
296 static void
297 ghid_end_layer ()
299 render_priv *priv = gport->render_priv;
300 hidgl_instance *hidgl = priv->hidgl;
302 end_subcomposite (hidgl);
305 void
306 ghid_destroy_gc (hidGC gc)
308 render_priv *priv = gport->render_priv;
310 priv->active_gc_list = g_list_remove (priv->active_gc_list, gc);
312 hidgl_finish_gc (gc);
313 g_free (gc);
316 hidGC
317 ghid_make_gc (void)
319 render_priv *priv = gport->render_priv;
320 hidGC gc = (hidGC) g_new0 (struct gtk_gc_struct, 1);
321 gtkGC gtk_gc = (gtkGC)gc;
323 gc->hid = &ghid_hid;
324 gc->hid_draw = &ghid_graphics;
326 hidgl_init_gc (priv->hidgl, gc);
328 gtk_gc->colorname = Settings.BackgroundColor;
329 gtk_gc->alpha_mult = 1.0;
331 priv->active_gc_list = g_list_prepend (priv->active_gc_list, gc);
333 return gc;
336 static void
337 ghid_draw_grid (hidGC gc, BoxType *drawn_area)
339 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
340 return;
342 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
344 gport->grid_color.red ^= gport->bg_color.red;
345 gport->grid_color.green ^= gport->bg_color.green;
346 gport->grid_color.blue ^= gport->bg_color.blue;
349 glDisable (GL_STENCIL_TEST);
350 glEnable (GL_COLOR_LOGIC_OP);
351 glLogicOp (GL_XOR);
353 glColor3f (gport->grid_color.red / 65535.,
354 gport->grid_color.green / 65535.,
355 gport->grid_color.blue / 65535.);
357 hidgl_draw_grid (gc, drawn_area);
359 glDisable (GL_COLOR_LOGIC_OP);
360 glEnable (GL_STENCIL_TEST);
363 static void
364 ghid_draw_bg_image (void)
366 static GLuint texture_handle = 0;
368 if (!ghidgui->bg_pixbuf)
369 return;
371 if (texture_handle == 0)
373 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
374 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
375 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
376 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
377 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
378 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
380 g_warn_if_fail (bits_per_sample == 8);
381 g_warn_if_fail (rowstride == width * n_channels);
383 glGenTextures (1, &texture_handle);
384 glBindTexture (GL_TEXTURE_2D, texture_handle);
386 /* XXX: We should proabbly determine what the maxmimum texture supported is,
387 * and if our image is larger, shrink it down using GDK pixbuf routines
388 * rather than having it fail below.
391 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
392 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
395 glBindTexture (GL_TEXTURE_2D, texture_handle);
397 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
398 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
399 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
400 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
401 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
402 glEnable (GL_TEXTURE_2D);
404 /* Render a quad with the background as a texture */
406 glBegin (GL_QUADS);
407 glTexCoord2d (0., 0.);
408 glVertex3i (0, 0, 0);
409 glTexCoord2d (1., 0.);
410 glVertex3i (PCB->MaxWidth, 0, 0);
411 glTexCoord2d (1., 1.);
412 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
413 glTexCoord2d (0., 1.);
414 glVertex3i (0, PCB->MaxHeight, 0);
415 glEnd ();
417 glDisable (GL_TEXTURE_2D);
420 void
421 ghid_use_mask (enum mask_mode mode)
423 render_priv *priv = gport->render_priv;
424 hidgl_instance *hidgl = priv->hidgl;
425 static int stencil_bit = 0;
427 if (mode == cur_mask)
428 return;
430 /* Flush out any existing geoemtry to be rendered */
431 hidgl_flush_triangles (hidgl);
433 switch (mode)
435 case HID_MASK_BEFORE:
436 /* The HID asks not to receive this mask type, so warn if we get it */
437 g_return_if_reached ();
439 case HID_MASK_CLEAR:
440 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
441 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
442 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
443 stencil_bit = hidgl_assign_clear_stencil_bit (hidgl); /* Get a new (clean) bitplane to stencil with */
444 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */
445 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
446 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
447 break;
449 case HID_MASK_AFTER:
450 /* Drawing operations as masked to areas where the stencil buffer is '0' */
451 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
452 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */
453 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */
454 break;
456 case HID_MASK_OFF:
457 /* Disable stenciling */
458 hidgl_return_stencil_bit (hidgl, stencil_bit); /* Relinquish any bitplane we previously used */
459 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
460 break;
462 cur_mask = mode;
466 /* Config helper functions for when the user changes color preferences.
467 | set_special colors used in the gtkhid.
469 static void
470 set_special_grid_color (void)
472 if (!gport->colormap)
473 return;
474 gport->grid_color.red ^= gport->bg_color.red;
475 gport->grid_color.green ^= gport->bg_color.green;
476 gport->grid_color.blue ^= gport->bg_color.blue;
479 void
480 ghid_set_special_colors (HID_Attribute * ha)
482 if (!ha->name || !ha->value)
483 return;
484 if (!strcmp (ha->name, "background-color"))
486 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
487 set_special_grid_color ();
489 else if (!strcmp (ha->name, "off-limit-color"))
491 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
493 else if (!strcmp (ha->name, "grid-color"))
495 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
496 set_special_grid_color ();
500 typedef struct
502 int color_set;
503 GdkColor color;
504 double red;
505 double green;
506 double blue;
507 } ColorCache;
509 static void
510 set_gl_color_for_gc (hidGC gc)
512 gtkGC gtk_gc = (gtkGC)gc;
513 render_priv *priv = gport->render_priv;
514 static void *cache = NULL;
515 hidval cval;
516 ColorCache *cc;
517 double r, g, b, a;
519 if (priv->current_colorname != NULL &&
520 strcmp (priv->current_colorname, gtk_gc->colorname) == 0 &&
521 priv->current_alpha_mult == gtk_gc->alpha_mult)
522 return;
524 free (priv->current_colorname);
525 priv->current_colorname = strdup (gtk_gc->colorname);
526 priv->current_alpha_mult = gtk_gc->alpha_mult;
528 if (gport->colormap == NULL)
529 gport->colormap = gtk_widget_get_colormap (gport->top_window);
530 if (strcmp (gtk_gc->colorname, "erase") == 0)
532 r = gport->bg_color.red / 65535.;
533 g = gport->bg_color.green / 65535.;
534 b = gport->bg_color.blue / 65535.;
535 a = 1.0;
537 else if (strcmp (gtk_gc->colorname, "drill") == 0)
539 r = gport->offlimits_color.red / 65535.;
540 g = gport->offlimits_color.green / 65535.;
541 b = gport->offlimits_color.blue / 65535.;
542 a = 0.85;
544 else
546 if (hid_cache_color (0, gtk_gc->colorname, &cval, &cache))
547 cc = (ColorCache *) cval.ptr;
548 else
550 cc = (ColorCache *) malloc (sizeof (ColorCache));
551 memset (cc, 0, sizeof (*cc));
552 cval.ptr = cc;
553 hid_cache_color (1, gtk_gc->colorname, &cval, &cache);
556 if (!cc->color_set)
558 if (gdk_color_parse (gtk_gc->colorname, &cc->color))
559 gdk_color_alloc (gport->colormap, &cc->color);
560 else
561 gdk_color_white (gport->colormap, &cc->color);
562 cc->red = cc->color.red / 65535.;
563 cc->green = cc->color.green / 65535.;
564 cc->blue = cc->color.blue / 65535.;
565 cc->color_set = 1;
567 r = cc->red;
568 g = cc->green;
569 b = cc->blue;
570 a = 0.7;
572 if (1) {
573 double maxi, mult;
574 a *= gtk_gc->alpha_mult;
575 if (!priv->trans_lines)
576 a = 1.0;
577 maxi = r;
578 if (g > maxi) maxi = g;
579 if (b > maxi) maxi = b;
580 mult = MIN (1 / a, 1 / maxi);
581 #if 1
582 r = r * mult;
583 g = g * mult;
584 b = b * mult;
585 #endif
588 if(!priv->in_context)
589 return;
591 hidgl_flush_triangles (gtk_gc->hidgl_gc.hidgl);
592 glColor4d (r, g, b, a);
595 void
596 ghid_set_color (hidGC gc, const char *name)
598 gtkGC gtk_gc = (gtkGC)gc;
600 gtk_gc->colorname = name;
601 set_gl_color_for_gc (gc);
604 void
605 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
607 gtkGC gtk_gc = (gtkGC)gc;
609 gtk_gc->alpha_mult = alpha_mult;
610 set_gl_color_for_gc (gc);
613 void
614 ghid_set_line_cap (hidGC gc, EndCapStyle style)
616 gtkGC gtk_gc = (gtkGC)gc;
618 gtk_gc->cap = style;
621 void
622 ghid_set_line_width (hidGC gc, Coord width)
624 gtkGC gtk_gc = (gtkGC)gc;
626 gtk_gc->width = width;
630 void
631 ghid_set_draw_xor (hidGC gc, int xor)
633 /* NOT IMPLEMENTED */
635 /* Only presently called when setting up a crosshair GC.
636 * We manage our own drawing model for that anyway. */
639 void
640 ghid_set_draw_faded (hidGC gc, int faded)
642 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
645 void
646 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
648 printf ("ghid_set_line_cap_angle() -- not implemented\n");
651 static void
652 ghid_invalidate_current_gc (void)
654 current_gc = NULL;
657 static int
658 use_gc (hidGC gc)
660 if (gc->hid != &ghid_hid)
662 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
663 abort ();
666 if (current_gc == gc)
667 return 1;
669 current_gc = gc;
671 set_gl_color_for_gc (gc);
672 return 1;
675 void
676 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
678 gtkGC gtk_gc = (gtkGC)gc;
679 USE_GC (gc);
681 hidgl_draw_line (gc, gtk_gc->cap, gtk_gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
684 void
685 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
686 Angle start_angle, Angle delta_angle)
688 gtkGC gtk_gc = (gtkGC)gc;
689 USE_GC (gc);
691 hidgl_draw_arc (gc, gtk_gc->width, cx, cy, xradius, yradius,
692 start_angle, delta_angle, gport->view.coord_per_px);
695 void
696 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
698 USE_GC (gc);
700 hidgl_draw_rect (gc, x1, y1, x2, y2);
704 void
705 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
707 USE_GC (gc);
709 hidgl_fill_circle (gc, cx, cy, radius, gport->view.coord_per_px);
713 void
714 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
716 USE_GC (gc);
718 hidgl_fill_polygon (gc, n_coords, x, y);
721 void
722 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
724 USE_GC (gc);
726 hidgl_fill_pcb_polygon (gc, poly, clip_box, gport->view.coord_per_px);
729 void
730 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
732 gtkGC gtk_gc = (gtkGC)gc;
734 double old_alpha_mult = gtk_gc->alpha_mult;
735 common_thindraw_pcb_polygon (gc, poly, clip_box);
736 ghid_set_alpha_mult (gc, gtk_gc->alpha_mult * 0.25);
737 hid_draw_fill_pcb_polygon (gc, poly, clip_box);
738 ghid_set_alpha_mult (gc, old_alpha_mult);
741 void
742 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
744 USE_GC (gc);
746 hidgl_fill_rect (gc, x1, y1, x2, y2);
749 void
750 ghid_invalidate_lr (int left, int right, int top, int bottom)
752 ghid_invalidate_all ();
755 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
756 void
757 ghid_invalidate_all ()
759 render_priv *priv = gport->render_priv;
760 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
762 ghid_draw_area_update (gport, NULL);
764 if (elapsed > MAX_ELAPSED)
765 gdk_window_process_all_updates ();
768 void
769 ghid_notify_crosshair_change (bool changes_complete)
771 /* We sometimes get called before the GUI is up */
772 if (gport->drawing_area == NULL)
773 return;
775 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
776 ghid_invalidate_all ();
779 void
780 ghid_notify_mark_change (bool changes_complete)
782 /* We sometimes get called before the GUI is up */
783 if (gport->drawing_area == NULL)
784 return;
786 /* FIXME: We could just invalidate the bounds of the mark? */
787 ghid_invalidate_all ();
790 static void
791 draw_right_cross (gint x, gint y, gint z)
793 glVertex3i (x, 0, z);
794 glVertex3i (x, PCB->MaxHeight, z);
795 glVertex3i (0, y, z);
796 glVertex3i (PCB->MaxWidth, y, z);
799 static void
800 draw_slanted_cross (gint x, gint y, gint z)
802 gint x0, y0, x1, y1;
804 x0 = x + (PCB->MaxHeight - y);
805 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
806 x1 = x - y;
807 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
808 y0 = y + (PCB->MaxWidth - x);
809 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
810 y1 = y - x;
811 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
812 glVertex3i (x0, y0, z);
813 glVertex3i (x1, y1, z);
815 x0 = x - (PCB->MaxHeight - y);
816 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
817 x1 = x + y;
818 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
819 y0 = y + x;
820 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
821 y1 = y - (PCB->MaxWidth - x);
822 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
823 glVertex3i (x0, y0, z);
824 glVertex3i (x1, y1, z);
827 static void
828 draw_dozen_cross (gint x, gint y, gint z)
830 gint x0, y0, x1, y1;
831 gdouble tan60 = sqrt (3);
833 x0 = x + (PCB->MaxHeight - y) / tan60;
834 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
835 x1 = x - y / tan60;
836 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
837 y0 = y + (PCB->MaxWidth - x) * tan60;
838 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
839 y1 = y - x * tan60;
840 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
841 glVertex3i (x0, y0, z);
842 glVertex3i (x1, y1, z);
844 x0 = x + (PCB->MaxHeight - y) * tan60;
845 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
846 x1 = x - y * tan60;
847 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
848 y0 = y + (PCB->MaxWidth - x) / tan60;
849 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
850 y1 = y - x / tan60;
851 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
852 glVertex3i (x0, y0, z);
853 glVertex3i (x1, y1, z);
855 x0 = x - (PCB->MaxHeight - y) / tan60;
856 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
857 x1 = x + y / tan60;
858 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
859 y0 = y + x * tan60;
860 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
861 y1 = y - (PCB->MaxWidth - x) * tan60;
862 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
863 glVertex3i (x0, y0, z);
864 glVertex3i (x1, y1, z);
866 x0 = x - (PCB->MaxHeight - y) * tan60;
867 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
868 x1 = x + y * tan60;
869 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
870 y0 = y + x / tan60;
871 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
872 y1 = y - (PCB->MaxWidth - x) / tan60;
873 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
874 glVertex3i (x0, y0, z);
875 glVertex3i (x1, y1, z);
878 static void
879 draw_crosshair (hidGC gc, render_priv *priv)
881 gtkGC gtk_gc = (gtkGC)gc;
882 gint x, y, z;
883 static int done_once = 0;
884 static GdkColor cross_color;
886 if (!done_once)
888 done_once = 1;
889 /* FIXME: when CrossColor changed from config */
890 ghid_map_color_string (Settings.CrossColor, &cross_color);
893 x = gport->crosshair_x;
894 y = gport->crosshair_y;
895 z = gtk_gc->hidgl_gc.depth;
897 glEnable (GL_COLOR_LOGIC_OP);
898 glLogicOp (GL_XOR);
900 glColor3f (cross_color.red / 65535.,
901 cross_color.green / 65535.,
902 cross_color.blue / 65535.);
904 glBegin (GL_LINES);
906 draw_right_cross (x, y, z);
907 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
908 draw_slanted_cross (x, y, z);
909 if (Crosshair.shape == Dozen_Crosshair_Shape)
910 draw_dozen_cross (x, y, z);
912 glEnd ();
914 glDisable (GL_COLOR_LOGIC_OP);
917 void
918 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
920 render_priv *priv;
922 port->render_priv = priv = g_new0 (render_priv, 1);
924 priv->time_since_expose = g_timer_new ();
926 gtk_gl_init(argc, argv);
928 /* setup GL-context */
929 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA |
930 GDK_GL_MODE_STENCIL |
931 GDK_GL_MODE_DOUBLE);
932 if (!priv->glconfig)
934 printf ("Could not setup GL-context!\n");
935 return; /* Should we abort? */
938 hidgl_init ();
939 priv->hidgl = hidgl_new_instance ();
941 /* Setup HID function pointers specific to the GL renderer*/
942 ghid_graphics_class.end_layer = ghid_end_layer;
943 ghid_graphics_class.fill_pcb_polygon = ghid_fill_pcb_polygon;
944 ghid_graphics_class.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
947 void
948 ghid_shutdown_renderer (GHidPort *port)
950 render_priv *priv = port->render_priv;
952 hidgl_free_instance (priv->hidgl);
954 ghid_cancel_lead_user ();
955 g_free (port->render_priv);
956 port->render_priv = NULL;
959 void
960 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
962 render_priv *priv = port->render_priv;
964 gtk_widget_set_gl_capability (widget,
965 priv->glconfig,
966 NULL,
967 TRUE,
968 GDK_GL_RGBA_TYPE);
971 void
972 ghid_drawing_area_configure_hook (GHidPort *port)
976 gboolean
977 ghid_start_drawing (GHidPort *port, GtkWidget *widget)
979 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
980 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
982 /* make GL-context "current" */
983 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
984 return FALSE;
986 port->render_priv->in_context = true;
988 hidgl_start_render (port->render_priv->hidgl);
990 return TRUE;
993 void
994 ghid_end_drawing (GHidPort *port, GtkWidget *widget)
996 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
998 hidgl_finish_render (port->render_priv->hidgl);
1000 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1001 gdk_gl_drawable_swap_buffers (pGlDrawable);
1002 else
1003 glFlush ();
1005 port->render_priv->in_context = false;
1007 /* end drawing to current GL-context */
1008 gdk_gl_drawable_gl_end (pGlDrawable);
1011 void
1012 ghid_screen_update (void)
1016 static int
1017 EMark_callback (const BoxType * b, void *cl)
1019 ElementType *element = (ElementType *) b;
1021 DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element));
1022 return 1;
1025 static void
1026 set_object_color (AnyObjectType *obj, char *warn_color, char *selected_color,
1027 char *connected_color, char *found_color, char *normal_color)
1029 char *color;
1031 if (warn_color != NULL && TEST_FLAG (WARNFLAG, obj)) color = warn_color;
1032 else if (selected_color != NULL && TEST_FLAG (SELECTEDFLAG, obj)) color = selected_color;
1033 else if (connected_color != NULL && TEST_FLAG (CONNECTEDFLAG, obj)) color = connected_color;
1034 else if (found_color != NULL && TEST_FLAG (FOUNDFLAG, obj)) color = found_color;
1035 else color = normal_color;
1037 hid_draw_set_color (Output.fgGC, color);
1040 static void
1041 set_layer_object_color (LayerType *layer, AnyObjectType *obj)
1043 set_object_color (obj, NULL, layer->SelectedColor, PCB->ConnectedColor, PCB->FoundColor, layer->Color);
1046 static void
1047 set_pv_inlayer_color (PinType *pv, LayerType *layer, int type)
1049 if (TEST_FLAG (WARNFLAG, pv)) hid_draw_set_color (Output.fgGC, PCB->WarnColor);
1050 else if (TEST_FLAG (SELECTEDFLAG, pv)) hid_draw_set_color (Output.fgGC, (type == VIA_TYPE) ? PCB->ViaSelectedColor
1051 : PCB->PinSelectedColor);
1052 else if (TEST_FLAG (CONNECTEDFLAG, pv)) hid_draw_set_color (Output.fgGC, PCB->ConnectedColor);
1053 else if (TEST_FLAG (FOUNDFLAG, pv)) hid_draw_set_color (Output.fgGC, PCB->FoundColor);
1054 else
1056 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1057 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1058 int this_group = GetLayerGroupNumberByPointer (layer);
1060 if (this_group == top_group || this_group == bottom_group)
1061 hid_draw_set_color (Output.fgGC, (SWAP_IDENT == (this_group == bottom_group)) ?
1062 PCB->ViaColor : PCB->InvisibleObjectsColor);
1063 else
1064 hid_draw_set_color (Output.fgGC, layer->Color);
1068 static void
1069 _draw_pv_name (PinType *pv)
1071 BoxType box;
1072 bool vert;
1073 TextType text;
1075 if (!pv->Name || !pv->Name[0])
1076 text.TextString = EMPTY (pv->Number);
1077 else
1078 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name);
1080 vert = TEST_FLAG (EDGE2FLAG, pv);
1082 if (vert)
1084 box.X1 = pv->X - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
1085 box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX;
1087 else
1089 box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX;
1090 box.Y1 = pv->Y - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
1093 hid_draw_set_color (Output.fgGC, PCB->PinNameColor);
1095 text.Flags = NoFlags ();
1096 /* Set font height to approx 56% of pin thickness */
1097 text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT;
1098 text.X = box.X1;
1099 text.Y = box.Y1;
1100 text.Direction = vert ? 1 : 0;
1102 hid_draw_pcb_text (Output.fgGC, &text, 0);
1105 static void
1106 _draw_pv (PinType *pv, bool draw_hole)
1108 if (TEST_FLAG (THINDRAWFLAG, PCB))
1109 hid_draw_thin_pcb_pv (Output.fgGC, Output.fgGC, pv, draw_hole, false);
1110 else
1111 hid_draw_fill_pcb_pv (Output.fgGC, Output.bgGC, pv, draw_hole, false);
1113 if (!TEST_FLAG (HOLEFLAG, pv) && TEST_FLAG (DISPLAYNAMEFLAG, pv))
1114 _draw_pv_name (pv);
1117 static void
1118 draw_pin (PinType *pin, bool draw_hole)
1120 set_object_color ((AnyObjectType *) pin, PCB->WarnColor, PCB->PinSelectedColor,
1121 PCB->ConnectedColor, PCB->FoundColor, PCB->PinColor);
1123 _draw_pv (pin, draw_hole);
1126 static int
1127 pin_callback (const BoxType * b, void *cl)
1129 draw_pin ((PinType *)b, TEST_FLAG (THINDRAWFLAG, PCB));
1130 return 1;
1133 static int
1134 pin_inlayer_callback (const BoxType * b, void *cl)
1136 set_pv_inlayer_color ((PinType *) b, cl, PIN_TYPE);
1137 _draw_pv ((PinType *) b, false);
1138 return 1;
1141 static void
1142 draw_via (PinType *via, bool draw_hole)
1144 set_object_color ((AnyObjectType *) via, PCB->WarnColor, PCB->ViaSelectedColor,
1145 PCB->ConnectedColor, PCB->FoundColor, PCB->ViaColor);
1147 _draw_pv (via, draw_hole);
1150 static int
1151 via_callback (const BoxType * b, void *cl)
1153 draw_via ((PinType *)b, TEST_FLAG (THINDRAWFLAG, PCB));
1154 return 1;
1157 static int
1158 via_inlayer_callback (const BoxType * b, void *cl)
1160 set_pv_inlayer_color ((PinType *) b, cl, VIA_TYPE);
1161 _draw_pv ((PinType *) b, TEST_FLAG (THINDRAWFLAG, PCB));
1162 return 1;
1165 static void
1166 draw_pad_name (PadType *pad)
1168 BoxType box;
1169 bool vert;
1170 TextType text;
1172 if (!pad->Name || !pad->Name[0])
1173 text.TextString = EMPTY (pad->Number);
1174 else
1175 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name);
1177 /* should text be vertical ? */
1178 vert = (pad->Point1.X == pad->Point2.X);
1180 if (vert)
1182 box.X1 = pad->Point1.X - pad->Thickness / 2;
1183 box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2;
1184 box.X1 += Settings.PinoutTextOffsetY;
1185 box.Y1 -= Settings.PinoutTextOffsetX;
1187 else
1189 box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2;
1190 box.Y1 = pad->Point1.Y - pad->Thickness / 2;
1191 box.X1 += Settings.PinoutTextOffsetX;
1192 box.Y1 += Settings.PinoutTextOffsetY;
1195 hid_draw_set_color (Output.fgGC, PCB->PinNameColor);
1197 text.Flags = NoFlags ();
1198 /* Set font height to approx 90% of pad thickness */
1199 text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT;
1200 text.X = box.X1;
1201 text.Y = box.Y1;
1202 text.Direction = vert ? 1 : 0;
1204 hid_draw_pcb_text (Output.fgGC, &text, 0);
1207 static void
1208 _draw_pad (hidGC gc, PadType *pad, bool clear, bool mask)
1210 if (clear && !mask && pad->Clearance <= 0)
1211 return;
1213 if (TEST_FLAG (THINDRAWFLAG, PCB) ||
1214 (clear && TEST_FLAG (THINDRAWPOLYFLAG, PCB)))
1215 hid_draw_thin_pcb_pad (gc, pad, clear, mask);
1216 else
1217 hid_draw_fill_pcb_pad (gc, pad, clear, mask);
1220 static void
1221 draw_pad (PadType *pad)
1223 set_object_color ((AnyObjectType *)pad, PCB->WarnColor,
1224 PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor,
1225 FRONT (pad) ? PCB->PinColor : PCB->InvisibleObjectsColor);
1227 _draw_pad (Output.fgGC, pad, false, false);
1229 if (TEST_FLAG (DISPLAYNAMEFLAG, pad))
1230 draw_pad_name (pad);
1233 static int
1234 pad_callback (const BoxType * b, void *cl)
1236 PadType *pad = (PadType *) b;
1237 int *side = cl;
1239 if (ON_SIDE (pad, *side))
1240 draw_pad (pad);
1241 return 1;
1245 static int
1246 hole_callback (const BoxType * b, void *cl)
1248 PinType *pv = (PinType *) b;
1249 int plated = cl ? *(int *) cl : -1;
1251 if ((plated == 0 && !TEST_FLAG (HOLEFLAG, pv)) ||
1252 (plated == 1 && TEST_FLAG (HOLEFLAG, pv)))
1253 return 1;
1255 if (TEST_FLAG (THINDRAWFLAG, PCB))
1257 if (!TEST_FLAG (HOLEFLAG, pv))
1259 hid_draw_set_line_cap (Output.fgGC, Round_Cap);
1260 hid_draw_set_line_width (Output.fgGC, 0);
1261 hid_draw_arc (Output.fgGC, pv->X, pv->Y,
1262 pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360);
1265 else
1266 hid_draw_fill_circle (Output.bgGC, pv->X, pv->Y, pv->DrillingHole / 2);
1268 if (TEST_FLAG (HOLEFLAG, pv))
1270 set_object_color ((AnyObjectType *) pv, PCB->WarnColor,
1271 PCB->ViaSelectedColor, NULL, NULL, Settings.BlackColor);
1273 hid_draw_set_line_cap (Output.fgGC, Round_Cap);
1274 hid_draw_set_line_width (Output.fgGC, 0);
1275 hid_draw_arc (Output.fgGC, pv->X, pv->Y,
1276 pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360);
1278 return 1;
1281 static int
1282 line_callback (const BoxType * b, void *cl)
1284 LayerType *layer = cl;
1285 LineType *line = (LineType *)b;
1287 set_layer_object_color (layer, (AnyObjectType *) line);
1288 hid_draw_pcb_line (Output.fgGC, line);
1289 return 1;
1292 static int
1293 arc_callback (const BoxType * b, void *cl)
1295 LayerType *layer = cl;
1296 ArcType *arc = (ArcType *)b;
1298 set_layer_object_color (layer, (AnyObjectType *) arc);
1299 hid_draw_pcb_arc (Output.fgGC, arc);
1300 return 1;
1303 static int
1304 text_callback (const BoxType * b, void *cl)
1306 LayerType *layer = cl;
1307 TextType *text = (TextType *)b;
1308 int min_silk_line;
1310 if (TEST_FLAG (SELECTEDFLAG, text))
1311 hid_draw_set_color (Output.fgGC, layer->SelectedColor);
1312 else
1313 hid_draw_set_color (Output.fgGC, layer->Color);
1314 if (layer == &PCB->Data->SILKLAYER ||
1315 layer == &PCB->Data->BACKSILKLAYER)
1316 min_silk_line = PCB->minSlk;
1317 else
1318 min_silk_line = PCB->minWid;
1319 hid_draw_pcb_text (Output.fgGC, text, min_silk_line);
1320 return 1;
1323 struct poly_info
1325 LayerType *layer;
1326 const BoxType *drawn_area;
1329 static int
1330 poly_callback (const BoxType * b, void *cl)
1332 struct poly_info *i = (struct poly_info *) cl;
1333 PolygonType *polygon = (PolygonType *)b;
1335 set_layer_object_color (i->layer, (AnyObjectType *) polygon);
1336 hid_draw_pcb_polygon (Output.fgGC, polygon, i->drawn_area);
1337 return 1;
1340 static int
1341 clearPin_callback (const BoxType * b, void *cl)
1343 PinType *pin = (PinType *) b;
1344 if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
1345 hid_draw_thin_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
1346 else
1347 hid_draw_fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
1348 return 1;
1351 static int
1352 clearPad_callback (const BoxType * b, void *cl)
1354 PadType *pad = (PadType *) b;
1355 int *side = cl;
1356 if (ON_SIDE (pad, *side) && pad->Mask)
1357 _draw_pad (Output.pmGC, pad, true, true);
1358 return 1;
1361 static int
1362 clearPin_callback_solid (const BoxType * b, void *cl)
1364 PinType *pin = (PinType *) b;
1365 hid_draw_fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
1366 return 1;
1369 static int
1370 clearPad_callback_solid (const BoxType * b, void *cl)
1372 PadType *pad = (PadType *) b;
1373 int *side = cl;
1374 if (ON_SIDE (pad, *side) && pad->Mask)
1375 hid_draw_fill_pcb_pad (Output.pmGC, pad, true, true);
1376 return 1;
1379 static void
1380 GhidDrawMask (int side, BoxType * screen)
1382 int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
1383 LayerType *Layer = LAYER_PTR (side == TOP_SIDE ? top_soldermask_layer : bottom_soldermask_layer);
1384 struct poly_info info;
1385 OutputType *out = &Output;
1387 if (thin)
1389 hid_draw_set_line_width (Output.pmGC, 0);
1390 hid_draw_set_color (Output.pmGC, PCB->MaskColor);
1391 r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, NULL);
1392 r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, NULL);
1393 r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &side);
1394 hid_draw_set_color (Output.pmGC, "erase");
1397 hid_draw_use_mask (&ghid_graphics, HID_MASK_CLEAR);
1399 info.layer = Layer;
1400 info.drawn_area = screen;
1401 r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
1402 r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
1403 r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
1404 r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
1406 r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback_solid, NULL);
1407 r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback_solid, NULL);
1408 r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback_solid, &side);
1410 hid_draw_use_mask (&ghid_graphics, HID_MASK_AFTER);
1411 hid_draw_set_color (out->fgGC, PCB->MaskColor);
1412 ghid_set_alpha_mult (out->fgGC, thin ? 0.35 : 1.0);
1413 hid_draw_fill_rect (out->fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
1414 ghid_set_alpha_mult (out->fgGC, 1.0);
1416 hid_draw_use_mask (&ghid_graphics, HID_MASK_OFF);
1419 static int
1420 GhidDrawLayerGroup (int group, const BoxType * screen)
1422 render_priv *priv = gport->render_priv;
1423 int i;
1424 int layernum;
1425 int side;
1426 struct poly_info info;
1427 LayerType *Layer;
1428 int n_entries = PCB->LayerGroups.Number[group];
1429 Cardinal *layers = PCB->LayerGroups.Entries[group];
1430 int first_run = 1;
1431 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1432 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1433 bool is_outline;
1435 if (!hid_draw_set_layer (&ghid_graphics, 0, group, 0))
1436 return 0;
1438 /* HACK: Subcomposite each layer in a layer group separately */
1439 for (i = n_entries - 1; i >= 0; i--) {
1440 layernum = layers[i];
1441 Layer = PCB->Data->Layer + layers[i];
1443 is_outline = strcmp (Layer->Name, "outline") == 0 ||
1444 strcmp (Layer->Name, "route") == 0;
1446 if (layernum < max_copper_layer && Layer->On) {
1448 if (!first_run)
1449 hid_draw_set_layer (&ghid_graphics, 0, group, 0);
1451 first_run = 0;
1453 if (!is_outline && !TEST_FLAG (THINDRAWFLAG, PCB)) {
1454 /* Mask out drilled holes on this layer */
1455 hidgl_flush_triangles (priv->hidgl);
1456 glPushAttrib (GL_COLOR_BUFFER_BIT);
1457 glColorMask (0, 0, 0, 0);
1458 hid_draw_set_color (Output.bgGC, PCB->MaskColor);
1459 if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, hole_callback, NULL);
1460 if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, hole_callback, NULL);
1461 hidgl_flush_triangles (priv->hidgl);
1462 glPopAttrib ();
1465 /* draw all polygons on this layer */
1466 if (Layer->PolygonN) {
1467 info.layer = Layer;
1468 info.drawn_area = screen;
1469 r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
1471 /* HACK: Subcomposite polygons separately from other layer primitives */
1472 /* Reset the compositing */
1473 hid_draw_end_layer (&ghid_graphics);
1474 hid_draw_set_layer (&ghid_graphics, 0, group, 0);
1476 if (!is_outline && !TEST_FLAG (THINDRAWFLAG, PCB)) {
1477 hidgl_flush_triangles (priv->hidgl);
1478 glPushAttrib (GL_COLOR_BUFFER_BIT);
1479 glColorMask (0, 0, 0, 0);
1480 /* Mask out drilled holes on this layer */
1481 if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, hole_callback, NULL);
1482 if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, hole_callback, NULL);
1483 hidgl_flush_triangles (priv->hidgl);
1484 glPopAttrib ();
1488 /* Draw pins, vias and pads on this layer */
1489 if (!global_view_2d && !is_outline) {
1490 if (PCB->PinOn) r_search (PCB->Data->pin_tree, screen, NULL, pin_inlayer_callback, Layer);
1491 if (PCB->ViaOn) r_search (PCB->Data->via_tree, screen, NULL, via_inlayer_callback, Layer);
1492 if (PCB->PinOn && group == top_group)
1494 side = TOP_SIDE;
1495 r_search (PCB->Data->pad_tree, screen, NULL, pad_callback, &side);
1497 if (PCB->PinOn && group == bottom_group)
1499 side = BOTTOM_SIDE;
1500 r_search (PCB->Data->pad_tree, screen, NULL, pad_callback, &side);
1504 if (TEST_FLAG (CHECKPLANESFLAG, PCB))
1505 continue;
1507 r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
1508 r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
1509 r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
1513 hid_draw_end_layer (&ghid_graphics);
1515 return (n_entries > 1);
1518 static void
1519 DrawDrillChannel (hidGC gc, int vx, int vy, int vr, int from_layer, int to_layer, double scale)
1521 #define PIXELS_PER_CIRCLINE 5.
1522 #define MIN_FACES_PER_CYL 6
1523 #define MAX_FACES_PER_CYL 360
1524 float radius = vr;
1525 float x1, y1;
1526 float x2, y2;
1527 float z1, z2;
1528 int i;
1529 int slices;
1531 slices = M_PI * 2 * vr / scale / PIXELS_PER_CIRCLINE;
1533 if (slices < MIN_FACES_PER_CYL)
1534 slices = MIN_FACES_PER_CYL;
1536 if (slices > MAX_FACES_PER_CYL)
1537 slices = MAX_FACES_PER_CYL;
1539 z1 = compute_depth (from_layer);
1540 z2 = compute_depth (to_layer);
1542 x1 = vx + vr;
1543 y1 = vy;
1545 hidgl_ensure_triangle_space (gc, 2 * slices);
1546 for (i = 0; i < slices; i++)
1548 x2 = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
1549 y2 = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
1550 hidgl_add_triangle_3D (gc, x1, y1, z1, x2, y2, z1, x1, y1, z2);
1551 hidgl_add_triangle_3D (gc, x2, y2, z1, x1, y1, z2, x2, y2, z2);
1552 x1 = x2;
1553 y1 = y2;
1557 struct cyl_info {
1558 int from_layer;
1559 int to_layer;
1560 double scale;
1563 static int
1564 draw_hole_cyl (PinType *Pin, struct cyl_info *info, int Type)
1566 char *color;
1568 if (TEST_FLAG (WARNFLAG, Pin))
1569 color = PCB->WarnColor;
1570 else if (TEST_FLAG (SELECTEDFLAG, Pin))
1571 color = (Type == VIA_TYPE) ? PCB->ViaSelectedColor : PCB->PinSelectedColor;
1572 else if (TEST_FLAG (CONNECTEDFLAG, Pin))
1573 color = PCB->ConnectedColor;
1574 else if (TEST_FLAG (FOUNDFLAG, Pin))
1575 color = PCB->FoundColor;
1576 else
1577 color = "drill";
1579 hid_draw_set_color (Output.fgGC, color);
1580 DrawDrillChannel (Output.fgGC, Pin->X, Pin->Y, Pin->DrillingHole / 2, info->from_layer, info->to_layer, info->scale);
1581 return 0;
1584 static int
1585 pin_hole_cyl_callback (const BoxType * b, void *cl)
1587 return draw_hole_cyl ((PinType *)b, (struct cyl_info *)cl, PIN_TYPE);
1590 static int
1591 via_hole_cyl_callback (const BoxType * b, void *cl)
1593 return draw_hole_cyl ((PinType *)b, (struct cyl_info *)cl, VIA_TYPE);
1596 void
1597 ghid_draw_everything (BoxType *drawn_area)
1599 render_priv *priv = gport->render_priv;
1600 int i, ngroups;
1601 int number_phys_on_top;
1602 int side;
1603 /* This is the list of layer groups we will draw. */
1604 int do_group[MAX_LAYER];
1605 /* This is the reverse of the order in which we draw them. */
1606 int drawn_groups[MAX_LAYER];
1607 struct cyl_info cyl_info;
1608 int reverse_layers;
1609 int save_show_solder;
1610 int top_group;
1611 int bottom_group;
1612 int min_phys_group;
1613 int max_phys_group;
1615 priv->current_colorname = NULL;
1617 /* Test direction of rendering */
1618 /* Look at sign of eye coordinate system z-coord when projecting a
1619 world vector along +ve Z axis, (0, 0, 1). */
1620 /* XXX: This isn't strictly correct, as I've ignored the matrix
1621 elements for homogeneous coordinates. */
1622 /* NB: last_modelview_matrix is transposed in memory! */
1623 reverse_layers = (last_modelview_matrix[2][2] < 0);
1625 save_show_solder = Settings.ShowBottomSide;
1626 Settings.ShowBottomSide = reverse_layers;
1628 PCB->Data->SILKLAYER.Color = PCB->ElementColor;
1629 PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
1631 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1632 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1634 min_phys_group = MIN (bottom_group, top_group);
1635 max_phys_group = MAX (bottom_group, top_group);
1637 memset (do_group, 0, sizeof (do_group));
1638 if (global_view_2d) {
1639 /* Draw in layer stack order when in 2D view */
1640 for (ngroups = 0, i = 0; i < max_copper_layer; i++) {
1641 int group = GetLayerGroupNumberByNumber (LayerStack[i]);
1643 if (!do_group[group]) {
1644 do_group[group] = 1;
1645 drawn_groups[ngroups++] = group;
1648 } else {
1649 /* Draw in group order when in 3D view */
1650 for (ngroups = 0, i = 0; i < max_group; i++) {
1651 int group = reverse_layers ? max_group - 1 - i : i;
1653 if (!do_group[group]) {
1654 do_group[group] = 1;
1655 drawn_groups[ngroups++] = group;
1661 * first draw all 'invisible' stuff
1663 side = SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE;
1665 if (!TEST_FLAG (CHECKPLANESFLAG, PCB) &&
1666 hid_draw_set_layer (&ghid_graphics, "invisible", SL (INVISIBLE, 0), 0)) {
1667 DrawSilk (&ghid_graphics, side, drawn_area);
1669 if (global_view_2d)
1670 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
1672 hid_draw_end_layer (&ghid_graphics);
1674 /* Draw the reverse-side solder mask if turned on */
1675 if (!global_view_2d &&
1676 hid_draw_set_layer (&ghid_graphics, SWAP_IDENT ? "componentmask" : "soldermask",
1677 SWAP_IDENT ? SL (MASK, TOP) : SL (MASK, BOTTOM), 0)) {
1678 GhidDrawMask (side, drawn_area);
1679 hid_draw_end_layer (&ghid_graphics);
1683 /* draw all layers in layerstack order */
1684 #define FADE_FACTOR 0.8
1685 number_phys_on_top = max_phys_group - min_phys_group;
1686 for (i = ngroups - 1; i >= 0; i--) {
1687 bool is_this_physical = drawn_groups[i] >= min_phys_group &&
1688 drawn_groups[i] <= max_phys_group;
1689 bool is_next_physical = i > 0 &&
1690 drawn_groups[i - 1] >= min_phys_group &&
1691 drawn_groups[i - 1] <= max_phys_group;
1693 double alpha_mult = global_view_2d ? pow (FADE_FACTOR, i) :
1694 (is_this_physical ? pow (FADE_FACTOR, number_phys_on_top) : 1.);
1696 if (is_this_physical)
1697 number_phys_on_top --;
1699 ghid_set_alpha_mult (Output.fgGC, alpha_mult);
1700 GhidDrawLayerGroup (drawn_groups [i], drawn_area);
1702 #if 1
1703 if (!global_view_2d && is_this_physical && is_next_physical) {
1704 cyl_info.from_layer = drawn_groups[i];
1705 cyl_info.to_layer = drawn_groups[i - 1];
1706 cyl_info.scale = gport->view.coord_per_px;
1707 hid_draw_set_color (Output.fgGC, "drill");
1708 ghid_set_alpha_mult (Output.fgGC, alpha_mult * 0.75);
1709 if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_hole_cyl_callback, &cyl_info);
1710 if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_hole_cyl_callback, &cyl_info);
1712 #endif
1714 #undef FADE_FACTOR
1716 ghid_set_alpha_mult (Output.fgGC, 1.0);
1718 if (TEST_FLAG (CHECKPLANESFLAG, PCB))
1719 return;
1721 side = SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE;
1723 /* Draw pins, pads, vias below silk */
1724 if (global_view_2d) {
1725 start_subcomposite (priv->hidgl);
1727 if (!TEST_FLAG (THINDRAWFLAG, PCB)) {
1728 /* Mask out drilled holes */
1729 hidgl_flush_triangles (priv->hidgl);
1730 glPushAttrib (GL_COLOR_BUFFER_BIT);
1731 glColorMask (0, 0, 0, 0);
1732 if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
1733 if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
1734 hidgl_flush_triangles (priv->hidgl);
1735 glPopAttrib ();
1738 if (PCB->PinOn) r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
1739 if (PCB->PinOn) r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
1740 if (PCB->ViaOn) r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
1742 end_subcomposite (priv->hidgl);
1745 /* Draw the solder mask if turned on */
1746 if (hid_draw_set_layer (&ghid_graphics, SWAP_IDENT ? "soldermask" : "componentmask",
1747 SWAP_IDENT ? SL (MASK, BOTTOM) : SL (MASK, TOP), 0)) {
1748 GhidDrawMask (side, drawn_area);
1749 hid_draw_end_layer (&ghid_graphics);
1752 if (hid_draw_set_layer (&ghid_graphics, SWAP_IDENT ? "bottomsilk" : "topsilk",
1753 SWAP_IDENT ? SL (SILK, BOTTOM) : SL (SILK, TOP), 0)) {
1754 DrawSilk (&ghid_graphics, side, drawn_area);
1755 hid_draw_end_layer (&ghid_graphics);
1758 /* Draw element Marks */
1759 if (PCB->PinOn)
1760 r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback, NULL);
1762 /* Draw rat lines on top */
1763 if (PCB->RatOn && hid_draw_set_layer (&ghid_graphics, "rats", SL (RATS, 0), 0)) {
1764 DrawRats (&ghid_graphics, drawn_area);
1765 hid_draw_end_layer (&ghid_graphics);
1768 Settings.ShowBottomSide = save_show_solder;
1771 #define Z_NEAR 3.0
1772 gboolean
1773 ghid_drawing_area_expose_cb (GtkWidget *widget,
1774 GdkEventExpose *ev,
1775 GHidPort *port)
1777 render_priv *priv = port->render_priv;
1778 GtkAllocation allocation;
1779 BoxType region;
1780 Coord min_x, min_y;
1781 Coord max_x, max_y;
1782 Coord new_x, new_y;
1783 Coord min_depth;
1784 Coord max_depth;
1786 gtk_widget_get_allocation (widget, &allocation);
1788 ghid_start_drawing (port, widget);
1790 Output.fgGC = hid_draw_make_gc (&ghid_graphics);
1791 Output.bgGC = hid_draw_make_gc (&ghid_graphics);
1792 Output.pmGC = hid_draw_make_gc (&ghid_graphics);
1794 /* If we don't have any stencil bits available,
1795 we can't use the hidgl polygon drawing routine */
1796 /* TODO: We could use the GLU tessellator though */
1797 if (hidgl_stencil_bits (priv->hidgl) == 0)
1798 ghid_graphics_class.fill_pcb_polygon = common_fill_pcb_polygon;
1800 glEnable (GL_BLEND);
1801 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1803 glViewport (0, 0, allocation.width, allocation.height);
1805 glEnable (GL_SCISSOR_TEST);
1806 glScissor (ev->area.x,
1807 allocation.height - ev->area.height - ev->area.y,
1808 ev->area.width, ev->area.height);
1810 glMatrixMode (GL_PROJECTION);
1811 glLoadIdentity ();
1812 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1813 glMatrixMode (GL_MODELVIEW);
1814 glLoadIdentity ();
1815 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
1816 glMultMatrixf ((GLfloat *)view_matrix);
1817 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
1818 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1819 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1820 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
1821 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1822 -port->view.x0,
1823 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1824 -port->view.y0, 0);
1825 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
1827 glEnable (GL_STENCIL_TEST);
1828 glClearColor (port->offlimits_color.red / 65535.,
1829 port->offlimits_color.green / 65535.,
1830 port->offlimits_color.blue / 65535.,
1831 1.);
1832 glStencilMask (~0);
1833 glClearStencil (0);
1834 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1835 hidgl_reset_stencil_usage (priv->hidgl);
1837 /* Disable the stencil test until we need it - otherwise it gets dirty */
1838 glDisable (GL_STENCIL_TEST);
1839 glStencilMask (0);
1840 glStencilFunc (GL_ALWAYS, 0, 0);
1842 /* Test the 8 corners of a cube spanning the event */
1843 min_depth = -50 + compute_depth (0); /* FIXME: NEED TO USE PHYSICAL GROUPS */
1844 max_depth = 50 + compute_depth (max_copper_layer - 1); /* FIXME: NEED TO USE PHYSICAL GROUPS */
1846 ghid_unproject_to_z_plane (ev->area.x,
1847 ev->area.y,
1848 min_depth, &new_x, &new_y);
1849 max_x = min_x = new_x;
1850 max_y = min_y = new_y;
1852 ghid_unproject_to_z_plane (ev->area.x,
1853 ev->area.y,
1854 max_depth, &new_x, &new_y);
1855 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1856 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1858 /* */
1859 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
1860 ev->area.y,
1861 min_depth, &new_x, &new_y);
1862 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1863 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1865 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
1866 max_depth, &new_x, &new_y);
1867 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1868 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1870 /* */
1871 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
1872 ev->area.y + ev->area.height,
1873 min_depth, &new_x, &new_y);
1874 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1875 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1877 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
1878 ev->area.y + ev->area.height,
1879 max_depth, &new_x, &new_y);
1880 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1881 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1883 /* */
1884 ghid_unproject_to_z_plane (ev->area.x,
1885 ev->area.y + ev->area.height,
1886 min_depth,
1887 &new_x, &new_y);
1888 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1889 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1891 ghid_unproject_to_z_plane (ev->area.x,
1892 ev->area.y + ev->area.height,
1893 max_depth,
1894 &new_x, &new_y);
1895 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
1896 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
1898 region.X1 = min_x; region.X2 = max_x + 1;
1899 region.Y1 = min_y; region.Y2 = max_y + 1;
1901 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1902 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1903 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1904 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1906 glColor3f (port->bg_color.red / 65535.,
1907 port->bg_color.green / 65535.,
1908 port->bg_color.blue / 65535.);
1910 ghid_invalidate_current_gc ();
1912 /* Setup stenciling */
1913 /* Drawing operations set the stencil buffer to '1' */
1914 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
1915 /* Drawing operations as masked to areas where the stencil buffer is '0' */
1916 /* glStencilFunc (GL_GREATER, 1, 1); */ /* Draw only where stencil buffer is 0 */
1918 if (global_view_2d) {
1919 glBegin (GL_QUADS);
1920 glVertex3i (0, 0, 0);
1921 glVertex3i (PCB->MaxWidth, 0, 0);
1922 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
1923 glVertex3i (0, PCB->MaxHeight, 0);
1924 glEnd ();
1925 } else {
1926 int top_group;
1927 int bottom_group;
1928 int min_phys_group;
1929 int max_phys_group;
1930 int i;
1932 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1933 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1935 min_phys_group = MIN (bottom_group, top_group);
1936 max_phys_group = MAX (bottom_group, top_group);
1938 glBegin (GL_QUADS);
1939 for (i = min_phys_group; i <= max_phys_group; i++) {
1940 int depth = compute_depth (i);
1941 glVertex3i (0, 0, depth);
1942 glVertex3i (PCB->MaxWidth, 0, depth);
1943 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, depth);
1944 glVertex3i (0, PCB->MaxHeight, depth);
1946 glEnd ();
1949 ghid_draw_bg_image ();
1951 /* hid_expose_callback (&ghid_graphics, &region, 0); */
1952 ghid_draw_everything (&region);
1953 hidgl_flush_triangles (priv->hidgl);
1955 /* Set the current depth to the right value for the layer we are editing */
1956 priv->edit_depth = compute_depth (GetLayerGroupNumberByNumber (INDEXOFCURRENT));
1957 hidgl_set_depth (Output.fgGC, priv->edit_depth);
1959 ghid_draw_grid (Output.fgGC, &region);
1961 ghid_invalidate_current_gc ();
1963 DrawAttached (Output.fgGC);
1964 DrawMark (Output.fgGC);
1965 hidgl_flush_triangles (priv->hidgl);
1967 draw_crosshair (Output.fgGC, priv);
1968 hidgl_flush_triangles (priv->hidgl);
1970 draw_lead_user (Output.fgGC, priv);
1972 ghid_end_drawing (port, widget);
1974 hid_draw_destroy_gc (Output.fgGC);
1975 hid_draw_destroy_gc (Output.bgGC);
1976 hid_draw_destroy_gc (Output.pmGC);
1978 Output.fgGC = NULL;
1979 Output.bgGC = NULL;
1980 Output.pmGC = NULL;
1981 g_timer_start (priv->time_since_expose);
1983 return FALSE;
1986 /* This realize callback is used to work around a crash bug in some mesa
1987 * versions (observed on a machine running the intel i965 driver. It isn't
1988 * obvious why it helps, but somehow fiddling with the GL context here solves
1989 * the issue. The problem appears to have been fixed in recent mesa versions.
1991 void
1992 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
1994 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
1995 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
1997 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
1998 return;
2000 gdk_gl_drawable_gl_end (gldrawable);
2001 return;
2004 gboolean
2005 ghid_pinout_preview_expose (GtkWidget *widget,
2006 GdkEventExpose *ev)
2008 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
2009 render_priv *priv = gport->render_priv;
2010 GtkAllocation allocation;
2011 view_data save_view;
2012 int save_width, save_height;
2013 Coord save_max_width;
2014 Coord save_max_height;
2015 double xz, yz;
2017 save_view = gport->view;
2018 save_width = gport->width;
2019 save_height = gport->height;
2020 save_max_width = PCB->MaxWidth;
2021 save_max_height = PCB->MaxHeight;
2023 /* Setup zoom factor for drawing routines */
2025 gtk_widget_get_allocation (widget, &allocation);
2026 xz = (double) pinout->x_max / allocation.width;
2027 yz = (double) pinout->y_max / allocation.height;
2028 if (xz > yz)
2029 gport->view.coord_per_px = xz;
2030 else
2031 gport->view.coord_per_px = yz;
2033 gport->width = allocation.width;
2034 gport->height = allocation.height;
2035 gport->view.width = allocation.width * gport->view.coord_per_px;
2036 gport->view.height = allocation.height * gport->view.coord_per_px;
2037 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
2038 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
2039 PCB->MaxWidth = pinout->x_max;
2040 PCB->MaxHeight = pinout->y_max;
2042 ghid_start_drawing (gport, widget);
2044 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not
2045 * call set_layer() as appropriate for us to sub-composite rendering
2046 * from each layer when drawing a single element. If we leave alpha-
2047 * blending on, it means text and overlapping pads are rendered ugly.
2050 glEnable (GL_BLEND);
2051 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2052 #endif
2054 glViewport (0, 0, allocation.width, allocation.height);
2056 #if 0 /* We disable the scissor test here, as it is interacting badly with
2057 * being handed expose events which don't cover the whole window.
2058 * As we have a double-buffered GL window, we end up with unintialised
2059 * contents remaining in the unpainted areas (outside the scissor
2060 * region), and these are being flipped onto the screen.
2062 * The debugging code below shows multiple expose events when the
2063 * window is shown the first time, some of which are very small.
2065 * XXX: There is clearly a perforamnce issue here, in that we may
2066 * be rendering the preview more times, and over a larger area
2067 * than is really required.
2070 glEnable (GL_SCISSOR_TEST);
2071 glScissor (ev->area.x,
2072 allocation.height - ev->area.height - ev->area.y,
2073 ev->area.width, ev->area.height);
2074 #endif
2076 #ifdef DEBUG
2077 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
2078 ev->area.x, ev->area.y, ev->area.width, ev->area.height,
2079 (double)ev->area.x,
2080 (double)(allocation.height - ev->area.height - ev->area.y),
2081 (double)ev->area.width,
2082 (double)ev->area.height);
2083 #endif
2085 glMatrixMode (GL_PROJECTION);
2086 glLoadIdentity ();
2087 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
2088 glMatrixMode (GL_MODELVIEW);
2089 glLoadIdentity ();
2090 glTranslatef (0.0f, 0.0f, -Z_NEAR);
2092 glClearColor (gport->bg_color.red / 65535.,
2093 gport->bg_color.green / 65535.,
2094 gport->bg_color.blue / 65535.,
2095 1.);
2096 glStencilMask (~0);
2097 glClearStencil (0);
2098 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2099 hidgl_reset_stencil_usage (priv->hidgl);
2101 /* Disable the stencil test until we need it - otherwise it gets dirty */
2102 glDisable (GL_STENCIL_TEST);
2103 glStencilMask (0);
2104 glStencilFunc (GL_ALWAYS, 0, 0);
2106 /* call the drawing routine */
2107 ghid_invalidate_current_gc ();
2108 glPushMatrix ();
2109 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
2110 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
2111 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
2112 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
2113 -gport->view.x0,
2114 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
2115 -gport->view.y0, 0);
2117 hid_expose_callback (&ghid_graphics, NULL, pinout->element);
2118 hidgl_flush_triangles (priv->hidgl);
2119 glPopMatrix ();
2121 ghid_end_drawing (gport, widget);
2123 gport->view = save_view;
2124 gport->width = save_width;
2125 gport->height = save_height;
2126 PCB->MaxWidth = save_max_width;
2127 PCB->MaxHeight = save_max_height;
2129 return FALSE;
2133 GdkPixmap *
2134 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
2136 render_priv *priv = gport->render_priv;
2137 GdkGLConfig *glconfig;
2138 GdkPixmap *pixmap;
2139 GdkGLPixmap *glpixmap;
2140 GdkGLContext* glcontext;
2141 GdkGLDrawable* gldrawable;
2142 view_data save_view;
2143 int save_width, save_height;
2144 BoxType region;
2146 save_view = gport->view;
2147 save_width = gport->width;
2148 save_height = gport->height;
2150 /* Setup rendering context for drawing routines
2153 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
2154 GDK_GL_MODE_STENCIL |
2155 GDK_GL_MODE_SINGLE);
2157 pixmap = gdk_pixmap_new (NULL, width, height, depth);
2158 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
2159 gldrawable = GDK_GL_DRAWABLE (glpixmap);
2160 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
2162 /* Setup zoom factor for drawing routines */
2164 gport->view.coord_per_px = zoom;
2165 gport->width = width;
2166 gport->height = height;
2167 gport->view.width = width * gport->view.coord_per_px;
2168 gport->view.height = height * gport->view.coord_per_px;
2169 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
2170 gport->view.x0 -= gport->view.height / 2;
2171 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
2172 gport->view.y0 -= gport->view.width / 2;
2174 /* make GL-context "current" */
2175 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
2176 return NULL;
2178 hidgl_start_render (priv->hidgl);
2179 gport->render_priv->in_context = true;
2181 glEnable (GL_BLEND);
2182 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2184 glViewport (0, 0, width, height);
2186 glEnable (GL_SCISSOR_TEST);
2187 glScissor (0, 0, width, height);
2189 glMatrixMode (GL_PROJECTION);
2190 glLoadIdentity ();
2191 glOrtho (0, width, height, 0, -100000, 100000);
2192 glMatrixMode (GL_MODELVIEW);
2193 glLoadIdentity ();
2194 glTranslatef (0.0f, 0.0f, -Z_NEAR);
2196 glClearColor (gport->bg_color.red / 65535.,
2197 gport->bg_color.green / 65535.,
2198 gport->bg_color.blue / 65535.,
2199 1.);
2200 glStencilMask (~0);
2201 glClearStencil (0);
2202 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2203 hidgl_reset_stencil_usage (priv->hidgl);
2205 /* Disable the stencil test until we need it - otherwise it gets dirty */
2206 glDisable (GL_STENCIL_TEST);
2207 glStencilMask (0);
2208 glStencilFunc (GL_ALWAYS, 0, 0);
2210 /* call the drawing routine */
2211 ghid_invalidate_current_gc ();
2212 glPushMatrix ();
2213 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
2214 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
2215 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
2216 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
2217 -gport->view.x0,
2218 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
2219 -gport->view.y0, 0);
2221 region.X1 = MIN(Px(0), Px(gport->width + 1));
2222 region.Y1 = MIN(Py(0), Py(gport->height + 1));
2223 region.X2 = MAX(Px(0), Px(gport->width + 1));
2224 region.Y2 = MAX(Py(0), Py(gport->height + 1));
2226 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
2227 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
2228 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
2229 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
2231 hid_expose_callback (&ghid_graphics, &region, NULL);
2232 hidgl_flush_triangles (priv->hidgl);
2233 glPopMatrix ();
2235 glFlush ();
2237 hidgl_finish_render (priv->hidgl);
2239 /* end drawing to current GL-context */
2240 gport->render_priv->in_context = false;
2241 gdk_gl_drawable_gl_end (gldrawable);
2243 gdk_pixmap_unset_gl_capability (pixmap);
2245 g_object_unref (glconfig);
2246 g_object_unref (glcontext);
2248 gport->view = save_view;
2249 gport->width = save_width;
2250 gport->height = save_height;
2252 return pixmap;
2255 HID_DRAW *
2256 ghid_request_debug_draw (void)
2258 GHidPort *port = gport;
2259 GtkWidget *widget = port->drawing_area;
2260 GtkAllocation allocation;
2262 gtk_widget_get_allocation (widget, &allocation);
2264 ghid_start_drawing (port, widget);
2266 glViewport (0, 0, allocation.width, allocation.height);
2268 glMatrixMode (GL_PROJECTION);
2269 glLoadIdentity ();
2270 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
2271 glMatrixMode (GL_MODELVIEW);
2272 glLoadIdentity ();
2273 glTranslatef (0.0f, 0.0f, -Z_NEAR);
2275 ghid_invalidate_current_gc ();
2277 /* Setup stenciling */
2278 glDisable (GL_STENCIL_TEST);
2280 glPushMatrix ();
2281 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
2282 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
2283 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
2284 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
2285 -port->view.x0,
2286 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
2287 -port->view.y0, 0);
2289 return &ghid_graphics;
2292 void
2293 ghid_flush_debug_draw (void)
2295 render_priv *priv = gport->render_priv;
2296 GtkWidget *widget = gport->drawing_area;
2297 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
2299 hidgl_flush_triangles (priv->hidgl);
2301 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
2302 gdk_gl_drawable_swap_buffers (pGlDrawable);
2303 else
2304 glFlush ();
2307 void
2308 ghid_finish_debug_draw (void)
2310 render_priv *priv = gport->render_priv;
2312 hidgl_flush_triangles (priv->hidgl);
2313 glPopMatrix ();
2315 ghid_end_drawing (gport, gport->drawing_area);
2318 static float
2319 determinant_2x2 (float m[2][2])
2321 float det;
2322 det = m[0][0] * m[1][1] -
2323 m[0][1] * m[1][0];
2324 return det;
2327 #if 0
2328 static float
2329 determinant_4x4 (float m[4][4])
2331 float det;
2332 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] -
2333 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
2334 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
2335 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
2336 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
2337 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
2338 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
2339 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
2340 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
2341 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
2342 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
2343 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
2344 return det;
2346 #endif
2348 static void
2349 invert_2x2 (float m[2][2], float out[2][2])
2351 float scale = 1 / determinant_2x2 (m);
2352 out[0][0] = m[1][1] * scale;
2353 out[0][1] = -m[0][1] * scale;
2354 out[1][0] = -m[1][0] * scale;
2355 out[1][1] = m[0][0] * scale;
2358 #if 0
2359 static void
2360 invert_4x4 (float m[4][4], float out[4][4])
2362 float scale = 1 / determinant_4x4 (m);
2364 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
2365 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
2366 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
2367 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
2368 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
2369 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
2370 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
2371 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
2372 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
2373 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
2374 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
2375 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
2376 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
2377 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
2378 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
2379 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
2380 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
2381 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
2382 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
2383 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
2384 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
2385 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
2386 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
2387 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
2388 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
2389 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
2390 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
2391 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
2392 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
2393 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
2394 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
2395 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
2396 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
2397 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
2398 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
2399 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
2400 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
2401 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
2402 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
2403 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
2404 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
2405 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
2406 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
2407 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
2408 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
2409 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
2410 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
2411 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
2413 #endif
2416 static void
2417 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
2419 float mat[2][2];
2420 float inv_mat[2][2];
2421 float x, y;
2424 ex = view_matrix[0][0] * vx +
2425 view_matrix[0][1] * vy +
2426 view_matrix[0][2] * vz +
2427 view_matrix[0][3] * 1;
2428 ey = view_matrix[1][0] * vx +
2429 view_matrix[1][1] * vy +
2430 view_matrix[1][2] * vz +
2431 view_matrix[1][3] * 1;
2432 UNKNOWN ez = view_matrix[2][0] * vx +
2433 view_matrix[2][1] * vy +
2434 view_matrix[2][2] * vz +
2435 view_matrix[2][3] * 1;
2437 ex - view_matrix[0][3] * 1
2438 - view_matrix[0][2] * vz
2439 = view_matrix[0][0] * vx +
2440 view_matrix[0][1] * vy;
2442 ey - view_matrix[1][3] * 1
2443 - view_matrix[1][2] * vz
2444 = view_matrix[1][0] * vx +
2445 view_matrix[1][1] * vy;
2448 /* NB: last_modelview_matrix is transposed in memory! */
2449 x = (float)ex - last_modelview_matrix[3][0] * 1
2450 - last_modelview_matrix[2][0] * pcb_z;
2452 y = (float)ey - last_modelview_matrix[3][1] * 1
2453 - last_modelview_matrix[2][1] * pcb_z;
2456 x = view_matrix[0][0] * vx +
2457 view_matrix[0][1] * vy;
2459 y = view_matrix[1][0] * vx +
2460 view_matrix[1][1] * vy;
2462 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
2463 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
2466 mat[0][0] = last_modelview_matrix[0][0];
2467 mat[0][1] = last_modelview_matrix[1][0];
2468 mat[1][0] = last_modelview_matrix[0][1];
2469 mat[1][1] = last_modelview_matrix[1][1];
2471 /* if (determinant_2x2 (mat) < 0.00001) */
2472 /* printf ("Determinant is quite small\n"); */
2474 invert_2x2 (mat, inv_mat);
2476 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
2477 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
2481 bool
2482 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
2484 render_priv *priv = gport->render_priv;
2486 ghid_unproject_to_z_plane (event_x, event_y, priv->edit_depth, pcb_x, pcb_y);
2488 return true;
2491 bool
2492 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
2494 render_priv *priv = gport->render_priv;
2496 /* NB: last_modelview_matrix is transposed in memory */
2497 float w = last_modelview_matrix[0][3] * (float)pcb_x +
2498 last_modelview_matrix[1][3] * (float)pcb_y +
2499 last_modelview_matrix[2][3] * 0. +
2500 last_modelview_matrix[3][3] * 1.;
2502 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
2503 last_modelview_matrix[1][0] * (float)pcb_y +
2504 last_modelview_matrix[2][0] * priv->edit_depth +
2505 last_modelview_matrix[3][0] * 1.) / w;
2506 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
2507 last_modelview_matrix[1][1] * (float)pcb_y +
2508 last_modelview_matrix[2][1] * priv->edit_depth +
2509 last_modelview_matrix[3][1] * 1.) / w;
2511 return true;
2514 void
2515 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
2517 global_view_2d = view_2d;
2518 ghid_invalidate_all ();
2521 void
2522 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
2524 #ifdef DEBUG_ROTATE
2525 int row, column;
2526 #endif
2528 build_rotmatrix (view_matrix, quarternion);
2530 #ifdef DEBUG_ROTATE
2531 for (row = 0; row < 4; row++) {
2532 printf ("[ %f", view_matrix[row][0]);
2533 for (column = 1; column < 4; column++) {
2534 printf (",\t%f", view_matrix[row][column]);
2536 printf ("\t]\n");
2538 printf ("\n");
2539 #endif
2541 ghid_invalidate_all ();
2545 #define LEAD_USER_WIDTH 0.2 /* millimeters */
2546 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
2547 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
2548 #define LEAD_USER_ARC_COUNT 3
2549 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
2550 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
2551 #define LEAD_USER_COLOR_R 1.
2552 #define LEAD_USER_COLOR_G 1.
2553 #define LEAD_USER_COLOR_B 0.
2555 static void
2556 draw_lead_user (hidGC gc, render_priv *priv)
2558 gtkGC gtk_gc = (gtkGC)gc;
2559 int i;
2560 double radius = priv->lead_user_radius;
2561 double width = MM_TO_COORD (LEAD_USER_WIDTH);
2562 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
2564 if (!priv->lead_user)
2565 return;
2567 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
2568 glEnable (GL_COLOR_LOGIC_OP);
2569 glLogicOp (GL_XOR);
2570 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
2573 /* arcs at the approrpriate radii */
2575 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
2577 if (radius < width)
2578 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
2580 /* Draw an arc at radius */
2581 hidgl_draw_arc (gc, width, priv->lead_user_x, priv->lead_user_y,
2582 radius, radius, 0, 360, gport->view.coord_per_px);
2585 hidgl_flush_triangles (gtk_gc->hidgl_gc.hidgl);
2586 glPopAttrib ();
2589 gboolean
2590 lead_user_cb (gpointer data)
2592 render_priv *priv = data;
2593 Coord step;
2594 double elapsed_time;
2596 /* Queue a redraw */
2597 ghid_invalidate_all ();
2599 /* Update radius */
2600 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
2601 g_timer_start (priv->lead_user_timer);
2603 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
2604 if (priv->lead_user_radius > step)
2605 priv->lead_user_radius -= step;
2606 else
2607 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
2609 return TRUE;
2612 void
2613 ghid_lead_user_to_location (Coord x, Coord y)
2615 render_priv *priv = gport->render_priv;
2617 ghid_cancel_lead_user ();
2619 priv->lead_user = true;
2620 priv->lead_user_x = x;
2621 priv->lead_user_y = y;
2622 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
2623 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
2624 priv->lead_user_timer = g_timer_new ();
2627 void
2628 ghid_cancel_lead_user (void)
2630 render_priv *priv = gport->render_priv;
2632 if (priv->lead_user_timeout)
2633 g_source_remove (priv->lead_user_timeout);
2635 if (priv->lead_user_timer)
2636 g_timer_destroy (priv->lead_user_timer);
2638 if (priv->lead_user)
2639 ghid_invalidate_all ();
2641 priv->lead_user_timeout = 0;
2642 priv->lead_user_timer = NULL;
2643 priv->lead_user = false;